diff options
-rw-r--r-- | arch/x86/include/asm/hw_irq.h | 37 | ||||
-rw-r--r-- | arch/x86/include/asm/irq_remapping.h | 36 | ||||
-rw-r--r-- | drivers/iommu/irq_remapping.c | 50 | ||||
-rw-r--r-- | drivers/iommu/irq_remapping.h | 10 |
4 files changed, 132 insertions, 1 deletions
diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h index 5b951ac56aa1..75a97a5bbfa8 100644 --- a/arch/x86/include/asm/hw_irq.h +++ b/arch/x86/include/asm/hw_irq.h @@ -113,10 +113,47 @@ struct irq_2_irte { #ifdef CONFIG_X86_LOCAL_APIC struct irq_data; struct irq_domain; +struct pci_dev; +struct msi_desc; + +enum irq_alloc_type { + X86_IRQ_ALLOC_TYPE_IOAPIC = 1, + X86_IRQ_ALLOC_TYPE_HPET, + X86_IRQ_ALLOC_TYPE_MSI, + X86_IRQ_ALLOC_TYPE_MSIX, +}; struct irq_alloc_info { + enum irq_alloc_type type; u32 flags; const struct cpumask *mask; /* CPU mask for vector allocation */ + union { + int unused; +#ifdef CONFIG_HPET_TIMER + struct { + int hpet_id; + int hpet_index; + void *hpet_data; + }; +#endif +#ifdef CONFIG_PCI_MSI + struct { + struct pci_dev *msi_dev; + irq_hw_number_t msi_hwirq; + }; +#endif +#ifdef CONFIG_X86_IO_APIC + struct { + int ioapic_id; + int ioapic_pin; + int ioapic_node; + u32 ioapic_trigger : 1; + u32 ioapic_polarity : 1; + u32 ioapic_valid : 1; + struct IO_APIC_route_entry *ioapic_entry; + }; +#endif + }; }; enum { diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h index 86d897bc15dd..0cd6195cc375 100644 --- a/arch/x86/include/asm/irq_remapping.h +++ b/arch/x86/include/asm/irq_remapping.h @@ -22,6 +22,8 @@ #ifndef __X86_IRQ_REMAPPING_H #define __X86_IRQ_REMAPPING_H +#include <linux/irqdomain.h> +#include <asm/hw_irq.h> #include <asm/io_apic.h> struct IO_APIC_route_entry; @@ -30,6 +32,7 @@ struct irq_chip; struct msi_msg; struct pci_dev; struct irq_cfg; +struct irq_alloc_info; #ifdef CONFIG_IRQ_REMAP @@ -56,6 +59,25 @@ extern bool setup_remapped_irq(int irq, void irq_remap_modify_chip_defaults(struct irq_chip *chip); +extern struct irq_domain * +irq_remapping_get_ir_irq_domain(struct irq_alloc_info *info); +extern struct irq_domain * +irq_remapping_get_irq_domain(struct irq_alloc_info *info); +extern void irq_remapping_print_chip(struct irq_data *data, struct seq_file *p); + +/* Create PCI MSI/MSIx irqdomain, use @parent as the parent irqdomain. */ +static inline struct irq_domain * +arch_create_msi_irq_domain(struct irq_domain *parent) +{ + return NULL; +} + +/* Get parent irqdomain for interrupt remapping irqdomain */ +static inline struct irq_domain *arch_get_ir_parent_domain(void) +{ + return x86_vector_domain; +} + #else /* CONFIG_IRQ_REMAP */ static inline void set_irq_remapping_broken(void) { } @@ -97,6 +119,20 @@ static inline bool setup_remapped_irq(int irq, { return false; } + +static inline struct irq_domain * +irq_remapping_get_ir_irq_domain(struct irq_alloc_info *info) +{ + return NULL; +} + +static inline struct irq_domain * +irq_remapping_get_irq_domain(struct irq_alloc_info *info) +{ + return NULL; +} + +#define irq_remapping_print_chip NULL #endif /* CONFIG_IRQ_REMAP */ extern int dmar_alloc_hwirq(void); diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index 5617150fd8fb..c306421d86c1 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -345,7 +345,7 @@ void panic_if_irq_remap(const char *msg) panic(msg); } -static void ir_ack_apic_edge(struct irq_data *data) +void ir_ack_apic_edge(struct irq_data *data) { ack_APIC_irq(); } @@ -356,6 +356,19 @@ static void ir_ack_apic_level(struct irq_data *data) eoi_ioapic_irq(data->irq, irqd_cfg(data)); } +void irq_remapping_print_chip(struct irq_data *data, struct seq_file *p) +{ + /* + * Assume interrupt is remapped if the parent irqdomain isn't the + * vector domain, which is true for MSI, HPET and IOAPIC on x86 + * platforms. + */ + if (data->domain && data->domain->parent != arch_get_ir_parent_domain()) + seq_printf(p, " IR-%s", data->chip->name); + else + seq_printf(p, " %s", data->chip->name); +} + static void ir_print_prefix(struct irq_data *data, struct seq_file *p) { seq_printf(p, " IR-%s", data->chip->name); @@ -377,3 +390,38 @@ bool setup_remapped_irq(int irq, struct irq_cfg *cfg, struct irq_chip *chip) irq_remap_modify_chip_defaults(chip); return true; } + +/** + * irq_remapping_get_ir_irq_domain - Get the irqdomain associated with the IOMMU + * device serving request @info + * @info: interrupt allocation information, used to identify the IOMMU device + * + * It's used to get parent irqdomain for HPET and IOAPIC irqdomains. + * Returns pointer to IRQ domain, or NULL on failure. + */ +struct irq_domain * +irq_remapping_get_ir_irq_domain(struct irq_alloc_info *info) +{ + if (!remap_ops || !remap_ops->get_ir_irq_domain) + return NULL; + + return remap_ops->get_ir_irq_domain(info); +} + +/** + * irq_remapping_get_irq_domain - Get the irqdomain serving the request @info + * @info: interrupt allocation information, used to identify the IOMMU device + * + * There will be one PCI MSI/MSIX irqdomain associated with each interrupt + * remapping device, so this interface is used to retrieve the PCI MSI/MSIX + * irqdomain serving request @info. + * Returns pointer to IRQ domain, or NULL on failure. + */ +struct irq_domain * +irq_remapping_get_irq_domain(struct irq_alloc_info *info) +{ + if (!remap_ops || !remap_ops->get_irq_domain) + return NULL; + + return remap_ops->get_irq_domain(info); +} diff --git a/drivers/iommu/irq_remapping.h b/drivers/iommu/irq_remapping.h index 7c70cc29ffe6..3e109b1ea688 100644 --- a/drivers/iommu/irq_remapping.h +++ b/drivers/iommu/irq_remapping.h @@ -30,6 +30,8 @@ struct irq_data; struct cpumask; struct pci_dev; struct msi_msg; +struct irq_domain; +struct irq_alloc_info; extern int irq_remap_broken; extern int disable_sourceid_checking; @@ -77,11 +79,19 @@ struct irq_remap_ops { /* Setup interrupt remapping for an HPET MSI */ int (*alloc_hpet_msi)(unsigned int, unsigned int); + + /* Get the irqdomain associated the IOMMU device */ + struct irq_domain *(*get_ir_irq_domain)(struct irq_alloc_info *); + + /* Get the MSI irqdomain associated with the IOMMU device */ + struct irq_domain *(*get_irq_domain)(struct irq_alloc_info *); }; extern struct irq_remap_ops intel_irq_remap_ops; extern struct irq_remap_ops amd_iommu_irq_ops; +extern void ir_ack_apic_edge(struct irq_data *data); + #else /* CONFIG_IRQ_REMAP */ #define irq_remapping_enabled 0 |