Skip to contentSkip to conversation

genirq: Hierarchical irq domains and generic MSI interrupt code

PATCH In review Thomas Gleixner 5 participants 94 messages Nov 12, 2014 – Dec 11, 2014

Subsystems (23)
lore
Share & tools
lore
#0 lore raw

cover genirq: Hierarchical irq domains and generic MSI interrupt code

This is an extract from Jiangs various patch series which only contains the generic irq and MSI parts w/o the x86 specific modifications.

This is roughly what I plan to merge into the generic irq core, so the various outstanding patches (irqchip/x86/...) can be based on this.

It's available from git as well:

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/irqdomain

Note, that branch is not yet exposed to linux-next and subject to modifications including rebasing.

Can all involved parties please have a close look and retest their patches on top of this?

Jiang, you need to merge that into x86/apic for rebasing your series.

Thanks,

tglx
----

 Documentation/IRQ-domain.txt           |   71 +++++
 arch/arm/mach-iop13xx/msi.c            |    2 
 arch/ia64/kernel/msi_ia64.c            |    4 
 arch/ia64/sn/kernel/msi_sn.c           |    4 
 arch/mips/pci/msi-octeon.c             |    2 
 arch/mips/pci/msi-xlp.c                |    2 
 arch/mips/pci/pci-xlr.c                |    2 
 arch/powerpc/platforms/cell/axon_msi.c |    2 
 arch/powerpc/platforms/powernv/pci.c   |    2 
 arch/powerpc/platforms/pseries/msi.c   |    2 
 arch/powerpc/sysdev/fsl_msi.c          |    2 
 arch/powerpc/sysdev/mpic_pasemi_msi.c  |    2 
 arch/powerpc/sysdev/mpic_u3msi.c       |    2 
 arch/powerpc/sysdev/ppc4xx_hsta_msi.c  |    2 
 arch/powerpc/sysdev/ppc4xx_msi.c       |    2 
 arch/s390/pci/pci.c                    |    2 
 arch/sparc/kernel/pci_msi.c            |    2 
 arch/tile/kernel/pci_gx.c              |    2 
 arch/x86/kernel/apic/io_apic.c         |    4 
 arch/x86/pci/xen.c                     |    4 
 drivers/iommu/irq_remapping.c          |    8 
 drivers/irqchip/irq-armada-370-xp.c    |    2 
 drivers/pci/Kconfig                    |    6 
 drivers/pci/host/pci-tegra.c           |    2 
 drivers/pci/host/pcie-designware.c     |    2 
 drivers/pci/host/pcie-rcar.c           |    2 
 drivers/pci/host/pcie-xilinx.c         |    2 
 drivers/pci/msi.c                      |  150 ++++++-----
 drivers/vfio/pci/vfio_pci_intrs.c      |    2 
 include/linux/irq.h                    |   33 ++
 include/linux/irqdomain.h              |   91 +++++++
 include/linux/irqhandler.h             |   14 +
 include/linux/msi.h                    |   53 +++-
 kernel/irq/Kconfig                     |   15 +
 kernel/irq/Makefile                    |    1 
 kernel/irq/chip.c                      |   37 ++
 kernel/irq/irqdomain.c                 |  418 +++++++++++++++++++++++++++++++--
 kernel/irq/manage.c                    |    2 
 kernel/irq/msi.c                       |  132 ++++++++++
 39 files changed, 959 insertions(+), 130 deletions(-)
#1 lore raw

PATCH 1/16 irqdomain: Introduce new interfaces to support hierarchy irqdomains

From: Jiang Liu <[email protected]>

We plan to use hierarchy irqdomain to suppport CPU vector assignment, interrupt remapping controller, IO-APIC controller, MSI interrupt and hypertransport interrupt etc on x86 platforms. So extend irqdomain interfaces to support hierarchy irqdomain.

There are already many clients of current irqdomain interfaces. To minimize the changes, we choose to introduce new version 2 interfaces to support hierarchy instead of extending existing irqdomain interfaces.

According to Thomas's suggestion, the most important design decision is to build hierarchy struct irq_data to support hierarchy irqdomain, so hierarchy irqdomain related data could be saved in struct irq_data. With support of hierarchy irq_data, we could also support stacked irq_chips. This is most useful in case of set_affinity().

The new hierarchy irqdomain introduces following interfaces:
1) irq_domain_alloc_irqs()/irq_domain_free_irqs(): allocate/release IRQ and related resources.
2) __irq_domain_alloc_irqs(): a special version to support legacy IRQs.
3) irq_domain_activate_irq()/irq_domain_deactivate_irq(): program interrupt controllers to activate/deactivate interrupt.

There are also several help functions to ease irqdomain implemenations:
1) irq_domain_get_irq_data(): get irq_data associated with a specific irqdomain.
2) irq_domain_set_hwirq_and_chip(): save irqdomain specific data into irq_data.
3) irq_domain_alloc_irqs_parent()/irq_domain_free_irqs_parent(): invoke parent irqdomain's alloc/free callbacks.

We also changed irq_startup()/irq_shutdown() to invoke irq_domain_activate_irq()/irq_domain_deactivate_irq() to program interrupt controller when start/stop interrupts.

[ tglx: Folded parts of the later patch series in ]

Cc Bjorn Helgaas <[email protected]>
Cc Grant Likely <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Yingjoe Chen <[email protected]>
Cc Yijing Wang <[email protected]>
---
 Documentation/IRQ-domain.txt |   71 +++++++
 include/linux/irq.h          |    5 
 include/linux/irqdomain.h    |   86 +++++++++
 kernel/irq/Kconfig           |    5 
 kernel/irq/chip.c            |    3 
 kernel/irq/irqdomain.c       |  391 +++++++++++++++++++++++++++++++++++++++++--
 6 files changed, 545 insertions(+), 16 deletions(-)
Documentation/IRQ-domain.txt +71 -0
Index: tip/Documentation/IRQ-domain.txt
===================================================================
@@ -151,3 +151,74 @@ used and no descriptor gets allocated it
 that the driver using the simple domain call irq_create_mapping()
 before any irq_find_mapping() since the latter will actually work
 for the static IRQ assignment case.
+
+==== Hierarchy IRQ domain ====
+On some architectures, there may be multiple interrupt controllers
+involved in delivering an interrupt from the device to the target CPU.
+Let's look at a typical interrupt delivering path on x86 platforms:
+
+Device --> IOAPIC -> Interrupt remapping Controller -> Local APIC -> CPU
+
+There are three interrupt controllers involved:
+1) IOAPIC controller
+2) Interrupt remapping controller
+3) Local APIC controller
+
+To support such a hardware topology and make software architecture match
+hardware architecture, an irq_domain data structure is built for each
+interrupt controller and those irq_domains are organized into hierarchy.
+When building irq_domain hierarchy, the irq_domain near to the device is
+child and the irq_domain near to CPU is parent. So a hierarchy structure
+as below will be built for the example above.
+	CPU Vector irq_domain (root irq_domain to manage CPU vectors)
+		^
+		|
+	Interrupt Remapping irq_domain (manage irq_remapping entries)
+		^
+		|
+	IOAPIC irq_domain (manage IOAPIC delivery entries/pins)
+
+There are four major interfaces to use hierarchy irq_domain:
+1) irq_domain_alloc_irqs(): allocate IRQ descriptors and interrupt
+   controller related resources to deliver these interrupts.
+2) irq_domain_free_irqs(): free IRQ descriptors and interrupt controller
+   related resources associated with these interrupts.
+3) irq_domain_activate_irq(): activate interrupt controller hardware to
+   deliver the interrupt.
+3) irq_domain_deactivate_irq(): deactivate interrupt controller hardware
+   to stop delivering the interrupt.
+
+Following changes are needed to support hierarchy irq_domain.
+1) a new field 'parent' is added to struct irq_domain; it's used to
+   maintain irq_domain hierarchy information.
+2) a new field 'parent_data' is added to struct irq_data; it's used to
+   build hierarchy irq_data to match hierarchy irq_domains. The irq_data
+   is used to store irq_domain pointer and hardware irq number.
+3) new callbacks are added to struct irq_domain_ops to support hierarchy
+   irq_domain operations.
+
+With support of hierarchy irq_domain and hierarchy irq_data ready, an
+irq_domain structure is built for each interrupt controller, and an
+irq_data structure is allocated for each irq_domain associated with an
+IRQ. Now we could go one step further to support stacked(hierarchy)
+irq_chip. That is, an irq_chip is associated with each irq_data along
+the hierarchy. A child irq_chip may implement a required action by
+itself or by cooperating with its parent irq_chip.
+
+With stacked irq_chip, interrupt controller driver only needs to deal
+with the hardware managed by itself and may ask for services from its
+parent irq_chip when needed. So we could achieve a much cleaner
+software architecture.
+
+For an interrupt controller driver to support hierarchy irq_domain, it
+needs to:
+1) Implement irq_domain_ops.alloc and irq_domain_ops.free
+2) Optionally implement irq_domain_ops.activate and
+   irq_domain_ops.deactivate.
+3) Optionally implement an irq_chip to manage the interrupt controller
+   hardware.
+4) No need to implement irq_domain_ops.map and irq_domain_ops.unmap,
+   they are unused with hierarchy irq_domain.
+
+Hierarchy irq_domain may also be used to support other architectures,
+such as ARM, ARM64 etc.
include/linux/irq.h +5 -0
Index: tip/include/linux/irq.h
===================================================================
@@ -133,6 +133,8 @@ struct irq_domain;
  * @chip:		low level interrupt hardware access
  * @domain:		Interrupt translation domain; responsible for mapping
  *			between hwirq number and linux irq number.
+ * @parent_data:	pointer to parent struct irq_data to support hierarchy
+ *			irq_domain
  * @handler_data:	per-IRQ data for the irq_chip methods
  * @chip_data:		platform-specific per-chip private data for the chip
  *			methods, to allow shared chip implementations
@@ -151,6 +153,9 @@ struct irq_data {
 	unsigned int		state_use_accessors;
 	struct irq_chip		*chip;
 	struct irq_domain	*domain;
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+	struct irq_data		*parent_data;
+#endif
 	void			*handler_data;
 	void			*chip_data;
 	struct msi_desc		*msi_desc;
include/linux/irqdomain.h +86 -0

134 lines not on this page · raw message

kernel/irq/Kconfig +5 -0
Index: tip/kernel/irq/Kconfig
===================================================================
@@ -55,6 +55,11 @@ config GENERIC_IRQ_CHIP
 config IRQ_DOMAIN
 	bool
 
+# Support for hierarchical irq domains
+config IRQ_DOMAIN_HIERARCHY
+	bool
+	select IRQ_DOMAIN
+
 config HANDLE_DOMAIN_IRQ
 	bool
 
kernel/irq/chip.c +3 -0
Index: tip/kernel/irq/chip.c
===================================================================
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
+#include <linux/irqdomain.h>
 
 #include <trace/events/irq.h>
 
@@ -178,6 +179,7 @@ int irq_startup(struct irq_desc *desc, b
 	irq_state_clr_disabled(desc);
 	desc->depth = 0;
 
+	irq_domain_activate_irq(&desc->irq_data);
 	if (desc->irq_data.chip->irq_startup) {
 		ret = desc->irq_data.chip->irq_startup(&desc->irq_data);
 		irq_state_clr_masked(desc);
@@ -199,6 +201,7 @@ void irq_shutdown(struct irq_desc *desc)
 		desc->irq_data.chip->irq_disable(&desc->irq_data);
 	else
 		desc->irq_data.chip->irq_mask(&desc->irq_data);
+	irq_domain_deactivate_irq(&desc->irq_data);
 	irq_state_set_masked(desc);
 }
 
kernel/irq/irqdomain.c +375 -16

454 lines not on this page · raw message

#2 lore raw

Re: [patch 01/16] irqdomain: Introduce new interfaces to support hierarchy irqdomains

Hi Thomas, Jiang,

Quoted 14 lines · Thomas Gleixner

From: Jiang Liu <[email protected]>
Index: tip/kernel/irq/chip.c
===================================================================

kernel/irq/chip.c +1 -0
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
+#include <linux/irqdomain.h>
 
 #include <trace/events/irq.h>
 

kernel/irq/chip.c int irq_startup(struct irq_desc *desc, b · line 182

Quoted 4 lines
kernel/irq/chip.c +1 -0
@@ -178,6 +179,7 @@ int irq_startup(struct irq_desc *desc, b
 	irq_state_clr_disabled(desc);
 	desc->depth = 0;
 
+	irq_domain_activate_irq(&desc->irq_data);

I'm not sure why this is needed, please help me out.. :)

Thanks,
Abel

Quoted 11 lines
kernel/irq/chip.c +1 -0
 	if (desc->irq_data.chip->irq_startup) {
 		ret = desc->irq_data.chip->irq_startup(&desc->irq_data);
 		irq_state_clr_masked(desc);
@@ -199,6 +201,7 @@ void irq_shutdown(struct irq_desc *desc)
 		desc->irq_data.chip->irq_disable(&desc->irq_data);
 	else
 		desc->irq_data.chip->irq_mask(&desc->irq_data);
+	irq_domain_deactivate_irq(&desc->irq_data);
 	irq_state_set_masked(desc);
 }
 
#3 lore raw

Re: [patch 01/16] irqdomain: Introduce new interfaces to support hierarchy irqdomains

Quoted 16 lines · Yun Wu (Abel)

Hi Thomas, Jiang,

Quoted 13 lines · Thomas Gleixner

From: Jiang Liu <[email protected]>
Index: tip/kernel/irq/chip.c
===================================================================

kernel/irq/chip.c +1 -0
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
+#include <linux/irqdomain.h>
 
 #include <trace/events/irq.h>
 
Quoted 7 lines

kernel/irq/chip.c int irq_startup(struct irq_desc *desc, b · line 182

Quoted 5 lines
kernel/irq/chip.c +1 -0
@@ -178,6 +179,7 @@ int irq_startup(struct irq_desc *desc, b
 	irq_state_clr_disabled(desc);
 	desc->depth = 0;
 
+	irq_domain_activate_irq(&desc->irq_data);

I'm not sure why this is needed, please help me out.. :)

Because it makes the whole error handling in stacked allocations way simpler.

We allocate and reserve resources, but do not program the hardware up to the point where request_irq and therefor irq_startup() is invoked.

So when in the allocation/reservation phase any of the stack level fails we just have to undo the allocations/reservations and not any hardware settings.

That also solves the issue that depending on the stacking we might not be able to program the hardware during the allocation because all stack levels need to be allocated/reserved before we can figure out which hardware configuration we need for the various levels.

So we decided to postpone the actual hardware programming to the point where the interrupt actually gets used.

Thanks,

tglx

#4 lore raw

Re: [patch 01/16] irqdomain: Introduce new interfaces to support hierarchy irqdomains

Quoted 35 lines · Thomas Gleixner
Quoted 16 lines · Yun Wu (Abel)

Hi Thomas, Jiang,

Quoted 13 lines · Thomas Gleixner

From: Jiang Liu <[email protected]>
Index: tip/kernel/irq/chip.c
===================================================================

kernel/irq/chip.c +1 -0
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
+#include <linux/irqdomain.h>
 
 #include <trace/events/irq.h>
 
Quoted 7 lines

kernel/irq/chip.c int irq_startup(struct irq_desc *desc, b · line 182

Quoted 5 lines
kernel/irq/chip.c +1 -0
@@ -178,6 +179,7 @@ int irq_startup(struct irq_desc *desc, b
 	irq_state_clr_disabled(desc);
 	desc->depth = 0;
 
+	irq_domain_activate_irq(&desc->irq_data);

I'm not sure why this is needed, please help me out.. :)

Because it makes the whole error handling in stacked allocations way simpler.

We allocate and reserve resources, but do not program the hardware up to the point where request_irq and therefor irq_startup() is invoked.

So when in the allocation/reservation phase any of the stack level fails we just have to undo the allocations/reservations and not any hardware settings.

Quoted 8 lines

That also solves the issue that depending on the stacking we might not be able to program the hardware during the allocation because all stack levels need to be allocated/reserved before we can figure out which hardware configuration we need for the various levels.

So we decided to postpone the actual hardware programming to the point where the interrupt actually gets used.

OK, I got it.

Thanks,
Abel

#5 lore raw

Re: [patch 01/16] irqdomain: Introduce new interfaces to support hierarchy irqdomains

In reply to Thomas Gleixner

Hi Thomas, Jiang,

Quoted 2 lines · Thomas Gleixner

From: Jiang Liu <[email protected]>

[...]

Quoted 5 lines

/* Number of irqs reserved for a legacy isa controller */
#define NUM_ISA_INTERRUPTS 16

include/linux/irqdomain.h +0 -0
@@ -64,6 +66,16 @@ struct irq_domain_ops {
 	int (*xlate)(struct irq_domain *d, struct device_node *node,
 		     const u32 *intspec, unsigned int intsize,

include/linux/irqdomain.h struct irq_domain_ops { · line 77

Quoted 10 lines
include/linux/irqdomain.h +9 -0
 		     unsigned long *out_hwirq, unsigned int *out_type);
+
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+	/* extended V2 interfaces to support hierarchy irq_domains */
+	int (*alloc)(struct irq_domain *d, unsigned int virq,
+		     unsigned int nr_irqs, void *arg);
+	void (*free)(struct irq_domain *d, unsigned int virq,
+		     unsigned int nr_irqs);
+	void (*activate)(struct irq_domain *d, struct irq_data *irq_data);
+	void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data);

What's the usage of the parameter domain reference in activate/deactivate? I think the purpose of the two callbacks is to activate/deactivate the irq_data->hwirq in irq_data->domain. If so, the first parameter @domain is required to be equal to irq_data->domain (which makes @domain useless). Besides, the main responsibility of interrupt domains is to manage mappings between hardware and linux interrupt numbers, so would it be better if move the two callbacks into struct irq_chip?

Thanks,
Abel.

Quoted 642 lines
include/linux/irqdomain.h +75 -0
+#endif
 };
 
 extern struct irq_domain_ops irq_generic_chip_ops;
@@ -77,6 +89,7 @@ struct irq_domain_chip_generic;
  * @ops: pointer to irq_domain methods
  * @host_data: private data pointer for use by owner.  Not touched by irq_domain
  *             core code.
+ * @flags: host per irq_domain flags
  *
  * Optional elements
  * @of_node: Pointer to device tree nodes associated with the irq_domain. Used
@@ -84,6 +97,7 @@ struct irq_domain_chip_generic;
  * @gc: Pointer to a list of generic chips. There is a helper function for
  *      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
  *
  * Revmap data, used internally by irq_domain
  * @revmap_direct_max_irq: The largest hwirq that can be set for controllers that
@@ -97,10 +111,14 @@ struct irq_domain {
 	const char *name;
 	const struct irq_domain_ops *ops;
 	void *host_data;
+	unsigned int flags;
 
 	/* Optional data */
 	struct device_node *of_node;
 	struct irq_domain_chip_generic *gc;
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+	struct irq_domain *parent;
+#endif
 
 	/* reverse map data. The linear map gets appended to the irq_domain */
 	irq_hw_number_t hwirq_max;
@@ -110,6 +128,9 @@ struct irq_domain {
 	unsigned int linear_revmap[];
 };
 
+#define	IRQ_DOMAIN_FLAG_HIERARCHY	0x1
+#define	IRQ_DOMAIN_FLAG_ARCH1		0x10000
+
 #ifdef CONFIG_IRQ_DOMAIN
 struct irq_domain *__irq_domain_add(struct device_node *of_node, int size,
 				    irq_hw_number_t hwirq_max, int direct_max,
@@ -220,8 +241,73 @@ int irq_domain_xlate_onetwocell(struct i
 			const u32 *intspec, unsigned int intsize,
 			irq_hw_number_t *out_hwirq, unsigned int *out_type);
 
+/* V2 interfaces to support hierarchy IRQ domains. */
+extern struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain,
+						unsigned int virq);
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+extern int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
+				   unsigned int nr_irqs, int node, void *arg,
+				   bool realloc);
+extern void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs);
+extern void irq_domain_activate_irq(struct irq_data *irq_data);
+extern void irq_domain_deactivate_irq(struct irq_data *irq_data);
+
+static inline int irq_domain_alloc_irqs(struct irq_domain *domain,
+			unsigned int nr_irqs, int node, void *arg)
+{
+	return __irq_domain_alloc_irqs(domain, -1, nr_irqs, node, arg, false);
+}
+
+extern int irq_domain_set_hwirq_and_chip(struct irq_domain *domain,
+					 unsigned int virq,
+					 irq_hw_number_t hwirq,
+					 struct irq_chip *chip,
+					 void *chip_data);
+extern void irq_domain_reset_irq_data(struct irq_data *irq_data);
+extern void irq_domain_free_irqs_common(struct irq_domain *domain,
+					int virq, int nr_irqs);
+extern void irq_domain_free_irqs_top(struct irq_domain *domain,
+				     int virq, int nr_irqs);
+
+static inline int irq_domain_alloc_irqs_parent(struct irq_domain *domain,
+				int irq_base, unsigned int nr_irqs, void *arg)
+{
+	if (domain->parent && domain->parent->ops->alloc)
+		return domain->parent->ops->alloc(domain->parent, irq_base,
+						  nr_irqs, arg);
+	return -ENOSYS;
+}
+
+static inline void irq_domain_free_irqs_parent(struct irq_domain *domain,
+					int irq_base, unsigned int nr_irqs)
+{
+	if (domain->parent && domain->parent->ops->free)
+		domain->parent->ops->free(domain->parent, irq_base, nr_irqs);
+}
+
+static inline bool irq_domain_is_hierarchy(struct irq_domain *domain)
+{
+	return domain->flags & IRQ_DOMAIN_FLAG_HIERARCHY;
+}
+#else	/* CONFIG_IRQ_DOMAIN_HIERARCHY */
+static inline void irq_domain_activate_irq(struct irq_data *data) { }
+static inline void irq_domain_deactivate_irq(struct irq_data *data) { }
+static inline int irq_domain_alloc_irqs(struct irq_domain *domain,
+			unsigned int nr_irqs, int node, void *arg)
+{
+	return -1;
+}
+
+static inline bool irq_domain_is_hierarchy(struct irq_domain *domain)
+{
+	return false;
+}
+#endif	/* CONFIG_IRQ_DOMAIN_HIERARCHY */
+
 #else /* CONFIG_IRQ_DOMAIN */
 static inline void irq_dispose_mapping(unsigned int virq) { }
+static inline void irq_domain_activate_irq(struct irq_data *data) { }
+static inline void irq_domain_deactivate_irq(struct irq_data *data) { }
 #endif /* !CONFIG_IRQ_DOMAIN */
 
 #endif /* _LINUX_IRQDOMAIN_H */

Index: tip/kernel/irq/Kconfig
===================================================================

kernel/irq/Kconfig +5 -0
@@ -55,6 +55,11 @@ config GENERIC_IRQ_CHIP
 config IRQ_DOMAIN
 	bool
 
+# Support for hierarchical irq domains
+config IRQ_DOMAIN_HIERARCHY
+	bool
+	select IRQ_DOMAIN
+
 config HANDLE_DOMAIN_IRQ
 	bool
 

Index: tip/kernel/irq/chip.c
===================================================================

kernel/irq/chip.c +3 -0
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
+#include <linux/irqdomain.h>
 
 #include <trace/events/irq.h>
 
@@ -178,6 +179,7 @@ int irq_startup(struct irq_desc *desc, b
 	irq_state_clr_disabled(desc);
 	desc->depth = 0;
 
+	irq_domain_activate_irq(&desc->irq_data);
 	if (desc->irq_data.chip->irq_startup) {
 		ret = desc->irq_data.chip->irq_startup(&desc->irq_data);
 		irq_state_clr_masked(desc);
@@ -199,6 +201,7 @@ void irq_shutdown(struct irq_desc *desc)
 		desc->irq_data.chip->irq_disable(&desc->irq_data);
 	else
 		desc->irq_data.chip->irq_mask(&desc->irq_data);
+	irq_domain_deactivate_irq(&desc->irq_data);
 	irq_state_set_masked(desc);
 }
 

Index: tip/kernel/irq/irqdomain.c
===================================================================

kernel/irq/irqdomain.c +375 -17
@@ -23,6 +23,10 @@ static DEFINE_MUTEX(irq_domain_mutex);
 static DEFINE_MUTEX(revmap_trees_mutex);
 static struct irq_domain *irq_default_domain;
 
+static int irq_domain_alloc_descs(int virq, unsigned int nr_irqs,
+				  irq_hw_number_t hwirq, int node);
+static void irq_domain_check_hierarchy(struct irq_domain *domain);
+
 /**
  * __irq_domain_add() - Allocate a new irq_domain data structure
  * @of_node: optional device-tree node of the interrupt controller
@@ -30,7 +34,7 @@ static struct irq_domain *irq_default_do
  * @hwirq_max: Maximum number of interrupts supported by controller
  * @direct_max: Maximum value of direct maps; Use ~0 for no limit; 0 for no
  *              direct mapping
- * @ops: map/unmap domain callbacks
+ * @ops: domain callbacks
  * @host_data: Controller private data pointer
  *
  * Allocates and initialize and irq_domain structure.
@@ -56,6 +60,7 @@ struct irq_domain *__irq_domain_add(stru
 	domain->hwirq_max = hwirq_max;
 	domain->revmap_size = size;
 	domain->revmap_direct_max_irq = direct_max;
+	irq_domain_check_hierarchy(domain);
 
 	mutex_lock(&irq_domain_mutex);
 	list_add(&domain->link, &irq_domain_list);
@@ -109,7 +114,7 @@ EXPORT_SYMBOL_GPL(irq_domain_remove);
  * @first_irq: first number of irq block assigned to the domain,
  *	pass zero to assign irqs on-the-fly. If first_irq is non-zero, then
  *	pre-map all of the irqs in the domain to virqs starting at first_irq.
- * @ops: map/unmap domain callbacks
+ * @ops: domain callbacks
  * @host_data: Controller private data pointer
  *
  * Allocates an irq_domain, and optionally if first_irq is positive then also
@@ -174,10 +179,8 @@ struct irq_domain *irq_domain_add_legacy
 
 	domain = __irq_domain_add(of_node, first_hwirq + size,
 				  first_hwirq + size, 0, ops, host_data);
-	if (!domain)
-		return NULL;
-
-	irq_domain_associate_many(domain, first_irq, first_hwirq, size);
+	if (domain)
+		irq_domain_associate_many(domain, first_irq, first_hwirq, size);
 
 	return domain;
 }
@@ -388,7 +391,6 @@ EXPORT_SYMBOL_GPL(irq_create_direct_mapp
 unsigned int irq_create_mapping(struct irq_domain *domain,
 				irq_hw_number_t hwirq)
 {
-	unsigned int hint;
 	int virq;
 
 	pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);
@@ -410,12 +412,8 @@ unsigned int irq_create_mapping(struct i
 	}
 
 	/* Allocate a virtual interrupt number */
-	hint = hwirq % nr_irqs;
-	if (hint == 0)
-		hint++;
-	virq = irq_alloc_desc_from(hint, of_node_to_nid(domain->of_node));
-	if (virq <= 0)
-		virq = irq_alloc_desc_from(1, of_node_to_nid(domain->of_node));
+	virq = irq_domain_alloc_descs(-1, 1, hwirq,
+				      of_node_to_nid(domain->of_node));
 	if (virq <= 0) {
 		pr_debug("-> virq allocation failed\n");
 		return 0;
@@ -471,7 +469,7 @@ unsigned int irq_create_of_mapping(struc
 	struct irq_domain *domain;
 	irq_hw_number_t hwirq;
 	unsigned int type = IRQ_TYPE_NONE;
-	unsigned int virq;
+	int virq;
 
 	domain = irq_data->np ? irq_find_host(irq_data->np) : irq_default_domain;
 	if (!domain) {
@@ -480,6 +478,11 @@ unsigned int irq_create_of_mapping(struc
 		return 0;
 	}
 
+	if (irq_domain_is_hierarchy(domain)) {
+		virq = irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, irq_data);
+		return virq <= 0 ? 0 : virq;
+	}
+
 	/* If domain has no translation, then we assume interrupt line */
 	if (domain->ops->xlate == NULL)
 		hwirq = irq_data->args[0];
@@ -540,8 +543,8 @@ unsigned int irq_find_mapping(struct irq
 		return 0;
 
 	if (hwirq < domain->revmap_direct_max_irq) {
-		data = irq_get_irq_data(hwirq);
-		if (data && (data->domain == domain) && (data->hwirq == hwirq))
+		data = irq_domain_get_irq_data(domain, hwirq);
+		if (data && data->hwirq == hwirq)
 			return hwirq;
 	}
 
@@ -709,3 +712,359 @@ const struct irq_domain_ops irq_domain_s
 	.xlate = irq_domain_xlate_onetwocell,
 };
 EXPORT_SYMBOL_GPL(irq_domain_simple_ops);
+
+static int irq_domain_alloc_descs(int virq, unsigned int cnt,
+				  irq_hw_number_t hwirq, int node)
+{
+	unsigned int hint;
+
+	if (virq >= 0) {
+		virq = irq_alloc_descs(virq, virq, cnt, node);
+	} else {
+		hint = hwirq % nr_irqs;
+		if (hint == 0)
+			hint++;
+		virq = irq_alloc_descs_from(hint, cnt, node);
+		if (virq <= 0 && hint > 1)
+			virq = irq_alloc_descs_from(1, cnt, node);
+	}
+
+	return virq;
+}
+
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+static void irq_domain_insert_irq(int virq)
+{
+	struct irq_data *data;
+
+	for (data = irq_get_irq_data(virq); data; data = data->parent_data) {
+		struct irq_domain *domain = data->domain;
+		irq_hw_number_t hwirq = data->hwirq;
+
+		if (hwirq < domain->revmap_size) {
+			domain->linear_revmap[hwirq] = virq;
+		} else {
+			mutex_lock(&revmap_trees_mutex);
+			radix_tree_insert(&domain->revmap_tree, hwirq, data);
+			mutex_unlock(&revmap_trees_mutex);
+		}
+
+		/* If not already assigned, give the domain the chip's name */
+		if (!domain->name && data->chip)
+			domain->name = data->chip->name;
+	}
+
+	irq_clear_status_flags(virq, IRQ_NOREQUEST);
+}
+
+static void irq_domain_remove_irq(int virq)
+{
+	struct irq_data *data;
+
+	irq_set_status_flags(virq, IRQ_NOREQUEST);
+	irq_set_chip_and_handler(virq, NULL, NULL);
+	synchronize_irq(virq);
+	smp_mb();
+
+	for (data = irq_get_irq_data(virq); data; data = data->parent_data) {
+		struct irq_domain *domain = data->domain;
+		irq_hw_number_t hwirq = data->hwirq;
+
+		if (hwirq < domain->revmap_size) {
+			domain->linear_revmap[hwirq] = 0;
+		} else {
+			mutex_lock(&revmap_trees_mutex);
+			radix_tree_delete(&domain->revmap_tree, hwirq);
+			mutex_unlock(&revmap_trees_mutex);
+		}
+	}
+}
+
+static struct irq_data *irq_domain_insert_irq_data(struct irq_domain *domain,
+						   struct irq_data *child)
+{
+	struct irq_data *irq_data;
+
+	irq_data = kzalloc_node(sizeof(*irq_data), GFP_KERNEL, child->node);
+	if (irq_data) {
+		child->parent_data = irq_data;
+		irq_data->irq = child->irq;
+		irq_data->node = child->node;
+		irq_data->domain = domain;
+	}
+
+	return irq_data;
+}
+
+static void irq_domain_free_irq_data(unsigned int virq, unsigned int nr_irqs)
+{
+	int i;
+	struct irq_data *irq_data, *tmp;
+
+	for (i = 0; i < nr_irqs; i++) {
+		irq_data = irq_get_irq_data(virq + i);
+		tmp = irq_data->parent_data;
+		irq_data->parent_data = NULL;
+		irq_data->domain = NULL;
+
+		while (tmp) {
+			irq_data = tmp;
+			tmp = tmp->parent_data;
+			kfree(irq_data);
+		}
+	}
+}
+
+static int irq_domain_alloc_irq_data(struct irq_domain *domain,
+				     unsigned int virq, unsigned int nr_irqs)
+{
+	int i;
+	struct irq_data *irq_data;
+	struct irq_domain *parent;
+
+	/* The outermost irq_data is embedded in struct irq_desc */
+	for (i = 0; i < nr_irqs; i++) {
+		irq_data = irq_get_irq_data(virq + i);
+		irq_data->domain = domain;
+
+		for (parent = domain->parent; parent; parent = parent->parent) {
+			irq_data = irq_domain_insert_irq_data(parent, irq_data);
+			if (!irq_data) {
+				irq_domain_free_irq_data(virq, i + 1);
+				return -ENOMEM;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * irq_domain_get_irq_data - Get irq_data associated with @virq and @domain
+ * @domain: domain to match
+ * @virq: IRQ number to get irq_data
+ */
+struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain,
+					 unsigned int virq)
+{
+	struct irq_data *irq_data;
+
+	for (irq_data = irq_get_irq_data(virq); irq_data;
+	     irq_data = irq_data->parent_data)
+		if (irq_data->domain == domain)
+			return irq_data;
+
+	return NULL;
+}
+
+int irq_domain_set_hwirq_and_chip(struct irq_domain *domain, unsigned int virq,
+				  irq_hw_number_t hwirq, struct irq_chip *chip,
+				  void *chip_data)
+{
+	struct irq_data *irq_data = irq_domain_get_irq_data(domain, virq);
+
+	if (!irq_data)
+		return -ENOENT;
+
+	irq_data->hwirq = hwirq;
+	irq_data->chip = chip ? chip : &no_irq_chip;
+	irq_data->chip_data = chip_data;
+
+	return 0;
+}
+
+void irq_domain_reset_irq_data(struct irq_data *irq_data)
+{
+	irq_data->hwirq = 0;
+	irq_data->chip = &no_irq_chip;
+	irq_data->chip_data = NULL;
+}
+
+void irq_domain_free_irqs_common(struct irq_domain *domain, int virq,
+				 int nr_irqs)
+{
+	int i;
+	struct irq_data *irq_data;
+
+	for (i = 0; i < nr_irqs; i++) {
+		irq_data = irq_domain_get_irq_data(domain, virq + i);
+		if (irq_data)
+			irq_domain_reset_irq_data(irq_data);
+	}
+	irq_domain_free_irqs_parent(domain, virq, nr_irqs);
+}
+
+void irq_domain_free_irqs_top(struct irq_domain *domain, int virq,
+			      int nr_irqs)
+{
+	int i;
+
+	for (i = 0; i < nr_irqs; i++) {
+		irq_set_handler_data(virq + i, NULL);
+		irq_set_handler(virq + i, NULL);
+	}
+	irq_domain_free_irqs_common(domain, virq, nr_irqs);
+}
+
+/**
+ * __irq_domain_alloc_irqs - Allocate IRQs from domain
+ * @domain: domain to allocate from
+ * @irq_base: allocate specified IRQ nubmer if irq_base >= 0
+ * @nr_irqs: number of IRQs to allocate
+ * @node: NUMA node id for memory allocation
+ * @arg: domain specific argument
+ * @realloc: IRQ descriptors have already been allocated if true
+ *
+ * Allocate IRQ numbers and initialized all data structures to support
+ * hiearchy IRQ domains.
+ * Parameter @realloc is mainly to support legacy IRQs.
+ * Returns error code or allocated IRQ number
+ *
+ * The whole process to setup an IRQ has been split into two steps.
+ * The first step, __irq_domain_alloc_irqs(), is to allocate IRQ
+ * descriptor and required hardware resources. The second step,
+ * irq_domain_activate_irq(), is to program hardwares with preallocated
+ * resources. In this way, it's easier to rollback when failing to
+ * allocate resources.
+ */
+int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
+			    unsigned int nr_irqs, int node, void *arg,
+			    bool realloc)
+{
+	int i, ret, virq;
+
+	if (domain == NULL) {
+		domain = irq_default_domain;
+		if (WARN(!domain, "domain is NULL; cannot allocate IRQ\n"))
+			return -EINVAL;
+	}
+
+	if (!domain->ops->alloc) {
+		pr_debug("domain->ops->alloc() is NULL\n");
+		return -ENOSYS;
+	}
+
+	if (realloc && irq_base >= 0) {
+		virq = irq_base;
+	} else {
+		virq = irq_domain_alloc_descs(irq_base, nr_irqs, 0, node);
+		if (virq < 0) {
+			pr_debug("cannot allocate IRQ(base %d, count %d)\n",
+				 irq_base, nr_irqs);
+			return virq;
+		}
+	}
+
+	if (irq_domain_alloc_irq_data(domain, virq, nr_irqs)) {
+		pr_debug("cannot allocate memory for IRQ%d\n", virq);
+		ret = -ENOMEM;
+		goto out_free_desc;
+	}
+
+	mutex_lock(&irq_domain_mutex);
+	ret = domain->ops->alloc(domain, virq, nr_irqs, arg);
+	if (ret < 0) {
+		mutex_unlock(&irq_domain_mutex);
+		goto out_free_irq_data;
+	}
+	for (i = 0; i < nr_irqs; i++)
+		irq_domain_insert_irq(virq + i);
+	mutex_unlock(&irq_domain_mutex);
+
+	return virq;
+
+out_free_irq_data:
+	irq_domain_free_irq_data(virq, nr_irqs);
+out_free_desc:
+	irq_free_descs(virq, nr_irqs);
+	return ret;
+}
+
+/**
+ * irq_domain_free_irqs - Free IRQ number and associated data structures
+ * @virq: base IRQ number
+ * @nr_irqs: number of IRQs to free
+ */
+void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs)
+{
+	int i;
+	struct irq_data *data = irq_get_irq_data(virq);
+
+	if (WARN(!data || !data->domain || !data->domain->ops->free,
+		 "NULL pointer, cannot free irq\n"))
+		return;
+
+	mutex_lock(&irq_domain_mutex);
+	for (i = 0; i < nr_irqs; i++)
+		irq_domain_remove_irq(virq + i);
+	data->domain->ops->free(data->domain, virq, nr_irqs);
+	mutex_unlock(&irq_domain_mutex);
+
+	irq_domain_free_irq_data(virq, nr_irqs);
+	irq_free_descs(virq, nr_irqs);
+}
+
+/**
+ * irq_domain_activate_irq - Call domain_ops->activate recursively to activate
+ *			     interrupt
+ * @irq_data: outermost irq_data associated with interrupt
+ *
+ * This is the second step to call domain_ops->activate to program interrupt
+ * controllers, so the interrupt could actually get delivered.
+ */
+void irq_domain_activate_irq(struct irq_data *irq_data)
+{
+	if (irq_data && irq_data->domain) {
+		struct irq_domain *domain = irq_data->domain;
+
+		if (irq_data->parent_data)
+			irq_domain_activate_irq(irq_data->parent_data);
+		if (domain->ops->activate)
+			domain->ops->activate(domain, irq_data);
+	}
+}
+
+/**
+ * irq_domain_deactivate_irq - Call domain_ops->deactivate recursively to
+ *			       deactivate interrupt
+ * @irq_data: outermost irq_data associated with interrupt
+ *
+ * It calls domain_ops->deactivate to program interrupt controllers to disable
+ * interrupt delivery.
+ */
+void irq_domain_deactivate_irq(struct irq_data *irq_data)
+{
+	if (irq_data && irq_data->domain) {
+		struct irq_domain *domain = irq_data->domain;
+
+		if (domain->ops->deactivate)
+			domain->ops->deactivate(domain, irq_data);
+		if (irq_data->parent_data)
+			irq_domain_deactivate_irq(irq_data->parent_data);
+	}
+}
+
+static void irq_domain_check_hierarchy(struct irq_domain *domain)
+{
+	/* Hierarchy irq_domains must implement callback alloc() */
+	if (domain->ops->alloc)
+		domain->flags |= IRQ_DOMAIN_FLAG_HIERARCHY;
+}
+#else	/* CONFIG_IRQ_DOMAIN_HIERARCHY */
+/**
+ * irq_domain_get_irq_data - Get irq_data associated with @virq and @domain
+ * @domain: domain to match
+ * @virq: IRQ number to get irq_data
+ */
+struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain,
+					 unsigned int virq)
+{
+	struct irq_data *irq_data = irq_get_irq_data(virq);
+
+	return (irq_data && irq_data->domain == domain) ? irq_data : NULL;
+}
+
+static void irq_domain_check_hierarchy(struct irq_domain *domain)
+{
+}
+#endif	/* CONFIG_IRQ_DOMAIN_HIERARCHY */
 
 
--

To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
.

#6 lore raw

Re: [patch 01/16] irqdomain: Introduce new interfaces to support hierarchy irqdomains

Quoted 22 lines · Yun Wu (Abel)

Hi Thomas, Jiang,

Quoted 2 lines · Thomas Gleixner

From: Jiang Liu <[email protected]>

[...]

Quoted 5 lines

/* Number of irqs reserved for a legacy isa controller */
#define NUM_ISA_INTERRUPTS 16

include/linux/irqdomain.h +0 -0
@@ -64,6 +66,16 @@ struct irq_domain_ops {
 	int (*xlate)(struct irq_domain *d, struct device_node *node,
 		     const u32 *intspec, unsigned int intsize,

include/linux/irqdomain.h struct irq_domain_ops { · line 77

Quoted 10 lines
include/linux/irqdomain.h +9 -0
 		     unsigned long *out_hwirq, unsigned int *out_type);
+
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+	/* extended V2 interfaces to support hierarchy irq_domains */
+	int (*alloc)(struct irq_domain *d, unsigned int virq,
+		     unsigned int nr_irqs, void *arg);
+	void (*free)(struct irq_domain *d, unsigned int virq,
+		     unsigned int nr_irqs);
+	void (*activate)(struct irq_domain *d, struct irq_data *irq_data);
+	void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data);
Quoted 7 lines

What's the usage of the parameter domain reference in activate/deactivate? I think the purpose of the two callbacks is to activate/deactivate the irq_data->hwirq in irq_data->domain. If so, the first parameter @domain is required to be equal to irq_data->domain (which makes @domain useless). Besides, the main responsibility of interrupt domains is to manage mappings between hardware and linux interrupt numbers, so would it be better if move the two callbacks into struct irq_chip?

No. It's not a function of the irq_chip to activate/deactivate a hierarchy. As I explained you before:

The existing irqdomain code maps between hardware and virtual interrupts and thereby activates the interrupt in hardware.

In the hierarchical case we do not touch the hardware in the allocation step, so we need to activate the allocated interrupt in the hardware before we can use it. And that's clearly a domain interface not a irq chip issue.

Thanks,

tglx

#7 lore raw

Re: [patch 01/16] irqdomain: Introduce new interfaces to support hierarchy irqdomains

Quoted 34 lines · Thomas Gleixner
Quoted 22 lines · Yun Wu (Abel)

Hi Thomas, Jiang,

Quoted 2 lines · Thomas Gleixner

From: Jiang Liu <[email protected]>

[...]

Quoted 5 lines

/* Number of irqs reserved for a legacy isa controller */
#define NUM_ISA_INTERRUPTS 16

include/linux/irqdomain.h +0 -0
@@ -64,6 +66,16 @@ struct irq_domain_ops {
 	int (*xlate)(struct irq_domain *d, struct device_node *node,
 		     const u32 *intspec, unsigned int intsize,

include/linux/irqdomain.h struct irq_domain_ops { · line 77

Quoted 10 lines
include/linux/irqdomain.h +9 -0
 		     unsigned long *out_hwirq, unsigned int *out_type);
+
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+	/* extended V2 interfaces to support hierarchy irq_domains */
+	int (*alloc)(struct irq_domain *d, unsigned int virq,
+		     unsigned int nr_irqs, void *arg);
+	void (*free)(struct irq_domain *d, unsigned int virq,
+		     unsigned int nr_irqs);
+	void (*activate)(struct irq_domain *d, struct irq_data *irq_data);
+	void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data);
Quoted 7 lines

What's the usage of the parameter domain reference in activate/deactivate? I think the purpose of the two callbacks is to activate/deactivate the irq_data->hwirq in irq_data->domain. If so, the first parameter @domain is required to be equal to irq_data->domain (which makes @domain useless). Besides, the main responsibility of interrupt domains is to manage mappings between hardware and linux interrupt numbers, so would it be better if move the two callbacks into struct irq_chip?

No. It's not a function of the irq_chip to activate/deactivate a hierarchy. As I explained you before:

Quoted 8 lines

The existing irqdomain code maps between hardware and virtual interrupts and thereby activates the interrupt in hardware.

In the hierarchical case we do not touch the hardware in the allocation step, so we need to activate the allocated interrupt in the hardware before we can use it. And that's clearly a domain interface not a irq chip issue.

Makes sense, now the interrupt domain seems to be the best place. And when the @domain parameter can be really useful? I haven't see anyone using it so far.

Thanks,
Abel

#8 lore raw

Re: [patch 01/16] irqdomain: Introduce new interfaces to support hierarchy irqdomains

Quoted 45 lines · Yun Wu (Abel)
Quoted 34 lines · Thomas Gleixner
Quoted 22 lines · Yun Wu (Abel)

Hi Thomas, Jiang,

Quoted 2 lines · Thomas Gleixner

From: Jiang Liu <[email protected]>

[...]

Quoted 5 lines

/* Number of irqs reserved for a legacy isa controller */
#define NUM_ISA_INTERRUPTS 16

include/linux/irqdomain.h +0 -0
@@ -64,6 +66,16 @@ struct irq_domain_ops {
 	int (*xlate)(struct irq_domain *d, struct device_node *node,
 		     const u32 *intspec, unsigned int intsize,

include/linux/irqdomain.h struct irq_domain_ops { · line 77

Quoted 10 lines
include/linux/irqdomain.h +9 -0
 		     unsigned long *out_hwirq, unsigned int *out_type);
+
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+	/* extended V2 interfaces to support hierarchy irq_domains */
+	int (*alloc)(struct irq_domain *d, unsigned int virq,
+		     unsigned int nr_irqs, void *arg);
+	void (*free)(struct irq_domain *d, unsigned int virq,
+		     unsigned int nr_irqs);
+	void (*activate)(struct irq_domain *d, struct irq_data *irq_data);
+	void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data);
Quoted 7 lines

What's the usage of the parameter domain reference in activate/deactivate? I think the purpose of the two callbacks is to activate/deactivate the irq_data->hwirq in irq_data->domain. If so, the first parameter @domain is required to be equal to irq_data->domain (which makes @domain useless). Besides, the main responsibility of interrupt domains is to manage mappings between hardware and linux interrupt numbers, so would it be better if move the two callbacks into struct irq_chip?

No. It's not a function of the irq_chip to activate/deactivate a hierarchy. As I explained you before:

Quoted 8 lines

The existing irqdomain code maps between hardware and virtual interrupts and thereby activates the interrupt in hardware.

In the hierarchical case we do not touch the hardware in the allocation step, so we need to activate the allocated interrupt in the hardware before we can use it. And that's clearly a domain interface not a irq chip issue.

Quoted 3 lines

Makes sense, now the interrupt domain seems to be the best place. And when the @domain parameter can be really useful? I haven't see anyone using it so far.

We will use it for IOAPIC on x86, as below:
void mp_irqdomain_deactivate(struct irq_domain *domain,
struct irq_data *irq_data)

{
        ioapic_mask_entry(mp_irqdomain_ioapic_idx(domain),
                          (int)irq_data->hwirq);
}
Quoted 1 line

From an object oriented point of view, we pass the object as the

first parameter. It's true that we could retrieve domain from irq_data->domain instead of explicitly passing it in, but that will cause irqdomain interfaces depends on irq_data, not sounds a good situation:)
Thanks!
Gerry

Quoted 10 lines

Thanks,
Abel

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#9 lore raw

Re: [patch 01/16] irqdomain: Introduce new interfaces to support hierarchy irqdomains

Quoted 57 lines · Jiang Liu
Quoted 45 lines · Yun Wu (Abel)
Quoted 34 lines · Thomas Gleixner
Quoted 22 lines · Yun Wu (Abel)

Hi Thomas, Jiang,

Quoted 2 lines · Thomas Gleixner

From: Jiang Liu <[email protected]>

[...]

Quoted 5 lines

/* Number of irqs reserved for a legacy isa controller */
#define NUM_ISA_INTERRUPTS 16

include/linux/irqdomain.h +0 -0
@@ -64,6 +66,16 @@ struct irq_domain_ops {
 	int (*xlate)(struct irq_domain *d, struct device_node *node,
 		     const u32 *intspec, unsigned int intsize,

include/linux/irqdomain.h struct irq_domain_ops { · line 77

Quoted 10 lines
include/linux/irqdomain.h +9 -0
 		     unsigned long *out_hwirq, unsigned int *out_type);
+
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+	/* extended V2 interfaces to support hierarchy irq_domains */
+	int (*alloc)(struct irq_domain *d, unsigned int virq,
+		     unsigned int nr_irqs, void *arg);
+	void (*free)(struct irq_domain *d, unsigned int virq,
+		     unsigned int nr_irqs);
+	void (*activate)(struct irq_domain *d, struct irq_data *irq_data);
+	void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data);
Quoted 7 lines

What's the usage of the parameter domain reference in activate/deactivate? I think the purpose of the two callbacks is to activate/deactivate the irq_data->hwirq in irq_data->domain. If so, the first parameter @domain is required to be equal to irq_data->domain (which makes @domain useless). Besides, the main responsibility of interrupt domains is to manage mappings between hardware and linux interrupt numbers, so would it be better if move the two callbacks into struct irq_chip?

No. It's not a function of the irq_chip to activate/deactivate a hierarchy. As I explained you before:

Quoted 8 lines

The existing irqdomain code maps between hardware and virtual interrupts and thereby activates the interrupt in hardware.

In the hierarchical case we do not touch the hardware in the allocation step, so we need to activate the allocated interrupt in the hardware before we can use it. And that's clearly a domain interface not a irq chip issue.

Quoted 3 lines

Makes sense, now the interrupt domain seems to be the best place. And when the @domain parameter can be really useful? I haven't see anyone using it so far.

We will use it for IOAPIC on x86, as below:
void mp_irqdomain_deactivate(struct irq_domain *domain,
struct irq_data *irq_data)

{
        ioapic_mask_entry(mp_irqdomain_ioapic_idx(domain),
                          (int)irq_data->hwirq);
}
Quoted 5 lines
Quoted 1 line

From an object oriented point of view, we pass the object as the

first parameter. It's true that we could retrieve domain from irq_data->domain instead of explicitly passing it in, but that will cause irqdomain interfaces depends on irq_data, not sounds a good situation:)

Hi Gerry,

Is there any possibility that domain doesn't equal to irq_data->domain? I'm a little confused..

Thanks,
Abel

#10 lore raw

Re: [patch 01/16] irqdomain: Introduce new interfaces to support hierarchy irqdomains

Quoted 65 lines · Yun Wu (Abel)
Quoted 57 lines · Jiang Liu
Quoted 45 lines · Yun Wu (Abel)
Quoted 34 lines · Thomas Gleixner
Quoted 22 lines · Yun Wu (Abel)

Hi Thomas, Jiang,

Quoted 2 lines · Thomas Gleixner

From: Jiang Liu <[email protected]>

[...]

Quoted 5 lines

/* Number of irqs reserved for a legacy isa controller */
#define NUM_ISA_INTERRUPTS 16

include/linux/irqdomain.h +0 -0
@@ -64,6 +66,16 @@ struct irq_domain_ops {
 	int (*xlate)(struct irq_domain *d, struct device_node *node,
 		     const u32 *intspec, unsigned int intsize,

include/linux/irqdomain.h struct irq_domain_ops { · line 77

Quoted 10 lines
include/linux/irqdomain.h +9 -0
 		     unsigned long *out_hwirq, unsigned int *out_type);
+
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+	/* extended V2 interfaces to support hierarchy irq_domains */
+	int (*alloc)(struct irq_domain *d, unsigned int virq,
+		     unsigned int nr_irqs, void *arg);
+	void (*free)(struct irq_domain *d, unsigned int virq,
+		     unsigned int nr_irqs);
+	void (*activate)(struct irq_domain *d, struct irq_data *irq_data);
+	void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data);
Quoted 7 lines

What's the usage of the parameter domain reference in activate/deactivate? I think the purpose of the two callbacks is to activate/deactivate the irq_data->hwirq in irq_data->domain. If so, the first parameter @domain is required to be equal to irq_data->domain (which makes @domain useless). Besides, the main responsibility of interrupt domains is to manage mappings between hardware and linux interrupt numbers, so would it be better if move the two callbacks into struct irq_chip?

No. It's not a function of the irq_chip to activate/deactivate a hierarchy. As I explained you before:

Quoted 8 lines

The existing irqdomain code maps between hardware and virtual interrupts and thereby activates the interrupt in hardware.

In the hierarchical case we do not touch the hardware in the allocation step, so we need to activate the allocated interrupt in the hardware before we can use it. And that's clearly a domain interface not a irq chip issue.

Quoted 3 lines

Makes sense, now the interrupt domain seems to be the best place. And when the @domain parameter can be really useful? I haven't see anyone using it so far.

We will use it for IOAPIC on x86, as below:
void mp_irqdomain_deactivate(struct irq_domain *domain,
struct irq_data *irq_data)

{
        ioapic_mask_entry(mp_irqdomain_ioapic_idx(domain),
                          (int)irq_data->hwirq);
}
Quoted 5 lines
Quoted 1 line

From an object oriented point of view, we pass the object as the

first parameter. It's true that we could retrieve domain from irq_data->domain instead of explicitly passing it in, but that will cause irqdomain interfaces depends on irq_data, not sounds a good situation:)

Quoted 4 lines

Hi Gerry,

Is there any possibility that domain doesn't equal to irq_data->domain? I'm a little confused..

Hi Yun,
Currently they are always the same, but we don't want irqdomain
interfaces make assumption of struct irq_data. If it will bring big performance improvement, we will try to kill the first parameter, otherwise we may prefer keeping irqdomain interfaces clear. Thanks!
Gerry

#11 lore raw

Re: [patch 01/16] irqdomain: Introduce new interfaces to support hierarchy irqdomains

Quoted 68 lines · Jiang Liu
Quoted 67 lines · Yun Wu (Abel)
Quoted 57 lines · Jiang Liu
Quoted 45 lines · Yun Wu (Abel)
Quoted 34 lines · Thomas Gleixner
Quoted 22 lines · Yun Wu (Abel)

Hi Thomas, Jiang,

Quoted 2 lines · Thomas Gleixner

From: Jiang Liu <[email protected]>

[...]

Quoted 5 lines

/* Number of irqs reserved for a legacy isa controller */
#define NUM_ISA_INTERRUPTS 16

(quoted diff) +0 -0
@@ -64,6 +66,16 @@ struct irq_domain_ops {
 	int (*xlate)(struct irq_domain *d, struct device_node *node,
 		     const u32 *intspec, unsigned int intsize,

Review struct irq_domain_ops { · line 77

Quoted 10 lines
(quoted diff) +9 -0
 		     unsigned long *out_hwirq, unsigned int *out_type);
+
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+	/* extended V2 interfaces to support hierarchy irq_domains */
+	int (*alloc)(struct irq_domain *d, unsigned int virq,
+		     unsigned int nr_irqs, void *arg);
+	void (*free)(struct irq_domain *d, unsigned int virq,
+		     unsigned int nr_irqs);
+	void (*activate)(struct irq_domain *d, struct irq_data *irq_data);
+	void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data);
Quoted 7 lines

What's the usage of the parameter domain reference in activate/deactivate? I think the purpose of the two callbacks is to activate/deactivate the irq_data->hwirq in irq_data->domain. If so, the first parameter @domain is required to be equal to irq_data->domain (which makes @domain useless). Besides, the main responsibility of interrupt domains is to manage mappings between hardware and linux interrupt numbers, so would it be better if move the two callbacks into struct irq_chip?

No. It's not a function of the irq_chip to activate/deactivate a hierarchy. As I explained you before:

Quoted 8 lines

The existing irqdomain code maps between hardware and virtual interrupts and thereby activates the interrupt in hardware.

In the hierarchical case we do not touch the hardware in the allocation step, so we need to activate the allocated interrupt in the hardware before we can use it. And that's clearly a domain interface not a irq chip issue.

Quoted 3 lines

Makes sense, now the interrupt domain seems to be the best place. And when the @domain parameter can be really useful? I haven't see anyone using it so far.

We will use it for IOAPIC on x86, as below:
void mp_irqdomain_deactivate(struct irq_domain *domain,
struct irq_data *irq_data)

{
        ioapic_mask_entry(mp_irqdomain_ioapic_idx(domain),
                          (int)irq_data->hwirq);
}
Quoted 5 lines
Quoted 1 line

From an object oriented point of view, we pass the object as the

first parameter. It's true that we could retrieve domain from irq_data->domain instead of explicitly passing it in, but that will cause irqdomain interfaces depends on irq_data, not sounds a good situation:)

Hi Gerry,

Quoted 7 lines
Quoted 2 lines

Is there any possibility that domain doesn't equal to irq_data->domain? I'm a little confused..

Hi Yun,
Currently they are always the same, but we don't want irqdomain
interfaces make assumption of struct irq_data. If it will bring big performance improvement, we will try to kill the first parameter, otherwise we may prefer keeping irqdomain interfaces clear.

OK, let's keep it as is. :)

Thanks,
Abel

#12 lore raw

Re: [patch 01/16] irqdomain: Introduce new interfaces to support hierarchy irqdomains

In reply to Yun Wu (Abel)
Quoted 10 lines · Yun Wu (Abel)
Quoted 5 lines · Thomas Gleixner

In the hierarchical case we do not touch the hardware in the allocation step, so we need to activate the allocated interrupt in the hardware before we can use it. And that's clearly a domain interface not a irq chip issue.

Makes sense, now the interrupt domain seems to be the best place. And when the @domain parameter can be really useful? I haven't see anyone using it so far.

All irqdomain callbacks take the domain pointer as their first parameter. So for consistency sake we made it that way.

You can argue in circles about whether the domain argument could be removed. It's going to stay for now as it does not matter at all.

Thanks,

tglx

#13 lore raw

Re: [patch 01/16] irqdomain: Introduce new interfaces to support hierarchy irqdomains

Quoted 12 lines · Thomas Gleixner
Quoted 10 lines · Yun Wu (Abel)
Quoted 5 lines · Thomas Gleixner

In the hierarchical case we do not touch the hardware in the allocation step, so we need to activate the allocated interrupt in the hardware before we can use it. And that's clearly a domain interface not a irq chip issue.

Makes sense, now the interrupt domain seems to be the best place. And when the @domain parameter can be really useful? I haven't see anyone using it so far.

Quoted 6 lines

All irqdomain callbacks take the domain pointer as their first parameter. So for consistency sake we made it that way.

You can argue in circles about whether the domain argument could be removed. It's going to stay for now as it does not matter at all.

Yes, you are right.

Thanks,
Abel

#14 lore raw

PATCH 2/16 irqdomain: Do irq_find_mapping and set_type for hierarchy irqdomain in case OF

In reply to Thomas Gleixner

From: Yingjoe Chen <[email protected]>

It is possible to call irq_create_of_mapping to create/translate the same IRQ from DT for multiple times. Perform irq_find_mapping check and set_type for hierarchy irqdomain in irq_create_of_mapping() to avoid duplicate these functionality in all outer most irqdomain.

Cc Bjorn Helgaas <[email protected]>
Cc Grant Likely <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Yingjoe Chen <[email protected]>
Cc Yijing Wang <[email protected]>
---
 kernel/irq/irqdomain.c |   27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)
kernel/irq/irqdomain.c +18 -9
index 610891e63844..4811bee1b8a7 100644
@@ -478,11 +478,6 @@ unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data)
 		return 0;
 	}
 
-	if (irq_domain_is_hierarchy(domain)) {
-		virq = irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, irq_data);
-		return virq <= 0 ? 0 : virq;
-	}
-
 	/* If domain has no translation, then we assume interrupt line */
 	if (domain->ops->xlate == NULL)
 		hwirq = irq_data->args[0];
@@ -492,10 +487,24 @@ unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data)
 			return 0;
 	}
 
-	/* Create mapping */
-	virq = irq_create_mapping(domain, hwirq);
-	if (!virq)
-		return virq;
+	if (irq_domain_is_hierarchy(domain)) {
+		/*
+		 * If we've already configured this interrupt,
+		 * don't do it again, or hell will break loose.
+		 */
+		virq = irq_find_mapping(domain, hwirq);
+		if (virq)
+			return virq;
+
+		virq = irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, irq_data);
+		if (virq <= 0)
+			return 0;
+	} else {
+		/* Create mapping */
+		virq = irq_create_mapping(domain, hwirq);
+		if (!virq)
+			return virq;
+	}
 
 	/* Set type if specified and different than the current one */
 	if (type != IRQ_TYPE_NONE &&
Signature · 1 line
1.7.10.4
#15 lore raw

PATCH 3/16 genirq: Introduce helper functions to support stacked irq_chip

In reply to Thomas Gleixner

From: Jiang Liu <[email protected]>

Now we already support hierarchy irq_data, so introduce several helpers to support stacked irq_chips.

Cc Bjorn Helgaas <[email protected]>
Cc Grant Likely <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Yingjoe Chen <[email protected]>
Cc Yijing Wang <[email protected]>
---
 include/linux/irq.h |    5 +++++
 kernel/irq/chip.c   |   17 +++++++++++++++++
 2 files changed, 22 insertions(+)
include/linux/irq.h +5 -0
index 13ba412ce3a0..0adcbbbf2e87 100644
@@ -443,6 +443,11 @@ extern void handle_percpu_devid_irq(unsigned int irq, struct irq_desc *desc);
 extern void handle_bad_irq(unsigned int irq, struct irq_desc *desc);
 extern void handle_nested_irq(unsigned int irq);
 
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+extern void irq_chip_ack_parent(struct irq_data *data);
+extern int irq_chip_retrigger_hierarchy(struct irq_data *data);
+#endif
+
 /* Handling of unhandled and spurious interrupts: */
 extern void note_interrupt(unsigned int irq, struct irq_desc *desc,
 			   irqreturn_t action_ret);
kernel/irq/chip.c +17 -0
index 72a93086216b..12f3e72449eb 100644
@@ -850,3 +850,20 @@ void irq_cpu_offline(void)
 		raw_spin_unlock_irqrestore(&desc->lock, flags);
 	}
 }
+
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+void irq_chip_ack_parent(struct irq_data *data)
+{
+	data = data->parent_data;
+	data->chip->irq_ack(data);
+}
+
+int irq_chip_retrigger_hierarchy(struct irq_data *data)
+{
+	for (data = data->parent_data; data; data = data->parent_data)
+		if (data->chip && data->chip->irq_retrigger)
+			return data->chip->irq_retrigger(data);
+
+	return -ENOSYS;
+}
+#endif
Signature · 1 line
1.7.10.4
#16 lore raw

PATCH 4/16 genirq: Introduce irq_chip.irq_compose_msi_msg() to support stacked irqchip

In reply to Thomas Gleixner

From: Jiang Liu <[email protected]>

Add callback irq_compose_msi_msg to struct irq_chip, which will be used to support stacked irqchip.

Cc Bjorn Helgaas <[email protected]>
Cc Grant Likely <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Yingjoe Chen <[email protected]>
Cc Yijing Wang <[email protected]>
---
 include/linux/irq.h |    5 +++++
 kernel/irq/chip.c   |   17 +++++++++++++++++
 2 files changed, 22 insertions(+)
include/linux/irq.h +5 -0
index 0adcbbbf2e87..536b7fc6c8f4 100644
@@ -29,6 +29,7 @@ struct seq_file;
 struct module;
 struct irq_desc;
 struct irq_data;
+struct msi_msg;
 typedef	void (*irq_flow_handler_t)(unsigned int irq,
 					    struct irq_desc *desc);
 typedef	void (*irq_preflow_handler_t)(struct irq_data *data);
@@ -320,6 +321,7 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
  *				any other callback related to this irq
  * @irq_release_resources:	optional to release resources acquired with
  *				irq_request_resources
+ * @irq_compose_msi_msg:	optional to compose message content for MSI
  * @flags:		chip specific flags
  */
 struct irq_chip {
@@ -356,6 +358,8 @@ struct irq_chip {
 	int		(*irq_request_resources)(struct irq_data *data);
 	void		(*irq_release_resources)(struct irq_data *data);
 
+	void		(*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);
+
 	unsigned long	flags;
 };
 
@@ -443,6 +447,7 @@ extern void handle_percpu_devid_irq(unsigned int irq, struct irq_desc *desc);
 extern void handle_bad_irq(unsigned int irq, struct irq_desc *desc);
 extern void handle_nested_irq(unsigned int irq);
 
+extern int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg);
 #ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
 extern void irq_chip_ack_parent(struct irq_data *data);
 extern int irq_chip_retrigger_hierarchy(struct irq_data *data);
kernel/irq/chip.c +17 -0
index 12f3e72449eb..8f362db17a8a 100644
@@ -867,3 +867,20 @@ int irq_chip_retrigger_hierarchy(struct irq_data *data)
 	return -ENOSYS;
 }
 #endif
+
+int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+	struct irq_data *pos = NULL;
+
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+	for (; data; data = data->parent_data)
+#endif
+		if (data->chip && data->chip->irq_compose_msi_msg)
+			pos = data;
+	if (!pos)
+		return -ENOSYS;
+
+	pos->chip->irq_compose_msi_msg(pos, msg);
+
+	return 0;
+}
Signature · 1 line
1.7.10.4
#17 lore raw

Re: [patch 04/16] genirq: Introduce irq_chip.irq_compose_msi_msg() to support stacked irqchip

Quoted 69 lines · Thomas Gleixner

From: Jiang Liu <[email protected]>

Add callback irq_compose_msi_msg to struct irq_chip, which will be used to support stacked irqchip.

Cc Bjorn Helgaas <[email protected]>
Cc Grant Likely <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Yingjoe Chen <[email protected]>
Cc Yijing Wang <[email protected]>
---
 include/linux/irq.h |    5 +++++
 kernel/irq/chip.c   |   17 +++++++++++++++++
 2 files changed, 22 insertions(+)
include/linux/irq.h +5 -0
index 0adcbbbf2e87..536b7fc6c8f4 100644
@@ -29,6 +29,7 @@ struct seq_file;
 struct module;
 struct irq_desc;
 struct irq_data;
+struct msi_msg;
 typedef	void (*irq_flow_handler_t)(unsigned int irq,
 					    struct irq_desc *desc);
 typedef	void (*irq_preflow_handler_t)(struct irq_data *data);
@@ -320,6 +321,7 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
  *				any other callback related to this irq
  * @irq_release_resources:	optional to release resources acquired with
  *				irq_request_resources
+ * @irq_compose_msi_msg:	optional to compose message content for MSI
  * @flags:		chip specific flags
  */
 struct irq_chip {
@@ -356,6 +358,8 @@ struct irq_chip {
 	int		(*irq_request_resources)(struct irq_data *data);
 	void		(*irq_release_resources)(struct irq_data *data);
 
+	void		(*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);
+
 	unsigned long	flags;
 };
 
@@ -443,6 +447,7 @@ extern void handle_percpu_devid_irq(unsigned int irq, struct irq_desc *desc);
 extern void handle_bad_irq(unsigned int irq, struct irq_desc *desc);
 extern void handle_nested_irq(unsigned int irq);
 
+extern int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg);
 #ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
 extern void irq_chip_ack_parent(struct irq_data *data);
 extern int irq_chip_retrigger_hierarchy(struct irq_data *data);
kernel/irq/chip.c +7 -0
index 12f3e72449eb..8f362db17a8a 100644
@@ -867,3 +867,20 @@ int irq_chip_retrigger_hierarchy(struct irq_data *data)
 	return -ENOSYS;
 }
 #endif
+
+int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+	struct irq_data *pos = NULL;
+
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+	for (; data; data = data->parent_data)

kernel/irq/chip.c int irq_chip_retrigger_hierarchy(struct irq_data *data) · line 886

Quoted 10 lines
kernel/irq/chip.c +10 -0
+#endif
+		if (data->chip && data->chip->irq_compose_msi_msg)
+			pos = data;
+	if (!pos)
+		return -ENOSYS;
+
+	pos->chip->irq_compose_msi_msg(pos, msg);
+
+	return 0;
+}

Adding message composing routine to struct irq_chip is OK to me, and it should be because it is interrupt controllers' duty to compose messages (so that they can parse the messages correctly without any pre-defined rules that endpoint devices absolutely need not to know).
However a problem comes out when deciding which parameters should be passed to this routine. A message can associate with multiple interrupts, which makes me think composing messages for each interrupt is not that appropriate. And we can take a look at the new routine irq_chip_compose_msi_msg(). It is called by msi_domain_activate() which will be called by irq_domain_activate_irq() in irq_startup() for each interrupt descriptor, result in composing a message for each interrupt, right? (Unless requiring a judge on the parameter @data when implementing the irq_compose_msi_msg() callback that only compose message for the first entry of that message. But I really don't like that...)

Regards,
Abel

#18 lore raw

Re: [patch 04/16] genirq: Introduce irq_chip.irq_compose_msi_msg() to support stacked irqchip

Quoted 23 lines · Yun Wu (Abel)
Quoted 6 lines · Thomas Gleixner
kernel/irq/chip.c +6 -0
+int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+	struct irq_data *pos = NULL;
+
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+	for (; data; data = data->parent_data)

kernel/irq/chip.c int irq_chip_retrigger_hierarchy(struct irq_data *data) · line 886

Quoted 10 lines
kernel/irq/chip.c +10 -0
+#endif
+		if (data->chip && data->chip->irq_compose_msi_msg)
+			pos = data;
+	if (!pos)
+		return -ENOSYS;
+
+	pos->chip->irq_compose_msi_msg(pos, msg);
+
+	return 0;
+}

Adding message composing routine to struct irq_chip is OK to me, and it should be because it is interrupt controllers' duty to compose messages (so that they can parse the messages correctly without any pre-defined rules that endpoint devices absolutely need not to know).
However a problem comes out when deciding which parameters should be passed to

Quoted 8 lines

this routine. A message can associate with multiple interrupts, which makes me think composing messages for each interrupt is not that appropriate. And we can take a look at the new routine irq_chip_compose_msi_msg(). It is called by msi_domain_activate() which will be called by irq_domain_activate_irq() in irq_startup() for each interrupt descriptor, result in composing a message for each interrupt, right? (Unless requiring a judge on the parameter @data when implementing the irq_compose_msi_msg() callback that only compose message for the first entry of that message. But I really don't like that...)

No, that's not correct. You are looking at some random stale version of this. The current state of affairs is in

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/irqdomain

See also https://lkml.org/lkml/2014/11/17/764

In activate we write the message, which is the right point to do so.

Thanks,

tglx

#19 lore raw

Re: [patch 04/16] genirq: Introduce irq_chip.irq_compose_msi_msg() to support stacked irqchip

Quoted 33 lines · Thomas Gleixner
Quoted 23 lines · Yun Wu (Abel)
Quoted 6 lines · Thomas Gleixner
kernel/irq/chip.c +6 -0
+int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+	struct irq_data *pos = NULL;
+
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+	for (; data; data = data->parent_data)

kernel/irq/chip.c int irq_chip_retrigger_hierarchy(struct irq_data *data) · line 886

Quoted 10 lines
kernel/irq/chip.c +10 -0
+#endif
+		if (data->chip && data->chip->irq_compose_msi_msg)
+			pos = data;
+	if (!pos)
+		return -ENOSYS;
+
+	pos->chip->irq_compose_msi_msg(pos, msg);
+
+	return 0;
+}

Adding message composing routine to struct irq_chip is OK to me, and it should be because it is interrupt controllers' duty to compose messages (so that they can parse the messages correctly without any pre-defined rules that endpoint devices absolutely need not to know).
However a problem comes out when deciding which parameters should be passed to

Quoted 8 lines

this routine. A message can associate with multiple interrupts, which makes me think composing messages for each interrupt is not that appropriate. And we can take a look at the new routine irq_chip_compose_msi_msg(). It is called by msi_domain_activate() which will be called by irq_domain_activate_irq() in irq_startup() for each interrupt descriptor, result in composing a message for each interrupt, right? (Unless requiring a judge on the parameter @data when implementing the irq_compose_msi_msg() callback that only compose message for the first entry of that message. But I really don't like that...)

Quoted 9 lines

No, that's not correct. You are looking at some random stale version of this. The current state of affairs is in

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/irqdomain

See also https://lkml.org/lkml/2014/11/17/764

In activate we write the message, which is the right point to do so.

I checked the current state, it seems to be the same.
Yes, the decision of postponing the actual hardware programming to the point where the interrupt actually gets used is right, but here above I was talking another thing.
As I mentioned, a message can associate with multiple interrupts. Enabling any of them will call irq_startup(). So if we don't want to compose or write messages repeatedly, we'd better require performing some checks before activating the interrupts.

Thanks,
Abel

#20 lore raw

Re: [patch 04/16] genirq: Introduce irq_chip.irq_compose_msi_msg() to support stacked irqchip

Quoted 45 lines · Yun Wu (Abel)
Quoted 33 lines · Thomas Gleixner
Quoted 23 lines · Yun Wu (Abel)
Quoted 6 lines · Thomas Gleixner
kernel/irq/chip.c +6 -0
+int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+	struct irq_data *pos = NULL;
+
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+	for (; data; data = data->parent_data)

kernel/irq/chip.c int irq_chip_retrigger_hierarchy(struct irq_data *data) · line 886

Quoted 10 lines
kernel/irq/chip.c +10 -0
+#endif
+		if (data->chip && data->chip->irq_compose_msi_msg)
+			pos = data;
+	if (!pos)
+		return -ENOSYS;
+
+	pos->chip->irq_compose_msi_msg(pos, msg);
+
+	return 0;
+}

Adding message composing routine to struct irq_chip is OK to me, and it should be because it is interrupt controllers' duty to compose messages (so that they can parse the messages correctly without any pre-defined rules that endpoint devices absolutely need not to know).
However a problem comes out when deciding which parameters should be passed to

Quoted 8 lines

this routine. A message can associate with multiple interrupts, which makes me think composing messages for each interrupt is not that appropriate. And we can take a look at the new routine irq_chip_compose_msi_msg(). It is called by msi_domain_activate() which will be called by irq_domain_activate_irq() in irq_startup() for each interrupt descriptor, result in composing a message for each interrupt, right? (Unless requiring a judge on the parameter @data when implementing the irq_compose_msi_msg() callback that only compose message for the first entry of that message. But I really don't like that...)

Quoted 9 lines

No, that's not correct. You are looking at some random stale version of this. The current state of affairs is in

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/irqdomain

See also https://lkml.org/lkml/2014/11/17/764

In activate we write the message, which is the right point to do so.

Quoted 8 lines

I checked the current state, it seems to be the same.
Yes, the decision of postponing the actual hardware programming to the point where the interrupt actually gets used is right, but here above I was talking another thing.
As I mentioned, a message can associate with multiple interrupts. Enabling any of them will call irq_startup(). So if we don't want to compose or write messages repeatedly, we'd better require performing some checks before activating the interrupts.

Hi Yun,
Seems you are talking about the case of multiple MSI support.
Yes, we have special treatment for multiple MSI, which only writes PCI MSI registers when starting up the first MSI interrupt.
void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg)

{
        struct msi_desc *desc = irq_data->msi_desc;

        /*
         * For MSI-X desc->irq is always equal to irq_data->irq. For
         * MSI only the first interrupt of MULTI MSI passes the test.
         */
        if (desc->irq == irq_data->irq)
                __pci_write_msi_msg(desc, msg);
}

Regards!
Gerry

Quoted 10 lines

Thanks,
Abel

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#21 lore raw

Re: [patch 04/16] genirq: Introduce irq_chip.irq_compose_msi_msg() to support stacked irqchip

Quoted 60 lines · Jiang Liu
Quoted 45 lines · Yun Wu (Abel)
Quoted 33 lines · Thomas Gleixner
Quoted 23 lines · Yun Wu (Abel)
Quoted 6 lines · Thomas Gleixner
kernel/irq/chip.c +6 -0
+int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+	struct irq_data *pos = NULL;
+
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+	for (; data; data = data->parent_data)

kernel/irq/chip.c int irq_chip_retrigger_hierarchy(struct irq_data *data) · line 886

Quoted 10 lines
kernel/irq/chip.c +10 -0
+#endif
+		if (data->chip && data->chip->irq_compose_msi_msg)
+			pos = data;
+	if (!pos)
+		return -ENOSYS;
+
+	pos->chip->irq_compose_msi_msg(pos, msg);
+
+	return 0;
+}

Adding message composing routine to struct irq_chip is OK to me, and it should be because it is interrupt controllers' duty to compose messages (so that they can parse the messages correctly without any pre-defined rules that endpoint devices absolutely need not to know).
However a problem comes out when deciding which parameters should be passed to

Quoted 8 lines

this routine. A message can associate with multiple interrupts, which makes me think composing messages for each interrupt is not that appropriate. And we can take a look at the new routine irq_chip_compose_msi_msg(). It is called by msi_domain_activate() which will be called by irq_domain_activate_irq() in irq_startup() for each interrupt descriptor, result in composing a message for each interrupt, right? (Unless requiring a judge on the parameter @data when implementing the irq_compose_msi_msg() callback that only compose message for the first entry of that message. But I really don't like that...)

Quoted 9 lines

No, that's not correct. You are looking at some random stale version of this. The current state of affairs is in

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/irqdomain

See also https://lkml.org/lkml/2014/11/17/764

In activate we write the message, which is the right point to do so.

Quoted 8 lines

I checked the current state, it seems to be the same.
Yes, the decision of postponing the actual hardware programming to the point where the interrupt actually gets used is right, but here above I was talking another thing.
As I mentioned, a message can associate with multiple interrupts. Enabling any of them will call irq_startup(). So if we don't want to compose or write messages repeatedly, we'd better require performing some checks before activating the interrupts.

Hi Yun,
Seems you are talking about the case of multiple MSI support.
Yes, we have special treatment for multiple MSI, which only writes PCI MSI registers when starting up the first MSI interrupt.
void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg)

Quoted 10 lines
{
        struct msi_desc *desc = irq_data->msi_desc;

        /*
         * For MSI-X desc->irq is always equal to irq_data->irq. For
         * MSI only the first interrupt of MULTI MSI passes the test.
         */
        if (desc->irq == irq_data->irq)
                __pci_write_msi_msg(desc, msg);
}

Yes, I picked the case of multiple MSI support.
The check should also be performed when composing messages. That's why I don't like its parameters. The @data only indicates one interrupt, while I prefer doing compose/write in the unit of message descriptor.

Thanks,
Abel

#22 lore raw

Re: [patch 04/16] genirq: Introduce irq_chip.irq_compose_msi_msg() to support stacked irqchip

Quoted 74 lines · Yun Wu (Abel)
Quoted 60 lines · Jiang Liu
Quoted 45 lines · Yun Wu (Abel)
Quoted 33 lines · Thomas Gleixner
Quoted 23 lines · Yun Wu (Abel)
Quoted 6 lines · Thomas Gleixner
kernel/irq/chip.c +6 -0
+int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+	struct irq_data *pos = NULL;
+
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+	for (; data; data = data->parent_data)

kernel/irq/chip.c int irq_chip_retrigger_hierarchy(struct irq_data *data) · line 886

Quoted 10 lines
kernel/irq/chip.c +10 -0
+#endif
+		if (data->chip && data->chip->irq_compose_msi_msg)
+			pos = data;
+	if (!pos)
+		return -ENOSYS;
+
+	pos->chip->irq_compose_msi_msg(pos, msg);
+
+	return 0;
+}

Adding message composing routine to struct irq_chip is OK to me, and it should be because it is interrupt controllers' duty to compose messages (so that they can parse the messages correctly without any pre-defined rules that endpoint devices absolutely need not to know).
However a problem comes out when deciding which parameters should be passed to

Quoted 8 lines

this routine. A message can associate with multiple interrupts, which makes me think composing messages for each interrupt is not that appropriate. And we can take a look at the new routine irq_chip_compose_msi_msg(). It is called by msi_domain_activate() which will be called by irq_domain_activate_irq() in irq_startup() for each interrupt descriptor, result in composing a message for each interrupt, right? (Unless requiring a judge on the parameter @data when implementing the irq_compose_msi_msg() callback that only compose message for the first entry of that message. But I really don't like that...)

Quoted 9 lines

No, that's not correct. You are looking at some random stale version of this. The current state of affairs is in

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/irqdomain

See also https://lkml.org/lkml/2014/11/17/764

In activate we write the message, which is the right point to do so.

Quoted 8 lines

I checked the current state, it seems to be the same.
Yes, the decision of postponing the actual hardware programming to the point where the interrupt actually gets used is right, but here above I was talking another thing.
As I mentioned, a message can associate with multiple interrupts. Enabling any of them will call irq_startup(). So if we don't want to compose or write messages repeatedly, we'd better require performing some checks before activating the interrupts.

Hi Yun,
Seems you are talking about the case of multiple MSI support.
Yes, we have special treatment for multiple MSI, which only writes PCI MSI registers when starting up the first MSI interrupt.
void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg)

Quoted 10 lines
{
        struct msi_desc *desc = irq_data->msi_desc;

        /*
         * For MSI-X desc->irq is always equal to irq_data->irq. For
         * MSI only the first interrupt of MULTI MSI passes the test.
         */
        if (desc->irq == irq_data->irq)
                __pci_write_msi_msg(desc, msg);
}
Quoted 4 lines

Yes, I picked the case of multiple MSI support.
The check should also be performed when composing messages. That's why I don't like its parameters. The @data only indicates one interrupt, while I prefer doing compose/write in the unit of message descriptor.

Hi Yun,
The common abstraction is that every message interrupt could be
controlled independently, so have compose_msi_msg()/write_msi_msg() per interrupt. MSI is abstracted as an special message signaled interrupt with hardware limitation where multiple interrupts sharing the same hardware registers. So we filter in pci_msi_domain_write_msg(). On the other handle, the generic MSI framework caches msi_msg in msi_desc, so we don't filter compose_msi_msg().
Regards!
Gerry

#23 lore raw

Re: [patch 04/16] genirq: Introduce irq_chip.irq_compose_msi_msg() to support stacked irqchip

Quoted 79 lines · Jiang Liu
Quoted 74 lines · Yun Wu (Abel)
Quoted 60 lines · Jiang Liu
Quoted 45 lines · Yun Wu (Abel)
Quoted 33 lines · Thomas Gleixner
Quoted 23 lines · Yun Wu (Abel)
Quoted 6 lines · Thomas Gleixner
(quoted diff) +6 -0
+int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+	struct irq_data *pos = NULL;
+
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+	for (; data; data = data->parent_data)

Review

Quoted 10 lines
(quoted diff) +10 -0
+#endif
+		if (data->chip && data->chip->irq_compose_msi_msg)
+			pos = data;
+	if (!pos)
+		return -ENOSYS;
+
+	pos->chip->irq_compose_msi_msg(pos, msg);
+
+	return 0;
+}

Adding message composing routine to struct irq_chip is OK to me, and it should be because it is interrupt controllers' duty to compose messages (so that they can parse the messages correctly without any pre-defined rules that endpoint devices absolutely need not to know).
However a problem comes out when deciding which parameters should be passed to

Quoted 8 lines

this routine. A message can associate with multiple interrupts, which makes me think composing messages for each interrupt is not that appropriate. And we can take a look at the new routine irq_chip_compose_msi_msg(). It is called by msi_domain_activate() which will be called by irq_domain_activate_irq() in irq_startup() for each interrupt descriptor, result in composing a message for each interrupt, right? (Unless requiring a judge on the parameter @data when implementing the irq_compose_msi_msg() callback that only compose message for the first entry of that message. But I really don't like that...)

Quoted 9 lines

No, that's not correct. You are looking at some random stale version of this. The current state of affairs is in

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/irqdomain

See also https://lkml.org/lkml/2014/11/17/764

In activate we write the message, which is the right point to do so.

Quoted 8 lines

I checked the current state, it seems to be the same.
Yes, the decision of postponing the actual hardware programming to the point where the interrupt actually gets used is right, but here above I was talking another thing.
As I mentioned, a message can associate with multiple interrupts. Enabling any of them will call irq_startup(). So if we don't want to compose or write messages repeatedly, we'd better require performing some checks before activating the interrupts.

Hi Yun,
Seems you are talking about the case of multiple MSI support.
Yes, we have special treatment for multiple MSI, which only writes PCI MSI registers when starting up the first MSI interrupt.
void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg)

Quoted 10 lines
{
        struct msi_desc *desc = irq_data->msi_desc;

        /*
         * For MSI-X desc->irq is always equal to irq_data->irq. For
         * MSI only the first interrupt of MULTI MSI passes the test.
         */
        if (desc->irq == irq_data->irq)
                __pci_write_msi_msg(desc, msg);
}
Quoted 4 lines

Yes, I picked the case of multiple MSI support.
The check should also be performed when composing messages. That's why I don't like its parameters. The @data only indicates one interrupt, while I prefer doing compose/write in the unit of message descriptor.

Quoted 9 lines

Hi Yun,
The common abstraction is that every message interrupt could be
controlled independently, so have compose_msi_msg()/write_msi_msg() per interrupt. MSI is abstracted as an special message signaled interrupt with hardware limitation where multiple interrupts sharing the same hardware registers. So we filter in pci_msi_domain_write_msg(). On the other handle, the generic MSI framework caches msi_msg in msi_desc, so we don't filter compose_msi_msg().

It's true that every message interrupt could be controlled independently, I mean, by enable/disable/mask/unmask. But the message data & address are shared among the interrupts of that message.
Despite the detailed hardware implementation, MSI and MSI-X are the same thing in software view, that is a message related with several consecutive interrupts. And the core MSI infrastructure you want to build should not be based on any hardware assumptions.

Thanks,
Abel

#24 lore raw

Re: [patch 04/16] genirq: Introduce irq_chip.irq_compose_msi_msg() to support stacked irqchip

Quoted 91 lines · Yun Wu (Abel)
Quoted 79 lines · Jiang Liu
Quoted 74 lines · Yun Wu (Abel)
Quoted 60 lines · Jiang Liu
Quoted 45 lines · Yun Wu (Abel)
Quoted 33 lines · Thomas Gleixner
Quoted 23 lines · Yun Wu (Abel)
Quoted 6 lines · Thomas Gleixner
(quoted diff) +6 -0
+int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+	struct irq_data *pos = NULL;
+
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+	for (; data; data = data->parent_data)

Review

Quoted 10 lines
(quoted diff) +10 -0
+#endif
+		if (data->chip && data->chip->irq_compose_msi_msg)
+			pos = data;
+	if (!pos)
+		return -ENOSYS;
+
+	pos->chip->irq_compose_msi_msg(pos, msg);
+
+	return 0;
+}

