aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiang Liu <jiang.liu@linux.intel.com>2015-04-13 02:11:35 -0400
committerThomas Gleixner <tglx@linutronix.de>2015-04-24 09:36:49 -0400
commit52f518a3a7c2f80551a38d38be28bc9f335e713c (patch)
tree76b270835fbb27ffdaf72004594405bc058c7d54
parent3cb96f0c97330834929abe9bd2ca3c252a83def0 (diff)
x86/MSI: Use hierarchical irqdomains to manage MSI interrupts
Enhance MSI code to support hierarchical irqdomains, it helps to make the architecture more clear. Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com> Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Cc: David Cohen <david.a.cohen@linux.intel.com> Cc: Sander Eikelenboom <linux@eikelenboom.it> Cc: David Vrabel <david.vrabel@citrix.com> Cc: Tony Luck <tony.luck@intel.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: iommu@lists.linux-foundation.org Cc: Joerg Roedel <jroedel@suse.de> Cc: Bjorn Helgaas <bhelgaas@google.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Rafael J. Wysocki <rjw@rjwysocki.net> Cc: Randy Dunlap <rdunlap@infradead.org> Cc: Yinghai Lu <yinghai@kernel.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Dimitri Sivanich <sivanich@sgi.com> Cc: Joerg Roedel <joro@8bytes.org> Link: http://lkml.kernel.org/r/1428905519-23704-14-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--arch/x86/Kconfig1
-rw-r--r--arch/x86/include/asm/hw_irq.h9
-rw-r--r--arch/x86/include/asm/irq_remapping.h6
-rw-r--r--arch/x86/include/asm/msi.h7
-rw-r--r--arch/x86/kernel/apic/msi.c141
-rw-r--r--arch/x86/kernel/apic/vector.c2
-rw-r--r--drivers/iommu/irq_remapping.c1
7 files changed, 94 insertions, 73 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index e75a96c38c58..26e066579637 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -914,6 +914,7 @@ config X86_LOCAL_APIC
914 depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC || PCI_MSI 914 depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC || PCI_MSI
915 select GENERIC_IRQ_LEGACY_ALLOC_HWIRQ 915 select GENERIC_IRQ_LEGACY_ALLOC_HWIRQ
916 select IRQ_DOMAIN_HIERARCHY 916 select IRQ_DOMAIN_HIERARCHY
917 select PCI_MSI_IRQ_DOMAIN if PCI_MSI
917 918
918config X86_IO_APIC 919config X86_IO_APIC
919 def_bool y 920 def_bool y
diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
index 75a97a5bbfa8..05829e973a2a 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 {
110}; 110};
111#endif /* CONFIG_IRQ_REMAP */ 111#endif /* CONFIG_IRQ_REMAP */
112 112
113struct irq_domain;
114
113#ifdef CONFIG_X86_LOCAL_APIC 115#ifdef CONFIG_X86_LOCAL_APIC
114struct irq_data; 116struct irq_data;
115struct irq_domain;
116struct pci_dev; 117struct pci_dev;
117struct msi_desc; 118struct msi_desc;
118 119
@@ -214,6 +215,12 @@ static inline void lock_vector_lock(void) {}
214static inline void unlock_vector_lock(void) {} 215static inline void unlock_vector_lock(void) {}
215#endif /* CONFIG_X86_LOCAL_APIC */ 216#endif /* CONFIG_X86_LOCAL_APIC */
216 217
218#ifdef CONFIG_PCI_MSI
219extern void arch_init_msi_domain(struct irq_domain *domain);
220#else
221static inline void arch_init_msi_domain(struct irq_domain *domain) { }
222#endif
223
217/* Statistics */ 224/* Statistics */
218extern atomic_t irq_err_count; 225extern atomic_t irq_err_count;
219extern atomic_t irq_mis_count; 226extern atomic_t irq_mis_count;
diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h
index 0cd6195cc375..0d3bbd0e2c42 100644
--- a/arch/x86/include/asm/irq_remapping.h
+++ b/arch/x86/include/asm/irq_remapping.h
@@ -66,11 +66,7 @@ irq_remapping_get_irq_domain(struct irq_alloc_info *info);
66extern void irq_remapping_print_chip(struct irq_data *data, struct seq_file *p); 66extern void irq_remapping_print_chip(struct irq_data *data, struct seq_file *p);
67 67
68/* Create PCI MSI/MSIx irqdomain, use @parent as the parent irqdomain. */ 68/* Create PCI MSI/MSIx irqdomain, use @parent as the parent irqdomain. */
69static inline struct irq_domain * 69extern struct irq_domain *arch_create_msi_irq_domain(struct irq_domain *parent);
70arch_create_msi_irq_domain(struct irq_domain *parent)
71{
72 return NULL;
73}
74 70
75/* Get parent irqdomain for interrupt remapping irqdomain */ 71/* Get parent irqdomain for interrupt remapping irqdomain */
76static inline struct irq_domain *arch_get_ir_parent_domain(void) 72static inline struct irq_domain *arch_get_ir_parent_domain(void)
diff --git a/arch/x86/include/asm/msi.h b/arch/x86/include/asm/msi.h
new file mode 100644
index 000000000000..93724cc62177
--- /dev/null
+++ b/arch/x86/include/asm/msi.h
@@ -0,0 +1,7 @@
1#ifndef _ASM_X86_MSI_H
2#define _ASM_X86_MSI_H
3#include <asm/hw_irq.h>
4
5typedef struct irq_alloc_info msi_alloc_info_t;
6
7#endif /* _ASM_X86_MSI_H */
diff --git a/arch/x86/kernel/apic/msi.c b/arch/x86/kernel/apic/msi.c
index 10d9ae8f2166..c426cd58844e 100644
--- a/arch/x86/kernel/apic/msi.c
+++ b/arch/x86/kernel/apic/msi.c
@@ -3,6 +3,8 @@
3 * 3 *
4 * Copyright (C) 1997, 1998, 1999, 2000, 2009 Ingo Molnar, Hajnalka Szabo 4 * Copyright (C) 1997, 1998, 1999, 2000, 2009 Ingo Molnar, Hajnalka Szabo
5 * Moved from arch/x86/kernel/apic/io_apic.c. 5 * Moved from arch/x86/kernel/apic/io_apic.c.
6 * Jiang Liu <jiang.liu@linux.intel.com>
7 * Convert to hierarchical irqdomain
6 * 8 *
7 * This program is free software; you can redistribute it and/or modify 9 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as 10 * it under the terms of the GNU General Public License version 2 as
@@ -21,6 +23,8 @@
21#include <asm/apic.h> 23#include <asm/apic.h>
22#include <asm/irq_remapping.h> 24#include <asm/irq_remapping.h>
23 25
26static struct irq_domain *msi_default_domain;
27
24void native_compose_msi_msg(struct pci_dev *pdev, 28void native_compose_msi_msg(struct pci_dev *pdev,
25 unsigned int irq, unsigned int dest, 29 unsigned int irq, unsigned int dest,
26 struct msi_msg *msg, u8 hpet_id) 30 struct msi_msg *msg, u8 hpet_id)
@@ -114,102 +118,107 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
114 return 0; 118 return 0;
115} 119}
116 120
117static int
118msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
119{
120 struct irq_cfg *cfg = irqd_cfg(data);
121 struct msi_msg msg;
122 unsigned int dest;
123 int ret;
124
125 ret = apic_set_affinity(data, mask, &dest);
126 if (ret)
127 return ret;
128
129 __get_cached_msi_msg(data->msi_desc, &msg);
130
131 msg.data &= ~MSI_DATA_VECTOR_MASK;
132 msg.data |= MSI_DATA_VECTOR(cfg->vector);
133 msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
134 msg.address_lo |= MSI_ADDR_DEST_ID(dest);
135
136 __pci_write_msi_msg(data->msi_desc, &msg);
137
138 return IRQ_SET_MASK_OK_NOCOPY;
139}
140
141/* 121/*
142 * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, 122 * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
143 * which implement the MSI or MSI-X Capability Structure. 123 * which implement the MSI or MSI-X Capability Structure.
144 */ 124 */
145static struct irq_chip msi_chip = { 125static struct irq_chip pci_msi_controller = {
146 .name = "PCI-MSI", 126 .name = "PCI-MSI",
147 .irq_unmask = pci_msi_unmask_irq, 127 .irq_unmask = pci_msi_unmask_irq,
148 .irq_mask = pci_msi_mask_irq, 128 .irq_mask = pci_msi_mask_irq,
149 .irq_ack = apic_ack_edge, 129 .irq_ack = irq_chip_ack_parent,
150 .irq_set_affinity = msi_set_affinity, 130 .irq_set_affinity = msi_domain_set_affinity,
151 .irq_retrigger = apic_retrigger_irq, 131 .irq_retrigger = irq_chip_retrigger_hierarchy,
132 .irq_print_chip = irq_remapping_print_chip,
133 .irq_compose_msi_msg = irq_msi_compose_msg,
134 .irq_write_msi_msg = pci_msi_domain_write_msg,
152 .flags = IRQCHIP_SKIP_SET_WAKE, 135 .flags = IRQCHIP_SKIP_SET_WAKE,
153}; 136};
154 137
155int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, 138int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
156 unsigned int irq_base, unsigned int irq_offset)
157{ 139{
158 struct irq_chip *chip = &msi_chip; 140 struct irq_domain *domain;
159 struct msi_msg msg; 141 struct irq_alloc_info info;
160 unsigned int irq = irq_base + irq_offset;
161 int ret;
162 142
163 ret = msi_compose_msg(dev, irq, &msg, -1); 143 init_irq_alloc_info(&info, NULL);
164 if (ret < 0) 144 info.type = X86_IRQ_ALLOC_TYPE_MSI;
165 return ret; 145 info.msi_dev = dev;
166 146
167 irq_set_msi_desc_off(irq_base, irq_offset, msidesc); 147 domain = irq_remapping_get_irq_domain(&info);
148 if (domain == NULL)
149 domain = msi_default_domain;
150 if (domain == NULL)
151 return -ENOSYS;
168 152
169 /* 153 return pci_msi_domain_alloc_irqs(domain, dev, nvec, type);
170 * MSI-X message is written per-IRQ, the offset is always 0. 154}
171 * MSI message denotes a contiguous group of IRQs, written for 0th IRQ.
172 */
173 if (!irq_offset)
174 pci_write_msi_msg(irq, &msg);
175 155
176 setup_remapped_irq(irq, irq_cfg(irq), chip); 156void native_teardown_msi_irq(unsigned int irq)
157{
158 irq_domain_free_irqs(irq, 1);
159}
177 160
178 irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge"); 161static irq_hw_number_t pci_msi_get_hwirq(struct msi_domain_info *info,
162 msi_alloc_info_t *arg)
163{
164 return arg->msi_hwirq;
165}
179 166
180 dev_dbg(&dev->dev, "irq %d for MSI/MSI-X\n", irq); 167static int pci_msi_prepare(struct irq_domain *domain, struct device *dev,
168 int nvec, msi_alloc_info_t *arg)
169{
170 struct pci_dev *pdev = to_pci_dev(dev);
171 struct msi_desc *desc = first_pci_msi_entry(pdev);
172
173 init_irq_alloc_info(arg, NULL);
174 arg->msi_dev = pdev;
175 if (desc->msi_attrib.is_msix) {
176 arg->type = X86_IRQ_ALLOC_TYPE_MSIX;
177 } else {
178 arg->type = X86_IRQ_ALLOC_TYPE_MSI;
179 arg->flags |= X86_IRQ_ALLOC_CONTIGUOUS_VECTORS;
180 }
181 181
182 return 0; 182 return 0;
183} 183}
184 184
185int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) 185static void pci_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
186{ 186{
187 struct msi_desc *msidesc; 187 arg->msi_hwirq = pci_msi_domain_calc_hwirq(arg->msi_dev, desc);
188 int irq, ret; 188}
189 189
190 /* Multiple MSI vectors only supported with interrupt remapping */ 190static struct msi_domain_ops pci_msi_domain_ops = {
191 if (type == PCI_CAP_ID_MSI && nvec > 1) 191 .get_hwirq = pci_msi_get_hwirq,
192 return 1; 192 .msi_prepare = pci_msi_prepare,
193 .set_desc = pci_msi_set_desc,
194};
193 195
194 list_for_each_entry(msidesc, &dev->msi_list, list) { 196static struct msi_domain_info pci_msi_domain_info = {
195 irq = irq_domain_alloc_irqs(NULL, 1, NUMA_NO_NODE, NULL); 197 .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
196 if (irq <= 0) 198 MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX,
197 return -ENOSPC; 199 .ops = &pci_msi_domain_ops,
200 .chip = &pci_msi_controller,
201 .handler = handle_edge_irq,
202 .handler_name = "edge",
203};
198 204
199 ret = setup_msi_irq(dev, msidesc, irq, 0); 205void arch_init_msi_domain(struct irq_domain *parent)
200 if (ret < 0) { 206{
201 irq_domain_free_irqs(irq, 1); 207 if (disable_apic)
202 return ret; 208 return;
203 }
204 209
205 } 210 msi_default_domain = pci_msi_create_irq_domain(NULL,
206 return 0; 211 &pci_msi_domain_info, parent);
212 if (!msi_default_domain)
213 pr_warn("failed to initialize irqdomain for MSI/MSI-x.\n");
207} 214}
208 215
209void native_teardown_msi_irq(unsigned int irq) 216#ifdef CONFIG_IRQ_REMAP
217struct irq_domain *arch_create_msi_irq_domain(struct irq_domain *parent)
210{ 218{
211 irq_domain_free_irqs(irq, 1); 219 return msi_create_irq_domain(NULL, &pci_msi_domain_info, parent);
212} 220}
221#endif
213 222
214#ifdef CONFIG_DMAR_TABLE 223#ifdef CONFIG_DMAR_TABLE
215static int 224static int
diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c
index 6358d8d351f5..a8d82896be75 100644
--- a/arch/x86/kernel/apic/vector.c
+++ b/arch/x86/kernel/apic/vector.c
@@ -364,6 +364,8 @@ int __init arch_early_irq_init(void)
364 BUG_ON(x86_vector_domain == NULL); 364 BUG_ON(x86_vector_domain == NULL);
365 irq_set_default_host(x86_vector_domain); 365 irq_set_default_host(x86_vector_domain);
366 366
367 arch_init_msi_domain(x86_vector_domain);
368
367 return arch_early_ioapic_init(); 369 return arch_early_ioapic_init();
368} 370}
369 371
diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c
index c306421d86c1..d77e3711c2aa 100644
--- a/drivers/iommu/irq_remapping.c
+++ b/drivers/iommu/irq_remapping.c
@@ -170,7 +170,6 @@ static void __init irq_remapping_modify_x86_ops(void)
170 x86_io_apic_ops.set_affinity = set_remapped_irq_affinity; 170 x86_io_apic_ops.set_affinity = set_remapped_irq_affinity;
171 x86_io_apic_ops.setup_entry = setup_ioapic_remapped_entry; 171 x86_io_apic_ops.setup_entry = setup_ioapic_remapped_entry;
172 x86_io_apic_ops.eoi_ioapic_pin = eoi_ioapic_pin_remapped; 172 x86_io_apic_ops.eoi_ioapic_pin = eoi_ioapic_pin_remapped;
173 x86_msi.setup_msi_irqs = irq_remapping_setup_msi_irqs;
174 x86_msi.setup_hpet_msi = setup_hpet_msi_remapped; 173 x86_msi.setup_hpet_msi = setup_hpet_msi_remapped;
175 x86_msi.compose_msi_msg = compose_remapped_msi_msg; 174 x86_msi.compose_msi_msg = compose_remapped_msi_msg;
176} 175}