Skip to content

Commit 52f518a

Browse files
Jiang LiuKAGA-KOKO
authored andcommitted
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 <[email protected]> Cc: Konrad Rzeszutek Wilk <[email protected]> Cc: David Cohen <[email protected]> Cc: Sander Eikelenboom <[email protected]> Cc: David Vrabel <[email protected]> Cc: Tony Luck <[email protected]> Cc: Greg Kroah-Hartman <[email protected]> Cc: [email protected] Cc: Joerg Roedel <[email protected]> Cc: Bjorn Helgaas <[email protected]> Cc: Benjamin Herrenschmidt <[email protected]> Cc: Rafael J. Wysocki <[email protected]> Cc: Randy Dunlap <[email protected]> Cc: Yinghai Lu <[email protected]> Cc: Borislav Petkov <[email protected]> Cc: Dimitri Sivanich <[email protected]> Cc: Joerg Roedel <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Thomas Gleixner <[email protected]>
1 parent 3cb96f0 commit 52f518a

File tree

7 files changed

+94
-73
lines changed

7 files changed

+94
-73
lines changed

arch/x86/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -914,6 +914,7 @@ config X86_LOCAL_APIC
914914
depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC || PCI_MSI
915915
select GENERIC_IRQ_LEGACY_ALLOC_HWIRQ
916916
select IRQ_DOMAIN_HIERARCHY
917+
select PCI_MSI_IRQ_DOMAIN if PCI_MSI
917918

918919
config X86_IO_APIC
919920
def_bool y

arch/x86/include/asm/hw_irq.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,10 @@ struct irq_2_irte {
110110
};
111111
#endif /* CONFIG_IRQ_REMAP */
112112

113+
struct irq_domain;
114+
113115
#ifdef CONFIG_X86_LOCAL_APIC
114116
struct irq_data;
115-
struct irq_domain;
116117
struct pci_dev;
117118
struct msi_desc;
118119

@@ -214,6 +215,12 @@ static inline void lock_vector_lock(void) {}
214215
static inline void unlock_vector_lock(void) {}
215216
#endif /* CONFIG_X86_LOCAL_APIC */
216217

218+
#ifdef CONFIG_PCI_MSI
219+
extern void arch_init_msi_domain(struct irq_domain *domain);
220+
#else
221+
static inline void arch_init_msi_domain(struct irq_domain *domain) { }
222+
#endif
223+
217224
/* Statistics */
218225
extern atomic_t irq_err_count;
219226
extern atomic_t irq_mis_count;

arch/x86/include/asm/irq_remapping.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,7 @@ irq_remapping_get_irq_domain(struct irq_alloc_info *info);
6666
extern void irq_remapping_print_chip(struct irq_data *data, struct seq_file *p);
6767

6868
/* Create PCI MSI/MSIx irqdomain, use @parent as the parent irqdomain. */
69-
static inline struct irq_domain *
70-
arch_create_msi_irq_domain(struct irq_domain *parent)
71-
{
72-
return NULL;
73-
}
69+
extern struct irq_domain *arch_create_msi_irq_domain(struct irq_domain *parent);
7470

7571
/* Get parent irqdomain for interrupt remapping irqdomain */
7672
static inline struct irq_domain *arch_get_ir_parent_domain(void)

arch/x86/include/asm/msi.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#ifndef _ASM_X86_MSI_H
2+
#define _ASM_X86_MSI_H
3+
#include <asm/hw_irq.h>
4+
5+
typedef struct irq_alloc_info msi_alloc_info_t;
6+
7+
#endif /* _ASM_X86_MSI_H */

arch/x86/kernel/apic/msi.c

Lines changed: 75 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
*
44
* Copyright (C) 1997, 1998, 1999, 2000, 2009 Ingo Molnar, Hajnalka Szabo
55
* Moved from arch/x86/kernel/apic/io_apic.c.
6+
* Jiang Liu <[email protected]>
7+
* Convert to hierarchical irqdomain
68
*
79
* This program is free software; you can redistribute it and/or modify
810
* it under the terms of the GNU General Public License version 2 as
@@ -21,6 +23,8 @@
2123
#include <asm/apic.h>
2224
#include <asm/irq_remapping.h>
2325

26+
static struct irq_domain *msi_default_domain;
27+
2428
void native_compose_msi_msg(struct pci_dev *pdev,
2529
unsigned int irq, unsigned int dest,
2630
struct msi_msg *msg, u8 hpet_id)
@@ -114,102 +118,107 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
114118
return 0;
115119
}
116120

