aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/io_apic.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2006-10-24 19:00:23 -0400
committerAndi Kleen <andi@one.(none)>2006-10-24 19:00:23 -0400
commit70a0a5357db20c291d46c04011d646d5d84c868c (patch)
treefb82087c685b2f3018172a5956f86cc36fc833d1 /arch/x86_64/kernel/io_apic.c
parentd1752aa884ec0ac3027c1a3d456bf69bf765c8b8 (diff)
[PATCH] x86-64: Only look at per_cpu data for online cpus.
When I generalized __assign_irq_vector I failed to pay attention to what happens when you access a per cpu data structure for a cpu that is not online. It is an undefined case making any code that does it have undefined behavior as well. The code still needs to be able to allocate a vector across cpus that are not online to properly handle combinations like lowest priority interrupt delivery and cpu_hotplug. Not that we can do that today but the infrastructure shouldn't prevent it. So this patch updates the places where we touch per cpu data to only touch online cpus, it makes cpu vector allocation an atomic operation with respect to cpu hotplug, and it updates the cpu start code to properly initialize vector_irq so we don't have inconsistencies. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Andi Kleen <ak@suse.de>
Diffstat (limited to 'arch/x86_64/kernel/io_apic.c')
-rw-r--r--arch/x86_64/kernel/io_apic.c42
1 files changed, 37 insertions, 5 deletions
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index 0e89ae7e7b22..fe429e5d6b29 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -63,7 +63,7 @@ int timer_over_8254 __initdata = 1;
63static struct { int pin, apic; } ioapic_i8259 = { -1, -1 }; 63static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
64 64
65static DEFINE_SPINLOCK(ioapic_lock); 65static DEFINE_SPINLOCK(ioapic_lock);
66static DEFINE_SPINLOCK(vector_lock); 66DEFINE_SPINLOCK(vector_lock);
67 67
68/* 68/*
69 * # of IRQ routing registers 69 * # of IRQ routing registers
@@ -618,6 +618,9 @@ static int __assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result)
618 618
619 BUG_ON((unsigned)irq >= NR_IRQ_VECTORS); 619 BUG_ON((unsigned)irq >= NR_IRQ_VECTORS);
620 620
621 /* Only try and allocate irqs on cpus that are present */
622 cpus_and(mask, mask, cpu_online_map);
623
621 if (irq_vector[irq] > 0) 624 if (irq_vector[irq] > 0)
622 old_vector = irq_vector[irq]; 625 old_vector = irq_vector[irq];
623 if (old_vector > 0) { 626 if (old_vector > 0) {
@@ -627,11 +630,12 @@ static int __assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result)
627 } 630 }
628 631
629 for_each_cpu_mask(cpu, mask) { 632 for_each_cpu_mask(cpu, mask) {
630 cpumask_t domain; 633 cpumask_t domain, new_mask;
631 int new_cpu; 634 int new_cpu;
632 int vector, offset; 635 int vector, offset;
633 636
634 domain = vector_allocation_domain(cpu); 637 domain = vector_allocation_domain(cpu);
638 cpus_and(new_mask, domain, cpu_online_map);
635 639
636 vector = current_vector; 640 vector = current_vector;
637 offset = current_offset; 641 offset = current_offset;
@@ -646,18 +650,20 @@ next:
646 continue; 650 continue;
647 if (vector == IA32_SYSCALL_VECTOR) 651 if (vector == IA32_SYSCALL_VECTOR)
648 goto next; 652 goto next;
649 for_each_cpu_mask(new_cpu, domain) 653 for_each_cpu_mask(new_cpu, new_mask)
650 if (per_cpu(vector_irq, new_cpu)[vector] != -1) 654 if (per_cpu(vector_irq, new_cpu)[vector] != -1)
651 goto next; 655 goto next;
652 /* Found one! */ 656 /* Found one! */
653 current_vector = vector; 657 current_vector = vector;
654 current_offset = offset; 658 current_offset = offset;
655 if (old_vector >= 0) { 659 if (old_vector >= 0) {
660 cpumask_t old_mask;
656 int old_cpu; 661 int old_cpu;
657 for_each_cpu_mask(old_cpu, irq_domain[irq]) 662 cpus_and(old_mask, irq_domain[irq], cpu_online_map);
663 for_each_cpu_mask(old_cpu, old_mask)
658 per_cpu(vector_irq, old_cpu)[old_vector] = -1; 664 per_cpu(vector_irq, old_cpu)[old_vector] = -1;
659 } 665 }
660 for_each_cpu_mask(new_cpu, domain) 666 for_each_cpu_mask(new_cpu, new_mask)
661 per_cpu(vector_irq, new_cpu)[vector] = irq; 667 per_cpu(vector_irq, new_cpu)[vector] = irq;
662 irq_vector[irq] = vector; 668 irq_vector[irq] = vector;
663 irq_domain[irq] = domain; 669 irq_domain[irq] = domain;
@@ -678,6 +684,32 @@ static int assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result)
678 return vector; 684 return vector;
679} 685}
680 686
687void __setup_vector_irq(int cpu)
688{
689 /* Initialize vector_irq on a new cpu */
690 /* This function must be called with vector_lock held */
691 unsigned long flags;
692 int irq, vector;
693
694
695 /* Mark the inuse vectors */
696 for (irq = 0; irq < NR_IRQ_VECTORS; ++irq) {
697 if (!cpu_isset(cpu, irq_domain[irq]))
698 continue;
699 vector = irq_vector[irq];
700 per_cpu(vector_irq, cpu)[vector] = irq;
701 }
702 /* Mark the free vectors */
703 for (vector = 0; vector < NR_VECTORS; ++vector) {
704 irq = per_cpu(vector_irq, cpu)[vector];
705 if (irq < 0)
706 continue;
707 if (!cpu_isset(cpu, irq_domain[irq]))
708 per_cpu(vector_irq, cpu)[vector] = -1;
709 }
710}
711
712
681extern void (*interrupt[NR_IRQS])(void); 713extern void (*interrupt[NR_IRQS])(void);
682 714
683static struct irq_chip ioapic_chip; 715static struct irq_chip ioapic_chip;