MFp4: SMP support

This commit is contained in:
marcel 2008-04-27 22:33:43 +00:00
parent 20ebf9deb0
commit 20ca53a7f4
16 changed files with 715 additions and 137 deletions

View File

@ -68,6 +68,7 @@ powerpc/aim/interrupt.c optional aim
powerpc/aim/locore.S optional aim no-obj
powerpc/aim/machdep.c optional aim
powerpc/aim/mmu_oea.c optional aim
powerpc/aim/mp_cpudep.c optional aim smp
powerpc/aim/nexus.c optional aim
powerpc/aim/ofw_machdep.c optional aim
powerpc/aim/ofwmagic.S optional aim

View File

@ -61,10 +61,11 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>
#include <sys/bus.h>
#include <sys/timetc.h>
#include <sys/interrupt.h>
#include <sys/pcpu.h>
#include <sys/sysctl.h>
#include <sys/timetc.h>
#include <dev/ofw/openfirm.h>
@ -76,11 +77,9 @@ __FBSDID("$FreeBSD$");
/*
* Initially we assume a processor with a bus frequency of 12.5 MHz.
*/
u_int tickspending;
u_long ns_per_tick = 80;
static u_long ticks_per_sec = 12500000;
static long ticks_per_intr;
static volatile u_long lasttb;
static timecounter_get_t decr_get_timecount;
@ -95,7 +94,6 @@ static struct timecounter decr_timecounter = {
void
decr_intr(struct trapframe *frame)
{
u_long tb;
long tick;
int nticks;
@ -109,36 +107,17 @@ decr_intr(struct trapframe *frame)
* Based on the actual time delay since the last decrementer reload,
* we arrange for earlier interrupt next time.
*/
__asm ("mftb %0; mfdec %1" : "=r"(tb), "=r"(tick));
__asm ("mfdec %0" : "=r"(tick));
for (nticks = 0; tick < 0; nticks++)
tick += ticks_per_intr;
mtdec(tick);
/*
* lasttb is used during microtime. Set it to the virtual
* start of this tick interval.
*/
lasttb = tb + tick - ticks_per_intr;
nticks += tickspending;
tickspending = 0;
/*
* Reenable interrupts
*/
#if 0
msr = mfmsr();
mtmsr(msr | PSL_EE | PSL_RI);
#endif
/*
* Do standard timer interrupt stuff.
* Do softclock stuff only on the last iteration.
*/
#if 0
while (--nticks > 0) {
while (nticks-- > 0) {
if (PCPU_GET(cpuid) == 0)
hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
else
hardclock_cpu(TRAPF_USERMODE(frame));
}
#endif
hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
}
void
@ -166,7 +145,6 @@ decr_init(void)
ns_per_tick = 1000000000 / ticks_per_sec;
ticks_per_intr = ticks_per_sec / hz;
__asm __volatile ("mftb %0" : "=r"(lasttb));
mtdec(ticks_per_intr);
mtmsr(msr);

View File

@ -77,20 +77,21 @@
.globl kernbase
.set kernbase, KERNBASE
#define TMPSTKSZ 8192 /* 8K temporary stack */
/*
* Globals
*/
.data
.align 4
GLOBAL(tmpstk)
.space 8192
.space TMPSTKSZ
GLOBAL(esym)
.long 0 /* end of symbol table */
GLOBAL(ofmsr)
.long 0, 0, 0, 0, 0 /* msr/sprg0-3 used in Open Firmware */
#define INTSTK 16384 /* 16K interrupt stack */
#define INTRCNT_COUNT 256 /* max(HROWPIC_IRQMAX,OPENPIC_IRQMAX) */
GLOBAL(intrnames)
.space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2
@ -152,9 +153,8 @@ __start:
stw 5,openfirmware_entry@l(8) /* save client interface handler */
mr 3,5
lis 1,tmpstk@ha
addi 1,1,tmpstk@l
addi 1,1,8192-16
lis 1,(tmpstk+TMPSTKSZ-16)@ha
addi 1,1,(tmpstk+TMPSTKSZ-16)@l
mfmsr 0
lis 9,ofmsr@ha

View File

@ -129,7 +129,8 @@ extern vm_offset_t ksym_start, ksym_end;
int cold = 1;
static struct pcpu pcpu0;
struct pcpu __pcpu[MAXCPU];
static struct trapframe frame0;
char machine[] = "powerpc";
@ -236,6 +237,9 @@ cpu_startup(void *dummy)
extern char kernel_text[], _end[];
#ifdef SMP
extern void *rstcode, *rstsize;
#endif
extern void *trapcode, *trapsize;
extern void *alitrap, *alisize;
extern void *dsitrap, *dsisize;
@ -288,7 +292,7 @@ powerpc_init(u_int startkernel, u_int endkernel, u_int basekernel, void *mdp)
/*
* Set up per-cpu data.
*/
pc = &pcpu0;
pc = __pcpu;
pcpu_init(pc, 0, sizeof(struct pcpu));
pc->pc_curthread = &thread0;
pc->pc_cpuid = 0;
@ -320,7 +324,11 @@ powerpc_init(u_int startkernel, u_int endkernel, u_int basekernel, void *mdp)
*/
mtmsr(mfmsr() & ~(PSL_IR | PSL_DR));
isync();
#ifdef SMP
bcopy(&rstcode, (void *)EXC_RST, (size_t)&rstsize);
#else
bcopy(&trapcode, (void *)EXC_RST, (size_t)&trapsize);
#endif
bcopy(&trapcode, (void *)EXC_MCHK, (size_t)&trapsize);
bcopy(&dsitrap, (void *)EXC_DSI, (size_t)&dsisize);
bcopy(&trapcode, (void *)EXC_ISI, (size_t)&trapsize);
@ -337,7 +345,6 @@ powerpc_init(u_int startkernel, u_int endkernel, u_int basekernel, void *mdp)
bcopy(&trapcode, (void *)EXC_THRM, (size_t)&trapsize);
bcopy(&trapcode, (void *)EXC_BPT, (size_t)&trapsize);
#ifdef KDB
bcopy(&dblow, (void *)EXC_RST, (size_t)&dbsize);
bcopy(&dblow, (void *)EXC_MCHK, (size_t)&dbsize);
bcopy(&dblow, (void *)EXC_PGM, (size_t)&dbsize);
bcopy(&dblow, (void *)EXC_TRC, (size_t)&dbsize);

View File

@ -147,6 +147,7 @@ __FBSDID("$FreeBSD$");
#include <machine/md_var.h>
#include <machine/psl.h>
#include <machine/pte.h>
#include <machine/smp.h>
#include <machine/sr.h>
#include <machine/mmuvar.h>
@ -203,8 +204,6 @@ static struct ofw_map *translations;
extern struct pmap ofw_pmap;
/*
* Lock for the pteg and pvo tables.
*/
@ -604,6 +603,59 @@ om_cmp(const void *a, const void *b)
return (0);
}
void
pmap_cpu_bootstrap(volatile uint32_t *trcp, int ap)
{
u_int sdr;
int i;
trcp[0] = 0x1000;
trcp[1] = (uint32_t)&pmap_cpu_bootstrap;
if (ap) {
__asm __volatile("mtdbatu 0,%0" :: "r"(battable[0].batu));
__asm __volatile("mtdbatl 0,%0" :: "r"(battable[0].batl));
isync();
__asm __volatile("mtibatu 0,%0" :: "r"(battable[0].batu));
__asm __volatile("mtibatl 0,%0" :: "r"(battable[0].batl));
isync();
}
trcp[0] = 0x1001;
for (i = 1; i < 4; i++) {
__asm __volatile("mtdbatu %0,%1" :: "n"(i), "r"(0));
__asm __volatile("mtibatu %0,%1" :: "n"(i), "r"(0));
isync();
}
trcp[0] = 0x1002;
__asm __volatile("mtdbatu 1,%0" :: "r"(battable[8].batu));
__asm __volatile("mtdbatl 1,%0" :: "r"(battable[8].batl));
isync();
trcp[0] = 0x1003;
for (i = 0; i < 16; i++)
mtsrin(i << ADDR_SR_SHFT, EMPTY_SEGMENT);
trcp[0] = 0x1004;
__asm __volatile("mtsr %0,%1" :: "n"(KERNEL_SR), "r"(KERNEL_SEGMENT));
__asm __volatile("mtsr %0,%1" :: "n"(KERNEL2_SR), "r"(KERNEL2_SEGMENT));
__asm __volatile("sync");
trcp[0] = 0x1005;
sdr = (u_int)moea_pteg_table | (moea_pteg_mask >> 10);
__asm __volatile("mtsdr1 %0" :: "r"(sdr));
isync();
trcp[0] = 0x1006;
trcp[1] = sdr;
}
void
moea_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend)
{
@ -612,9 +664,9 @@ moea_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend)
int sz;
int i, j;
int ofw_mappings;
uint32_t trace[2];
vm_size_t size, physsz, hwphyssz;
vm_offset_t pa, va, off;
u_int batl, batu;
/*
* Set up BAT0 to map the lowest 256 MB area
@ -647,18 +699,15 @@ moea_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend)
* Use an IBAT and a DBAT to map the bottom segment of memory
* where we are.
*/
batu = BATU(0x00000000, BAT_BL_256M, BAT_Vs);
batl = BATL(0x00000000, BAT_M, BAT_PP_RW);
__asm (".balign 32; \n"
"mtibatu 0,%0; mtibatl 0,%1; isync; \n"
"mtdbatu 0,%0; mtdbatl 0,%1; isync"
:: "r"(batu), "r"(batl));
:: "r"(battable[0].batu), "r"(battable[0].batl));
/* map pci space */
batu = BATU(0x80000000, BAT_BL_256M, BAT_Vs);
batl = BATL(0x80000000, BAT_I|BAT_G, BAT_PP_RW);
__asm ("mtdbatu 1,%0; mtdbatl 1,%1; isync"
:: "r"(batu), "r"(batl));
__asm __volatile("mtdbatu 1,%0" :: "r"(battable[8].batu));
__asm __volatile("mtdbatl 1,%0" :: "r"(battable[8].batl));
isync();
mem_regions(&pregions, &pregions_sz, &regions, &regions_sz);
CTR0(KTR_PMAP, "moea_bootstrap: physical memory");
@ -844,18 +893,7 @@ moea_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend)
kernel_pmap->pm_sr[KERNEL2_SR] = KERNEL2_SEGMENT;
kernel_pmap->pm_active = ~0;
/*
* Initialize hardware.
*/
for (i = 0; i < 16; i++) {
mtsrin(i << ADDR_SR_SHFT, EMPTY_SEGMENT);
}
__asm __volatile ("mtsr %0,%1"
:: "n"(KERNEL_SR), "r"(KERNEL_SEGMENT));
__asm __volatile ("mtsr %0,%1"
:: "n"(KERNEL2_SR), "r"(KERNEL2_SEGMENT));
__asm __volatile ("sync; mtsdr1 %0; isync"
:: "r"((u_int)moea_pteg_table | (moea_pteg_mask >> 10)));
pmap_cpu_bootstrap(trace, 0);
tlbia();
pmap_bootstrapped++;

231
sys/powerpc/aim/mp_cpudep.c Normal file
View File

@ -0,0 +1,231 @@
/*-
* Copyright (c) 2008 Marcel Moolenaar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/pcpu.h>
#include <sys/proc.h>
#include <sys/smp.h>
#include <machine/bat.h>
#include <machine/bus.h>
#include <machine/cpu.h>
#include <machine/hid.h>
#include <machine/intr_machdep.h>
#include <machine/pcb.h>
#include <machine/psl.h>
#include <machine/smp.h>
#include <machine/spr.h>
#include <machine/trap_aim.h>
#include <dev/ofw/openfirm.h>
#include <machine/ofw_machdep.h>
extern void *rstcode;
void *ap_pcpu;
static int
powerpc_smp_fill_cpuref(struct cpuref *cpuref, phandle_t cpu)
{
int cpuid, res;
cpuref->cr_hwref = cpu;
res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid));
if (res < 0)
return (ENOENT);
cpuref->cr_cpuid = cpuid & 0xff;
return (0);
}
int
powerpc_smp_first_cpu(struct cpuref *cpuref)
{
char buf[8];
phandle_t cpu, dev, root;
int res;
root = OF_peer(0);
dev = OF_child(root);
while (dev != 0) {
res = OF_getprop(dev, "name", buf, sizeof(buf));
if (res > 0 && strcmp(buf, "cpus") == 0)
break;
dev = OF_peer(dev);
}
if (dev == 0)
return (ENOENT);
cpu = OF_child(dev);
while (cpu != 0) {
res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
if (res > 0 && strcmp(buf, "cpu") == 0)
break;
cpu = OF_peer(cpu);
}
if (cpu == 0)
return (ENOENT);
return (powerpc_smp_fill_cpuref(cpuref, cpu));
}
int
powerpc_smp_next_cpu(struct cpuref *cpuref)
{
char buf[8];
phandle_t cpu;
int res;
cpu = OF_peer(cpuref->cr_hwref);
while (cpu != 0) {
res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
if (res > 0 && strcmp(buf, "cpu") == 0)
break;
cpu = OF_peer(cpu);
}
if (cpu == 0)
return (ENOENT);
return (powerpc_smp_fill_cpuref(cpuref, cpu));
}
int
powerpc_smp_get_bsp(struct cpuref *cpuref)
{
ihandle_t inst;
phandle_t bsp, chosen;
int res;
chosen = OF_finddevice("/chosen");
if (chosen == 0)
return (ENXIO);
res = OF_getprop(chosen, "cpu", &inst, sizeof(inst));
if (res < 0)
return (ENXIO);
bsp = OF_instance_to_package(inst);
return (powerpc_smp_fill_cpuref(cpuref, bsp));
}
uint32_t
cpudep_ap_bootstrap(volatile uint32_t *trcp)
{
uint32_t hid, msr, sp;
trcp[0] = 0x2000;
trcp[1] = (uint32_t)&cpudep_ap_bootstrap;
__asm __volatile("mtsprg 0, %0" :: "r"(ap_pcpu));
__asm __volatile("sync");
trcp[0] = 0x2001;
trcp[1] = (uint32_t)pcpup;
hid = mfspr(SPR_HID0);
hid &= ~(HID0_ICE | HID0_DCE);
hid &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP);
mtspr(SPR_HID0, hid);
isync();
trcp[0] = 0x2002;
trcp[1] = hid;
hid |= HID0_ICFI | HID0_DCFI;
hid |= HID0_ICE | HID0_DCE;
mtspr(SPR_HID0, hid);
isync();
trcp[0] = 0x2003;
trcp[1] = hid;
msr = PSL_IR | PSL_DR | PSL_ME;
mtmsr(msr);
isync();
trcp[0] = 0x2004;
trcp[1] = msr;
hid |= HID0_NAP | HID0_DPM;
mtspr(SPR_HID0, hid);
isync();
trcp[0] = 0x2005;
trcp[1] = hid;
pcpup->pc_curthread = pcpup->pc_idlethread;
pcpup->pc_curpcb = pcpup->pc_curthread->td_pcb;
sp = pcpup->pc_curpcb->pcb_sp;
trcp[0] = 0x2006;
trcp[1] = sp;
return (sp);
}
int
powerpc_smp_start_cpu(struct pcpu *pc)
{
phandle_t cpu;
volatile uint32_t *trcp;
volatile uint8_t *rstvec;
uint32_t trace;
int res, reset, timeout;
cpu = pc->pc_hwref;
res = OF_getprop(cpu, "soft-reset", &reset, sizeof(reset));
if (res < 0)
return (ENXIO);
trcp = (uint32_t *)(EXC_RST + 4);
trace = *trcp;
ap_pcpu = pc;
rstvec = (uint8_t *)(0x80000000 + reset);
*rstvec = 4;
__asm __volatile("sync");
DELAY(1);
*rstvec = 0;
__asm __volatile("sync");
timeout = 1000;
while (!pc->pc_awake && timeout--)
DELAY(100);
if (!pc->pc_awake)
printf("XXX: timeout (trace=%x; data=%x)\n", trcp[0], trcp[1]);
return (0);
}

View File

@ -66,6 +66,13 @@
#include <machine/psl.h>
#include <machine/asm.h>
/*
* void cpu_throw(struct thread *old, struct thread *new)
*/
ENTRY(cpu_throw)
mr %r15, %r4
b cpu_switchin
/*
* void cpu_switch(struct thread *old,
* struct thread *new,
@ -94,7 +101,8 @@ ENTRY(cpu_switch)
mr %r14,%r3 /* Copy the old thread ptr... */
mr %r15,%r4 /* and the new thread ptr in scratch */
lwz %r6,PCB_FLAGS(%r5) /* Save FPU context if needed */
lwz %r6,PCB_FLAGS(%r5)
/* Save FPU context if needed */
andi. %r6, %r6, PCB_FPU
beq .L1
bl save_fpu
@ -102,6 +110,7 @@ ENTRY(cpu_switch)
.L1:
bl pmap_deactivate /* Deactivate the current pmap */
cpu_switchin:
mr %r3,%r15 /* Get new thread ptr */
bl pmap_activate /* Activate the new address space */
@ -110,7 +119,8 @@ ENTRY(cpu_switch)
lwz %r17,TD_PCB(%r15) /* Store new current PCB */
stw %r17,PC_CURPCB(%r7)
lwz %r6, PCB_FLAGS(%r17) /* Restore FPU context if needed */
lwz %r6, PCB_FLAGS(%r17)
/* Restore FPU context if needed */
andi. %r6, %r6, PCB_FPU
beq .L2
mr %r3,%r15 /* Pass curthread to enable_fpu */