117-
static int
118-
msi_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-
141121
/*
142122
* IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
143123
* which implement the MSI or MSI-X Capability Structure.
144124
*/
145-
static struct irq_chip msi_chip = {
125+
static struct irq_chip pci_msi_controller = {
146126
.name = "PCI-MSI",
147127
.irq_unmask = pci_msi_unmask_irq,
148128
.irq_mask = pci_msi_mask_irq,
149-
.irq_ack = apic_ack_edge,
150-
.irq_set_affinity = msi_set_affinity,
151-
.irq_retrigger = apic_retrigger_irq,
129+
.irq_ack = irq_chip_ack_parent,
130+
.irq_set_affinity = msi_domain_set_affinity,
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,
152135
.flags = IRQCHIP_SKIP_SET_WAKE,
153136
};
154137

155-
int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
156-
unsigned int irq_base, unsigned int irq_offset)
138+
int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
157139
{
158-
struct irq_chip *chip = &msi_chip;
159-
struct msi_msg msg;
160-
unsigned int irq = irq_base + irq_offset;
161-
int ret;
140+
struct irq_domain *domain;
141+
struct irq_alloc_info info;
162142

163-
ret = msi_compose_msg(dev, irq, &msg, -1);
164-
if (ret < 0)
165-
return ret;
143+
init_irq_alloc_info(&info, NULL);
144+
info.type = X86_IRQ_ALLOC_TYPE_MSI;
145+
info.msi_dev = dev;
166146

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;
168152

169-
/*
170-
* MSI-X message is written per-IRQ, the offset is always 0.
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);
153+
return pci_msi_domain_alloc_irqs(domain, dev, nvec, type);
154+
}
175155

176-
setup_remapped_irq(irq, irq_cfg(irq), chip);
156+
void native_teardown_msi_irq(unsigned int irq)
157+
{
158+
irq_domain_free_irqs(irq, 1);
159+
}
177160

178-
irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
161+
static 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+
}
179166

180-
dev_dbg(&dev->dev, "irq %d for MSI/MSI-X\n", irq);
167+
static 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+
}
181181

182182
return 0;
183183
}
184184

185-
int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
185+
static void pci_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
186186
{
187-
struct msi_desc *msidesc;
188-
int irq, ret;
187+
arg->msi_hwirq = pci_msi_domain_calc_hwirq(arg->msi_dev, desc);
188+
}
189189

190-
/* Multiple MSI vectors only supported with interrupt remapping */
191-
if (type == PCI_CAP_ID_MSI && nvec > 1)
192-
return 1;
190+
static struct msi_domain_ops pci_msi_domain_ops = {
191+
.get_hwirq = pci_msi_get_hwirq,
192+
.msi_prepare = pci_msi_prepare,
193+
.set_desc = pci_msi_set_desc,
194+
};
193195

194-
list_for_each_entry(msidesc, &dev->msi_list, list) {
195-
irq = irq_domain_alloc_irqs(NULL, 1, NUMA_NO_NODE, NULL);
196-
if (irq <= 0)
197-
return -ENOSPC;
196+
static struct msi_domain_info pci_msi_domain_info = {
197+
.flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
198+
MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX,
199+
.ops = &pci_msi_domain_ops,
200+
.chip = &pci_msi_controller,
201+
.handler = handle_edge_irq,
202+
.handler_name = "edge",
203+
};
198204

199-
ret = setup_msi_irq(dev, msidesc, irq, 0);
200-
if (ret < 0) {
201-
irq_domain_free_irqs(irq, 1);
202-
return ret;
203-
}
205+
void arch_init_msi_domain(struct irq_domain *parent)
206+
{
207+
if (disable_apic)
208+
return;
204209

205-
}
206-
return 0;
210+
msi_default_domain = pci_msi_create_irq_domain(NULL,
211+
&pci_msi_domain_info, parent);
212+
if (!msi_default_domain)
213+
pr_warn("failed to initialize irqdomain for MSI/MSI-x.\n");
207214
}
208215

209-
void native_teardown_msi_irq(unsigned int irq)
216+
#ifdef CONFIG_IRQ_REMAP
217+
struct irq_domain *arch_create_msi_irq_domain(struct irq_domain *parent)
210218
{
211-
irq_domain_free_irqs(irq, 1);
219+
return msi_create_irq_domain(NULL, &pci_msi_domain_info, parent);
212220
}
221+
#endif
213222

214223
#ifdef CONFIG_DMAR_TABLE
215224
static int

arch/x86/kernel/apic/vector.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,8 @@ int __init arch_early_irq_init(void)
364364
BUG_ON(x86_vector_domain == NULL);
365365
irq_set_default_host(x86_vector_domain);
366366

367+
arch_init_msi_domain(x86_vector_domain);
368+
367369
return arch_early_ioapic_init();
368370
}
369371

drivers/iommu/irq_remapping.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,6 @@ static void __init irq_remapping_modify_x86_ops(void)
170170
x86_io_apic_ops.set_affinity = set_remapped_irq_affinity;
171171
x86_io_apic_ops.setup_entry = setup_ioapic_remapped_entry;
172172
x86_io_apic_ops.eoi_ioapic_pin = eoi_ioapic_pin_remapped;
173-
x86_msi.setup_msi_irqs = irq_remapping_setup_msi_irqs;
174173
x86_msi.setup_hpet_msi = setup_hpet_msi_remapped;
175174
x86_msi.compose_msi_msg = compose_remapped_msi_msg;
176175
}

0 commit comments

Comments
 (0)