#include <libkern/OSAtomic.h>
#include <libkern/c++/OSCollection.h>
+#include <IOKit/IODeviceTreeSupport.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOPlatformActions.h>
#include <IOKit/IOPMGR.h>
gPMGR->updateCPUIdle(new_timeout_ticks);
}
+static OSDictionary *
+matching_dict_for_cpu_id(unsigned int cpu_id)
+{
+ // The cpu-id property in EDT doesn't necessarily match the dynamically
+ // assigned logical ID in XNU, so look up the cpu node by the physical
+ // (cluster/core) ID instead.
+ OSSymbolConstPtr cpuTypeSymbol = OSSymbol::withCString("cpu");
+ OSSymbolConstPtr cpuIdSymbol = OSSymbol::withCString("reg");
+ OSDataPtr cpuId = OSData::withBytes(&(topology_info->cpus[cpu_id].phys_id), sizeof(uint32_t));
+
+ OSDictionary *propMatch = OSDictionary::withCapacity(4);
+ propMatch->setObject(gIODTTypeKey, cpuTypeSymbol);
+ propMatch->setObject(cpuIdSymbol, cpuId);
+
+ OSDictionary *matching = IOService::serviceMatching("IOPlatformDevice");
+ matching->setObject(gIOPropertyMatchKey, propMatch);
+
+ propMatch->release();
+ cpuTypeSymbol->release();
+ cpuIdSymbol->release();
+ cpuId->release();
+
+ return matching;
+}
+
static void
register_aic_handlers(const ml_topology_cpu *cpu_info,
ipi_handler_t ipi_handler,
perfmon_interrupt_handler_func pmi_handler)
{
- const int n_irqs = 3;
- int i;
- IOInterruptVectorNumber irqlist[n_irqs] = {
- cpu_info->self_ipi_irq,
- cpu_info->other_ipi_irq,
- cpu_info->pmi_irq };
-
- IOService *fakeCPU = new IOService();
- if (!fakeCPU || !fakeCPU->init()) {
- panic("Can't initialize fakeCPU");
- }
+ OSDictionary *matching = matching_dict_for_cpu_id(cpu_info->cpu_id);
+ IOService *cpu = IOService::waitForMatchingService(matching, UINT64_MAX);
+ matching->release();
- IOInterruptSource source[n_irqs];
- for (i = 0; i < n_irqs; i++) {
- source[i].vectorData = OSData::withBytes(&irqlist[i], sizeof(irqlist[0]));
+ OSArray *irqs = (OSArray *) cpu->getProperty(gIOInterruptSpecifiersKey);
+ if (!irqs) {
+ panic("Error finding interrupts for CPU %d", cpu_info->cpu_id);
}
- fakeCPU->_interruptSources = source;
- if (cpu_info->self_ipi_irq && cpu_info->other_ipi_irq) {
+ unsigned int irqcount = irqs->getCount();
+
+ if (irqcount == 3) {
// Legacy configuration, for !HAS_IPI chips (pre-Skye).
- if (gAIC->registerInterrupt(fakeCPU, 0, NULL, (IOInterruptHandler)ipi_handler, NULL) != kIOReturnSuccess ||
- gAIC->enableInterrupt(fakeCPU, 0) != kIOReturnSuccess ||
- gAIC->registerInterrupt(fakeCPU, 1, NULL, (IOInterruptHandler)ipi_handler, NULL) != kIOReturnSuccess ||
- gAIC->enableInterrupt(fakeCPU, 1) != kIOReturnSuccess) {
+ if (cpu->registerInterrupt(0, NULL, (IOInterruptAction)ipi_handler, NULL) != kIOReturnSuccess ||
+ cpu->enableInterrupt(0) != kIOReturnSuccess ||
+ cpu->registerInterrupt(2, NULL, (IOInterruptAction)ipi_handler, NULL) != kIOReturnSuccess ||
+ cpu->enableInterrupt(2) != kIOReturnSuccess) {
panic("Error registering IPIs");
}
#if !defined(HAS_IPI)
aic_ipis = true;
#endif
}
+
// Conditional, because on Skye and later, we use an FIQ instead of an external IRQ.
- if (pmi_handler && cpu_info->pmi_irq) {
- if (gAIC->registerInterrupt(fakeCPU, 2, NULL, (IOInterruptHandler)pmi_handler, NULL) != kIOReturnSuccess ||
- gAIC->enableInterrupt(fakeCPU, 2) != kIOReturnSuccess) {
+ if (pmi_handler && irqcount == 1) {
+ if (cpu->registerInterrupt(1, NULL, (IOInterruptAction)pmi_handler, NULL) != kIOReturnSuccess ||
+ cpu->enableInterrupt(1) != kIOReturnSuccess) {
panic("Error registering PMI");
}
}
-
- for (i = 0; i < n_irqs; i++) {
- source[i].vectorData->release();
- }
}
static void
}
memset(machProcessors, 0, array_size);
- ml_cpu_init_state();
for (unsigned int cpu = 0; cpu < topology_info->num_cpus; cpu++) {
const ml_topology_cpu *cpu_info = &topology_info->cpus[cpu];
const unsigned int cpu_id = cpu_info->cpu_id;
panic("processor_start failed");
}
}
+ ml_cpu_init_completed();
IOService::publishResource(gIOAllCPUInitializedKey, kOSBooleanTrue);
}
unsigned int cpu_id = target_to_cpu_id(target);
if (cpu_id != boot_cpu) {
- gPMGR->enableCPUCore(cpu_id);
+ extern unsigned int LowResetVectorBase;
+ gPMGR->enableCPUCore(cpu_id, ml_vtophys((vm_offset_t)&LowResetVectorBase));
}
return KERN_SUCCESS;
}