View File

@ -228,20 +228,67 @@
mfsprg2 %r2; /* restore r2 & r3 */ \
mfsprg3 %r3
#ifdef KDB
#ifdef SMP
/*
* Define the kdb debugger stack
* Processor reset exception handler. These are typically
* the first instructions the processor executes after a
* software reset.
*/
.data
GLOBAL(dbstk)
.space INTSTK+8 /* kdb stack */
.globl CNAME(rstcode), CNAME(rstsize)
CNAME(rstcode):
bl 1f
/* We use this space for tracing purposes. */
.long 0
.long 0
1:
mflr %r2
mfmsr %r3
stw %r2,0(%r2) /* trace: 0x104 - we're here. */
stw %r3,4(%r2) /* trace data: MSR */
sync
lis %r1,(tmpstk+TMPSTKSZ-16)@ha
addi %r1,%r1,(tmpstk+TMPSTKSZ-16)@l
addi %r3,%r2,4
stw %r3,0(%r1)
sync
stw %r3,0(%r2) /* trace: 0x108 - stack is writable */
stw %r1,4(%r2) /* trace data: SP */
sync
mr %r3,%r2
lis %r4,1@l
bla CNAME(pmap_cpu_bootstrap)
addi %r3,%r2,8
stw %r3,0(%r2) /* trace 0x10c - back from 1st call */
sync
mr %r3,%r2
bla CNAME(cpudep_ap_bootstrap)
mr %r1,%r3
addi %r3,%r2,12
stw %r3,0(%r2) /* trace 0x110 - back from 2nd call */
stw %r1,4(%r2) /* trace data: SP */
mr %r3,%r2
bla CNAME(machdep_ap_bootstrap)
/* Should not be reached */
9:
b 9b
CNAME(rstsize) = . - CNAME(rstcode)
#endif
/*
* This code gets copied to all the trap vectors
* (except ISI/DSI, ALI, and the interrupts)
*/
.text
.globl CNAME(trapcode),CNAME(trapsize)
CNAME(trapcode):
mtsprg1 %r1 /* save SP */
@ -385,8 +432,8 @@ disitrap:
stw %r30,(PC_DBSAVE +CPUSAVE_R30)(%r1) /* save r30 */
lwz %r31,(PC_DISISAVE+CPUSAVE_R31)(%r1) /* get r31 */
stw %r31,(PC_DBSAVE +CPUSAVE_R31)(%r1) /* save r31 */
lis %r1,dbstk+INTSTK@ha /* get new SP */
addi %r1,%r1,dbstk+INTSTK@l
lis %r1,(tmpstk+TMPSTKSZ-16)@ha /* get new SP */
addi %r1,%r1,(tmpstk+TMPSTKSZ-16)@l
b dbtrap
#endif
@ -457,8 +504,8 @@ CNAME(vectrapsize) = .-CNAME(vectrap)
/*
* Deliberate entry to dbtrap
*/
.globl CNAME(ppc_db_trap)
CNAME(ppc_db_trap):
.globl CNAME(breakpoint)
CNAME(breakpoint):
mtsprg1 %r1
mfmsr %r3
mtsrr1 %r3
@ -533,8 +580,8 @@ CNAME(dblow):
stw %r30,(PC_DBSAVE+CPUSAVE_R30)(%r1) /* free r30 */
stw %r31,(PC_DBSAVE+CPUSAVE_R31)(%r1) /* free r31 */
mflr %r28 /* save LR */
lis %r1,dbstk+INTSTK@ha /* get new SP */
addi %r1,%r1,dbstk+INTSTK@l
lis %r1,(tmpstk+TMPSTKSZ-16)@ha /* get new SP */
addi %r1,%r1,(tmpstk+TMPSTKSZ-16)@l
bla dbtrap
CNAME(dbsize) = .-CNAME(dblow)
#endif /* KDB */

View File

@ -192,15 +192,6 @@ cpu_exit(td)
{
}
/* Temporary helper */
void
cpu_throw(struct thread *old, struct thread *new)
{
cpu_switch(old, new, old->td_lock);
panic("cpu_throw() didn't");
}
/*
* Reset back to firmware.
*/

View File

@ -795,8 +795,8 @@ CNAME(asttrapexit):
/*
* Deliberate entry to dbtrap
*/
.globl CNAME(ppc_db_trap)
CNAME(ppc_db_trap):
.globl CNAME(breakpoint)
CNAME(breakpoint):
mtsprg1 %r1
mfmsr %r3
mtsrr1 %r3

View File

@ -61,8 +61,6 @@ nodevice dcons_crom
#####################################################################
# Options we don't want to deal with
nooption SMP
nooption ADAPTIVE_SX
nooption PPC_DEBUG
nooption PPC_PROBE_CHIPSET
nooption SC_NO_MODE_CHANGE

View File

@ -49,17 +49,9 @@ powerpc_mb(void)
struct thread;
#ifdef KDB
void ppc_db_trap(void);
void breakpoint(void);
#endif
static __inline void
breakpoint(void)
{
#ifdef KDB
ppc_db_trap();
#endif
}
/* CPU register mangling inlines */
static __inline void

