Re: time.c CP0_COMPARE

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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);
 	}
 
 	/* 

[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux