/shark/trunk/oslib/kl/event1.c |
---|
31,6 → 31,7 |
#include <ll/i386/stdlib.h> |
#include <ll/i386/mem.h> |
#include <ll/i386/pit.h> |
#include <ll/i386/apic.h> |
#include <ll/i386/advtimer.h> |
#include <ll/sys/ll/ll-data.h> |
55,6 → 56,8 |
extern void (*evt_epil) (void); |
extern unsigned char use_tsc; |
extern unsigned int use_apic; |
extern unsigned int apic_clk_per_msec; |
/* TODO: oneshot_event_delete & oneshot_event_init... */ |
105,10 → 108,15 |
SUBTIMESPEC(&(firstevent->time), &now, &tmp); |
} |
tnext = TIMESPEC2USEC(&tmp); |
if (!use_apic) { |
tnext = (signed long long)(tnext) * 1193182 / 1000000; |
pit_setconstant(0, tnext); |
} else { |
tnext = (signed long long)(tnext) * apic_clk_per_msec / 1000; |
setup_APIC_LVTT(tnext); |
} |
} |
} |
p->next = p1; |
return p->index; |
186,14 → 194,22 |
} |
/* SUBTIMESPEC(&(firstevent->time), &now, &ttmp); */ |
tnext = TIMESPEC2USEC(&ttmp); |
if (!use_apic) { |
tnext = (signed long long)(tnext) * 1193182 / 1000000; |
pit_setconstant(0, tnext); |
} else { |
tnext = (signed long long)(tnext) * apic_clk_per_msec / 1000; |
setup_APIC_LVTT(tnext); |
} |
activeEvent = 0; |
} else { |
if (!use_apic) { |
pit_setconstant(0, 0xFFFF); |
} else { |
setup_APIC_LVTT(0xFFFFFFFF); |
} |
} |
} |
int oneshot_event_delete(int index) |
{ |
224,8 → 240,12 |
if (!activeEvent) { |
if (firstevent == NULL) { |
if (!use_apic) { |
pit_setconstant(0, 0xFFFF); |
} else { |
setup_APIC_LVTT(0xFFFFFFFF); |
} |
} else { |
if (firstdeleted) { |
ll_gettime(TIME_NEW, &now); |
if (TIMESPEC_A_GT_B(&now, &(firstevent->time))) { |
235,10 → 255,15 |
} |
/*SUBTIMESPEC(&now, &(firstevent->time), &tmp); */ |
tnext = TIMESPEC2USEC(&tmp); |
if (!use_apic) { |
tnext = (signed long long)(tnext) * 1193182 / 1000000; |
pit_setconstant(0, tnext); |
} else { |
tnext = (signed long long)(tnext) * apic_clk_per_msec / 1000; |
setup_APIC_LVTT(tnext); |
} |
} |
} |
} |
return 1; |
} |
/shark/trunk/oslib/kl/advtimer.c |
---|
29,6 → 29,7 |
#include <ll/sys/ll/ll-data.h> |
#include <ll/sys/ll/ll-func.h> |
#include <ll/i386/pic.h> |
#include <ll/i386/apic.h> |
#include <ll/sys/ll/event.h> |
#include <ll/sys/ll/time.h> |
36,6 → 37,7 |
unsigned char use_tsc = 1; //Enable the TSC counter mode |
unsigned char use_cmos = 0; //Enable the RTC correction |
unsigned char use_apic = 0; //Enable the APIC |
//Max single delta_clk_per_msec increment = clk_per_msec / MAX_DIV_INK; |
#define MAX_DIV_INK 30000 |
49,6 → 51,8 |
signed long long clk_per_msec; |
signed long long * ptr_clk_per_msec = &clk_per_msec; |
signed long long apic_clk_per_msec; |
signed long last_delta_clk_per_msec; |
signed long total_delta_clk_per_msec; |
247,7 → 251,7 |
signed long long irq8_start; |
signed long long irq8_end; |
void calibrate_IRQ8(void *p) |
void calibrate_tsc_IRQ8(void *p) |
{ |
unsigned char set; |
285,7 → 289,7 |
cli(); |
irq_bind(8, calibrate_IRQ8, INT_FORCE); |
irq_bind(8, calibrate_tsc_IRQ8, INT_FORCE); |
CMOS_READ(0x0A,save_CMOS_regA); |
CMOS_READ(0x0B,save_CMOS_regB); |
305,7 → 309,7 |
clk_per_msec = dtsc / 500; |
message("Calibrated Clk_per_msec = %10ld\n",(long)clk_per_msec); |
message("Calibrated CPU Clk/msec = %10ld\n",(long)clk_per_msec); |
cli(); |
365,6 → 369,285 |
} |
int apic_get_maxlvt(void) |
{ |
unsigned int v, ver, maxlvt; |
v = apic_read(APIC_LVR); |
ver = GET_APIC_VERSION(v); |
/* 82489DXs do not report # of LVT entries. */ |
maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(v) : 2; |
return maxlvt; |
} |
void clear_local_APIC(void) |
{ |
int maxlvt; |
unsigned long v; |
maxlvt = apic_get_maxlvt(); |
/* |
* Masking an LVT entry on a P6 can trigger a local APIC error |
* if the vector is zero. Mask LVTERR first to prevent this. |
*/ |
if (maxlvt >= 3) { |
v = 0xFF; /* any non-zero vector will do */ |
apic_write_around(APIC_LVTERR, v | APIC_LVT_MASKED); |
} |
/* |
* Careful: we have to set masks only first to deassert |
* any level-triggered sources. |
*/ |
v = apic_read(APIC_LVTT); |
apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED); |
v = apic_read(APIC_LVT0); |
apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED); |
v = apic_read(APIC_LVT1); |
apic_write_around(APIC_LVT1, v | APIC_LVT_MASKED); |
if (maxlvt >= 4) { |
v = apic_read(APIC_LVTPC); |
apic_write_around(APIC_LVTPC, v | APIC_LVT_MASKED); |
} |
/* |
* Clean APIC state for other OSs: |
*/ |
apic_write_around(APIC_LVTT, APIC_LVT_MASKED); |
apic_write_around(APIC_LVT0, APIC_LVT_MASKED); |
apic_write_around(APIC_LVT1, APIC_LVT_MASKED); |
if (maxlvt >= 3) |
apic_write_around(APIC_LVTERR, APIC_LVT_MASKED); |
if (maxlvt >= 4) |
apic_write_around(APIC_LVTPC, APIC_LVT_MASKED); |
v = GET_APIC_VERSION(apic_read(APIC_LVR)); |
if (APIC_INTEGRATED(v)) { /* !82489DX */ |
if (maxlvt > 3) |
apic_write(APIC_ESR, 0); |
apic_read(APIC_ESR); |
} |
} |
void connect_bsp_APIC(void) |
{ |
/* |
* Do not trust the local APIC being empty at bootup. |
*/ |
clear_local_APIC(); |
/* |
* PIC mode, enable APIC mode in the IMCR, i.e. |
* connect BSP's local APIC to INT and NMI lines. |
*/ |
outp(0x22, 0x70); |
outp(0x23, 0x01); |
} |
void disconnect_bsp_APIC(void) |
{ |
/* |
* Put the board back into PIC mode (has an effect |
* only on certain older boards). Note that APIC |
* interrupts, including IPIs, won't work beyond |
* this point! The only exception are INIT IPIs. |
*/ |
outp(0x22, 0x70); |
outp(0x23, 0x00); |
} |
void disable_local_APIC(void) |
{ |
unsigned long value; |
clear_local_APIC(); |
/* |
* Disable APIC (implies clearing of registers |
* for 82489DX!). |
*/ |
value = apic_read(APIC_SPIV); |
value &= ~APIC_SPIV_APIC_ENABLED; |
apic_write_around(APIC_SPIV, value); |
} |
#define SPURIOUS_APIC_VECTOR 0xFF |
/* |
* An initial setup of the virtual wire mode. |
*/ |
void setup_local_APIC (void) |
{ |
unsigned long value, ver; |
/* Pound the ESR really hard over the head with a big hammer - mbligh */ |
apic_write(APIC_ESR, 0); |
apic_write(APIC_ESR, 0); |
apic_write(APIC_ESR, 0); |
apic_write(APIC_ESR, 0); |
value = apic_read(APIC_LVR); |
ver = GET_APIC_VERSION(value); |
/* |
* Set Task Priority to 'accept all'. We never change this |
* later on. |
*/ |
value = apic_read(APIC_TASKPRI); |
value &= ~APIC_TPRI_MASK; |
apic_write_around(APIC_TASKPRI, value); |
/* |
* Now that we are all set up, enable the APIC |
*/ |
value = apic_read(APIC_SPIV); |
value &= ~APIC_VECTOR_MASK; |
/* |
* Enable APIC |
*/ |
value |= APIC_SPIV_APIC_ENABLED; |
/* |
* Some unknown Intel IO/APIC (or APIC) errata is biting us with |
* certain networking cards. If high frequency interrupts are |
* happening on a particular IOAPIC pin, plus the IOAPIC routing |
* entry is masked/unmasked at a high rate as well then sooner or |
* later IOAPIC line gets 'stuck', no more interrupts are received |
* from the device. If focus CPU is disabled then the hang goes |
* away, oh well :-( |
* |
* [ This bug can be reproduced easily with a level-triggered |
* PCI Ne2000 networking cards and PII/PIII processors, dual |
* BX chipset. ] |
*/ |
/* |
* Actually disabling the focus CPU check just makes the hang less |
* frequent as it makes the interrupt distributon model be more |
* like LRU than MRU (the short-term load is more even across CPUs). |
* See also the comment in end_level_ioapic_irq(). --macro |
*/ |
#if 1 |
/* Enable focus processor (bit==0) */ |
value &= ~APIC_SPIV_FOCUS_DISABLED; |
#else |
/* Disable focus processor (bit==1) */ |
value |= APIC_SPIV_FOCUS_DISABLED; |
#endif |
/* |
* Set spurious IRQ vector |
*/ |
value |= SPURIOUS_APIC_VECTOR; |
apic_write_around(APIC_SPIV, value); |
/* |
* Set up LVT0, LVT1: |
* |
* set up through-local-APIC on the BP's LINT0. This is not |
* strictly necessery in pure symmetric-IO mode, but sometimes |
* we delegate interrupts to the 8259A. |
*/ |
/* |
* TODO: set up through-local-APIC from through-I/O-APIC? --macro |
*/ |
value = APIC_DM_EXTINT; |
apic_write_around(APIC_LVT0, value); |
value = APIC_DM_NMI | APIC_LVT_MASKED; |
if (!APIC_INTEGRATED(ver)) /* 82489DX */ |
value |= APIC_LVT_LEVEL_TRIGGER; |
apic_write_around(APIC_LVT1, value); |
} |
void disable_APIC_timer(void) |
{ |
unsigned long v; |
v = apic_read(APIC_LVTT); |
apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED); |
} |
void enable_APIC_timer(void) |
{ |
unsigned long v; |
v = apic_read(APIC_LVTT); |
apic_write_around(APIC_LVTT, v & ~APIC_LVT_MASKED); |
} |
#define LOCAL_TIMER_VECTOR 0x40 |
void setup_APIC_LVTT(unsigned int clocks) |
{ |
unsigned int lvtt1_value, tmp_value; |
lvtt1_value = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) | |
APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR; |
apic_write_around(APIC_LVTT, lvtt1_value); |
/* |
* Divide PICLK by 1 |
*/ |
tmp_value = apic_read(APIC_TDCR); |
apic_write_around(APIC_TDCR, (tmp_value |
& ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE)) |
| APIC_TDR_DIV_1); |
apic_write_around(APIC_TMICT, clocks); |
} |
#define APIC_LIMIT 0xFF000000 |
void ll_calibrate_apic(void) |
{ |
unsigned int apic_start = 0, apic_end = 0, dapic; |
signed long long tsc_start = 0, tsc_end = 0, dtsc; |
unsigned int tmp_value; |
cli(); |
tmp_value = apic_read(APIC_TDCR); |
apic_write_around(APIC_TDCR, (tmp_value |
& ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE)) |
| APIC_TDR_DIV_1); |
apic_write(APIC_TMICT, MAX_DWORD); |
barrier(); |
rdtscll(tsc_start); |
barrier(); |
apic_start = apic_read(APIC_TMCCT); |
barrier(); |
while (apic_read(APIC_TMCCT) > APIC_LIMIT) { |
barrier(); |
rdtscll(tsc_end); |
} |
barrier(); |
rdtscll(tsc_end); |
barrier(); |
apic_end = apic_read(APIC_TMCCT); |
barrier(); |
sti(); |
dtsc = tsc_end - tsc_start; |
dapic = apic_start - apic_end; |
apic_clk_per_msec = clk_per_msec * (signed long long)(dapic) / dtsc; |
message("Calibrated APIC Clk/msec = %10ld\n",(long)apic_clk_per_msec); |
} |
void ll_init_advtimer() |
{ |
382,6 → 665,24 |
rdtscll(init_tsc); // Read start TSC |
init_nsec = 0; |
if (use_apic) { |
unsigned long msr_low_orig, tmp; |
cli(); |
rdmsr(APIC_BASE_MSR, msr_low_orig, tmp); |
wrmsr(APIC_BASE_MSR, msr_low_orig|(1<<11), 0); |
connect_bsp_APIC(); |
setup_local_APIC(); |
sti(); |
ll_calibrate_apic(); |
} |
if (use_cmos) { |
message("CMOS adjustement enabled\n"); |
/shark/trunk/oslib/kl/apic.c |
---|
0,0 → 1,322 |
#include "ll/i386/apic.h" |
int get_maxlvt(void) |
{ |
unsigned int v, ver, maxlvt; |
v = apic_read(APIC_LVR); |
ver = GET_APIC_VERSION(v); |
/* 82489DXs do not report # of LVT entries. */ |
maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(v) : 2; |
return maxlvt; |
} |
void clear_local_APIC(void) |
{ |
int maxlvt; |
unsigned long v; |
maxlvt = get_maxlvt(); |
/* |
* Masking an LVT entry on a P6 can trigger a local APIC error |
* if the vector is zero. Mask LVTERR first to prevent this. |
*/ |
if (maxlvt >= 3) { |
v = ERROR_APIC_VECTOR; /* any non-zero vector will do */ |
apic_write_around(APIC_LVTERR, v | APIC_LVT_MASKED); |
} |
/* |
* Careful: we have to set masks only first to deassert |
* any level-triggered sources. |
*/ |
v = apic_read(APIC_LVTT); |
apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED); |
v = apic_read(APIC_LVT0); |
apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED); |
v = apic_read(APIC_LVT1); |
apic_write_around(APIC_LVT1, v | APIC_LVT_MASKED); |
if (maxlvt >= 4) { |
v = apic_read(APIC_LVTPC); |
apic_write_around(APIC_LVTPC, v | APIC_LVT_MASKED); |
} |
/* |
* Clean APIC state for other OSs: |
*/ |
apic_write_around(APIC_LVTT, APIC_LVT_MASKED); |
apic_write_around(APIC_LVT0, APIC_LVT_MASKED); |
apic_write_around(APIC_LVT1, APIC_LVT_MASKED); |
if (maxlvt >= 3) |
apic_write_around(APIC_LVTERR, APIC_LVT_MASKED); |
if (maxlvt >= 4) |
apic_write_around(APIC_LVTPC, APIC_LVT_MASKED); |
v = GET_APIC_VERSION(apic_read(APIC_LVR)); |
if (APIC_INTEGRATED(v)) { /* !82489DX */ |
if (maxlvt > 3) |
apic_write(APIC_ESR, 0); |
apic_read(APIC_ESR); |
} |
} |
void __init connect_bsp_APIC(void) |
{ |
if (pic_mode) { |
/* |
* Do not trust the local APIC being empty at bootup. |
*/ |
clear_local_APIC(); |
/* |
* PIC mode, enable APIC mode in the IMCR, i.e. |
* connect BSP's local APIC to INT and NMI lines. |
*/ |
printk("leaving PIC mode, enabling APIC mode.\n"); |
outb(0x70, 0x22); |
outb(0x01, 0x23); |
} |
} |
void disconnect_bsp_APIC(void) |
{ |
if (pic_mode) { |
/* |
* Put the board back into PIC mode (has an effect |
* only on certain older boards). Note that APIC |
* interrupts, including IPIs, won't work beyond |
* this point! The only exception are INIT IPIs. |
*/ |
printk("disabling APIC mode, entering PIC mode.\n"); |
outb(0x70, 0x22); |
outb(0x00, 0x23); |
} |
} |
void disable_local_APIC(void) |
{ |
unsigned long value; |
clear_local_APIC(); |
/* |
* Disable APIC (implies clearing of registers |
* for 82489DX!). |
*/ |
value = apic_read(APIC_SPIV); |
value &= ~APIC_SPIV_APIC_ENABLED; |
apic_write_around(APIC_SPIV, value); |
} |
/* |
* An initial setup of the virtual wire mode. |
*/ |
void __init init_bsp_APIC(void) |
{ |
unsigned long value, ver; |
/* |
* Don't do the setup now if we have a SMP BIOS as the |
* through-I/O-APIC virtual wire mode might be active. |
*/ |
if (smp_found_config || !cpu_has_apic) |
return; |
value = apic_read(APIC_LVR); |
ver = GET_APIC_VERSION(value); |
/* |
* Do not trust the local APIC being empty at bootup. |
*/ |
clear_local_APIC(); |
/* |
* Enable APIC. |
*/ |
value = apic_read(APIC_SPIV); |
value &= ~APIC_VECTOR_MASK; |
value |= APIC_SPIV_APIC_ENABLED; |
value |= APIC_SPIV_FOCUS_DISABLED; |
value |= SPURIOUS_APIC_VECTOR; |
apic_write_around(APIC_SPIV, value); |
/* |
* Set up the virtual wire mode. |
*/ |
apic_write_around(APIC_LVT0, APIC_DM_EXTINT); |
value = APIC_DM_NMI; |
if (!APIC_INTEGRATED(ver)) /* 82489DX */ |
value |= APIC_LVT_LEVEL_TRIGGER; |
apic_write_around(APIC_LVT1, value); |
} |
static unsigned long calculate_ldr(unsigned long old) |
{ |
unsigned long id; |
if(clustered_apic_mode == CLUSTERED_APIC_XAPIC) |
id = physical_to_logical_apicid(hard_smp_processor_id()); |
else |
id = 1UL << smp_processor_id(); |
return (old & ~APIC_LDR_MASK)|SET_APIC_LOGICAL_ID(id); |
} |
void __init setup_local_APIC (void) |
{ |
unsigned long value, ver, maxlvt; |
/* Pound the ESR really hard over the head with a big hammer - mbligh */ |
if (esr_disable) { |
apic_write(APIC_ESR, 0); |
apic_write(APIC_ESR, 0); |
apic_write(APIC_ESR, 0); |
apic_write(APIC_ESR, 0); |
} |
value = apic_read(APIC_LVR); |
ver = GET_APIC_VERSION(value); |
if ((SPURIOUS_APIC_VECTOR & 0x0f) != 0x0f) |
__error_in_apic_c(); |
/* |
* Double-check wether this APIC is really registered. |
* This is meaningless in clustered apic mode, so we skip it. |
*/ |
if (!clustered_apic_mode && |
!test_bit(GET_APIC_ID(apic_read(APIC_ID)), &phys_cpu_present_map)) |
BUG(); |
/* |
* Intel recommends to set DFR, LDR and TPR before enabling |
* an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel |
* document number 292116). So here it goes... |
*/ |
if (clustered_apic_mode != CLUSTERED_APIC_NUMAQ) { |
/* |
* For NUMA-Q (clustered apic logical), the firmware does this |
* for us. Otherwise put the APIC into clustered or flat |
* delivery mode. Must be "all ones" explicitly for 82489DX. |
*/ |
if(clustered_apic_mode == CLUSTERED_APIC_XAPIC) |
apic_write_around(APIC_DFR, APIC_DFR_CLUSTER); |
else |
apic_write_around(APIC_DFR, APIC_DFR_FLAT); |
/* |
* Set up the logical destination ID. |
*/ |
value = apic_read(APIC_LDR); |
apic_write_around(APIC_LDR, calculate_ldr(value)); |
} |
/* |
* Set Task Priority to 'accept all'. We never change this |
* later on. |
*/ |
value = apic_read(APIC_TASKPRI); |
value &= ~APIC_TPRI_MASK; |
apic_write_around(APIC_TASKPRI, value); |
/* |
* Now that we are all set up, enable the APIC |
*/ |
value = apic_read(APIC_SPIV); |
value &= ~APIC_VECTOR_MASK; |
/* |
* Enable APIC |
*/ |
value |= APIC_SPIV_APIC_ENABLED; |
/* |
* Some unknown Intel IO/APIC (or APIC) errata is biting us with |
* certain networking cards. If high frequency interrupts are |
* happening on a particular IOAPIC pin, plus the IOAPIC routing |
* entry is masked/unmasked at a high rate as well then sooner or |
* later IOAPIC line gets 'stuck', no more interrupts are received |
* from the device. If focus CPU is disabled then the hang goes |
* away, oh well :-( |
* |
* [ This bug can be reproduced easily with a level-triggered |
* PCI Ne2000 networking cards and PII/PIII processors, dual |
* BX chipset. ] |
*/ |
/* |
* Actually disabling the focus CPU check just makes the hang less |
* frequent as it makes the interrupt distributon model be more |
* like LRU than MRU (the short-term load is more even across CPUs). |
* See also the comment in end_level_ioapic_irq(). --macro |
*/ |
#if 1 |
/* Enable focus processor (bit==0) */ |
value &= ~APIC_SPIV_FOCUS_DISABLED; |
#else |
/* Disable focus processor (bit==1) */ |
value |= APIC_SPIV_FOCUS_DISABLED; |
#endif |
/* |
* Set spurious IRQ vector |
*/ |
value |= SPURIOUS_APIC_VECTOR; |
apic_write_around(APIC_SPIV, value); |
/* |
* Set up LVT0, LVT1: |
* |
* set up through-local-APIC on the BP's LINT0. This is not |
* strictly necessery in pure symmetric-IO mode, but sometimes |
* we delegate interrupts to the 8259A. |
*/ |
/* |
* TODO: set up through-local-APIC from through-I/O-APIC? --macro |
*/ |
value = apic_read(APIC_LVT0) & APIC_LVT_MASKED; |
if (!smp_processor_id() && (pic_mode || !value)) { |
value = APIC_DM_EXTINT; |
printk("enabled ExtINT on CPU#%d\n", smp_processor_id()); |
} else { |
value = APIC_DM_EXTINT | APIC_LVT_MASKED; |
printk("masked ExtINT on CPU#%d\n", smp_processor_id()); |
} |
apic_write_around(APIC_LVT0, value); |
/* |
* only the BP should see the LINT1 NMI signal, obviously. |
*/ |
if (!smp_processor_id()) |
value = APIC_DM_NMI; |
else |
value = APIC_DM_NMI | APIC_LVT_MASKED; |
if (!APIC_INTEGRATED(ver)) /* 82489DX */ |
value |= APIC_LVT_LEVEL_TRIGGER; |
apic_write_around(APIC_LVT1, value); |
if (APIC_INTEGRATED(ver) && !esr_disable) { /* !82489DX */ |
maxlvt = get_maxlvt(); |
if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ |
apic_write(APIC_ESR, 0); |
value = apic_read(APIC_ESR); |
printk("ESR value before enabling vector: %08lx\n", value); |
value = ERROR_APIC_VECTOR; // enables sending errors |
apic_write_around(APIC_LVTERR, value); |
/* |
* spec says clear errors after enabling vector. |
*/ |
if (maxlvt > 3) |
apic_write(APIC_ESR, 0); |
value = apic_read(APIC_ESR); |
printk("ESR value after enabling vector: %08lx\n", value); |
} else { |
if (esr_disable) |
/* |
* Something untraceble is creating bad interrupts on |
* secondary quads ... for the moment, just leave the |
* ESR disabled - we can't do anything useful with the |
* errors anyway - mbligh |
*/ |
printk("Leaving ESR disabled.\n"); |
else |
printk("No ESR for 82489DX.\n"); |
} |
if (nmi_watchdog == NMI_LOCAL_APIC) |
setup_apic_nmi_watchdog(); |
} |
/shark/trunk/oslib/kl/event.c |
---|
34,6 → 34,7 |
#include <ll/i386/hw-arch.h> |
#include <ll/i386/pic.h> |
#include <ll/i386/pit.h> |
#include <ll/i386/apic.h> |
#include <ll/i386/advtimer.h> |
#include <ll/sys/ll/ll-data.h> |
71,6 → 72,8 |
extern void (*evt_epil) (void); |
extern unsigned char use_tsc; |
extern unsigned char use_apic; |
extern signed long long apic_clk_per_msec; |
void event_setlasthandler(void *p) |
{ |
207,21 → 210,30 |
void event_init(struct ll_initparms *l) |
{ |
extern void ll_timer(void); |
extern void ll_apic_timer(void); |
int i; |
BYTE mask; |
TIME t; |
DWORD apic_clk; |
if (use_tsc) ll_init_advtimer(); |
if (!use_apic) |
IDT_place(0x40,ll_timer); |
else |
IDT_place(0x40,ll_apic_timer); |
if (l->mode != LL_PERIODIC) { |
message("One-shot mode\n"); |
t = 0; |
if (!use_apic) { |
/* Mode: Binary/Mode 4/16 bit Time_const/Counter 0 */ |
pit_init(0, TMR_MD4, 0xFFFF); /* Timer 0, Mode 4, constant 0xFFFF */ |
} else |
setup_APIC_LVTT(0xFFFFFFFF); |
} else { |
t = l->tick; |
/* Translate the tick value in usec into a suitable time constant */ |
/* for 8254 timer chip; the chip is driven with a 1.19718 MHz */ |
/* frequency; then the effective frequency is given by the base */ |
230,6 → 242,9 |
/* Time-Constant = f_base (MHz) * tick (usec) */ |
/* If T-C == 0 -> T-C = 65536 (Max available) */ |
ticksize = t; |
if (!use_apic) { |
t = (signed long long)(t) * 1193182 / 1000000; |
/* Only for security! This should cause timer overrun */ |
240,10 → 255,18 |
/* Mode: Binary/Mode 2/16 bit Time_const/Counter 0 */ |
pit_init(0, TMR_MD2, t); /* Timer 0, Mode 2, Time constant t */ |
} else { |
apic_clk = (signed long long)(t) * apic_clk_per_msec / 1000; |
setup_APIC_LVTT(apic_clk); |
} |
} |
timermode = l->mode; |
if (!use_apic) { |
if (ll_arch.x86.cpu > 4) { |
/* Timer1: mode 0, time const 0... */ |
pit_init(1, TMR_MD0, 0); |
258,6 → 281,7 |
mask &= 0xFE; /* 0xFE = ~0x01 */ |
ll_out(0x21, mask); |
} |
/* Init the event list... */ |
for (i = 0; i < MAX_EVENT; i++) { |
289,5 → 313,6 |
} |
/* Last but not least... */ |
irq_unmask(0); |
if (!use_apic) irq_unmask(0); |
} |
/shark/trunk/oslib/kl/timeint.s |
---|
46,8 → 46,99 |
.extern SYMBOL_NAME(periodic_wake_up) |
.extern SYMBOL_NAME(oneshot_wake_up) |
.extern SYMBOL_NAME(ack_APIC_irq) |
.text |
.globl SYMBOL_NAME(ll_apic_timer) |
/* APIC ll_timer */ |
SYMBOL_NAME_LABEL(ll_apic_timer) |
pushal |
pushw %ds |
pushw %es |
pushw %fs |
pushw %gs |
movw $(X_FLATDATA_SEL),%ax |
movw %ax,%ds |
movw %ax,%es |
/* Send EOI to APIC */ |
movl $0xFEE000B0,%ebx |
movl $0,(%ebx) |
/* Call wake_up(actual_context) */ |
movl SYMBOL_NAME(ll_clock),%eax |
incl %eax |
movl %eax,SYMBOL_NAME(ll_clock) |
/* The following could be optimized a little... */ |
xorl %ebx, %ebx |
movw %ss, %bx |
/* We must switch to a ``safe stack'' */ |
/* |
* OK, this is the idea: in %esp we have the address of the |
* stack pointer in the APPLICATION address space... |
* We assume that address spaces are implemented through segments... |
* What we have to do is to add the segment base to %esp: |
* - Load the GDT base in a register |
* - Add DS * 8 to that value |
* - Read the corresponding GDT entry (the segment descriptor) |
* - Compute the base... |
* It is (*p & 0xFC) | (*(p +1) & 0x0F) << 16) | *(p + 2) |
*/ |
movl SYMBOL_NAME(GDT_base), %edi |
addl %ebx, %edi |
xorl %ebx, %ebx |
movb 7(%edi), %bh |
movb 4(%edi), %bl |
shl $16, %ebx |
movw 2(%edi), %bx |
/* Is it correct? I think so... Test it!!! */ |
addl %ebx, %esp |
/* Save EBX for returning to our stack... */ |
movw %ds, %cx |
movw %ss, %dx |
movw %cx, %ss |
pushl %ebx |
pushl %edx |
cld |
movl SYMBOL_NAME(timermode), %eax |
cmpl $1, %eax |
je apic_oneshot |
call SYMBOL_NAME(periodic_wake_up) |
jmp apic_Timer_OK |
apic_oneshot: call SYMBOL_NAME(oneshot_wake_up) |
apic_Timer_OK: |
/* Restore ESP */ |
popl %edx |
popl %ebx /* We must subtract it from ESP...*/ |
subl %ebx, %esp |
movw %dx, %ss |
#ifdef __VIRCSW__ |
movw SYMBOL_NAME(currCtx), %ax |
cmpw %ax,JmpSel |
je apic_NoPreempt2 |
movw %ax,JmpSel |
ljmp JmpZone /* DISPATCH! */ |
#endif |
apic_NoPreempt2: |
cmpl $0, SYMBOL_NAME(last_handler) |
je apic_nohandler |
movl SYMBOL_NAME(last_handler), %ebx |
call *%ebx |
apic_nohandler: |
popw %gs |
popw %fs |
popw %es |
popw %ds |
popal |
iret |
.globl SYMBOL_NAME(ll_timer) |
/* This is the timer handler; it reloads for safety the DS register; this */ |
/* prevents from mess when timer interrupts linear access to memory (not in */ |
/shark/trunk/oslib/ll/i386/advtimer.h |
---|
57,6 → 57,16 |
: "=A" (val) \ |
:: "ebx","ecx") |
#define rdmsr(msr,val1,val2) \ |
__asm__ __volatile__("rdmsr" \ |
: "=a" (val1), "=d" (val2) \ |
: "c" (msr)) |
#define wrmsr(msr,val1,val2) \ |
__asm__ __volatile__("wrmsr" \ |
: /* no outputs */ \ |
: "c" (msr), "a" (val1), "d" (val2)) |
/* RTC */ |
#define RTC_PORT(x) (0x70 + (x)) |
/shark/trunk/oslib/ll/i386/apic.h |
---|
0,0 → 1,150 |
#ifndef __APIC_H__ |
#define __APIC_H__ |
#define APIC_DEFAULT_PHYS_BASE 0xfee00000 |
#define APIC_ID 0x20 |
#define APIC_ID_MASK (0x0F<<24) |
#define GET_APIC_ID(x) (((x)>>24)&0x0F) |
#define APIC_LVR 0x30 |
#define APIC_LVR_MASK 0xFF00FF |
#define GET_APIC_VERSION(x) ((x)&0xFF) |
#define GET_APIC_MAXLVT(x) (((x)>>16)&0xFF) |
#define APIC_INTEGRATED(x) ((x)&0xF0) |
#define APIC_TASKPRI 0x80 |
#define APIC_TPRI_MASK 0xFF |
#define APIC_ARBPRI 0x90 |
#define APIC_ARBPRI_MASK 0xFF |
#define APIC_PROCPRI 0xA0 |
#define APIC_EOI 0xB0 |
#define APIC_EIO_ACK 0x0 /* Write this to the EOI register */ |
#define APIC_RRR 0xC0 |
#define APIC_LDR 0xD0 |
#define APIC_LDR_MASK (0xFF<<24) |
#define GET_APIC_LOGICAL_ID(x) (((x)>>24)&0xFF) |
#define SET_APIC_LOGICAL_ID(x) (((x)<<24)) |
#define APIC_ALL_CPUS 0xFF |
#define APIC_DFR 0xE0 |
#define APIC_DFR_CLUSTER 0x0FFFFFFFul /* Clustered */ |
#define APIC_DFR_FLAT 0xFFFFFFFFul /* Flat mode */ |
#define APIC_SPIV 0xF0 |
#define APIC_SPIV_FOCUS_DISABLED (1<<9) |
#define APIC_SPIV_APIC_ENABLED (1<<8) |
#define APIC_ISR 0x100 |
#define APIC_TMR 0x180 |
#define APIC_IRR 0x200 |
#define APIC_ESR 0x280 |
#define APIC_ESR_SEND_CS 0x00001 |
#define APIC_ESR_RECV_CS 0x00002 |
#define APIC_ESR_SEND_ACC 0x00004 |
#define APIC_ESR_RECV_ACC 0x00008 |
#define APIC_ESR_SENDILL 0x00020 |
#define APIC_ESR_RECVILL 0x00040 |
#define APIC_ESR_ILLREGA 0x00080 |
#define APIC_ICR 0x300 |
#define APIC_DEST_SELF 0x40000 |
#define APIC_DEST_ALLINC 0x80000 |
#define APIC_DEST_ALLBUT 0xC0000 |
#define APIC_ICR_RR_MASK 0x30000 |
#define APIC_ICR_RR_INVALID 0x00000 |
#define APIC_ICR_RR_INPROG 0x10000 |
#define APIC_ICR_RR_VALID 0x20000 |
#define APIC_INT_LEVELTRIG 0x08000 |
#define APIC_INT_ASSERT 0x04000 |
#define APIC_ICR_BUSY 0x01000 |
#define APIC_DEST_PHYSICAL 0x00000 |
#define APIC_DEST_LOGICAL 0x00800 |
#define APIC_DM_FIXED 0x00000 |
#define APIC_DM_LOWEST 0x00100 |
#define APIC_DM_SMI 0x00200 |
#define APIC_DM_REMRD 0x00300 |
#define APIC_DM_NMI 0x00400 |
#define APIC_DM_INIT 0x00500 |
#define APIC_DM_STARTUP 0x00600 |
#define APIC_DM_EXTINT 0x00700 |
#define APIC_VECTOR_MASK 0x000FF |
#define APIC_ICR2 0x310 |
#define GET_APIC_DEST_FIELD(x) (((x)>>24)&0xFF) |
#define SET_APIC_DEST_FIELD(x) ((x)<<24) |
#define APIC_LVTT 0x320 |
#define APIC_LVTPC 0x340 |
#define APIC_LVT0 0x350 |
#define APIC_LVT_TIMER_BASE_MASK (0x3<<18) |
#define GET_APIC_TIMER_BASE(x) (((x)>>18)&0x3) |
#define SET_APIC_TIMER_BASE(x) (((x)<<18)) |
#define APIC_TIMER_BASE_CLKIN 0x0 |
#define APIC_TIMER_BASE_TMBASE 0x1 |
#define APIC_TIMER_BASE_DIV 0x2 |
#define APIC_LVT_TIMER_PERIODIC (1<<17) |
#define APIC_LVT_MASKED (1<<16) |
#define APIC_LVT_LEVEL_TRIGGER (1<<15) |
#define APIC_LVT_REMOTE_IRR (1<<14) |
#define APIC_INPUT_POLARITY (1<<13) |
#define APIC_SEND_PENDING (1<<12) |
#define GET_APIC_DELIVERY_MODE(x) (((x)>>8)&0x7) |
#define SET_APIC_DELIVERY_MODE(x,y) (((x)&~0x700)|((y)<<8)) |
#define APIC_MODE_FIXED 0x0 |
#define APIC_MODE_NMI 0x4 |
#define APIC_MODE_EXINT 0x7 |
#define APIC_LVT1 0x360 |
#define APIC_LVTERR 0x370 |
#define APIC_TMICT 0x380 |
#define APIC_TMCCT 0x390 |
#define APIC_TDCR 0x3E0 |
#define APIC_TDR_DIV_TMBASE (1<<2) |
#define APIC_TDR_DIV_1 0xB |
#define APIC_TDR_DIV_2 0x0 |
#define APIC_TDR_DIV_4 0x1 |
#define APIC_TDR_DIV_8 0x2 |
#define APIC_TDR_DIV_16 0x3 |
#define APIC_TDR_DIV_32 0x8 |
#define APIC_TDR_DIV_64 0x9 |
#define APIC_TDR_DIV_128 0xA |
#define APIC_BASE APIC_DEFAULT_PHYS_BASE |
#define APIC_BASE_MSR 0x1B |
/* |
* Basic functions accessing APICs. |
*/ |
static __inline__ void apic_write(unsigned long reg, unsigned long v) |
{ |
*((volatile unsigned long *)(APIC_BASE+reg)) = v; |
} |
static __inline__ unsigned long apic_read(unsigned long reg) |
{ |
return *((volatile unsigned long *)(APIC_BASE+reg)); |
} |
static __inline__ void apic_wait_icr_idle(void) |
{ |
do { } while ( apic_read( APIC_ICR ) & APIC_ICR_BUSY ); |
} |
#define apic_read_around(x) |
#define apic_write_around(x,y) apic_write((x),(y)) |
static __inline__ void ack_APIC_irq(void) |
{ |
/* |
* ack_APIC_irq() actually gets compiled as a single instruction: |
* - a single rmw on Pentium/82489DX |
* - a single write on P6+ cores (CONFIG_X86_GOOD_APIC) |
* ... yummie. |
*/ |
/* Docs say use 0 for future compatibility */ |
apic_write_around(APIC_EOI, 0); |
} |
extern int get_maxlvt(void); |
extern void clear_local_APIC(void); |
extern void connect_bsp_APIC (void); |
extern void disconnect_bsp_APIC (void); |
extern void disable_local_APIC (void); |
extern void setup_APIC_LVTT(unsigned int clocks); |
#endif |