View File

@ -40,6 +40,11 @@ struct pmap;
int pc_inside_intr; \
struct pmap *pc_curpmap; /* current pmap */ \
struct thread *pc_fputhread; /* current fpu user */ \
uintptr_t pc_hwref; \
uint32_t pc_pir; \
int pc_bsp:1; \
int pc_awake:1; \
uint32_t pc_ipimask; \
register_t pc_tempsave[CPUSAVE_LEN]; \
register_t pc_disisave[CPUSAVE_LEN]; \
register_t pc_dbsave[CPUSAVE_LEN];
@ -112,18 +117,18 @@ struct pmap;
int pc_md_placeholder
#endif
#define PCPUP ((struct pcpu *) powerpc_get_pcpup())
#define pcpup ((struct pcpu *) powerpc_get_pcpup())
#define PCPU_GET(member) (PCPUP->pc_ ## member)
#define PCPU_GET(member) (pcpup->pc_ ## member)
/*
* XXX The implementation of this operation should be made atomic
* with respect to preemption.
*/
#define PCPU_ADD(member, value) (PCPUP->pc_ ## member += (value))
#define PCPU_ADD(member, value) (pcpup->pc_ ## member += (value))
#define PCPU_INC(member) PCPU_ADD(member, 1)
#define PCPU_PTR(member) (&PCPUP->pc_ ## member)
#define PCPU_SET(member,value) (PCPUP->pc_ ## member = (value))
#define PCPU_PTR(member) (&pcpup->pc_ ## member)
#define PCPU_SET(member,value) (pcpup->pc_ ## member = (value))
#endif /* _KERNEL */

