summaryrefslogtreecommitdiff
path: root/kernel/smp.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/smp.c')
-rw-r--r--kernel/smp.c58
1 files changed, 41 insertions, 17 deletions
diff --git a/kernel/smp.c b/kernel/smp.c
index da91148..b2ce6b0 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -43,6 +43,7 @@ volatile uint8_t proc;
uint32_t cpu_counter[SMP_MAX_PROC];
uint32_t local_apic_addr;
+uint32_t countdown;
void writeAPIC(uint32_t offset, uint32_t value)
{
@@ -81,6 +82,35 @@ void apicEnable()
}
+/** select mode : divisor.
+ * 0 - 1
+ * 1 - 2
+ * 2 - 4
+ * 3 - 8
+ * 4 - 16
+ * 5 - 32
+ * 6 - 64
+ * 7 - 128
+ */
+
+uint32_t probeBusSpeed(uint32_t sel)
+{
+ uint32_t div[]={1,2,4,8,16,32,64,128};
+ uint32_t reg[]={0b1011,0,1,2,3,0b1000,0b1001,0b1010};
+
+ uint32_t divisor=div[sel];
+
+ klog("Probing bus speed for 50ms (div=%d)) ...",divisor);
+ writeAPIC(APIC_TMRDIV, reg[sel]);
+ writeAPIC(APIC_TMRINITCNT, 0xFFFFFFFF);
+// for(int i=0;i<20;i++)
+ asm_pit_sleep_50ms();
+ //writeAPIC(APIC_LVT_TMR, APIC_LVT_INT_MASKED); //??
+ uint32_t ticksInS = 0xFFFFFFFF - readAPIC(APIC_TMRCURRCNT);
+ ticksInS*=20; // adjust to one full second.
+ klog("%d MHz (%d Hz) bus speed (ticks=%d)",ticksInS/(1000000/divisor),ticksInS*divisor,ticksInS/20);
+ return ticksInS*divisor;
+}
void smp_main()
{
// setup stack
@@ -99,7 +129,6 @@ void kernel_ap()
int_install();
gdt_init();
- uint32_t countdown=0x0fffffff; // TODO: calc to be constant, depending on bus speed. (use pit for measurement?)
writeAPIC(APIC_TMRDIV, 0x3);
writeAPIC(APIC_LVT_TMR, 200 | TMR_PERIODIC);
writeAPIC(APIC_TMRINITCNT, countdown);
@@ -151,9 +180,18 @@ void smp_start_aps(smp_processors *pros)
{
// TODO: check if local APIC is present via CPUID (P6 (i686) and above)
local_apic_addr=pros->local_apic_address;
-
klog("bsp local apic id: 0x%08X",apicID());
+ apicEnable(); // bsp apic seems to be enabled anyway.
+
+ uint32_t speed=probeBusSpeed(4); // get bus speed (divisor: 16)
+
+ // setup apic timer
+ countdown=speed/16; // tick once a second
+ writeAPIC(APIC_TMRDIV, 0x3); // divisor 16
+ writeAPIC(APIC_LVT_TMR, 200 | TMR_PERIODIC); // on interrupt 200
+ writeAPIC(APIC_TMRINITCNT, countdown);
+
for(int i=0;i<pros->processors;i++)
{
if(pros->boot==i)continue;
@@ -177,19 +215,5 @@ void smp_start_aps(smp_processors *pros)
// TODO retry 110 SIPI with 1s timeout
}
-
- apicEnable(); // bsp seems to be enabled anyway.
-
- writeAPIC(APIC_TMRDIV, 0x3);
- writeAPIC(APIC_TMRINITCNT, 0xFFFFFFFF);
- //asm_pit_sleep_1ms();
- //writeAPIC(APIC_LVT_TMR, APIC_LVT_INT_MASKED); //??
- uint32_t ticksInS = 0xFFFFFFFF - readAPIC(APIC_TMRCURRCNT);
-
- klog("%d MHz bus speed",ticksInS/1000);
-
- uint32_t countdown=0x0fffffff; // TODO: calc to be constant, depending on bus speed. (use pit for measurement?)
- writeAPIC(APIC_TMRDIV, 0x3);
- writeAPIC(APIC_LVT_TMR, 200 | TMR_PERIODIC);
- writeAPIC(APIC_TMRINITCNT, countdown);
}
+