Ralf Baechle wrote: > On Wed, Aug 28, 2002 at 06:32:06PM -0700, Matthew Dharm wrote: > > >>Reading the information on the new time.c system, I'm wondering who >>sets CP0_COMPARE the first time. >> >>The timer_interrupt() function will re-set the CP0_COMPARE to a new >>value when processing an interrupt. But what sets the CP0_COMPARE >>initially? Is that the responsiblity of the board_timer_setup() >>function? That's what it looks like, but... If so, what's the proper >>value? CP0_COUNT + cycle_per_jiffy? But cycles_per_jiffy is static >>to time.c... > > > c0_compare = c0_count + mips_counter_frequency / HZ. > > That's what the individual boards are currently doing themselves though that > should be done in generic code. > > Good idea. The attached patch attempts to set the first interrupt. It should be benign even if a system is not using CPU counter as timer interrupt. I also updated the time.README, including a new section about implementation on a SMP machine. Please apply. Jun
diff -Nru link/Documentation/mips/time.README.orig link/Documentation/mips/time.README --- link/Documentation/mips/time.README.orig Thu Apr 19 14:05:18 2001 +++ link/Documentation/mips/time.README Thu Aug 29 10:27:33 2002 @@ -103,9 +103,9 @@ Do you plan to use the CPU counter register as the timer interrupt or use an exnternal timer? - In order to CPU counter register as the timer interrupt source, you must - know the counter speed (mips_counter_frequency). It is usually the - same as the CPU speed (Or it is ALWAYS the same?) + In order to use CPU counter register as the timer interrupt source, you + must know the counter speed (mips_counter_frequency). It is usually the + same as the CPU speed or an integral divisor of it. d) decide on whether you want to use high-level or low-level timer interrupt routines. The low-level one is presumably faster, but should @@ -154,8 +154,45 @@ for some of the functions in time.c. For example, you may define your own timer interrupt routine, which does -its own processing and in turn calls timer_interrupt(). +some of its own processing and then calls timer_interrupt(). You can also over-ride any of the built-in functions (gettimeoffset, RTC routines and/or timer interrupt routine). + +PORTING NOTES FOR SMP +---------------------- + +If you have a SMP box, things are slightly more complicated. + +The time service running every jiffy is logically divided into two parts: + + 1) the one for the whole system (defined in timer_interrupt()) + 2) the one that should run for each CPU (defined in local_timer_interrupt()) + +You need to decide on your timer interrupt sources. + + case 1) - whole system has only one timer interrupt delivered to one CPU + + In this case, you set up timer interrupt as in UP systems. In addtion, + you need to set emulate_local_timer_interrupt to 1 so that other + CPUs get to call local_timer_interrupt(). + + THIS IS CURRENTLY NOT IMPLEMNETED. However, it is rather easy to write + one should such a need arise. You simply make a IPI call. + + case 2) - each CPU has a separate timer interrupt + + In this case, you need to set up IRQ such that each of them will + call local_timer_interrupt(). In addition, you need to arrange + one and only one of them to call timer_interrupt(). + + You can also do the low-level version of those interrupt routines, + following similar dispatching routes described above. + +Note about do_gettimeoffset(): + + It is very likely the CPU counter registers are not sync'ed up in a SMP box. + Therefore you cannot really use the many of the existing routines that + are based on CPU counter. You should wirte your own gettimeoffset rouinte + if you want intra-jiffy resolution. diff -Nru link/arch/mips/kernel/time.c.orig link/arch/mips/kernel/time.c --- link/arch/mips/kernel/time.c.orig Mon Mar 18 14:18:59 2002 +++ link/arch/mips/kernel/time.c Thu Aug 29 09:43:38 2002 @@ -501,6 +501,8 @@ /* caclulate cache parameters */ if (mips_counter_frequency) { + u32 count; + cycles_per_jiffy = mips_counter_frequency / HZ; /* sll32_usecs_per_cycle = 10^6 * 2^32 / mips_counter_freq */ @@ -508,6 +510,14 @@ sll32_usecs_per_cycle = mips_counter_frequency / 100000; sll32_usecs_per_cycle = 0xffffffff / sll32_usecs_per_cycle; sll32_usecs_per_cycle *= 10; + + /* + * for those using cpu counter as timer, this sets up the + * the first interrupt + */ + count = read_32bit_cp0_register(CP0_COUNT); + write_32bit_cp0_register (CP0_COMPARE, + count + cycles_per_jiffy); } /* diff -Nru link/arch/mips64/kernel/time.c.orig link/arch/mips64/kernel/time.c --- link/arch/mips64/kernel/time.c.orig Thu Aug 29 10:27:54 2002 +++ link/arch/mips64/kernel/time.c Thu Aug 29 10:28:58 2002 @@ -500,6 +500,8 @@ /* caclulate cache parameters */ if (mips_counter_frequency) { + u32 count; + cycles_per_jiffy = mips_counter_frequency / HZ; /* sll32_usecs_per_cycle = 10^6 * 2^32 / mips_counter_freq */ @@ -507,6 +509,14 @@ sll32_usecs_per_cycle = mips_counter_frequency / 100000; sll32_usecs_per_cycle = 0xffffffff / sll32_usecs_per_cycle; sll32_usecs_per_cycle *= 10; + + /* + * for those using cpu counter as timer, this sets up the + * the first interrupt + */ + count = read_32bit_cp0_register(CP0_COUNT); + write_32bit_cp0_register (CP0_COMPARE, + count + cycles_per_jiffy); } /*