#include <i386/cpuid.h>
#include <i386/machine_cpu.h>
#include <i386/lock.h>
+#include <i386/perfmon.h>
/*
* Kernel parameter determining whether threads are halted unconditionally
*/
int idlehalt = 1;
-void
-cpu_thread_init(void)
+
+static boolean_t
+cpu_is_hyperthreaded(void)
{
- int my_cpu = get_cpu_number();
- int my_core_base_cpu;
- int ret;
- cpu_core_t *my_core;
+ if (cpuid_features() & CPUID_FEATURE_HTT)
+ return (cpuid_info()->cpuid_logical_per_package /
+ cpuid_info()->cpuid_cores_per_package) > 1;
+ else
+ return FALSE;
+}
- /* Have we initialized already for this cpu? */
- if (cpu_core())
- return;
+void *
+cpu_thread_alloc(int cpu)
+{
+ int core_base_cpu;
+ int ret;
+ cpu_core_t *core;
- if (cpuid_features() & CPUID_FEATURE_HTT) {
+ /*
+ * Assume that all cpus have the same features.
+ */
+ if (cpu_is_hyperthreaded()) {
/*
* Get the cpu number of the base thread in the core.
*/
- my_core_base_cpu = cpu_to_core_cpu(my_cpu);
- current_cpu_datap()->cpu_threadtype = CPU_THREADTYPE_INTEL_HTT;
+ core_base_cpu = cpu_to_core_cpu(cpu);
+ cpu_datap(cpu)->cpu_threadtype = CPU_THREADTYPE_INTEL_HTT;
} else {
- my_core_base_cpu = my_cpu;
- current_cpu_datap()->cpu_threadtype = CPU_THREADTYPE_NONE;
+ core_base_cpu = cpu;
+ cpu_datap(cpu)->cpu_threadtype = CPU_THREADTYPE_NONE;
}
- /*
- * Allocate the base cpu_core struct if none exists.
- * Since we could be racing with other threads in the same core,
- * this needs care without using locks. We allocate a new core
- * structure and assign it atomically, freeing it if we lost the race.
- */
- my_core = (cpu_core_t *) cpu_to_core(my_core_base_cpu);
- if (my_core == NULL) {
- cpu_core_t *new_core;
-
+ core = (cpu_core_t *) cpu_to_core(core_base_cpu);
+ if (core == NULL) {
ret = kmem_alloc(kernel_map,
- (void *) &new_core, sizeof(cpu_core_t));
+ (void *) &core, sizeof(cpu_core_t));
if (ret != KERN_SUCCESS)
- panic("cpu_thread_init() kmem_alloc ret=%d\n", ret);
- bzero((void *) new_core, sizeof(cpu_core_t));
- new_core->base_cpu = my_core_base_cpu;
- if (atomic_cmpxchg((uint32_t *) &cpu_to_core(my_core_base_cpu),
- 0, (uint32_t) new_core)) {
- atomic_incl((long *) &machine_info.physical_cpu, 1);
- atomic_incl((long *) &machine_info.physical_cpu_max, 1);
- } else {
- kmem_free(kernel_map,
- (vm_offset_t)new_core, sizeof(cpu_core_t));
- }
- my_core = (cpu_core_t *) cpu_to_core(my_core_base_cpu);
+ panic("cpu_thread_alloc() kmem_alloc ret=%d\n", ret);
+ bzero((void *) core, sizeof(cpu_core_t));
+
+ core->base_cpu = core_base_cpu;
+
+ atomic_incl((long *) &machine_info.physical_cpu_max, 1);
+
+ /* Allocate performance counter data area (if available) */
+ core->pmc = pmc_alloc();
}
+ atomic_incl((long *) &machine_info.logical_cpu_max, 1);
- cpu_to_core(my_cpu) = (struct cpu_core *) my_core;
+ return (void *) core;
+}
+
+void
+cpu_thread_init(void)
+{
+ int my_cpu = get_cpu_number();
+ cpu_core_t *my_core;
+
+ /*
+ * If we're the boot processor we allocate the core structure here.
+ * Otherwise the core has already been allocated (by the boot cpu).
+ */
+ if (my_cpu == master_cpu)
+ cpu_to_core(master_cpu) = cpu_thread_alloc(master_cpu);
+
+ my_core = cpu_core();
+ if (my_core == NULL)
+ panic("cpu_thread_init() no core allocated for cpu %d", my_cpu);
atomic_incl((long *) &my_core->active_threads, 1);
- atomic_incl((long *) &my_core->num_threads, 1);
atomic_incl((long *) &machine_info.logical_cpu, 1);
- atomic_incl((long *) &machine_info.logical_cpu_max, 1);
-
+ /* Note: cpus are started serially so this isn't as racey as it looks */
+ if (my_core->num_threads == 0)
+ atomic_incl((long *) &machine_info.physical_cpu, 1);
+ atomic_incl((long *) &my_core->num_threads, 1);
}
/*
{
cpu_core_t *my_core = cpu_core();
- /* Note: don't ever decrement the number of physical processors */
- atomic_decl((long *) &my_core->active_threads, 1);
- atomic_decl((long *) &my_core->num_threads, 1);
atomic_decl((long *) &machine_info.logical_cpu, 1);
+ atomic_decl((long *) &my_core->active_threads, 1);
+ if (atomic_decl_and_test((long *) &my_core->num_threads, 1))
+ atomic_decl((long *) &machine_info.physical_cpu, 1);
cpu_halt();
}