diff options
author | Jiang Liu <jiang.liu@linux.intel.com> | 2014-06-09 04:20:06 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2014-06-21 17:05:44 -0400 |
commit | df334bead7e94772c41745af9f329383067d44ae (patch) | |
tree | 54b2a66608d15d87c3235ca17ecc0c436f5b9e6d | |
parent | 16ee7b3dcc56be14b9a813612cff2cc2339cdced (diff) |
x86, irq: Introduce helper functions to release IOAPIC pin
Introduce function mp_unmap_irq() to release IOAPIC IRQ when IRQ is not
used any more, which will typically called by pcibios_disabled_irq.
And function mp_irqdomain_unmap() is a common implementation of
irq_domain_ops.unmap for IOAPIC.
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-38-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.h | 3 | ||||
-rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 61 |
2 files changed, 64 insertions, 0 deletions
diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h index af6f9d4309bf..0aeed5ca356e 100644 --- a/arch/x86/include/asm/io_apic.h +++ b/arch/x86/include/asm/io_apic.h | |||
@@ -187,10 +187,12 @@ extern int mp_find_ioapic(u32 gsi); | |||
187 | extern int mp_find_ioapic_pin(int ioapic, u32 gsi); | 187 | extern int mp_find_ioapic_pin(int ioapic, u32 gsi); |
188 | extern u32 mp_pin_to_gsi(int ioapic, int pin); | 188 | extern u32 mp_pin_to_gsi(int ioapic, int pin); |
189 | extern int mp_map_gsi_to_irq(u32 gsi, unsigned int flags); | 189 | extern int mp_map_gsi_to_irq(u32 gsi, unsigned int flags); |
190 | extern void mp_unmap_irq(int irq); | ||
190 | extern void __init mp_register_ioapic(int id, u32 address, u32 gsi_base, | 191 | extern void __init mp_register_ioapic(int id, u32 address, u32 gsi_base, |
191 | struct ioapic_domain_cfg *cfg); | 192 | struct ioapic_domain_cfg *cfg); |
192 | extern int mp_irqdomain_map(struct irq_domain *domain, unsigned int virq, | 193 | extern int mp_irqdomain_map(struct irq_domain *domain, unsigned int virq, |
193 | irq_hw_number_t hwirq); | 194 | irq_hw_number_t hwirq); |
195 | extern void mp_irqdomain_unmap(struct irq_domain *domain, unsigned int virq); | ||
194 | extern int mp_set_gsi_attr(u32 gsi, int trigger, int polarity, int node); | 196 | extern int mp_set_gsi_attr(u32 gsi, int trigger, int polarity, int node); |
195 | extern void __init pre_init_apic_IRQ0(void); | 197 | extern void __init pre_init_apic_IRQ0(void); |
196 | 198 | ||
@@ -234,6 +236,7 @@ static inline void ioapic_insert_resources(void) { } | |||
234 | static inline int mp_find_ioapic(u32 gsi) { return 0; } | 236 | static inline int mp_find_ioapic(u32 gsi) { return 0; } |
235 | static inline u32 mp_pin_to_gsi(int ioapic, int pin) { return UINT_MAX; } | 237 | static inline u32 mp_pin_to_gsi(int ioapic, int pin) { return UINT_MAX; } |
236 | static inline int mp_map_gsi_to_irq(u32 gsi, unsigned int flags) { return gsi; } | 238 | static inline int mp_map_gsi_to_irq(u32 gsi, unsigned int flags) { return gsi; } |
239 | static inline void mp_unmap_irq(int irq) { } | ||
237 | 240 | ||
238 | static inline int save_ioapic_entries(void) | 241 | static inline int save_ioapic_entries(void) |
239 | { | 242 | { |
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 8485d904b653..8d80a8f1d670 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
@@ -467,6 +467,21 @@ static int __add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pi | |||
467 | return 0; | 467 | return 0; |
468 | } | 468 | } |
469 | 469 | ||
470 | static void __remove_pin_from_irq(struct irq_cfg *cfg, int apic, int pin) | ||
471 | { | ||
472 | struct irq_pin_list **last, *entry; | ||
473 | |||
474 | last = &cfg->irq_2_pin; | ||
475 | for_each_irq_pin(entry, cfg->irq_2_pin) | ||
476 | if (entry->apic == apic && entry->pin == pin) { | ||
477 | *last = entry->next; | ||
478 | kfree(entry); | ||
479 | return; | ||
480 | } else { | ||
481 | last = &entry->next; | ||
482 | } | ||
483 | } | ||
484 | |||
470 | static void add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin) | 485 | static void add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin) |
471 | { | 486 | { |
472 | if (__add_pin_to_irq_node(cfg, node, apic, pin)) | 487 | if (__add_pin_to_irq_node(cfg, node, apic, pin)) |
@@ -1119,6 +1134,31 @@ int mp_map_gsi_to_irq(u32 gsi, unsigned int flags) | |||
1119 | return mp_map_pin_to_irq(gsi, idx, ioapic, pin, flags); | 1134 | return mp_map_pin_to_irq(gsi, idx, ioapic, pin, flags); |
1120 | } | 1135 | } |
1121 | 1136 | ||
1137 | void mp_unmap_irq(int irq) | ||
1138 | { | ||
1139 | struct irq_data *data = irq_get_irq_data(irq); | ||
1140 | struct mp_pin_info *info; | ||
1141 | int ioapic, pin; | ||
1142 | |||
1143 | if (!data || !data->domain) | ||
1144 | return; | ||
1145 | |||
1146 | ioapic = (int)(long)data->domain->host_data; | ||
1147 | pin = (int)data->hwirq; | ||
1148 | info = mp_pin_info(ioapic, pin); | ||
1149 | |||
1150 | mutex_lock(&ioapic_mutex); | ||
1151 | if (--info->count == 0) { | ||
1152 | info->set = 0; | ||
1153 | if (irq < nr_legacy_irqs() && | ||
1154 | ioapics[ioapic].irqdomain_cfg.type == IOAPIC_DOMAIN_LEGACY) | ||
1155 | mp_irqdomain_unmap(data->domain, irq); | ||
1156 | else | ||
1157 | irq_dispose_mapping(irq); | ||
1158 | } | ||
1159 | mutex_unlock(&ioapic_mutex); | ||
1160 | } | ||
1161 | |||
1122 | /* | 1162 | /* |
1123 | * Find a specific PCI IRQ entry. | 1163 | * Find a specific PCI IRQ entry. |
1124 | * Not an __init, possibly needed by modules | 1164 | * Not an __init, possibly needed by modules |
@@ -3878,6 +3918,27 @@ int mp_irqdomain_map(struct irq_domain *domain, unsigned int virq, | |||
3878 | return io_apic_setup_irq_pin(virq, info->node, &attr); | 3918 | return io_apic_setup_irq_pin(virq, info->node, &attr); |
3879 | } | 3919 | } |
3880 | 3920 | ||
3921 | void mp_irqdomain_unmap(struct irq_domain *domain, unsigned int virq) | ||
3922 | { | ||
3923 | struct irq_data *data = irq_get_irq_data(virq); | ||
3924 | struct irq_cfg *cfg = irq_cfg(virq); | ||
3925 | int ioapic = (int)(long)domain->host_data; | ||
3926 | int pin = (int)data->hwirq; | ||
3927 | |||
3928 | /* | ||
3929 | * Skip the timer IRQ if there's a quirk handler installed and if it | ||
3930 | * returns 1: | ||
3931 | */ | ||
3932 | if (apic->multi_timer_check && | ||
3933 | apic->multi_timer_check(ioapic, virq)) | ||
3934 | return; | ||
3935 | |||
3936 | ioapic_mask_entry(ioapic, pin); | ||
3937 | __remove_pin_from_irq(cfg, ioapic, pin); | ||
3938 | WARN_ON(cfg->irq_2_pin != NULL); | ||
3939 | arch_teardown_hwirq(virq); | ||
3940 | } | ||
3941 | |||
3881 | int mp_set_gsi_attr(u32 gsi, int trigger, int polarity, int node) | 3942 | int mp_set_gsi_attr(u32 gsi, int trigger, int polarity, int node) |
3882 | { | 3943 | { |
3883 | int ret = 0; | 3944 | int ret = 0; |