aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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{