Applied NewOS change 1914: moved APIC setup into the kernel due to a

problem with the APIC clock speed test.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6980 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2004-03-14 22:54:00 +00:00
parent 7ec81f4c11
commit 4a2e872cca
8 changed files with 129 additions and 93 deletions

View File

@ -18,8 +18,9 @@ struct kernel_args;
extern "C" {
#endif
int arch_smp_init(struct kernel_args *ka);
void arch_smp_send_ici(int target_cpu);
status_t arch_smp_init(struct kernel_args *args);
status_t arch_smp_per_cpu_init(struct kernel_args *args, int32 cpu);
void arch_smp_send_ici(int32 target_cpu);
void arch_smp_send_broadcast_ici(void);
#ifdef __cplusplus

View File

@ -5,11 +5,11 @@
#ifndef _KERNEL_ARCH_x86_SMP_PRIV_H
#define _KERNEL_ARCH_x86_SMP_PRIV_H
#include <ktypes.h>
#include <SupportDefs.h>
int i386_smp_interrupt(int vector);
void arch_smp_ack_interrupt(void);
int arch_smp_set_apic_timer(bigtime_t relative_timeout);
status_t arch_smp_set_apic_timer(bigtime_t relativeTimeout);
int arch_smp_clear_apic_timer(void);
#endif /* _KERNEL_ARCH_x86_SMP_PRIV_H */

View File

@ -26,7 +26,8 @@ enum {
SMP_MSG_FLAG_SYNC,
};
int smp_init(struct kernel_args *ka);
status_t smp_init(struct kernel_args *args);
status_t smp_per_cpu_init(struct kernel_args *args, int32 cpu);
int smp_trap_non_boot_cpus(struct kernel_args *ka, int cpu);
void smp_wake_up_all_non_boot_cpus(void);
void smp_wait_for_ap_cpus(struct kernel_args *ka);

View File

@ -259,56 +259,6 @@ smp_find_mp_config(kernel_args *ka)
}
static int
smp_setup_apic(kernel_args *ka)
{
uint32 config;
TRACE(("setting up the apic..."));
/* set spurious interrupt vector to 0xff */
config = apic_read(APIC_SIVR) & 0xfffffc00;
config |= APIC_ENABLE | 0xff;
apic_write(APIC_SIVR, config);
#if 1
/* setup LINT0 as ExtINT */
config = (apic_read(APIC_LINT0) & 0xffff1c00);
config |= APIC_LVT_DM_ExtINT | APIC_LVT_IIPP | APIC_LVT_TM;
apic_write(APIC_LINT0, config);
/* setup LINT1 as NMI */
config = (apic_read(APIC_LINT1) & 0xffff1c00);
config |= APIC_LVT_DM_NMI | APIC_LVT_IIPP;
apic_write(APIC_LINT1, config);
#endif
/* setup timer */
config = apic_read(APIC_LVTT) & ~APIC_LVTT_MASK;
config |= 0xfb | APIC_LVTT_M; // vector 0xfb, timer masked
apic_write(APIC_LVTT, config);
apic_write(APIC_ICRT, 0); // zero out the clock
config = apic_read(APIC_TDCR) & ~0x0000000f;
config |= APIC_TDCR_1; // clock division by 1
apic_write(APIC_TDCR, config);
/* setup error vector to 0xfe */
config = (apic_read(APIC_LVT3) & 0xffffff00) | 0xfe;
apic_write(APIC_LVT3, config);
/* accept all interrupts */
config = apic_read(APIC_TPRI) & 0xffffff00;
apic_write(APIC_TPRI, config);
config = apic_read(APIC_SIVR);
apic_write(APIC_EOI, 0);
TRACE((" done\n"));
return 0;
}
/** Target function of the trampoline code.
* The trampoline code should have the pgdir and a gdt set up for us,
* along with us being on the final stack for this processor. We need
@ -331,8 +281,6 @@ smp_cpu_ready(void)
asm("cld");
asm("fninit");
smp_setup_apic(ka);
// Set up the final idt
idt_descr.a = IDT_LIMIT - 1;
idt_descr.b = (uint32 *)ka->arch_args.vir_idt;
@ -537,9 +485,6 @@ smp_boot(kernel_args *ka, uint32 kernel_entry)
TRACE(("apic = %p\n", ka->arch_args.apic));
TRACE(("ioapic = %p\n", ka->arch_args.ioapic));
// set up the apic
smp_setup_apic(ka);
// calculate how fast the apic timer is
calculate_apic_timer_conversion_factor(ka);

View File

@ -3,12 +3,9 @@
** Distributed under the terms of the NewOS License.
*/
#include <boot/stage2.h>
#include <kernel.h>
#include <console.h>
#include <debug.h>
#include <OS.h>
#include <boot/kernel_args.h>
#include <vm.h>
#include <kernel.h>
#include <int.h>
#include <smp.h>
#include <smp_priv.h>
@ -25,10 +22,18 @@
#include <stdio.h>
//#define TRACE_ARCH_SMP
#ifdef TRACE_ARCH_SMP
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
static uint32 *apic = NULL;
static uint32 cpu_apic_id[SMP_MAX_CPUS] = {0, 0};
static uint32 cpu_os_id[SMP_MAX_CPUS] = {0, 0};
static uint32 cpu_apic_version[SMP_MAX_CPUS] = {0, 0};
static uint32 cpu_apic_id[B_MAX_CPU_COUNT] = {0, 0};
static uint32 cpu_os_id[B_MAX_CPU_COUNT] = {0, 0};
static uint32 cpu_apic_version[B_MAX_CPU_COUNT] = {0, 0};
static uint32 *ioapic = NULL;
static uint32 apic_timer_tics_per_sec = 0;
@ -68,7 +73,7 @@ static int32
i386_smp_error_interrupt(void *data)
{
// smp error interrupt
// dprintf("smp error interrupt on cpu %d\n", arch_smp_get_current_cpu());
TRACE(("smp error interrupt on cpu %d\n", arch_smp_get_current_cpu()));
arch_smp_ack_interrupt();
return B_HANDLED_INTERRUPT;
@ -90,10 +95,10 @@ apic_write(uint32 offset, uint32 data)
}
int
status_t
arch_smp_init(kernel_args *ka)
{
dprintf("arch_smp_init: entry\n");
TRACE(("arch_smp_init: entry\n"));
if (ka->num_cpus > 1) {
// setup some globals
@ -110,20 +115,84 @@ arch_smp_init(kernel_args *ka)
vm_create_anonymous_region(vm_get_kernel_aspace_id(), "ioapic", (void *)&ioapic,
REGION_ADDR_EXACT_ADDRESS, PAGE_SIZE, REGION_WIRING_WIRED_ALREADY, LOCK_RW|LOCK_KERNEL);
// set up the local apic on the boot cpu
arch_smp_per_cpu_init(ka, 0);
install_interrupt_handler(0xfb, &i386_timer_interrupt, NULL);
install_interrupt_handler(0xfd, &i386_ici_interrupt, NULL);
install_interrupt_handler(0xfe, &i386_smp_error_interrupt, NULL);
install_interrupt_handler(0xff, &i386_spurious_interrupt, NULL);
}
return B_OK;
}
static int
smp_setup_apic(kernel_args *ka)
{
uint32 config;
TRACE(("setting up the apic..."));
/* set spurious interrupt vector to 0xff */
config = apic_read(APIC_SIVR) & 0xfffffc00;
config |= APIC_ENABLE | 0xff;
apic_write(APIC_SIVR, config);
#if 0
/* setup LINT0 as ExtINT */
config = (apic_read(APIC_LINT0) & 0xffff1c00);
config |= APIC_LVT_DM_ExtINT | APIC_LVT_IIPP | APIC_LVT_TM;
apic_write(APIC_LINT0, config);
/* setup LINT1 as NMI */
config = (apic_read(APIC_LINT1) & 0xffff1c00);
config |= APIC_LVT_DM_NMI | APIC_LVT_IIPP;
apic_write(APIC_LINT1, config);
#endif
/* setup timer */
config = apic_read(APIC_LVTT) & ~APIC_LVTT_MASK;
config |= 0xfb | APIC_LVTT_M; // vector 0xfb, timer masked
apic_write(APIC_LVTT, config);
apic_write(APIC_ICRT, 0); // zero out the clock
config = apic_read(APIC_TDCR) & ~0x0000000f;
config |= APIC_TDCR_1; // clock division by 1
apic_write(APIC_TDCR, config);
/* setup error vector to 0xfe */
config = (apic_read(APIC_LVT3) & 0xffffff00) | 0xfe;
apic_write(APIC_LVT3, config);
/* accept all interrupts */
config = apic_read(APIC_TPRI) & 0xffffff00;
apic_write(APIC_TPRI, config);
config = apic_read(APIC_SIVR);
apic_write(APIC_EOI, 0);
TRACE((" done\n"));
return 0;
}
status_t
arch_smp_per_cpu_init(kernel_args *args, int32 cpu)
{
// set up the local apic on the current cpu
TRACE(("arch_smp_init_percpu: setting up the apic on cpu %ld\n", cpu));
smp_setup_apic(args);
return B_OK;
}
void
arch_smp_send_broadcast_ici(void)
{
uint32 config;
int state = disable_interrupts();
cpu_status state = disable_interrupts();
config = apic_read(APIC_ICR1) & APIC_ICR1_WRITE_MASK;
apic_write(APIC_ICR1, config | 0xfd | APIC_ICR1_DELMODE_FIXED | APIC_ICR1_DESTMODE_PHYS | APIC_ICR1_DEST_ALL_BUT_SELF);
@ -133,7 +202,7 @@ arch_smp_send_broadcast_ici(void)
void
arch_smp_send_ici(int target_cpu)
arch_smp_send_ici(int32 target_cpu)
{
uint32 config;
int state = disable_interrupts();
@ -156,21 +225,21 @@ arch_smp_ack_interrupt(void)
#define MIN_TIMEOUT 1000
int
arch_smp_set_apic_timer(bigtime_t relative_timeout)
status_t
arch_smp_set_apic_timer(bigtime_t relativeTimeout)
{
cpu_status state;
uint32 config;
uint32 ticks;
int state;
if (apic == NULL)
return -1;
return B_ERROR;
if (relative_timeout < MIN_TIMEOUT)
relative_timeout = MIN_TIMEOUT;
if (relativeTimeout < MIN_TIMEOUT)
relativeTimeout = MIN_TIMEOUT;
// calculation should be ok, since it's going to be 64-bit
ticks = ((relative_timeout * apic_timer_tics_per_sec) / 1000000);
ticks = ((relativeTimeout * apic_timer_tics_per_sec) / 1000000);
state = disable_interrupts();
@ -182,19 +251,22 @@ arch_smp_set_apic_timer(bigtime_t relative_timeout)
config = apic_read(APIC_LVTT) & ~APIC_LVTT_M; // unmask the timer
apic_write(APIC_LVTT, config);
TRACE(("arch_smp_set_apic_timer: config 0x%x, timeout %Ld, tics/sec %d, tics %d\n",
config, relative_timeout, apic_timer_tics_per_sec, ticks));
apic_write(APIC_ICRT, ticks); // start it up
restore_interrupts(state);
return 0;
return B_OK;
}
int
arch_smp_clear_apic_timer(void)
{
cpu_status state;
uint32 config;
int state;
if (apic == NULL)
return -1;

View File

@ -39,13 +39,16 @@ set_isa_hardware_timer(long long relative_timeout)
out8(0x30, 0x43);
out8(next_event_clocks & 0xff, 0x40);
out8((next_event_clocks >> 8) & 0xff, 0x40);
arch_int_enable_io_interrupt(0);
}
static void
clear_isa_hardware_timer(void)
{
// XXX do something here
// mask out the timer
arch_int_disable_io_interrupt(0);
}
@ -86,6 +89,8 @@ arch_init_timer(kernel_args *ka)
dprintf("arch_init_timer: entry\n");
install_io_interrupt_handler(0, &isa_timer_interrupt, NULL, 0);
clear_isa_hardware_timer();
// apic timer interrupt set up by smp code
return 0;

View File

@ -1,6 +1,9 @@
/* This is main - initializes processors and starts init */
/*
** Copyright 2002-2004, The OpenBeOS Team. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
**
** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
** Distributed under the terms of the NewOS License.
*/
@ -34,8 +37,8 @@
#include <string.h>
#define TRACE_BOOT 1
#if TRACE_BOOT
#define TRACE_BOOT
#ifdef TRACE_BOOT
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
@ -91,9 +94,9 @@ _start(kernel_args *oldka, int cpu_num)
sem_init(&ka);
dprintf("##################################################################\n");
dprintf("semaphores now available\n");
dprintf("##################################################################\n");
TRACE(("##################################################################\n"));
TRACE(("semaphores now available\n"));
TRACE(("##################################################################\n"));
// now we can create and use semaphores
vm_init_postsem(&ka);
@ -118,16 +121,18 @@ _start(kernel_args *oldka, int cpu_num)
start_scheduler();
} else {
// this is run per cpu for each AP processor after they've been set loose
smp_per_cpu_init(&ka, cpu_num);
thread_init_percpu(cpu_num);
}
dprintf("##################################################################\n");
dprintf("interrupts now enabled\n");
dprintf("##################################################################\n");
TRACE(("##################################################################\n"));
TRACE(("interrupts now enabled\n"));
TRACE(("##################################################################\n"));
kernel_startup = false;
enable_interrupts();
TRACE(("main: done... begin idle loop on cpu %d\n", cpu_num));
for(;;)
for (;;)
arch_cpu_idle();
return 0;

View File

@ -524,7 +524,7 @@ smp_wait_for_ap_cpus(kernel_args *ka)
}
int
status_t
smp_init(kernel_args *ka)
{
struct smp_msg *msg;
@ -554,6 +554,13 @@ smp_init(kernel_args *ka)
}
status_t
smp_per_cpu_init(kernel_args *args, int32 cpu)
{
return arch_smp_per_cpu_init(args, cpu);
}
void
smp_set_num_cpus(int num_cpus)
{