]> Pileus Git - ~andy/linux/blobdiff - arch/mips/kernel/smtc.c
[MIPS] Dyntick support for SMTC:
[~andy/linux] / arch / mips / kernel / smtc.c
index 137183bba54f38bc1a12e8e56bdc0348c30ebd74..4d1ac9692dcd985e5d9ed30b8ab9766d935485bd 100644 (file)
@@ -1,5 +1,6 @@
 /* Copyright (C) 2004 Mips Technologies, Inc */
 
+#include <linux/clockchips.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/cpumask.h>
@@ -62,7 +63,7 @@ asiduse smtc_live_asid[MAX_SMTC_TLBS][MAX_SMTC_ASIDS];
  * Clock interrupt "latch" buffers, per "CPU"
  */
 
-unsigned int ipi_timer_latch[NR_CPUS];
+static atomic_t ipi_timer_latch[NR_CPUS];
 
 /*
  * Number of InterProcessor Interupt (IPI) message buffers to allocate
@@ -296,8 +297,10 @@ int __init mipsmt_build_cpu_map(int start_cpu_slot)
                __cpu_number_map[i] = i;
                __cpu_logical_map[i] = i;
        }
+#ifdef CONFIG_MIPS_MT_FPAFF
        /* Initialize map of CPUs with FPUs */
        cpus_clear(mt_fpu_cpumask);
+#endif
 
        /* One of those TC's is the one booting, and not a secondary... */
        printk("%i available secondary CPU TC(s)\n", i - 1);
@@ -359,7 +362,7 @@ void mipsmt_prepare_cpus(void)
                IPIQ[i].head = IPIQ[i].tail = NULL;
                spin_lock_init(&IPIQ[i].lock);
                IPIQ[i].depth = 0;
-               ipi_timer_latch[i] = 0;
+               atomic_set(&ipi_timer_latch[i], 0);
        }
 
        /* cpu_data index starts at zero */
@@ -482,10 +485,12 @@ void mipsmt_prepare_cpus(void)
 
        /* Set up coprocessor affinity CPU mask(s) */
 
+#ifdef CONFIG_MIPS_MT_FPAFF
        for (tc = 0; tc < ntc; tc++) {
                if (cpu_data[tc].options & MIPS_CPU_FPU)
                        cpu_set(tc, mt_fpu_cpumask);
        }
+#endif
 
        /* set up ipi interrupts... */
 
@@ -702,7 +707,7 @@ static void smtc_ipi_qdump(void)
  * be done with the atomic.h primitives). And since this is
  * MIPS MT, we can assume that we have LL/SC.
  */
-static __inline__ int atomic_postincrement(unsigned int *pv)
+static inline int atomic_postincrement(atomic_t *v)
 {
        unsigned long result;
 
@@ -714,8 +719,8 @@ static __inline__ int atomic_postincrement(unsigned int *pv)
        "       sc      %1, %2                                  \n"
        "       beqz    %1, 1b                                  \n"
        __WEAK_LLSC_MB
-       : "=&r" (result), "=&r" (temp), "=m" (*pv)
-       : "m" (*pv)
+       : "=&r" (result), "=&r" (temp), "=m" (v->counter)
+       : "m" (v->counter)
        : "memory");
 
        return result;
@@ -743,6 +748,8 @@ void smtc_send_ipi(int cpu, int type, unsigned int action)
        pipi->arg = (void *)action;
        pipi->dest = cpu;
        if (cpu_data[cpu].vpe_id != cpu_data[smp_processor_id()].vpe_id) {
+               if (type == SMTC_CLOCK_TICK)
+                       atomic_inc(&ipi_timer_latch[cpu]);
                /* If not on same VPE, enqueue and send cross-VPE interupt */
                smtc_ipi_nq(&IPIQ[cpu], pipi);
                LOCK_CORE_PRA();
@@ -784,6 +791,8 @@ void smtc_send_ipi(int cpu, int type, unsigned int action)
                        }
                        smtc_ipi_nq(&IPIQ[cpu], pipi);
                } else {
+                       if (type == SMTC_CLOCK_TICK)
+                               atomic_inc(&ipi_timer_latch[cpu]);
                        post_direct_ipi(cpu, pipi);
                        write_tc_c0_tchalt(0);
                        UNLOCK_CORE_PRA();
@@ -801,6 +810,7 @@ static void post_direct_ipi(int cpu, struct smtc_ipi *pipi)
        unsigned long tcrestart;
        extern u32 kernelsp[NR_CPUS];
        extern void __smtc_ipi_vector(void);
+//printk("%s: on %d for %d\n", __func__, smp_processor_id(), cpu);
 
        /* Extract Status, EPC from halted TC */
        tcstatus = read_tc_c0_tcstatus();
@@ -851,25 +861,31 @@ static void ipi_call_interrupt(void)
        smp_call_function_interrupt();
 }
 
