aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiang Liu <jiang.liu@linux.intel.com>2014-06-09 04:19:58 -0400
committerThomas Gleixner <tglx@linutronix.de>2014-06-21 17:05:43 -0400
commit15a3c7cc9154321fc3ed1f7738bb7bbe690af91d (patch)
treed49ed8ee8696ad34921579c5a9ae872d77a8213f
parentfacd8fdb25fc4d041a283446cfb040cbfe2c3723 (diff)
x86, irq: Introduce two helper functions to support irqdomain map operation
Currently there are multiple entries to program IOAPIC pins, such as io_apic_setup_irq_pin_once(), io_apic_set_pci_routing() and setup_IO_APIC_irq_extra() etc. This patch introduces two functions to help consolidate the code to program IOAPIC pins. Function mp_set_pin_attr() is used to optionally set trigger, polarity and NUMA node property for an IOAPIC pin. If mp_set_pin_attr() is not invoked for a pin, the default configuration from BIOS will be used. Function mp_irqdomain_map() is an common implementation of irqdomain map() operation. It figures out attribures for pin and then actually programs the IOAPIC pin. We hope this will be the only entrance for programming IOAPIC pin. And the flow will: 1) caller such as xxx_pci_irq_enable figures out pin attributes. 2) Invoke mp_set_pin_attr() to set attributes for a pin. If the pin has already bin programmed, mp_set_pin_attr() will aslo detects attribute confictions. 3) Invoke mp_map_pin_to_irq() 3.1) If IRQ has already been assigned, return irq_find_mapping() 3.2) Else irq_create_mapping() ->irq_domain_associate() ->mp_irqdomain_map() ->io_apic_setup_irq_pin() So every pin will only programmed once by mp_irqdomain_map(), so we could kill io_apic_setup_irq_pin_once(), io_apic_set_pci_routing() and setup_IO_APIC_irq_extra() etc. Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com> Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Cc: Tony Luck <tony.luck@intel.com> Cc: Joerg Roedel <joro@8bytes.org> Cc: Paul Gortmaker <paul.gortmaker@windriver.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Grant Likely <grant.likely@linaro.org> Cc: Rafael J. Wysocki <rjw@rjwysocki.net> Cc: Bjorn Helgaas <bhelgaas@google.com> Cc: Randy Dunlap <rdunlap@infradead.org> Cc: Yinghai Lu <yinghai@kernel.org> Link: http://lkml.kernel.org/r/1402302011-23642-30-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--arch/x86/include/asm/io_apic.h5
-rw-r--r--arch/x86/kernel/apic/io_apic.c99
2 files changed, 103 insertions, 1 deletions
diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h
index 3e4bea3a52b1..c53587868590 100644
--- a/arch/x86/include/asm/io_apic.h
+++ b/arch/x86/include/asm/io_apic.h
@@ -173,7 +173,9 @@ enum ioapic_domain_type {
173}; 173};
174 174
175struct device_node; 175struct device_node;
176struct irq_domain;
176struct irq_domain_ops; 177struct irq_domain_ops;
178
177struct ioapic_domain_cfg { 179struct ioapic_domain_cfg {
178 enum ioapic_domain_type type; 180 enum ioapic_domain_type type;
179 const struct irq_domain_ops *ops; 181 const struct irq_domain_ops *ops;
@@ -192,6 +194,9 @@ extern u32 mp_pin_to_gsi(int ioapic, int pin);
192extern int mp_map_gsi_to_irq(u32 gsi, unsigned int flags); 194extern int mp_map_gsi_to_irq(u32 gsi, unsigned int flags);
193extern void __init mp_register_ioapic(int id, u32 address, u32 gsi_base, 195extern void __init mp_register_ioapic(int id, u32 address, u32 gsi_base,
194 struct ioapic_domain_cfg *cfg); 196 struct ioapic_domain_cfg *cfg);
197extern int mp_irqdomain_map(struct irq_domain *domain, unsigned int virq,
198 irq_hw_number_t hwirq);
199extern int mp_set_gsi_attr(u32 gsi, int trigger, int polarity, int node);
195extern void __init pre_init_apic_IRQ0(void); 200extern void __init pre_init_apic_IRQ0(void);
196 201
197extern void mp_save_irq(struct mpc_intsrc *m); 202extern void mp_save_irq(struct mpc_intsrc *m);
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 563f4504f54d..a602b35bcfe7 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -87,6 +87,14 @@ static DEFINE_RAW_SPINLOCK(vector_lock);
87static DEFINE_MUTEX(ioapic_mutex); 87static DEFINE_MUTEX(ioapic_mutex);
88static unsigned int ioapic_dynirq_base; 88static unsigned int ioapic_dynirq_base;
89 89
90struct mp_pin_info {
91 int trigger;
92 int polarity;
93 int node;
94 int set;
95 u32 count;
96};
97
90static struct ioapic { 98static struct ioapic {
91 /* 99 /*
92 * # of IRQ routing registers 100 * # of IRQ routing registers
@@ -102,6 +110,7 @@ static struct ioapic {
102 struct mp_ioapic_gsi gsi_config; 110 struct mp_ioapic_gsi gsi_config;
103 struct ioapic_domain_cfg irqdomain_cfg; 111 struct ioapic_domain_cfg irqdomain_cfg;
104 struct irq_domain *irqdomain; 112 struct irq_domain *irqdomain;
113 struct mp_pin_info *pin_info;
105 DECLARE_BITMAP(pin_programmed, MP_MAX_IOAPIC_PIN + 1); 114 DECLARE_BITMAP(pin_programmed, MP_MAX_IOAPIC_PIN + 1);
106} ioapics[MAX_IO_APICS]; 115} ioapics[MAX_IO_APICS];
107 116
@@ -147,6 +156,11 @@ static inline int mp_init_irq_at_boot(int ioapic, int irq)
147 return ioapic == 0 || (irq >= 0 && irq < nr_legacy_irqs()); 156 return ioapic == 0 || (irq >= 0 && irq < nr_legacy_irqs());
148} 157}
149 158
159static inline struct mp_pin_info *mp_pin_info(int ioapic_idx, int pin)
160{
161 return ioapics[ioapic_idx].pin_info + pin;
162}
163
150static inline struct irq_domain *mp_ioapic_irqdomain(int ioapic) 164static inline struct irq_domain *mp_ioapic_irqdomain(int ioapic)
151{ 165{
152 return ioapics[ioapic].irqdomain; 166 return ioapics[ioapic].irqdomain;
@@ -1006,6 +1020,7 @@ static int mp_map_pin_to_irq(u32 gsi, int idx, int ioapic, int pin,
1006{ 1020{
1007 int irq; 1021 int irq;
1008 struct irq_domain *domain = mp_ioapic_irqdomain(ioapic); 1022 struct irq_domain *domain = mp_ioapic_irqdomain(ioapic);
1023 struct mp_pin_info *info = mp_pin_info(ioapic, pin);
1009 1024
1010 /* 1025 /*
1011 * Don't use irqdomain to manage ISA IRQs because there may be 1026 * Don't use irqdomain to manage ISA IRQs because there may be
@@ -1034,6 +1049,13 @@ static int mp_map_pin_to_irq(u32 gsi, int idx, int ioapic, int pin,
1034 irq = irq_find_mapping(domain, pin); 1049 irq = irq_find_mapping(domain, pin);
1035 if (irq <= 0 && (flags & IOAPIC_MAP_ALLOC)) 1050 if (irq <= 0 && (flags & IOAPIC_MAP_ALLOC))
1036 irq = alloc_irq_from_domain(domain, gsi, pin); 1051 irq = alloc_irq_from_domain(domain, gsi, pin);
1052
1053 if (flags & IOAPIC_MAP_ALLOC) {
1054 if (irq > 0)
1055 info->count++;
1056 else if (info->count == 0)
1057 info->set = 0;
1058 }
1037 mutex_unlock(&ioapic_mutex); 1059 mutex_unlock(&ioapic_mutex);
1038 1060
1039 return irq > 0 ? irq : -1; 1061 return irq > 0 ? irq : -1;
@@ -2923,18 +2945,27 @@ out:
2923 2945
2924static int mp_irqdomain_create(int ioapic) 2946static int mp_irqdomain_create(int ioapic)
2925{ 2947{
2948 size_t size;
2926 int hwirqs = mp_ioapic_pin_count(ioapic); 2949 int hwirqs = mp_ioapic_pin_count(ioapic);
2927 struct ioapic *ip = &ioapics[ioapic]; 2950 struct ioapic *ip = &ioapics[ioapic];
2928 struct ioapic_domain_cfg *cfg = &ip->irqdomain_cfg; 2951 struct ioapic_domain_cfg *cfg = &ip->irqdomain_cfg;
2929 struct mp_ioapic_gsi *gsi_cfg = mp_ioapic_gsi_routing(ioapic); 2952 struct mp_ioapic_gsi *gsi_cfg = mp_ioapic_gsi_routing(ioapic);
2930 2953
2954 size = sizeof(struct mp_pin_info) * mp_ioapic_pin_count(ioapic);
2955 ip->pin_info = kzalloc(size, GFP_KERNEL);
2956 if (!ip->pin_info)
2957 return -ENOMEM;
2958
2931 if (cfg->type == IOAPIC_DOMAIN_INVALID) 2959 if (cfg->type == IOAPIC_DOMAIN_INVALID)
2932 return 0; 2960 return 0;
2933 2961
2934 ip->irqdomain = irq_domain_add_linear(cfg->dev, hwirqs, cfg->ops, 2962 ip->irqdomain = irq_domain_add_linear(cfg->dev, hwirqs, cfg->ops,
2935 (void *)(long)ioapic); 2963 (void *)(long)ioapic);
2936 if(!ip->irqdomain) 2964 if(!ip->irqdomain) {
2965 kfree(ip->pin_info);
2966 ip->pin_info = NULL;
2937 return -ENOMEM; 2967 return -ENOMEM;
2968 }
2938 2969
2939 if (cfg->type == IOAPIC_DOMAIN_LEGACY || 2970 if (cfg->type == IOAPIC_DOMAIN_LEGACY ||
2940 cfg->type == IOAPIC_DOMAIN_STRICT) 2971 cfg->type == IOAPIC_DOMAIN_STRICT)
@@ -3902,6 +3933,72 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base,
3902 nr_ioapics++; 3933 nr_ioapics++;
3903} 3934}
3904 3935
3936int mp_irqdomain_map(struct irq_domain *domain, unsigned int virq,
3937 irq_hw_number_t hwirq)
3938{
3939 int ioapic = (int)(long)domain->host_data;
3940 struct mp_pin_info *info = mp_pin_info(ioapic, hwirq);
3941 struct io_apic_irq_attr attr;
3942
3943 /*
3944 * Skip the timer IRQ if there's a quirk handler installed and if it
3945 * returns 1:
3946 */
3947 if (apic->multi_timer_check &&
3948 apic->multi_timer_check(ioapic, virq))
3949 return 0;
3950
3951 /* Get default attribute if not set by caller yet */
3952 if (!info->set) {
3953 u32 gsi = mp_pin_to_gsi(ioapic, hwirq);
3954
3955 if (acpi_get_override_irq(gsi, &info->trigger,
3956 &info->polarity) < 0) {
3957 /*
3958 * PCI interrupts are always polarity one level
3959 * triggered.
3960 */
3961 info->trigger = 1;
3962 info->polarity = 1;
3963 }
3964 info->node = NUMA_NO_NODE;
3965 info->set = 1;
3966 }
3967 set_io_apic_irq_attr(&attr, ioapic, hwirq, info->trigger,
3968 info->polarity);
3969
3970 return io_apic_setup_irq_pin(virq, info->node, &attr);
3971}
3972
3973int mp_set_gsi_attr(u32 gsi, int trigger, int polarity, int node)
3974{
3975 int ret = 0;
3976 int ioapic, pin;
3977 struct mp_pin_info *info;
3978
3979 ioapic = mp_find_ioapic(gsi);
3980 if (ioapic < 0)
3981 return -ENODEV;
3982
3983 pin = mp_find_ioapic_pin(ioapic, gsi);
3984 info = mp_pin_info(ioapic, pin);
3985 trigger = trigger ? 1 : 0;
3986 polarity = polarity ? 1 : 0;
3987
3988 mutex_lock(&ioapic_mutex);
3989 if (!info->set) {
3990 info->trigger = trigger;
3991 info->polarity = polarity;
3992 info->node = node;
3993 info->set = 1;
3994 } else if (info->trigger != trigger || info->polarity != polarity) {
3995 ret = -EBUSY;
3996 }
3997 mutex_unlock(&ioapic_mutex);
3998
3999 return ret;
4000}
4001
3905/* Enable IOAPIC early just for system timer */ 4002/* Enable IOAPIC early just for system timer */
3906void __init pre_init_apic_IRQ0(void) 4003void __init pre_init_apic_IRQ0(void)
3907{ 4004{