View File

@ -78,6 +78,7 @@
#include <machine/frame.h>
#include <machine/intr_machdep.h>
#include <machine/md_var.h>
#include <machine/smp.h>
#include <machine/trap.h>
#include "pic_if.h"
@ -99,6 +100,12 @@ static struct powerpc_intr *powerpc_intrs[INTR_VECTORS];
static u_int nvectors; /* Allocated vectors */
static u_int stray_count;
#ifdef SMP
static void *ipi_cookie;
#endif
static u_int ipi_irq;
device_t pic;
static void
@ -190,14 +197,31 @@ powerpc_register_pic(device_t dev, u_int ipi)
{
pic = dev;
ipi_irq = ipi;
}
int
powerpc_enable_intr(void)
{
struct powerpc_intr *i;
#ifdef SMP
int error;
#endif
int vector;
if (pic == NULL)
panic("no PIC detected\n");
#ifdef SMP
/* Install an IPI handler. */
error = powerpc_setup_intr("IPI", ipi_irq, powerpc_ipi_handler,
NULL, NULL, INTR_TYPE_MISC | INTR_EXCL | INTR_FAST, &ipi_cookie);
if (error) {
printf("unable to setup IPI handler\n");
return (error);
}
#endif
for (vector = 0; vector < nvectors; vector++) {
i = powerpc_intrs[vector];
if (i == NULL)
@ -211,6 +235,11 @@ powerpc_enable_intr(void)
PIC_ENABLE(pic, i->irq, vector);
}
#ifdef SMP
/* Send ourself a test IPI message. */
ipi_self(IPI_PPC_TEST);
#endif
return (0);
}

View File

@ -1,75 +1,316 @@
/*-
* Copyright (c) 2000 Doug Rabson
* Copyright (c) 2008 Marcel Moolenaar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/ktr.h>
#include <sys/proc.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/pcpu.h>
#include <sys/proc.h>
#include <sys/sched.h>
#include <sys/smp.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <vm/vm_map.h>
#include <machine/bus.h>
#include <machine/cpu.h>
#include <machine/intr_machdep.h>
#include <machine/smp.h>
#include <machine/atomic.h>
#include <machine/pmap.h>
#include "pic_if.h"
int boot_cpu_id;
extern struct pcpu __pcpu[MAXCPU];
volatile static int ap_awake;
volatile static u_int ap_state;
volatile static uint32_t ap_decr;
int mp_ipi_test = 0;
void
machdep_ap_bootstrap(volatile uint32_t *trcp)
{
trcp[0] = 0x3000;
trcp[1] = (uint32_t)&machdep_ap_bootstrap;
// __asm __volatile("mtspr 1023,%0" :: "r"(PCPU_GET(cpuid)));
__asm __volatile("mfspr %0,1023" : "=r"(pcpup->pc_pir));
pcpup->pc_awake = 1;
while (ap_state == 0)
;
__asm __volatile("mtdec %0" :: "r"(ap_decr));
ap_awake++;
/* Initialize curthread. */
PCPU_SET(curthread, PCPU_GET(idlethread));
mtmsr(mfmsr() | PSL_EE | PSL_RI);
sched_throw(NULL);
}
struct cpu_group *
cpu_topo(void)
{
return smp_topo_none();
return (smp_topo_none());
}
void
cpu_mp_setmaxid(void)
{
struct cpuref cpuref;
int error;
mp_ncpus = 0;
error = powerpc_smp_first_cpu(&cpuref);
while (!error) {
mp_ncpus++;
error = powerpc_smp_next_cpu(&cpuref);
}
/* Sanity. */
if (mp_ncpus == 0)
mp_ncpus = 1;
/*
* Set the largest cpuid we're going to use. This is necessary
* for VM initialization.
*/
mp_maxid = min(mp_ncpus, MAXCPU) - 1;
}
int
cpu_mp_probe(void)
{
all_cpus = 1; /* needed for MB init code */
return 0;
/*
* We're not going to enable SMP if there's only 1 processor.
*/
return (mp_ncpus > 1);
}
void
cpu_mp_start(void)
{
struct cpuref bsp, cpu;
struct pcpu *pc;
int error;
error = powerpc_smp_get_bsp(&bsp);
KASSERT(error == 0, ("Don't know BSP"));
KASSERT(bsp.cr_cpuid == 0, ("%s: cpuid != 0", __func__));
error = powerpc_smp_first_cpu(&cpu);
while (!error) {
if (cpu.cr_cpuid >= MAXCPU) {
printf("SMP: cpu%d: skipped -- ID out of range\n",
cpu.cr_cpuid);
goto next;
}
if (all_cpus & (1 << cpu.cr_cpuid)) {
printf("SMP: cpu%d: skipped - duplicate ID\n",
cpu.cr_cpuid);
goto next;
}
if (cpu.cr_cpuid != bsp.cr_cpuid) {
pc = &__pcpu[cpu.cr_cpuid];
pcpu_init(pc, cpu.cr_cpuid, sizeof(*pc));
} else {
pc = pcpup;
pc->pc_cpuid = bsp.cr_cpuid;
pc->pc_bsp = 1;
}
pc->pc_cpumask = 1 << pc->pc_cpuid;
pc->pc_hwref = cpu.cr_hwref;
all_cpus |= pc->pc_cpumask;
next:
error = powerpc_smp_next_cpu(&cpu);
}
}
void
cpu_mp_announce(void)
{
struct pcpu *pc;
int i;
for (i = 0; i <= mp_maxid; i++) {
pc = pcpu_find(i);
if (pc == NULL)
continue;
printf("cpu%d: dev=%x", i, pc->pc_hwref);
if (pc->pc_bsp)
printf(" (BSP)");
printf("\n");
}
}
static void
cpu_mp_unleash(void *dummy)
{
struct pcpu *pc;
int cpus;
if (mp_ncpus <= 1)
return;
if (mp_ipi_test != 1) {
printf("SMP: ERROR: sending of a test IPI failed\n");
return;
}
cpus = 0;
smp_cpus = 0;
SLIST_FOREACH(pc, &cpuhead, pc_allcpu) {
cpus++;
pc->pc_other_cpus = all_cpus & ~pc->pc_cpumask;
if (!pc->pc_bsp) {
printf("Waking up CPU %d (dev=%x)\n", pc->pc_cpuid,
pc->pc_hwref);
powerpc_smp_start_cpu(pc);
} else {
__asm __volatile("mfspr %0,1023" : "=r"(pc->pc_pir));
pc->pc_awake = 1;
}
if (pc->pc_awake)
smp_cpus++;
}
ap_awake = 1;
__asm __volatile("mfdec %0" : "=r"(ap_decr));
ap_state++;
while (ap_awake < smp_cpus)
;
if (smp_cpus != cpus || cpus != mp_ncpus) {
printf("SMP: %d CPUs found; %d CPUs usable; %d CPUs woken\n",
mp_ncpus, cpus, smp_cpus);
}
smp_active = 1;
smp_started = 1;
}
SYSINIT(start_aps, SI_SUB_SMP, SI_ORDER_FIRST, cpu_mp_unleash, NULL);
static u_int ipi_msg_cnt[32];
int
powerpc_ipi_handler(void *arg)
{
cpumask_t self;
uint32_t ipimask;
int msg;
ipimask = atomic_readandclear_32(&(pcpup->pc_ipimask));
if (ipimask == 0)
return (FILTER_STRAY);
while ((msg = ffs(ipimask) - 1) != -1) {
ipimask &= ~(1u << msg);
ipi_msg_cnt[msg]++;
switch (msg) {
case IPI_AST:
break;
case IPI_PREEMPT:
sched_preempt(curthread);
break;
case IPI_RENDEZVOUS:
smp_rendezvous_action();
break;
case IPI_STOP:
self = PCPU_GET(cpumask);
savectx(PCPU_GET(curpcb));
atomic_set_int(&stopped_cpus, self);
while ((started_cpus & self) == 0)
cpu_spinwait();
atomic_clear_int(&started_cpus, self);
atomic_clear_int(&stopped_cpus, self);
break;
case IPI_PPC_TEST:
mp_ipi_test++;
break;
}
}
return (FILTER_HANDLED);
}
static void
ipi_send(struct pcpu *pc, int ipi)
{
atomic_set_32(&pc->pc_ipimask, (1 << ipi));
PIC_IPI(pic, pc->pc_cpuid);
}
/* Send an IPI to a set of cpus. */
void
ipi_selected(cpumask_t cpus, int ipi)
{
struct pcpu *pc;
SLIST_FOREACH(pc, &cpuhead, pc_allcpu) {
if (cpus & pc->pc_cpumask)
ipi_send(pc, ipi);
}
}
/* Send an IPI to all CPUs, including myself. */
void
ipi_all(int ipi)
{
struct pcpu *pc;
SLIST_FOREACH(pc, &cpuhead, pc_allcpu) {
ipi_send(pc, ipi);
}
}
/* Send an IPI to all CPUs EXCEPT myself. */
void
ipi_all_but_self(int ipi)
{
struct pcpu *pc;
SLIST_FOREACH(pc, &cpuhead, pc_allcpu) {
if (pc != pcpup)
ipi_send(pc, ipi);
}
}
/* Send an IPI to myself. */
void
ipi_self(int ipi)
{
ipi_send(pcpup, ipi);
}

