# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.523 -> 1.524 # arch/i386/kernel/process.c 1.19.1.20 -> 1.29 # arch/i386/kernel/visws_apic.c 1.2 -> 1.4 arch/i386/mach-visws/visws_apic.c (moved) # include/asm-i386/irq.h 1.6 -> 1.7 # arch/i386/kernel/setup-visws.c 1.1.1.1 -> 1.5 arch/i386/mach-visws/setup.c (moved) # arch/i386/kernel/traps.c 1.19.1.9 -> 1.27 # arch/i386/kernel/Makefile 1.5.1.16 -> 1.19 # arch/i386/kernel/mca.c 1.4.1.1 -> 1.7 # include/asm-i386/irq_vectors.h 1.1 -> 1.4 arch/i386/mach-generic/irq_vectors.h (moved) # arch/i386/kernel/entry.S 1.26.1.15 -> 1.35 # arch/i386/kernel/cpu/intel.c 1.2.1.3 -> 1.6 # arch/i386/kernel/mpparse.c 1.7.6.6 -> 1.19 # arch/i386/config.in 1.27.1.19 -> 1.43 # arch/i386/Makefile 1.3.1.13 -> 1.12 # arch/i386/pci/common.c 1.19.3.10 -> 1.31 # fs/binfmt_elf.c 1.22.1.4 -> 1.26 # arch/i386/kernel/setup.c 1.41.1.18 -> 1.59 # arch/i386/kernel/smpboot.c 1.17.1.14 -> 1.32 # arch/i386/kernel/time.c 1.7.1.4 -> 1.12 # arch/i386/pci/Makefile 1.10 -> 1.11 # arch/i386/pci/visws.c 1.2.1.3 -> 1.6 arch/i386/mach-visws/pci-visws.c (moved) # arch/i386/kernel/i8259.c 1.7.1.9 -> 1.17 # arch/i386/pci/irq.c 1.11.3.7 -> 1.19 # arch/i386/kernel/apic.c 1.12.1.12 -> 1.20 # (new) -> 1.4 arch/i386/mach-generic/entry_arch.h # (new) -> 1.2 include/asm-i386/arch_hooks.h # (new) -> 1.2 arch/i386/mach-generic/setup_arch_pre.h # (new) -> 1.2 arch/i386/mach-visws/irq_vectors.h # (new) -> 1.1 arch/i386/mach-visws/smpboot_hooks.h # (new) -> 1.3 arch/i386/mach-visws/mpparse.c # (new) -> 1.6 arch/i386/mach-generic/setup_arch_post.h # (new) -> 1.3 arch/i386/mach-generic/Makefile # (new) -> 1.4 arch/i386/kernel/reboot.c # (new) -> 1.3 arch/i386/mach-visws/do_timer.h # (new) -> 1.1 arch/i386/mach-generic/smpboot_hooks.h # (new) -> 1.2 arch/i386/mach-visws/setup_arch_pre.h # (new) -> 1.4 arch/i386/mach-generic/do_timer.h # (new) -> 1.4 arch/i386/mach-generic/setup.c # (new) -> 1.6 arch/i386/mach-visws/setup_arch_post.h # (new) -> 1.2 arch/i386/mach-visws/traps.c # (new) -> 1.3 arch/i386/mach-visws/Makefile # (new) -> 1.2 arch/i386/mach-visws/entry_arch.h # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/08/27 jejb@mulgrave.(none) 1.524 # Merge mulgrave.(none):/home/jejb/BK/linux-2.5 # into mulgrave.(none):/home/jejb/BK/arch-split-2.5 # -------------------------------------------- # diff -Nru a/arch/i386/Makefile b/arch/i386/Makefile --- a/arch/i386/Makefile Thu Aug 29 08:48:01 2002 +++ b/arch/i386/Makefile Thu Aug 29 08:48:01 2002 @@ -85,12 +85,24 @@ CFLAGS += -march=i586 endif +ifdef CONFIG_VISWS +MACHINE := mach-visws +else +MACHINE := mach-generic +endif + HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o -SUBDIRS += arch/i386/kernel arch/i386/mm arch/i386/lib +SUBDIRS += arch/i386/kernel arch/i386/mm arch/i386/lib \ + arch/i386/$(MACHINE) + +CORE_FILES := arch/i386/kernel/kernel.o arch/i386/mm/mm.o \ + arch/i386/$(MACHINE)/$(MACHINE).o $(CORE_FILES) -CORE_FILES := arch/i386/kernel/kernel.o arch/i386/mm/mm.o $(CORE_FILES) LIBS := $(TOPDIR)/arch/i386/lib/lib.a $(LIBS) $(TOPDIR)/arch/i386/lib/lib.a + +CFLAGS += -I$(TOPDIR)/arch/i386/$(MACHINE) +AFLAGS += -I$(TOPDIR)/arch/i386/$(MACHINE) ifdef CONFIG_MATH_EMULATION SUBDIRS += arch/i386/math-emu diff -Nru a/arch/i386/config.in b/arch/i386/config.in --- a/arch/i386/config.in Thu Aug 29 08:48:01 2002 +++ b/arch/i386/config.in Thu Aug 29 08:48:01 2002 @@ -239,6 +239,7 @@ if [ "$CONFIG_SMP" = "y" ]; then define_bool CONFIG_X86_IO_APIC y define_bool CONFIG_X86_LOCAL_APIC y + define_bool CONFIG_X86_MPPARSE y fi bool 'PCI support' CONFIG_PCI if [ "$CONFIG_PCI" = "y" ]; then @@ -416,7 +417,19 @@ fi fi +if [ "$CONFIG_X86_LOCAL_APIC" = "y" ]; then + define_bool CONFIG_X86_EXTRA_IRQS y + define_bool CONFIG_X86_FIND_SMP_CONFIG y +fi + endmenu source security/Config.in source lib/Config.in + +if [ "$CONFIG_SMP" = "y" ]; then + define_bool CONFIG_X86_SMP y + define_bool CONFIG_X86_HT y +fi + +define_bool CONFIG_X86_BIOS_REBOOT y diff -Nru a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile --- a/arch/i386/kernel/Makefile Thu Aug 29 08:48:01 2002 +++ b/arch/i386/kernel/Makefile Thu Aug 29 08:48:01 2002 @@ -14,21 +14,17 @@ bootflag.o obj-y += cpu/ +obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o obj-$(CONFIG_MCA) += mca.o obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_APM) += apm.o -obj-$(CONFIG_ACPI) += acpi.o -obj-$(CONFIG_ACPI_SLEEP) += acpi_wakeup.o -obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o -obj-$(CONFIG_X86_LOCAL_APIC) += mpparse.o apic.o nmi.o +obj-$(CONFIG_X86_SMP) += smp.o smpboot.o 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_SOFTWARE_SUSPEND) += suspend.o -ifdef CONFIG_VISWS -obj-y += setup-visws.o -obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o -endif EXTRA_AFLAGS := -traditional diff -Nru a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c --- a/arch/i386/kernel/apic.c Thu Aug 29 08:48:01 2002 +++ b/arch/i386/kernel/apic.c Thu Aug 29 08:48:01 2002 @@ -29,6 +29,21 @@ #include #include #include +#include +#include + +void __init apic_intr_init(void) +{ +#ifdef CONFIG_SMP + smp_intr_init(); +#endif + /* self generated IPI for local APIC timer */ + set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); + + /* IPI vectors for APIC spurious and error interrupts */ + set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); + set_intr_gate(ERROR_APIC_VECTOR, error_interrupt); +} /* Using APIC to generate smp_local_timer_interrupt? */ int using_apic_timer = 0; diff -Nru a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c --- a/arch/i386/kernel/cpu/intel.c Thu Aug 29 08:48:01 2002 +++ b/arch/i386/kernel/cpu/intel.c Thu Aug 29 08:48:01 2002 @@ -257,7 +257,7 @@ if ( p ) strcpy(c->x86_model_id, p); -#ifdef CONFIG_SMP +#ifdef CONFIG_X86_HT if (test_bit(X86_FEATURE_HT, c->x86_capability) && !disable_P4_HT) { extern int phys_proc_id[NR_CPUS]; diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S --- a/arch/i386/kernel/entry.S Thu Aug 29 08:48:01 2002 +++ b/arch/i386/kernel/entry.S Thu Aug 29 08:48:01 2002 @@ -47,7 +47,7 @@ #include #include #include -#include +#include "irq_vectors.h" EBX = 0x00 ECX = 0x04 @@ -344,34 +344,8 @@ call smp_/**/name; \ jmp ret_from_intr; -/* - * The following vectors are part of the Linux architecture, there - * is no hardware IRQ pin equivalent for them, they are triggered - * through the ICC by us (IPIs) - */ -#ifdef CONFIG_SMP -BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR) -BUILD_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR) -BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR) -#endif - -/* - * every pentium local APIC has two 'local interrupts', with a - * soft-definable vector attached to both interrupts, one of - * which is a timer interrupt, the other one is error counter - * overflow. Linux uses the local APIC timer interrupt to get - * a much simpler SMP time architecture: - */ -#ifdef CONFIG_X86_LOCAL_APIC -BUILD_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR) -BUILD_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR) -BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR) - -#ifdef CONFIG_X86_MCE_P4THERMAL -BUILD_INTERRUPT(thermal_interrupt,THERMAL_APIC_VECTOR) -#endif - -#endif +/* The include is where all of the SMP etc. interrupts come from */ +#include "entry_arch.h" ENTRY(divide_error) pushl $0 # no error code diff -Nru a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c --- a/arch/i386/kernel/i8259.c Thu Aug 29 08:48:01 2002 +++ b/arch/i386/kernel/i8259.c Thu Aug 29 08:48:01 2002 @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -332,15 +333,6 @@ */ static struct irqaction irq13 = { math_error_irq, 0, 0, "fpu", NULL, NULL }; -/* - * IRQ2 is cascade interrupt to second interrupt controller - */ - -#ifndef CONFIG_VISWS -static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL}; -#endif - - void __init init_ISA_irqs (void) { int i; @@ -373,11 +365,9 @@ { int i; -#ifndef CONFIG_X86_VISWS_APIC - init_ISA_irqs(); -#else - init_VISWS_APIC_irqs(); -#endif + /* all the set up before the call gates are initialised */ + pre_intr_init_hook(); + /* * Cover the whole vector space, no vector can escape * us. (some of these will be overridden and become @@ -389,39 +379,9 @@ set_intr_gate(vector, interrupt[i]); } -#ifdef CONFIG_SMP - /* - * IRQ0 must be given a fixed assignment and initialized, - * because it's used before the IO-APIC is set up. - */ - set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]); - - /* - * The reschedule interrupt is a CPU-to-CPU reschedule-helper - * IPI, driven by wakeup. - */ - set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); - - /* IPI for invalidation */ - set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt); - - /* IPI for generic function call */ - set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); -#endif - -#ifdef CONFIG_X86_LOCAL_APIC - /* self generated IPI for local APIC timer */ - set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt); - - /* IPI vectors for APIC spurious and error interrupts */ - set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); - set_intr_gate(ERROR_APIC_VECTOR, error_interrupt); - - /* thermal monitor LVT interrupt */ -#ifdef CONFIG_X86_MCE_P4THERMAL - set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); -#endif -#endif + /* setup after call gates are initialised (usually add in + * the architecture specific gates */ + intr_init_hook(); /* * Set the clock to HZ Hz, we already have a valid @@ -430,10 +390,6 @@ outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ outb_p(LATCH & 0xff , 0x40); /* LSB */ outb(LATCH >> 8 , 0x40); /* MSB */ - -#ifndef CONFIG_VISWS - setup_irq(2, &irq2); -#endif /* * External FPU? Set up irq13 if so, for diff -Nru a/arch/i386/kernel/mca.c b/arch/i386/kernel/mca.c --- a/arch/i386/kernel/mca.c Thu Aug 29 08:48:01 2002 +++ b/arch/i386/kernel/mca.c Thu Aug 29 08:48:01 2002 @@ -52,6 +52,7 @@ #include #include #include +#include /* This structure holds MCA information. Each (plug-in) adapter has * eight POS registers. Then the machine may have integrated video and @@ -379,12 +380,7 @@ } } - /* If I recall correctly, there's a whole bunch of other things that - * we can do to check for NMI problems, but that's all I know about - * at the moment. - */ - - printk("NMI generated from unknown source!\n"); + mca_nmi_hook(); } /* mca_handle_nmi */ /*--------------------------------------------------------------------*/ diff -Nru a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c --- a/arch/i386/kernel/mpparse.c Thu Aug 29 08:48:01 2002 +++ b/arch/i386/kernel/mpparse.c Thu Aug 29 08:48:01 2002 @@ -73,7 +73,7 @@ * Intel MP BIOS table parsing routines: */ -#ifndef CONFIG_X86_VISWS_APIC + /* * Checksum an MP configuration block. */ @@ -737,7 +737,7 @@ return 0; } -void __init find_intel_smp (void) +void __init find_smp_config (void) { unsigned int address; @@ -775,40 +775,6 @@ smp_scan_config(address, 0x400); if (smp_found_config) printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.kernel.org if you experience SMP problems!\n"); -} - -#else - -/* - * The Visual Workstation is Intel MP compliant in the hardware - * sense, but it doesn't have a BIOS(-configuration table). - * No problem for Linux. - */ -void __init find_visws_smp(void) -{ - smp_found_config = 1; - - phys_cpu_present_map |= 2; /* or in id 1 */ - apic_version[1] |= 0x10; /* integrated APIC */ - apic_version[0] |= 0x10; - - mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; -} - -#endif - -/* - * - Intel MP Configuration Table - * - or SGI Visual Workstation configuration - */ -void __init find_smp_config (void) -{ -#ifdef CONFIG_X86_LOCAL_APIC - find_intel_smp(); -#endif -#ifdef CONFIG_VISWS - find_visws_smp(); -#endif } diff -Nru a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c --- a/arch/i386/kernel/process.c Thu Aug 29 08:48:01 2002 +++ b/arch/i386/kernel/process.c Thu Aug 29 08:48:01 2002 @@ -66,11 +66,6 @@ */ void (*pm_idle)(void); -/* - * Power off function, if any - */ -void (*pm_power_off)(void); - void disable_hlt(void) { hlt_counter++; @@ -159,282 +154,6 @@ } __setup("idle=", idle_setup); - -static long no_idt[2]; -static int reboot_mode; -int reboot_thru_bios; - -#ifdef CONFIG_SMP -int reboot_smp = 0; -static int reboot_cpu = -1; -/* shamelessly grabbed from lib/vsprintf.c for readability */ -#define is_digit(c) ((c) >= '0' && (c) <= '9') -#endif -static int __init reboot_setup(char *str) -{ - while(1) { - switch (*str) { - case 'w': /* "warm" reboot (no memory testing etc) */ - reboot_mode = 0x1234; - break; - case 'c': /* "cold" reboot (with memory testing etc) */ - reboot_mode = 0x0; - break; - case 'b': /* "bios" reboot by jumping through the BIOS */ - reboot_thru_bios = 1; - break; - case 'h': /* "hard" reboot by toggling RESET and/or crashing the CPU */ - reboot_thru_bios = 0; - break; -#ifdef CONFIG_SMP - case 's': /* "smp" reboot by executing reset on BSP or other CPU*/ - reboot_smp = 1; - if (is_digit(*(str+1))) { - reboot_cpu = (int) (*(str+1) - '0'); - if (is_digit(*(str+2))) - reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0'); - } - /* we will leave sorting out the final value - when we are ready to reboot, since we might not - have set up boot_cpu_id or smp_num_cpu */ - break; -#endif - } - if((str = strchr(str,',')) != NULL) - str++; - else - break; - } - return 1; -} - -__setup("reboot=", reboot_setup); - -/* The following code and data reboots the machine by switching to real - mode and jumping to the BIOS reset entry point, as if the CPU has - really been reset. The previous version asked the keyboard - controller to pulse the CPU reset line, which is more thorough, but - doesn't work with at least one type of 486 motherboard. It is easy - to stop this code working; hence the copious comments. */ - -static unsigned long long -real_mode_gdt_entries [3] = -{ - 0x0000000000000000ULL, /* Null descriptor */ - 0x00009a000000ffffULL, /* 16-bit real-mode 64k code at 0x00000000 */ - 0x000092000100ffffULL /* 16-bit real-mode 64k data at 0x00000100 */ -}; - -static struct -{ - unsigned short size __attribute__ ((packed)); - unsigned long long * base __attribute__ ((packed)); -} -real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, real_mode_gdt_entries }, -real_mode_idt = { 0x3ff, 0 }; - -/* This is 16-bit protected mode code to disable paging and the cache, - switch to real mode and jump to the BIOS reset code. - - The instruction that switches to real mode by writing to CR0 must be - followed immediately by a far jump instruction, which set CS to a - valid value for real mode, and flushes the prefetch queue to avoid - running instructions that have already been decoded in protected - mode. - - Clears all the flags except ET, especially PG (paging), PE - (protected-mode enable) and TS (task switch for coprocessor state - save). Flushes the TLB after paging has been disabled. Sets CD and - NW, to disable the cache on a 486, and invalidates the cache. This - is more like the state of a 486 after reset. I don't know if - something else should be done for other chips. - - More could be done here to set up the registers as if a CPU reset had - occurred; hopefully real BIOSs don't assume much. */ - -static unsigned char real_mode_switch [] = -{ - 0x66, 0x0f, 0x20, 0xc0, /* movl %cr0,%eax */ - 0x66, 0x83, 0xe0, 0x11, /* andl $0x00000011,%eax */ - 0x66, 0x0d, 0x00, 0x00, 0x00, 0x60, /* orl $0x60000000,%eax */ - 0x66, 0x0f, 0x22, 0xc0, /* movl %eax,%cr0 */ - 0x66, 0x0f, 0x22, 0xd8, /* movl %eax,%cr3 */ - 0x66, 0x0f, 0x20, 0xc3, /* movl %cr0,%ebx */ - 0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60, /* andl $0x60000000,%ebx */ - 0x74, 0x02, /* jz f */ - 0x0f, 0x08, /* invd */ - 0x24, 0x10, /* f: andb $0x10,al */ - 0x66, 0x0f, 0x22, 0xc0 /* movl %eax,%cr0 */ -}; -static unsigned char jump_to_bios [] = -{ - 0xea, 0x00, 0x00, 0xff, 0xff /* ljmp $0xffff,$0x0000 */ -}; - -static inline void kb_wait(void) -{ - int i; - - for (i=0; i<0x10000; i++) - if ((inb_p(0x64) & 0x02) == 0) - break; -} - -/* - * Switch to real mode and then execute the code - * specified by the code and length parameters. - * We assume that length will aways be less that 100! - */ -void machine_real_restart(unsigned char *code, int length) -{ - unsigned long flags; - - local_irq_disable(); - - /* Write zero to CMOS register number 0x0f, which the BIOS POST - routine will recognize as telling it to do a proper reboot. (Well - that's what this book in front of me says -- it may only apply to - the Phoenix BIOS though, it's not clear). At the same time, - disable NMIs by setting the top bit in the CMOS address register, - as we're about to do peculiar things to the CPU. I'm not sure if - `outb_p' is needed instead of just `outb'. Use it to be on the - safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.) - */ - - spin_lock_irqsave(&rtc_lock, flags); - CMOS_WRITE(0x00, 0x8f); - spin_unlock_irqrestore(&rtc_lock, flags); - - /* Remap the kernel at virtual address zero, as well as offset zero - from the kernel segment. This assumes the kernel segment starts at - virtual address PAGE_OFFSET. */ - - memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, - sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS); - - /* - * Use `swapper_pg_dir' as our page directory. - */ - load_cr3(swapper_pg_dir); - - /* Write 0x1234 to absolute memory location 0x472. The BIOS reads - this on booting to tell it to "Bypass memory test (also warm - boot)". This seems like a fairly standard thing that gets set by - REBOOT.COM programs, and the previous reset routine did this - too. */ - - *((unsigned short *)0x472) = reboot_mode; - - /* For the switch to real mode, copy some code to low memory. It has - to be in the first 64k because it is running in 16-bit mode, and it - has to have the same physical and virtual address, because it turns - off paging. Copy it near the end of the first page, out of the way - of BIOS variables. */ - - memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100), - real_mode_switch, sizeof (real_mode_switch)); - memcpy ((void *) (0x1000 - 100), code, length); - - /* Set up the IDT for real mode. */ - - __asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt)); - - /* Set up a GDT from which we can load segment descriptors for real - mode. The GDT is not used in real mode; it is just needed here to - prepare the descriptors. */ - - __asm__ __volatile__ ("lgdt %0" : : "m" (real_mode_gdt)); - - /* Load the data segment registers, and thus the descriptors ready for - real mode. The base address of each segment is 0x100, 16 times the - selector value being loaded here. This is so that the segment - registers don't have to be reloaded after switching to real mode: - the values are consistent for real mode operation already. */ - - __asm__ __volatile__ ("movl $0x0010,%%eax\n" - "\tmovl %%eax,%%ds\n" - "\tmovl %%eax,%%es\n" - "\tmovl %%eax,%%fs\n" - "\tmovl %%eax,%%gs\n" - "\tmovl %%eax,%%ss" : : : "eax"); - - /* Jump to the 16-bit code that we copied earlier. It disables paging - and the cache, switches to real mode, and jumps to the BIOS reset - entry point. */ - - __asm__ __volatile__ ("ljmp $0x0008,%0" - : - : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100))); -} - -void machine_restart(char * __unused) -{ -#if CONFIG_SMP - int cpuid; - - cpuid = GET_APIC_ID(apic_read(APIC_ID)); - - if (reboot_smp) { - - /* check to see if reboot_cpu is valid - if its not, default to the BSP */ - if ((reboot_cpu == -1) || - (reboot_cpu > (NR_CPUS -1)) || - !(phys_cpu_present_map & (1< + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_MATH_EMULATION +#include +#endif + +#include +#include + +/* + * Power off function, if any + */ +void (*pm_power_off)(void); + +static long no_idt[2]; +static int reboot_mode; +int reboot_thru_bios; + +#ifdef CONFIG_SMP +int reboot_smp = 0; +static int reboot_cpu = -1; +/* shamelessly grabbed from lib/vsprintf.c for readability */ +#define is_digit(c) ((c) >= '0' && (c) <= '9') +#endif +static int __init reboot_setup(char *str) +{ + while(1) { + switch (*str) { + case 'w': /* "warm" reboot (no memory testing etc) */ + reboot_mode = 0x1234; + break; + case 'c': /* "cold" reboot (with memory testing etc) */ + reboot_mode = 0x0; + break; + case 'b': /* "bios" reboot by jumping through the BIOS */ + reboot_thru_bios = 1; + break; + case 'h': /* "hard" reboot by toggling RESET and/or crashing the CPU */ + reboot_thru_bios = 0; + break; +#ifdef CONFIG_SMP + case 's': /* "smp" reboot by executing reset on BSP or other CPU*/ + reboot_smp = 1; + if (is_digit(*(str+1))) { + reboot_cpu = (int) (*(str+1) - '0'); + if (is_digit(*(str+2))) + reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0'); + } + /* we will leave sorting out the final value + when we are ready to reboot, since we might not + have set up boot_cpu_id or smp_num_cpu */ + break; +#endif + } + if((str = strchr(str,',')) != NULL) + str++; + else + break; + } + return 1; +} + +__setup("reboot=", reboot_setup); + +/* The following code and data reboots the machine by switching to real + mode and jumping to the BIOS reset entry point, as if the CPU has + really been reset. The previous version asked the keyboard + controller to pulse the CPU reset line, which is more thorough, but + doesn't work with at least one type of 486 motherboard. It is easy + to stop this code working; hence the copious comments. */ + +static unsigned long long +real_mode_gdt_entries [3] = +{ + 0x0000000000000000ULL, /* Null descriptor */ + 0x00009a000000ffffULL, /* 16-bit real-mode 64k code at 0x00000000 */ + 0x000092000100ffffULL /* 16-bit real-mode 64k data at 0x00000100 */ +}; + +static struct +{ + unsigned short size __attribute__ ((packed)); + unsigned long long * base __attribute__ ((packed)); +} +real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, real_mode_gdt_entries }, +real_mode_idt = { 0x3ff, 0 }; + +/* This is 16-bit protected mode code to disable paging and the cache, + switch to real mode and jump to the BIOS reset code. + + The instruction that switches to real mode by writing to CR0 must be + followed immediately by a far jump instruction, which set CS to a + valid value for real mode, and flushes the prefetch queue to avoid + running instructions that have already been decoded in protected + mode. + + Clears all the flags except ET, especially PG (paging), PE + (protected-mode enable) and TS (task switch for coprocessor state + save). Flushes the TLB after paging has been disabled. Sets CD and + NW, to disable the cache on a 486, and invalidates the cache. This + is more like the state of a 486 after reset. I don't know if + something else should be done for other chips. + + More could be done here to set up the registers as if a CPU reset had + occurred; hopefully real BIOSs don't assume much. */ + +static unsigned char real_mode_switch [] = +{ + 0x66, 0x0f, 0x20, 0xc0, /* movl %cr0,%eax */ + 0x66, 0x83, 0xe0, 0x11, /* andl $0x00000011,%eax */ + 0x66, 0x0d, 0x00, 0x00, 0x00, 0x60, /* orl $0x60000000,%eax */ + 0x66, 0x0f, 0x22, 0xc0, /* movl %eax,%cr0 */ + 0x66, 0x0f, 0x22, 0xd8, /* movl %eax,%cr3 */ + 0x66, 0x0f, 0x20, 0xc3, /* movl %cr0,%ebx */ + 0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60, /* andl $0x60000000,%ebx */ + 0x74, 0x02, /* jz f */ + 0x0f, 0x08, /* invd */ + 0x24, 0x10, /* f: andb $0x10,al */ + 0x66, 0x0f, 0x22, 0xc0 /* movl %eax,%cr0 */ +}; +static unsigned char jump_to_bios [] = +{ + 0xea, 0x00, 0x00, 0xff, 0xff /* ljmp $0xffff,$0x0000 */ +}; + +static inline void kb_wait(void) +{ + int i; + + for (i=0; i<0x10000; i++) + if ((inb_p(0x64) & 0x02) == 0) + break; +} + +/* + * Switch to real mode and then execute the code + * specified by the code and length parameters. + * We assume that length will aways be less that 100! + */ +void machine_real_restart(unsigned char *code, int length) +{ + unsigned long flags; + + local_irq_disable(); + + /* Write zero to CMOS register number 0x0f, which the BIOS POST + routine will recognize as telling it to do a proper reboot. (Well + that's what this book in front of me says -- it may only apply to + the Phoenix BIOS though, it's not clear). At the same time, + disable NMIs by setting the top bit in the CMOS address register, + as we're about to do peculiar things to the CPU. I'm not sure if + `outb_p' is needed instead of just `outb'. Use it to be on the + safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.) + */ + + spin_lock_irqsave(&rtc_lock, flags); + CMOS_WRITE(0x00, 0x8f); + spin_unlock_irqrestore(&rtc_lock, flags); + + /* Remap the kernel at virtual address zero, as well as offset zero + from the kernel segment. This assumes the kernel segment starts at + virtual address PAGE_OFFSET. */ + + memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, + sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS); + + /* + * Use `swapper_pg_dir' as our page directory. + */ + load_cr3(swapper_pg_dir); + + /* Write 0x1234 to absolute memory location 0x472. The BIOS reads + this on booting to tell it to "Bypass memory test (also warm + boot)". This seems like a fairly standard thing that gets set by + REBOOT.COM programs, and the previous reset routine did this + too. */ + + *((unsigned short *)0x472) = reboot_mode; + + /* For the switch to real mode, copy some code to low memory. It has + to be in the first 64k because it is running in 16-bit mode, and it + has to have the same physical and virtual address, because it turns + off paging. Copy it near the end of the first page, out of the way + of BIOS variables. */ + + memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100), + real_mode_switch, sizeof (real_mode_switch)); + memcpy ((void *) (0x1000 - 100), code, length); + + /* Set up the IDT for real mode. */ + + __asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt)); + + /* Set up a GDT from which we can load segment descriptors for real + mode. The GDT is not used in real mode; it is just needed here to + prepare the descriptors. */ + + __asm__ __volatile__ ("lgdt %0" : : "m" (real_mode_gdt)); + + /* Load the data segment registers, and thus the descriptors ready for + real mode. The base address of each segment is 0x100, 16 times the + selector value being loaded here. This is so that the segment + registers don't have to be reloaded after switching to real mode: + the values are consistent for real mode operation already. */ + + __asm__ __volatile__ ("movl $0x0010,%%eax\n" + "\tmovl %%eax,%%ds\n" + "\tmovl %%eax,%%es\n" + "\tmovl %%eax,%%fs\n" + "\tmovl %%eax,%%gs\n" + "\tmovl %%eax,%%ss" : : : "eax"); + + /* Jump to the 16-bit code that we copied earlier. It disables paging + and the cache, switches to real mode, and jumps to the BIOS reset + entry point. */ + + __asm__ __volatile__ ("ljmp $0x0008,%0" + : + : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100))); +} + +void machine_restart(char * __unused) +{ +#if CONFIG_SMP + int cpuid; + + cpuid = GET_APIC_ID(apic_read(APIC_ID)); + + if (reboot_smp) { + + /* check to see if reboot_cpu is valid + if its not, default to the BSP */ + if ((reboot_cpu == -1) || + (reboot_cpu > (NR_CPUS -1)) || + !(phys_cpu_present_map & (1< - -char visws_board_type = -1; -char visws_board_rev = -1; - -#define PIIX_PM_START 0x0F80 - -#define SIO_GPIO_START 0x0FC0 - -#define SIO_PM_START 0x0FC8 - -#define PMBASE PIIX_PM_START -#define GPIREG0 (PMBASE+0x30) -#define GPIREG(x) (GPIREG0+((x)/8)) -#define PIIX_GPI_BD_ID1 18 -#define PIIX_GPI_BD_REG GPIREG(PIIX_GPI_BD_ID1) - -#define PIIX_GPI_BD_SHIFT (PIIX_GPI_BD_ID1 % 8) - -#define SIO_INDEX 0x2e -#define SIO_DATA 0x2f - -#define SIO_DEV_SEL 0x7 -#define SIO_DEV_ENB 0x30 -#define SIO_DEV_MSB 0x60 -#define SIO_DEV_LSB 0x61 - -#define SIO_GP_DEV 0x7 - -#define SIO_GP_BASE SIO_GPIO_START -#define SIO_GP_MSB (SIO_GP_BASE>>8) -#define SIO_GP_LSB (SIO_GP_BASE&0xff) - -#define SIO_GP_DATA1 (SIO_GP_BASE+0) - -#define SIO_PM_DEV 0x8 - -#define SIO_PM_BASE SIO_PM_START -#define SIO_PM_MSB (SIO_PM_BASE>>8) -#define SIO_PM_LSB (SIO_PM_BASE&0xff) -#define SIO_PM_INDEX (SIO_PM_BASE+0) -#define SIO_PM_DATA (SIO_PM_BASE+1) - -#define SIO_PM_FER2 0x1 - -#define SIO_PM_GP_EN 0x80 - -void __init visws_get_board_type_and_rev(void) -{ - int raw; - - visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG) - >> PIIX_GPI_BD_SHIFT; -/* - * Get Board rev. - * First, we have to initialize the 307 part to allow us access - * to the GPIO registers. Let's map them at 0x0fc0 which is right - * after the PIIX4 PM section. - */ - outb_p(SIO_DEV_SEL, SIO_INDEX); - outb_p(SIO_GP_DEV, SIO_DATA); /* Talk to GPIO regs. */ - - outb_p(SIO_DEV_MSB, SIO_INDEX); - outb_p(SIO_GP_MSB, SIO_DATA); /* MSB of GPIO base address */ - - outb_p(SIO_DEV_LSB, SIO_INDEX); - outb_p(SIO_GP_LSB, SIO_DATA); /* LSB of GPIO base address */ - - outb_p(SIO_DEV_ENB, SIO_INDEX); - outb_p(1, SIO_DATA); /* Enable GPIO registers. */ - -/* - * Now, we have to map the power management section to write - * a bit which enables access to the GPIO registers. - * What lunatic came up with this shit? - */ - outb_p(SIO_DEV_SEL, SIO_INDEX); - outb_p(SIO_PM_DEV, SIO_DATA); /* Talk to GPIO regs. */ - - outb_p(SIO_DEV_MSB, SIO_INDEX); - outb_p(SIO_PM_MSB, SIO_DATA); /* MSB of PM base address */ - - outb_p(SIO_DEV_LSB, SIO_INDEX); - outb_p(SIO_PM_LSB, SIO_DATA); /* LSB of PM base address */ - - outb_p(SIO_DEV_ENB, SIO_INDEX); - outb_p(1, SIO_DATA); /* Enable PM registers. */ - -/* - * Now, write the PM register which enables the GPIO registers. - */ - outb_p(SIO_PM_FER2, SIO_PM_INDEX); - outb_p(SIO_PM_GP_EN, SIO_PM_DATA); - -/* - * Now, initialize the GPIO registers. - * We want them all to be inputs which is the - * power on default, so let's leave them alone. - * So, let's just read the board rev! - */ - raw = inb_p(SIO_GP_DATA1); - raw &= 0x7f; /* 7 bits of valid board revision ID. */ - - if (visws_board_type == VISWS_320) { - if (raw < 0x6) { - visws_board_rev = 4; - } else if (raw < 0xc) { - visws_board_rev = 5; - } else { - visws_board_rev = 6; - } - } else if (visws_board_type == VISWS_540) { - visws_board_rev = 2; - } else { - visws_board_rev = raw; - } - - printk(KERN_INFO "Silicon Graphics %s (rev %d)\n", - visws_board_type == VISWS_320 ? "320" : - (visws_board_type == VISWS_540 ? "540" : - "unknown"), visws_board_rev); - } -} diff -Nru a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c --- a/arch/i386/kernel/setup.c Thu Aug 29 08:48:01 2002 +++ b/arch/i386/kernel/setup.c Thu Aug 29 08:48:01 2002 @@ -36,6 +36,10 @@ #include #include #include +#include +#include "setup_arch_pre.h" + +static inline char * __init machine_specific_memory_setup(void); /* * Machine setup.. @@ -492,31 +496,8 @@ static void __init setup_memory_region(void) { - char *who = "BIOS-e820"; + char *who = machine_specific_memory_setup(); - /* - * Try to copy the BIOS-supplied E820-map. - * - * Otherwise fake a memory map; one section from 0k->640k, - * the next section from 1mb->appropriate_mem_k - */ - sanitize_e820_map(E820_MAP, &E820_MAP_NR); - if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) { - unsigned long mem_size; - - /* compare results from other methods and take the greater */ - if (ALT_MEM_K < EXT_MEM_K) { - mem_size = EXT_MEM_K; - who = "BIOS-88"; - } else { - mem_size = ALT_MEM_K; - who = "BIOS-e801"; - } - - e820.nr_map = 0; - add_memory_region(0, LOWMEMSIZE(), E820_RAM); - add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM); - } printk(KERN_INFO "BIOS-provided physical RAM map:\n"); print_memory_map(who); } /* setup_memory_region */ @@ -598,16 +579,16 @@ unsigned long start_pfn, max_low_pfn; int i; + pre_setup_arch_hook(); early_cpu_init(); -#ifdef CONFIG_VISWS - visws_get_board_type_and_rev(); -#endif ROOT_DEV = ORIG_ROOT_DEV; drive_info = DRIVE_INFO; screen_info = SCREEN_INFO; +#ifdef CONFIG_APM apm_info.bios = APM_BIOS_INFO; +#endif saved_videomode = VIDEO_MODE; printk("Video mode to be used for restore is %lx\n", saved_videomode); if( SYS_DESC_TABLE.length != 0 ) { @@ -623,6 +604,7 @@ rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); #endif + ARCH_SETUP setup_memory_region(); if (!MOUNT_ROOT_RDONLY) @@ -803,7 +785,7 @@ */ acpi_reserve_bootmem(); #endif -#ifdef CONFIG_X86_LOCAL_APIC +#ifdef CONFIG_X86_FIND_SMP_CONFIG /* * Find and reserve possible boot-time SMP configuration: */ @@ -907,6 +889,8 @@ } __setup("nohighio", highio_setup); + +#include "setup_arch_post.h" /* * Local Variables: * mode:c diff -Nru a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c --- a/arch/i386/kernel/smpboot.c Thu Aug 29 08:48:01 2002 +++ b/arch/i386/kernel/smpboot.c Thu Aug 29 08:48:01 2002 @@ -49,6 +49,9 @@ #include #include #include +#include +#include +#include "smpboot_hooks.h" /* Set if we find a B stepping CPU */ static int __initdata smp_b_stepping; @@ -1005,9 +1008,7 @@ */ if (!smp_found_config) { printk(KERN_NOTICE "SMP motherboard not detected.\n"); -#ifndef CONFIG_VISWS - io_apic_irqs = 0; -#endif + smpboot_clear_io_apic_irqs(); phys_cpu_present_map = 1; if (APIC_init_uniprocessor()) printk(KERN_NOTICE "Local APIC not detected." @@ -1034,9 +1035,7 @@ printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", boot_cpu_physical_apicid); printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n"); -#ifndef CONFIG_VISWS - io_apic_irqs = 0; -#endif + smpboot_clear_io_apic_irqs(); phys_cpu_present_map = 1; return; } @@ -1049,9 +1048,7 @@ if (!max_cpus) { smp_found_config = 0; printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n"); -#ifndef CONFIG_VISWS - io_apic_irqs = 0; -#endif + smpboot_clear_io_apic_irqs(); phys_cpu_present_map = 1; return; } @@ -1108,22 +1105,7 @@ /* * Cleanup possible dangling ends... */ -#ifndef CONFIG_VISWS - { - /* - * Install writable page 0 entry to set BIOS data area. - */ - local_flush_tlb(); - - /* - * Paranoid: Set warm reset code and vector here back - * to default values. - */ - CMOS_WRITE(0, 0xf); - - *((volatile long *) phys_to_virt(0x467)) = 0; - } -#endif + smpboot_setup_warm_reset_vector(); /* * Allow the user to impress friends. @@ -1175,15 +1157,8 @@ } } } - -#ifndef CONFIG_VISWS - /* - * Here we can be sure that there is an IO-APIC in the system. Let's - * go and set it up: - */ - if (!skip_ioapic_setup && nr_ioapics) - setup_IO_APIC(); -#endif + + smpboot_setup_io_apic(); setup_boot_APIC_clock(); @@ -1221,4 +1196,30 @@ void __init smp_cpus_done(unsigned int max_cpus) { zap_low_mappings(); +} + +void __init smp_intr_init() +{ + /* + * IRQ0 must be given a fixed assignment and initialized, + * because it's used before the IO-APIC is set up. + */ + set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]); + + /* + * The reschedule interrupt is a CPU-to-CPU reschedule-helper + * IPI, driven by wakeup. + */ + set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt); + + /* IPI for invalidation */ + set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt); + + /* IPI for generic function call */ + set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); + + /* thermal monitor LVT interrupt */ +#ifdef CONFIG_X86_MCE_P4THERMAL + set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); +#endif } diff -Nru a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c --- a/arch/i386/kernel/time.c Thu Aug 29 08:48:01 2002 +++ b/arch/i386/kernel/time.c Thu Aug 29 08:48:01 2002 @@ -57,8 +57,11 @@ #include #include -#include -#include +#include + +extern spinlock_t i8259A_lock; + +#include "do_timer.h" /* * for x86_do_profile() @@ -120,8 +123,6 @@ spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED; EXPORT_SYMBOL(i8253_lock); -extern spinlock_t i8259A_lock; - #ifndef CONFIG_X86_TSC /* This function must be called with interrupts disabled @@ -202,47 +203,11 @@ * (see c't 95/10 page 335 for Neptun bug.) */ -/* you can safely undefine this if you don't have the Neptune chipset */ - -#define BUGGY_NEPTUN_TIMER if( jiffies_t == jiffies_p ) { if( count > count_p ) { /* the nutcase */ - - int i; - - spin_lock(&i8259A_lock); - /* - * This is tricky when I/O APICs are used; - * see do_timer_interrupt(). - */ - i = inb(0x20); - spin_unlock(&i8259A_lock); - - /* assumption about timer being IRQ0 */ - if (i & 0x01) { - /* - * We cannot detect lost timer interrupts ... - * well, that's why we call them lost, don't we? :) - * [hmm, on the Pentium and Alpha we can ... sort of] - */ - count -= LATCH; - } else { -#ifdef BUGGY_NEPTUN_TIMER - /* - * for the Neptun bug we know that the 'latch' - * command doesnt latch the high and low value - * of the counter atomically. Thus we have to - * substract 256 from the counter - * ... funny, isnt it? :) - */ - - count -= 256; -#else - printk("do_slow_gettimeoffset(): hardware timer problem?\n"); -#endif - } + count = do_timer_overflow(count); } } else jiffies_p = jiffies_t; @@ -412,23 +377,7 @@ } #endif -#ifdef CONFIG_VISWS - /* Clear the interrupt */ - co_cpu_write(CO_CPU_STAT,co_cpu_read(CO_CPU_STAT) & ~CO_STAT_TIMEINTR); -#endif - do_timer(regs); -/* - * In the SMP case we use the local APIC timer interrupt to do the - * profiling, except when we simulate SMP mode on a uniprocessor - * system, in that case we have to call the local interrupt handler. - */ -#ifndef CONFIG_X86_LOCAL_APIC - if (!user_mode(regs)) - x86_do_profile(regs->eip); -#else - if (!using_apic_timer) - smp_local_timer_interrupt(regs); -#endif + do_timer_interrupt_hook(regs); /* * If we have an externally synchronized Linux clock, then update @@ -469,7 +418,7 @@ * Time Stamp Counter value at the time of the timer interrupt, so that * we later on can estimate the time of day more exactly. */ -static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { int count; @@ -559,8 +508,6 @@ return mktime(year, mon, day, hour, min, sec); } -static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL}; - /* ------ Calibrate the TSC ------- * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset(). * Too much 64-bit arithmetic here to do this cleanly in C, and for @@ -573,6 +520,7 @@ #define CALIBRATE_LATCH (5 * LATCH) #define CALIBRATE_TIME (5 * 1000020/HZ) +#ifdef CONFIG_X86_TSC static unsigned long __init calibrate_tsc(void) { /* Set the Gate high, disable speaker */ @@ -637,6 +585,7 @@ bad_ctc: return 0; } +#endif /* CONFIG_X86_TSC */ static struct device device_i8253 = { .name = "i8253", @@ -652,7 +601,9 @@ void __init time_init(void) { +#ifdef CONFIG_X86_TSC extern int x86_udelay_tsc; +#endif xtime.tv_sec = get_cmos_time(); xtime.tv_usec = 0; @@ -671,6 +622,7 @@ * to disk; this won't break the kernel, though, 'cuz we're * smart. See arch/i386/kernel/apm.c. */ +#ifdef CONFIG_X86_TSC /* * Firstly we have to do a CPU check for chips with * a potentially buggy TSC. At this point we haven't run @@ -711,22 +663,7 @@ } } } +#endif /* CONFIG_X86_TSC */ -#ifdef CONFIG_VISWS - printk("Starting Cobalt Timer system clock\n"); - - /* Set the countdown value */ - co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ); - - /* Start the timer */ - co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) | CO_CTRL_TIMERUN); - - /* Enable (unmask) the timer interrupt */ - co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK); - - /* Wire cpu IDT entry to s/w handler (and Cobalt APIC to IDT) */ - setup_irq(CO_IRQ_TIMER, &irq0); -#else - setup_irq(0, &irq0); -#endif + time_init_hook(); } diff -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c --- a/arch/i386/kernel/traps.c Thu Aug 29 08:48:01 2002 +++ b/arch/i386/kernel/traps.c Thu Aug 29 08:48:01 2002 @@ -43,12 +43,7 @@ #include #include - -#ifdef CONFIG_X86_VISWS_APIC -#include -#include -#include -#endif +#include #include #include @@ -831,96 +826,6 @@ _set_gate(a,12,3,addr); } -#ifdef CONFIG_X86_VISWS_APIC - -/* - * On Rev 005 motherboards legacy device interrupt lines are wired directly - * to Lithium from the 307. But the PROM leaves the interrupt type of each - * 307 logical device set appropriate for the 8259. Later we'll actually use - * the 8259, but for now we have to flip the interrupt types to - * level triggered, active lo as required by Lithium. - */ - -#define REG 0x2e /* The register to read/write */ -#define DEV 0x07 /* Register: Logical device select */ -#define VAL 0x2f /* The value to read/write */ - -static void -superio_outb(int dev, int reg, int val) -{ - outb(DEV, REG); - outb(dev, VAL); - outb(reg, REG); - outb(val, VAL); -} - -static int __attribute__ ((unused)) -superio_inb(int dev, int reg) -{ - outb(DEV, REG); - outb(dev, VAL); - outb(reg, REG); - return inb(VAL); -} - -#define FLOP 3 /* floppy logical device */ -#define PPORT 4 /* parallel logical device */ -#define UART5 5 /* uart2 logical device (not wired up) */ -#define UART6 6 /* uart1 logical device (THIS is the serial port!) */ -#define IDEST 0x70 /* int. destination (which 307 IRQ line) reg. */ -#define ITYPE 0x71 /* interrupt type register */ - -/* interrupt type bits */ -#define LEVEL 0x01 /* bit 0, 0 == edge triggered */ -#define ACTHI 0x02 /* bit 1, 0 == active lo */ - -static void -superio_init(void) -{ - if (visws_board_type == VISWS_320 && visws_board_rev == 5) { - superio_outb(UART6, IDEST, 0); /* 0 means no intr propagated */ - printk("SGI 320 rev 5: disabling 307 uart1 interrupt\n"); - } -} - -static void -lithium_init(void) -{ - set_fixmap(FIX_LI_PCIA, LI_PCI_A_PHYS); - printk("Lithium PCI Bridge A, Bus Number: %d\n", - li_pcia_read16(LI_PCI_BUSNUM) & 0xff); - set_fixmap(FIX_LI_PCIB, LI_PCI_B_PHYS); - printk("Lithium PCI Bridge B (PIIX4), Bus Number: %d\n", - li_pcib_read16(LI_PCI_BUSNUM) & 0xff); - - /* XXX blindly enables all interrupts */ - li_pcia_write16(LI_PCI_INTEN, 0xffff); - li_pcib_write16(LI_PCI_INTEN, 0xffff); -} - -static void -cobalt_init(void) -{ - /* - * On normal SMP PC this is used only with SMP, but we have to - * use it and set it up here to start the Cobalt clock - */ - set_fixmap(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE); - printk("Local APIC ID %lx\n", apic_read(APIC_ID)); - printk("Local APIC Version %lx\n", apic_read(APIC_LVR)); - - set_fixmap(FIX_CO_CPU, CO_CPU_PHYS); - printk("Cobalt Revision %lx\n", co_cpu_read(CO_CPU_REV)); - - set_fixmap(FIX_CO_APIC, CO_APIC_PHYS); - printk("Cobalt APIC ID %lx\n", co_apic_read(CO_APIC_ID)); - - /* Enable Cobalt APIC being careful to NOT change the ID! */ - co_apic_write(CO_APIC_ID, co_apic_read(CO_APIC_ID)|CO_APIC_ENABLE); - - printk("Cobalt APIC enabled: ID reg %lx\n", co_apic_read(CO_APIC_ID)); -} -#endif #ifdef CONFIG_EISA int EISA_bus; @@ -976,9 +881,5 @@ */ cpu_init(); -#ifdef CONFIG_X86_VISWS_APIC - superio_init(); - lithium_init(); - cobalt_init(); -#endif + trap_init_hook(); } diff -Nru a/arch/i386/kernel/visws_apic.c b/arch/i386/kernel/visws_apic.c --- a/arch/i386/kernel/visws_apic.c Thu Aug 29 08:48:01 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,410 +0,0 @@ -/* - * linux/arch/i386/kernel/visws_apic.c - * - * Copyright (C) 1999 Bent Hagemark, Ingo Molnar - * - * SGI Visual Workstation interrupt controller - * - * The Cobalt system ASIC in the Visual Workstation contains a "Cobalt" APIC - * which serves as the main interrupt controller in the system. Non-legacy - * hardware in the system uses this controller directly. Legacy devices - * are connected to the PIIX4 which in turn has its 8259(s) connected to - * a of the Cobalt APIC entry. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -/* - * This is the PIIX4-based 8259 that is wired up indirectly to Cobalt - * -- not the manner expected by the normal 8259 code in irq.c. - * - * there is a 'master' physical interrupt source that gets sent to - * the CPU. But in the chipset there are various 'virtual' interrupts - * waiting to be handled. We represent this to Linux through a 'master' - * interrupt controller type, and through a special virtual interrupt- - * controller. Device drivers only see the virtual interrupt sources. - */ - -#define CO_IRQ_BASE 0x20 /* This is the 0x20 in init_IRQ()! */ - -static void startup_piix4_master_irq(unsigned int irq); -static void shutdown_piix4_master_irq(unsigned int irq); -static void do_piix4_master_IRQ(unsigned int irq, struct pt_regs * regs); -#define enable_piix4_master_irq startup_piix4_master_irq -#define disable_piix4_master_irq shutdown_piix4_master_irq - -static struct hw_interrupt_type piix4_master_irq_type = { - "PIIX4-master", - startup_piix4_master_irq, - shutdown_piix4_master_irq, - do_piix4_master_IRQ, - enable_piix4_master_irq, - disable_piix4_master_irq -}; - -static void enable_piix4_virtual_irq(unsigned int irq); -static void disable_piix4_virtual_irq(unsigned int irq); -#define startup_piix4_virtual_irq enable_piix4_virtual_irq -#define shutdown_piix4_virtual_irq disable_piix4_virtual_irq - -static struct hw_interrupt_type piix4_virtual_irq_type = { - "PIIX4-virtual", - startup_piix4_virtual_irq, - shutdown_piix4_virtual_irq, - 0, /* no handler, it's never called physically */ - enable_piix4_virtual_irq, - disable_piix4_virtual_irq -}; - -/* - * This is the SGI Cobalt (IO-)APIC: - */ - -static void do_cobalt_IRQ(unsigned int irq, struct pt_regs * regs); -static void enable_cobalt_irq(unsigned int irq); -static void disable_cobalt_irq(unsigned int irq); -static void startup_cobalt_irq(unsigned int irq); -#define shutdown_cobalt_irq disable_cobalt_irq - -static spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED; - -static struct hw_interrupt_type cobalt_irq_type = { - "Cobalt-APIC", - startup_cobalt_irq, - shutdown_cobalt_irq, - do_cobalt_IRQ, - enable_cobalt_irq, - disable_cobalt_irq -}; - - -/* - * Not an __init, needed by the reboot code - */ -void disable_IO_APIC(void) -{ - /* Nop on Cobalt */ -} - -/* - * Cobalt (IO)-APIC functions to handle PCI devices. - */ - -static void disable_cobalt_irq(unsigned int irq) -{ - /* XXX undo the APIC entry here? */ - - /* - * definitely, we do not want to have IRQ storms from - * unused devices --mingo - */ -} - -static void enable_cobalt_irq(unsigned int irq) -{ -} - -/* - * Set the given Cobalt APIC Redirection Table entry to point - * to the given IDT vector/index. - */ -static void co_apic_set(int entry, int idtvec) -{ - co_apic_write(CO_APIC_LO(entry), CO_APIC_LEVEL | (CO_IRQ_BASE+idtvec)); - co_apic_write(CO_APIC_HI(entry), 0); - - printk("Cobalt APIC Entry %d IDT Vector %d\n", entry, idtvec); -} - -/* - * "irq" really just serves to identify the device. Here is where we - * map this to the Cobalt APIC entry where it's physically wired. - * This is called via request_irq -> setup_x86_irq -> irq_desc->startup() - */ -static void startup_cobalt_irq(unsigned int irq) -{ - /* - * These "irq"'s are wired to the same Cobalt APIC entries - * for all (known) motherboard types/revs - */ - switch (irq) { - case CO_IRQ_TIMER: co_apic_set(CO_APIC_CPU, CO_IRQ_TIMER); - return; - - case CO_IRQ_ENET: co_apic_set(CO_APIC_ENET, CO_IRQ_ENET); - return; - - case CO_IRQ_SERIAL: return; /* XXX move to piix4-8259 "virtual" */ - - case CO_IRQ_8259: co_apic_set(CO_APIC_8259, CO_IRQ_8259); - return; - - case CO_IRQ_IDE: - switch (visws_board_type) { - case VISWS_320: - switch (visws_board_rev) { - case 5: - co_apic_set(CO_APIC_0_5_IDE0, CO_IRQ_IDE); - co_apic_set(CO_APIC_0_5_IDE1, CO_IRQ_IDE); - return; - case 6: - co_apic_set(CO_APIC_0_6_IDE0, CO_IRQ_IDE); - co_apic_set(CO_APIC_0_6_IDE1, CO_IRQ_IDE); - return; - } - case VISWS_540: - switch (visws_board_rev) { - case 2: - co_apic_set(CO_APIC_1_2_IDE0, CO_IRQ_IDE); - return; - } - } - break; - default: - panic("huh?"); - } -} - -/* - * This is the handle() op in do_IRQ() - */ -static void do_cobalt_IRQ(unsigned int irq, struct pt_regs * regs) -{ - struct irqaction * action; - irq_desc_t *desc = irq_desc + irq; - - spin_lock(&irq_controller_lock); - { - unsigned int status; - /* XXX APIC EOI? */ - status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); - action = NULL; - if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { - action = desc->action; - status |= IRQ_INPROGRESS; - } - desc->status = status; - } - spin_unlock(&irq_controller_lock); - - /* Exit early if we had no action or it was disabled */ - if (!action) - return; - - handle_IRQ_event(irq, regs, action); - - (void)co_cpu_read(CO_CPU_REV); /* Sync driver ack to its h/w */ - apic_write(APIC_EOI, APIC_EIO_ACK); /* Send EOI to Cobalt APIC */ - - spin_lock(&irq_controller_lock); - { - unsigned int status = desc->status & ~IRQ_INPROGRESS; - desc->status = status; - if (!(status & IRQ_DISABLED)) - enable_cobalt_irq(irq); - } - spin_unlock(&irq_controller_lock); -} - -/* - * PIIX4-8259 master/virtual functions to handle: - * - * floppy - * parallel - * serial - * audio (?) - * - * None of these get Cobalt APIC entries, neither do they have IDT - * entries. These interrupts are purely virtual and distributed from - * the 'master' interrupt source: CO_IRQ_8259. - * - * When the 8259 interrupts its handler figures out which of these - * devices is interrupting and dispatches to it's handler. - * - * CAREFUL: devices see the 'virtual' interrupt only. Thus disable/ - * enable_irq gets the right irq. This 'master' irq is never directly - * manipulated by any driver. - */ - -static void startup_piix4_master_irq(unsigned int irq) -{ - /* ICW1 */ - outb(0x11, 0x20); - outb(0x11, 0xa0); - - /* ICW2 */ - outb(0x08, 0x21); - outb(0x70, 0xa1); - - /* ICW3 */ - outb(0x04, 0x21); - outb(0x02, 0xa1); - - /* ICW4 */ - outb(0x01, 0x21); - outb(0x01, 0xa1); - - /* OCW1 - disable all interrupts in both 8259's */ - outb(0xff, 0x21); - outb(0xff, 0xa1); - - startup_cobalt_irq(irq); -} - -static void shutdown_piix4_master_irq(unsigned int irq) -{ - /* - * [we skip the 8259 magic here, not strictly necessary] - */ - - shutdown_cobalt_irq(irq); -} - -static void do_piix4_master_IRQ(unsigned int irq, struct pt_regs * regs) -{ - int realirq, mask; - - /* Find out what's interrupting in the PIIX4 8259 */ - - spin_lock(&irq_controller_lock); - outb(0x0c, 0x20); /* OCW3 Poll command */ - realirq = inb(0x20); - - if (!(realirq & 0x80)) { - /* - * Bit 7 == 0 means invalid/spurious - */ - goto out_unlock; - } - realirq &= 0x7f; - - /* - * mask and ack the 8259 - */ - mask = inb(0x21); - if ((mask >> realirq) & 0x01) - /* - * This IRQ is masked... ignore - */ - goto out_unlock; - - outb(mask | (1<status & IRQ_DISABLED)) - enable_piix4_virtual_irq(realirq); - } - spin_unlock(&irq_controller_lock); - return; - -out_unlock: - spin_unlock(&irq_controller_lock); - return; -} - -static void enable_piix4_virtual_irq(unsigned int irq) -{ - /* - * assumes this irq is one of the legacy devices - */ - - unsigned int mask = inb(0x21); - mask &= ~(1 << irq); - outb(mask, 0x21); - enable_cobalt_irq(irq); -} - -/* - * assumes this irq is one of the legacy devices - */ -static void disable_piix4_virtual_irq(unsigned int irq) -{ - unsigned int mask; - - disable_cobalt_irq(irq); - - mask = inb(0x21); - mask &= ~(1 << irq); - outb(mask, 0x21); -} - -static struct irqaction master_action = - { no_action, 0, 0, "PIIX4-8259", NULL, NULL }; - -void init_VISWS_APIC_irqs(void) -{ - int i; - - for (i = 0; i < 16; i++) { - irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = 0; - irq_desc[i].depth = 1; - - /* - * Cobalt IRQs are mapped to standard ISA - * interrupt vectors: - */ - switch (i) { - /* - * Only CO_IRQ_8259 will be raised - * externally. - */ - case CO_IRQ_8259: - irq_desc[i].handler = &piix4_master_irq_type; - break; - case CO_IRQ_FLOPPY: - case CO_IRQ_PARLL: - irq_desc[i].handler = &piix4_virtual_irq_type; - break; - default: - irq_desc[i].handler = &cobalt_irq_type; - break; - } - } - - /* - * The master interrupt is always present: - */ - setup_x86_irq(CO_IRQ_8259, &master_action); -} - diff -Nru a/arch/i386/mach-generic/Makefile b/arch/i386/mach-generic/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-generic/Makefile Thu Aug 29 08:48:01 2002 @@ -0,0 +1,21 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +.S.o: + $(CC) $(AFLAGS) -traditional -c $< -o $*.o + +all: mach-generic.o + +O_TARGET := mach-generic.o +EXTRA_CFLAGS += -I../kernel +export-objs := + +obj-y := setup.o + +include $(TOPDIR)/Rules.make diff -Nru a/arch/i386/mach-generic/do_timer.h b/arch/i386/mach-generic/do_timer.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-generic/do_timer.h Thu Aug 29 08:48:01 2002 @@ -0,0 +1,81 @@ +/* defines for inline arch setup functions */ + +/** + * do_timer_interrupt_hook - hook into timer tick + * @regs: standard registers from interrupt + * + * Description: + * This hook is called immediately after the timer interrupt is ack'd. + * It's primary purpose is to allow architectures that don't possess + * individual per CPU clocks (like the CPU APICs supply) to broadcast the + * timer interrupt as a means of triggering reschedules etc. + **/ + +static inline void do_timer_interrupt_hook(struct pt_regs *regs) +{ + do_timer(regs); +/* + * In the SMP case we use the local APIC timer interrupt to do the + * profiling, except when we simulate SMP mode on a uniprocessor + * system, in that case we have to call the local interrupt handler. + */ +#ifndef CONFIG_X86_LOCAL_APIC + if (!user_mode(regs)) + x86_do_profile(regs->eip); +#else + if (!using_apic_timer) + smp_local_timer_interrupt(regs); +#endif +} + + +/* you can safely undefine this if you don't have the Neptune chipset */ + +#define BUGGY_NEPTUN_TIMER + +/** + * do_timer_overflow - process a detected timer overflow condition + * @count: hardware timer interrupt count on overflow + * + * Description: + * This call is invoked when the jiffies count has not incremented but + * the hardware timer interrupt has. It means that a timer tick interrupt + * came along while the previous one was pending, thus a tick was missed + **/ +static inline int do_timer_overflow(int count) +{ + int i; + + spin_lock(&i8259A_lock); + /* + * This is tricky when I/O APICs are used; + * see do_timer_interrupt(). + */ + i = inb(0x20); + spin_unlock(&i8259A_lock); + + /* assumption about timer being IRQ0 */ + if (i & 0x01) { + /* + * We cannot detect lost timer interrupts ... + * well, that's why we call them lost, don't we? :) + * [hmm, on the Pentium and Alpha we can ... sort of] + */ + count -= LATCH; + } else { +#ifdef BUGGY_NEPTUN_TIMER + /* + * for the Neptun bug we know that the 'latch' + * command doesnt latch the high and low value + * of the counter atomically. Thus we have to + * substract 256 from the counter + * ... funny, isnt it? :) + */ + + count -= 256; +#else + printk("do_slow_gettimeoffset(): hardware timer problem?\n"); +#endif + } + return count; +} diff -Nru a/arch/i386/mach-generic/entry_arch.h b/arch/i386/mach-generic/entry_arch.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-generic/entry_arch.h Thu Aug 29 08:48:01 2002 @@ -0,0 +1,34 @@ +/* + * This file is designed to contain the BUILD_INTERRUPT specifications for + * all of the extra named interrupt vectors used by the architecture. + * Usually this is the Inter Process Interrupts (IPIs) + */ + +/* + * The following vectors are part of the Linux architecture, there + * is no hardware IRQ pin equivalent for them, they are triggered + * through the ICC by us (IPIs) + */ +#ifdef CONFIG_X86_SMP +BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR) +BUILD_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR) +BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR) +#endif + +/* + * every pentium local APIC has two 'local interrupts', with a + * soft-definable vector attached to both interrupts, one of + * which is a timer interrupt, the other one is error counter + * overflow. Linux uses the local APIC timer interrupt to get + * a much simpler SMP time architecture: + */ +#ifdef CONFIG_X86_LOCAL_APIC +BUILD_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR) +BUILD_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR) +BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR) + +#ifdef CONFIG_X86_MCE_P4THERMAL +BUILD_INTERRUPT(thermal_interrupt,THERMAL_APIC_VECTOR) +#endif + +#endif diff -Nru a/arch/i386/mach-generic/irq_vectors.h b/arch/i386/mach-generic/irq_vectors.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-generic/irq_vectors.h Thu Aug 29 08:48:01 2002 @@ -0,0 +1,85 @@ +/* + * This file should contain #defines for all of the interrupt vector + * numbers used by this architecture. + * + * In addition, there are some standard defines: + * + * FIRST_EXTERNAL_VECTOR: + * The first free place for external interrupts + * + * SYSCALL_VECTOR: + * The IRQ vector a syscall makes the user to kernel transition + * under. + * + * TIMER_IRQ: + * The IRQ number the timer interrupt comes in at. + * + * NR_IRQS: + * The total number of interrupt vectors (including all the + * architecture specific interrupts) needed. + * + */ +#ifndef _ASM_IRQ_VECTORS_H +#define _ASM_IRQ_VECTORS_H + +/* + * IDT vectors usable for external interrupt sources start + * at 0x20: + */ +#define FIRST_EXTERNAL_VECTOR 0x20 + +#define SYSCALL_VECTOR 0x80 + +/* + * Vectors 0x20-0x2f are used for ISA interrupts. + */ + +/* + * Special IRQ vectors used by the SMP architecture, 0xf0-0xff + * + * some of the following vectors are 'rare', they are merged + * into a single vector (CALL_FUNCTION_VECTOR) to save vector space. + * TLB, reschedule and local APIC vectors are performance-critical. + * + * Vectors 0xf0-0xfa are free (reserved for future Linux use). + */ +#define SPURIOUS_APIC_VECTOR 0xff +#define ERROR_APIC_VECTOR 0xfe +#define INVALIDATE_TLB_VECTOR 0xfd +#define RESCHEDULE_VECTOR 0xfc +#define CALL_FUNCTION_VECTOR 0xfb + +#define THERMAL_APIC_VECTOR 0xf0 +/* + * Local APIC timer IRQ vector is on a different priority level, + * to work around the 'lost local interrupt if more than 2 IRQ + * sources per level' errata. + */ +#define LOCAL_TIMER_VECTOR 0xef + +/* + * First APIC vector available to drivers: (vectors 0x30-0xee) + * we start at 0x31 to spread out vectors evenly between priority + * levels. (0x80 is the syscall vector) + */ +#define FIRST_DEVICE_VECTOR 0x31 +#define FIRST_SYSTEM_VECTOR 0xef + +#define TIMER_IRQ 0 + +/* + * 16 8259A IRQ's, 208 potential APIC interrupt sources. + * Right now the APIC is mostly only used for SMP. + * 256 vectors is an architectural limit. (we can have + * more than 256 devices theoretically, but they will + * have to use shared interrupts) + * Since vectors 0x00-0x1f are used/reserved for the CPU, + * the usable vector space is 0x20-0xff (224 vectors) + */ +#ifdef CONFIG_X86_IO_APIC +#define NR_IRQS 224 +#else +#define NR_IRQS 16 +#endif + +#endif /* _ASM_IRQ_VECTORS_H */ diff -Nru a/arch/i386/mach-generic/setup.c b/arch/i386/mach-generic/setup.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-generic/setup.c Thu Aug 29 08:48:01 2002 @@ -0,0 +1,104 @@ +/* + * Machine specific setup for generic + */ + +#include +#include +#include +#include +#include +#include + +/** + * pre_intr_init_hook - initialisation prior to setting up interrupt vectors + * + * Description: + * Perform any necessary interrupt initialisation prior to setting up + * the "ordinary" interrupt call gates. For legacy reasons, the ISA + * interrupts should be initialised here if the machine emulates a PC + * in any way. + **/ +void __init pre_intr_init_hook(void) +{ + init_ISA_irqs(); +} + +/* + * IRQ2 is cascade interrupt to second interrupt controller + */ +static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL}; + +/** + * intr_init_hook - post gate setup interrupt initialisation + * + * Description: + * Fill in any interrupts that may have been left out by the general + * init_IRQ() routine. interrupts having to do with the machine rather + * than the devices on the I/O bus (like APIC interrupts in intel MP + * systems) are started here. + **/ +void __init intr_init_hook(void) +{ +#ifdef CONFIG_X86_LOCAL_APIC + apic_intr_init(); +#endif + + setup_irq(2, &irq2); +} + +/** + * pre_setup_arch_hook - hook called prior to any setup_arch() execution + * + * Description: + * generally used to activate any machine specific identification + * routines that may be needed before setup_arch() runs. On VISWS + * this is used to get the board revision and type. + **/ +void __init pre_setup_arch_hook(void) +{ +} + +/** + * trap_init_hook - initialise system specific traps + * + * Description: + * Called as the final act of trap_init(). Used in VISWS to initialise + * the various board specific APIC traps. + **/ +void __init trap_init_hook(void) +{ +} + +static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL}; + +/** + * time_init_hook - do any specific initialisations for the system timer. + * + * Description: + * Must plug the system timer interrupt source at HZ into the IRQ listed + * in irq_vectors.h:TIMER_IRQ + **/ +void __init time_init_hook(void) +{ + setup_irq(0, &irq0); +} + +#ifdef CONFIG_MCA +/** + * mca_nmi_hook - hook into MCA specific NMI chain + * + * Description: + * The MCA (Microchannel Arcitecture) has an NMI chain for NMI sources + * along the MCA bus. Use this to hook into that chain if you will need + * it. + **/ +void __init mca_nmi_hook(void) +{ + /* If I recall correctly, there's a whole bunch of other things that + * we can do to check for NMI problems, but that's all I know about + * at the moment. + */ + + printk("NMI generated from unknown source!\n"); +} +#endif diff -Nru a/arch/i386/mach-generic/setup_arch_post.h b/arch/i386/mach-generic/setup_arch_post.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-generic/setup_arch_post.h Thu Aug 29 08:48:01 2002 @@ -0,0 +1,40 @@ +/** + * machine_specific_memory_setup - Hook for machine specific memory setup. + * + * Description: + * This is included late in kernel/setup.c so that it can make + * use of all of the static functions. + **/ + +static inline char * __init machine_specific_memory_setup(void) +{ + char *who; + + + who = "BIOS-e820"; + + /* + * Try to copy the BIOS-supplied E820-map. + * + * Otherwise fake a memory map; one section from 0k->640k, + * the next section from 1mb->appropriate_mem_k + */ + sanitize_e820_map(E820_MAP, &E820_MAP_NR); + if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) { + unsigned long mem_size; + + /* compare results from other methods and take the greater */ + if (ALT_MEM_K < EXT_MEM_K) { + mem_size = EXT_MEM_K; + who = "BIOS-88"; + } else { + mem_size = ALT_MEM_K; + who = "BIOS-e801"; + } + + e820.nr_map = 0; + add_memory_region(0, LOWMEMSIZE(), E820_RAM); + add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM); + } + return who; +} diff -Nru a/arch/i386/mach-generic/setup_arch_pre.h b/arch/i386/mach-generic/setup_arch_pre.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-generic/setup_arch_pre.h Thu Aug 29 08:48:01 2002 @@ -0,0 +1,5 @@ +/* Hook to call BIOS initialisation function */ + +/* no action for generic */ + +#define ARCH_SETUP diff -Nru a/arch/i386/mach-generic/smpboot_hooks.h b/arch/i386/mach-generic/smpboot_hooks.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-generic/smpboot_hooks.h Thu Aug 29 08:48:01 2002 @@ -0,0 +1,33 @@ +/* two abstractions specific to kernel/smpboot.c, mainly to cater to visws + * which needs to alter them. */ + +static inline void smpboot_clear_io_apic_irqs(void) +{ + io_apic_irqs = 0; +} + +static inline void smpboot_setup_warm_reset_vector(void) +{ + /* + * Install writable page 0 entry to set BIOS data area. + */ + local_flush_tlb(); + + /* + * Paranoid: Set warm reset code and vector here back + * to default values. + */ + CMOS_WRITE(0, 0xf); + + *((volatile long *) phys_to_virt(0x467)) = 0; +} + +static inline void smpboot_setup_io_apic(void) +{ + /* + * Here we can be sure that there is an IO-APIC in the system. Let's + * go and set it up: + */ + if (!skip_ioapic_setup && nr_ioapics) + setup_IO_APIC(); +} diff -Nru a/arch/i386/mach-visws/Makefile b/arch/i386/mach-visws/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/Makefile Thu Aug 29 08:48:01 2002 @@ -0,0 +1,25 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +.S.o: + $(CC) $(AFLAGS) -traditional -c $< -o $*.o + +all: mach-visws.o + +O_TARGET := mach-visws.o +EXTRA_CFLAGS += -I../kernel +export-objs := + +obj-y := setup.o traps.o + +obj-$(CONFIG_PCI) += pci-visws.o +obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o +obj-$(CONFIG_X86_LOCAL_APIC) += mpparse.o + +include $(TOPDIR)/Rules.make diff -Nru a/arch/i386/mach-visws/do_timer.h b/arch/i386/mach-visws/do_timer.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/do_timer.h Thu Aug 29 08:48:01 2002 @@ -0,0 +1,50 @@ +/* defines for inline arch setup functions */ + +#include +#include + +static inline void do_timer_interrupt_hook(struct pt_regs *regs) +{ + /* Clear the interrupt */ + co_cpu_write(CO_CPU_STAT,co_cpu_read(CO_CPU_STAT) & ~CO_STAT_TIMEINTR); + + do_timer(regs); +/* + * In the SMP case we use the local APIC timer interrupt to do the + * profiling, except when we simulate SMP mode on a uniprocessor + * system, in that case we have to call the local interrupt handler. + */ +#ifndef CONFIG_X86_LOCAL_APIC + if (!user_mode(regs)) + x86_do_profile(regs->eip); +#else + if (!using_apic_timer) + smp_local_timer_interrupt(regs); +#endif +} + +static inline int do_timer_overflow(int count) +{ + int i; + + spin_lock(&i8259A_lock); + /* + * This is tricky when I/O APICs are used; + * see do_timer_interrupt(). + */ + i = inb(0x20); + spin_unlock(&i8259A_lock); + + /* assumption about timer being IRQ0 */ + if (i & 0x01) { + /* + * We cannot detect lost timer interrupts ... + * well, that's why we call them lost, don't we? :) + * [hmm, on the Pentium and Alpha we can ... sort of] + */ + count -= LATCH; + } else { + printk("do_slow_gettimeoffset(): hardware timer problem?\n"); + } + return count; +} diff -Nru a/arch/i386/mach-visws/entry_arch.h b/arch/i386/mach-visws/entry_arch.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/entry_arch.h Thu Aug 29 08:48:01 2002 @@ -0,0 +1,23 @@ +/* + * The following vectors are part of the Linux architecture, there + * is no hardware IRQ pin equivalent for them, they are triggered + * through the ICC by us (IPIs) + */ +#ifdef CONFIG_X86_SMP +BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR) +BUILD_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR) +BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR) +#endif + +/* + * every pentium local APIC has two 'local interrupts', with a + * soft-definable vector attached to both interrupts, one of + * which is a timer interrupt, the other one is error counter + * overflow. Linux uses the local APIC timer interrupt to get + * a much simpler SMP time architecture: + */ +#ifdef CONFIG_X86_LOCAL_APIC +BUILD_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR) +BUILD_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR) +BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR) +#endif diff -Nru a/arch/i386/mach-visws/irq_vectors.h b/arch/i386/mach-visws/irq_vectors.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/irq_vectors.h Thu Aug 29 08:48:01 2002 @@ -0,0 +1,64 @@ +#ifndef _ASM_IRQ_VECTORS_H +#define _ASM_IRQ_VECTORS_H + +/* + * IDT vectors usable for external interrupt sources start + * at 0x20: + */ +#define FIRST_EXTERNAL_VECTOR 0x20 + +#define SYSCALL_VECTOR 0x80 + +/* + * Vectors 0x20-0x2f are used for ISA interrupts. + */ + +/* + * Special IRQ vectors used by the SMP architecture, 0xf0-0xff + * + * some of the following vectors are 'rare', they are merged + * into a single vector (CALL_FUNCTION_VECTOR) to save vector space. + * TLB, reschedule and local APIC vectors are performance-critical. + * + * Vectors 0xf0-0xfa are free (reserved for future Linux use). + */ +#define SPURIOUS_APIC_VECTOR 0xff +#define ERROR_APIC_VECTOR 0xfe +#define INVALIDATE_TLB_VECTOR 0xfd +#define RESCHEDULE_VECTOR 0xfc +#define CALL_FUNCTION_VECTOR 0xfb + +#define THERMAL_APIC_VECTOR 0xf0 +/* + * Local APIC timer IRQ vector is on a different priority level, + * to work around the 'lost local interrupt if more than 2 IRQ + * sources per level' errata. + */ +#define LOCAL_TIMER_VECTOR 0xef + +/* + * First APIC vector available to drivers: (vectors 0x30-0xee) + * we start at 0x31 to spread out vectors evenly between priority + * levels. (0x80 is the syscall vector) + */ +#define FIRST_DEVICE_VECTOR 0x31 +#define FIRST_SYSTEM_VECTOR 0xef + +#define TIMER_IRQ 0 + +/* + * 16 8259A IRQ's, 208 potential APIC interrupt sources. + * Right now the APIC is mostly only used for SMP. + * 256 vectors is an architectural limit. (we can have + * more than 256 devices theoretically, but they will + * have to use shared interrupts) + * Since vectors 0x00-0x1f are used/reserved for the CPU, + * the usable vector space is 0x20-0xff (224 vectors) + */ +#ifdef CONFIG_X86_IO_APIC +#define NR_IRQS 224 +#else +#define NR_IRQS 16 +#endif + +#endif /* _ASM_IRQ_VECTORS_H */ diff -Nru a/arch/i386/mach-visws/mpparse.c b/arch/i386/mach-visws/mpparse.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/mpparse.c Thu Aug 29 08:48:01 2002 @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Have we found an MP table */ +int smp_found_config; + +/* + * Various Linux-internal data structures created from the + * MP-table. + */ +int apic_version [MAX_APICS]; +int mp_bus_id_to_type [MAX_MP_BUSSES]; +int mp_bus_id_to_node [MAX_MP_BUSSES]; +int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 }; +int mp_current_pci_id; + +/* I/O APIC entries */ +struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS]; + +/* # of MP IRQ source entries */ +struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; + +/* MP IRQ source entries */ +int mp_irq_entries; + +int nr_ioapics; + +int pic_mode; +unsigned long mp_lapic_addr; + +/* Processor that is doing the boot up */ +unsigned int boot_cpu_physical_apicid = -1U; +unsigned int boot_cpu_logical_apicid = -1U; +/* Internal processor count */ +static unsigned int num_processors; + +/* Bitmask of physically existing CPUs */ +unsigned long phys_cpu_present_map; + +/* + * The Visual Workstation is Intel MP compliant in the hardware + * sense, but it doesn't have a BIOS(-configuration table). + * No problem for Linux. + */ +void __init find_smp_config(void) +{ + smp_found_config = 1; + + phys_cpu_present_map |= 2; /* or in id 1 */ + apic_version[1] |= 0x10; /* integrated APIC */ + apic_version[0] |= 0x10; + + mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; +} + diff -Nru a/arch/i386/mach-visws/pci-visws.c b/arch/i386/mach-visws/pci-visws.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/pci-visws.c Thu Aug 29 08:48:01 2002 @@ -0,0 +1,141 @@ +/* + * Low-Level PCI Support for SGI Visual Workstation + * + * (c) 1999--2000 Martin Mares + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "pci-i386.h" + +unsigned int pci_probe = 0; + +/* + * The VISWS uses configuration access type 1 only. + */ + +#define CONFIG_CMD(dev, where) (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3)) + +static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value) +{ + outl(CONFIG_CMD(dev,where), 0xCF8); + *value = inb(0xCFC + (where&3)); + return PCIBIOS_SUCCESSFUL; +} + +static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value) +{ + outl(CONFIG_CMD(dev,where), 0xCF8); + *value = inw(0xCFC + (where&2)); + return PCIBIOS_SUCCESSFUL; +} + +static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value) +{ + outl(CONFIG_CMD(dev,where), 0xCF8); + *value = inl(0xCFC); + return PCIBIOS_SUCCESSFUL; +} + +static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value) +{ + outl(CONFIG_CMD(dev,where), 0xCF8); + outb(value, 0xCFC + (where&3)); + return PCIBIOS_SUCCESSFUL; +} + +static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value) +{ + outl(CONFIG_CMD(dev,where), 0xCF8); + outw(value, 0xCFC + (where&2)); + return PCIBIOS_SUCCESSFUL; +} + +static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value) +{ + outl(CONFIG_CMD(dev,where), 0xCF8); + outl(value, 0xCFC); + return PCIBIOS_SUCCESSFUL; +} + +#undef CONFIG_CMD + +static struct pci_ops visws_pci_ops = { + pci_conf1_read_config_byte, + pci_conf1_read_config_word, + pci_conf1_read_config_dword, + pci_conf1_write_config_byte, + pci_conf1_write_config_word, + pci_conf1_write_config_dword +}; + +static void __init pcibios_fixup_irqs(void) +{ + struct pci_dev *dev, *p; + u8 pin; + int irq; + + pci_for_each_dev(dev) { + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + dev->irq = 0; + if (!pin) + continue; + pin--; + if (dev->bus->parent) { + p = dev->bus->parent->self; + pin = (pin + PCI_SLOT(dev->devfn)) % 4; + } else + p = dev; + irq = visws_get_PCI_irq_vector(p->bus->number, PCI_SLOT(p->devfn), pin+1); + if (irq >= 0) + dev->irq = irq; + DBG("PCI IRQ: %s pin %d -> %d\n", dev->slot_name, pin, irq); + } +} + +void __init pcibios_fixup_bus(struct pci_bus *b) +{ + pci_read_bridge_bases(b); +} + +#if 0 +static struct resource visws_pci_bus_resources[2] = { + { "Host bus 1", 0xf4000000, 0xf7ffffff, 0 }, + { "Host bus 2", 0xf0000000, 0xf3ffffff, 0 } +}; +#endif + +void __init pcibios_init(void) +{ + unsigned int sec_bus = li_pcib_read16(LI_PCI_BUSNUM) & 0xff; + + printk("PCI: Probing PCI hardware on host buses 00 and %02x\n", sec_bus); + pci_scan_bus(0, &visws_pci_ops, NULL); + pci_scan_bus(sec_bus, &visws_pci_ops, NULL); + pcibios_fixup_irqs(); + pcibios_resource_survey(); +} + +char * __init pcibios_setup(char *str) +{ + return str; +} + +int pcibios_enable_device(struct pci_dev *dev) +{ + return pcibios_enable_resources(dev); +} + +void __init pcibios_penalize_isa_irq(irq) +{ +} diff -Nru a/arch/i386/mach-visws/setup.c b/arch/i386/mach-visws/setup.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/setup.c Thu Aug 29 08:48:01 2002 @@ -0,0 +1,170 @@ +/* + * Unmaintained SGI Visual Workstation support. + * Split out from setup.c by davej@suse.de + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +char visws_board_type = -1; +char visws_board_rev = -1; + +#define PIIX_PM_START 0x0F80 + +#define SIO_GPIO_START 0x0FC0 + +#define SIO_PM_START 0x0FC8 + +#define PMBASE PIIX_PM_START +#define GPIREG0 (PMBASE+0x30) +#define GPIREG(x) (GPIREG0+((x)/8)) +#define PIIX_GPI_BD_ID1 18 +#define PIIX_GPI_BD_REG GPIREG(PIIX_GPI_BD_ID1) + +#define PIIX_GPI_BD_SHIFT (PIIX_GPI_BD_ID1 % 8) + +#define SIO_INDEX 0x2e +#define SIO_DATA 0x2f + +#define SIO_DEV_SEL 0x7 +#define SIO_DEV_ENB 0x30 +#define SIO_DEV_MSB 0x60 +#define SIO_DEV_LSB 0x61 + +#define SIO_GP_DEV 0x7 + +#define SIO_GP_BASE SIO_GPIO_START +#define SIO_GP_MSB (SIO_GP_BASE>>8) +#define SIO_GP_LSB (SIO_GP_BASE&0xff) + +#define SIO_GP_DATA1 (SIO_GP_BASE+0) + +#define SIO_PM_DEV 0x8 + +#define SIO_PM_BASE SIO_PM_START +#define SIO_PM_MSB (SIO_PM_BASE>>8) +#define SIO_PM_LSB (SIO_PM_BASE&0xff) +#define SIO_PM_INDEX (SIO_PM_BASE+0) +#define SIO_PM_DATA (SIO_PM_BASE+1) + +#define SIO_PM_FER2 0x1 + +#define SIO_PM_GP_EN 0x80 + +void __init visws_get_board_type_and_rev(void) +{ + int raw; + + visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG) + >> PIIX_GPI_BD_SHIFT; +/* + * Get Board rev. + * First, we have to initialize the 307 part to allow us access + * to the GPIO registers. Let's map them at 0x0fc0 which is right + * after the PIIX4 PM section. + */ + outb_p(SIO_DEV_SEL, SIO_INDEX); + outb_p(SIO_GP_DEV, SIO_DATA); /* Talk to GPIO regs. */ + + outb_p(SIO_DEV_MSB, SIO_INDEX); + outb_p(SIO_GP_MSB, SIO_DATA); /* MSB of GPIO base address */ + + outb_p(SIO_DEV_LSB, SIO_INDEX); + outb_p(SIO_GP_LSB, SIO_DATA); /* LSB of GPIO base address */ + + outb_p(SIO_DEV_ENB, SIO_INDEX); + outb_p(1, SIO_DATA); /* Enable GPIO registers. */ + +/* + * Now, we have to map the power management section to write + * a bit which enables access to the GPIO registers. + * What lunatic came up with this shit? + */ + outb_p(SIO_DEV_SEL, SIO_INDEX); + outb_p(SIO_PM_DEV, SIO_DATA); /* Talk to GPIO regs. */ + + outb_p(SIO_DEV_MSB, SIO_INDEX); + outb_p(SIO_PM_MSB, SIO_DATA); /* MSB of PM base address */ + + outb_p(SIO_DEV_LSB, SIO_INDEX); + outb_p(SIO_PM_LSB, SIO_DATA); /* LSB of PM base address */ + + outb_p(SIO_DEV_ENB, SIO_INDEX); + outb_p(1, SIO_DATA); /* Enable PM registers. */ + +/* + * Now, write the PM register which enables the GPIO registers. + */ + outb_p(SIO_PM_FER2, SIO_PM_INDEX); + outb_p(SIO_PM_GP_EN, SIO_PM_DATA); + +/* + * Now, initialize the GPIO registers. + * We want them all to be inputs which is the + * power on default, so let's leave them alone. + * So, let's just read the board rev! + */ + raw = inb_p(SIO_GP_DATA1); + raw &= 0x7f; /* 7 bits of valid board revision ID. */ + + if (visws_board_type == VISWS_320) { + if (raw < 0x6) { + visws_board_rev = 4; + } else if (raw < 0xc) { + visws_board_rev = 5; + } else { + visws_board_rev = 6; + } + } else if (visws_board_type == VISWS_540) { + visws_board_rev = 2; + } else { + visws_board_rev = raw; + } + + printk(KERN_INFO "Silicon Graphics %s (rev %d)\n", + visws_board_type == VISWS_320 ? "320" : + (visws_board_type == VISWS_540 ? "540" : + "unknown"), visws_board_rev); +} + +void __init pre_intr_init_hook(void) +{ + init_VISWS_APIC_irqs(); +} + +void __init intr_init_hook(void) +{ +#ifdef CONFIG_X86_LOCAL_APIC + apic_intr_init(); +#endif +} + +void __init pre_setup_arch_hook() +{ + visws_get_board_type_and_rev(); +} +static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL}; + +void __init time_init_hook(void) +{ + printk("Starting Cobalt Timer system clock\n"); + + /* Set the countdown value */ + co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ); + + /* Start the timer */ + co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) | CO_CTRL_TIMERUN); + + /* Enable (unmask) the timer interrupt */ + co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK); + + /* Wire cpu IDT entry to s/w handler (and Cobalt APIC to IDT) */ + setup_irq(CO_IRQ_TIMER, &irq0); +} diff -Nru a/arch/i386/mach-visws/setup_arch_post.h b/arch/i386/mach-visws/setup_arch_post.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/setup_arch_post.h Thu Aug 29 08:48:01 2002 @@ -0,0 +1,37 @@ +/* Hook for machine specific memory setup. + * + * This is included late in kernel/setup.c so that it can make use of all of + * the static functions. */ + +static inline char * __init machine_specific_memory_setup(void) +{ + char *who; + + + who = "BIOS-e820"; + + /* + * Try to copy the BIOS-supplied E820-map. + * + * Otherwise fake a memory map; one section from 0k->640k, + * the next section from 1mb->appropriate_mem_k + */ + sanitize_e820_map(E820_MAP, &E820_MAP_NR); + if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) { + unsigned long mem_size; + + /* compare results from other methods and take the greater */ + if (ALT_MEM_K < EXT_MEM_K) { + mem_size = EXT_MEM_K; + who = "BIOS-88"; + } else { + mem_size = ALT_MEM_K; + who = "BIOS-e801"; + } + + e820.nr_map = 0; + add_memory_region(0, LOWMEMSIZE(), E820_RAM); + add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM); + } + return who; +} diff -Nru a/arch/i386/mach-visws/setup_arch_pre.h b/arch/i386/mach-visws/setup_arch_pre.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/setup_arch_pre.h Thu Aug 29 08:48:01 2002 @@ -0,0 +1,5 @@ +/* Hook to call BIOS initialisation function */ + +/* no action for visws */ + +#define ARCH_SETUP diff -Nru a/arch/i386/mach-visws/smpboot_hooks.h b/arch/i386/mach-visws/smpboot_hooks.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/smpboot_hooks.h Thu Aug 29 08:48:01 2002 @@ -0,0 +1,13 @@ +/* for visws do nothing for any of these */ + +static inline void smpboot_clear_io_apic_irqs(void) +{ +} + +static inline void smpboot_setup_warm_reset_vector(void) +{ +} + +static inline void smpboot_setup_io_apic(void) +{ +} diff -Nru a/arch/i386/mach-visws/traps.c b/arch/i386/mach-visws/traps.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/traps.c Thu Aug 29 08:48:01 2002 @@ -0,0 +1,134 @@ +/* VISWS traps */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_X86_VISWS_APIC +#include +#include +#include +#endif + +#ifdef CONFIG_X86_VISWS_APIC + +/* + * On Rev 005 motherboards legacy device interrupt lines are wired directly + * to Lithium from the 307. But the PROM leaves the interrupt type of each + * 307 logical device set appropriate for the 8259. Later we'll actually use + * the 8259, but for now we have to flip the interrupt types to + * level triggered, active lo as required by Lithium. + */ + +#define REG 0x2e /* The register to read/write */ +#define DEV 0x07 /* Register: Logical device select */ +#define VAL 0x2f /* The value to read/write */ + +static void +superio_outb(int dev, int reg, int val) +{ + outb(DEV, REG); + outb(dev, VAL); + outb(reg, REG); + outb(val, VAL); +} + +static int __attribute__ ((unused)) +superio_inb(int dev, int reg) +{ + outb(DEV, REG); + outb(dev, VAL); + outb(reg, REG); + return inb(VAL); +} + +#define FLOP 3 /* floppy logical device */ +#define PPORT 4 /* parallel logical device */ +#define UART5 5 /* uart2 logical device (not wired up) */ +#define UART6 6 /* uart1 logical device (THIS is the serial port!) */ +#define IDEST 0x70 /* int. destination (which 307 IRQ line) reg. */ +#define ITYPE 0x71 /* interrupt type register */ + +/* interrupt type bits */ +#define LEVEL 0x01 /* bit 0, 0 == edge triggered */ +#define ACTHI 0x02 /* bit 1, 0 == active lo */ + +static __init void +superio_init(void) +{ + if (visws_board_type == VISWS_320 && visws_board_rev == 5) { + superio_outb(UART6, IDEST, 0); /* 0 means no intr propagated */ + printk("SGI 320 rev 5: disabling 307 uart1 interrupt\n"); + } +} + +static __init void +lithium_init(void) +{ + set_fixmap(FIX_LI_PCIA, LI_PCI_A_PHYS); + printk("Lithium PCI Bridge A, Bus Number: %d\n", + li_pcia_read16(LI_PCI_BUSNUM) & 0xff); + set_fixmap(FIX_LI_PCIB, LI_PCI_B_PHYS); + printk("Lithium PCI Bridge B (PIIX4), Bus Number: %d\n", + li_pcib_read16(LI_PCI_BUSNUM) & 0xff); + + /* XXX blindly enables all interrupts */ + li_pcia_write16(LI_PCI_INTEN, 0xffff); + li_pcib_write16(LI_PCI_INTEN, 0xffff); +} + +static __init void +cobalt_init(void) +{ + /* + * On normal SMP PC this is used only with SMP, but we have to + * use it and set it up here to start the Cobalt clock + */ + set_fixmap(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE); + printk("Local APIC ID %lx\n", apic_read(APIC_ID)); + printk("Local APIC Version %lx\n", apic_read(APIC_LVR)); + + set_fixmap(FIX_CO_CPU, CO_CPU_PHYS); + printk("Cobalt Revision %lx\n", co_cpu_read(CO_CPU_REV)); + + set_fixmap(FIX_CO_APIC, CO_APIC_PHYS); + printk("Cobalt APIC ID %lx\n", co_apic_read(CO_APIC_ID)); + + /* Enable Cobalt APIC being careful to NOT change the ID! */ + co_apic_write(CO_APIC_ID, co_apic_read(CO_APIC_ID)|CO_APIC_ENABLE); + + printk("Cobalt APIC enabled: ID reg %lx\n", co_apic_read(CO_APIC_ID)); +} +#endif + +void __init trap_init_hook() +{ +#ifdef CONFIG_X86_VISWS_APIC + superio_init(); + lithium_init(); + cobalt_init(); +#endif +} diff -Nru a/arch/i386/mach-visws/visws_apic.c b/arch/i386/mach-visws/visws_apic.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-visws/visws_apic.c Thu Aug 29 08:48:01 2002 @@ -0,0 +1,410 @@ +/* + * linux/arch/i386/kernel/visws_apic.c + * + * Copyright (C) 1999 Bent Hagemark, Ingo Molnar + * + * SGI Visual Workstation interrupt controller + * + * The Cobalt system ASIC in the Visual Workstation contains a "Cobalt" APIC + * which serves as the main interrupt controller in the system. Non-legacy + * hardware in the system uses this controller directly. Legacy devices + * are connected to the PIIX4 which in turn has its 8259(s) connected to + * a of the Cobalt APIC entry. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +/* + * This is the PIIX4-based 8259 that is wired up indirectly to Cobalt + * -- not the manner expected by the normal 8259 code in irq.c. + * + * there is a 'master' physical interrupt source that gets sent to + * the CPU. But in the chipset there are various 'virtual' interrupts + * waiting to be handled. We represent this to Linux through a 'master' + * interrupt controller type, and through a special virtual interrupt- + * controller. Device drivers only see the virtual interrupt sources. + */ + +#define CO_IRQ_BASE 0x20 /* This is the 0x20 in init_IRQ()! */ + +static void startup_piix4_master_irq(unsigned int irq); +static void shutdown_piix4_master_irq(unsigned int irq); +static void do_piix4_master_IRQ(unsigned int irq, struct pt_regs * regs); +#define enable_piix4_master_irq startup_piix4_master_irq +#define disable_piix4_master_irq shutdown_piix4_master_irq + +static struct hw_interrupt_type piix4_master_irq_type = { + "PIIX4-master", + startup_piix4_master_irq, + shutdown_piix4_master_irq, + do_piix4_master_IRQ, + enable_piix4_master_irq, + disable_piix4_master_irq +}; + +static void enable_piix4_virtual_irq(unsigned int irq); +static void disable_piix4_virtual_irq(unsigned int irq); +#define startup_piix4_virtual_irq enable_piix4_virtual_irq +#define shutdown_piix4_virtual_irq disable_piix4_virtual_irq + +static struct hw_interrupt_type piix4_virtual_irq_type = { + "PIIX4-virtual", + startup_piix4_virtual_irq, + shutdown_piix4_virtual_irq, + 0, /* no handler, it's never called physically */ + enable_piix4_virtual_irq, + disable_piix4_virtual_irq +}; + +/* + * This is the SGI Cobalt (IO-)APIC: + */ + +static void do_cobalt_IRQ(unsigned int irq, struct pt_regs * regs); +static void enable_cobalt_irq(unsigned int irq); +static void disable_cobalt_irq(unsigned int irq); +static void startup_cobalt_irq(unsigned int irq); +#define shutdown_cobalt_irq disable_cobalt_irq + +static spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED; + +static struct hw_interrupt_type cobalt_irq_type = { + "Cobalt-APIC", + startup_cobalt_irq, + shutdown_cobalt_irq, + do_cobalt_IRQ, + enable_cobalt_irq, + disable_cobalt_irq +}; + + +/* + * Not an __init, needed by the reboot code + */ +void disable_IO_APIC(void) +{ + /* Nop on Cobalt */ +} + +/* + * Cobalt (IO)-APIC functions to handle PCI devices. + */ + +static void disable_cobalt_irq(unsigned int irq) +{ + /* XXX undo the APIC entry here? */ + + /* + * definitely, we do not want to have IRQ storms from + * unused devices --mingo + */ +} + +static void enable_cobalt_irq(unsigned int irq) +{ +} + +/* + * Set the given Cobalt APIC Redirection Table entry to point + * to the given IDT vector/index. + */ +static void co_apic_set(int entry, int idtvec) +{ + co_apic_write(CO_APIC_LO(entry), CO_APIC_LEVEL | (CO_IRQ_BASE+idtvec)); + co_apic_write(CO_APIC_HI(entry), 0); + + printk("Cobalt APIC Entry %d IDT Vector %d\n", entry, idtvec); +} + +/* + * "irq" really just serves to identify the device. Here is where we + * map this to the Cobalt APIC entry where it's physically wired. + * This is called via request_irq -> setup_x86_irq -> irq_desc->startup() + */ +static void startup_cobalt_irq(unsigned int irq) +{ + /* + * These "irq"'s are wired to the same Cobalt APIC entries + * for all (known) motherboard types/revs + */ + switch (irq) { + case CO_IRQ_TIMER: co_apic_set(CO_APIC_CPU, CO_IRQ_TIMER); + return; + + case CO_IRQ_ENET: co_apic_set(CO_APIC_ENET, CO_IRQ_ENET); + return; + + case CO_IRQ_SERIAL: return; /* XXX move to piix4-8259 "virtual" */ + + case CO_IRQ_8259: co_apic_set(CO_APIC_8259, CO_IRQ_8259); + return; + + case CO_IRQ_IDE: + switch (visws_board_type) { + case VISWS_320: + switch (visws_board_rev) { + case 5: + co_apic_set(CO_APIC_0_5_IDE0, CO_IRQ_IDE); + co_apic_set(CO_APIC_0_5_IDE1, CO_IRQ_IDE); + return; + case 6: + co_apic_set(CO_APIC_0_6_IDE0, CO_IRQ_IDE); + co_apic_set(CO_APIC_0_6_IDE1, CO_IRQ_IDE); + return; + } + case VISWS_540: + switch (visws_board_rev) { + case 2: + co_apic_set(CO_APIC_1_2_IDE0, CO_IRQ_IDE); + return; + } + } + break; + default: + panic("huh?"); + } +} + +/* + * This is the handle() op in do_IRQ() + */ +static void do_cobalt_IRQ(unsigned int irq, struct pt_regs * regs) +{ + struct irqaction * action; + irq_desc_t *desc = irq_desc + irq; + + spin_lock(&irq_controller_lock); + { + unsigned int status; + /* XXX APIC EOI? */ + status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); + action = NULL; + if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { + action = desc->action; + status |= IRQ_INPROGRESS; + } + desc->status = status; + } + spin_unlock(&irq_controller_lock); + + /* Exit early if we had no action or it was disabled */ + if (!action) + return; + + handle_IRQ_event(irq, regs, action); + + (void)co_cpu_read(CO_CPU_REV); /* Sync driver ack to its h/w */ + apic_write(APIC_EOI, APIC_EIO_ACK); /* Send EOI to Cobalt APIC */ + + spin_lock(&irq_controller_lock); + { + unsigned int status = desc->status & ~IRQ_INPROGRESS; + desc->status = status; + if (!(status & IRQ_DISABLED)) + enable_cobalt_irq(irq); + } + spin_unlock(&irq_controller_lock); +} + +/* + * PIIX4-8259 master/virtual functions to handle: + * + * floppy + * parallel + * serial + * audio (?) + * + * None of these get Cobalt APIC entries, neither do they have IDT + * entries. These interrupts are purely virtual and distributed from + * the 'master' interrupt source: CO_IRQ_8259. + * + * When the 8259 interrupts its handler figures out which of these + * devices is interrupting and dispatches to it's handler. + * + * CAREFUL: devices see the 'virtual' interrupt only. Thus disable/ + * enable_irq gets the right irq. This 'master' irq is never directly + * manipulated by any driver. + */ + +static void startup_piix4_master_irq(unsigned int irq) +{ + /* ICW1 */ + outb(0x11, 0x20); + outb(0x11, 0xa0); + + /* ICW2 */ + outb(0x08, 0x21); + outb(0x70, 0xa1); + + /* ICW3 */ + outb(0x04, 0x21); + outb(0x02, 0xa1); + + /* ICW4 */ + outb(0x01, 0x21); + outb(0x01, 0xa1); + + /* OCW1 - disable all interrupts in both 8259's */ + outb(0xff, 0x21); + outb(0xff, 0xa1); + + startup_cobalt_irq(irq); +} + +static void shutdown_piix4_master_irq(unsigned int irq) +{ + /* + * [we skip the 8259 magic here, not strictly necessary] + */ + + shutdown_cobalt_irq(irq); +} + +static void do_piix4_master_IRQ(unsigned int irq, struct pt_regs * regs) +{ + int realirq, mask; + + /* Find out what's interrupting in the PIIX4 8259 */ + + spin_lock(&irq_controller_lock); + outb(0x0c, 0x20); /* OCW3 Poll command */ + realirq = inb(0x20); + + if (!(realirq & 0x80)) { + /* + * Bit 7 == 0 means invalid/spurious + */ + goto out_unlock; + } + realirq &= 0x7f; + + /* + * mask and ack the 8259 + */ + mask = inb(0x21); + if ((mask >> realirq) & 0x01) + /* + * This IRQ is masked... ignore + */ + goto out_unlock; + + outb(mask | (1<status & IRQ_DISABLED)) + enable_piix4_virtual_irq(realirq); + } + spin_unlock(&irq_controller_lock); + return; + +out_unlock: + spin_unlock(&irq_controller_lock); + return; +} + +static void enable_piix4_virtual_irq(unsigned int irq) +{ + /* + * assumes this irq is one of the legacy devices + */ + + unsigned int mask = inb(0x21); + mask &= ~(1 << irq); + outb(mask, 0x21); + enable_cobalt_irq(irq); +} + +/* + * assumes this irq is one of the legacy devices + */ +static void disable_piix4_virtual_irq(unsigned int irq) +{ + unsigned int mask; + + disable_cobalt_irq(irq); + + mask = inb(0x21); + mask &= ~(1 << irq); + outb(mask, 0x21); +} + +static struct irqaction master_action = + { no_action, 0, 0, "PIIX4-8259", NULL, NULL }; + +void init_VISWS_APIC_irqs(void) +{ + int i; + + for (i = 0; i < 16; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = 0; + irq_desc[i].depth = 1; + + /* + * Cobalt IRQs are mapped to standard ISA + * interrupt vectors: + */ + switch (i) { + /* + * Only CO_IRQ_8259 will be raised + * externally. + */ + case CO_IRQ_8259: + irq_desc[i].handler = &piix4_master_irq_type; + break; + case CO_IRQ_FLOPPY: + case CO_IRQ_PARLL: + irq_desc[i].handler = &piix4_virtual_irq_type; + break; + default: + irq_desc[i].handler = &cobalt_irq_type; + break; + } + } + + /* + * The master interrupt is always present: + */ + setup_x86_irq(CO_IRQ_8259, &master_action); +} + diff -Nru a/arch/i386/pci/Makefile b/arch/i386/pci/Makefile --- a/arch/i386/pci/Makefile Thu Aug 29 08:48:01 2002 +++ b/arch/i386/pci/Makefile Thu Aug 29 08:48:01 2002 @@ -2,10 +2,6 @@ obj-y := i386.o -ifdef CONFIG_VISWS -obj-y += visws.o -else - obj-$(CONFIG_PCI_BIOS) += pcbios.o obj-$(CONFIG_PCI_DIRECT) += direct.o @@ -22,6 +18,5 @@ endif # CONFIG_MULTIQUAD obj-y += irq.o common.o -endif # CONFIG_VISWS include $(TOPDIR)/Rules.make diff -Nru a/arch/i386/pci/visws.c b/arch/i386/pci/visws.c --- a/arch/i386/pci/visws.c Thu Aug 29 08:48:01 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,141 +0,0 @@ -/* - * Low-Level PCI Support for SGI Visual Workstation - * - * (c) 1999--2000 Martin Mares - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "pci-i386.h" - -unsigned int pci_probe = 0; - -/* - * The VISWS uses configuration access type 1 only. - */ - -#define CONFIG_CMD(dev, where) (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3)) - -static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value) -{ - outl(CONFIG_CMD(dev,where), 0xCF8); - *value = inb(0xCFC + (where&3)); - return PCIBIOS_SUCCESSFUL; -} - -static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value) -{ - outl(CONFIG_CMD(dev,where), 0xCF8); - *value = inw(0xCFC + (where&2)); - return PCIBIOS_SUCCESSFUL; -} - -static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value) -{ - outl(CONFIG_CMD(dev,where), 0xCF8); - *value = inl(0xCFC); - return PCIBIOS_SUCCESSFUL; -} - -static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value) -{ - outl(CONFIG_CMD(dev,where), 0xCF8); - outb(value, 0xCFC + (where&3)); - return PCIBIOS_SUCCESSFUL; -} - -static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value) -{ - outl(CONFIG_CMD(dev,where), 0xCF8); - outw(value, 0xCFC + (where&2)); - return PCIBIOS_SUCCESSFUL; -} - -static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value) -{ - outl(CONFIG_CMD(dev,where), 0xCF8); - outl(value, 0xCFC); - return PCIBIOS_SUCCESSFUL; -} - -#undef CONFIG_CMD - -static struct pci_ops visws_pci_ops = { - pci_conf1_read_config_byte, - pci_conf1_read_config_word, - pci_conf1_read_config_dword, - pci_conf1_write_config_byte, - pci_conf1_write_config_word, - pci_conf1_write_config_dword -}; - -static void __init pcibios_fixup_irqs(void) -{ - struct pci_dev *dev, *p; - u8 pin; - int irq; - - pci_for_each_dev(dev) { - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); - dev->irq = 0; - if (!pin) - continue; - pin--; - if (dev->bus->parent) { - p = dev->bus->parent->self; - pin = (pin + PCI_SLOT(dev->devfn)) % 4; - } else - p = dev; - irq = visws_get_PCI_irq_vector(p->bus->number, PCI_SLOT(p->devfn), pin+1); - if (irq >= 0) - dev->irq = irq; - DBG("PCI IRQ: %s pin %d -> %d\n", dev->slot_name, pin, irq); - } -} - -void __init pcibios_fixup_bus(struct pci_bus *b) -{ - pci_read_bridge_bases(b); -} - -#if 0 -static struct resource visws_pci_bus_resources[2] = { - { "Host bus 1", 0xf4000000, 0xf7ffffff, 0 }, - { "Host bus 2", 0xf0000000, 0xf3ffffff, 0 } -}; -#endif - -void __init pcibios_init(void) -{ - unsigned int sec_bus = li_pcib_read16(LI_PCI_BUSNUM) & 0xff; - - printk("PCI: Probing PCI hardware on host buses 00 and %02x\n", sec_bus); - pci_scan_bus(0, &visws_pci_ops, NULL); - pci_scan_bus(sec_bus, &visws_pci_ops, NULL); - pcibios_fixup_irqs(); - pcibios_resource_survey(); -} - -char * __init pcibios_setup(char *str) -{ - return str; -} - -int pcibios_enable_device(struct pci_dev *dev) -{ - return pcibios_enable_resources(dev); -} - -void __init pcibios_penalize_isa_irq(irq) -{ -} diff -Nru a/fs/binfmt_elf.c b/fs/binfmt_elf.c --- a/fs/binfmt_elf.c Thu Aug 29 08:48:01 2002 +++ b/fs/binfmt_elf.c Thu Aug 29 08:48:01 2002 @@ -143,7 +143,7 @@ } else u_platform = p; -#if defined(__i386__) && defined(CONFIG_SMP) +#ifdef CONFIG_X86_HT /* * In some cases (e.g. Hyper-Threading), we want to avoid L1 evictions * by the processes running on the same package. One thing we can do diff -Nru a/include/asm-i386/arch_hooks.h b/include/asm-i386/arch_hooks.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-i386/arch_hooks.h Thu Aug 29 08:48:01 2002 @@ -0,0 +1,25 @@ +#ifndef _ASM_ARCH_HOOKS_H +#define _ASM_ARCH_HOOKS_H + +/* + * linux/include/asm/arch_hooks.h + * + * define the architecture specific hooks + */ + +/* these aren't arch hooks, they are generic routines + * that can be used by the hooks */ +extern void init_ISA_irqs(void); +extern void apic_intr_init(void); +extern void smp_intr_init(void); +extern void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +/* these are the defined hooks */ +extern void intr_init_hook(void); +extern void pre_intr_init_hook(void); +extern void pre_setup_arch_hook(void); +extern void trap_init_hook(void); +extern void time_init_hook(void); +extern void mca_nmi_hook(void); + +#endif diff -Nru a/include/asm-i386/irq.h b/include/asm-i386/irq.h --- a/include/asm-i386/irq.h Thu Aug 29 08:48:01 2002 +++ b/include/asm-i386/irq.h Thu Aug 29 08:48:01 2002 @@ -12,7 +12,8 @@ #include #include -#include +/* include comes from machine specific directory */ +#include "irq_vectors.h" static __inline__ int irq_cannonicalize(int irq) { diff -Nru a/include/asm-i386/irq_vectors.h b/include/asm-i386/irq_vectors.h --- a/include/asm-i386/irq_vectors.h Thu Aug 29 08:48:01 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,64 +0,0 @@ -#ifndef _ASM_IRQ_VECTORS_H -#define _ASM_IRQ_VECTORS_H - -/* - * IDT vectors usable for external interrupt sources start - * at 0x20: - */ -#define FIRST_EXTERNAL_VECTOR 0x20 - -#define SYSCALL_VECTOR 0x80 - -/* - * Vectors 0x20-0x2f are used for ISA interrupts. - */ - -/* - * Special IRQ vectors used by the SMP architecture, 0xf0-0xff - * - * some of the following vectors are 'rare', they are merged - * into a single vector (CALL_FUNCTION_VECTOR) to save vector space. - * TLB, reschedule and local APIC vectors are performance-critical. - * - * Vectors 0xf0-0xfa are free (reserved for future Linux use). - */ -#define SPURIOUS_APIC_VECTOR 0xff -#define ERROR_APIC_VECTOR 0xfe -#define INVALIDATE_TLB_VECTOR 0xfd -#define RESCHEDULE_VECTOR 0xfc -#define CALL_FUNCTION_VECTOR 0xfb - -#define THERMAL_APIC_VECTOR 0xf0 -/* - * Local APIC timer IRQ vector is on a different priority level, - * to work around the 'lost local interrupt if more than 2 IRQ - * sources per level' errata. - */ -#define LOCAL_TIMER_VECTOR 0xef - -/* - * First APIC vector available to drivers: (vectors 0x30-0xee) - * we start at 0x31 to spread out vectors evenly between priority - * levels. (0x80 is the syscall vector) - */ -#define FIRST_DEVICE_VECTOR 0x31 -#define FIRST_SYSTEM_VECTOR 0xef - -#define TIMER_IRQ 0 - -/* - * 16 8259A IRQ's, 208 potential APIC interrupt sources. - * Right now the APIC is mostly only used for SMP. - * 256 vectors is an architectural limit. (we can have - * more than 256 devices theoretically, but they will - * have to use shared interrupts) - * Since vectors 0x00-0x1f are used/reserved for the CPU, - * the usable vector space is 0x20-0xff (224 vectors) - */ -#ifdef CONFIG_X86_IO_APIC -#define NR_IRQS 224 -#else -#define NR_IRQS 16 -#endif - -#endif /* _ASM_IRQ_VECTORS_H */