Adding message composing routine to struct irq_chip is OK to me, and it should be because it is interrupt controllers' duty to compose messages (so that they can parse the messages correctly without any pre-defined rules that endpoint devices absolutely need not to know).
However a problem comes out when deciding which parameters should be passed to

Quoted 8 lines

this routine. A message can associate with multiple interrupts, which makes me think composing messages for each interrupt is not that appropriate. And we can take a look at the new routine irq_chip_compose_msi_msg(). It is called by msi_domain_activate() which will be called by irq_domain_activate_irq() in irq_startup() for each interrupt descriptor, result in composing a message for each interrupt, right? (Unless requiring a judge on the parameter @data when implementing the irq_compose_msi_msg() callback that only compose message for the first entry of that message. But I really don't like that...)

Quoted 9 lines

No, that's not correct. You are looking at some random stale version of this. The current state of affairs is in

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/irqdomain

See also https://lkml.org/lkml/2014/11/17/764

In activate we write the message, which is the right point to do so.

Quoted 8 lines

I checked the current state, it seems to be the same.
Yes, the decision of postponing the actual hardware programming to the point where the interrupt actually gets used is right, but here above I was talking another thing.
As I mentioned, a message can associate with multiple interrupts. Enabling any of them will call irq_startup(). So if we don't want to compose or write messages repeatedly, we'd better require performing some checks before activating the interrupts.

Hi Yun,
Seems you are talking about the case of multiple MSI support.
Yes, we have special treatment for multiple MSI, which only writes PCI MSI registers when starting up the first MSI interrupt.
void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg)

Quoted 10 lines
{
        struct msi_desc *desc = irq_data->msi_desc;

        /*
         * For MSI-X desc->irq is always equal to irq_data->irq. For
         * MSI only the first interrupt of MULTI MSI passes the test.
         */
        if (desc->irq == irq_data->irq)
                __pci_write_msi_msg(desc, msg);
}
Quoted 4 lines

Yes, I picked the case of multiple MSI support.
The check should also be performed when composing messages. That's why I don't like its parameters. The @data only indicates one interrupt, while I prefer doing compose/write in the unit of message descriptor.

Quoted 9 lines

Hi Yun,
The common abstraction is that every message interrupt could be
controlled independently, so have compose_msi_msg()/write_msi_msg() per interrupt. MSI is abstracted as an special message signaled interrupt with hardware limitation where multiple interrupts sharing the same hardware registers. So we filter in pci_msi_domain_write_msg(). On the other handle, the generic MSI framework caches msi_msg in msi_desc, so we don't filter compose_msi_msg().

Quoted 7 lines

It's true that every message interrupt could be controlled independently, I mean, by enable/disable/mask/unmask. But the message data & address are shared among the interrupts of that message.
Despite the detailed hardware implementation, MSI and MSI-X are the same thing in software view, that is a message related with several consecutive interrupts. And the core MSI infrastructure you want to build should not be based on any hardware assumptions.

That's the key point. We abstract MSI as using a message to control an interrupt source instead of controlling several consecutive interrupts. PCI MSI is just a special case which controls a group of consecutive interrupts all together due to hardware limitation.

Quoted 5 lines

Thanks,
Abel

#25 lore raw

Re: [patch 04/16] genirq: Introduce irq_chip.irq_compose_msi_msg() to support stacked irqchip

Quoted 99 lines · Jiang Liu
Quoted 91 lines · Yun Wu (Abel)
Quoted 79 lines · Jiang Liu
Quoted 74 lines · Yun Wu (Abel)
Quoted 60 lines · Jiang Liu
Quoted 45 lines · Yun Wu (Abel)
Quoted 33 lines · Thomas Gleixner
Quoted 23 lines · Yun Wu (Abel)
Quoted 6 lines · Thomas Gleixner
(quoted diff) +6 -0
+int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+	struct irq_data *pos = NULL;
+
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+	for (; data; data = data->parent_data)

Review

Quoted 10 lines
(quoted diff) +10 -0
+#endif
+		if (data->chip && data->chip->irq_compose_msi_msg)
+			pos = data;
+	if (!pos)
+		return -ENOSYS;
+
+	pos->chip->irq_compose_msi_msg(pos, msg);
+
+	return 0;
+}

Adding message composing routine to struct irq_chip is OK to me, and it should be because it is interrupt controllers' duty to compose messages (so that they can parse the messages correctly without any pre-defined rules that endpoint devices absolutely need not to know).
However a problem comes out when deciding which parameters should be passed to

Quoted 8 lines

this routine. A message can associate with multiple interrupts, which makes me think composing messages for each interrupt is not that appropriate. And we can take a look at the new routine irq_chip_compose_msi_msg(). It is called by msi_domain_activate() which will be called by irq_domain_activate_irq() in irq_startup() for each interrupt descriptor, result in composing a message for each interrupt, right? (Unless requiring a judge on the parameter @data when implementing the irq_compose_msi_msg() callback that only compose message for the first entry of that message. But I really don't like that...)

Quoted 9 lines

No, that's not correct. You are looking at some random stale version of this. The current state of affairs is in

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/irqdomain

See also https://lkml.org/lkml/2014/11/17/764

In activate we write the message, which is the right point to do so.

Quoted 8 lines

I checked the current state, it seems to be the same.
Yes, the decision of postponing the actual hardware programming to the point where the interrupt actually gets used is right, but here above I was talking another thing.
As I mentioned, a message can associate with multiple interrupts. Enabling any of them will call irq_startup(). So if we don't want to compose or write messages repeatedly, we'd better require performing some checks before activating the interrupts.

Hi Yun,
Seems you are talking about the case of multiple MSI support.
Yes, we have special treatment for multiple MSI, which only writes PCI MSI registers when starting up the first MSI interrupt.
void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg)

Quoted 10 lines
{
        struct msi_desc *desc = irq_data->msi_desc;

        /*
         * For MSI-X desc->irq is always equal to irq_data->irq. For
         * MSI only the first interrupt of MULTI MSI passes the test.
         */
        if (desc->irq == irq_data->irq)
                __pci_write_msi_msg(desc, msg);
}
Quoted 4 lines

Yes, I picked the case of multiple MSI support.
The check should also be performed when composing messages. That's why I don't like its parameters. The @data only indicates one interrupt, while I prefer doing compose/write in the unit of message descriptor.

Quoted 9 lines

Hi Yun,
The common abstraction is that every message interrupt could be
controlled independently, so have compose_msi_msg()/write_msi_msg() per interrupt. MSI is abstracted as an special message signaled interrupt with hardware limitation where multiple interrupts sharing the same hardware registers. So we filter in pci_msi_domain_write_msg(). On the other handle, the generic MSI framework caches msi_msg in msi_desc, so we don't filter compose_msi_msg().

Quoted 7 lines

It's true that every message interrupt could be controlled independently, I mean, by enable/disable/mask/unmask. But the message data & address are shared among the interrupts of that message.
Despite the detailed hardware implementation, MSI and MSI-X are the same thing in software view, that is a message related with several consecutive interrupts. And the core MSI infrastructure you want to build should not be based on any hardware assumptions.

Quoted 5 lines

That's the key point. We abstract MSI as using a message to control an interrupt source instead of controlling several consecutive interrupts. PCI MSI is just a special case which controls a group of consecutive interrupts all together due to hardware limitation.

Oh, I see. We abstract it in different ways...
And sounds like you treat multiple MSI as a broken implementation?

Abel

#26 lore raw

Re: [patch 04/16] genirq: Introduce irq_chip.irq_compose_msi_msg() to support stacked irqchip

Quoted 100 lines · Yun Wu (Abel)
Quoted 98 lines · Jiang Liu
Quoted 97 lines · Yun Wu (Abel)
Quoted 78 lines · Jiang Liu
Quoted 73 lines · Yun Wu (Abel)
Quoted 59 lines · Jiang Liu
Quoted 44 lines · Yun Wu (Abel)
Quoted 32 lines · Thomas Gleixner
Quoted 22 lines · Yun Wu (Abel)
Quoted 5 lines · Thomas Gleixner
(quoted diff) +5 -0
+int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+	struct irq_data *pos = NULL;
+
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY

Review

Quoted 10 lines
(quoted diff) +10 -0
+	for (; data; data = data->parent_data)
+#endif
+		if (data->chip && data->chip->irq_compose_msi_msg)
+			pos = data;>>>>>>>>> +	if (!pos)
+		return -ENOSYS;
+
+	pos->chip->irq_compose_msi_msg(pos, msg);
+
+	return 0;
+}

Adding message composing routine to struct irq_chip is OK to me, and it should be because it is interrupt controllers' duty to compose messages (so that they can parse the messages correctly without any pre-defined rules that endpoint devices absolutely need not to know).
However a problem comes out when deciding which parameters should be passed to

Quoted 8 lines

this routine. A message can associate with multiple interrupts, which makes me think composing messages for each interrupt is not that appropriate. And we can take a look at the new routine irq_chip_compose_msi_msg(). It is called by msi_domain_activate() which will be called by irq_domain_activate_irq() in irq_startup() for each interrupt descriptor, result in composing a message for each interrupt, right? (Unless requiring a judge on the parameter @data when implementing the irq_compose_msi_msg() callback that only compose message for the first entry of that message. But I really don't like that...)

Quoted 9 lines

No, that's not correct. You are looking at some random stale version of this. The current state of affairs is in

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/irqdomain

See also https://lkml.org/lkml/2014/11/17/764

In activate we write the message, which is the right point to do so.

Quoted 8 lines

I checked the current state, it seems to be the same.
Yes, the decision of postponing the actual hardware programming to the point where the interrupt actually gets used is right, but here above I was talking another thing.
As I mentioned, a message can associate with multiple interrupts. Enabling any of them will call irq_startup(). So if we don't want to compose or write messages repeatedly, we'd better require performing some checks before activating the interrupts.

Hi Yun,
Seems you are talking about the case of multiple MSI support.
Yes, we have special treatment for multiple MSI, which only writes PCI MSI registers when starting up the first MSI interrupt.
void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg)

Quoted 10 lines
{
        struct msi_desc *desc = irq_data->msi_desc;

        /*
         * For MSI-X desc->irq is always equal to irq_data->irq. For
         * MSI only the first interrupt of MULTI MSI passes the test.
         */
        if (desc->irq == irq_data->irq)
                __pci_write_msi_msg(desc, msg);
}
Quoted 4 lines

Yes, I picked the case of multiple MSI support.
The check should also be performed when composing messages. That's why I don't like its parameters. The @data only indicates one interrupt, while I prefer doing compose/write in the unit of message descriptor.

Quoted 9 lines

Hi Yun,
The common abstraction is that every message interrupt could be
controlled independently, so have compose_msi_msg()/write_msi_msg() per interrupt. MSI is abstracted as an special message signaled interrupt with hardware limitation where multiple interrupts sharing the same hardware registers. So we filter in pci_msi_domain_write_msg(). On the other handle, the generic MSI framework caches msi_msg in msi_desc, so we don't filter compose_msi_msg().

It's true that every message interrupt could be controlled independently, I mean, by enable/disable/mask/unmask. But the message data & address are shared among the interrupts of that message.
Despite the detailed hardware implementation, MSI and MSI-X are the same thing in software view, that is a message related with several consecutive interrupts. And the core MSI infrastructure you want to build should not be based on any hardware assumptions.

Quoted 8 lines
Quoted 5 lines

That's the key point. We abstract MSI as using a message to control an interrupt source instead of controlling several consecutive interrupts. PCI MSI is just a special case which controls a group of consecutive interrupts all together due to hardware limitation.

Oh, I see. We abstract it in different ways...
And sounds like you treat multiple MSI as a broken implementation?

Basically, yes:)

#27 lore raw

PATCH 5/16 genirq: Add IRQ_SET_MASK_OK_DONE to support stacked irqchip

In reply to Thomas Gleixner

From: Jiang Liu <[email protected]>

Add IRQ_SET_MASK_OK_DONE in addition to IRQ_SET_MASK_OK and IRQ_SET_MASK_OK_NOCOPY to support stacked irqchip. IRQ_SET_MASK_OK_DONE is the same as IRQ_SET_MASK_OK to irq core. To stacked irqchip, it means that ascendant irqchips have done all the work and no more handling needed in descendant irqchips.

Cc Bjorn Helgaas <[email protected]>
Cc Grant Likely <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Yingjoe Chen <[email protected]>
Cc Yijing Wang <[email protected]>
---
 include/linux/irq.h |    4 ++++
 kernel/irq/manage.c |    2 ++
 2 files changed, 6 insertions(+)
