|
@@ -500,3 +500,118 @@ smp_cpus_done(unsigned int max_cpus)
|
|
|
|
|
|
|
|
|
|
void
|
|
void
|
|
|
|
+smp_percpu_timer_interrupt(struct pt_regs *regs)
|
|
|
|
+{
|
|
|
|
+ struct pt_regs *old_regs;
|
|
|
|
+ int cpu = smp_processor_id();
|
|
|
|
+ unsigned long user = user_mode(regs);
|
|
|
|
+ struct cpuinfo_alpha *data = &cpu_data[cpu];
|
|
|
|
+
|
|
|
|
+ old_regs = set_irq_regs(regs);
|
|
|
|
+
|
|
|
|
+ /* Record kernel PC. */
|
|
|
|
+ profile_tick(CPU_PROFILING);
|
|
|
|
+
|
|
|
|
+ if (!--data->prof_counter) {
|
|
|
|
+ /* We need to make like a normal interrupt -- otherwise
|
|
|
|
+ timer interrupts ignore the global interrupt lock,
|
|
|
|
+ which would be a Bad Thing. */
|
|
|
|
+ irq_enter();
|
|
|
|
+
|
|
|
|
+ update_process_times(user);
|
|
|
|
+
|
|
|
|
+ data->prof_counter = data->prof_multiplier;
|
|
|
|
+
|
|
|
|
+ irq_exit();
|
|
|
|
+ }
|
|
|
|
+ set_irq_regs(old_regs);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int
|
|
|
|
+setup_profiling_timer(unsigned int multiplier)
|
|
|
|
+{
|
|
|
|
+ return -EINVAL;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static void
|
|
|
|
+send_ipi_message(const struct cpumask *to_whom, enum ipi_message_type operation)
|
|
|
|
+{
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ mb();
|
|
|
|
+ for_each_cpu(i, to_whom)
|
|
|
|
+ set_bit(operation, &ipi_data[i].bits);
|
|
|
|
+
|
|
|
|
+ mb();
|
|
|
|
+ for_each_cpu(i, to_whom)
|
|
|
|
+ wripir(i);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void
|
|
|
|
+handle_ipi(struct pt_regs *regs)
|
|
|
|
+{
|
|
|
|
+ int this_cpu = smp_processor_id();
|
|
|
|
+ unsigned long *pending_ipis = &ipi_data[this_cpu].bits;
|
|
|
|
+ unsigned long ops;
|
|
|
|
+
|
|
|
|
+#if 0
|
|
|
|
+ DBGS(("handle_ipi: on CPU %d ops 0x%lx PC 0x%lx\n",
|
|
|
|
+ this_cpu, *pending_ipis, regs->pc));
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+ mb(); /* Order interrupt and bit testing. */
|
|
|
|
+ while ((ops = xchg(pending_ipis, 0)) != 0) {
|
|
|
|
+ mb(); /* Order bit clearing and data access. */
|
|
|
|
+ do {
|
|
|
|
+ unsigned long which;
|
|
|
|
+
|
|
|
|
+ which = ops & -ops;
|
|
|
|
+ ops &= ~which;
|
|
|
|
+ which = __ffs(which);
|
|
|
|
+
|
|
|
|
+ switch (which) {
|
|
|
|
+ case IPI_RESCHEDULE:
|
|
|
|
+ scheduler_ipi();
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case IPI_CALL_FUNC:
|
|
|
|
+ generic_smp_call_function_interrupt();
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case IPI_CALL_FUNC_SINGLE:
|
|
|
|
+ generic_smp_call_function_single_interrupt();
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case IPI_CPU_STOP:
|
|
|
|
+ halt();
|
|
|
|
+
|
|
|
|
+ default:
|
|
|
|
+ printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n",
|
|
|
|
+ this_cpu, which);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ } while (ops);
|
|
|
|
+
|
|
|
|
+ mb(); /* Order data access and bit testing. */
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ cpu_data[this_cpu].ipi_count++;
|
|
|
|
+
|
|
|
|
+ if (hwrpb->txrdy)
|
|
|
|
+ recv_secondary_console_msg();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void
|
|
|
|
+smp_send_reschedule(int cpu)
|
|
|
|
+{
|
|
|
|
+#ifdef DEBUG_IPI_MSG
|
|
|
|
+ if (cpu == hard_smp_processor_id())
|
|
|
|
+ printk(KERN_WARNING
|
|
|
|
+ "smp_send_reschedule: Sending IPI to self.\n");
|
|
|
|
+#endif
|
|
|
|
+ send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void
|
|
|
|
+smp_send_stop(void)
|