patch-2.4.20 linux-2.4.20/arch/mips/sibyte/sb1250/time.c

Next file: linux-2.4.20/arch/mips/sibyte/swarm/Makefile
Previous file: linux-2.4.20/arch/mips/sibyte/sb1250/smp.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.19/arch/mips/sibyte/sb1250/time.c linux-2.4.20/arch/mips/sibyte/sb1250/time.c
@@ -10,17 +10,17 @@
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
-/* 
+/*
  * These are routines to set up and handle interrupts from the
  * sb1250 general purpose timer 0.  We're using the timer as a
  * system clock, so we set it up to run at 100 Hz.  On every
- * interrupt, we update our idea of what the time of day is, 
+ * interrupt, we update our idea of what the time of day is,
  * then call do_timer() in the architecture-independent kernel
  * code to do general bookkeeping (e.g. update jiffies, run
  * bottom halves, etc.)
@@ -29,6 +29,7 @@
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/spinlock.h>
+#include <linux/kernel_stat.h>
 
 #include <asm/irq.h>
 #include <asm/ptrace.h>
@@ -46,6 +47,8 @@
 #define IMR_IP3_VAL	K_INT_MAP_I1
 #define IMR_IP4_VAL	K_INT_MAP_I2
 
+extern int sb1250_steal_irq(int irq);
+
 void sb1250_time_init(void)
 {
 	int cpu = smp_processor_id();
@@ -55,11 +58,16 @@
 		BUG();
 	}
 
+	if (!cpu) {
+		/* Use our own gettimeoffset() routine */
+		do_gettimeoffset = sb1250_gettimeoffset;
+	}
+
 	sb1250_mask_irq(cpu, K_INT_TIMER_0 + cpu);
-	
+
 	/* Map the timer interrupt to ip[4] of this cpu */
-	out64(IMR_IP4_VAL, KSEG1 + A_IMR_REGISTER(cpu, R_IMR_INTERRUPT_MAP_BASE) 
-	      + ((K_INT_TIMER_0 + cpu)<<3)); 
+	out64(IMR_IP4_VAL, KSEG1 + A_IMR_REGISTER(cpu, R_IMR_INTERRUPT_MAP_BASE)
+	      + ((K_INT_TIMER_0 + cpu)<<3));
 
 	/* the general purpose timer ticks at 1 Mhz independent if the rest of the system */
 	/* Disable the timer and set up the count */
@@ -77,6 +85,7 @@
 	      KSEG1 + A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG));
 
 	sb1250_unmask_irq(cpu, K_INT_TIMER_0 + cpu);
+	sb1250_steal_irq(K_INT_TIMER_0 + cpu);
 	/*
 	 * This interrupt is "special" in that it doesn't use the request_irq
 	 * way to hook the irq line.  The timer interrupt is initialized early
@@ -91,9 +100,10 @@
 {
 	int cpu = smp_processor_id();
 
+	kstat.irqs[cpu][K_INT_TIMER_0+cpu]++;
 	/* Reset the timer */
 	out64(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS,
-	      KSEG1 + A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG));  
+	      KSEG1 + A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG));
 
 	/*
 	 * CPU 0 handles the global timer interrupt job
@@ -107,3 +117,17 @@
 	 */
 	ll_local_timer_interrupt(0, regs);
 }
+
+/*
+ * We use our own do_gettimeoffset() instead of the generic one,
+ * because the generic one does not work for SMP case.
+ * In addition, since we use general timer 0 for system time,
+ * we can get accurate intra-jiffy offset without calibration.
+ */
+unsigned long sb1250_gettimeoffset(void)
+{
+	unsigned long count =
+		in64(KSEG1 + A_SCD_TIMER_REGISTER(0, R_SCD_TIMER_CNT));
+
+	return 1000000/HZ - count;
+ }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)