Start of merge from work on the AMD760MP platform.
This is the safe part just additions to files, and comment changes
This commit is contained in:
parent
ad44ad6bc8
commit
228148aa23
63 changed files with 6591 additions and 3 deletions
30
src/arch/i386/include/arch/asm.h
Normal file
30
src/arch/i386/include/arch/asm.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef ASM_H
|
||||
#define ASM_H
|
||||
|
||||
#define ASSEMBLER
|
||||
|
||||
/*
|
||||
* Bootstrap code for the STPC Consumer
|
||||
* Copyright (c) 1999 by Net Insight AB. All Rights Reserved.
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#define I386_ALIGN_TEXT 0
|
||||
#define I386_ALIGN_DATA 0
|
||||
|
||||
/*
|
||||
* XXX
|
||||
*/
|
||||
#ifdef __ELF__
|
||||
#define EXT(x) x
|
||||
#else
|
||||
#define EXT(x) _ ## x
|
||||
#endif
|
||||
|
||||
#define STATIC(x) .align I386_ALIGN_TEXT; EXT(x):
|
||||
#define GLOBAL(x) .globl EXT(x); STATIC(x)
|
||||
#define ENTRY(x) .text; GLOBAL(x)
|
||||
|
||||
#endif /* ASM_H */
|
||||
7
src/arch/i386/include/arch/i386_subr.h
Normal file
7
src/arch/i386/include/arch/i386_subr.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef I386_SUBR_H
|
||||
#define I386_SUBR_H
|
||||
|
||||
void cache_on(unsigned long totalram);
|
||||
void interrupts_on(void);
|
||||
|
||||
#endif /* I386_SUBR_H */
|
||||
369
src/arch/i386/include/arch/intel.h
Normal file
369
src/arch/i386/include/arch/intel.h
Normal file
|
|
@ -0,0 +1,369 @@
|
|||
/*
|
||||
This software and ancillary information (herein called SOFTWARE )
|
||||
called LinuxBIOS is made available under the terms described
|
||||
here. The SOFTWARE has been approved for release with associated
|
||||
LA-CC Number 00-34 . Unless otherwise indicated, this SOFTWARE has
|
||||
been authored by an employee or employees of the University of
|
||||
California, operator of the Los Alamos National Laboratory under
|
||||
Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The
|
||||
U.S. Government has rights to use, reproduce, and distribute this
|
||||
SOFTWARE. The public may copy, distribute, prepare derivative works
|
||||
and publicly display this SOFTWARE without charge, provided that this
|
||||
Notice and any statement of authorship are reproduced on all copies.
|
||||
Neither the Government nor the University makes any warranty, express
|
||||
or implied, or assumes any liability or responsibility for the use of
|
||||
this SOFTWARE. If SOFTWARE is modified to produce derivative works,
|
||||
such modified SOFTWARE should be clearly marked, so as not to confuse
|
||||
it with the version available from LANL.
|
||||
*/
|
||||
/* Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL
|
||||
* rminnich@lanl.gov
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ROM_INTEL_H
|
||||
#define ROM_INTEL_H
|
||||
|
||||
/*
|
||||
* Bootstrap code for the Intel
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Config registers.
|
||||
*/
|
||||
/* yeah, yeah, I know these are macros, which is bad. Don't forget:
|
||||
* we have almost no assembly, so I am not worrying just yet about this.
|
||||
* we'll fix it someday if we care. My guess is we won't.
|
||||
*/
|
||||
|
||||
/* well we want functions. But first we want to see it work at all. */
|
||||
#undef FUNCTIONS
|
||||
#ifndef FUNCTIONS
|
||||
|
||||
|
||||
#define RET_LABEL(label) \
|
||||
jmp label##_done
|
||||
|
||||
#define CALL_LABEL(label) \
|
||||
jmp label ;\
|
||||
label##_done:
|
||||
|
||||
#define CALLSP(func) \
|
||||
lea 0f, %esp ; \
|
||||
jmp func ; \
|
||||
0:
|
||||
|
||||
#define RETSP \
|
||||
jmp *%esp
|
||||
|
||||
|
||||
#define DELAY(x) mov x, %ecx ;\
|
||||
1: loop 1b ;\
|
||||
|
||||
|
||||
/*
|
||||
* Macro: PCI_WRITE_CONFIG_BYTE
|
||||
* Arguments: %eax address to write to (includes bus, device, function, &offset)
|
||||
* %dl byte to write
|
||||
*
|
||||
* Results: none
|
||||
*
|
||||
* Trashed: %eax, %edx
|
||||
* Effects: writes a single byte to pci config space
|
||||
*
|
||||
* Notes: This routine is optimized for minimal register usage.
|
||||
* And the tricks it does cannot scale beyond writing a single byte.
|
||||
*
|
||||
* What it does is almost simple.
|
||||
* It preserves %eax (baring special bits) until it is written
|
||||
* out to the appropriate port. And hides the data byte
|
||||
* in the high half of edx.
|
||||
*
|
||||
* In %edx[3] it stores the byte to write.
|
||||
* In %edx[2] it stores the lower three bits of the address.
|
||||
*/
|
||||
|
||||
|
||||
#define PCI_WRITE_CONFIG_BYTE \
|
||||
shll $8, %edx ; \
|
||||
movb %al, %dl ; \
|
||||
andb $0x3, %dl ; \
|
||||
shll $16, %edx ; \
|
||||
\
|
||||
orl $0x80000000, %eax ; \
|
||||
andl $0xfffffffc, %eax ; \
|
||||
movw $0xcf8, %dx ; \
|
||||
outl %eax, %dx ; \
|
||||
\
|
||||
shrl $16, %edx ; \
|
||||
movb %dh, %al ; \
|
||||
movb $0, %dh ; \
|
||||
addl $0xcfc, %edx ; \
|
||||
outb %al, %dx
|
||||
|
||||
|
||||
/*
|
||||
* Macro: PCI_WRITE_CONFIG_WORD
|
||||
* Arguments: %eax address to write to (includes bus, device, function, &offset)
|
||||
* %ecx word to write
|
||||
*
|
||||
* Results: none
|
||||
*
|
||||
* Trashed: %eax, %edx
|
||||
* Preserved: %ecx
|
||||
* Effects: writes a single byte to pci config space
|
||||
*
|
||||
* Notes: This routine is optimized for minimal register usage.
|
||||
*
|
||||
* What it does is almost simple.
|
||||
* It preserves %eax (baring special bits) until it is written
|
||||
* out to the appropriate port. And hides the least significant
|
||||
* bits of the address in the high half of edx.
|
||||
*
|
||||
* In %edx[2] it stores the lower three bits of the address.
|
||||
*/
|
||||
|
||||
|
||||
#define PCI_WRITE_CONFIG_WORD \
|
||||
movb %al, %dl ; \
|
||||
andl $0x3, %edx ; \
|
||||
shll $16, %edx ; \
|
||||
\
|
||||
orl $0x80000000, %eax ; \
|
||||
andl $0xfffffffc, %eax ; \
|
||||
movw $0xcf8, %dx ; \
|
||||
outl %eax, %dx ; \
|
||||
\
|
||||
shrl $16, %edx ; \
|
||||
movl %ecx, %eax ; \
|
||||
addl $0xcfc, %edx ; \
|
||||
outw %ax, %dx
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Macro: PCI_WRITE_CONFIG_DWORD
|
||||
* Arguments: %eax address to write to (includes bus, device, function, &offset)
|
||||
* %ecx dword to write
|
||||
*
|
||||
* Results: none
|
||||
*
|
||||
* Trashed: %eax, %edx
|
||||
* Preserved: %ecx
|
||||
* Effects: writes a single byte to pci config space
|
||||
*
|
||||
* Notes: This routine is optimized for minimal register usage.
|
||||
*
|
||||
* What it does is almost simple.
|
||||
* It preserves %eax (baring special bits) until it is written
|
||||
* out to the appropriate port. And hides the least significant
|
||||
* bits of the address in the high half of edx.
|
||||
*
|
||||
* In %edx[2] it stores the lower three bits of the address.
|
||||
*/
|
||||
|
||||
|
||||
#define PCI_WRITE_CONFIG_DWORD \
|
||||
movb %al, %dl ; \
|
||||
andl $0x3, %edx ; \
|
||||
shll $16, %edx ; \
|
||||
\
|
||||
orl $0x80000000, %eax ; \
|
||||
andl $0xfffffffc, %eax ; \
|
||||
movw $0xcf8, %dx ; \
|
||||
outl %eax, %dx ; \
|
||||
\
|
||||
shrl $16, %edx ; \
|
||||
movl %ecx, %eax ; \
|
||||
addl $0xcfc, %edx ; \
|
||||
outl %eax, %dx
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Macro: PCI_READ_CONFIG_BYTE
|
||||
* Arguments: %eax address to read from (includes bus, device, function, &offset)
|
||||
*
|
||||
* Results: %al Byte read
|
||||
*
|
||||
* Trashed: %eax, %edx
|
||||
* Effects: reads a single byte from pci config space
|
||||
*
|
||||
* Notes: This routine is optimized for minimal register usage.
|
||||
*
|
||||
* What it does is almost simple.
|
||||
* It preserves %eax (baring special bits) until it is written
|
||||
* out to the appropriate port. And hides the least significant
|
||||
* bits of the address in the high half of edx.
|
||||
*
|
||||
* In %edx[2] it stores the lower three bits of the address.
|
||||
*/
|
||||
|
||||
|
||||
#define PCI_READ_CONFIG_BYTE \
|
||||
movb %al, %dl ; \
|
||||
andl $0x3, %edx ; \
|
||||
shll $16, %edx ; \
|
||||
\
|
||||
orl $0x80000000, %eax ; \
|
||||
andl $0xfffffffc, %eax ; \
|
||||
movw $0xcf8, %dx ; \
|
||||
outl %eax, %dx ; \
|
||||
\
|
||||
shrl $16, %edx ; \
|
||||
addl $0xcfc, %edx ; \
|
||||
inb %dx, %al
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Macro: PCI_READ_CONFIG_WORD
|
||||
* Arguments: %eax address to read from (includes bus, device, function, &offset)
|
||||
*
|
||||
* Results: %ax word read
|
||||
*
|
||||
* Trashed: %eax, %edx
|
||||
* Effects: reads a 2 bytes from pci config space
|
||||
*
|
||||
* Notes: This routine is optimized for minimal register usage.
|
||||
*
|
||||
* What it does is almost simple.
|
||||
* It preserves %eax (baring special bits) until it is written
|
||||
* out to the appropriate port. And hides the least significant
|
||||
* bits of the address in the high half of edx.
|
||||
*
|
||||
* In %edx[2] it stores the lower three bits of the address.
|
||||
*/
|
||||
|
||||
|
||||
#define PCI_READ_CONFIG_WORD \
|
||||
movb %al, %dl ; \
|
||||
andl $0x3, %edx ; \
|
||||
shll $16, %edx ; \
|
||||
\
|
||||
orl $0x80000000, %eax ; \
|
||||
andl $0xfffffffc, %eax ; \
|
||||
movw $0xcf8, %dx ; \
|
||||
outl %eax, %dx ; \
|
||||
\
|
||||
shrl $16, %edx ; \
|
||||
addl $0xcfc, %edx ; \
|
||||
inw %dx, %ax
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Macro: PCI_READ_CONFIG_DWORD
|
||||
* Arguments: %eax address to read from (includes bus, device, function, &offset)
|
||||
*
|
||||
* Results: %eax
|
||||
*
|
||||
* Trashed: %edx
|
||||
* Effects: reads 4 bytes from pci config space
|
||||
*
|
||||
* Notes: This routine is optimized for minimal register usage.
|
||||
*
|
||||
* What it does is almost simple.
|
||||
* It preserves %eax (baring special bits) until it is written
|
||||
* out to the appropriate port. And hides the least significant
|
||||
* bits of the address in the high half of edx.
|
||||
*
|
||||
* In %edx[2] it stores the lower three bits of the address.
|
||||
*/
|
||||
|
||||
|
||||
#define PCI_READ_CONFIG_DWORD \
|
||||
movb %al, %dl ; \
|
||||
andl $0x3, %edx ; \
|
||||
shll $16, %edx ; \
|
||||
\
|
||||
orl $0x80000000, %eax ; \
|
||||
andl $0xfffffffc, %eax ; \
|
||||
movw $0xcf8, %dx ; \
|
||||
outl %eax, %dx ; \
|
||||
\
|
||||
shrl $16, %edx ; \
|
||||
addl $0xcfc, %edx ; \
|
||||
inl %dx, %eax
|
||||
|
||||
|
||||
|
||||
|
||||
#define CS_READ(which) \
|
||||
mov $0x80000000,%eax ; \
|
||||
mov which,%ax ; \
|
||||
and $0xfc,%al /* clear bits 1-0 */ ; \
|
||||
mov $0xcf8,%dx /* port 0xcf8 ?*/ ; \
|
||||
outl %eax,%dx /* open up CS config */ ; \
|
||||
add $0x4,%dl /* 0xcfc data port 0 */ ; \
|
||||
mov which,%al ; \
|
||||
and $0x3,%al /* only bits 1-0 */ ; \
|
||||
add %al,%dl ; \
|
||||
inb %dx,%al /* read */ ; \
|
||||
|
||||
|
||||
#define CS_WRITE(which, data) \
|
||||
mov $0x80000000,%eax /* 32bit word with bit 31 set */ ; \
|
||||
mov which,%ax /* put the reg# in the low part */ ; \
|
||||
and $0xfc,%al /* dword align the reg# */ ; \
|
||||
mov $0xcf8,%dx /* enable port */ ; \
|
||||
outl %eax,%dx ; \
|
||||
add $0x4,%dl /* 1st data port */ ; \
|
||||
mov which,%ax /* register# */ ; \
|
||||
and $0x3,%ax ; \
|
||||
add %al,%dl ; \
|
||||
mov data, %al ; \
|
||||
outb %al,%dx /* write to reg */
|
||||
|
||||
#define REGBIS(which, bis) \
|
||||
CS_READ(which) ;\
|
||||
movb bis, %cl ;\
|
||||
orb %al, %cl ;\
|
||||
CS_WRITE(which, %cl)
|
||||
|
||||
#define REGBIC(which, bic) \
|
||||
CS_READ(which) ;\
|
||||
movb bic, %cl ;\
|
||||
notb %cl ;\
|
||||
andb %al, %cl ;\
|
||||
CS_WRITE(which, %cl)
|
||||
|
||||
|
||||
/* macro to BIC and BIS a reg. calls read a reg,
|
||||
* does a BIC and then a BIS on it.
|
||||
* to clear no bits, make BIC 0.
|
||||
* to set no bits, make BIS 0
|
||||
*/
|
||||
#define REGBICBIS(which, bic, bis) \
|
||||
CS_READ(which) ;\
|
||||
movb bic, %cl ;\
|
||||
notb %cl ;\
|
||||
andb %cl, %al ;\
|
||||
movb bis, %cl ;\
|
||||
orb %al, %cl ;\
|
||||
CS_WRITE(which, %cl)
|
||||
|
||||
#else
|
||||
NO FUNCTIONS YET!
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* originally this macro was from STPC BIOS */
|
||||
#define intel_chip_post_macro(value) \
|
||||
movb $value, %al ; \
|
||||
outb %al, $0x80
|
||||
|
||||
#define INTEL_PDATA_MAGIC 0xdeadbeef
|
||||
|
||||
/* SLOW_DOWN_IO is a delay we can use that is roughly cpu neutral,
|
||||
* and can be used before memory or timer chips come up.
|
||||
* Since this hits the isa bus it's roughly
|
||||
*/
|
||||
#define SLOW_DOWN_IO inb $0x80, %al
|
||||
|
||||
#endif /* ROM_INTEL_H */
|
||||
11
src/arch/i386/include/arch/ioapic.h
Normal file
11
src/arch/i386/include/arch/ioapic.h
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef ARCH_IOAPIC_H
|
||||
#define ARCH_IOAPIC_H
|
||||
|
||||
|
||||
#ifdef IOAPIC
|
||||
extern void setup_ioapic(void);
|
||||
#else
|
||||
#define setup_ioapic() do {} while(0)
|
||||
#endif
|
||||
|
||||
#endif /* ARCH_IOAPIC_H */
|
||||
21
src/arch/i386/include/arch/pirq_routing.h
Normal file
21
src/arch/i386/include/arch/pirq_routing.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef ARCH_PIRQ_ROUTING_H
|
||||
#define ARCH_PIRQ_ROUTING_H
|
||||
|
||||
#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
|
||||
#define PIRQ_VERSION 0x0100
|
||||
|
||||
extern const struct irq_routing_table intel_irq_routing_table;
|
||||
|
||||
#if !defined(DEBUG) && defined(HAVE_PIRQ_TABLE)
|
||||
void check_pirq_routing_table(void);
|
||||
#else
|
||||
#define check_pirq_routing_table() do {} while(0)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_PIRQ_ROUTING_TABLE)
|
||||
void copy_pirq_routing_table(void);
|
||||
#else
|
||||
#define copy_pirq_routing_table() do {} while(0)
|
||||
#endif
|
||||
|
||||
#endif /* ARCH_PIRQ_ROUTING_H */
|
||||
69
src/arch/i386/include/arch/smp/atomic.h
Normal file
69
src/arch/i386/include/arch/smp/atomic.h
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
#ifndef ARCH_SMP_ATOMIC_H
|
||||
#define ARCH_SMP_ATOMIC_H
|
||||
|
||||
/*
|
||||
* Make sure gcc doesn't try to be clever and move things around
|
||||
* on us. We need to use _exactly_ the address the user gave us,
|
||||
* not some alias that contains the same information.
|
||||
*/
|
||||
typedef struct { volatile int counter; } atomic_t;
|
||||
|
||||
#define ATOMIC_INIT(i) { (i) }
|
||||
|
||||
/*
|
||||
* Atomic operations that C can't guarantee us. Useful for
|
||||
* resource counting etc..
|
||||
*/
|
||||
|
||||
/**
|
||||
* atomic_read - read atomic variable
|
||||
* @v: pointer of type atomic_t
|
||||
*
|
||||
* Atomically reads the value of @v. Note that the guaranteed
|
||||
* useful range of an atomic_t is only 24 bits.
|
||||
*/
|
||||
#define atomic_read(v) ((v)->counter)
|
||||
|
||||
/**
|
||||
* atomic_set - set atomic variable
|
||||
* @v: pointer of type atomic_t
|
||||
* @i: required value
|
||||
*
|
||||
* Atomically sets the value of @v to @i. Note that the guaranteed
|
||||
* useful range of an atomic_t is only 24 bits.
|
||||
*/
|
||||
#define atomic_set(v,i) (((v)->counter) = (i))
|
||||
|
||||
/**
|
||||
* atomic_inc - increment atomic variable
|
||||
* @v: pointer of type atomic_t
|
||||
*
|
||||
* Atomically increments @v by 1. Note that the guaranteed
|
||||
* useful range of an atomic_t is only 24 bits.
|
||||
*/
|
||||
static __inline__ void atomic_inc(atomic_t *v)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
"lock ; incl %0"
|
||||
:"=m" (v->counter)
|
||||
:"m" (v->counter));
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic_dec - decrement atomic variable
|
||||
* @v: pointer of type atomic_t
|
||||
*
|
||||
* Atomically decrements @v by 1. Note that the guaranteed
|
||||
* useful range of an atomic_t is only 24 bits.
|
||||
*/
|
||||
static __inline__ void atomic_dec(atomic_t *v)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
"lock ; decl %0"
|
||||
:"=m" (v->counter)
|
||||
:"m" (v->counter));
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* ARCH_SMP_ATOMIC_H */
|
||||
275
src/arch/i386/include/arch/smp/mpspec.h
Normal file
275
src/arch/i386/include/arch/smp/mpspec.h
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
#ifndef __ASM_MPSPEC_H
|
||||
#define __ASM_MPSPEC_H
|
||||
|
||||
#ifdef HAVE_MP_TABLE
|
||||
|
||||
/*
|
||||
* Structure definitions for SMP machines following the
|
||||
* Intel Multiprocessing Specification 1.1 and 1.4.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This tag identifies where the SMP configuration
|
||||
* information is.
|
||||
*/
|
||||
|
||||
#define SMP_MAGIC_IDENT (('_'<<24)|('P'<<16)|('M'<<8)|'_')
|
||||
|
||||
/*
|
||||
* a maximum of 16 APICs with the current APIC ID architecture.
|
||||
*/
|
||||
#define MAX_APICS 16
|
||||
|
||||
|
||||
#define SMP_FLOATING_TABLE_LEN sizeof(struct intel_mp_floating)
|
||||
|
||||
struct intel_mp_floating
|
||||
{
|
||||
char mpf_signature[4]; /* "_MP_" */
|
||||
unsigned long mpf_physptr; /* Configuration table address */
|
||||
unsigned char mpf_length; /* Our length (paragraphs) */
|
||||
unsigned char mpf_specification;/* Specification version */
|
||||
unsigned char mpf_checksum; /* Checksum (makes sum 0) */
|
||||
unsigned char mpf_feature1; /* Standard or configuration ? */
|
||||
unsigned char mpf_feature2; /* Bit7 set for IMCR|PIC */
|
||||
unsigned char mpf_feature3; /* Unused (0) */
|
||||
unsigned char mpf_feature4; /* Unused (0) */
|
||||
unsigned char mpf_feature5; /* Unused (0) */
|
||||
};
|
||||
|
||||
struct mp_config_table
|
||||
{
|
||||
char mpc_signature[4];
|
||||
#define MPC_SIGNATURE "PCMP"
|
||||
unsigned short mpc_length; /* Size of table */
|
||||
char mpc_spec; /* 0x01 */
|
||||
char mpc_checksum;
|
||||
char mpc_oem[8];
|
||||
char mpc_productid[12];
|
||||
unsigned long mpc_oemptr; /* 0 if not present */
|
||||
unsigned short mpc_oemsize; /* 0 if not present */
|
||||
unsigned short mpc_entry_count;
|
||||
unsigned long mpc_lapic; /* APIC address */
|
||||
unsigned short mpe_length; /* Extended Table size */
|
||||
unsigned char mpe_checksum; /* Extended Table checksum */
|
||||
unsigned char reserved;
|
||||
};
|
||||
|
||||
/* Followed by entries */
|
||||
|
||||
#define MP_PROCESSOR 0
|
||||
#define MP_BUS 1
|
||||
#define MP_IOAPIC 2
|
||||
#define MP_INTSRC 3
|
||||
#define MP_LINTSRC 4
|
||||
|
||||
struct mpc_config_processor
|
||||
{
|
||||
unsigned char mpc_type;
|
||||
unsigned char mpc_apicid; /* Local APIC number */
|
||||
unsigned char mpc_apicver; /* Its versions */
|
||||
unsigned char mpc_cpuflag;
|
||||
#define CPU_ENABLED 1 /* Processor is available */
|
||||
#define CPU_BOOTPROCESSOR 2 /* Processor is the BP */
|
||||
unsigned long mpc_cpufeature;
|
||||
#define CPU_STEPPING_MASK 0x0F
|
||||
#define CPU_MODEL_MASK 0xF0
|
||||
#define CPU_FAMILY_MASK 0xF00
|
||||
unsigned long mpc_featureflag; /* CPUID feature value */
|
||||
unsigned long mpc_reserved[2];
|
||||
};
|
||||
|
||||
struct mpc_config_bus
|
||||
{
|
||||
unsigned char mpc_type;
|
||||
unsigned char mpc_busid;
|
||||
unsigned char mpc_bustype[6] __attribute((packed));
|
||||
};
|
||||
|
||||
#define BUSTYPE_EISA "EISA"
|
||||
#define BUSTYPE_ISA "ISA"
|
||||
#define BUSTYPE_INTERN "INTERN" /* Internal BUS */
|
||||
#define BUSTYPE_MCA "MCA"
|
||||
#define BUSTYPE_VL "VL" /* Local bus */
|
||||
#define BUSTYPE_PCI "PCI"
|
||||
#define BUSTYPE_PCMCIA "PCMCIA"
|
||||
|
||||
struct mpc_config_ioapic
|
||||
{
|
||||
unsigned char mpc_type;
|
||||
unsigned char mpc_apicid;
|
||||
unsigned char mpc_apicver;
|
||||
unsigned char mpc_flags;
|
||||
#define MPC_APIC_USABLE 0x01
|
||||
unsigned long mpc_apicaddr;
|
||||
};
|
||||
|
||||
struct mpc_config_intsrc
|
||||
{
|
||||
unsigned char mpc_type;
|
||||
unsigned char mpc_irqtype;
|
||||
unsigned short mpc_irqflag;
|
||||
unsigned char mpc_srcbus;
|
||||
unsigned char mpc_srcbusirq;
|
||||
unsigned char mpc_dstapic;
|
||||
unsigned char mpc_dstirq;
|
||||
};
|
||||
|
||||
enum mp_irq_source_types {
|
||||
mp_INT = 0,
|
||||
mp_NMI = 1,
|
||||
mp_SMI = 2,
|
||||
mp_ExtINT = 3
|
||||
};
|
||||
|
||||
#define MP_IRQ_POLARITY_DEFAULT 0x0
|
||||
#define MP_IRQ_POLARITY_HIGH 0x1
|
||||
#define MP_IRQ_POLARITY_LOW 0x3
|
||||
#define MP_IRQ_POLARITY_MASK 0x3
|
||||
#define MP_IRQ_TRIGGER_DEFAULT 0x0
|
||||
#define MP_IRQ_TRIGGER_EDGE 0x4
|
||||
#define MP_IRQ_TRIGGER_LEVEL 0xc
|
||||
#define MP_IRQ_TRIGGER_MASK 0xc
|
||||
|
||||
|
||||
struct mpc_config_lintsrc
|
||||
{
|
||||
unsigned char mpc_type;
|
||||
unsigned char mpc_irqtype;
|
||||
unsigned short mpc_irqflag;
|
||||
unsigned char mpc_srcbusid;
|
||||
unsigned char mpc_srcbusirq;
|
||||
unsigned char mpc_destapic;
|
||||
#define MP_APIC_ALL 0xFF
|
||||
unsigned char mpc_destapiclint;
|
||||
};
|
||||
|
||||
/*
|
||||
* Default configurations
|
||||
*
|
||||
* 1 2 CPU ISA 82489DX
|
||||
* 2 2 CPU EISA 82489DX neither IRQ 0 timer nor IRQ 13 DMA chaining
|
||||
* 3 2 CPU EISA 82489DX
|
||||
* 4 2 CPU MCA 82489DX
|
||||
* 5 2 CPU ISA+PCI
|
||||
* 6 2 CPU EISA+PCI
|
||||
* 7 2 CPU MCA+PCI
|
||||
*/
|
||||
|
||||
#define MAX_IRQ_SOURCES 128
|
||||
#define MAX_MP_BUSSES 32
|
||||
enum mp_bustype {
|
||||
MP_BUS_ISA,
|
||||
MP_BUS_EISA,
|
||||
MP_BUS_PCI,
|
||||
MP_BUS_MCA
|
||||
};
|
||||
|
||||
/* Followed by entries */
|
||||
|
||||
#define MPE_SYSTEM_ADDRESS_SPACE 0x80
|
||||
#define MPE_BUS_HIERARCHY 0x81
|
||||
#define MPE_COMPATIBILITY_ADDRESS_SPACE 0x82
|
||||
|
||||
struct mp_exten_config {
|
||||
unsigned char mpe_type;
|
||||
unsigned char mpe_length;
|
||||
};
|
||||
|
||||
typedef struct mp_exten_config *mpe_t;
|
||||
|
||||
struct mp_exten_system_address_space {
|
||||
unsigned char mpe_type;
|
||||
unsigned char mpe_length;
|
||||
unsigned char mpe_busid;
|
||||
unsigned char mpe_address_type;
|
||||
#define ADDRESS_TYPE_IO 0
|
||||
#define ADDRESS_TYPE_MEM 1
|
||||
#define ADDRESS_TYPE_PREFETCH 2
|
||||
unsigned int mpe_address_base_low;
|
||||
unsigned int mpe_address_base_high;
|
||||
unsigned int mpe_address_length_low;
|
||||
unsigned int mpe_address_length_high;
|
||||
};
|
||||
|
||||
struct mp_exten_bus_hierarchy {
|
||||
unsigned char mpe_type;
|
||||
unsigned char mpe_length;
|
||||
unsigned char mpe_busid;
|
||||
unsigned char mpe_bus_info;
|
||||
#define BUS_SUBTRACTIVE_DECODE 1
|
||||
unsigned char mpe_parent_busid;
|
||||
unsigned char reserved[3];
|
||||
};
|
||||
|
||||
struct mp_exten_compatibility_address_space {
|
||||
unsigned char mpe_type;
|
||||
unsigned char mpe_length;
|
||||
unsigned char mpe_busid;
|
||||
unsigned char mpe_address_modifier;
|
||||
#define ADDRESS_RANGE_SUBTRACT 1
|
||||
#define ADDRESS_RANGE_ADD 0
|
||||
unsigned int mpe_range_list;
|
||||
#define RANGE_LIST_IO_ISA 0
|
||||
/* X100 - X3FF
|
||||
* X500 - X7FF
|
||||
* X900 - XBFF
|
||||
* XD00 - XFFF
|
||||
*/
|
||||
#define RANGE_LIST_IO_VGA 1
|
||||
/* X3B0 - X3BB
|
||||
* X3C0 - X3DF
|
||||
* X7B0 - X7BB
|
||||
* X7C0 - X7DF
|
||||
* XBB0 - XBBB
|
||||
* XBC0 - XBDF
|
||||
* XFB0 - XFBB
|
||||
* XFC0 - XCDF
|
||||
*/
|
||||
};
|
||||
|
||||
/* Default local apic addr */
|
||||
#define LAPIC_ADDR 0xFEE00000
|
||||
|
||||
void *smp_next_mpc_entry(struct mp_config_table *mc);
|
||||
void *smp_next_mpe_entry(struct mp_config_table *mc);
|
||||
|
||||
void smp_write_processor(struct mp_config_table *mc,
|
||||
unsigned char apicid, unsigned char apicver,
|
||||
unsigned char cpuflag, unsigned int cpufeature,
|
||||
unsigned int featureflag);
|
||||
void smp_write_processors(struct mp_config_table *mc);
|
||||
void smp_write_bus(struct mp_config_table *mc,
|
||||
unsigned char id, unsigned char *bustype);
|
||||
void smp_write_ioapic(struct mp_config_table *mc,
|
||||
unsigned char id, unsigned char ver,
|
||||
unsigned long apicaddr);
|
||||
void smp_write_intsrc(struct mp_config_table *mc,
|
||||
unsigned char irqtype, unsigned short irqflag,
|
||||
unsigned char srcbus, unsigned char srcbusirq,
|
||||
unsigned char dstapic, unsigned char dstirq);
|
||||
void smp_write_lintsrc(struct mp_config_table *mc,
|
||||
unsigned char irqtype, unsigned short irqflag,
|
||||
unsigned char srcbusid, unsigned char srcbusirq,
|
||||
unsigned char destapic, unsigned char destapiclint);
|
||||
void smp_write_address_space(struct mp_config_table *mc,
|
||||
unsigned char busid, unsigned char address_type,
|
||||
unsigned int address_base_low, unsigned int address_base_high,
|
||||
unsigned int address_length_low, unsigned int address_length_high);
|
||||
void smp_write_bus_hierarchy(struct mp_config_table *mc,
|
||||
unsigned char busid, unsigned char bus_info,
|
||||
unsigned char parent_busid);
|
||||
void smp_write_compatibility_address_space(struct mp_config_table *mc,
|
||||
unsigned char busid, unsigned char address_modifier,
|
||||
unsigned int range_list);
|
||||
unsigned char smp_compute_checksum(void *v, int len);
|
||||
void smp_write_floating_table(void *v);
|
||||
void write_smp_table(void *v);
|
||||
|
||||
|
||||
#else /* HAVE_MP_TABLE */
|
||||
#define write_smp_table(v) do {} while(0)
|
||||
#endif /* HAVE_MP_TABLE */
|
||||
|
||||
#endif
|
||||
|
||||
57
src/arch/i386/include/arch/smp/spinlock.h
Normal file
57
src/arch/i386/include/arch/smp/spinlock.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#ifndef ARCH_SMP_SPINLOCK_H
|
||||
#define ARCH_SMP_SPINLOCK_H
|
||||
|
||||
/*
|
||||
* Your basic SMP spinlocks, allowing only a single CPU anywhere
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
volatile unsigned int lock;
|
||||
} spinlock_t;
|
||||
|
||||
|
||||
#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 }
|
||||
|
||||
/*
|
||||
* Simple spin lock operations. There are two variants, one clears IRQ's
|
||||
* on the local processor, one does not.
|
||||
*
|
||||
* We make no fairness assumptions. They have a cost.
|
||||
*/
|
||||
#define barrier() __asm__ __volatile__("": : :"memory")
|
||||
#define spin_is_locked(x) (*(volatile char *)(&(x)->lock) <= 0)
|
||||
#define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x))
|
||||
|
||||
#define spin_lock_string \
|
||||
"\n1:\t" \
|
||||
"lock ; decb %0\n\t" \
|
||||
"js 2f\n" \
|
||||
".section .text.lock,\"ax\"\n" \
|
||||
"2:\t" \
|
||||
"cmpb $0,%0\n\t" \
|
||||
"rep;nop\n\t" \
|
||||
"jle 2b\n\t" \
|
||||
"jmp 1b\n" \
|
||||
".previous"
|
||||
|
||||
/*
|
||||
* This works. Despite all the confusion.
|
||||
*/
|
||||
#define spin_unlock_string \
|
||||
"movb $1,%0"
|
||||
|
||||
static inline void spin_lock(spinlock_t *lock)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
spin_lock_string
|
||||
:"=m" (lock->lock) : : "memory");
|
||||
}
|
||||
|
||||
static inline void spin_unlock(spinlock_t *lock)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
spin_unlock_string
|
||||
:"=m" (lock->lock) : : "memory");
|
||||
}
|
||||
|
||||
#endif /* ARCH_SMP_SPINLOCK_H */
|
||||
55
src/arch/i386/lib/cpu_reset.inc
Normal file
55
src/arch/i386/lib/cpu_reset.inc
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
jmp cpu_reset_out
|
||||
|
||||
#ifdef DEBUG
|
||||
cpu_reset_str: .string "cpu_reset\r\n";
|
||||
cpu_size_set_str: .string "cpu memory size set\r\n";
|
||||
#endif
|
||||
|
||||
|
||||
__cpu_reset:
|
||||
#ifdef DEBUG
|
||||
TTYS0_TX_STRING($cpu_reset_str);
|
||||
#endif /* DEBUG */
|
||||
|
||||
CALLSP(set_memory_size)
|
||||
|
||||
#ifdef DEBUG
|
||||
TTYS0_TX_STRING($cpu_size_set_str);
|
||||
#endif /* DEBUG */
|
||||
|
||||
#ifdef SMP
|
||||
/* Test to see if we are the boot strap processor.
|
||||
* If so the boot must be complete.
|
||||
*/
|
||||
movl $0x1b, %ecx
|
||||
rdmsr
|
||||
testl $0x100, %eax
|
||||
jnz __reboot
|
||||
|
||||
/* Fixed mtrrs are enabled by the C code so if they
|
||||
* aren't enabled yet we must be a secondary
|
||||
* processor initializing in an SMP system.
|
||||
*/
|
||||
mov $MTRRdefType_MSR, %ecx
|
||||
rdmsr
|
||||
testl $0x400, %eax
|
||||
jnz __reboot
|
||||
|
||||
/* set the stack pointer */
|
||||
movl $_estack, %esp
|
||||
movl $APIC_DEFAULT_BASE, %edi
|
||||
movl APIC_ID(%edi), %eax
|
||||
shrl $24, %eax
|
||||
movl $STACK_SIZE, %ebx
|
||||
mull %ebx
|
||||
subl %eax, %esp
|
||||
|
||||
call EXT(secondary_cpu_init)
|
||||
/* Fall through in case we somehow return */
|
||||
#endif /* SMP */
|
||||
|
||||
__reboot:
|
||||
movl $0xffffffff, %ebp
|
||||
jmp __main
|
||||
|
||||
cpu_reset_out:
|
||||
65
src/arch/i386/lib/pirq_routing.c
Normal file
65
src/arch/i386/lib/pirq_routing.c
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
#ifdef HAVE_PIRQ_TABLE
|
||||
#include <printk.h>
|
||||
#include <pci.h>
|
||||
#include <arch/pirq_routing.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
void check_pirq_routing_table(void)
|
||||
{
|
||||
const u8 *addr;
|
||||
const struct irq_routing_table *rt;
|
||||
int i;
|
||||
u8 sum;
|
||||
|
||||
printk_info("Checking IRQ routing tables...");
|
||||
|
||||
rt = &intel_irq_routing_table;
|
||||
addr = (u8 *)rt;
|
||||
|
||||
sum = 0;
|
||||
for (i = 0; i < rt->size; i++)
|
||||
sum += addr[i];
|
||||
|
||||
printk_debug("%s:%6d:%s() - irq_routing_table located at: 0x%p\n",
|
||||
__FILE__, __LINE__, __FUNCTION__, addr);
|
||||
|
||||
sum = (unsigned char)(rt->checksum-sum);
|
||||
|
||||
if (sum != rt->checksum) {
|
||||
printk_warning("%s:%6d:%s() - "
|
||||
"checksum is: 0x%02x but should be: 0x%02x\n",
|
||||
__FILE__, __LINE__, __FUNCTION__, rt->checksum, sum);
|
||||
}
|
||||
|
||||
if (rt->signature != PIRQ_SIGNATURE || rt->version != PIRQ_VERSION ||
|
||||
rt->size % 16 || rt->size < sizeof(struct irq_routing_table)) {
|
||||
printk_warning("%s:%6d:%s() - "
|
||||
"Interrupt Routing Table not valid\n",
|
||||
__FILE__, __LINE__, __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
sum = 0;
|
||||
for (i=0; i<rt->size; i++)
|
||||
sum += addr[i];
|
||||
|
||||
if (sum) {
|
||||
printk_warning("%s:%6d:%s() - "
|
||||
"checksum error in irq routing table\n",
|
||||
__FILE__, __LINE__, __FUNCTION__);
|
||||
}
|
||||
|
||||
printk_info("done.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#define RTABLE_DEST 0xf0000
|
||||
|
||||
void copy_pirq_routing_table(void)
|
||||
{
|
||||
printk_info("Copying IRQ routing tables...");
|
||||
memcpy((char *) RTABLE_DEST, &intel_irq_routing_table, intel_irq_routing_table.size);
|
||||
printk_info("done.\n");
|
||||
}
|
||||
#endif /* HAVE_PIRQ_TABLE */
|
||||
|
||||
3
src/arch/i386/smp/Config
Normal file
3
src/arch/i386/smp/Config
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
object mpspec.o
|
||||
object ioapic.o
|
||||
object start_stop.o
|
||||
137
src/arch/i386/smp/ioapic.c
Normal file
137
src/arch/i386/smp/ioapic.c
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
#if defined(IOAPIC)
|
||||
#include <arch/ioapic.h>
|
||||
#include <printk.h>
|
||||
|
||||
/* TODO: this must move to chip/intel */
|
||||
/* we have to do more than we thought. I assumed Linux would do all the
|
||||
* interesting parts, and I was wrong.
|
||||
*/
|
||||
struct ioapicreg {
|
||||
unsigned int reg;
|
||||
unsigned int value_low, value_high;
|
||||
};
|
||||
struct ioapicreg ioapicregvalues[] = {
|
||||
#define ALL (0xff << 24)
|
||||
#define NONE (0)
|
||||
#define DISABLED (1 << 16)
|
||||
#define ENABLED (0 << 16)
|
||||
#define TRIGGER_EDGE (0 << 15)
|
||||
#define TRIGGER_LEVEL (1 << 15)
|
||||
#define POLARITY_HIGH (0 << 13)
|
||||
#define POLARITY_LOW (1 << 13)
|
||||
#define PHYSICAL_DEST (0 << 11)
|
||||
#define LOGICAL_DEST (1 << 11)
|
||||
#define ExtINT (7 << 8)
|
||||
#define NMI (4 << 8)
|
||||
#define SMI (2 << 8)
|
||||
#define INT (1 << 8)
|
||||
#if 0 /* L440GX */
|
||||
{0x00, DISABLED, NONE},
|
||||
{0x01, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x59, ALL},
|
||||
{0x02, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x51, ALL},
|
||||
{0x03, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x61, NONE},
|
||||
{0x04, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x69, ALL},
|
||||
{0x05, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x71, NONE},
|
||||
{0x06, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x79, NONE},
|
||||
{0x07, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x81, NONE},
|
||||
{0x08, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x89, ALL},
|
||||
{0x09, DISABLED, NONE},
|
||||
{0x0a, DISABLED, NONE},
|
||||
{0x0b, DISABLED, NONE},
|
||||
{0x0c, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x91, ALL},
|
||||
{0x0d, DISABLED, NONE},
|
||||
{0x0e, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x99, ALL},
|
||||
{0x0f, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0xa1, ALL},
|
||||
{0x10, DISABLED, NONE},
|
||||
{0x11, DISABLED, NONE},
|
||||
{0x12, DISABLED, NONE},
|
||||
{0x13, ENABLED|TRIGGER_LEVEL|POLARITY_LOW|LOGICAL_DEST|INT|0xa9, ALL},
|
||||
{0x14, DISABLED, NONE},
|
||||
{0x15, ENABLED|TRIGGER_LEVEL|POLARITY_LOW|LOGICAL_DEST|INT|0xb1, ALL},
|
||||
{0x16, DISABLED, NONE},
|
||||
{0x17, DISABLED, NONE}
|
||||
#endif
|
||||
#if 0 /* tyan guinness */
|
||||
/* mask, trigger, polarity, destination, delivery, vector */
|
||||
{0x00, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|ExtINT|0x0, ALL},
|
||||
{0x01, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x1, ALL},
|
||||
{0x02, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x0, ALL},
|
||||
{0x03, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x3, ALL},
|
||||
{0x04, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x4, ALL},
|
||||
{0x05, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x5, ALL},
|
||||
{0x06, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x6, ALL},
|
||||
{0x07, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x7, ALL},
|
||||
{0x08, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x8, ALL},
|
||||
{0x09, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0x9, ALL},
|
||||
{0x0a, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0xa, ALL},
|
||||
{0x0b, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0xb, ALL},
|
||||
{0x0c, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0xc, ALL},
|
||||
{0x0d, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0xd, ALL},
|
||||
{0x0e, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0xe, ALL},
|
||||
{0x0f, ENABLED|TRIGGER_EDGE|POLARITY_HIGH|LOGICAL_DEST|INT|0xf, ALL},
|
||||
{0x10, ENABLED|TRIGGER_LEVEL|POLARITY_LOW|LOGICAL_DEST|INT|0x10, ALL},
|
||||
{0x11, ENABLED|TRIGGER_LEVEL|POLARITY_LOW|LOGICAL_DEST|INT|0x11, ALL},
|
||||
{0x12, ENABLED|TRIGGER_LEVEL|POLARITY_LOW|LOGICAL_DEST|INT|0x12, ALL},
|
||||
{0x13, ENABLED|TRIGGER_LEVEL|POLARITY_LOW|LOGICAL_DEST|INT|0x13, ALL},
|
||||
{0x14, DISABLED, NONE},
|
||||
{0x14, DISABLED, NONE},
|
||||
{0x15, DISABLED, NONE},
|
||||
{0x16, DISABLED, NONE},
|
||||
{0x17, DISABLED, NONE},
|
||||
#endif
|
||||
#if 1
|
||||
/* mask, trigger, polarity, destination, delivery, vector */
|
||||
{0x00, DISABLED, NONE},
|
||||
{0x01, DISABLED, NONE},
|
||||
{0x02, DISABLED, NONE},
|
||||
{0x03, DISABLED, NONE},
|
||||
{0x04, DISABLED, NONE},
|
||||
{0x05, DISABLED, NONE},
|
||||
{0x06, DISABLED, NONE},
|
||||
{0x07, DISABLED, NONE},
|
||||
{0x08, DISABLED, NONE},
|
||||
{0x09, DISABLED, NONE},
|
||||
{0x0a, DISABLED, NONE},
|
||||
{0x0b, DISABLED, NONE},
|
||||
{0x0c, DISABLED, NONE},
|
||||
{0x0d, DISABLED, NONE},
|
||||
{0x0e, DISABLED, NONE},
|
||||
{0x0f, DISABLED, NONE},
|
||||
{0x10, DISABLED, NONE},
|
||||
{0x11, DISABLED, NONE},
|
||||
{0x12, DISABLED, NONE},
|
||||
{0x13, DISABLED, NONE},
|
||||
{0x14, DISABLED, NONE},
|
||||
{0x14, DISABLED, NONE},
|
||||
{0x15, DISABLED, NONE},
|
||||
{0x16, DISABLED, NONE},
|
||||
{0x17, DISABLED, NONE},
|
||||
#endif
|
||||
};
|
||||
|
||||
void setup_ioapic(void)
|
||||
{
|
||||
int i;
|
||||
unsigned long value_low, value_high;
|
||||
unsigned long nvram = 0xfec00000;
|
||||
volatile unsigned long *l;
|
||||
struct ioapicreg *a = ioapicregvalues;
|
||||
|
||||
l = (unsigned long *) nvram;
|
||||
for (i = 0; i < sizeof(ioapicregvalues) / sizeof(ioapicregvalues[0]);
|
||||
i++, a++) {
|
||||
l[0] = (a->reg * 2) + 0x10;
|
||||
l[4] = a->value_low;
|
||||
value_low = l[4];
|
||||
l[0] = (a->reg *2) + 0x11;
|
||||
l[4] = a->value_high;
|
||||
value_high = l[4];
|
||||
if ((i==0) && (value_low == 0xffffffff)) {
|
||||
printk_warning("IO APIC not responding.\n");
|
||||
return;
|
||||
}
|
||||
printk_spew("for IRQ, reg 0x%08x value 0x%08x 0x%08x\n",
|
||||
a->reg, a->value_low, a->value_high);
|
||||
}
|
||||
}
|
||||
#endif /* IOAPIC */
|
||||
243
src/arch/i386/smp/mpspec.c
Normal file
243
src/arch/i386/smp/mpspec.c
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
#ifdef HAVE_MP_TABLE
|
||||
|
||||
#ifndef lint
|
||||
static char rcsid[] = "$Id$";
|
||||
#endif
|
||||
|
||||
#include <smp/start_stop.h>
|
||||
#include <arch/smp/mpspec.h>
|
||||
#include <string.h>
|
||||
#include <cpu/p5/cpuid.h>
|
||||
#include <cpu/p6/apic.h>
|
||||
#include <printk.h>
|
||||
|
||||
unsigned char smp_compute_checksum(void *v, int len)
|
||||
{
|
||||
unsigned char *bytes;
|
||||
unsigned char checksum;
|
||||
int i;
|
||||
bytes = v;
|
||||
checksum = 0;
|
||||
for(i = 0; i < len; i++) {
|
||||
checksum -= bytes[i];
|
||||
}
|
||||
return checksum;
|
||||
}
|
||||
|
||||
void smp_write_floating_table(void *v)
|
||||
{
|
||||
struct intel_mp_floating *mf;
|
||||
|
||||
mf = v;
|
||||
mf->mpf_signature[0] = '_';
|
||||
mf->mpf_signature[1] = 'M';
|
||||
mf->mpf_signature[2] = 'P';
|
||||
mf->mpf_signature[3] = '_';
|
||||
mf->mpf_physptr = (unsigned long)(((char *)v) + SMP_FLOATING_TABLE_LEN);
|
||||
mf->mpf_length = 1;
|
||||
mf->mpf_specification = 4;
|
||||
mf->mpf_checksum = 0;
|
||||
mf->mpf_feature1 = 0;
|
||||
mf->mpf_feature2 = 0;
|
||||
mf->mpf_feature3 = 0;
|
||||
mf->mpf_feature4 = 0;
|
||||
mf->mpf_feature5 = 0;
|
||||
mf->mpf_checksum = smp_compute_checksum(mf, mf->mpf_length*16);
|
||||
}
|
||||
|
||||
void *smp_next_mpc_entry(struct mp_config_table *mc)
|
||||
{
|
||||
void *v;
|
||||
v = (void *)(((char *)mc) + mc->mpc_length);
|
||||
return v;
|
||||
}
|
||||
static void smp_add_mpc_entry(struct mp_config_table *mc, unsigned length)
|
||||
{
|
||||
mc->mpc_length += length;
|
||||
mc->mpc_entry_count++;
|
||||
}
|
||||
|
||||
void *smp_next_mpe_entry(struct mp_config_table *mc)
|
||||
{
|
||||
void *v;
|
||||
v = (void *)(((char *)mc) + mc->mpc_length + mc->mpe_length);
|
||||
return v;
|
||||
}
|
||||
static void smp_add_mpe_entry(struct mp_config_table *mc, mpe_t mpe)
|
||||
{
|
||||
mc->mpe_length += mpe->mpe_length;
|
||||
}
|
||||
|
||||
void smp_write_processor(struct mp_config_table *mc,
|
||||
unsigned char apicid, unsigned char apicver,
|
||||
unsigned char cpuflag, unsigned int cpufeature,
|
||||
unsigned int featureflag)
|
||||
{
|
||||
struct mpc_config_processor *mpc;
|
||||
mpc = smp_next_mpc_entry(mc);
|
||||
memset(mpc, '\0', sizeof(*mpc));
|
||||
mpc->mpc_type = MP_PROCESSOR;
|
||||
mpc->mpc_apicid = apicid;
|
||||
mpc->mpc_apicver = apicver;
|
||||
mpc->mpc_cpuflag = cpuflag;
|
||||
mpc->mpc_cpufeature = cpufeature;
|
||||
mpc->mpc_featureflag = featureflag;
|
||||
smp_add_mpc_entry(mc, sizeof(*mpc));
|
||||
}
|
||||
|
||||
/* If we assume a symmetric processor configuration we can
|
||||
* get all of the information we need to write the processor
|
||||
* entry from the bootstrap processor.
|
||||
* Plus I don't think linux really even cares.
|
||||
* Having the proper apicid's in the table so the non-bootstrap
|
||||
* processors can be woken up should be enough.
|
||||
*/
|
||||
void smp_write_processors(struct mp_config_table *mc)
|
||||
{
|
||||
int i;
|
||||
int processor_id;
|
||||
unsigned apic_version;
|
||||
unsigned cpu_features;
|
||||
unsigned cpu_feature_flags;
|
||||
int eax, ebx, ecx, edx;
|
||||
processor_id = this_processors_id();
|
||||
apic_version = apic_read(APIC_LVR) & 0xff;
|
||||
cpuid(1, &eax, &ebx, &ecx, &edx);
|
||||
cpu_features = eax;
|
||||
cpu_feature_flags = edx;
|
||||
for(i = 0; i < MAX_CPUS; i++) {
|
||||
smp_write_processor(mc, i, apic_version,
|
||||
((processor_id == i)? CPU_BOOTPROCESSOR:0) | CPU_ENABLED,
|
||||
cpu_features, cpu_feature_flags
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void smp_write_bus(struct mp_config_table *mc,
|
||||
unsigned char id, unsigned char *bustype)
|
||||
{
|
||||
struct mpc_config_bus *mpc;
|
||||
mpc = smp_next_mpc_entry(mc);
|
||||
memset(mpc, '\0', sizeof(*mpc));
|
||||
mpc->mpc_type = MP_BUS;
|
||||
mpc->mpc_busid = id;
|
||||
memcpy(mpc->mpc_bustype, bustype, sizeof(mpc->mpc_bustype));
|
||||
smp_add_mpc_entry(mc, sizeof(*mpc));
|
||||
}
|
||||
|
||||
void smp_write_ioapic(struct mp_config_table *mc,
|
||||
unsigned char id, unsigned char ver,
|
||||
unsigned long apicaddr)
|
||||
{
|
||||
struct mpc_config_ioapic *mpc;
|
||||
mpc = smp_next_mpc_entry(mc);
|
||||
memset(mpc, '\0', sizeof(*mpc));
|
||||
mpc->mpc_type = MP_IOAPIC;
|
||||
mpc->mpc_apicid = id;
|
||||
mpc->mpc_apicver = ver;
|
||||
mpc->mpc_flags = MPC_APIC_USABLE;
|
||||
mpc->mpc_apicaddr = apicaddr;
|
||||
smp_add_mpc_entry(mc, sizeof(*mpc));
|
||||
}
|
||||
|
||||
void smp_write_intsrc(struct mp_config_table *mc,
|
||||
unsigned char irqtype, unsigned short irqflag,
|
||||
unsigned char srcbus, unsigned char srcbusirq,
|
||||
unsigned char dstapic, unsigned char dstirq)
|
||||
{
|
||||
struct mpc_config_intsrc *mpc;
|
||||
mpc = smp_next_mpc_entry(mc);
|
||||
memset(mpc, '\0', sizeof(*mpc));
|
||||
mpc->mpc_type = MP_INTSRC;
|
||||
mpc->mpc_irqtype = irqtype;
|
||||
mpc->mpc_irqflag = irqflag;
|
||||
mpc->mpc_srcbus = srcbus;
|
||||
mpc->mpc_srcbusirq = srcbusirq;
|
||||
mpc->mpc_dstapic = dstapic;
|
||||
mpc->mpc_dstirq = dstirq;
|
||||
smp_add_mpc_entry(mc, sizeof(*mpc));
|
||||
}
|
||||
|
||||
|
||||
void smp_write_lintsrc(struct mp_config_table *mc,
|
||||
unsigned char irqtype, unsigned short irqflag,
|
||||
unsigned char srcbusid, unsigned char srcbusirq,
|
||||
unsigned char destapic, unsigned char destapiclint)
|
||||
{
|
||||
struct mpc_config_lintsrc *mpc;
|
||||
mpc = smp_next_mpc_entry(mc);
|
||||
memset(mpc, '\0', sizeof(*mpc));
|
||||
mpc->mpc_type = MP_LINTSRC;
|
||||
mpc->mpc_irqtype = irqtype;
|
||||
mpc->mpc_irqflag = irqflag;
|
||||
mpc->mpc_srcbusid = srcbusid;
|
||||
mpc->mpc_srcbusirq = srcbusirq;
|
||||
mpc->mpc_destapic = destapic;
|
||||
mpc->mpc_destapiclint = destapiclint;
|
||||
smp_add_mpc_entry(mc, sizeof(*mpc));
|
||||
}
|
||||
|
||||
void smp_write_address_space(struct mp_config_table *mc,
|
||||
unsigned char busid, unsigned char address_type,
|
||||
unsigned int address_base_low, unsigned int address_base_high,
|
||||
unsigned int address_length_low, unsigned int address_length_high)
|
||||
{
|
||||
struct mp_exten_system_address_space *mpe;
|
||||
mpe = smp_next_mpe_entry(mc);
|
||||
memset(mpe, '\0', sizeof(*mpe));
|
||||
mpe->mpe_type = MPE_SYSTEM_ADDRESS_SPACE;
|
||||
mpe->mpe_length = sizeof(*mpe);
|
||||
mpe->mpe_busid = busid;
|
||||
mpe->mpe_address_type = address_type;
|
||||
mpe->mpe_address_base_low = address_base_low;
|
||||
mpe->mpe_address_base_high = address_base_high;
|
||||
mpe->mpe_address_length_low = address_length_low;
|
||||
mpe->mpe_address_length_high = address_length_high;
|
||||
smp_add_mpe_entry(mc, (mpe_t)mpe);
|
||||
}
|
||||
|
||||
|
||||
void smp_write_bus_hierarchy(struct mp_config_table *mc,
|
||||
unsigned char busid, unsigned char bus_info,
|
||||
unsigned char parent_busid)
|
||||
{
|
||||
struct mp_exten_bus_hierarchy *mpe;
|
||||
mpe = smp_next_mpe_entry(mc);
|
||||
memset(mpe, '\0', sizeof(*mpe));
|
||||
mpe->mpe_type = MPE_BUS_HIERARCHY;
|
||||
mpe->mpe_length = sizeof(*mpe);
|
||||
mpe->mpe_busid = busid;
|
||||
mpe->mpe_bus_info = bus_info;
|
||||
mpe->mpe_parent_busid = parent_busid;
|
||||
smp_add_mpe_entry(mc, (mpe_t)mpe);
|
||||
}
|
||||
|
||||
void smp_write_compatibility_address_space(struct mp_config_table *mc,
|
||||
unsigned char busid, unsigned char address_modifier,
|
||||
unsigned int range_list)
|
||||
{
|
||||
struct mp_exten_compatibility_address_space *mpe;
|
||||
mpe = smp_next_mpe_entry(mc);
|
||||
memset(mpe, '\0', sizeof(*mpe));
|
||||
mpe->mpe_type = MPE_COMPATIBILITY_ADDRESS_SPACE;
|
||||
mpe->mpe_length = sizeof(*mpe);
|
||||
mpe->mpe_busid = busid;
|
||||
mpe->mpe_address_modifier = address_modifier;
|
||||
mpe->mpe_range_list = range_list;
|
||||
smp_add_mpe_entry(mc, (mpe_t)mpe);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* memcpy standard block */
|
||||
const static char smpblock[] =
|
||||
{0x5F, 0x4D, 0x50, 0x5F, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0x04, 0x9B, 0x05, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
void write_smp_table(void *v)
|
||||
{
|
||||
memcpy(v, smpblock, sizeof(smpblock));
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
#endif /* HAVE_MP_TABLE */
|
||||
194
src/arch/i386/smp/start_stop.c
Normal file
194
src/arch/i386/smp/start_stop.c
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
#include <smp/start_stop.h>
|
||||
#include <cpu/p6/apic.h>
|
||||
#include <delay.h>
|
||||
|
||||
static inline void hlt(void)
|
||||
{
|
||||
asm("hlt");
|
||||
return;
|
||||
}
|
||||
|
||||
int this_processors_id(void)
|
||||
{
|
||||
return apic_read(APIC_ID) >> 24;
|
||||
}
|
||||
|
||||
void stop_cpu(int apicid)
|
||||
{
|
||||
int timeout;
|
||||
unsigned long send_status;
|
||||
|
||||
/* send an APIC INIT to myself */
|
||||
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
|
||||
apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT);
|
||||
|
||||
/* wait for the ipi send to finish */
|
||||
printk_spew("Waiting for send to finish...\n");
|
||||
timeout = 0;
|
||||
do {
|
||||
printk_spew("+");
|
||||
udelay(100);
|
||||
send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
|
||||
} while (send_status && (timeout++ < 1000));
|
||||
if (timeout >= 1000) {
|
||||
printk_spew("timed out\n");
|
||||
}
|
||||
mdelay(10);
|
||||
|
||||
printk_spew("Deasserting INIT.\n");
|
||||
/* Deassert the APIC INIT */
|
||||
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
|
||||
apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
|
||||
|
||||
printk_spew("Waiting for send to finish...\n");
|
||||
timeout = 0;
|
||||
do {
|
||||
printk_spew("+");
|
||||
udelay(100);
|
||||
send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
|
||||
} while (send_status && (timeout++ < 1000));
|
||||
if (timeout >= 1000) {
|
||||
printk_debug("timed out\n");
|
||||
}
|
||||
|
||||
while(1) {
|
||||
hlt();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void start_cpu(int apicid)
|
||||
{
|
||||
int timeout;
|
||||
unsigned long send_status, accept_status, start_eip;
|
||||
int j, num_starts, maxlvt;
|
||||
/*
|
||||
* Starting actual IPI sequence...
|
||||
*/
|
||||
|
||||
printk_spew("Asserting INIT.\n");
|
||||
|
||||
/*
|
||||
* Turn INIT on target chip
|
||||
*/
|
||||
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
|
||||
|
||||
/*
|
||||
* Send IPI
|
||||
*/
|
||||
apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT
|
||||
| APIC_DM_INIT);
|
||||
|
||||
printk_spew("Waiting for send to finish...\n");
|
||||
timeout = 0;
|
||||
do {
|
||||
printk_spew("+");
|
||||
udelay(100);
|
||||
send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
|
||||
} while (send_status && (timeout++ < 1000));
|
||||
if (timeout >= 1000) {
|
||||
printk_spew("timed out\n");
|
||||
}
|
||||
|
||||
mdelay(10);
|
||||
|
||||
printk_spew("Deasserting INIT.\n");
|
||||
|
||||
/* Target chip */
|
||||
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
|
||||
|
||||
/* Send IPI */
|
||||
apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
|
||||
|
||||
printk_spew("Waiting for send to finish...\n");
|
||||
timeout = 0;
|
||||
do {
|
||||
printk_spew("+");
|
||||
udelay(100);
|
||||
send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
|
||||
} while (send_status && (timeout++ < 1000));
|
||||
if (timeout >= 1000) {
|
||||
printk_spew("timed out\n");
|
||||
}
|
||||
|
||||
/* FIXME start_eip should be more flexible! */
|
||||
start_eip = 0xf0000;
|
||||
printk_spew("start eip=0x%08lx\n", start_eip);
|
||||
|
||||
num_starts = 2;
|
||||
|
||||
/*
|
||||
* Run STARTUP IPI loop.
|
||||
*/
|
||||
printk_spew("#startup loops: %d.\n", num_starts);
|
||||
|
||||
maxlvt = 4;
|
||||
|
||||
for (j = 1; j <= num_starts; j++) {
|
||||
printk_spew("Sending STARTUP #%d.\n",j);
|
||||
apic_read_around(APIC_SPIV);
|
||||
apic_write(APIC_ESR, 0);
|
||||
apic_read(APIC_ESR);
|
||||
printk_spew("After apic_write.\n");
|
||||
|
||||
/*
|
||||
* STARTUP IPI
|
||||
*/
|
||||
|
||||
/* Target chip */
|
||||
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
|
||||
|
||||
/* Boot on the stack */
|
||||
/* Kick the second */
|
||||
apic_write_around(APIC_ICR, APIC_DM_STARTUP
|
||||
| (start_eip >> 12));
|
||||
|
||||
/*
|
||||
* Give the other CPU some time to accept the IPI.
|
||||
*/
|
||||
udelay(300);
|
||||
|
||||
printk_spew("Startup point 1.\n");
|
||||
|
||||
printk_spew("Waiting for send to finish...\n");
|
||||
timeout = 0;
|
||||
do {
|
||||
printk_spew("+");
|
||||
udelay(100);
|
||||
send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
|
||||
} while (send_status && (timeout++ < 1000));
|
||||
|
||||
/*
|
||||
* Give the other CPU some time to accept the IPI.
|
||||
*/
|
||||
udelay(200);
|
||||
/*
|
||||
* Due to the Pentium erratum 3AP.
|
||||
*/
|
||||
if (maxlvt > 3) {
|
||||
apic_read_around(APIC_SPIV);
|
||||
apic_write(APIC_ESR, 0);
|
||||
}
|
||||
accept_status = (apic_read(APIC_ESR) & 0xEF);
|
||||
if (send_status || accept_status)
|
||||
break;
|
||||
}
|
||||
printk_spew("After Startup.\n");
|
||||
if (send_status)
|
||||
printk_warning("APIC never delivered???\n");
|
||||
if (accept_status)
|
||||
printk_warning("APIC delivery error (%lx).\n", accept_status);
|
||||
}
|
||||
|
||||
void startup_other_cpus(void)
|
||||
{
|
||||
int apicid = this_processors_id();
|
||||
int i;
|
||||
/* Assume the cpus are densly packed by apicid */
|
||||
for(i = 0; i < MAX_CPUS; i++) {
|
||||
if (i == apicid ) {
|
||||
continue;
|
||||
}
|
||||
start_cpu(i);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue