Commit 5fdfb610 authored by James Bottomley's avatar James Bottomley

Merge by Hand

parents ef078caa 85429999
......@@ -86,13 +86,25 @@ ifdef CONFIG_MCYRIXIII
CFLAGS += -march=i586
endif
ifdef CONFIG_VISWS
MACHINE := visws
else
MACHINE := 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
DRIVERS += arch/i386/math-emu/math.o
......
......@@ -408,6 +408,18 @@ if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
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 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
#
# 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: generic.o
O_TARGET := generic.o
EXTRA_CFLAGS += -I../kernel
export-objs :=
obj-y := setup.o
obj-$(CONFIG_PCI) += pci-pc.o pci-irq.o
obj-$(CONFIG_X86_LOCAL_APIC) += mpparse.o
include $(TOPDIR)/Rules.make
/* defines for inline arch setup functions */
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
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;
}
/*
* 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
......@@ -70,7 +70,7 @@ unsigned long phys_cpu_present_map;
* Intel MP BIOS table parsing routines:
*/
#ifndef CONFIG_X86_VISWS_APIC
/*
* Checksum an MP configuration block.
*/
......@@ -760,7 +760,7 @@ static int __init smp_scan_config (unsigned long base, unsigned long length)
return 0;
}
void __init find_intel_smp (void)
void __init find_smp_config (void)
{
unsigned int address;
......@@ -800,37 +800,3 @@ 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");
}
#else
/*
* The Visual Workstation is Intel MP compliant in the hardware
* sense, but it doesnt 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
}
/*
* 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>
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};
void __init intr_init_hook(void)
{
#ifdef CONFIG_X86_LOCAL_APIC
apic_intr_init();
#endif
setup_irq(2, &irq2);
}
void __init pre_setup_arch_hook(void)
{
}
void __init trap_init_hook(void)
{
}
static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};
void __init time_init_hook(void)
{
setup_irq(0, &irq0);
}
#ifdef CONFIG_MCA
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
#ifndef SETUP_POST
#define ARCH_SETUP
#else
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;
}
#endif
......@@ -21,21 +21,16 @@ obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
i386_ksyms.o i387.o bluesmoke.o dmi_scan.o \
bootflag.o
obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o
obj-$(CONFIG_MCA) += mca.o
obj-$(CONFIG_MTRR) += mtrr.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_LOCAL_APIC) += apic.o nmi.o
obj-$(CONFIG_X86_IO_APIC) += io_apic.o
ifdef CONFIG_VISWS
obj-y += setup-visws.o
obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o
endif
kernel-subdir-$(CONFIG_PCI) += pci
subdir-y := $(kernel-subdir-y)
......
......@@ -29,6 +29,21 @@
#include <asm/mtrr.h>
#include <asm/mpspec.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? */
int using_apic_timer = 0;
......
......@@ -47,7 +47,7 @@
#include <asm/errno.h>
#include <asm/segment.h>
#include <asm/smp.h>
#include <asm/irq_vectors.h>
#include "irq_vectors.h"
EBX = 0x00
ECX = 0x04
......@@ -373,29 +373,8 @@ ENTRY(name) \
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)
#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
......
......@@ -21,6 +21,7 @@
#include <asm/delay.h>
#include <asm/desc.h>
#include <asm/apic.h>
#include <asm/arch_hooks.h>
#include <linux/irq.h>
......@@ -307,15 +308,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 };
/*
* 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;
......@@ -348,11 +340,8 @@ void __init init_IRQ(void)
{
int i;
#ifndef CONFIG_X86_VISWS_APIC
init_ISA_irqs();
#else
init_VISWS_APIC_irqs();
#endif
pre_intr_init_hook();
/*
* Cover the whole vector space, no vector can escape
* us. (some of these will be overridden and become
......@@ -364,39 +353,6 @@ void __init init_IRQ(void)
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, smp_thermal_interrupt);
#endif
#endif
/*
* Set the clock to HZ Hz, we already have a valid
......@@ -406,10 +362,6 @@ void __init init_IRQ(void)
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
* original braindamaged IBM FERR coupling.
......
......@@ -52,6 +52,7 @@
#include <linux/ioport.h>
#include <asm/uaccess.h>
#include <linux/init.h>
#include <asm/arch_hooks.h>
/* This structure holds MCA information. Each (plug-in) adapter has
* eight POS registers. Then the machine may have integrated video and
......@@ -371,12 +372,7 @@ void mca_handle_nmi(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");
mca_nmi_hook();
} /* mca_handle_nmi */
/*--------------------------------------------------------------------*/
......
......@@ -67,11 +67,6 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
*/
void (*pm_idle)(void);
/*
* Power off function, if any
*/
void (*pm_power_off)(void);
void disable_hlt(void)
{
hlt_counter++;
......@@ -161,287 +156,6 @@ static int __init idle_setup (char *str)
__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;
cli();
/* 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);
/* Make sure the first page is mapped to the start of physical memory.
It is normally not mapped, to trap kernel NULL pointer dereferences. */
pg0[0] = _PAGE_RW | _PAGE_PRESENT;
/*
* Use `swapper_pg_dir' as our page directory.
*/
asm volatile("movl %0,%%cr3": :"r" (__pa(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);
void show_regs(struct pt_regs * regs)
......
This diff is collapsed.
......@@ -116,6 +116,10 @@
#include <asm/dma.h>
#include <asm/mpspec.h>
#include <asm/mmu_context.h>
#include <asm/arch_hooks.h>
#include "setup_arch.h"
static inline char * __init machine_specific_memory_setup(void);
/*
* Machine setup..
......@@ -559,31 +563,8 @@ static int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
static void __init setup_memory_region(void)
{
char *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";
}
char *who = machine_specific_memory_setup();
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 */
......@@ -673,14 +654,14 @@ void __init setup_arch(char **cmdline_p)
unsigned long start_pfn, max_low_pfn;
int i;
#ifdef CONFIG_VISWS
visws_get_board_type_and_rev();
#endif
pre_setup_arch_hook();
ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
drive_info = DRIVE_INFO;
screen_info = SCREEN_INFO;
#ifdef CONFIG_APM
apm_info.bios = APM_BIOS_INFO;
#endif
if( SYS_DESC_TABLE.length != 0 ) {
MCA_bus = SYS_DESC_TABLE.table[3] &0x2;
machine_id = SYS_DESC_TABLE.table[0];
......@@ -694,6 +675,7 @@ void __init setup_arch(char **cmdline_p)
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)
......@@ -874,7 +856,7 @@ void __init setup_arch(char **cmdline_p)
*/
acpi_reserve_bootmem();
#endif
#ifdef CONFIG_X86_LOCAL_APIC
#ifdef CONFIG_X86_FIND_SMP_CONFIG
/*
* Find and reserve possible boot-time SMP configuration:
*/
......@@ -2152,12 +2134,12 @@ static void __init init_intel(struct cpuinfo_x86 *c)
if ( p )
strcpy(c->x86_model_id, p);
#ifdef CONFIG_SMP
/* PGE CPUID bug: Pentium4 supports PGE, but seems to have SMP bugs.. */
if ( c->x86 == 15 )
clear_bit(X86_FEATURE_PGE, c->x86_capability);
#ifdef CONFIG_X86_HT
if (test_bit(X86_FEATURE_HT, c->x86_capability)) {
extern int phys_proc_id[NR_CPUS];
......@@ -2943,6 +2925,9 @@ int __init ppro_with_ram_bug(void)
return 0;
}
#define SETUP_POST
#include "setup_arch.h"
/*
* Local Variables:
* mode:c
......
......@@ -49,6 +49,8 @@
#include <asm/pgalloc.h>
#include <asm/tlbflush.h>
#include <asm/smpboot.h>
#include <asm/desc.h>
#include <asm/arch_hooks.h>
/* Set if we find a B stepping CPU */
static int smp_b_stepping;
......@@ -1253,3 +1255,29 @@ void __init smp_boot_cpus(void)
smp_done:
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, smp_thermal_interrupt);
#endif
}
......@@ -56,8 +56,11 @@
#include <linux/timex.h>
#include <linux/config.h>
#include <asm/fixmap.h>
#include <asm/cobalt.h>
#include <asm/arch_hooks.h>
extern spinlock_t i8259A_lock;
#include "do_timer.h"
/*
* for x86_do_profile()
......@@ -118,8 +121,6 @@ static inline unsigned long do_fast_gettimeoffset(void)
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
......@@ -200,47 +201,11 @@ static unsigned long do_slow_gettimeoffset(void)
* (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;
......@@ -410,23 +375,7 @@ static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *reg
}
#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
......@@ -467,7 +416,7 @@ static int use_tsc;
* 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;
......@@ -557,8 +506,6 @@ unsigned long get_cmos_time(void)
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
......@@ -571,6 +518,7 @@ static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NUL
#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 */
......@@ -635,6 +583,7 @@ static unsigned long __init calibrate_tsc(void)
bad_ctc:
return 0;
}
#endif /* CONFIG_X86_TSC */
void __init time_init(void)
{
......@@ -657,6 +606,7 @@ void __init time_init(void)
* 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
......@@ -697,22 +647,7 @@ void __init time_init(void)
}
}
}
#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();
}
......@@ -44,12 +44,7 @@
#include <asm/smp.h>
#include <asm/pgalloc.h>
#ifdef CONFIG_X86_VISWS_APIC
#include <asm/fixmap.h>
#include <asm/cobalt.h>
#include <asm/lithium.h>
#endif
#include <asm/arch_hooks.h>
#include <linux/irq.h>
#include <linux/module.h>
......@@ -864,96 +859,6 @@ void set_ldt_desc(unsigned int n, void *addr, unsigned int size)
_set_tssldt_desc(gdt_table+__LDT(n), (int)addr, ((size << 3)-1), 0x82);
}
#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;
......@@ -1009,9 +914,5 @@ void __init trap_init(void)
*/
cpu_init();
#ifdef CONFIG_X86_VISWS_APIC
superio_init();
lithium_init();
cobalt_init();
#endif
trap_init_hook();
}
#
# 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: visws.o
O_TARGET := 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
#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 */
#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 doesnt 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,6 +3,16 @@
* Split out from setup.c by davej@suse.de
*/
#include <linux/smp.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_rev = -1;
......@@ -122,5 +132,39 @@ void __init visws_get_board_type_and_rev(void)
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);
}
#ifndef SETUP_POST
#define ARCH_SETUP
#else
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;
}
#endif
/* 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
}
......@@ -142,7 +142,7 @@ create_elf_tables(char *p, int argc, int envc,
} 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
......
#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 @@
#include <linux/config.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)
{
......
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