Convert x86 to hierarchy irqdomain and stacked irqchip
v7 cover Convert x86 to hierarchy irqdomain and stacked irqchip
Hi all,
The generic hierarchy irqdomain and stacked irqchip implementation
has been merged into v3.19, so this patch set converts x86 interupt management to hierarchy irqdomain and stacked irqchip. I will send out another following-on patch set to clean up code and interfaces obseleted by this patch set.
This patch set has been reviewed several times and it missed v3.19
merging because several got fixed just before the merging window.
The main changes since last review are:
1) Rebased the patch set onto v3.19-rc5.
2) Merged bugfixes into the patch introducing the bug so it won't break bisecting.
Hi Thomas,
Rafael needs more time to review the patch set to refine ACPI
resource paring interface, and we are nearing to v3.19-rc6. So it would be helpful to move onto the x86 hierarchy irqdomain patch set first, so we may catch up with v3.20 merging window.
Thanks!
Gerry
Jiang Liu (36):
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
irq_remapping: Introduce new interfaces to support hierarchy
irqdomain
irq_remapping/vt-d: Change prototypes to prepare for enabling
hierarchy irqdomain
irq_remapping/vt-d: Enhance Intel IR driver to suppport hierarchy
irqdomain
irq_remapping/amd: Enhance AMD IR driver to suppport hierarchy
irqdomain
x86/hpet: Enhance HPET IRQ to support hierarchy irqdomain x86/MSI: Use hierarchy irqdomain to manage MSI interrupts x86/irq: Directly call native_compose_msi_msg() for DMAR IRQ irq_remapping/vt-d: Clean up unused MSI related code irq_remapping/amd: Clean up unused MSI related code
irq_remapping: Clean up unused MSI related code
x86/MSI: 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 x86/irq: Normalize x86 irq_chip name
x86/MSI: Simplify the way to deal with remapped MSI interrupts x86/MSI: Replace msi_update_msg() with irq_chip_compose_msi_msg() x86/irq: Implement irq_chip.irq_write_msi_msg for MSI/DMAR/HPET
irq_chips
x86/irq: Simplify MSI/DMAR/HPET implementation by using common code
irq_remapping: Kill unused function irq_remapping_print_chip() x86/intel-mid, trivial: Refine code syntax for sfi_parse_mtmr() x86/irq: Kill unused pre_init_apic_IRQ0()
x86/irq: Prepare IOAPIC interfaces to support hierarchy irqdomain x86/irq: Implement callbacks to enable hierarchy irqdomain on IOAPICs x86/irq: Refine the way to allocate irq_cfg for legacy IRQs x86/irq: Simplify the way to print IOAPIC entry
x86/irq: Introduce helper functions to support hierarchy irqdomain
for IOAPIC
x86/irq: Convert IOAPIC to use hierarchy irqdomain interfaces
Rickard Strandqvist (1):
x86/apb_timer: Remove unused function is_apbt_capable()
Thomas Gleixner (1):
x86/intel-mid: Delay initialization of APB timer
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 | 91 +++ arch/x86/include/asm/io_apic.h | 25 +- arch/x86/include/asm/irq_remapping.h | 45 +- arch/x86/include/asm/msi.h | 7 + arch/x86/include/asm/pci.h | 5 - arch/x86/include/asm/x86_init.h | 4 - arch/x86/kernel/acpi/boot.c | 20 +- arch/x86/kernel/apb_timer.c | 12 - arch/x86/kernel/apic/htirq.c | 173 ++++-- arch/x86/kernel/apic/io_apic.c | 600 +++++++++++++++----- arch/x86/kernel/apic/msi.c | 416 ++++++++------ arch/x86/kernel/apic/vector.c | 205 ++++++- arch/x86/kernel/devicetree.c | 37 +- arch/x86/kernel/hpet.c | 57 +- arch/x86/kernel/mpparse.c | 6 +- arch/x86/kernel/x86_init.c | 2 - arch/x86/pci/intel_mid_pci.c | 6 +- .../platform/intel-mid/device_libs/platform_wdt.c | 5 +- arch/x86/platform/intel-mid/intel-mid.c | 18 +- arch/x86/platform/intel-mid/sfi.c | 30 +- arch/x86/platform/sfi/sfi.c | 5 +- arch/x86/platform/uv/uv_irq.c | 299 ++++------ drivers/iommu/amd_iommu.c | 376 +++++++++--- 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 | 451 ++++++++++----- drivers/iommu/irq_remapping.c | 178 ++---- drivers/iommu/irq_remapping.h | 20 +- drivers/pci/htirq.c | 48 +- include/linux/dmar.h | 3 +- include/linux/htirq.h | 22 +- include/linux/intel-iommu.h | 4 + 38 files changed, 2100 insertions(+), 1159 deletions(-) create mode 100644 arch/x86/include/asm/msi.h
Signature · 1 line
1.7.10.4
PATCH v7 1/38 x86/irq: Save destination CPU ID in irq_cfg
Cache 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 v7 2/38 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 interrupt vectors. It's the base to enable hierarchy irqdomain on x86 systems. Eventually we will build a irqdomain hierarchy 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 | 17 +++++ arch/x86/kernel/apic/io_apic.c | 3 - arch/x86/kernel/apic/vector.c | 156 ++++++++++++++++++++++++++++++++++++---- 4 files changed, 161 insertions(+), 18 deletions(-)
arch/x86/Kconfig +1 -2
@@ -457,7 +457,6 @@ config X86_INTEL_CE select X86_REBOOTFIXUPS select OF select OF_EARLY_FLATTREE - select IRQ_DOMAIN ---help--- Select for the Intel CE media processor (CE4100) SOC. This option compiles in support for the CE4100 SOC for settop
@@ -884,11 +883,11 @@ 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_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 +17 -0
@@ -112,6 +112,17 @@ 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 */ +}; + +enum { + /* Allocate contigious CPU vectors */ + X86_IRQ_ALLOC_CONTIGOUS_VECTORS = 0x1, +}; struct irq_cfg { cpumask_var_t domain;
@@ -135,6 +146,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
@@ -2356,9 +2356,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 v7 3/38 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 v7 4/38 x86/MSI: Use new irqdomain interfaces to allocate/free IRQ
In reply to Jiang LiuUse new irqdomain interfaces to allocate/free IRQ for PCI 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 v7 5/38 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 v7 6/38 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 v7 7/38 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
@@ -99,7 +99,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>
@@ -49,6 +50,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 ;
@@ -104,7 +117,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 ;
@@ -127,7 +140,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 v7 8/38 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. In a further step we will store the irqdomain pointer in the device struct to avoid this call in the irq allocation path.
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 following 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 | 37 +++++++++++++++++++++++++ arch/x86/include/asm/irq_remapping.h | 36 ++++++++++++++++++++++++ drivers/iommu/irq_remapping.c | 50 +++++++++++++++++++++++++++++++++- drivers/iommu/irq_remapping.h | 10 +++++++ 4 files changed, 132 insertions(+), 1 deletion(-)
arch/x86/include/asm/hw_irq.h +37 -0
@@ -113,10 +113,47 @@ struct irq_2_irte {#ifdef CONFIG_X86_LOCAL_APIC struct irq_data ;struct irq_domain ; +struct pci_dev ; +struct msi_desc ; + +enum irq_alloc_type { +X86_IRQ_ALLOC_TYPE_IOAPIC =1 , +X86_IRQ_ALLOC_TYPE_HPET , +X86_IRQ_ALLOC_TYPE_MSI , +X86_IRQ_ALLOC_TYPE_MSIX , +};struct irq_alloc_info { +enum irq_alloc_type type;u32 flags;const struct cpumask *mask;/* CPU mask for vector allocation */ +union { +int unused; +#ifdef CONFIG_HPET_TIMER +struct { +int hpet_id; +int hpet_index; +void *hpet_data; + }; +#endif +#ifdef CONFIG_PCI_MSI +struct { +struct pci_dev *msi_dev; +irq_hw_number_t msi_hwirq; + }; +#endif +#ifdef CONFIG_X86_IO_APIC +struct { +int ioapic_id; +int ioapic_pin; +int ioapic_node; +u32 ioapic_trigger :1 ; +u32 ioapic_polarity :1 ; +u32 ioapic_valid :1 ; +struct IO_APIC_route_entry *ioapic_entry; + }; +#endif + }; }; enum {
arch/x86/include/asm/irq_remapping.h +36 -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
@@ -56,6 +59,25 @@ extern bool setup_remapped_irq(int irq,void irq_remap_modify_chip_defaults (struct irq_chip *chip); +extern struct irq_domain * +irq_remapping_get_ir_irq_domain (struct irq_alloc_info *info); +extern struct irq_domain * +irq_remapping_get_irq_domain (struct irq_alloc_info *info); +extern void irq_remapping_print_chip (struct irq_data *data,struct seq_file *p); + +/* Create PCI MSI/MSIx irqdomain, use @parent as the parent irqdomain. */ +static inline struct irq_domain * +arch_create_msi_irq_domain (struct irq_domain *parent) +{ +return NULL ; +} + +/* Get parent irqdomain for interrupt remapping irqdomain */ +static inline struct irq_domain *arch_get_ir_parent_domain (void ) +{ +return x86_vector_domain; +} +#else /* CONFIG_IRQ_REMAP */ static inline void set_irq_remapping_broken (void ) { }
@@ -97,6 +119,20 @@ static inline bool setup_remapped_irq(int irq, {return false; } + +static inline struct irq_domain * +irq_remapping_get_ir_irq_domain (struct irq_alloc_info *info) +{ +return NULL ; +} + +static inline struct irq_domain * +irq_remapping_get_irq_domain (struct irq_alloc_info *info) +{ +return NULL ; +} + +#define irq_remapping_print_chip NULL#endif /* CONFIG_IRQ_REMAP */ extern int dmar_alloc_hwirq (void );
drivers/iommu/irq_remapping.c +49 -1
65 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 irq_remap_broken;extern int disable_sourceid_checking;
@@ -77,11 +79,19 @@ struct irq_remap_ops {/* Setup interrupt remapping for an HPET MSI */ int (*alloc_hpet_msi)(unsigned int ,unsigned int ); + +/* Get the irqdomain associated the IOMMU device */ +struct irq_domain *(*get_ir_irq_domain)(struct irq_alloc_info *); + +/* Get the MSI irqdomain associated with the IOMMU device */ + struct irq_domain *(*get_irq_domain)(struct irq_alloc_info *); };extern struct irq_remap_ops intel_irq_remap_ops;extern struct irq_remap_ops amd_iommu_irq_ops; +extern void ir_ack_apic_edge (struct irq_data *data); +#else /* CONFIG_IRQ_REMAP */ #define irq_remapping_enabled 0
Signature · 1 line
1.7.10.4
PATCH v7 9/38 irq_remapping/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);
@@ -986,7 +986,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);
@@ -1002,7 +1002,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 "
@@ -1089,7 +1089,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
@@ -1125,7 +1125,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;
@@ -1152,7 +1152,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",
@@ -1196,7 +1196,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 v7 10/38 irq_remapping/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 | 337 ++++++++++++++++++++++++++++++++++- include/linux/intel-iommu.h | 4 + 2 files changed, 333 insertions(+), 8 deletions(-)
drivers/iommu/intel_irq_remapping.c +329 -8
@@ -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) ((eim_mode) ? dest : dest << 8)
@@ -50,6 +59,7 @@ static struct hpet_scope ir_hpet[MAX_HPET_TBS];* 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);
@@ -488,7 +498,6 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu) pages =alloc_pages_node (iommu->node,GFP_KERNEL | __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 );
@@ -502,11 +511,23 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu) goto out_free_pages; } + iommu->ir_domain =irq_domain_add_hierarchy (arch_get_ir_parent_domain (), +0 ,INTR_REMAP_TABLE_ENTRIES , +NULL , &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_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;return 0 ; +out_free_bitmap: +kfree (bitmap); out_free_pages:__free_pages (pages,INTR_REMAP_PAGE_ORDER ); out_free_table:
@@ -517,6 +538,14 @@ out_free_table:static void intel_teardown_irq_remapping (struct intel_iommu *iommu) {if (iommu && iommu->ir_table) { +if (iommu->ir_msi_domain) { +irq_domain_remove (iommu->ir_msi_domain); + iommu->ir_msi_domain =NULL ; + } +if (iommu->ir_domain) { +irq_domain_remove (iommu->ir_domain); + iommu->ir_domain =NULL ; + }free_pages ((unsigned long )iommu->ir_table->base,INTR_REMAP_PAGE_ORDER );kfree (iommu->ir_table->bitmap);
@@ -1062,12 +1091,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 ;
@@ -1100,6 +1123,7 @@ intel_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,send_cleanup_vector (cfg);cpumask_copy (data->affinity, mask); +return 0 ; }
@@ -1205,6 +1229,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 = { .prepare = intel_prepare_irq_remapping, .enable = intel_enable_irq_remapping,
@@ -1218,6 +1289,256 @@ 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 v7 11/38 irq_remapping/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>
@@ -3857,6 +3858,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)
@@ -3950,7 +3961,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;
@@ -3972,15 +3984,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;
@@ -4225,7 +4234,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; }
@@ -4272,7 +4281,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;
@@ -4283,6 +4292,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 = { .prepare = amd_iommu_prepare, .enable = amd_iommu_enable,
@@ -4296,5 +4371,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) +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
@@ -62,6 +62,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 v7 12/38 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, 167 insertions(+), 63 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 +147 -19
201 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 v7 13/38 x86/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/include/asm/msi.h | 7 ++ arch/x86/kernel/apic/msi.c | 141 ++++++++++++++++++---------------- arch/x86/kernel/apic/vector.c | 2 + drivers/iommu/irq_remapping.c | 1 - 7 files changed, 94 insertions(+), 73 deletions(-) create mode 100644 arch/x86/include/asm/msi.h
arch/x86/Kconfig +1 -0
@@ -884,6 +884,7 @@ config X86_LOCAL_APIC depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC || PCI_MSI select GENERIC_IRQ_LEGACY_ALLOC_HWIRQ 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 ;
@@ -214,6 +215,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
@@ -66,11 +66,7 @@ irq_remapping_get_irq_domain(struct irq_alloc_info *info);extern void irq_remapping_print_chip (struct irq_data *data,struct seq_file *p);/* Create PCI MSI/MSIx irqdomain, use @parent as the parent irqdomain. */ -static inline struct irq_domain * -arch_create_msi_irq_domain (struct irq_domain *parent) -{ -return NULL ; -} +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/include/asm/msi.h new file +7 -0
@@ -0,0 +1,7 @@ +#ifndef _ASM_X86_MSI_H +#define _ASM_X86_MSI_H +#include <asm/hw_irq.h> + +typedef struct irq_alloc_info msi_alloc_info_t ; + +#endif /* _ASM_X86_MSI_H */
arch/x86/kernel/apic/msi.c +75 -66
189 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
@@ -170,7 +170,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 v7 14/38 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
@@ -259,12 +259,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 v7 15/38 irq_remapping/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) {
@@ -1127,108 +1089,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 ;
@@ -1285,10 +1145,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 v7 16/38 irq_remapping/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
@@ -3961,8 +3961,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;
@@ -3988,11 +3987,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; } }
@@ -4192,106 +4186,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 ;
@@ -4367,10 +4261,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, };
@@ -4468,8 +4358,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 v7 17/38 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
@@ -48,10 +48,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,
@@ -91,15 +87,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 arch specific hooks */
drivers/iommu/irq_remapping.c +0 -151
175 lines not on this page · raw message
drivers/iommu/irq_remapping.h +0 -14
@@ -66,20 +66,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 v7 18/38 x86/MSI: 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 | 55 +++------------------------------------ 3 files changed, 4 insertions(+), 64 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
@@ -175,13 +175,9 @@ struct msi_msg;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); };struct IO_APIC_route_entry ;
arch/x86/kernel/apic/msi.c +4 -51
89 lines not on this page · raw message
Signature · 1 line
1.7.10.4
PATCH v7 19/38 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 hierarchy 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
@@ -117,8 +117,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
@@ -228,25 +228,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
@@ -1087,8 +1087,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) {
@@ -1642,23 +1642,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
@@ -227,6 +227,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 v7 20/38 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 | 153 ++++++++++++++++++++++++++--------------- 2 files changed, 103 insertions(+), 57 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 {
@@ -154,6 +155,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 +96 -57
193 lines not on this page · raw message
Signature · 1 line
1.7.10.4
PATCH v7 21/38 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 | 161 ++++++++++++++++++++++++++++++----------- arch/x86/kernel/apic/vector.c | 1 + drivers/pci/htirq.c | 47 ++---------- include/linux/htirq.h | 24 ++++-- 5 files changed, 158 insertions(+), 88 deletions(-)
arch/x86/include/asm/hw_irq.h +13 -0
@@ -161,6 +161,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 }; };
@@ -227,6 +235,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 +120 -41
209 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 v7 22/38 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!
Folded a patch from Dimitri Sivanich <[email protected]> to fix a bug on UV platforms, please refer to:
http://lkml.org/lkml/2014/12/16/351
--- arch/x86/include/asm/hw_irq.h | 9 ++ arch/x86/platform/uv/uv_irq.c | 290 ++++++++++++++++------------------------- 2 files changed, 119 insertions(+), 180 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 {
@@ -169,6 +170,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 +110 -180
361 lines not on this page · raw message
Signature · 1 line
1.7.10.4
PATCH v7 23/38 x86/irq: Normalize x86 irq_chip name
In reply to Jiang LiuSome irq_chip names use underscore, others use hyphen. So normalize them to use hythen as separator.
--- arch/x86/kernel/apic/msi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/kernel/apic/msi.c +2 -2
@@ -188,7 +188,7 @@ dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask, }static struct irq_chip dmar_msi_controller = { - .name ="DMAR_MSI" , + .name ="DMAR-MSI" , .irq_unmask = dmar_msi_unmask, .irq_mask = dmar_msi_mask, .irq_ack = irq_chip_ack_parent,
@@ -319,7 +319,7 @@ static int hpet_msi_set_affinity(struct irq_data *data, }static struct irq_chip hpet_msi_controller = { - .name ="HPET_MSI" , + .name ="HPET-MSI" , .irq_unmask = hpet_msi_unmask, .irq_mask = hpet_msi_mask, .irq_ack = irq_chip_ack_parent,
Signature · 1 line
1.7.10.4
PATCH v7 24/38 x86/MSI: Simplify the way to deal with remapped MSI interrupts
In reply to Jiang LiuSimplify the way to deal with remapped MSI interrupts, so we could kill irq_chip.irq_print_chip later.
--- arch/x86/kernel/apic/msi.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-)
arch/x86/kernel/apic/msi.c +24 -4
@@ -77,7 +77,6 @@ static struct irq_chip pci_msi_controller = { .irq_ack = irq_chip_ack_parent, .irq_set_affinity = msi_domain_set_affinity, .irq_retrigger = irq_chip_retrigger_hierarchy, - .irq_print_chip = irq_remapping_print_chip, .irq_compose_msi_msg = irq_msi_compose_msg, .irq_write_msi_msg = pci_msi_domain_write_msg, .flags = IRQCHIP_SKIP_SET_WAKE,
@@ -143,7 +142,7 @@ static struct msi_domain_ops pci_msi_domain_ops = {static struct msi_domain_info pci_msi_domain_info = { .flags =MSI_FLAG_USE_DEF_DOM_OPS |MSI_FLAG_USE_DEF_CHIP_OPS | -MSI_FLAG_MULTI_PCI_MSI |MSI_FLAG_PCI_MSIX , +MSI_FLAG_PCI_MSIX , .ops = &pci_msi_domain_ops, .chip = &pci_msi_controller, .handler = handle_edge_irq,
@@ -162,9 +161,29 @@ void arch_init_msi_domain(struct irq_domain *parent) }#ifdef CONFIG_IRQ_REMAP +static struct irq_chip pci_msi_ir_controller = { + .name ="IR-PCI-MSI" , + .irq_unmask = pci_msi_unmask_irq, + .irq_mask = pci_msi_mask_irq, + .irq_ack = irq_chip_ack_parent, + .irq_set_affinity = msi_domain_set_affinity, + .irq_retrigger = irq_chip_retrigger_hierarchy, + .irq_write_msi_msg = pci_msi_domain_write_msg, + .flags =IRQCHIP_SKIP_SET_WAKE , +}; + +static struct msi_domain_info pci_msi_ir_domain_info = { + .flags =MSI_FLAG_USE_DEF_DOM_OPS |MSI_FLAG_USE_DEF_CHIP_OPS | +MSI_FLAG_MULTI_PCI_MSI |MSI_FLAG_PCI_MSIX , + .ops = &pci_msi_domain_ops, + .chip = &pci_msi_ir_controller, + .handler = handle_edge_irq, + .handler_name ="edge" , +}; +struct irq_domain *arch_create_msi_irq_domain (struct irq_domain *parent) { -return msi_create_irq_domain (NULL , &pci_msi_domain_info, parent); +return pci_msi_create_irq_domain (NULL , &pci_msi_ir_domain_info, parent); }#endif
@@ -325,7 +344,6 @@ static struct irq_chip hpet_msi_controller = { .irq_ack = irq_chip_ack_parent, .irq_set_affinity = hpet_msi_set_affinity, .irq_retrigger = irq_chip_retrigger_hierarchy, - .irq_print_chip = irq_remapping_print_chip, .irq_compose_msi_msg = irq_msi_compose_msg, .flags = IRQCHIP_SKIP_SET_WAKE, };
@@ -402,6 +420,8 @@ struct irq_domain *hpet_create_irq_domain(int hpet_id) parent =irq_remapping_get_ir_irq_domain (&info);if (parent ==NULL ) parent = x86_vector_domain; +else + hpet_msi_controller.name ="IR-HPET-MSI" ;return irq_domain_add_hierarchy (parent,0 ,0 ,NULL , &hpet_domain_ops, (void *)(long )hpet_id);
Signature · 1 line
1.7.10.4
PATCH v7 25/38 x86/MSI: Replace msi_update_msg() with irq_chip_compose_msi_msg()
In reply to Jiang LiuFunction irq_chip_compose_msi_msg() can achieve the same goal as msi_update_msg(), so kill msi_update_msg().
--- arch/x86/kernel/apic/msi.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-)
arch/x86/kernel/apic/msi.c +2 -17
@@ -53,19 +53,6 @@ static void irq_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)MSI_DATA_VECTOR (cfg->vector); } -static void msi_update_msg (struct msi_msg *msg,struct irq_data *irq_data) -{ -struct irq_cfg *cfg =irqd_cfg (irq_data); - - msg->data &= ~MSI_DATA_VECTOR_MASK ; - msg->data |=MSI_DATA_VECTOR (cfg->vector); - msg->address_lo &= ~MSI_ADDR_DEST_ID_MASK ; - msg->address_lo |=MSI_ADDR_DEST_ID (cfg->dest_apicid); -if (x2apic_enabled ()) - msg->address_hi =MSI_ADDR_BASE_HI | -MSI_ADDR_EXT_DEST_ID (cfg->dest_apicid); -} -/* * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, * which implement the MSI or MSI-X Capability Structure.
@@ -198,8 +185,7 @@ dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask, ret = parent->chip->irq_set_affinity (parent, mask, force);if (ret >=0 ) { -dmar_msi_read (data->irq, &msg); -msi_update_msg (&msg, data); +irq_chip_compose_msi_msg (data, &msg);dmar_msi_write (data->irq, &msg); }
@@ -329,8 +315,7 @@ static int hpet_msi_set_affinity(struct irq_data *data, ret = parent->chip->irq_set_affinity (parent, mask, force);if (ret >=0 && ret !=IRQ_SET_MASK_OK_DONE ) { -hpet_msi_read (data->handler_data, &msg); -msi_update_msg (&msg, data); +irq_chip_compose_msi_msg (data, &msg);hpet_msi_write (data->handler_data, &msg); }
Signature · 1 line
1.7.10.4
PATCH v7 26/38 x86/irq: Implement irq_chip.irq_write_msi_msg for MSI/DMAR/HPET irq_chips
In reply to Jiang LiuImplement irq_chip.irq_write_msi_msg for MSI/DMAR/HPET irq_chips, they will be used to share common code later.
--- arch/x86/kernel/apic/msi.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
arch/x86/kernel/apic/msi.c +12 -0
@@ -192,6 +192,11 @@ dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask,return ret; } +static void dmar_msi_write_msg (struct irq_data *data,struct msi_msg *msg) +{ +dmar_msi_write (data->irq, msg); +} +static struct irq_chip dmar_msi_controller = { .name ="DMAR-MSI" , .irq_unmask = dmar_msi_unmask,
@@ -200,6 +205,7 @@ static struct irq_chip dmar_msi_controller = { .irq_set_affinity = dmar_msi_set_affinity, .irq_retrigger = irq_chip_retrigger_hierarchy, .irq_compose_msi_msg = irq_msi_compose_msg, + .irq_write_msi_msg = dmar_msi_write_msg, .flags = IRQCHIP_SKIP_SET_WAKE, };
@@ -322,6 +328,11 @@ static int hpet_msi_set_affinity(struct irq_data *data,return ret; } +static void hpet_msi_write_msg (struct irq_data *data,struct msi_msg *msg) +{ +hpet_msi_write (data->handler_data, msg); +} +static struct irq_chip hpet_msi_controller = { .name ="HPET-MSI" , .irq_unmask = hpet_msi_unmask,
@@ -330,6 +341,7 @@ static struct irq_chip hpet_msi_controller = { .irq_set_affinity = hpet_msi_set_affinity, .irq_retrigger = irq_chip_retrigger_hierarchy, .irq_compose_msi_msg = irq_msi_compose_msg, + .irq_write_msi_msg = hpet_msi_write_msg, .flags = IRQCHIP_SKIP_SET_WAKE, };
Signature · 1 line
1.7.10.4
PATCH v7 27/38 x86/irq: Simplify MSI/DMAR/HPET implementation by using common code
In reply to Jiang LiuUse common MSI interfaces to simplify DMAR/HPET driver implementation.
--- arch/x86/kernel/apic/msi.c | 192 +++++++++++++------------------------------- 1 file changed, 54 insertions(+), 138 deletions(-)
arch/x86/kernel/apic/msi.c +54 -138
@@ -62,10 +62,8 @@ static struct irq_chip pci_msi_controller = { .irq_unmask = pci_msi_unmask_irq, .irq_mask = pci_msi_mask_irq, .irq_ack = irq_chip_ack_parent, - .irq_set_affinity = msi_domain_set_affinity, .irq_retrigger = irq_chip_retrigger_hierarchy, .irq_compose_msi_msg = irq_msi_compose_msg, - .irq_write_msi_msg = pci_msi_domain_write_msg, .flags = IRQCHIP_SKIP_SET_WAKE, };
@@ -153,9 +151,7 @@ static struct irq_chip pci_msi_ir_controller = { .irq_unmask = pci_msi_unmask_irq, .irq_mask = pci_msi_mask_irq, .irq_ack = irq_chip_ack_parent, - .irq_set_affinity = msi_domain_set_affinity, .irq_retrigger = irq_chip_retrigger_hierarchy, - .irq_write_msi_msg = pci_msi_domain_write_msg, .flags = IRQCHIP_SKIP_SET_WAKE, };
@@ -175,23 +171,6 @@ struct irq_domain *arch_create_msi_irq_domain(struct irq_domain *parent)#endif #ifdef CONFIG_DMAR_TABLE -static int -dmar_msi_set_affinity (struct irq_data *data,const struct cpumask *mask, -bool force) -{ -struct irq_data *parent = data->parent_data; -struct msi_msg msg; -int ret; - - ret = parent->chip->irq_set_affinity (parent, mask, force); -if (ret >=0 ) { -irq_chip_compose_msi_msg (data, &msg); -dmar_msi_write (data->irq, &msg); - } - -return ret; -} -static void dmar_msi_write_msg (struct irq_data *data,struct msi_msg *msg) {dmar_msi_write (data->irq, msg);
@@ -202,67 +181,37 @@ static struct irq_chip dmar_msi_controller = { .irq_unmask = dmar_msi_unmask, .irq_mask = dmar_msi_mask, .irq_ack = irq_chip_ack_parent, - .irq_set_affinity = dmar_msi_set_affinity, + .irq_set_affinity = msi_domain_set_affinity, .irq_retrigger = irq_chip_retrigger_hierarchy, .irq_compose_msi_msg = irq_msi_compose_msg, .irq_write_msi_msg = dmar_msi_write_msg, .flags = IRQCHIP_SKIP_SET_WAKE, }; -static int dmar_domain_alloc (struct irq_domain *domain,unsigned int virq, -unsigned int nr_irqs,void *arg) +static irq_hw_number_t dmar_msi_get_hwirq (struct msi_domain_info *info, +msi_alloc_info_t *arg) { -struct irq_alloc_info *info = arg; -int ret; - -if (nr_irqs >1 || !info || info->type !=X86_IRQ_ALLOC_TYPE_DMAR ) -return -EINVAL ; -if (irq_find_mapping (domain, info->dmar_id)) { -pr_warn ("IRQ for DMAR%d already exists.\n" , info->dmar_id); -return -EEXIST ; - } - - ret =irq_domain_alloc_irqs_parent (domain, virq, nr_irqs, arg); -if (ret >=0 ) { -irq_domain_set_hwirq_and_chip (domain, virq, info->dmar_id, - &dmar_msi_controller,NULL ); -irq_set_handler_data (virq, info->dmar_data); -__irq_set_handler (virq, handle_edge_irq,0 ,"edge" ); - } - -return ret; +return arg->dmar_id; } -static void dmar_domain_free (struct irq_domain *domain,unsigned int virq, -unsigned int nr_irqs) +static int dmar_msi_init (struct irq_domain *domain, +struct msi_domain_info *info,unsigned int virq, +irq_hw_number_t hwirq,msi_alloc_info_t *arg) { -BUG_ON (nr_irqs >1 ); -irq_domain_free_irqs_top (domain, virq, nr_irqs); -} +irq_domain_set_info (domain, virq, arg->dmar_id, info->chip,NULL , + handle_edge_irq, arg->dmar_data,"edge" ); -static void dmar_domain_activate (struct irq_domain *domain, -struct irq_data *irq_data) -{ -struct msi_msg msg; - -BUG_ON (irq_chip_compose_msi_msg (irq_data, &msg)); -dmar_msi_write (irq_data->irq, &msg); +return 0 ; } -static void dmar_domain_deactivate (struct irq_domain *domain, -struct irq_data *irq_data) -{ -struct msi_msg msg; - -memset (&msg,0 ,sizeof (msg)); -dmar_msi_write (irq_data->irq, &msg); -} +static struct msi_domain_ops dmar_msi_domain_ops = { + .get_hwirq = dmar_msi_get_hwirq, + .msi_init = dmar_msi_init, +}; -static struct irq_domain_ops dmar_domain_ops = { - .alloc = dmar_domain_alloc, - .free = dmar_domain_free, - .activate = dmar_domain_activate, - .deactivate = dmar_domain_deactivate, +static struct msi_domain_info dmar_msi_domain_info = { + .ops = &dmar_msi_domain_ops, + .chip = &dmar_msi_controller, };static struct irq_domain *dmar_get_irq_domain (void )
@@ -271,11 +220,9 @@ static struct irq_domain *dmar_get_irq_domain(void)static DEFINE_MUTEX (dmar_lock);mutex_lock (&dmar_lock); -if (dmar_domain ==NULL ) { - dmar_domain =irq_domain_add_tree (NULL , &dmar_domain_ops,NULL ); -if (dmar_domain) - dmar_domain->parent = x86_vector_domain; - } +if (dmar_domain ==NULL ) + dmar_domain =msi_create_irq_domain (NULL , &dmar_msi_domain_info, + x86_vector_domain);mutex_unlock (&dmar_lock);return dmar_domain;
@@ -309,23 +256,9 @@ void dmar_free_hwirq(int irq)#ifdef CONFIG_HPET_TIMER static inline int hpet_dev_id (struct irq_domain *domain) { -return (int )(long )domain->host_data; -} +struct msi_domain_info *info =msi_get_domain_info (domain); -static int hpet_msi_set_affinity (struct irq_data *data, -const struct cpumask *mask,bool force) -{ -struct irq_data *parent = data->parent_data; -struct msi_msg msg; -int ret; - - ret = parent->chip->irq_set_affinity (parent, mask, force); -if (ret >=0 && ret !=IRQ_SET_MASK_OK_DONE ) { -irq_chip_compose_msi_msg (data, &msg); -hpet_msi_write (data->handler_data, &msg); - } - -return ret; +return (int )(long )info->data; }static void hpet_msi_write_msg (struct irq_data *data,struct msi_msg *msg)
@@ -338,79 +271,63 @@ static struct irq_chip hpet_msi_controller = { .irq_unmask = hpet_msi_unmask, .irq_mask = hpet_msi_mask, .irq_ack = irq_chip_ack_parent, - .irq_set_affinity = hpet_msi_set_affinity, + .irq_set_affinity = msi_domain_set_affinity, .irq_retrigger = irq_chip_retrigger_hierarchy, .irq_compose_msi_msg = irq_msi_compose_msg, .irq_write_msi_msg = hpet_msi_write_msg, .flags = IRQCHIP_SKIP_SET_WAKE, }; -static int hpet_domain_alloc (struct irq_domain *domain,unsigned int virq, -unsigned int nr_irqs,void *arg) -{ -struct irq_alloc_info *info = arg; -int ret; - -if (nr_irqs >1 || !info || info->type !=X86_IRQ_ALLOC_TYPE_HPET ) -return -EINVAL ; -if (irq_find_mapping (domain, info->hpet_index)) { -pr_warn ("IRQ for HPET%d already exists.\n" , info->hpet_index); -return -EEXIST ; - } - - ret =irq_domain_alloc_irqs_parent (domain, virq, nr_irqs, arg); -if (ret >=0 ) { -irq_set_status_flags (virq,IRQ_MOVE_PCNTXT ); -irq_domain_set_hwirq_and_chip (domain, virq, info->hpet_index, - &hpet_msi_controller,NULL ); -irq_set_handler_data (virq, info->hpet_data); -__irq_set_handler (virq, handle_edge_irq,0 ,"edge" ); - } - -return ret; -} - -static void hpet_domain_free (struct irq_domain *domain,unsigned int virq, -unsigned int nr_irqs) +static irq_hw_number_t hpet_msi_get_hwirq (struct msi_domain_info *info, +msi_alloc_info_t *arg) { -BUG_ON (nr_irqs >1 ); -irq_clear_status_flags (virq,IRQ_MOVE_PCNTXT ); -irq_domain_free_irqs_top (domain, virq, nr_irqs); +return arg->hpet_index; } -static void hpet_domain_activate (struct irq_domain *domain, -struct irq_data *irq_data) +static int hpet_msi_init (struct irq_domain *domain, +struct msi_domain_info *info,unsigned int virq, +irq_hw_number_t hwirq,msi_alloc_info_t *arg) { -struct msi_msg msg; +irq_set_status_flags (virq,IRQ_MOVE_PCNTXT ); +irq_domain_set_info (domain, virq, arg->hpet_index, info->chip,NULL , + handle_edge_irq, arg->hpet_data,"edge" ); -BUG_ON (irq_chip_compose_msi_msg (irq_data, &msg)); -hpet_msi_write (irq_get_handler_data (irq_data->irq), &msg); +return 0 ; } -static void hpet_domain_deactivate (struct irq_domain *domain, -struct irq_data *irq_data) +static void hpet_msi_free (struct irq_domain *domain, +struct msi_domain_info *info,unsigned int virq) { -struct msi_msg msg; - -memset (&msg,0 ,sizeof (msg)); -hpet_msi_write (irq_get_handler_data (irq_data->irq), &msg); +irq_clear_status_flags (virq,IRQ_MOVE_PCNTXT ); } -static struct irq_domain_ops hpet_domain_ops = { - .alloc = hpet_domain_alloc, - .free = hpet_domain_free, - .activate = hpet_domain_activate, - .deactivate = hpet_domain_deactivate, +static struct msi_domain_ops hpet_msi_domain_ops = { + .get_hwirq = hpet_msi_get_hwirq, + .msi_init = hpet_msi_init, + .msi_free = hpet_msi_free, +}; + +static struct msi_domain_info hpet_msi_domain_info = { + .ops = &hpet_msi_domain_ops, + .chip = &hpet_msi_controller, };struct irq_domain *hpet_create_irq_domain (int hpet_id) {struct irq_domain *parent;struct irq_alloc_info info; +struct msi_domain_info *domain_info;if (x86_vector_domain ==NULL )return NULL ; + domain_info =kzalloc (sizeof (*domain_info),GFP_KERNEL ); +if (!domain_info) +return NULL ; + + *domain_info = hpet_msi_domain_info; + domain_info->data = (void *)(long )hpet_id; +init_irq_alloc_info (&info,NULL ); info.type =X86_IRQ_ALLOC_TYPE_HPET ; info.hpet_id = hpet_id;
@@ -420,8 +337,7 @@ struct irq_domain *hpet_create_irq_domain(int hpet_id)else hpet_msi_controller.name ="IR-HPET-MSI" ; -return irq_domain_add_hierarchy (parent,0 ,0 ,NULL , &hpet_domain_ops, - (void *)(long )hpet_id); +return msi_create_irq_domain (NULL , domain_info, parent); } int hpet_assign_irq(struct irq_domain *domain, struct hpet_dev *dev,
Signature · 1 line
1.7.10.4
PATCH v7 28/38 irq_remapping: Kill unused function irq_remapping_print_chip()
In reply to Jiang LiuNow there's no user of irq_remapping_print_chip(), so kill it.
--- arch/x86/include/asm/irq_remapping.h | 2 -- drivers/iommu/irq_remapping.c | 13 ------------- 2 files changed, 15 deletions(-)
arch/x86/include/asm/irq_remapping.h +0 -2
@@ -59,7 +59,6 @@ extern struct irq_domain * irq_remapping_get_ir_irq_domain( struct irq_alloc_info *info);extern struct irq_domain *irq_remapping_get_irq_domain (struct irq_alloc_info *info); -extern void irq_remapping_print_chip (struct irq_data *data,struct seq_file *p);/* Create PCI MSI/MSIx irqdomain, use @parent as the parent irqdomain. */ extern struct irq_domain *arch_create_msi_irq_domain (struct irq_domain *parent);
@@ -115,6 +114,5 @@ irq_remapping_get_irq_domain(struct irq_alloc_info *info)return NULL ; } -#define irq_remapping_print_chip NULL#endif /* CONFIG_IRQ_REMAP */ #endif /* __X86_IRQ_REMAPPING_H */
drivers/iommu/irq_remapping.c +0 -13
@@ -204,19 +204,6 @@ static void ir_ack_apic_level(struct irq_data *data)eoi_ioapic_irq (data->irq,irqd_cfg (data)); } -void irq_remapping_print_chip (struct irq_data *data,struct seq_file *p) -{ -/* -* Assume interrupt is remapped if the parent irqdomain isn't the -* vector domain, which is true for MSI, HPET and IOAPIC on x86 -* platforms. -*/ -if (data->domain && data->domain->parent !=arch_get_ir_parent_domain ()) -seq_printf (p," IR-%s" , data->chip->name); -else -seq_printf (p," %s" , data->chip->name); -} -static void ir_print_prefix (struct irq_data *data,struct seq_file *p) {seq_printf (p," IR-%s" , data->chip->name);
Signature · 1 line
1.7.10.4
PATCH v7 29/38 x86/intel-mid: Delay initialization of APB timer
In reply to Jiang LiuFrom: Thomas Gleixner <[email protected]>
MID has no PIC, but depending on the platform it requires the abt_timer, which is connected to irq0. The timer is set up at late_time_init().
But, looking at the MID code it seems, that there is no reason to do so. The only code which might need the timer working is the TSC calibration code, but thats a non issue on MID as that is using its own empty calibration function. And check_timer() is not invoked either because MID has no PIC and therefor no legacy irqs.
So if you look at intel_mid_time_init() then you'll see that in the ARAT case the timer setup is skipped already. So until the point where x86_init.timers.setup_percpu_clockev() is called for the boot cpu nothing really needs a timer on MID.
According to the MID code the apbt horror is only used for moorestown. Medfield and later use the local apic timer without the apbt nonsense.
The best thing we can do is to drop moorestown support and get rid of that apbt nonsense alltogether.
I don't think anyone deeply cares about it not being supported from 3.18 on. The number of devices which sport a moorestown should be pretty limited and the only relevant use case of those is to act as a pocket heater with short battery life time. Its pretty pointless to update kernels on pocket heaters except for bragging reasons.
If someone at Intel really thinks that we need to keep moorestown alive for other than documentary and sentimental reasons, then we can move the apbt setup to x86_init.timers.setup_percpu_clockev(). At that point the IOAPIC is setup already, so it should just work.
--- arch/x86/kernel/apb_timer.c | 4 ---- arch/x86/platform/intel-mid/intel-mid.c | 18 +++++++++++++----- arch/x86/platform/intel-mid/sfi.c | 2 -- 3 files changed, 13 insertions(+), 11 deletions(-)
arch/x86/kernel/apb_timer.c +0 -4
@@ -179,10 +179,6 @@ static int __init apbt_clockevent_register(void)static void apbt_setup_irq (struct apbt_dev *adev) { -/* timer0 irq has been setup early */ -if (adev->irq ==0 ) -return ; -irq_modify_status (adev->irq,0 ,IRQ_MOVE_PCNTXT );irq_set_affinity (adev->irq,cpumask_of (adev->cpu)); }
arch/x86/platform/intel-mid/intel-mid.c +13 -5
@@ -81,26 +81,34 @@ static unsigned long __init intel_mid_calibrate_tsc(void)return 0 ; } +static void __init intel_mid_setup_bp_timer (void ) +{ +apbt_time_init (); +setup_boot_APIC_clock (); +} +static void __init intel_mid_time_init (void ) {sfi_table_parse (SFI_SIG_MTMR ,NULL ,NULL , sfi_parse_mtmr); +switch (intel_mid_timer_options) {case INTEL_MID_TIMER_APBT_ONLY :break ;case INTEL_MID_TIMER_LAPIC_APBT : - x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock; +/* Use apbt and local apic */ + x86_init.timers.setup_percpu_clockev = intel_mid_setup_bp_timer; x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock; -break ; +return ;default :if (!boot_cpu_has (X86_FEATURE_ARAT ))break ; +/* Lapic only, no apbt */ x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock; x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock;return ; } -/* we need at least one APB timer */ -pre_init_apic_IRQ0 (); -apbt_time_init (); + + x86_init.timers.setup_percpu_clockev = apbt_time_init; }static void intel_mid_arch_setup (void )
arch/x86/platform/intel-mid/sfi.c +0 -2
@@ -95,8 +95,6 @@ int __init sfi_parse_mtmr(struct sfi_table_header *table)pr_debug ("timer[%d]: paddr = 0x%08x, freq = %dHz, irq = %d\n" , totallen, (u32 )pentry->phys_addr, pentry->freq_hz, pentry->irq); -if (!pentry->irq) -continue ; mp_irq.type =MP_INTSRC ; mp_irq.irqtype = mp_INT;/* triggering mode edge bit 2-3, active high polarity bit 0-1 */
Signature · 1 line
1.7.10.4
PATCH v7 30/38 x86/intel-mid, trivial: Refine code syntax for sfi_parse_mtmr()
In reply to Jiang LiuCorrectly indent code in function sfi_parse_mtmr().
--- arch/x86/platform/intel-mid/sfi.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
arch/x86/platform/intel-mid/sfi.c +10 -10
@@ -95,16 +95,16 @@ int __init sfi_parse_mtmr(struct sfi_table_header *table)pr_debug ("timer[%d]: paddr = 0x%08x, freq = %dHz, irq = %d\n" , totallen, (u32 )pentry->phys_addr, pentry->freq_hz, pentry->irq); - mp_irq.type =MP_INTSRC ; - mp_irq.irqtype = mp_INT; -/* triggering mode edge bit 2-3, active high polarity bit 0-1 */ - mp_irq.irqflag =5 ; - mp_irq.srcbus =MP_BUS_ISA ; - mp_irq.srcbusirq = pentry->irq;/* IRQ */ - mp_irq.dstapic =MP_APIC_ALL ; - mp_irq.dstirq = pentry->irq; -mp_save_irq (&mp_irq); -mp_map_gsi_to_irq (pentry->irq,IOAPIC_MAP_ALLOC ); + mp_irq.type =MP_INTSRC ; + mp_irq.irqtype = mp_INT; +/* triggering mode edge bit 2-3, active high polarity bit 0-1 */ + mp_irq.irqflag =5 ; + mp_irq.srcbus =MP_BUS_ISA ; + mp_irq.srcbusirq = pentry->irq;/* IRQ */ + mp_irq.dstapic =MP_APIC_ALL ; + mp_irq.dstirq = pentry->irq; +mp_save_irq (&mp_irq); +mp_map_gsi_to_irq (pentry->irq,IOAPIC_MAP_ALLOC ); }return 0 ;
Signature · 1 line
1.7.10.4
PATCH v7 31/38 x86/apb_timer: Remove unused function is_apbt_capable()
In reply to Jiang LiuFrom: Rickard Strandqvist <[email protected]>
Remove the function is_apbt_capable() that is not used anywhere.
This was partially found by using a static code analysis program called cppcheck.
--- arch/x86/kernel/apb_timer.c | 8 -------- 1 file changed, 8 deletions(-)
arch/x86/kernel/apb_timer.c +0 -8
@@ -135,14 +135,6 @@ static inline void apbt_clear_mapping(void) apbt_virt_address =NULL ; } -/* -* APBT timer interrupt enable / disable -*/ -static inline int is_apbt_capable (void ) -{ -return apbt_virt_address ?1 :0 ; -} -static int __init apbt_clockevent_register (void ) {struct sfi_timer_table_entry *mtmr;
Signature · 1 line
1.7.10.4
PATCH v7 32/38 x86/irq: Kill unused pre_init_apic_IRQ0()
In reply to Jiang LiuNow there's no user of pre_init_apic_IRQ0(), so kill it.
--- arch/x86/include/asm/io_apic.h | 1 - arch/x86/kernel/apic/io_apic.c | 17 ----------------- 2 files changed, 18 deletions(-)
arch/x86/include/asm/io_apic.h +0 -1
@@ -204,7 +204,6 @@ extern int mp_irqdomain_map(struct irq_domain *domain, unsigned int virq, irq_hw_number_t hwirq);extern void mp_irqdomain_unmap (struct irq_domain *domain,unsigned int virq);extern int mp_set_gsi_attr (u32 gsi,int trigger,int polarity,int node); -extern void __init pre_init_apic_IRQ0 (void );extern void mp_save_irq (struct mpc_intsrc *m);
arch/x86/kernel/apic/io_apic.c +0 -17
@@ -3091,20 +3091,3 @@ int mp_set_gsi_attr(u32 gsi, int trigger, int polarity, int node)return ret; } - -/* Enable IOAPIC early just for system timer */ -void __init pre_init_apic_IRQ0 (void ) -{ -struct io_apic_irq_attr attr = {0 ,0 ,0 ,0 }; - -printk (KERN_INFO "Early APIC setup for system timer0\n" ); -#ifndef CONFIG_SMP -physid_set_mask_of_physid (boot_cpu_physical_apicid, - &phys_cpu_present_map); -#endif -setup_local_APIC (); - -io_apic_setup_irq_pin (0 ,0 , &attr); -irq_set_chip_and_handler_name (0 , &ioapic_chip, handle_edge_irq, -"edge" ); -}
Signature · 1 line
1.7.10.4
PATCH v7 33/38 x86/irq: Prepare IOAPIC interfaces to support hierarchy irqdomain
In reply to Jiang LiuIntroduce helper functions to manipulate struct irq_alloc_info for IOAPIC. Also add extra parameter to IOAPIC interfaces to prepare for hierarchy irqdomain. Function mp_set_gsi_attr() will be killed once we have switched to hierarchy irqdomain.
--- arch/x86/include/asm/io_apic.h | 14 ++++++- arch/x86/kernel/acpi/boot.c | 9 +++-- arch/x86/kernel/apic/io_apic.c | 39 +++++++++++++------- arch/x86/pci/intel_mid_pci.c | 4 +- .../platform/intel-mid/device_libs/platform_wdt.c | 4 +- arch/x86/platform/intel-mid/sfi.c | 9 +++-- 6 files changed, 56 insertions(+), 23 deletions(-)
arch/x86/include/asm/io_apic.h +12 -2
@@ -95,6 +95,8 @@ struct IR_IO_APIC_route_entry { index :15 ; } __attribute__ ((packed)); +struct irq_alloc_info ; +#define IOAPIC_AUTO -1#define IOAPIC_EDGE 0#define IOAPIC_LEVEL 1
@@ -194,7 +196,8 @@ extern u32 gsi_top;extern int mp_find_ioapic (u32 gsi);extern int mp_find_ioapic_pin (int ioapic,u32 gsi);extern u32 mp_pin_to_gsi (int ioapic,int pin); -extern int mp_map_gsi_to_irq (u32 gsi,unsigned int flags); +extern int mp_map_gsi_to_irq (u32 gsi,unsigned int flags, +struct irq_alloc_info *info);extern void mp_unmap_irq (int irq);extern int mp_register_ioapic (int id,u32 address,u32 gsi_base,struct ioapic_domain_cfg *cfg);
@@ -203,6 +206,8 @@ extern int mp_ioapic_registered(u32 gsi_base);extern int mp_irqdomain_map (struct irq_domain *domain,unsigned int virq,irq_hw_number_t hwirq);extern void mp_irqdomain_unmap (struct irq_domain *domain,unsigned int virq); +extern void ioapic_set_alloc_attr (struct irq_alloc_info *info, +int node,int trigger,int polarity);extern int mp_set_gsi_attr (u32 gsi,int trigger,int polarity,int node);extern void mp_save_irq (struct mpc_intsrc *m);
@@ -253,7 +258,12 @@ static inline void print_IO_APICs(void) {}#define gsi_top (NR_IRQS_LEGACY)static inline int mp_find_ioapic (u32 gsi) {return 0 ; }static inline u32 mp_pin_to_gsi (int ioapic,int pin) {return UINT_MAX ; } -static inline int mp_map_gsi_to_irq (u32 gsi,unsigned int flags) {return gsi; } +static inline int mp_map_gsi_to_irq (u32 gsi,unsigned int flags, +struct irq_alloc_info *info) +{ +return gsi; +} +static inline void mp_unmap_irq (int irq) { }static inline int save_ioapic_entries (void )
arch/x86/kernel/acpi/boot.c +6 -3
@@ -404,6 +404,7 @@ static int mp_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) {int irq, node; +struct irq_alloc_info info;if (acpi_irq_model !=ACPI_IRQ_MODEL_IOAPIC )return gsi;
@@ -416,7 +417,8 @@ static int mp_register_gsi(struct device *dev, u32 gsi, int trigger,return -1 ; } - irq =mp_map_gsi_to_irq (gsi,IOAPIC_MAP_ALLOC ); +ioapic_set_alloc_attr (&info, node, trigger, polarity); + irq =mp_map_gsi_to_irq (gsi,IOAPIC_MAP_ALLOC , &info);if (irq <0 )return irq;
@@ -434,7 +436,7 @@ static void mp_unregister_gsi(u32 gsi)if (acpi_irq_model !=ACPI_IRQ_MODEL_IOAPIC )return ; - irq =mp_map_gsi_to_irq (gsi,0 ); + irq =mp_map_gsi_to_irq (gsi,0 ,NULL );if (irq >0 )mp_unmap_irq (irq); }
@@ -618,7 +620,8 @@ int acpi_gsi_to_irq(u32 gsi, unsigned int *irqp) }else {mutex_lock (&acpi_ioapic_lock); irq =mp_map_gsi_to_irq (gsi, -IOAPIC_MAP_ALLOC |IOAPIC_MAP_CHECK ); +IOAPIC_MAP_ALLOC |IOAPIC_MAP_CHECK , +NULL );mutex_unlock (&acpi_ioapic_lock);if (irq <0 )return -1 ;
arch/x86/kernel/apic/io_apic.c +26 -13
@@ -938,7 +938,19 @@ static int irq_trigger(int idx)return trigger; } -static int alloc_irq_from_domain (struct irq_domain *domain,u32 gsi,int pin) +void ioapic_set_alloc_attr (struct irq_alloc_info *info,int node, +int trigger,int polarity) +{ +init_irq_alloc_info (info,NULL ); + info->type =X86_IRQ_ALLOC_TYPE_IOAPIC ; + info->ioapic_node = node; + info->ioapic_trigger = trigger; + info->ioapic_polarity = polarity; + info->ioapic_valid =1 ; +} + +static int alloc_irq_from_domain (struct irq_domain *domain,u32 gsi,int pin, +struct irq_alloc_info *info) {int irq =-1 ;int ioapic = (int )(long )domain->host_data;
@@ -971,11 +983,11 @@ static int alloc_irq_from_domain(struct irq_domain *domain, u32 gsi, int pin) }static int mp_map_pin_to_irq (u32 gsi,int idx,int ioapic,int pin, -unsigned int flags) +unsigned int flags,struct irq_alloc_info *info) {int irq;struct irq_domain *domain =mp_ioapic_irqdomain (ioapic); -struct mp_pin_info *info =mp_pin_info (ioapic, pin); +struct mp_pin_info *pinfo =mp_pin_info (ioapic, pin);if (!domain)return -1 ;
@@ -997,30 +1009,30 @@ static int mp_map_pin_to_irq(u32 gsi, int idx, int ioapic, int pin,if (idx >=0 &&test_bit (mp_irqs[idx].srcbus, mp_bus_not_pci)) { irq = mp_irqs[idx].srcbusirq;if (flags &IOAPIC_MAP_ALLOC ) { -if (info->count ==0 && +if (pinfo->count ==0 &&mp_irqdomain_map (domain, irq, pin) !=0 ) irq =-1 ;/* special handling for timer IRQ0 */ if (irq ==0 ) - info->count++; + pinfo->count++; } }else { irq =irq_find_mapping (domain, pin);if (irq <=0 && (flags &IOAPIC_MAP_ALLOC )) - irq =alloc_irq_from_domain (domain, gsi, pin); + irq =alloc_irq_from_domain (domain, gsi, pin, info); }if (flags &IOAPIC_MAP_ALLOC ) {/* special handling for legacy IRQs */ -if (irq <nr_legacy_irqs () && info->count ==1 && +if (irq <nr_legacy_irqs () && pinfo->count ==1 &&mp_irqdomain_map (domain, irq, pin) !=0 ) irq =-1 ;if (irq >0 ) - info->count++; -else if (info->count ==0 ) - info->set =0 ; + pinfo->count++; +else if (pinfo->count ==0 ) + pinfo->set =0 ; }mutex_unlock (&ioapic_mutex);
@@ -1058,10 +1070,11 @@ static int pin_2_irq(int idx, int ioapic, int pin, unsigned int flags) }#endif -return mp_map_pin_to_irq (gsi, idx, ioapic, pin, flags); +return mp_map_pin_to_irq (gsi, idx, ioapic, pin, flags,NULL ); } -int mp_map_gsi_to_irq (u32 gsi,unsigned int flags) +int mp_map_gsi_to_irq (u32 gsi,unsigned int flags, +struct irq_alloc_info *info) {int ioapic, pin, idx;
@@ -1074,7 +1087,7 @@ int mp_map_gsi_to_irq(u32 gsi, unsigned int flags)if ((flags &IOAPIC_MAP_CHECK ) && idx <0 )return -1 ; -return mp_map_pin_to_irq (gsi, idx, ioapic, pin, flags); +return mp_map_pin_to_irq (gsi, idx, ioapic, pin, flags, info); }void mp_unmap_irq (int irq)
arch/x86/pci/intel_mid_pci.c +3 -1
@@ -208,6 +208,7 @@ static int pci_write(struct pci_bus *bus, unsigned int devfn, int where,static int intel_mid_pci_irq_enable (struct pci_dev *dev) { +struct irq_alloc_info info;int polarity;if (dev->irq_managed && dev->irq >0 )
@@ -217,6 +218,7 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev) polarity =0 ;/* active high */ else polarity =1 ;/* active low */ +ioapic_set_alloc_attr (&info,dev_to_node (&dev->dev),1 , polarity);/* * MRST only have IOAPIC, the PCI irq lines are 1:1 mapped to
@@ -224,7 +226,7 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev)*/ if (mp_set_gsi_attr (dev->irq,1 , polarity,dev_to_node (&dev->dev)))return -EBUSY ; -if (mp_map_gsi_to_irq (dev->irq,IOAPIC_MAP_ALLOC ) <0 ) +if (mp_map_gsi_to_irq (dev->irq,IOAPIC_MAP_ALLOC , &info) <0 )return -EBUSY ; dev->irq_managed =1 ;
arch/x86/platform/intel-mid/device_libs/platform_wdt.c +3 -1
@@ -27,6 +27,7 @@ static struct platform_device wdt_dev = {static int tangier_probe (struct platform_device *pdev) {int gsi; +struct irq_alloc_info info;struct intel_mid_wdt_pdata *pdata = pdev->dev.platform_data;if (!pdata)
@@ -34,8 +35,9 @@ static int tangier_probe(struct platform_device *pdev)/* IOAPIC builds identity mapping between GSI and IRQ on MID */ gsi = pdata->irq; +ioapic_set_alloc_attr (&info,cpu_to_node (0 ),1 ,0 );if (mp_set_gsi_attr (gsi,1 ,0 ,cpu_to_node (0 )) || -mp_map_gsi_to_irq (gsi,IOAPIC_MAP_ALLOC ) <=0 ) { +mp_map_gsi_to_irq (gsi,IOAPIC_MAP_ALLOC , &info) <=0 ) {dev_warn (&pdev->dev,"cannot find interrupt %d in ioapic\n" , gsi);return -EINVAL ;
arch/x86/platform/intel-mid/sfi.c +6 -3
@@ -104,7 +104,7 @@ int __init sfi_parse_mtmr(struct sfi_table_header *table) mp_irq.dstapic =MP_APIC_ALL ; mp_irq.dstirq = pentry->irq;mp_save_irq (&mp_irq); -mp_map_gsi_to_irq (pentry->irq,IOAPIC_MAP_ALLOC ); +mp_map_gsi_to_irq (pentry->irq,IOAPIC_MAP_ALLOC ,NULL ); }return 0 ;
@@ -175,7 +175,7 @@ int __init sfi_parse_mrtc(struct sfi_table_header *table) mp_irq.dstapic =MP_APIC_ALL ; mp_irq.dstirq = pentry->irq;mp_save_irq (&mp_irq); -mp_map_gsi_to_irq (pentry->irq,IOAPIC_MAP_ALLOC ); +mp_map_gsi_to_irq (pentry->irq,IOAPIC_MAP_ALLOC ,NULL ); }return 0 ; }
@@ -434,6 +434,7 @@ static int __init sfi_parse_devs(struct sfi_table_header *table)struct devs_id *dev =NULL ;int num, i, ret;int polarity; +struct irq_alloc_info info; sb = (struct sfi_table_simple *)table; num = SFI_GET_NUM_ENTRIES(sb, struct sfi_device_table_entry);
@@ -467,9 +468,11 @@ static int __init sfi_parse_devs(struct sfi_table_header *table) polarity =1 ; } +ioapic_set_alloc_attr (&info,NUMA_NO_NODE ,1 , polarity); ret =mp_set_gsi_attr (irq,1 , polarity,NUMA_NO_NODE );if (ret ==0 ) - ret =mp_map_gsi_to_irq (irq,IOAPIC_MAP_ALLOC ); + ret =mp_map_gsi_to_irq (irq,IOAPIC_MAP_ALLOC , + &info);WARN_ON (ret <0 ); }
Signature · 1 line
1.7.10.4
PATCH v7 34/38 x86/irq: Implement callbacks to enable hierarchy irqdomain on IOAPICs
In reply to Jiang LiuImplement required callbacks to prepare for enabling hierarchy irqdomain on IOAPICs. Later we will clean up IOAPIC code a lot by using hierarchy irqdomain framework.
--- arch/x86/include/asm/io_apic.h | 10 +++ arch/x86/kernel/apic/io_apic.c | 159 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 166 insertions(+), 3 deletions(-)
arch/x86/include/asm/io_apic.h +10 -0
@@ -96,6 +96,7 @@ struct IR_IO_APIC_route_entry { } __attribute__ ((packed));struct irq_alloc_info ; +struct irq_data ;#define IOAPIC_AUTO -1#define IOAPIC_EDGE 0
@@ -206,6 +207,15 @@ extern int mp_ioapic_registered(u32 gsi_base);extern int mp_irqdomain_map (struct irq_domain *domain,unsigned int virq,irq_hw_number_t hwirq);extern void mp_irqdomain_unmap (struct irq_domain *domain,unsigned int virq); +extern int mp_irqdomain_alloc (struct irq_domain *domain,unsigned int virq, +unsigned int nr_irqs,void *arg); +extern void mp_irqdomain_free (struct irq_domain *domain,unsigned int virq, +unsigned int nr_irqs); +extern void mp_irqdomain_activate (struct irq_domain *domain, +struct irq_data *irq_data); +extern void mp_irqdomain_deactivate (struct irq_domain *domain, +struct irq_data *irq_data); +extern int mp_irqdomain_ioapic_idx (struct irq_domain *domain);extern void ioapic_set_alloc_attr (struct irq_alloc_info *info,int node,int trigger,int polarity);extern int mp_set_gsi_attr (u32 gsi,int trigger,int polarity,int node);
arch/x86/kernel/apic/io_apic.c +156 -3
196 lines not on this page · raw message
Signature · 1 line
1.7.10.4
PATCH v7 35/38 x86/irq: Refine the way to allocate irq_cfg for legacy IRQs
In reply to Jiang LiuTo support legacy ISA IRQs, we need to preallocate irq_cfg structures for legacy ISA IRQs. Refine the way to allocate irq_cfg for legacy ISA IRQs, so it's more friend to hierarchy irqdomain implementation.
--- arch/x86/kernel/apic/io_apic.c | 13 +------------ arch/x86/kernel/apic/vector.c | 42 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 13 deletions(-)
arch/x86/kernel/apic/io_apic.c +1 -12
@@ -254,8 +254,7 @@ static void free_ioapic_saved_registers(int idx)int __init arch_early_ioapic_init (void ) { -struct irq_cfg *cfg; -int i, node =cpu_to_node (0 ); +int i;if (!nr_legacy_irqs ()) io_apic_irqs = ~0UL ;
@@ -263,16 +262,6 @@ int __init arch_early_ioapic_init(void)for_each_ioapic (i)alloc_ioapic_saved_registers (i); -/* -* For legacy IRQ's, start with assigning irq0 to irq15 to -* IRQ0_VECTOR to IRQ15_VECTOR for all cpu's. -*/ -for (i =0 ; i <nr_legacy_irqs (); i++) { - cfg =alloc_irq_and_cfg_at (i, node); - cfg->vector =IRQ0_VECTOR + i; -cpumask_setall (cfg->domain); - } -return 0 ; }
arch/x86/kernel/apic/vector.c +41 -1
68 lines not on this page · raw message
Signature · 1 line
1.7.10.4
PATCH v7 36/38 x86/irq: Simplify the way to print IOAPIC entry
In reply to Jiang LiuSimplify the way to print IOAPIC entry content, so we could kill native_io_apic_print_entries(), intel_ir_io_apic_print_entries() and x86_io_apic_ops.print_entries() later.
Folded a patch from Thomas to fix errors in printed pin attributes,
http://www.spinics.net/lists/linux-tip-commits/msg26108.html
--- arch/x86/kernel/apic/io_apic.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-)
arch/x86/kernel/apic/io_apic.c +28 -2
@@ -1424,6 +1424,33 @@ void ioapic_zap_locks(void)raw_spin_lock_init (&ioapic_lock); } +static void io_apic_print_entries (unsigned int apic,unsigned int nr_entries) +{ +int i; +char buf[256 ]; +struct IO_APIC_route_entry entry; +struct IR_IO_APIC_route_entry *ir_entry = (void *)&entry; + +printk (KERN_DEBUG "IOAPIC %d:\n" , apic); +for (i =0 ; i <= nr_entries; i++) { + entry =ioapic_read_entry (apic, i); +snprintf (buf,sizeof (buf), +" pin%02x, %s, %s, %s, V(%02X), IRR(%1d), S(%1d)" , + i, entry.mask ?"disabled" :"enabled " , + entry.trigger ?"level" :"edge " , + entry.polarity ?"low " :"high" , + entry.vector, entry.irr, entry.delivery_status); +if (ir_entry->format) +printk (KERN_DEBUG "%s, remapped, I(%04X), Z(%X)\n" , + buf, (ir_entry->index <<15 ) | ir_entry->index, + ir_entry->zero); +else +printk (KERN_DEBUG "%s, %s, D(%02X), M(%1d)\n" , + buf, entry.dest_mode ?"logical " :"physical" , + entry.dest, entry.delivery_mode); + } +} +static void __init print_IO_APIC (int ioapic_idx) {union IO_APIC_reg_00 reg_00;
@@ -1477,8 +1504,7 @@ static void __init print_IO_APIC(int ioapic_idx) }printk (KERN_DEBUG ".... IRQ redirection table:\n" ); - - x86_io_apic_ops.print_entries (ioapic_idx, reg_01.bits.entries); +io_apic_print_entries (ioapic_idx, reg_01.bits.entries); }void __init print_IO_APICs (void )
Signature · 1 line
1.7.10.4
PATCH v7 37/38 x86/irq: Introduce helper functions to support hierarchy irqdomain for IOAPIC
In reply to Jiang LiuIntroduce several helper functions, which will be used to enable hierarchy irqdomain for IOAPIC.
--- arch/x86/kernel/apic/io_apic.c | 59 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+)
arch/x86/kernel/apic/io_apic.c +59 -0
@@ -67,6 +67,8 @@#define for_each_irq_pin (entry, head) \ list_for_each_entry(entry, &head, list) +int acpi_get_override_irq (u32 gsi,int *trigger,int *polarity); +/* * Is the SiS APIC rmw bug present ? * -1 = don't know, 0 = no, 1 = yes
@@ -82,6 +84,7 @@ struct mp_chip_data {struct IO_APIC_route_entry entry;int trigger;int polarity; +u32 count;bool isa_irq; };
@@ -945,6 +948,42 @@ void ioapic_set_alloc_attr(struct irq_alloc_info *info, int node, info->ioapic_valid =1 ; } +static void ioapic_copy_alloc_attr (struct irq_alloc_info *dst, +struct irq_alloc_info *src, +u32 gsi,int ioapic_idx,int pin) +{ +int trigger, polarity; + +copy_irq_alloc_info (dst, src); + dst->type =X86_IRQ_ALLOC_TYPE_IOAPIC ; + dst->ioapic_id =mpc_ioapic_id (ioapic_idx); + dst->ioapic_pin = pin; + dst->ioapic_valid =1 ; +if (src && src->ioapic_valid) { + dst->ioapic_node = src->ioapic_node; + dst->ioapic_trigger = src->ioapic_trigger; + dst->ioapic_polarity = src->ioapic_polarity; + }else { + dst->ioapic_node =NUMA_NO_NODE ; +if (acpi_get_override_irq (gsi, &trigger, &polarity) >=0 ) { + dst->ioapic_trigger = trigger; + dst->ioapic_polarity = polarity; + }else { +/* +* PCI interrupts are always polarity one level +* triggered. +*/ + dst->ioapic_trigger =1 ; + dst->ioapic_polarity =1 ; + } + } +} + +static int ioapic_alloc_attr_node (struct irq_alloc_info *info) +{ +return (info && info->ioapic_valid) ? info->ioapic_node :NUMA_NO_NODE ; +} +static void mp_register_handler (unsigned int irq,unsigned long trigger) {irq_flow_handler_t hdl;
@@ -962,6 +1001,26 @@ static void mp_register_handler(unsigned int irq, unsigned long trigger)__irq_set_handler (irq, hdl,0 , fasteoi ?"fasteoi" :"edge" ); } +static bool mp_check_pin_attr (int irq,struct irq_alloc_info *info) +{ +struct mp_chip_data *data =irq_get_chip_data (irq); + +/* +* setup_IO_APIC_irqs() programs all legacy IRQs with default trigger +* and polarity attirbutes. So allow the first user to reprogram the +* pin with real trigger and polarity attributes. +*/ +if (irq <nr_legacy_irqs () && data->count ==1 ) { +if (info->ioapic_trigger != data->trigger) +mp_register_handler (irq, data->trigger); + data->entry.trigger = data->trigger = info->ioapic_trigger; + data->entry.polarity = data->polarity = info->ioapic_polarity; + } + +return data->trigger == info->ioapic_trigger && + data->polarity == info->ioapic_polarity; +} +static int alloc_irq_from_domain (struct irq_domain *domain,u32 gsi,int pin,struct irq_alloc_info *info) {
Signature · 1 line
1.7.10.4
PATCH v7 38/38 x86/irq: Convert IOAPIC to use hierarchy irqdomain interfaces
In reply to Jiang LiuConvert IOAPIC driver to support and use hierarchy irqdomain interfaces. It's a little big, but it always break bisectings if we split it into multiple patches.
Fold in a patch from Andy Shevchenko <[email protected]> to make it bisectable.
http://lkml.org/lkml/2014/12/10/622
--- arch/x86/kernel/acpi/boot.c | 11 +- arch/x86/kernel/apic/io_apic.c | 308 ++++++++++++++------ arch/x86/kernel/devicetree.c | 37 +-- arch/x86/kernel/mpparse.c | 6 +- arch/x86/pci/intel_mid_pci.c | 2 - .../platform/intel-mid/device_libs/platform_wdt.c | 3 +- arch/x86/platform/intel-mid/sfi.c | 5 +- arch/x86/platform/sfi/sfi.c | 5 +- 8 files changed, 240 insertions(+), 137 deletions(-)
arch/x86/kernel/acpi/boot.c +4 -7
@@ -412,11 +412,6 @@ static int mp_register_gsi(struct device *dev, u32 gsi, int trigger, trigger = trigger ==ACPI_EDGE_SENSITIVE ?0 :1 ; polarity = polarity ==ACPI_ACTIVE_HIGH ?0 :1 ; node = dev ?dev_to_node (dev) :NUMA_NO_NODE ; -if (mp_set_gsi_attr (gsi, trigger, polarity, node)) { -pr_warn ("Failed to set pin attr for GSI%d\n" , gsi); -return -1 ; - } -ioapic_set_alloc_attr (&info, node, trigger, polarity); irq =mp_map_gsi_to_irq (gsi,IOAPIC_MAP_ALLOC , &info);if (irq <0 )
@@ -442,8 +437,10 @@ static void mp_unregister_gsi(u32 gsi) }static struct irq_domain_ops acpi_irqdomain_ops = { - .map = mp_irqdomain_map, - .unmap = mp_irqdomain_unmap, + .alloc = mp_irqdomain_alloc, + .free = mp_irqdomain_free, + .activate = mp_irqdomain_activate, + .deactivate = mp_irqdomain_deactivate, }; static int __init
arch/x86/kernel/apic/io_apic.c +211 -97
496 lines not on this page · raw message
arch/x86/kernel/devicetree.c +15 -22
@@ -196,38 +196,31 @@ static struct of_ioapic_type of_ioapic_type[] = }, }; -static int ioapic_xlate (struct irq_domain *domain, -struct device_node *controller, -const u32 *intspec,u32 intsize, -irq_hw_number_t *out_hwirq,u32 *out_type) +static int dt_irqdomain_alloc (struct irq_domain *domain,unsigned int virq, +unsigned int nr_irqs,void *arg) { +struct of_phandle_args *irq_data = (void *)arg;struct of_ioapic_type *it; -u32 line, idx, gsi; +struct irq_alloc_info tmp; -if (WARN_ON (intsize <2 )) +if (WARN_ON (irq_data->args_count <2 ))return -EINVAL ; - - line = intspec[0 ]; - -if (intspec[1 ] >=ARRAY_SIZE (of_ioapic_type)) +if (irq_data->args[1 ] >=ARRAY_SIZE (of_ioapic_type))return -EINVAL ; - it = &of_ioapic_type[intspec[1 ]]; + it = &of_ioapic_type[irq_data->args[1 ]]; +ioapic_set_alloc_attr (&tmp,NUMA_NO_NODE , it->trigger, it->polarity); + tmp.ioapic_id =mpc_ioapic_id (mp_irqdomain_ioapic_idx (domain)); + tmp.ioapic_pin = irq_data->args[0 ]; - idx = (u32 )(long )domain->host_data; - gsi =mp_pin_to_gsi (idx, line); -if (mp_set_gsi_attr (gsi, it->trigger, it->polarity,cpu_to_node (0 ))) -return -EBUSY ; - - *out_hwirq = line; - *out_type = it->out_type; -return 0 ; +return mp_irqdomain_alloc (domain, virq, nr_irqs, &tmp); }const struct irq_domain_ops ioapic_irq_domain_ops = { - .map = mp_irqdomain_map, - .unmap = mp_irqdomain_unmap, - .xlate = ioapic_xlate, + .alloc = dt_irqdomain_alloc, + .free = mp_irqdomain_free, + .activate = mp_irqdomain_activate, + .deactivate = mp_irqdomain_deactivate, };static void __init dtb_add_ioapic (struct device_node *dn)
arch/x86/kernel/mpparse.c +4 -2
@@ -114,8 +114,10 @@ static void __init MP_bus_info(struct mpc_bus *m) }static struct irq_domain_ops mp_ioapic_irqdomain_ops = { - .map = mp_irqdomain_map, - .unmap = mp_irqdomain_unmap, + .alloc = mp_irqdomain_alloc, + .free = mp_irqdomain_free, + .activate = mp_irqdomain_activate, + .deactivate = mp_irqdomain_deactivate, };static void __init MP_ioapic_info (struct mpc_ioapic *m)
arch/x86/pci/intel_mid_pci.c +0 -2
@@ -224,8 +224,6 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev)* MRST only have IOAPIC, the PCI irq lines are 1:1 mapped to * IOAPIC RTE entries, so we just enable RTE for the device. */ -if (mp_set_gsi_attr (dev->irq,1 , polarity,dev_to_node (&dev->dev))) -return -EBUSY ;if (mp_map_gsi_to_irq (dev->irq,IOAPIC_MAP_ALLOC , &info) <0 )return -EBUSY ;
arch/x86/platform/intel-mid/device_libs/platform_wdt.c +1 -2
@@ -36,8 +36,7 @@ static int tangier_probe(struct platform_device *pdev)/* IOAPIC builds identity mapping between GSI and IRQ on MID */ gsi = pdata->irq;ioapic_set_alloc_attr (&info,cpu_to_node (0 ),1 ,0 ); -if (mp_set_gsi_attr (gsi,1 ,0 ,cpu_to_node (0 )) || -mp_map_gsi_to_irq (gsi,IOAPIC_MAP_ALLOC , &info) <=0 ) { +if (mp_map_gsi_to_irq (gsi,IOAPIC_MAP_ALLOC , &info) <=0 ) {dev_warn (&pdev->dev,"cannot find interrupt %d in ioapic\n" , gsi);return -EINVAL ;
arch/x86/platform/intel-mid/sfi.c +1 -4
@@ -469,10 +469,7 @@ static int __init sfi_parse_devs(struct sfi_table_header *table) }ioapic_set_alloc_attr (&info,NUMA_NO_NODE ,1 , polarity); - ret =mp_set_gsi_attr (irq,1 , polarity,NUMA_NO_NODE ); -if (ret ==0 ) - ret =mp_map_gsi_to_irq (irq,IOAPIC_MAP_ALLOC , - &info); + ret =mp_map_gsi_to_irq (irq,IOAPIC_MAP_ALLOC , &info);WARN_ON (ret <0 ); }
arch/x86/platform/sfi/sfi.c +4 -1
@@ -72,7 +72,10 @@ static int __init sfi_parse_cpus(struct sfi_table_header *table)#ifdef CONFIG_X86_IO_APIC static struct irq_domain_ops sfi_ioapic_irqdomain_ops = { - .map = mp_irqdomain_map, + .alloc = mp_irqdomain_alloc, + .free = mp_irqdomain_free, + .activate = mp_irqdomain_activate, + .deactivate = mp_irqdomain_deactivate, };static int __init sfi_parse_ioapic (struct sfi_table_header *table)
Signature · 1 line
1.7.10.4
Ping:)
Quoted 114 lines · Jiang Liu
Hi all,
The generic hierarchy irqdomain and stacked irqchip implementation
has been merged into v3.19, so this patch set converts x86 interupt management to hierarchy irqdomain and stacked irqchip. I will send out another following-on patch set to clean up code and interfaces obseleted by this patch set.This patch set has been reviewed several times and it missed v3.19
merging because several got fixed just before the merging window.
The main changes since last review are:
1) Rebased the patch set onto v3.19-rc5.
2) Merged bugfixes into the patch introducing the bug so it won't break bisecting.Hi Thomas,
Rafael needs more time to review the patch set to refine ACPI
resource paring interface, and we are nearing to v3.19-rc6. So it would be helpful to move onto the x86 hierarchy irqdomain patch set first, so we may catch up with v3.20 merging window.
Thanks!
GerryJiang Liu (36):
x86/irq: Save destination CPU ID inirq_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
irq_remapping: Introduce new interfaces to support hierarchy
irqdomain
irq_remapping/vt-d: Change prototypes to prepare for enabling
hierarchy irqdomain
irq_remapping/vt-d: Enhance Intel IR driver to suppport hierarchy
irqdomain
irq_remapping/amd: Enhance AMD IR driver to suppport hierarchy
irqdomain
x86/hpet: Enhance HPET IRQ to support hierarchy irqdomain x86/MSI: Use hierarchy irqdomain to manage MSI interrupts x86/irq: Directly callnative_compose_msi_msg()for DMAR IRQ irq_remapping/vt-d: Clean up unused MSI related code irq_remapping/amd: Clean up unused MSI related code
irq_remapping: Clean up unused MSI related code
x86/MSI: 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 x86/irq: Normalize x86irq_chipname
x86/MSI: Simplify the way to deal with remapped MSI interrupts x86/MSI: Replacemsi_update_msg()withirq_chip_compose_msi_msg()x86/irq: Implement irq_chip.irq_write_msi_msg for MSI/DMAR/HPET
irq_chips
x86/irq: Simplify MSI/DMAR/HPET implementation by using common code
irq_remapping: Kill unused functionirq_remapping_print_chip()x86/intel-mid, trivial: Refine code syntax forsfi_parse_mtmr()x86/irq: Kill unusedpre_init_apic_IRQ0()
x86/irq: Prepare IOAPIC interfaces to support hierarchy irqdomain x86/irq: Implement callbacks to enable hierarchy irqdomain on IOAPICs x86/irq: Refine the way to allocateirq_cfgfor legacy IRQs x86/irq: Simplify the way to print IOAPIC entry
x86/irq: Introduce helper functions to support hierarchy irqdomain
for IOAPIC
x86/irq: Convert IOAPIC to use hierarchy irqdomain interfacesRickard Strandqvist (1):
x86/apb_timer: Remove unused functionis_apbt_capable()Thomas Gleixner (1):
x86/intel-mid: Delay initialization of APB timerarch/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 | 91 +++ arch/x86/include/asm/io_apic.h | 25 +- arch/x86/include/asm/irq_remapping.h | 45 +- arch/x86/include/asm/msi.h | 7 + arch/x86/include/asm/pci.h | 5 - arch/x86/include/asm/x86_init.h | 4 - arch/x86/kernel/acpi/boot.c | 20 +- arch/x86/kernel/apb_timer.c | 12 - arch/x86/kernel/apic/htirq.c | 173 ++++-- arch/x86/kernel/apic/io_apic.c | 600 +++++++++++++++----- arch/x86/kernel/apic/msi.c | 416 ++++++++------ arch/x86/kernel/apic/vector.c | 205 ++++++- arch/x86/kernel/devicetree.c | 37 +- arch/x86/kernel/hpet.c | 57 +- arch/x86/kernel/mpparse.c | 6 +- arch/x86/kernel/x86_init.c | 2 - arch/x86/pci/intel_mid_pci.c | 6 +- .../platform/intel-mid/device_libs/platform_wdt.c | 5 +- arch/x86/platform/intel-mid/intel-mid.c | 18 +- arch/x86/platform/intel-mid/sfi.c | 30 +- arch/x86/platform/sfi/sfi.c | 5 +- arch/x86/platform/uv/uv_irq.c | 299 ++++------ drivers/iommu/amd_iommu.c | 376 +++++++++--- 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 | 451 ++++++++++----- drivers/iommu/irq_remapping.c | 178 ++---- drivers/iommu/irq_remapping.h | 20 +- drivers/pci/htirq.c | 48 +- include/linux/dmar.h | 3 +- include/linux/htirq.h | 22 +- include/linux/intel-iommu.h | 4 + 38 files changed, 2100 insertions(+), 1159 deletions(-) create mode 100644 arch/x86/include/asm/msi.h