+
+
+/*
+ * Routine: cpu_timebase_signal_handler
+ * Function:
+ */
+void
+cpu_timebase_signal_handler(
+ struct per_proc_info *proc_info,
+ struct SIGtimebase *timebaseAddr)
+{
+ unsigned int tbu, tbu2, tbl;
+
+ if(proc_info->time_base_enable != (void(*)(cpu_id_t, boolean_t ))NULL)
+ proc_info->time_base_enable(proc_info->cpu_id, FALSE);
+
+ timebaseAddr->abstime = 0; /* Touch to force into cache */
+ sync();
+
+ do {
+ asm volatile(" mftbu %0" : "=r" (tbu));
+ asm volatile(" mftb %0" : "=r" (tbl));
+ asm volatile(" mftbu %0" : "=r" (tbu2));
+ } while (tbu != tbu2);
+
+ timebaseAddr->abstime = ((uint64_t)tbu << 32) | tbl;
+ sync(); /* Force order */
+
+ timebaseAddr->avail = TRUE;
+
+ while (timebaseAddr->ready == FALSE)
+ continue;
+
+ if(proc_info->time_base_enable != (void(*)(cpu_id_t, boolean_t ))NULL)
+ proc_info->time_base_enable(proc_info->cpu_id, TRUE);
+
+ timebaseAddr->done = TRUE;
+}
+
+
+/*
+ * Routine: cpu_control
+ * Function:
+ */
+kern_return_t
+cpu_control(
+ int slot_num,
+ processor_info_t info,
+ unsigned int count)
+{
+ struct per_proc_info *proc_info;
+ cpu_type_t tcpu_type;
+ cpu_subtype_t tcpu_subtype;
+ processor_pm_regs_t perf_regs;
+ processor_control_cmd_t cmd;
+ boolean_t oldlevel;
+#define MMCR0_SUPPORT_MASK 0xf83f1fff
+#define MMCR1_SUPPORT_MASK 0xffc00000
+#define MMCR2_SUPPORT_MASK 0x80000000
+
+ proc_info = PerProcTable[slot_num].ppe_vaddr;
+ tcpu_type = proc_info->cpu_type;
+ tcpu_subtype = proc_info->cpu_subtype;
+ cmd = (processor_control_cmd_t) info;
+
+ if (count < PROCESSOR_CONTROL_CMD_COUNT)
+ return(KERN_FAILURE);
+
+ if ( tcpu_type != cmd->cmd_cpu_type ||
+ tcpu_subtype != cmd->cmd_cpu_subtype)
+ return(KERN_FAILURE);
+
+ if (perfmon_acquire_facility(current_task()) != KERN_SUCCESS) {
+ return(KERN_RESOURCE_SHORTAGE); /* cpu performance facility in use by another task */
+ }
+
+ switch (cmd->cmd_op)
+ {
+ case PROCESSOR_PM_CLR_PMC: /* Clear Performance Monitor Counters */
+ switch (tcpu_subtype)
+ {
+ case CPU_SUBTYPE_POWERPC_750:
+ case CPU_SUBTYPE_POWERPC_7400:
+ case CPU_SUBTYPE_POWERPC_7450:
+ {
+ oldlevel = ml_set_interrupts_enabled(FALSE); /* disable interrupts */
+ mtpmc1(0x0);
+ mtpmc2(0x0);
+ mtpmc3(0x0);
+ mtpmc4(0x0);
+ ml_set_interrupts_enabled(oldlevel); /* enable interrupts */
+ return(KERN_SUCCESS);
+ }
+ default:
+ return(KERN_FAILURE);
+ } /* tcpu_subtype */
+ case PROCESSOR_PM_SET_REGS: /* Set Performance Monitor Registors */
+ switch (tcpu_subtype)
+ {
+ case CPU_SUBTYPE_POWERPC_750:
+ if (count < (PROCESSOR_CONTROL_CMD_COUNT +
+ PROCESSOR_PM_REGS_COUNT_POWERPC_750))
+ return(KERN_FAILURE);
+ else
+ {
+ perf_regs = (processor_pm_regs_t)cmd->cmd_pm_regs;
+ oldlevel = ml_set_interrupts_enabled(FALSE); /* disable interrupts */
+ mtmmcr0(PERFMON_MMCR0(perf_regs) & MMCR0_SUPPORT_MASK);
+ mtpmc1(PERFMON_PMC1(perf_regs));
+ mtpmc2(PERFMON_PMC2(perf_regs));
+ mtmmcr1(PERFMON_MMCR1(perf_regs) & MMCR1_SUPPORT_MASK);
+ mtpmc3(PERFMON_PMC3(perf_regs));
+ mtpmc4(PERFMON_PMC4(perf_regs));
+ ml_set_interrupts_enabled(oldlevel); /* enable interrupts */
+ return(KERN_SUCCESS);
+ }
+ case CPU_SUBTYPE_POWERPC_7400:
+ case CPU_SUBTYPE_POWERPC_7450:
+ if (count < (PROCESSOR_CONTROL_CMD_COUNT +
+ PROCESSOR_PM_REGS_COUNT_POWERPC_7400))
+ return(KERN_FAILURE);
+ else
+ {
+ perf_regs = (processor_pm_regs_t)cmd->cmd_pm_regs;
+ oldlevel = ml_set_interrupts_enabled(FALSE); /* disable interrupts */
+ mtmmcr0(PERFMON_MMCR0(perf_regs) & MMCR0_SUPPORT_MASK);
+ mtpmc1(PERFMON_PMC1(perf_regs));
+ mtpmc2(PERFMON_PMC2(perf_regs));
+ mtmmcr1(PERFMON_MMCR1(perf_regs) & MMCR1_SUPPORT_MASK);
+ mtpmc3(PERFMON_PMC3(perf_regs));
+ mtpmc4(PERFMON_PMC4(perf_regs));
+ mtmmcr2(PERFMON_MMCR2(perf_regs) & MMCR2_SUPPORT_MASK);
+ ml_set_interrupts_enabled(oldlevel); /* enable interrupts */
+ return(KERN_SUCCESS);
+ }
+ default:
+ return(KERN_FAILURE);
+ } /* switch tcpu_subtype */
+ case PROCESSOR_PM_SET_MMCR:
+ switch (tcpu_subtype)
+ {
+ case CPU_SUBTYPE_POWERPC_750:
+ if (count < (PROCESSOR_CONTROL_CMD_COUNT +
+ PROCESSOR_PM_REGS_COUNT_POWERPC_750))
+ return(KERN_FAILURE);
+ else
+ {
+ perf_regs = (processor_pm_regs_t)cmd->cmd_pm_regs;
+ oldlevel = ml_set_interrupts_enabled(FALSE); /* disable interrupts */
+ mtmmcr0(PERFMON_MMCR0(perf_regs) & MMCR0_SUPPORT_MASK);
+ mtmmcr1(PERFMON_MMCR1(perf_regs) & MMCR1_SUPPORT_MASK);
+ ml_set_interrupts_enabled(oldlevel); /* enable interrupts */
+ return(KERN_SUCCESS);
+ }
+ case CPU_SUBTYPE_POWERPC_7400:
+ case CPU_SUBTYPE_POWERPC_7450:
+ if (count < (PROCESSOR_CONTROL_CMD_COUNT +
+ PROCESSOR_PM_REGS_COUNT_POWERPC_7400))
+ return(KERN_FAILURE);
+ else
+ {
+ perf_regs = (processor_pm_regs_t)cmd->cmd_pm_regs;
+ oldlevel = ml_set_interrupts_enabled(FALSE); /* disable interrupts */
+ mtmmcr0(PERFMON_MMCR0(perf_regs) & MMCR0_SUPPORT_MASK);
+ mtmmcr1(PERFMON_MMCR1(perf_regs) & MMCR1_SUPPORT_MASK);
+ mtmmcr2(PERFMON_MMCR2(perf_regs) & MMCR2_SUPPORT_MASK);
+ ml_set_interrupts_enabled(oldlevel); /* enable interrupts */
+ return(KERN_SUCCESS);
+ }
+ default:
+ return(KERN_FAILURE);
+ } /* tcpu_subtype */
+ default:
+ return(KERN_FAILURE);
+ } /* switch cmd_op */
+}
+
+
+/*
+ * Routine: cpu_info_count
+ * Function:
+ */
+kern_return_t
+cpu_info_count(
+ processor_flavor_t flavor,
+ unsigned int *count)
+{
+ cpu_subtype_t tcpu_subtype;
+
+ /*
+ * For now, we just assume that all CPUs are of the same type
+ */
+ tcpu_subtype = PerProcTable[master_cpu].ppe_vaddr->cpu_subtype;
+ switch (flavor) {
+ case PROCESSOR_PM_REGS_INFO:
+ switch (tcpu_subtype) {
+ case CPU_SUBTYPE_POWERPC_750:
+
+ *count = PROCESSOR_PM_REGS_COUNT_POWERPC_750;
+ return(KERN_SUCCESS);
+
+ case CPU_SUBTYPE_POWERPC_7400:
+ case CPU_SUBTYPE_POWERPC_7450:
+
+ *count = PROCESSOR_PM_REGS_COUNT_POWERPC_7400;
+ return(KERN_SUCCESS);
+
+ default:
+ *count = 0;
+ return(KERN_INVALID_ARGUMENT);
+ } /* switch tcpu_subtype */
+
+ case PROCESSOR_TEMPERATURE:
+ *count = PROCESSOR_TEMPERATURE_COUNT;
+ return (KERN_SUCCESS);
+
+ default:
+ *count = 0;
+ return(KERN_INVALID_ARGUMENT);
+
+ }
+}
+
+
+/*
+ * Routine: cpu_info
+ * Function:
+ */
+kern_return_t
+cpu_info(
+ processor_flavor_t flavor,
+ int slot_num,
+ processor_info_t info,
+ unsigned int *count)
+{
+ cpu_subtype_t tcpu_subtype;
+ processor_pm_regs_t perf_regs;
+ boolean_t oldlevel;
+
+ tcpu_subtype = PerProcTable[slot_num].ppe_vaddr->cpu_subtype;
+
+ switch (flavor) {
+ case PROCESSOR_PM_REGS_INFO:
+
+ perf_regs = (processor_pm_regs_t) info;
+
+ switch (tcpu_subtype) {
+ case CPU_SUBTYPE_POWERPC_750:
+
+ if (*count < PROCESSOR_PM_REGS_COUNT_POWERPC_750)
+ return(KERN_FAILURE);
+
+ oldlevel = ml_set_interrupts_enabled(FALSE); /* disable interrupts */
+ PERFMON_MMCR0(perf_regs) = mfmmcr0();
+ PERFMON_PMC1(perf_regs) = mfpmc1();
+ PERFMON_PMC2(perf_regs) = mfpmc2();
+ PERFMON_MMCR1(perf_regs) = mfmmcr1();
+ PERFMON_PMC3(perf_regs) = mfpmc3();
+ PERFMON_PMC4(perf_regs) = mfpmc4();
+ ml_set_interrupts_enabled(oldlevel); /* enable interrupts */
+
+ *count = PROCESSOR_PM_REGS_COUNT_POWERPC_750;
+ return(KERN_SUCCESS);
+
+ case CPU_SUBTYPE_POWERPC_7400:
+ case CPU_SUBTYPE_POWERPC_7450:
+
+ if (*count < PROCESSOR_PM_REGS_COUNT_POWERPC_7400)
+ return(KERN_FAILURE);
+
+ oldlevel = ml_set_interrupts_enabled(FALSE); /* disable interrupts */
+ PERFMON_MMCR0(perf_regs) = mfmmcr0();
+ PERFMON_PMC1(perf_regs) = mfpmc1();
+ PERFMON_PMC2(perf_regs) = mfpmc2();
+ PERFMON_MMCR1(perf_regs) = mfmmcr1();
+ PERFMON_PMC3(perf_regs) = mfpmc3();
+ PERFMON_PMC4(perf_regs) = mfpmc4();
+ PERFMON_MMCR2(perf_regs) = mfmmcr2();
+ ml_set_interrupts_enabled(oldlevel); /* enable interrupts */
+
+ *count = PROCESSOR_PM_REGS_COUNT_POWERPC_7400;
+ return(KERN_SUCCESS);
+
+ default:
+ return(KERN_FAILURE);
+ } /* switch tcpu_subtype */
+
+ case PROCESSOR_TEMPERATURE: /* Get the temperature of a processor */
+
+ *info = -1; /* Get the temperature */
+ return(KERN_FAILURE);
+
+ default:
+ return(KERN_INVALID_ARGUMENT);
+
+ } /* flavor */
+}
+
+
+/*
+ * Routine: cpu_to_processor
+ * Function:
+ */
+processor_t
+cpu_to_processor(
+ int cpu)
+{
+ return ((processor_t)PerProcTable[cpu].ppe_vaddr->processor);
+}
+
+
+/*
+ * Routine: slot_type
+ * Function:
+ */
+cpu_type_t
+slot_type(
+ int slot_num)
+{
+ return (PerProcTable[slot_num].ppe_vaddr->cpu_type);
+}
+
+
+/*
+ * Routine: slot_subtype
+ * Function:
+ */
+cpu_subtype_t
+slot_subtype(
+ int slot_num)
+{
+ return (PerProcTable[slot_num].ppe_vaddr->cpu_subtype);
+}
+
+
+/*
+ * Routine: slot_threadtype
+ * Function:
+ */
+cpu_threadtype_t
+slot_threadtype(
+ int slot_num)
+{
+ return (PerProcTable[slot_num].ppe_vaddr->cpu_threadtype);
+}
+
+
+/*
+ * Routine: cpu_type
+ * Function:
+ */
+cpu_type_t
+cpu_type(void)
+{
+ return (getPerProc()->cpu_type);
+}
+
+
+/*
+ * Routine: cpu_subtype
+ * Function:
+ */
+cpu_subtype_t
+cpu_subtype(void)
+{
+ return (getPerProc()->cpu_subtype);
+}
+
+
+/*
+ * Routine: cpu_threadtype
+ * Function:
+ */
+cpu_threadtype_t
+cpu_threadtype(void)
+{
+ return (getPerProc()->cpu_threadtype);
+}
+
+/*
+ * Call a function on all running processors
+ *
+ * Note that the synch paramter is used to wait until all functions are complete.
+ * It is not passed to the other processor and must be known by the called function.
+ * The called function must do a thread_wakeup on the synch if it decrements the
+ * synch count to 0.
+ *
+ * We start by initializing the synchronizer to the number of possible cpus.
+ * The we signal each popssible processor.
+ * If the signal fails, we count it. We also skip our own.
+ * When we are finished signaling, we adjust the syncronizer count down buy the number of failed signals.
+ * Because the signaled processors are also decrementing the synchronizer count, the adjustment may result in a 0
+ * If this happens, all other processors are finished with the function.
+ * If so, we clear the wait and continue
+ * Otherwise, we block waiting for the other processor(s) to finish.
+ *
+ * Meanwhile, the other processors are decrementing the synchronizer when they are done
+ * If it goes to zero, thread_wakeup is called to run the broadcaster
+ *
+ * Note that because we account for the broadcaster in the synchronization count, we will not get any
+ * premature wakeup calls.
+ *
+ * Also note that when we do the adjustment of the synchronization count, it the result is 0, it means that
+ * all of the other processors are finished. Otherwise, we know that there is at least one more.
+ * When that thread decrements the synchronizer to zero, it will do a thread_wake.
+ *
+ */
+
+int32_t
+cpu_broadcast(uint32_t *synch, broadcastFunc func, uint32_t parm)
+{
+ int failsig;
+ unsigned int cpu, ocpu;
+
+ cpu = cpu_number(); /* Who are we? */
+ failsig = 0; /* Clear called processor count */
+
+ if(real_ncpus > 1) { /* Are we just a uni? */
+
+ *synch = real_ncpus; /* Set how many we are going to try */
+ assert_wait((event_t)synch, THREAD_UNINT); /* If more than one processor, we may have to wait */
+
+ for(ocpu = 0; ocpu < real_ncpus; ocpu++) { /* Tell everyone to call */
+
+ if(ocpu == cpu) continue; /* If we talk to ourselves, people will wonder... */
+
+ if(KERN_SUCCESS != cpu_signal(ocpu, SIGPcall, (uint32_t)func, parm)) { /* Call the function on the other processor */
+ failsig++; /* Count failed signals */
+ }
+ }
+
+ if (hw_atomic_sub(synch, failsig + 1) == 0)
+ clear_wait(current_thread(), THREAD_AWAKENED); /* Clear wait if we never signalled or all of the others finished */
+ else
+ thread_block(THREAD_CONTINUE_NULL); /* Wait for everyone to get into step... */
+ }
+
+ return (real_ncpus - failsig - 1); /* Return the number of guys actually signalled... */
+}