Enable hierarchy irqdomian on x86 platforms
Subsystems (9)
v5 cover Enable hierarchy irqdomian on x86 platforms
We plan to restructure x86 interrupt code based on hierarchy irqdomain, that is to build irqdomains for CPU vector, interrupt remapping unit, IOAPIC, MSI and HPET etc and organize those irqdomains in hierarchy mode. Each irqdomain manages corresponding interrupt controller and talks to parent interrupt controller through public irqdomain interfaces. We also support stacked irq_chip based on hierarchy irqdomain. It will make the x86 interrupt architecture much more clear and more easy to maintain with hierarchy irqdomain and stacked irq_chip. It may also help ARM interrupt management architecture too.
This is the second patch set to enable support of hierarchy irqdomain on x86 platforms. It's based on tip/x86/apic branch.
And you may access it at:
https://github.com/jiangliu/linux.git irqdomain/p2v5
And there will be a third patch set to convert IOAPIC driver to support hierarchy irqdomain and clean up code.
Patch 1-5 enhance irqdomain and irq core to support hierarchy irqdomain and stacked irqchip.
Patch 6-12 implement an irqdomain to manange CPU interrupt vectors, and it's the root irqdomain for x86 platforms.
Patch 13-16 converts Intel and AMD interrupt remapping drivers to support hierarchy irqdomain.
Patch 17-23 converts HPET and MSI to support hierarchy irqdomain. Patch 24-27 cleans up unsued code in x86 arch and interrupt remapping drivers.
Patch 28-31 converts DMAR, HTIRQ and UV to support hierarchy irqdomain.
We have tested this patchset on Intel 32-bit and 64-bit systems. And it also passes Fengguang's 0day tests. But helps are need for testing:
1) AMD HT_IRQ
2) UV platform
V4->V5:
1) Refine PCI MSI interfaces to support hierarchy irqdomain
2) Fix a bug with dealing multiple MSI interrupts
3) Improve commit messagesV3->V4:
1) Simplify IRQ remapping interfaces
2) Hide all IRQ remapping logic from MSI/HPET drivers
3) Move most MSI irqdomain code to public drivers/pci/msi.c so it could be resued
4) Improve common PCI MSI code
5) Rebase to tip/x86/apicV2->V3:
1) Fix bugs in handling OF irqdomain
2) Add documentation
3) Rebase to v3.18-rc2V1->V2
1) Add hierarchy iredomain support of DMAR IRQ and UV IRQ.
2) Fix bugs reported by Joe C.
3) Address all review comments from Thomas
4) Fix a bug found during tests
5) Fix errors and warning found by 0day tests
Jiang Liu (30):
irqdomain: Introduce new interfaces to support hierarchy irqdomains
genirq: Introduce helper functions to support stacked irq_chip
genirq: Introduce irq_chip.irq_compose_msi_msg() to support stacked
irqchip
genirq: Add IRQ_SET_MASK_OK_DONE to support stacked irqchip x86, irq: Save destination CPU ID in irq_cfg
x86, irq: Use hierarchy irqdomain to manage CPU interrupt vectors x86, hpet: Use new irqdomain interfaces to allocate/free IRQ x86, MSI: Use new irqdomain interfaces to allocate/free IRQ x86, uv: Use new irqdomain interfaces to allocate/free IRQ x86, htirq: Use new irqdomain interfaces to allocate/free IRQ x86, dmar: Use new irqdomain interfaces to allocate/free IRQ
x86: irq_remapping: Introduce new interfaces to support hierarchy
irqdomain
iommu/vt-d: Change prototypes to prepare for enabling hierarchy
irqdomain
iommu/vt-d: Enhance Intel IR driver to suppport hierarchy irqdomain iommu/amd: Enhance AMD IR driver to suppport hierarchy irqdomain x86, hpet: Enhance HPET IRQ to support hierarchy irqdomain PCI/MSI: Remove unnecessary braces around single statements PCI/MSI: Simplify PCI MSI code by initializing msi_desc.nvec_used
earlier
PCI/MSI: Kill redundant call of irq_set_msi_desc() for MSI-X
interrupts
PCI/MSI: Enhance core to support hierarchy irqdomain x86, PCI, MSI: Use hierarchy irqdomain to manage MSI interrupts x86, irq: Directly call native_compose_msi_msg() for DMAR IRQ iommu/vt-d: Clean up unused MSI related code
iommu/amd: Clean up unused MSI related code
x86: irq_remapping: Clean up unused MSI related code x86, irq: Clean up unused MSI related code and interfaces iommu/vt-d: Refine the interfaces to create IRQ for DMAR unit x86, irq: Use hierarchy irqdomain to manage DMAR interrupts x86, htirq: Use hierarchy irqdomain to manage Hypertransport
interrupts
x86, uv: Use hierarchy irqdomain to manage UV interrupts
Yingjoe Chen (1):
irqdomain: Do irq_find_mapping and set_type for hierarchy irqdomain
in case OF
Documentation/IRQ-domain.txt | 71 +++++ arch/ia64/include/asm/irq_remapping.h | 2 - arch/ia64/kernel/msi_ia64.c | 30 ++- arch/x86/Kconfig | 4 +- arch/x86/include/asm/hpet.h | 16 +- arch/x86/include/asm/hw_irq.h | 87 ++++++ arch/x86/include/asm/irq_remapping.h | 50 ++-- arch/x86/include/asm/pci.h | 5 - arch/x86/include/asm/x86_init.h | 4 - arch/x86/kernel/apic/htirq.c | 174 ++++++++---- arch/x86/kernel/apic/io_apic.c | 3 - arch/x86/kernel/apic/msi.c | 422 ++++++++++++++++++++---------- arch/x86/kernel/apic/vector.c | 165 +++++++++++- arch/x86/kernel/hpet.c | 57 ++-- arch/x86/kernel/x86_init.c | 2 - arch/x86/platform/uv/uv_irq.c | 299 ++++++++------------- drivers/iommu/amd_iommu.c | 378 +++++++++++++++++++++------ drivers/iommu/amd_iommu_init.c | 4 + drivers/iommu/amd_iommu_proto.h | 9 + drivers/iommu/amd_iommu_types.h | 5 + drivers/iommu/dmar.c | 19 +- drivers/iommu/intel_irq_remapping.c | 465 ++++++++++++++++++++++----------- drivers/iommu/irq_remapping.c | 197 ++++---------- drivers/iommu/irq_remapping.h | 20 +- drivers/pci/Kconfig | 4 + drivers/pci/htirq.c | 48 +--- drivers/pci/msi.c | 184 ++++++++++--- include/linux/dmar.h | 3 +- include/linux/htirq.h | 22 +- include/linux/intel-iommu.h | 4 + include/linux/irq.h | 19 ++ include/linux/irqdomain.h | 86 ++++++ include/linux/msi.h | 14 + kernel/irq/Kconfig | 4 + kernel/irq/chip.c | 37 +++ kernel/irq/irqdomain.c | 408 +++++++++++++++++++++++++++-- kernel/irq/manage.c | 2 + 37 files changed, 2327 insertions(+), 996 deletions(-)
Signature · 1 line
1.7.10.4
PATCH v5 1/31 irqdomain: Introduce new interfaces to support hierarchy irqdomains
We plan to use hierarchy irqdomain to suppport CPU vector assignment, interrupt remapping controller, IO-APIC controller, MSI interrupt and hypertransport interrupt etc on x86 platforms. So extend irqdomain interfaces to support hierarchy irqdomain.
There are already many clients of current irqdomain interfaces. To minimize the changes, we choose to introduce new version 2 interfaces to support hierarchy instead of extending existing irqdomain interfaces.
According to Thomas's suggestion, the most important design decision is to build hierarchy struct irq_data to support hierarchy irqdomain, so hierarchy irqdomain related data could be saved in struct irq_data. With support of hierarchy irq_data, we could also support stacked irq_chips. This is most useful in case of set_affinity().
The new hierarchy irqdomain introduces following interfaces:
1) irq_domain_alloc_irqs()/irq_domain_free_irqs(): allocate/release IRQ and related resources.
2) __irq_domain_alloc_irqs(): a special version to support legacy IRQs.
3) irq_domain_activate_irq()/irq_domain_deactivate_irq(): program interrupt controllers to activate/deactivate interrupt.
There are also several help functions to ease irqdomain implemenations:
1) irq_domain_get_irq_data(): get irq_data associated with a specific irqdomain.
2) irq_domain_set_hwirq_and_chip(): save irqdomain specific data into irq_data.
3) irq_domain_alloc_irqs_parent()/irq_domain_free_irqs_parent(): invoke parent irqdomain's alloc/free callbacks.
We also changed irq_startup()/irq_shutdown() to invoke irq_domain_activate_irq()/irq_domain_deactivate_irq() to program interrupt controller when start/stop interrupts.
--- Documentation/IRQ-domain.txt | 71 ++++++++ include/linux/irq.h | 5 + include/linux/irqdomain.h | 86 ++++++++++ kernel/irq/Kconfig | 4 + kernel/irq/chip.c | 3 + kernel/irq/irqdomain.c | 391 ++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 544 insertions(+), 16 deletions(-)
Documentation/IRQ-domain.txt +71 -0
@@ -151,3 +151,74 @@ used and no descriptor gets allocated it is very important to make sure that the driver using the simple domain call irq_create_mapping() before any irq_find_mapping() since the latter will actually work for the static IRQ assignment case. + +==== Hierarchy IRQ domain ==== +On some architectures, there may be multiple interrupt controllers +involved in delivering an interrupt from the device to the target CPU. +Let's look at a typical interrupt delivering path on x86 platforms: + +Device --> IOAPIC -> Interrupt remapping Controller -> Local APIC -> CPU + +There are three interrupt controllers involved: +1) IOAPIC controller +2) Interrupt remapping controller +3) Local APIC controller + +To support such a hardware topology and make software architecture match +hardware architecture, an irq_domain data structure is built for each +interrupt controller and those irq_domains are organized into hierarchy. +When building irq_domain hierarchy, the irq_domain near to the device is +child and the irq_domain near to CPU is parent. So a hierarchy structure +as below will be built for the example above. + CPU Vector irq_domain (root irq_domain to manage CPU vectors) + ^ + | + Interrupt Remapping irq_domain (manage irq_remapping entries) + ^ + | + IOAPIC irq_domain (manage IOAPIC delivery entries/pins) + +There are four major interfaces to use hierarchy irq_domain: +1) irq_domain_alloc_irqs(): allocate IRQ descriptors and interrupt + controller related resources to deliver these interrupts. +2) irq_domain_free_irqs(): free IRQ descriptors and interrupt controller + related resources associated with these interrupts. +3) irq_domain_activate_irq(): activate interrupt controller hardware to + deliver the interrupt. +3) irq_domain_deactivate_irq(): deactivate interrupt controller hardware + to stop delivering the interrupt. + +Following changes are needed to support hierarchy irq_domain. +1) a new field 'parent' is added to struct irq_domain; it's used to + maintain irq_domain hierarchy information. +2) a new field 'parent_data' is added to struct irq_data; it's used to + build hierarchy irq_data to match hierarchy irq_domains. The irq_data + is used to store irq_domain pointer and hardware irq number. +3) new callbacks are added to struct irq_domain_ops to support hierarchy + irq_domain operations. + +With support of hierarchy irq_domain and hierarchy irq_data ready, an +irq_domain structure is built for each interrupt controller, and an +irq_data structure is allocated for each irq_domain associated with an +IRQ. Now we could go one step further to support stacked(hierarchy) +irq_chip. That is, an irq_chip is associated with each irq_data along +the hierarchy. A child irq_chip may implement a required action by +itself or by cooperating with its parent irq_chip. + +With stacked irq_chip, interrupt controller driver only needs to deal +with the hardware managed by itself and may ask for services from its +parent irq_chip when needed. So we could achieve a much cleaner +software architecture. + +For an interrupt controller driver to support hierarchy irq_domain, it +needs to: +1) Implement irq_domain_ops.alloc and irq_domain_ops.free +2) Optionally implement irq_domain_ops.activate and + irq_domain_ops.deactivate. +3) Optionally implement an irq_chip to manage the interrupt controller + hardware. +4) No need to implement irq_domain_ops.map and irq_domain_ops.unmap, + they are unused with hierarchy irq_domain. + +Hierarchy irq_domain may also be used to support other architectures, +such as ARM, ARM64 etc.
include/linux/irq.h +5 -0
@@ -133,6 +133,8 @@ struct irq_domain;* @chip: low level interrupt hardware access * @domain: Interrupt translation domain; responsible for mapping * between hwirq number and linux irq number. +* @parent_data: pointer to parent struct irq_data to support hierarchy +* irq_domain * @handler_data: per-IRQ data for the irq_chip methods * @chip_data: platform-specific per-chip private data for the chip * methods, to allow shared chip implementations
@@ -151,6 +153,9 @@ struct irq_data {unsigned int state_use_accessors;struct irq_chip *chip;struct irq_domain *domain; +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY +struct irq_data *parent_data; +#endif void *handler_data;void *chip_data;struct msi_desc *msi_desc;
include/linux/irqdomain.h +86 -0
134 lines not on this page · raw message
kernel/irq/Kconfig +4 -0
@@ -55,6 +55,10 @@ config GENERIC_IRQ_CHIP config IRQ_DOMAIN bool +config IRQ_DOMAIN_HIERARCHY + bool + depends on IRQ_DOMAIN + config HANDLE_DOMAIN_IRQ bool
kernel/irq/chip.c +3 -0
@@ -15,6 +15,7 @@#include <linux/module.h> #include <linux/interrupt.h> #include <linux/kernel_stat.h> +#include <linux/irqdomain.h> #include <trace/events/irq.h>
@@ -178,6 +179,7 @@ int irq_startup(struct irq_desc *desc, bool resend)irq_state_clr_disabled (desc); desc->depth =0 ; +irq_domain_activate_irq (&desc->irq_data);if (desc->irq_data.chip->irq_startup) { ret = desc->irq_data.chip->irq_startup (&desc->irq_data);irq_state_clr_masked (desc);
@@ -199,6 +201,7 @@ void irq_shutdown(struct irq_desc *desc) desc->irq_data.chip->irq_disable (&desc->irq_data); else desc->irq_data.chip->irq_mask(&desc->irq_data); +irq_domain_deactivate_irq (&desc->irq_data);irq_state_set_masked (desc); }
kernel/irq/irqdomain.c +375 -16
454 lines not on this page · raw message
Signature · 1 line
1.7.10.4
PATCH v5 2/31 irqdomain: Do irq_find_mapping and set_type for hierarchy irqdomain in case OF
In reply to Jiang LiuFrom: Yingjoe Chen <[email protected]>
It is possible to call irq_create_of_mapping to create/translate the same IRQ from DT for multiple times. Perform irq_find_mapping check and set_type for hierarchy irqdomain in irq_create_of_mapping() to avoid duplicate these functionality in all outer most irqdomain.
--- kernel/irq/irqdomain.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-)
kernel/irq/irqdomain.c +18 -9
@@ -478,11 +478,6 @@ unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data)return 0 ; } -if (irq_domain_is_hierarchy (domain)) { - virq =irq_domain_alloc_irqs (domain,1 ,NUMA_NO_NODE , irq_data); -return virq <=0 ?0 : virq; - } -/* If domain has no translation, then we assume interrupt line */ if (domain->ops->xlate ==NULL ) hwirq = irq_data->args[0 ];
@@ -492,10 +487,24 @@ unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data)return 0 ; } -/* Create mapping */ - virq =irq_create_mapping (domain, hwirq); -if (!virq) -return virq; +if (irq_domain_is_hierarchy (domain)) { +/* +* If we've already configured this interrupt, +* don't do it again, or hell will break loose. +*/ + virq =irq_find_mapping (domain, hwirq); +if (virq) +return virq; + + virq =irq_domain_alloc_irqs (domain,1 ,NUMA_NO_NODE , irq_data); +if (virq <=0 ) +return 0 ; + }else { +/* Create mapping */ + virq =irq_create_mapping (domain, hwirq); +if (!virq) +return virq; + }/* Set type if specified and different than the current one */ if (type != IRQ_TYPE_NONE &&
Signature · 1 line
1.7.10.4
PATCH v5 3/31 genirq: Introduce helper functions to support stacked irq_chip
In reply to Jiang LiuNow we already support hierarchy irq_data, so introduce several helpers to support stacked irq_chips.
--- include/linux/irq.h | 5 +++++ kernel/irq/chip.c | 17 +++++++++++++++++ 2 files changed, 22 insertions(+)
include/linux/irq.h +5 -0
@@ -443,6 +443,11 @@ extern void handle_percpu_devid_irq(unsigned int irq, struct irq_desc *desc);extern void handle_bad_irq (unsigned int irq,struct irq_desc *desc);extern void handle_nested_irq (unsigned int irq); +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY +extern void irq_chip_ack_parent (struct irq_data *data); +extern int irq_chip_retrigger_hierarchy (struct irq_data *data); +#endif +/* Handling of unhandled and spurious interrupts: */ extern void note_interrupt (unsigned int irq,struct irq_desc *desc,irqreturn_t action_ret);
kernel/irq/chip.c +17 -0
@@ -850,3 +850,20 @@ void irq_cpu_offline(void)raw_spin_unlock_irqrestore (&desc->lock, flags); } } + +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY +void irq_chip_ack_parent (struct irq_data *data) +{ + data = data->parent_data; + data->chip->irq_ack (data); +} + +int irq_chip_retrigger_hierarchy (struct irq_data *data) +{ +for (data = data->parent_data; data; data = data->parent_data) +if (data->chip && data->chip->irq_retrigger) +return data->chip->irq_retrigger (data); + +return -ENOSYS ; +} +#endif
Signature · 1 line
1.7.10.4
PATCH v5 4/31 genirq: Introduce irq_chip.irq_compose_msi_msg() to support stacked irqchip
In reply to Jiang LiuAdd callback irq_compose_msi_msg to struct irq_chip, which will be used to support stacked irqchip.
--- include/linux/irq.h | 5 +++++ kernel/irq/chip.c | 17 +++++++++++++++++ 2 files changed, 22 insertions(+)
include/linux/irq.h +5 -0
@@ -29,6 +29,7 @@ struct seq_file;struct module ;struct irq_desc ;struct irq_data ; +struct msi_msg ;typedef void (*irq_flow_handler_t )(unsigned int irq,struct irq_desc *desc);typedef void (*irq_preflow_handler_t )(struct irq_data *data);
@@ -320,6 +321,7 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)* any other callback related to this irq * @irq_release_resources: optional to release resources acquired with * irq_request_resources +* @irq_compose_msi_msg: optional to compose message content for MSI * @flags: chip specific flags */ struct irq_chip {
@@ -356,6 +358,8 @@ struct irq_chip {int (*irq_request_resources)(struct irq_data *data);void (*irq_release_resources)(struct irq_data *data); +void (*irq_compose_msi_msg)(struct irq_data *data,struct msi_msg *msg); +unsigned long flags; };
@@ -443,6 +447,7 @@ extern void handle_percpu_devid_irq(unsigned int irq, struct irq_desc *desc);extern void handle_bad_irq (unsigned int irq,struct irq_desc *desc);extern void handle_nested_irq (unsigned int irq); +extern int irq_chip_compose_msi_msg (struct irq_data *data,struct msi_msg *msg);#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY extern void irq_chip_ack_parent (struct irq_data *data);extern int irq_chip_retrigger_hierarchy (struct irq_data *data);
kernel/irq/chip.c +17 -0
@@ -867,3 +867,20 @@ int irq_chip_retrigger_hierarchy(struct irq_data *data)return -ENOSYS ; }#endif + +int irq_chip_compose_msi_msg (struct irq_data *data,struct msi_msg *msg) +{ +struct irq_data *pos =NULL ; + +#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY + for (; data; data = data->parent_data) +#endif +if (data->chip && data->chip->irq_compose_msi_msg) + pos = data; +if (!pos) +return -ENOSYS ; + + pos->chip->irq_compose_msi_msg (pos, msg); + +return 0 ; +}
Signature · 1 line
1.7.10.4
PATCH v5 5/31 genirq: Add IRQ_SET_MASK_OK_DONE to support stacked irqchip
In reply to Jiang LiuAdd IRQ_SET_MASK_OK_DONE in addition to IRQ_SET_MASK_OK and IRQ_SET_MASK_OK_NOCOPY to support stacked irqchip. IRQ_SET_MASK_OK_DONE is the same as IRQ_SET_MASK_OK to irq core. To stacked irqchip, it means that ascendant irqchips have done all the work and no more handling needed in descendant irqchips.
--- include/linux/irq.h | 4 ++++ kernel/irq/manage.c | 2 ++ 2 files changed, 6 insertions(+)
include/linux/irq.h +4 -0
@@ -114,10 +114,14 @@ enum {* * IRQ_SET_MASK_OK - OK, core updates irq_data.affinity * IRQ_SET_MASK_NOCPY - OK, chip did update irq_data.affinity +* IRQ_SET_MASK_OK_DONE - Same as IRQ_SET_MASK_OK for core. Special code to +* support stacked irqchips, which indicates skipping +* all descendent irqchips. */ enum {IRQ_SET_MASK_OK =0 ,IRQ_SET_MASK_OK_NOCOPY , +IRQ_SET_MASK_OK_DONE , };struct msi_desc ;
kernel/irq/manage.c +2 -0
@@ -183,6 +183,7 @@ int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask, ret = chip->irq_set_affinity (data, mask, force);switch (ret) {case IRQ_SET_MASK_OK : +case IRQ_SET_MASK_OK_DONE :cpumask_copy (data->affinity, mask);case IRQ_SET_MASK_OK_NOCOPY :irq_set_thread_affinity (desc);
@@ -600,6 +601,7 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,switch (ret) {case IRQ_SET_MASK_OK : +case IRQ_SET_MASK_OK_DONE :irqd_clear (&desc->irq_data,IRQD_TRIGGER_MASK );irqd_set (&desc->irq_data, flags);
Signature · 1 line
1.7.10.4
PATCH v5 6/31 x86, irq: Save destination CPU ID in irq_cfg
In reply to Jiang LiuCache destination CPU APIC ID into struct irq_cfg when assigning vector for interrupt. Upper layer just needs to read the cached APIC ID instead of calling apic->cpu_mask_to_apicid_and(), it helps to hide APIC driver details from IOAPIC/HPET/MSI drivers..
--- arch/x86/include/asm/hw_irq.h | 1 + arch/x86/kernel/apic/vector.c | 6 ++++++ 2 files changed, 7 insertions(+)
arch/x86/include/asm/hw_irq.h +1 -0
@@ -116,6 +116,7 @@ struct irq_data;struct irq_cfg {cpumask_var_t domain;cpumask_var_t old_domain; +unsigned int dest_apicid;u8 vector;u8 move_in_progress :1 ;#ifdef CONFIG_IRQ_REMAP
arch/x86/kernel/apic/vector.c +6 -0
@@ -188,6 +188,12 @@ next: }free_cpumask_var (tmp_mask); +if (!err) { +/* cache destination APIC IDs into cfg->dest_apicid */ + err = apic->cpu_mask_to_apicid_and (mask, cfg->domain, + &cfg->dest_apicid); + } +return err; }
Signature · 1 line
1.7.10.4
PATCH v5 7/31 x86, irq: Use hierarchy irqdomain to manage CPU interrupt vectors
In reply to Jiang LiuAbstract CPU local APIC as an interrupt controller and create an irqdomain for it to manage CPU interupt vectors. It's the base to enable hierarchy irqdomain on x86 systems. Eventually we will build a irqdomain hiearchy as below:
IOAPIC domain-------|
MSI/MSI-x domain------> [Inerrupt Remapping domain] -> CPU vector domain
HPET_IRQ domain_____| ^ DMAR domain---------------------------------------------------| HT_IRQ domain-------------------------------------------------|
--- arch/x86/Kconfig | 3 +- arch/x86/include/asm/hw_irq.h | 15 ++++ arch/x86/kernel/apic/io_apic.c | 3 - arch/x86/kernel/apic/vector.c | 156 ++++++++++++++++++++++++++++++++++++---- 4 files changed, 160 insertions(+), 17 deletions(-)
arch/x86/Kconfig +2 -1
@@ -883,11 +883,12 @@ config X86_LOCAL_APIC def_bool y depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC || PCI_MSI select GENERIC_IRQ_LEGACY_ALLOC_HWIRQ + select IRQ_DOMAIN + select IRQ_DOMAIN_HIERARCHY config X86_IO_APIC def_bool X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_IOAPIC depends on X86_LOCAL_APIC - select IRQ_DOMAIN config X86_REROUTE_FOR_BROKEN_BOOT_IRQS bool "Reroute for broken boot IRQs"
arch/x86/include/asm/hw_irq.h +15 -0
@@ -112,6 +112,15 @@ struct irq_2_irte { #ifdef CONFIG_X86_LOCAL_APIC struct irq_data; +struct irq_domain; + +struct irq_alloc_info { + u32 flags; + const struct cpumask *mask; /* CPU mask for vector allocation */ +}; + +/* Request contigious CPU vectors */ +#define X86_IRQ_ALLOC_CONTIGOUS_VECTORS 0x1 struct irq_cfg { cpumask_var_t domain;
@@ -135,6 +144,12 @@ struct irq_cfg { }; }; +extern struct irq_domain *x86_vector_domain; + +extern void init_irq_alloc_info (struct irq_alloc_info *info, +const struct cpumask *mask); +extern void copy_irq_alloc_info (struct irq_alloc_info *dst, +struct irq_alloc_info *src);extern struct irq_cfg *irq_cfg (unsigned int irq);extern struct irq_cfg *irqd_cfg (struct irq_data *irq_data);extern struct irq_cfg *alloc_irq_and_cfg_at (unsigned int at,int node);
arch/x86/kernel/apic/io_apic.c +0 -3
@@ -2353,9 +2353,6 @@ static int mp_irqdomain_create(int ioapic) ioapic_dynirq_base =max (ioapic_dynirq_base, gsi_cfg->gsi_end +1 ); -if (gsi_cfg->gsi_base ==0 ) -irq_set_default_host (ip->irqdomain); -return 0 ; }
arch/x86/kernel/apic/vector.c +143 -13
231 lines not on this page · raw message
Signature · 1 line
1.7.10.4
PATCH v5 8/31 x86, hpet: Use new irqdomain interfaces to allocate/free IRQ
In reply to Jiang LiuUse new irqdomain interfaces to allocate/free IRQ for HPET, so we could kill GENERIC_IRQ_LEGACY_ALLOC_HWIRQ later.
--- arch/x86/kernel/hpet.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
arch/x86/kernel/hpet.c +5 -3
@@ -11,6 +11,7 @@#include <linux/cpu.h> #include <linux/pm.h> #include <linux/io.h> +#include <linux/irqdomain.h> #include <asm/fixmap.h> #include <asm/hpet.h>
@@ -476,7 +477,7 @@ static int hpet_msi_next_event(unsigned long delta,static int hpet_setup_msi_irq (unsigned int irq) {if (x86_msi.setup_hpet_msi (irq, hpet_blockid)) { -irq_free_hwirq (irq); +irq_domain_free_irqs (irq,1 );return -EINVAL ; }return 0 ;
@@ -484,9 +485,10 @@ static int hpet_setup_msi_irq(unsigned int irq)static int hpet_assign_irq (struct hpet_dev *dev) { -unsigned int irq =irq_alloc_hwirq (-1 ); +int irq; -if (!irq) + irq =irq_domain_alloc_irqs (NULL ,1 ,NUMA_NO_NODE ,NULL ); +if (irq <=0 )return -EINVAL ;irq_set_handler_data (irq, dev);
Signature · 1 line
1.7.10.4
PATCH v5 9/31 x86, MSI: Use new irqdomain interfaces to allocate/free IRQ
In reply to Jiang LiuUse new irqdomain interfaces to allocate/free IRQ for MSI, so we could kill GENERIC_IRQ_LEGACY_ALLOC_HWIRQ later.
--- arch/x86/kernel/apic/msi.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-)
arch/x86/kernel/apic/msi.c +6 -8
@@ -14,6 +14,7 @@#include <linux/dmar.h> #include <linux/hpet.h> #include <linux/msi.h> +#include <linux/irqdomain.h> #include <asm/msidef.h> #include <asm/hpet.h> #include <asm/hw_irq.h>
@@ -146,23 +147,20 @@ 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; -unsigned int irq; -int node, ret; +int irq, ret;/* Multiple MSI vectors only supported with interrupt remapping */ if (type ==PCI_CAP_ID_MSI && nvec >1 )return 1 ; - node =dev_to_node (&dev->dev); -list_for_each_entry (msidesc, &dev->msi_list, list) { - irq =irq_alloc_hwirq (node); -if (!irq) + irq =irq_domain_alloc_irqs (NULL ,1 ,NUMA_NO_NODE ,NULL ); +if (irq <=0 )return -ENOSPC ; ret =setup_msi_irq (dev, msidesc, irq,0 );if (ret <0 ) { -irq_free_hwirq (irq); +irq_domain_free_irqs (irq,1 );return ret; }
@@ -172,7 +170,7 @@ int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)void native_teardown_msi_irq (unsigned int irq) { -irq_free_hwirq (irq); +irq_domain_free_irqs (irq,1 ); }#ifdef CONFIG_DMAR_TABLE
Signature · 1 line
1.7.10.4
PATCH v5 10/31 x86, uv: Use new irqdomain interfaces to allocate/free IRQ
In reply to Jiang LiuUse new irqdomain interfaces to allocate/free IRQ, so we could kill GENERIC_IRQ_LEGACY_ALLOC_HWIRQ later.
--- arch/x86/platform/uv/uv_irq.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-)
arch/x86/platform/uv/uv_irq.c +11 -16
@@ -12,6 +12,7 @@#include <linux/rbtree.h> #include <linux/slab.h> #include <linux/irq.h> +#include <linux/irqdomain.h> #include <asm/apic.h> #include <asm/uv/uv_irq.h>
@@ -130,24 +131,14 @@ static int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade, unsigned long mmr_offset, int limit) { -const struct cpumask *eligible_cpu =cpumask_of (cpu);struct irq_cfg *cfg =irq_cfg (irq);unsigned long mmr_value;struct uv_IO_APIC_route_entry *entry; -int mmr_pnode, err; -unsigned int dest; +int mmr_pnode;BUILD_BUG_ON (sizeof (struct uv_IO_APIC_route_entry ) !=sizeof (unsigned long )); - err =assign_irq_vector (irq, cfg, eligible_cpu); -if (err !=0 ) -return err; - - err = apic->cpu_mask_to_apicid_and (eligible_cpu, eligible_cpu, &dest); -if (err !=0 ) -return err; -if (limit ==UV_AFFINITY_CPU )irq_set_status_flags (irq,IRQ_NO_BALANCING );else
@@ -164,7 +155,7 @@ arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade, entry->polarity =0 ; entry->trigger =0 ; entry->mask =0 ; - entry->dest = dest; + entry->dest = cfg->dest_apicid; mmr_pnode =uv_blade_to_pnode (mmr_blade);uv_write_global_mmr64 (mmr_pnode, mmr_offset, mmr_value);
@@ -238,9 +229,13 @@ uv_set_irq_affinity(struct irq_data *data, const struct cpumask *mask,int uv_setup_irq (char *irq_name,int cpu,int mmr_blade,unsigned long mmr_offset,int limit) { -int ret, irq =irq_alloc_hwirq (uv_blade_to_memory_nid (mmr_blade)); +int ret, irq; +struct irq_alloc_info info; -if (!irq) +init_irq_alloc_info (&info,cpumask_of (cpu)); + irq =irq_domain_alloc_irqs (NULL ,1 ,uv_blade_to_memory_nid (mmr_blade), + &info); +if (irq <=0 )return -EBUSY ; ret = arch_enable_uv_irq(irq_name, irq, cpu, mmr_blade, mmr_offset,
@@ -248,7 +243,7 @@ int uv_setup_irq(char *irq_name, int cpu, int mmr_blade,if (ret == irq)uv_set_irq_2_mmr_info (irq, mmr_offset, mmr_blade);else -irq_free_hwirq (irq); +irq_domain_free_irqs (irq,1 );return ret; }
@@ -283,6 +278,6 @@ void uv_teardown_irq(unsigned int irq) n = n->rb_right; }spin_unlock_irqrestore (&uv_irq_lock, irqflags); -irq_free_hwirq (irq); +irq_domain_free_irqs (irq,1 ); }EXPORT_SYMBOL_GPL (uv_teardown_irq);
Signature · 1 line
1.7.10.4
PATCH v5 11/31 x86, htirq: Use new irqdomain interfaces to allocate/free IRQ
In reply to Jiang LiuUse new irqdomain interfaces to allocate/free IRQ for HTIRQ, so we could kill GENERIC_IRQ_LEGACY_ALLOC_HWIRQ later.
This patch changes the interfaces between arch independent PCI driver and arch specific code. Currently HT_IRQ is only enabled on x86, so it shouldn't break other architectures.
--- arch/x86/kernel/apic/htirq.c | 26 +++++++++++++------------- drivers/pci/htirq.c | 7 +++---- include/linux/htirq.h | 2 ++ 3 files changed, 18 insertions(+), 17 deletions(-)
arch/x86/kernel/apic/htirq.c +13 -13
@@ -14,6 +14,7 @@#include <linux/device.h> #include <linux/pci.h> #include <linux/htirq.h> +#include <linux/irqdomain.h> #include <asm/hw_irq.h> #include <asm/apic.h> #include <asm/hypertransport.h>
@@ -61,31 +62,30 @@ static struct irq_chip ht_irq_chip = { .flags = IRQCHIP_SKIP_SET_WAKE, }; +int arch_alloc_ht_irq (struct pci_dev *dev) +{ +return irq_domain_alloc_irqs (NULL ,1 ,dev_to_node (&dev->dev),NULL ); +} + +void arch_free_ht_irq (int irq) +{ +irq_domain_free_irqs (irq,1 ); +} +int arch_setup_ht_irq (unsigned int irq,struct pci_dev *dev) {struct irq_cfg *cfg;struct ht_irq_msg msg; -unsigned dest; -int err;if (disable_apic)return -ENXIO ; cfg =irq_cfg (irq); - err =assign_irq_vector (irq, cfg, apic->target_cpus ()); -if (err) -return err; - - err = apic->cpu_mask_to_apicid_and (cfg->domain, - apic->target_cpus (), &dest); -if (err) -return err; - - msg.address_hi =HT_IRQ_HIGH_DEST_ID (dest); + msg.address_hi =HT_IRQ_HIGH_DEST_ID (cfg->dest_apicid); msg.address_lo =HT_IRQ_LOW_BASE | -HT_IRQ_LOW_DEST_ID (dest) | +HT_IRQ_LOW_DEST_ID (cfg->dest_apicid) | HT_IRQ_LOW_VECTOR(cfg->vector) | ((apic->irq_dest_mode == 0) ? HT_IRQ_LOW_DM_PHYSICAL :
drivers/pci/htirq.c +3 -4
@@ -117,8 +117,8 @@ int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update) cfg->msg.address_lo =0xffffffff ; cfg->msg.address_hi =0xffffffff ; - irq =irq_alloc_hwirq (dev_to_node (&dev->dev)); -if (!irq) { + irq =arch_alloc_ht_irq (dev); +if (irq <=0 ) {kfree (cfg);return -EBUSY ; }
@@ -163,8 +163,7 @@ void ht_destroy_irq(unsigned int irq) cfg =irq_get_handler_data (irq);irq_set_chip (irq,NULL );irq_set_handler_data (irq,NULL ); -irq_free_hwirq (irq); - +arch_free_ht_irq (irq);kfree (cfg); }EXPORT_SYMBOL (ht_destroy_irq);
include/linux/htirq.h +2 -0
@@ -15,6 +15,8 @@ void unmask_ht_irq(struct irq_data *data);/* The arch hook for getting things started */ int arch_setup_ht_irq (unsigned int irq,struct pci_dev *dev); +int arch_alloc_ht_irq (struct pci_dev *dev); +void arch_free_ht_irq (int irq);/* For drivers of buggy hardware */ typedef void (ht_irq_update_t)(struct pci_dev *dev, int irq,
Signature · 1 line
1.7.10.4
PATCH v5 12/31 x86, dmar: Use new irqdomain interfaces to allocate/free IRQ
In reply to Jiang LiuUse 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.
--- 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(-)
arch/x86/include/asm/irq_remapping.h +2 -2
@@ -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 */
arch/x86/kernel/apic/msi.c +10 -0
@@ -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 /*
drivers/iommu/irq_remapping.c +15 -2
@@ -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; }
Signature · 1 line
1.7.10.4
PATCH v5 13/31 x86: irq_remapping: Introduce new interfaces to support hierarchy irqdomain
In reply to Jiang LiuIntroduce 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.
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 *);
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.
--- arch/x86/include/asm/hw_irq.h | 35 +++++++++++++++++++++++++ arch/x86/include/asm/irq_remapping.h | 39 +++++++++++++++++++++++++++ drivers/iommu/irq_remapping.c | 48 +++++++++++++++++++++++++++++++++- drivers/iommu/irq_remapping.h | 10 +++++++ 4 files changed, 131 insertions(+), 1 deletion(-)
arch/x86/include/asm/hw_irq.h +35 -0
@@ -113,10 +113,45 @@ struct irq_2_irte {#ifdef CONFIG_X86_LOCAL_APIC struct irq_data ;struct irq_domain ; +struct pci_dev ; +struct msi_desc ; + +enum irq_alloc_type { +X86_IRQ_ALLOC_TYPE_IOAPIC =1 , +X86_IRQ_ALLOC_TYPE_HPET , +X86_IRQ_ALLOC_TYPE_MSI , +X86_IRQ_ALLOC_TYPE_MSIX , +};struct irq_alloc_info { +enum irq_alloc_type type;u32 flags;const struct cpumask *mask;/* CPU mask for vector allocation */ +union { +int unused; +#ifdef CONFIG_HPET_TIMER +struct { +int hpet_id; +int hpet_index; +void *hpet_data; + }; +#endif +#ifdef CONFIG_PCI_MSI +struct { +struct pci_dev *msi_dev; +irq_hw_number_t msi_hwirq; + }; +#endif +#ifdef CONFIG_X86_IO_APIC +struct { +int ioapic_id; +int ioapic_pin; +u32 ioapic_trigger :1 ; +u32 ioapic_polarity :1 ; +struct IO_APIC_route_entry *ioapic_entry; + }; +#endif + }; };/* Request contigious CPU vectors */
arch/x86/include/asm/irq_remapping.h +39 -0
@@ -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,28 @@ extern bool setup_remapped_irq(int irq,void irq_remap_modify_chip_defaults (struct irq_chip *chip); +extern struct irq_domain *irq_remapping_get_ir_irq_domain ( +struct irq_alloc_info *info); +extern struct irq_domain *irq_remapping_get_irq_domain ( +struct irq_alloc_info *info); +extern void irq_remapping_print_chip (struct irq_data *data,struct seq_file *p); + +/* +* Create 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; +} +#else /* CONFIG_IRQ_REMAP */ static inline void setup_irq_remapping_ops (void ) { }
@@ -101,6 +126,20 @@ static inline bool setup_remapped_irq(int irq, {return false; } + +static inline struct irq_domain * +irq_remapping_get_ir_irq_domain (struct irq_alloc_info *info) +{ +return NULL ; +} + +static inline struct irq_domain * +irq_remapping_get_irq_domain (struct irq_alloc_info *info) +{ +return NULL ; +} + +#define irq_remapping_print_chip NULL#endif /* CONFIG_IRQ_REMAP */ extern int dmar_alloc_hwirq (void );
drivers/iommu/irq_remapping.c +47 -1
63 lines not on this page · raw message
drivers/iommu/irq_remapping.h +10 -0
@@ -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,19 @@ struct irq_remap_ops {/* Setup interrupt remapping for an HPET MSI */ int (*alloc_hpet_msi)(unsigned int ,unsigned int ); + +/* Get the irqdomain associated the IOMMU device */ +struct irq_domain *(*get_ir_irq_domain)(struct irq_alloc_info *); + +/* Get the MSI irqdomain associated with the IOMMU device */ + struct irq_domain *(*get_irq_domain)(struct irq_alloc_info *); };extern struct irq_remap_ops intel_irq_remap_ops;extern struct irq_remap_ops amd_iommu_irq_ops; +extern void ir_ack_apic_edge (struct irq_data *data); +#else /* CONFIG_IRQ_REMAP */ #define irq_remapping_enabled 0
Signature · 1 line
1.7.10.4
PATCH v5 14/31 iommu/vt-d: Change prototypes to prepare for enabling hierarchy irqdomain
In reply to Jiang LiuPrepare for support hierarchy irqdomain by changing function prototypes, should be no function changes.
--- drivers/iommu/intel_irq_remapping.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-)
drivers/iommu/intel_irq_remapping.c +11 -11
@@ -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 subhareturn 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 ; }
Signature · 1 line
1.7.10.4
PATCH v5 15/31 iommu/vt-d: Enhance Intel IR driver to suppport hierarchy irqdomain
In reply to Jiang LiuEnhance 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.
--- drivers/iommu/intel_irq_remapping.c | 349 +++++++++++++++++++++++++++++++++-- include/linux/intel-iommu.h | 4 + 2 files changed, 335 insertions(+), 18 deletions(-)
drivers/iommu/intel_irq_remapping.c +331 -18
@@ -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,14 @@ 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; + }; +}; +#define IR_X2APIC_MODE (mode) (mode ? (1 << 11) : 0)#define IRTE_DEST (dest) ((x2apic_mode) ? dest : dest << 8)
@@ -50,6 +59,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 +273,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 +490,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 +1034,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 ;
@@ -1051,6 +1066,7 @@ intel_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,send_cleanup_vector (cfg);cpumask_copy (data->affinity, mask); +return 0 ; }
@@ -1156,6 +1172,53 @@ 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 ; +} +struct irq_remap_ops intel_irq_remap_ops = { .supported = intel_irq_remapping_supported, .prepare = dmar_table_init,
@@ -1170,4 +1233,254 @@ 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, +}; + +/* +* 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 || ret ==IRQ_SET_MASK_OK_DONE ) +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 IRQ_SET_MASK_OK_DONE ; +} + +static void intel_ir_compose_msi_msg (struct irq_data *irq_data, +struct msi_msg *msg) +{ +struct intel_ir_data *ir_data = irq_data->chip_data; + + *msg = ir_data->msi_entry; +} + +static struct irq_chip intel_ir_chip = { + .irq_ack = ir_ack_apic_edge, + .irq_set_affinity = intel_ir_set_affinity, + .irq_compose_msi_msg = intel_ir_compose_msi_msg, +}; + +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 IR_IO_APIC_route_entry *entry; +struct irte *irte = &data->irte_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); + + entry = (struct IR_IO_APIC_route_entry *)info->ioapic_entry; + info->ioapic_entry =NULL ; +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 ; + +/* +* With IRQ remapping enabled, don't need contigious CPU vectors +* to support multiple MSI interrupts. +*/ +if (info->type ==X86_IRQ_ALLOC_TYPE_MSI ) + info->flags &= ~X86_IRQ_ALLOC_CONTIGOUS_VECTORS ; + + 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_common (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_common (domain, virq, nr_irqs); +} + +static void 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); +} + +static void 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); +} + +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, };
include/linux/intel-iommu.h +4 -0
@@ -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;
Signature · 1 line
1.7.10.4
PATCH v5 16/31 iommu/amd: Enhance AMD IR driver to suppport hierarchy irqdomain
In reply to Jiang LiuEnhance AMD interrupt remapping driver to support hierarchy irqdomain, it will simplify the code eventually.
--- drivers/iommu/amd_iommu.c | 329 ++++++++++++++++++++++++++++++++++++++- drivers/iommu/amd_iommu_init.c | 4 + drivers/iommu/amd_iommu_proto.h | 9 ++ drivers/iommu/amd_iommu_types.h | 5 + 4 files changed, 341 insertions(+), 6 deletions(-)
drivers/iommu/amd_iommu.c +323 -6
@@ -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,16 @@ union irte { } fields; }; +struct amd_ir_data { +struct irq_2_irte irq_2_irte; +union irte irte_entry; +union { +struct msi_msg msi_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 +3958,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 +3981,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 +4231,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 +4278,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 +4289,72 @@ 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 ; +} +struct irq_remap_ops amd_iommu_irq_ops = { .supported = amd_iommu_supported, .prepare = amd_iommu_prepare,
@@ -4294,5 +4369,247 @@ 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, +}; + +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 msi_msg *msg = &data->msi_entry; +struct IO_APIC_route_entry *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 */ + entry = info->ioapic_entry; + info->ioapic_entry =NULL ; +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 ; + +/* +* With IRQ remapping enabled, don't need contigious CPU vectors +* to support multiple MSI interrupts. +*/ +if (info->type ==X86_IRQ_ALLOC_TYPE_MSI ) + info->flags &= ~X86_IRQ_ALLOC_CONTIGOUS_VECTORS ; + + 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); + } +for (i =0 ; i < nr_irqs; i++) +free_irte (devid, index + i); +out_free_parent: +irq_domain_free_irqs_common (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); +kfree (data); + } + } +irq_domain_free_irqs_common (domain, virq, nr_irqs); +} + +static void 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); +} + +static void 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); +} + +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 || ret ==IRQ_SET_MASK_OK_DONE ) +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 IRQ_SET_MASK_OK_DONE ; +} + +static void ir_compose_msi_msg (struct irq_data *irq_data,struct msi_msg *msg) +{ +struct amd_ir_data *ir_data = irq_data->chip_data; + + *msg = ir_data->msi_entry; +} + +static struct irq_chip amd_ir_chip = { + .irq_ack = ir_ack_apic_edge, + .irq_set_affinity = amd_ir_set_affinity, + .irq_compose_msi_msg = ir_compose_msi_msg, +}; + +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
drivers/iommu/amd_iommu_init.c +4 -0
@@ -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!
drivers/iommu/amd_iommu_proto.h +9 -0
@@ -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
drivers/iommu/amd_iommu_types.h +5 -0
@@ -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 {
Signature · 1 line
1.7.10.4
PATCH v5 17/31 x86, hpet: Enhance HPET IRQ to support hierarchy irqdomain
In reply to Jiang LiuEnhance HPET code to support hierarchy irqdomain, it helps to make the architecture more clear.
--- arch/x86/include/asm/hpet.h | 7 +- arch/x86/kernel/apic/msi.c | 166 ++++++++++++++++++++++++++++++++++++++----- arch/x86/kernel/hpet.c | 57 ++++----------- 3 files changed, 169 insertions(+), 61 deletions(-)
arch/x86/include/asm/hpet.h +6 -1
@@ -74,11 +74,16 @@ extern unsigned int hpet_readl(unsigned int a);extern void force_hpet_resume (void );struct irq_data ; +struct hpet_dev ; +struct irq_domain ; +extern void hpet_msi_unmask (struct irq_data *data);extern void hpet_msi_mask (struct irq_data *data); -struct hpet_dev ;extern void hpet_msi_write (struct hpet_dev *hdev,struct msi_msg *msg);extern void hpet_msi_read (struct hpet_dev *hdev,struct msi_msg *msg); +extern struct irq_domain *hpet_create_irq_domain (int hpet_id); +extern int hpet_assign_irq (struct irq_domain *domain, +struct hpet_dev *dev,int dev_num);#ifdef CONFIG_PCI_MSI extern int default_setup_hpet_msi (unsigned int irq,unsigned int id);
arch/x86/kernel/apic/msi.c +149 -17
197 lines not on this page · raw message
arch/x86/kernel/hpet.c +14 -43
114 lines not on this page · raw message
Signature · 1 line
1.7.10.4
PATCH v5 18/31 PCI/MSI: Remove unnecessary braces around single statements
In reply to Jiang LiuPer Documentation/CodingStyle, don't use braces around single statements.
--- drivers/pci/msi.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)
drivers/pci/msi.c +3 -6
@@ -244,9 +244,8 @@ void default_restore_msi_irqs(struct pci_dev *dev) {struct msi_desc *entry; -list_for_each_entry (entry, &dev->msi_list, list) { +list_for_each_entry (entry, &dev->msi_list, list)default_restore_msi_irq (dev, entry->irq); - } }void __read_msi_msg (struct msi_desc *entry,struct msi_msg *msg)
@@ -451,9 +450,8 @@ static void __pci_restore_msix_state(struct pci_dev *dev) PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL);arch_restore_msi_irqs (dev); -list_for_each_entry (entry, &dev->msi_list, list) { +list_for_each_entry (entry, &dev->msi_list, list)msix_mask_irq (entry, entry->masked); - }msix_clear_and_set_ctrl (dev,PCI_MSIX_FLAGS_MASKALL ,0 ); }
@@ -497,9 +495,8 @@ static int populate_msi_sysfs(struct pci_dev *pdev)int count =0 ;/* Determine how many msi entries we have */ -list_for_each_entry (entry, &pdev->msi_list, list) { +list_for_each_entry (entry, &pdev->msi_list, list) ++num_msi; - }if (!num_msi)return 0 ;
Signature · 1 line
1.7.10.4
PATCH v5 19/31 PCI/MSI: Simplify PCI MSI code by initializing msi_desc.nvec_used earlier
In reply to Jiang LiuSimplify PCI MSI code by initializing msi_desc.nvec_used and msi_desc.msi_attrib.multiple when creating MSI descriptors.
Also remove redundant checks in IRQ remapping drivers, PCI MSI core already guarantees these.
--- drivers/iommu/irq_remapping.c | 8 -------- drivers/pci/msi.c | 40 +++++++++++++++------------------------- 2 files changed, 15 insertions(+), 33 deletions(-)
drivers/iommu/irq_remapping.c +0 -8
@@ -69,19 +69,13 @@ static int do_setup_msi_irqs(struct pci_dev *dev, int nvec)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);
@@ -109,8 +103,6 @@ error:* IRQs from tearing down again in default_teardown_msi_irqs() */ msidesc->irq =0 ; - msidesc->nvec_used =0 ; - msidesc->msi_attrib.multiple =0 ;return ret; }
drivers/pci/msi.c +15 -25
@@ -85,19 +85,13 @@ int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)*/ void default_teardown_msi_irqs (struct pci_dev *dev) { +int i;struct msi_desc *entry; -list_for_each_entry (entry, &dev->msi_list, list) { -int i, nvec; -if (entry->irq ==0 ) -continue ; -if (entry->nvec_used) - nvec = entry->nvec_used; -else - nvec =1 << entry->msi_attrib.multiple; -for (i =0 ; i < nvec; i++) -arch_teardown_msi_irq (entry->irq + i); - } +list_for_each_entry (entry, &dev->msi_list, list) +if (entry->irq) +for (i =0 ; i < entry->nvec_used; i++) +arch_teardown_msi_irq (entry->irq + i); }void __weak arch_teardown_msi_irqs (struct pci_dev *dev)
@@ -353,19 +347,12 @@ static void free_msi_irqs(struct pci_dev *dev)struct msi_desc *entry, *tmp;struct attribute **msi_attrs;struct device_attribute *dev_attr; -int count =0 ; +int i, count =0 ; -list_for_each_entry (entry, &dev->msi_list, list) { -int i, nvec; -if (!entry->irq) -continue ; -if (entry->nvec_used) - nvec = entry->nvec_used; -else - nvec =1 << entry->msi_attrib.multiple; -for (i =0 ; i < nvec; i++) -BUG_ON (irq_has_action (entry->irq + i)); - } +list_for_each_entry (entry, &dev->msi_list, list) +if (entry->irq) +for (i =0 ; i < entry->nvec_used; i++) +BUG_ON (irq_has_action (entry->irq + i));arch_teardown_msi_irqs (dev);
@@ -556,7 +543,7 @@ error_attrs:return ret; } -static struct msi_desc *msi_setup_entry (struct pci_dev *dev) +static struct msi_desc *msi_setup_entry (struct pci_dev *dev,int nvec) {u16 control;struct msi_desc *entry;
@@ -574,6 +561,8 @@ static struct msi_desc *msi_setup_entry(struct pci_dev *dev) entry->msi_attrib.maskbit = !!(control &PCI_MSI_FLAGS_MASKBIT ); entry->msi_attrib.default_irq = dev->irq;/* Save IOAPIC IRQ */ entry->msi_attrib.multi_cap = (control &PCI_MSI_FLAGS_QMASK ) >>1 ; + entry->msi_attrib.multiple =ilog2 (__roundup_pow_of_two (nvec)); + entry->nvec_used = nvec;if (control &PCI_MSI_FLAGS_64BIT ) entry->mask_pos = dev->msi_cap +PCI_MSI_MASK_64 ;
@@ -606,7 +595,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec)msi_set_enable (dev,0 );/* Disable MSI during set up */ - entry =msi_setup_entry (dev); + entry =msi_setup_entry (dev, nvec);if (!entry)return -ENOMEM ;
@@ -677,6 +666,7 @@ static int msix_setup_entries(struct pci_dev *dev, void __iomem *base, entry->msi_attrib.entry_nr = entries[i].entry; entry->msi_attrib.default_irq = dev->irq; entry->mask_base = base; + entry->nvec_used =1 ;list_add_tail (&entry->list, &dev->msi_list); }
Signature · 1 line
1.7.10.4
PATCH v5 20/31 PCI/MSI: Kill redundant call of irq_set_msi_desc() for MSI-X interrupts
In reply to Jiang LiuIt's arch_setup_msi_irq()/arch_setup_msi_irqs()'s responsibility to call irq_set_msi_desc() to associate IRQ descriptors and MSI descriptors, so kill the redundant call of irq_set_msi_desc() for MSI-X interrupts in PCI MSI core.
--- drivers/pci/msi.c | 1 - 1 file changed, 1 deletion(-)
drivers/pci/msi.c +0 -1
@@ -685,7 +685,6 @@ static void msix_program_entries(struct pci_dev *dev,PCI_MSIX_ENTRY_VECTOR_CTRL ; entries[i].vector = entry->irq; -irq_set_msi_desc (entry->irq, entry); entry->masked =readl (entry->mask_base + offset);msix_mask_irq (entry,1 ); i++;
Signature · 1 line
1.7.10.4
PATCH v5 21/31 PCI/MSI: Enhance core to support hierarchy irqdomain
In reply to Jiang LiuEnhance PCI MSI core to support hierarchy irqdomain, so the common code could be shared among architectures.
---
Hi Thomas,
These changes are a temporary solution, I'm working on another
patch set which will refine these interfaces, especially kill arch_msi_irq_domain_{set|get}_hwirq().
Regards!
Gerry
--- drivers/pci/Kconfig | 4 ++ drivers/pci/msi.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/msi.h | 14 ++++++ 3 files changed, 152 insertions(+)
drivers/pci/Kconfig +4 -0
@@ -16,6 +16,10 @@ config PCI_MSI If you don't know what to do here, say Y. +config PCI_MSI_IRQ_DOMAIN + bool + depends on PCI_MSI && IRQ_DOMAIN_HIERARCHY + config PCI_DEBUG bool "PCI Debugging" depends on PCI && DEBUG_KERNEL
drivers/pci/msi.c +134 -0
143 lines not on this page · raw message
include/linux/msi.h +14 -0
@@ -75,4 +75,18 @@ struct msi_chip { void (*teardown_irq)(struct msi_chip *chip, unsigned int irq); }; +#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN +struct irq_domain ; +struct irq_chip ; + +struct irq_domain *msi_create_irq_domain (struct device_node *of_node, +struct irq_chip *chip, +struct irq_domain *parent); +int msi_irq_domain_alloc_irqs (struct irq_domain *domain,int type, +struct pci_dev *dev,void *arg); + +irq_hw_number_t arch_msi_irq_domain_get_hwirq (void *arg); +void arch_msi_irq_domain_set_hwirq (void *arg,irq_hw_number_t hwirq); +#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */ +#endif /* LINUX_MSI_H */
Signature · 1 line
1.7.10.4
Re: [Patch Part2 v5 21/31] PCI/MSI: Enhance core to support hierarchy irqdomain
Quoted 9 lines · Jiang Liu
Enhance PCI MSI core to support hierarchy irqdomain, so the common code could be shared among architectures.
Signed-off-by Jiang Liu <[email protected]>---
Hi Thomas,
These changes are a temporary solution, I'm working on another
patch set which will refine these interfaces, especially kill arch_msi_irq_domain_{set|get}_hwirq().
Ok. Please don't forget the irq_chip change :)
Thanks,
tglx
Re: [Patch Part2 v5 21/31] PCI/MSI: Enhance core to support hierarchy irqdomain
In reply to Jiang LiuHi Gerry,
Please see my comments / questions below.
Quoted 11 lines · Jiang Liu
Enhance PCI MSI core to support hierarchy irqdomain, so the common code could be shared among architectures.
Signed-off-by Jiang Liu <[email protected]>---
Hi Thomas,
These changes are a temporary solution, I'm working on another
patch set which will refine these interfaces, especially kill arch_msi_irq_domain_{set|get}_hwirq().
Regards!
Gerry
Would the change includes the struct irqdomain_msi_data proposed by Thomas here (https://lkml.org/lkml/2014/11/6/210)?
Quoted 4 lines
[...]
drivers/pci/msi.c +3
-0+static int msi_domain_alloc (struct irq_domain *domain,unsigned int virq, +unsigned int nr_irqs,void *arg) +{
drivers/pci/msi.c int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, · line 1128
Quoted 10 lines
drivers/pci/msi.c +10
-0+int i, ret; +irq_hw_number_t hwirq =arch_msi_irq_domain_get_hwirq (arg); + +if (irq_find_mapping (domain, hwirq) >0 ) +return -EEXIST ; + + ret =irq_domain_alloc_irqs_parent (domain, virq, nr_irqs, arg); +if (ret <0 ) +return ret; +
When executing irq_domain_alloc_irqs_parent(), it triggers the following warning message due to
WARN_ON(desc->irq_data.chip == &no_irq_chip)
------------[ cut here ]------------ WARNING: CPU: 2 PID: 912 at kernel/irq/chip.c:734 __irq_set_handler+0x138/0x13c() Modules linked in: mlx4_core(+) rtc_efi efivarfs CPU: 2 PID: 912 Comm: modprobe Not tainted 3.18.0-rc3-p2v5+ #53 Call trace: [<fffffe00000963d4>] dump_backtrace+0x0/0x16c [<fffffe0000096550>] show_stack+0x10/0x1c [<fffffe000067545c>] dump_stack+0x74/0x98 [<fffffe00000b205c>] warn_slowpath_common+0x84/0xac [<fffffe00000b2148>] warn_slowpath_null+0x14/0x20 [<fffffe00000ed968>] __irq_set_handler+0x134/0x13c [<fffffe000042af14>] gic_irq_domain_map+0x4c/0xac [<fffffe000042afd4>] gic_irq_domain_alloc+0x60/0x88 [<fffffe000042b374>] gicv2m_domain_alloc+0x30/0xa8 [<fffffe00000efc1c>] __irq_domain_alloc_irqs+0x144/0x30c [<fffffe000042b58c>] gicv2m_setup_msi_irq+0xc0/0x118 [<fffffe000044548c>] arch_setup_msi_irq+0x34/0x60 [<fffffe0000445544>] arch_setup_msi_irqs+0x50/0xb0 [<fffffe0000445e3c>] pci_enable_msix+0x310/0x39c [<fffffe0000445efc>] pci_enable_msix_range+0x34/0x9c
....
However, I think if we call irq_domain_set_hwirq_and_chip() in the msi_create_irq_domain() as suggested by Thomas, that should also fix this issue.
drivers/pci/msi.c int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, · line 1134
Quoted 6 lines
drivers/pci/msi.c +6
-0+for (i =0 ; i < nr_irqs; i++) { +irq_domain_set_hwirq_and_chip (domain, virq + i, hwirq + i, + domain->host_data, + (void *)(long )i); +__irq_set_handler (virq + i, handle_edge_irq,0 ,"edge" ); + }
Is there are a way to specify other type of handler besides edge?
drivers/pci/msi.c int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, · line 1164
Quoted 13 lines
[...]
drivers/pci/msi.c +12
-0+static void msi_domain_activate (struct irq_domain *domain, +struct irq_data *irq_data) +{ +struct msi_msg msg; + +/* +* irq_data->chip_data is MSI/MSI-X 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 ;
Actually, I am a bit confused with this comment here. If you look at "/drivers/pci/msi.c: arch_setup_msi_irq()", it calls irq_set_chip_data(des->irq, chip) where chip is *msi_chip.
It looks like if the arch uses this API, it would conflict with what you have here where the irq_data->chip_data would be not NULL at the logic above, and would always return.
Thank you,
Suravee
Re: [Patch Part2 v5 21/31] PCI/MSI: Enhance core to support hierarchy irqdomain
Quoted 17 lines · Suravee Suthikulpanit
Hi Gerry,
Please see my comments / questions below.
Quoted 11 lines · Jiang Liu
Enhance PCI MSI core to support hierarchy irqdomain, so the common code could be shared among architectures.
Signed-off-by Jiang Liu <[email protected]>---
Hi Thomas,
These changes are a temporary solution, I'm working on another
patch set which will refine these interfaces, especially kill arch_msi_irq_domain_{set|get}_hwirq().
Regards!
Gerry
Quoted 2 lines
Would the change includes the struct
irqdomain_msi_dataproposed by Thomas here (https://lkml.org/lkml/2014/11/6/210)?
Hi Suravee,
I'm working on another patch set which will refine the way to
create irqdomain for MSI. I hope will solve all issues mentioned by Thomas. I will post that patch set as RFC within one or two days.
Quoted 43 lines
Quoted 6 lines
[...]
+static int msi_domain_alloc(structirq_domain*domain, unsigned int virq,drivers/pci/msi.c +2
-0+ unsigned int nr_irqs, void *arg) +{drivers/pci/msi.c int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, · line 1128
Quoted 10 lines
drivers/pci/msi.c +10
-0+int i, ret; +irq_hw_number_t hwirq =arch_msi_irq_domain_get_hwirq (arg); + +if (irq_find_mapping (domain, hwirq) >0 ) +return -EEXIST ; + + ret =irq_domain_alloc_irqs_parent (domain, virq, nr_irqs, arg); +if (ret <0 ) +return ret; +When executing
irq_domain_alloc_irqs_parent(), it triggers the following warning message due toWARN_ON(desc->irq_data.chip == &no_irq_chip)------------[ cut here ]------------ WARNING: CPU: 2 PID: 912 at kernel/irq/chip.c:734 __irq_set_handler+0x138/0x13c() Modules linked in: mlx4_core(+) rtc_efi efivarfs CPU: 2 PID: 912 Comm: modprobe Not tainted 3.18.0-rc3-p2v5+ #53 Call trace: [<fffffe00000963d4>] dump_backtrace+0x0/0x16c [<fffffe0000096550>] show_stack+0x10/0x1c [<fffffe000067545c>] dump_stack+0x74/0x98 [<fffffe00000b205c>] warn_slowpath_common+0x84/0xac [<fffffe00000b2148>] warn_slowpath_null+0x14/0x20 [<fffffe00000ed968>] __irq_set_handler+0x134/0x13c [<fffffe000042af14>] gic_irq_domain_map+0x4c/0xac [<fffffe000042afd4>] gic_irq_domain_alloc+0x60/0x88 [<fffffe000042b374>] gicv2m_domain_alloc+0x30/0xa8 [<fffffe00000efc1c>] __irq_domain_alloc_irqs+0x144/0x30c [<fffffe000042b58c>] gicv2m_setup_msi_irq+0xc0/0x118 [<fffffe000044548c>] arch_setup_msi_irq+0x34/0x60 [<fffffe0000445544>] arch_setup_msi_irqs+0x50/0xb0 [<fffffe0000445e3c>] pci_enable_msix+0x310/0x39c [<fffffe0000445efc>] pci_enable_msix_range+0x34/0x9c
Quoted 5 lines
....
However, I think if we call
irq_domain_set_hwirq_and_chip()in themsi_create_irq_domain()as suggested by Thomas, that should also fix this issue.
We didn't trigger this warning on x86 because only the outer-most irqdomain will set irq flow handler. On ARM, the inner GIC domain will set irq flow handler, but the irq_data->chip for outer-most domain hasn't been set yet.
I'm still find a way out here. Maybe we need to relax the WARN_ON().
Quoted 9 lines
drivers/pci/msi.c int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, · line 1134
Quoted 7 lines
drivers/pci/msi.c +6
-0+for (i =0 ; i < nr_irqs; i++) { +irq_domain_set_hwirq_and_chip (domain, virq + i, hwirq + i, + domain->host_data, + (void *)(long )i); +__irq_set_handler (virq + i, handle_edge_irq,0 ,"edge" ); + }Is there are a way to specify other type of handler besides edge?
Yes, the new patch set will address this requirement.
Quoted 20 lines
Quoted 12 lines
[...]
drivers/pci/msi.c +9
-0+static void msi_domain_activate (struct irq_domain *domain, +struct irq_data *irq_data) +{ +struct msi_msg msg; + +/* +* irq_data->chip_data is MSI/MSI-X 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.
drivers/pci/msi.c int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, · line 1164
Quoted 3 lines
drivers/pci/msi.c +3
-0+*/ +if (irq_data->chip_data) +return ;Actually, I am a bit confused with this comment here. If you look at "/drivers/pci/msi.c:
arch_setup_msi_irq()", it callsirq_set_chip_data(des->irq, chip)where chip is*msi_chip.
Quoted 3 lines
It looks like if the arch uses this API, it would conflict with what you have here where the
irq_data->chip_datawould be not NULL at the logic above, and would always return.
Good point, it's work on x86, but will break ARM or other platforms. Will refine this part.
Regards!
Gerry
Quoted 4 lines
Thank you,
Suravee
Re: [Patch Part2 v5 21/31] PCI/MSI: Enhance core to support hierarchy irqdomain
Quoted 18 lines · Jiang Liu
Quoted 17 lines · Suravee Suthikulpanit
Hi Gerry,
Please see my comments / questions below.
Quoted 11 lines · Jiang Liu
Enhance PCI MSI core to support hierarchy irqdomain, so the common code could be shared among architectures.
Signed-off-by Jiang Liu <[email protected]>---
Hi Thomas,
These changes are a temporary solution, I'm working on another
patch set which will refine these interfaces, especially kill arch_msi_irq_domain_{set|get}_hwirq().
Regards!
Gerry
Quoted 6 lines
Quoted 2 lines
Would the change includes the struct
irqdomain_msi_dataproposed by Thomas here (https://lkml.org/lkml/2014/11/6/210)?Hi Suravee,
I'm working on another patch set which will refine the way to
create irqdomain for MSI. I hope will solve all issues mentioned by Thomas. I will post that patch set as RFC within one or two days.
Let me know if I can help.
Quoted 48 lines
Quoted 43 lines
Quoted 6 lines
[...]
+static int msi_domain_alloc(structirq_domain*domain, unsigned int virq,drivers/pci/msi.c +2
-0+ unsigned int nr_irqs, void *arg) +{drivers/pci/msi.c int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, · line 1128
Quoted 10 lines
drivers/pci/msi.c +10
-0+int i, ret; +irq_hw_number_t hwirq =arch_msi_irq_domain_get_hwirq (arg); + +if (irq_find_mapping (domain, hwirq) >0 ) +return -EEXIST ; + + ret =irq_domain_alloc_irqs_parent (domain, virq, nr_irqs, arg); +if (ret <0 ) +return ret; +When executing
irq_domain_alloc_irqs_parent(), it triggers the following warning message due toWARN_ON(desc->irq_data.chip == &no_irq_chip)------------[ cut here ]------------ WARNING: CPU: 2 PID: 912 at kernel/irq/chip.c:734 __irq_set_handler+0x138/0x13c() Modules linked in: mlx4_core(+) rtc_efi efivarfs CPU: 2 PID: 912 Comm: modprobe Not tainted 3.18.0-rc3-p2v5+ #53 Call trace: [<fffffe00000963d4>] dump_backtrace+0x0/0x16c [<fffffe0000096550>] show_stack+0x10/0x1c [<fffffe000067545c>] dump_stack+0x74/0x98 [<fffffe00000b205c>] warn_slowpath_common+0x84/0xac [<fffffe00000b2148>] warn_slowpath_null+0x14/0x20 [<fffffe00000ed968>] __irq_set_handler+0x134/0x13c [<fffffe000042af14>] gic_irq_domain_map+0x4c/0xac [<fffffe000042afd4>] gic_irq_domain_alloc+0x60/0x88 [<fffffe000042b374>] gicv2m_domain_alloc+0x30/0xa8 [<fffffe00000efc1c>] __irq_domain_alloc_irqs+0x144/0x30c [<fffffe000042b58c>] gicv2m_setup_msi_irq+0xc0/0x118 [<fffffe000044548c>] arch_setup_msi_irq+0x34/0x60 [<fffffe0000445544>] arch_setup_msi_irqs+0x50/0xb0 [<fffffe0000445e3c>] pci_enable_msix+0x310/0x39c [<fffffe0000445efc>] pci_enable_msix_range+0x34/0x9cQuoted 5 lines
....
However, I think if we call
irq_domain_set_hwirq_and_chip()in themsi_create_irq_domain()as suggested by Thomas, that should also fix this issue.
Quoted 6 lines
We didn't trigger this warning on x86 because only the outer-most irqdomain will set irq flow handler. On ARM, the inner GIC domain will set irq flow handler, but the
irq_data->chipfor outer-most domain hasn't been set yet.I'm still find a way out here. Maybe we need to relax the
WARN_ON().
What if we just switch the order and call the irq_domain_alloc_irqs_parent() after the loop? That way we can still keep the WARN_ON().
Suravee
PATCH 1/1 PCI/MSI: Enhance core to support hierarchy irqdomain
In reply to Jiang LiuEnhance PCI MSI core to support hierarchy irqdomain, so the common code could be shared among architectures.
---
Hi Thomas,
This update fixes a possible conflict on other architectures
when they try to use the new MSI hierarchy irqdomain, as pointed out by Suravee Suthikulanit. The main change is as below.
Regards!
Gerry
static void msi_domain_deactivate(struct irq_domain *domain,
struct irq_data *irq_data)
{
struct msi_msg msg;
+ struct msi_desc *desc = irq_data->msi_desc;
- if (!irq_data->chip_data) {
+ if (desc->irq == irq_data->irq) {
memset(&msg, 0, sizeof(msg)); __write_msi_msg(irq_data->msi_desc, &msg);
}
--- drivers/pci/Kconfig | 4 ++ drivers/pci/msi.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/msi.h | 14 ++++++ 3 files changed, 151 insertions(+)
drivers/pci/Kconfig +4 -0
@@ -16,6 +16,10 @@ config PCI_MSI If you don't know what to do here, say Y. +config PCI_MSI_IRQ_DOMAIN + bool + depends on PCI_MSI && IRQ_DOMAIN_HIERARCHY + config PCI_DEBUG bool "PCI Debugging" depends on PCI && DEBUG_KERNEL
drivers/pci/msi.c +133 -0
142 lines not on this page · raw message
include/linux/msi.h +14 -0
@@ -75,4 +75,18 @@ struct msi_chip { void (*teardown_irq)(struct msi_chip *chip, unsigned int irq); }; +#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN +struct irq_domain ; +struct irq_chip ; + +struct irq_domain *msi_create_irq_domain (struct device_node *of_node, +struct irq_chip *chip, +struct irq_domain *parent); +int msi_irq_domain_alloc_irqs (struct irq_domain *domain,int type, +struct pci_dev *dev,void *arg); + +irq_hw_number_t arch_msi_irq_domain_get_hwirq (void *arg); +void arch_msi_irq_domain_set_hwirq (void *arg,irq_hw_number_t hwirq); +#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */ +#endif /* LINUX_MSI_H */
Signature · 1 line
1.7.10.4
PATCH v5 22/31 x86, PCI, MSI: Use hierarchy irqdomain to manage MSI interrupts
In reply to Jiang LiuEnhance MSI code to support hierarchy irqdomain, it helps to make the architecture more clear.
--- arch/x86/Kconfig | 1 + arch/x86/include/asm/hw_irq.h | 9 ++- arch/x86/include/asm/irq_remapping.h | 6 +- arch/x86/kernel/apic/msi.c | 120 +++++++++++++++++----------------- arch/x86/kernel/apic/vector.c | 2 + drivers/iommu/irq_remapping.c | 1 - 6 files changed, 72 insertions(+), 67 deletions(-)
arch/x86/Kconfig +1 -0
@@ -885,6 +885,7 @@ config X86_LOCAL_APIC select GENERIC_IRQ_LEGACY_ALLOC_HWIRQ select IRQ_DOMAIN select IRQ_DOMAIN_HIERARCHY + select PCI_MSI_IRQ_DOMAIN if PCI_MSI config X86_IO_APIC def_bool X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_IOAPIC
arch/x86/include/asm/hw_irq.h +8 -1
@@ -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 ;
@@ -210,6 +211,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;
arch/x86/include/asm/irq_remapping.h +1 -5
@@ -71,11 +71,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 )
arch/x86/kernel/apic/msi.c +60 -60
170 lines not on this page · raw message
arch/x86/kernel/apic/vector.c +2 -0
@@ -364,6 +364,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 (); }
drivers/iommu/irq_remapping.c +0 -1
@@ -171,7 +171,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; }
Signature · 1 line
1.7.10.4
PATCH v5 23/31 x86, irq: Directly call native_compose_msi_msg() for DMAR IRQ
In reply to Jiang LiuDMAR interrupt won't be remapped by interrupt remapping hardware, so directly call native_compose_msi_msg() for DMAR IRQ to compose MSI message data. This will help to simplify MSI code later.
--- arch/x86/kernel/apic/msi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
arch/x86/kernel/apic/msi.c +2 -4
@@ -250,12 +250,10 @@ static struct irq_chip dmar_msi_type = {int arch_setup_dmar_msi (unsigned int irq) { -int ret;struct msi_msg msg; +struct irq_cfg *cfg =irq_cfg (irq); - ret =msi_compose_msg (NULL , irq, &msg,-1 ); -if (ret <0 ) -return ret; +native_compose_msi_msg (NULL , irq, cfg->dest_apicid, &msg,-1 );dmar_msi_write (irq, &msg);irq_set_chip_and_handler_name (irq, &dmar_msi_type, handle_edge_irq,"edge" );
Signature · 1 line
1.7.10.4
PATCH v5 24/31 iommu/vt-d: Clean up unused MSI related code
In reply to Jiang LiuNow MSI interrupt has been converted to new hierarchy irqdomain interfaces, so kill legacy MSI related code.
--- drivers/iommu/intel_irq_remapping.c | 144 ----------------------------------- 1 file changed, 144 deletions(-)
drivers/iommu/intel_irq_remapping.c +0 -144
@@ -145,44 +145,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 ;
@@ -1229,10 +1089,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, };
Signature · 1 line
1.7.10.4
PATCH v5 25/31 iommu/amd: Clean up unused MSI related code
In reply to Jiang LiuNow MSI interrupt has been converted to new hierarchy irqdomain interfaces, so kill legacy MSI related code.
--- drivers/iommu/amd_iommu.c | 115 +-------------------------------------------- 1 file changed, 2 insertions(+), 113 deletions(-)
drivers/iommu/amd_iommu.c +2 -113
@@ -3958,8 +3958,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;
@@ -3985,11 +3984,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; } }
@@ -4189,106 +4183,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 ;
@@ -4365,10 +4259,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, };
@@ -4466,8 +4356,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" );
Signature · 1 line
1.7.10.4
PATCH v5 26/31 x86: irq_remapping: Clean up unused MSI related code
In reply to Jiang LiuNow MSI interrupt has been converted to new hierarchy irqdomain interfaces, so kill legacy MSI related code and interfaces.
--- 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 | 151 ---------------------------------- drivers/iommu/irq_remapping.h | 14 ---- 5 files changed, 185 deletions(-)
arch/x86/include/asm/irq_remapping.h +0 -13
@@ -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,
@@ -98,15 +94,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) {
arch/x86/include/asm/pci.h +0 -5
@@ -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
arch/x86/kernel/x86_init.c +0 -2
@@ -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, };
drivers/iommu/irq_remapping.c +0 -151
175 lines not on this page · raw message
drivers/iommu/irq_remapping.h +0 -14
@@ -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 *);
Signature · 1 line
1.7.10.4
PATCH v5 27/31 x86, irq: Clean up unused MSI related code and interfaces
In reply to Jiang LiuNow MSI interrupt has been converted to new hierarchy irqdomain interfaces, so kill legacy MSI related code and interfaces.
--- arch/x86/include/asm/hpet.h | 9 ------ arch/x86/include/asm/x86_init.h | 4 --- arch/x86/kernel/apic/msi.c | 61 +++++---------------------------------- 3 files changed, 7 insertions(+), 67 deletions(-)
arch/x86/include/asm/hpet.h +0 -9
@@ -85,15 +85,6 @@ extern struct irq_domain *hpet_create_irq_domain(int hpet_id);extern int hpet_assign_irq (struct irq_domain *domain,struct hpet_dev *dev,int dev_num); -#ifdef CONFIG_PCI_MSI -extern int default_setup_hpet_msi (unsigned int irq,unsigned int id); -#else -static inline int default_setup_hpet_msi (unsigned int irq,unsigned int id) -{ -return -EINVAL ; -} -#endif -#ifdef CONFIG_HPET_EMULATE_RTC #include <linux/interrupt.h>
arch/x86/include/asm/x86_init.h +0 -4
@@ -176,13 +176,9 @@ struct msi_desc;struct x86_msi_ops {int (*setup_msi_irqs)(struct pci_dev *dev,int nvec,int type); -void (*compose_msi_msg)(struct pci_dev *dev,unsigned int irq, -unsigned int dest,struct msi_msg *msg, -u8 hpet_id);void (*teardown_msi_irq)(unsigned int irq);void (*teardown_msi_irqs)(struct pci_dev *dev);void (*restore_msi_irqs)(struct pci_dev *dev); -int (*setup_hpet_msi)(unsigned int irq,unsigned int id);u32 (*msi_mask_irq)(struct msi_desc *desc,u32 mask,u32 flag);u32 (*msix_mask_irq)(struct msi_desc *desc,u32 flag); };
arch/x86/kernel/apic/msi.c +7 -54
110 lines not on this page · raw message
Signature · 1 line
1.7.10.4
PATCH v5 28/31 iommu/vt-d: Refine the interfaces to create IRQ for DMAR unit
In reply to Jiang LiuRefine 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.
--- 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(-)
arch/ia64/include/asm/irq_remapping.h +0 -2
@@ -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
arch/ia64/kernel/msi_ia64.c +19 -11
@@ -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 */
arch/x86/include/asm/irq_remapping.h +0 -4
@@ -124,8 +124,4 @@ irq_remapping_get_irq_domain(struct irq_alloc_info *info)#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 */
arch/x86/kernel/apic/msi.c +13 -11
@@ -219,25 +219,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
drivers/iommu/dmar.c +5 -14
@@ -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" );
include/linux/dmar.h +2 -1
@@ -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__ */
Signature · 1 line
1.7.10.4
PATCH v5 29/31 x86, irq: Use hierarchy irqdomain to manage DMAR interrupts
In reply to Jiang LiuEnhance DMAR code to support hierarchy irqdomain, it helps to make the architecture more clear.
--- arch/x86/include/asm/hw_irq.h | 7 ++ arch/x86/kernel/apic/msi.c | 151 ++++++++++++++++++++++++++--------------- 2 files changed, 102 insertions(+), 56 deletions(-)
arch/x86/include/asm/hw_irq.h +7 -0
@@ -122,6 +122,7 @@ enum irq_alloc_type {X86_IRQ_ALLOC_TYPE_HPET ,X86_IRQ_ALLOC_TYPE_MSI ,X86_IRQ_ALLOC_TYPE_MSIX , + X86_IRQ_ALLOC_TYPE_DMAR, }; struct irq_alloc_info {
@@ -152,6 +153,12 @@ struct irq_alloc_info { struct IO_APIC_route_entry *ioapic_entry; };#endif +#ifdef CONFIG_DMAR_TABLE +struct { +int dmar_id; +void *dmar_data; + }; +#endif }; };
arch/x86/kernel/apic/msi.c +95 -56
192 lines not on this page · raw message
Signature · 1 line
1.7.10.4
PATCH v5 30/31 x86, htirq: Use hierarchy irqdomain to manage Hypertransport interrupts
In reply to Jiang LiuUse hierarchy irqdomain to manage Hypertransport interrupts. We have slightly changed the architecture interfaces to support htirq PCI driver, it should be safe because currently Hypertransport interrupt is only enabled on x86 platforms.
--- arch/x86/include/asm/hw_irq.h | 13 ++++ arch/x86/kernel/apic/htirq.c | 162 ++++++++++++++++++++++++++++++----------- arch/x86/kernel/apic/vector.c | 1 + drivers/pci/htirq.c | 47 ++---------- include/linux/htirq.h | 24 ++++-- 5 files changed, 159 insertions(+), 88 deletions(-)
arch/x86/include/asm/hw_irq.h +13 -0
@@ -159,6 +159,14 @@ struct irq_alloc_info { void *dmar_data; };#endif +#ifdef CONFIG_HT_IRQ +struct { +int ht_pos; +int ht_idx; +struct pci_dev *ht_dev; +void *ht_update; + }; +#endif }; };
@@ -223,6 +231,11 @@ extern void arch_init_msi_domain(struct irq_domain *domain);#else static inline void arch_init_msi_domain (struct irq_domain *domain) { }#endif +#ifdef CONFIG_HT_IRQ +extern void arch_init_htirq_domain (struct irq_domain *domain); +#else +static inline void arch_init_htirq_domain (struct irq_domain *domain) { } +#endif /* Statistics */ extern atomic_t irq_err_count;
arch/x86/kernel/apic/htirq.c +121 -41
210 lines not on this page · raw message
arch/x86/kernel/apic/vector.c +1 -0
@@ -365,6 +365,7 @@ int __init arch_early_irq_init(void)irq_set_default_host (x86_vector_domain);arch_init_msi_domain (x86_vector_domain); +arch_init_htirq_domain (x86_vector_domain);return arch_early_ioapic_init (); }
drivers/pci/htirq.c +6 -41
80 lines not on this page · raw message
include/linux/htirq.h +18 -6
@@ -1,26 +1,38 @@#ifndef LINUX_HTIRQ_H #define LINUX_HTIRQ_H +struct pci_dev ; +struct irq_data ; +struct ht_irq_msg {u32 address_lo;/* low 32 bits of the ht irq message */ u32 address_hi;/* high 32 bits of the it irq message */ }; +typedef void (ht_irq_update_t )(struct pci_dev *dev,int irq, +struct ht_irq_msg *msg); + +struct ht_irq_cfg { +struct pci_dev *dev; +/* Update callback used to cope with buggy hardware */ +ht_irq_update_t *update; +unsigned pos; +unsigned idx; +struct ht_irq_msg msg; +}; +/* Helper functions.. */ void fetch_ht_irq_msg (unsigned int irq,struct ht_irq_msg *msg);void write_ht_irq_msg (unsigned int irq,struct ht_irq_msg *msg); -struct irq_data ;void mask_ht_irq (struct irq_data *data);void unmask_ht_irq (struct irq_data *data);/* The arch hook for getting things started */ -int arch_setup_ht_irq (unsigned int irq,struct pci_dev *dev); -int arch_alloc_ht_irq (struct pci_dev *dev); -void arch_free_ht_irq (int irq); +int arch_setup_ht_irq (int idx,int pos,struct pci_dev *dev, +ht_irq_update_t *update); +void arch_teardown_ht_irq (unsigned int irq);/* For drivers of buggy hardware */ -typedef void (ht_irq_update_t )(struct pci_dev *dev,int irq, -struct ht_irq_msg *msg);int __ht_create_irq (struct pci_dev *dev,int idx,ht_irq_update_t *update);#endif /* LINUX_HTIRQ_H */
Signature · 1 line
1.7.10.4
PATCH v5 31/31 x86, uv: Use hierarchy irqdomain to manage UV interrupts
In reply to Jiang LiuEnhance UV code to support hierarchy irqdomain, it helps to make the architecture more clear.
We should construct hwirq based on mmr_blade and mmr_offset, but mmr_offset is type of unsigned long, it may exceed the range of irq_hw_number_t. So help about the way to construct hwirq based on mmr_blade and mmr_offset is welcomed!
--- arch/x86/include/asm/hw_irq.h | 9 ++ arch/x86/platform/uv/uv_irq.c | 288 ++++++++++++++++------------------------- 2 files changed, 118 insertions(+), 179 deletions(-)
arch/x86/include/asm/hw_irq.h +9 -0
@@ -123,6 +123,7 @@ enum irq_alloc_type {X86_IRQ_ALLOC_TYPE_MSI ,X86_IRQ_ALLOC_TYPE_MSIX ,X86_IRQ_ALLOC_TYPE_DMAR , + X86_IRQ_ALLOC_TYPE_UV, }; struct irq_alloc_info {
@@ -167,6 +168,14 @@ struct irq_alloc_info { void *ht_update; };#endif +#ifdef CONFIG_X86_UV +struct { +int uv_limit; +int uv_blade; +unsigned long uv_offset; +char *uv_name; + }; +#endif }; };
arch/x86/platform/uv/uv_irq.c +109 -179
360 lines not on this page · raw message
Signature · 1 line
1.7.10.4