Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
038a96e2
Commit
038a96e2
authored
Sep 19, 2002
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
parents
d103aab6
993d4ad8
Changes
39
Hide whitespace changes
Inline
Side-by-side
Showing
39 changed files
with
1275 additions
and
667 deletions
+1275
-667
arch/i386/Makefile
arch/i386/Makefile
+10
-3
arch/i386/config.in
arch/i386/config.in
+13
-0
arch/i386/kernel/Makefile
arch/i386/kernel/Makefile
+4
-6
arch/i386/kernel/apic.c
arch/i386/kernel/apic.c
+15
-0
arch/i386/kernel/cpu/intel.c
arch/i386/kernel/cpu/intel.c
+1
-1
arch/i386/kernel/entry.S
arch/i386/kernel/entry.S
+3
-29
arch/i386/kernel/i8259.c
arch/i386/kernel/i8259.c
+7
-51
arch/i386/kernel/mca.c
arch/i386/kernel/mca.c
+2
-6
arch/i386/kernel/mpparse.c
arch/i386/kernel/mpparse.c
+2
-36
arch/i386/kernel/process.c
arch/i386/kernel/process.c
+0
-281
arch/i386/kernel/reboot.c
arch/i386/kernel/reboot.c
+324
-0
arch/i386/kernel/setup.c
arch/i386/kernel/setup.c
+10
-29
arch/i386/kernel/smpboot.c
arch/i386/kernel/smpboot.c
+35
-34
arch/i386/kernel/time.c
arch/i386/kernel/time.c
+15
-78
arch/i386/kernel/traps.c
arch/i386/kernel/traps.c
+2
-101
arch/i386/mach-generic/Makefile
arch/i386/mach-generic/Makefile
+21
-0
arch/i386/mach-generic/do_timer.h
arch/i386/mach-generic/do_timer.h
+81
-0
arch/i386/mach-generic/entry_arch.h
arch/i386/mach-generic/entry_arch.h
+34
-0
arch/i386/mach-generic/irq_vectors.h
arch/i386/mach-generic/irq_vectors.h
+85
-0
arch/i386/mach-generic/setup.c
arch/i386/mach-generic/setup.c
+104
-0
arch/i386/mach-generic/setup_arch_post.h
arch/i386/mach-generic/setup_arch_post.h
+40
-0
arch/i386/mach-generic/setup_arch_pre.h
arch/i386/mach-generic/setup_arch_pre.h
+5
-0
arch/i386/mach-generic/smpboot_hooks.h
arch/i386/mach-generic/smpboot_hooks.h
+33
-0
arch/i386/mach-visws/Makefile
arch/i386/mach-visws/Makefile
+25
-0
arch/i386/mach-visws/do_timer.h
arch/i386/mach-visws/do_timer.h
+50
-0
arch/i386/mach-visws/entry_arch.h
arch/i386/mach-visws/entry_arch.h
+23
-0
arch/i386/mach-visws/irq_vectors.h
arch/i386/mach-visws/irq_vectors.h
+0
-0
arch/i386/mach-visws/mpparse.c
arch/i386/mach-visws/mpparse.c
+67
-0
arch/i386/mach-visws/pci-visws.c
arch/i386/mach-visws/pci-visws.c
+0
-0
arch/i386/mach-visws/setup.c
arch/i386/mach-visws/setup.c
+47
-5
arch/i386/mach-visws/setup_arch_post.h
arch/i386/mach-visws/setup_arch_post.h
+37
-0
arch/i386/mach-visws/setup_arch_pre.h
arch/i386/mach-visws/setup_arch_pre.h
+5
-0
arch/i386/mach-visws/smpboot_hooks.h
arch/i386/mach-visws/smpboot_hooks.h
+13
-0
arch/i386/mach-visws/traps.c
arch/i386/mach-visws/traps.c
+134
-0
arch/i386/mach-visws/visws_apic.c
arch/i386/mach-visws/visws_apic.c
+0
-0
arch/i386/pci/Makefile
arch/i386/pci/Makefile
+0
-5
fs/binfmt_elf.c
fs/binfmt_elf.c
+1
-1
include/asm-i386/arch_hooks.h
include/asm-i386/arch_hooks.h
+25
-0
include/asm-i386/irq.h
include/asm-i386/irq.h
+2
-1
No files found.
arch/i386/Makefile
View file @
038a96e2
...
...
@@ -85,15 +85,22 @@ ifdef CONFIG_MCYRIXIII
CFLAGS
+=
-march
=
i586
endif
ifdef
CONFIG_VISWS
MACHINE
:=
mach-visws
else
MACHINE
:=
mach-generic
endif
HEAD
:=
arch
/i386/kernel/head.o
arch
/i386/kernel/init_task.o
libs-y
+=
arch
/i386/lib/
core-y
+=
arch
/i386/kernel/
arch
/i386/mm/
core-y
+=
arch
/i386/kernel/
arch
/i386/mm/
arch
/i386/
(
MACHINE
)
/
drivers-$(CONFIG_MATH_EMULATION)
+=
arch
/i386/math-emu/
drivers-$(CONFIG_PCI)
+=
arch
/i386/pci/
CFLAGS
+=
-I
$(TOPDIR)
/arch/i386/
$(MACHINE)
AFLAGS
+=
-I
$(TOPDIR)
/arch/i386/
$(MACHINE)
MAKEBOOT
=
+
$(MAKE)
-C
arch
/
$(ARCH)
/boot
.PHONY
:
zImage bzImage compressed zlilo bzlilo zdisk bzdisk install
\
...
...
arch/i386/config.in
View file @
038a96e2
...
...
@@ -260,6 +260,7 @@ else
if [ "$CONFIG_SMP" = "y" ]; then
define_bool CONFIG_X86_IO_APIC y
define_bool CONFIG_X86_LOCAL_APIC y
define_bool CONFIG_X86_MPPARSE y
fi
bool 'PCI support' CONFIG_PCI
if [ "$CONFIG_PCI" = "y" ]; then
...
...
@@ -437,7 +438,19 @@ 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 security/Config.in
source lib/Config.in
if [ "$CONFIG_SMP" = "y" ]; then
define_bool CONFIG_X86_SMP y
define_bool CONFIG_X86_HT y
fi
define_bool CONFIG_X86_BIOS_REBOOT y
arch/i386/kernel/Makefile
View file @
038a96e2
...
...
@@ -12,6 +12,7 @@ obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
bootflag.o
obj-y
+=
cpu/
obj-$(CONFIG_X86_BIOS_REBOOT)
+=
reboot.o
obj-$(CONFIG_MCA)
+=
mca.o
obj-$(CONFIG_X86_MSR)
+=
msr.o
obj-$(CONFIG_X86_CPUID)
+=
cpuid.o
...
...
@@ -19,15 +20,12 @@ obj-$(CONFIG_MICROCODE) += microcode.o
obj-$(CONFIG_APM)
+=
apm.o
obj-$(CONFIG_ACPI)
+=
acpi.o
obj-$(CONFIG_ACPI_SLEEP)
+=
acpi_wakeup.o
obj-$(CONFIG_SMP)
+=
smp.o smpboot.o trampoline.o
obj-$(CONFIG_X86_LOCAL_APIC)
+=
mpparse.o apic.o nmi.o
obj-$(CONFIG_X86_SMP)
+=
smp.o smpboot.o trampoline.o
obj-$(CONFIG_X86_MPPARSE)
+=
mpparse.o
obj-$(CONFIG_X86_LOCAL_APIC)
+=
apic.o nmi.o
obj-$(CONFIG_X86_IO_APIC)
+=
io_apic.o
obj-$(CONFIG_SOFTWARE_SUSPEND)
+=
suspend.o
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
...
...
arch/i386/kernel/apic.c
View file @
038a96e2
...
...
@@ -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
;
...
...
arch/i386/kernel/cpu/intel.c
View file @
038a96e2
...
...
@@ -257,7 +257,7 @@ static void __init init_intel(struct cpuinfo_x86 *c)
if
(
p
)
strcpy
(
c
->
x86_model_id
,
p
);
#ifdef CONFIG_
SMP
#ifdef CONFIG_
X86_HT
if
(
test_bit
(
X86_FEATURE_HT
,
c
->
x86_capability
)
&&
!
disable_P4_HT
)
{
extern
int
phys_proc_id
[
NR_CPUS
];
...
...
arch/i386/kernel/entry.S
View file @
038a96e2
...
...
@@ -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
...
...
@@ -344,34 +344,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
)
#ifdef CONFIG_X86_MCE_P4THERMAL
BUILD_INTERRUPT
(
thermal_interrupt
,
THERMAL_APIC_VECTOR
)
#endif
#endif
/*
The
include
is
where
all
of
the
SMP
etc
.
interrupts
come
from
*/
#include "entry_arch.h"
ENTRY
(
divide_error
)
pushl
$
0
#
no
error
code
...
...
arch/i386/kernel/i8259.c
View file @
038a96e2
...
...
@@ -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>
...
...
@@ -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
};
/*
* IRQ2 is cascade interrupt to second interrupt controller
*/
#ifndef CONFIG_VISWS
static
struct
irqaction
irq2
=
{
no_action
,
0
,
0
,
"cascade"
,
NULL
,
NULL
};
#endif
void
__init
init_ISA_irqs
(
void
)
{
int
i
;
...
...
@@ -373,11 +365,9 @@ void __init init_IRQ(void)
{
int
i
;
#ifndef CONFIG_X86_VISWS_APIC
init_ISA_irqs
();
#else
init_VISWS_APIC_irqs
();
#endif
/* all the set up before the call gates are initialised */
pre_intr_init_hook
();
/*
* Cover the whole vector space, no vector can escape
* us. (some of these will be overridden and become
...
...
@@ -389,39 +379,9 @@ 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
,
thermal_interrupt
);
#endif
#endif
/* setup after call gates are initialised (usually add in
* the architecture specific gates */
intr_init_hook
();
/*
* Set the clock to HZ Hz, we already have a valid
...
...
@@ -431,10 +391,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.
...
...
arch/i386/kernel/mca.c
View file @
038a96e2
...
...
@@ -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
...
...
@@ -379,12 +380,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 */
/*--------------------------------------------------------------------*/
...
...
arch/i386/kernel/mpparse.c
View file @
038a96e2
...
...
@@ -73,7 +73,7 @@ unsigned long phys_cpu_present_map;
* Intel MP BIOS table parsing routines:
*/
#ifndef CONFIG_X86_VISWS_APIC
/*
* Checksum an MP configuration block.
*/
...
...
@@ -737,7 +737,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
;
...
...
@@ -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
"
);
}
#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
...
...
arch/i386/kernel/process.c
View file @
038a96e2
...
...
@@ -66,11 +66,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
++
;
...
...
@@ -160,282 +155,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
;
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
"
"
\t
movl %%eax,%%ds
\n
"
"
\t
movl %%eax,%%es
\n
"
"
\t
movl %%eax,%%fs
\n
"
"
\t
movl %%eax,%%gs
\n
"
"
\t
movl %%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
)
...
...
arch/i386/kernel/reboot.c
0 → 100644
View file @
038a96e2
/*
* 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
"
"
\t
movl %%eax,%%ds
\n
"
"
\t
movl %%eax,%%es
\n
"
"
\t
movl %%eax,%%fs
\n
"
"
\t
movl %%eax,%%gs
\n
"
"
\t
movl %%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
();
}
arch/i386/kernel/setup.c
View file @
038a96e2
...
...
@@ -37,6 +37,10 @@
#include <asm/e820.h>
#include <asm/mpspec.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..
...
...
@@ -470,31 +474,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 */
...
...
@@ -757,7 +738,7 @@ static unsigned long __init setup_memory(void)
*/
acpi_reserve_bootmem
();
#endif
#ifdef CONFIG_X86_
LOCAL_APIC
#ifdef CONFIG_X86_
FIND_SMP_CONFIG
/*
* Find and reserve possible boot-time SMP configuration:
*/
...
...
@@ -838,12 +819,9 @@ void __init setup_arch(char **cmdline_p)
{
unsigned
long
max_low_pfn
;
pre_setup_arch_hook
();
early_cpu_init
();
#ifdef CONFIG_VISWS
visws_get_board_type_and_rev
();
#endif
ROOT_DEV
=
ORIG_ROOT_DEV
;
drive_info
=
DRIVE_INFO
;
screen_info
=
SCREEN_INFO
;
...
...
@@ -863,6 +841,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
)
...
...
@@ -922,6 +901,8 @@ static int __init highio_setup(char *str)
}
__setup
(
"nohighio"
,
highio_setup
);
#include "setup_arch_post.h"
/*
* Local Variables:
* mode:c
...
...
arch/i386/kernel/smpboot.c
View file @
038a96e2
...
...
@@ -48,6 +48,9 @@
#include <asm/pgalloc.h>
#include <asm/tlbflush.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 */
static
int
__initdata
smp_b_stepping
;
...
...
@@ -1003,9 +1006,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
*/
if
(
!
smp_found_config
)
{
printk
(
KERN_NOTICE
"SMP motherboard not detected.
\n
"
);
#ifndef CONFIG_VISWS
io_apic_irqs
=
0
;
#endif
smpboot_clear_io_apic_irqs
();
phys_cpu_present_map
=
1
;
if
(
APIC_init_uniprocessor
())
printk
(
KERN_NOTICE
"Local APIC not detected."
...
...
@@ -1032,9 +1033,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
printk
(
KERN_ERR
"BIOS bug, local APIC #%d not detected!...
\n
"
,
boot_cpu_physical_apicid
);
printk
(
KERN_ERR
"... forcing use of dummy APIC emulation. (tell your hw vendor)
\n
"
);
#ifndef CONFIG_VISWS
io_apic_irqs
=
0
;
#endif
smpboot_clear_io_apic_irqs
();
phys_cpu_present_map
=
1
;
return
;
}
...
...
@@ -1047,9 +1046,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
if
(
!
max_cpus
)
{
smp_found_config
=
0
;
printk
(
KERN_INFO
"SMP mode deactivated, forcing use of dummy APIC emulation.
\n
"
);
#ifndef CONFIG_VISWS
io_apic_irqs
=
0
;
#endif
smpboot_clear_io_apic_irqs
();
phys_cpu_present_map
=
1
;
return
;
}
...
...
@@ -1106,22 +1103,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
/*
* Cleanup possible dangling ends...
*/
#ifndef CONFIG_VISWS
{
/*
* Install writable page 0 entry to set BIOS data area.
*/
local_flush_tlb
();
/*
* Paranoid: Set warm reset code and vector here back
* to default values.
*/
CMOS_WRITE
(
0
,
0xf
);
*
((
volatile
long
*
)
phys_to_virt
(
0x467
))
=
0
;
}
#endif
smpboot_setup_warm_reset_vector
();
/*
* Allow the user to impress friends.
...
...
@@ -1173,15 +1155,8 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
}
}
}
#ifndef CONFIG_VISWS
/*
* Here we can be sure that there is an IO-APIC in the system. Let's
* go and set it up:
*/
if
(
!
skip_ioapic_setup
&&
nr_ioapics
)
setup_IO_APIC
();
#endif
smpboot_setup_io_apic
();
setup_boot_APIC_clock
();
...
...
@@ -1220,3 +1195,29 @@ void __init smp_cpus_done(unsigned int max_cpus)
{
zap_low_mappings
();
}
void
__init
smp_intr_init
()
{
/*
* IRQ0 must be given a fixed assignment and initialized,
* because it's used before the IO-APIC is set up.
*/
set_intr_gate
(
FIRST_DEVICE_VECTOR
,
interrupt
[
0
]);
/*
* The reschedule interrupt is a CPU-to-CPU reschedule-helper
* IPI, driven by wakeup.
*/
set_intr_gate
(
RESCHEDULE_VECTOR
,
reschedule_interrupt
);
/* IPI for invalidation */
set_intr_gate
(
INVALIDATE_TLB_VECTOR
,
invalidate_interrupt
);
/* IPI for generic function call */
set_intr_gate
(
CALL_FUNCTION_VECTOR
,
call_function_interrupt
);
/* thermal monitor LVT interrupt */
#ifdef CONFIG_X86_MCE_P4THERMAL
set_intr_gate
(
THERMAL_APIC_VECTOR
,
thermal_interrupt
);
#endif
}
arch/i386/kernel/time.c
View file @
038a96e2
...
...
@@ -57,8 +57,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()
...
...
@@ -120,8 +123,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
...
...
@@ -202,47 +203,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
;
...
...
@@ -413,23 +378,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
...
...
@@ -470,7 +419,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
;
...
...
@@ -560,8 +509,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
...
...
@@ -574,6 +521,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 */
...
...
@@ -638,6 +586,7 @@ static unsigned long __init calibrate_tsc(void)
bad_ctc:
return
0
;
}
#endif
/* CONFIG_X86_TSC */
static
struct
device
device_i8253
=
{
.
name
=
"i8253"
,
...
...
@@ -653,7 +602,9 @@ __initcall(time_init_driverfs);
void
__init
time_init
(
void
)
{
#ifdef CONFIG_X86_TSC
extern
int
x86_udelay_tsc
;
#endif
xtime
.
tv_sec
=
get_cmos_time
();
xtime
.
tv_nsec
=
0
;
...
...
@@ -672,6 +623,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
...
...
@@ -712,22 +664,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
();
}
arch/i386/kernel/traps.c
View file @
038a96e2
...
...
@@ -43,12 +43,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>
...
...
@@ -840,96 +835,6 @@ static void __init set_call_gate(void *a, void *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
int
EISA_bus
;
...
...
@@ -985,9 +890,5 @@ void __init trap_init(void)
*/
cpu_init
();
#ifdef CONFIG_X86_VISWS_APIC
superio_init
();
lithium_init
();
cobalt_init
();
#endif
trap_init_hook
();
}
arch/i386/mach-generic/Makefile
0 → 100644
View file @
038a96e2
#
# 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
arch/i386/mach-generic/do_timer.h
0 → 100644
View file @
038a96e2
/* 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
;
}
arch/i386/mach-generic/entry_arch.h
0 → 100644
View file @
038a96e2
/*
* 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
arch/i386/mach-generic/irq_vectors.h
0 → 100644
View file @
038a96e2
/*
* 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 */
arch/i386/mach-generic/setup.c
0 → 100644
View file @
038a96e2
/*
* 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
arch/i386/mach-generic/setup_arch_post.h
0 → 100644
View file @
038a96e2
/**
* 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
;
}
arch/i386/mach-generic/setup_arch_pre.h
0 → 100644
View file @
038a96e2
/* Hook to call BIOS initialisation function */
/* no action for generic */
#define ARCH_SETUP
arch/i386/mach-generic/smpboot_hooks.h
0 → 100644
View file @
038a96e2
/* 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
();
}
arch/i386/mach-visws/Makefile
0 → 100644
View file @
038a96e2
#
# 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
arch/i386/mach-visws/do_timer.h
0 → 100644
View file @
038a96e2
/* 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
;
}
arch/i386/mach-visws/entry_arch.h
0 → 100644
View file @
038a96e2
/*
* 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/asm-i386
/irq_vectors.h
→
arch/i386/mach-visws
/irq_vectors.h
View file @
038a96e2
File moved
arch/i386/mach-visws/mpparse.c
0 → 100644
View file @
038a96e2
#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
;
}
arch/i386/
pci/
visws.c
→
arch/i386/
mach-visws/pci-
visws.c
View file @
038a96e2
File moved
arch/i386/
kernel/setup-visws
.c
→
arch/i386/
mach-visws/setup
.c
View file @
038a96e2
...
...
@@ -3,7 +3,15 @@
* 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
;
...
...
@@ -120,9 +128,43 @@ void __init visws_get_board_type_and_rev(void)
visws_board_rev
=
raw
;
}
printk
(
KERN_INFO
"Silicon Graphics %s (rev %d)
\n
"
,
visws_board_type
==
VISWS_320
?
"320"
:
(
visws_board_type
==
VISWS_540
?
"540"
:
"unknown"
),
visws_board_rev
);
}
printk
(
KERN_INFO
"Silicon Graphics %s (rev %d)
\n
"
,
visws_board_type
==
VISWS_320
?
"320"
:
(
visws_board_type
==
VISWS_540
?
"540"
:
"unknown"
),
visws_board_rev
);
}
void
__init
pre_intr_init_hook
(
void
)
{
init_VISWS_APIC_irqs
();
}
void
__init
intr_init_hook
(
void
)
{
#ifdef CONFIG_X86_LOCAL_APIC
apic_intr_init
();
#endif
}
void
__init
pre_setup_arch_hook
()
{
visws_get_board_type_and_rev
();
}
static
struct
irqaction
irq0
=
{
timer_interrupt
,
SA_INTERRUPT
,
0
,
"timer"
,
NULL
,
NULL
};
void
__init
time_init_hook
(
void
)
{
printk
(
"Starting Cobalt Timer system clock
\n
"
);
/* Set the countdown value */
co_cpu_write
(
CO_CPU_TIMEVAL
,
CO_TIME_HZ
/
HZ
);
/* Start the timer */
co_cpu_write
(
CO_CPU_CTRL
,
co_cpu_read
(
CO_CPU_CTRL
)
|
CO_CTRL_TIMERUN
);
/* Enable (unmask) the timer interrupt */
co_cpu_write
(
CO_CPU_CTRL
,
co_cpu_read
(
CO_CPU_CTRL
)
&
~
CO_CTRL_TIMEMASK
);
/* Wire cpu IDT entry to s/w handler (and Cobalt APIC to IDT) */
setup_irq
(
CO_IRQ_TIMER
,
&
irq0
);
}
arch/i386/mach-visws/setup_arch_post.h
0 → 100644
View file @
038a96e2
/* 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
;
}
arch/i386/mach-visws/setup_arch_pre.h
0 → 100644
View file @
038a96e2
/* Hook to call BIOS initialisation function */
/* no action for visws */
#define ARCH_SETUP
arch/i386/mach-visws/smpboot_hooks.h
0 → 100644
View file @
038a96e2
/* 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
)
{
}
arch/i386/mach-visws/traps.c
0 → 100644
View file @
038a96e2
/* 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
}
arch/i386/
kernel
/visws_apic.c
→
arch/i386/
mach-visws
/visws_apic.c
View file @
038a96e2
File moved
arch/i386/pci/Makefile
View file @
038a96e2
obj-y
:=
i386.o
ifdef
CONFIG_VISWS
obj-y
+=
visws.o
else
obj-$(CONFIG_PCI_BIOS)
+=
pcbios.o
obj-$(CONFIG_PCI_DIRECT)
+=
direct.o
...
...
@@ -20,6 +16,5 @@ obj-y += legacy.o
endif
# CONFIG_MULTIQUAD
obj-y
+=
irq.o common.o
endif
# CONFIG_VISWS
include
$(TOPDIR)/Rules.make
fs/binfmt_elf.c
View file @
038a96e2
...
...
@@ -146,7 +146,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec,
if
(
k_platform
)
{
size_t
len
=
strlen
(
k_platform
)
+
1
;
#if
defined(__i386__) && defined(CONFIG_SMP)
#if
def 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
...
...
include/asm-i386/arch_hooks.h
0 → 100644
View file @
038a96e2
#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
include/asm-i386/irq.h
View file @
038a96e2
...
...
@@ -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
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment