Commit 4dcab932 authored by James Bottomley's avatar James Bottomley

merge by hand

parents 0d961969 a582b049
...@@ -85,13 +85,25 @@ ifdef CONFIG_MCYRIXIII ...@@ -85,13 +85,25 @@ ifdef CONFIG_MCYRIXIII
CFLAGS += -march=i586 CFLAGS += -march=i586
endif endif
ifdef CONFIG_VISWS
MACHINE := mach-visws
else
MACHINE := mach-generic
endif
HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o 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 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 ifdef CONFIG_MATH_EMULATION
SUBDIRS += arch/i386/math-emu SUBDIRS += arch/i386/math-emu
DRIVERS += arch/i386/math-emu/math.o DRIVERS += arch/i386/math-emu/math.o
......
...@@ -254,6 +254,7 @@ else ...@@ -254,6 +254,7 @@ else
if [ "$CONFIG_SMP" = "y" ]; then if [ "$CONFIG_SMP" = "y" ]; then
define_bool CONFIG_X86_IO_APIC y define_bool CONFIG_X86_IO_APIC y
define_bool CONFIG_X86_LOCAL_APIC y define_bool CONFIG_X86_LOCAL_APIC y
define_bool CONFIG_X86_MPPARSE y
fi fi
bool 'PCI support' CONFIG_PCI bool 'PCI support' CONFIG_PCI
if [ "$CONFIG_PCI" = "y" ]; then if [ "$CONFIG_PCI" = "y" ]; then
...@@ -431,7 +432,19 @@ if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then ...@@ -431,7 +432,19 @@ if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
fi fi
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 endmenu
source security/Config.in source security/Config.in
source lib/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
...@@ -14,22 +14,18 @@ obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ ...@@ -14,22 +14,18 @@ obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
bootflag.o bootflag.o
obj-y += cpu/ obj-y += cpu/
obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o
obj-$(CONFIG_MCA) += mca.o obj-$(CONFIG_MCA) += mca.o
obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_MSR) += msr.o
obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_X86_CPUID) += cpuid.o
obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_MICROCODE) += microcode.o
obj-$(CONFIG_APM) += apm.o obj-$(CONFIG_APM) += apm.o
obj-$(CONFIG_ACPI) += acpi.o obj-$(CONFIG_X86_SMP) += smp.o smpboot.o trampoline.o
obj-$(CONFIG_ACPI_SLEEP) += acpi_wakeup.o obj-$(CONFIG_X86_MPPARSE) += mpparse.o
obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o
obj-$(CONFIG_X86_LOCAL_APIC) += mpparse.o apic.o nmi.o
obj-$(CONFIG_X86_IO_APIC) += io_apic.o obj-$(CONFIG_X86_IO_APIC) += io_apic.o
obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o
obj-$(CONFIG_X86_NUMAQ) += numaq.o obj-$(CONFIG_X86_NUMAQ) += numaq.o
ifdef CONFIG_VISWS
obj-y += setup-visws.o
obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o
endif
EXTRA_AFLAGS := -traditional EXTRA_AFLAGS := -traditional
......
...@@ -29,6 +29,21 @@ ...@@ -29,6 +29,21 @@
#include <asm/mtrr.h> #include <asm/mtrr.h>
#include <asm/mpspec.h> #include <asm/mpspec.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/desc.h>
#include <asm/arch_hooks.h>
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? */ /* Using APIC to generate smp_local_timer_interrupt? */
int using_apic_timer = 0; int using_apic_timer = 0;
......
...@@ -257,7 +257,7 @@ static void __init init_intel(struct cpuinfo_x86 *c) ...@@ -257,7 +257,7 @@ static void __init init_intel(struct cpuinfo_x86 *c)
if ( p ) if ( p )
strcpy(c->x86_model_id, 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) { if (test_bit(X86_FEATURE_HT, c->x86_capability) && !disable_P4_HT) {
extern int phys_proc_id[NR_CPUS]; extern int phys_proc_id[NR_CPUS];
......
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
#include <asm/errno.h> #include <asm/errno.h>
#include <asm/segment.h> #include <asm/segment.h>
#include <asm/smp.h> #include <asm/smp.h>
#include <asm/irq_vectors.h> #include "irq_vectors.h"
EBX = 0x00 EBX = 0x00
ECX = 0x04 ECX = 0x04
...@@ -344,34 +344,8 @@ ENTRY(name) \ ...@@ -344,34 +344,8 @@ ENTRY(name) \
call smp_/**/name; \ call smp_/**/name; \
jmp ret_from_intr; jmp ret_from_intr;
/* /* The include is where all of the SMP etc. interrupts come from */
* The following vectors are part of the Linux architecture, there #include "entry_arch.h"
* 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
ENTRY(divide_error) ENTRY(divide_error)
pushl $0 # no error code pushl $0 # no error code
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <asm/delay.h> #include <asm/delay.h>
#include <asm/desc.h> #include <asm/desc.h>
#include <asm/apic.h> #include <asm/apic.h>
#include <asm/arch_hooks.h>
#include <linux/irq.h> #include <linux/irq.h>
...@@ -332,15 +333,6 @@ static void math_error_irq(int cpl, void *dev_id, struct pt_regs *regs) ...@@ -332,15 +333,6 @@ static void math_error_irq(int cpl, void *dev_id, struct pt_regs *regs)
*/ */
static struct irqaction irq13 = { math_error_irq, 0, 0, "fpu", NULL, NULL }; 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) void __init init_ISA_irqs (void)
{ {
int i; int i;
...@@ -373,11 +365,9 @@ void __init init_IRQ(void) ...@@ -373,11 +365,9 @@ void __init init_IRQ(void)
{ {
int i; int i;
#ifndef CONFIG_X86_VISWS_APIC /* all the set up before the call gates are initialised */
init_ISA_irqs(); pre_intr_init_hook();
#else
init_VISWS_APIC_irqs();
#endif
/* /*
* Cover the whole vector space, no vector can escape * Cover the whole vector space, no vector can escape
* us. (some of these will be overridden and become * us. (some of these will be overridden and become
...@@ -389,39 +379,9 @@ void __init init_IRQ(void) ...@@ -389,39 +379,9 @@ void __init init_IRQ(void)
set_intr_gate(vector, interrupt[i]); set_intr_gate(vector, interrupt[i]);
} }
#ifdef CONFIG_SMP /* setup after call gates are initialised (usually add in
/* * the architecture specific gates */
* IRQ0 must be given a fixed assignment and initialized, intr_init_hook();
* 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
/* /*
* Set the clock to HZ Hz, we already have a valid * Set the clock to HZ Hz, we already have a valid
...@@ -431,10 +391,6 @@ void __init init_IRQ(void) ...@@ -431,10 +391,6 @@ void __init init_IRQ(void)
outb_p(LATCH & 0xff , 0x40); /* LSB */ outb_p(LATCH & 0xff , 0x40); /* LSB */
outb(LATCH >> 8 , 0x40); /* MSB */ outb(LATCH >> 8 , 0x40); /* MSB */
#ifndef CONFIG_VISWS
setup_irq(2, &irq2);
#endif
/* /*
* External FPU? Set up irq13 if so, for * External FPU? Set up irq13 if so, for
* original braindamaged IBM FERR coupling. * original braindamaged IBM FERR coupling.
......
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/init.h> #include <linux/init.h>
#include <asm/arch_hooks.h>
/* This structure holds MCA information. Each (plug-in) adapter has /* This structure holds MCA information. Each (plug-in) adapter has
* eight POS registers. Then the machine may have integrated video and * eight POS registers. Then the machine may have integrated video and
...@@ -379,12 +380,7 @@ void mca_handle_nmi(void) ...@@ -379,12 +380,7 @@ void mca_handle_nmi(void)
} }
} }
/* If I recall correctly, there's a whole bunch of other things that mca_nmi_hook();
* 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_handle_nmi */ } /* mca_handle_nmi */
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
......
...@@ -73,7 +73,7 @@ unsigned long phys_cpu_present_map; ...@@ -73,7 +73,7 @@ unsigned long phys_cpu_present_map;
* Intel MP BIOS table parsing routines: * Intel MP BIOS table parsing routines:
*/ */
#ifndef CONFIG_X86_VISWS_APIC
/* /*
* Checksum an MP configuration block. * Checksum an MP configuration block.
*/ */
...@@ -737,7 +737,7 @@ static int __init smp_scan_config (unsigned long base, unsigned long length) ...@@ -737,7 +737,7 @@ static int __init smp_scan_config (unsigned long base, unsigned long length)
return 0; return 0;
} }
void __init find_intel_smp (void) void __init find_smp_config (void)
{ {
unsigned int address; unsigned int address;
...@@ -777,40 +777,6 @@ void __init find_intel_smp (void) ...@@ -777,40 +777,6 @@ void __init find_intel_smp (void)
printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.kernel.org if you experience SMP problems!\n"); 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
}
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
ACPI-based MP Configuration ACPI-based MP Configuration
......
...@@ -66,11 +66,6 @@ unsigned long thread_saved_pc(struct task_struct *tsk) ...@@ -66,11 +66,6 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
*/ */
void (*pm_idle)(void); void (*pm_idle)(void);
/*
* Power off function, if any
*/
void (*pm_power_off)(void);
void disable_hlt(void) void disable_hlt(void)
{ {
hlt_counter++; hlt_counter++;
...@@ -160,282 +155,6 @@ static int __init idle_setup (char *str) ...@@ -160,282 +155,6 @@ static int __init idle_setup (char *str)
__setup("idle=", idle_setup); __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<<cpuid)))
reboot_cpu = boot_cpu_physical_apicid;
reboot_smp = 0; /* use this as a flag to only go through this once*/
/* re-run this function on the other CPUs
it will fall though this section since we have
cleared reboot_smp, and do the reboot if it is the
correct CPU, otherwise it halts. */
if (reboot_cpu != cpuid)
smp_call_function((void *)machine_restart , NULL, 1, 0);
}
/* if reboot_cpu is still -1, then we want a tradional reboot,
and if we are not running on the reboot_cpu,, halt */
if ((reboot_cpu != -1) && (cpuid != reboot_cpu)) {
for (;;)
__asm__ __volatile__ ("hlt");
}
/*
* Stop all CPUs and turn off local APICs and the IO-APIC, so
* other OSs see a clean IRQ state.
*/
smp_send_stop();
disable_IO_APIC();
#endif
if(!reboot_thru_bios) {
/* rebooting needs to touch the page at absolute addr 0 */
*((unsigned short *)__va(0x472)) = reboot_mode;
for (;;) {
int i;
for (i=0; i<100; i++) {
kb_wait();
udelay(50);
outb(0xfe,0x64); /* pulse reset low */
udelay(50);
}
/* That didn't work - force a triple fault.. */
__asm__ __volatile__("lidt %0": :"m" (no_idt));
__asm__ __volatile__("int3");
}
}
machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
}
void machine_halt(void)
{
}
void machine_power_off(void)
{
if (pm_power_off)
pm_power_off();
}
extern void show_trace(unsigned long* esp); extern void show_trace(unsigned long* esp);
void show_regs(struct pt_regs * regs) void show_regs(struct pt_regs * regs)
......
/*
* linux/arch/i386/kernel/reboot.c
*/
#define __KERNEL_SYSCALLS__
#include <stdarg.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/interrupt.h>
#include <linux/config.h>
#include <linux/delay.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/mc146818rtc.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/ldt.h>
#include <asm/processor.h>
#include <asm/i387.h>
#include <asm/desc.h>
#ifdef CONFIG_MATH_EMULATION
#include <asm/math_emu.h>
#endif
#include <linux/irq.h>
#include <linux/err.h>
/*
* 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<<cpuid)))
reboot_cpu = boot_cpu_physical_apicid;
reboot_smp = 0; /* use this as a flag to only go through this once*/
/* re-run this function on the other CPUs
it will fall though this section since we have
cleared reboot_smp, and do the reboot if it is the
correct CPU, otherwise it halts. */
if (reboot_cpu != cpuid)
smp_call_function((void *)machine_restart , NULL, 1, 0);
}
/* if reboot_cpu is still -1, then we want a tradional reboot,
and if we are not running on the reboot_cpu,, halt */
if ((reboot_cpu != -1) && (cpuid != reboot_cpu)) {
for (;;)
__asm__ __volatile__ ("hlt");
}
/*
* Stop all CPUs and turn off local APICs and the IO-APIC, so
* other OSs see a clean IRQ state.
*/
smp_send_stop();
disable_IO_APIC();
#endif
if(!reboot_thru_bios) {
/* rebooting needs to touch the page at absolute addr 0 */
*((unsigned short *)__va(0x472)) = reboot_mode;
for (;;) {
int i;
for (i=0; i<100; i++) {
kb_wait();
udelay(50);
outb(0xfe,0x64); /* pulse reset low */
udelay(50);
}
/* That didn't work - force a triple fault.. */
__asm__ __volatile__("lidt %0": :"m" (no_idt));
__asm__ __volatile__("int3");
}
}
machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
}
void machine_halt(void)
{
}
void machine_power_off(void)
{
if (pm_power_off)
pm_power_off();
}
...@@ -37,6 +37,10 @@ ...@@ -37,6 +37,10 @@
#include <asm/e820.h> #include <asm/e820.h>
#include <asm/mpspec.h> #include <asm/mpspec.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/arch_hooks.h>
#include "setup_arch_pre.h"
static inline char * __init machine_specific_memory_setup(void);
/* /*
* Machine setup.. * Machine setup..
...@@ -470,31 +474,8 @@ static int __init copy_e820_map(struct e820entry * biosmap, int nr_map) ...@@ -470,31 +474,8 @@ static int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
static void __init setup_memory_region(void) 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"); printk(KERN_INFO "BIOS-provided physical RAM map:\n");
print_memory_map(who); print_memory_map(who);
} /* setup_memory_region */ } /* setup_memory_region */
...@@ -757,7 +738,7 @@ static unsigned long __init setup_memory(void) ...@@ -757,7 +738,7 @@ static unsigned long __init setup_memory(void)
*/ */
acpi_reserve_bootmem(); acpi_reserve_bootmem();
#endif #endif
#ifdef CONFIG_X86_LOCAL_APIC #ifdef CONFIG_X86_FIND_SMP_CONFIG
/* /*
* Find and reserve possible boot-time SMP configuration: * Find and reserve possible boot-time SMP configuration:
*/ */
...@@ -838,12 +819,9 @@ void __init setup_arch(char **cmdline_p) ...@@ -838,12 +819,9 @@ void __init setup_arch(char **cmdline_p)
{ {
unsigned long max_low_pfn; unsigned long max_low_pfn;
pre_setup_arch_hook();
early_cpu_init(); early_cpu_init();
#ifdef CONFIG_VISWS
visws_get_board_type_and_rev();
#endif
ROOT_DEV = ORIG_ROOT_DEV; ROOT_DEV = ORIG_ROOT_DEV;
drive_info = DRIVE_INFO; drive_info = DRIVE_INFO;
screen_info = SCREEN_INFO; screen_info = SCREEN_INFO;
...@@ -863,6 +841,7 @@ void __init setup_arch(char **cmdline_p) ...@@ -863,6 +841,7 @@ void __init setup_arch(char **cmdline_p)
rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
#endif #endif
ARCH_SETUP
setup_memory_region(); setup_memory_region();
if (!MOUNT_ROOT_RDONLY) if (!MOUNT_ROOT_RDONLY)
...@@ -922,6 +901,8 @@ static int __init highio_setup(char *str) ...@@ -922,6 +901,8 @@ static int __init highio_setup(char *str)
} }
__setup("nohighio", highio_setup); __setup("nohighio", highio_setup);
#include "setup_arch_post.h"
/* /*
* Local Variables: * Local Variables:
* mode:c * mode:c
......
...@@ -49,6 +49,9 @@ ...@@ -49,6 +49,9 @@
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/smpboot.h> #include <asm/smpboot.h>
#include <asm/desc.h>
#include <asm/arch_hooks.h>
#include "smpboot_hooks.h"
/* Set if we find a B stepping CPU */ /* Set if we find a B stepping CPU */
static int __initdata smp_b_stepping; static int __initdata smp_b_stepping;
...@@ -1005,9 +1008,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus) ...@@ -1005,9 +1008,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
*/ */
if (!smp_found_config) { if (!smp_found_config) {
printk(KERN_NOTICE "SMP motherboard not detected.\n"); printk(KERN_NOTICE "SMP motherboard not detected.\n");
#ifndef CONFIG_VISWS smpboot_clear_io_apic_irqs();
io_apic_irqs = 0;
#endif
phys_cpu_present_map = 1; phys_cpu_present_map = 1;
if (APIC_init_uniprocessor()) if (APIC_init_uniprocessor())
printk(KERN_NOTICE "Local APIC not detected." printk(KERN_NOTICE "Local APIC not detected."
...@@ -1034,9 +1035,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus) ...@@ -1034,9 +1035,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
boot_cpu_physical_apicid); boot_cpu_physical_apicid);
printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n"); printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n");
#ifndef CONFIG_VISWS smpboot_clear_io_apic_irqs();
io_apic_irqs = 0;
#endif
phys_cpu_present_map = 1; phys_cpu_present_map = 1;
return; return;
} }
...@@ -1049,9 +1048,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus) ...@@ -1049,9 +1048,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
if (!max_cpus) { if (!max_cpus) {
smp_found_config = 0; smp_found_config = 0;
printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n"); printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n");
#ifndef CONFIG_VISWS smpboot_clear_io_apic_irqs();
io_apic_irqs = 0;
#endif
phys_cpu_present_map = 1; phys_cpu_present_map = 1;
return; return;
} }
...@@ -1108,22 +1105,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus) ...@@ -1108,22 +1105,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
/* /*
* Cleanup possible dangling ends... * Cleanup possible dangling ends...
*/ */
#ifndef CONFIG_VISWS smpboot_setup_warm_reset_vector();
{
/*
* 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
/* /*
* Allow the user to impress friends. * Allow the user to impress friends.
...@@ -1176,14 +1158,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus) ...@@ -1176,14 +1158,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
} }
} }
#ifndef CONFIG_VISWS smpboot_setup_io_apic();
/*
* 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
setup_boot_APIC_clock(); setup_boot_APIC_clock();
...@@ -1222,3 +1197,29 @@ void __init smp_cpus_done(unsigned int max_cpus) ...@@ -1222,3 +1197,29 @@ void __init smp_cpus_done(unsigned int max_cpus)
{ {
zap_low_mappings(); 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
}
...@@ -57,8 +57,11 @@ ...@@ -57,8 +57,11 @@
#include <linux/timex.h> #include <linux/timex.h>
#include <linux/config.h> #include <linux/config.h>
#include <asm/fixmap.h> #include <asm/arch_hooks.h>
#include <asm/cobalt.h>
extern spinlock_t i8259A_lock;
#include "do_timer.h"
/* /*
* for x86_do_profile() * for x86_do_profile()
...@@ -120,8 +123,6 @@ static inline unsigned long do_fast_gettimeoffset(void) ...@@ -120,8 +123,6 @@ static inline unsigned long do_fast_gettimeoffset(void)
spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED; spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED;
EXPORT_SYMBOL(i8253_lock); EXPORT_SYMBOL(i8253_lock);
extern spinlock_t i8259A_lock;
#ifndef CONFIG_X86_TSC #ifndef CONFIG_X86_TSC
/* This function must be called with interrupts disabled /* This function must be called with interrupts disabled
...@@ -202,47 +203,11 @@ static unsigned long do_slow_gettimeoffset(void) ...@@ -202,47 +203,11 @@ static unsigned long do_slow_gettimeoffset(void)
* (see c't 95/10 page 335 for Neptun bug.) * (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( jiffies_t == jiffies_p ) {
if( count > count_p ) { if( count > count_p ) {
/* the nutcase */ /* the nutcase */
count = do_timer_overflow(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
}
} }
} else } else
jiffies_p = jiffies_t; jiffies_p = jiffies_t;
...@@ -412,23 +377,7 @@ static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *reg ...@@ -412,23 +377,7 @@ static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *reg
} }
#endif #endif
#ifdef CONFIG_VISWS do_timer_interrupt_hook(regs);
/* 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
/* /*
* If we have an externally synchronized Linux clock, then update * If we have an externally synchronized Linux clock, then update
...@@ -469,7 +418,7 @@ static int use_tsc; ...@@ -469,7 +418,7 @@ static int use_tsc;
* Time Stamp Counter value at the time of the timer interrupt, so that * Time Stamp Counter value at the time of the timer interrupt, so that
* we later on can estimate the time of day more exactly. * 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; int count;
...@@ -559,8 +508,6 @@ unsigned long get_cmos_time(void) ...@@ -559,8 +508,6 @@ unsigned long get_cmos_time(void)
return mktime(year, mon, day, hour, min, sec); return mktime(year, mon, day, hour, min, sec);
} }
static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};
/* ------ Calibrate the TSC ------- /* ------ Calibrate the TSC -------
* Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset(). * 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 * Too much 64-bit arithmetic here to do this cleanly in C, and for
...@@ -573,6 +520,7 @@ static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NUL ...@@ -573,6 +520,7 @@ static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NUL
#define CALIBRATE_LATCH (5 * LATCH) #define CALIBRATE_LATCH (5 * LATCH)
#define CALIBRATE_TIME (5 * 1000020/HZ) #define CALIBRATE_TIME (5 * 1000020/HZ)
#ifdef CONFIG_X86_TSC
static unsigned long __init calibrate_tsc(void) static unsigned long __init calibrate_tsc(void)
{ {
/* Set the Gate high, disable speaker */ /* Set the Gate high, disable speaker */
...@@ -637,6 +585,7 @@ static unsigned long __init calibrate_tsc(void) ...@@ -637,6 +585,7 @@ static unsigned long __init calibrate_tsc(void)
bad_ctc: bad_ctc:
return 0; return 0;
} }
#endif /* CONFIG_X86_TSC */
static struct device device_i8253 = { static struct device device_i8253 = {
.name = "i8253", .name = "i8253",
...@@ -652,7 +601,9 @@ __initcall(time_init_driverfs); ...@@ -652,7 +601,9 @@ __initcall(time_init_driverfs);
void __init time_init(void) void __init time_init(void)
{ {
#ifdef CONFIG_X86_TSC
extern int x86_udelay_tsc; extern int x86_udelay_tsc;
#endif
xtime.tv_sec = get_cmos_time(); xtime.tv_sec = get_cmos_time();
xtime.tv_usec = 0; xtime.tv_usec = 0;
...@@ -671,6 +622,7 @@ void __init time_init(void) ...@@ -671,6 +622,7 @@ void __init time_init(void)
* to disk; this won't break the kernel, though, 'cuz we're * to disk; this won't break the kernel, though, 'cuz we're
* smart. See arch/i386/kernel/apm.c. * smart. See arch/i386/kernel/apm.c.
*/ */
#ifdef CONFIG_X86_TSC
/* /*
* Firstly we have to do a CPU check for chips with * Firstly we have to do a CPU check for chips with
* a potentially buggy TSC. At this point we haven't run * a potentially buggy TSC. At this point we haven't run
...@@ -711,22 +663,7 @@ void __init time_init(void) ...@@ -711,22 +663,7 @@ void __init time_init(void)
} }
} }
} }
#endif /* CONFIG_X86_TSC */
#ifdef CONFIG_VISWS time_init_hook();
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
} }
...@@ -43,12 +43,7 @@ ...@@ -43,12 +43,7 @@
#include <asm/smp.h> #include <asm/smp.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/arch_hooks.h>
#ifdef CONFIG_X86_VISWS_APIC
#include <asm/fixmap.h>
#include <asm/cobalt.h>
#include <asm/lithium.h>
#endif
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -832,96 +827,6 @@ static void __init set_call_gate(void *a, void *addr) ...@@ -832,96 +827,6 @@ static void __init set_call_gate(void *a, void *addr)
_set_gate(a,12,3,addr); _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 #ifdef CONFIG_EISA
int EISA_bus; int EISA_bus;
...@@ -977,9 +882,5 @@ void __init trap_init(void) ...@@ -977,9 +882,5 @@ void __init trap_init(void)
*/ */
cpu_init(); cpu_init();
#ifdef CONFIG_X86_VISWS_APIC trap_init_hook();
superio_init();
lithium_init();
cobalt_init();
#endif
} }
#
# 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
/* 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;
}
/*
* 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
/*
* 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 */
/*
* Machine specific setup for generic
*/
#include <linux/config.h>
#include <linux/smp.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <asm/arch_hooks.h>
/**
* 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
/**
* 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;
}
/* Hook to call BIOS initialisation function */
/* no action for generic */
#define ARCH_SETUP
/* 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();
}
#
# 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
/* defines for inline arch setup functions */
#include <asm/fixmap.h>
#include <asm/cobalt.h>
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;
}
/*
* 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
#include <linux/mm.h>
#include <linux/irq.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/config.h>
#include <linux/bootmem.h>
#include <linux/smp_lock.h>
#include <linux/kernel_stat.h>
#include <linux/mc146818rtc.h>
#include <asm/smp.h>
#include <asm/mtrr.h>
#include <asm/mpspec.h>
#include <asm/pgalloc.h>
/* 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;
}
...@@ -3,7 +3,15 @@ ...@@ -3,7 +3,15 @@
* Split out from setup.c by davej@suse.de * Split out from setup.c by davej@suse.de
*/ */
#include <linux/smp.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <asm/fixmap.h>
#include <asm/cobalt.h>
#include <asm/arch_hooks.h>
#include <asm/io.h>
char visws_board_type = -1; char visws_board_type = -1;
char visws_board_rev = -1; char visws_board_rev = -1;
...@@ -124,5 +132,39 @@ void __init visws_get_board_type_and_rev(void) ...@@ -124,5 +132,39 @@ void __init visws_get_board_type_and_rev(void)
visws_board_type == VISWS_320 ? "320" : visws_board_type == VISWS_320 ? "320" :
(visws_board_type == VISWS_540 ? "540" : (visws_board_type == VISWS_540 ? "540" :
"unknown"), visws_board_rev); "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);
} }
/* 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;
}
/* Hook to call BIOS initialisation function */
/* no action for visws */
#define ARCH_SETUP
/* 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)
{
}
/* VISWS traps */
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/highmem.h>
#include <linux/init.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/atomic.h>
#include <asm/debugreg.h>
#include <asm/desc.h>
#include <asm/i387.h>
#include <asm/smp.h>
#include <asm/pgalloc.h>
#include <asm/arch_hooks.h>
#ifdef CONFIG_X86_VISWS_APIC
#include <asm/fixmap.h>
#include <asm/cobalt.h>
#include <asm/lithium.h>
#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
}
...@@ -2,10 +2,6 @@ O_TARGET := pci.o ...@@ -2,10 +2,6 @@ O_TARGET := pci.o
obj-y := i386.o obj-y := i386.o
ifdef CONFIG_VISWS
obj-y += visws.o
else
obj-$(CONFIG_PCI_BIOS) += pcbios.o obj-$(CONFIG_PCI_BIOS) += pcbios.o
obj-$(CONFIG_PCI_DIRECT) += direct.o obj-$(CONFIG_PCI_DIRECT) += direct.o
...@@ -22,6 +18,5 @@ obj-y += legacy.o ...@@ -22,6 +18,5 @@ obj-y += legacy.o
endif # CONFIG_MULTIQUAD endif # CONFIG_MULTIQUAD
obj-y += irq.o common.o obj-y += irq.o common.o
endif # CONFIG_VISWS
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
...@@ -146,7 +146,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec, ...@@ -146,7 +146,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec,
if (k_platform) { if (k_platform) {
size_t len = strlen(k_platform) + 1; size_t len = strlen(k_platform) + 1;
#if defined(__i386__) && defined(CONFIG_SMP) #ifdef CONFIG_X86_HT
/* /*
* In some cases (e.g. Hyper-Threading), we want to avoid L1 * In some cases (e.g. Hyper-Threading), we want to avoid L1
* evictions by the processes running on the same package. One * evictions by the processes running on the same package. One
......
#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
...@@ -12,7 +12,8 @@ ...@@ -12,7 +12,8 @@
#include <linux/config.h> #include <linux/config.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <asm/irq_vectors.h> /* include comes from machine specific directory */
#include "irq_vectors.h"
static __inline__ int irq_cannonicalize(int irq) static __inline__ int irq_cannonicalize(int irq)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment