- 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:
@@ -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
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -9,7 +9,7 @@ static void hlt(void)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#if defined(__GNUC__) && !defined(__ROMCC__)
|
||||
static inline void hlt(void)
|
||||
{
|
||||
asm("hlt");
|
||||
|
@@ -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);
|
||||
|
@@ -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 */
|
@@ -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
|
||||
|
||||
|
@@ -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 */
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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 */
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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)
|
||||
|
@@ -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();
|
||||
}
|
||||
|
Reference in New Issue
Block a user