From 5f2dbbc51734fc51e8e3e2c3ab7096a58ac72e86 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 1 Jun 2015 16:05:14 +0800 Subject: [PATCH 01/16] x86/irq: Use accessor irq_data_get_node() Use accessor irq_data_get_node() to hide struct irq_data implementation detail, so we can move node to irq_data_common later. Signed-off-by: Jiang Liu Cc: Borislav Petkov Signed-off-by: Thomas Gleixner --- arch/x86/kernel/apic/vector.c | 8 ++++---- arch/x86/platform/uv/uv_irq.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c index 28eba2d38b15..9b62f690b0ff 100644 --- a/arch/x86/kernel/apic/vector.c +++ b/arch/x86/kernel/apic/vector.c @@ -296,7 +296,7 @@ static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq, struct irq_alloc_info *info = arg; struct apic_chip_data *data; struct irq_data *irq_data; - int i, err; + int i, err, node; if (disable_apic) return -ENXIO; @@ -308,12 +308,13 @@ static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq, for (i = 0; i < nr_irqs; i++) { irq_data = irq_domain_get_irq_data(domain, virq + i); BUG_ON(!irq_data); + node = irq_data_get_node(irq_data); #ifdef CONFIG_X86_IO_APIC if (virq + i < nr_legacy_irqs() && legacy_irq_data[virq + i]) data = legacy_irq_data[virq + i]; else #endif - data = alloc_apic_chip_data(irq_data->node); + data = alloc_apic_chip_data(node); if (!data) { err = -ENOMEM; goto error; @@ -322,8 +323,7 @@ static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq, irq_data->chip = &lapic_controller; irq_data->chip_data = data; irq_data->hwirq = virq + i; - err = assign_irq_vector_policy(virq, irq_data->node, data, - info); + err = assign_irq_vector_policy(virq, node, data, info); if (err) goto error; } diff --git a/arch/x86/platform/uv/uv_irq.c b/arch/x86/platform/uv/uv_irq.c index 8570abe68be1..e1c24631afbb 100644 --- a/arch/x86/platform/uv/uv_irq.c +++ b/arch/x86/platform/uv/uv_irq.c @@ -89,7 +89,7 @@ static int uv_domain_alloc(struct irq_domain *domain, unsigned int virq, return -EINVAL; chip_data = kmalloc_node(sizeof(*chip_data), GFP_KERNEL, - irq_data->node); + irq_data_get_node(irq_data)); if (!chip_data) return -ENOMEM; From ff96b4d0333baa001b404882b28b7d992b02415b Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 1 Jun 2015 16:05:18 +0800 Subject: [PATCH 02/16] x86/irq: Use accessor irq_data_get_irq_handler_data() Use accessor function irq_data_get_irq_handler_data() to hide irq_desc implementation details. Signed-off-by: Jiang Liu Signed-off-by: Thomas Gleixner --- arch/x86/kernel/apic/msi.c | 2 +- arch/x86/kernel/hpet.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/apic/msi.c b/arch/x86/kernel/apic/msi.c index 1a9d735e09c6..5f1feb6854af 100644 --- a/arch/x86/kernel/apic/msi.c +++ b/arch/x86/kernel/apic/msi.c @@ -264,7 +264,7 @@ static inline int hpet_dev_id(struct irq_domain *domain) static void hpet_msi_write_msg(struct irq_data *data, struct msi_msg *msg) { - hpet_msi_write(data->handler_data, msg); + hpet_msi_write(irq_data_get_irq_handler_data(data), msg); } static struct irq_chip hpet_msi_controller = { diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 10757d0a3fcf..2de7e4e07dfa 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -426,7 +426,7 @@ static struct irq_domain *hpet_domain; void hpet_msi_unmask(struct irq_data *data) { - struct hpet_dev *hdev = data->handler_data; + struct hpet_dev *hdev = irq_data_get_irq_handler_data(data); unsigned int cfg; /* unmask it */ @@ -437,7 +437,7 @@ void hpet_msi_unmask(struct irq_data *data) void hpet_msi_mask(struct irq_data *data) { - struct hpet_dev *hdev = data->handler_data; + struct hpet_dev *hdev = irq_data_get_irq_handler_data(data); unsigned int cfg; /* mask it */ From c149e4cd08ba01f4d2d0104f469d5f5419294e06 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Wed, 3 Jun 2015 11:46:22 +0800 Subject: [PATCH 03/16] x86/irq: Use access helper irq_data_get_affinity_mask() This is a preparatory patch for moving irq_data struct members. Signed-off-by: Jiang Liu Signed-off-by: Thomas Gleixner --- arch/x86/kernel/apic/io_apic.c | 2 +- arch/x86/kernel/apic/vector.c | 3 ++- arch/x86/kernel/irq.c | 5 +++-- drivers/xen/events/events_base.c | 4 ++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 845dc0df2002..09921de4210f 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -2541,7 +2541,7 @@ void __init setup_ioapic_dest(void) * Honour affinities which have been set in early boot */ if (!irqd_can_balance(idata) || irqd_affinity_was_set(idata)) - mask = idata->affinity; + mask = irq_data_get_affinity_mask(idata); else mask = apic->target_cpus(); diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c index 9b62f690b0ff..7ad911ea4f56 100644 --- a/arch/x86/kernel/apic/vector.c +++ b/arch/x86/kernel/apic/vector.c @@ -496,7 +496,8 @@ static int apic_set_affinity(struct irq_data *irq_data, if (err) { struct irq_data *top = irq_get_irq_data(irq); - if (assign_irq_vector(irq, data, top->affinity)) + if (assign_irq_vector(irq, data, + irq_data_get_affinity_mask(top))) pr_err("Failed to recover vector for irq %d\n", irq); return err; } diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index 88b366487b0e..7ed9cba27637 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -348,7 +348,8 @@ int check_irq_vectors_for_cpu_disable(void) continue; data = irq_desc_get_irq_data(desc); - cpumask_copy(&affinity_new, data->affinity); + cpumask_copy(&affinity_new, + irq_data_get_affinity_mask(data)); cpumask_clear_cpu(this_cpu, &affinity_new); /* Do not count inactive or per-cpu irqs. */ @@ -426,7 +427,7 @@ void fixup_irqs(void) raw_spin_lock(&desc->lock); data = irq_desc_get_irq_data(desc); - affinity = data->affinity; + affinity = irq_data_get_affinity_mask(data); if (!irq_has_action(irq) || irqd_is_per_cpu(data) || cpumask_subset(affinity, cpu_online_mask)) { raw_spin_unlock(&desc->lock); diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index 96093ae369a5..ed8bf1067a97 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c @@ -336,7 +336,7 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu) BUG_ON(irq == -1); #ifdef CONFIG_SMP - cpumask_copy(irq_get_irq_data(irq)->affinity, cpumask_of(cpu)); + cpumask_copy(irq_get_affinity_mask(irq), cpumask_of(cpu)); #endif xen_evtchn_port_bind_to_cpu(info, cpu); @@ -373,7 +373,7 @@ static void xen_irq_init(unsigned irq) struct irq_info *info; #ifdef CONFIG_SMP /* By default all event channels notify CPU#0. */ - cpumask_copy(irq_get_irq_data(irq)->affinity, cpumask_of(0)); + cpumask_copy(irq_get_affinity_mask(irq), cpumask_of(0)); #endif info = kzalloc(sizeof(*info), GFP_KERNEL); From b23d8e527815954768861bb20d2b224009fff7cd Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 16 Jul 2015 16:28:44 +0530 Subject: [PATCH 04/16] x86/apic: Migrate apic timer to new set_state interface Migrate apic driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. We weren't doing anything while switching to resume mode and so that callback isn't implemented. Signed-off-by: Viresh Kumar Cc: linaro-kernel@lists.linaro.org Cc: Jiang Liu Cc: Borislav Petkov Cc: David Rientjes Cc: Bandan Das Link: http://lkml.kernel.org/r/1896ac5989d27f2ac37f4786af9bd537e1921b83.1437042675.git.viresh.kumar@linaro.org Signed-off-by: Thomas Gleixner --- arch/x86/kernel/apic/apic.c | 86 ++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 35 deletions(-) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index dcb52850a28f..ecd6705c9f4b 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -462,40 +462,53 @@ static int lapic_next_deadline(unsigned long delta, return 0; } -/* - * Setup the lapic timer in periodic or oneshot mode - */ -static void lapic_timer_setup(enum clock_event_mode mode, - struct clock_event_device *evt) +static int lapic_timer_shutdown(struct clock_event_device *evt) { unsigned long flags; unsigned int v; /* Lapic used as dummy for broadcast ? */ if (evt->features & CLOCK_EVT_FEAT_DUMMY) - return; + return 0; local_irq_save(flags); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - case CLOCK_EVT_MODE_ONESHOT: - __setup_APIC_LVTT(lapic_timer_frequency, - mode != CLOCK_EVT_MODE_PERIODIC, 1); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - v = apic_read(APIC_LVTT); - v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR); - apic_write(APIC_LVTT, v); - apic_write(APIC_TMICT, 0); - break; - case CLOCK_EVT_MODE_RESUME: - /* Nothing to do here */ - break; - } + v = apic_read(APIC_LVTT); + v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR); + apic_write(APIC_LVTT, v); + apic_write(APIC_TMICT, 0); local_irq_restore(flags); + + return 0; +} + +static inline int +lapic_timer_set_periodic_oneshot(struct clock_event_device *evt, bool oneshot) +{ + unsigned long flags; + + /* Lapic used as dummy for broadcast ? */ + if (evt->features & CLOCK_EVT_FEAT_DUMMY) + return 0; + + local_irq_save(flags); + + __setup_APIC_LVTT(lapic_timer_frequency, oneshot, 1); + + local_irq_restore(flags); + + return 0; +} + +static int lapic_timer_set_periodic(struct clock_event_device *evt) +{ + return lapic_timer_set_periodic_oneshot(evt, false); +} + +static int lapic_timer_set_oneshot(struct clock_event_device *evt) +{ + return lapic_timer_set_periodic_oneshot(evt, true); } /* @@ -513,15 +526,18 @@ static void lapic_timer_broadcast(const struct cpumask *mask) * The local apic timer can be used for any function which is CPU local. */ static struct clock_event_device lapic_clockevent = { - .name = "lapic", - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT - | CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY, - .shift = 32, - .set_mode = lapic_timer_setup, - .set_next_event = lapic_next_event, - .broadcast = lapic_timer_broadcast, - .rating = 100, - .irq = -1, + .name = "lapic", + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP + | CLOCK_EVT_FEAT_DUMMY, + .shift = 32, + .set_state_shutdown = lapic_timer_shutdown, + .set_state_periodic = lapic_timer_set_periodic, + .set_state_oneshot = lapic_timer_set_oneshot, + .set_next_event = lapic_next_event, + .broadcast = lapic_timer_broadcast, + .rating = 100, + .irq = -1, }; static DEFINE_PER_CPU(struct clock_event_device, lapic_events); @@ -778,7 +794,7 @@ static int __init calibrate_APIC_clock(void) * Setup the apic timer manually */ levt->event_handler = lapic_cal_handler; - lapic_timer_setup(CLOCK_EVT_MODE_PERIODIC, levt); + lapic_timer_set_periodic(levt); lapic_cal_loops = -1; /* Let the interrupts run */ @@ -788,7 +804,7 @@ static int __init calibrate_APIC_clock(void) cpu_relax(); /* Stop the lapic timer */ - lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, levt); + lapic_timer_shutdown(levt); /* Jiffies delta */ deltaj = lapic_cal_j2 - lapic_cal_j1; @@ -878,7 +894,7 @@ static void local_apic_timer_interrupt(void) if (!evt->event_handler) { pr_warning("Spurious LAPIC timer interrupt on cpu %d\n", cpu); /* Switch it off */ - lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, evt); + lapic_timer_shutdown(evt); return; } From c948c26048ecb1023d2e68222c736f7da41da498 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 30 Jul 2015 00:30:51 +0200 Subject: [PATCH 05/16] x86/apic: Drop local_irq_save/restore in timer callbacks These callbacks are called with interrupts disabled from the core code. Fixup the local caller to disable interrupts. Signed-off-by: Thomas Gleixner Cc: Viresh Kumar --- arch/x86/kernel/apic/apic.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index ecd6705c9f4b..1dceb2732425 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -464,40 +464,27 @@ static int lapic_next_deadline(unsigned long delta, static int lapic_timer_shutdown(struct clock_event_device *evt) { - unsigned long flags; unsigned int v; /* Lapic used as dummy for broadcast ? */ if (evt->features & CLOCK_EVT_FEAT_DUMMY) return 0; - local_irq_save(flags); - v = apic_read(APIC_LVTT); v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR); apic_write(APIC_LVTT, v); apic_write(APIC_TMICT, 0); - - local_irq_restore(flags); - return 0; } static inline int lapic_timer_set_periodic_oneshot(struct clock_event_device *evt, bool oneshot) { - unsigned long flags; - /* Lapic used as dummy for broadcast ? */ if (evt->features & CLOCK_EVT_FEAT_DUMMY) return 0; - local_irq_save(flags); - __setup_APIC_LVTT(lapic_timer_frequency, oneshot, 1); - - local_irq_restore(flags); - return 0; } @@ -804,6 +791,7 @@ static int __init calibrate_APIC_clock(void) cpu_relax(); /* Stop the lapic timer */ + local_irq_disable(); lapic_timer_shutdown(levt); /* Jiffies delta */ @@ -815,8 +803,8 @@ static int __init calibrate_APIC_clock(void) apic_printk(APIC_VERBOSE, "... jiffies result ok\n"); else levt->features |= CLOCK_EVT_FEAT_DUMMY; - } else - local_irq_enable(); + } + local_irq_enable(); if (levt->features & CLOCK_EVT_FEAT_DUMMY) { pr_warning("APIC timer disabled due to verification failure\n"); From 27a6f41c1a20a3339f456647a21e45fca5b82b62 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 4 Aug 2015 14:02:55 +0930 Subject: [PATCH 06/16] x86/lguest: Clean up lguest_setup_irq We make it static and hoist it higher in the file for the next patch. We also give a nice panic if it fails during boot. Signed-off-by: Rusty Russell Link: http://lkml.kernel.org/r/1438662776-4823-1-git-send-email-rusty@rustcorp.com.au Signed-off-by: Thomas Gleixner --- arch/x86/lguest/boot.c | 43 +++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index f2dc08c003eb..d933a11ceba6 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c @@ -835,6 +835,26 @@ static struct irq_chip lguest_irq_controller = { .irq_unmask = enable_lguest_irq, }; +/* + * Interrupt descriptors are allocated as-needed, but low-numbered ones are + * reserved by the generic x86 code. So we ignore irq_alloc_desc_at if it + * tells us the irq is already used: other errors (ie. ENOMEM) we take + * seriously. + */ +static int lguest_setup_irq(unsigned int irq) +{ + int err; + + /* Returns -ve error or vector number. */ + err = irq_alloc_desc_at(irq, 0); + if (err < 0 && err != -EEXIST) + return err; + + irq_set_chip_and_handler_name(irq, &lguest_irq_controller, + handle_level_irq, "level"); + return 0; +} + static int lguest_enable_irq(struct pci_dev *dev) { u8 line = 0; @@ -878,26 +898,6 @@ static void __init lguest_init_IRQ(void) irq_ctx_init(smp_processor_id()); } -/* - * Interrupt descriptors are allocated as-needed, but low-numbered ones are - * reserved by the generic x86 code. So we ignore irq_alloc_desc_at if it - * tells us the irq is already used: other errors (ie. ENOMEM) we take - * seriously. - */ -int lguest_setup_irq(unsigned int irq) -{ - int err; - - /* Returns -ve error or vector number. */ - err = irq_alloc_desc_at(irq, 0); - if (err < 0 && err != -EEXIST) - return err; - - irq_set_chip_and_handler_name(irq, &lguest_irq_controller, - handle_level_irq, "level"); - return 0; -} - /* * Time. * @@ -1040,7 +1040,8 @@ static void lguest_time_irq(unsigned int irq, struct irq_desc *desc) static void lguest_time_init(void) { /* Set up the timer interrupt (0) to go to our simple timer routine */ - lguest_setup_irq(0); + if (lguest_setup_irq(0) != 0) + panic("Could not set up timer irq"); irq_set_handler(0, lguest_time_irq); clocksource_register_hz(&lguest_clock, NSEC_PER_SEC); From ad3f8d5afe503faa78d61a50a1f6eec3afa7c787 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 4 Aug 2015 14:02:56 +0930 Subject: [PATCH 07/16] x86/lguest: Do not setup unused irq vectors No point in assigning the interrupt vectors if there is no interrupt chip installed. Move it to lguest_setup_irq() and call it from lguest_enable_irq. [ rusty: Typo fix and error handling ] Signed-off-by: Thomas Gleixner Signed-off-by: Rusty Russell Link: http://lkml.kernel.org/r/1438662776-4823-2-git-send-email-rusty@rustcorp.com.au Signed-off-by: Thomas Gleixner --- arch/x86/lguest/boot.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index d933a11ceba6..2165f45befff 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c @@ -850,21 +850,29 @@ static int lguest_setup_irq(unsigned int irq) if (err < 0 && err != -EEXIST) return err; + /* + * Tell the Linux infrastructure that the interrupt is + * controlled by our level-based lguest interrupt controller. + */ irq_set_chip_and_handler_name(irq, &lguest_irq_controller, handle_level_irq, "level"); + + /* Some systems map "vectors" to interrupts weirdly. Not us! */ + __this_cpu_write(vector_irq[FIRST_EXTERNAL_VECTOR + irq], irq); return 0; } static int lguest_enable_irq(struct pci_dev *dev) { + int err; u8 line = 0; /* We literally use the PCI interrupt line as the irq number. */ pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &line); - irq_set_chip_and_handler_name(line, &lguest_irq_controller, - handle_level_irq, "level"); - dev->irq = line; - return 0; + err = lguest_setup_irq(line); + if (!err) + dev->irq = line; + return err; } /* We don't do hotplug PCI, so this shouldn't be called. */ @@ -875,17 +883,13 @@ static void lguest_disable_irq(struct pci_dev *dev) /* * This sets up the Interrupt Descriptor Table (IDT) entry for each hardware - * interrupt (except 128, which is used for system calls), and then tells the - * Linux infrastructure that each interrupt is controlled by our level-based - * lguest interrupt controller. + * interrupt (except 128, which is used for system calls). */ static void __init lguest_init_IRQ(void) { unsigned int i; for (i = FIRST_EXTERNAL_VECTOR; i < FIRST_SYSTEM_VECTOR; i++) { - /* Some systems map "vectors" to interrupts weirdly. Not us! */ - __this_cpu_write(vector_irq[i], i - FIRST_EXTERNAL_VECTOR); if (i != IA32_SYSCALL_VECTOR) set_intr_gate(i, irq_entries_start + 8 * (i - FIRST_EXTERNAL_VECTOR)); From df54c4934e030e73cb6a7bd6713f697350dabd0b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 2 Aug 2015 20:38:23 +0000 Subject: [PATCH 08/16] x86/irq: Protect smp_cleanup_move smp_cleanup_move fiddles without protection in the interrupt descriptors and the vector array. A concurrent irq setup/teardown or affinity setting can pull the rug under that operation. Add proper locking. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Peter Zijlstra Cc: Rusty Russell Cc: Bjorn Helgaas Link: http://lkml.kernel.org/r/20150802203609.222975294@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/kernel/apic/vector.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c index f47069e8efac..63d58b08a109 100644 --- a/arch/x86/kernel/apic/vector.c +++ b/arch/x86/kernel/apic/vector.c @@ -539,6 +539,9 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void) entering_ack_irq(); + /* Prevent vectors vanishing under us */ + raw_spin_lock(&vector_lock); + me = smp_processor_id(); for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) { int irq; @@ -546,6 +549,7 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void) struct irq_desc *desc; struct apic_chip_data *data; + retry: irq = __this_cpu_read(vector_irq[vector]); if (irq <= VECTOR_UNDEFINED) @@ -555,12 +559,16 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void) if (!desc) continue; + if (!raw_spin_trylock(&desc->lock)) { + raw_spin_unlock(&vector_lock); + cpu_relax(); + raw_spin_lock(&vector_lock); + goto retry; + } + data = apic_chip_data(&desc->irq_data); if (!data) - continue; - - raw_spin_lock(&desc->lock); - + goto unlock; /* * Check if the irq migration is in progress. If so, we * haven't received the cleanup request yet for this irq. @@ -589,6 +597,8 @@ unlock: raw_spin_unlock(&desc->lock); } + raw_spin_unlock(&vector_lock); + exiting_irq(); } From 24c70e07a0311a98dbb5e7a7472fa96a22b789d3 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 2 Aug 2015 20:38:24 +0000 Subject: [PATCH 09/16] x86/irq: Replace numeric constant Use the proper define instead of 0. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Peter Zijlstra Cc: Rusty Russell Cc: Bjorn Helgaas Link: http://lkml.kernel.org/r/20150802203609.385495420@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/kernel/irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index bc28496fd196..35d4cb287771 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -401,8 +401,8 @@ int check_irq_vectors_for_cpu_disable(void) for (vector = FIRST_EXTERNAL_VECTOR; vector < first_system_vector; vector++) { if (!test_bit(vector, used_vectors) && - per_cpu(vector_irq, cpu)[vector] < 0) - count++; + per_cpu(vector_irq, cpu)[vector] <= VECTOR_UNDEFINED) + count++; } } From 7276c6a2cb5f7ae46fd0c9539af02dbcb7c4f3f5 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 2 Aug 2015 20:38:25 +0000 Subject: [PATCH 10/16] x86/irq: Rename VECTOR_UNDEFINED to VECTOR_UNUSED VECTOR_UNDEFINED is a misnomer. The vector is defined, but unused. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Peter Zijlstra Cc: Rusty Russell Cc: Bjorn Helgaas Link: http://lkml.kernel.org/r/20150802203609.477282494@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/hw_irq.h | 2 +- arch/x86/kernel/apic/vector.c | 15 +++++++-------- arch/x86/kernel/irq.c | 8 ++++---- arch/x86/kernel/irqinit.c | 4 ++-- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h index 6615032e19c8..62bb8d23b826 100644 --- a/arch/x86/include/asm/hw_irq.h +++ b/arch/x86/include/asm/hw_irq.h @@ -182,7 +182,7 @@ extern char irq_entries_start[]; #define trace_irq_entries_start irq_entries_start #endif -#define VECTOR_UNDEFINED (-1) +#define VECTOR_UNUSED (-1) #define VECTOR_RETRIGGERED (-2) typedef int vector_irq_t[NR_VECTORS]; diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c index 63d58b08a109..9a6d11258684 100644 --- a/arch/x86/kernel/apic/vector.c +++ b/arch/x86/kernel/apic/vector.c @@ -169,8 +169,7 @@ next: goto next; for_each_cpu_and(new_cpu, vector_cpumask, cpu_online_mask) { - if (per_cpu(vector_irq, new_cpu)[vector] > - VECTOR_UNDEFINED) + if (per_cpu(vector_irq, new_cpu)[vector] > VECTOR_UNUSED) goto next; } /* Found one! */ @@ -232,7 +231,7 @@ static void clear_irq_vector(int irq, struct apic_chip_data *data) vector = data->cfg.vector; for_each_cpu_and(cpu, data->domain, cpu_online_mask) - per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED; + per_cpu(vector_irq, cpu)[vector] = VECTOR_UNUSED; data->cfg.vector = 0; cpumask_clear(data->domain); @@ -247,7 +246,7 @@ static void clear_irq_vector(int irq, struct apic_chip_data *data) vector++) { if (per_cpu(vector_irq, cpu)[vector] != irq) continue; - per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED; + per_cpu(vector_irq, cpu)[vector] = VECTOR_UNUSED; break; } } @@ -423,12 +422,12 @@ static void __setup_vector_irq(int cpu) /* Mark the free vectors */ for (vector = 0; vector < NR_VECTORS; ++vector) { irq = per_cpu(vector_irq, cpu)[vector]; - if (irq <= VECTOR_UNDEFINED) + if (irq <= VECTOR_UNUSED) continue; data = apic_chip_data(irq_get_irq_data(irq)); if (!cpumask_test_cpu(cpu, data->domain)) - per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED; + per_cpu(vector_irq, cpu)[vector] = VECTOR_UNUSED; } } @@ -552,7 +551,7 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void) retry: irq = __this_cpu_read(vector_irq[vector]); - if (irq <= VECTOR_UNDEFINED) + if (irq <= VECTOR_UNUSED) continue; desc = irq_to_desc(irq); @@ -592,7 +591,7 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void) apic->send_IPI_self(IRQ_MOVE_CLEANUP_VECTOR); goto unlock; } - __this_cpu_write(vector_irq[vector], VECTOR_UNDEFINED); + __this_cpu_write(vector_irq[vector], VECTOR_UNUSED); unlock: raw_spin_unlock(&desc->lock); } diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index 35d4cb287771..931bdd2f9759 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -228,7 +228,7 @@ __visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs) __func__, smp_processor_id(), vector, irq); } else { - __this_cpu_write(vector_irq[vector], VECTOR_UNDEFINED); + __this_cpu_write(vector_irq[vector], VECTOR_UNUSED); } } @@ -401,7 +401,7 @@ int check_irq_vectors_for_cpu_disable(void) for (vector = FIRST_EXTERNAL_VECTOR; vector < first_system_vector; vector++) { if (!test_bit(vector, used_vectors) && - per_cpu(vector_irq, cpu)[vector] <= VECTOR_UNDEFINED) + per_cpu(vector_irq, cpu)[vector] <= VECTOR_UNUSED) count++; } } @@ -506,7 +506,7 @@ void fixup_irqs(void) for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) { unsigned int irr; - if (__this_cpu_read(vector_irq[vector]) <= VECTOR_UNDEFINED) + if (__this_cpu_read(vector_irq[vector]) <= VECTOR_UNUSED) continue; irr = apic_read(APIC_IRR + (vector / 32 * 0x10)); @@ -524,7 +524,7 @@ void fixup_irqs(void) raw_spin_unlock(&desc->lock); } if (__this_cpu_read(vector_irq[vector]) != VECTOR_RETRIGGERED) - __this_cpu_write(vector_irq[vector], VECTOR_UNDEFINED); + __this_cpu_write(vector_irq[vector], VECTOR_UNUSED); } } #endif diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c index a3a5e158ed69..32a637ffdf98 100644 --- a/arch/x86/kernel/irqinit.c +++ b/arch/x86/kernel/irqinit.c @@ -52,7 +52,7 @@ static struct irqaction irq2 = { }; DEFINE_PER_CPU(vector_irq_t, vector_irq) = { - [0 ... NR_VECTORS - 1] = VECTOR_UNDEFINED, + [0 ... NR_VECTORS - 1] = VECTOR_UNUSED, }; int vector_used_by_percpu_irq(unsigned int vector) @@ -60,7 +60,7 @@ int vector_used_by_percpu_irq(unsigned int vector) int cpu; for_each_online_cpu(cpu) { - if (per_cpu(vector_irq, cpu)[vector] > VECTOR_UNDEFINED) + if (per_cpu(vector_irq, cpu)[vector] > VECTOR_UNUSED) return 1; } From 44825757a3ee37c030165a94d6b4dd79c564f661 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 2 Aug 2015 20:38:25 +0000 Subject: [PATCH 11/16] x86/irq: Get rid of an indentation level Make the code simpler to read. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Peter Zijlstra Cc: Rusty Russell Cc: Bjorn Helgaas Link: http://lkml.kernel.org/r/20150802203609.555253675@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/kernel/irq.c | 72 +++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index 931bdd2f9759..140950fb9902 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -342,47 +342,45 @@ int check_irq_vectors_for_cpu_disable(void) this_count = 0; for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) { irq = __this_cpu_read(vector_irq[vector]); - if (irq >= 0) { - desc = irq_to_desc(irq); - if (!desc) - continue; + if (irq < 0) + continue; + desc = irq_to_desc(irq); + if (!desc) + continue; - /* - * Protect against concurrent action removal, - * affinity changes etc. - */ - raw_spin_lock(&desc->lock); - data = irq_desc_get_irq_data(desc); - cpumask_copy(&affinity_new, - irq_data_get_affinity_mask(data)); - cpumask_clear_cpu(this_cpu, &affinity_new); - - /* Do not count inactive or per-cpu irqs. */ - if (!irq_has_action(irq) || irqd_is_per_cpu(data)) { - raw_spin_unlock(&desc->lock); - continue; - } + /* + * Protect against concurrent action removal, affinity + * changes etc. + */ + raw_spin_lock(&desc->lock); + data = irq_desc_get_irq_data(desc); + cpumask_copy(&affinity_new, irq_data_get_affinity_mask(data)); + cpumask_clear_cpu(this_cpu, &affinity_new); + /* Do not count inactive or per-cpu irqs. */ + if (!irq_has_action(irq) || irqd_is_per_cpu(data)) { raw_spin_unlock(&desc->lock); - /* - * A single irq may be mapped to multiple - * cpu's vector_irq[] (for example IOAPIC cluster - * mode). In this case we have two - * possibilities: - * - * 1) the resulting affinity mask is empty; that is - * this the down'd cpu is the last cpu in the irq's - * affinity mask, or - * - * 2) the resulting affinity mask is no longer - * a subset of the online cpus but the affinity - * mask is not zero; that is the down'd cpu is the - * last online cpu in a user set affinity mask. - */ - if (cpumask_empty(&affinity_new) || - !cpumask_subset(&affinity_new, &online_new)) - this_count++; + continue; } + + raw_spin_unlock(&desc->lock); + /* + * A single irq may be mapped to multiple cpu's + * vector_irq[] (for example IOAPIC cluster mode). In + * this case we have two possibilities: + * + * 1) the resulting affinity mask is empty; that is + * this the down'd cpu is the last cpu in the irq's + * affinity mask, or + * + * 2) the resulting affinity mask is no longer a + * subset of the online cpus but the affinity mask is + * not zero; that is the down'd cpu is the last online + * cpu in a user set affinity mask. + */ + if (cpumask_empty(&affinity_new) || + !cpumask_subset(&affinity_new, &online_new)) + this_count++; } count = 0; From f61ae4fb66a4f7ae49e3456003fc4328d6db09c9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 2 Aug 2015 20:38:26 +0000 Subject: [PATCH 12/16] genirq: Provide irq_desc_has_action If we have a reference to irq_desc already, there is no point to do another lookup. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Peter Zijlstra Cc: Rusty Russell Cc: Bjorn Helgaas Link: http://lkml.kernel.org/r/20150802203609.638130301@linutronix.de Signed-off-by: Thomas Gleixner --- include/linux/irqdesc.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index fcea4e48e21f..5acfa26602e1 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -166,10 +166,14 @@ static inline int handle_domain_irq(struct irq_domain *domain, #endif /* Test to see if a driver has successfully requested an irq */ +static inline int irq_desc_has_action(struct irq_desc *desc) +{ + return desc->action != NULL; +} + static inline int irq_has_action(unsigned int irq) { - struct irq_desc *desc = irq_to_desc(irq); - return desc->action != NULL; + return irq_desc_has_action(irq_to_desc(irq)); } /* caller has locked the irq_desc and both params are valid */ From a782a7e46bb50822fabfeb7271605762a59c86df Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 2 Aug 2015 20:38:27 +0000 Subject: [PATCH 13/16] x86/irq: Store irq descriptor in vector array We can spare the irq_desc lookup in the interrupt entry code if we store the descriptor pointer in the vector array instead the interrupt number. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Peter Zijlstra Cc: Rusty Russell Cc: Bjorn Helgaas Link: http://lkml.kernel.org/r/20150802203609.717724106@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/hw_irq.h | 6 ++--- arch/x86/include/asm/irq.h | 4 ++- arch/x86/kernel/apic/vector.c | 51 +++++++++++++++++------------------ arch/x86/kernel/irq.c | 37 +++++++++++-------------- arch/x86/kernel/irq_32.c | 9 +++---- arch/x86/kernel/irq_64.c | 9 +++---- arch/x86/kernel/irqinit.c | 4 +-- arch/x86/lguest/boot.c | 4 ++- 8 files changed, 58 insertions(+), 66 deletions(-) diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h index 62bb8d23b826..1e3408e88604 100644 --- a/arch/x86/include/asm/hw_irq.h +++ b/arch/x86/include/asm/hw_irq.h @@ -182,10 +182,10 @@ extern char irq_entries_start[]; #define trace_irq_entries_start irq_entries_start #endif -#define VECTOR_UNUSED (-1) -#define VECTOR_RETRIGGERED (-2) +#define VECTOR_UNUSED NULL +#define VECTOR_RETRIGGERED ((void *)~0UL) -typedef int vector_irq_t[NR_VECTORS]; +typedef struct irq_desc* vector_irq_t[NR_VECTORS]; DECLARE_PER_CPU(vector_irq_t, vector_irq); #endif /* !ASSEMBLY_ */ diff --git a/arch/x86/include/asm/irq.h b/arch/x86/include/asm/irq.h index 8008d06581c7..881b4768644a 100644 --- a/arch/x86/include/asm/irq.h +++ b/arch/x86/include/asm/irq.h @@ -36,7 +36,9 @@ extern void kvm_set_posted_intr_wakeup_handler(void (*handler)(void)); extern void (*x86_platform_ipi_callback)(void); extern void native_init_IRQ(void); -extern bool handle_irq(unsigned irq, struct pt_regs *regs); + +struct irq_desc; +extern bool handle_irq(struct irq_desc *desc, struct pt_regs *regs); extern __visible unsigned int do_IRQ(struct pt_regs *regs); diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c index 9a6d11258684..200b5a5d6b79 100644 --- a/arch/x86/kernel/apic/vector.c +++ b/arch/x86/kernel/apic/vector.c @@ -169,7 +169,7 @@ next: goto next; for_each_cpu_and(new_cpu, vector_cpumask, cpu_online_mask) { - if (per_cpu(vector_irq, new_cpu)[vector] > VECTOR_UNUSED) + if (!IS_ERR_OR_NULL(per_cpu(vector_irq, new_cpu)[vector])) goto next; } /* Found one! */ @@ -181,7 +181,7 @@ next: cpumask_intersects(d->old_domain, cpu_online_mask); } for_each_cpu_and(new_cpu, vector_cpumask, cpu_online_mask) - per_cpu(vector_irq, new_cpu)[vector] = irq; + per_cpu(vector_irq, new_cpu)[vector] = irq_to_desc(irq); d->cfg.vector = vector; cpumask_copy(d->domain, vector_cpumask); err = 0; @@ -223,8 +223,9 @@ static int assign_irq_vector_policy(int irq, int node, static void clear_irq_vector(int irq, struct apic_chip_data *data) { - int cpu, vector; + struct irq_desc *desc; unsigned long flags; + int cpu, vector; raw_spin_lock_irqsave(&vector_lock, flags); BUG_ON(!data->cfg.vector); @@ -241,10 +242,11 @@ static void clear_irq_vector(int irq, struct apic_chip_data *data) return; } + desc = irq_to_desc(irq); for_each_cpu_and(cpu, data->old_domain, cpu_online_mask) { for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) { - if (per_cpu(vector_irq, cpu)[vector] != irq) + if (per_cpu(vector_irq, cpu)[vector] != desc) continue; per_cpu(vector_irq, cpu)[vector] = VECTOR_UNUSED; break; @@ -402,30 +404,30 @@ int __init arch_early_irq_init(void) return arch_early_ioapic_init(); } +/* Initialize vector_irq on a new cpu */ static void __setup_vector_irq(int cpu) { - /* Initialize vector_irq on a new cpu */ - int irq, vector; struct apic_chip_data *data; + struct irq_desc *desc; + int irq, vector; /* Mark the inuse vectors */ - for_each_active_irq(irq) { - data = apic_chip_data(irq_get_irq_data(irq)); - if (!data) - continue; + for_each_irq_desc(irq, desc) { + struct irq_data *idata = irq_desc_get_irq_data(desc); - if (!cpumask_test_cpu(cpu, data->domain)) + data = apic_chip_data(idata); + if (!data || !cpumask_test_cpu(cpu, data->domain)) continue; vector = data->cfg.vector; - per_cpu(vector_irq, cpu)[vector] = irq; + per_cpu(vector_irq, cpu)[vector] = desc; } /* Mark the free vectors */ for (vector = 0; vector < NR_VECTORS; ++vector) { - irq = per_cpu(vector_irq, cpu)[vector]; - if (irq <= VECTOR_UNUSED) + desc = per_cpu(vector_irq, cpu)[vector]; + if (IS_ERR_OR_NULL(desc)) continue; - data = apic_chip_data(irq_get_irq_data(irq)); + data = apic_chip_data(irq_desc_get_irq_data(desc)); if (!cpumask_test_cpu(cpu, data->domain)) per_cpu(vector_irq, cpu)[vector] = VECTOR_UNUSED; } @@ -447,7 +449,7 @@ void setup_vector_irq(int cpu) * legacy vector to irq mapping: */ for (irq = 0; irq < nr_legacy_irqs(); irq++) - per_cpu(vector_irq, cpu)[ISA_IRQ_VECTOR(irq)] = irq; + per_cpu(vector_irq, cpu)[ISA_IRQ_VECTOR(irq)] = irq_to_desc(irq); __setup_vector_irq(cpu); } @@ -543,19 +545,13 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void) me = smp_processor_id(); for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) { - int irq; - unsigned int irr; - struct irq_desc *desc; struct apic_chip_data *data; + struct irq_desc *desc; + unsigned int irr; retry: - irq = __this_cpu_read(vector_irq[vector]); - - if (irq <= VECTOR_UNUSED) - continue; - - desc = irq_to_desc(irq); - if (!desc) + desc = __this_cpu_read(vector_irq[vector]); + if (IS_ERR_OR_NULL(desc)) continue; if (!raw_spin_trylock(&desc->lock)) { @@ -565,9 +561,10 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void) goto retry; } - data = apic_chip_data(&desc->irq_data); + data = apic_chip_data(irq_desc_get_irq_data(desc)); if (!data) goto unlock; + /* * Check if the irq migration is in progress. If so, we * haven't received the cleanup request yet for this irq. diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index 140950fb9902..e010847583d7 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -211,22 +211,21 @@ u64 arch_irq_stat(void) __visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); - + struct irq_desc * desc; /* high bit used in ret_from_ code */ unsigned vector = ~regs->orig_ax; - unsigned irq; entering_irq(); - irq = __this_cpu_read(vector_irq[vector]); + desc = __this_cpu_read(vector_irq[vector]); - if (!handle_irq(irq, regs)) { + if (!handle_irq(desc, regs)) { ack_APIC_irq(); - if (irq != VECTOR_RETRIGGERED) { - pr_emerg_ratelimited("%s: %d.%d No irq handler for vector (irq %d)\n", + if (desc != VECTOR_RETRIGGERED) { + pr_emerg_ratelimited("%s: %d.%d No irq handler for vector\n", __func__, smp_processor_id(), - vector, irq); + vector); } else { __this_cpu_write(vector_irq[vector], VECTOR_UNUSED); } @@ -330,10 +329,10 @@ static struct cpumask affinity_new, online_new; */ int check_irq_vectors_for_cpu_disable(void) { - int irq, cpu; unsigned int this_cpu, vector, this_count, count; struct irq_desc *desc; struct irq_data *data; + int cpu; this_cpu = smp_processor_id(); cpumask_copy(&online_new, cpu_online_mask); @@ -341,24 +340,21 @@ int check_irq_vectors_for_cpu_disable(void) this_count = 0; for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) { - irq = __this_cpu_read(vector_irq[vector]); - if (irq < 0) + desc = __this_cpu_read(vector_irq[vector]); + if (IS_ERR_OR_NULL(desc)) continue; - desc = irq_to_desc(irq); - if (!desc) - continue; - /* * Protect against concurrent action removal, affinity * changes etc. */ raw_spin_lock(&desc->lock); data = irq_desc_get_irq_data(desc); - cpumask_copy(&affinity_new, irq_data_get_affinity_mask(data)); + cpumask_copy(&affinity_new, + irq_data_get_affinity_mask(data)); cpumask_clear_cpu(this_cpu, &affinity_new); /* Do not count inactive or per-cpu irqs. */ - if (!irq_has_action(irq) || irqd_is_per_cpu(data)) { + if (!irq_desc_has_action(desc) || irqd_is_per_cpu(data)) { raw_spin_unlock(&desc->lock); continue; } @@ -399,8 +395,8 @@ int check_irq_vectors_for_cpu_disable(void) for (vector = FIRST_EXTERNAL_VECTOR; vector < first_system_vector; vector++) { if (!test_bit(vector, used_vectors) && - per_cpu(vector_irq, cpu)[vector] <= VECTOR_UNUSED) - count++; + IS_ERR_OR_NULL(per_cpu(vector_irq, cpu)[vector])) + count++; } } @@ -504,14 +500,13 @@ void fixup_irqs(void) for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) { unsigned int irr; - if (__this_cpu_read(vector_irq[vector]) <= VECTOR_UNUSED) + if (IS_ERR_OR_NULL(__this_cpu_read(vector_irq[vector]))) continue; irr = apic_read(APIC_IRR + (vector / 32 * 0x10)); if (irr & (1 << (vector % 32))) { - irq = __this_cpu_read(vector_irq[vector]); + desc = __this_cpu_read(vector_irq[vector]); - desc = irq_to_desc(irq); raw_spin_lock(&desc->lock); data = irq_desc_get_irq_data(desc); chip = irq_data_get_irq_chip(data); diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c index cd74f5978ab9..217b01388038 100644 --- a/arch/x86/kernel/irq_32.c +++ b/arch/x86/kernel/irq_32.c @@ -148,21 +148,20 @@ void do_softirq_own_stack(void) call_on_stack(__do_softirq, isp); } -bool handle_irq(unsigned irq, struct pt_regs *regs) +bool handle_irq(struct irq_desc *desc, struct pt_regs *regs) { - struct irq_desc *desc; + unsigned int irq = irq_desc_get_irq(desc); int overflow; overflow = check_stack_overflow(); - desc = irq_to_desc(irq); - if (unlikely(!desc)) + if (IS_ERR_OR_NULL(desc)) return false; if (user_mode(regs) || !execute_on_irq_stack(overflow, desc, irq)) { if (unlikely(overflow)) print_stack_overflow(); - desc->handle_irq(irq, desc); + generic_handle_irq_desc(irq, desc); } return true; diff --git a/arch/x86/kernel/irq_64.c b/arch/x86/kernel/irq_64.c index bc4604e500a3..ff16ccb918f2 100644 --- a/arch/x86/kernel/irq_64.c +++ b/arch/x86/kernel/irq_64.c @@ -68,16 +68,13 @@ static inline void stack_overflow_check(struct pt_regs *regs) #endif } -bool handle_irq(unsigned irq, struct pt_regs *regs) +bool handle_irq(struct irq_desc *desc, struct pt_regs *regs) { - struct irq_desc *desc; - stack_overflow_check(regs); - desc = irq_to_desc(irq); - if (unlikely(!desc)) + if (unlikely(IS_ERR_OR_NULL(desc))) return false; - generic_handle_irq_desc(irq, desc); + generic_handle_irq_desc(irq_desc_get_irq(desc), desc); return true; } diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c index 32a637ffdf98..1423ab1b0312 100644 --- a/arch/x86/kernel/irqinit.c +++ b/arch/x86/kernel/irqinit.c @@ -60,7 +60,7 @@ int vector_used_by_percpu_irq(unsigned int vector) int cpu; for_each_online_cpu(cpu) { - if (per_cpu(vector_irq, cpu)[vector] > VECTOR_UNUSED) + if (!IS_ERR_OR_NULL(per_cpu(vector_irq, cpu)[vector])) return 1; } @@ -94,7 +94,7 @@ void __init init_IRQ(void) * irq's migrate etc. */ for (i = 0; i < nr_legacy_irqs(); i++) - per_cpu(vector_irq, 0)[ISA_IRQ_VECTOR(i)] = i; + per_cpu(vector_irq, 0)[ISA_IRQ_VECTOR(i)] = irq_to_desc(i); x86_init.irqs.intr_init(); } diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index 2165f45befff..47071a08bfa6 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c @@ -843,6 +843,7 @@ static struct irq_chip lguest_irq_controller = { */ static int lguest_setup_irq(unsigned int irq) { + struct irq_desc *desc; int err; /* Returns -ve error or vector number. */ @@ -858,7 +859,8 @@ static int lguest_setup_irq(unsigned int irq) handle_level_irq, "level"); /* Some systems map "vectors" to interrupts weirdly. Not us! */ - __this_cpu_write(vector_irq[FIRST_EXTERNAL_VECTOR + irq], irq); + desc = irq_to_desc(irq); + __this_cpu_write(vector_irq[FIRST_EXTERNAL_VECTOR + irq], desc); return 0; } From e523caa601f4a7c2fa1ecd040db921baf7453798 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 26 Aug 2015 10:42:26 +0930 Subject: [PATCH 14/16] tools/lguest: Fix redefinition of struct virtio_pci_cfg_cap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ours uses a u32 for the data, since we ensure it's always aligned and it's x86 so it doesn't matter anyway. lguest.c:128:8: error: redefinition of ‘struct virtio_pci_cfg_cap’ Signed-off-by: Rusty Russell Cc: Linus Torvalds Cc: Michael S. Tsirkin Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Fixes: 3121bb023e2db ("virtio: define virtio_pci_cfg_cap in header.") Signed-off-by: Ingo Molnar --- tools/lguest/lguest.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tools/lguest/lguest.c b/tools/lguest/lguest.c index e44052483ed9..80159e6811c2 100644 --- a/tools/lguest/lguest.c +++ b/tools/lguest/lguest.c @@ -125,7 +125,11 @@ struct device_list { /* The list of Guest devices, based on command line arguments. */ static struct device_list devices; -struct virtio_pci_cfg_cap { +/* + * Just like struct virtio_pci_cfg_cap in uapi/linux/virtio_pci.h, + * but uses a u32 explicitly for the data. + */ +struct virtio_pci_cfg_cap_u32 { struct virtio_pci_cap cap; u32 pci_cfg_data; /* Data for BAR access. */ }; @@ -157,7 +161,7 @@ struct pci_config { struct virtio_pci_notify_cap notify; struct virtio_pci_cap isr; struct virtio_pci_cap device; - struct virtio_pci_cfg_cap cfg_access; + struct virtio_pci_cfg_cap_u32 cfg_access; }; /* The device structure describes a single device. */ @@ -1291,7 +1295,7 @@ static struct device *dev_and_reg(u32 *reg) * only fault if they try to write with some invalid bar/offset/length. */ static bool valid_bar_access(struct device *d, - struct virtio_pci_cfg_cap *cfg_access) + struct virtio_pci_cfg_cap_u32 *cfg_access) { /* We only have 1 bar (BAR0) */ if (cfg_access->cap.bar != 0) From b51aa1cc7807f4dff7b70a762aa6d8814976d706 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 26 Aug 2015 10:42:27 +0930 Subject: [PATCH 15/16] tools/lguest: Clean up include dir It contains a symlinked header we use; ignore it and clean it up on 'make clean'. Signed-off-by: Rusty Russell Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar --- tools/lguest/.gitignore | 1 + tools/lguest/Makefile | 1 + 2 files changed, 2 insertions(+) diff --git a/tools/lguest/.gitignore b/tools/lguest/.gitignore index 115587fd5f65..8d9a8383a52e 100644 --- a/tools/lguest/.gitignore +++ b/tools/lguest/.gitignore @@ -1 +1,2 @@ lguest +include diff --git a/tools/lguest/Makefile b/tools/lguest/Makefile index a107b5e4da13..d04599a79802 100644 --- a/tools/lguest/Makefile +++ b/tools/lguest/Makefile @@ -11,3 +11,4 @@ lguest: include/linux/virtio_types.h clean: rm -f lguest + rm -rf include From a47d4576cd1c58157a2d8cfffa93aa7ca375eede Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 28 Aug 2015 10:30:15 +0200 Subject: [PATCH 16/16] x86/irq: Do not dereference irq descriptor before checking it Having the IS_NULL_OR_ERR() check after dereferencing the pointer is not really working well. Move the dereference after the check. Fixes: a782a7e46bb5 'x86/irq: Store irq descriptor in vector array' Reported-and-tested-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- arch/x86/kernel/irq_32.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c index 217b01388038..c80cf6699678 100644 --- a/arch/x86/kernel/irq_32.c +++ b/arch/x86/kernel/irq_32.c @@ -150,7 +150,7 @@ void do_softirq_own_stack(void) bool handle_irq(struct irq_desc *desc, struct pt_regs *regs) { - unsigned int irq = irq_desc_get_irq(desc); + unsigned int irq; int overflow; overflow = check_stack_overflow(); @@ -158,6 +158,7 @@ bool handle_irq(struct irq_desc *desc, struct pt_regs *regs) if (IS_ERR_OR_NULL(desc)) return false; + irq = irq_desc_get_irq(desc); if (user_mode(regs) || !execute_on_irq_stack(overflow, desc, irq)) { if (unlikely(overflow)) print_stack_overflow();