+DECLARE_PER_CPU(struct clock_event_device, smtc_dummy_clockevent_device);
+
 void ipi_decode(struct smtc_ipi *pipi)
 {
+       unsigned int cpu = smp_processor_id();
+       struct clock_event_device *cd;
        void *arg_copy = pipi->arg;
        int type_copy = pipi->type;
-       int dest_copy = pipi->dest;
+       int ticks;
 
        smtc_ipi_nq(&freeIPIq, pipi);
        switch (type_copy) {
        case SMTC_CLOCK_TICK:
                irq_enter();
-               kstat_this_cpu.irqs[MIPS_CPU_IRQ_BASE + cp0_compare_irq]++;
-               /* Invoke Clock "Interrupt" */
-               ipi_timer_latch[dest_copy] = 0;
-#ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG
-               clock_hang_reported[dest_copy] = 0;
-#endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */
-               local_timer_interrupt(0, NULL);
+               kstat_this_cpu.irqs[MIPS_CPU_IRQ_BASE + 1]++;
+               cd = &per_cpu(smtc_dummy_clockevent_device, cpu);
+               ticks = atomic_read(&ipi_timer_latch[cpu]);
+               atomic_sub(ticks, &ipi_timer_latch[cpu]);
+               while (ticks) {
+                       cd->event_handler(cd);
+                       ticks--;
+               }
                irq_exit();
                break;
+
        case LINUX_SMP_IPI:
                switch ((int)arg_copy) {
                case SMP_RESCHEDULE_YOURSELF:
@@ -920,25 +936,6 @@ void deferred_smtc_ipi(void)
        }
 }
 
-/*
- * Send clock tick to all TCs except the one executing the funtion
- */
-
-void smtc_timer_broadcast(void)
-{
-       int cpu;
-       int myTC = cpu_data[smp_processor_id()].tc_id;
-       int myVPE = cpu_data[smp_processor_id()].vpe_id;
-
-       smtc_cpu_stats[smp_processor_id()].timerints++;
-
-       for_each_online_cpu(cpu) {
-               if (cpu_data[cpu].vpe_id == myVPE &&
-                   cpu_data[cpu].tc_id != myTC)
-                       smtc_send_ipi(cpu, SMTC_CLOCK_TICK, 0);
-       }
-}
-
 /*
  * Cross-VPE interrupts in the SMTC prototype use "software interrupts"
  * set via cross-VPE MTTR manipulation of the Cause register. It would be
@@ -1180,11 +1177,11 @@ void smtc_idle_loop_hook(void)
        for (tc = 0; tc < NR_CPUS; tc++) {
                /* Don't check ourself - we'll dequeue IPIs just below */
                if ((tc != smp_processor_id()) &&
-                   ipi_timer_latch[tc] > timerq_limit) {
+                   atomic_read(&ipi_timer_latch[tc]) > timerq_limit) {
                    if (clock_hang_reported[tc] == 0) {
                        pdb_msg += sprintf(pdb_msg,
                                "TC %d looks hung with timer latch at %d\n",
-                               tc, ipi_timer_latch[tc]);
+                               tc, atomic_read(&ipi_timer_latch[tc]));
                        clock_hang_reported[tc]++;
                        }
                }
@@ -1225,7 +1222,7 @@ void smtc_soft_dump(void)
        smtc_ipi_qdump();
        printk("Timer IPI Backlogs:\n");
        for (i=0; i < NR_CPUS; i++) {
-               printk("%d: %d\n", i, ipi_timer_latch[i]);
+               printk("%d: %d\n", i, atomic_read(&ipi_timer_latch[i]));
        }
        printk("%d Recoveries of \"stolen\" FPU\n",
               atomic_read(&smtc_fpu_recoveries));