Enable hierarchy irqdomian on x86 platforms
v6 cover Enable hierarchy irqdomian on x86 platforms
We plan to restructure x86 interrupt code based on hierarchy irqdomain, that is to build irqdomains for CPU vector, interrupt remapping unit, IOAPIC, MSI and HPET etc and organize those irqdomains in hierarchy mode. Each irqdomain manages corresponding interrupt controller and talks to parent interrupt controller through public irqdomain interfaces. We also support stacked irq_chip based on hierarchy irqdomain. It will make the x86 interrupt architecture much more clear and more easy to maintain with hierarchy irqdomain and stacked irq_chip.
This is the second patch set to enable support of hierarchy irqdomain on x86 platforms. It's based on tip/x86/apic branch and IOMMU x86/vt-d branch at:
https://git.kernel.org/cgit/linux/kernel/git/joro/iommu.git/ x86/vt-d
You may access it at:
https://github.com/jiangliu/linux.git irqdomain/p2v6
There will aslo be a third patch set to convert IOAPIC driver to support hierarchy irqdomain and clean up code.
We have tested this patchset on Intel 32-bit and 64-bit systems. Joerg has helped to test it on AMD platforms. It also passes Fengguang's 0day tests. Helps are still needed for testings on:
1) AMD HT_IRQ
2) UV platform
3) Intel MID platforms
Patch 1-7 introduce vector domain to manage CPU vectors and convert
PCI MSI/HPET/DMAT etc to use vector domain.
Patch 8-11 introduce new irq_remapping interfaces to support hierarchy
irqdomain.
Patch 12-14, 19-20, 24-27 convert PCI MSI/HPET/DMAR to use new hierarchy
irqdomain framework.
Patch 15-18 clean up old irq_remapping interfaces to support PCI MSI and
HPET interrupts.
Patch 21-22 convert HT_IRQ and UV platform to use new hierarchy irqdomain. Patch 23 normalizes irqchip names on x86 platforms.
V5->V6:
1) Common hierarchy irqdomian code has been moved into tip/irq/irqdomain
2) Rebase onto tip/irq/irqdomain and iommu/x86/vt-d
3) Convert PCI MSI/HPET/DMAR to use the new generic MSI framework
4) Fix bugs and conflicts when merging with IOMMU hotplug code
5) More code cleanupsV4->V5:
1) Refine PCI MSI interfaces to support hierarchy irqdomain
2) Fix a bug with dealing multiple MSI interrupts
3) Improve commit messagesV3->V4:
1) Simplify IRQ remapping interfaces
2) Hide all IRQ remapping logic from MSI/HPET drivers
3) Move most MSI irqdomain code to public drivers/pci/msi.c so it could be resued
4) Improve common PCI MSI code
5) Rebase to tip/x86/apicV2->V3:
1) Fix bugs in handling OF irqdomain
2) Add documentation
3) Rebase to v3.18-rc2V1->V2
1) Add hierarchy iredomain support of DMAR IRQ and UV IRQ.
2) Fix bugs reported by Joe C.
3) Address all review comments from Thomas
4) Fix a bug found during tests
5) Fix errors and warning found by 0day tests
Jiang Liu (27):
x86, irq: Save destination CPU ID in irq_cfg
x86, irq: Use hierarchy irqdomain to manage CPU interrupt vectors x86, hpet: Use new irqdomain interfaces to allocate/free IRQ x86, MSI: Use new irqdomain interfaces to allocate/free IRQ x86, uv: Use new irqdomain interfaces to allocate/free IRQ x86, htirq: Use new irqdomain interfaces to allocate/free IRQ x86, dmar: Use new irqdomain interfaces to allocate/free IRQ
x86: irq_remapping: Introduce new interfaces to support hierarchy
irqdomain
iommu/vt-d: Change prototypes to prepare for enabling hierarchy
irqdomain
iommu/vt-d: Enhance Intel IR driver to suppport hierarchy irqdomain iommu/amd: Enhance AMD IR driver to suppport hierarchy irqdomain x86, hpet: Enhance HPET IRQ to support hierarchy irqdomain x86, PCI, MSI: Use hierarchy irqdomain to manage MSI interrupts x86, irq: Directly call native_compose_msi_msg() for DMAR IRQ iommu/vt-d: Clean up unused MSI related code
iommu/amd: Clean up unused MSI related code
x86: irq_remapping: Clean up unused MSI related code
x86, irq: Clean up unused MSI related code and interfaces iommu/vt-d: Refine the interfaces to create IRQ for DMAR unit x86, irq: Use hierarchy irqdomain to manage DMAR interrupts x86, htirq: Use hierarchy irqdomain to manage Hypertransport
interrupts
x86, uv: Use hierarchy irqdomain to manage UV interrupts x86, irq: Normalize x86 irq_chip name
x86, PCI/MSI: Simplify the way to deal with remapped MSI interrupts PCI/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
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/irq_remapping.h | 47 ++-- 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/apic/htirq.c | 173 +++++++++---- arch/x86/kernel/apic/io_apic.c | 3 - arch/x86/kernel/apic/msi.c | 420 +++++++++++++++++------------- arch/x86/kernel/apic/vector.c | 165 +++++++++++- arch/x86/kernel/hpet.c | 57 ++--- arch/x86/kernel/x86_init.c | 2 - arch/x86/platform/uv/uv_irq.c | 298 ++++++++-------------- drivers/iommu/amd_iommu.c | 378 ++++++++++++++++++++------- drivers/iommu/amd_iommu_init.c | 4 + drivers/iommu/amd_iommu_proto.h | 9 + drivers/iommu/amd_iommu_types.h | 5 + drivers/iommu/dmar.c | 19 +- drivers/iommu/intel_irq_remapping.c | 453 +++++++++++++++++++++++---------- drivers/iommu/irq_remapping.c | 191 ++++---------- 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 + 28 files changed, 1523 insertions(+), 957 deletions(-) create mode 100644 arch/x86/include/asm/msi.h
Signature · 1 line
1.7.10.4
PATCH v6 1/27 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
tip-bot for Jiang Liu
merge bot[tip:x86/apic] x86, irq: Save destination CPU ID in irq_cfg
x86, irq: Save destination CPU ID in irq_cfg
Commit-ID: 489e71db03c76fa74d570133b51abe02b5192450 Gitweb: http://git.kernel.org/tip/489e71db03c76fa74d570133b51abe02b5192450 Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:10 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:23 +0100
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; }
PATCH v6 2/27 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
@@ -456,7 +456,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
@@ -883,11 +882,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
@@ -2353,9 +2353,6 @@ static int mp_irqdomain_create(int ioapic) ioapic_dynirq_base =max (ioapic_dynirq_base, gsi_cfg->gsi_end +1 ); -if (gsi_cfg->gsi_base ==0 ) -irq_set_default_host (ip->irqdomain); -return 0 ; }
arch/x86/kernel/apic/vector.c +143 -13
231 lines not on this page · raw message
Signature · 1 line
1.7.10.4
tip-bot for Jiang Liu
merge bot[tip:x86/apic] x86, irq: Use hierarchy irqdomain to manage CPU interrupt vectors
x86, irq: Use hierarchy irqdomain to manage CPU interrupt vectors
Commit-ID: f40750c0b44c6534a596b9d1c1b96559a01cd540 Gitweb: http://git.kernel.org/tip/f40750c0b44c6534a596b9d1c1b96559a01cd540 Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:11 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:24 +0100
x86, irq: Use hierarchy irqdomain to manage CPU interrupt vectors
Abstract 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
@@ -456,7 +456,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
@@ -883,11 +882,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
@@ -2353,9 +2353,6 @@ static int mp_irqdomain_create(int ioapic) ioapic_dynirq_base =max (ioapic_dynirq_base, gsi_cfg->gsi_end +1 ); -if (gsi_cfg->gsi_base ==0 ) -irq_set_default_host (ip->irqdomain); -return 0 ; }
arch/x86/kernel/apic/vector.c +143 -13
231 lines not on this page · raw message
PATCH v6 3/27 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
tip-bot for Jiang Liu
merge bot[tip:x86/apic] x86, hpet: Use new irqdomain interfaces to allocate/free IRQ
x86, hpet: Use new irqdomain interfaces to allocate/free IRQ
Commit-ID: 654eda5170093e5dc6fe63c044be390b933b172c Gitweb: http://git.kernel.org/tip/654eda5170093e5dc6fe63c044be390b933b172c Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:12 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:24 +0100
x86, hpet: Use new irqdomain interfaces to allocate/free IRQ
Use 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);
tip-bot for Jiang Liu
merge bot[tip:x86/apic] x86/hpet: Use new irqdomain interfaces to allocate /free IRQ
In reply to Jiang Liux86/hpet: Use new irqdomain interfaces to allocate/free IRQ
Commit-ID: bd8eb63f8a3907bb477992145cb6ce0064a1e43f Gitweb: http://git.kernel.org/tip/bd8eb63f8a3907bb477992145cb6ce0064a1e43f Author: Jiang Liu <[email protected]> AuthorDate: Mon, 13 Apr 2015 14:11:25 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Fri, 24 Apr 2015 15:36:48 +0200
x86/hpet: Use new irqdomain interfaces to allocate/free IRQ
Use new irqdomain interfaces to allocate/free IRQ for HPET, so we can remove 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);
PATCH v6 4/27 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
tip-bot for Jiang Liu
merge bot[tip:x86/apic] x86, MSI: Use new irqdomain interfaces to allocate /free IRQ
x86, MSI: Use new irqdomain interfaces to allocate/free IRQ
Commit-ID: 9d022961a12205a64c077d22312fb5832ccd6c72 Gitweb: http://git.kernel.org/tip/9d022961a12205a64c077d22312fb5832ccd6c72 Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:13 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:24 +0100
x86, MSI: Use new irqdomain interfaces to allocate/free IRQ
Use 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
tip-bot for Jiang Liu
merge bot[tip:x86/apic] x86/MSI: Use new irqdomain interfaces to allocate/ free IRQ
In reply to Jiang Liux86/MSI: Use new irqdomain interfaces to allocate/free IRQ
Commit-ID: 4c8f9960ee497020d0858362c81ece984bc89aa5 Gitweb: http://git.kernel.org/tip/4c8f9960ee497020d0858362c81ece984bc89aa5 Author: Jiang Liu <[email protected]> AuthorDate: Mon, 13 Apr 2015 14:11:26 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Fri, 24 Apr 2015 15:36:48 +0200
x86/MSI: Use new irqdomain interfaces to allocate/free IRQ
Use new irqdomain interfaces to allocate/free IRQ for PCI MSI, so we can remove 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
PATCH v6 5/27 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
tip-bot for Jiang Liu
merge bot[tip:x86/apic] x86, uv: Use new irqdomain interfaces to allocate/ free IRQ
x86, uv: Use new irqdomain interfaces to allocate/free IRQ
Commit-ID: d3555fdf8d5724886e9cdaaa11c1c1c978b3832a Gitweb: http://git.kernel.org/tip/d3555fdf8d5724886e9cdaaa11c1c1c978b3832a Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:14 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:24 +0100
x86, uv: Use new irqdomain interfaces to allocate/free IRQ
Use 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);
PATCH v6 6/27 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
tip-bot for Jiang Liu
merge bot[tip:x86/apic] x86, htirq: Use new irqdomain interfaces to allocate/free IRQ
x86, htirq: Use new irqdomain interfaces to allocate/free IRQ
Commit-ID: f30152929529a63ac7935b50116d0183f82b289d Gitweb: http://git.kernel.org/tip/f30152929529a63ac7935b50116d0183f82b289d Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:15 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:24 +0100
x86, htirq: Use new irqdomain interfaces to allocate/free IRQ
Use 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,
PATCH v6 7/27 x86, dmar: Use new irqdomain interfaces to allocate/free IRQ
In reply to Jiang LiuUse new irqdomain interfaces to allocate/free IRQ for DMAR and interrupt remapping, so we could kill GENERIC_IRQ_LEGACY_ALLOC_HWIRQ later.
The private definition of irq_alloc_hwirqs()/irq_free_hwirqs() are temporary solution, it will be removed once we have converted interrupt remapping driver to use irqdomain framework.
--- arch/x86/include/asm/irq_remapping.h | 4 ++-- arch/x86/kernel/apic/msi.c | 10 ++++++++++ drivers/iommu/irq_remapping.c | 17 +++++++++++++++-- 3 files changed, 27 insertions(+), 4 deletions(-)
arch/x86/include/asm/irq_remapping.h +2 -2
@@ -103,7 +103,7 @@ static inline bool setup_remapped_irq(int irq, }#endif /* CONFIG_IRQ_REMAP */ -#define dmar_alloc_hwirq () irq_alloc_hwirq(-1) -#define dmar_free_hwirq irq_free_hwirq +extern int dmar_alloc_hwirq (void ); +extern void dmar_free_hwirq (int irq);#endif /* __X86_IRQ_REMAPPING_H */
arch/x86/kernel/apic/msi.c +10 -0
@@ -223,6 +223,16 @@ int arch_setup_dmar_msi(unsigned int irq) "edge"); return 0; } + +int dmar_alloc_hwirq (void ) +{ +return irq_domain_alloc_irqs (NULL ,1 ,NUMA_NO_NODE ,NULL ); +} + +void dmar_free_hwirq (int irq) +{ +irq_domain_free_irqs (irq,1 ); +}#endif /*
drivers/iommu/irq_remapping.c +15 -2
@@ -6,6 +6,7 @@#include <linux/msi.h> #include <linux/irq.h> #include <linux/pci.h> +#include <linux/irqdomain.h> #include <asm/hw_irq.h> #include <asm/irq_remapping.h>
@@ -50,6 +51,18 @@ static void irq_remapping_disable_io_apic(void)disconnect_bsp_APIC (0 ); } +#ifndef CONFIG_GENERIC_IRQ_LEGACY_ALLOC_HWIRQ +static unsigned int irq_alloc_hwirqs (int cnt,int node) +{ +return irq_domain_alloc_irqs (NULL ,-1 , cnt, node,NULL ); +} + +static void irq_free_hwirqs (unsigned int from,int cnt) +{ +irq_domain_free_irqs (from, cnt); +} +#endif +static int do_setup_msi_irqs (struct pci_dev *dev,int nvec) {int ret, sub_handle, nvec_pow2, index =0 ;
@@ -105,7 +118,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 ;
@@ -128,7 +141,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
tip-bot for Jiang Liu
merge bot[tip:x86/apic] x86, dmar: Use new irqdomain interfaces to allocate/free IRQ
x86, dmar: Use new irqdomain interfaces to allocate/free IRQ
Commit-ID: 7f35ca7e7693ae7eb049a83a116065784d73a2f2 Gitweb: http://git.kernel.org/tip/7f35ca7e7693ae7eb049a83a116065784d73a2f2 Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:16 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:24 +0100
x86, dmar: Use new irqdomain interfaces to allocate/free IRQ
Use new irqdomain interfaces to allocate/free IRQ for DMAR and interrupt remapping, so we could kill GENERIC_IRQ_LEGACY_ALLOC_HWIRQ later.
The private definition of irq_alloc_hwirqs()/irq_free_hwirqs() are temporary solution, it will be removed once we have converted interrupt remapping driver to use irqdomain framework.
--- arch/x86/include/asm/irq_remapping.h | 4 ++-- arch/x86/kernel/apic/msi.c | 10 ++++++++++ drivers/iommu/irq_remapping.c | 17 +++++++++++++++-- 3 files changed, 27 insertions(+), 4 deletions(-)
arch/x86/include/asm/irq_remapping.h +2 -2
@@ -103,7 +103,7 @@ static inline bool setup_remapped_irq(int irq, }#endif /* CONFIG_IRQ_REMAP */ -#define dmar_alloc_hwirq () irq_alloc_hwirq(-1) -#define dmar_free_hwirq irq_free_hwirq +extern int dmar_alloc_hwirq (void ); +extern void dmar_free_hwirq (int irq);#endif /* __X86_IRQ_REMAPPING_H */
arch/x86/kernel/apic/msi.c +10 -0
@@ -223,6 +223,16 @@ int arch_setup_dmar_msi(unsigned int irq) "edge"); return 0; } + +int dmar_alloc_hwirq (void ) +{ +return irq_domain_alloc_irqs (NULL ,1 ,NUMA_NO_NODE ,NULL ); +} + +void dmar_free_hwirq (int irq) +{ +irq_domain_free_irqs (irq,1 ); +}#endif /*
drivers/iommu/irq_remapping.c +15 -2
@@ -6,6 +6,7 @@#include <linux/msi.h> #include <linux/irq.h> #include <linux/pci.h> +#include <linux/irqdomain.h> #include <asm/hw_irq.h> #include <asm/irq_remapping.h>
@@ -50,6 +51,18 @@ static void irq_remapping_disable_io_apic(void)disconnect_bsp_APIC (0 ); } +#ifndef CONFIG_GENERIC_IRQ_LEGACY_ALLOC_HWIRQ +static unsigned int irq_alloc_hwirqs (int cnt,int node) +{ +return irq_domain_alloc_irqs (NULL ,-1 , cnt, node,NULL ); +} + +static void irq_free_hwirqs (unsigned int from,int cnt) +{ +irq_domain_free_irqs (from, cnt); +} +#endif +static int do_setup_msi_irqs (struct pci_dev *dev,int nvec) {int ret, sub_handle, nvec_pow2, index =0 ;
@@ -105,7 +118,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 ;
@@ -128,7 +141,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; }
PATCH v6 8/27 x86: irq_remapping: Introduce new interfaces to support hierarchy irqdomain
In reply to Jiang LiuIntroduce new interfaces for interrupt remapping drivers to support hierarchy irqdomain:
1) irq_remapping_get_ir_irq_domain(): get irqdomain associated with an interrupt remapping unit. IOAPIC/HPET drivers use this interface to get parent interrupt remapping irqdomain.
2) irq_remapping_get_irq_domain(): get irqdomain for an IRQ allocation. This is mainly used to support MSI irqdomain. We must build one MSI irqdomain for each interrupt remapping unit. MSI driver calls this interface to get MSI irqdomain associated with an IR irqdomain which manages the PCI devices.
Architecture specific needs to implement two hooks:
1) arch_get_ir_parent_domain(): get parent irqdomain for IR irqdomain, which is x86_vector_domain on x86 platforms.
2) arch_create_msi_irq_domain(): create an MSI irqdomain associated with the interrupt remapping unit.
We also add 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
@@ -58,6 +61,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 setup_irq_remapping_ops (void ) { }
@@ -101,6 +123,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 disable_irq_remap;extern int irq_remap_broken;
@@ -81,11 +83,19 @@ struct irq_remap_ops {/* Setup interrupt remapping for an HPET MSI */ int (*alloc_hpet_msi)(unsigned int ,unsigned int ); + +/* Get the irqdomain associated the IOMMU device */ +struct irq_domain *(*get_ir_irq_domain)(struct irq_alloc_info *); + +/* Get the MSI irqdomain associated with the IOMMU device */ + struct irq_domain *(*get_irq_domain)(struct irq_alloc_info *); };extern struct irq_remap_ops intel_irq_remap_ops;extern struct irq_remap_ops amd_iommu_irq_ops; +extern void ir_ack_apic_edge (struct irq_data *data); +#else /* CONFIG_IRQ_REMAP */ #define irq_remapping_enabled 0
Signature · 1 line
1.7.10.4
tip-bot for Jiang Liu
merge bot[tip:x86/apic] x86: irq_remapping: Introduce new interfaces to support hierarchy irqdomain
x86: irq_remapping: Introduce new interfaces to support hierarchy irqdomain
Commit-ID: 924e90f8d1688f7b9b2daf57b0395a1882bb94a8 Gitweb: http://git.kernel.org/tip/924e90f8d1688f7b9b2daf57b0395a1882bb94a8 Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:17 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:24 +0100
x86: irq_remapping: Introduce new interfaces to support hierarchy irqdomain
Introduce new interfaces for interrupt remapping drivers to support hierarchy irqdomain:
1) irq_remapping_get_ir_irq_domain(): get irqdomain associated with an interrupt remapping unit. IOAPIC/HPET drivers use this interface to get parent interrupt remapping irqdomain.
2) irq_remapping_get_irq_domain(): get irqdomain for an IRQ allocation. This is mainly used to support MSI irqdomain. We must build one MSI irqdomain for each interrupt remapping unit. MSI driver calls this interface to get MSI irqdomain associated with an IR irqdomain which manages the PCI devices. 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
@@ -58,6 +61,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 setup_irq_remapping_ops (void ) { }
@@ -101,6 +123,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 disable_irq_remap;extern int irq_remap_broken;
@@ -81,11 +83,19 @@ struct irq_remap_ops {/* Setup interrupt remapping for an HPET MSI */ int (*alloc_hpet_msi)(unsigned int ,unsigned int ); + +/* Get the irqdomain associated the IOMMU device */ +struct irq_domain *(*get_ir_irq_domain)(struct irq_alloc_info *); + +/* Get the MSI irqdomain associated with the IOMMU device */ + struct irq_domain *(*get_irq_domain)(struct irq_alloc_info *); };extern struct irq_remap_ops intel_irq_remap_ops;extern struct irq_remap_ops amd_iommu_irq_ops; +extern void ir_ack_apic_edge (struct irq_data *data); +#else /* CONFIG_IRQ_REMAP */ #define irq_remapping_enabled 0
PATCH v6 9/27 iommu/vt-d: Change prototypes to prepare for enabling hierarchy irqdomain
In reply to Jiang LiuPrepare for support hierarchy irqdomain by changing function prototypes, should be no function changes.
--- drivers/iommu/intel_irq_remapping.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-)
drivers/iommu/intel_irq_remapping.c +11 -11
@@ -81,10 +81,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;
@@ -172,9 +172,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;
@@ -241,7 +241,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);
@@ -979,7 +979,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);
@@ -995,7 +995,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 "
@@ -1082,7 +1082,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
@@ -1118,7 +1118,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;
@@ -1145,7 +1145,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",
@@ -1189,7 +1189,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
tip-bot for Jiang Liu
merge bot[tip:x86/apic] iommu/vt-d: Change prototypes to prepare for enabling hierarchy irqdomain
iommu/vt-d: Change prototypes to prepare for enabling hierarchy irqdomain
Commit-ID: 72110a7279426fd0cc544f8c8a06ec0f4129c788 Gitweb: http://git.kernel.org/tip/72110a7279426fd0cc544f8c8a06ec0f4129c788 Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:18 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:24 +0100
iommu/vt-d: Change prototypes to prepare for enabling hierarchy irqdomain
Prepare 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
@@ -81,10 +81,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;
@@ -172,9 +172,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;
@@ -241,7 +241,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);
@@ -979,7 +979,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);
@@ -995,7 +995,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 "
@@ -1082,7 +1082,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
@@ -1118,7 +1118,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;
@@ -1145,7 +1145,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",
@@ -1189,7 +1189,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 ; }
PATCH v6 10/27 iommu/vt-d: Enhance Intel IR driver to suppport hierarchy irqdomain
In reply to Jiang LiuEnhance Intel interrupt remapping driver to support hierarchy irqdomain, it will simplify the code eventually. It also implements intel_ir_chip to support stacked irq_chip.
--- drivers/iommu/intel_irq_remapping.c | 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) ((x2apic_mode) ? dest : dest << 8)
@@ -49,6 +58,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 );
@@ -262,7 +272,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);
@@ -487,7 +497,6 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu) pages =alloc_pages_node (iommu->node,GFP_ATOMIC | __GFP_ZERO,INTR_REMAP_PAGE_ORDER ); -if (!pages) {pr_err ("IR%d: failed to allocate pages of order %d\n" , iommu->seq_id,INTR_REMAP_PAGE_ORDER );
@@ -501,11 +510,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:
@@ -516,6 +537,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);
@@ -1055,12 +1084,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 ;
@@ -1093,6 +1116,7 @@ intel_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,send_cleanup_vector (cfg);cpumask_copy (data->affinity, mask); +return 0 ; }
@@ -1198,6 +1222,53 @@ static int intel_alloc_hpet_msi(unsigned int irq, unsigned int id)return ret; } +static struct irq_domain *intel_get_ir_irq_domain (struct irq_alloc_info *info) +{ +struct intel_iommu *iommu =NULL ; + +if (!info) +return NULL ; + +switch (info->type) { +case X86_IRQ_ALLOC_TYPE_IOAPIC : + iommu =map_ioapic_to_ir (info->ioapic_id); +break ; +case X86_IRQ_ALLOC_TYPE_HPET : + iommu =map_hpet_to_ir (info->hpet_id); +break ; +case X86_IRQ_ALLOC_TYPE_MSI : +case X86_IRQ_ALLOC_TYPE_MSIX : + iommu =map_dev_to_ir (info->msi_dev); +break ; +default : +BUG_ON (1 ); +break ; + } + +return iommu ? iommu->ir_domain :NULL ; +} + +static struct irq_domain *intel_get_irq_domain (struct irq_alloc_info *info) +{ +struct intel_iommu *iommu; + +if (!info) +return NULL ; + +switch (info->type) { +case X86_IRQ_ALLOC_TYPE_MSI : +case X86_IRQ_ALLOC_TYPE_MSIX : + iommu =map_dev_to_ir (info->msi_dev); +if (iommu) +return iommu->ir_msi_domain; +break ; +default : +break ; + } + +return NULL ; +} +struct irq_remap_ops intel_irq_remap_ops = { .supported = intel_irq_remapping_supported, .prepare = dmar_table_init,
@@ -1212,6 +1283,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
tip-bot for Jiang Liu
merge bot[tip:x86/apic] iommu/vt-d: Enhance Intel IR driver to suppport hierarchy irqdomain
iommu/vt-d: Enhance Intel IR driver to suppport hierarchy irqdomain
Commit-ID: 289472f461d922507f75dd2451770282adb3a99b Gitweb: http://git.kernel.org/tip/289472f461d922507f75dd2451770282adb3a99b Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:19 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:24 +0100
iommu/vt-d: Enhance Intel IR driver to suppport hierarchy irqdomain
Enhance Intel interrupt remapping driver to support hierarchy irqdomain, it will simplify the code eventually. It also implements intel_ir_chip to support stacked irq_chip.
--- 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) ((x2apic_mode) ? dest : dest << 8)
@@ -49,6 +58,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 );
@@ -262,7 +272,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);
@@ -487,7 +497,6 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu) pages =alloc_pages_node (iommu->node,GFP_ATOMIC | __GFP_ZERO,INTR_REMAP_PAGE_ORDER ); -if (!pages) {pr_err ("IR%d: failed to allocate pages of order %d\n" , iommu->seq_id,INTR_REMAP_PAGE_ORDER );
@@ -501,11 +510,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:
@@ -516,6 +537,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);
@@ -1055,12 +1084,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 ;
@@ -1093,6 +1116,7 @@ intel_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,send_cleanup_vector (cfg);cpumask_copy (data->affinity, mask); +return 0 ; }
@@ -1198,6 +1222,53 @@ static int intel_alloc_hpet_msi(unsigned int irq, unsigned int id)return ret; } +static struct irq_domain *intel_get_ir_irq_domain (struct irq_alloc_info *info) +{ +struct intel_iommu *iommu =NULL ; + +if (!info) +return NULL ; + +switch (info->type) { +case X86_IRQ_ALLOC_TYPE_IOAPIC : + iommu =map_ioapic_to_ir (info->ioapic_id); +break ; +case X86_IRQ_ALLOC_TYPE_HPET : + iommu =map_hpet_to_ir (info->hpet_id); +break ; +case X86_IRQ_ALLOC_TYPE_MSI : +case X86_IRQ_ALLOC_TYPE_MSIX : + iommu =map_dev_to_ir (info->msi_dev); +break ; +default : +BUG_ON (1 ); +break ; + } + +return iommu ? iommu->ir_domain :NULL ; +} + +static struct irq_domain *intel_get_irq_domain (struct irq_alloc_info *info) +{ +struct intel_iommu *iommu; + +if (!info) +return NULL ; + +switch (info->type) { +case X86_IRQ_ALLOC_TYPE_MSI : +case X86_IRQ_ALLOC_TYPE_MSIX : + iommu =map_dev_to_ir (info->msi_dev); +if (iommu) +return iommu->ir_msi_domain; +break ; +default : +break ; + } + +return NULL ; +} +struct irq_remap_ops intel_irq_remap_ops = { .supported = intel_irq_remapping_supported, .prepare = dmar_table_init,
@@ -1212,6 +1283,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;
PATCH v6 11/27 iommu/amd: Enhance AMD IR driver to suppport hierarchy irqdomain
In reply to Jiang LiuEnhance AMD interrupt remapping driver to support hierarchy irqdomain, it will simplify the code eventually.
--- drivers/iommu/amd_iommu.c | 329 ++++++++++++++++++++++++++++++++++++++- drivers/iommu/amd_iommu_init.c | 4 + drivers/iommu/amd_iommu_proto.h | 9 ++ drivers/iommu/amd_iommu_types.h | 5 + 4 files changed, 341 insertions(+), 6 deletions(-)
drivers/iommu/amd_iommu.c +323 -6
@@ -33,6 +33,7 @@#include <linux/export.h> #include <linux/irq.h> #include <linux/msi.h> +#include <linux/irqdomain.h> #include <asm/irq_remapping.h> #include <asm/io_apic.h> #include <asm/apic.h>
@@ -3854,6 +3855,16 @@ union irte { } fields; }; +struct amd_ir_data { +struct irq_2_irte irq_2_irte; +union irte irte_entry; +union { +struct msi_msg msi_entry; + }; +}; + +static struct irq_chip amd_ir_chip; +#define DTE_IRQ_PHYS_ADDR_MASK (((1ULL << 45)-1) << 6)#define DTE_IRQ_REMAP_INTCTL (2ULL << 60)#define DTE_IRQ_TABLE_LEN (8ULL << 1)
@@ -3947,7 +3958,8 @@ out_unlock:return table; } -static int alloc_irq_index (struct irq_cfg *cfg,u16 devid,int count) +static int alloc_irq_index (struct irq_cfg *cfg,struct irq_2_irte *irte_info, +u16 devid,int count) {struct irq_remap_table *table;unsigned long flags;
@@ -3969,15 +3981,12 @@ static int alloc_irq_index(struct irq_cfg *cfg, u16 devid, int count) c =0 ;if (c == count) { -struct irq_2_irte *irte_info; -for (; c !=0 ; --c) table->table[index - c +1 ] =IRTE_ALLOCATED ; index -= count -1 ; cfg->remapped =1 ; - irte_info = &cfg->irq_2_irte; irte_info->devid = devid; irte_info->index = index;
@@ -4222,7 +4231,7 @@ static int msi_alloc_irq(struct pci_dev *pdev, int irq, int nvec)return -EINVAL ; devid =get_device_id (&pdev->dev); - index =alloc_irq_index (cfg, devid, nvec); + index =alloc_irq_index (cfg, &cfg->irq_2_irte, devid, nvec);return index <0 ?MAX_IRQS_PER_TABLE : index; }
@@ -4269,7 +4278,7 @@ static int alloc_hpet_msi(unsigned int irq, unsigned int id)if (devid <0 )return devid; - index =alloc_irq_index (cfg, devid,1 ); + index =alloc_irq_index (cfg, &cfg->irq_2_irte, devid,1 );if (index <0 )return index;
@@ -4280,6 +4289,72 @@ static int alloc_hpet_msi(unsigned int irq, unsigned int id)return 0 ; } +static int get_devid (struct irq_alloc_info *info) +{ +int devid =-1 ; + +switch (info->type) { +case X86_IRQ_ALLOC_TYPE_IOAPIC : + devid =get_ioapic_devid (info->ioapic_id); +break ; +case X86_IRQ_ALLOC_TYPE_HPET : + devid =get_hpet_devid (info->hpet_id); +break ; +case X86_IRQ_ALLOC_TYPE_MSI : +case X86_IRQ_ALLOC_TYPE_MSIX : + devid =get_device_id (&info->msi_dev->dev); +break ; +default : +BUG_ON (1 ); +break ; + } + +return devid; +} + +static struct irq_domain *get_ir_irq_domain (struct irq_alloc_info *info) +{ +int devid; +struct amd_iommu *iommu; + +if (!info) +return NULL ; + + devid =get_devid (info); +if (devid >=0 ) { + iommu = amd_iommu_rlookup_table[devid]; +if (iommu) +return iommu->ir_domain; + } + +return NULL ; +} + +static struct irq_domain *get_irq_domain (struct irq_alloc_info *info) +{ +int devid; +struct amd_iommu *iommu; + +if (!info) +return NULL ; + +switch (info->type) { +case X86_IRQ_ALLOC_TYPE_MSI : +case X86_IRQ_ALLOC_TYPE_MSIX : + devid =get_device_id (&info->msi_dev->dev); +if (devid >=0 ) { + iommu = amd_iommu_rlookup_table[devid]; +if (iommu) +return iommu->msi_domain; + } +break ; +default : +break ; + } + +return NULL ; +} +struct irq_remap_ops amd_iommu_irq_ops = { .supported = amd_iommu_supported, .prepare = amd_iommu_prepare,
@@ -4294,5 +4369,247 @@ struct irq_remap_ops amd_iommu_irq_ops = { .msi_alloc_irq = msi_alloc_irq, .msi_setup_irq = msi_setup_irq, .alloc_hpet_msi = alloc_hpet_msi, + .get_ir_irq_domain = get_ir_irq_domain, + .get_irq_domain = get_irq_domain, +}; + +static void irq_remapping_prepare_irte (struct amd_ir_data *data, +struct irq_cfg *irq_cfg, +struct irq_alloc_info *info, +int devid,int index,int sub_handle) +{ +union irte *irte = &data->irte_entry; +struct irq_2_irte *irte_info = &data->irq_2_irte; +struct msi_msg *msg = &data->msi_entry; +struct IO_APIC_route_entry *entry; + + irq_cfg->remapped =1 ; + data->irq_2_irte.devid = devid; + data->irq_2_irte.index = index + sub_handle; + +/* Setup IRTE for IOMMU */ + irte->val =0 ; + irte->fields.vector = irq_cfg->vector; + irte->fields.int_type = apic->irq_delivery_mode; + irte->fields.destination = irq_cfg->dest_apicid; + irte->fields.dm = apic->irq_dest_mode; + irte->fields.valid =1 ; + +switch (info->type) { +case X86_IRQ_ALLOC_TYPE_IOAPIC : +/* Setup IOAPIC entry */ + entry = info->ioapic_entry; + info->ioapic_entry =NULL ; +memset (entry,0 ,sizeof (*entry)); + entry->vector = index; + entry->mask =0 ; + entry->trigger = info->ioapic_trigger; + entry->polarity = info->ioapic_polarity; +/* Mask level triggered irqs. */ +if (info->ioapic_trigger) + entry->mask =1 ; +break ; + +case X86_IRQ_ALLOC_TYPE_HPET : +case X86_IRQ_ALLOC_TYPE_MSI : +case X86_IRQ_ALLOC_TYPE_MSIX : + msg->address_hi =MSI_ADDR_BASE_HI ; + msg->address_lo =MSI_ADDR_BASE_LO ; + msg->data = irte_info->index; +break ; + +default : +BUG_ON (1 ); +break ; + } +} + +static int irq_remapping_alloc (struct irq_domain *domain,unsigned int virq, +unsigned int nr_irqs,void *arg) +{ +struct irq_alloc_info *info = arg; +struct amd_ir_data *data; +struct irq_data *irq_data; +struct irq_cfg *cfg; +int i, ret, devid; +int index =-1 ; + +if (!info) +return -EINVAL ; +if (nr_irqs >1 && info->type !=X86_IRQ_ALLOC_TYPE_MSI && + info->type !=X86_IRQ_ALLOC_TYPE_MSIX ) +return -EINVAL ; + +/* +* With IRQ remapping enabled, don't need contigious CPU vectors +* to support multiple MSI interrupts. +*/ +if (info->type ==X86_IRQ_ALLOC_TYPE_MSI ) + info->flags &= ~X86_IRQ_ALLOC_CONTIGOUS_VECTORS ; + + devid =get_devid (info); +if (devid <0 ) +return -EINVAL ; + + ret =irq_domain_alloc_irqs_parent (domain, virq, nr_irqs, arg); +if (ret <0 ) +return ret; + + ret = -ENOMEM ; + data =kzalloc (sizeof (*data),GFP_KERNEL ); +if (!data) + goto out_free_parent; + +if (info->type ==X86_IRQ_ALLOC_TYPE_IOAPIC ) { +if (get_irq_table (devid, true)) + index = info->ioapic_pin; +else + ret = -ENOMEM ; + }else { + cfg =irq_cfg (virq); + index =alloc_irq_index (cfg, &data->irq_2_irte, devid, nr_irqs); + } +if (index <0 ) { +pr_warn ("Failed to allocate IRTE\n" ); +kfree (data); + goto out_free_parent; + } + +for (i =0 ; i < nr_irqs; i++) { + irq_data =irq_domain_get_irq_data (domain, virq + i); + cfg =irqd_cfg (irq_data); +if (!irq_data || !cfg) { + ret = -EINVAL ; + goto out_free_data; + } + +if (i >0 ) { + data =kzalloc (sizeof (*data),GFP_KERNEL ); +if (!data) + goto out_free_data; + } + irq_data->hwirq = (devid <<16 ) + i; + irq_data->chip_data = data; + irq_data->chip = &amd_ir_chip; +irq_remapping_prepare_irte (data, cfg, info, devid, index, i); +irq_set_status_flags (virq + i,IRQ_MOVE_PCNTXT ); + } +return 0 ; + +out_free_data: +for (i--; i >=0 ; i--) { + irq_data =irq_domain_get_irq_data (domain, virq + i); +if (irq_data) +kfree (irq_data->chip_data); + } +for (i =0 ; i < nr_irqs; i++) +free_irte (devid, index + i); +out_free_parent: +irq_domain_free_irqs_common (domain, virq, nr_irqs); +return ret; +} + +static void irq_remapping_free (struct irq_domain *domain,unsigned int virq, +unsigned int nr_irqs) +{ +struct irq_data *irq_data; +struct amd_ir_data *data; +struct irq_2_irte *irte_info; +int i; + +for (i =0 ; i < nr_irqs; i++) { + irq_data =irq_domain_get_irq_data (domain, virq + i); +if (irq_data && irq_data->chip_data) { + data = irq_data->chip_data; + irte_info = &data->irq_2_irte; +free_irte (irte_info->devid, irte_info->index); +kfree (data); + } + } +irq_domain_free_irqs_common (domain, virq, nr_irqs); +} + +static void irq_remapping_activate (struct irq_domain *domain, +struct irq_data *irq_data) +{ +struct amd_ir_data *data = irq_data->chip_data; +struct irq_2_irte *irte_info = &data->irq_2_irte; + +modify_irte (irte_info->devid, irte_info->index, data->irte_entry); +} + +static void irq_remapping_deactivate (struct irq_domain *domain, +struct irq_data *irq_data) +{ +struct amd_ir_data *data = irq_data->chip_data; +struct irq_2_irte *irte_info = &data->irq_2_irte; +union irte entry; + + entry.val =0 ; +modify_irte (irte_info->devid, irte_info->index, data->irte_entry); +} + +static struct irq_domain_ops amd_ir_domain_ops = { + .alloc = irq_remapping_alloc, + .free = irq_remapping_free, + .activate = irq_remapping_activate, + .deactivate = irq_remapping_deactivate, }; + +static int amd_ir_set_affinity (struct irq_data *data, +const struct cpumask *mask,bool force) +{ +struct amd_ir_data *ir_data = data->chip_data; +struct irq_2_irte *irte_info = &ir_data->irq_2_irte; +struct irq_cfg *cfg =irqd_cfg (data); +struct irq_data *parent = data->parent_data; +int ret; + + ret = parent->chip->irq_set_affinity (parent, mask, force); +if (ret <0 || ret ==IRQ_SET_MASK_OK_DONE ) +return ret; + +/* +* Atomically updates the IRTE with the new destination, vector +* and flushes the interrupt entry cache. +*/ + ir_data->irte_entry.fields.vector = cfg->vector; + ir_data->irte_entry.fields.destination = cfg->dest_apicid; +modify_irte (irte_info->devid, irte_info->index, ir_data->irte_entry); + +/* +* After this point, all the interrupts will start arriving +* at the new destination. So, time to cleanup the previous +* vector allocation. +*/ +if (cfg->move_in_progress) +send_cleanup_vector (cfg); + +return IRQ_SET_MASK_OK_DONE ; +} + +static void ir_compose_msi_msg (struct irq_data *irq_data,struct msi_msg *msg) +{ +struct amd_ir_data *ir_data = irq_data->chip_data; + + *msg = ir_data->msi_entry; +} + +static struct irq_chip amd_ir_chip = { + .irq_ack = ir_ack_apic_edge, + .irq_set_affinity = amd_ir_set_affinity, + .irq_compose_msi_msg = ir_compose_msi_msg, +}; + +int amd_iommu_create_irq_domain (struct amd_iommu *iommu) +{ + iommu->ir_domain =irq_domain_add_tree (NULL , &amd_ir_domain_ops, iommu); +if (!iommu->ir_domain) +return -ENOMEM ; + + iommu->ir_domain->parent =arch_get_ir_parent_domain (); + iommu->msi_domain =arch_create_msi_irq_domain (iommu->ir_domain); + +return 0 ; +}#endif
drivers/iommu/amd_iommu_init.c +4 -0
@@ -1124,6 +1124,10 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)if (ret)return ret; + ret =amd_iommu_create_irq_domain (iommu); +if (ret) +return ret; +/* * Make sure IOMMU is not considered to translate itself. The IVRS * table tells us so, but this is a lie!
drivers/iommu/amd_iommu_proto.h +9 -0
@@ -63,6 +63,15 @@ extern u8 amd_iommu_pc_get_max_counters(u16 devid);extern int amd_iommu_pc_get_set_reg_val (u16 devid,u8 bank,u8 cntr,u8 fxn,u64 *value,bool is_write); +#ifdef CONFIG_IRQ_REMAP +extern int amd_iommu_create_irq_domain (struct amd_iommu *iommu); +#else +static inline int amd_iommu_create_irq_domain (struct amd_iommu *iommu) +{ +return 0 ; +} +#endif +#define PPR_SUCCESS 0x0#define PPR_INVALID 0x1#define PPR_FAILURE 0xf
drivers/iommu/amd_iommu_types.h +5 -0
@@ -392,6 +392,7 @@ struct amd_iommu_fault {struct iommu_domain ; +struct irq_domain ;/* * This structure contains generic data for IOMMU protection domains
@@ -574,6 +575,10 @@ struct amd_iommu {/* The maximum PC banks and counters/bank (PCSup=1) */ u8 max_banks;u8 max_counters; +#ifdef CONFIG_IRQ_REMAP +struct irq_domain *ir_domain; +struct irq_domain *msi_domain; +#endif };struct devid_map {
Signature · 1 line
1.7.10.4
tip-bot for Jiang Liu
merge bot[tip:x86/apic] iommu/amd: Enhance AMD IR driver to suppport hierarchy irqdomain
iommu/amd: Enhance AMD IR driver to suppport hierarchy irqdomain
Commit-ID: ecf87b38d902dd0369e8c7039749183dfc309707 Gitweb: http://git.kernel.org/tip/ecf87b38d902dd0369e8c7039749183dfc309707 Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:20 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:24 +0100
iommu/amd: Enhance AMD IR driver to suppport hierarchy irqdomain
Enhance AMD interrupt remapping driver to support hierarchy irqdomain, it will simplify the code eventually.
--- drivers/iommu/amd_iommu.c | 329 +++++++++++++++++++++++++++++++++++++++- drivers/iommu/amd_iommu_init.c | 4 + drivers/iommu/amd_iommu_proto.h | 9 ++ drivers/iommu/amd_iommu_types.h | 5 + 4 files changed, 341 insertions(+), 6 deletions(-)
drivers/iommu/amd_iommu.c +323 -6
@@ -33,6 +33,7 @@#include <linux/export.h> #include <linux/irq.h> #include <linux/msi.h> +#include <linux/irqdomain.h> #include <asm/irq_remapping.h> #include <asm/io_apic.h> #include <asm/apic.h>
@@ -3854,6 +3855,16 @@ union irte { } fields; }; +struct amd_ir_data { +struct irq_2_irte irq_2_irte; +union irte irte_entry; +union { +struct msi_msg msi_entry; + }; +}; + +static struct irq_chip amd_ir_chip; +#define DTE_IRQ_PHYS_ADDR_MASK (((1ULL << 45)-1) << 6)#define DTE_IRQ_REMAP_INTCTL (2ULL << 60)#define DTE_IRQ_TABLE_LEN (8ULL << 1)
@@ -3947,7 +3958,8 @@ out_unlock:return table; } -static int alloc_irq_index (struct irq_cfg *cfg,u16 devid,int count) +static int alloc_irq_index (struct irq_cfg *cfg,struct irq_2_irte *irte_info, +u16 devid,int count) {struct irq_remap_table *table;unsigned long flags;
@@ -3969,15 +3981,12 @@ static int alloc_irq_index(struct irq_cfg *cfg, u16 devid, int count) c =0 ;if (c == count) { -struct irq_2_irte *irte_info; -for (; c !=0 ; --c) table->table[index - c +1 ] =IRTE_ALLOCATED ; index -= count -1 ; cfg->remapped =1 ; - irte_info = &cfg->irq_2_irte; irte_info->devid = devid; irte_info->index = index;
@@ -4222,7 +4231,7 @@ static int msi_alloc_irq(struct pci_dev *pdev, int irq, int nvec)return -EINVAL ; devid =get_device_id (&pdev->dev); - index =alloc_irq_index (cfg, devid, nvec); + index =alloc_irq_index (cfg, &cfg->irq_2_irte, devid, nvec);return index <0 ?MAX_IRQS_PER_TABLE : index; }
@@ -4269,7 +4278,7 @@ static int alloc_hpet_msi(unsigned int irq, unsigned int id)if (devid <0 )return devid; - index =alloc_irq_index (cfg, devid,1 ); + index =alloc_irq_index (cfg, &cfg->irq_2_irte, devid,1 );if (index <0 )return index;
@@ -4280,6 +4289,72 @@ static int alloc_hpet_msi(unsigned int irq, unsigned int id)return 0 ; } +static int get_devid (struct irq_alloc_info *info) +{ +int devid =-1 ; + +switch (info->type) { +case X86_IRQ_ALLOC_TYPE_IOAPIC : + devid =get_ioapic_devid (info->ioapic_id); +break ; +case X86_IRQ_ALLOC_TYPE_HPET : + devid =get_hpet_devid (info->hpet_id); +break ; +case X86_IRQ_ALLOC_TYPE_MSI : +case X86_IRQ_ALLOC_TYPE_MSIX : + devid =get_device_id (&info->msi_dev->dev); +break ; +default : +BUG_ON (1 ); +break ; + } + +return devid; +} + +static struct irq_domain *get_ir_irq_domain (struct irq_alloc_info *info) +{ +int devid; +struct amd_iommu *iommu; + +if (!info) +return NULL ; + + devid =get_devid (info); +if (devid >=0 ) { + iommu = amd_iommu_rlookup_table[devid]; +if (iommu) +return iommu->ir_domain; + } + +return NULL ; +} + +static struct irq_domain *get_irq_domain (struct irq_alloc_info *info) +{ +int devid; +struct amd_iommu *iommu; + +if (!info) +return NULL ; + +switch (info->type) { +case X86_IRQ_ALLOC_TYPE_MSI : +case X86_IRQ_ALLOC_TYPE_MSIX : + devid =get_device_id (&info->msi_dev->dev); +if (devid >=0 ) { + iommu = amd_iommu_rlookup_table[devid]; +if (iommu) +return iommu->msi_domain; + } +break ; +default : +break ; + } + +return NULL ; +} +struct irq_remap_ops amd_iommu_irq_ops = { .supported = amd_iommu_supported, .prepare = amd_iommu_prepare,
@@ -4294,5 +4369,247 @@ struct irq_remap_ops amd_iommu_irq_ops = { .msi_alloc_irq = msi_alloc_irq, .msi_setup_irq = msi_setup_irq, .alloc_hpet_msi = alloc_hpet_msi, + .get_ir_irq_domain = get_ir_irq_domain, + .get_irq_domain = get_irq_domain, +}; + +static void irq_remapping_prepare_irte (struct amd_ir_data *data, +struct irq_cfg *irq_cfg, +struct irq_alloc_info *info, +int devid,int index,int sub_handle) +{ +union irte *irte = &data->irte_entry; +struct irq_2_irte *irte_info = &data->irq_2_irte; +struct msi_msg *msg = &data->msi_entry; +struct IO_APIC_route_entry *entry; + + irq_cfg->remapped =1 ; + data->irq_2_irte.devid = devid; + data->irq_2_irte.index = index + sub_handle; + +/* Setup IRTE for IOMMU */ + irte->val =0 ; + irte->fields.vector = irq_cfg->vector; + irte->fields.int_type = apic->irq_delivery_mode; + irte->fields.destination = irq_cfg->dest_apicid; + irte->fields.dm = apic->irq_dest_mode; + irte->fields.valid =1 ; + +switch (info->type) { +case X86_IRQ_ALLOC_TYPE_IOAPIC : +/* Setup IOAPIC entry */ + entry = info->ioapic_entry; + info->ioapic_entry =NULL ; +memset (entry,0 ,sizeof (*entry)); + entry->vector = index; + entry->mask =0 ; + entry->trigger = info->ioapic_trigger; + entry->polarity = info->ioapic_polarity; +/* Mask level triggered irqs. */ +if (info->ioapic_trigger) + entry->mask =1 ; +break ; + +case X86_IRQ_ALLOC_TYPE_HPET : +case X86_IRQ_ALLOC_TYPE_MSI : +case X86_IRQ_ALLOC_TYPE_MSIX : + msg->address_hi =MSI_ADDR_BASE_HI ; + msg->address_lo =MSI_ADDR_BASE_LO ; + msg->data = irte_info->index; +break ; + +default : +BUG_ON (1 ); +break ; + } +} + +static int irq_remapping_alloc (struct irq_domain *domain,unsigned int virq, +unsigned int nr_irqs,void *arg) +{ +struct irq_alloc_info *info = arg; +struct amd_ir_data *data; +struct irq_data *irq_data; +struct irq_cfg *cfg; +int i, ret, devid; +int index =-1 ; + +if (!info) +return -EINVAL ; +if (nr_irqs >1 && info->type !=X86_IRQ_ALLOC_TYPE_MSI && + info->type !=X86_IRQ_ALLOC_TYPE_MSIX ) +return -EINVAL ; + +/* +* With IRQ remapping enabled, don't need contigious CPU vectors +* to support multiple MSI interrupts. +*/ +if (info->type ==X86_IRQ_ALLOC_TYPE_MSI ) + info->flags &= ~X86_IRQ_ALLOC_CONTIGOUS_VECTORS ; + + devid =get_devid (info); +if (devid <0 ) +return -EINVAL ; + + ret =irq_domain_alloc_irqs_parent (domain, virq, nr_irqs, arg); +if (ret <0 ) +return ret; + + ret = -ENOMEM ; + data =kzalloc (sizeof (*data),GFP_KERNEL ); +if (!data) + goto out_free_parent; + +if (info->type ==X86_IRQ_ALLOC_TYPE_IOAPIC ) { +if (get_irq_table (devid, true)) + index = info->ioapic_pin; +else + ret = -ENOMEM ; + }else { + cfg =irq_cfg (virq); + index =alloc_irq_index (cfg, &data->irq_2_irte, devid, nr_irqs); + } +if (index <0 ) { +pr_warn ("Failed to allocate IRTE\n" ); +kfree (data); + goto out_free_parent; + } + +for (i =0 ; i < nr_irqs; i++) { + irq_data =irq_domain_get_irq_data (domain, virq + i); + cfg =irqd_cfg (irq_data); +if (!irq_data || !cfg) { + ret = -EINVAL ; + goto out_free_data; + } + +if (i >0 ) { + data =kzalloc (sizeof (*data),GFP_KERNEL ); +if (!data) + goto out_free_data; + } + irq_data->hwirq = (devid <<16 ) + i; + irq_data->chip_data = data; + irq_data->chip = &amd_ir_chip; +irq_remapping_prepare_irte (data, cfg, info, devid, index, i); +irq_set_status_flags (virq + i,IRQ_MOVE_PCNTXT ); + } +return 0 ; + +out_free_data: +for (i--; i >=0 ; i--) { + irq_data =irq_domain_get_irq_data (domain, virq + i); +if (irq_data) +kfree (irq_data->chip_data); + } +for (i =0 ; i < nr_irqs; i++) +free_irte (devid, index + i); +out_free_parent: +irq_domain_free_irqs_common (domain, virq, nr_irqs); +return ret; +} + +static void irq_remapping_free (struct irq_domain *domain,unsigned int virq, +unsigned int nr_irqs) +{ +struct irq_data *irq_data; +struct amd_ir_data *data; +struct irq_2_irte *irte_info; +int i; + +for (i =0 ; i < nr_irqs; i++) { + irq_data =irq_domain_get_irq_data (domain, virq + i); +if (irq_data && irq_data->chip_data) { + data = irq_data->chip_data; + irte_info = &data->irq_2_irte; +free_irte (irte_info->devid, irte_info->index); +kfree (data); + } + } +irq_domain_free_irqs_common (domain, virq, nr_irqs); +} + +static void irq_remapping_activate (struct irq_domain *domain, +struct irq_data *irq_data) +{ +struct amd_ir_data *data = irq_data->chip_data; +struct irq_2_irte *irte_info = &data->irq_2_irte; + +modify_irte (irte_info->devid, irte_info->index, data->irte_entry); +} + +static void irq_remapping_deactivate (struct irq_domain *domain, +struct irq_data *irq_data) +{ +struct amd_ir_data *data = irq_data->chip_data; +struct irq_2_irte *irte_info = &data->irq_2_irte; +union irte entry; + + entry.val =0 ; +modify_irte (irte_info->devid, irte_info->index, data->irte_entry); +} + +static struct irq_domain_ops amd_ir_domain_ops = { + .alloc = irq_remapping_alloc, + .free = irq_remapping_free, + .activate = irq_remapping_activate, + .deactivate = irq_remapping_deactivate, }; + +static int amd_ir_set_affinity (struct irq_data *data, +const struct cpumask *mask,bool force) +{ +struct amd_ir_data *ir_data = data->chip_data; +struct irq_2_irte *irte_info = &ir_data->irq_2_irte; +struct irq_cfg *cfg =irqd_cfg (data); +struct irq_data *parent = data->parent_data; +int ret; + + ret = parent->chip->irq_set_affinity (parent, mask, force); +if (ret <0 || ret ==IRQ_SET_MASK_OK_DONE ) +return ret; + +/* +* Atomically updates the IRTE with the new destination, vector +* and flushes the interrupt entry cache. +*/ + ir_data->irte_entry.fields.vector = cfg->vector; + ir_data->irte_entry.fields.destination = cfg->dest_apicid; +modify_irte (irte_info->devid, irte_info->index, ir_data->irte_entry); + +/* +* After this point, all the interrupts will start arriving +* at the new destination. So, time to cleanup the previous +* vector allocation. +*/ +if (cfg->move_in_progress) +send_cleanup_vector (cfg); + +return IRQ_SET_MASK_OK_DONE ; +} + +static void ir_compose_msi_msg (struct irq_data *irq_data,struct msi_msg *msg) +{ +struct amd_ir_data *ir_data = irq_data->chip_data; + + *msg = ir_data->msi_entry; +} + +static struct irq_chip amd_ir_chip = { + .irq_ack = ir_ack_apic_edge, + .irq_set_affinity = amd_ir_set_affinity, + .irq_compose_msi_msg = ir_compose_msi_msg, +}; + +int amd_iommu_create_irq_domain (struct amd_iommu *iommu) +{ + iommu->ir_domain =irq_domain_add_tree (NULL , &amd_ir_domain_ops, iommu); +if (!iommu->ir_domain) +return -ENOMEM ; + + iommu->ir_domain->parent =arch_get_ir_parent_domain (); + iommu->msi_domain =arch_create_msi_irq_domain (iommu->ir_domain); + +return 0 ; +}#endif
drivers/iommu/amd_iommu_init.c +4 -0
@@ -1124,6 +1124,10 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)if (ret)return ret; + ret =amd_iommu_create_irq_domain (iommu); +if (ret) +return ret; +/* * Make sure IOMMU is not considered to translate itself. The IVRS * table tells us so, but this is a lie!
drivers/iommu/amd_iommu_proto.h +9 -0
@@ -63,6 +63,15 @@ extern u8 amd_iommu_pc_get_max_counters(u16 devid);extern int amd_iommu_pc_get_set_reg_val (u16 devid,u8 bank,u8 cntr,u8 fxn,u64 *value,bool is_write); +#ifdef CONFIG_IRQ_REMAP +extern int amd_iommu_create_irq_domain (struct amd_iommu *iommu); +#else +static inline int amd_iommu_create_irq_domain (struct amd_iommu *iommu) +{ +return 0 ; +} +#endif +#define PPR_SUCCESS 0x0#define PPR_INVALID 0x1#define PPR_FAILURE 0xf
drivers/iommu/amd_iommu_types.h +5 -0
@@ -392,6 +392,7 @@ struct amd_iommu_fault {struct iommu_domain ; +struct irq_domain ;/* * This structure contains generic data for IOMMU protection domains
@@ -574,6 +575,10 @@ struct amd_iommu {/* The maximum PC banks and counters/bank (PCSup=1) */ u8 max_banks;u8 max_counters; +#ifdef CONFIG_IRQ_REMAP +struct irq_domain *ir_domain; +struct irq_domain *msi_domain; +#endif };struct devid_map {
PATCH v6 12/27 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
tip-bot for Jiang Liu
merge bot[tip:x86/apic] x86, hpet: Enhance HPET IRQ to support hierarchy irqdomain
x86, hpet: Enhance HPET IRQ to support hierarchy irqdomain
Commit-ID: 33702cbb08c945615af8aaae0be20ac2d3112056 Gitweb: http://git.kernel.org/tip/33702cbb08c945615af8aaae0be20ac2d3112056 Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:21 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:25 +0100
x86, hpet: Enhance HPET IRQ to support hierarchy irqdomain
Enhance 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
PATCH v6 13/27 x86, PCI, MSI: Use hierarchy irqdomain to manage MSI interrupts
In reply to Jiang LiuEnhance MSI code to support hierarchy irqdomain, it helps to make the architecture more clear.
--- arch/x86/Kconfig | 1 + arch/x86/include/asm/hw_irq.h | 9 ++- arch/x86/include/asm/irq_remapping.h | 6 +- arch/x86/include/asm/msi.h | 7 ++ arch/x86/kernel/apic/msi.c | 145 ++++++++++++++++++---------------- arch/x86/kernel/apic/vector.c | 2 + drivers/iommu/irq_remapping.c | 1 - 7 files changed, 96 insertions(+), 75 deletions(-) create mode 100644 arch/x86/include/asm/msi.h
arch/x86/Kconfig +1 -0
@@ -883,6 +883,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
@@ -68,11 +68,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 +77 -68
191 lines not on this page · raw message
arch/x86/kernel/apic/vector.c +2 -0
@@ -364,6 +364,8 @@ int __init arch_early_irq_init(void)BUG_ON (x86_vector_domain ==NULL );irq_set_default_host (x86_vector_domain); +arch_init_msi_domain (x86_vector_domain); +return arch_early_ioapic_init (); }
drivers/iommu/irq_remapping.c +0 -1
@@ -171,7 +171,6 @@ static void __init irq_remapping_modify_x86_ops(void) x86_io_apic_ops.set_affinity = set_remapped_irq_affinity; x86_io_apic_ops.setup_entry = setup_ioapic_remapped_entry; x86_io_apic_ops.eoi_ioapic_pin = eoi_ioapic_pin_remapped; - x86_msi.setup_msi_irqs = irq_remapping_setup_msi_irqs; x86_msi.setup_hpet_msi = setup_hpet_msi_remapped; x86_msi.compose_msi_msg = compose_remapped_msi_msg; }
Signature · 1 line
1.7.10.4
tip-bot for Jiang Liu
merge bot[tip:x86/apic] x86, PCI, MSI: Use hierarchy irqdomain to manage MSI interrupts
x86, PCI, MSI: Use hierarchy irqdomain to manage MSI interrupts
Commit-ID: c07a443c77c4fe7d9f85c18e127020653bb8a45c Gitweb: http://git.kernel.org/tip/c07a443c77c4fe7d9f85c18e127020653bb8a45c Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:22 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:25 +0100
x86, PCI, MSI: Use hierarchy irqdomain to manage MSI interrupts
Enhance 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(-)
arch/x86/Kconfig +1 -0
@@ -883,6 +883,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
@@ -68,11 +68,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
@@ -171,7 +171,6 @@ static void __init irq_remapping_modify_x86_ops(void) x86_io_apic_ops.set_affinity = set_remapped_irq_affinity; x86_io_apic_ops.setup_entry = setup_ioapic_remapped_entry; x86_io_apic_ops.eoi_ioapic_pin = eoi_ioapic_pin_remapped; - x86_msi.setup_msi_irqs = irq_remapping_setup_msi_irqs; x86_msi.setup_hpet_msi = setup_hpet_msi_remapped; x86_msi.compose_msi_msg = compose_remapped_msi_msg; }
PATCH v6 14/27 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
tip-bot for Jiang Liu
merge bot[tip:x86/apic] x86, irq: Directly call native_compose_msi_msg() for DMAR IRQ
x86, irq: Directly call native_compose_msi_msg() for DMAR IRQ
Commit-ID: 786964a35e95596bbade35eab393fd9b01bd2cad Gitweb: http://git.kernel.org/tip/786964a35e95596bbade35eab393fd9b01bd2cad Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:23 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:25 +0100
x86, irq: Directly call native_compose_msi_msg() for DMAR IRQ
DMAR 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" );
PATCH v6 15/27 iommu/vt-d: Clean up unused MSI related code
In reply to Jiang LiuNow MSI interrupt has been converted to new hierarchy irqdomain interfaces, so kill legacy MSI related code.
--- drivers/iommu/intel_irq_remapping.c | 144 ----------------------------------- 1 file changed, 144 deletions(-)
drivers/iommu/intel_irq_remapping.c +0 -144
@@ -144,44 +144,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) {
@@ -1120,108 +1082,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 ;
@@ -1279,10 +1139,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
tip-bot for Jiang Liu
merge bot[tip:x86/apic] iommu/vt-d: Clean up unused MSI related code
iommu/vt-d: Clean up unused MSI related code
Commit-ID: aa398ca77f6a77b5fa4fa24fe306f0f246864475 Gitweb: http://git.kernel.org/tip/aa398ca77f6a77b5fa4fa24fe306f0f246864475 Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:24 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:25 +0100
iommu/vt-d: Clean up unused MSI related code
Now 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
@@ -144,44 +144,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) {
@@ -1120,108 +1082,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 ;
@@ -1279,10 +1139,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, };
PATCH v6 16/27 iommu/amd: Clean up unused MSI related code
In reply to Jiang LiuNow MSI interrupt has been converted to new hierarchy irqdomain interfaces, so kill legacy MSI related code.
--- drivers/iommu/amd_iommu.c | 115 +-------------------------------------------- 1 file changed, 2 insertions(+), 113 deletions(-)
drivers/iommu/amd_iommu.c +2 -113
@@ -3958,8 +3958,7 @@ out_unlock:return table; } -static int alloc_irq_index (struct irq_cfg *cfg,struct irq_2_irte *irte_info, -u16 devid,int count) +static int alloc_irq_index (u16 devid,int count) {struct irq_remap_table *table;unsigned long flags;
@@ -3985,11 +3984,6 @@ static int alloc_irq_index(struct irq_cfg *cfg, struct irq_2_irte *irte_info, table->table[index - c +1 ] =IRTE_ALLOCATED ; index -= count -1 ; - - cfg->remapped =1 ; - irte_info->devid = devid; - irte_info->index = index; - goto out; } }
@@ -4189,106 +4183,6 @@ static int free_irq(int irq)return 0 ; } -static void compose_msi_msg (struct pci_dev *pdev, -unsigned int irq,unsigned int dest, -struct msi_msg *msg,u8 hpet_id) -{ -struct irq_2_irte *irte_info; -struct irq_cfg *cfg; -union irte irte; - - cfg =irq_cfg (irq); -if (!cfg) -return ; - - irte_info = &cfg->irq_2_irte; - - irte.val =0 ; - irte.fields.vector = cfg->vector; - irte.fields.int_type = apic->irq_delivery_mode; - irte.fields.destination = dest; - irte.fields.dm = apic->irq_dest_mode; - irte.fields.valid =1 ; - -modify_irte (irte_info->devid, irte_info->index, irte); - - msg->address_hi =MSI_ADDR_BASE_HI ; - msg->address_lo =MSI_ADDR_BASE_LO ; - msg->data = irte_info->index; -} - -static int msi_alloc_irq (struct pci_dev *pdev,int irq,int nvec) -{ -struct irq_cfg *cfg; -int index; -u16 devid; - -if (!pdev) -return -EINVAL ; - - cfg =irq_cfg (irq); -if (!cfg) -return -EINVAL ; - - devid =get_device_id (&pdev->dev); - index =alloc_irq_index (cfg, &cfg->irq_2_irte, devid, nvec); - -return index <0 ?MAX_IRQS_PER_TABLE : index; -} - -static int msi_setup_irq (struct pci_dev *pdev,unsigned int irq, -int index,int offset) -{ -struct irq_2_irte *irte_info; -struct irq_cfg *cfg; -u16 devid; - -if (!pdev) -return -EINVAL ; - - cfg =irq_cfg (irq); -if (!cfg) -return -EINVAL ; - -if (index >=MAX_IRQS_PER_TABLE ) -return 0 ; - - devid =get_device_id (&pdev->dev); - irte_info = &cfg->irq_2_irte; - - cfg->remapped =1 ; - irte_info->devid = devid; - irte_info->index = index + offset; - -return 0 ; -} - -static int alloc_hpet_msi (unsigned int irq,unsigned int id) -{ -struct irq_2_irte *irte_info; -struct irq_cfg *cfg; -int index, devid; - - cfg =irq_cfg (irq); -if (!cfg) -return -EINVAL ; - - irte_info = &cfg->irq_2_irte; - devid =get_hpet_devid (id); -if (devid <0 ) -return devid; - - index =alloc_irq_index (cfg, &cfg->irq_2_irte, devid,1 ); -if (index <0 ) -return index; - - cfg->remapped =1 ; - irte_info->devid = devid; - irte_info->index = index; - -return 0 ; -} -static int get_devid (struct irq_alloc_info *info) {int devid =-1 ;
@@ -4365,10 +4259,6 @@ struct irq_remap_ops amd_iommu_irq_ops = { .setup_ioapic_entry = setup_ioapic_entry, .set_affinity = set_affinity, .free_irq = free_irq, - .compose_msi_msg = compose_msi_msg, - .msi_alloc_irq = msi_alloc_irq, - .msi_setup_irq = msi_setup_irq, - .alloc_hpet_msi = alloc_hpet_msi, .get_ir_irq_domain = get_ir_irq_domain, .get_irq_domain = get_irq_domain, };
@@ -4466,8 +4356,7 @@ static int irq_remapping_alloc(struct irq_domain *domain, unsigned int virq,else ret = -ENOMEM ; }else { - cfg =irq_cfg (virq); - index =alloc_irq_index (cfg, &data->irq_2_irte, devid, nr_irqs); + index =alloc_irq_index (devid, nr_irqs); }if (index <0 ) {pr_warn ("Failed to allocate IRTE\n" );
Signature · 1 line
1.7.10.4
tip-bot for Jiang Liu
merge bot[tip:x86/apic] iommu/amd: Clean up unused MSI related code
iommu/amd: Clean up unused MSI related code
Commit-ID: 2be90208a0c0ef8cde3ee7e6361366047abbe3a7 Gitweb: http://git.kernel.org/tip/2be90208a0c0ef8cde3ee7e6361366047abbe3a7 Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:25 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:25 +0100
iommu/amd: Clean up unused MSI related code
Now MSI interrupt has been converted to new hierarchy irqdomain interfaces, so kill legacy MSI related code.
--- drivers/iommu/amd_iommu.c | 115 +--------------------------------------------- 1 file changed, 2 insertions(+), 113 deletions(-)
drivers/iommu/amd_iommu.c +2 -113
@@ -3958,8 +3958,7 @@ out_unlock:return table; } -static int alloc_irq_index (struct irq_cfg *cfg,struct irq_2_irte *irte_info, -u16 devid,int count) +static int alloc_irq_index (u16 devid,int count) {struct irq_remap_table *table;unsigned long flags;
@@ -3985,11 +3984,6 @@ static int alloc_irq_index(struct irq_cfg *cfg, struct irq_2_irte *irte_info, table->table[index - c +1 ] =IRTE_ALLOCATED ; index -= count -1 ; - - cfg->remapped =1 ; - irte_info->devid = devid; - irte_info->index = index; - goto out; } }
@@ -4189,106 +4183,6 @@ static int free_irq(int irq)return 0 ; } -static void compose_msi_msg (struct pci_dev *pdev, -unsigned int irq,unsigned int dest, -struct msi_msg *msg,u8 hpet_id) -{ -struct irq_2_irte *irte_info; -struct irq_cfg *cfg; -union irte irte; - - cfg =irq_cfg (irq); -if (!cfg) -return ; - - irte_info = &cfg->irq_2_irte; - - irte.val =0 ; - irte.fields.vector = cfg->vector; - irte.fields.int_type = apic->irq_delivery_mode; - irte.fields.destination = dest; - irte.fields.dm = apic->irq_dest_mode; - irte.fields.valid =1 ; - -modify_irte (irte_info->devid, irte_info->index, irte); - - msg->address_hi =MSI_ADDR_BASE_HI ; - msg->address_lo =MSI_ADDR_BASE_LO ; - msg->data = irte_info->index; -} - -static int msi_alloc_irq (struct pci_dev *pdev,int irq,int nvec) -{ -struct irq_cfg *cfg; -int index; -u16 devid; - -if (!pdev) -return -EINVAL ; - - cfg =irq_cfg (irq); -if (!cfg) -return -EINVAL ; - - devid =get_device_id (&pdev->dev); - index =alloc_irq_index (cfg, &cfg->irq_2_irte, devid, nvec); - -return index <0 ?MAX_IRQS_PER_TABLE : index; -} - -static int msi_setup_irq (struct pci_dev *pdev,unsigned int irq, -int index,int offset) -{ -struct irq_2_irte *irte_info; -struct irq_cfg *cfg; -u16 devid; - -if (!pdev) -return -EINVAL ; - - cfg =irq_cfg (irq); -if (!cfg) -return -EINVAL ; - -if (index >=MAX_IRQS_PER_TABLE ) -return 0 ; - - devid =get_device_id (&pdev->dev); - irte_info = &cfg->irq_2_irte; - - cfg->remapped =1 ; - irte_info->devid = devid; - irte_info->index = index + offset; - -return 0 ; -} - -static int alloc_hpet_msi (unsigned int irq,unsigned int id) -{ -struct irq_2_irte *irte_info; -struct irq_cfg *cfg; -int index, devid; - - cfg =irq_cfg (irq); -if (!cfg) -return -EINVAL ; - - irte_info = &cfg->irq_2_irte; - devid =get_hpet_devid (id); -if (devid <0 ) -return devid; - - index =alloc_irq_index (cfg, &cfg->irq_2_irte, devid,1 ); -if (index <0 ) -return index; - - cfg->remapped =1 ; - irte_info->devid = devid; - irte_info->index = index; - -return 0 ; -} -static int get_devid (struct irq_alloc_info *info) {int devid =-1 ;
@@ -4365,10 +4259,6 @@ struct irq_remap_ops amd_iommu_irq_ops = { .setup_ioapic_entry = setup_ioapic_entry, .set_affinity = set_affinity, .free_irq = free_irq, - .compose_msi_msg = compose_msi_msg, - .msi_alloc_irq = msi_alloc_irq, - .msi_setup_irq = msi_setup_irq, - .alloc_hpet_msi = alloc_hpet_msi, .get_ir_irq_domain = get_ir_irq_domain, .get_irq_domain = get_irq_domain, };
@@ -4466,8 +4356,7 @@ static int irq_remapping_alloc(struct irq_domain *domain, unsigned int virq,else ret = -ENOMEM ; }else { - cfg =irq_cfg (virq); - index =alloc_irq_index (cfg, &data->irq_2_irte, devid, nr_irqs); + index =alloc_irq_index (devid, nr_irqs); }if (index <0 ) {pr_warn ("Failed to allocate IRTE\n" );
PATCH v6 17/27 x86: irq_remapping: Clean up unused MSI related code
In reply to Jiang LiuNow MSI interrupt has been converted to new hierarchy irqdomain interfaces, so kill legacy MSI related code and interfaces.
--- arch/x86/include/asm/irq_remapping.h | 13 --- arch/x86/include/asm/pci.h | 5 -- arch/x86/kernel/x86_init.c | 2 - drivers/iommu/irq_remapping.c | 151 ---------------------------------- drivers/iommu/irq_remapping.h | 14 ---- 5 files changed, 185 deletions(-)
arch/x86/include/asm/irq_remapping.h +0 -13
@@ -50,10 +50,6 @@ extern int setup_ioapic_remapped_entry(int irq,int vector, struct io_apic_irq_attr *attr);extern void free_remapped_irq (int irq); -extern void compose_remapped_msi_msg (struct pci_dev *pdev, -unsigned int irq,unsigned int dest, -struct msi_msg *msg,u8 hpet_id); -extern int setup_hpet_msi_remapped (unsigned int irq,unsigned int id);extern void panic_if_irq_remap (const char *msg); extern bool setup_remapped_irq(int irq, struct irq_cfg *cfg,
@@ -95,15 +91,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
@@ -70,20 +70,6 @@ struct irq_remap_ops {/* Free an IRQ */ int (*free_irq)(int ); -/* Create MSI msg to use for interrupt remapping */ -void (*compose_msi_msg)(struct pci_dev *, -unsigned int ,unsigned int , -struct msi_msg *,u8 ); - -/* Allocate remapping resources for MSI */ -int (*msi_alloc_irq)(struct pci_dev *,int ,int ); - -/* Setup the remapped MSI irq */ -int (*msi_setup_irq)(struct pci_dev *,unsigned int ,int ,int ); - -/* Setup interrupt remapping for an HPET MSI */ -int (*alloc_hpet_msi)(unsigned int ,unsigned int ); -/* Get the irqdomain associated the IOMMU device */ struct irq_domain *(*get_ir_irq_domain)(struct irq_alloc_info *);
Signature · 1 line
1.7.10.4
tip-bot for Jiang Liu
merge bot[tip:x86/apic] x86: irq_remapping: Clean up unused MSI related code
x86: irq_remapping: Clean up unused MSI related code
Commit-ID: bd3f1972356fc17e25f9cc98a94efe5d3535c831 Gitweb: http://git.kernel.org/tip/bd3f1972356fc17e25f9cc98a94efe5d3535c831 Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:26 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:25 +0100
x86: irq_remapping: Clean up unused MSI related code
Now MSI interrupt has been converted to new hierarchy irqdomain interfaces, so kill legacy MSI related code and interfaces.
--- arch/x86/include/asm/irq_remapping.h | 13 --- arch/x86/include/asm/pci.h | 5 -- arch/x86/kernel/x86_init.c | 2 - drivers/iommu/irq_remapping.c | 151 ----------------------------------- drivers/iommu/irq_remapping.h | 14 ---- 5 files changed, 185 deletions(-)
arch/x86/include/asm/irq_remapping.h +0 -13
@@ -50,10 +50,6 @@ extern int setup_ioapic_remapped_entry(int irq,int vector, struct io_apic_irq_attr *attr);extern void free_remapped_irq (int irq); -extern void compose_remapped_msi_msg (struct pci_dev *pdev, -unsigned int irq,unsigned int dest, -struct msi_msg *msg,u8 hpet_id); -extern int setup_hpet_msi_remapped (unsigned int irq,unsigned int id);extern void panic_if_irq_remap (const char *msg); extern bool setup_remapped_irq(int irq, struct irq_cfg *cfg,
@@ -95,15 +91,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
@@ -70,20 +70,6 @@ struct irq_remap_ops {/* Free an IRQ */ int (*free_irq)(int ); -/* Create MSI msg to use for interrupt remapping */ -void (*compose_msi_msg)(struct pci_dev *, -unsigned int ,unsigned int , -struct msi_msg *,u8 ); - -/* Allocate remapping resources for MSI */ -int (*msi_alloc_irq)(struct pci_dev *,int ,int ); - -/* Setup the remapped MSI irq */ -int (*msi_setup_irq)(struct pci_dev *,unsigned int ,int ,int ); - -/* Setup interrupt remapping for an HPET MSI */ -int (*alloc_hpet_msi)(unsigned int ,unsigned int ); -/* Get the irqdomain associated the IOMMU device */ struct irq_domain *(*get_ir_irq_domain)(struct irq_alloc_info *);
PATCH v6 18/27 x86, irq: Clean up unused MSI related code and interfaces
In reply to Jiang LiuNow MSI interrupt has been converted to new hierarchy irqdomain interfaces, so kill legacy MSI related code and interfaces.
--- arch/x86/include/asm/hpet.h | 9 ------- arch/x86/include/asm/x86_init.h | 4 --- arch/x86/kernel/apic/msi.c | 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
tip-bot for Jiang Liu
merge bot[tip:x86/apic] x86, irq: Clean up unused MSI related code and interfaces
x86, irq: Clean up unused MSI related code and interfaces
Commit-ID: 052a2081707e21677516602c573f6136de6ab077 Gitweb: http://git.kernel.org/tip/052a2081707e21677516602c573f6136de6ab077 Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:27 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:25 +0100
x86, irq: Clean up unused MSI related code and interfaces
Now 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
PATCH v6 19/27 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
@@ -121,8 +121,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
tip-bot for Jiang Liu
merge bot[tip:x86/apic] iommu/vt-d: Refine the interfaces to create IRQ for DMAR unit
iommu/vt-d: Refine the interfaces to create IRQ for DMAR unit
Commit-ID: 82ebe4e0c0d6ce8ef20cac67ef4ce4b46b9e219b Gitweb: http://git.kernel.org/tip/82ebe4e0c0d6ce8ef20cac67ef4ce4b46b9e219b Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:28 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:25 +0100
iommu/vt-d: Refine the interfaces to create IRQ for DMAR unit
Refine 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
@@ -121,8 +121,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__ */
PATCH v6 20/27 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
tip-bot for Jiang Liu
merge bot[tip:x86/apic] x86, irq: Use hierarchy irqdomain to manage DMAR interrupts
x86, irq: Use hierarchy irqdomain to manage DMAR interrupts
Commit-ID: 9a013f9684208bc74e9aff1e0414276489396a1a Gitweb: http://git.kernel.org/tip/9a013f9684208bc74e9aff1e0414276489396a1a Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:29 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:25 +0100
x86, irq: Use hierarchy irqdomain to manage DMAR interrupts
Enhance 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
PATCH v6 21/27 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
tip-bot for Jiang Liu
merge bot[tip:x86/apic] x86, htirq: Use hierarchy irqdomain to manage Hypertransport interrupts
x86, htirq: Use hierarchy irqdomain to manage Hypertransport interrupts
Commit-ID: 8b6f6c101166f9738586d1b2653db5bb89e59504 Gitweb: http://git.kernel.org/tip/8b6f6c101166f9738586d1b2653db5bb89e59504 Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:30 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:26 +0100
x86, htirq: Use hierarchy irqdomain to manage Hypertransport interrupts
Use 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 */
PATCH v6 22/27 x86, uv: Use hierarchy irqdomain to manage UV interrupts
In reply to Jiang LiuEnhance UV code to support hierarchy irqdomain, it helps to make the architecture more clear.
We should construct hwirq based on mmr_blade and mmr_offset, but mmr_offset is type of unsigned long, it may exceed the range of irq_hw_number_t. So help about the way to construct hwirq based on mmr_blade and mmr_offset is welcomed!
--- arch/x86/include/asm/hw_irq.h | 9 ++ arch/x86/platform/uv/uv_irq.c | 287 ++++++++++++++++------------------------- 2 files changed, 117 insertions(+), 179 deletions(-)
arch/x86/include/asm/hw_irq.h +9 -0
@@ -123,6 +123,7 @@ enum irq_alloc_type {X86_IRQ_ALLOC_TYPE_MSI ,X86_IRQ_ALLOC_TYPE_MSIX ,X86_IRQ_ALLOC_TYPE_DMAR , + X86_IRQ_ALLOC_TYPE_UV, }; struct irq_alloc_info {
@@ -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 +108 -179
359 lines not on this page · raw message
Signature · 1 line
1.7.10.4
tip-bot for Jiang Liu
merge bot[tip:x86/apic] x86, uv: Use hierarchy irqdomain to manage UV interrupts
x86, uv: Use hierarchy irqdomain to manage UV interrupts
Commit-ID: 3f83d863fb839937de0cf462a867777105e83875 Gitweb: http://git.kernel.org/tip/3f83d863fb839937de0cf462a867777105e83875 Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:31 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:26 +0100
x86, uv: Use hierarchy irqdomain to manage UV interrupts
Enhance UV code to support hierarchy irqdomain, it helps to make the architecture more clear.
We should construct hwirq based on mmr_blade and mmr_offset, but mmr_offset is type of unsigned long, it may exceed the range of irq_hw_number_t. So help about the way to construct hwirq based on mmr_blade and mmr_offset is welcomed!
--- arch/x86/include/asm/hw_irq.h | 9 ++ arch/x86/platform/uv/uv_irq.c | 287 ++++++++++++++++-------------------------- 2 files changed, 117 insertions(+), 179 deletions(-)
arch/x86/include/asm/hw_irq.h +9 -0
@@ -123,6 +123,7 @@ enum irq_alloc_type {X86_IRQ_ALLOC_TYPE_MSI ,X86_IRQ_ALLOC_TYPE_MSIX ,X86_IRQ_ALLOC_TYPE_DMAR , + X86_IRQ_ALLOC_TYPE_UV, }; struct irq_alloc_info {
@@ -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 +108 -179
359 lines not on this page · raw message
Re: [Patch Part2 v6 22/27] x86, uv: Use hierarchy irqdomain to manage UV interrupts
In reply to Jiang LiuWas this patch ever tested on a UV system?
Also, adding some SGI folks to the CC list, since there were none listed before.
Quoted 417 lines · Jiang Liu
Enhance UV code to support hierarchy irqdomain, it helps to make the architecture more clear.
We should construct hwirq based on
mmr_bladeandmmr_offset, butmmr_offsetis type of unsigned long, it may exceed the range ofirq_hw_number_t. So help about the way to construct hwirq based onmmr_bladeandmmr_offsetis welcomed!Signed-off-by Jiang Liu <[email protected]>--- arch/x86/include/asm/hw_irq.h | 9 ++ arch/x86/platform/uv/uv_irq.c | 287 ++++++++++++++++------------------------- 2 files changed, 117 insertions(+), 179 deletions(-)arch/x86/include/asm/hw_irq.h +9
-0@@ -123,6 +123,7 @@ enum irq_alloc_type {X86_IRQ_ALLOC_TYPE_MSI ,X86_IRQ_ALLOC_TYPE_MSIX ,X86_IRQ_ALLOC_TYPE_DMAR , + X86_IRQ_ALLOC_TYPE_UV, }; struct irq_alloc_info {@@ -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 +108
-179@@ -19,17 +19,31 @@#include <asm/uv/uv_hub.h> /* MMR offset and pnode of hub sourcing interrupts for a given irq */ -struct uv_irq_2_mmr_pnode { -struct rb_node list; +struct uv_irq_2_mmr_pnode {unsigned long offset;int pnode; -int irq; }; -static DEFINE_SPINLOCK (uv_irq_lock); -static struct rb_root uv_irq_root; +static void uv_program_mmr (struct irq_cfg *cfg,struct uv_irq_2_mmr_pnode *info) +{ +unsigned long mmr_value; +struct uv_IO_APIC_route_entry *entry; + +BUILD_BUG_ON (sizeof (struct uv_IO_APIC_route_entry ) != +sizeof (unsigned long )); + + mmr_value =0 ; + entry = (struct uv_IO_APIC_route_entry *)&mmr_value; + entry->vector = cfg->vector; + entry->delivery_mode = apic->irq_delivery_mode; + entry->dest_mode = apic->irq_dest_mode; + entry->polarity =0 ; + entry->trigger =0 ; + entry->mask =0 ; + entry->dest = cfg->dest_apicid; -static int uv_set_irq_affinity (struct irq_data *,const struct cpumask *,bool ); +uv_write_global_mmr64 (info->pnode, info->offset, mmr_value); +}static void uv_noop (struct irq_data *data) { }@@ -38,6 +52,24 @@ static void uv_ack_apic(struct irq_data *data)ack_APIC_irq (); } +static int +uv_set_irq_affinity (struct irq_data *data,const struct cpumask *mask, +bool force) +{ +struct irq_data *parent = data->parent_data; +struct irq_cfg *cfg =irqd_cfg (data); +int ret; + + ret = parent->chip->irq_set_affinity (parent, mask, force); +if (ret >=0 ) { +uv_program_mmr (cfg, data->chip_data); +if (cfg->move_in_progress) +send_cleanup_vector (cfg); + } + +return ret; +} +static struct irq_chip uv_irq_chip = { .name ="UV-CORE" , .irq_mask = uv_noop,@@ -46,179 +78,99 @@ static struct irq_chip uv_irq_chip = { .irq_set_affinity = uv_set_irq_affinity, }; -/* -* Add offset and pnode information of the hub sourcing interrupts to the -* rb tree for a specific irq. -*/ -static int uv_set_irq_2_mmr_info (int irq,unsigned long offset,unsigned blade) +static int uv_domain_alloc (struct irq_domain *domain,unsigned int virq, +unsigned int nr_irqs,void *arg) { -struct rb_node **link = &uv_irq_root.rb_node; -struct rb_node *parent =NULL ; -struct uv_irq_2_mmr_pnode *n; -struct uv_irq_2_mmr_pnode *e; -unsigned long irqflags; - - n =kmalloc_node (sizeof (struct uv_irq_2_mmr_pnode ),GFP_KERNEL , -uv_blade_to_memory_nid (blade)); -if (!n) +struct uv_irq_2_mmr_pnode *chip_data; +struct irq_alloc_info *info = arg; +struct irq_data *irq_data =irq_domain_get_irq_data (domain, virq); +int ret; + +if (nr_irqs >1 || !info || info->type !=X86_IRQ_ALLOC_TYPE_UV ) +return -EINVAL ; + + chip_data =kmalloc_node (sizeof (*chip_data),GFP_KERNEL , + irq_data->node); +if (!chip_data)return -ENOMEM ; - n->irq = irq; - n->offset = offset; - n->pnode =uv_blade_to_pnode (blade); -spin_lock_irqsave (&uv_irq_lock, irqflags); -/* Find the right place in the rbtree: */ -while (*link) { - parent = *link; - e = rb_entry(parent, struct uv_irq_2_mmr_pnode, list); - -if (unlikely (irq == e->irq)) { -/* irq entry exists */ - e->pnode =uv_blade_to_pnode (blade); - e->offset = offset; -spin_unlock_irqrestore (&uv_irq_lock, irqflags); -kfree (n); -return 0 ; - } - -if (irq < e->irq) - link = &(*link)->rb_left; + ret =irq_domain_alloc_irqs_parent (domain, virq, nr_irqs, arg); +if (ret >=0 ) { +if (info->uv_limit ==UV_AFFINITY_CPU ) +irq_set_status_flags (virq,IRQ_NO_BALANCING );else - link = &(*link)->rb_right; +irq_set_status_flags (virq,IRQ_MOVE_PCNTXT ); + + chip_data->pnode =uv_blade_to_pnode (info->uv_blade); + chip_data->offset = info->uv_offset; +irq_domain_set_info (domain, virq, virq, &uv_irq_chip, chip_data, + handle_percpu_irq,NULL , info->uv_name); + }else { +kfree (chip_data); } -/* Insert the node into the rbtree. */ -rb_link_node (&n->list, parent, link); -rb_insert_color (&n->list, &uv_irq_root); - -spin_unlock_irqrestore (&uv_irq_lock, irqflags); -return 0 ; +return ret; } -/* Retrieve offset and pnode information from the rb tree for a specific irq */ -int uv_irq_2_mmr_info (int irq,unsigned long *offset,int *pnode) +static void uv_domain_free (struct irq_domain *domain,unsigned int virq, +unsigned int nr_irqs) { -struct uv_irq_2_mmr_pnode *e; -struct rb_node *n; -unsigned long irqflags; - -spin_lock_irqsave (&uv_irq_lock, irqflags); - n = uv_irq_root.rb_node; -while (n) { - e = rb_entry(n, struct uv_irq_2_mmr_pnode, list); - -if (e->irq == irq) { - *offset = e->offset; - *pnode = e->pnode; -spin_unlock_irqrestore (&uv_irq_lock, irqflags); -return 0 ; - } - -if (irq < e->irq) - n = n->rb_left; -else - n = n->rb_right; - } -spin_unlock_irqrestore (&uv_irq_lock, irqflags); -return -1 ; +struct irq_data *irq_data =irq_domain_get_irq_data (domain, virq); + +BUG_ON (nr_irqs !=1 ); +kfree (irq_data->chip_data); +irq_clear_status_flags (virq,IRQ_MOVE_PCNTXT ); +irq_clear_status_flags (virq,IRQ_NO_BALANCING ); +irq_domain_free_irqs_top (domain, virq, nr_irqs); }/* * Re-target the irq to the specified CPU and enable the specified MMR located * on the specified blade to allow the sending of MSIs to the specified CPU. */ -static int -arch_enable_uv_irq (char *irq_name,unsigned int irq,int cpu,int mmr_blade, -unsigned long mmr_offset,int limit) +static void uv_domain_activate (struct irq_domain *domain, +struct irq_data *irq_data) { -struct irq_cfg *cfg =irq_cfg (irq); -unsigned long mmr_value; -struct uv_IO_APIC_route_entry *entry; -int mmr_pnode; - -BUILD_BUG_ON (sizeof (struct uv_IO_APIC_route_entry ) != -sizeof (unsigned long )); - -if (limit ==UV_AFFINITY_CPU ) -irq_set_status_flags (irq,IRQ_NO_BALANCING ); -else -irq_set_status_flags (irq,IRQ_MOVE_PCNTXT ); - -irq_set_chip_and_handler_name (irq, &uv_irq_chip, handle_percpu_irq, - irq_name); - - mmr_value =0 ; - entry = (struct uv_IO_APIC_route_entry *)&mmr_value; - entry->vector = cfg->vector; - entry->delivery_mode = apic->irq_delivery_mode; - entry->dest_mode = apic->irq_dest_mode; - entry->polarity =0 ; - entry->trigger =0 ; - entry->mask =0 ; - entry->dest = cfg->dest_apicid; - - mmr_pnode =uv_blade_to_pnode (mmr_blade); -uv_write_global_mmr64 (mmr_pnode, mmr_offset, mmr_value); - -if (cfg->move_in_progress) -send_cleanup_vector (cfg); - -return irq; +uv_program_mmr (irqd_cfg (irq_data), irq_data->chip_data); }/* * Disable the specified MMR located on the specified blade so that MSIs are * longer allowed to be sent. */ -static void arch_disable_uv_irq (int mmr_pnode,unsigned long mmr_offset) +static void uv_domain_deactivate (struct irq_domain *domain, +struct irq_data *irq_data) {unsigned long mmr_value;struct uv_IO_APIC_route_entry *entry; -BUILD_BUG_ON (sizeof (struct uv_IO_APIC_route_entry ) != -sizeof (unsigned long )); - mmr_value =0 ; entry = (struct uv_IO_APIC_route_entry *)&mmr_value; entry->mask =1 ; - -uv_write_global_mmr64 (mmr_pnode, mmr_offset, mmr_value); +uv_program_mmr (irqd_cfg (irq_data), irq_data->chip_data); } -static int -uv_set_irq_affinity (struct irq_data *data,const struct cpumask *mask, -bool force) -{ -struct irq_cfg *cfg =irqd_cfg (data); -unsigned int dest; -unsigned long mmr_value, mmr_offset; -struct uv_IO_APIC_route_entry *entry; -int mmr_pnode; - -if (apic_set_affinity (data, mask, &dest)) -return -1 ; - - mmr_value =0 ; - entry = (struct uv_IO_APIC_route_entry *)&mmr_value; - - entry->vector = cfg->vector; - entry->delivery_mode = apic->irq_delivery_mode; - entry->dest_mode = apic->irq_dest_mode; - entry->polarity =0 ; - entry->trigger =0 ; - entry->mask =0 ; - entry->dest = dest; - -/* Get previously stored MMR and pnode of hub sourcing interrupts */ -if (uv_irq_2_mmr_info (data->irq, &mmr_offset, &mmr_pnode)) -return -1 ; - -uv_write_global_mmr64 (mmr_pnode, mmr_offset, mmr_value); +static struct irq_domain_ops uv_domain_ops = { + .alloc = uv_domain_alloc, + .free = uv_domain_free, + .activate = uv_domain_activate, + .deactivate = uv_domain_deactivate, +}; -if (cfg->move_in_progress) -send_cleanup_vector (cfg); +static struct irq_domain *uv_get_irq_domain (void ) +{ +static struct irq_domain *uv_domain; +static DEFINE_MUTEX (uv_lock); + +mutex_lock (&uv_lock); +if (uv_domain ==NULL ) { + uv_domain =irq_domain_add_tree (NULL , &uv_domain_ops,NULL ); +if (uv_domain) + uv_domain->parent = x86_vector_domain; + } +mutex_unlock (&uv_lock); -return IRQ_SET_MASK_OK_NOCOPY ; +return uv_domain; }/* @@ -229,23 +181,20 @@ 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;struct irq_alloc_info info; +struct irq_domain *domain =uv_get_irq_domain (); + +if (!domain) +return -ENOMEM ;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, - limit); -if (ret == irq) -uv_set_irq_2_mmr_info (irq, mmr_offset, mmr_blade); -else -irq_domain_free_irqs (irq,1 ); + info.uv_limit = limit; + info.uv_blade = mmr_blade; + info.uv_offset = mmr_offset; + info.uv_name = irq_name; -return ret; +return irq_domain_alloc_irqs (domain,1 , +uv_blade_to_memory_nid (mmr_blade), &info); }EXPORT_SYMBOL_GPL (uv_setup_irq);@@ -258,26 +207,6 @@ EXPORT_SYMBOL_GPL(uv_setup_irq);*/ void uv_teardown_irq (unsigned int irq) { -struct uv_irq_2_mmr_pnode *e; -struct rb_node *n; -unsigned long irqflags; - -spin_lock_irqsave (&uv_irq_lock, irqflags); - n = uv_irq_root.rb_node; -while (n) { - e = rb_entry(n, struct uv_irq_2_mmr_pnode, list); -if (e->irq == irq) { -arch_disable_uv_irq (e->pnode, e->offset); -rb_erase (n, &uv_irq_root); -kfree (e); -break ; - } -if (irq < e->irq) - n = n->rb_left; -else - n = n->rb_right; - } -spin_unlock_irqrestore (&uv_irq_lock, irqflags);irq_domain_free_irqs (irq,1 ); }EXPORT_SYMBOL_GPL (uv_teardown_irq);Signature · 7 lines
1.7.10.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [Patch Part2 v6 22/27] x86, uv: Use hierarchy irqdomain to manage UV interrupts
I answered my own question, this had never been tested on UV.
The gru driver fails with:
SGI GRU Device Driver: uv_setup_irq failed, errno=22
The info->type in uv_domain_alloc() is not set to X86_IRQ_ALLOC_TYPE_UV (info->type is never set to that value anywhere).
Adding the following to uv_setup_irq allows it to work:
arch/x86/platform/uv/uv_irq.c +1 -0
@@ -187,6 +187,7 @@ int uv_setup_irq(char *irq_name, int cpureturn -ENOMEM ;init_irq_alloc_info (&info,cpumask_of (cpu)); + info.type =X86_IRQ_ALLOC_TYPE_UV ; info.uv_limit = limit; info.uv_blade = mmr_blade; info.uv_offset = mmr_offset;
Quoted 422 lines · Dimitri Sivanich
Was this patch ever tested on a UV system?
Also, adding some SGI folks to the CC list, since there were none listed before.
Quoted 417 lines · Jiang Liu
Enhance UV code to support hierarchy irqdomain, it helps to make the architecture more clear.
We should construct hwirq based on
mmr_bladeandmmr_offset, butmmr_offsetis type of unsigned long, it may exceed the range ofirq_hw_number_t. So help about the way to construct hwirq based onmmr_bladeandmmr_offsetis welcomed!Signed-off-by Jiang Liu <[email protected]>--- arch/x86/include/asm/hw_irq.h | 9 ++ arch/x86/platform/uv/uv_irq.c | 287 ++++++++++++++++------------------------- 2 files changed, 117 insertions(+), 179 deletions(-)arch/x86/include/asm/hw_irq.h +9
-0@@ -123,6 +123,7 @@ enum irq_alloc_type {X86_IRQ_ALLOC_TYPE_MSI ,X86_IRQ_ALLOC_TYPE_MSIX ,X86_IRQ_ALLOC_TYPE_DMAR , + X86_IRQ_ALLOC_TYPE_UV, }; struct irq_alloc_info {@@ -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 +108
-179@@ -19,17 +19,31 @@#include <asm/uv/uv_hub.h> /* MMR offset and pnode of hub sourcing interrupts for a given irq */ -struct uv_irq_2_mmr_pnode { -struct rb_node list; +struct uv_irq_2_mmr_pnode {unsigned long offset;int pnode; -int irq; }; -static DEFINE_SPINLOCK (uv_irq_lock); -static struct rb_root uv_irq_root; +static void uv_program_mmr (struct irq_cfg *cfg,struct uv_irq_2_mmr_pnode *info) +{ +unsigned long mmr_value; +struct uv_IO_APIC_route_entry *entry; + +BUILD_BUG_ON (sizeof (struct uv_IO_APIC_route_entry ) != +sizeof (unsigned long )); + + mmr_value =0 ; + entry = (struct uv_IO_APIC_route_entry *)&mmr_value; + entry->vector = cfg->vector; + entry->delivery_mode = apic->irq_delivery_mode; + entry->dest_mode = apic->irq_dest_mode; + entry->polarity =0 ; + entry->trigger =0 ; + entry->mask =0 ; + entry->dest = cfg->dest_apicid; -static int uv_set_irq_affinity (struct irq_data *,const struct cpumask *,bool ); +uv_write_global_mmr64 (info->pnode, info->offset, mmr_value); +}static void uv_noop (struct irq_data *data) { }@@ -38,6 +52,24 @@ static void uv_ack_apic(struct irq_data *data)ack_APIC_irq (); } +static int +uv_set_irq_affinity (struct irq_data *data,const struct cpumask *mask, +bool force) +{ +struct irq_data *parent = data->parent_data; +struct irq_cfg *cfg =irqd_cfg (data); +int ret; + + ret = parent->chip->irq_set_affinity (parent, mask, force); +if (ret >=0 ) { +uv_program_mmr (cfg, data->chip_data); +if (cfg->move_in_progress) +send_cleanup_vector (cfg); + } + +return ret; +} +static struct irq_chip uv_irq_chip = { .name ="UV-CORE" , .irq_mask = uv_noop,@@ -46,179 +78,99 @@ static struct irq_chip uv_irq_chip = { .irq_set_affinity = uv_set_irq_affinity, }; -/* -* Add offset and pnode information of the hub sourcing interrupts to the -* rb tree for a specific irq. -*/ -static int uv_set_irq_2_mmr_info (int irq,unsigned long offset,unsigned blade) +static int uv_domain_alloc (struct irq_domain *domain,unsigned int virq, +unsigned int nr_irqs,void *arg) { -struct rb_node **link = &uv_irq_root.rb_node; -struct rb_node *parent =NULL ; -struct uv_irq_2_mmr_pnode *n; -struct uv_irq_2_mmr_pnode *e; -unsigned long irqflags; - - n =kmalloc_node (sizeof (struct uv_irq_2_mmr_pnode ),GFP_KERNEL , -uv_blade_to_memory_nid (blade)); -if (!n) +struct uv_irq_2_mmr_pnode *chip_data; +struct irq_alloc_info *info = arg; +struct irq_data *irq_data =irq_domain_get_irq_data (domain, virq); +int ret; + +if (nr_irqs >1 || !info || info->type !=X86_IRQ_ALLOC_TYPE_UV ) +return -EINVAL ; + + chip_data =kmalloc_node (sizeof (*chip_data),GFP_KERNEL , + irq_data->node); +if (!chip_data)return -ENOMEM ; - n->irq = irq; - n->offset = offset; - n->pnode =uv_blade_to_pnode (blade); -spin_lock_irqsave (&uv_irq_lock, irqflags); -/* Find the right place in the rbtree: */ -while (*link) { - parent = *link; - e = rb_entry(parent, struct uv_irq_2_mmr_pnode, list); - -if (unlikely (irq == e->irq)) { -/* irq entry exists */ - e->pnode =uv_blade_to_pnode (blade); - e->offset = offset; -spin_unlock_irqrestore (&uv_irq_lock, irqflags); -kfree (n); -return 0 ; - } - -if (irq < e->irq) - link = &(*link)->rb_left; + ret =irq_domain_alloc_irqs_parent (domain, virq, nr_irqs, arg); +if (ret >=0 ) { +if (info->uv_limit ==UV_AFFINITY_CPU ) +irq_set_status_flags (virq,IRQ_NO_BALANCING );else - link = &(*link)->rb_right; +irq_set_status_flags (virq,IRQ_MOVE_PCNTXT ); + + chip_data->pnode =uv_blade_to_pnode (info->uv_blade); + chip_data->offset = info->uv_offset; +irq_domain_set_info (domain, virq, virq, &uv_irq_chip, chip_data, + handle_percpu_irq,NULL , info->uv_name); + }else { +kfree (chip_data); } -/* Insert the node into the rbtree. */ -rb_link_node (&n->list, parent, link); -rb_insert_color (&n->list, &uv_irq_root); - -spin_unlock_irqrestore (&uv_irq_lock, irqflags); -return 0 ; +return ret; } -/* Retrieve offset and pnode information from the rb tree for a specific irq */ -int uv_irq_2_mmr_info (int irq,unsigned long *offset,int *pnode) +static void uv_domain_free (struct irq_domain *domain,unsigned int virq, +unsigned int nr_irqs) { -struct uv_irq_2_mmr_pnode *e; -struct rb_node *n; -unsigned long irqflags; - -spin_lock_irqsave (&uv_irq_lock, irqflags); - n = uv_irq_root.rb_node; -while (n) { - e = rb_entry(n, struct uv_irq_2_mmr_pnode, list); - -if (e->irq == irq) { - *offset = e->offset; - *pnode = e->pnode; -spin_unlock_irqrestore (&uv_irq_lock, irqflags); -return 0 ; - } - -if (irq < e->irq) - n = n->rb_left; -else - n = n->rb_right; - } -spin_unlock_irqrestore (&uv_irq_lock, irqflags); -return -1 ; +struct irq_data *irq_data =irq_domain_get_irq_data (domain, virq); + +BUG_ON (nr_irqs !=1 ); +kfree (irq_data->chip_data); +irq_clear_status_flags (virq,IRQ_MOVE_PCNTXT ); +irq_clear_status_flags (virq,IRQ_NO_BALANCING ); +irq_domain_free_irqs_top (domain, virq, nr_irqs); }/* * Re-target the irq to the specified CPU and enable the specified MMR located * on the specified blade to allow the sending of MSIs to the specified CPU. */ -static int -arch_enable_uv_irq (char *irq_name,unsigned int irq,int cpu,int mmr_blade, -unsigned long mmr_offset,int limit) +static void uv_domain_activate (struct irq_domain *domain, +struct irq_data *irq_data) { -struct irq_cfg *cfg =irq_cfg (irq); -unsigned long mmr_value; -struct uv_IO_APIC_route_entry *entry; -int mmr_pnode; - -BUILD_BUG_ON (sizeof (struct uv_IO_APIC_route_entry ) != -sizeof (unsigned long )); - -if (limit ==UV_AFFINITY_CPU ) -irq_set_status_flags (irq,IRQ_NO_BALANCING ); -else -irq_set_status_flags (irq,IRQ_MOVE_PCNTXT ); - -irq_set_chip_and_handler_name (irq, &uv_irq_chip, handle_percpu_irq, - irq_name); - - mmr_value =0 ; - entry = (struct uv_IO_APIC_route_entry *)&mmr_value; - entry->vector = cfg->vector; - entry->delivery_mode = apic->irq_delivery_mode; - entry->dest_mode = apic->irq_dest_mode; - entry->polarity =0 ; - entry->trigger =0 ; - entry->mask =0 ; - entry->dest = cfg->dest_apicid; - - mmr_pnode =uv_blade_to_pnode (mmr_blade); -uv_write_global_mmr64 (mmr_pnode, mmr_offset, mmr_value); - -if (cfg->move_in_progress) -send_cleanup_vector (cfg); - -return irq; +uv_program_mmr (irqd_cfg (irq_data), irq_data->chip_data); }/* * Disable the specified MMR located on the specified blade so that MSIs are * longer allowed to be sent. */ -static void arch_disable_uv_irq (int mmr_pnode,unsigned long mmr_offset) +static void uv_domain_deactivate (struct irq_domain *domain, +struct irq_data *irq_data) {unsigned long mmr_value;struct uv_IO_APIC_route_entry *entry; -BUILD_BUG_ON (sizeof (struct uv_IO_APIC_route_entry ) != -sizeof (unsigned long )); - mmr_value =0 ; entry = (struct uv_IO_APIC_route_entry *)&mmr_value; entry->mask =1 ; - -uv_write_global_mmr64 (mmr_pnode, mmr_offset, mmr_value); +uv_program_mmr (irqd_cfg (irq_data), irq_data->chip_data); } -static int -uv_set_irq_affinity (struct irq_data *data,const struct cpumask *mask, -bool force) -{ -struct irq_cfg *cfg =irqd_cfg (data); -unsigned int dest; -unsigned long mmr_value, mmr_offset; -struct uv_IO_APIC_route_entry *entry; -int mmr_pnode; - -if (apic_set_affinity (data, mask, &dest)) -return -1 ; - - mmr_value =0 ; - entry = (struct uv_IO_APIC_route_entry *)&mmr_value; - - entry->vector = cfg->vector; - entry->delivery_mode = apic->irq_delivery_mode; - entry->dest_mode = apic->irq_dest_mode; - entry->polarity =0 ; - entry->trigger =0 ; - entry->mask =0 ; - entry->dest = dest; - -/* Get previously stored MMR and pnode of hub sourcing interrupts */ -if (uv_irq_2_mmr_info (data->irq, &mmr_offset, &mmr_pnode)) -return -1 ; - -uv_write_global_mmr64 (mmr_pnode, mmr_offset, mmr_value); +static struct irq_domain_ops uv_domain_ops = { + .alloc = uv_domain_alloc, + .free = uv_domain_free, + .activate = uv_domain_activate, + .deactivate = uv_domain_deactivate, +}; -if (cfg->move_in_progress) -send_cleanup_vector (cfg); +static struct irq_domain *uv_get_irq_domain (void ) +{ +static struct irq_domain *uv_domain; +static DEFINE_MUTEX (uv_lock); + +mutex_lock (&uv_lock); +if (uv_domain ==NULL ) { + uv_domain =irq_domain_add_tree (NULL , &uv_domain_ops,NULL ); +if (uv_domain) + uv_domain->parent = x86_vector_domain; + } +mutex_unlock (&uv_lock); -return IRQ_SET_MASK_OK_NOCOPY ; +return uv_domain; }/* @@ -229,23 +181,20 @@ 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;struct irq_alloc_info info; +struct irq_domain *domain =uv_get_irq_domain (); + +if (!domain) +return -ENOMEM ;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, - limit); -if (ret == irq) -uv_set_irq_2_mmr_info (irq, mmr_offset, mmr_blade); -else -irq_domain_free_irqs (irq,1 ); + info.uv_limit = limit; + info.uv_blade = mmr_blade; + info.uv_offset = mmr_offset; + info.uv_name = irq_name; -return ret; +return irq_domain_alloc_irqs (domain,1 , +uv_blade_to_memory_nid (mmr_blade), &info); }EXPORT_SYMBOL_GPL (uv_setup_irq);@@ -258,26 +207,6 @@ EXPORT_SYMBOL_GPL(uv_setup_irq);*/ void uv_teardown_irq (unsigned int irq) { -struct uv_irq_2_mmr_pnode *e; -struct rb_node *n; -unsigned long irqflags; - -spin_lock_irqsave (&uv_irq_lock, irqflags); - n = uv_irq_root.rb_node; -while (n) { - e = rb_entry(n, struct uv_irq_2_mmr_pnode, list); -if (e->irq == irq) { -arch_disable_uv_irq (e->pnode, e->offset); -rb_erase (n, &uv_irq_root); -kfree (e); -break ; - } -if (irq < e->irq) - n = n->rb_left; -else - n = n->rb_right; - } -spin_unlock_irqrestore (&uv_irq_lock, irqflags);irq_domain_free_irqs (irq,1 ); }EXPORT_SYMBOL_GPL (uv_teardown_irq);Signature · 7 lines
1.7.10.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [Patch Part2 v6 22/27] x86, uv: Use hierarchy irqdomain to manage UV interrupts
Quoted 21 lines · Dimitri Sivanich
I answered my own question, this had never been tested on UV.
The gru driver fails with:
SGI GRU Device Driver:uv_setup_irqfailed, errno=22The
info->typeinuv_domain_alloc()is not set toX86_IRQ_ALLOC_TYPE_UV(info->typeis never set to that value anywhere).Adding the following to
uv_setup_irqallows it to work:arch/x86/platform/uv/uv_irq.c +1
-0@@ -187,6 +187,7 @@ int uv_setup_irq(char *irq_name, int cpureturn -ENOMEM ;init_irq_alloc_info (&info,cpumask_of (cpu)); + info.type =X86_IRQ_ALLOC_TYPE_UV ; info.uv_limit = limit; info.uv_blade = mmr_blade; info.uv_offset = mmr_offset;
Quoted 1 line
On Mon, Dec 15, 2014 at 03:37:35PM -0600, Dimitri Sivanich wrote:
Hi Dimitri,
Thanks for reporting and fixing this bug. We will rebase the
tip/x86/apic branch and fold the above patch into the original patch. May I assume a Tested-by from you? I have no UV systems for testing. Regards!
Gerry
Quoted 428 lines
Quoted 417 lines
Was this patch ever tested on a UV system?
Also, adding some SGI folks to the CC list, since there were none listed before.
Quoted 412 lines · Jiang Liu
Enhance UV code to support hierarchy irqdomain, it helps to make the architecture more clear.
We should construct hwirq based on
mmr_bladeandmmr_offset, butmmr_offsetis type of unsigned long, it may exceed the range ofirq_hw_number_t. So help about the way to construct hwirq based onmmr_bladeandmmr_offsetis welcomed!Signed-off-by Jiang Liu <[email protected]>--- arch/x86/include/asm/hw_irq.h | 9 ++ arch/x86/platform/uv/uv_irq.c | 287 ++++++++++++++++------------------------- 2 files changed, 117 insertions(+), 179 deletions(-)arch/x86/include/asm/hw_irq.h +9
-0@@ -123,6 +123,7 @@ enum irq_alloc_type {X86_IRQ_ALLOC_TYPE_MSI ,X86_IRQ_ALLOC_TYPE_MSIX ,X86_IRQ_ALLOC_TYPE_DMAR , + X86_IRQ_ALLOC_TYPE_UV, }; struct irq_alloc_info {@@ -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 +108
-179@@ -19,17 +19,31 @@#include <asm/uv/uv_hub.h> /* MMR offset and pnode of hub sourcing interrupts for a given irq */ -struct uv_irq_2_mmr_pnode { -struct rb_node list; +struct uv_irq_2_mmr_pnode {unsigned long offset;int pnode; -int irq; }; -static DEFINE_SPINLOCK (uv_irq_lock); -static struct rb_root uv_irq_root; +static void uv_program_mmr (struct irq_cfg *cfg,struct uv_irq_2_mmr_pnode *info) +{ +unsigned long mmr_value; +struct uv_IO_APIC_route_entry *entry; + +BUILD_BUG_ON (sizeof (struct uv_IO_APIC_route_entry ) != +sizeof (unsigned long )); + + mmr_value =0 ; + entry = (struct uv_IO_APIC_route_entry *)&mmr_value; + entry->vector = cfg->vector; + entry->delivery_mode = apic->irq_delivery_mode; + entry->dest_mode = apic->irq_dest_mode; + entry->polarity =0 ; + entry->trigger =0 ; + entry->mask =0 ; + entry->dest = cfg->dest_apicid; -static int uv_set_irq_affinity (struct irq_data *,const struct cpumask *,bool ); +uv_write_global_mmr64 (info->pnode, info->offset, mmr_value); +}static void uv_noop (struct irq_data *data) { }@@ -38,6 +52,24 @@ static void uv_ack_apic(struct irq_data *data)ack_APIC_irq (); } +static int +uv_set_irq_affinity (struct irq_data *data,const struct cpumask *mask, +bool force) +{ +struct irq_data *parent = data->parent_data; +struct irq_cfg *cfg =irqd_cfg (data); +int ret; + + ret = parent->chip->irq_set_affinity (parent, mask, force); +if (ret >=0 ) { +uv_program_mmr (cfg, data->chip_data); +if (cfg->move_in_progress) +send_cleanup_vector (cfg); + } + +return ret; +} +static struct irq_chip uv_irq_chip = { .name ="UV-CORE" , .irq_mask = uv_noop,@@ -46,179 +78,99 @@ static struct irq_chip uv_irq_chip = { .irq_set_affinity = uv_set_irq_affinity, }; -/* -* Add offset and pnode information of the hub sourcing interrupts to the -* rb tree for a specific irq. -*/ -static int uv_set_irq_2_mmr_info (int irq,unsigned long offset,unsigned blade) +static int uv_domain_alloc (struct irq_domain *domain,unsigned int virq, +unsigned int nr_irqs,void *arg) { -struct rb_node **link = &uv_irq_root.rb_node; -struct rb_node *parent =NULL ; -struct uv_irq_2_mmr_pnode *n; -struct uv_irq_2_mmr_pnode *e; -unsigned long irqflags; - - n =kmalloc_node (sizeof (struct uv_irq_2_mmr_pnode ),GFP_KERNEL , -uv_blade_to_memory_nid (blade)); -if (!n) +struct uv_irq_2_mmr_pnode *chip_data; +struct irq_alloc_info *info = arg; +struct irq_data *irq_data =irq_domain_get_irq_data (domain, virq); +int ret; + +if (nr_irqs >1 || !info || info->type !=X86_IRQ_ALLOC_TYPE_UV ) +return -EINVAL ; + + chip_data =kmalloc_node (sizeof (*chip_data),GFP_KERNEL , + irq_data->node); +if (!chip_data)return -ENOMEM ; - n->irq = irq; - n->offset = offset; - n->pnode =uv_blade_to_pnode (blade); -spin_lock_irqsave (&uv_irq_lock, irqflags); -/* Find the right place in the rbtree: */ -while (*link) { - parent = *link; - e = rb_entry(parent, struct uv_irq_2_mmr_pnode, list); - -if (unlikely (irq == e->irq)) { -/* irq entry exists */ - e->pnode =uv_blade_to_pnode (blade); - e->offset = offset; -spin_unlock_irqrestore (&uv_irq_lock, irqflags); -kfree (n); -return 0 ; - } - -if (irq < e->irq) - link = &(*link)->rb_left; + ret =irq_domain_alloc_irqs_parent (domain, virq, nr_irqs, arg); +if (ret >=0 ) { +if (info->uv_limit ==UV_AFFINITY_CPU ) +irq_set_status_flags (virq,IRQ_NO_BALANCING );else - link = &(*link)->rb_right; +irq_set_status_flags (virq,IRQ_MOVE_PCNTXT ); + + chip_data->pnode =uv_blade_to_pnode (info->uv_blade); + chip_data->offset = info->uv_offset; +irq_domain_set_info (domain, virq, virq, &uv_irq_chip, chip_data, + handle_percpu_irq,NULL , info->uv_name); + }else { +kfree (chip_data); } -/* Insert the node into the rbtree. */ -rb_link_node (&n->list, parent, link); -rb_insert_color (&n->list, &uv_irq_root); - -spin_unlock_irqrestore (&uv_irq_lock, irqflags); -return 0 ; +return ret; } -/* Retrieve offset and pnode information from the rb tree for a specific irq */ -int uv_irq_2_mmr_info (int irq,unsigned long *offset,int *pnode) +static void uv_domain_free (struct irq_domain *domain,unsigned int virq, +unsigned int nr_irqs) { -struct uv_irq_2_mmr_pnode *e; -struct rb_node *n; -unsigned long irqflags; - -spin_lock_irqsave (&uv_irq_lock, irqflags); - n = uv_irq_root.rb_node; -while (n) { - e = rb_entry(n, struct uv_irq_2_mmr_pnode, list); - -if (e->irq == irq) { - *offset = e->offset; - *pnode = e->pnode; -spin_unlock_irqrestore (&uv_irq_lock, irqflags); -return 0 ; - } - -if (irq < e->irq) - n = n->rb_left; -else - n = n->rb_right; - } -spin_unlock_irqrestore (&uv_irq_lock, irqflags); -return -1 ; +struct irq_data *irq_data =irq_domain_get_irq_data (domain, virq); + +BUG_ON (nr_irqs !=1 ); +kfree (irq_data->chip_data); +irq_clear_status_flags (virq,IRQ_MOVE_PCNTXT ); +irq_clear_status_flags (virq,IRQ_NO_BALANCING ); +irq_domain_free_irqs_top (domain, virq, nr_irqs); }/* * Re-target the irq to the specified CPU and enable the specified MMR located * on the specified blade to allow the sending of MSIs to the specified CPU. */ -static int -arch_enable_uv_irq (char *irq_name,unsigned int irq,int cpu,int mmr_blade, -unsigned long mmr_offset,int limit) +static void uv_domain_activate (struct irq_domain *domain, +struct irq_data *irq_data) { -struct irq_cfg *cfg =irq_cfg (irq); -unsigned long mmr_value; -struct uv_IO_APIC_route_entry *entry; -int mmr_pnode; - -BUILD_BUG_ON (sizeof (struct uv_IO_APIC_route_entry ) != -sizeof (unsigned long )); - -if (limit ==UV_AFFINITY_CPU ) -irq_set_status_flags (irq,IRQ_NO_BALANCING ); -else -irq_set_status_flags (irq,IRQ_MOVE_PCNTXT ); - -irq_set_chip_and_handler_name (irq, &uv_irq_chip, handle_percpu_irq, - irq_name); - - mmr_value =0 ; - entry = (struct uv_IO_APIC_route_entry *)&mmr_value; - entry->vector = cfg->vector; - entry->delivery_mode = apic->irq_delivery_mode; - entry->dest_mode = apic->irq_dest_mode; - entry->polarity =0 ; - entry->trigger =0 ; - entry->mask =0 ; - entry->dest = cfg->dest_apicid; - - mmr_pnode =uv_blade_to_pnode (mmr_blade); -uv_write_global_mmr64 (mmr_pnode, mmr_offset, mmr_value); - -if (cfg->move_in_progress) -send_cleanup_vector (cfg); - -return irq; +uv_program_mmr (irqd_cfg (irq_data), irq_data->chip_data); }/* * Disable the specified MMR located on the specified blade so that MSIs are * longer allowed to be sent. */ -static void arch_disable_uv_irq (int mmr_pnode,unsigned long mmr_offset) +static void uv_domain_deactivate (struct irq_domain *domain, +struct irq_data *irq_data) {unsigned long mmr_value;struct uv_IO_APIC_route_entry *entry; -BUILD_BUG_ON (sizeof (struct uv_IO_APIC_route_entry ) != -sizeof (unsigned long )); - mmr_value =0 ; entry = (struct uv_IO_APIC_route_entry *)&mmr_value; entry->mask =1 ; - -uv_write_global_mmr64 (mmr_pnode, mmr_offset, mmr_value); +uv_program_mmr (irqd_cfg (irq_data), irq_data->chip_data); } -static int -uv_set_irq_affinity (struct irq_data *data,const struct cpumask *mask, -bool force) -{ -struct irq_cfg *cfg =irqd_cfg (data); -unsigned int dest; -unsigned long mmr_value, mmr_offset; -struct uv_IO_APIC_route_entry *entry; -int mmr_pnode; - -if (apic_set_affinity (data, mask, &dest)) -return -1 ; - - mmr_value =0 ; - entry = (struct uv_IO_APIC_route_entry *)&mmr_value; - - entry->vector = cfg->vector; - entry->delivery_mode = apic->irq_delivery_mode; - entry->dest_mode = apic->irq_dest_mode; - entry->polarity =0 ; - entry->trigger =0 ; - entry->mask =0 ; - entry->dest = dest; - -/* Get previously stored MMR and pnode of hub sourcing interrupts */ -if (uv_irq_2_mmr_info (data->irq, &mmr_offset, &mmr_pnode)) -return -1 ; - -uv_write_global_mmr64 (mmr_pnode, mmr_offset, mmr_value); +static struct irq_domain_ops uv_domain_ops = { + .alloc = uv_domain_alloc, + .free = uv_domain_free, + .activate = uv_domain_activate, + .deactivate = uv_domain_deactivate, +}; -if (cfg->move_in_progress) -send_cleanup_vector (cfg); +static struct irq_domain *uv_get_irq_domain (void ) +{ +static struct irq_domain *uv_domain; +static DEFINE_MUTEX (uv_lock); + +mutex_lock (&uv_lock); +if (uv_domain ==NULL ) { + uv_domain =irq_domain_add_tree (NULL , &uv_domain_ops,NULL ); +if (uv_domain) + uv_domain->parent = x86_vector_domain; + } +mutex_unlock (&uv_lock); -return IRQ_SET_MASK_OK_NOCOPY ; +return uv_domain; }/* @@ -229,23 +181,20 @@ 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;struct irq_alloc_info info; +struct irq_domain *domain =uv_get_irq_domain (); + +if (!domain) +return -ENOMEM ;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, - limit); -if (ret == irq) -uv_set_irq_2_mmr_info (irq, mmr_offset, mmr_blade); -else -irq_domain_free_irqs (irq,1 ); + info.uv_limit = limit; + info.uv_blade = mmr_blade; + info.uv_offset = mmr_offset; + info.uv_name = irq_name; -return ret; +return irq_domain_alloc_irqs (domain,1 , +uv_blade_to_memory_nid (mmr_blade), &info); }EXPORT_SYMBOL_GPL (uv_setup_irq);@@ -258,26 +207,6 @@ EXPORT_SYMBOL_GPL(uv_setup_irq);*/ void uv_teardown_irq (unsigned int irq) { -struct uv_irq_2_mmr_pnode *e; -struct rb_node *n; -unsigned long irqflags; - -spin_lock_irqsave (&uv_irq_lock, irqflags); - n = uv_irq_root.rb_node; -while (n) { - e = rb_entry(n, struct uv_irq_2_mmr_pnode, list); -if (e->irq == irq) { -arch_disable_uv_irq (e->pnode, e->offset); -rb_erase (n, &uv_irq_root); -kfree (e); -break ; - } -if (irq < e->irq) - n = n->rb_left; -else - n = n->rb_right; - } -spin_unlock_irqrestore (&uv_irq_lock, irqflags);irq_domain_free_irqs (irq,1 ); }EXPORT_SYMBOL_GPL (uv_teardown_irq);Signature · 1 line
1.7.10.4Quoted 5 lines
Quoted 5 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Re: [Patch Part2 v6 22/27] x86, uv: Use hierarchy irqdomain to manage UV interrupts
Quoted 22 lines · Jiang Liu
Quoted 21 lines · Dimitri Sivanich
I answered my own question, this had never been tested on UV.
The gru driver fails with:
SGI GRU Device Driver:uv_setup_irqfailed, errno=22The
info->typeinuv_domain_alloc()is not set toX86_IRQ_ALLOC_TYPE_UV(info->typeis never set to that value anywhere).Adding the following to
uv_setup_irqallows it to work:arch/x86/platform/uv/uv_irq.c +1
-0@@ -187,6 +187,7 @@ int uv_setup_irq(char *irq_name, int cpureturn -ENOMEM ;init_irq_alloc_info (&info,cpumask_of (cpu)); + info.type =X86_IRQ_ALLOC_TYPE_UV ; info.uv_limit = limit; info.uv_blade = mmr_blade; info.uv_offset = mmr_offset;
Quoted 5 lines
Quoted 1 line · Dimitri Sivanich
Hi Dimitri,
Thanks for reporting and fixing this bug. We will rebase the
tip/x86/apic branch and fold the above patch into the original patch. May I assume a Tested-by from you? I have no UV systems for testing.
287 lines of change in uv_irq.c completely untested in linux-next? Ouch.
Dimitri tested the one line change above, because the driver would not even load without it. It will take some time to look through your extensive changes to understand and verify it works.
Thanks.
Quoted 431 lines
Regards!
GerryQuoted 428 lines
Quoted 417 lines
Was this patch ever tested on a UV system?
Also, adding some SGI folks to the CC list, since there were none listed before.
Quoted 412 lines · Jiang Liu
Enhance UV code to support hierarchy irqdomain, it helps to make the architecture more clear.
We should construct hwirq based on
mmr_bladeandmmr_offset, butmmr_offsetis type of unsigned long, it may exceed the range ofirq_hw_number_t. So help about the way to construct hwirq based onmmr_bladeandmmr_offsetis welcomed!Signed-off-by Jiang Liu <[email protected]>--- arch/x86/include/asm/hw_irq.h | 9 ++ arch/x86/platform/uv/uv_irq.c | 287 ++++++++++++++++------------------------- 2 files changed, 117 insertions(+), 179 deletions(-)arch/x86/include/asm/hw_irq.h +9
-0@@ -123,6 +123,7 @@ enum irq_alloc_type {X86_IRQ_ALLOC_TYPE_MSI ,X86_IRQ_ALLOC_TYPE_MSIX ,X86_IRQ_ALLOC_TYPE_DMAR , + X86_IRQ_ALLOC_TYPE_UV, }; struct irq_alloc_info {@@ -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 +108
-179@@ -19,17 +19,31 @@#include <asm/uv/uv_hub.h> /* MMR offset and pnode of hub sourcing interrupts for a given irq */ -struct uv_irq_2_mmr_pnode { -struct rb_node list; +struct uv_irq_2_mmr_pnode {unsigned long offset;int pnode; -int irq; }; -static DEFINE_SPINLOCK (uv_irq_lock); -static struct rb_root uv_irq_root; +static void uv_program_mmr (struct irq_cfg *cfg,struct uv_irq_2_mmr_pnode *info) +{ +unsigned long mmr_value; +struct uv_IO_APIC_route_entry *entry; + +BUILD_BUG_ON (sizeof (struct uv_IO_APIC_route_entry ) != +sizeof (unsigned long )); + + mmr_value =0 ; + entry = (struct uv_IO_APIC_route_entry *)&mmr_value; + entry->vector = cfg->vector; + entry->delivery_mode = apic->irq_delivery_mode; + entry->dest_mode = apic->irq_dest_mode; + entry->polarity =0 ; + entry->trigger =0 ; + entry->mask =0 ; + entry->dest = cfg->dest_apicid; -static int uv_set_irq_affinity (struct irq_data *,const struct cpumask *,bool ); +uv_write_global_mmr64 (info->pnode, info->offset, mmr_value); +}static void uv_noop (struct irq_data *data) { }@@ -38,6 +52,24 @@ static void uv_ack_apic(struct irq_data *data)ack_APIC_irq (); } +static int +uv_set_irq_affinity (struct irq_data *data,const struct cpumask *mask, +bool force) +{ +struct irq_data *parent = data->parent_data; +struct irq_cfg *cfg =irqd_cfg (data); +int ret; + + ret = parent->chip->irq_set_affinity (parent, mask, force); +if (ret >=0 ) { +uv_program_mmr (cfg, data->chip_data); +if (cfg->move_in_progress) +send_cleanup_vector (cfg); + } + +return ret; +} +static struct irq_chip uv_irq_chip = { .name ="UV-CORE" , .irq_mask = uv_noop,@@ -46,179 +78,99 @@ static struct irq_chip uv_irq_chip = { .irq_set_affinity = uv_set_irq_affinity, }; -/* -* Add offset and pnode information of the hub sourcing interrupts to the -* rb tree for a specific irq. -*/ -static int uv_set_irq_2_mmr_info (int irq,unsigned long offset,unsigned blade) +static int uv_domain_alloc (struct irq_domain *domain,unsigned int virq, +unsigned int nr_irqs,void *arg) { -struct rb_node **link = &uv_irq_root.rb_node; -struct rb_node *parent =NULL ; -struct uv_irq_2_mmr_pnode *n; -struct uv_irq_2_mmr_pnode *e; -unsigned long irqflags; - - n =kmalloc_node (sizeof (struct uv_irq_2_mmr_pnode ),GFP_KERNEL , -uv_blade_to_memory_nid (blade)); -if (!n) +struct uv_irq_2_mmr_pnode *chip_data; +struct irq_alloc_info *info = arg; +struct irq_data *irq_data =irq_domain_get_irq_data (domain, virq); +int ret; + +if (nr_irqs >1 || !info || info->type !=X86_IRQ_ALLOC_TYPE_UV ) +return -EINVAL ; + + chip_data =kmalloc_node (sizeof (*chip_data),GFP_KERNEL , + irq_data->node); +if (!chip_data)return -ENOMEM ; - n->irq = irq; - n->offset = offset; - n->pnode =uv_blade_to_pnode (blade); -spin_lock_irqsave (&uv_irq_lock, irqflags); -/* Find the right place in the rbtree: */ -while (*link) { - parent = *link; - e = rb_entry(parent, struct uv_irq_2_mmr_pnode, list); - -if (unlikely (irq == e->irq)) { -/* irq entry exists */ - e->pnode =uv_blade_to_pnode (blade); - e->offset = offset; -spin_unlock_irqrestore (&uv_irq_lock, irqflags); -kfree (n); -return 0 ; - } - -if (irq < e->irq) - link = &(*link)->rb_left; + ret =irq_domain_alloc_irqs_parent (domain, virq, nr_irqs, arg); +if (ret >=0 ) { +if (info->uv_limit ==UV_AFFINITY_CPU ) +irq_set_status_flags (virq,IRQ_NO_BALANCING );else - link = &(*link)->rb_right; +irq_set_status_flags (virq,IRQ_MOVE_PCNTXT ); + + chip_data->pnode =uv_blade_to_pnode (info->uv_blade); + chip_data->offset = info->uv_offset; +irq_domain_set_info (domain, virq, virq, &uv_irq_chip, chip_data, + handle_percpu_irq,NULL , info->uv_name); + }else { +kfree (chip_data); } -/* Insert the node into the rbtree. */ -rb_link_node (&n->list, parent, link); -rb_insert_color (&n->list, &uv_irq_root); - -spin_unlock_irqrestore (&uv_irq_lock, irqflags); -return 0 ; +return ret; } -/* Retrieve offset and pnode information from the rb tree for a specific irq */ -int uv_irq_2_mmr_info (int irq,unsigned long *offset,int *pnode) +static void uv_domain_free (struct irq_domain *domain,unsigned int virq, +unsigned int nr_irqs) { -struct uv_irq_2_mmr_pnode *e; -struct rb_node *n; -unsigned long irqflags; - -spin_lock_irqsave (&uv_irq_lock, irqflags); - n = uv_irq_root.rb_node; -while (n) { - e = rb_entry(n, struct uv_irq_2_mmr_pnode, list); - -if (e->irq == irq) { - *offset = e->offset; - *pnode = e->pnode; -spin_unlock_irqrestore (&uv_irq_lock, irqflags); -return 0 ; - } - -if (irq < e->irq) - n = n->rb_left; -else - n = n->rb_right; - } -spin_unlock_irqrestore (&uv_irq_lock, irqflags); -return -1 ; +struct irq_data *irq_data =irq_domain_get_irq_data (domain, virq); + +BUG_ON (nr_irqs !=1 ); +kfree (irq_data->chip_data); +irq_clear_status_flags (virq,IRQ_MOVE_PCNTXT ); +irq_clear_status_flags (virq,IRQ_NO_BALANCING ); +irq_domain_free_irqs_top (domain, virq, nr_irqs); }/* * Re-target the irq to the specified CPU and enable the specified MMR located * on the specified blade to allow the sending of MSIs to the specified CPU. */ -static int -arch_enable_uv_irq (char *irq_name,unsigned int irq,int cpu,int mmr_blade, -unsigned long mmr_offset,int limit) +static void uv_domain_activate (struct irq_domain *domain, +struct irq_data *irq_data) { -struct irq_cfg *cfg =irq_cfg (irq); -unsigned long mmr_value; -struct uv_IO_APIC_route_entry *entry; -int mmr_pnode; - -BUILD_BUG_ON (sizeof (struct uv_IO_APIC_route_entry ) != -sizeof (unsigned long )); - -if (limit ==UV_AFFINITY_CPU ) -irq_set_status_flags (irq,IRQ_NO_BALANCING ); -else -irq_set_status_flags (irq,IRQ_MOVE_PCNTXT ); - -irq_set_chip_and_handler_name (irq, &uv_irq_chip, handle_percpu_irq, - irq_name); - - mmr_value =0 ; - entry = (struct uv_IO_APIC_route_entry *)&mmr_value; - entry->vector = cfg->vector; - entry->delivery_mode = apic->irq_delivery_mode; - entry->dest_mode = apic->irq_dest_mode; - entry->polarity =0 ; - entry->trigger =0 ; - entry->mask =0 ; - entry->dest = cfg->dest_apicid; - - mmr_pnode =uv_blade_to_pnode (mmr_blade); -uv_write_global_mmr64 (mmr_pnode, mmr_offset, mmr_value); - -if (cfg->move_in_progress) -send_cleanup_vector (cfg); - -return irq; +uv_program_mmr (irqd_cfg (irq_data), irq_data->chip_data); }/* * Disable the specified MMR located on the specified blade so that MSIs are * longer allowed to be sent. */ -static void arch_disable_uv_irq (int mmr_pnode,unsigned long mmr_offset) +static void uv_domain_deactivate (struct irq_domain *domain, +struct irq_data *irq_data) {unsigned long mmr_value;struct uv_IO_APIC_route_entry *entry; -BUILD_BUG_ON (sizeof (struct uv_IO_APIC_route_entry ) != -sizeof (unsigned long )); - mmr_value =0 ; entry = (struct uv_IO_APIC_route_entry *)&mmr_value; entry->mask =1 ; - -uv_write_global_mmr64 (mmr_pnode, mmr_offset, mmr_value); +uv_program_mmr (irqd_cfg (irq_data), irq_data->chip_data); } -static int -uv_set_irq_affinity (struct irq_data *data,const struct cpumask *mask, -bool force) -{ -struct irq_cfg *cfg =irqd_cfg (data); -unsigned int dest; -unsigned long mmr_value, mmr_offset; -struct uv_IO_APIC_route_entry *entry; -int mmr_pnode; - -if (apic_set_affinity (data, mask, &dest)) -return -1 ; - - mmr_value =0 ; - entry = (struct uv_IO_APIC_route_entry *)&mmr_value; - - entry->vector = cfg->vector; - entry->delivery_mode = apic->irq_delivery_mode; - entry->dest_mode = apic->irq_dest_mode; - entry->polarity =0 ; - entry->trigger =0 ; - entry->mask =0 ; - entry->dest = dest; - -/* Get previously stored MMR and pnode of hub sourcing interrupts */ -if (uv_irq_2_mmr_info (data->irq, &mmr_offset, &mmr_pnode)) -return -1 ; - -uv_write_global_mmr64 (mmr_pnode, mmr_offset, mmr_value); +static struct irq_domain_ops uv_domain_ops = { + .alloc = uv_domain_alloc, + .free = uv_domain_free, + .activate = uv_domain_activate, + .deactivate = uv_domain_deactivate, +}; -if (cfg->move_in_progress) -send_cleanup_vector (cfg); +static struct irq_domain *uv_get_irq_domain (void ) +{ +static struct irq_domain *uv_domain; +static DEFINE_MUTEX (uv_lock); + +mutex_lock (&uv_lock); +if (uv_domain ==NULL ) { + uv_domain =irq_domain_add_tree (NULL , &uv_domain_ops,NULL ); +if (uv_domain) + uv_domain->parent = x86_vector_domain; + } +mutex_unlock (&uv_lock); -return IRQ_SET_MASK_OK_NOCOPY ; +return uv_domain; }/* @@ -229,23 +181,20 @@ 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;struct irq_alloc_info info; +struct irq_domain *domain =uv_get_irq_domain (); + +if (!domain) +return -ENOMEM ;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, - limit); -if (ret == irq) -uv_set_irq_2_mmr_info (irq, mmr_offset, mmr_blade); -else -irq_domain_free_irqs (irq,1 ); + info.uv_limit = limit; + info.uv_blade = mmr_blade; + info.uv_offset = mmr_offset; + info.uv_name = irq_name; -return ret; +return irq_domain_alloc_irqs (domain,1 , +uv_blade_to_memory_nid (mmr_blade), &info); }EXPORT_SYMBOL_GPL (uv_setup_irq);@@ -258,26 +207,6 @@ EXPORT_SYMBOL_GPL(uv_setup_irq);*/ void uv_teardown_irq (unsigned int irq) { -struct uv_irq_2_mmr_pnode *e; -struct rb_node *n; -unsigned long irqflags; - -spin_lock_irqsave (&uv_irq_lock, irqflags); - n = uv_irq_root.rb_node; -while (n) { - e = rb_entry(n, struct uv_irq_2_mmr_pnode, list); -if (e->irq == irq) { -arch_disable_uv_irq (e->pnode, e->offset); -rb_erase (n, &uv_irq_root); -kfree (e); -break ; - } -if (irq < e->irq) - n = n->rb_left; -else - n = n->rb_right; - } -spin_unlock_irqrestore (&uv_irq_lock, irqflags);irq_domain_free_irqs (irq,1 ); }EXPORT_SYMBOL_GPL (uv_teardown_irq);Signature · 1 line
1.7.10.4Quoted 5 lines
Quoted 5 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Signature · 2 lines
Russ Anderson, Kernel and Performance Software Team Manager SGI - Silicon Graphics Inc [email protected]
Re: [Patch Part2 v6 22/27] x86, uv: Use hierarchy irqdomain to manage UV interrupts
Quoted 29 lines · Russ Anderson
Quoted 22 lines · Jiang Liu
Quoted 21 lines · Dimitri Sivanich
I answered my own question, this had never been tested on UV.
The gru driver fails with:
SGI GRU Device Driver:uv_setup_irqfailed, errno=22The
info->typeinuv_domain_alloc()is not set toX86_IRQ_ALLOC_TYPE_UV(info->typeis never set to that value anywhere).Adding the following to
uv_setup_irqallows it to work:arch/x86/platform/uv/uv_irq.c +1
-0@@ -187,6 +187,7 @@ int uv_setup_irq(char *irq_name, int cpureturn -ENOMEM ;init_irq_alloc_info (&info,cpumask_of (cpu)); + info.type =X86_IRQ_ALLOC_TYPE_UV ; info.uv_limit = limit; info.uv_blade = mmr_blade; info.uv_offset = mmr_offset;Quoted 5 lines
Quoted 1 line · Dimitri Sivanich
Hi Dimitri,
Thanks for reporting and fixing this bug. We will rebase the
tip/x86/apic branch and fold the above patch into the original patch. May I assume a Tested-by from you? I have no UV systems for testing.
Quoted 5 lines
287 lines of change in
uv_irq.ccompletely untested in linux-next? Ouch.Dimitri tested the one line change above, because the driver would not even load without it. It will take some time to look through your extensive changes to understand and verify it works.
Hi Anderson,
The whole patch set has been exposed to linux-next through
tip/x86/apic, but not sure why this bug hasn't been discovered. Will Cc you and Dimitri next time.
Regards!
Gerry
Quoted 435 lines
Thanks.
Quoted 431 lines
Regards!
GerryQuoted 428 lines
Quoted 417 lines
Was this patch ever tested on a UV system?
Also, adding some SGI folks to the CC list, since there were none listed before.
Quoted 412 lines · Jiang Liu
Enhance UV code to support hierarchy irqdomain, it helps to make the architecture more clear.
We should construct hwirq based on
mmr_bladeandmmr_offset, butmmr_offsetis type of unsigned long, it may exceed the range ofirq_hw_number_t. So help about the way to construct hwirq based onmmr_bladeandmmr_offsetis welcomed!Signed-off-by Jiang Liu <[email protected]>--- arch/x86/include/asm/hw_irq.h | 9 ++ arch/x86/platform/uv/uv_irq.c | 287 ++++++++++++++++------------------------- 2 files changed, 117 insertions(+), 179 deletions(-)arch/x86/include/asm/hw_irq.h +9
-0@@ -123,6 +123,7 @@ enum irq_alloc_type {X86_IRQ_ALLOC_TYPE_MSI ,X86_IRQ_ALLOC_TYPE_MSIX ,X86_IRQ_ALLOC_TYPE_DMAR , + X86_IRQ_ALLOC_TYPE_UV, }; struct irq_alloc_info {@@ -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 +108
-179@@ -19,17 +19,31 @@#include <asm/uv/uv_hub.h> /* MMR offset and pnode of hub sourcing interrupts for a given irq */ -struct uv_irq_2_mmr_pnode { -struct rb_node list; +struct uv_irq_2_mmr_pnode {unsigned long offset;int pnode; -int irq; }; -static DEFINE_SPINLOCK (uv_irq_lock); -static struct rb_root uv_irq_root; +static void uv_program_mmr (struct irq_cfg *cfg,struct uv_irq_2_mmr_pnode *info) +{ +unsigned long mmr_value; +struct uv_IO_APIC_route_entry *entry; + +BUILD_BUG_ON (sizeof (struct uv_IO_APIC_route_entry ) != +sizeof (unsigned long )); + + mmr_value =0 ; + entry = (struct uv_IO_APIC_route_entry *)&mmr_value; + entry->vector = cfg->vector; + entry->delivery_mode = apic->irq_delivery_mode; + entry->dest_mode = apic->irq_dest_mode; + entry->polarity =0 ; + entry->trigger =0 ; + entry->mask =0 ; + entry->dest = cfg->dest_apicid; -static int uv_set_irq_affinity (struct irq_data *,const struct cpumask *,bool ); +uv_write_global_mmr64 (info->pnode, info->offset, mmr_value); +}static void uv_noop (struct irq_data *data) { }@@ -38,6 +52,24 @@ static void uv_ack_apic(struct irq_data *data)ack_APIC_irq (); } +static int +uv_set_irq_affinity (struct irq_data *data,const struct cpumask *mask, +bool force) +{ +struct irq_data *parent = data->parent_data; +struct irq_cfg *cfg =irqd_cfg (data); +int ret; + + ret = parent->chip->irq_set_affinity (parent, mask, force); +if (ret >=0 ) { +uv_program_mmr (cfg, data->chip_data); +if (cfg->move_in_progress) +send_cleanup_vector (cfg); + } + +return ret; +} +static struct irq_chip uv_irq_chip = { .name ="UV-CORE" , .irq_mask = uv_noop,@@ -46,179 +78,99 @@ static struct irq_chip uv_irq_chip = { .irq_set_affinity = uv_set_irq_affinity, }; -/* -* Add offset and pnode information of the hub sourcing interrupts to the -* rb tree for a specific irq. -*/ -static int uv_set_irq_2_mmr_info (int irq,unsigned long offset,unsigned blade) +static int uv_domain_alloc (struct irq_domain *domain,unsigned int virq, +unsigned int nr_irqs,void *arg) { -struct rb_node **link = &uv_irq_root.rb_node; -struct rb_node *parent =NULL ; -struct uv_irq_2_mmr_pnode *n; -struct uv_irq_2_mmr_pnode *e; -unsigned long irqflags; - - n =kmalloc_node (sizeof (struct uv_irq_2_mmr_pnode ),GFP_KERNEL , -uv_blade_to_memory_nid (blade)); -if (!n) +struct uv_irq_2_mmr_pnode *chip_data; +struct irq_alloc_info *info = arg; +struct irq_data *irq_data =irq_domain_get_irq_data (domain, virq); +int ret; + +if (nr_irqs >1 || !info || info->type !=X86_IRQ_ALLOC_TYPE_UV ) +return -EINVAL ; + + chip_data =kmalloc_node (sizeof (*chip_data),GFP_KERNEL , + irq_data->node); +if (!chip_data)return -ENOMEM ; - n->irq = irq; - n->offset = offset; - n->pnode =uv_blade_to_pnode (blade); -spin_lock_irqsave (&uv_irq_lock, irqflags); -/* Find the right place in the rbtree: */ -while (*link) { - parent = *link; - e = rb_entry(parent, struct uv_irq_2_mmr_pnode, list); - -if (unlikely (irq == e->irq)) { -/* irq entry exists */ - e->pnode =uv_blade_to_pnode (blade); - e->offset = offset; -spin_unlock_irqrestore (&uv_irq_lock, irqflags); -kfree (n); -return 0 ; - } - -if (irq < e->irq) - link = &(*link)->rb_left; + ret =irq_domain_alloc_irqs_parent (domain, virq, nr_irqs, arg); +if (ret >=0 ) { +if (info->uv_limit ==UV_AFFINITY_CPU ) +irq_set_status_flags (virq,IRQ_NO_BALANCING );else - link = &(*link)->rb_right; +irq_set_status_flags (virq,IRQ_MOVE_PCNTXT ); + + chip_data->pnode =uv_blade_to_pnode (info->uv_blade); + chip_data->offset = info->uv_offset; +irq_domain_set_info (domain, virq, virq, &uv_irq_chip, chip_data, + handle_percpu_irq,NULL , info->uv_name); + }else { +kfree (chip_data); } -/* Insert the node into the rbtree. */ -rb_link_node (&n->list, parent, link); -rb_insert_color (&n->list, &uv_irq_root); - -spin_unlock_irqrestore (&uv_irq_lock, irqflags); -return 0 ; +return ret; } -/* Retrieve offset and pnode information from the rb tree for a specific irq */ -int uv_irq_2_mmr_info (int irq,unsigned long *offset,int *pnode) +static void uv_domain_free (struct irq_domain *domain,unsigned int virq, +unsigned int nr_irqs) { -struct uv_irq_2_mmr_pnode *e; -struct rb_node *n; -unsigned long irqflags; - -spin_lock_irqsave (&uv_irq_lock, irqflags); - n = uv_irq_root.rb_node; -while (n) { - e = rb_entry(n, struct uv_irq_2_mmr_pnode, list); - -if (e->irq == irq) { - *offset = e->offset; - *pnode = e->pnode; -spin_unlock_irqrestore (&uv_irq_lock, irqflags); -return 0 ; - } - -if (irq < e->irq) - n = n->rb_left; -else - n = n->rb_right; - } -spin_unlock_irqrestore (&uv_irq_lock, irqflags); -return -1 ; +struct irq_data *irq_data =irq_domain_get_irq_data (domain, virq); + +BUG_ON (nr_irqs !=1 ); +kfree (irq_data->chip_data); +irq_clear_status_flags (virq,IRQ_MOVE_PCNTXT ); +irq_clear_status_flags (virq,IRQ_NO_BALANCING ); +irq_domain_free_irqs_top (domain, virq, nr_irqs); }/* * Re-target the irq to the specified CPU and enable the specified MMR located * on the specified blade to allow the sending of MSIs to the specified CPU. */ -static int -arch_enable_uv_irq (char *irq_name,unsigned int irq,int cpu,int mmr_blade, -unsigned long mmr_offset,int limit) +static void uv_domain_activate (struct irq_domain *domain, +struct irq_data *irq_data) { -struct irq_cfg *cfg =irq_cfg (irq); -unsigned long mmr_value; -struct uv_IO_APIC_route_entry *entry; -int mmr_pnode; - -BUILD_BUG_ON (sizeof (struct uv_IO_APIC_route_entry ) != -sizeof (unsigned long )); - -if (limit ==UV_AFFINITY_CPU ) -irq_set_status_flags (irq,IRQ_NO_BALANCING ); -else -irq_set_status_flags (irq,IRQ_MOVE_PCNTXT ); - -irq_set_chip_and_handler_name (irq, &uv_irq_chip, handle_percpu_irq, - irq_name); - - mmr_value =0 ; - entry = (struct uv_IO_APIC_route_entry *)&mmr_value; - entry->vector = cfg->vector; - entry->delivery_mode = apic->irq_delivery_mode; - entry->dest_mode = apic->irq_dest_mode; - entry->polarity =0 ; - entry->trigger =0 ; - entry->mask =0 ; - entry->dest = cfg->dest_apicid; - - mmr_pnode =uv_blade_to_pnode (mmr_blade); -uv_write_global_mmr64 (mmr_pnode, mmr_offset, mmr_value); - -if (cfg->move_in_progress) -send_cleanup_vector (cfg); - -return irq; +uv_program_mmr (irqd_cfg (irq_data), irq_data->chip_data); }/* * Disable the specified MMR located on the specified blade so that MSIs are * longer allowed to be sent. */ -static void arch_disable_uv_irq (int mmr_pnode,unsigned long mmr_offset) +static void uv_domain_deactivate (struct irq_domain *domain, +struct irq_data *irq_data) {unsigned long mmr_value;struct uv_IO_APIC_route_entry *entry; -BUILD_BUG_ON (sizeof (struct uv_IO_APIC_route_entry ) != -sizeof (unsigned long )); - mmr_value =0 ; entry = (struct uv_IO_APIC_route_entry *)&mmr_value; entry->mask =1 ; - -uv_write_global_mmr64 (mmr_pnode, mmr_offset, mmr_value); +uv_program_mmr (irqd_cfg (irq_data), irq_data->chip_data); } -static int -uv_set_irq_affinity (struct irq_data *data,const struct cpumask *mask, -bool force) -{ -struct irq_cfg *cfg =irqd_cfg (data); -unsigned int dest; -unsigned long mmr_value, mmr_offset; -struct uv_IO_APIC_route_entry *entry; -int mmr_pnode; - -if (apic_set_affinity (data, mask, &dest)) -return -1 ; - - mmr_value =0 ; - entry = (struct uv_IO_APIC_route_entry *)&mmr_value; - - entry->vector = cfg->vector; - entry->delivery_mode = apic->irq_delivery_mode; - entry->dest_mode = apic->irq_dest_mode; - entry->polarity =0 ; - entry->trigger =0 ; - entry->mask =0 ; - entry->dest = dest; - -/* Get previously stored MMR and pnode of hub sourcing interrupts */ -if (uv_irq_2_mmr_info (data->irq, &mmr_offset, &mmr_pnode)) -return -1 ; - -uv_write_global_mmr64 (mmr_pnode, mmr_offset, mmr_value); +static struct irq_domain_ops uv_domain_ops = { + .alloc = uv_domain_alloc, + .free = uv_domain_free, + .activate = uv_domain_activate, + .deactivate = uv_domain_deactivate, +}; -if (cfg->move_in_progress) -send_cleanup_vector (cfg); +static struct irq_domain *uv_get_irq_domain (void ) +{ +static struct irq_domain *uv_domain; +static DEFINE_MUTEX (uv_lock); + +mutex_lock (&uv_lock); +if (uv_domain ==NULL ) { + uv_domain =irq_domain_add_tree (NULL , &uv_domain_ops,NULL ); +if (uv_domain) + uv_domain->parent = x86_vector_domain; + } +mutex_unlock (&uv_lock); -return IRQ_SET_MASK_OK_NOCOPY ; +return uv_domain; }/* @@ -229,23 +181,20 @@ 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;struct irq_alloc_info info; +struct irq_domain *domain =uv_get_irq_domain (); + +if (!domain) +return -ENOMEM ;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, - limit); -if (ret == irq) -uv_set_irq_2_mmr_info (irq, mmr_offset, mmr_blade); -else -irq_domain_free_irqs (irq,1 ); + info.uv_limit = limit; + info.uv_blade = mmr_blade; + info.uv_offset = mmr_offset; + info.uv_name = irq_name; -return ret; +return irq_domain_alloc_irqs (domain,1 , +uv_blade_to_memory_nid (mmr_blade), &info); }EXPORT_SYMBOL_GPL (uv_setup_irq);@@ -258,26 +207,6 @@ EXPORT_SYMBOL_GPL(uv_setup_irq);*/ void uv_teardown_irq (unsigned int irq) { -struct uv_irq_2_mmr_pnode *e; -struct rb_node *n; -unsigned long irqflags; - -spin_lock_irqsave (&uv_irq_lock, irqflags); - n = uv_irq_root.rb_node; -while (n) { - e = rb_entry(n, struct uv_irq_2_mmr_pnode, list); -if (e->irq == irq) { -arch_disable_uv_irq (e->pnode, e->offset); -rb_erase (n, &uv_irq_root); -kfree (e); -break ; - } -if (irq < e->irq) - n = n->rb_left; -else - n = n->rb_right; - } -spin_unlock_irqrestore (&uv_irq_lock, irqflags);irq_domain_free_irqs (irq,1 ); }EXPORT_SYMBOL_GPL (uv_teardown_irq);Signature · 1 line
1.7.10.4Quoted 5 lines
Quoted 5 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
PATCH v6 23/27 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
tip-bot for Jiang Liu
merge bot[tip:x86/apic] x86, irq: Normalize x86 irq_chip name
x86, irq: Normalize x86 irq_chip name
Commit-ID: 179f77471f9654cc18693d6502fbc7ce075ed765 Gitweb: http://git.kernel.org/tip/179f77471f9654cc18693d6502fbc7ce075ed765 Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:32 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:26 +0100
x86, irq: Normalize x86 irq_chip name
Some 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,
PATCH v6 24/27 x86, PCI/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
tip-bot for Jiang Liu
merge bot[tip:x86/apic] x86, PCI/MSI: Simplify the way to deal with remapped MSI interrupts
x86, PCI/MSI: Simplify the way to deal with remapped MSI interrupts
Commit-ID: 7fa48d748b0871b91263b57a0ca119a7e972d29a Gitweb: http://git.kernel.org/tip/7fa48d748b0871b91263b57a0ca119a7e972d29a Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:33 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:26 +0100
x86, PCI/MSI: Simplify the way to deal with remapped MSI interrupts
Simplify 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);
PATCH v6 25/27 PCI/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
tip-bot for Jiang Liu
merge bot[tip:x86/apic] PCI/MSI: Replace msi_update_msg() with irq_chip_compose_msi_msg()
PCI/MSI: Replace msi_update_msg() with irq_chip_compose_msi_msg()
Commit-ID: 51911edac211c75cef7c95d4874e2b1f77134a85 Gitweb: http://git.kernel.org/tip/51911edac211c75cef7c95d4874e2b1f77134a85 Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:34 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:26 +0100
PCI/MSI: Replace msi_update_msg() with irq_chip_compose_msi_msg()
Function 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); }
PATCH v6 26/27 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
tip-bot for Jiang Liu
merge bot[tip:x86/apic] x86, irq: Implement irq_chip.irq_write_msi_msg for MSI/DMAR/HPET irq_chips
x86, irq: Implement irq_chip.irq_write_msi_msg for MSI/DMAR/HPET irq_chips
Commit-ID: 232d47f45baeb4a6784503b9bffd7c8e78b400b1 Gitweb: http://git.kernel.org/tip/232d47f45baeb4a6784503b9bffd7c8e78b400b1 Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:35 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:26 +0100
x86, irq: Implement irq_chip.irq_write_msi_msg for MSI/DMAR/HPET irq_chips
Implement 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, };
PATCH v6 27/27 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
tip-bot for Jiang Liu
merge bot[tip:x86/apic] x86, irq: Simplify MSI/DMAR/ HPET implementation by using common code
x86, irq: Simplify MSI/DMAR/HPET implementation by using common code
Commit-ID: 8590d1fd22caf31a81deb3d526f6817288780ffc Gitweb: http://git.kernel.org/tip/8590d1fd22caf31a81deb3d526f6817288780ffc Author: Jiang Liu <[email protected]> AuthorDate: Tue, 25 Nov 2014 13:53:36 +0800 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 26 Nov 2014 18:59:26 +0100
x86, irq: Simplify MSI/DMAR/HPET implementation by using common code
Use 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,