- First pass through with with device tree enhancement merge. Most of the mechanisms should

be in place but don't expect anything to quite work yet.


git-svn-id: svn://svn.coreboot.org/coreboot/trunk@1662 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
Eric Biederman
2004-10-14 20:54:17 +00:00
parent cadfd4c462
commit b78c1972fe
52 changed files with 1723 additions and 1778 deletions

View File

@@ -5,6 +5,8 @@
#include "linuxbios_table.h"
#include <string.h>
#include <version.h>
#include <device/device.h>
#include <stdlib.h>
struct lb_header *lb_table_init(unsigned long addr)
@@ -217,18 +219,75 @@ struct lb_memory *get_lb_mem(void)
return mem_ranges;
}
struct mem_range *sizeram(void)
{
struct mem_range *mem, *rmem;
struct device *dev;
unsigned int count;
count = 0;
for(dev = all_devices; dev; dev = dev->next) {
struct resource *res, *last;
last = &dev->resource[dev->resources];
for(res = &dev->resource[0]; res < last; res++) {
if ((res->flags & IORESOURCE_MEM) &&
(res->flags & IORESOURCE_CACHEABLE))
{
count++;
}
}
}
rmem = mem = malloc(sizeof(*mem) * (count + 1));
for(dev = all_devices; dev; dev = dev->next) {
struct resource *res, *last;
last = &dev->resource[dev->resources];
for(res = &dev->resource[0]; res < last; res++) {
if ((res->flags & IORESOURCE_MEM) &&
(res->flags & IORESOURCE_CACHEABLE))
{
mem->basek = res->base >> 10;
mem->sizek = res->size >> 10;
mem++;
}
}
}
mem->basek = 0;
mem->sizek = 0;
#if 0
for(mem = rmem; mem->sizek; mem++) {
printk_debug("basek: %lu sizek: %lu\n",
mem->basek, mem->sizek);
}
#endif
return rmem;
}
static struct mem_range *get_ramsize(void)
{
struct mem_range *mem = 0;
if (!mem) {
mem = sizeram();
}
if (!mem) {
printk_emerg("No memory size information!\n");
for(;;) {
/* Ensure this loop is not optimized away */
asm volatile("":/* outputs */:/*inputs */ :"memory");
}
}
return mem;
}
unsigned long write_linuxbios_table(
unsigned long *processor_map,
struct mem_range *ram,
unsigned long low_table_start, unsigned long low_table_end,
unsigned long rom_table_startk, unsigned long rom_table_endk)
{
unsigned long table_size;
struct mem_range *ramp;
struct mem_range *ram, *ramp;
struct lb_header *head;
struct lb_memory *mem;
struct lb_record *rec_dest, *rec_src;
ram = get_ramsize();
head = lb_table_init(low_table_end);
low_table_end = (unsigned long)head;
#if HAVE_OPTION_TABLE == 1

View File

@@ -3,12 +3,8 @@
#include <boot/linuxbios_tables.h>
struct mem_range;
/* This file holds function prototypes for building the linuxbios table. */
unsigned long write_linuxbios_table(
unsigned long *processor_map,
struct mem_range *ram,
unsigned long low_table_start, unsigned long low_table_end,
unsigned long rom_table_start, unsigned long rom_table_end);

View File

@@ -1,39 +1,13 @@
#include <console/console.h>
#include <mem.h>
#include <cpu/cpu.h>
#include <boot/tables.h>
#include <boot/linuxbios_tables.h>
#include <arch/pirq_routing.h>
#include <arch/smp/mpspec.h>
#include <arch/acpi.h>
#include <pc80/mc146818rtc.h>
#include "linuxbios_table.h"
#if CONFIG_SMP && CONFIG_MAX_PHYSICAL_CPUS && (CONFIG_MAX_PHYSICAL_CPUS < CONFIG_MAX_CPUS)
static void remove_logical_cpus(unsigned long *processor_map)
{
/* To turn off hyperthreading just remove the logical
* cpus from the processor map.
*/
int disable_logical_cpus = !CONFIG_LOGICAL_CPUS;
if (get_option(&disable_logical_cpus,"hyper_threading")) {
disable_logical_cpus = !CONFIG_LOGICAL_CPUS;
}
if (disable_logical_cpus) {
/* disable logical cpus */
int cnt;
for(cnt=CONFIG_MAX_PHYSICAL_CPUS;cnt<CONFIG_MAX_CPUS;cnt++)
processor_map[cnt]=0;
printk_debug("logical cpus disabled\n");
}
}
#else
#define remove_logical_cpus(processor_map) do {} while(0)
#endif /* CONFIG_SMP && CONFIG_MAX_PHYSICAL_CPUS */
struct lb_memory *write_tables(struct mem_range *mem, unsigned long *processor_map)
struct lb_memory *write_tables(void)
{
unsigned long low_table_start, low_table_end;
unsigned long rom_table_start, rom_table_end;
@@ -56,8 +30,7 @@ struct lb_memory *write_tables(struct mem_range *mem, unsigned long *processor_m
post_code(0x96);
/* The smp table must be in 0-1K, 639K-640K, or 960K-1M */
remove_logical_cpus(processor_map);
low_table_end = write_smp_table(low_table_end, processor_map);
low_table_end = write_smp_table(low_table_end);
/* Write ACPI tables */
/* write them in the rom area because DSDT can be large (8K on epia-m) which
@@ -73,7 +46,7 @@ struct lb_memory *write_tables(struct mem_range *mem, unsigned long *processor_m
}
/* The linuxbios table must be in 0-4K or 960K-1M */
write_linuxbios_table(processor_map, mem,
write_linuxbios_table(
low_table_start, low_table_end,
rom_table_start >> 10, rom_table_end >> 10);

View File

@@ -9,7 +9,7 @@ static void hlt(void)
#endif
#ifdef __GNUC__
#if defined(__GNUC__) && !defined(__ROMCC__)
static inline void hlt(void)
{
asm("hlt");

View File

@@ -191,6 +191,11 @@ static inline void pnp_set_iobase(device_t dev, unsigned index, unsigned iobase)
pnp_write_config(dev, index + 1, iobase & 0xff);
}
static inline uint16_t pnp_read_iobase(device_t dev, unsigned index)
{
return (uint16_t)((pnp_read_config(dev, index) << 8) | pnp_read_config(dev, index + 1));
}
static inline void pnp_set_irq(device_t dev, unsigned index, unsigned irq)
{
pnp_write_config(dev, index, irq);

View File

@@ -1,55 +0,0 @@
#ifndef ARCH_SMP_LAPIC_H
#define ARCH_SMP_LAPIC_H
#include <cpu/p6/msr.h>
#include <cpu/p6/apic.h>
#include <arch/hlt.h>
static void enable_lapic(void)
{
msr_t msr;
msr = rdmsr(0x1b);
msr.hi &= 0xffffff00;
msr.lo &= 0x000007ff;
msr.lo |= APIC_DEFAULT_BASE | (1 << 11);
wrmsr(0x1b, msr);
}
static void disable_lapic(void)
{
msr_t msr;
msr = rdmsr(0x1b);
msr.lo &= ~ (1 << 11);
wrmsr(0x1b, msr);
}
static inline unsigned long lapicid(void)
{
return apic_read(APIC_ID) >> 24;
}
static void stop_this_cpu(void)
{
unsigned apicid;
apicid = lapicid();
/* Send an APIC INIT to myself */
apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT);
/* Wait for the ipi send to finish */
apic_wait_icr_idle();
/* Deassert the APIC INIT */
apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
/* Wait for the ipi send to finish */
apic_wait_icr_idle();
/* If I haven't halted spin forever */
for(;;) {
hlt();
}
}
#endif /* ARCH_SMP_LAPIC_H */

View File

@@ -238,8 +238,7 @@ 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,
unsigned long *processor_map);
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,
@@ -265,18 +264,15 @@ void smp_write_compatibility_address_space(struct mp_config_table *mc,
unsigned int range_list);
unsigned char smp_compute_checksum(void *v, int len);
void *smp_write_floating_table(unsigned long addr);
unsigned long write_smp_table(unsigned long addr, unsigned long *processor_map);
unsigned long write_smp_table(unsigned long addr);
#else /* HAVE_MP_TABLE */
static inline
unsigned long write_smp_table(unsigned long addr, unsigned long *processor_map)
unsigned long write_smp_table(unsigned long addr);
{
return addr;
}
#endif /* HAVE_MP_TABLE */
/* A table (per mainboard) listing the initial apicid of each cpu. */
extern unsigned long initial_apicid[CONFIG_MAX_CPUS];
#endif

View File

@@ -54,4 +54,10 @@ static inline void spin_unlock(spinlock_t *lock)
:"=m" (lock->lock) : : "memory");
}
/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
static inline void cpu_relax(void)
{
__asm__ __volatile__("rep;nop": : :"memory");
}
#endif /* ARCH_SMP_SPINLOCK_H */

View File

@@ -8,7 +8,7 @@ typedef long ssize_t;
typedef int wchar_t;
typedef unsigned int wint_t;
#define NULL 0
#define NULL ((void *)0)
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

View File

@@ -1,7 +1,7 @@
#ifndef I386_STDINT_H
#define I386_STDINT_H
#if defined(__GNUC__)
#if defined(__GNUC__) && !defined(__ROMCC__)
#define __HAVE_LONG_LONG__ 1
#else
#define __HAVE_LONG_LONG__ 0

View File

@@ -1,8 +1,5 @@
#include <arch/asm.h>
#include <arch/intel.h>
#if CONFIG_SMP==1
#include <cpu/p6/apic.h>
#endif
.section ".text"
.code32
.globl _start
@@ -39,27 +36,10 @@ _start:
/* set new stack */
movl $_estack, %esp
#if CONFIG_SMP==1
/* Get the cpu id */
movl $APIC_DEFAULT_BASE, %edi
movl APIC_ID(%edi), %eax
shrl $24, %eax
/* Get the cpu index (CONFIG_MAX_CPUS on error) */
movl $-4, %ebx
1: addl $4, %ebx
cmpl $(CONFIG_MAX_CPUS << 2), %ebx
je 2
cmpl %eax, initial_apicid(%ebx)
jne 1b
2: shrl $2, %ebx
/* Now compute the appropriate stack */
movl %ebx, %eax
movl $STACK_SIZE, %ebx
mull %ebx
subl %eax, %esp
#endif
/* Push the cpu index and struct cpu */
pushl $0
pushl $0
/* push the boot_complete flag */
pushl %ebp
@@ -74,7 +54,7 @@ _start:
*/
intel_chip_post_macro(0xfe) /* post fe */
/* Resort the stack location */
/* Restore the stack location */
movl %ebp, %esp
/* The boot_complete flag has already been pushed */

View File

@@ -118,21 +118,18 @@ static void print_spew_hex16(unsigned short value){ __console_tx_hex16(BIOS_SPEW
static void print_spew_hex32(unsigned int value) { __console_tx_hex32(BIOS_SPEW, value); }
static void print_spew(const char *str) { __console_tx_string(BIOS_SPEW, str); }
#define __STR(X) #X
#define STR(X) __STR(X)
#ifndef LINUXBIOS_EXTRA_VERSION
#define LINUXBIOS_EXTRA_VERSION
#define LINUXBIOS_EXTRA_VERSION ""
#endif
static void console_init(void)
{
static const char console_test[] =
"\r\n\r\nLinuxBIOS-"
STR(LINUXBIOS_VERSION)
STR(LINUXBIOS_EXTRA_VERSION)
LINUXBIOS_VERSION
LINUXBIOS_EXTRA_VERSION
" "
STR(LINUXBIOS_BUILD)
LINUXBIOS_BUILD
" starting...\r\n";
print_info(console_test);
}

View File

@@ -2,11 +2,8 @@
jmp console0
#define __STR(X) #X
#define STR(X) __STR(X)
#ifndef LINUXBIOS_EXTRA_VERSION
#define LINUXBIOS_EXTRA_VERSION
#define LINUXBIOS_EXTRA_VERSION ""
#endif
#ifndef ASM_CONSOLE_LOGLEVEL
@@ -14,13 +11,12 @@ jmp console0
#endif
console_test:
.ascii "\r\n\r\nLinuxBIOS-"
.ascii STR(LINUXBIOS_VERSION)
.ascii STR(LINUXBIOS_EXTRA_VERSION)
.ascii LINUXBIOS_VERSION
.ascii LINUXBIOS_EXTRA_VERSION
.ascii " "
.ascii STR(LINUXBIOS_BUILD)
.ascii LINUXBIOS_BUILD
.asciz " starting...\r\n"
#undef STR
/* uses: ax, dx */
#if CONFIG_CONSOLE_SERIAL8250
#define __CONSOLE_INLINE_TX_AL TTYS0_TX_AL

View File

@@ -1,147 +1,252 @@
#include <console/console.h>
#include <cpu/cpu.h>
#include <mem.h>
#include <arch/io.h>
#include <string.h>
#include <cpu/cpufixup.h>
#include <smp/start_stop.h>
#include <cpu/cpufixup.h>
#include <cpu/p6/mtrr.h>
#include <cpu/p6/msr.h>
#include <cpu/p6/apic.h>
#include <cpu/p5/cpuid.h>
#include <arch/smp/lapic.h>
#if 0
#include <cpu/l2_cache.h>
#endif
#include <cpu/x86/mtrr.h>
#include <cpu/x86/msr.h>
#include <cpu/x86/lapic.h>
#include <arch/cpu.h>
#include <device/path.h>
#include <device/device.h>
#include <smp/spinlock.h>
#if CONFIG_SMP || CONFIG_IOAPIC
#define APIC 1
#endif
static void cache_on(struct mem_range *mem)
/* Standard macro to see if a specific flag is changeable */
static inline int flag_is_changeable_p(uint32_t flag)
{
post_code(0x60);
printk_info("Enabling cache...");
uint32_t f1, f2;
/* we need an #ifdef i586 here at some point ... */
__asm__ __volatile__("mov %cr0, %eax\n\t"
"and $0x9fffffff,%eax\n\t"
"mov %eax, %cr0\n\t");
/* turns out cache isn't really on until you set MTRR registers on
* 686 and later.
* NOTHING FANCY. Linux does a much better job anyway.
* so absolute minimum needed to get it going.
*/
/* OK, linux it turns out does nothing. We have to do it ... */
#if i686==1
// totalram here is in linux sizing, i.e. units of KB.
// set_mtrr is responsible for getting it into the right units!
setup_mtrrs(mem);
#endif
post_code(0x6A);
printk_info("done.\n");
asm(
"pushfl\n\t"
"pushfl\n\t"
"popl %0\n\t"
"movl %0,%1\n\t"
"xorl %2,%0\n\t"
"pushl %0\n\t"
"popfl\n\t"
"pushfl\n\t"
"popl %0\n\t"
"popfl\n\t"
: "=&r" (f1), "=&r" (f2)
: "ir" (flag));
return ((f1^f2) & flag) != 0;
}
static void interrupts_on()
/* Probe for the CPUID instruction */
static int have_cpuid_p(void)
{
/* this is so interrupts work. This is very limited scope --
* linux will do better later, we hope ...
*/
/* this is the first way we learned to do it. It fails on real SMP
* stuff. So we have to do things differently ...
* see the Intel mp1.4 spec, page A-3
*/
#if defined(APIC)
/* Only Pentium Pro and later have those MSR stuff */
msr_t msr;
printk_info("Setting up local apic...");
/* Enable the local apic */
msr = rdmsr(APIC_BASE_MSR);
msr.lo |= APIC_BASE_MSR_ENABLE;
msr.lo &= ~APIC_BASE_MSR_ADDR_MASK;
msr.lo |= APIC_DEFAULT_BASE;
wrmsr(APIC_BASE_MSR, msr);
/*
* Set Task Priority to 'accept all'.
*/
apic_write_around(APIC_TASKPRI,
apic_read_around(APIC_TASKPRI) & ~APIC_TPRI_MASK);
/* Put the local apic in virtual wire mode */
apic_write_around(APIC_SPIV,
(apic_read_around(APIC_SPIV) & ~(APIC_VECTOR_MASK))
| APIC_SPIV_ENABLE);
apic_write_around(APIC_LVT0,
(apic_read_around(APIC_LVT0) &
~(APIC_LVT_MASKED | APIC_LVT_LEVEL_TRIGGER |
APIC_LVT_REMOTE_IRR | APIC_INPUT_POLARITY |
APIC_SEND_PENDING |APIC_LVT_RESERVED_1 |
APIC_DELIVERY_MODE_MASK))
| (APIC_LVT_REMOTE_IRR |APIC_SEND_PENDING |
APIC_DELIVERY_MODE_EXTINT)
);
apic_write_around(APIC_LVT1,
(apic_read_around(APIC_LVT1) &
~(APIC_LVT_MASKED | APIC_LVT_LEVEL_TRIGGER |
APIC_LVT_REMOTE_IRR | APIC_INPUT_POLARITY |
APIC_SEND_PENDING |APIC_LVT_RESERVED_1 |
APIC_DELIVERY_MODE_MASK))
| (APIC_LVT_REMOTE_IRR |APIC_SEND_PENDING |
APIC_DELIVERY_MODE_NMI)
);
printk_debug(" apic_id: %d ", lapicid());
#else /* APIC */
#if i686==1
/* Only Pentium Pro and later have those MSR stuff */
msr_t msr;
printk_info("Disabling local apic...");
msr = rdmsr(APIC_BASE_MSR);
msr.lo &= ~APIC_BASE_MSR_ENABLE;
wrmsr(APIC_BASE_MSR, msr);
#endif /* i686 */
#endif /* APIC */
printk_info("done.\n");
post_code(0x9b);
return flag_is_changeable_p(X86_EFLAGS_ID);
}
unsigned long cpu_initialize(struct mem_range *mem)
/*
* Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected
* by the fact that they preserve the flags across the division of 5/2.
* PII and PPro exhibit this behavior too, but they have cpuid available.
*/
/*
* Perform the Cyrix 5/2 test. A Cyrix won't change
* the flags, while other 486 chips will.
*/
static inline int test_cyrix_52div(void)
{
unsigned int test;
__asm__ __volatile__(
"sahf\n\t" /* clear flags (%eax = 0x0005) */
"div %b2\n\t" /* divide 5 by 2 */
"lahf" /* store flags into %ah */
: "=a" (test)
: "0" (5), "q" (2)
: "cc");
/* AH is 0x02 on Cyrix after the divide.. */
return (unsigned char) (test >> 8) == 0x02;
}
/*
* Detect a NexGen CPU running without BIOS hypercode new enough
* to have CPUID. (Thanks to Herbert Oppmann)
*/
static int deep_magic_nexgen_probe(void)
{
int ret;
__asm__ __volatile__ (
" movw $0x5555, %%ax\n"
" xorw %%dx,%%dx\n"
" movw $2, %%cx\n"
" divw %%cx\n"
" movl $0, %%eax\n"
" jnz 1f\n"
" movl $1, %%eax\n"
"1:\n"
: "=a" (ret) : : "cx", "dx" );
return ret;
}
/* List of cpu vendor strings along with their normalized
* id values.
*/
static struct {
int vendor;
const char *name;
} x86_vendors[] = {
{ X86_VENDOR_INTEL, "GenuineIntel", },
{ X86_VENDOR_CYRIX, "CyrixInstead", },
{ X86_VENDOR_AMD, "AuthenticAMD", },
{ X86_VENDOR_UMC, "UMC UMC UMC ", },
{ X86_VENDOR_NEXGEN, "NexGenDriven", },
{ X86_VENDOR_CENTAUR, "CentaurHauls", },
{ X86_VENDOR_RISE, "RiseRiseRise", },
{ X86_VENDOR_TRANSMETA, "GenuineTMx86", },
{ X86_VENDOR_TRANSMETA, "TransmetaCPU", },
{ X86_VENDOR_NSC, "Geode by NSC", },
{ X86_VENDOR_SIS, "SiS SiS SiS ", },
};
static const char *x86_vendor_name[] = {
[X86_VENDOR_INTEL] = "Intel",
[X86_VENDOR_CYRIX] = "Cyrix",
[X86_VENDOR_AMD] = "AMD",
[X86_VENDOR_UMC] = "UMC",
[X86_VENDOR_NEXGEN] = "NexGen",
[X86_VENDOR_CENTAUR] = "Centaur",
[X86_VENDOR_RISE] = "Rise",
[X86_VENDOR_TRANSMETA] = "Transmeta",
[X86_VENDOR_NSC] = "NSC",
[X86_VENDOR_SIS] = "SiS",
};
static const char *cpu_vendor_name(int vendor)
{
const char *name;
name = "<invalid cpu vendor>";
if ((vendor < (sizeof(x86_vendor_name)/sizeof(x86_vendor_name[0]))) &&
(x86_vendor_name[vendor] != 0))
{
name = x86_vendor_name[vendor];
}
return name;
}
static void identify_cpu(struct device *cpu)
{
char vendor_name[16];
int cpuid_level;
int i;
vendor_name[0] = '\0'; /* Unset */
cpuid_level = -1; /* Maximum supported CPUID level, -1=no CPUID */
/* Find the id and vendor_name */
if (!have_cpuid_p()) {
/* Its a 486 if we can modify the AC flag */
if (flag_is_changeable_p(X86_EFLAGS_AC)) {
cpu->device = 0x00000400; /* 486 */
} else {
cpu->device = 0x00000300; /* 386 */
}
if ((cpu->device == 0x00000400) && test_cyrix_52div()) {
memcpy(vendor_name, "CyrixInstead", 13);
/* If we ever care we can enable cpuid here */
}
/* Detect NexGen with old hypercode */
else if (deep_magic_nexgen_probe()) {
memcpy(vendor_name, "NexGenDriven", 13);
}
}
if (have_cpuid_p()) {
struct cpuid_result result;
result = cpuid(0x00000000);
cpuid_level = result.eax;
vendor_name[ 0] = (result.ebx >> 0) & 0xff;
vendor_name[ 1] = (result.ebx >> 8) & 0xff;
vendor_name[ 2] = (result.ebx >> 16) & 0xff;
vendor_name[ 3] = (result.ebx >> 24) & 0xff;
vendor_name[ 4] = (result.edx >> 0) & 0xff;
vendor_name[ 5] = (result.edx >> 8) & 0xff;
vendor_name[ 6] = (result.edx >> 16) & 0xff;
vendor_name[ 7] = (result.edx >> 24) & 0xff;
vendor_name[ 8] = (result.ecx >> 0) & 0xff;
vendor_name[ 9] = (result.ecx >> 8) & 0xff;
vendor_name[10] = (result.ecx >> 16) & 0xff;
vendor_name[11] = (result.ecx >> 24) & 0xff;
vendor_name[12] = '\0';
/* Intel-defined flags: level 0x00000001 */
if (cpuid_level >= 0x00000001) {
cpu->device = cpuid_eax(0x00000001);
}
else {
/* Have CPUID level 0 only unheard of */
cpu->device = 0x00000400;
}
}
cpu->vendor = X86_VENDOR_UNKNOWN;
for(i = 0; i < sizeof(x86_vendors)/sizeof(x86_vendors[0]); i++) {
if (memcmp(vendor_name, x86_vendors[i].name, 12) == 0) {
cpu->vendor = x86_vendors[i].vendor;
break;
}
}
}
static void set_cpu_ops(struct device *cpu)
{
struct cpu_driver *driver;
cpu->ops = 0;
for (driver = cpu_drivers; driver < ecpu_drivers; driver++) {
struct cpu_device_id *id;
for(id = driver->id_table; id->vendor != X86_VENDOR_INVALID; id++) {
if ((cpu->vendor == id->vendor) &&
(cpu->device == id->device))
{
goto found;
}
}
}
die("Unknown cpu");
return;
found:
cpu->ops = driver->ops;
}
void cpu_initialize(void)
{
/* Because we busy wait at the printk spinlock.
* It is important to keep the number of printed messages
* from secondary cpus to a minimum, when debugging is
* disabled.
*/
unsigned long processor_id = this_processors_id();
printk_notice("Initializing CPU #%d\n", processor_id);
struct device *cpu;
struct cpu_info *info;
info = cpu_info();
/* Turn on caching if we haven't already */
cache_on(mem);
#if i586==1
display_cpuid();
#endif
#if i686==1
mtrr_check();
#endif
printk_notice("Initializing CPU #%d\n", info->index);
/* some cpus need a fixup done. This is the hook for doing that. */
cpufixup(mem);
cpu = info->cpu;
if (!cpu) {
die("CPU: missing cpu device structure");
}
interrupts_on();
/* Find what type of cpu we are dealing with */
identify_cpu(cpu);
printk_debug("CPU: vendor %s device %x\n",
cpu_vendor_name(cpu->vendor), cpu->device);
/* Lookup the cpu's operations */
set_cpu_ops(cpu);
processor_id = this_processors_id();
printk_info("CPU #%d Initialized\n", processor_id);
return processor_id;
/* Initialize the cpu */
if (cpu->ops && cpu->ops->init) {
cpu->enabled = 1;
cpu->initialized = 1;
cpu->ops->init(cpu);
}
printk_info("CPU #%d Initialized\n", info->index);
return;
}

View File

@@ -1,21 +1,16 @@
.section ".id", "a", @progbits
#define __STR(X) #X
#define STR(X) __STR(X)
.section ".id", "a", @progbits
.globl __id_start
__id_start:
vendor:
.asciz STR(MAINBOARD_VENDOR)
.asciz MAINBOARD_VENDOR
part:
.asciz STR(MAINBOARD_PART_NUMBER)
.asciz MAINBOARD_PART_NUMBER
.long __id_end + 0x10 - vendor /* Reverse offset to the vendor id */
.long __id_end + 0x10 - part /* Reverse offset to the part number */
.long PAYLOAD_SIZE + ROM_IMAGE_SIZE /* Size of this romimage */
.globl __id_end
#undef __STR
#undef STR
__id_end:
.previous

View File

@@ -1,12 +1,8 @@
uses HAVE_MP_TABLE
uses CONFIG_SMP
if HAVE_MP_TABLE
object mpspec.o
end
#object ioapic.o CONFIG_IOAPIC
if CONFIG_SMP
object start_stop.o
object secondary.S
end

View File

@@ -1,10 +1,9 @@
#include <console/console.h>
#include <cpu/cpu.h>
#include <smp/start_stop.h>
#include <arch/smp/mpspec.h>
#include <string.h>
#include <cpu/p5/cpuid.h>
#include <cpu/p6/apic.h>
#include <arch/cpu.h>
#include <cpu/x86/lapic.h>
unsigned char smp_compute_checksum(void *v, int len)
{
@@ -94,30 +93,33 @@ void smp_write_processor(struct mp_config_table *mc,
* 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,
unsigned long *processor_map)
void smp_write_processors(struct mp_config_table *mc)
{
int i;
int processor_id;
int boot_apic_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 < CONFIG_MAX_CPUS; i++) {
unsigned long cpu_apicid = initial_apicid[i];
struct cpuid_result result;
device_t cpu;
boot_apic_id = lapicid();
apic_version = lapic_read(LAPIC_LVR) & 0xff;
result = cpuid(1);
cpu_features = result.eax;
cpu_feature_flags = result.edx;
for(cpu = dev_root.link[1].children; cpu; cpu = cpu->sibling) {
unsigned long cpu_flag;
if(initial_apicid[i]==-1)
if (cpu->path.type != DEVICE_PATH_APIC) {
continue;
cpu_flag = MPC_CPU_ENABLED;
if (processor_map[i] & CPU_BOOTPROCESSOR) {
cpu_flag |= MPC_CPU_BOOTPROCESSOR;
}
smp_write_processor(mc, cpu_apicid, apic_version,
if (!cpu->enabled) {
continue;
}
cpu_flag = MPC_CPU_ENABLED;
if (boot_apic_id == cpu->path.u.apic.apic_id) {
cpu_flag = MPC_CPU_ENABLED;
}
smp_write_processor(mc,
cpu->path.u.apic.apic_id, apic_version,
cpu_flag, cpu_features, cpu_feature_flags
);
}
@@ -136,8 +138,8 @@ void smp_write_bus(struct mp_config_table *mc,
}
void smp_write_ioapic(struct mp_config_table *mc,
unsigned char id, unsigned char ver,
unsigned long apicaddr)
unsigned char id, unsigned char ver,
unsigned long apicaddr)
{
struct mpc_config_ioapic *mpc;
mpc = smp_next_mpc_entry(mc);

View File

@@ -1,76 +0,0 @@
#include <arch/asm.h>
#include <arch/intel.h>
#include <cpu/p6/mtrr.h>
#include <cpu/p6/apic.h>
.text
.globl _secondary_start
.balign 4096
_secondary_start:
.code16
cli
xorl %eax, %eax
movl %eax, %cr3 /* Invalidate TLB*/
/* On hyper threaded cpus invalidating the cache here is
* very very bad. Don't.
*/
/* setup the data segment */
movw %cs, %ax
movw %ax, %ds
data32 lgdt gdtaddr - _secondary_start
movl %cr0, %eax
andl $0x7FFAFFD1, %eax /* PG,AM,WP,NE,TS,EM,MP = 0 */
orl $0x60000001, %eax /* CD, NW, PE = 1 */
movl %eax, %cr0
ljmpl $0x10, $1f
1:
.code32
movw $0x18, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %ss
movw %ax, %fs
movw %ax, %gs
/* Enable the local apic, and map it where we expext it */
movl $APIC_BASE_MSR, %ecx
rdmsr
orl $APIC_BASE_MSR_ENABLE, %eax
andl $(~APIC_BASE_MSR_ADDR_MASK), %eax
orl $APIC_DEFAULT_BASE, %eax
wrmsr
/* Get the apic_id */
movl (APIC_ID + APIC_DEFAULT_BASE), %edi
shrl $24, %edi
/* Get the cpu index (CONFIG_MAX_CPUS on error) */
movl $-4, %ebx
1: addl $4, %ebx
cmpl $(CONFIG_MAX_CPUS << 2), %ebx
je 2
cmpl %edi, initial_apicid(%ebx)
jne 1b
2: shrl $2, %ebx
/* set the stack pointer */
movl $_estack, %esp
movl %ebx, %eax
movl $STACK_SIZE, %ebx
mull %ebx
subl %eax, %esp
call secondary_cpu_init
1: hlt
jmp 1b
gdtaddr:
.word gdt_limit /* the table limit */
.long gdt /* we know the offset */
.code32

View File

@@ -1,240 +0,0 @@
#include <smp/start_stop.h>
#include <arch/smp/mpspec.h>
#include <cpu/p6/apic.h>
#include <delay.h>
#include <string.h>
#include <console/console.h>
#include <arch/smp/lapic.h>
#include <arch/hlt.h>
unsigned long this_processors_id(void)
{
return lapicid();
}
int processor_index(unsigned long apicid)
{
int i;
for(i = 0; i < CONFIG_MAX_CPUS; i++) {
if (initial_apicid[i] == apicid) {
return i;
}
}
return -1;
}
void stop_cpu(unsigned long 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_err("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_err("timed out\n");
}
while(1) {
hlt();
}
}
/* This is a lot more paranoid now, since Linux can NOT handle
* being told there is a CPU when none exists. So any errors
* will return 0, meaning no CPU.
*
* We actually handling that case by noting which cpus startup
* and not telling anyone about the ones that dont.
*/
int start_cpu(unsigned long apicid)
{
int timeout;
unsigned long send_status, accept_status, start_eip;
int j, num_starts, maxlvt;
extern char _secondary_start[];
/*
* 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_err("CPU %d: First apic write timed out. Disabling\n",
apicid);
// too bad.
printk_err("ESR is 0x%x\n", apic_read(APIC_ESR));
if (apic_read(APIC_ESR)) {
printk_err("Try to reset ESR\n");
apic_write_around(APIC_ESR, 0);
printk_err("ESR is 0x%x\n", apic_read(APIC_ESR));
}
return 0;
}
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_err("CPU %d: Second apic write timed out. Disabling\n",
apicid);
// too bad.
return 0;
}
start_eip = (unsigned long)_secondary_start;
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 to %u.\n", j, apicid);
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);
if (send_status || accept_status)
return 0;
return 1;
}
void startup_other_cpus(unsigned long *processor_map)
{
unsigned long apicid = this_processors_id();
int i;
/* Assume the cpus are densly packed by apicid */
for(i = 0; i < CONFIG_MAX_CPUS; i++) {
unsigned long cpu_apicid = initial_apicid[i];
if (cpu_apicid == -1) {
printk_err("CPU %d not found\n",i);
processor_map[i] = 0;
continue;
}
if (cpu_apicid == apicid ) {
continue;
}
if (!start_cpu(cpu_apicid)) {
/* Put an error in processor_map[i]? */
printk_err("CPU %d/%u would not start!\n",
i, cpu_apicid);
processor_map[i] = 0;
}
}
}

View File

@@ -218,7 +218,6 @@ struct lb_memory *get_lb_mem(void)
}
unsigned long write_linuxbios_table(
unsigned long *processor_map,
struct mem_range *ram,
unsigned long low_table_start, unsigned long low_table_end,
unsigned long rom_table_startk, unsigned long rom_table_endk)

View File

@@ -6,7 +6,7 @@
#include "linuxbios_table.h"
struct lb_memory *
write_tables(struct mem_range *mem, unsigned long *processor_map)
write_tables(struct mem_range *mem)
{
unsigned long low_table_start, low_table_end;
unsigned long rom_table_start, rom_table_end;
@@ -19,28 +19,10 @@ write_tables(struct mem_range *mem, unsigned long *processor_map)
low_table_start = 0;
low_table_end = 16;
#if 0
post_code(0x9a);
check_pirq_routing_table();
/* This table must be betweeen 0xf0000 & 0x100000 */
rom_table_end = copy_pirq_routing_table(rom_table_end);
rom_table_end = (rom_table_end + 1023) & ~1023;
/* copy the smp block to address 0 */
post_code(0x96);
/* The smp table must be in 0-1K, 639K-640K, or 960K-1M */
remove_logical_cpus();
low_table_end = write_smp_table(low_table_end, processor_map);
/* Don't write anything in the traditional x86 BIOS data segment */
if (low_table_end < 0x500) {
low_table_end = 0x500;
}
#endif
/* The linuxbios table must be in 0-4K or 960K-1M */
write_linuxbios_table(processor_map, mem,
low_table_start, low_table_end,
rom_table_start >> 10, rom_table_end >> 10);
write_linuxbios_table(mem,
low_table_start, low_table_end,
rom_table_start >> 10, rom_table_end >> 10);
return get_lb_mem();
}