include/linux/irq.h +4 -0
index 536b7fc6c8f4..041edd6dc409 100644
@@ -114,10 +114,14 @@ enum {
  *
  * IRQ_SET_MASK_OK	- OK, core updates irq_data.affinity
  * IRQ_SET_MASK_NOCPY	- OK, chip did update irq_data.affinity
+ * IRQ_SET_MASK_OK_DONE	- Same as IRQ_SET_MASK_OK for core. Special code to
+ *			  support stacked irqchips, which indicates skipping
+ *			  all descendent irqchips.
  */
 enum {
 	IRQ_SET_MASK_OK = 0,
 	IRQ_SET_MASK_OK_NOCOPY,
+	IRQ_SET_MASK_OK_DONE,
 };
 
 struct msi_desc;
kernel/irq/manage.c +2 -0
index 0a9104b4608b..80692373abd6 100644
@@ -183,6 +183,7 @@ int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask,
 	ret = chip->irq_set_affinity(data, mask, force);
 	switch (ret) {
 	case IRQ_SET_MASK_OK:
+	case IRQ_SET_MASK_OK_DONE:
 		cpumask_copy(data->affinity, mask);
 	case IRQ_SET_MASK_OK_NOCOPY:
 		irq_set_thread_affinity(desc);
@@ -600,6 +601,7 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
 
 	switch (ret) {
 	case IRQ_SET_MASK_OK:
+	case IRQ_SET_MASK_OK_DONE:
 		irqd_clear(&desc->irq_data, IRQD_TRIGGER_MASK);
 		irqd_set(&desc->irq_data, flags);
 
Signature · 1 line
1.7.10.4
#28 lore raw

PATCH 6/16 genirq: Split out flow handler typedefs into seperate header file

In reply to Thomas Gleixner

Required to avoid circular include dependencies.

---
 include/linux/irq.h        |    6 +-----
 include/linux/irqhandler.h |   14 ++++++++++++++
 2 files changed, 15 insertions(+), 5 deletions(-)
include/linux/irq.h +1 -5
Index: tip/include/linux/irq.h
===================================================================
@@ -15,6 +15,7 @@
 #include <linux/spinlock.h>
 #include <linux/cpumask.h>
 #include <linux/gfp.h>
+#include <linux/irqhandler.h>
 #include <linux/irqreturn.h>
 #include <linux/irqnr.h>
 #include <linux/errno.h>
@@ -27,12 +28,7 @@
 
 struct seq_file;
 struct module;
-struct irq_desc;
-struct irq_data;
 struct msi_msg;
-typedef	void (*irq_flow_handler_t)(unsigned int irq,
-					    struct irq_desc *desc);
-typedef	void (*irq_preflow_handler_t)(struct irq_data *data);
 
 /*
  * IRQ line status.
include/linux/irqhandler.h new file +14 -0
Index: tip/include/linux/irqhandler.h
===================================================================
@@ -0,0 +1,14 @@
+#ifndef _LINUX_IRQHANDLER_H
+#define _LINUX_IRQHANDLER_H
+
+/*
+ * Interrupt flow handler typedefs are defined here to avoid circular
+ * include dependencies.
+ */
+
+struct irq_desc;
+struct irq_data;
+typedef	void (*irq_flow_handler_t)(unsigned int irq, struct irq_desc *desc);
+typedef	void (*irq_preflow_handler_t)(struct irq_data *data);
+
+#endif
#29 lore raw

PATCH 7/16 genirq: Introduce helper irq_domain_set_info() to reduce duplicated code

In reply to Thomas Gleixner

From: Jiang Liu <[email protected]>

Cc Bjorn Helgaas <[email protected]>
Cc Grant Likely <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Yingjoe Chen <[email protected]>
Cc Yijing Wang <[email protected]>
---
 include/linux/irqdomain.h |    5 +++++
 kernel/irq/irqdomain.c    |   10 ++++++++++
 2 files changed, 15 insertions(+)
include/linux/irqdomain.h +5 -0
Index: tip/include/linux/irqdomain.h
===================================================================
@@ -33,6 +33,7 @@
 #define _LINUX_IRQDOMAIN_H
 
 #include <linux/types.h>
+#include <linux/irqhandler.h>
 #include <linux/radix-tree.h>
 
 struct device_node;
@@ -263,6 +264,10 @@ extern int irq_domain_set_hwirq_and_chip
 					 irq_hw_number_t hwirq,
 					 struct irq_chip *chip,
 					 void *chip_data);
+extern void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
+				irq_hw_number_t hwirq, struct irq_chip *chip,
+				void *chip_data, irq_flow_handler_t handler,
+				void *handler_data, const char *handler_name);
 extern void irq_domain_reset_irq_data(struct irq_data *irq_data);
 extern void irq_domain_free_irqs_common(struct irq_domain *domain,
 					int virq, int nr_irqs);
kernel/irq/irqdomain.c +10 -0
Index: tip/kernel/irq/irqdomain.c
===================================================================
@@ -882,6 +882,16 @@ int irq_domain_set_hwirq_and_chip(struct
 	return 0;
 }
 
+void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
+			 irq_hw_number_t hwirq, struct irq_chip *chip,
+			 void *chip_data, irq_flow_handler_t handler,
+			 void *handler_data, const char *handler_name)
+{
+	irq_domain_set_hwirq_and_chip(domain, virq, hwirq, chip, chip_data);
+	__irq_set_handler(virq, handler, 0, handler_name);
+	irq_set_handler_data(virq, handler_data);
+}
+
 void irq_domain_reset_irq_data(struct irq_data *irq_data)
 {
 	irq_data->hwirq = 0;
#30 lore raw

Re: [patch 07/16] genirq: Introduce helper irq_domain_set_info() to reduce duplicated code

Quoted 47 lines · Thomas Gleixner

plain text document attachment (rfc-part4-v1-02-17-genirq-introduce-helper-irq_domain_set_info-to-reduce-duplicated-code.patch)
From: Jiang Liu <[email protected]>

Cc Bjorn Helgaas <[email protected]>
Cc Grant Likely <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Yingjoe Chen <[email protected]>
Cc Yijing Wang <[email protected]>
---
 include/linux/irqdomain.h |    5 +++++
 kernel/irq/irqdomain.c    |   10 ++++++++++
 2 files changed, 15 insertions(+)

Index: tip/include/linux/irqdomain.h
===================================================================

include/linux/irqdomain.h +5 -0
@@ -33,6 +33,7 @@
 #define _LINUX_IRQDOMAIN_H
 
 #include <linux/types.h>
+#include <linux/irqhandler.h>
 #include <linux/radix-tree.h>
 
 struct device_node;
@@ -263,6 +264,10 @@ extern int irq_domain_set_hwirq_and_chip
 					 irq_hw_number_t hwirq,
 					 struct irq_chip *chip,
 					 void *chip_data);
+extern void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
+				irq_hw_number_t hwirq, struct irq_chip *chip,
+				void *chip_data, irq_flow_handler_t handler,
+				void *handler_data, const char *handler_name);
 extern void irq_domain_reset_irq_data(struct irq_data *irq_data);
 extern void irq_domain_free_irqs_common(struct irq_domain *domain,
 					int virq, int nr_irqs);

Index: tip/kernel/irq/irqdomain.c
===================================================================

kernel/irq/irqdomain.c +0 -0
@@ -882,6 +882,16 @@ int irq_domain_set_hwirq_and_chip(struct
 	return 0;
 }
 

kernel/irq/irqdomain.c int irq_domain_set_hwirq_and_chip(struct · line 894

Quoted 10 lines
kernel/irq/irqdomain.c +10 -0
+void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
+			 irq_hw_number_t hwirq, struct irq_chip *chip,
+			 void *chip_data, irq_flow_handler_t handler,
+			 void *handler_data, const char *handler_name)
+{
+	irq_domain_set_hwirq_and_chip(domain, virq, hwirq, chip, chip_data);
+	__irq_set_handler(virq, handler, 0, handler_name);
+	irq_set_handler_data(virq, handler_data);
+}
+

Hi,

While trying to use this function, I'm not sure about its interface. This function have 8 parameters but only save 3 function calls. After checking uses in Jiang's original patch, I think this make code harder to understand.

Joe.C

#31 lore raw

Re: [patch 07/16] genirq: Introduce helper irq_domain_set_info() to reduce duplicated code

Quoted 22 lines · Yingjoe Chen
Quoted 8 lines · Thomas Gleixner

Index: tip/kernel/irq/irqdomain.c
===================================================================

kernel/irq/irqdomain.c +0 -0
@@ -882,6 +882,16 @@ int irq_domain_set_hwirq_and_chip(struct
 	return 0;
 }
 

kernel/irq/irqdomain.c int irq_domain_set_hwirq_and_chip(struct · line 894

Quoted 10 lines
kernel/irq/irqdomain.c +10 -0
+void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
+			 irq_hw_number_t hwirq, struct irq_chip *chip,
+			 void *chip_data, irq_flow_handler_t handler,
+			 void *handler_data, const char *handler_name)
+{
+	irq_domain_set_hwirq_and_chip(domain, virq, hwirq, chip, chip_data);
+	__irq_set_handler(virq, handler, 0, handler_name);
+	irq_set_handler_data(virq, handler_data);
+}
+

Hi,

Quoted 4 lines

While trying to use this function, I'm not sure about its interface. This function have 8 parameters but only save 3 function calls. After checking uses in Jiang's original patch, I think this make code harder to understand.

Hi Joe,

	It's true, but we also want to reduce duplicated code:(

Regards!
Gerry

Quoted 7 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#32 lore raw

Re: [patch 07/16] genirq: Introduce helper irq_domain_set_info() to reduce duplicated code

Quoted 23 lines · Jiang Liu
Quoted 22 lines · Yingjoe Chen
Quoted 8 lines · Thomas Gleixner

Index: tip/kernel/irq/irqdomain.c
===================================================================

kernel/irq/irqdomain.c +0 -0
@@ -882,6 +882,16 @@ int irq_domain_set_hwirq_and_chip(struct
 	return 0;
 }
 

kernel/irq/irqdomain.c int irq_domain_set_hwirq_and_chip(struct · line 894

Quoted 10 lines
kernel/irq/irqdomain.c +10 -0
+void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
+			 irq_hw_number_t hwirq, struct irq_chip *chip,
+			 void *chip_data, irq_flow_handler_t handler,
+			 void *handler_data, const char *handler_name)
+{
+	irq_domain_set_hwirq_and_chip(domain, virq, hwirq, chip, chip_data);
+	__irq_set_handler(virq, handler, 0, handler_name);
+	irq_set_handler_data(virq, handler_data);
+}
+

Hi,

Quoted 6 lines
Quoted 4 lines

While trying to use this function, I'm not sure about its interface. This function have 8 parameters but only save 3 function calls. After checking uses in Jiang's original patch, I think this make code harder to understand.

Hi Joe,

	It's true, but we also want to reduce duplicated code:(

I'm in two minds about this one.

Yes, it looks horrible (to be fair, I hate anything that has more than 3 or 4 parameters, because I can never remember what they're for).

On the other hand, it gives you a nice check-point in your code, with all the bits you need to set, or at least consider. Because it depends on so many things that you may have to construct/obtain, you quickly realize that there is not that many locations in your stack that fits these requirements. Yes, this a twisted reasoning.

Thanks,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#33 lore raw

Re: [patch 07/16] genirq: Introduce helper irq_domain_set_info() to reduce duplicated code

In reply to Thomas Gleixner
Quoted 45 lines · Thomas Gleixner

From: Jiang Liu <[email protected]>

Cc Bjorn Helgaas <[email protected]>
Cc Grant Likely <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Yingjoe Chen <[email protected]>
Cc Yijing Wang <[email protected]>
---
 include/linux/irqdomain.h |    5 +++++
 kernel/irq/irqdomain.c    |   10 ++++++++++
 2 files changed, 15 insertions(+)

Index: tip/include/linux/irqdomain.h
===================================================================

include/linux/irqdomain.h +5 -0
@@ -33,6 +33,7 @@
 #define _LINUX_IRQDOMAIN_H
 
 #include <linux/types.h>
+#include <linux/irqhandler.h>
 #include <linux/radix-tree.h>
 
 struct device_node;
@@ -263,6 +264,10 @@ extern int irq_domain_set_hwirq_and_chip
 					 irq_hw_number_t hwirq,
 					 struct irq_chip *chip,
 					 void *chip_data);
+extern void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
+				irq_hw_number_t hwirq, struct irq_chip *chip,
+				void *chip_data, irq_flow_handler_t handler,
+				void *handler_data, const char *handler_name);
 extern void irq_domain_reset_irq_data(struct irq_data *irq_data);
 extern void irq_domain_free_irqs_common(struct irq_domain *domain,
 					int virq, int nr_irqs);

Index: tip/kernel/irq/irqdomain.c
===================================================================

kernel/irq/irqdomain.c +0 -0
@@ -882,6 +882,16 @@ int irq_domain_set_hwirq_and_chip(struct
 	return 0;
 }
 

kernel/irq/irqdomain.c int irq_domain_set_hwirq_and_chip(struct · line 894

Quoted 10 lines
kernel/irq/irqdomain.c +10 -0
+void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
+			 irq_hw_number_t hwirq, struct irq_chip *chip,
+			 void *chip_data, irq_flow_handler_t handler,
+			 void *handler_data, const char *handler_name)
+{
+	irq_domain_set_hwirq_and_chip(domain, virq, hwirq, chip, chip_data);
+	__irq_set_handler(virq, handler, 0, handler_name);
+	irq_set_handler_data(virq, handler_data);
+}
+

We still have the issue that, depending on where in the stack this is
called, this will succeed or fail: If this is called from the inner
irqchip, __irq_set_handler() will fail, as it will look at the outer domain as the (desc->irq_data.chip == &no_irq_chip) test fails (we haven't set the top level yet).

I have this very imperfect workaround in my tree:

kernel/irq/chip.c +10 -1
index d028b34..91e6515 100644
@@ -731,7 +731,16 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
 	if (!handle) {
 		handle = handle_bad_irq;
 	} else {
-		if (WARN_ON(desc->irq_data.chip == &no_irq_chip))
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+		struct irq_data *irq_data = &desc->irq_data;
+		while (irq_data) {
+			if (irq_data->chip != &no_irq_chip)
+				break;
+			irq_data = irq_data->parent_data;
+		}
+#endif
+
+		if (WARN_ON(!irq_data || irq_data->chip == &no_irq_chip))
 			goto out;
 	}
 

Which translate into: If there is at least one irqchip in the domain, it will probably sort itself out. Not ideal. Any real solution to this problem?

GICv2 faces this exact problem, as some of its interrupts are used directly, and some others are used through the MSI domain. In the GIC driver, it is almost impossible to find out...

Thanks,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#34 lore raw

Re: [patch 07/16] genirq: Introduce helper irq_domain_set_info() to reduce duplicated code

Quoted 91 lines · Marc Zyngier
Quoted 45 lines · Thomas Gleixner

From: Jiang Liu <[email protected]>

Cc Bjorn Helgaas <[email protected]>
Cc Grant Likely <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Yingjoe Chen <[email protected]>
Cc Yijing Wang <[email protected]>
---
 include/linux/irqdomain.h |    5 +++++
 kernel/irq/irqdomain.c    |   10 ++++++++++
 2 files changed, 15 insertions(+)

Index: tip/include/linux/irqdomain.h
===================================================================

include/linux/irqdomain.h +5 -0
@@ -33,6 +33,7 @@
 #define _LINUX_IRQDOMAIN_H
 
 #include <linux/types.h>
+#include <linux/irqhandler.h>
 #include <linux/radix-tree.h>
 
 struct device_node;
@@ -263,6 +264,10 @@ extern int irq_domain_set_hwirq_and_chip
 					 irq_hw_number_t hwirq,
 					 struct irq_chip *chip,
 					 void *chip_data);
+extern void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
+				irq_hw_number_t hwirq, struct irq_chip *chip,
+				void *chip_data, irq_flow_handler_t handler,
+				void *handler_data, const char *handler_name);
 extern void irq_domain_reset_irq_data(struct irq_data *irq_data);
 extern void irq_domain_free_irqs_common(struct irq_domain *domain,
 					int virq, int nr_irqs);

Index: tip/kernel/irq/irqdomain.c
===================================================================

kernel/irq/irqdomain.c +0 -0
@@ -882,6 +882,16 @@ int irq_domain_set_hwirq_and_chip(struct
 	return 0;
 }
 

kernel/irq/irqdomain.c int irq_domain_set_hwirq_and_chip(struct · line 894

Quoted 10 lines
kernel/irq/irqdomain.c +10 -0
+void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
+			 irq_hw_number_t hwirq, struct irq_chip *chip,
+			 void *chip_data, irq_flow_handler_t handler,
+			 void *handler_data, const char *handler_name)
+{
+	irq_domain_set_hwirq_and_chip(domain, virq, hwirq, chip, chip_data);
+	__irq_set_handler(virq, handler, 0, handler_name);
+	irq_set_handler_data(virq, handler_data);
+}
+

We still have the issue that, depending on where in the stack this is
called, this will succeed or fail: If this is called from the inner
irqchip, __irq_set_handler() will fail, as it will look at the outer domain as the (desc->irq_data.chip == &no_irq_chip) test fails (we haven't set the top level yet).

I have this very imperfect workaround in my tree:

kernel/irq/chip.c +10 -1
index d028b34..91e6515 100644
@@ -731,7 +731,16 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
 	if (!handle) {
 		handle = handle_bad_irq;
 	} else {
-		if (WARN_ON(desc->irq_data.chip == &no_irq_chip))
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+		struct irq_data *irq_data = &desc->irq_data;
+		while (irq_data) {
+			if (irq_data->chip != &no_irq_chip)
+				break;
+			irq_data = irq_data->parent_data;
+		}
+#endif
+
+		if (WARN_ON(!irq_data || irq_data->chip == &no_irq_chip))
 			goto out;
 	}
 

Which translate into: If there is at least one irqchip in the domain, it will probably sort itself out. Not ideal. Any real solution to this problem?

Quoted 3 lines

GICv2 faces this exact problem, as some of its interrupts are used directly, and some others are used through the MSI domain. In the GIC driver, it is almost impossible to find out...

Hi Marc,
I prefer the above solution to relax the warning conditions.
Changing the calling order in irq_domain_ops->alloc() looks a little strange, and other interrupt drivers may still run into the same issue. Regards!
Gerry

Quoted 5 lines

Thanks,

	M.
#35 lore raw

Re: [patch 07/16] genirq: Introduce helper irq_domain_set_info() to reduce duplicated code

Quoted 92 lines · Jiang Liu
Quoted 91 lines · Marc Zyngier
Quoted 45 lines · Thomas Gleixner

From: Jiang Liu <[email protected]>

Cc Bjorn Helgaas <[email protected]>
Cc Grant Likely <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Yingjoe Chen <[email protected]>
Cc Yijing Wang <[email protected]>
---
 include/linux/irqdomain.h |    5 +++++
 kernel/irq/irqdomain.c    |   10 ++++++++++
 2 files changed, 15 insertions(+)

Index: tip/include/linux/irqdomain.h
===================================================================

include/linux/irqdomain.h +5 -0
@@ -33,6 +33,7 @@
 #define _LINUX_IRQDOMAIN_H
 
 #include <linux/types.h>
+#include <linux/irqhandler.h>
 #include <linux/radix-tree.h>
 
 struct device_node;
@@ -263,6 +264,10 @@ extern int irq_domain_set_hwirq_and_chip
 					 irq_hw_number_t hwirq,
 					 struct irq_chip *chip,
 					 void *chip_data);
+extern void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
+				irq_hw_number_t hwirq, struct irq_chip *chip,
+				void *chip_data, irq_flow_handler_t handler,
+				void *handler_data, const char *handler_name);
 extern void irq_domain_reset_irq_data(struct irq_data *irq_data);
 extern void irq_domain_free_irqs_common(struct irq_domain *domain,
 					int virq, int nr_irqs);

Index: tip/kernel/irq/irqdomain.c
===================================================================

kernel/irq/irqdomain.c +0 -0
@@ -882,6 +882,16 @@ int irq_domain_set_hwirq_and_chip(struct
 	return 0;
 }
 

kernel/irq/irqdomain.c int irq_domain_set_hwirq_and_chip(struct · line 894

Quoted 10 lines
kernel/irq/irqdomain.c +10 -0
+void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
+			 irq_hw_number_t hwirq, struct irq_chip *chip,
+			 void *chip_data, irq_flow_handler_t handler,
+			 void *handler_data, const char *handler_name)
+{
+	irq_domain_set_hwirq_and_chip(domain, virq, hwirq, chip, chip_data);
+	__irq_set_handler(virq, handler, 0, handler_name);
+	irq_set_handler_data(virq, handler_data);
+}
+

We still have the issue that, depending on where in the stack this is
called, this will succeed or fail: If this is called from the inner
irqchip, __irq_set_handler() will fail, as it will look at the outer domain as the (desc->irq_data.chip == &no_irq_chip) test fails (we haven't set the top level yet).

I have this very imperfect workaround in my tree:

kernel/irq/chip.c +10 -1
index d028b34..91e6515 100644
@@ -731,7 +731,16 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
 	if (!handle) {
 		handle = handle_bad_irq;
 	} else {
-		if (WARN_ON(desc->irq_data.chip == &no_irq_chip))
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+		struct irq_data *irq_data = &desc->irq_data;
+		while (irq_data) {
+			if (irq_data->chip != &no_irq_chip)
+				break;
+			irq_data = irq_data->parent_data;
+		}
+#endif
+
+		if (WARN_ON(!irq_data || irq_data->chip == &no_irq_chip))
 			goto out;
 	}
 

Which translate into: If there is at least one irqchip in the domain, it will probably sort itself out. Not ideal. Any real solution to this problem?

Quoted 7 lines
Quoted 3 lines

GICv2 faces this exact problem, as some of its interrupts are used directly, and some others are used through the MSI domain. In the GIC driver, it is almost impossible to find out...

Hi Marc,
I prefer the above solution to relax the warning conditions.
Changing the calling order in irq_domain_ops->alloc() looks a little strange, and other interrupt drivers may still run into the same issue.

OK. Where do we from from there? Do you want a proper patch, or will you fold this into the existing code?

Thanks,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#36 lore raw

Re: [patch 07/16] genirq: Introduce helper irq_domain_set_info() to reduce duplicated code

Quoted 101 lines · Marc Zyngier
Quoted 92 lines · Jiang Liu
Quoted 91 lines · Marc Zyngier
Quoted 45 lines · Thomas Gleixner

From: Jiang Liu <[email protected]>

Cc Bjorn Helgaas <[email protected]>
Cc Grant Likely <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Yingjoe Chen <[email protected]>
Cc Yijing Wang <[email protected]>
---
 include/linux/irqdomain.h |    5 +++++
 kernel/irq/irqdomain.c    |   10 ++++++++++
 2 files changed, 15 insertions(+)

Index: tip/include/linux/irqdomain.h
===================================================================

include/linux/irqdomain.h +5 -0
@@ -33,6 +33,7 @@
 #define _LINUX_IRQDOMAIN_H
 
 #include <linux/types.h>
+#include <linux/irqhandler.h>
 #include <linux/radix-tree.h>
 
 struct device_node;
@@ -263,6 +264,10 @@ extern int irq_domain_set_hwirq_and_chip
 					 irq_hw_number_t hwirq,
 					 struct irq_chip *chip,
 					 void *chip_data);
+extern void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
+				irq_hw_number_t hwirq, struct irq_chip *chip,
+				void *chip_data, irq_flow_handler_t handler,
+				void *handler_data, const char *handler_name);
 extern void irq_domain_reset_irq_data(struct irq_data *irq_data);
 extern void irq_domain_free_irqs_common(struct irq_domain *domain,
 					int virq, int nr_irqs);

Index: tip/kernel/irq/irqdomain.c
===================================================================

kernel/irq/irqdomain.c +0 -0
@@ -882,6 +882,16 @@ int irq_domain_set_hwirq_and_chip(struct
 	return 0;
 }
 

kernel/irq/irqdomain.c int irq_domain_set_hwirq_and_chip(struct · line 894

Quoted 10 lines
kernel/irq/irqdomain.c +10 -0
+void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
+			 irq_hw_number_t hwirq, struct irq_chip *chip,
+			 void *chip_data, irq_flow_handler_t handler,
+			 void *handler_data, const char *handler_name)
+{
+	irq_domain_set_hwirq_and_chip(domain, virq, hwirq, chip, chip_data);
+	__irq_set_handler(virq, handler, 0, handler_name);
+	irq_set_handler_data(virq, handler_data);
+}
+

We still have the issue that, depending on where in the stack this is
called, this will succeed or fail: If this is called from the inner
irqchip, __irq_set_handler() will fail, as it will look at the outer domain as the (desc->irq_data.chip == &no_irq_chip) test fails (we haven't set the top level yet).

I have this very imperfect workaround in my tree:

kernel/irq/chip.c +10 -1
index d028b34..91e6515 100644
@@ -731,7 +731,16 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
 	if (!handle) {
 		handle = handle_bad_irq;
 	} else {
-		if (WARN_ON(desc->irq_data.chip == &no_irq_chip))
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+		struct irq_data *irq_data = &desc->irq_data;
+		while (irq_data) {
+			if (irq_data->chip != &no_irq_chip)
+				break;
+			irq_data = irq_data->parent_data;
+		}
+#endif
+
+		if (WARN_ON(!irq_data || irq_data->chip == &no_irq_chip))
 			goto out;
 	}
 

Which translate into: If there is at least one irqchip in the domain, it will probably sort itself out. Not ideal. Any real solution to this problem?

Quoted 7 lines
Quoted 3 lines

GICv2 faces this exact problem, as some of its interrupts are used directly, and some others are used through the MSI domain. In the GIC driver, it is almost impossible to find out...

Hi Marc,
I prefer the above solution to relax the warning conditions.
Changing the calling order in irq_domain_ops->alloc() looks a little strange, and other interrupt drivers may still run into the same issue.

Quoted 2 lines

OK. Where do we from from there? Do you want a proper patch, or will you fold this into the existing code?

A patch will be great:)

Quoted 5 lines

Thanks,

	M.
#37 lore raw

Re: [patch 07/16] genirq: Introduce helper irq_domain_set_info() to reduce duplicated code

In reply to Thomas Gleixner

Hi Thomas, Jiang,

Quoted 1 line · Thomas Gleixner

From: Jiang Liu <[email protected]>

[...]

kernel/irq/irqdomain.c int irq_domain_set_hwirq_and_chip(struct · line 893

Quoted 9 lines
kernel/irq/irqdomain.c +9 -0
+void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
+			 irq_hw_number_t hwirq, struct irq_chip *chip,
+			 void *chip_data, irq_flow_handler_t handler,
+			 void *handler_data, const char *handler_name)
+{
+	irq_domain_set_hwirq_and_chip(domain, virq, hwirq, chip, chip_data);
+	__irq_set_handler(virq, handler, 0, handler_name);
+	irq_set_handler_data(virq, handler_data);
+}

When stacked domain enabled, there will be a semantic shift to the linux interrupt identifiers. The @virq now delivers much more than before.
More specifically, now we need both @virq and @domain, rather than only @irq, to determine which irq_data we want to configure. And once we configure @irq without providing the exact domain, it means we are configuring all the domains related to that @irq. So I think this routine just messed all things up.

Regards,
Abel

#38 lore raw

Re: [patch 07/16] genirq: Introduce helper irq_domain_set_info() to reduce duplicated code

Quoted 5 lines · Yun Wu (Abel)

Hi Thomas, Jiang,

Quoted 1 line · Thomas Gleixner

From: Jiang Liu <[email protected]>

[...]

Quoted 16 lines

kernel/irq/irqdomain.c int irq_domain_set_hwirq_and_chip(struct · line 893

Quoted 9 lines
kernel/irq/irqdomain.c +9 -0
+void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
+			 irq_hw_number_t hwirq, struct irq_chip *chip,
+			 void *chip_data, irq_flow_handler_t handler,
+			 void *handler_data, const char *handler_name)
+{
+	irq_domain_set_hwirq_and_chip(domain, virq, hwirq, chip, chip_data);
+	__irq_set_handler(virq, handler, 0, handler_name);
+	irq_set_handler_data(virq, handler_data);
+}

When stacked domain enabled, there will be a semantic shift to the linux interrupt identifiers. The @virq now delivers much more than before.
More specifically, now we need both @virq and @domain, rather than only @irq, to determine which irq_data we want to configure. And once we configure @irq without providing the exact domain, it means we are configuring all the domains related to that @irq. So I think this routine just messed all things up.

You can mess up anything by using an interface in the wrong way. Open coding will not make that harder.

Thanks,

tglx

#39 lore raw

Re: [patch 07/16] genirq: Introduce helper irq_domain_set_info() to reduce duplicated code

Quoted 24 lines · Thomas Gleixner
Quoted 5 lines · Yun Wu (Abel)

Hi Thomas, Jiang,

Quoted 1 line · Thomas Gleixner

From: Jiang Liu <[email protected]>

[...]

Quoted 16 lines

kernel/irq/irqdomain.c int irq_domain_set_hwirq_and_chip(struct · line 893

Quoted 9 lines
kernel/irq/irqdomain.c +9 -0
+void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
+			 irq_hw_number_t hwirq, struct irq_chip *chip,
+			 void *chip_data, irq_flow_handler_t handler,
+			 void *handler_data, const char *handler_name)
+{
+	irq_domain_set_hwirq_and_chip(domain, virq, hwirq, chip, chip_data);
+	__irq_set_handler(virq, handler, 0, handler_name);
+	irq_set_handler_data(virq, handler_data);
+}

When stacked domain enabled, there will be a semantic shift to the linux interrupt identifiers. The @virq now delivers much more than before.
More specifically, now we need both @virq and @domain, rather than only @irq, to determine which irq_data we want to configure. And once we configure @irq without providing the exact domain, it means we are configuring all the domains related to that @irq. So I think this routine just messed all things up.

Quoted 3 lines

You can mess up anything by using an interface in the wrong way. Open coding will not make that harder.

But what's the correct way to use this interface?

Thanks,
Abel

#40 lore raw

Re: [patch 07/16] genirq: Introduce helper irq_domain_set_info() to reduce duplicated code

Quoted 26 lines · Yun Wu (Abel)
Quoted 24 lines · Thomas Gleixner
Quoted 21 lines · Yun Wu (Abel)

Hi Thomas, Jiang,

Quoted 1 line · Thomas Gleixner

From: Jiang Liu <[email protected]>

[...]

kernel/irq/irqdomain.c int irq_domain_set_hwirq_and_chip(struct · line 893

Quoted 9 lines
kernel/irq/irqdomain.c +9 -0
+void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
+			 irq_hw_number_t hwirq, struct irq_chip *chip,
+			 void *chip_data, irq_flow_handler_t handler,
+			 void *handler_data, const char *handler_name)
+{
+	irq_domain_set_hwirq_and_chip(domain, virq, hwirq, chip, chip_data);
+	__irq_set_handler(virq, handler, 0, handler_name);
+	irq_set_handler_data(virq, handler_data);
+}

When stacked domain enabled, there will be a semantic shift to the linux interrupt identifiers. The @virq now delivers much more than before.
More specifically, now we need both @virq and @domain, rather than only @irq, to determine which irq_data we want to configure. And once we configure @irq without providing the exact domain, it means we are configuring all the domains related to that @irq. So I think this routine just messed all things up.

Quoted 5 lines
Quoted 3 lines

You can mess up anything by using an interface in the wrong way. Open coding will not make that harder.

But what's the correct way to use this interface?

Hi Yun,
It's to be used by interrupt controller drivers to implement
hierarchy irqdomains.
Regards!
Gerry

Quoted 10 lines

Thanks,
Abel

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#41 lore raw

Re: [patch 07/16] genirq: Introduce helper irq_domain_set_info() to reduce duplicated code

Quoted 27 lines · Jiang Liu
Quoted 26 lines · Yun Wu (Abel)
Quoted 24 lines · Thomas Gleixner
Quoted 21 lines · Yun Wu (Abel)

Hi Thomas, Jiang,

Quoted 1 line · Thomas Gleixner

From: Jiang Liu <[email protected]>

[...]

kernel/irq/irqdomain.c int irq_domain_set_hwirq_and_chip(struct · line 893

Quoted 9 lines
kernel/irq/irqdomain.c +9 -0
+void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
+			 irq_hw_number_t hwirq, struct irq_chip *chip,
+			 void *chip_data, irq_flow_handler_t handler,
+			 void *handler_data, const char *handler_name)
+{
+	irq_domain_set_hwirq_and_chip(domain, virq, hwirq, chip, chip_data);
+	__irq_set_handler(virq, handler, 0, handler_name);
+	irq_set_handler_data(virq, handler_data);
+}

When stacked domain enabled, there will be a semantic shift to the linux interrupt identifiers. The @virq now delivers much more than before.
More specifically, now we need both @virq and @domain, rather than only @irq, to determine which irq_data we want to configure. And once we configure @irq without providing the exact domain, it means we are configuring all the domains related to that @irq. So I think this routine just messed all things up.

Quoted 9 lines
Quoted 5 lines
Quoted 3 lines

You can mess up anything by using an interface in the wrong way. Open coding will not make that harder.

But what's the correct way to use this interface?

It's to be used by interrupt controller drivers to implement
hierarchy irqdomains.

Each time an interrupt domain calls this, the previous (@handler, @handler_name, @handler_data) will be overrode. It's because the routines __irq_set_handler() and irq_set_handler_data() only configure top level (without Marc's fix which is not ideal). Is this what we really want to see?

Thanks,
Abel

#42 lore raw

Re: [patch 07/16] genirq: Introduce helper irq_domain_set_info() to reduce duplicated code

Quoted 35 lines · Yun Wu (Abel)
Quoted 33 lines · Jiang Liu
Quoted 31 lines · Yun Wu (Abel)
Quoted 24 lines · Thomas Gleixner
Quoted 5 lines · Yun Wu (Abel)

Hi Thomas, Jiang,

Quoted 1 line · Thomas Gleixner

From: Jiang Liu <[email protected]>

[...]

Quoted 16 lines

kernel/irq/irqdomain.c int irq_domain_set_hwirq_and_chip(struct · line 893

Quoted 9 lines
kernel/irq/irqdomain.c +9 -0
+void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
+			 irq_hw_number_t hwirq, struct irq_chip *chip,
+			 void *chip_data, irq_flow_handler_t handler,
+			 void *handler_data, const char *handler_name)
+{
+	irq_domain_set_hwirq_and_chip(domain, virq, hwirq, chip, chip_data);
+	__irq_set_handler(virq, handler, 0, handler_name);
+	irq_set_handler_data(virq, handler_data);
+}

When stacked domain enabled, there will be a semantic shift to the linux interrupt identifiers. The @virq now delivers much more than before.
More specifically, now we need both @virq and @domain, rather than only @irq, to determine which irq_data we want to configure. And once we configure @irq without providing the exact domain, it means we are configuring all the domains related to that @irq. So I think this routine just messed all things up.

Quoted 3 lines

You can mess up anything by using an interface in the wrong way. Open coding will not make that harder.

But what's the correct way to use this interface?

Quoted 8 lines
Quoted 3 lines

It's to be used by interrupt controller drivers to implement
hierarchy irqdomains.

Each time an interrupt domain calls this, the previous (@handler, @handler_name, @handler_data) will be overrode. It's because the routines __irq_set_handler() and irq_set_handler_data() only configure top level (without Marc's fix which is not ideal). Is this what we really want to see?

Hi Yun,
There are different interfaces for different purposes.
irq_domain_set_hwirq_and_chip() sets hwirq, irq_chip and irq_chip_data. irq_domain_set_info() sets handler and handler_data in addition to irq_domain_set_hwirq_and_chip().
Which irqdomain to call irq_domain_set_info() to set irq_handler
is determined by the interrupt hierarchy. And at least on irqdomain in the hierarchy must set flow handler for the irq.
Thanks!
Gerry

Quoted 4 lines

Thanks,
Abel

#43 lore raw

PATCH 8/16 genirq: Introduce callback irq_chip.irq_write_msi_msg

In reply to Thomas Gleixner

From: Jiang Liu <[email protected]>

Introduce callback irq_chip.irq_write_msi_msg, so we can share common code among MSI alike interrupt controllers, such as HPET and DMAR.

Cc Bjorn Helgaas <[email protected]>
Cc Grant Likely <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Yingjoe Chen <[email protected]>
Cc Yijing Wang <[email protected]>
---
 include/linux/irq.h |    8 ++++++++
 1 file changed, 8 insertions(+)
include/linux/irq.h +8 -0
Index: tip/include/linux/irq.h
===================================================================
@@ -322,6 +322,7 @@ static inline irq_hw_number_t irqd_to_hw
  * @irq_release_resources:	optional to release resources acquired with
  *				irq_request_resources
  * @irq_compose_msi_msg:	optional to compose message content for MSI
+ * @irq_write_msi_msg:	optional to write message content for MSI
  * @flags:		chip specific flags
  */
 struct irq_chip {
@@ -359,6 +360,7 @@ struct irq_chip {
 	void		(*irq_release_resources)(struct irq_data *data);
 
 	void		(*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);
+	void		(*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg);
 
 	unsigned long	flags;
 };
@@ -453,6 +455,12 @@ extern void irq_chip_ack_parent(struct i
 extern int irq_chip_retrigger_hierarchy(struct irq_data *data);
 #endif
 
+static inline void irq_chip_write_msi_msg(struct irq_data *data,
+					  struct msi_msg *msg)
+{
+	data->chip->irq_write_msi_msg(data, msg);
+}
+
 /* Handling of unhandled and spurious interrupts: */
 extern void note_interrupt(unsigned int irq, struct irq_desc *desc,
 			   irqreturn_t action_ret);
#44 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Hi Thomas, Jiang,

Quoted 29 lines · Thomas Gleixner

From: Jiang Liu <[email protected]>

Introduce callback irq_chip.irq_write_msi_msg, so we can share common code among MSI alike interrupt controllers, such as HPET and DMAR.

Cc Bjorn Helgaas <[email protected]>
Cc Grant Likely <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Yingjoe Chen <[email protected]>
Cc Yijing Wang <[email protected]>
---
 include/linux/irq.h |    8 ++++++++
 1 file changed, 8 insertions(+)

Index: tip/include/linux/irq.h
===================================================================

include/linux/irq.h +1 -0
@@ -322,6 +322,7 @@ static inline irq_hw_number_t irqd_to_hw
  * @irq_release_resources:	optional to release resources acquired with
  *				irq_request_resources
  * @irq_compose_msi_msg:	optional to compose message content for MSI
+ * @irq_write_msi_msg:	optional to write message content for MSI
  * @flags:		chip specific flags
  */
 struct irq_chip {

include/linux/irq.h struct irq_chip { · line 363

Quoted 4 lines
include/linux/irq.h +1 -0
@@ -359,6 +360,7 @@ struct irq_chip {
 	void		(*irq_release_resources)(struct irq_data *data);
 
 	void		(*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);
+	void		(*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg);

Hmm... It's really weird.
I don't think it's the interrupt controllers' responsibility to write messages for all the endpoint devices since the methods of configuring message registers may different between these devices. And theoretically, the endpoint devices themselves should take the responsibility to configure their message registers. To say the least, the write_msg callback here still need to call some certain interfaces provided by the corresponding device.
There would be lots of ARM new devices capable of sending message based interrupts to interrupt controllers, does all the drivers of the devices need to expose a write_msg callback to interrupt controllers?

Regards,
Abel

Quoted 26 lines
include/linux/irq.h +6 -1
 	unsigned long	flags;
 };
@@ -453,6 +455,12 @@ extern void irq_chip_ack_parent(struct i
 extern int irq_chip_retrigger_hierarchy(struct irq_data *data);
 #endif
 
+static inline void irq_chip_write_msi_msg(struct irq_data *data,
+					  struct msi_msg *msg)
+{
+	data->chip->irq_write_msi_msg(data, msg);
+}
+
 /* Handling of unhandled and spurious interrupts: */
 extern void note_interrupt(unsigned int irq, struct irq_desc *desc,
 			   irqreturn_t action_ret);
 
 
--

To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
.

#45 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Quoted 16 lines · Yun Wu (Abel)

include/linux/irq.h struct irq_chip { · line 363

Quoted 6 lines · Thomas Gleixner

struct irq_chip {

include/linux/irq.h +1 -0
@@ -359,6 +360,7 @@ struct irq_chip {
 	void		(*irq_release_resources)(struct irq_data *data);
 
 	void		(*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);
+	void		(*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg);

Hmm... It's really weird.
I don't think it's the interrupt controllers' responsibility to write messages for all the endpoint devices since the methods of configuring message registers may different between these devices. And theoretically, the endpoint devices themselves should take the responsibility to configure their message registers. To say the least, the write_msg callback here still need to call some certain interfaces provided by the corresponding device.

Quoted 4 lines

There would be lots of ARM new devices capable of sending message based interrupts to interrupt controllers, does all the drivers of the devices need to expose a write_msg callback to interrupt controllers?

Well, writing the message _IS_ part of the interrupt controller.

So in order to enable non PCI based MSI we want to have generic infrastructure with minimal per device/device class callbacks and of course you need to provide that callback for your special device.

We already have non PCI based MSI controllers in x86 today and we need to handle the whole stuff with tons of copied coded extra for each of those. So consolidating it into common infrastructure allows us to get rid of the pointless copied code and reduce the per device effort to the relevant hardware specific callbacks. irq_write_msi_msg being one of those.

Thanks,

tglx

#46 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Quoted 28 lines · Thomas Gleixner
Quoted 16 lines · Yun Wu (Abel)

include/linux/irq.h struct irq_chip { · line 363

Quoted 6 lines · Thomas Gleixner

struct irq_chip {

include/linux/irq.h +1 -0
@@ -359,6 +360,7 @@ struct irq_chip {
 	void		(*irq_release_resources)(struct irq_data *data);
 
 	void		(*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);
+	void		(*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg);

Hmm... It's really weird.
I don't think it's the interrupt controllers' responsibility to write messages for all the endpoint devices since the methods of configuring message registers may different between these devices. And theoretically, the endpoint devices themselves should take the responsibility to configure their message registers. To say the least, the write_msg callback here still need to call some certain interfaces provided by the corresponding device.

Quoted 4 lines

There would be lots of ARM new devices capable of sending message based interrupts to interrupt controllers, does all the drivers of the devices need to expose a write_msg callback to interrupt controllers?

Well, writing the message _IS_ part of the interrupt controller.

So in order to enable non PCI based MSI we want to have generic infrastructure with minimal per device/device class callbacks and of course you need to provide that callback for your special device.

Quoted 7 lines

We already have non PCI based MSI controllers in x86 today and we need to handle the whole stuff with tons of copied coded extra for each of those. So consolidating it into common infrastructure allows us to get rid of the pointless copied code and reduce the per device effort to the relevant hardware specific callbacks. irq_write_msi_msg being one of those.

At least, we have the same goal.
I will illustrate my thoughts by an example.
The current code is something like:

Device A
========
void A_write_msg() { ... }

Group B
(a group of devices behave same on writing messages, i.e. PCI)
=======
void B_write_msg() { ... }

Controller
==========

irq_chip.irq_write_msi_msg () {
	if (A)
		A_write_msg();
	if (B)
		B_write_msg();
}

It's horrible when new devices come out, since we need to modify the controller part for each new device.
What I suggested is:

MSI Core
========
struct msi_ops { .write_msg, };
struct msi_desc { .msi_ops, };

write_msg() {
	X = get_dev();
	irq_chip.compose_msg(X);	// IRQ chips' responsibility
	X_msi_ops.write_msg();		// nothing to do with IRQ chips
}

Device A
========
void A_write_msg() { ... }
A_msi_ops.write_msg = A_write_msg;

Group B
=======
void B_write_msg() { ... }
B_msi_ops.write_msg = B_write_msg;

Please correct me if I misunderstood anything.

Thanks,
Abel

#47 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Quoted 80 lines · Yun Wu (Abel)
Quoted 28 lines · Thomas Gleixner
Quoted 16 lines · Yun Wu (Abel)

include/linux/irq.h struct irq_chip { · line 363

Quoted 6 lines · Thomas Gleixner

struct irq_chip {

include/linux/irq.h +1 -0
@@ -359,6 +360,7 @@ struct irq_chip {
 	void		(*irq_release_resources)(struct irq_data *data);
 
 	void		(*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);
+	void		(*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg);

Hmm... It's really weird.
I don't think it's the interrupt controllers' responsibility to write messages for all the endpoint devices since the methods of configuring message registers may different between these devices. And theoretically, the endpoint devices themselves should take the responsibility to configure their message registers. To say the least, the write_msg callback here still need to call some certain interfaces provided by the corresponding device.

Quoted 4 lines

There would be lots of ARM new devices capable of sending message based interrupts to interrupt controllers, does all the drivers of the devices need to expose a write_msg callback to interrupt controllers?

Well, writing the message _IS_ part of the interrupt controller.

So in order to enable non PCI based MSI we want to have generic infrastructure with minimal per device/device class callbacks and of course you need to provide that callback for your special device.

Quoted 7 lines

We already have non PCI based MSI controllers in x86 today and we need to handle the whole stuff with tons of copied coded extra for each of those. So consolidating it into common infrastructure allows us to get rid of the pointless copied code and reduce the per device effort to the relevant hardware specific callbacks. irq_write_msi_msg being one of those.

At least, we have the same goal.
I will illustrate my thoughts by an example.
The current code is something like:

Device A
========
void A_write_msg() { ... }

Group B
(a group of devices behave same on writing messages, i.e. PCI)
=======
void B_write_msg() { ... }

Controller
==========

irq_chip.irq_write_msi_msg () {
	if (A)
		A_write_msg();
	if (B)
		B_write_msg();
}

It's horrible when new devices come out, since we need to modify the controller part for each new device.
What I suggested is:

MSI Core
========
struct msi_ops { .write_msg, };
struct msi_desc { .msi_ops, };

write_msg() {
	X = get_dev();
	irq_chip.compose_msg(X);	// IRQ chips' responsibility
	X_msi_ops.write_msg();		// nothing to do with IRQ chips
}

Device A
========
void A_write_msg() { ... }
A_msi_ops.write_msg = A_write_msg;

Quoted 6 lines

Group B
=======
void B_write_msg() { ... }
B_msi_ops.write_msg = B_write_msg;

Please correct me if I misunderstood anything.

Hi Yun,
We provide an irq_chip for each type of interrupt controller
instead of devices. For the example mentioned above, if device A and Group B has different interrupt controllers, we just need to implement irq_chip_A and irq_chip_B and set irq_chip.irq_write_msi_msg() to suitable callbacks.
The framework already achieves what you you want:)
Regards!
Gerry

Quoted 4 lines

Thanks,
Abel

#48 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Quoted 86 lines · Jiang Liu
Quoted 85 lines · Yun Wu (Abel)
Quoted 28 lines · Thomas Gleixner
Quoted 16 lines · Yun Wu (Abel)

include/linux/irq.h struct irq_chip { · line 363

Quoted 6 lines · Thomas Gleixner

struct irq_chip {

include/linux/irq.h +1 -0
@@ -359,6 +360,7 @@ struct irq_chip {
 	void		(*irq_release_resources)(struct irq_data *data);
 
 	void		(*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);
+	void		(*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg);

Hmm... It's really weird.
I don't think it's the interrupt controllers' responsibility to write messages for all the endpoint devices since the methods of configuring message registers may different between these devices. And theoretically, the endpoint devices themselves should take the responsibility to configure their message registers. To say the least, the write_msg callback here still need to call some certain interfaces provided by the corresponding device.

Quoted 4 lines

There would be lots of ARM new devices capable of sending message based interrupts to interrupt controllers, does all the drivers of the devices need to expose a write_msg callback to interrupt controllers?

Well, writing the message _IS_ part of the interrupt controller.

So in order to enable non PCI based MSI we want to have generic infrastructure with minimal per device/device class callbacks and of course you need to provide that callback for your special device.

Quoted 7 lines

We already have non PCI based MSI controllers in x86 today and we need to handle the whole stuff with tons of copied coded extra for each of those. So consolidating it into common infrastructure allows us to get rid of the pointless copied code and reduce the per device effort to the relevant hardware specific callbacks. irq_write_msi_msg being one of those.

At least, we have the same goal.
I will illustrate my thoughts by an example.
The current code is something like:

Device A
========
void A_write_msg() { ... }

Group B
(a group of devices behave same on writing messages, i.e. PCI)
=======
void B_write_msg() { ... }

Controller
==========

irq_chip.irq_write_msi_msg () {
	if (A)
		A_write_msg();
	if (B)
		B_write_msg();
}

It's horrible when new devices come out, since we need to modify the controller part for each new device.
What I suggested is:

MSI Core
========
struct msi_ops { .write_msg, };
struct msi_desc { .msi_ops, };

write_msg() {
	X = get_dev();
	irq_chip.compose_msg(X);	// IRQ chips' responsibility
	X_msi_ops.write_msg();		// nothing to do with IRQ chips
}

Device A
========
void A_write_msg() { ... }
A_msi_ops.write_msg = A_write_msg;

Group B
=======
void B_write_msg() { ... }
B_msi_ops.write_msg = B_write_msg;

Quoted 8 lines
Quoted 1 line

Please correct me if I misunderstood anything.

Hi Yun,
We provide an irq_chip for each type of interrupt controller
instead of devices. For the example mentioned above, if device A and Group B has different interrupt controllers, we just need to implement irq_chip_A and irq_chip_B and set irq_chip.irq_write_msi_msg() to suitable callbacks.
The framework already achieves what you you want:)

What if device A and group B have the same interrupt controller?

Regards,
Abel

#49 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Quoted 97 lines · Yun Wu (Abel)
Quoted 86 lines · Jiang Liu
Quoted 85 lines · Yun Wu (Abel)
Quoted 28 lines · Thomas Gleixner
Quoted 16 lines · Yun Wu (Abel)

include/linux/irq.h struct irq_chip { · line 363

Quoted 6 lines · Thomas Gleixner

struct irq_chip {

include/linux/irq.h +1 -0
@@ -359,6 +360,7 @@ struct irq_chip {
 	void		(*irq_release_resources)(struct irq_data *data);
 
 	void		(*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);
+	void		(*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg);

Hmm... It's really weird.
I don't think it's the interrupt controllers' responsibility to write messages for all the endpoint devices since the methods of configuring message registers may different between these devices. And theoretically, the endpoint devices themselves should take the responsibility to configure their message registers. To say the least, the write_msg callback here still need to call some certain interfaces provided by the corresponding device.

Quoted 4 lines

There would be lots of ARM new devices capable of sending message based interrupts to interrupt controllers, does all the drivers of the devices need to expose a write_msg callback to interrupt controllers?

Well, writing the message _IS_ part of the interrupt controller.

So in order to enable non PCI based MSI we want to have generic infrastructure with minimal per device/device class callbacks and of course you need to provide that callback for your special device.

Quoted 7 lines

We already have non PCI based MSI controllers in x86 today and we need to handle the whole stuff with tons of copied coded extra for each of those. So consolidating it into common infrastructure allows us to get rid of the pointless copied code and reduce the per device effort to the relevant hardware specific callbacks. irq_write_msi_msg being one of those.

At least, we have the same goal.
I will illustrate my thoughts by an example.
The current code is something like:

Device A
========
void A_write_msg() { ... }

Group B
(a group of devices behave same on writing messages, i.e. PCI)
=======
void B_write_msg() { ... }

Controller
==========

irq_chip.irq_write_msi_msg () {
	if (A)
		A_write_msg();
	if (B)
		B_write_msg();
}

It's horrible when new devices come out, since we need to modify the controller part for each new device.
What I suggested is:

MSI Core
========
struct msi_ops { .write_msg, };
struct msi_desc { .msi_ops, };

write_msg() {
	X = get_dev();
	irq_chip.compose_msg(X);	// IRQ chips' responsibility
	X_msi_ops.write_msg();		// nothing to do with IRQ chips
}

Device A
========
void A_write_msg() { ... }
A_msi_ops.write_msg = A_write_msg;

Group B
=======
void B_write_msg() { ... }
B_msi_ops.write_msg = B_write_msg;

Quoted 8 lines
Quoted 1 line

Please correct me if I misunderstood anything.

Hi Yun,
We provide an irq_chip for each type of interrupt controller
instead of devices. For the example mentioned above, if device A and Group B has different interrupt controllers, we just need to implement irq_chip_A and irq_chip_B and set irq_chip.irq_write_msi_msg() to suitable callbacks.
The framework already achieves what you you want:)

Quoted 1 line

What if device A and group B have the same interrupt controller?

Device doesn't care about interrupt controllers, it just cares about interrupts used by itself. It's the interrupt source (controller) enumerators' responsibility to discover interrupt source, associate methods to control the interrupt source and assign irq numbers for interrupt sources.
There are two ways to associate irq numbers with device:
1) arch code/bus drivers statically assigns irq number for devices when creating device objects, such as PCI legacy interrupt (INTA-INTD), IOAPIC interrupts.
2) device drivers ask interrupt source enumerators to dynamically create irq numbers, such pci_enable_msix_range() and friends.
So device driver definitely doesn't need to known about irq_chip methods to control interrupt sources.
Regards!
Gerry

#50 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Quoted 13 lines · Jiang Liu
Quoted 11 lines · Yun Wu (Abel)
Quoted 8 lines · Jiang Liu

On 2014/11/18 21:33, Yun Wu (Abel) wrote:
Hi Yun,
We provide an irq_chip for each type of interrupt controller
instead of devices. For the example mentioned above, if device A and Group B has different interrupt controllers, we just need to implement irq_chip_A and irq_chip_B and set irq_chip.irq_write_msi_msg() to suitable callbacks.
The framework already achieves what you you want:)

Quoted 1 line

What if device A and group B have the same interrupt controller?

Quoted 13 lines

Device doesn't care about interrupt controllers, it just cares about interrupts used by itself. It's the interrupt source (controller) enumerators' responsibility to discover interrupt source, associate methods to control the interrupt source and assign irq numbers for interrupt sources.
There are two ways to associate irq numbers with device:
1) arch code/bus drivers statically assigns irq number for devices when creating device objects, such as PCI legacy interrupt (INTA-INTD), IOAPIC interrupts.
2) device drivers ask interrupt source enumerators to dynamically create irq numbers, such pci_enable_msix_range() and friends.
So device driver definitely doesn't need to known about irq_chip methods to control interrupt sources.

Please refer to
http://www.xisanqi.net/year/2014/pdf/2014-pdf-09-reconstruct-x86-interrupt-architecture.pdf
for more information
about the hierarchy irqdomain background:)

Quoted 5 lines

To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#51 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

In reply to Jiang Liu
Quoted 98 lines · Jiang Liu
Quoted 97 lines · Yun Wu (Abel)
Quoted 94 lines · Jiang Liu
Quoted 80 lines · Yun Wu (Abel)
Quoted 28 lines · Thomas Gleixner
Quoted 16 lines · Yun Wu (Abel)

Review struct irq_chip { · line 363

Quoted 6 lines · Thomas Gleixner

struct irq_chip {

(quoted diff) +1 -0
@@ -359,6 +360,7 @@ struct irq_chip {
 	void		(*irq_release_resources)(struct irq_data *data);
 
 	void		(*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);
+	void		(*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg);

Hmm... It's really weird.
I don't think it's the interrupt controllers' responsibility to write messages for all the endpoint devices since the methods of configuring message registers may different between these devices. And theoretically, the endpoint devices themselves should take the responsibility to configure their message registers. To say the least, the write_msg callback here still need to call some certain interfaces provided by the corresponding device.

Quoted 4 lines

There would be lots of ARM new devices capable of sending message based interrupts to interrupt controllers, does all the drivers of the devices need to expose a write_msg callback to interrupt controllers?

Well, writing the message _IS_ part of the interrupt controller.

So in order to enable non PCI based MSI we want to have generic infrastructure with minimal per device/device class callbacks and of course you need to provide that callback for your special device.

Quoted 7 lines

We already have non PCI based MSI controllers in x86 today and we need to handle the whole stuff with tons of copied coded extra for each of those. So consolidating it into common infrastructure allows us to get rid of the pointless copied code and reduce the per device effort to the relevant hardware specific callbacks. irq_write_msi_msg being one of those.

At least, we have the same goal.
I will illustrate my thoughts by an example.
The current code is something like:

Device A
========
void A_write_msg() { ... }

Group B
(a group of devices behave same on writing messages, i.e. PCI)
=======
void B_write_msg() { ... }

Controller
==========

irq_chip.irq_write_msi_msg () {
	if (A)
		A_write_msg();
	if (B)
		B_write_msg();
}

It's horrible when new devices come out, since we need to modify the controller part for each new device.
What I suggested is:

MSI Core
========
struct msi_ops { .write_msg, };
struct msi_desc { .msi_ops, };

write_msg() {
	X = get_dev();
	irq_chip.compose_msg(X);	// IRQ chips' responsibility
	X_msi_ops.write_msg();		// nothing to do with IRQ chips
}

Device A
========
void A_write_msg() { ... }
A_msi_ops.write_msg = A_write_msg;

Quoted 6 lines

Group B
=======
void B_write_msg() { ... }
B_msi_ops.write_msg = B_write_msg;

Please correct me if I misunderstood anything.

Hi Yun,
We provide an irq_chip for each type of interrupt controller
instead of devices. For the example mentioned above, if device A and Group B has different interrupt controllers, we just need to implement irq_chip_A and irq_chip_B and set irq_chip.irq_write_msi_msg() to suitable callbacks.
The framework already achieves what you you want:)

Quoted 6 lines
Quoted 1 line

What if device A and group B have the same interrupt controller?

Device doesn't care about interrupt controllers, it just cares about interrupts used by itself. It's the interrupt source (controller) enumerators' responsibility to discover interrupt source, associate methods to control the interrupt source and assign irq numbers for interrupt sources.

Yes, indeed.

Quoted 4 lines

There are two ways to associate irq numbers with device:
1) arch code/bus drivers statically assigns irq number for devices when creating device objects, such as PCI legacy interrupt (INTA-INTD), IOAPIC interrupts.

And OF interfaces.

Quoted 5 lines

2) device drivers ask interrupt source enumerators to dynamically create irq numbers, such pci_enable_msix_range() and friends.
So device driver definitely doesn't need to known about irq_chip methods to control interrupt sources.

The above you described is absolutely right, but not the things I want to know. :)
Take GICv3 ITS for example, it deals with both PCI and non PCI message interrupts. IIUC, several irq_chips need to be implemented in the ITS driver (i.e. pci_msi_chip, A_msi_chip and B_msi_chip). What should we do to the ITS driver if new MSI-capable devices come out?

Regards,
Abel

#52 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Quoted 122 lines · Yun Wu (Abel)
Quoted 98 lines · Jiang Liu
Quoted 97 lines · Yun Wu (Abel)
Quoted 94 lines · Jiang Liu
Quoted 80 lines · Yun Wu (Abel)
Quoted 28 lines · Thomas Gleixner
Quoted 16 lines · Yun Wu (Abel)

Review struct irq_chip { · line 363

Quoted 6 lines · Thomas Gleixner

struct irq_chip {

(quoted diff) +1 -0
@@ -359,6 +360,7 @@ struct irq_chip {
 	void		(*irq_release_resources)(struct irq_data *data);
 
 	void		(*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);
+	void		(*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg);

Hmm... It's really weird.
I don't think it's the interrupt controllers' responsibility to write messages for all the endpoint devices since the methods of configuring message registers may different between these devices. And theoretically, the endpoint devices themselves should take the responsibility to configure their message registers. To say the least, the write_msg callback here still need to call some certain interfaces provided by the corresponding device.

Quoted 4 lines

There would be lots of ARM new devices capable of sending message based interrupts to interrupt controllers, does all the drivers of the devices need to expose a write_msg callback to interrupt controllers?

Well, writing the message _IS_ part of the interrupt controller.

So in order to enable non PCI based MSI we want to have generic infrastructure with minimal per device/device class callbacks and of course you need to provide that callback for your special device.

Quoted 7 lines

We already have non PCI based MSI controllers in x86 today and we need to handle the whole stuff with tons of copied coded extra for each of those. So consolidating it into common infrastructure allows us to get rid of the pointless copied code and reduce the per device effort to the relevant hardware specific callbacks. irq_write_msi_msg being one of those.

At least, we have the same goal.
I will illustrate my thoughts by an example.
The current code is something like:

Device A
========
void A_write_msg() { ... }

Group B
(a group of devices behave same on writing messages, i.e. PCI)
=======
void B_write_msg() { ... }

Controller
==========

irq_chip.irq_write_msi_msg () {
	if (A)
		A_write_msg();
	if (B)
		B_write_msg();
}

It's horrible when new devices come out, since we need to modify the controller part for each new device.
What I suggested is:

MSI Core
========
struct msi_ops { .write_msg, };
struct msi_desc { .msi_ops, };

write_msg() {
	X = get_dev();
	irq_chip.compose_msg(X);	// IRQ chips' responsibility
	X_msi_ops.write_msg();		// nothing to do with IRQ chips
}

Device A
========
void A_write_msg() { ... }
A_msi_ops.write_msg = A_write_msg;

Quoted 6 lines

Group B
=======
void B_write_msg() { ... }
B_msi_ops.write_msg = B_write_msg;

Please correct me if I misunderstood anything.

Hi Yun,
We provide an irq_chip for each type of interrupt controller
instead of devices. For the example mentioned above, if device A and Group B has different interrupt controllers, we just need to implement irq_chip_A and irq_chip_B and set irq_chip.irq_write_msi_msg() to suitable callbacks.
The framework already achieves what you you want:)

Quoted 6 lines
Quoted 1 line

What if device A and group B have the same interrupt controller?

Device doesn't care about interrupt controllers, it just cares about interrupts used by itself. It's the interrupt source (controller) enumerators' responsibility to discover interrupt source, associate methods to control the interrupt source and assign irq numbers for interrupt sources.

Yes, indeed.

Quoted 4 lines

There are two ways to associate irq numbers with device:
1) arch code/bus drivers statically assigns irq number for devices when creating device objects, such as PCI legacy interrupt (INTA-INTD), IOAPIC interrupts.

And OF interfaces.

Quoted 5 lines

2) device drivers ask interrupt source enumerators to dynamically create irq numbers, such pci_enable_msix_range() and friends.
So device driver definitely doesn't need to known about irq_chip methods to control interrupt sources.

Quoted 6 lines

The above you described is absolutely right, but not the things I want to know. :)
Take GICv3 ITS for example, it deals with both PCI and non PCI message interrupts. IIUC, several irq_chips need to be implemented in the ITS driver (i.e. pci_msi_chip, A_msi_chip and B_msi_chip). What should we do to the ITS driver if new MSI-capable devices come out?

Marc has posted a patchset to enable ITS based on the hierarchy irqdomain framework, please refer to "[PATCH 00/15] arm64: PCI/MSI:
GICv3 ITS support (stacked domain edition)" at
https://lkml.org/lkml/2014/11/11/620

Quoted 4 lines

Regards,
Abel

#53 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Quoted 131 lines · Jiang Liu
Quoted 122 lines · Yun Wu (Abel)
Quoted 98 lines · Jiang Liu
Quoted 97 lines · Yun Wu (Abel)
Quoted 94 lines · Jiang Liu
Quoted 80 lines · Yun Wu (Abel)
Quoted 28 lines · Thomas Gleixner
Quoted 16 lines · Yun Wu (Abel)

Review struct irq_chip { · line 363

Quoted 6 lines · Thomas Gleixner

struct irq_chip {

(quoted diff) +1 -0
@@ -359,6 +360,7 @@ struct irq_chip {
 	void		(*irq_release_resources)(struct irq_data *data);
 
 	void		(*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);
+	void		(*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg);

Hmm... It's really weird.
I don't think it's the interrupt controllers' responsibility to write messages for all the endpoint devices since the methods of configuring message registers may different between these devices. And theoretically, the endpoint devices themselves should take the responsibility to configure their message registers. To say the least, the write_msg callback here still need to call some certain interfaces provided by the corresponding device.

Quoted 4 lines

There would be lots of ARM new devices capable of sending message based interrupts to interrupt controllers, does all the drivers of the devices need to expose a write_msg callback to interrupt controllers?

Well, writing the message _IS_ part of the interrupt controller.

So in order to enable non PCI based MSI we want to have generic infrastructure with minimal per device/device class callbacks and of course you need to provide that callback for your special device.

Quoted 7 lines

We already have non PCI based MSI controllers in x86 today and we need to handle the whole stuff with tons of copied coded extra for each of those. So consolidating it into common infrastructure allows us to get rid of the pointless copied code and reduce the per device effort to the relevant hardware specific callbacks. irq_write_msi_msg being one of those.

At least, we have the same goal.
I will illustrate my thoughts by an example.
The current code is something like:

Device A
========
void A_write_msg() { ... }

Group B
(a group of devices behave same on writing messages, i.e. PCI)
=======
void B_write_msg() { ... }

Controller
==========

irq_chip.irq_write_msi_msg () {
	if (A)
		A_write_msg();
	if (B)
		B_write_msg();
}

It's horrible when new devices come out, since we need to modify the controller part for each new device.
What I suggested is:

MSI Core
========
struct msi_ops { .write_msg, };
struct msi_desc { .msi_ops, };

write_msg() {
	X = get_dev();
	irq_chip.compose_msg(X);	// IRQ chips' responsibility
	X_msi_ops.write_msg();		// nothing to do with IRQ chips
}

Device A
========
void A_write_msg() { ... }
A_msi_ops.write_msg = A_write_msg;

Quoted 6 lines

Group B
=======
void B_write_msg() { ... }
B_msi_ops.write_msg = B_write_msg;

Please correct me if I misunderstood anything.

Hi Yun,
We provide an irq_chip for each type of interrupt controller
instead of devices. For the example mentioned above, if device A and Group B has different interrupt controllers, we just need to implement irq_chip_A and irq_chip_B and set irq_chip.irq_write_msi_msg() to suitable callbacks.
The framework already achieves what you you want:)

Quoted 6 lines
Quoted 1 line

What if device A and group B have the same interrupt controller?

Device doesn't care about interrupt controllers, it just cares about interrupts used by itself. It's the interrupt source (controller) enumerators' responsibility to discover interrupt source, associate methods to control the interrupt source and assign irq numbers for interrupt sources.

Yes, indeed.

Quoted 4 lines

There are two ways to associate irq numbers with device:
1) arch code/bus drivers statically assigns irq number for devices when creating device objects, such as PCI legacy interrupt (INTA-INTD), IOAPIC interrupts.

And OF interfaces.

Quoted 5 lines

2) device drivers ask interrupt source enumerators to dynamically create irq numbers, such pci_enable_msix_range() and friends.
So device driver definitely doesn't need to known about irq_chip methods to control interrupt sources.

Quoted 6 lines

The above you described is absolutely right, but not the things I want to know. :)
Take GICv3 ITS for example, it deals with both PCI and non PCI message interrupts. IIUC, several irq_chips need to be implemented in the ITS driver (i.e. pci_msi_chip, A_msi_chip and B_msi_chip). What should we do to the ITS driver if new MSI-capable devices come out?

Quoted 5 lines

Marc has posted a patchset to enable ITS based on the hierarchy irqdomain framework, please refer to "[PATCH 00/15] arm64: PCI/MSI:
GICv3 ITS support (stacked domain edition)" at
https://lkml.org/lkml/2014/11/11/620

IIUC, Marc's patch now only supports PCI MSI/MSI-X...

Thanks,
Abel

#54 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Quoted 138 lines · Yun Wu (Abel)
Quoted 136 lines · Jiang Liu
Quoted 133 lines · Yun Wu (Abel)
Quoted 103 lines · Jiang Liu
Quoted 102 lines · Yun Wu (Abel)
Quoted 99 lines · Jiang Liu
Quoted 85 lines · Yun Wu (Abel)
Quoted 33 lines · Thomas Gleixner
Quoted 21 lines · Yun Wu (Abel)

Review struct irq_chip { · line 363

Quoted 6 lines · Thomas Gleixner

struct irq_chip {

(quoted diff) +1 -0
@@ -359,6 +360,7 @@ struct irq_chip {
 	void		(*irq_release_resources)(struct irq_data *data);
 
 	void		(*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);
+	void		(*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg);

Hmm... It's really weird.
I don't think it's the interrupt controllers' responsibility to write messages
for all the endpoint devices since the methods of configuring message registers
may different between these devices. And theoretically, the endpoint devices
themselves should take the responsibility to configure their message registers.
To say the least, the write_msg callback here still need to call some certain
interfaces provided by the corresponding device.

Quoted 4 lines

There would be lots of ARM new devices capable of sending message based interrupts to interrupt controllers, does all the drivers of the devices need to expose a write_msg callback to interrupt controllers?

Well, writing the message _IS_ part of the interrupt controller.

So in order to enable non PCI based MSI we want to have generic infrastructure with minimal per device/device class callbacks and of course you need to provide that callback for your special device.

Quoted 7 lines

We already have non PCI based MSI controllers in x86 today and we need to handle the whole stuff with tons of copied coded extra for each of those. So consolidating it into common infrastructure allows us to get rid of the pointless copied code and reduce the per device effort to the relevant hardware specific callbacks. irq_write_msi_msg being one of those.

At least, we have the same goal.
I will illustrate my thoughts by an example.
The current code is something like:

Device A
========
void A_write_msg() { ... }

Group B
(a group of devices behave same on writing messages, i.e. PCI)
=======
void B_write_msg() { ... }

Controller
==========

irq_chip.irq_write_msi_msg () {
	if (A)
		A_write_msg();
	if (B)
		B_write_msg();
}

It's horrible when new devices come out, since we need to modify the controller part for each new device.
What I suggested is:

MSI Core
========
struct msi_ops { .write_msg, };
struct msi_desc { .msi_ops, };

write_msg() {
	X = get_dev();
	irq_chip.compose_msg(X);	// IRQ chips' responsibility
	X_msi_ops.write_msg();		// nothing to do with IRQ chips
}

Device A
========
void A_write_msg() { ... }
A_msi_ops.write_msg = A_write_msg;

Quoted 6 lines

Group B
=======
void B_write_msg() { ... }
B_msi_ops.write_msg = B_write_msg;

Please correct me if I misunderstood anything.

Hi Yun,
We provide an irq_chip for each type of interrupt controller
instead of devices. For the example mentioned above, if device A and Group B has different interrupt controllers, we just need to implement irq_chip_A and irq_chip_B and set irq_chip.irq_write_msi_msg() to suitable callbacks.
The framework already achieves what you you want:)

Quoted 6 lines
Quoted 1 line

What if device A and group B have the same interrupt controller?

Device doesn't care about interrupt controllers, it just cares about interrupts used by itself. It's the interrupt source (controller) enumerators' responsibility to discover interrupt source, associate methods to control the interrupt source and assign irq numbers for interrupt sources.

Yes, indeed.

Quoted 4 lines

There are two ways to associate irq numbers with device:
1) arch code/bus drivers statically assigns irq number for devices when creating device objects, such as PCI legacy interrupt (INTA-INTD), IOAPIC interrupts.

And OF interfaces.

Quoted 5 lines

2) device drivers ask interrupt source enumerators to dynamically create irq numbers, such pci_enable_msix_range() and friends.
So device driver definitely doesn't need to known about irq_chip methods to control interrupt sources.

The above you described is absolutely right, but not the things I want to know. :)
Take GICv3 ITS for example, it deals with both PCI and non PCI message interrupts. IIUC, several irq_chips need to be implemented in the ITS driver (i.e. pci_msi_chip, A_msi_chip and B_msi_chip). What should we do to the ITS driver if new MSI-capable devices come out?

Quoted 7 lines
Quoted 5 lines

Marc has posted a patchset to enable ITS based on the hierarchy irqdomain framework, please refer to "[PATCH 00/15] arm64: PCI/MSI:
GICv3 ITS support (stacked domain edition)" at
https://lkml.org/lkml/2014/11/11/620

IIUC, Marc's patch now only supports PCI MSI/MSI-X...

Indeed, and the current solution makes is relatively easy to plug in non-PCI MSI. Just don't plug the ITS into the *PCI* MSI framework when you encounter such a thing.

Thanks,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny.
#55 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Quoted 1 line · Marc Zyngier

On Tue, Nov 18 2014 at 2:46:02 pm GMT, "Yun Wu (Abel)" <[email protected]> wrote:

[...]

Quoted 6 lines
Quoted 1 line

IIUC, Marc's patch now only supports PCI MSI/MSI-X...

Indeed, and the current solution makes is relatively easy to plug in non-PCI MSI. Just don't plug the ITS into the *PCI* MSI framework when you encounter such a thing.

I am looking forward to that. :)
I guess the main reason you haven't plugged in non-PCI MSI is the way of obtaining device ids used in searching DT table.

Thanks,
Abel

#56 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Quoted 4 lines · Yun Wu (Abel)
Quoted 1 line · Marc Zyngier

On Tue, Nov 18 2014 at 2:46:02 pm GMT, "Yun Wu (Abel)" <[email protected]> wrote:

[...]

Quoted 8 lines
Quoted 6 lines
Quoted 1 line

IIUC, Marc's patch now only supports PCI MSI/MSI-X...

Indeed, and the current solution makes is relatively easy to plug in non-PCI MSI. Just don't plug the ITS into the *PCI* MSI framework when you encounter such a thing.

I am looking forward to that. :)

I really don't.

Quoted 2 lines

I guess the main reason you haven't plugged in non-PCI MSI is the way of obtaining device ids used in searching DT table.

That, and also:
- No way to carve out LPI ranges for non-PCI allocations, should some ITS mandate specific ranges
- No description of how to program the generating device, it required
- No platform with such requirements aiming for upstream support

To put it mildly, non-PCI support on the ITS is a rather long way away, and it has nothing to do with the code. It has everything to do with specifying what we want to support, and how we describe it in DT. Until then, not much is going to happen.

Thanks,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny.
#57 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

In reply to Yun Wu (Abel)

On Tue, 18 Nov 2014, Yun Wu (Abel) wrote:

Can you please trim the messages when you're replying?

Quoted 6 lines

The above you described is absolutely right, but not the things I want to know. :)
Take GICv3 ITS for example, it deals with both PCI and non PCI message interrupts. IIUC, several irq_chips need to be implemented in the ITS driver (i.e. pci_msi_chip, A_msi_chip and B_msi_chip). What should we do to the ITS driver if new MSI-capable devices come out?

You seem to miss the stacking here

PCI-MSI ->
A-MSI -> ITS -> GIC
B-MSI ->

So each of the device types has its own MSI controller. Each of them will have their own callbacks and are backed by the underlying ITS/GIC implementation.

And that's the only sensible solution.

Thanks,

tglx

#58 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Quoted 13 lines · Thomas Gleixner

On Tue, 18 Nov 2014, Yun Wu (Abel) wrote:

Can you please trim the messages when you're replying?

Quoted 6 lines

The above you described is absolutely right, but not the things I want to know. :)
Take GICv3 ITS for example, it deals with both PCI and non PCI message interrupts. IIUC, several irq_chips need to be implemented in the ITS driver (i.e. pci_msi_chip, A_msi_chip and B_msi_chip). What should we do to the ITS driver if new MSI-capable devices come out?

You seem to miss the stacking here

Quoted 7 lines

PCI-MSI ->
A-MSI -> ITS -> GIC
B-MSI ->

So each of the device types has its own MSI controller. Each of them will have their own callbacks and are backed by the underlying ITS/GIC implementation.

Yes, this hits the key point. Once a new device type becomes available, we need to add pieces of code outside the new device's driver to make it work, which in my opinion is due to lack of core infrastructure. More specifically, the core infrastructure needs to support mechanism of MSI, not the various types of devices.

Quoted 3 lines

And that's the only sensible solution.

It's sensible, but not perfect.
What I suggested is to add a generic layer:

PCI-MSI ->
A-MSI -> (generic layer) -> ITS -> GICR
B-MSI ->

The PCI/A/B/... passes its hardware properties to the generic layer which gets configurations ready by calling ITS's domain/chip callbacks. When a new device type arrives, the only thing need to do is to implement the driver of that device, with nothing to do with the generic layer or ITS.

Thanks,
Abel

#59 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Quoted 23 lines · Yun Wu (Abel)
Quoted 13 lines · Thomas Gleixner

On Tue, 18 Nov 2014, Yun Wu (Abel) wrote:

Can you please trim the messages when you're replying?

Quoted 6 lines

The above you described is absolutely right, but not the things I want to know. :)
Take GICv3 ITS for example, it deals with both PCI and non PCI message interrupts. IIUC, several irq_chips need to be implemented in the ITS driver (i.e. pci_msi_chip, A_msi_chip and B_msi_chip). What should we do to the ITS driver if new MSI-capable devices come out?

You seem to miss the stacking here

Quoted 7 lines

PCI-MSI ->
A-MSI -> ITS -> GIC
B-MSI ->

So each of the device types has its own MSI controller. Each of them will have their own callbacks and are backed by the underlying ITS/GIC implementation.

Quoted 5 lines

Yes, this hits the key point. Once a new device type becomes available, we need to add pieces of code outside the new device's driver to make it work, which in my opinion is due to lack of core infrastructure. More specifically, the core infrastructure needs to support mechanism of MSI, not the various types of devices.

It depends on the implementation details whether we need to change ITS to support new devices. One possible way to avoid changing ITS to support new devices is:
1) ITS only allocates and manages interrupt translation tables and pass some type of identifier back to MSI controller drivers.
2) Each MSI controller driver implements its own compose_msi_msg() and write_msi_msg() according to hardware specifications.
By this way, there is no need to change ITS to support new types of MSI controllers.

On x86 systems, interrupt remapping is optional and we also want to hide implementation details, so we chose another solution:
1) interrupt remapping driver allocates and manages remapping resources, it also implements different compose_msi_msg() to support different MSI controllers.
2) MSI controller implement write_msi_msg(), it also implements compose_msi_msg() if interrupt remapping is disabled.
By this way, we do need to change interrupt remapping driver(ITS on ARM) to support new type of MSI controllers.

So it totally depends on how you implement the hierarchy irqdomain, there are no limitations from the framework side.

For the proposal to add some type of ops structure into struct msi_desc, actually I have a serial of patches to support device specific mask/unmask/write/compose/startup/shutdown operations by adding msi_desc.chip_ops. But there's no actual users of those interfaces currently and we don't want to over-engineering, so I abandoned that patch set. I may rework on it when enabling generic MSI support later.
Regards!
Gerry

Quoted 26 lines
Quoted 4 lines

And that's the only sensible solution.

It's sensible, but not perfect.
What I suggested is to add a generic layer:

PCI-MSI ->
A-MSI -> (generic layer) -> ITS -> GICR
B-MSI ->

The PCI/A/B/... passes its hardware properties to the generic layer which gets configurations ready by calling ITS's domain/chip callbacks. When a new device type arrives, the only thing need to do is to implement the driver of that device, with nothing to do with the generic layer or ITS.

Thanks,
Abel

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#60 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

In reply to Yun Wu (Abel)
Quoted 36 lines · Yun Wu (Abel)
Quoted 13 lines · Thomas Gleixner

On Tue, 18 Nov 2014, Yun Wu (Abel) wrote:

Can you please trim the messages when you're replying?

Quoted 6 lines

The above you described is absolutely right, but not the things I want to know. :)
Take GICv3 ITS for example, it deals with both PCI and non PCI message interrupts. IIUC, several irq_chips need to be implemented in the ITS driver (i.e. pci_msi_chip, A_msi_chip and B_msi_chip). What should we do to the ITS driver if new MSI-capable devices come out?

You seem to miss the stacking here

Quoted 7 lines

PCI-MSI ->
A-MSI -> ITS -> GIC
B-MSI ->

So each of the device types has its own MSI controller. Each of them will have their own callbacks and are backed by the underlying ITS/GIC implementation.

Yes, this hits the key point. Once a new device type becomes available, we need to add pieces of code outside the new device's driver to make it work, which in my opinion is due to lack of core infrastructure. More specifically, the core infrastructure needs to support mechanism of MSI, not the various types of devices.

Quoted 3 lines

And that's the only sensible solution.

It's sensible, but not perfect.
What I suggested is to add a generic layer:

Quoted 8 lines

PCI-MSI ->
A-MSI -> (generic layer) -> ITS -> GICR
B-MSI ->

The PCI/A/B/... passes its hardware properties to the generic layer which gets configurations ready by calling ITS's domain/chip callbacks. When a new device type arrives, the only thing need to do is to implement the driver of that device, with nothing to do with the generic layer or ITS.

I really don't get your "generic layer" story. To me, it looks like a glorified set of function pointers. And that's exactly what stacked domains are giving you:

A-MSI -> ITS -> GIC

This "A-MSI" is responsible for:
- implementing the "prepare" callback, which allocates the ITT
- implementing the "irq_compose_msi_msg"

Hardly anything to change in the ITS driver, and I can probably make it so that you don't even have to write a single line of code in the ITS driver.

If the generic MSI layer we now have is not enough for you, then please submit detailed use cases.

Thanks,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny.
#61 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Quoted 56 lines · Marc Zyngier
Quoted 36 lines · Yun Wu (Abel)
Quoted 13 lines · Thomas Gleixner

On Tue, 18 Nov 2014, Yun Wu (Abel) wrote:

Can you please trim the messages when you're replying?

Quoted 6 lines

The above you described is absolutely right, but not the things I want to know. :)
Take GICv3 ITS for example, it deals with both PCI and non PCI message interrupts. IIUC, several irq_chips need to be implemented in the ITS driver (i.e. pci_msi_chip, A_msi_chip and B_msi_chip). What should we do to the ITS driver if new MSI-capable devices come out?

You seem to miss the stacking here

Quoted 7 lines

PCI-MSI ->
A-MSI -> ITS -> GIC
B-MSI ->

So each of the device types has its own MSI controller. Each of them will have their own callbacks and are backed by the underlying ITS/GIC implementation.

Yes, this hits the key point. Once a new device type becomes available, we need to add pieces of code outside the new device's driver to make it work, which in my opinion is due to lack of core infrastructure. More specifically, the core infrastructure needs to support mechanism of MSI, not the various types of devices.

Quoted 3 lines

And that's the only sensible solution.

It's sensible, but not perfect.
What I suggested is to add a generic layer:

Quoted 8 lines

PCI-MSI ->
A-MSI -> (generic layer) -> ITS -> GICR
B-MSI ->

The PCI/A/B/... passes its hardware properties to the generic layer which gets configurations ready by calling ITS's domain/chip callbacks. When a new device type arrives, the only thing need to do is to implement the driver of that device, with nothing to do with the generic layer or ITS.

I really don't get your "generic layer" story. To me, it looks like a glorified set of function pointers. And that's exactly what stacked domains are giving you:

A-MSI -> ITS -> GIC

This "A-MSI" is responsible for:
- implementing the "prepare" callback, which allocates the ITT
- implementing the "irq_compose_msi_msg"

Quoted 7 lines

Hardly anything to change in the ITS driver, and I can probably make it so that you don't even have to write a single line of code in the ITS driver.

If the generic MSI layer we now have is not enough for you, then please submit detailed use cases.

Hi Marc,

As I said, I never thought Gerry's patch don't work, I am just trying to make it better. :)

As to the "generic layer" story, please check the following URL:
https://lkml.org/lkml/2014/12/10/93

Thanks,
Abel

#62 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

In reply to Yun Wu (Abel)
Quoted 9 lines · Yun Wu (Abel)
Quoted 6 lines · Jiang Liu

We provide an irq_chip for each type of interrupt controller
instead of devices. For the example mentioned above, if device A and Group B has different interrupt controllers, we just need to implement irq_chip_A and irq_chip_B and set irq_chip.irq_write_msi_msg() to suitable callbacks.
The framework already achieves what you you want:)

What if device A and group B have the same interrupt controller?

Well, if write_msg() is different they are hardly the same.

Thanks,

tglx

#63 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Quoted 9 lines · Thomas Gleixner
Quoted 8 lines · Yun Wu (Abel)
Quoted 6 lines · Jiang Liu

We provide an irq_chip for each type of interrupt controller
instead of devices. For the example mentioned above, if device A and Group B has different interrupt controllers, we just need to implement irq_chip_A and irq_chip_B and set irq_chip.irq_write_msi_msg() to suitable callbacks.
The framework already achieves what you you want:)

Quoted 4 lines
Quoted 1 line

What if device A and group B have the same interrupt controller?

Well, if write_msg() is different they are hardly the same.

The GICv3 ITS now deals with both PCI and non PCI message interrupts. We can't require the new devices behave writing message in a same way. What we can do is to abstract all the endpoints' behavior, and I provided one abstraction in an earlier reply.

Thanks,
Abel

#64 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Quoted 13 lines · Yun Wu (Abel)
Quoted 11 lines · Thomas Gleixner
Quoted 9 lines · Yun Wu (Abel)
Quoted 6 lines · Jiang Liu

We provide an irq_chip for each type of interrupt controller
instead of devices. For the example mentioned above, if device A and Group B has different interrupt controllers, we just need to implement irq_chip_A and irq_chip_B and set irq_chip.irq_write_msi_msg() to suitable callbacks.
The framework already achieves what you you want:)

What if device A and group B have the same interrupt controller?

Quoted 7 lines
Quoted 2 lines

Well, if write_msg() is different they are hardly the same.

The GICv3 ITS now deals with both PCI and non PCI message interrupts. We can't require the new devices behave writing message in a same way. What we can do is to abstract all the endpoints' behavior, and I provided one abstraction in an earlier reply.

It should be easy to extend:)
Actually, x86 interrupt remapping drivers already support two types of MSIs, one is PCI MSI/MSIX, another is HPET interrupt.

Quoted 4 lines

Thanks,
Abel

#65 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Quoted 17 lines · Jiang Liu
Quoted 16 lines · Yun Wu (Abel)
Quoted 13 lines · Thomas Gleixner
Quoted 9 lines · Yun Wu (Abel)
Quoted 6 lines · Jiang Liu

We provide an irq_chip for each type of interrupt controller
instead of devices. For the example mentioned above, if device A and Group B has different interrupt controllers, we just need to implement irq_chip_A and irq_chip_B and set irq_chip.irq_write_msi_msg() to suitable callbacks.
The framework already achieves what you you want:)

What if device A and group B have the same interrupt controller?

Well, if write_msg() is different they are hardly the same.

Quoted 7 lines
Quoted 4 lines

The GICv3 ITS now deals with both PCI and non PCI message interrupts. We can't require the new devices behave writing message in a same way. What we can do is to abstract all the endpoints' behavior, and I provided one abstraction in an earlier reply.

It should be easy to extend:)
Actually, x86 interrupt remapping drivers already support two types of MSIs, one is PCI MSI/MSIX, another is HPET interrupt.

Well, if there are one hundred types, I don't think it's as easy as you thought to extend. Of course we can doubt the possibility of being hundred, but tens or twenties is reasonably possible lying under the fact we have already startet to integrate the MSI registers (or some other form to store information) into the individual devices.

Thanks,
Abel

#66 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Quoted 28 lines · Yun Wu (Abel)
Quoted 17 lines · Jiang Liu
Quoted 16 lines · Yun Wu (Abel)
Quoted 13 lines · Thomas Gleixner
Quoted 9 lines · Yun Wu (Abel)
Quoted 6 lines · Jiang Liu

We provide an irq_chip for each type of interrupt controller
instead of devices. For the example mentioned above, if device A and Group B has different interrupt controllers, we just need to implement irq_chip_A and irq_chip_B and set irq_chip.irq_write_msi_msg() to suitable callbacks.
The framework already achieves what you you want:)

What if device A and group B have the same interrupt controller?

Well, if write_msg() is different they are hardly the same.

Quoted 7 lines
Quoted 4 lines

The GICv3 ITS now deals with both PCI and non PCI message interrupts. We can't require the new devices behave writing message in a same way. What we can do is to abstract all the endpoints' behavior, and I provided one abstraction in an earlier reply.

It should be easy to extend:)
Actually, x86 interrupt remapping drivers already support two types of MSIs, one is PCI MSI/MSIX, another is HPET interrupt.

Quoted 5 lines

Well, if there are one hundred types, I don't think it's as easy as you thought to extend. Of course we can doubt the possibility of being hundred, but tens or twenties is reasonably possible lying under the fact we have already startet to integrate the MSI registers (or some other form to store information) into the individual devices.

If your hardware designers decided to come up with 20+ different ways to implement MSI support, then it's not a reason to inflict completely non-sensical crap into the core infrastucture.

The infrastructure we provided is optimized for sane use cases, while it allows you to deal with totally brainwrecked hardware designs.

If you have 20 different ways, you need 20 different controllers for it, whether you like it or not. No magic 'generic' abstraction will solve that for you.

Thanks,

tglx

#67 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

In reply to Yun Wu (Abel)
Quoted 13 lines · Yun Wu (Abel)
Quoted 11 lines · Thomas Gleixner
Quoted 9 lines · Yun Wu (Abel)
Quoted 6 lines · Jiang Liu

We provide an irq_chip for each type of interrupt controller
instead of devices. For the example mentioned above, if device A and Group B has different interrupt controllers, we just need to implement irq_chip_A and irq_chip_B and set irq_chip.irq_write_msi_msg() to suitable callbacks.
The framework already achieves what you you want:)

What if device A and group B have the same interrupt controller?

Quoted 7 lines
Quoted 2 lines

Well, if write_msg() is different they are hardly the same.

The GICv3 ITS now deals with both PCI and non PCI message interrupts. We can't require the new devices behave writing message in a same way. What we can do is to abstract all the endpoints' behavior, and I provided one abstraction in an earlier reply.

This is why the framework gives you the opportunity to provide methods that:
- compose the message
- program the message into the device

None of that has to be PCI specific, and gives you a clean abstraction. The framework only gives you a number of shortcuts for PCI MSI, because that's what most people care about.

Thanks,

        M.
Signature · 1 line
Jazz is not dead. It just smells funny.
#68 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Quoted 22 lines · Marc Zyngier
Quoted 13 lines · Yun Wu (Abel)
Quoted 11 lines · Thomas Gleixner
Quoted 9 lines · Yun Wu (Abel)
Quoted 6 lines · Jiang Liu

We provide an irq_chip for each type of interrupt controller
instead of devices. For the example mentioned above, if device A and Group B has different interrupt controllers, we just need to implement irq_chip_A and irq_chip_B and set irq_chip.irq_write_msi_msg() to suitable callbacks.
The framework already achieves what you you want:)

What if device A and group B have the same interrupt controller?

Quoted 7 lines
Quoted 2 lines

Well, if write_msg() is different they are hardly the same.

The GICv3 ITS now deals with both PCI and non PCI message interrupts. We can't require the new devices behave writing message in a same way. What we can do is to abstract all the endpoints' behavior, and I provided one abstraction in an earlier reply.

Quoted 9 lines

This is why the framework gives you the opportunity to provide methods that:
- compose the message
- program the message into the device

None of that has to be PCI specific, and gives you a clean abstraction. The framework only gives you a number of shortcuts for PCI MSI, because that's what most people care about.

Indeed, and I never said Jiang's patches don't work, I was just thinking that they were not that perfect.

Thanks,
Abel

#69 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Quoted 6 lines · Yun Wu (Abel)
Quoted 5 lines · Marc Zyngier

This is why the framework gives you the opportunity to provide methods that:
- compose the message
- program the message into the device

Quoted 7 lines
Quoted 4 lines

None of that has to be PCI specific, and gives you a clean abstraction. The framework only gives you a number of shortcuts for PCI MSI, because that's what most people care about.

Indeed, and I never said Jiang's patches don't work, I was just thinking that they were not that perfect.

But your magic extra layer of indirection is perfect? It's not, it just violates sane layering in order to support braindead hardware designs.

Thanks,

tglx

#70 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Quoted 12 lines · Thomas Gleixner
Quoted 11 lines · Yun Wu (Abel)
Quoted 9 lines · Marc Zyngier

This is why the framework gives you the opportunity to provide methods that:
- compose the message
- program the message into the device

None of that has to be PCI specific, and gives you a clean abstraction. The framework only gives you a number of shortcuts for PCI MSI, because that's what most people care about.

Quoted 7 lines
Quoted 2 lines

Indeed, and I never said Jiang's patches don't work, I was just thinking that they were not that perfect.

But your magic extra layer of indirection is perfect? It's not, it just violates sane layering in order to support braindead hardware designs.

Hi Thomas, Gerry and Marc,

I spent last two weeks implementing and testing my original idea about making the sub domains generic, based on stacked domain feature. Now it comes real, please see the attached patch.

With this patch applied, I think things will get easier.

For drivers of interrupt controllers, they need to implement:
a) struct irq_chip, gets associated in domain's map/alloc callback
b) struct irq_domain, with corresponding operations
c) create sub generic MBI domain of IRQ domain to deal with all MBI types. This changes almost nothing of the current code.

For drivers of MBI-capable devices, they need to implement:
a) MBI operations, like mask/unmask or setting message.
This will remove current ugly arch-specific code by organizing the device behavior into a generic structure used in generic MBI layer.

The MBI generic code will build the bridge between the two groups. So when a new driver need to implement, either controller's or endpoint's, just code the corresponding 'need' described above with no more work to do.

This patch (also with several other patches) is tested on Hisilicon ARM64 SoC, with non PCI devices capable of message based interrupts. The PCI part is not tested because it needs large refactoring work to do. So yes, the testing work is not sufficient, but I think the patch is enough to present what I really wanted to express. :)

A new term introduced by the patch named Message Based Interrupt (MBI) is used for presenting the generic MSIs (which does help me avoid conflicting with the existing code). Actually the new name is proposed by Marc several months ago, suggesting that MSI implies too much about PCI. I think it's a good idea to use MBI in generic code and make the MSI/MSI-x a wrapper of MBI inside the PCI core. Anyway, naming is not the key point yet.

Finally, yes, my thoughts is not perfect, but I am just trying to make it better.

Best regards and thanks,
Abel

Quoted 1 line

From 64c5440f685440bb7d92ab716013f9f54f21bca2 Mon Sep 17 00:00:00 2001

From: Yun Wu <[email protected]>
Date: Wed, 10 Dec 2014 10:32:58 +0800
Subject: [PATCH] MBI: initial support for message based interrupts

This patch provides initial support for Message Based Interrupt (MBI), which is a write from the device to a special address which causes an interrupt to be received by the CPU.

MBI is a generic mechanism not specific to any architectures or any subsystems. MSI/MSI-X defined in PCI specification are special MBIs.

---
 arch/arm64/Kconfig     |   1 +
 include/linux/device.h |   3 +
 include/linux/irq.h    |  22 ++++
 include/linux/mbi.h    |  95 ++++++++++++++++++
 kernel/irq/Kconfig     |   5 +
 kernel/irq/Makefile    |   1 +
 kernel/irq/chip.c      |  66 ++++++++++++
 kernel/irq/mbi.c       | 260 +++++++++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 453 insertions(+)
 create mode 100644 include/linux/mbi.h
 create mode 100644 kernel/irq/mbi.c
arch/arm64/Kconfig +1 -0
index 1f49c288..ef55541 100644
@@ -13,6 +13,7 @@ config ARM64
 	select ARM_GIC
 	select AUDIT_ARCH_COMPAT_GENERIC
 	select ARM_GIC_V3
+	select MBI
 	select ARM_GIC_V3_ITS if PCI_MSI
 	select BUILDTIME_EXTABLE_SORT
 	select CLONE_BACKWARDS
include/linux/device.h +3 -0
index ce1f2160..e0618c2 100644
@@ -715,6 +715,7 @@ struct acpi_dev_node {
  * 		gone away. This should be set by the allocator of the
  * 		device (i.e. the bus driver that discovered the device).
  * @iommu_group: IOMMU group the device belongs to.
+ * @mbi:	Pointer to the data of message based interrupts.
  *
  * @offline_disabled: If set, the device is permanently online.
  * @offline:	Set after successful invocation of bus type's .offline().
@@ -794,6 +795,8 @@ struct device {
 	void	(*release)(struct device *dev);
 	struct iommu_group	*iommu_group;
 
+	struct mbi_data		*mbi;
+
 	bool			offline_disabled:1;
 	bool			offline:1;
 };
include/linux/irq.h +22 -0
index 8badf34..92e25e6 100644
@@ -28,6 +28,7 @@
 
 struct seq_file;
 struct module;
+struct mbi_msg;
 struct msi_msg;
 
 /*
@@ -120,6 +121,7 @@ enum {
 	IRQ_SET_MASK_OK_DONE,
 };
 
+struct mbi_desc;
 struct msi_desc;
 struct irq_domain;
 
@@ -139,6 +141,7 @@ struct irq_domain;
  * @handler_data:	per-IRQ data for the irq_chip methods
  * @chip_data:		platform-specific per-chip private data for the chip
  *			methods, to allow shared chip implementations
+ * @mbi_desc:		MBI descriptor
  * @msi_desc:		MSI descriptor
  * @affinity:		IRQ affinity on SMP
  *
@@ -159,6 +162,7 @@ struct irq_data {
 #endif
 	void			*handler_data;
 	void			*chip_data;
+	struct mbi_desc		*mbi_desc;
 	struct msi_desc		*msi_desc;
 	cpumask_var_t		affinity;
 };
@@ -323,6 +327,7 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
  *				irq_request_resources
  * @irq_compose_msi_msg:	optional to compose message content for MSI
  * @irq_write_msi_msg:	optional to write message content for MSI
+ * @irq_compose_msg:	optional to write message content for MBI
  * @flags:		chip specific flags
  */
 struct irq_chip {
@@ -362,6 +367,8 @@ struct irq_chip {
 	void		(*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);
 	void		(*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg);
 
+	void		(*irq_compose_msg)(struct irq_data *data, struct mbi_msg *msg);
+
 	unsigned long	flags;
 };
 
@@ -567,10 +574,14 @@ extern int irq_set_chip(unsigned int irq, struct irq_chip *chip);
 extern int irq_set_handler_data(unsigned int irq, void *data);
 extern int irq_set_chip_data(unsigned int irq, void *data);
 extern int irq_set_irq_type(unsigned int irq, unsigned int type);
+extern int irq_set_mbi_desc(unsigned int irq, struct mbi_desc *entry);
+extern int irq_set_mbi_desc_range(unsigned int irq, struct mbi_desc *entry,
+				  unsigned int count);
 extern int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry);
 extern int irq_set_msi_desc_off(unsigned int irq_base, unsigned int irq_offset,
 				struct msi_desc *entry);
 extern struct irq_data *irq_get_irq_data(unsigned int irq);
+extern int irq_compose_mbi_msg(struct irq_data *data, struct mbi_msg *msg);
 
 static inline struct irq_chip *irq_get_chip(unsigned int irq)
 {
@@ -605,6 +616,17 @@ static inline void *irq_data_get_irq_handler_data(struct irq_data *d)
 	return d->handler_data;
 }
 
+static inline struct mbi_desc *irq_get_mbi_desc(unsigned int irq)
+{
+	struct irq_data *d = irq_get_irq_data(irq);
+	return d ? d->mbi_desc : NULL;
+}
+
+static inline struct mbi_desc *irq_data_get_mbi(struct irq_data *d)
+{
+	return d->mbi_desc;
+}
+
 static inline struct msi_desc *irq_get_msi_desc(unsigned int irq)
 {
 	struct irq_data *d = irq_get_irq_data(irq);
include/linux/mbi.h new file +95 -0

95 lines not on this page · raw message

kernel/irq/Kconfig +5 -0
index 9a76e3b..d1071cf 100644
@@ -60,6 +60,11 @@ config IRQ_DOMAIN_HIERARCHY
 	bool
 	select IRQ_DOMAIN
 
+# Support for Message Based Interrupt (MBI)
+config MBI
+	bool "Support Message Based Interrupt (MBI)"
+	select IRQ_DOMAIN_HIERARCHY
+
 # Generic MSI interrupt support
 config GENERIC_MSI_IRQ
 	bool
kernel/irq/Makefile +1 -0
index d121235..1e5f4b8 100644
@@ -6,4 +6,5 @@ obj-$(CONFIG_IRQ_DOMAIN) += irqdomain.o
 obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o
 obj-$(CONFIG_PM_SLEEP) += pm.o
+obj-$(CONFIG_MBI) += mbi.o
 obj-$(CONFIG_GENERIC_MSI_IRQ) += msi.o
kernel/irq/chip.c +66 -0

78 lines not on this page · raw message

kernel/irq/mbi.c new file +260 -0

260 lines not on this page · raw message

Signature · 1 line
1.8.0
#71 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Quoted 4 lines · Yun Wu (Abel)

On 2014/11/19 19:11, Thomas Gleixner wrote:
I spent last two weeks implementing and testing my original idea about making the sub domains generic, based on stacked domain feature. Now it comes real, please see the attached patch.

Can you please send patches inline? Attached is a pain to reply to.

Quoted 1 line

With this patch applied, I think things will get easier.

I don't see what gets easier. It's just another infrastructure which is painfully similar to MSI.

Quoted 5 lines

This patch (also with several other patches) is tested on Hisilicon ARM64 SoC, with non PCI devices capable of message based interrupts. The PCI part is not tested because it needs large refactoring work to do. So yes, the testing work is not sufficient, but I think the patch is enough to present what I really wanted to express. :)

Not really.

If you provide proper patches which make use of it and most important a proper refactoring of the PCI/MSI side then we can discuss that, but for now it's just handwaving.

Thanks,

tglx

#72 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

Quoted 7 lines · Thomas Gleixner
Quoted 4 lines · Yun Wu (Abel)

On 2014/11/19 19:11, Thomas Gleixner wrote:
I spent last two weeks implementing and testing my original idea about making the sub domains generic, based on stacked domain feature. Now it comes real, please see the attached patch.

Can you please send patches inline? Attached is a pain to reply to.

Sure, why not.

Quoted 5 lines
Quoted 2 lines

With this patch applied, I think things will get easier.

I don't see what gets easier. It's just another infrastructure which is painfully similar to MSI.

Then please help me feel that pain when I post inline patches, thanks. :)

Quoted 7 lines
Quoted 6 lines

This patch (also with several other patches) is tested on Hisilicon ARM64 SoC, with non PCI devices capable of message based interrupts. The PCI part is not tested because it needs large refactoring work to do. So yes, the testing work is not sufficient, but I think the patch is enough to present what I really wanted to express. :)

Quoted 6 lines

Not really.

If you provide proper patches which make use of it and most important a proper refactoring of the PCI/MSI side then we can discuss that, but for now it's just handwaving.

OK, I will start a new thread when I finished PCI/MSI refactoring work.

Thanks,
Abel

#73 lore raw

Re: [patch 08/16] genirq: Introduce callback irq_chip.irq_write_msi_msg

In reply to Yun Wu (Abel)
Quoted 80 lines · Yun Wu (Abel)
Quoted 28 lines · Thomas Gleixner
Quoted 16 lines · Yun Wu (Abel)

include/linux/irq.h struct irq_chip { · line 363

Quoted 6 lines · Thomas Gleixner

struct irq_chip {

include/linux/irq.h +1 -0
@@ -359,6 +360,7 @@ struct irq_chip {
 	void		(*irq_release_resources)(struct irq_data *data);
 
 	void		(*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);
+	void		(*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg);

Hmm... It's really weird.
I don't think it's the interrupt controllers' responsibility to write messages for all the endpoint devices since the methods of configuring message registers may different between these devices. And theoretically, the endpoint devices themselves should take the responsibility to configure their message registers. To say the least, the write_msg callback here still need to call some certain interfaces provided by the corresponding device.

Quoted 4 lines

There would be lots of ARM new devices capable of sending message based interrupts to interrupt controllers, does all the drivers of the devices need to expose a write_msg callback to interrupt controllers?

Well, writing the message _IS_ part of the interrupt controller.

So in order to enable non PCI based MSI we want to have generic infrastructure with minimal per device/device class callbacks and of course you need to provide that callback for your special device.

Quoted 7 lines

We already have non PCI based MSI controllers in x86 today and we need to handle the whole stuff with tons of copied coded extra for each of those. So consolidating it into common infrastructure allows us to get rid of the pointless copied code and reduce the per device effort to the relevant hardware specific callbacks. irq_write_msi_msg being one of those.

At least, we have the same goal.
I will illustrate my thoughts by an example.
The current code is something like:

Device A
========
void A_write_msg() { ... }

Group B
(a group of devices behave same on writing messages, i.e. PCI)
=======
void B_write_msg() { ... }

Controller
==========

irq_chip.irq_write_msi_msg () {
	if (A)
		A_write_msg();
	if (B)
		B_write_msg();
}

It's horrible when new devices come out, since we need to modify the controller part for each new device.
What I suggested is:

MSI Core
========
struct msi_ops { .write_msg, };
struct msi_desc { .msi_ops, };

write_msg() {
	X = get_dev();
	irq_chip.compose_msg(X);	// IRQ chips' responsibility
	X_msi_ops.write_msg();		// nothing to do with IRQ chips
}

Device A
========
void A_write_msg() { ... }
A_msi_ops.write_msg = A_write_msg;

Quoted 6 lines

Group B
=======
void B_write_msg() { ... }
B_msi_ops.write_msg = B_write_msg;

Please correct me if I misunderstood anything.

Please take a look at following file, which uses the common MSI framework to support PCI, DMAR and HPET interrupt on x86.
https://github.com/jiangliu/linux/blob/irqdomain/p2v7/arch/x86/kernel/apic/msi.c
Regards!
Gerry

Quoted 10 lines

Thanks,
Abel

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#74 lore raw

PATCH 9/16 genirq: Add generic msi irq domain support

In reply to Thomas Gleixner

From: Jiang Liu <[email protected]>

Implement the basic functions for MSI interrupt support with hierarchical interrupt domains.

[ tglx: Extracted and combined from several patches ]

Cc Bjorn Helgaas <[email protected]>
Cc Grant Likely <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Yingjoe Chen <[email protected]>
Cc Yijing Wang <[email protected]>
---
 include/linux/msi.h |   35 +++++++++++++++
 kernel/irq/Kconfig  |   10 ++++
 kernel/irq/Makefile |    1 
 kernel/irq/msi.c    |  119 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 165 insertions(+)
include/linux/msi.h +35 -0
Index: tip/include/linux/msi.h
===================================================================
@@ -77,4 +77,39 @@ struct msi_chip {
 	void (*teardown_irq)(struct msi_chip *chip, unsigned int irq);
 };
 
+#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
+struct irq_domain;
+struct irq_chip;
+struct device_node;
+struct msi_domain_info;
+
+struct msi_domain_ops {
+	void		(*calc_hwirq)(struct msi_domain_info *info, void *arg,
+				      struct msi_desc *desc);
+	irq_hw_number_t	(*get_hwirq)(struct msi_domain_info *info, void *arg);
+	int		(*msi_init)(struct irq_domain *domain,
+				    struct msi_domain_info *info,
+				    unsigned int virq, irq_hw_number_t hwirq,
+				    void *arg);
+	void		(*msi_free)(struct irq_domain *domain,
+				    struct msi_domain_info *info,
+				    unsigned int virq);
+};
+
+struct msi_domain_info {
+	struct msi_domain_ops	*ops;
+	struct irq_chip		*chip;
+	void			*data;
+};
+
+int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,
+			    bool force);
+
+struct irq_domain *msi_create_irq_domain(struct device_node *of_node,
+					 struct msi_domain_info *info,
+					 struct irq_domain *parent);
+struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain);
+
+#endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */
+
 #endif /* LINUX_MSI_H */
kernel/irq/Kconfig +10 -0
Index: tip/kernel/irq/Kconfig
===================================================================
@@ -60,6 +60,16 @@ config IRQ_DOMAIN_HIERARCHY
 	bool
 	select IRQ_DOMAIN
 
+# Generic MSI interrupt support
+config GENERIC_MSI_IRQ
+	bool
+
+# Generic MSI hierarchical interrupt domain support
+config GENERIC_MSI_IRQ_DOMAIN
+	bool
+	select IRQ_DOMAIN_HIERARCHY
+	select GENERIC_MSI_IRQ
+
 config HANDLE_DOMAIN_IRQ
 	bool
 
kernel/irq/Makefile +1 -0
Index: tip/kernel/irq/Makefile
===================================================================
@@ -6,3 +6,4 @@ obj-$(CONFIG_IRQ_DOMAIN) += irqdomain.o
 obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o
 obj-$(CONFIG_PM_SLEEP) += pm.o
+obj-$(CONFIG_GENERIC_MSI_IRQ) += msi.o
kernel/irq/msi.c new file +119 -0

119 lines not on this page · raw message

#75 lore raw

Re: [patch 09/16] genirq: Add generic msi irq domain support

Quoted 150 lines · Thomas Gleixner

From: Jiang Liu <[email protected]>

Implement the basic functions for MSI interrupt support with hierarchical interrupt domains.

[ tglx: Extracted and combined from several patches ]

Cc Bjorn Helgaas <[email protected]>
Cc Grant Likely <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Yingjoe Chen <[email protected]>
Cc Yijing Wang <[email protected]>
---
 include/linux/msi.h |   35 +++++++++++++++
 kernel/irq/Kconfig  |   10 ++++
 kernel/irq/Makefile |    1 
 kernel/irq/msi.c    |  119 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 165 insertions(+)

Index: tip/include/linux/msi.h
===================================================================

include/linux/msi.h +35 -0
@@ -77,4 +77,39 @@ struct msi_chip {
 	void (*teardown_irq)(struct msi_chip *chip, unsigned int irq);
 };
 
+#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
+struct irq_domain;
+struct irq_chip;
+struct device_node;
+struct msi_domain_info;
+
+struct msi_domain_ops {
+	void		(*calc_hwirq)(struct msi_domain_info *info, void *arg,
+				      struct msi_desc *desc);
+	irq_hw_number_t	(*get_hwirq)(struct msi_domain_info *info, void *arg);
+	int		(*msi_init)(struct irq_domain *domain,
+				    struct msi_domain_info *info,
+				    unsigned int virq, irq_hw_number_t hwirq,
+				    void *arg);
+	void		(*msi_free)(struct irq_domain *domain,
+				    struct msi_domain_info *info,
+				    unsigned int virq);
+};
+
+struct msi_domain_info {
+	struct msi_domain_ops	*ops;
+	struct irq_chip		*chip;
+	void			*data;
+};
+
+int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,
+			    bool force);
+
+struct irq_domain *msi_create_irq_domain(struct device_node *of_node,
+					 struct msi_domain_info *info,
+					 struct irq_domain *parent);
+struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain);
+
+#endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */
+
 #endif /* LINUX_MSI_H */

Index: tip/kernel/irq/Kconfig
===================================================================

kernel/irq/Kconfig +10 -0
@@ -60,6 +60,16 @@ config IRQ_DOMAIN_HIERARCHY
 	bool
 	select IRQ_DOMAIN
 
+# Generic MSI interrupt support
+config GENERIC_MSI_IRQ
+	bool
+
+# Generic MSI hierarchical interrupt domain support
+config GENERIC_MSI_IRQ_DOMAIN
+	bool
+	select IRQ_DOMAIN_HIERARCHY
+	select GENERIC_MSI_IRQ
+
 config HANDLE_DOMAIN_IRQ
 	bool
 

Index: tip/kernel/irq/Makefile
===================================================================

kernel/irq/Makefile +1 -0
@@ -6,3 +6,4 @@ obj-$(CONFIG_IRQ_DOMAIN) += irqdomain.o
 obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o
 obj-$(CONFIG_PM_SLEEP) += pm.o
+obj-$(CONFIG_GENERIC_MSI_IRQ) += msi.o

Index: tip/kernel/irq/msi.c
===================================================================

kernel/irq/msi.c new file +50 -0
@@ -0,0 +1,119 @@
+/*
+ * linux/kernel/irq/msi.c
+ *
+ * Copyright (C) 2014 Intel Corp.
+ * Author: Jiang Liu <[email protected]>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file contains common code to support Message Signalled Interrupt for
+ * PCI compatible and non PCI compatible devices.
+ */
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/msi.h>
+
+#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
+int msi_domain_set_affinity(struct irq_data *irq_data,
+			    const struct cpumask *mask, bool force)
+{
+	struct irq_data *parent = irq_data->parent_data;
+	struct msi_msg msg;
+	int ret;
+
+	ret = parent->chip->irq_set_affinity(parent, mask, force);
+	if (ret >= 0 && ret != IRQ_SET_MASK_OK_DONE) {
+		BUG_ON(irq_chip_compose_msi_msg(irq_data, &msg));
+		irq_chip_write_msi_msg(irq_data, &msg);
+	}
+
+	return ret;
+}
+
+static void msi_domain_activate(struct irq_domain *domain,
+				struct irq_data *irq_data)
+{
+	struct msi_msg msg;
+
+	BUG_ON(irq_chip_compose_msi_msg(irq_data, &msg));
+	irq_chip_write_msi_msg(irq_data, &msg);
+}
+
+static void msi_domain_deactivate(struct irq_domain *domain,
+				  struct irq_data *irq_data)
+{
+	struct msi_msg msg;
+
+	memset(&msg, 0, sizeof(msg));
+	irq_chip_write_msi_msg(irq_data, &msg);
+}
+

kernel/irq/msi.c line 60

Quoted 10 lines
kernel/irq/msi.c new file +10 -0
+static int msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
+			    unsigned int nr_irqs, void *arg)
+{
+	struct msi_domain_info *info = domain->host_data;
+	struct msi_domain_ops *ops = info->ops;
+	irq_hw_number_t hwirq = ops->get_hwirq(info, arg);
+	int i, ret;
+
+	if (irq_find_mapping(domain, hwirq) > 0)
+		return -EEXIST;

I think we need to check range here.
I fixed this by applying a patch showed in the bottom.

kernel/irq/msi.c line 70

Quoted 10 lines
kernel/irq/msi.c new file +10 -0
+
+	ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < nr_irqs; i++) {
+		ret = ops->msi_init(domain, info, virq + i, hwirq + i, arg);
+		if (ret < 0) {
+			if (ops->msi_free) {
+				for (i--; i > 0; i--)

while (i--) ?

Regards,
Abel

Quoted 41 lines
kernel/irq/msi.c new file +39 -0
+					ops->msi_free(domain, info, virq + i);
+			}
+			irq_domain_free_irqs_top(domain, virq, nr_irqs);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void msi_domain_free(struct irq_domain *domain, unsigned int virq,
+			    unsigned int nr_irqs)
+{
+	struct msi_domain_info *info = domain->host_data;
+	int i;
+
+	if (info->ops->msi_free) {
+		for (i = 0; i < nr_irqs; i++)
+			info->ops->msi_free(domain, info, virq + i);
+	}
+	irq_domain_free_irqs_top(domain, virq, nr_irqs);
+}
+
+static struct irq_domain_ops msi_domain_ops = {
+	.alloc		= msi_domain_alloc,
+	.free		= msi_domain_free,
+	.activate	= msi_domain_activate,
+	.deactivate	= msi_domain_deactivate,
+};
+
+struct irq_domain *msi_create_irq_domain(struct device_node *of_node,
+					 struct msi_domain_info *info,
+					 struct irq_domain *parent)
+{
+	struct irq_domain *domain;
+
+	domain = irq_domain_add_tree(of_node, &msi_domain_ops, info);
+	if (domain)
+		domain->parent = parent;

kernel/irq/msi.c line 119

Quoted 10 lines
kernel/irq/msi.c new file +10 -0
+
+	return domain;
+}
+
+struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain)
+{
+	return (struct msi_domain_info *)domain->host_data;
+}
+
+#endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */
kernel/irq/irqdomain.c +28 -0
index cc18182..6d1be00 100644
@@ -568,6 +568,34 @@ unsigned int irq_find_mapping(struct irq_domain *domain,
 }
 EXPORT_SYMBOL_GPL(irq_find_mapping);
 
+/**
+ * irq_find_mapping_many() - Find a range of linux irqs from a range of hwirqs.
+ * @domain:	domain owning these hardware interrupts
+ * @hwirq:	start hardware irq number in @domain space
+ * @count:	number of interrupts to find
+ *
+ * Returns the first linux irq number on success, or 0 when not found, or error.
+ */
+int irq_find_mapping_many(struct irq_domain *domain, irq_hw_number_t hwirq,
+			  int count)
+{
+	unsigned int from;
+	int i;
+
+	for (i = from = 0; i < count; i++) {
+		if (!from) {
+			from = irq_find_mapping(domain, hwirq + i);
+			if (from && i)
+				return -1;
+		} else if ((from + i) != irq_find_mapping(domain, hwirq + i)) {
+			return -1;
+		}
+	}
+
+	return from;
+}
+EXPORT_SYMBOL_GPL(irq_find_mapping_many);
+
 #ifdef CONFIG_IRQ_DOMAIN_DEBUG
 static int virq_debug_show(struct seq_file *m, void *private)
 {
#76 lore raw

Re: [patch 09/16] genirq: Add generic msi irq domain support

Quoted 3 lines · Yun Wu (Abel)
Quoted 1 line · Thomas Gleixner

From: Jiang Liu <[email protected]>

<snip>

Quoted 5 lines
Quoted 5 lines
(quoted diff) +5 -0
+static int msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
+			    unsigned int nr_irqs, void *arg)
+{
+	struct msi_domain_info *info = domain->host_data;
+	struct msi_domain_ops *ops = info->ops;
Quoted 8 lines

Review

Quoted 5 lines
(quoted diff) +5 -0
+	irq_hw_number_t hwirq = ops->get_hwirq(info, arg);
+	int i, ret;
+
+	if (irq_find_mapping(domain, hwirq) > 0)
+		return -EEXIST;

I think we need to check range here.
I fixed this by applying a patch showed in the bottom.

Hi Yun,
Yes, we have some assumptions here about the way the interface
will be used for. Will improve it in future patches. Regards!
Gerry

Quoted 111 lines

Review

Quoted 11 lines
(quoted diff) +10 -0
+
+	ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < nr_irqs; i++) {
+		ret = ops->msi_init(domain, info, virq + i, hwirq + i, arg);
+		if (ret < 0) {
+			if (ops->msi_free) {
+				for (i--; i > 0; i--)

while (i--) ?

Regards,
Abel

Quoted 51 lines
(quoted diff) +49 -0
+					ops->msi_free(domain, info, virq + i);
+			}
+			irq_domain_free_irqs_top(domain, virq, nr_irqs);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void msi_domain_free(struct irq_domain *domain, unsigned int virq,
+			    unsigned int nr_irqs)
+{
+	struct msi_domain_info *info = domain->host_data;
+	int i;
+
+	if (info->ops->msi_free) {
+		for (i = 0; i < nr_irqs; i++)
+			info->ops->msi_free(domain, info, virq + i);
+	}
+	irq_domain_free_irqs_top(domain, virq, nr_irqs);
+}
+
+static struct irq_domain_ops msi_domain_ops = {
+	.alloc		= msi_domain_alloc,
+	.free		= msi_domain_free,
+	.activate	= msi_domain_activate,
+	.deactivate	= msi_domain_deactivate,
+};
+
+struct irq_domain *msi_create_irq_domain(struct device_node *of_node,
+					 struct msi_domain_info *info,
+					 struct irq_domain *parent)
+{
+	struct irq_domain *domain;
+
+	domain = irq_domain_add_tree(of_node, &msi_domain_ops, info);
+	if (domain)
+		domain->parent = parent;
+
+	return domain;
+}
+
+struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain)
+{
+	return (struct msi_domain_info *)domain->host_data;
+}
+
+#endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */
kernel/irq/irqdomain.c +28 -0
index cc18182..6d1be00 100644
@@ -568,6 +568,34 @@ unsigned int irq_find_mapping(struct irq_domain *domain,
 }
 EXPORT_SYMBOL_GPL(irq_find_mapping);
 
+/**
+ * irq_find_mapping_many() - Find a range of linux irqs from a range of hwirqs.
+ * @domain:	domain owning these hardware interrupts
+ * @hwirq:	start hardware irq number in @domain space
+ * @count:	number of interrupts to find
+ *
+ * Returns the first linux irq number on success, or 0 when not found, or error.
+ */
+int irq_find_mapping_many(struct irq_domain *domain, irq_hw_number_t hwirq,
+			  int count)
+{
+	unsigned int from;
+	int i;
+
+	for (i = from = 0; i < count; i++) {
+		if (!from) {
+			from = irq_find_mapping(domain, hwirq + i);
+			if (from && i)
+				return -1;
+		} else if ((from + i) != irq_find_mapping(domain, hwirq + i)) {
+			return -1;
+		}
+	}
+
+	return from;
+}
+EXPORT_SYMBOL_GPL(irq_find_mapping_many);
+
 #ifdef CONFIG_IRQ_DOMAIN_DEBUG
 static int virq_debug_show(struct seq_file *m, void *private)
 {
#77 lore raw

Re: [patch 09/16] genirq: Add generic msi irq domain support

Quoted 19 lines · Jiang Liu
Quoted 3 lines · Yun Wu (Abel)
Quoted 1 line · Thomas Gleixner

From: Jiang Liu <[email protected]>

<snip>

Quoted 5 lines
Quoted 5 lines
(quoted diff) +5 -0
+static int msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
+			    unsigned int nr_irqs, void *arg)
+{
+	struct msi_domain_info *info = domain->host_data;
+	struct msi_domain_ops *ops = info->ops;
Quoted 8 lines

Review

Quoted 5 lines
(quoted diff) +5 -0
+	irq_hw_number_t hwirq = ops->get_hwirq(info, arg);
+	int i, ret;
+
+	if (irq_find_mapping(domain, hwirq) > 0)
+		return -EEXIST;

I think we need to check range here.
I fixed this by applying a patch showed in the bottom.

Quoted 6 lines

Hi Yun,
Yes, we have some assumptions here about the way the interface
will be used for. Will improve it in future patches. Regards!
Gerry

Quoted 1 line

OK. Just note that don't forget to check my second inline comment below. :)

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
(quoted diff) +5 -0
+
+	ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
+	if (ret < 0)
+		return ret;
+
Quoted 8 lines
Quoted 8 lines

Review

Quoted 5 lines
(quoted diff) +5 -0
+	for (i = 0; i < nr_irqs; i++) {
+		ret = ops->msi_init(domain, info, virq + i, hwirq + i, arg);
+		if (ret < 0) {
+			if (ops->msi_free) {
+				for (i--; i > 0; i--)

while (i--) ?

Here.

Thanks,
Abel

Quoted 98 lines
Quoted 85 lines
Quoted 52 lines
(quoted diff) +49 -0
+					ops->msi_free(domain, info, virq + i);
+			}
+			irq_domain_free_irqs_top(domain, virq, nr_irqs);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void msi_domain_free(struct irq_domain *domain, unsigned int virq,
+			    unsigned int nr_irqs)
+{
+	struct msi_domain_info *info = domain->host_data;
+	int i;
+
+	if (info->ops->msi_free) {
+		for (i = 0; i < nr_irqs; i++)
+			info->ops->msi_free(domain, info, virq + i);
+	}
+	irq_domain_free_irqs_top(domain, virq, nr_irqs);
+}
+
+static struct irq_domain_ops msi_domain_ops = {
+	.alloc		= msi_domain_alloc,
+	.free		= msi_domain_free,
+	.activate	= msi_domain_activate,
+	.deactivate	= msi_domain_deactivate,
+};
+
+struct irq_domain *msi_create_irq_domain(struct device_node *of_node,
+					 struct msi_domain_info *info,
+					 struct irq_domain *parent)
+{
+	struct irq_domain *domain;
+
+	domain = irq_domain_add_tree(of_node, &msi_domain_ops, info);
+	if (domain)
+		domain->parent = parent;
+
+	return domain;
+}
+
+struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain)
+{
+	return (struct msi_domain_info *)domain->host_data;
+}
+
+#endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */
kernel/irq/irqdomain.c +21 -0
index cc18182..6d1be00 100644
@@ -568,6 +568,34 @@ unsigned int irq_find_mapping(struct irq_domain *domain,
 }
 EXPORT_SYMBOL_GPL(irq_find_mapping);
 
+/**
+ * irq_find_mapping_many() - Find a range of linux irqs from a range of hwirqs.
+ * @domain:	domain owning these hardware interrupts
+ * @hwirq:	start hardware irq number in @domain space
+ * @count:	number of interrupts to find
+ *
+ * Returns the first linux irq number on success, or 0 when not found, or error.
+ */
+int irq_find_mapping_many(struct irq_domain *domain, irq_hw_number_t hwirq,
+			  int count)
+{
+	unsigned int from;
+	int i;
+
+	for (i = from = 0; i < count; i++) {
+		if (!from) {
+			from = irq_find_mapping(domain, hwirq + i);
+			if (from && i)
+				return -1;
+		} else if ((from + i) != irq_find_mapping(domain, hwirq + i)) {
+			return -1;

kernel/irq/irqdomain.c unsigned int irq_find_mapping(struct irq_domain *domain, · line 601

Quoted 10 lines
kernel/irq/irqdomain.c +7 -0
+		}
+	}
+
+	return from;
+}
+EXPORT_SYMBOL_GPL(irq_find_mapping_many);
+
 #ifdef CONFIG_IRQ_DOMAIN_DEBUG
 static int virq_debug_show(struct seq_file *m, void *private)
 {

.

#78 lore raw

Re: [patch 09/16] genirq: Add generic msi irq domain support

Quoted 12 lines · Yun Wu (Abel)
Quoted 11 lines · Jiang Liu
Quoted 11 lines

Review

Quoted 9 lines
(quoted diff) +9 -0
+	ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < nr_irqs; i++) {
+		ret = ops->msi_init(domain, info, virq + i, hwirq + i, arg);
+		if (ret < 0) {
+			if (ops->msi_free) {
+				for (i--; i > 0; i--)

while (i--) ?

The allocation for 'i' failed. So we don't free i. You missed the real bug here:

Quoted 1 line
Quoted 1 line
Quoted 1 line

Review

Quoted 1 line
(quoted diff) +1 -0
+				for (i--; i > 0; i--)

Must be i >= 0.

Thanks,

tglx

#79 lore raw

Re: [patch 09/16] genirq: Add generic msi irq domain support

Quoted 14 lines · Thomas Gleixner
Quoted 12 lines · Yun Wu (Abel)
Quoted 11 lines · Jiang Liu
Quoted 11 lines

Review

Quoted 9 lines
(quoted diff) +9 -0
+	ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < nr_irqs; i++) {
+		ret = ops->msi_init(domain, info, virq + i, hwirq + i, arg);
+		if (ret < 0) {
+			if (ops->msi_free) {
+				for (i--; i > 0; i--)

while (i--) ?

Quoted 7 lines

The allocation for 'i' failed. So we don't free i. You missed the real bug here:

Quoted 1 line
Quoted 1 line
Quoted 1 line

Review

Quoted 1 line
(quoted diff) +1 -0
+				for (i--; i > 0; i--)

Must be i >= 0.

"for (i--; i >= 0; i--)" is just the same as "while (i--)".

Thanks,
Abel

#80 lore raw

Re: [patch 09/16] genirq: Add generic msi irq domain support

In reply to Thomas Gleixner
Quoted 14 lines · Thomas Gleixner
Quoted 12 lines · Yun Wu (Abel)
Quoted 11 lines · Jiang Liu
Quoted 11 lines

Review

Quoted 9 lines
(quoted diff) +9 -0
+	ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < nr_irqs; i++) {
+		ret = ops->msi_init(domain, info, virq + i, hwirq + i, arg);
+		if (ret < 0) {
+			if (ops->msi_free) {
+				for (i--; i > 0; i--)

while (i--) ?

Quoted 6 lines

The allocation for 'i' failed. So we don't free i. You missed the real bug here:

Quoted 1 line
Quoted 1 line
Quoted 1 line

Review

Quoted 1 line
(quoted diff) +1 -0
+				for (i--; i > 0; i--)

Must be i >= 0.

Hi Thomas,
You will take care of this bug, right? Or should I send a patch
for it?
Regards!
Gerry

#81 lore raw

PATCH 10/16 PCI/MSI: Move cached entry functions to irq core

In reply to Thomas Gleixner

From: Jiang Liu <[email protected]>

Required to support non PCI based MSI.

[ tglx: Extracted from Jiangs patch series ]

---
 drivers/pci/Kconfig |    1 +
 drivers/pci/msi.c   |   18 ------------------
 kernel/irq/msi.c    |   13 +++++++++++++
 3 files changed, 14 insertions(+), 18 deletions(-)
drivers/pci/Kconfig +1 -0
Index: tip/drivers/pci/Kconfig
===================================================================
@@ -4,6 +4,7 @@
 config PCI_MSI
 	bool "Message Signaled Interrupts (MSI and MSI-X)"
 	depends on PCI
+	select GENERIC_MSI_IRQ
 	help
 	   This allows device drivers to enable MSI (Message Signaled
 	   Interrupts).  Message Signaled Interrupts enable a device to
drivers/pci/msi.c +0 -18
Index: tip/drivers/pci/msi.c
===================================================================
@@ -286,24 +286,6 @@ void read_msi_msg(unsigned int irq, stru
 	__read_msi_msg(entry, msg);
 }
 
-void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
-{
-	/* Assert that the cache is valid, assuming that
-	 * valid messages are not all-zeroes. */
-	BUG_ON(!(entry->msg.address_hi | entry->msg.address_lo |
-		 entry->msg.data));
-
-	*msg = entry->msg;
-}
-
-void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg)
-{
-	struct msi_desc *entry = irq_get_msi_desc(irq);
-
-	__get_cached_msi_msg(entry, msg);
-}
-EXPORT_SYMBOL_GPL(get_cached_msi_msg);
-
 void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
 {
 	if (entry->dev->current_state != PCI_D0) {
kernel/irq/msi.c +13 -0
Index: tip/kernel/irq/msi.c
===================================================================
@@ -13,6 +13,19 @@
 #include <linux/irqdomain.h>
 #include <linux/msi.h>
 
+void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
+{
+	*msg = entry->msg;
+}
+
+void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg)
+{
+	struct msi_desc *entry = irq_get_msi_desc(irq);
+
+	__get_cached_msi_msg(entry, msg);
+}
+EXPORT_SYMBOL_GPL(get_cached_msi_msg);
+
 #ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
 int msi_domain_set_affinity(struct irq_data *irq_data,
 			    const struct cpumask *mask, bool force)
#82 lore raw

PATCH 11/16 PCI/MSI: Remove unnecessary braces around single statements

In reply to Thomas Gleixner

From: Jiang Liu <[email protected]>

Per Documentation/CodingStyle, don't use braces around single statements.

Cc Bjorn Helgaas <[email protected]>
Cc Grant Likely <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Yingjoe Chen <[email protected]>
Cc Yijing Wang <[email protected]>
---
 drivers/pci/msi.c |    9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)
drivers/pci/msi.c +3 -6
Index: tip/drivers/pci/msi.c
===================================================================
@@ -244,9 +244,8 @@ void default_restore_msi_irqs(struct pci
 {
 	struct msi_desc *entry;
 
-	list_for_each_entry(entry, &dev->msi_list, list) {
+	list_for_each_entry(entry, &dev->msi_list, list)
 		default_restore_msi_irq(dev, entry->irq);
-	}
 }
 
 void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
@@ -433,9 +432,8 @@ static void __pci_restore_msix_state(str
 				PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL);
 
 	arch_restore_msi_irqs(dev);
-	list_for_each_entry(entry, &dev->msi_list, list) {
+	list_for_each_entry(entry, &dev->msi_list, list)
 		msix_mask_irq(entry, entry->masked);
-	}
 
 	msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0);
 }
@@ -479,9 +477,8 @@ static int populate_msi_sysfs(struct pci
 	int count = 0;
 
 	/* Determine how many msi entries we have */
-	list_for_each_entry(entry, &pdev->msi_list, list) {
+	list_for_each_entry(entry, &pdev->msi_list, list)
 		++num_msi;
-	}
 	if (!num_msi)
 		return 0;
 
#83 lore raw

PATCH 12/16 PCI/MSI: Simplify PCI MSI code by initializing msi_desc.nvec_used earlier

In reply to Thomas Gleixner

From: Jiang Liu <[email protected]>

Simplify PCI MSI code by initializing msi_desc.nvec_used and msi_desc.msi_attrib.multiple when creating MSI descriptors.

Also remove redundant checks in IRQ remapping drivers, PCI MSI core already guarantees these.

Cc Bjorn Helgaas <[email protected]>
Cc Grant Likely <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Yingjoe Chen <[email protected]>
Cc Yijing Wang <[email protected]>
---
 drivers/iommu/irq_remapping.c |    8 --------
 drivers/pci/msi.c             |   40 +++++++++++++++-------------------------
 2 files changed, 15 insertions(+), 33 deletions(-)
drivers/iommu/irq_remapping.c +0 -8
Index: tip/drivers/iommu/irq_remapping.c
===================================================================
@@ -56,19 +56,13 @@ static int do_setup_msi_irqs(struct pci_
 	unsigned int irq;
 	struct msi_desc *msidesc;
 
-	WARN_ON(!list_is_singular(&dev->msi_list));
 	msidesc = list_entry(dev->msi_list.next, struct msi_desc, list);
-	WARN_ON(msidesc->irq);
-	WARN_ON(msidesc->msi_attrib.multiple);
-	WARN_ON(msidesc->nvec_used);
 
 	irq = irq_alloc_hwirqs(nvec, dev_to_node(&dev->dev));
 	if (irq == 0)
 		return -ENOSPC;
 
 	nvec_pow2 = __roundup_pow_of_two(nvec);
-	msidesc->nvec_used = nvec;
-	msidesc->msi_attrib.multiple = ilog2(nvec_pow2);
 	for (sub_handle = 0; sub_handle < nvec; sub_handle++) {
 		if (!sub_handle) {
 			index = msi_alloc_remapped_irq(dev, irq, nvec_pow2);
@@ -96,8 +90,6 @@ error:
 	 * IRQs from tearing down again in default_teardown_msi_irqs()
 	 */
 	msidesc->irq = 0;
-	msidesc->nvec_used = 0;
-	msidesc->msi_attrib.multiple = 0;
 
 	return ret;
 }
drivers/pci/msi.c +15 -25
Index: tip/drivers/pci/msi.c
===================================================================
@@ -85,19 +85,13 @@ int __weak arch_setup_msi_irqs(struct pc
  */
 void default_teardown_msi_irqs(struct pci_dev *dev)
 {
+	int i;
 	struct msi_desc *entry;
 
-	list_for_each_entry(entry, &dev->msi_list, list) {
-		int i, nvec;
-		if (entry->irq == 0)
-			continue;
-		if (entry->nvec_used)
-			nvec = entry->nvec_used;
-		else
-			nvec = 1 << entry->msi_attrib.multiple;
-		for (i = 0; i < nvec; i++)
-			arch_teardown_msi_irq(entry->irq + i);
-	}
+	list_for_each_entry(entry, &dev->msi_list, list)
+		if (entry->irq)
+			for (i = 0; i < entry->nvec_used; i++)
+				arch_teardown_msi_irq(entry->irq + i);
 }
 
 void __weak arch_teardown_msi_irqs(struct pci_dev *dev)
@@ -335,19 +329,12 @@ static void free_msi_irqs(struct pci_dev
 	struct msi_desc *entry, *tmp;
 	struct attribute **msi_attrs;
 	struct device_attribute *dev_attr;
-	int count = 0;
+	int i, count = 0;
 
-	list_for_each_entry(entry, &dev->msi_list, list) {
-		int i, nvec;
-		if (!entry->irq)
-			continue;
-		if (entry->nvec_used)
-			nvec = entry->nvec_used;
-		else
-			nvec = 1 << entry->msi_attrib.multiple;
-		for (i = 0; i < nvec; i++)
-			BUG_ON(irq_has_action(entry->irq + i));
-	}
+	list_for_each_entry(entry, &dev->msi_list, list)
+		if (entry->irq)
+			for (i = 0; i < entry->nvec_used; i++)
+				BUG_ON(irq_has_action(entry->irq + i));
 
 	arch_teardown_msi_irqs(dev);
 
@@ -538,7 +525,7 @@ error_attrs:
 	return ret;
 }
 
-static struct msi_desc *msi_setup_entry(struct pci_dev *dev)
+static struct msi_desc *msi_setup_entry(struct pci_dev *dev, int nvec)
 {
 	u16 control;
 	struct msi_desc *entry;
@@ -556,6 +543,8 @@ static struct msi_desc *msi_setup_entry(
 	entry->msi_attrib.maskbit	= !!(control & PCI_MSI_FLAGS_MASKBIT);
 	entry->msi_attrib.default_irq	= dev->irq;	/* Save IOAPIC IRQ */
 	entry->msi_attrib.multi_cap	= (control & PCI_MSI_FLAGS_QMASK) >> 1;
+	entry->msi_attrib.multiple	= ilog2(__roundup_pow_of_two(nvec));
+	entry->nvec_used		= nvec;
 
 	if (control & PCI_MSI_FLAGS_64BIT)
 		entry->mask_pos = dev->msi_cap + PCI_MSI_MASK_64;
@@ -588,7 +577,7 @@ static int msi_capability_init(struct pc
 
 	msi_set_enable(dev, 0);	/* Disable MSI during set up */
 
-	entry = msi_setup_entry(dev);
+	entry = msi_setup_entry(dev, nvec);
 	if (!entry)
 		return -ENOMEM;
 
@@ -659,6 +648,7 @@ static int msix_setup_entries(struct pci
 		entry->msi_attrib.entry_nr	= entries[i].entry;
 		entry->msi_attrib.default_irq	= dev->irq;
 		entry->mask_base		= base;
+		entry->nvec_used		= 1;
 
 		list_add_tail(&entry->list, &dev->msi_list);
 	}
#84 lore raw

PATCH 13/16 PCI/MSI: Kill redundant call of irq_set_msi_desc() for MSI-X interrupts

In reply to Thomas Gleixner

From: Jiang Liu <[email protected]>

It is the repsonsibility of arch_setup_msi_irq()/arch_setup_msi_irqs() to call irq_set_msi_desc() to associate IRQ descriptors and MSI descriptors. Kill the redundant call of irq_set_msi_desc() for MSI-X interrupts in the PCI MSI core.

Cc Bjorn Helgaas <[email protected]>
Cc Grant Likely <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Yingjoe Chen <[email protected]>
Cc Yijing Wang <[email protected]>
---
 drivers/pci/msi.c |    1 -
 1 file changed, 1 deletion(-)
drivers/pci/msi.c +0 -1
Index: tip/drivers/pci/msi.c
===================================================================
@@ -667,7 +667,6 @@ static void msix_program_entries(struct
 						PCI_MSIX_ENTRY_VECTOR_CTRL;
 
 		entries[i].vector = entry->irq;
-		irq_set_msi_desc(entry->irq, entry);
 		entry->masked = readl(entry->mask_base + offset);
 		msix_mask_irq(entry, 1);
 		i++;
#85 lore raw

PATCH 14/16 PCI/MSI: Rename __read_msi_msg() to __pci_read_msi_msg()

In reply to Thomas Gleixner

Rename __read_msi_msg() to __pci_read_msi_msg() and kill unused read_msi_msg(). It's a preparation to separate generic MSI code from PCI core.

Cc Bjorn Helgaas <[email protected]>
Cc Grant Likely <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Yingjoe Chen <[email protected]>
Cc Yijing Wang <[email protected]>
---
 arch/powerpc/platforms/pseries/msi.c |    2 +-
 arch/x86/pci/xen.c                   |    2 +-
 drivers/pci/msi.c                    |    9 +--------
 include/linux/msi.h                  |    6 ++++--
 4 files changed, 7 insertions(+), 12 deletions(-)
arch/powerpc/platforms/pseries/msi.c +1 -1
Index: tip/arch/powerpc/platforms/pseries/msi.c
===================================================================
@@ -476,7 +476,7 @@ again:
 		irq_set_msi_desc(virq, entry);
 
 		/* Read config space back so we can restore after reset */
-		__read_msi_msg(entry, &msg);
+		__pci_read_msi_msg(entry, &msg);
 		entry->msg = msg;
 	}
 
arch/x86/pci/xen.c +1 -1
Index: tip/arch/x86/pci/xen.c
===================================================================
@@ -229,7 +229,7 @@ static int xen_hvm_setup_msi_irqs(struct
 		return 1;
 
 	list_for_each_entry(msidesc, &dev->msi_list, list) {
-		__read_msi_msg(msidesc, &msg);
+		__pci_read_msi_msg(msidesc, &msg);
 		pirq = MSI_ADDR_EXT_DEST_ID(msg.address_hi) |
 			((msg.address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff);
 		if (msg.data != XEN_PIRQ_MSI_DATA ||
drivers/pci/msi.c +1 -8
Index: tip/drivers/pci/msi.c
===================================================================
@@ -242,7 +242,7 @@ void default_restore_msi_irqs(struct pci
 		default_restore_msi_irq(dev, entry->irq);
 }
 
-void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
+void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
 {
 	BUG_ON(entry->dev->current_state != PCI_D0);
 
@@ -272,13 +272,6 @@ void __read_msi_msg(struct msi_desc *ent
 	}
 }
 
-void read_msi_msg(unsigned int irq, struct msi_msg *msg)
-{
-	struct msi_desc *entry = irq_get_msi_desc(irq);
-
-	__read_msi_msg(entry, msg);
-}
-
 void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
 {
 	if (entry->dev->current_state != PCI_D0) {
include/linux/msi.h +4 -2
Index: tip/include/linux/msi.h
===================================================================
@@ -15,10 +15,8 @@ struct irq_data;
 struct msi_desc;
 void mask_msi_irq(struct irq_data *data);
 void unmask_msi_irq(struct irq_data *data);
-void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
 void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
 void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
-void read_msi_msg(unsigned int irq, struct msi_msg *msg);
 void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg);
 void write_msi_msg(unsigned int irq, struct msi_msg *msg);
 
@@ -48,6 +46,10 @@ struct msi_desc {
 	struct msi_msg msg;
 };
 
+#ifdef CONFIG_PCI_MSI
+void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
+#endif
+
 /*
  * The arch hooks to setup up msi irqs. Those functions are
  * implemented as weak symbols so that they /can/ be overriden by
#86 lore raw

PATCH 15/16 PCI/MSI: Rename write_msi_msg() to pci_write_msi_msg()

In reply to Thomas Gleixner

From: Jiang Liu <[email protected]>

Rename write_msi_msg() to pci_write_msi_msg() to mark it as PCI specific.

Cc Bjorn Helgaas <[email protected]>
Cc Grant Likely <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Yingjoe Chen <[email protected]>
Cc Yijing Wang <[email protected]>
---
 arch/arm/mach-iop13xx/msi.c            |    2 +-
 arch/ia64/kernel/msi_ia64.c            |    4 ++--
 arch/ia64/sn/kernel/msi_sn.c           |    4 ++--
 arch/mips/pci/msi-octeon.c             |    2 +-
 arch/mips/pci/msi-xlp.c                |    2 +-
 arch/mips/pci/pci-xlr.c                |    2 +-
 arch/powerpc/platforms/cell/axon_msi.c |    2 +-
 arch/powerpc/platforms/powernv/pci.c   |    2 +-
 arch/powerpc/sysdev/fsl_msi.c          |    2 +-
 arch/powerpc/sysdev/mpic_pasemi_msi.c  |    2 +-
 arch/powerpc/sysdev/mpic_u3msi.c       |    2 +-
 arch/powerpc/sysdev/ppc4xx_hsta_msi.c  |    2 +-
 arch/powerpc/sysdev/ppc4xx_msi.c       |    2 +-
 arch/s390/pci/pci.c                    |    2 +-
 arch/sparc/kernel/pci_msi.c            |    2 +-
 arch/tile/kernel/pci_gx.c              |    2 +-
 arch/x86/kernel/apic/io_apic.c         |    4 ++--
 arch/x86/pci/xen.c                     |    2 +-
 drivers/irqchip/irq-armada-370-xp.c    |    2 +-
 drivers/pci/host/pci-tegra.c           |    2 +-
 drivers/pci/host/pcie-designware.c     |    2 +-
 drivers/pci/host/pcie-rcar.c           |    2 +-
 drivers/pci/host/pcie-xilinx.c         |    2 +-
 drivers/pci/msi.c                      |   11 +++++------
 drivers/vfio/pci/vfio_pci_intrs.c      |    2 +-
 include/linux/msi.h                    |    4 ++--
 26 files changed, 34 insertions(+), 35 deletions(-)
arch/arm/mach-iop13xx/msi.c +1 -1
Index: tip/arch/arm/mach-iop13xx/msi.c
===================================================================
@@ -153,7 +153,7 @@ int arch_setup_msi_irq(struct pci_dev *p
 	id = iop13xx_cpu_id();
 	msg.data = (id << IOP13XX_MU_MIMR_CORE_SELECT) | (irq & 0x7f);
 
-	write_msi_msg(irq, &msg);
+	pci_write_msi_msg(irq, &msg);
 	irq_set_chip_and_handler(irq, &iop13xx_msi_chip, handle_simple_irq);
 
 	return 0;
arch/ia64/kernel/msi_ia64.c +2 -2
Index: tip/arch/ia64/kernel/msi_ia64.c
===================================================================
@@ -35,7 +35,7 @@ static int ia64_set_msi_irq_affinity(str
 	data |= MSI_DATA_VECTOR(irq_to_vector(irq));
 	msg.data = data;
 
-	write_msi_msg(irq, &msg);
+	pci_write_msi_msg(irq, &msg);
 	cpumask_copy(idata->affinity, cpumask_of(cpu));
 
 	return 0;
@@ -71,7 +71,7 @@ int ia64_setup_msi_irq(struct pci_dev *p
 		MSI_DATA_DELIVERY_FIXED |
 		MSI_DATA_VECTOR(vector);
 
-	write_msi_msg(irq, &msg);
+	pci_write_msi_msg(irq, &msg);
 	irq_set_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq);
 
 	return 0;
arch/ia64/sn/kernel/msi_sn.c +2 -2
Index: tip/arch/ia64/sn/kernel/msi_sn.c
===================================================================
@@ -145,7 +145,7 @@ int sn_setup_msi_irq(struct pci_dev *pde
 	msg.data = 0x100 + irq;
 
 	irq_set_msi_desc(irq, entry);
-	write_msi_msg(irq, &msg);
+	pci_write_msi_msg(irq, &msg);
 	irq_set_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq);
 
 	return 0;
@@ -205,7 +205,7 @@ static int sn_set_msi_irq_affinity(struc
 	msg.address_hi = (u32)(bus_addr >> 32);
 	msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff);
 
-	write_msi_msg(irq, &msg);
+	pci_write_msi_msg(irq, &msg);
 	cpumask_copy(data->affinity, cpu_mask);
 
 	return 0;
arch/mips/pci/msi-octeon.c +1 -1
Index: tip/arch/mips/pci/msi-octeon.c
===================================================================
@@ -178,7 +178,7 @@ msi_irq_allocated:
 	pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
 
 	irq_set_msi_desc(irq, desc);
-	write_msi_msg(irq, &msg);
+	pci_write_msi_msg(irq, &msg);
 	return 0;
 }
 
arch/mips/pci/msi-xlp.c +1 -1
Index: tip/arch/mips/pci/msi-xlp.c
===================================================================
@@ -345,7 +345,7 @@ static int xlp_setup_msi(uint64_t lnkbas
 	if (ret < 0)
 		return ret;
 
-	write_msi_msg(xirq, &msg);
+	pci_write_msi_msg(xirq, &msg);
 	return 0;
 }
 
arch/mips/pci/pci-xlr.c +1 -1
Index: tip/arch/mips/pci/pci-xlr.c
===================================================================
@@ -260,7 +260,7 @@ int arch_setup_msi_irq(struct pci_dev *d
 	if (ret < 0)
 		return ret;
 
-	write_msi_msg(irq, &msg);
+	pci_write_msi_msg(irq, &msg);
 	return 0;
 }
 #endif
arch/powerpc/platforms/cell/axon_msi.c +1 -1
Index: tip/arch/powerpc/platforms/cell/axon_msi.c
===================================================================
@@ -279,7 +279,7 @@ static int axon_msi_setup_msi_irqs(struc
 
 		irq_set_msi_desc(virq, entry);
 		msg.data = virq;
-		write_msi_msg(virq, &msg);
+		pci_write_msi_msg(virq, &msg);
 	}
 
 	return 0;
arch/powerpc/platforms/powernv/pci.c +1 -1
Index: tip/arch/powerpc/platforms/powernv/pci.c
===================================================================
@@ -91,7 +91,7 @@ static int pnv_setup_msi_irqs(struct pci
 			return rc;
 		}
 		irq_set_msi_desc(virq, entry);
-		write_msi_msg(virq, &msg);
+		pci_write_msi_msg(virq, &msg);
 	}
 	return 0;
 }
arch/powerpc/sysdev/fsl_msi.c +1 -1
Index: tip/arch/powerpc/sysdev/fsl_msi.c
===================================================================
@@ -242,7 +242,7 @@ static int fsl_setup_msi_irqs(struct pci
 		irq_set_msi_desc(virq, entry);
 
 		fsl_compose_msi_msg(pdev, hwirq, &msg, msi_data);
-		write_msi_msg(virq, &msg);
+		pci_write_msi_msg(virq, &msg);
 	}
 	return 0;
 
arch/powerpc/sysdev/mpic_pasemi_msi.c +1 -1
Index: tip/arch/powerpc/sysdev/mpic_pasemi_msi.c
===================================================================
@@ -136,7 +136,7 @@ static int pasemi_msi_setup_msi_irqs(str
 		 * register to generate MSI [512...1023]
 		 */
 		msg.data = hwirq-0x200;
-		write_msi_msg(virq, &msg);
+		pci_write_msi_msg(virq, &msg);
 	}
 
 	return 0;
arch/powerpc/sysdev/mpic_u3msi.c +1 -1
Index: tip/arch/powerpc/sysdev/mpic_u3msi.c
===================================================================
@@ -171,7 +171,7 @@ static int u3msi_setup_msi_irqs(struct p
 		printk("u3msi: allocated virq 0x%x (hw 0x%x) addr 0x%lx\n",
 			  virq, hwirq, (unsigned long)addr);
 		msg.data = hwirq;
-		write_msi_msg(virq, &msg);
+		pci_write_msi_msg(virq, &msg);
 
 		hwirq++;
 	}
arch/powerpc/sysdev/ppc4xx_hsta_msi.c +1 -1
Index: tip/arch/powerpc/sysdev/ppc4xx_hsta_msi.c
===================================================================
@@ -85,7 +85,7 @@ static int hsta_setup_msi_irqs(struct pc
 			msi_bitmap_free_hwirqs(&ppc4xx_hsta_msi.bmp, irq, 1);
 			return -EINVAL;
 		}
-		write_msi_msg(hwirq, &msg);
+		pci_write_msi_msg(hwirq, &msg);
 	}
 
 	return 0;
arch/powerpc/sysdev/ppc4xx_msi.c +1 -1
Index: tip/arch/powerpc/sysdev/ppc4xx_msi.c
===================================================================
@@ -116,7 +116,7 @@ static int ppc4xx_setup_msi_irqs(struct
 
 		irq_set_msi_desc(virq, entry);
 		msg.data = int_no;
-		write_msi_msg(virq, &msg);
+		pci_write_msi_msg(virq, &msg);
 	}
 	return 0;
 }
arch/s390/pci/pci.c +1 -1
Index: tip/arch/s390/pci/pci.c
===================================================================
@@ -403,7 +403,7 @@ int arch_setup_msi_irqs(struct pci_dev *
 		msg.data = hwirq;
 		msg.address_lo = zdev->msi_addr & 0xffffffff;
 		msg.address_hi = zdev->msi_addr >> 32;
-		write_msi_msg(irq, &msg);
+		pci_write_msi_msg(irq, &msg);
 		airq_iv_set_data(zdev->aibv, hwirq, irq);
 		hwirq++;
 	}
arch/sparc/kernel/pci_msi.c +1 -1
Index: tip/arch/sparc/kernel/pci_msi.c
===================================================================
@@ -161,7 +161,7 @@ static int sparc64_setup_msi_irq(unsigne
 	msg.data = msi;
 
 	irq_set_msi_desc(*irq_p, entry);
-	write_msi_msg(*irq_p, &msg);
+	pci_write_msi_msg(*irq_p, &msg);
 
 	return 0;
 
arch/tile/kernel/pci_gx.c +1 -1
Index: tip/arch/tile/kernel/pci_gx.c
===================================================================
@@ -1590,7 +1590,7 @@ int arch_setup_msi_irq(struct pci_dev *p
 	msg.address_hi = msi_addr >> 32;
 	msg.address_lo = msi_addr & 0xffffffff;
 
-	write_msi_msg(irq, &msg);
+	pci_write_msi_msg(irq, &msg);
 	irq_set_chip_and_handler(irq, &tilegx_msi_chip, handle_level_irq);
 	irq_set_handler_data(irq, controller);
 
arch/x86/kernel/apic/io_apic.c +2 -2
Index: tip/arch/x86/kernel/apic/io_apic.c
===================================================================
@@ -3158,7 +3158,7 @@ msi_set_affinity(struct irq_data *data,
 	msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
 	msg.address_lo |= MSI_ADDR_DEST_ID(dest);
 
-	__write_msi_msg(data->msi_desc, &msg);
+	__pci_write_msi_msg(data->msi_desc, &msg);
 
 	return IRQ_SET_MASK_OK_NOCOPY;
 }
@@ -3196,7 +3196,7 @@ int setup_msi_irq(struct pci_dev *dev, s
 	 * MSI message denotes a contiguous group of IRQs, written for 0th IRQ.
 	 */
 	if (!irq_offset)
-		write_msi_msg(irq, &msg);
+		pci_write_msi_msg(irq, &msg);
 
 	setup_remapped_irq(irq, irq_cfg(irq), chip);
 
arch/x86/pci/xen.c +1 -1
Index: tip/arch/x86/pci/xen.c
===================================================================
@@ -240,7 +240,7 @@ static int xen_hvm_setup_msi_irqs(struct
 				goto error;
 			}
 			xen_msi_compose_msg(dev, pirq, &msg);
-			__write_msi_msg(msidesc, &msg);
+			__pci_write_msi_msg(msidesc, &msg);
 			dev_dbg(&dev->dev, "xen: msi bound to pirq=%d\n", pirq);
 		} else {
 			dev_dbg(&dev->dev,
drivers/irqchip/irq-armada-370-xp.c +1 -1
Index: tip/drivers/irqchip/irq-armada-370-xp.c
===================================================================
@@ -157,7 +157,7 @@ static int armada_370_xp_setup_msi_irq(s
 	msg.address_hi = 0;
 	msg.data = 0xf00 | (hwirq + 16);
 
-	write_msi_msg(virq, &msg);
+	pci_write_msi_msg(virq, &msg);
 	return 0;
 }
 
drivers/pci/host/pci-tegra.c +1 -1
Index: tip/drivers/pci/host/pci-tegra.c
===================================================================
@@ -1308,7 +1308,7 @@ static int tegra_msi_setup_irq(struct ms
 	msg.address_hi = 0;
 	msg.data = hwirq;
 
-	write_msi_msg(irq, &msg);
+	pci_write_msi_msg(irq, &msg);
 
 	return 0;
 }
drivers/pci/host/pcie-designware.c +1 -1
Index: tip/drivers/pci/host/pcie-designware.c
===================================================================
@@ -298,7 +298,7 @@ static int dw_msi_setup_irq(struct msi_c
 	else
 		msg.data = pos;
 
-	write_msi_msg(irq, &msg);
+	pci_write_msi_msg(irq, &msg);
 
 	return 0;
 }
drivers/pci/host/pcie-rcar.c +1 -1
Index: tip/drivers/pci/host/pcie-rcar.c
===================================================================
@@ -647,7 +647,7 @@ static int rcar_msi_setup_irq(struct msi
 	msg.address_hi = rcar_pci_read_reg(pcie, PCIEMSIAUR);
 	msg.data = hwirq;
 
-	write_msi_msg(irq, &msg);
+	pci_write_msi_msg(irq, &msg);
 
 	return 0;
 }
drivers/pci/host/pcie-xilinx.c +1 -1
Index: tip/drivers/pci/host/pcie-xilinx.c
===================================================================
@@ -374,7 +374,7 @@ static int xilinx_pcie_msi_setup_irq(str
 	msg.address_lo = msg_addr;
 	msg.data = irq;
 
-	write_msi_msg(irq, &msg);
+	pci_write_msi_msg(irq, &msg);
 
 	return 0;
 }
drivers/pci/msi.c +5 -6
Index: tip/drivers/pci/msi.c
===================================================================
@@ -26,7 +26,6 @@ static int pci_msi_enable = 1;
 
 #define msix_table_size(flags)	((flags & PCI_MSIX_FLAGS_QSIZE) + 1)
 
-
 /* Arch hooks */
 
 int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
@@ -114,7 +113,7 @@ static void default_restore_msi_irq(stru
 	}
 
 	if (entry)
-		__write_msi_msg(entry, &entry->msg);
+		__pci_write_msi_msg(entry, &entry->msg);
 }
 
 void __weak arch_restore_msi_irqs(struct pci_dev *dev)
@@ -272,7 +271,7 @@ void __pci_read_msi_msg(struct msi_desc
 	}
 }
 
-void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
+void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
 {
 	if (entry->dev->current_state != PCI_D0) {
 		/* Don't touch the hardware now */
@@ -309,13 +308,13 @@ void __write_msi_msg(struct msi_desc *en
 	entry->msg = *msg;
 }
 
-void write_msi_msg(unsigned int irq, struct msi_msg *msg)
+void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg)
 {
 	struct msi_desc *entry = irq_get_msi_desc(irq);
 
-	__write_msi_msg(entry, msg);
+	__pci_write_msi_msg(entry, msg);
 }
-EXPORT_SYMBOL_GPL(write_msi_msg);
+EXPORT_SYMBOL_GPL(pci_write_msi_msg);
 
 static void free_msi_irqs(struct pci_dev *dev)
 {
drivers/vfio/pci/vfio_pci_intrs.c +1 -1
Index: tip/drivers/vfio/pci/vfio_pci_intrs.c
===================================================================
@@ -560,7 +560,7 @@ static int vfio_msi_set_vector_signal(st
 		struct msi_msg msg;
 
 		get_cached_msi_msg(irq, &msg);
-		write_msi_msg(irq, &msg);
+		pci_write_msi_msg(irq, &msg);
 	}
 
 	ret = request_irq(irq, vfio_msihandler, 0,
include/linux/msi.h +2 -2
Index: tip/include/linux/msi.h
===================================================================
@@ -16,9 +16,7 @@ struct msi_desc;
 void mask_msi_irq(struct irq_data *data);
 void unmask_msi_irq(struct irq_data *data);
 void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
-void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
 void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg);
-void write_msi_msg(unsigned int irq, struct msi_msg *msg);
 
 struct msi_desc {
 	struct {
@@ -48,6 +46,8 @@ struct msi_desc {
 
 #ifdef CONFIG_PCI_MSI
 void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
+void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
+void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg);
 #endif
 
 /*
#87 lore raw

Re: [patch 15/16] PCI/MSI: Rename write_msi_msg() to pci_write_msi_msg()

Hi Thomas,
Could you please help to fold this into patch 15?
Regards!
Gerry
PCI, MSI: Replace write_msi_msg() with pci_write_msi_msg()

Commit e5f1a59c4e12 "PCI/MSI: Rename write_msi_msg() to pci_write_msi_msg()" missed one instance of write_msi_msg() in file arch/mips/pci/msi-xlp.c.

---
 arch/mips/pci/msi-xlp.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/mips/pci/msi-xlp.c +0 -0
index 262001ee1554..75bceb99e9a6 100644
@@ -446,7 +446,7 @@ static int xlp_setup_msix(uint64_t lnkbase, int

node, int link,

        if (ret < 0)
                return ret;

- write_msi_msg(xirq, &msg);

+       pci_write_msi_msg(xirq, &msg);
        return 0;

}

--

On 2014/11/12 21:43, Thomas Gleixner wrote:

#88 lore raw

PATCH 16/16 PCI/MSI: Enhance core to support hierarchy irqdomain

In reply to Thomas Gleixner

From: Jiang Liu <[email protected]>

Enhance PCI MSI core to support hierarchy irqdomain, so the common code can be shared across architectures.

[ tglx: Extracted and combined from several patches ]

Cc Bjorn Helgaas <[email protected]>
Cc Grant Likely <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Yingjoe Chen <[email protected]>
Cc Yijing Wang <[email protected]>
---
 drivers/pci/Kconfig |    5 ++++
 drivers/pci/msi.c   |   62 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/msi.h |    8 ++++++
 3 files changed, 75 insertions(+)
drivers/pci/Kconfig +5 -0
Index: tip/drivers/pci/Kconfig
===================================================================
@@ -17,6 +17,11 @@ config PCI_MSI
 
 	   If you don't know what to do here, say Y.
 
+config PCI_MSI_IRQ_DOMAIN
+	bool
+	depends on PCI_MSI
+	select GENERIC_MSI_IRQ_DOMAIN
+
 config PCI_DEBUG
 	bool "PCI Debugging"
 	depends on PCI && DEBUG_KERNEL
drivers/pci/msi.c +62 -0

71 lines not on this page · raw message

include/linux/msi.h +8 -0
Index: tip/include/linux/msi.h
===================================================================
@@ -112,4 +112,12 @@ struct msi_domain_info *msi_get_domain_i
 
 #endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */
 
+#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
+void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg);
+int pci_msi_domain_alloc_irqs(struct irq_domain *domain, int type,
+			      struct pci_dev *dev, void *arg);
+irq_hw_number_t pci_msi_domain_calc_hwirq(struct pci_dev *dev,
+					  struct msi_desc *desc);
+#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
+
 #endif /* LINUX_MSI_H */
#89 lore raw

Re: [patch 16/16] PCI/MSI: Enhance core to support hierarchy irqdomain

Hi Thomas,

Quoted 54 lines · Thomas Gleixner

From: Jiang Liu <[email protected]>

Enhance PCI MSI core to support hierarchy irqdomain, so the common code can be shared across architectures.

[ tglx: Extracted and combined from several patches ]

Cc Bjorn Helgaas <[email protected]>
Cc Grant Likely <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Yingjoe Chen <[email protected]>
Cc Yijing Wang <[email protected]>
---
 drivers/pci/Kconfig |    5 ++++
 drivers/pci/msi.c   |   62 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/msi.h |    8 ++++++
 3 files changed, 75 insertions(+)

Index: tip/drivers/pci/Kconfig
===================================================================

drivers/pci/Kconfig +5 -0
@@ -17,6 +17,11 @@ config PCI_MSI
 
 	   If you don't know what to do here, say Y.
 
+config PCI_MSI_IRQ_DOMAIN
+	bool
+	depends on PCI_MSI
+	select GENERIC_MSI_IRQ_DOMAIN
+
 config PCI_DEBUG
 	bool "PCI Debugging"
 	depends on PCI && DEBUG_KERNEL

Index: tip/drivers/pci/msi.c
===================================================================

drivers/pci/msi.c +3 -0
@@ -19,6 +19,7 @@
 #include <linux/errno.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/irqdomain.h>
 
 #include "pci.h"
 
@@ -1072,3 +1073,64 @@ int pci_enable_msix_range(struct pci_dev
 	return nvec;
 }
 EXPORT_SYMBOL(pci_enable_msix_range);
+
+#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN

drivers/pci/msi.c int pci_enable_msix_range(struct pci_dev · line 1087

Quoted 10 lines
drivers/pci/msi.c +10 -0
+void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg)
+{
+	struct msi_desc *desc = irq_data->msi_desc;
+
+	/*
+	 * MSI-X message is written per-IRQ.
+	 * MSI message denotes a contiguous group of IRQs, written for 0th IRQ.
+	 */
+	if (desc->irq == irq_data->irq)
+		pci_write_msi_msg(desc, msg);

My compiler barks at this. Shouldn't that be either:

		pci_write_msi_msg(desc->irq, msg);
or
		__pci_write_msi_msg(desc, msg);

?

Thanks,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#90 lore raw

Re: [patch 16/16] PCI/MSI: Enhance core to support hierarchy irqdomain

Quoted 13 lines · Marc Zyngier

drivers/pci/msi.c int pci_enable_msix_range(struct pci_dev · line 1087

Quoted 11 lines
drivers/pci/msi.c +11 -0
+#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
+void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg)
+{
+	struct msi_desc *desc = irq_data->msi_desc;
+
+	/*
+	 * MSI-X message is written per-IRQ.
+	 * MSI message denotes a contiguous group of IRQs, written for 0th IRQ.
+	 */
+	if (desc->irq == irq_data->irq)
+		pci_write_msi_msg(desc, msg);

My compiler barks at this. Shouldn't that be either:

Quoted 3 lines
		pci_write_msi_msg(desc->irq, msg);
or
		__pci_write_msi_msg(desc, msg);

The latter.

Thanks,

tglx

#91 lore raw
In reply to Thomas Gleixner
Quoted 7 lines · Thomas Gleixner

This is an extract from Jiangs various patch series which only contains the generic irq and MSI parts w/o the x86 specific modifications.

This is roughly what I plan to merge into the generic irq core, so the various outstanding patches (irqchip/x86/...) can be based on this.

Quoted 6 lines

It's available from git as well:

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/irqdomain

Note, that branch is not yet exposed to linux-next and subject to modifications including rebasing.

Hi,

I checked the branch and it is just plain v3.18-rc4. Is this branch ready now?

https://git.kernel.org/cgit/linux/kernel/git/tip/tip.git/log/?h=irq/irqdomain

Joe.C

#92 lore raw
Quoted 15 lines · Yingjoe Chen
Quoted 7 lines · Thomas Gleixner

This is an extract from Jiangs various patch series which only contains the generic irq and MSI parts w/o the x86 specific modifications.

This is roughly what I plan to merge into the generic irq core, so the various outstanding patches (irqchip/x86/...) can be based on this.

Quoted 6 lines

It's available from git as well:

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/irqdomain

Note, that branch is not yet exposed to linux-next and subject to modifications including rebasing.

Quoted 6 lines

Hi,

I checked the branch and it is just plain v3.18-rc4. Is this branch ready now?

https://git.kernel.org/cgit/linux/kernel/git/tip/tip.git/log/?h=irq/irqdomain

It's in the master repository so it should be propagated towards the public interfaces soon.

Thanks,

tglx

#93 lore raw
In reply to Thomas Gleixner

Hi Thomas, Jiang,

I finally get some time on this, hopefully not too late... In brief, I like the part of stacked domain, and have some opinions on the part of refactoring MSI. Please check inline comments.

Regards,
Abel

Quoted 75 lines · Thomas Gleixner

This is an extract from Jiangs various patch series which only contains the generic irq and MSI parts w/o the x86 specific modifications.

This is roughly what I plan to merge into the generic irq core, so the various outstanding patches (irqchip/x86/...) can be based on this.

It's available from git as well:

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/irqdomain

Note, that branch is not yet exposed to linux-next and subject to modifications including rebasing.

Can all involved parties please have a close look and retest their patches on top of this?

Jiang, you need to merge that into x86/apic for rebasing your series.

Thanks,

tglx
----

 Documentation/IRQ-domain.txt           |   71 +++++
 arch/arm/mach-iop13xx/msi.c            |    2 
 arch/ia64/kernel/msi_ia64.c            |    4 
 arch/ia64/sn/kernel/msi_sn.c           |    4 
 arch/mips/pci/msi-octeon.c             |    2 
 arch/mips/pci/msi-xlp.c                |    2 
 arch/mips/pci/pci-xlr.c                |    2 
 arch/powerpc/platforms/cell/axon_msi.c |    2 
 arch/powerpc/platforms/powernv/pci.c   |    2 
 arch/powerpc/platforms/pseries/msi.c   |    2 
 arch/powerpc/sysdev/fsl_msi.c          |    2 
 arch/powerpc/sysdev/mpic_pasemi_msi.c  |    2 
 arch/powerpc/sysdev/mpic_u3msi.c       |    2 
 arch/powerpc/sysdev/ppc4xx_hsta_msi.c  |    2 
 arch/powerpc/sysdev/ppc4xx_msi.c       |    2 
 arch/s390/pci/pci.c                    |    2 
 arch/sparc/kernel/pci_msi.c            |    2 
 arch/tile/kernel/pci_gx.c              |    2 
 arch/x86/kernel/apic/io_apic.c         |    4 
 arch/x86/pci/xen.c                     |    4 
 drivers/iommu/irq_remapping.c          |    8 
 drivers/irqchip/irq-armada-370-xp.c    |    2 
 drivers/pci/Kconfig                    |    6 
 drivers/pci/host/pci-tegra.c           |    2 
 drivers/pci/host/pcie-designware.c     |    2 
 drivers/pci/host/pcie-rcar.c           |    2 
 drivers/pci/host/pcie-xilinx.c         |    2 
 drivers/pci/msi.c                      |  150 ++++++-----
 drivers/vfio/pci/vfio_pci_intrs.c      |    2 
 include/linux/irq.h                    |   33 ++
 include/linux/irqdomain.h              |   91 +++++++
 include/linux/irqhandler.h             |   14 +
 include/linux/msi.h                    |   53 +++-
 kernel/irq/Kconfig                     |   15 +
 kernel/irq/Makefile                    |    1 
 kernel/irq/chip.c                      |   37 ++
 kernel/irq/irqdomain.c                 |  418 +++++++++++++++++++++++++++++++--
 kernel/irq/manage.c                    |    2 
 kernel/irq/msi.c                       |  132 ++++++++++
 39 files changed, 959 insertions(+), 130 deletions(-)

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
.