version 1.39.8.1, 1999/12/27 18:31:19 |
version 1.40, 1999/12/02 01:09:11 |
Line 96 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 96 __KERNEL_RCSID(0, "$NetBSD$"); |
|
struct cpu_info cpu_info[ALPHA_MAXPROCS]; |
struct cpu_info cpu_info[ALPHA_MAXPROCS]; |
|
|
/* Bitmask of CPUs currently running. */ |
/* Bitmask of CPUs currently running. */ |
__volatile u_long cpus_running; |
u_long cpus_running; |
|
|
void cpu_boot_secondary __P((struct cpu_info *)); |
void cpu_create_idle_thread __P((void *)); |
#else |
#else |
paddr_t curpcb; /* PA of our current context */ |
paddr_t curpcb; /* PA of our current context */ |
struct proc *fpcurproc; /* current owner of FPU */ |
struct proc *fpcurproc; /* current owner of FPU */ |
Line 155 struct cputable_struct { |
|
Line 155 struct cputable_struct { |
|
* works. |
* works. |
* |
* |
* As we find processors during the autoconfiguration sequence, all |
* As we find processors during the autoconfiguration sequence, all |
* processors have idle stacks and PCBs created for them, including |
* processors that are available and not the primary are set up to |
* the primary (although the primary idles on proc0's PCB until its |
* have a kernel thread created for them. This kernel thread will |
* idle PCB is created). |
* be that CPUs "idle thread" (analog of proc0). These threads are |
|
* created after init(8) is created. |
* |
* |
* Right before calling uvm_scheduler(), main() calls, on proc0's |
* cpu_create_idle_thread() creates one idle thread, and starts that |
* context, cpu_boot_secondary_processors(). This is our key to |
* thread's prcessor, switches it to OSF/1 PALcode, sets the entry point |
* actually spin up the additional processor's we've found. We |
* to cpu_spinup_trampoline, and then sends a "START" command to the |
* run through our cpu_info[] array looking for secondary processors |
* secondary processor's console. |
* with idle PCBs, and spin them up. |
|
* |
|
* The spinup involves switching the secondary processor to the |
|
* OSF/1 PALcode, setting the entry point to cpu_spinup_trampoline(), |
|
* and sending a "START" message to the secondary's console. |
|
* |
* |
* Upon successful processor bootup, the cpu_spinup_trampoline will call |
* Upon successful processor bootup, the cpu_spinup_trampoline will call |
* cpu_hatch(), which will print a message indicating that the processor |
* cpu_hatch(), which will print a message indicating that the processor |
Line 209 cpuattach(parent, dev, aux) |
|
Line 205 cpuattach(parent, dev, aux) |
|
#endif |
#endif |
u_int32_t major, minor; |
u_int32_t major, minor; |
#if defined(MULTIPROCESSOR) |
#if defined(MULTIPROCESSOR) |
extern paddr_t avail_start, avail_end; |
|
struct pcb *pcb; |
|
struct cpu_info *ci; |
struct cpu_info *ci; |
struct pglist mlist; |
|
int error; |
|
#endif |
#endif |
|
|
p = LOCATE_PCS(hwrpb, ma->ma_slot); |
p = LOCATE_PCS(hwrpb, ma->ma_slot); |
|
|
|
|
#if defined(MULTIPROCESSOR) |
#if defined(MULTIPROCESSOR) |
/* |
/* |
* Make sure the processor is available for use. |
* If we're the primary CPU, no more work to do; we're already |
|
* running! |
*/ |
*/ |
if ((p->pcs_flags & PCS_PA) == 0) { |
if (ma->ma_slot == hwrpb->rpb_primary_cpu_id) { |
if (ma->ma_slot == hwrpb->rpb_primary_cpu_id) |
u_long cpumask = (1UL << ma->ma_slot); |
panic("cpu_attach: primary not available?!"); |
|
printf("%s: processor not available for use\n", dev->dv_xname); |
|
return; |
|
} |
|
|
|
/* Make sure the processor has valid PALcode. */ |
ci->ci_flags |= CPUF_PRIMARY; |
if ((p->pcs_flags & PCS_PV) == 0) { |
ci->ci_idle_thread = &proc0; |
if (ma->ma_slot == hwrpb->rpb_primary_cpu_id) |
alpha_atomic_setbits_q(&cpus_running, cpumask); |
panic("cpu_attach: primary has invalid PALcode?!"); |
|
printf("%s: PALcode not valid\n", ci->ci_dev->dv_xname); |
|
return; |
return; |
} |
} |
|
|
/* |
/* |
* Allocate UPAGES contiguous pages for the idle PCB and stack. |
* Not the primary CPU; need to queue a kernel thread to be created |
|
* to be this processor's idle thread. The creation of the kernel |
|
* thread will also spin up the processor. |
*/ |
*/ |
TAILQ_INIT(&mlist); |
|
error = uvm_pglistalloc(USPACE, avail_start, avail_end, 0, 0, |
if ((p->pcs_flags & PCS_PA) == 0) { |
&mlist, 1, 1); |
printf("%s: processor not available for use\n", dev->dv_xname); |
if (error != 0) { |
|
if (ma->ma_slot == hwrpb->rpb_primary_cpu_id) { |
|
panic("cpu_attach: unable to alloate idle stack for" |
|
" primary"); |
|
} |
|
printf("%s: unable to allocate idle stack\n", dev->dv_xname); |
|
return; |
return; |
} |
} |
|
|
ci->ci_idle_pcb_paddr = VM_PAGE_TO_PHYS(TAILQ_FIRST(&mlist)); |
kthread_create(cpu_create_idle_thread, ci); |
pcb = ci->ci_idle_pcb = (struct pcb *) |
|
ALPHA_PHYS_TO_K0SEG(ci->ci_idle_pcb_paddr); |
|
memset(pcb, 0, USPACE); |
|
|
|
/* |
|
* Initialize the idle stack pointer, reserving space for an |
|
* (empty) trapframe (XXX is the trapframe really necessary?) |
|
*/ |
|
pcb->pcb_hw.apcb_ksp = |
|
(u_int64_t)pcb + USPACE - sizeof(struct trapframe); |
|
|
|
/* |
|
* Initialize the idle PCB. |
|
*/ |
|
pcb->pcb_hw.apcb_backup_ksp = pcb->pcb_hw.apcb_ksp; |
|
pcb->pcb_hw.apcb_asn = proc0.p_addr->u_pcb.pcb_hw.apcb_asn; |
|
pcb->pcb_hw.apcb_ptbr = proc0.p_addr->u_pcb.pcb_hw.apcb_ptbr; |
|
#if 0 |
|
printf("%s: hwpcb ksp = 0x%lx\n", sc->sc_dev.dv_xname, |
|
pcb->pcb_hw.apcb_ksp); |
|
printf("%s: hwpcb ptbr = 0x%lx\n", sc->sc_dev.dv_xname, |
|
pcb->pcb_hw.apcb_ptbr); |
|
#endif |
|
|
|
/* |
|
* If we're the primary CPU, no more work to do; we're already |
|
* running! |
|
*/ |
|
if (ma->ma_slot == hwrpb->rpb_primary_cpu_id) { |
|
ci->ci_flags |= CPUF_PRIMARY; |
|
alpha_atomic_setbits_q(&cpus_running, (1UL << ma->ma_slot)); |
|
} |
|
#endif /* MULTIPROCESSOR */ |
#endif /* MULTIPROCESSOR */ |
} |
} |
|
|
#if defined(MULTIPROCESSOR) |
#if defined(MULTIPROCESSOR) |
void |
void |
cpu_boot_secondary_processors() |
cpu_create_idle_thread(arg) |
{ |
void *arg; |
struct cpu_info *ci; |
|
u_long i; |
|
|
|
for (i = 0; i < ALPHA_MAXPROCS; i++) { |
|
ci = &cpu_info[i]; |
|
if (ci->ci_idle_pcb == NULL) |
|
continue; |
|
if (ci->ci_flags & CPUF_PRIMARY) |
|
continue; |
|
|
|
/* This processor is all set up; boot it! */ |
|
cpu_boot_secondary(ci); |
|
} |
|
} |
|
|
|
void |
|
cpu_boot_secondary(ci) |
|
struct cpu_info *ci; |
|
{ |
{ |
|
struct cpu_info *ci = arg; |
|
struct proc *p; |
long timeout; |
long timeout; |
struct pcs *pcsp, *primary_pcsp; |
struct pcs *pcsp, *primary_pcsp; |
struct pcb *pcb; |
struct pcb *pcb; |
u_long cpumask; |
u_long cpumask; |
|
|
pcb = ci->ci_idle_pcb; |
|
primary_pcsp = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id); |
primary_pcsp = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id); |
pcsp = LOCATE_PCS(hwrpb, ci->ci_cpuid); |
pcsp = LOCATE_PCS(hwrpb, ci->ci_cpuid); |
cpumask = (1UL << ci->ci_cpuid); |
cpumask = (1UL << ci->ci_cpuid); |
|
|
|
/* Make sure the processor has valid PALcode. */ |
|
if ((pcsp->pcs_flags & PCS_PV) == 0) { |
|
printf("%s: PALcode not valid\n", ci->ci_dev->dv_xname); |
|
return; |
|
} |
|
|
|
/* |
|
* Create the CPU's idle thread. Note, the thread entry point |
|
* and argument is effectively ignored in this case; we set up |
|
* the entry point below, when we set up the CPU's HWPCB. |
|
*/ |
|
if (kthread_create1(NULL, NULL, &ci->ci_idle_thread, "%s idle", |
|
ci->ci_dev->dv_xname)) { |
|
printf("%s: unable to create idle thread\n", |
|
ci->ci_dev->dv_xname); |
|
return; |
|
} |
|
p = ci->ci_idle_thread; |
|
|
/* |
/* |
* Set up the PCS's HWPCB to match ours. |
* Initialize the idle thread's PCB. Note we initialize the |
|
* ASN and PTBR now, but we're going to call pmap_activate() |
|
* immediately once the CPU is hatched. |
*/ |
*/ |
|
pcb = &p->p_addr->u_pcb; |
|
pcb->pcb_hw.apcb_backup_ksp = pcb->pcb_hw.apcb_ksp; |
|
pcb->pcb_hw.apcb_asn = proc0.p_addr->u_pcb.pcb_hw.apcb_asn; |
|
pcb->pcb_hw.apcb_ptbr = proc0.p_addr->u_pcb.pcb_hw.apcb_ptbr; |
memcpy(pcsp->pcs_hwpcb, &pcb->pcb_hw, sizeof(pcb->pcb_hw)); |
memcpy(pcsp->pcs_hwpcb, &pcb->pcb_hw, sizeof(pcb->pcb_hw)); |
|
#if 0 |
|
printf("%s: hwpcb ksp = 0x%lx\n", sc->sc_dev.dv_xname, |
|
pcb->pcb_hw.apcb_ksp); |
|
printf("%s: hwpcb ptbr = 0x%lx\n", sc->sc_dev.dv_xname, |
|
pcb->pcb_hw.apcb_ptbr); |
|
#endif |
|
|
/* |
/* |
* Set up the HWRPB to restart the secondary processor |
* Set up the HWRPB to restart the secondary processor |
Line 447 cpu_boot_secondary(ci) |
|
Line 412 cpu_boot_secondary(ci) |
|
*/ |
*/ |
for (timeout = 10000; timeout != 0; timeout--) { |
for (timeout = 10000; timeout != 0; timeout--) { |
alpha_mb(); |
alpha_mb(); |
if (cpus_running & cpumask) |
if ((volatile u_long)cpus_running & cpumask) |
break; |
break; |
delay(1000); |
delay(1000); |
} |
} |
Line 469 cpu_halt_secondary(cpu_id) |
|
Line 434 cpu_halt_secondary(cpu_id) |
|
#endif |
#endif |
|
|
alpha_mb(); |
alpha_mb(); |
if ((cpus_running & cpumask) == 0) { |
if (((volatile u_long)cpus_running & cpumask) == 0) { |
/* Processor not running. */ |
/* Processor not running. */ |
return; |
return; |
} |
} |
Line 480 cpu_halt_secondary(cpu_id) |
|
Line 445 cpu_halt_secondary(cpu_id) |
|
/* ...and wait for it to shut down. */ |
/* ...and wait for it to shut down. */ |
for (timeout = 10000; timeout != 0; timeout--) { |
for (timeout = 10000; timeout != 0; timeout--) { |
alpha_mb(); |
alpha_mb(); |
if ((cpus_running & cpumask) == 0) |
if (((volatile u_long)cpus_running & cpumask) == 0) |
return; |
return; |
delay(1000); |
delay(1000); |
} |
} |
|
|
u_long cpumask = (1UL << ci->ci_cpuid); |
u_long cpumask = (1UL << ci->ci_cpuid); |
|
|
/* Set our `curpcb' to reflect our context. */ |
/* Set our `curpcb' to reflect our context. */ |
curpcb = ci->ci_idle_pcb_paddr; |
curpcb = (paddr_t)ci->ci_idle_thread->p_md.md_pcbpaddr; |
|
|
/* Mark the kernel pmap active on this processor. */ |
/* Fully activate our address space. */ |
alpha_atomic_setbits_q(&pmap_kernel()->pm_cpus, cpumask); |
pmap_activate(ci->ci_idle_thread); |
|
|
/* Initialize trap vectors for this processor. */ |
/* Initialize trap vectors for this processor. */ |
trap_init(); |
trap_init(); |