* [Patch Part2 v3 09/24] x86, dmar: Use new irqdomain interfaces to allocate/free IRQ
[not found] ` <1414484803-10311-1-git-send-email-jiang.liu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
@ 2014-10-28 8:26 ` Jiang Liu
2014-10-28 8:26 ` [Patch Part2 v3 10/24] x86: irq_remapping: Introduce new interfaces to support hierarchy irqdomain Jiang Liu
` (8 subsequent siblings)
9 siblings, 0 replies; 17+ messages in thread
From: Jiang Liu @ 2014-10-28 8:26 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Thomas Gleixner, Ingo Molnar,
H. Peter Anvin, Rafael J. Wysocki, Bjorn Helgaas, Randy Dunlap,
Yinghai Lu, Borislav Petkov, Grant Likely, Marc Zyngier,
Yingjoe Chen, x86-DgEjT+Ai2ygdnm+yROfE0A, Joerg Roedel,
Matthias Brugger, Jiang Liu
Cc: Tony Luck, Greg Kroah-Hartman,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-pci-u79uwXL29TY76Z2rM5mHXA, Andrew Morton,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Use new irqdomain interfaces to allocate/free IRQ for DMAR and interrupt
remapping, so we could kill GENERIC_IRQ_LEGACY_ALLOC_HWIRQ later.
The private definition of irq_alloc_hwirqs()/irq_free_hwirqs() are
temporary solution, it will be removed once we have converted interrupt
remapping driver to use irqdomain framework.
Signed-off-by: Jiang Liu <jiang.liu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
---
arch/x86/include/asm/irq_remapping.h | 4 ++--
arch/x86/kernel/apic/msi.c | 10 ++++++++++
drivers/iommu/irq_remapping.c | 17 +++++++++++++++--
3 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h
index b7747c4c2cf2..230dde9b695e 100644
--- a/arch/x86/include/asm/irq_remapping.h
+++ b/arch/x86/include/asm/irq_remapping.h
@@ -103,7 +103,7 @@ static inline bool setup_remapped_irq(int irq,
}
#endif /* CONFIG_IRQ_REMAP */
-#define dmar_alloc_hwirq() irq_alloc_hwirq(-1)
-#define dmar_free_hwirq irq_free_hwirq
+extern int dmar_alloc_hwirq(void);
+extern void dmar_free_hwirq(int irq);
#endif /* __X86_IRQ_REMAPPING_H */
diff --git a/arch/x86/kernel/apic/msi.c b/arch/x86/kernel/apic/msi.c
index 7e45991c0e79..4bb2b583be7f 100644
--- a/arch/x86/kernel/apic/msi.c
+++ b/arch/x86/kernel/apic/msi.c
@@ -223,6 +223,16 @@ int arch_setup_dmar_msi(unsigned int irq)
"edge");
return 0;
}
+
+int dmar_alloc_hwirq(void)
+{
+ return irq_domain_alloc_irqs(NULL, 1, NUMA_NO_NODE, NULL);
+}
+
+void dmar_free_hwirq(int irq)
+{
+ irq_domain_free_irqs(irq, 1);
+}
#endif
/*
diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c
index e9fbd68db96e..63886bafed9f 100644
--- a/drivers/iommu/irq_remapping.c
+++ b/drivers/iommu/irq_remapping.c
@@ -6,6 +6,7 @@
#include <linux/msi.h>
#include <linux/irq.h>
#include <linux/pci.h>
+#include <linux/irqdomain.h>
#include <asm/hw_irq.h>
#include <asm/irq_remapping.h>
@@ -50,6 +51,18 @@ static void irq_remapping_disable_io_apic(void)
disconnect_bsp_APIC(0);
}
+#ifndef CONFIG_GENERIC_IRQ_LEGACY_ALLOC_HWIRQ
+static unsigned int irq_alloc_hwirqs(int cnt, int node)
+{
+ return irq_domain_alloc_irqs(NULL, -1, cnt, node, NULL);
+}
+
+static void irq_free_hwirqs(unsigned int from, int cnt)
+{
+ irq_domain_free_irqs(from, cnt);
+}
+#endif
+
static int do_setup_msi_irqs(struct pci_dev *dev, int nvec)
{
int ret, sub_handle, nvec_pow2, index = 0;
@@ -113,7 +126,7 @@ static int do_setup_msix_irqs(struct pci_dev *dev, int nvec)
list_for_each_entry(msidesc, &dev->msi_list, list) {
- irq = irq_alloc_hwirq(node);
+ irq = irq_alloc_hwirqs(1, node);
if (irq == 0)
return -1;
@@ -136,7 +149,7 @@ static int do_setup_msix_irqs(struct pci_dev *dev, int nvec)
return 0;
error:
- irq_free_hwirq(irq);
+ irq_free_hwirqs(irq, 1);
return ret;
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [Patch Part2 v3 10/24] x86: irq_remapping: Introduce new interfaces to support hierarchy irqdomain
[not found] ` <1414484803-10311-1-git-send-email-jiang.liu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2014-10-28 8:26 ` [Patch Part2 v3 09/24] x86, dmar: Use new irqdomain interfaces to allocate/free IRQ Jiang Liu
@ 2014-10-28 8:26 ` Jiang Liu
2014-10-28 8:26 ` [Patch Part2 v3 11/24] iommu/vt-d: Change prototypes to prepare for enabling " Jiang Liu
` (7 subsequent siblings)
9 siblings, 0 replies; 17+ messages in thread
From: Jiang Liu @ 2014-10-28 8:26 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Thomas Gleixner, Ingo Molnar,
H. Peter Anvin, Rafael J. Wysocki, Bjorn Helgaas, Randy Dunlap,
Yinghai Lu, Borislav Petkov, Grant Likely, Marc Zyngier,
Yingjoe Chen, x86-DgEjT+Ai2ygdnm+yROfE0A, Joerg Roedel,
Matthias Brugger, Jiang Liu
Cc: Tony Luck, Greg Kroah-Hartman,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-pci-u79uwXL29TY76Z2rM5mHXA, Andrew Morton,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Introduce new interfaces for interrupt remapping drivers to support
hierarchy irqdomain:
1) irq_remapping_get_ir_irq_domain(): get irqdomain associated with an
interrupt remapping unit. IOAPIC/HPET drivers use this interface to
get parent interrupt remapping irqdomain.
2) irq_remapping_get_irq_domain(): get irqdomain for an IRQ allocation.
This is mainly used to support MSI irqdomain. We must build one MSI
irqdomain for each interrupt remapping unit. MSI driver calls this
interface to get MSI irqdomain associated with an IR irqdomain which
manages the PCI devices.
3) irq_remapping_get_ioapic_entry(): get IOAPIC entry content rewritten
by the interrupt remapping driver for remapped IOAPIC interrupt.
4) irq_remapping_get_msi_entry(): get MSI/HPET entry content rewritten
by the interrupt remapping driver for remapped MSI/HPET interrupt.
Architecture specific needs to implement two hooks:
1) arch_get_ir_parent_domain(): get parent irqdomain for IR irqdomain,
which is x86_vector_domain on x86 platforms.
2) arch_create_msi_irq_domain(): create an MSI irqdomain associated with
the interrupt remapping unit.
We also add follwing callbacks into struct irq_remap_ops:
struct irq_domain *(*get_ir_irq_domain)(struct irq_alloc_info *);
struct irq_domain *(*get_irq_domain)(struct irq_alloc_info *);
int (*get_ioapic_entry)(struct irq_data *,
struct IR_IO_APIC_route_entry *);
int (*get_msi_entry)(struct irq_data *, struct msi_msg *);
Once all clients of IR have been converted to new hierarchy irqdomain
interfaces, we will:
1) Remove set_ioapic_entry, set_affinity, free_irq, compose_msi_msg,
msi_alloc_irq, msi_setup_irq, setup_hpet_msi from struct remap_osp
2) Kill setup_ioapic_remapped_entry, free_remapped_irq,
compose_remapped_msi_msg, setup_hpet_msi_remapped, setup_remapped_irq.
3) Simplify x86_io_apic_ops and x86_msi.
We could achieve a much more clear architecture with all these changes
applied.
Signed-off-by: Jiang Liu <jiang.liu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
---
arch/x86/include/asm/hw_irq.h | 36 +++++++++++++++-
arch/x86/include/asm/irq_remapping.h | 74 ++++++++++++++++++++++++++++++++
drivers/iommu/irq_remapping.c | 78 +++++++++++++++++++++++++++++++++-
drivers/iommu/irq_remapping.h | 17 ++++++++
4 files changed, 203 insertions(+), 2 deletions(-)
diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
index 1300702adb1e..545460d470bd 100644
--- a/arch/x86/include/asm/hw_irq.h
+++ b/arch/x86/include/asm/hw_irq.h
@@ -113,9 +113,43 @@ 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 {
- const struct cpumask *mask; /* CPU mask for vector allocation */
+ const struct cpumask *mask; /* CPU mask for vector allocation */
+ enum irq_alloc_type type;
+ 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;
+ struct msi_desc *msi_desc;
+ };
+#endif
+#ifdef CONFIG_X86_IO_APIC
+ struct {
+ int ioapic_id;
+ int ioapic_pin;
+ u32 ioapic_trigger : 1;
+ u32 ioapic_polarity : 1;
+ };
+#endif
+ };
};
struct irq_cfg {
diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h
index 230dde9b695e..f5f624529386 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
@@ -58,6 +61,42 @@ 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 int irq_remapping_get_ioapic_entry(struct irq_data *irq_data,
+ struct IR_IO_APIC_route_entry *entry);
+extern int irq_remapping_get_msi_entry(struct irq_data *irq_data,
+ struct msi_msg *entry);
+extern void irq_remapping_print_chip(struct irq_data *data, struct seq_file *p);
+
+/*
+ * Create MSI/MSIx irqdomain for interrupt remapping device, use @parent as
+ * 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;
+}
+
+static inline void irq_remapping_domain_set_remapped(struct irq_domain *domain)
+{
+ domain->flags |= IRQ_DOMAIN_FLAG_ARCH1;
+}
+
+static inline bool irq_remapping_domain_is_remapped(struct irq_domain *domain)
+{
+ return domain->flags & IRQ_DOMAIN_FLAG_ARCH1;
+}
+
#else /* CONFIG_IRQ_REMAP */
static inline void setup_irq_remapping_ops(void) { }
@@ -101,6 +140,41 @@ 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;
+}
+
+static inline int irq_remapping_get_ioapic_entry(struct irq_data *irq_data,
+ struct IR_IO_APIC_route_entry *entry)
+{
+ return -ENOSYS;
+}
+
+static inline int irq_remapping_get_msi_entry(struct irq_data *irq_data,
+ struct msi_msg *entry)
+{
+ return -ENOSYS;
+}
+
+static inline void irq_remapping_domain_set_remapped(struct irq_domain *domain)
+{
+}
+
+static inline bool irq_remapping_domain_is_remapped(struct irq_domain *domain)
+{
+ return false;
+}
+
+#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 63886bafed9f..3a7f62c8becb 100644
--- a/drivers/iommu/irq_remapping.c
+++ b/drivers/iommu/irq_remapping.c
@@ -377,7 +377,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();
}
@@ -388,6 +388,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);
@@ -409,3 +422,66 @@ 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 the IOMMU
+ * device serving @info
+ * @info: interrupt allocation information, used to find the IOMMU device
+ *
+ * It's used to get parent irqdomain for HPET and IOAPIC domains.
+ * 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 MSI interrupt
+ * @info: interrupt allocation information, used to find the IOMMU device
+ *
+ * It's used to get irqdomain for MSI/MSIx interrupt allocation.
+ * 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);
+}
+
+/**
+ * irq_remapping_get_ioapic_entry - Get IOAPIC entry content rewritten by
+ * interrupt remapping driver
+ * @irq_data: irq_data associated with interrupt remapping irqdomain
+ * @entry: host returned data
+ *
+ * Caller must make sure that the interrupt is remapped.
+ * Return 0 on success, otherwise return error code
+ */
+int irq_remapping_get_ioapic_entry(struct irq_data *irq_data,
+ struct IR_IO_APIC_route_entry *entry)
+{
+ return remap_ops->get_ioapic_entry(irq_data, entry);
+}
+
+/**
+ * irq_remapping_get_ioapic_entry - Get MSI data rewritten by interrupt
+ * remapping driver
+ * @irq_data: irq_data associated with interrupt remapping irqdomain
+ * @entry: host returned data
+ *
+ * Caller must make sure that the interrupt is remapped.
+ * Return 0 on success, otherwise return error code
+ */
+int irq_remapping_get_msi_entry(struct irq_data *irq_data,
+ struct msi_msg *entry)
+{
+ return remap_ops->get_msi_entry(irq_data, entry);
+}
diff --git a/drivers/iommu/irq_remapping.h b/drivers/iommu/irq_remapping.h
index fde250f86e60..fd0270b7a351 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 disable_irq_remap;
extern int irq_remap_broken;
@@ -81,11 +83,26 @@ 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 *);
+
+ /* Get IOAPIC entry content rewritten by interrupt remapping driver */
+ int (*get_ioapic_entry)(struct irq_data *,
+ struct IR_IO_APIC_route_entry *);
+
+ /* Get MSI data rewritten by interrupt remapping driver */
+ int (*get_msi_entry)(struct irq_data *, struct msi_msg *);
};
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
--
1.7.10.4
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [Patch Part2 v3 11/24] iommu/vt-d: Change prototypes to prepare for enabling hierarchy irqdomain
[not found] ` <1414484803-10311-1-git-send-email-jiang.liu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2014-10-28 8:26 ` [Patch Part2 v3 09/24] x86, dmar: Use new irqdomain interfaces to allocate/free IRQ Jiang Liu
2014-10-28 8:26 ` [Patch Part2 v3 10/24] x86: irq_remapping: Introduce new interfaces to support hierarchy irqdomain Jiang Liu
@ 2014-10-28 8:26 ` Jiang Liu
2014-10-28 8:26 ` [Patch Part2 v3 12/24] iommu/vt-d: Enhance Intel IR driver to suppport " Jiang Liu
` (6 subsequent siblings)
9 siblings, 0 replies; 17+ messages in thread
From: Jiang Liu @ 2014-10-28 8:26 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Thomas Gleixner, Ingo Molnar,
H. Peter Anvin, Rafael J. Wysocki, Bjorn Helgaas, Randy Dunlap,
Yinghai Lu, Borislav Petkov, Grant Likely, Marc Zyngier,
Yingjoe Chen, Joerg Roedel, Matthias Brugger
Cc: Tony Luck, Greg Kroah-Hartman, x86-DgEjT+Ai2ygdnm+yROfE0A,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-pci-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, Jiang Liu,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Prepare for support hierarchy irqdomain by changing function prototypes,
should be no function changes.
Signed-off-by: Jiang Liu <jiang.liu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
---
drivers/iommu/intel_irq_remapping.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c
index fd181cf8a589..5acad492701e 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -82,10 +82,10 @@ static int get_irte(int irq, struct irte *entry)
return 0;
}
-static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
+static int alloc_irte(struct intel_iommu *iommu, int irq,
+ struct irq_2_iommu *irq_iommu, u16 count)
{
struct ir_table *table = iommu->ir_table;
- struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
struct irq_cfg *cfg = irq_cfg(irq);
unsigned int mask = 0;
unsigned long flags;
@@ -173,9 +173,9 @@ static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subha
return 0;
}
-static int modify_irte(int irq, struct irte *irte_modified)
+static int modify_irte(struct irq_2_iommu *irq_iommu,
+ struct irte *irte_modified)
{
- struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
struct intel_iommu *iommu;
unsigned long flags;
struct irte *irte;
@@ -242,7 +242,7 @@ static int clear_entries(struct irq_2_iommu *irq_iommu)
return 0;
iommu = irq_iommu->iommu;
- index = irq_iommu->irte_index + irq_iommu->sub_handle;
+ index = irq_iommu->irte_index;
start = iommu->ir_table->base + index;
end = start + (1 << irq_iommu->irte_mask);
@@ -937,7 +937,7 @@ static int intel_setup_ioapic_entry(int irq,
pr_warn("No mapping iommu for ioapic %d\n", ioapic_id);
index = -ENODEV;
} else {
- index = alloc_irte(iommu, irq, 1);
+ index = alloc_irte(iommu, irq, irq_2_iommu(irq), 1);
if (index < 0) {
pr_warn("Failed to allocate IRTE for ioapic %d\n",
ioapic_id);
@@ -953,7 +953,7 @@ static int intel_setup_ioapic_entry(int irq,
/* Set source-id of interrupt request */
set_ioapic_sid(&irte, ioapic_id);
- modify_irte(irq, &irte);
+ modify_irte(irq_2_iommu(irq), &irte);
apic_printk(APIC_VERBOSE, KERN_DEBUG "IOAPIC[%d]: "
"Set IRTE entry (P:%d FPD:%d Dst_Mode:%d "
@@ -1040,7 +1040,7 @@ intel_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
* Atomically updates the IRTE with the new destination, vector
* and flushes the interrupt entry cache.
*/
- modify_irte(irq, &irte);
+ modify_irte(irq_2_iommu(irq), &irte);
/*
* After this point, all the interrupts will start arriving
@@ -1076,7 +1076,7 @@ static void intel_compose_msi_msg(struct pci_dev *pdev,
else
set_hpet_sid(&irte, hpet_id);
- modify_irte(irq, &irte);
+ modify_irte(irq_2_iommu(irq), &irte);
msg->address_hi = MSI_ADDR_BASE_HI;
msg->data = sub_handle;
@@ -1103,7 +1103,7 @@ static int intel_msi_alloc_irq(struct pci_dev *dev, int irq, int nvec)
"Unable to map PCI %s to iommu\n", pci_name(dev));
index = -ENOENT;
} else {
- index = alloc_irte(iommu, irq, nvec);
+ index = alloc_irte(iommu, irq, irq_2_iommu(irq), nvec);
if (index < 0) {
printk(KERN_ERR
"Unable to allocate %d IRTE for PCI %s\n",
@@ -1147,7 +1147,7 @@ static int intel_alloc_hpet_msi(unsigned int irq, unsigned int id)
down_read(&dmar_global_lock);
iommu = map_hpet_to_ir(id);
if (iommu) {
- index = alloc_irte(iommu, irq, 1);
+ index = alloc_irte(iommu, irq, irq_2_iommu(irq), 1);
if (index >= 0)
ret = 0;
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [Patch Part2 v3 12/24] iommu/vt-d: Enhance Intel IR driver to suppport hierarchy irqdomain
[not found] ` <1414484803-10311-1-git-send-email-jiang.liu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
` (2 preceding siblings ...)
2014-10-28 8:26 ` [Patch Part2 v3 11/24] iommu/vt-d: Change prototypes to prepare for enabling " Jiang Liu
@ 2014-10-28 8:26 ` Jiang Liu
2014-10-28 8:26 ` [Patch Part2 v3 13/24] iommu/amd: Enhance AMD " Jiang Liu
` (5 subsequent siblings)
9 siblings, 0 replies; 17+ messages in thread
From: Jiang Liu @ 2014-10-28 8:26 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Thomas Gleixner, Ingo Molnar,
H. Peter Anvin, Rafael J. Wysocki, Bjorn Helgaas, Randy Dunlap,
Yinghai Lu, Borislav Petkov, Grant Likely, Marc Zyngier,
Yingjoe Chen, Joerg Roedel, David Woodhouse, Matthias Brugger
Cc: Tony Luck, Greg Kroah-Hartman, x86-DgEjT+Ai2ygdnm+yROfE0A,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-pci-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, Jiang Liu,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Enhance Intel interrupt remapping driver to support hierarchy irqdomain,
it will simplify the code eventually. It also implements intel_ir_chip
to support stacked irq_chip.
Signed-off-by: Jiang Liu <jiang.liu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
---
drivers/iommu/intel_irq_remapping.c | 356 +++++++++++++++++++++++++++++++++--
include/linux/intel-iommu.h | 4 +
2 files changed, 342 insertions(+), 18 deletions(-)
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c
index 5acad492701e..fdaa15026909 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -8,6 +8,7 @@
#include <linux/irq.h>
#include <linux/intel-iommu.h>
#include <linux/acpi.h>
+#include <linux/irqdomain.h>
#include <asm/io_apic.h>
#include <asm/smp.h>
#include <asm/cpu.h>
@@ -31,6 +32,15 @@ struct hpet_scope {
unsigned int devfn;
};
+struct intel_ir_data {
+ struct irq_2_iommu irq_2_iommu;
+ struct irte irte_entry;
+ union {
+ struct msi_msg msi_entry;
+ struct IR_IO_APIC_route_entry ioapic_entry;
+ };
+};
+
#define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0)
#define IRTE_DEST(dest) ((x2apic_mode) ? dest : dest << 8)
@@ -50,6 +60,7 @@ static int ir_ioapic_num, ir_hpet_num;
* the dmar_global_lock.
*/
static DEFINE_RAW_SPINLOCK(irq_2_ir_lock);
+static struct irq_domain_ops intel_ir_domain_ops;
static int __init parse_ioapics_under_ir(void);
@@ -263,7 +274,7 @@ static int free_irte(int irq)
unsigned long flags;
int rc;
- if (!irq_iommu)
+ if (!irq_iommu || irq_iommu->iommu == NULL)
return -1;
raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
@@ -480,36 +491,47 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu, int mode)
struct page *pages;
unsigned long *bitmap;
- ir_table = iommu->ir_table = kzalloc(sizeof(struct ir_table),
- GFP_ATOMIC);
-
- if (!iommu->ir_table)
+ ir_table = kzalloc(sizeof(struct ir_table), GFP_ATOMIC);
+ if (!ir_table)
return -ENOMEM;
pages = alloc_pages_node(iommu->node, GFP_ATOMIC | __GFP_ZERO,
INTR_REMAP_PAGE_ORDER);
-
if (!pages) {
pr_err("IR%d: failed to allocate pages of order %d\n",
iommu->seq_id, INTR_REMAP_PAGE_ORDER);
- kfree(iommu->ir_table);
- return -ENOMEM;
+ goto out_free_table;
}
bitmap = kcalloc(BITS_TO_LONGS(INTR_REMAP_TABLE_ENTRIES),
sizeof(long), GFP_ATOMIC);
if (bitmap == NULL) {
pr_err("IR%d: failed to allocate bitmap\n", iommu->seq_id);
- __free_pages(pages, INTR_REMAP_PAGE_ORDER);
- kfree(ir_table);
- return -ENOMEM;
+ goto out_free_pages;
+ }
+
+ iommu->ir_domain = irq_domain_add_linear(NULL, INTR_REMAP_TABLE_ENTRIES,
+ &intel_ir_domain_ops, iommu);
+ if (!iommu->ir_domain) {
+ pr_err("IR%d: failed to allocate irqdomain\n", iommu->seq_id);
+ goto out_free_bitmap;
}
+ iommu->ir_domain->parent = arch_get_ir_parent_domain();
+ iommu->ir_msi_domain = arch_create_msi_irq_domain(iommu->ir_domain);
ir_table->base = page_address(pages);
ir_table->bitmap = bitmap;
-
+ iommu->ir_table = ir_table;
iommu_set_irq_remapping(iommu, mode);
return 0;
+
+out_free_bitmap:
+ kfree(bitmap);
+out_free_pages:
+ __free_pages(pages, INTR_REMAP_PAGE_ORDER);
+out_free_table:
+ kfree(ir_table);
+ return -ENOMEM;
}
/*
@@ -1013,12 +1035,6 @@ intel_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
struct irte irte;
int err;
- if (!config_enabled(CONFIG_SMP))
- return -EINVAL;
-
- if (!cpumask_intersects(mask, cpu_online_mask))
- return -EINVAL;
-
if (get_irte(irq, &irte))
return -EBUSY;
@@ -1156,6 +1172,72 @@ static int intel_alloc_hpet_msi(unsigned int irq, unsigned int id)
return ret;
}
+static struct irq_domain *intel_get_ir_irq_domain(struct irq_alloc_info *info)
+{
+ struct intel_iommu *iommu = NULL;
+
+ if (!info)
+ return NULL;
+
+ switch (info->type) {
+ case X86_IRQ_ALLOC_TYPE_IOAPIC:
+ iommu = map_ioapic_to_ir(info->ioapic_id);
+ break;
+ case X86_IRQ_ALLOC_TYPE_HPET:
+ iommu = map_hpet_to_ir(info->hpet_id);
+ break;
+ case X86_IRQ_ALLOC_TYPE_MSI:
+ case X86_IRQ_ALLOC_TYPE_MSIX:
+ iommu = map_dev_to_ir(info->msi_dev);
+ break;
+ default:
+ BUG_ON(1);
+ break;
+ }
+
+ return iommu ? iommu->ir_domain : NULL;
+}
+
+static struct irq_domain *intel_get_irq_domain(struct irq_alloc_info *info)
+{
+ struct intel_iommu *iommu;
+
+ if (!info)
+ return NULL;
+
+ switch (info->type) {
+ case X86_IRQ_ALLOC_TYPE_MSI:
+ case X86_IRQ_ALLOC_TYPE_MSIX:
+ iommu = map_dev_to_ir(info->msi_dev);
+ if (iommu)
+ return iommu->ir_msi_domain;
+ break;
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static int intel_get_ioapic_entry(struct irq_data *irq_data,
+ struct IR_IO_APIC_route_entry *entry)
+{
+ struct intel_ir_data *ir_data = irq_data->chip_data;
+
+ *entry = ir_data->ioapic_entry;
+
+ return 0;
+}
+
+static int intel_get_msi_entry(struct irq_data *irq_data, struct msi_msg *msg)
+{
+ struct intel_ir_data *ir_data = irq_data->chip_data;
+
+ *msg = ir_data->msi_entry;
+
+ return 0;
+}
+
struct irq_remap_ops intel_irq_remap_ops = {
.supported = intel_irq_remapping_supported,
.prepare = dmar_table_init,
@@ -1170,4 +1252,242 @@ struct irq_remap_ops intel_irq_remap_ops = {
.msi_alloc_irq = intel_msi_alloc_irq,
.msi_setup_irq = intel_msi_setup_irq,
.alloc_hpet_msi = intel_alloc_hpet_msi,
+ .get_ir_irq_domain = intel_get_ir_irq_domain,
+ .get_irq_domain = intel_get_irq_domain,
+ .get_ioapic_entry = intel_get_ioapic_entry,
+ .get_msi_entry = intel_get_msi_entry,
+};
+
+/*
+ * Migrate the IO-APIC irq in the presence of intr-remapping.
+ *
+ * For both level and edge triggered, irq migration is a simple atomic
+ * update(of vector and cpu destination) of IRTE and flush the hardware cache.
+ *
+ * For level triggered, we eliminate the io-apic RTE modification (with the
+ * updated vector information), by using a virtual vector (io-apic pin number).
+ * Real vector that is used for interrupting cpu will be coming from
+ * the interrupt-remapping table entry.
+ *
+ * As the migration is a simple atomic update of IRTE, the same mechanism
+ * is used to migrate MSI irq's in the presence of interrupt-remapping.
+ */
+static int
+intel_ir_set_affinity(struct irq_data *data, const struct cpumask *mask,
+ bool force)
+{
+ struct intel_ir_data *ir_data = data->chip_data;
+ struct irte *irte = &ir_data->irte_entry;
+ struct irq_cfg *cfg = irqd_cfg(data);
+ struct irq_data *parent = data->parent_data;
+ int ret;
+
+ ret = parent->chip->irq_set_affinity(parent, mask, force);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Atomically updates the IRTE with the new destination, vector
+ * and flushes the interrupt entry cache.
+ */
+ irte->vector = cfg->vector;
+ irte->dest_id = IRTE_DEST(cfg->dest_apicid);
+ modify_irte(&ir_data->irq_2_iommu, irte);
+
+ /*
+ * After this point, all the interrupts will start arriving
+ * at the new destination. So, time to cleanup the previous
+ * vector allocation.
+ */
+ if (cfg->move_in_progress)
+ send_cleanup_vector(cfg);
+
+ return ret;
+}
+
+static struct irq_chip intel_ir_chip = {
+ .irq_ack = ir_ack_apic_edge,
+ .irq_set_affinity = intel_ir_set_affinity,
+};
+
+static void intel_irq_remapping_prepare_irte(struct intel_ir_data *data,
+ struct irq_cfg *irq_cfg,
+ struct irq_alloc_info *info,
+ int index, int sub_handle)
+{
+ struct irte *irte = &data->irte_entry;
+ struct IR_IO_APIC_route_entry *entry = &data->ioapic_entry;
+ struct msi_msg *msg = &data->msi_entry;
+
+ prepare_irte(irte, irq_cfg->vector, irq_cfg->dest_apicid);
+ switch (info->type) {
+ case X86_IRQ_ALLOC_TYPE_IOAPIC:
+ /* Set source-id of interrupt request */
+ set_ioapic_sid(irte, info->ioapic_id);
+ apic_printk(APIC_VERBOSE, KERN_DEBUG "IOAPIC[%d]: Set IRTE entry (P:%d FPD:%d Dst_Mode:%d Redir_hint:%d Trig_Mode:%d Dlvry_Mode:%X Avail:%X Vector:%02X Dest:%08X SID:%04X SQ:%X SVT:%X)\n",
+ info->ioapic_id, irte->present, irte->fpd,
+ irte->dst_mode, irte->redir_hint,
+ irte->trigger_mode, irte->dlvry_mode,
+ irte->avail, irte->vector, irte->dest_id,
+ irte->sid, irte->sq, irte->svt);
+
+ memset(entry, 0, sizeof(*entry));
+ entry->index2 = (index >> 15) & 0x1;
+ entry->zero = 0;
+ entry->format = 1;
+ entry->index = (index & 0x7fff);
+ /*
+ * IO-APIC RTE will be configured with virtual vector.
+ * irq handler will do the explicit EOI to the io-apic.
+ */
+ entry->vector = info->ioapic_pin;
+ entry->mask = 0; /* enable IRQ */
+ entry->trigger = info->ioapic_trigger;
+ entry->polarity = info->ioapic_polarity;
+ if (info->ioapic_trigger)
+ entry->mask = 1; /* Mask level triggered irqs. */
+ break;
+
+ case X86_IRQ_ALLOC_TYPE_HPET:
+ case X86_IRQ_ALLOC_TYPE_MSI:
+ case X86_IRQ_ALLOC_TYPE_MSIX:
+ if (info->type == X86_IRQ_ALLOC_TYPE_HPET)
+ set_hpet_sid(irte, info->hpet_id);
+ else
+ set_msi_sid(irte, info->msi_dev);
+
+ msg->address_hi = MSI_ADDR_BASE_HI;
+ msg->data = sub_handle;
+ msg->address_lo = MSI_ADDR_BASE_LO | MSI_ADDR_IR_EXT_INT |
+ MSI_ADDR_IR_SHV |
+ MSI_ADDR_IR_INDEX1(index) |
+ MSI_ADDR_IR_INDEX2(index);
+ break;
+
+ default:
+ BUG_ON(1);
+ break;
+ }
+}
+
+static void intel_free_irq_resources(struct irq_domain *domain,
+ unsigned int virq, unsigned int nr_irqs)
+{
+ struct irq_data *irq_data;
+ struct intel_ir_data *data;
+ struct irq_2_iommu *irq_iommu;
+ unsigned long flags;
+ int i;
+
+ for (i = 0; i < nr_irqs; i++) {
+ irq_data = irq_domain_get_irq_data(domain, virq + i);
+ if (irq_data && irq_data->chip_data) {
+ data = irq_data->chip_data;
+ irq_iommu = &data->irq_2_iommu;
+ raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
+ clear_entries(irq_iommu);
+ raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
+ irq_domain_reset_irq_data(irq_data);
+ kfree(data);
+ }
+ }
+}
+
+static int intel_irq_remapping_alloc(struct irq_domain *domain,
+ unsigned int virq, unsigned int nr_irqs,
+ void *arg)
+{
+ struct intel_iommu *iommu = domain->host_data;
+ struct irq_alloc_info *info = arg;
+ struct intel_ir_data *data;
+ struct irq_data *irq_data;
+ struct irq_cfg *irq_cfg;
+ int i, ret, index;
+
+ if (!info || !iommu)
+ return -EINVAL;
+ if (nr_irqs > 1 && info->type != X86_IRQ_ALLOC_TYPE_MSI &&
+ info->type != X86_IRQ_ALLOC_TYPE_MSIX)
+ return -EINVAL;
+
+ ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
+ if (ret < 0)
+ return ret;
+
+ ret = -ENOMEM;
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ goto out_free_parent;
+
+ down_read(&dmar_global_lock);
+ index = alloc_irte(iommu, virq, &data->irq_2_iommu, nr_irqs);
+ up_read(&dmar_global_lock);
+ if (index < 0) {
+ pr_warn("Failed to allocate IRTE\n");
+ kfree(data);
+ goto out_free_parent;
+ }
+
+ for (i = 0; i < nr_irqs; i++) {
+ irq_data = irq_domain_get_irq_data(domain, virq + i);
+ irq_cfg = irqd_cfg(irq_data);
+ if (!irq_data || !irq_cfg) {
+ ret = -EINVAL;
+ goto out_free_data;
+ }
+
+ if (i > 0) {
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ goto out_free_data;
+ }
+ irq_data->hwirq = (index << 16) + i;
+ irq_data->chip_data = data;
+ irq_data->chip = &intel_ir_chip;
+ intel_irq_remapping_prepare_irte(data, irq_cfg, info, index, i);
+ irq_set_status_flags(virq + i, IRQ_MOVE_PCNTXT);
+ }
+ return 0;
+
+out_free_data:
+ intel_free_irq_resources(domain, virq, i);
+out_free_parent:
+ irq_domain_free_irqs_parent(domain, virq, nr_irqs);
+ return ret;
+}
+
+static void intel_irq_remapping_free(struct irq_domain *domain,
+ unsigned int virq, unsigned int nr_irqs)
+{
+ intel_free_irq_resources(domain, virq, nr_irqs);
+ irq_domain_free_irqs_parent(domain, virq, nr_irqs);
+}
+
+static int intel_irq_remapping_activate(struct irq_domain *domain,
+ struct irq_data *irq_data)
+{
+ struct intel_ir_data *data = irq_data->chip_data;
+
+ modify_irte(&data->irq_2_iommu, &data->irte_entry);
+
+ return 0;
+}
+
+static int intel_irq_remapping_deactivate(struct irq_domain *domain,
+ struct irq_data *irq_data)
+{
+ struct intel_ir_data *data = irq_data->chip_data;
+ struct irte entry;
+
+ memset(&entry, 0, sizeof(entry));
+ modify_irte(&data->irq_2_iommu, &entry);
+
+ return 0;
+}
+
+static struct irq_domain_ops intel_ir_domain_ops = {
+ .alloc = intel_irq_remapping_alloc,
+ .free = intel_irq_remapping_free,
+ .activate = intel_irq_remapping_activate,
+ .deactivate = intel_irq_remapping_deactivate,
};
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index a65208a8fe18..ecaf3a937845 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -286,6 +286,8 @@ struct q_inval {
#define INTR_REMAP_TABLE_ENTRIES 65536
+struct irq_domain;
+
struct ir_table {
struct irte *base;
unsigned long *bitmap;
@@ -335,6 +337,8 @@ struct intel_iommu {
#ifdef CONFIG_IRQ_REMAP
struct ir_table *ir_table; /* Interrupt remapping info */
+ struct irq_domain *ir_domain;
+ struct irq_domain *ir_msi_domain;
#endif
struct device *iommu_dev; /* IOMMU-sysfs device */
int node;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [Patch Part2 v3 13/24] iommu/amd: Enhance AMD IR driver to suppport hierarchy irqdomain
[not found] ` <1414484803-10311-1-git-send-email-jiang.liu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
` (3 preceding siblings ...)
2014-10-28 8:26 ` [Patch Part2 v3 12/24] iommu/vt-d: Enhance Intel IR driver to suppport " Jiang Liu
@ 2014-10-28 8:26 ` Jiang Liu
2014-10-28 8:26 ` [Patch Part2 v3 15/24] x86, MSI: Use hierarchy irqdomain to manage MSI interrupts Jiang Liu
` (4 subsequent siblings)
9 siblings, 0 replies; 17+ messages in thread
From: Jiang Liu @ 2014-10-28 8:26 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Thomas Gleixner, Ingo Molnar,
H. Peter Anvin, Rafael J. Wysocki, Bjorn Helgaas, Randy Dunlap,
Yinghai Lu, Borislav Petkov, Grant Likely, Marc Zyngier,
Yingjoe Chen, Joerg Roedel, Matthias Brugger
Cc: Tony Luck, Greg Kroah-Hartman, x86-DgEjT+Ai2ygdnm+yROfE0A,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-pci-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, Jiang Liu,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Enhance AMD interrupt remapping driver to support hierarchy irqdomain,
it will simplify the code eventually.
Signed-off-by: Jiang Liu <jiang.liu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
---
drivers/iommu/amd_iommu.c | 341 ++++++++++++++++++++++++++++++++++++++-
drivers/iommu/amd_iommu_init.c | 4 +
drivers/iommu/amd_iommu_proto.h | 9 ++
drivers/iommu/amd_iommu_types.h | 5 +
4 files changed, 353 insertions(+), 6 deletions(-)
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 6fda7cc789eb..a3ef3407bb1b 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -33,6 +33,7 @@
#include <linux/export.h>
#include <linux/irq.h>
#include <linux/msi.h>
+#include <linux/irqdomain.h>
#include <asm/irq_remapping.h>
#include <asm/io_apic.h>
#include <asm/apic.h>
@@ -3854,6 +3855,17 @@ union irte {
} fields;
};
+struct amd_ir_data {
+ struct irq_2_irte irq_2_irte;
+ union irte irte_entry;
+ union {
+ struct msi_msg msi_entry;
+ struct IR_IO_APIC_route_entry ioapic_entry;
+ };
+};
+
+static struct irq_chip amd_ir_chip;
+
#define DTE_IRQ_PHYS_ADDR_MASK (((1ULL << 45)-1) << 6)
#define DTE_IRQ_REMAP_INTCTL (2ULL << 60)
#define DTE_IRQ_TABLE_LEN (8ULL << 1)
@@ -3947,7 +3959,8 @@ out_unlock:
return table;
}
-static int alloc_irq_index(struct irq_cfg *cfg, u16 devid, int count)
+static int alloc_irq_index(struct irq_cfg *cfg, struct irq_2_irte *irte_info,
+ u16 devid, int count)
{
struct irq_remap_table *table;
unsigned long flags;
@@ -3969,15 +3982,12 @@ static int alloc_irq_index(struct irq_cfg *cfg, u16 devid, int count)
c = 0;
if (c == count) {
- struct irq_2_irte *irte_info;
-
for (; c != 0; --c)
table->table[index - c + 1] = IRTE_ALLOCATED;
index -= count - 1;
cfg->remapped = 1;
- irte_info = &cfg->irq_2_irte;
irte_info->devid = devid;
irte_info->index = index;
@@ -4222,7 +4232,7 @@ static int msi_alloc_irq(struct pci_dev *pdev, int irq, int nvec)
return -EINVAL;
devid = get_device_id(&pdev->dev);
- index = alloc_irq_index(cfg, devid, nvec);
+ index = alloc_irq_index(cfg, &cfg->irq_2_irte, devid, nvec);
return index < 0 ? MAX_IRQS_PER_TABLE : index;
}
@@ -4269,7 +4279,7 @@ static int alloc_hpet_msi(unsigned int irq, unsigned int id)
if (devid < 0)
return devid;
- index = alloc_irq_index(cfg, devid, 1);
+ index = alloc_irq_index(cfg, &cfg->irq_2_irte, devid, 1);
if (index < 0)
return index;
@@ -4280,6 +4290,91 @@ static int alloc_hpet_msi(unsigned int irq, unsigned int id)
return 0;
}
+static int get_devid(struct irq_alloc_info *info)
+{
+ int devid = -1;
+
+ switch (info->type) {
+ case X86_IRQ_ALLOC_TYPE_IOAPIC:
+ devid = get_ioapic_devid(info->ioapic_id);
+ break;
+ case X86_IRQ_ALLOC_TYPE_HPET:
+ devid = get_hpet_devid(info->hpet_id);
+ break;
+ case X86_IRQ_ALLOC_TYPE_MSI:
+ case X86_IRQ_ALLOC_TYPE_MSIX:
+ devid = get_device_id(&info->msi_dev->dev);
+ break;
+ default:
+ BUG_ON(1);
+ break;
+ }
+
+ return devid;
+}
+
+static struct irq_domain *get_ir_irq_domain(struct irq_alloc_info *info)
+{
+ int devid;
+ struct amd_iommu *iommu;
+
+ if (!info)
+ return NULL;
+
+ devid = get_devid(info);
+ if (devid >= 0) {
+ iommu = amd_iommu_rlookup_table[devid];
+ if (iommu)
+ return iommu->ir_domain;
+ }
+
+ return NULL;
+}
+
+static struct irq_domain *get_irq_domain(struct irq_alloc_info *info)
+{
+ int devid;
+ struct amd_iommu *iommu;
+
+ if (!info)
+ return NULL;
+
+ switch (info->type) {
+ case X86_IRQ_ALLOC_TYPE_MSI:
+ case X86_IRQ_ALLOC_TYPE_MSIX:
+ devid = get_device_id(&info->msi_dev->dev);
+ if (devid >= 0) {
+ iommu = amd_iommu_rlookup_table[devid];
+ if (iommu)
+ return iommu->msi_domain;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static int get_ioapic_entry(struct irq_data *irq_data,
+ struct IR_IO_APIC_route_entry *entry)
+{
+ struct amd_ir_data *ir_data = irq_data->chip_data;
+
+ *entry = ir_data->ioapic_entry;
+
+ return 0;
+}
+
+static int get_msi_entry(struct irq_data *irq_data, struct msi_msg *msg)
+{
+ struct amd_ir_data *ir_data = irq_data->chip_data;
+
+ *msg = ir_data->msi_entry;
+
+ return 0;
+}
+
struct irq_remap_ops amd_iommu_irq_ops = {
.supported = amd_iommu_supported,
.prepare = amd_iommu_prepare,
@@ -4294,5 +4389,239 @@ struct irq_remap_ops amd_iommu_irq_ops = {
.msi_alloc_irq = msi_alloc_irq,
.msi_setup_irq = msi_setup_irq,
.alloc_hpet_msi = alloc_hpet_msi,
+ .get_ir_irq_domain = get_ir_irq_domain,
+ .get_irq_domain = get_irq_domain,
+ .get_ioapic_entry = get_ioapic_entry,
+ .get_msi_entry = get_msi_entry,
};
+
+static void irq_remapping_prepare_irte(struct amd_ir_data *data,
+ struct irq_cfg *irq_cfg,
+ struct irq_alloc_info *info,
+ int devid, int index, int sub_handle)
+{
+ union irte *irte = &data->irte_entry;
+ struct irq_2_irte *irte_info = &data->irq_2_irte;
+ struct IR_IO_APIC_route_entry *entry = &data->ioapic_entry;
+ struct msi_msg *msg = &data->msi_entry;
+
+ irq_cfg->remapped = 1;
+ data->irq_2_irte.devid = devid;
+ data->irq_2_irte.index = index + sub_handle;
+
+ /* Setup IRTE for IOMMU */
+ irte->val = 0;
+ irte->fields.vector = irq_cfg->vector;
+ irte->fields.int_type = apic->irq_delivery_mode;
+ irte->fields.destination = irq_cfg->dest_apicid;
+ irte->fields.dm = apic->irq_dest_mode;
+ irte->fields.valid = 1;
+
+ switch (info->type) {
+ case X86_IRQ_ALLOC_TYPE_IOAPIC:
+ /* Setup IOAPIC entry */
+ memset(entry, 0, sizeof(*entry));
+ entry->vector = index;
+ entry->mask = 0;
+ entry->trigger = info->ioapic_trigger;
+ entry->polarity = info->ioapic_polarity;
+ /* Mask level triggered irqs. */
+ if (info->ioapic_trigger)
+ entry->mask = 1;
+ break;
+
+ case X86_IRQ_ALLOC_TYPE_HPET:
+ case X86_IRQ_ALLOC_TYPE_MSI:
+ case X86_IRQ_ALLOC_TYPE_MSIX:
+ msg->address_hi = MSI_ADDR_BASE_HI;
+ msg->address_lo = MSI_ADDR_BASE_LO;
+ msg->data = irte_info->index;
+ break;
+
+ default:
+ BUG_ON(1);
+ break;
+ }
+}
+
+static int irq_remapping_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *arg)
+{
+ struct irq_alloc_info *info = arg;
+ struct amd_ir_data *data;
+ struct irq_data *irq_data;
+ struct irq_cfg *cfg;
+ int i, ret, devid;
+ int index = -1;
+
+ if (!info)
+ return -EINVAL;
+ if (nr_irqs > 1 && info->type != X86_IRQ_ALLOC_TYPE_MSI &&
+ info->type != X86_IRQ_ALLOC_TYPE_MSIX)
+ return -EINVAL;
+
+ devid = get_devid(info);
+ if (devid < 0)
+ return -EINVAL;
+
+ ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
+ if (ret < 0)
+ return ret;
+
+ ret = -ENOMEM;
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ goto out_free_parent;
+
+ if (info->type == X86_IRQ_ALLOC_TYPE_IOAPIC) {
+ if (get_irq_table(devid, true))
+ index = info->ioapic_pin;
+ else
+ ret = -ENOMEM;
+ } else {
+ cfg = irq_cfg(virq);
+ index = alloc_irq_index(cfg, &data->irq_2_irte, devid, nr_irqs);
+ }
+ if (index < 0) {
+ pr_warn("Failed to allocate IRTE\n");
+ kfree(data);
+ goto out_free_parent;
+ }
+
+ for (i = 0; i < nr_irqs; i++) {
+ irq_data = irq_domain_get_irq_data(domain, virq + i);
+ cfg = irqd_cfg(irq_data);
+ if (!irq_data || !cfg) {
+ ret = -EINVAL;
+ goto out_free_data;
+ }
+
+ if (i > 0) {
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ goto out_free_data;
+ }
+ irq_data->hwirq = (devid << 16) + i;
+ irq_data->chip_data = data;
+ irq_data->chip = &amd_ir_chip;
+ irq_remapping_prepare_irte(data, cfg, info, devid, index, i);
+ irq_set_status_flags(virq + i, IRQ_MOVE_PCNTXT);
+ }
+ return 0;
+
+out_free_data:
+ for (i--; i >= 0; i--) {
+ irq_data = irq_domain_get_irq_data(domain, virq + i);
+ if (irq_data->chip_data) {
+ kfree(irq_data->chip_data);
+ irq_domain_reset_irq_data(irq_data);
+ }
+ }
+ for (i = 0; i < nr_irqs; i++)
+ free_irte(devid, index + i);
+out_free_parent:
+ irq_domain_free_irqs_parent(domain, virq, nr_irqs);
+ return ret;
+}
+
+static void irq_remapping_free(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs)
+{
+ struct irq_data *irq_data;
+ struct amd_ir_data *data;
+ struct irq_2_irte *irte_info;
+ int i;
+
+ for (i = 0; i < nr_irqs; i++) {
+ irq_data = irq_domain_get_irq_data(domain, virq + i);
+ if (irq_data && irq_data->chip_data) {
+ data = irq_data->chip_data;
+ irte_info = &data->irq_2_irte;
+ free_irte(irte_info->devid, irte_info->index);
+ irq_domain_reset_irq_data(irq_data);
+ kfree(data);
+ }
+ }
+ irq_domain_free_irqs_parent(domain, virq, nr_irqs);
+}
+
+static int irq_remapping_activate(struct irq_domain *domain,
+ struct irq_data *irq_data)
+{
+ struct amd_ir_data *data = irq_data->chip_data;
+ struct irq_2_irte *irte_info = &data->irq_2_irte;
+
+ modify_irte(irte_info->devid, irte_info->index, data->irte_entry);
+
+ return 0;
+}
+
+static int irq_remapping_deactivate(struct irq_domain *domain,
+ struct irq_data *irq_data)
+{
+ struct amd_ir_data *data = irq_data->chip_data;
+ struct irq_2_irte *irte_info = &data->irq_2_irte;
+ union irte entry;
+
+ entry.val = 0;
+ modify_irte(irte_info->devid, irte_info->index, data->irte_entry);
+
+ return 0;
+}
+
+static struct irq_domain_ops amd_ir_domain_ops = {
+ .alloc = irq_remapping_alloc,
+ .free = irq_remapping_free,
+ .activate = irq_remapping_activate,
+ .deactivate = irq_remapping_deactivate,
+};
+
+static int amd_ir_set_affinity(struct irq_data *data,
+ const struct cpumask *mask, bool force)
+{
+ struct amd_ir_data *ir_data = data->chip_data;
+ struct irq_2_irte *irte_info = &ir_data->irq_2_irte;
+ struct irq_cfg *cfg = irqd_cfg(data);
+ struct irq_data *parent = data->parent_data;
+ int ret;
+
+ ret = parent->chip->irq_set_affinity(parent, mask, force);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Atomically updates the IRTE with the new destination, vector
+ * and flushes the interrupt entry cache.
+ */
+ ir_data->irte_entry.fields.vector = cfg->vector;
+ ir_data->irte_entry.fields.destination = cfg->dest_apicid;
+ modify_irte(irte_info->devid, irte_info->index, ir_data->irte_entry);
+
+ /*
+ * After this point, all the interrupts will start arriving
+ * at the new destination. So, time to cleanup the previous
+ * vector allocation.
+ */
+ if (cfg->move_in_progress)
+ send_cleanup_vector(cfg);
+
+ return ret;
+}
+
+static struct irq_chip amd_ir_chip = {
+ .irq_ack = ir_ack_apic_edge,
+ .irq_set_affinity = amd_ir_set_affinity,
+};
+
+int amd_iommu_create_irq_domain(struct amd_iommu *iommu)
+{
+ iommu->ir_domain = irq_domain_add_tree(NULL, &amd_ir_domain_ops, iommu);
+ if (!iommu->ir_domain)
+ return -ENOMEM;
+
+ iommu->ir_domain->parent = arch_get_ir_parent_domain();
+ iommu->msi_domain = arch_create_msi_irq_domain(iommu->ir_domain);
+
+ return 0;
+}
#endif
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index b0522f15730f..de3390a7d345 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -1124,6 +1124,10 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
if (ret)
return ret;
+ ret = amd_iommu_create_irq_domain(iommu);
+ if (ret)
+ return ret;
+
/*
* Make sure IOMMU is not considered to translate itself. The IVRS
* table tells us so, but this is a lie!
diff --git a/drivers/iommu/amd_iommu_proto.h b/drivers/iommu/amd_iommu_proto.h
index 95ed6deae47f..612a22192fa0 100644
--- a/drivers/iommu/amd_iommu_proto.h
+++ b/drivers/iommu/amd_iommu_proto.h
@@ -63,6 +63,15 @@ extern u8 amd_iommu_pc_get_max_counters(u16 devid);
extern int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn,
u64 *value, bool is_write);
+#ifdef CONFIG_IRQ_REMAP
+extern int amd_iommu_create_irq_domain(struct amd_iommu *iommu);
+#else
+static inline int amd_iommu_create_irq_domain(struct amd_iommu *iommu)
+{
+ return 0;
+}
+#endif
+
#define PPR_SUCCESS 0x0
#define PPR_INVALID 0x1
#define PPR_FAILURE 0xf
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h
index cec51a8ba844..ef12d74a03fe 100644
--- a/drivers/iommu/amd_iommu_types.h
+++ b/drivers/iommu/amd_iommu_types.h
@@ -392,6 +392,7 @@ struct amd_iommu_fault {
struct iommu_domain;
+struct irq_domain;
/*
* This structure contains generic data for IOMMU protection domains
@@ -574,6 +575,10 @@ struct amd_iommu {
/* The maximum PC banks and counters/bank (PCSup=1) */
u8 max_banks;
u8 max_counters;
+#ifdef CONFIG_IRQ_REMAP
+ struct irq_domain *ir_domain;
+ struct irq_domain *msi_domain;
+#endif
};
struct devid_map {
--
1.7.10.4
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [Patch Part2 v3 15/24] x86, MSI: Use hierarchy irqdomain to manage MSI interrupts
[not found] ` <1414484803-10311-1-git-send-email-jiang.liu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
` (4 preceding siblings ...)
2014-10-28 8:26 ` [Patch Part2 v3 13/24] iommu/amd: Enhance AMD " Jiang Liu
@ 2014-10-28 8:26 ` Jiang Liu
[not found] ` <1414484803-10311-16-git-send-email-jiang.liu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2014-10-28 8:26 ` [Patch Part2 v3 17/24] iommu/vt-d: Clean up unused MSI related code Jiang Liu
` (3 subsequent siblings)
9 siblings, 1 reply; 17+ messages in thread
From: Jiang Liu @ 2014-10-28 8:26 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Thomas Gleixner, Ingo Molnar,
H. Peter Anvin, Rafael J. Wysocki, Bjorn Helgaas, Randy Dunlap,
Yinghai Lu, Borislav Petkov, Grant Likely, Marc Zyngier,
Yingjoe Chen, x86-DgEjT+Ai2ygdnm+yROfE0A, Joerg Roedel,
Matthias Brugger, Jiang Liu
Cc: Tony Luck, Greg Kroah-Hartman,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-pci-u79uwXL29TY76Z2rM5mHXA, Andrew Morton,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Enhance MSI code to support hierarchy irqdomain, it helps to make
the architecture more clear.
Signed-off-by: Jiang Liu <jiang.liu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
---
arch/x86/include/asm/hw_irq.h | 9 +-
arch/x86/include/asm/irq_remapping.h | 6 +-
arch/x86/kernel/apic/msi.c | 237 ++++++++++++++++++++++++++++------
arch/x86/kernel/apic/vector.c | 2 +
drivers/iommu/irq_remapping.c | 1 -
5 files changed, 209 insertions(+), 46 deletions(-)
diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
index 545460d470bd..1ff7a7f61bf9 100644
--- a/arch/x86/include/asm/hw_irq.h
+++ b/arch/x86/include/asm/hw_irq.h
@@ -110,9 +110,10 @@ struct irq_2_irte {
};
#endif /* CONFIG_IRQ_REMAP */
+struct irq_domain;
+
#ifdef CONFIG_X86_LOCAL_APIC
struct irq_data;
-struct irq_domain;
struct pci_dev;
struct msi_desc;
@@ -200,6 +201,12 @@ static inline void lock_vector_lock(void) {}
static inline void unlock_vector_lock(void) {}
#endif /* CONFIG_X86_LOCAL_APIC */
+#ifdef CONFIG_PCI_MSI
+extern void arch_init_msi_domain(struct irq_domain *domain);
+#else
+static inline void arch_init_msi_domain(struct irq_domain *domain) { }
+#endif
+
/* Statistics */
extern atomic_t irq_err_count;
extern atomic_t irq_mis_count;
diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h
index f5f624529386..ea71f86423ee 100644
--- a/arch/x86/include/asm/irq_remapping.h
+++ b/arch/x86/include/asm/irq_remapping.h
@@ -75,11 +75,7 @@ extern void irq_remapping_print_chip(struct irq_data *data, struct seq_file *p);
* Create MSI/MSIx irqdomain for interrupt remapping device, use @parent as
* parent irqdomain.
*/
-static inline struct irq_domain *
-arch_create_msi_irq_domain(struct irq_domain *parent)
-{
- return NULL;
-}
+extern struct irq_domain *arch_create_msi_irq_domain(struct irq_domain *parent);
/* Get parent irqdomain for interrupt remapping irqdomain */
static inline struct irq_domain *arch_get_ir_parent_domain(void)
diff --git a/arch/x86/kernel/apic/msi.c b/arch/x86/kernel/apic/msi.c
index 47d3a24793ce..354abd7ef2ad 100644
--- a/arch/x86/kernel/apic/msi.c
+++ b/arch/x86/kernel/apic/msi.c
@@ -3,6 +3,8 @@
*
* Copyright (C) 1997, 1998, 1999, 2000, 2009 Ingo Molnar, Hajnalka Szabo
* Moved from arch/x86/kernel/apic/io_apic.c.
+ * Jiang Liu <jiang.liu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
+ * Add support of hierarchy irqdomain
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -21,6 +23,8 @@
#include <asm/apic.h>
#include <asm/irq_remapping.h>
+static struct irq_domain *msi_default_domain;
+
static void msi_reset_irq_data_and_handler(struct irq_domain *domain, int virq)
{
struct irq_data *irq_data = irq_domain_get_irq_data(domain, virq);
@@ -96,28 +100,28 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
return 0;
}
-static int
-msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
+static bool msi_irq_remapped(struct irq_data *irq_data)
{
- struct irq_cfg *cfg = irqd_cfg(data);
- struct msi_msg msg;
- unsigned int dest;
- int ret;
-
- ret = apic_set_affinity(data, mask, &dest);
- if (ret)
- return ret;
+ return irq_remapping_domain_is_remapped(irq_data->domain);
+}
- __get_cached_msi_msg(data->msi_desc, &msg);
+static int msi_set_affinity(struct irq_data *data, const struct cpumask *mask,
+ bool force)
+{
+ struct irq_data *parent = data->parent_data;
+ int ret;
- msg.data &= ~MSI_DATA_VECTOR_MASK;
- msg.data |= MSI_DATA_VECTOR(cfg->vector);
- msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
- msg.address_lo |= MSI_ADDR_DEST_ID(dest);
+ ret = parent->chip->irq_set_affinity(parent, mask, force);
+ /* No need to reprogram MSI registers if interrupt is remapped */
+ if (ret >= 0 && !msi_irq_remapped(data)) {
+ struct msi_msg msg;
- __write_msi_msg(data->msi_desc, &msg);
+ __get_cached_msi_msg(data->msi_desc, &msg);
+ msi_update_msg(&msg, data);
+ __write_msi_msg(data->msi_desc, &msg);
+ }
- return IRQ_SET_MASK_OK_NOCOPY;
+ return ret;
}
/*
@@ -128,12 +132,106 @@ static struct irq_chip msi_chip = {
.name = "PCI-MSI",
.irq_unmask = unmask_msi_irq,
.irq_mask = mask_msi_irq,
- .irq_ack = apic_ack_edge,
+ .irq_ack = irq_chip_ack_parent,
.irq_set_affinity = msi_set_affinity,
- .irq_retrigger = apic_retrigger_irq,
+ .irq_retrigger = irq_chip_retrigger_hierarchy,
+ .irq_print_chip = irq_remapping_print_chip,
.flags = IRQCHIP_SKIP_SET_WAKE,
};
+static inline irq_hw_number_t
+get_hwirq_from_pcidev(struct pci_dev *pdev, struct msi_desc *msidesc)
+{
+ return (irq_hw_number_t)msidesc->msi_attrib.entry_nr |
+ PCI_DEVID(pdev->bus->number, pdev->devfn) << 11 |
+ (pci_domain_nr(pdev->bus) & 0xFFFFFFFF) << 27;
+}
+
+static int msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *arg)
+{
+ int i, ret;
+ irq_hw_number_t hwirq;
+ struct irq_alloc_info *info = arg;
+
+ hwirq = get_hwirq_from_pcidev(info->msi_dev, info->msi_desc);
+ if (irq_find_mapping(domain, hwirq) > 0)
+ return -EEXIST;
+
+ ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, info);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < nr_irqs; i++) {
+ irq_set_msi_desc_off(virq, i, info->msi_desc);
+ irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
+ &msi_chip, (void *)(long)i);
+ __irq_set_handler(virq + i, handle_edge_irq, 0, "edge");
+ dev_dbg(&info->msi_dev->dev, "irq %d for MSI/MSI-X\n",
+ virq + i);
+ }
+
+ return ret;
+}
+
+static void msi_domain_free(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs)
+{
+ int i;
+ struct msi_desc *msidesc = irq_get_msi_desc(virq);
+
+ if (msidesc)
+ msidesc->irq = 0;
+ for (i = 0; i < nr_irqs; i++)
+ msi_reset_irq_data_and_handler(domain, virq + i);
+ irq_domain_free_irqs_parent(domain, virq, nr_irqs);
+}
+
+static int msi_domain_activate(struct irq_domain *domain,
+ struct irq_data *irq_data)
+{
+ struct msi_msg msg;
+ struct irq_cfg *cfg = irqd_cfg(irq_data);
+
+ /*
+ * irq_data->chip_data is MSI/MSIx offset.
+ * MSI-X message is written per-IRQ, the offset is always 0.
+ * MSI message denotes a contiguous group of IRQs, written for 0th IRQ.
+ */
+ if (irq_data->chip_data)
+ return 0;
+
+ if (msi_irq_remapped(irq_data))
+ irq_remapping_get_msi_entry(irq_data->parent_data, &msg);
+ else
+ native_compose_msi_msg(NULL, irq_data->irq, cfg->dest_apicid,
+ &msg, 0);
+ write_msi_msg(irq_data->irq, &msg);
+
+ return 0;
+}
+
+static int msi_domain_deactivate(struct irq_domain *domain,
+ struct irq_data *irq_data)
+{
+ struct msi_msg msg;
+
+ if (irq_data->chip_data)
+ return 0;
+
+ memset(&msg, 0, sizeof(msg));
+ write_msi_msg(irq_data->irq, &msg);
+
+ return 0;
+}
+
+static struct irq_domain_ops msi_domain_ops = {
+ .alloc = msi_domain_alloc,
+ .free = msi_domain_free,
+ .activate = msi_domain_activate,
+ .deactivate = msi_domain_deactivate,
+};
+
int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
unsigned int irq_base, unsigned int irq_offset)
{
@@ -166,25 +264,59 @@ int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{
- struct msi_desc *msidesc;
- int irq, ret;
+ int irq, cnt, nvec_pow2;
+ struct irq_domain *domain;
+ struct msi_desc *msidesc, *iter;
+ struct irq_alloc_info info;
+ int node = dev_to_node(&dev->dev);
- /* Multiple MSI vectors only supported with interrupt remapping */
- if (type == PCI_CAP_ID_MSI && nvec > 1)
- return 1;
+ if (disable_apic)
+ return -ENOSYS;
- list_for_each_entry(msidesc, &dev->msi_list, list) {
- irq = irq_domain_alloc_irqs(NULL, 1, NUMA_NO_NODE, NULL);
+ init_irq_alloc_info(&info, NULL);
+ info.msi_dev = dev;
+ if (type == PCI_CAP_ID_MSI) {
+ msidesc = list_first_entry(&dev->msi_list,
+ struct msi_desc, list);
+ WARN_ON(!list_is_singular(&dev->msi_list));
+ WARN_ON(msidesc->irq);
+ WARN_ON(msidesc->msi_attrib.multiple);
+ WARN_ON(msidesc->nvec_used);
+ info.type = X86_IRQ_ALLOC_TYPE_MSI;
+ cnt = nvec;
+ } else {
+ info.type = X86_IRQ_ALLOC_TYPE_MSIX;
+ cnt = 1;
+ }
+
+ domain = irq_remapping_get_irq_domain(&info);
+ if (domain == NULL) {
+ /*
+ * Multiple MSI vectors only supported with interrupt
+ * remapping
+ */
+ if (type == PCI_CAP_ID_MSI && nvec > 1)
+ return 1;
+ domain = msi_default_domain;
+ }
+ if (domain == NULL)
+ return -ENOSYS;
+
+ list_for_each_entry(iter, &dev->msi_list, list) {
+ info.msi_desc = iter;
+ irq = irq_domain_alloc_irqs(domain, cnt, node, &info);
if (irq <= 0)
return -ENOSPC;
+ }
- ret = setup_msi_irq(dev, msidesc, irq, 0);
- if (ret < 0) {
- irq_domain_free_irqs(irq, 1);
- return ret;
- }
-
+ if (type == PCI_CAP_ID_MSI) {
+ nvec_pow2 = __roundup_pow_of_two(nvec);
+ msidesc = list_first_entry(&dev->msi_list,
+ struct msi_desc, list);
+ msidesc->msi_attrib.multiple = ilog2(nvec_pow2);
+ msidesc->nvec_used = nvec;
}
+
return 0;
}
@@ -193,6 +325,38 @@ void native_teardown_msi_irq(unsigned int irq)
irq_domain_free_irqs(irq, 1);
}
+static struct irq_domain *msi_create_domain(struct irq_domain *parent,
+ bool remapped)
+{
+ struct irq_domain *domain;
+
+ domain = irq_domain_add_tree(NULL, &msi_domain_ops, NULL);
+ if (domain) {
+ domain->parent = parent;
+ if (remapped)
+ irq_remapping_domain_set_remapped(domain);
+ }
+
+ return domain;
+}
+
+void arch_init_msi_domain(struct irq_domain *parent)
+{
+ if (disable_apic)
+ return;
+
+ msi_default_domain = msi_create_domain(parent, false);
+ if (!msi_default_domain)
+ pr_warn("failed to initialize irqdomain for MSI/MSI-x.\n");
+}
+
+#ifdef CONFIG_IRQ_REMAP
+struct irq_domain *arch_create_msi_irq_domain(struct irq_domain *parent)
+{
+ return msi_create_domain(parent, true);
+}
+#endif
+
#ifdef CONFIG_DMAR_TABLE
static int
dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask,
@@ -264,11 +428,6 @@ static inline int hpet_dev_id(struct irq_domain *domain)
return (int)(long)domain->host_data;
}
-static inline bool hpet_irq_remapped(struct irq_data *irq_data)
-{
- return irq_remapping_domain_is_remapped(irq_data->domain);
-}
-
static int hpet_msi_set_affinity(struct irq_data *data,
const struct cpumask *mask, bool force)
{
@@ -278,7 +437,7 @@ static int hpet_msi_set_affinity(struct irq_data *data,
ret = parent->chip->irq_set_affinity(parent, mask, force);
/* No need to rewrite HPET registers if interrupt is remapped */
- if (ret >= 0 && !hpet_irq_remapped(data)) {
+ if (ret >= 0 && !msi_irq_remapped(data)) {
hpet_msi_read(data->handler_data, &msg);
msi_update_msg(&msg, data);
hpet_msi_write(data->handler_data, &msg);
@@ -356,7 +515,7 @@ static int hpet_domain_activate(struct irq_domain *domain,
struct msi_msg msg;
struct irq_cfg *cfg = irqd_cfg(irq_data);
- if (hpet_irq_remapped(irq_data))
+ if (msi_irq_remapped(irq_data))
irq_remapping_get_msi_entry(irq_data->parent_data, &msg);
else
native_compose_msi_msg(NULL, irq_data->irq, cfg->dest_apicid,
diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c
index c97848125895..61c55d0aeaec 100644
--- a/arch/x86/kernel/apic/vector.c
+++ b/arch/x86/kernel/apic/vector.c
@@ -359,6 +359,8 @@ int __init arch_early_irq_init(void)
BUG_ON(x86_vector_domain == NULL);
irq_set_default_host(x86_vector_domain);
+ arch_init_msi_domain(x86_vector_domain);
+
return arch_early_ioapic_init();
}
diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c
index 3a7f62c8becb..f92d49110f83 100644
--- a/drivers/iommu/irq_remapping.c
+++ b/drivers/iommu/irq_remapping.c
@@ -179,7 +179,6 @@ static void __init irq_remapping_modify_x86_ops(void)
x86_io_apic_ops.set_affinity = set_remapped_irq_affinity;
x86_io_apic_ops.setup_entry = setup_ioapic_remapped_entry;
x86_io_apic_ops.eoi_ioapic_pin = eoi_ioapic_pin_remapped;
- x86_msi.setup_msi_irqs = irq_remapping_setup_msi_irqs;
x86_msi.setup_hpet_msi = setup_hpet_msi_remapped;
x86_msi.compose_msi_msg = compose_remapped_msi_msg;
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [Patch Part2 v3 17/24] iommu/vt-d: Clean up unused MSI related code
[not found] ` <1414484803-10311-1-git-send-email-jiang.liu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
` (5 preceding siblings ...)
2014-10-28 8:26 ` [Patch Part2 v3 15/24] x86, MSI: Use hierarchy irqdomain to manage MSI interrupts Jiang Liu
@ 2014-10-28 8:26 ` Jiang Liu
2014-10-28 8:26 ` [Patch Part2 v3 18/24] iommu/amd: " Jiang Liu
` (2 subsequent siblings)
9 siblings, 0 replies; 17+ messages in thread
From: Jiang Liu @ 2014-10-28 8:26 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Thomas Gleixner, Ingo Molnar,
H. Peter Anvin, Rafael J. Wysocki, Bjorn Helgaas, Randy Dunlap,
Yinghai Lu, Borislav Petkov, Grant Likely, Marc Zyngier,
Yingjoe Chen, Joerg Roedel, Matthias Brugger
Cc: Tony Luck, Greg Kroah-Hartman, x86-DgEjT+Ai2ygdnm+yROfE0A,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-pci-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, Jiang Liu,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Now MSI interrupt has been converted to new hierarchy irqdomain
interfaces, so kill legacy MSI related code.
Signed-off-by: Jiang Liu <jiang.liu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
---
drivers/iommu/intel_irq_remapping.c | 144 -----------------------------------
1 file changed, 144 deletions(-)
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c
index fdaa15026909..9742011190fb 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -146,44 +146,6 @@ static int qi_flush_iec(struct intel_iommu *iommu, int index, int mask)
return qi_submit_sync(&desc, iommu);
}
-static int map_irq_to_irte_handle(int irq, u16 *sub_handle)
-{
- struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
- unsigned long flags;
- int index;
-
- if (!irq_iommu)
- return -1;
-
- raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
- *sub_handle = irq_iommu->sub_handle;
- index = irq_iommu->irte_index;
- raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
- return index;
-}
-
-static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
-{
- struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
- struct irq_cfg *cfg = irq_cfg(irq);
- unsigned long flags;
-
- if (!irq_iommu)
- return -1;
-
- raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
-
- cfg->remapped = 1;
- irq_iommu->iommu = iommu;
- irq_iommu->irte_index = index;
- irq_iommu->sub_handle = subhandle;
- irq_iommu->irte_mask = 0;
-
- raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
-
- return 0;
-}
-
static int modify_irte(struct irq_2_iommu *irq_iommu,
struct irte *irte_modified)
{
@@ -1070,108 +1032,6 @@ intel_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
return 0;
}
-static void intel_compose_msi_msg(struct pci_dev *pdev,
- unsigned int irq, unsigned int dest,
- struct msi_msg *msg, u8 hpet_id)
-{
- struct irq_cfg *cfg;
- struct irte irte;
- u16 sub_handle = 0;
- int ir_index;
-
- cfg = irq_cfg(irq);
-
- ir_index = map_irq_to_irte_handle(irq, &sub_handle);
- BUG_ON(ir_index == -1);
-
- prepare_irte(&irte, cfg->vector, dest);
-
- /* Set source-id of interrupt request */
- if (pdev)
- set_msi_sid(&irte, pdev);
- else
- set_hpet_sid(&irte, hpet_id);
-
- modify_irte(irq_2_iommu(irq), &irte);
-
- msg->address_hi = MSI_ADDR_BASE_HI;
- msg->data = sub_handle;
- msg->address_lo = MSI_ADDR_BASE_LO | MSI_ADDR_IR_EXT_INT |
- MSI_ADDR_IR_SHV |
- MSI_ADDR_IR_INDEX1(ir_index) |
- MSI_ADDR_IR_INDEX2(ir_index);
-}
-
-/*
- * Map the PCI dev to the corresponding remapping hardware unit
- * and allocate 'nvec' consecutive interrupt-remapping table entries
- * in it.
- */
-static int intel_msi_alloc_irq(struct pci_dev *dev, int irq, int nvec)
-{
- struct intel_iommu *iommu;
- int index;
-
- down_read(&dmar_global_lock);
- iommu = map_dev_to_ir(dev);
- if (!iommu) {
- printk(KERN_ERR
- "Unable to map PCI %s to iommu\n", pci_name(dev));
- index = -ENOENT;
- } else {
- index = alloc_irte(iommu, irq, irq_2_iommu(irq), nvec);
- if (index < 0) {
- printk(KERN_ERR
- "Unable to allocate %d IRTE for PCI %s\n",
- nvec, pci_name(dev));
- index = -ENOSPC;
- }
- }
- up_read(&dmar_global_lock);
-
- return index;
-}
-
-static int intel_msi_setup_irq(struct pci_dev *pdev, unsigned int irq,
- int index, int sub_handle)
-{
- struct intel_iommu *iommu;
- int ret = -ENOENT;
-
- down_read(&dmar_global_lock);
- iommu = map_dev_to_ir(pdev);
- if (iommu) {
- /*
- * setup the mapping between the irq and the IRTE
- * base index, the sub_handle pointing to the
- * appropriate interrupt remap table entry.
- */
- set_irte_irq(irq, iommu, index, sub_handle);
- ret = 0;
- }
- up_read(&dmar_global_lock);
-
- return ret;
-}
-
-static int intel_alloc_hpet_msi(unsigned int irq, unsigned int id)
-{
- int ret = -1;
- struct intel_iommu *iommu;
- int index;
-
- down_read(&dmar_global_lock);
- iommu = map_hpet_to_ir(id);
- if (iommu) {
- index = alloc_irte(iommu, irq, irq_2_iommu(irq), 1);
- if (index >= 0)
- ret = 0;
- }
- up_read(&dmar_global_lock);
-
- return ret;
-}
-
static struct irq_domain *intel_get_ir_irq_domain(struct irq_alloc_info *info)
{
struct intel_iommu *iommu = NULL;
@@ -1248,10 +1108,6 @@ struct irq_remap_ops intel_irq_remap_ops = {
.setup_ioapic_entry = intel_setup_ioapic_entry,
.set_affinity = intel_ioapic_set_affinity,
.free_irq = free_irte,
- .compose_msi_msg = intel_compose_msi_msg,
- .msi_alloc_irq = intel_msi_alloc_irq,
- .msi_setup_irq = intel_msi_setup_irq,
- .alloc_hpet_msi = intel_alloc_hpet_msi,
.get_ir_irq_domain = intel_get_ir_irq_domain,
.get_irq_domain = intel_get_irq_domain,
.get_ioapic_entry = intel_get_ioapic_entry,
--
1.7.10.4
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [Patch Part2 v3 18/24] iommu/amd: Clean up unused MSI related code
[not found] ` <1414484803-10311-1-git-send-email-jiang.liu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
` (6 preceding siblings ...)
2014-10-28 8:26 ` [Patch Part2 v3 17/24] iommu/vt-d: Clean up unused MSI related code Jiang Liu
@ 2014-10-28 8:26 ` Jiang Liu
2014-10-28 8:26 ` [Patch Part2 v3 19/24] x86: irq_remapping: " Jiang Liu
2014-10-28 8:26 ` [Patch Part2 v3 21/24] iommu/vt-d: Refine the interfaces to create IRQ for DMAR unit Jiang Liu
9 siblings, 0 replies; 17+ messages in thread
From: Jiang Liu @ 2014-10-28 8:26 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Thomas Gleixner, Ingo Molnar,
H. Peter Anvin, Rafael J. Wysocki, Bjorn Helgaas, Randy Dunlap,
Yinghai Lu, Borislav Petkov, Grant Likely, Marc Zyngier,
Yingjoe Chen, Joerg Roedel, Matthias Brugger
Cc: Tony Luck, Greg Kroah-Hartman, x86-DgEjT+Ai2ygdnm+yROfE0A,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-pci-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, Jiang Liu,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Now MSI interrupt has been converted to new hierarchy irqdomain
interfaces, so kill legacy MSI related code.
Signed-off-by: Jiang Liu <jiang.liu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
---
drivers/iommu/amd_iommu.c | 115 +--------------------------------------------
1 file changed, 2 insertions(+), 113 deletions(-)
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index a3ef3407bb1b..0b648772c221 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -3959,8 +3959,7 @@ out_unlock:
return table;
}
-static int alloc_irq_index(struct irq_cfg *cfg, struct irq_2_irte *irte_info,
- u16 devid, int count)
+static int alloc_irq_index(u16 devid, int count)
{
struct irq_remap_table *table;
unsigned long flags;
@@ -3986,11 +3985,6 @@ static int alloc_irq_index(struct irq_cfg *cfg, struct irq_2_irte *irte_info,
table->table[index - c + 1] = IRTE_ALLOCATED;
index -= count - 1;
-
- cfg->remapped = 1;
- irte_info->devid = devid;
- irte_info->index = index;
-
goto out;
}
}
@@ -4190,106 +4184,6 @@ static int free_irq(int irq)
return 0;
}
-static void compose_msi_msg(struct pci_dev *pdev,
- unsigned int irq, unsigned int dest,
- struct msi_msg *msg, u8 hpet_id)
-{
- struct irq_2_irte *irte_info;
- struct irq_cfg *cfg;
- union irte irte;
-
- cfg = irq_cfg(irq);
- if (!cfg)
- return;
-
- irte_info = &cfg->irq_2_irte;
-
- irte.val = 0;
- irte.fields.vector = cfg->vector;
- irte.fields.int_type = apic->irq_delivery_mode;
- irte.fields.destination = dest;
- irte.fields.dm = apic->irq_dest_mode;
- irte.fields.valid = 1;
-
- modify_irte(irte_info->devid, irte_info->index, irte);
-
- msg->address_hi = MSI_ADDR_BASE_HI;
- msg->address_lo = MSI_ADDR_BASE_LO;
- msg->data = irte_info->index;
-}
-
-static int msi_alloc_irq(struct pci_dev *pdev, int irq, int nvec)
-{
- struct irq_cfg *cfg;
- int index;
- u16 devid;
-
- if (!pdev)
- return -EINVAL;
-
- cfg = irq_cfg(irq);
- if (!cfg)
- return -EINVAL;
-
- devid = get_device_id(&pdev->dev);
- index = alloc_irq_index(cfg, &cfg->irq_2_irte, devid, nvec);
-
- return index < 0 ? MAX_IRQS_PER_TABLE : index;
-}
-
-static int msi_setup_irq(struct pci_dev *pdev, unsigned int irq,
- int index, int offset)
-{
- struct irq_2_irte *irte_info;
- struct irq_cfg *cfg;
- u16 devid;
-
- if (!pdev)
- return -EINVAL;
-
- cfg = irq_cfg(irq);
- if (!cfg)
- return -EINVAL;
-
- if (index >= MAX_IRQS_PER_TABLE)
- return 0;
-
- devid = get_device_id(&pdev->dev);
- irte_info = &cfg->irq_2_irte;
-
- cfg->remapped = 1;
- irte_info->devid = devid;
- irte_info->index = index + offset;
-
- return 0;
-}
-
-static int alloc_hpet_msi(unsigned int irq, unsigned int id)
-{
- struct irq_2_irte *irte_info;
- struct irq_cfg *cfg;
- int index, devid;
-
- cfg = irq_cfg(irq);
- if (!cfg)
- return -EINVAL;
-
- irte_info = &cfg->irq_2_irte;
- devid = get_hpet_devid(id);
- if (devid < 0)
- return devid;
-
- index = alloc_irq_index(cfg, &cfg->irq_2_irte, devid, 1);
- if (index < 0)
- return index;
-
- cfg->remapped = 1;
- irte_info->devid = devid;
- irte_info->index = index;
-
- return 0;
-}
-
static int get_devid(struct irq_alloc_info *info)
{
int devid = -1;
@@ -4385,10 +4279,6 @@ struct irq_remap_ops amd_iommu_irq_ops = {
.setup_ioapic_entry = setup_ioapic_entry,
.set_affinity = set_affinity,
.free_irq = free_irq,
- .compose_msi_msg = compose_msi_msg,
- .msi_alloc_irq = msi_alloc_irq,
- .msi_setup_irq = msi_setup_irq,
- .alloc_hpet_msi = alloc_hpet_msi,
.get_ir_irq_domain = get_ir_irq_domain,
.get_irq_domain = get_irq_domain,
.get_ioapic_entry = get_ioapic_entry,
@@ -4479,8 +4369,7 @@ static int irq_remapping_alloc(struct irq_domain *domain, unsigned int virq,
else
ret = -ENOMEM;
} else {
- cfg = irq_cfg(virq);
- index = alloc_irq_index(cfg, &data->irq_2_irte, devid, nr_irqs);
+ index = alloc_irq_index(devid, nr_irqs);
}
if (index < 0) {
pr_warn("Failed to allocate IRTE\n");
--
1.7.10.4
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [Patch Part2 v3 19/24] x86: irq_remapping: Clean up unused MSI related code
[not found] ` <1414484803-10311-1-git-send-email-jiang.liu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
` (7 preceding siblings ...)
2014-10-28 8:26 ` [Patch Part2 v3 18/24] iommu/amd: " Jiang Liu
@ 2014-10-28 8:26 ` Jiang Liu
2014-10-28 8:26 ` [Patch Part2 v3 21/24] iommu/vt-d: Refine the interfaces to create IRQ for DMAR unit Jiang Liu
9 siblings, 0 replies; 17+ messages in thread
From: Jiang Liu @ 2014-10-28 8:26 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Thomas Gleixner, Ingo Molnar,
H. Peter Anvin, Rafael J. Wysocki, Bjorn Helgaas, Randy Dunlap,
Yinghai Lu, Borislav Petkov, Grant Likely, Marc Zyngier,
Yingjoe Chen, x86-DgEjT+Ai2ygdnm+yROfE0A, Joerg Roedel,
Matthias Brugger, Jiang Liu, Rafael J. Wysocki,
Konrad Rzeszutek Wilk
Cc: Tony Luck, Greg Kroah-Hartman,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-pci-u79uwXL29TY76Z2rM5mHXA, Andrew Morton,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Now MSI interrupt has been converted to new hierarchy irqdomain
interfaces, so kill legacy MSI related code and interfaces.
Signed-off-by: Jiang Liu <jiang.liu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
---
arch/x86/include/asm/irq_remapping.h | 13 ---
arch/x86/include/asm/pci.h | 5 --
arch/x86/kernel/x86_init.c | 2 -
drivers/iommu/irq_remapping.c | 159 ----------------------------------
drivers/iommu/irq_remapping.h | 14 ---
5 files changed, 193 deletions(-)
diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h
index ea71f86423ee..cda6efe15f63 100644
--- a/arch/x86/include/asm/irq_remapping.h
+++ b/arch/x86/include/asm/irq_remapping.h
@@ -50,10 +50,6 @@ extern int setup_ioapic_remapped_entry(int irq,
int vector,
struct io_apic_irq_attr *attr);
extern void free_remapped_irq(int irq);
-extern void compose_remapped_msi_msg(struct pci_dev *pdev,
- unsigned int irq, unsigned int dest,
- struct msi_msg *msg, u8 hpet_id);
-extern int setup_hpet_msi_remapped(unsigned int irq, unsigned int id);
extern void panic_if_irq_remap(const char *msg);
extern bool setup_remapped_irq(int irq,
struct irq_cfg *cfg,
@@ -112,15 +108,6 @@ static inline int setup_ioapic_remapped_entry(int irq,
return -ENODEV;
}
static inline void free_remapped_irq(int irq) { }
-static inline void compose_remapped_msi_msg(struct pci_dev *pdev,
- unsigned int irq, unsigned int dest,
- struct msi_msg *msg, u8 hpet_id)
-{
-}
-static inline int setup_hpet_msi_remapped(unsigned int irq, unsigned int id)
-{
- return -ENODEV;
-}
static inline void panic_if_irq_remap(const char *msg)
{
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
index 4e370a5d8117..d8c80ff32e8c 100644
--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -96,15 +96,10 @@ extern void pci_iommu_alloc(void);
#ifdef CONFIG_PCI_MSI
/* implemented in arch/x86/kernel/apic/io_apic. */
struct msi_desc;
-void native_compose_msi_msg(struct pci_dev *pdev, unsigned int irq,
- unsigned int dest, struct msi_msg *msg, u8 hpet_id);
int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
void native_teardown_msi_irq(unsigned int irq);
void native_restore_msi_irqs(struct pci_dev *dev);
-int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
- unsigned int irq_base, unsigned int irq_offset);
#else
-#define native_compose_msi_msg NULL
#define native_setup_msi_irqs NULL
#define native_teardown_msi_irq NULL
#endif
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index e48b674639cc..814fcbadaad1 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -111,11 +111,9 @@ EXPORT_SYMBOL_GPL(x86_platform);
#if defined(CONFIG_PCI_MSI)
struct x86_msi_ops x86_msi = {
.setup_msi_irqs = native_setup_msi_irqs,
- .compose_msi_msg = native_compose_msi_msg,
.teardown_msi_irq = native_teardown_msi_irq,
.teardown_msi_irqs = default_teardown_msi_irqs,
.restore_msi_irqs = default_restore_msi_irqs,
- .setup_hpet_msi = default_setup_hpet_msi,
.msi_mask_irq = default_msi_mask_irq,
.msix_mask_irq = default_msix_mask_irq,
};
diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c
index f92d49110f83..8fabc1d05f93 100644
--- a/drivers/iommu/irq_remapping.c
+++ b/drivers/iommu/irq_remapping.c
@@ -26,9 +26,6 @@ int no_x2apic_optout;
static struct irq_remap_ops *remap_ops;
-static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec);
-static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
- int index, int sub_handle);
static int set_remapped_irq_affinity(struct irq_data *data,
const struct cpumask *mask,
bool force);
@@ -51,117 +48,6 @@ static void irq_remapping_disable_io_apic(void)
disconnect_bsp_APIC(0);
}
-#ifndef CONFIG_GENERIC_IRQ_LEGACY_ALLOC_HWIRQ
-static unsigned int irq_alloc_hwirqs(int cnt, int node)
-{
- return irq_domain_alloc_irqs(NULL, -1, cnt, node, NULL);
-}
-
-static void irq_free_hwirqs(unsigned int from, int cnt)
-{
- irq_domain_free_irqs(from, cnt);
-}
-#endif
-
-static int do_setup_msi_irqs(struct pci_dev *dev, int nvec)
-{
- int ret, sub_handle, nvec_pow2, index = 0;
- 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);
- if (index < 0) {
- ret = index;
- goto error;
- }
- } else {
- ret = msi_setup_remapped_irq(dev, irq + sub_handle,
- index, sub_handle);
- if (ret < 0)
- goto error;
- }
- ret = setup_msi_irq(dev, msidesc, irq, sub_handle);
- if (ret < 0)
- goto error;
- }
- return 0;
-
-error:
- irq_free_hwirqs(irq, nvec);
-
- /*
- * Restore altered MSI descriptor fields and prevent just destroyed
- * IRQs from tearing down again in default_teardown_msi_irqs()
- */
- msidesc->irq = 0;
- msidesc->nvec_used = 0;
- msidesc->msi_attrib.multiple = 0;
-
- return ret;
-}
-
-static int do_setup_msix_irqs(struct pci_dev *dev, int nvec)
-{
- int node, ret, sub_handle, index = 0;
- struct msi_desc *msidesc;
- unsigned int irq;
-
- node = dev_to_node(&dev->dev);
- sub_handle = 0;
-
- list_for_each_entry(msidesc, &dev->msi_list, list) {
-
- irq = irq_alloc_hwirqs(1, node);
- if (irq == 0)
- return -1;
-
- if (sub_handle == 0)
- ret = index = msi_alloc_remapped_irq(dev, irq, nvec);
- else
- ret = msi_setup_remapped_irq(dev, irq, index, sub_handle);
-
- if (ret < 0)
- goto error;
-
- ret = setup_msi_irq(dev, msidesc, irq, 0);
- if (ret < 0)
- goto error;
-
- sub_handle += 1;
- irq += 1;
- }
-
- return 0;
-
-error:
- irq_free_hwirqs(irq, 1);
- return ret;
-}
-
-static int irq_remapping_setup_msi_irqs(struct pci_dev *dev,
- int nvec, int type)
-{
- if (type == PCI_CAP_ID_MSI)
- return do_setup_msi_irqs(dev, nvec);
- else
- return do_setup_msix_irqs(dev, nvec);
-}
-
static void eoi_ioapic_pin_remapped(int apic, int pin, int vector)
{
/*
@@ -179,8 +65,6 @@ static void __init irq_remapping_modify_x86_ops(void)
x86_io_apic_ops.set_affinity = set_remapped_irq_affinity;
x86_io_apic_ops.setup_entry = setup_ioapic_remapped_entry;
x86_io_apic_ops.eoi_ioapic_pin = eoi_ioapic_pin_remapped;
- x86_msi.setup_hpet_msi = setup_hpet_msi_remapped;
- x86_msi.compose_msi_msg = compose_remapped_msi_msg;
}
static __init int setup_nointremap(char *str)
@@ -327,49 +211,6 @@ void free_remapped_irq(int irq)
remap_ops->free_irq(irq);
}
-void compose_remapped_msi_msg(struct pci_dev *pdev,
- unsigned int irq, unsigned int dest,
- struct msi_msg *msg, u8 hpet_id)
-{
- struct irq_cfg *cfg = irq_cfg(irq);
-
- if (!irq_remapped(cfg))
- native_compose_msi_msg(pdev, irq, dest, msg, hpet_id);
- else if (remap_ops && remap_ops->compose_msi_msg)
- remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id);
-}
-
-static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec)
-{
- if (!remap_ops || !remap_ops->msi_alloc_irq)
- return -ENODEV;
-
- return remap_ops->msi_alloc_irq(pdev, irq, nvec);
-}
-
-static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
- int index, int sub_handle)
-{
- if (!remap_ops || !remap_ops->msi_setup_irq)
- return -ENODEV;
-
- return remap_ops->msi_setup_irq(pdev, irq, index, sub_handle);
-}
-
-int setup_hpet_msi_remapped(unsigned int irq, unsigned int id)
-{
- int ret;
-
- if (!remap_ops || !remap_ops->alloc_hpet_msi)
- return -ENODEV;
-
- ret = remap_ops->alloc_hpet_msi(irq, id);
- if (ret)
- return -EINVAL;
-
- return default_setup_hpet_msi(irq, id);
-}
-
void panic_if_irq_remap(const char *msg)
{
if (irq_remapping_enabled)
diff --git a/drivers/iommu/irq_remapping.h b/drivers/iommu/irq_remapping.h
index fd0270b7a351..b01a51ed1780 100644
--- a/drivers/iommu/irq_remapping.h
+++ b/drivers/iommu/irq_remapping.h
@@ -70,20 +70,6 @@ struct irq_remap_ops {
/* Free an IRQ */
int (*free_irq)(int);
- /* Create MSI msg to use for interrupt remapping */
- void (*compose_msi_msg)(struct pci_dev *,
- unsigned int, unsigned int,
- struct msi_msg *, u8);
-
- /* Allocate remapping resources for MSI */
- int (*msi_alloc_irq)(struct pci_dev *, int, int);
-
- /* Setup the remapped MSI irq */
- int (*msi_setup_irq)(struct pci_dev *, unsigned int, int, int);
-
- /* 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 *);
--
1.7.10.4
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [Patch Part2 v3 21/24] iommu/vt-d: Refine the interfaces to create IRQ for DMAR unit
[not found] ` <1414484803-10311-1-git-send-email-jiang.liu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
` (8 preceding siblings ...)
2014-10-28 8:26 ` [Patch Part2 v3 19/24] x86: irq_remapping: " Jiang Liu
@ 2014-10-28 8:26 ` Jiang Liu
9 siblings, 0 replies; 17+ messages in thread
From: Jiang Liu @ 2014-10-28 8:26 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Thomas Gleixner, Ingo Molnar,
H. Peter Anvin, Rafael J. Wysocki, Bjorn Helgaas, Randy Dunlap,
Yinghai Lu, Borislav Petkov, Grant Likely, Marc Zyngier,
Yingjoe Chen, Tony Luck, Fenghua Yu, x86-DgEjT+Ai2ygdnm+yROfE0A,
Joerg Roedel, Vinod Koul, Matthias Brugger, Jiang Liu
Cc: linux-ia64-u79uwXL29TY76Z2rM5mHXA, Greg Kroah-Hartman,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-acpi-u79uwXL29TY76Z2rM5mHXA,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-pci-u79uwXL29TY76Z2rM5mHXA,
dmaengine-u79uwXL29TY76Z2rM5mHXA, Andrew Morton,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Refine the interfaces to create IRQ for DMAR unit. It's a preparation
for converting DMAR IRQ to irqdomain on x86.
It also moves dmar_alloc_hwirq()/dmar_free_hwirq() from irq_remapping.h
to dmar.h. They are not irq_remapping specific.
Signed-off-by: Jiang Liu <jiang.liu-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
---
arch/ia64/include/asm/irq_remapping.h | 2 --
arch/ia64/kernel/msi_ia64.c | 30 +++++++++++++++++++-----------
arch/x86/include/asm/irq_remapping.h | 4 ----
arch/x86/kernel/apic/msi.c | 24 +++++++++++++-----------
drivers/iommu/dmar.c | 19 +++++--------------
include/linux/dmar.h | 3 ++-
6 files changed, 39 insertions(+), 43 deletions(-)
diff --git a/arch/ia64/include/asm/irq_remapping.h b/arch/ia64/include/asm/irq_remapping.h
index e3b3556e2e1b..a8687b1d8906 100644
--- a/arch/ia64/include/asm/irq_remapping.h
+++ b/arch/ia64/include/asm/irq_remapping.h
@@ -1,6 +1,4 @@
#ifndef __IA64_INTR_REMAPPING_H
#define __IA64_INTR_REMAPPING_H
#define irq_remapping_enabled 0
-#define dmar_alloc_hwirq create_irq
-#define dmar_free_hwirq destroy_irq
#endif
diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c
index 8c3730c3c63d..15032330573b 100644
--- a/arch/ia64/kernel/msi_ia64.c
+++ b/arch/ia64/kernel/msi_ia64.c
@@ -166,7 +166,7 @@ static struct irq_chip dmar_msi_type = {
.irq_retrigger = ia64_msi_retrigger_irq,
};
-static int
+static void
msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
{
struct irq_cfg *cfg = irq_cfg + irq;
@@ -188,21 +188,29 @@ msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
MSI_DATA_LEVEL_ASSERT |
MSI_DATA_DELIVERY_FIXED |
MSI_DATA_VECTOR(cfg->vector);
- return 0;
}
-int arch_setup_dmar_msi(unsigned int irq)
+int dmar_alloc_hwirq(int id, int node, void *arg)
{
- int ret;
+ int irq;
struct msi_msg msg;
- ret = msi_compose_msg(NULL, irq, &msg);
- if (ret < 0)
- return ret;
- dmar_msi_write(irq, &msg);
- irq_set_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq,
- "edge");
- return 0;
+ irq = create_irq();
+ if (irq > 0) {
+ irq_set_handler_data(irq, arg);
+ irq_set_chip_and_handler_name(irq, &dmar_msi_type,
+ handle_edge_irq, "edge");
+ msi_compose_msg(NULL, irq, &msg);
+ dmar_msi_write(irq, &msg);
+ }
+
+ return irq;
+}
+
+void dmar_free_hwirq(int irq)
+{
+ irq_set_handler_data(irq, NULL);
+ destroy_irq(irq);
}
#endif /* CONFIG_INTEL_IOMMU */
diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h
index cda6efe15f63..68d6dfcf7d92 100644
--- a/arch/x86/include/asm/irq_remapping.h
+++ b/arch/x86/include/asm/irq_remapping.h
@@ -159,8 +159,4 @@ static inline bool irq_remapping_domain_is_remapped(struct irq_domain *domain)
#define irq_remapping_print_chip NULL
#endif /* CONFIG_IRQ_REMAP */
-
-extern int dmar_alloc_hwirq(void);
-extern void dmar_free_hwirq(int irq);
-
#endif /* __X86_IRQ_REMAPPING_H */
diff --git a/arch/x86/kernel/apic/msi.c b/arch/x86/kernel/apic/msi.c
index 20350b2aaaab..11ced51d6ef2 100644
--- a/arch/x86/kernel/apic/msi.c
+++ b/arch/x86/kernel/apic/msi.c
@@ -334,25 +334,27 @@ static struct irq_chip dmar_msi_type = {
.flags = IRQCHIP_SKIP_SET_WAKE,
};
-int arch_setup_dmar_msi(unsigned int irq)
+int dmar_alloc_hwirq(int id, int node, void *arg)
{
+ int irq;
struct msi_msg msg;
- struct irq_cfg *cfg = irq_cfg(irq);
- native_compose_msi_msg(cfg, &msg);
- dmar_msi_write(irq, &msg);
- irq_set_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq,
- "edge");
- return 0;
-}
+ irq = irq_domain_alloc_irqs(NULL, 1, node, NULL);
+ if (irq > 0) {
+ irq_set_handler_data(irq, arg);
+ irq_set_chip_and_handler_name(irq, &dmar_msi_type,
+ handle_edge_irq, "edge");
+ native_compose_msi_msg(irq_cfg(irq), &msg);
+ dmar_msi_write(irq, &msg);
+ }
-int dmar_alloc_hwirq(void)
-{
- return irq_domain_alloc_irqs(NULL, 1, NUMA_NO_NODE, NULL);
+ return irq;
}
void dmar_free_hwirq(int irq)
{
+ irq_set_handler_data(irq, NULL);
+ irq_set_handler(irq, NULL);
irq_domain_free_irqs(irq, 1);
}
#endif
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index c5c61cabd6e3..25f47937f1d5 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -1018,8 +1018,8 @@ static void free_iommu(struct intel_iommu *iommu)
if (iommu->irq) {
free_irq(iommu->irq, iommu);
- irq_set_handler_data(iommu->irq, NULL);
dmar_free_hwirq(iommu->irq);
+ iommu->irq = 0;
}
if (iommu->qi) {
@@ -1572,23 +1572,14 @@ int dmar_set_interrupt(struct intel_iommu *iommu)
if (iommu->irq)
return 0;
- irq = dmar_alloc_hwirq();
- if (irq <= 0) {
+ irq = dmar_alloc_hwirq(iommu->seq_id, iommu->node, iommu);
+ if (irq > 0) {
+ iommu->irq = irq;
+ } else {
pr_err("IOMMU: no free vectors\n");
return -EINVAL;
}
- irq_set_handler_data(irq, iommu);
- iommu->irq = irq;
-
- ret = arch_setup_dmar_msi(irq);
- if (ret) {
- irq_set_handler_data(irq, NULL);
- iommu->irq = 0;
- dmar_free_hwirq(irq);
- return ret;
- }
-
ret = request_irq(irq, dmar_fault, IRQF_NO_THREAD, iommu->name, iommu);
if (ret)
pr_err("IOMMU: can't request irq\n");
diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index 593fff99e6bf..df3918482073 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -189,6 +189,7 @@ extern void dmar_msi_read(int irq, struct msi_msg *msg);
extern void dmar_msi_write(int irq, struct msi_msg *msg);
extern int dmar_set_interrupt(struct intel_iommu *iommu);
extern irqreturn_t dmar_fault(int irq, void *dev_id);
-extern int arch_setup_dmar_msi(unsigned int irq);
+extern int dmar_alloc_hwirq(int id, int node, void *arg);
+extern void dmar_free_hwirq(int irq);
#endif /* __DMAR_H__ */
--
1.7.10.4
^ permalink raw reply related [flat|nested] 17+ messages in thread