- add APIC support for the SCC
- seems to work, only the APIC timer doesn't work! git-svn-id: http://svn.lfbs.rwth-aachen.de/svn/scc/trunk/MetalSVM@273 315a16e6-25f9-4109-90ae-ca3045a26c18
This commit is contained in:
parent
1cfc42c5a6
commit
bc67c946af
7 changed files with 155 additions and 45 deletions
|
@ -87,6 +87,8 @@ typedef struct {
|
|||
|
||||
typedef struct {
|
||||
uint32_t pid;
|
||||
uint32_t tile_frequency; // in MHz
|
||||
uint32_t router_frequency; // in MHz
|
||||
mem_region_t private_mem[SCC_PMEM_REGIONS];
|
||||
} scc_info_t;
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
#define APIC_TPR 0x0080 // Task Priority Regster
|
||||
#define APIC_EOI 0x00B0 // EOI Register
|
||||
#define APIC_SVR 0x00F0 // Spurious Interrupt Vector Register
|
||||
#define APIC_LVT_T 0x0320 // LVT Thermal Sensor Register (P4/Xeon only)
|
||||
#define APIC_LVT_T 0x0320 // LVT Timer Register
|
||||
#define APIC_LVT_PMC 0x0340 // LVT Performance Monitoring Counters Register
|
||||
#define APIC_LINT0 0x0350 // LVT LINT0 Register
|
||||
#define APIC_LINT1 0x0360 // LVT LINT1 Register
|
||||
|
@ -45,8 +45,14 @@
|
|||
|
||||
static apic_mp_t* apic_mp = NULL;
|
||||
static apic_config_table_t* apic_config = NULL;
|
||||
static uint32_t lapic = 0;
|
||||
static uint32_t ncores = 1;
|
||||
|
||||
static inline void apic_write(uint32_t addr, uint32_t value)
|
||||
{
|
||||
asm volatile ("movl (%%eax), %%edx; movl %%ebx, (%%eax)" :: "a"(addr), "b"(value) : "%edx");
|
||||
}
|
||||
|
||||
#ifndef CONFIG_MULTIBOOT
|
||||
static unsigned int* search_apic(unsigned int base, unsigned int limit) {
|
||||
unsigned int *ptr;
|
||||
|
@ -65,7 +71,8 @@ static unsigned int* search_apic(unsigned int base, unsigned int limit) {
|
|||
*/
|
||||
void apic_eoi(void)
|
||||
{
|
||||
*((uint32_t*) (apic_config->lapic+APIC_EOI)) = 0;
|
||||
if (lapic)
|
||||
apic_write(lapic+APIC_EOI, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -74,6 +81,7 @@ void apic_eoi(void)
|
|||
*/
|
||||
int apic_calibration(void)
|
||||
{
|
||||
#ifndef CONFIG_ROCKCREEK
|
||||
uint64_t ticks, old;
|
||||
uint32_t diff;
|
||||
|
||||
|
@ -86,23 +94,55 @@ int apic_calibration(void)
|
|||
while((ticks = get_clock_tick()) - old == 0)
|
||||
;
|
||||
|
||||
*((uint32_t*) (apic_config->lapic+APIC_DCR)) = 0xB; // set it to 1 clock increments
|
||||
*((uint32_t*) (apic_config->lapic+APIC_LVT_T)) = 0x20030; // connects the timer to 48 and enables it
|
||||
*((uint32_t*) (apic_config->lapic+APIC_ICR)) = 0xFFFFFFFF;
|
||||
apic_write(lapic+APIC_DCR, 0xB); // set it to 1 clock increments
|
||||
apic_write(lapic+APIC_LVT_T, 0x20030); // connects the timer to 48 and enables it
|
||||
apic_write(lapic+APIC_ICR), 0xFFFFFFFF);
|
||||
|
||||
/* wait 3 time slices to determine a ICR */
|
||||
while(get_clock_tick() - ticks < 3)
|
||||
;
|
||||
|
||||
diff = 0xFFFFFFFF - *((uint32_t*) (apic_config->lapic+APIC_CCR));
|
||||
diff = 0xFFFFFFFF - *((uint32_t*) (lapic+APIC_CCR));
|
||||
|
||||
*((uint32_t*) (apic_config->lapic+APIC_DCR)) = 0xB; // set it to 1 clock increments
|
||||
*((uint32_t*) (apic_config->lapic+APIC_LVT_T)) = 0x20030; // connects the timer to 48 and enables it
|
||||
*((uint32_t*) (apic_config->lapic+APIC_ICR)) = diff / 3;
|
||||
apic_write(lapic+APIC_DCR, 0xB); // set it to 1 clock increments
|
||||
apic_write(lapic+APIC_LVT_T, 0x20030); // connects the timer to 48 and enables it
|
||||
apic_write(lapic+APIC_ICR, diff / 3);
|
||||
|
||||
// Now, MetalSVM is able to use the APIC => Therefore, we disable the PIC
|
||||
outportb(0xA1, 0xFF);
|
||||
outportb(0x21, 0xFF);
|
||||
#else
|
||||
/*
|
||||
* On the SCC, we already know the processor frequency
|
||||
* and possess no PIC timer. Therfore, we use the rdtsc to
|
||||
* to calibrate the APIC timer.
|
||||
*/
|
||||
uint64_t start, end, ticks;
|
||||
uint32_t diff;
|
||||
|
||||
if (!has_apic())
|
||||
return -ENXIO;
|
||||
|
||||
apic_write(lapic+APIC_DCR, 0xB); // set it to 1 clock increments
|
||||
apic_write(lapic+APIC_LVT_T, 0x20030); // connects the timer to 48 and enables it
|
||||
apic_write(lapic+APIC_ICR, 0xFFFFFFFF);
|
||||
|
||||
/* wait 3 time slices to determine a ICR */
|
||||
start = rdtsc();
|
||||
do {
|
||||
flush_pipeline();
|
||||
end = rdtsc();
|
||||
ticks = end > start ? end - start : start - end;
|
||||
} while(ticks < 3*scc_info.tile_frequency*1000000 / TIMER_FREQ);
|
||||
|
||||
diff = 0xFFFFFFFF - *((uint32_t*) (lapic+APIC_CCR));
|
||||
|
||||
apic_write(lapic+APIC_DCR, 0xB); // set it to 1 clock increments
|
||||
apic_write(lapic+APIC_LVT_T, 0x20030); // connects the timer to 48 and enables it
|
||||
apic_write(lapic+APIC_ICR, diff / 3);
|
||||
#endif
|
||||
|
||||
kprintf("APIC calibration detects an ICR of 0x%x\n", diff / 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -110,7 +150,7 @@ int apic_calibration(void)
|
|||
static int apic_probe(void)
|
||||
{
|
||||
size_t addr;
|
||||
uint32_t i, count, dummy;
|
||||
uint32_t i, count;
|
||||
|
||||
// searching MP signature in the reserved memory areas
|
||||
#ifdef CONFIG_MULTIBOOT
|
||||
|
@ -133,28 +173,28 @@ static int apic_probe(void)
|
|||
mmap++;
|
||||
}
|
||||
}
|
||||
found_mp:
|
||||
#else
|
||||
apic_mp = (apic_mp_t*) search_apic(0xF0000, 0x100000);
|
||||
if (!apic_mp)
|
||||
apic_mp = (apic_mp_t*) search_apic(0x9F000, 0xA0000);
|
||||
#endif
|
||||
found_mp:
|
||||
|
||||
if (!apic_mp)
|
||||
goto out;
|
||||
goto no_mp;
|
||||
|
||||
kprintf("System uses Multiprocessing Specification 1.%d\n", apic_mp->version);
|
||||
kprintf("MP features 1: %d\n", apic_mp->features[0]);
|
||||
|
||||
if (apic_mp->features[0]) {
|
||||
kputs("Currently, MetalSVM supports only multiprocessing via the MP config tables!\n");
|
||||
goto out;
|
||||
goto no_mp;
|
||||
}
|
||||
|
||||
apic_config = (apic_config_table_t*) apic_mp->mp_config;
|
||||
if (!apic_config || strncmp((void*) &apic_config->signature, "PCMP", 4) !=0) {
|
||||
kputs("Invalid MP config table\n");
|
||||
goto out;
|
||||
goto no_mp;
|
||||
}
|
||||
|
||||
addr = (size_t) apic_config;
|
||||
|
@ -172,34 +212,45 @@ found_mp:
|
|||
|
||||
if (count > MAX_CORES) {
|
||||
kputs("Found too many cores! Increase the macro MAX_CORES!\n");
|
||||
goto out;
|
||||
goto no_mp;
|
||||
}
|
||||
ncores = count;
|
||||
|
||||
i = *((uint32_t*) (apic_config->lapic+APIC_VERSION));
|
||||
kprintf("Found APIC at 0x%x\n", apic_config->lapic);
|
||||
check_lapic:
|
||||
if (apic_config) {
|
||||
lapic = apic_config->lapic;
|
||||
} else {
|
||||
uint32_t eax, edx, dummy;
|
||||
|
||||
cpuid(0x1, &eax, &dummy, &dummy, &edx);
|
||||
if (edx & (1 << 9))
|
||||
lapic = 0xFEE00000;
|
||||
|
||||
kprintf("Processor familiy %u, model %u, stepping %u\n", (eax>>8)&0xF, (eax>>4)&0xF, eax&0xF);
|
||||
}
|
||||
|
||||
if (!lapic)
|
||||
goto out;
|
||||
|
||||
i = *((uint32_t*) (lapic+APIC_VERSION));
|
||||
kprintf("Found APIC at 0x%x\n", lapic);
|
||||
kprintf("Maximum LVT Entry: 0x%x\n", (i >> 16) & 0xFF);
|
||||
kprintf("APIC Version: 0x%x\n", i & 0xFF);
|
||||
|
||||
cpuid(0x1, &i, &dummy, &dummy, &dummy);
|
||||
if (!(i & (1 << 5))) {
|
||||
kputs("Unable to use Machine-Specific Registers (MSR)\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(rdmsr(0x1B) & (1 << 11))) {
|
||||
kputs("Unable to use APIC Global Enable flag!\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
apic_mp = NULL;
|
||||
apic_config = NULL;
|
||||
lapic = 0;
|
||||
ncores = 1;
|
||||
|
||||
return -ENXIO;
|
||||
|
||||
no_mp:
|
||||
apic_mp = NULL;
|
||||
apic_config = NULL;
|
||||
ncores = 1;
|
||||
goto check_lapic;
|
||||
}
|
||||
|
||||
int apic_init(void)
|
||||
|
@ -210,18 +261,18 @@ int apic_init(void)
|
|||
if (!ret)
|
||||
return ret;
|
||||
|
||||
*((uint32_t*) (apic_config->lapic+APIC_TPR)) = 0x20; // inhibit softint delivery
|
||||
*((uint32_t*) (apic_config->lapic+APIC_LVT_T)) = 0x10000; // disable timer interrupt
|
||||
*((uint32_t*) (apic_config->lapic+APIC_LVT_PMC)) = 0x10000; // disable performance counter interrupt
|
||||
*((uint32_t*) (apic_config->lapic+APIC_LINT0)) = 0x31; // connect LINT0 to idt entry 49
|
||||
*((uint32_t*) (apic_config->lapic+APIC_LINT1)) = 0x32; // connect LINT1 to idt entry 50
|
||||
*((uint32_t*) (apic_config->lapic+APIC_LVT_ER)) = 0x33; // connect error to idt entry 51
|
||||
*((uint32_t*) (apic_config->lapic+APIC_SVR)) = 0x134; // enable the apic and connect to the idt entry 52
|
||||
apic_write(lapic+APIC_TPR, 0x00); // allow all interrupts
|
||||
apic_write(lapic+APIC_LVT_T, 0x10000); // disable timer interrupt
|
||||
apic_write(lapic+APIC_LVT_PMC, 0x10000);// disable performance counter interrupt
|
||||
apic_write(lapic+APIC_LINT0, 0x31); // connect LINT0 to idt entry 49
|
||||
apic_write(lapic+APIC_LINT1, 0x32); // connect LINT1 to idt entry 50
|
||||
apic_write(lapic+APIC_LVT_ER, 0x33); // connect error to idt entry 51
|
||||
apic_write(lapic+APIC_SVR, 0x17F); // enable the apic and connect to the idt entry 207
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int has_apic(void)
|
||||
{
|
||||
return ((apic_mp != NULL) && (apic_config != NULL));
|
||||
return (lapic != 0);
|
||||
}
|
||||
|
|
|
@ -718,7 +718,7 @@ apic_svr:
|
|||
; Therefore, the interrupt flag (IF) is already cleared.
|
||||
; cli
|
||||
push byte 0
|
||||
push byte 52
|
||||
push byte 127
|
||||
jmp irq_common_stub
|
||||
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ extern void apic_lint1(void);
|
|||
extern void apic_error(void);
|
||||
extern void apic_svr(void);
|
||||
|
||||
#define MAX_HANDLERS 32
|
||||
#define MAX_HANDLERS 256
|
||||
|
||||
/*
|
||||
* This array is actually an array of function pointers. We use
|
||||
|
@ -93,6 +93,7 @@ int irq_uninstall_handler(unsigned int irq)
|
|||
*/
|
||||
static int irq_remap(void)
|
||||
{
|
||||
#ifndef CONFIG_ROCKCREEK
|
||||
outportb(0x20, 0x11);
|
||||
outportb(0xA0, 0x11);
|
||||
outportb(0x21, 0x20);
|
||||
|
@ -103,6 +104,7 @@ static int irq_remap(void)
|
|||
outportb(0xA1, 0x01);
|
||||
outportb(0x21, 0x0);
|
||||
outportb(0xA1, 0x0);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -158,7 +160,7 @@ static int irq_install(void)
|
|||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(51, (unsigned)apic_error, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(52, (unsigned)apic_svr, KERNEL_CODE_SELECTOR,
|
||||
idt_set_gate(127, (unsigned)apic_svr, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
}
|
||||
|
||||
|
@ -194,6 +196,11 @@ void irq_handler(struct state *s)
|
|||
/* This is a blank function pointer */
|
||||
void (*handler) (struct state * s);
|
||||
|
||||
if (s->int_no - 32 > MAX_HANDLERS) {
|
||||
apic_eoi();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find out if we have a custom handler to run for this
|
||||
* IRQ and then finally, run it
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <metalsvm/tasks.h>
|
||||
#include <asm/irqflags.h>
|
||||
#include <asm/isrs.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/idt.h>
|
||||
|
||||
/*
|
||||
|
@ -172,9 +173,12 @@ void fault_handler(struct state *s)
|
|||
kputs(" Exception.\n");
|
||||
|
||||
/* Now, we signalize that we have handled the interrupt */
|
||||
outportb(0x20, 0x20);
|
||||
irq_enable();
|
||||
if (has_apic())
|
||||
apic_eoi();
|
||||
else
|
||||
outportb(0x20, 0x20);
|
||||
|
||||
irq_enable();
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,25 +18,29 @@
|
|||
*/
|
||||
|
||||
#include <metalsvm/stdio.h>
|
||||
#include <metalsvm/errno.h>
|
||||
#include <asm/scc.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#ifdef CONFIG_ROCKCREEK
|
||||
|
||||
#define CCR_INTR_ACTIVE 0x02
|
||||
|
||||
scc_info_t scc_info;
|
||||
|
||||
int scc_init(void)
|
||||
{
|
||||
int tmp, x, y, z;
|
||||
uint32_t x, y, z;
|
||||
uint32_t tmp;
|
||||
|
||||
kprintf("Initialize Rock Creek!\n");
|
||||
|
||||
tmp = *((int*) (CRB_OWN+MYTILEID));
|
||||
tmp = *((uint32_t*) (CRB_OWN+MYTILEID));
|
||||
x=(tmp>>3) & 0x0f; // bits 06:03
|
||||
y=(tmp>>7) & 0x0f; // bits 10:07
|
||||
z=(tmp ) & 0x07; // bits 02:00
|
||||
scc_info.pid = PID(x, y, z);
|
||||
kprintf("SCC Processor Id: %d (%d,%d,%d)\n", scc_info.pid, x, y, z);
|
||||
kprintf("SCC Processor Id: %u (%u,%u,%u)\n", scc_info.pid, x, y, z);
|
||||
|
||||
/* default values for 16 GB system */
|
||||
scc_info.private_mem[0].low = 0x00;
|
||||
|
@ -44,6 +48,42 @@ int scc_init(void)
|
|||
scc_info.private_mem[1].low = 0xFF000000;
|
||||
scc_info.private_mem[1].high = 0xFFFFFFFF;
|
||||
|
||||
tmp = *((uint32_t*) (CRB_OWN+GCBCFG));
|
||||
tmp = (tmp & 0x3FFFFFF) >> 7;
|
||||
//kprintf("Own GCBCFG is 0x%x\n", tmp);
|
||||
if (tmp == 0x70E1) {
|
||||
scc_info.tile_frequency = 800;
|
||||
scc_info.router_frequency = 1600;
|
||||
} else {
|
||||
scc_info.tile_frequency = 533;
|
||||
scc_info.router_frequency = 800;
|
||||
}
|
||||
|
||||
kprintf("The default tile frequency is %u MHz\nThe default router frequency is %u MHz\n",
|
||||
scc_info.tile_frequency, scc_info.router_frequency);
|
||||
|
||||
if (z == 0)
|
||||
tmp = *((uint32_t*) (CRB_OWN+GLCFG0));
|
||||
else if (z == 1)
|
||||
tmp = *((uint32_t*) (CRB_OWN+GLCFG1));
|
||||
else
|
||||
tmp = 0;
|
||||
|
||||
/* set INTR to enable maskable interrupts */
|
||||
tmp = tmp | CCR_INTR_ACTIVE;
|
||||
if (z == 0)
|
||||
*((uint32_t*) (CRB_OWN+GLCFG0)) = tmp;
|
||||
else if (z == 1)
|
||||
*((uint32_t*) (CRB_OWN+GLCFG1)) = tmp;
|
||||
|
||||
/* reload core configuration */
|
||||
tmp = 0;
|
||||
if (z == 0)
|
||||
tmp = *((uint32_t*) (CRB_OWN+GLCFG0));
|
||||
else if (z == 1)
|
||||
tmp = *((uint32_t*) (CRB_OWN+GLCFG1));
|
||||
kprintf("Core Configuration %u: 0x%x\n", z, tmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -87,6 +87,11 @@ int timer_init(void)
|
|||
irq_install_handler(0, timer_handler);
|
||||
irq_install_handler(16, timer_handler);
|
||||
|
||||
/*
|
||||
* The Rock Creek processor doesn't posseess an tradional PIC.
|
||||
* Therefore, we have not to configure the PIC timer.
|
||||
*/
|
||||
#ifndef CONFIG_ROCKCREEK
|
||||
outportb(0x43, 0x34);
|
||||
/* before we write to 0x40, we wait some time */
|
||||
start = rdtsc();
|
||||
|
@ -98,6 +103,7 @@ int timer_init(void)
|
|||
while(rdtsc() - start < 1000000)
|
||||
;
|
||||
outportb(0x40, LATCH(TIMER_FREQ) >> 8); /* high byte */
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue