Added set_timer(usec) function
authorAndrew Waterman <waterman@parcad.millennium.berkeley.edu>
Tue, 19 Jan 2010 23:22:24 +0000 (15:22 -0800)
committerAndrew Waterman <waterman@parcad.millennium.berkeley.edu>
Tue, 19 Jan 2010 23:22:24 +0000 (15:22 -0800)
On i386, it uses lapic_set_timer; on SPARC it uses
the hacked-up RAMP interrupt timer.

kern/arch/i386/apic.c
kern/arch/sparc/sparc.h
kern/arch/sparc/timer.c
kern/arch/sparc/timer.h
kern/include/timing.h

index 0b45c54..92c4ee1 100644 (file)
@@ -90,6 +90,11 @@ void lapic_set_timer(uint32_t usec, bool periodic)
                          LAPIC_TIMER_DEFAULT_DIVISOR);
 }
 
+void set_timer(uint32_t usec)
+{
+       lapic_set_timer(usec,!!usec);
+}
+
 uint32_t lapic_get_default_id(void)
 {
        uint32_t ebx;
index 192ac4c..eeb10c4 100644 (file)
@@ -165,13 +165,27 @@ mmu_probe(uint32_t va)
        return load_alternate((va & ~0xFFF) | 0x400, 3);
 }
 
+static __inline void
+store_iobus(uint32_t device, uint32_t addr, uint32_t data)
+{
+       store_alternate(device << 16 | addr, 2, data);
+}
+
 static __inline uint32_t
 send_ipi(uint32_t dst)
 {
-       store_alternate(2 << 16 | dst << 10, 2, 0);
+       store_iobus(2,dst<<10,0);
        return 0;
 }
 
+// arm the calling core's interrupt timer.
+// enable must be 1 or 0; clocks must be a power of 2
+static __inline void
+sparc_set_timer(uint32_t clocks, uint32_t enable)
+{
+       store_iobus(1,0,enable << 24 | (clocks-1));
+}
+
 #endif /* !__ASSEMBLER__ */
 
 #endif /* !ROS_INC_X86_H */
index 01ceef2..820333a 100644 (file)
@@ -30,25 +30,30 @@ asm (
 void
 timer_init(void)
 {      
-#if 0
-       uint32_t ticks = timer_ticks;
-       uint64_t tsc_ticks;
-
-       while(ticks == timer_ticks) ;
-
-       ticks = timer_ticks;
-       tsc_ticks = read_tsc();
-
-       while(ticks == timer_ticks) ;
-
-       system_timing.tsc_freq = (read_tsc() - tsc_ticks)*INTERRUPT_TIMER_HZ;
-#endif
-       system_timing.tsc_freq = 1000000;
-
+       system_timing.tsc_freq = TSC_HZ;
        cprintf("TSC Frequency: %llu\n", system_timing.tsc_freq);
 }
 
 void
+set_timer(uint32_t usec)
+{
+       uint32_t clocks =  (uint64_t)usec*TSC_HZ/1000000;
+       if(clocks & (clocks-1))
+       {
+               clocks = ROUNDUPPWR2(clocks);
+               warn("set_timer: rounding up to %d usec",
+                    (uint64_t)clocks*1000000/TSC_HZ);
+       }
+       if(clocks > TIMER_MAX_PERIOD)
+       {
+               clocks = TIMER_MAX_PERIOD;
+               warn("set_timer: truncating to %d usec",
+                    (uint64_t)clocks*1000000/TSC_HZ);
+       }
+       sparc_set_timer(clocks,!!clocks);
+}
+
+void
 udelay(uint64_t usec)
 {
        if (system_timing.tsc_freq != 0)
index 37264b4..7d0e030 100644 (file)
@@ -1,7 +1,8 @@
 #ifndef ROS_ARCH_TIMER_H
 #define ROS_ARCH_TIMER_H
 
-#define INTERRUPT_TIMER_HZ     100
+#define TSC_HZ 1000000 // really, this is the core clock frequency
+#define TIMER_MAX_PERIOD (1 << 24) // in cycles
 
 #include <ros/common.h>
 
index 0edd068..5ee9f08 100644 (file)
@@ -5,4 +5,8 @@
 
 void udelay(uint64_t usec);
 
+// arm the programmable interrupt timer.
+// usec=0 disables it.
+void set_timer(uint32_t usec);
+
 #endif