diff options
-rw-r--r-- | arch/x86/include/asm/io_apic.h | 5 | ||||
-rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 99 |
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 | ||
175 | struct device_node; | 175 | struct device_node; |
176 | struct irq_domain; | ||
176 | struct irq_domain_ops; | 177 | struct irq_domain_ops; |
178 | |||
177 | struct ioapic_domain_cfg { | 179 | struct 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); | |||
192 | extern int mp_map_gsi_to_irq(u32 gsi, unsigned int flags); | 194 | extern int mp_map_gsi_to_irq(u32 gsi, unsigned int flags); |
193 | extern void __init mp_register_ioapic(int id, u32 address, u32 gsi_base, | 195 | extern void __init mp_register_ioapic(int id, u32 address, u32 gsi_base, |
194 | struct ioapic_domain_cfg *cfg); | 196 | struct ioapic_domain_cfg *cfg); |
197 | extern int mp_irqdomain_map(struct irq_domain *domain, unsigned int virq, | ||
198 | irq_hw_number_t hwirq); | ||
199 | extern int mp_set_gsi_attr(u32 gsi, int trigger, int polarity, int node); | ||
195 | extern void __init pre_init_apic_IRQ0(void); | 200 | extern void __init pre_init_apic_IRQ0(void); |
196 | 201 | ||
197 | extern void mp_save_irq(struct mpc_intsrc *m); | 202 | extern 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); | |||
87 | static DEFINE_MUTEX(ioapic_mutex); | 87 | static DEFINE_MUTEX(ioapic_mutex); |
88 | static unsigned int ioapic_dynirq_base; | 88 | static unsigned int ioapic_dynirq_base; |
89 | 89 | ||
90 | struct mp_pin_info { | ||
91 | int trigger; | ||
92 | int polarity; | ||
93 | int node; | ||
94 | int set; | ||
95 | u32 count; | ||
96 | }; | ||
97 | |||
90 | static struct ioapic { | 98 | static 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 | ||
159 | static inline struct mp_pin_info *mp_pin_info(int ioapic_idx, int pin) | ||
160 | { | ||
161 | return ioapics[ioapic_idx].pin_info + pin; | ||
162 | } | ||
163 | |||
150 | static inline struct irq_domain *mp_ioapic_irqdomain(int ioapic) | 164 | static 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 | ||
2924 | static int mp_irqdomain_create(int ioapic) | 2946 | static 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 | ||
3936 | int 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 | |||
3973 | int 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 */ |
3906 | void __init pre_init_apic_IRQ0(void) | 4003 | void __init pre_init_apic_IRQ0(void) |
3907 | { | 4004 | { |