On Tue, Jun 20, 2006 at 08:21:00PM -0600, Eric W. Biederman wrote: > Rajesh Shah <rajesh.shah@xxxxxxxxx> writes: > > > It would be really good to decouple MSI implementation from IO > > APICs, since there's really no real hardware dependence here. > > This code can actually go to arch/xxx/pci/msi-apic.c > > I agree in theory. In practice however msi interrupts look like io_apics. > with a different register set and the use all of the same support facilities. > So until that part of the architecture is refactored it doesn't make much > sense. There is a slightly better case for moving the code into a separate > file. Namely I think I know of a second common implementation for x86_64. > At which point the files will probably be named msi-intel.c and msi-amd.c > Or something like that. > Actually, I meant just the vector tracking code could be in a separate file and the ioapic and msi code could both assign vectors from a common routine. I had the patch below in my patchkit, plus another patch for x86_64 to do the same thing in io_apic.c and share the same intrvec.c file between the two archs. Once you have this, the MSI callbacks in arch code can be moved out of io_apic.c arch/i386/kernel/Makefile | 2 arch/i386/kernel/intrvec.c | 94 ++++++++++++++++++++++++++++ arch/i386/kernel/io_apic.c | 26 ++----- include/asm-i386/mach-default/irq_vectors.h | 1 4 files changed, 105 insertions(+), 18 deletions(-) Index: linux-2.6.17-rc6-mm2/arch/i386/kernel/intrvec.c =================================================================== --- /dev/null +++ linux-2.6.17-rc6-mm2/arch/i386/kernel/intrvec.c @@ -0,0 +1,94 @@ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2006 Intel Corporation (rajesh.shah@xxxxxxxxx) + * + */ + +#include <linux/irq.h> + +/* + * Code to manage interrupt vectors to program for IO-APIC and PCI + * Message Signalled Interrupts (MSI/MSI-X) + */ +#define VECTOR_STRIDE 8 +#define NUM_VECTORS (FIRST_SYSTEM_VECTOR-FIRST_DEVICE_VECTOR) + +static DEFINE_SPINLOCK(intr_vector_lock); +static DECLARE_BITMAP(vectors_used, NUM_VECTORS); +int current_vector = FIRST_DEVICE_VECTOR; +int offset = 0; + +static inline void mark_vector_used(int vector) +{ + if ((vector >= FIRST_DEVICE_VECTOR) && (vector < FIRST_SYSTEM_VECTOR)) + set_bit((vector - FIRST_DEVICE_VECTOR), vectors_used); +} + +static inline void mark_vector_free(int vector) +{ + if ((vector >= FIRST_DEVICE_VECTOR) && (vector < FIRST_SYSTEM_VECTOR)) + clear_bit((vector - FIRST_DEVICE_VECTOR), vectors_used); +} + +static inline int is_used(int vector) +{ + if ((vector < FIRST_DEVICE_VECTOR) || (vector >= FIRST_SYSTEM_VECTOR)) + return 1; + return (test_bit((vector - FIRST_DEVICE_VECTOR), vectors_used)); +} + +int assign_vector(void) +{ + unsigned long flags; + int vector; + + spin_lock_irqsave(&intr_vector_lock, flags); + if (bitmap_full(vectors_used, NUM_VECTORS)) { + spin_unlock_irqrestore(&intr_vector_lock, flags); + return -1; + } + vector = current_vector; + while (is_used(vector)) { + vector += VECTOR_STRIDE; + if (vector >= FIRST_SYSTEM_VECTOR) + vector = FIRST_DEVICE_VECTOR + + (++offset % VECTOR_STRIDE); + } + mark_vector_used(vector); + current_vector = vector; + spin_unlock_irqrestore(&intr_vector_lock, flags); + return vector; +} + +void free_vector(int vector) +{ + unsigned long flags; + + spin_lock_irqsave(&intr_vector_lock, flags); + mark_vector_free(vector); + current_vector = vector; /* use this vector at next request */ + spin_unlock_irqrestore(&intr_vector_lock, flags); +} + +static int __init init_vector_array(void) +{ + mark_vector_used(IA32_SYSCALL_VECTOR); + return 0; +} + +core_initcall(init_vector_array); + Index: linux-2.6.17-rc6-mm2/arch/i386/kernel/Makefile =================================================================== --- linux-2.6.17-rc6-mm2.orig/arch/i386/kernel/Makefile +++ linux-2.6.17-rc6-mm2/arch/i386/kernel/Makefile @@ -21,7 +21,7 @@ obj-$(CONFIG_X86_SMP) += smp.o smpboot. obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o obj-$(CONFIG_X86_MPPARSE) += mpparse.o obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o -obj-$(CONFIG_X86_IO_APIC) += io_apic.o +obj-$(CONFIG_X86_IO_APIC) += io_apic.o intrvec.o obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o Index: linux-2.6.17-rc6-mm2/arch/i386/kernel/io_apic.c =================================================================== --- linux-2.6.17-rc6-mm2.orig/arch/i386/kernel/io_apic.c +++ linux-2.6.17-rc6-mm2/arch/i386/kernel/io_apic.c @@ -95,6 +95,8 @@ int vector_irq[NR_VECTORS] __read_mostly #define vector_to_irq(vector) (vector) #endif +extern int assign_vector(void); + /* * The common case is 1:1 IRQ<->pin mappings. Sometimes there are * shared ISA-space IRQs, so we have to support them. We are super @@ -1163,38 +1165,28 @@ u8 irq_vector[NR_IRQ_VECTORS] __read_mos int assign_irq_vector(int irq) { - static int current_vector = FIRST_DEVICE_VECTOR, offset = 0; - unsigned long flags; int vector; BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS); - spin_lock_irqsave(&vector_lock, flags); + spin_lock(&vector_lock); if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) { - spin_unlock_irqrestore(&vector_lock, flags); + spin_unlock(&vector_lock); return IO_APIC_VECTOR(irq); } -next: - current_vector += 8; - if (current_vector == SYSCALL_VECTOR) - goto next; - if (current_vector >= FIRST_SYSTEM_VECTOR) { - offset++; - if (!(offset%8)) { - spin_unlock_irqrestore(&vector_lock, flags); - return -ENOSPC; - } - current_vector = FIRST_DEVICE_VECTOR + offset; + vector = assign_vector(); + if (vector < 0) { + spin_unlock(&vector_lock); + return -1; } - vector = current_vector; vector_irq[vector] = irq; if (irq != AUTO_ASSIGN) IO_APIC_VECTOR(irq) = vector; - spin_unlock_irqrestore(&vector_lock, flags); + spin_unlock(&vector_lock); return vector; } Index: linux-2.6.17-rc6-mm2/include/asm-i386/mach-default/irq_vectors.h =================================================================== --- linux-2.6.17-rc6-mm2.orig/include/asm-i386/mach-default/irq_vectors.h +++ linux-2.6.17-rc6-mm2/include/asm-i386/mach-default/irq_vectors.h @@ -29,6 +29,7 @@ #define FIRST_EXTERNAL_VECTOR 0x20 #define SYSCALL_VECTOR 0x80 +#define IA32_SYSCALL_VECTOR SYSCALL_VECTOR /* * Vectors 0x20-0x2f are used for ISA interrupts. - To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html