View File

@ -82,7 +82,7 @@ int
openpic_attach(device_t dev)
{
struct openpic_softc *sc;
u_int ipi, irq;
u_int cpu, ipi, irq;
u_int32_t x;
sc = device_get_softc(dev);
@ -132,6 +132,9 @@ openpic_attach(device_t dev)
"Version %s, supports %d CPUs and %d irqs\n",
sc->sc_version, sc->sc_ncpu, sc->sc_nirq);
for (cpu = 0; cpu < sc->sc_ncpu; cpu++)
openpic_write(sc, OPENPIC_PCPU_TPR(cpu), 15);
/* Reset and disable all interrupts. */
for (irq = 0; irq < sc->sc_nirq; irq++) {
x = irq; /* irq == vector. */
@ -150,8 +153,6 @@ openpic_attach(device_t dev)
openpic_write(sc, OPENPIC_IPI_VECTOR(ipi), x);
}
openpic_set_priority(sc, 15);
/* we don't need 8259 passthrough mode */
x = openpic_read(sc, OPENPIC_CONFIG);
x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE;
@ -161,9 +162,8 @@ openpic_attach(device_t dev)
for (irq = 0; irq < sc->sc_nirq; irq++)
openpic_write(sc, OPENPIC_IDEST(irq), 1 << 0);
/* XXX set spurious intr vector */
openpic_set_priority(sc, 0);
for (cpu = 0; cpu < sc->sc_ncpu; cpu++)
openpic_write(sc, OPENPIC_PCPU_TPR(cpu), 0);
/* clear all pending interrupts */
for (irq = 0; irq < sc->sc_nirq; irq++) {
@ -203,15 +203,25 @@ openpic_config(device_t dev, u_int irq, enum intr_trigger trig,
void
openpic_dispatch(device_t dev, struct trapframe *tf)
{
static int once = 0;
struct openpic_softc *sc;
u_int vector;
if (once == 0 && PCPU_GET(cpuid) != 0) {
printf("XXX: got interrupt!\n");
once++;
}
sc = device_get_softc(dev);
while (1) {
vector = openpic_read(sc, OPENPIC_PCPU_IACK(PCPU_GET(cpuid)));
vector &= OPENPIC_VECTOR_MASK;
if (vector == 255)
break;
if (once == 1 && PCPU_GET(cpuid) != 0) {
printf("XXX: got vector %u\n", vector);
once++;
}
powerpc_dispatch_intr(vector, tf);
}
}