Subversion Repositories shark

Compare Revisions

Ignore whitespace Rev 298 → Rev 299

/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,8 → 108,13
SUBTIMESPEC(&(firstevent->time), &now, &tmp);
}
tnext = TIMESPEC2USEC(&tmp);
tnext = (signed long long)(tnext) * 1193182 / 1000000;
pit_setconstant(0, tnext);
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;
186,12 → 194,20
}
/* SUBTIMESPEC(&(firstevent->time), &now, &ttmp); */
tnext = TIMESPEC2USEC(&ttmp);
tnext = (signed long long)(tnext) * 1193182 / 1000000;
pit_setconstant(0, tnext);
 
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 {
pit_setconstant(0, 0xFFFF);
if (!use_apic) {
pit_setconstant(0, 0xFFFF);
} else {
setup_APIC_LVTT(0xFFFFFFFF);
}
}
}
 
224,7 → 240,11
 
if (!activeEvent) {
if (firstevent == NULL) {
pit_setconstant(0, 0xFFFF);
if (!use_apic) {
pit_setconstant(0, 0xFFFF);
} else {
setup_APIC_LVTT(0xFFFFFFFF);
}
} else {
if (firstdeleted) {
ll_gettime(TIME_NEW, &now);
235,8 → 255,13
}
/*SUBTIMESPEC(&now, &(firstevent->time), &tmp); */
tnext = TIMESPEC2USEC(&tmp);
tnext = (signed long long)(tnext) * 1193182 / 1000000;
pit_setconstant(0, tnext);
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);
}
}
}
}
/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,22 → 210,31
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();
 
IDT_place(0x40,ll_timer);
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;
/* Mode: Binary/Mode 4/16 bit Time_const/Counter 0 */
pit_init(0, TMR_MD4, 0xFFFF); /* Timer 0, Mode 4, constant 0xFFFF */
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 */
/* 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 */
/* frequency divided for the time constant; the tick is the inverse */
230,35 → 242,47
/* Time-Constant = f_base (MHz) * tick (usec) */
/* If T-C == 0 -> T-C = 65536 (Max available) */
ticksize = t;
t = (signed long long)(t) * 1193182 / 1000000;
 
/* Only for security! This should cause timer overrun */
/* While 0 would set maximum period on timer */
if (t == 0)
t = 1;
pit_time_const = (WORD) (t & 0xFFFF);
/* Mode: Binary/Mode 2/16 bit Time_const/Counter 0 */
pit_init(0, TMR_MD2, t); /* Timer 0, Mode 2, Time constant t */
if (!use_apic) {
t = (signed long long)(t) * 1193182 / 1000000;
 
/* Only for security! This should cause timer overrun */
/* While 0 would set maximum period on timer */
if (t == 0)
t = 1;
pit_time_const = (WORD) (t & 0xFFFF);
/* 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 (ll_arch.x86.cpu > 4) {
/* Timer1: mode 0, time const 0... */
if (!use_apic) {
if (ll_arch.x86.cpu > 4) {
/* Timer1: mode 0, time const 0... */
pit_init(1, TMR_MD0, 0);
frc = 1;
} else {
} else {
frc = 2;
pit_init(2, TMR_MD0, 0);
outp(0x61, 3);
}
 
mask = ll_in(0x21);
mask &= 0xFE; /* 0xFE = ~0x01 */
ll_out(0x21, mask);
}
 
mask = ll_in(0x21);
mask &= 0xFE; /* 0xFE = ~0x01 */
ll_out(0x21, mask);
 
 
/* Init the event list... */
for (i = 0; i < MAX_EVENT; i++) {
if (i < MAX_EVENT - 1) {
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