void MacRISC2CPU::quiesceCPU(void) { if (bootCPU) { if (processorSpeedChange) { // Send PMU command to speed the system pmu->callPlatformFunction("setSpeedNow", false, (void *)currentProcessorSpeed, 0, 0, 0); } else { // Send PMU command to shutdown system before io is turned off if (!gPHibernateState || !*gPHibernateState) pmu->callPlatformFunction("sleepNow", false, 0, 0, 0, 0); // Disables the interrupts for this CPU. if (!haveSleptMPIC && (macRISC2PE->getMachineType() == kMacRISC2TypePowerMac)) { haveSleptMPIC = true; kprintf("MacRISC2CPU::quiesceCPU %ld -> mpic->setUpForSleep off", getCPUNumber()); mpic->callPlatformFunction(mpic_setUpForSleep, false, (void *)true, (void *)getCPUNumber(), 0, 0); } kprintf("MacRISC2CPU::quiesceCPU %ld -> keyLargo->saveRegisterState()\n", getCPUNumber()); // Save KeyLargo's register state. keyLargo->callPlatformFunction(keyLargo_saveRegisterState, false, 0, 0, 0, 0); // Turn Off all KeyLargo I/O. if (!gPHibernateState || !*gPHibernateState) { kprintf("MacRISC2CPU::quiesceCPU %ld -> keyLargo->turnOffIO\n", getCPUNumber()); keyLargo->callPlatformFunction(keyLargo_turnOffIO, false, (void *)false, 0, 0, 0); } } kprintf("MacRISC2CPU::quiesceCPU %ld -> here\n", getCPUNumber()); // Set the wake vector to point to the reset vector ml_phys_write(0x0080, 0x100); uniN->callPlatformFunction (uniN_setPowerState, false, (void *)(kUniNSave), (void *)0, (void *)0, (void *)0); if (processorSpeedChange || (!gPHibernateState || !*gPHibernateState)) { // Set the sleeping state for HWInit. // Tell Uni-N to enter normal mode. uniN->callPlatformFunction (uniN_setPowerState, false, (void *)(processorSpeedChange ? kUniNIdle2 : kUniNSleep), (void *)0, (void *)0, (void *)0); } } ml_ppc_sleep(); }
/* * Routine: cpu_start * Function: */ kern_return_t cpu_start( int cpu) { struct per_proc_info *proc_info; kern_return_t ret; mapping_t *mp; proc_info = PerProcTable[cpu].ppe_vaddr; if (cpu == cpu_number()) { PE_cpu_machine_init(proc_info->cpu_id, !(proc_info->cpu_flags & BootDone)); ml_init_interrupt(); proc_info->cpu_flags |= BootDone|SignalReady; return KERN_SUCCESS; } else { proc_info->cpu_flags &= BootDone; proc_info->interrupts_enabled = 0; proc_info->pending_ast = AST_NONE; proc_info->istackptr = proc_info->intstack_top_ss; proc_info->rtcPop = EndOfAllTime; proc_info->FPU_owner = NULL; proc_info->VMX_owner = NULL; proc_info->pms.pmsStamp = 0; /* Dummy transition time */ proc_info->pms.pmsPop = EndOfAllTime; /* Set the pop way into the future */ proc_info->pms.pmsState = pmsParked; /* Park the stepper */ proc_info->pms.pmsCSetCmd = pmsCInit; /* Set dummy initial hardware state */ mp = (mapping_t *)(&proc_info->ppUMWmp); mp->mpFlags = 0x01000000 | mpLinkage | mpPerm | 1; mp->mpSpace = invalSpace; if (proc_info->start_paddr == EXCEPTION_VECTOR(T_RESET)) { simple_lock(&rht_lock); while (rht_state & RHT_BUSY) { rht_state |= RHT_WAIT; thread_sleep_usimple_lock((event_t)&rht_state, &rht_lock, THREAD_UNINT); } rht_state |= RHT_BUSY; simple_unlock(&rht_lock); ml_phys_write((vm_offset_t)&ResetHandler + 0, RESET_HANDLER_START); ml_phys_write((vm_offset_t)&ResetHandler + 4, (vm_offset_t)_start_cpu); ml_phys_write((vm_offset_t)&ResetHandler + 8, (vm_offset_t)&PerProcTable[cpu]); } /* * Note: we pass the current time to the other processor here. He will load it * as early as possible so that there is a chance that it is close to accurate. * After the machine is up a while, we will officially resync the clocks so * that all processors are the same. This is just to get close. */ ml_get_timebase((unsigned long long *)&proc_info->ruptStamp); __asm__ volatile("sync"); /* Commit to storage */ __asm__ volatile("isync"); /* Wait a second */ ret = PE_cpu_start(proc_info->cpu_id, proc_info->start_paddr, (vm_offset_t)proc_info); if (ret != KERN_SUCCESS) { if (proc_info->start_paddr == EXCEPTION_VECTOR(T_RESET)) { simple_lock(&rht_lock); if (rht_state & RHT_WAIT) thread_wakeup(&rht_state); rht_state &= ~(RHT_BUSY|RHT_WAIT); simple_unlock(&rht_lock); }; } else { simple_lock(&SignalReadyLock); if (!((*(volatile short *)&proc_info->cpu_flags) & SignalReady)) { (void)hw_atomic_or(&proc_info->ppXFlags, SignalReadyWait); thread_sleep_simple_lock((event_t)&proc_info->cpu_flags, &SignalReadyLock, THREAD_UNINT); } simple_unlock(&SignalReadyLock); } return(ret); } }
/* * Routine: cpu_sleep * Function: */ void cpu_sleep( void) { struct per_proc_info *proc_info; unsigned int i; unsigned int wait_ncpus_sleep, ncpus_sleep; facility_context *fowner; proc_info = getPerProc(); proc_info->running = FALSE; fowner = proc_info->FPU_owner; /* Cache this */ if(fowner) /* If anyone owns FPU, save it */ fpu_save(fowner); proc_info->FPU_owner = NULL; /* Set no fpu owner now */ fowner = proc_info->VMX_owner; /* Cache this */ if(fowner) vec_save(fowner); /* If anyone owns vectors, save it */ proc_info->VMX_owner = NULL; /* Set no vector owner now */ if (proc_info->cpu_number == master_cpu) { proc_info->cpu_flags &= BootDone; proc_info->interrupts_enabled = 0; proc_info->pending_ast = AST_NONE; if (proc_info->start_paddr == EXCEPTION_VECTOR(T_RESET)) { ml_phys_write((vm_offset_t)&ResetHandler + 0, RESET_HANDLER_START); ml_phys_write((vm_offset_t)&ResetHandler + 4, (vm_offset_t)_start_cpu); ml_phys_write((vm_offset_t)&ResetHandler + 8, (vm_offset_t)&PerProcTable[master_cpu]); __asm__ volatile("sync"); __asm__ volatile("isync"); }