Add support for 64-bit PowerPC CPUs operating in the 64-bit bridge mode

provided, for example, on the PowerPC 970 (G5), as well as on related CPUs
like the POWER3 and POWER4.

This also adds support for various built-in hardware found on Apple G5
hardware (e.g. the IBM CPC925 northbridge).

Reviewed by:    grehan
This commit is contained in:
Nathan Whitehorn 2009-04-04 00:22:44 +00:00
parent cd5e62f992
commit 1c96bdd146
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=190681
28 changed files with 3775 additions and 230 deletions

View file

@ -119,7 +119,7 @@ _CPUCFLAGS = -mcpu=${CPUTYPE}
MACHINE_CPU = booke
_CPUCFLAGS = -Wa,-me500 -msoft-float
. else
_CPUCFLAGS = -mcpu=${CPUTYPE}
_CPUCFLAGS = -mcpu=${CPUTYPE} -mno-powerpc64
. endif
. elif ${MACHINE_ARCH} == "mips"
. if ${CPUTYPE} == "mips32"

View file

@ -76,13 +76,13 @@ 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/mmu_oea64.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
powerpc/aim/swtch.S optional aim
powerpc/aim/trap.c optional aim
powerpc/aim/uio_machdep.c optional aim
powerpc/aim/uma_machdep.c optional aim
powerpc/aim/vm_machdep.c optional aim
powerpc/booke/clock.c optional e500
@ -93,7 +93,6 @@ powerpc/booke/machdep.c optional e500
powerpc/booke/pmap.c optional e500
powerpc/booke/swtch.S optional e500
powerpc/booke/trap.c optional e500
powerpc/booke/uio_machdep.c optional e500
powerpc/booke/vm_machdep.c optional e500
powerpc/fpu/fpu_add.c optional fpu_emu
powerpc/fpu/fpu_compare.c optional fpu_emu
@ -127,6 +126,7 @@ powerpc/powermac/uninorth.c optional powermac pci
powerpc/powermac/cuda.c optional powermac cuda
powerpc/powermac/pmu.c optional powermac pmu
powerpc/powermac/macgpio.c optional powermac pci
powerpc/powermac/cpcht.c optional powermac pci
powerpc/powerpc/altivec.c optional aim
powerpc/powerpc/atomic.S standard
powerpc/powerpc/autoconf.c standard
@ -158,6 +158,7 @@ powerpc/powerpc/stack_machdep.c optional ddb | stack
powerpc/powerpc/suswintr.c standard
powerpc/powerpc/syncicache.c standard
powerpc/powerpc/sys_machdep.c standard
powerpc/powerpc/uio_machdep.c standard
powerpc/psim/iobus.c optional psim
powerpc/psim/ata_iobus.c optional ata psim
powerpc/psim/openpic_iobus.c optional psim

View file

@ -131,19 +131,25 @@ powermac_nvram_attach(device_t dev)
{
struct powermac_nvram_softc *sc;
phandle_t node;
u_int32_t reg[2];
int gen0, gen1;
u_int32_t reg[3];
int gen0, gen1, i;
node = ofw_bus_get_node(dev);
sc = device_get_softc(dev);
if (OF_getprop(node, "reg", reg, sizeof(reg)) < 8)
if ((i = OF_getprop(node, "reg", reg, sizeof(reg))) < 8)
return ENXIO;
sc->sc_dev = dev;
sc->sc_node = node;
sc->sc_bank0 = (vm_offset_t)pmap_mapdev(reg[0], NVRAM_SIZE * 2);
/*
* Find which byte of reg corresponds to the 32-bit physical address.
* We should probably read #address-cells from /chosen instead.
*/
i = (i/4) - 2;
sc->sc_bank0 = (vm_offset_t)pmap_mapdev(reg[i], NVRAM_SIZE * 2);
sc->sc_bank1 = sc->sc_bank0 + NVRAM_SIZE;
gen0 = powermac_nvram_check((void *)sc->sc_bank0);

View file

@ -31,6 +31,8 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <machine/bus.h>
@ -53,8 +55,7 @@ bus_space_tag_t uart_bus_space_mem = &bs_le_tag;
int
uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
{
return ((b1->bsh == b2->bsh) ? 1 : 0);
return ((pmap_kextract(b1->bsh) == pmap_kextract(b2->bsh)) ? 1 : 0);
}
#ifdef MPC85XX
@ -116,7 +117,16 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di)
return (ENXIO);
if (OF_getprop(input, "name", buf, sizeof(buf)) == -1)
return (ENXIO);
if (strcmp(buf, "ch-a"))
if (strcmp(buf, "ch-a") == 0) {
class = &uart_z8530_class;
di->bas.regshft = 4;
di->bas.chan = 1;
} else if (strcmp(buf,"serial") == 0) {
class = &uart_ns8250_class;
di->bas.regshft = 0;
di->bas.chan = 0;
} else
return (ENXIO);
error = OF_decode_addr(input, 0, &di->bas.bst, &di->bas.bsh);
@ -125,11 +135,13 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di)
di->ops = uart_getops(class);
di->bas.rclk = 230400;
di->bas.chan = 1;
di->bas.regshft = 4;
if (OF_getprop(input, "clock-frequency", &di->bas.rclk,
sizeof(di->bas.rclk)) == -1)
di->bas.rclk = 230400;
if (OF_getprop(input, "current-speed", &di->baudrate,
sizeof(di->baudrate)) == -1)
di->baudrate = 0;
di->baudrate = 0;
di->databits = 8;
di->stopbits = 1;
di->parity = UART_PARITY_NONE;

View file

@ -130,6 +130,8 @@ extern vm_offset_t ksym_start, ksym_end;
int cold = 1;
int cacheline_size = 32;
int ppc64 = 0;
int hw_direct_map = 1;
struct pcpu __pcpu[MAXCPU];
@ -230,10 +232,13 @@ cpu_startup(void *dummy)
extern char kernel_text[], _end[];
extern void *testppc64, *testppc64size;
extern void *restorebridge, *restorebridgesize;
extern void *rfid_patch, *rfi_patch1, *rfi_patch2;
#ifdef SMP
extern void *rstcode, *rstsize;
#endif
extern void *trapcode, *trapsize;
extern void *trapcode, *trapcode64, *trapsize;
extern void *alitrap, *alisize;
extern void *dsitrap, *dsisize;
extern void *decrint, *decrsize;
@ -245,11 +250,16 @@ powerpc_init(u_int startkernel, u_int endkernel, u_int basekernel, void *mdp)
{
struct pcpu *pc;
vm_offset_t end;
void *generictrap;
size_t trap_offset;
void *kmdp;
char *env;
int vers;
uint32_t msr, scratch;
end = 0;
kmdp = NULL;
trap_offset = 0;
/*
* Parse metadata if present and fetch parameters. Must be done
@ -315,6 +325,26 @@ powerpc_init(u_int startkernel, u_int endkernel, u_int basekernel, void *mdp)
printf("powerpc_init: no loader metadata.\n");
}
/*
* Set cacheline_size based on the CPU model.
*/
vers = mfpvr() >> 16;
switch (vers) {
case IBM970:
case IBM970FX:
case IBM970MP:
case IBM970GX:
cacheline_size = 128;
break;
default:
cacheline_size = 32;
}
/*
* Init KDB
*/
kdb_init();
/*
@ -322,47 +352,110 @@ powerpc_init(u_int startkernel, u_int endkernel, u_int basekernel, void *mdp)
* Disable translation in case the vector area
* hasn't been mapped (G5)
*/
mtmsr(mfmsr() & ~(PSL_IR | PSL_DR));
msr = mfmsr();
mtmsr(msr & ~(PSL_IR | PSL_DR));
isync();
/*
* Figure out whether we need to use the 64 bit PMAP. This works by
* executing an instruction that is only legal on 64-bit PPC (mtmsrd),
* and setting ppc64 = 0 if that causes a trap.
*/
ppc64 = 1;
bcopy(&testppc64, (void *)EXC_PGM, (size_t)&testppc64size);
__syncicache((void *)EXC_PGM, (size_t)&testppc64size);
__asm __volatile("\
mfmsr %0; \
mtsprg2 %1; \
\
mtmsrd %0; \
mfsprg2 %1;"
: "=r"(scratch), "=r"(ppc64));
/*
* Now copy restorebridge into all the handlers, if necessary,
* and set up the trap tables.
*/
if (ppc64) {
/* Patch the two instances of rfi -> rfid */
bcopy(&rfid_patch,&rfi_patch1,4);
bcopy(&rfid_patch,&rfi_patch2,4);
/*
* Copy a code snippet to restore 32-bit bridge mode
* to the top of every non-generic trap handler
*/
trap_offset += (size_t)&restorebridgesize;
bcopy(&restorebridge, (void *)EXC_RST, trap_offset);
bcopy(&restorebridge, (void *)EXC_DSI, trap_offset);
bcopy(&restorebridge, (void *)EXC_ALI, trap_offset);
bcopy(&restorebridge, (void *)EXC_PGM, trap_offset);
bcopy(&restorebridge, (void *)EXC_MCHK, trap_offset);
bcopy(&restorebridge, (void *)EXC_TRC, trap_offset);
bcopy(&restorebridge, (void *)EXC_BPT, trap_offset);
/*
* Set the common trap entry point to the one that
* knows to restore 32-bit operation on execution.
*/
generictrap = &trapcode64;
} else {
generictrap = &trapcode;
}
#ifdef SMP
bcopy(&rstcode, (void *)EXC_RST, (size_t)&rstsize);
bcopy(&rstcode, (void *)(EXC_RST + trap_offset), (size_t)&rstsize);
#else
bcopy(&trapcode, (void *)EXC_RST, (size_t)&trapsize);
bcopy(generictrap, (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);
bcopy(&trapcode, (void *)EXC_EXI, (size_t)&trapsize);
bcopy(&alitrap, (void *)EXC_ALI, (size_t)&alisize);
bcopy(&trapcode, (void *)EXC_PGM, (size_t)&trapsize);
bcopy(&trapcode, (void *)EXC_FPU, (size_t)&trapsize);
bcopy(&trapcode, (void *)EXC_DECR, (size_t)&trapsize);
bcopy(&trapcode, (void *)EXC_SC, (size_t)&trapsize);
bcopy(&trapcode, (void *)EXC_TRC, (size_t)&trapsize);
bcopy(&trapcode, (void *)EXC_FPA, (size_t)&trapsize);
bcopy(&trapcode, (void *)EXC_VEC, (size_t)&trapsize);
bcopy(&trapcode, (void *)EXC_VECAST, (size_t)&trapsize);
bcopy(&trapcode, (void *)EXC_THRM, (size_t)&trapsize);
bcopy(&trapcode, (void *)EXC_BPT, (size_t)&trapsize);
#ifdef KDB
bcopy(&dblow, (void *)EXC_MCHK, (size_t)&dbsize);
bcopy(&dblow, (void *)EXC_PGM, (size_t)&dbsize);
bcopy(&dblow, (void *)EXC_TRC, (size_t)&dbsize);
bcopy(&dblow, (void *)EXC_BPT, (size_t)&dbsize);
bcopy(&dblow, (void *)(EXC_MCHK + trap_offset), (size_t)&dbsize);
bcopy(&dblow, (void *)(EXC_PGM + trap_offset), (size_t)&dbsize);
bcopy(&dblow, (void *)(EXC_TRC + trap_offset), (size_t)&dbsize);
bcopy(&dblow, (void *)(EXC_BPT + trap_offset), (size_t)&dbsize);
#else
bcopy(generictrap, (void *)EXC_MCHK, (size_t)&trapsize);
bcopy(generictrap, (void *)EXC_PGM, (size_t)&trapsize);
bcopy(generictrap, (void *)EXC_TRC, (size_t)&trapsize);
bcopy(generictrap, (void *)EXC_BPT, (size_t)&trapsize);
#endif
bcopy(&dsitrap, (void *)(EXC_DSI + trap_offset), (size_t)&dsisize);
bcopy(&alitrap, (void *)(EXC_ALI + trap_offset), (size_t)&alisize);
bcopy(generictrap, (void *)EXC_ISI, (size_t)&trapsize);
bcopy(generictrap, (void *)EXC_EXI, (size_t)&trapsize);
bcopy(generictrap, (void *)EXC_FPU, (size_t)&trapsize);
bcopy(generictrap, (void *)EXC_DECR, (size_t)&trapsize);
bcopy(generictrap, (void *)EXC_SC, (size_t)&trapsize);
bcopy(generictrap, (void *)EXC_FPA, (size_t)&trapsize);
bcopy(generictrap, (void *)EXC_VEC, (size_t)&trapsize);
bcopy(generictrap, (void *)EXC_VECAST, (size_t)&trapsize);
bcopy(generictrap, (void *)EXC_THRM, (size_t)&trapsize);
__syncicache(EXC_RSVD, EXC_LAST - EXC_RSVD);
/*
* Make sure translation has been enabled
* Restore MSR
*/
mtmsr(mfmsr() | PSL_IR|PSL_DR|PSL_ME|PSL_RI);
mtmsr(msr);
isync();
/*
* Initialise virtual memory.
*/
pmap_mmu_install(MMU_TYPE_OEA, 0); /* XXX temporary */
if (ppc64)
pmap_mmu_install(MMU_TYPE_G5, 0);
else
pmap_mmu_install(MMU_TYPE_OEA, 0);
pmap_bootstrap(startkernel, endkernel);
mtmsr(mfmsr() | PSL_IR|PSL_DR|PSL_ME|PSL_RI);
isync();
/*
* Initialize params/tunables that are derived from memsize

View file

@ -323,6 +323,7 @@ void moea_zero_page_area(mmu_t, vm_page_t, int, int);
void moea_zero_page_idle(mmu_t, vm_page_t);
void moea_activate(mmu_t, struct thread *);
void moea_deactivate(mmu_t, struct thread *);
void moea_cpu_bootstrap(mmu_t, int);
void moea_bootstrap(mmu_t, vm_offset_t, vm_offset_t);
void *moea_mapdev(mmu_t, vm_offset_t, vm_size_t);
void moea_unmapdev(mmu_t, vm_offset_t, vm_size_t);
@ -364,6 +365,7 @@ static mmu_method_t moea_methods[] = {
/* Internal interfaces */
MMUMETHOD(mmu_bootstrap, moea_bootstrap),
MMUMETHOD(mmu_cpu_bootstrap, moea_cpu_bootstrap),
MMUMETHOD(mmu_mapdev, moea_mapdev),
MMUMETHOD(mmu_unmapdev, moea_unmapdev),
MMUMETHOD(mmu_kextract, moea_kextract),
@ -617,7 +619,7 @@ om_cmp(const void *a, const void *b)
}
void
pmap_cpu_bootstrap(int ap)
moea_cpu_bootstrap(mmu_t mmup, int ap)
{
u_int sdr;
int i;
@ -709,6 +711,9 @@ moea_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend)
__asm __volatile("mtdbatl 1,%0" :: "r"(battable[8].batl));
isync();
/* set global direct map flag */
hw_direct_map = 1;
mem_regions(&pregions, &pregions_sz, &regions, &regions_sz);
CTR0(KTR_PMAP, "moea_bootstrap: physical memory");
@ -895,7 +900,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;
pmap_cpu_bootstrap(0);
moea_cpu_bootstrap(mmup,0);
pmap_bootstrapped++;

2443
sys/powerpc/aim/mmu_oea64.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -35,7 +35,6 @@ __FBSDID("$FreeBSD$");
#include <sys/proc.h>
#include <sys/smp.h>
#include <machine/bat.h>
#include <machine/bus.h>
#include <machine/cpu.h>
#include <machine/hid.h>
@ -250,8 +249,10 @@ cpudep_ap_bootstrap(void)
mtmsr(msr);
isync();
reg = l3_enable();
reg = l2_enable();
if (l3cr_config != 0)
reg = l3_enable();
if (l2cr_config != 0)
reg = l2_enable();
reg = l1d_enable();
reg = l1i_enable();

View file

@ -62,6 +62,12 @@ __FBSDID("$FreeBSD$");
static struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3];
static struct mem_region OFfree[OFMEM_REGIONS + 3];
struct mem_region64 {
vm_offset_t mr_start_hi;
vm_offset_t mr_start_lo;
vm_size_t mr_size;
};
extern register_t ofmsr[5];
extern struct pmap ofw_pmap;
static int (*ofwcall)(void *);
@ -141,24 +147,86 @@ void
mem_regions(struct mem_region **memp, int *memsz,
struct mem_region **availp, int *availsz)
{
int phandle;
phandle_t phandle;
int asz, msz, fsz;
int i, j;
int still_merging;
cell_t address_cells;
asz = msz = 0;
/*
* Get #address-cells from root node, defaulting to 1 if it cannot
* be found.
*/
phandle = OF_finddevice("/");
if (OF_getprop(phandle, "#address-cells", &address_cells,
sizeof(address_cells)) < sizeof(address_cells))
address_cells = 1;
/*
* Get memory.
*/
if ((phandle = OF_finddevice("/memory")) == -1
|| (msz = OF_getprop(phandle, "reg",
OFmem, sizeof OFmem[0] * OFMEM_REGIONS))
<= 0
|| (asz = OF_getprop(phandle, "available",
OFavail, sizeof OFavail[0] * OFMEM_REGIONS))
<= 0)
panic("no memory?");
OFavail, sizeof OFavail[0] * OFMEM_REGIONS)) <= 0)
{
if (ofw_real_mode) {
/* XXX MAMBO */
printf("Physical memory unknown -- guessing 128 MB\n");
/* Leave the first 0xA000000 bytes for the kernel */
OFavail[0].mr_start = 0xA00000;
OFavail[0].mr_size = 0x75FFFFF;
asz = sizeof(OFavail[0]);
} else {
panic("no memory?");
}
}
if (address_cells == 2) {
struct mem_region64 OFmem64[OFMEM_REGIONS + 1];
if ((phandle == -1) || (msz = OF_getprop(phandle, "reg",
OFmem64, sizeof OFmem64[0] * OFMEM_REGIONS)) <= 0) {
if (ofw_real_mode) {
/* XXX MAMBO */
OFmem64[0].mr_start_hi = 0;
OFmem64[0].mr_start_lo = 0x0;
OFmem64[0].mr_size = 0x7FFFFFF;
msz = sizeof(OFmem64[0]);
} else {
panic("Physical memory map not found");
}
}
for (i = 0, j = 0; i < msz/sizeof(OFmem64[0]); i++) {
if (OFmem64[i].mr_start_hi == 0) {
OFmem[i].mr_start = OFmem64[i].mr_start_lo;
OFmem[i].mr_size = OFmem64[i].mr_size;
/*
* Check for memory regions extending above 32-bit
* memory space, and restrict them to stay there.
*/
if (((uint64_t)OFmem[i].mr_start +
(uint64_t)OFmem[i].mr_size) >
BUS_SPACE_MAXADDR_32BIT) {
OFmem[i].mr_size = BUS_SPACE_MAXADDR_32BIT -
OFmem[i].mr_start;
}
j++;
}
}
msz = j*sizeof(OFmem[0]);
} else {
if ((msz = OF_getprop(phandle, "reg",
OFmem, sizeof OFmem[0] * OFMEM_REGIONS)) <= 0)
panic("Physical memory map not found");
}
*memp = OFmem;
*memsz = msz / sizeof(struct mem_region);
/*
* OFavail may have overlapping regions - collapse these
@ -268,8 +336,10 @@ openfirmware(void *args)
/*
* Clear battable[] translations
*/
__asm __volatile("mtdbatu 2, %0\n"
"mtdbatu 3, %0" : : "r" (0));
if (!ppc64) {
__asm __volatile("mtdbatu 2, %0\n"
"mtdbatu 3, %0" : : "r" (0));
}
isync();
}
@ -469,3 +539,4 @@ mem_valid(vm_offset_t addr, int len)
return (EFAULT);
}

View file

@ -223,10 +223,54 @@
lwz %r3,(savearea+CPUSAVE_SRR0)(%r2); /* restore srr0 */ \
mtsrr0 %r3; \
lwz %r3,(savearea+CPUSAVE_SRR1)(%r2); /* restore srr1 */ \
\
/* Make sure HV bit of MSR propagated to SRR1 */ \
mfmsr %r2; \
or %r3,%r2,%r3; \
\
mtsrr1 %r3; \
mfsprg2 %r2; /* restore r2 & r3 */ \
mfsprg3 %r3
/*
* The next two routines are 64-bit glue code. The first is used to test if
* we are on a 64-bit system. By copying it to the illegal instruction
* handler, we can test for 64-bit mode by trying to execute a 64-bit
* instruction and seeing what happens. The second gets copied in front
* of all the other handlers to restore 32-bit bridge mode when traps
* are taken.
*/
/* 64-bit test code. Sets SPRG2 to 0 if an illegal instruction is executed */
.globl CNAME(testppc64),CNAME(testppc64size)
CNAME(testppc64):
mtsprg1 %r31
mfsrr0 %r31
addi %r31, %r31, 4
mtsrr0 %r31
li %r31, 0
mtsprg2 %r31
mfsprg1 %r31
rfi
CNAME(testppc64size) = .-CNAME(testppc64)
/* 64-bit bridge mode restore snippet. Gets copied in front of everything else
* on 64-bit systems. */
.globl CNAME(restorebridge),CNAME(restorebridgesize)
CNAME(restorebridge):
mtsprg1 %r31
mfmsr %r31
clrldi %r31,%r31,1
mtmsrd %r31
mfsprg1 %r31
isync
CNAME(restorebridgesize) = .-CNAME(restorebridge)
#ifdef SMP
/*
* Processor reset exception handler. These are typically
@ -269,6 +313,17 @@ CNAME(trapcode):
bla generictrap /* LR & SPRG3 is exception # */
CNAME(trapsize) = .-CNAME(trapcode)
/*
* 64-bit version of trapcode. Identical, except it calls generictrap64.
*/
.globl CNAME(trapcode64)
CNAME(trapcode64):
mtsprg1 %r1 /* save SP */
mflr %r1 /* Save the old LR in r1 */
mtsprg2 %r1 /* And then in SPRG2 */
li %r1, 0x20 /* How to get the vector from LR */
bla generictrap64 /* LR & SPRG3 is exception # */
/*
* For ALI: has to save DSISR and DAR
*/
@ -433,6 +488,14 @@ realtrap:
* SPRG2 - Original LR
*/
generictrap64:
mtsprg3 %r31
mfmsr %r31
clrldi %r31,%r31,1
mtmsrd %r31
mfsprg3 %r31
isync
generictrap:
/* Save R1 for computing the exception vector */
mtsprg3 %r1
@ -504,8 +567,15 @@ CNAME(asttrapexit):
b trapexit /* test ast ret value ? */
1:
FRAME_LEAVE(PC_TEMPSAVE)
.globl CNAME(rfi_patch1) /* replace rfi with rfid on ppc64 */
CNAME(rfi_patch1):
rfi
.globl CNAME(rfid_patch)
CNAME(rfid_patch):
rfid
#if defined(KDB)
/*
* Deliberate entry to dbtrap
@ -566,6 +636,8 @@ dbtrap:
b realtrap
dbleave:
FRAME_LEAVE(PC_DBSAVE)
.globl CNAME(rfi_patch2) /* replace rfi with rfid on ppc64 */
CNAME(rfi_patch2):
rfi
/*

View file

@ -1,124 +0,0 @@
/*-
* Copyright (c) 2004 Alan L. Cox <alc@cs.rice.edu>
* Copyright (c) 1982, 1986, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* 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.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
* @(#)kern_subr.c 8.3 (Berkeley) 1/21/94
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/uio.h>
#include <vm/vm.h>
#include <vm/vm_page.h>
#include <machine/md_var.h>
#include <machine/vmparam.h>
/*
* Implement uiomove(9) from physical memory using the direct map to
* avoid the creation and destruction of ephemeral mappings.
*/
int
uiomove_fromphys(vm_page_t ma[], vm_offset_t offset, int n, struct uio *uio)
{
struct thread *td = curthread;
struct iovec *iov;
void *cp;
vm_offset_t page_offset;
size_t cnt;
int error = 0;
int save = 0;
KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE,
("uiomove_fromphys: mode"));
KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == curthread,
("uiomove_fromphys proc"));
save = td->td_pflags & TDP_DEADLKTREAT;
td->td_pflags |= TDP_DEADLKTREAT;
while (n > 0 && uio->uio_resid) {
iov = uio->uio_iov;
cnt = iov->iov_len;
if (cnt == 0) {
uio->uio_iov++;
uio->uio_iovcnt--;
continue;
}
if (cnt > n)
cnt = n;
page_offset = offset & PAGE_MASK;
cnt = min(cnt, PAGE_SIZE - page_offset);
cp = (char *)VM_PAGE_TO_PHYS(ma[offset >> PAGE_SHIFT]) +
page_offset;
switch (uio->uio_segflg) {
case UIO_USERSPACE:
if (ticks - PCPU_GET(switchticks) >= hogticks)
uio_yield();
if (uio->uio_rw == UIO_READ)
error = copyout(cp, iov->iov_base, cnt);
else
error = copyin(iov->iov_base, cp, cnt);
if (error)
goto out;
if (uio->uio_rw == UIO_WRITE &&
pmap_page_executable(ma[offset >> PAGE_SHIFT]))
__syncicache(cp, cnt);
break;
case UIO_SYSSPACE:
if (uio->uio_rw == UIO_READ)
bcopy(cp, iov->iov_base, cnt);
else
bcopy(iov->iov_base, cp, cnt);
break;
case UIO_NOCOPY:
break;
}
iov->iov_base = (char *)iov->iov_base + cnt;
iov->iov_len -= cnt;
uio->uio_resid -= cnt;
uio->uio_offset += cnt;
offset += cnt;
n -= cnt;
}
out:
if (save == 0)
td->td_pflags &= ~TDP_DEADLKTREAT;
return (error);
}

View file

@ -35,9 +35,13 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#include <vm/vm.h>
#include <vm/vm_page.h>
#include <vm/vm_kern.h>
#include <vm/vm_pageout.h>
#include <vm/vm_extern.h>
#include <vm/uma.h>
#include <vm/uma.h>
#include <vm/uma_int.h>
#include <machine/md_var.h>
#include <machine/vmparam.h>
static int hw_uma_mdpages;
@ -51,6 +55,13 @@ uma_small_alloc(uma_zone_t zone, int bytes, u_int8_t *flags, int wait)
void *va;
vm_page_t m;
int pflags;
if (!hw_direct_map) {
*flags = UMA_SLAB_KMEM;
va = (void *)kmem_malloc(kmem_map, bytes, wait);
return va;
}
*flags = UMA_SLAB_PRIV;
if ((wait & (M_NOWAIT|M_USE_RESERVE)) == M_NOWAIT)
@ -83,6 +94,12 @@ uma_small_free(void *mem, int size, u_int8_t flags)
{
vm_page_t m;
if (!hw_direct_map) {
kmem_free(kmem_map, (vm_offset_t)mem, size);
return;
}
m = PHYS_TO_VM_PAGE((u_int32_t)mem);
m->wire_count--;
vm_page_free(m);

View file

@ -100,6 +100,37 @@
#include <vm/vm_map.h>
#include <vm/vm_extern.h>
/*
* On systems without a direct mapped region (e.g. PPC64),
* we use the same code as the Book E implementation. Since
* we need to have runtime detection of this, define some machinery
* for sf_bufs in this case, and ignore it on systems with direct maps.
*/
#ifndef NSFBUFS
#define NSFBUFS (512 + maxusers * 16)
#endif
static void sf_buf_init(void *arg);
SYSINIT(sock_sf, SI_SUB_MBUF, SI_ORDER_ANY, sf_buf_init, NULL);
LIST_HEAD(sf_head, sf_buf);
/* A hash table of active sendfile(2) buffers */
static struct sf_head *sf_buf_active;
static u_long sf_buf_hashmask;
#define SF_BUF_HASH(m) (((m) - vm_page_array) & sf_buf_hashmask)
static TAILQ_HEAD(, sf_buf) sf_buf_freelist;
static u_int sf_buf_alloc_want;
/*
* A lock used to synchronize access to the hash table and free list
*/
static struct mtx sf_buf_lock;
/*
* Finish a fork operation, with process p2 nearly set up.
* Copy and update the pcb, set up the stack so that the child
@ -202,24 +233,122 @@ cpu_reset()
}
/*
* Allocate an sf_buf for the given vm_page. On this machine, however, there
* is no sf_buf object. Instead, an opaque pointer to the given vm_page is
* returned.
* Allocate a pool of sf_bufs (sendfile(2) or "super-fast" if you prefer. :-))
*/
struct sf_buf *
sf_buf_alloc(struct vm_page *m, int pri)
static void
sf_buf_init(void *arg)
{
struct sf_buf *sf_bufs;
vm_offset_t sf_base;
int i;
return ((struct sf_buf *)m);
/* Don't bother on systems with a direct map */
if (hw_direct_map)
return;
nsfbufs = NSFBUFS;
TUNABLE_INT_FETCH("kern.ipc.nsfbufs", &nsfbufs);
sf_buf_active = hashinit(nsfbufs, M_TEMP, &sf_buf_hashmask);
TAILQ_INIT(&sf_buf_freelist);
sf_base = kmem_alloc_nofault(kernel_map, nsfbufs * PAGE_SIZE);
sf_bufs = malloc(nsfbufs * sizeof(struct sf_buf), M_TEMP, M_NOWAIT | M_ZERO);
for (i = 0; i < nsfbufs; i++) {
sf_bufs[i].kva = sf_base + i * PAGE_SIZE;
TAILQ_INSERT_TAIL(&sf_buf_freelist, &sf_bufs[i], free_entry);
}
sf_buf_alloc_want = 0;
mtx_init(&sf_buf_lock, "sf_buf", NULL, MTX_DEF);
}
/*
* Free the sf_buf. In fact, do nothing because there are no resources
* associated with the sf_buf.
* Get an sf_buf from the freelist. Will block if none are available.
*/
struct sf_buf *
sf_buf_alloc(struct vm_page *m, int flags)
{
struct sf_head *hash_list;
struct sf_buf *sf;
int error;
if (hw_direct_map) {
/* Shortcut the direct mapped case */
return ((struct sf_buf *)m);
}
hash_list = &sf_buf_active[SF_BUF_HASH(m)];
mtx_lock(&sf_buf_lock);
LIST_FOREACH(sf, hash_list, list_entry) {
if (sf->m == m) {
sf->ref_count++;
if (sf->ref_count == 1) {
TAILQ_REMOVE(&sf_buf_freelist, sf, free_entry);
nsfbufsused++;
nsfbufspeak = imax(nsfbufspeak, nsfbufsused);
}
goto done;
}
}
while ((sf = TAILQ_FIRST(&sf_buf_freelist)) == NULL) {
if (flags & SFB_NOWAIT)
goto done;
sf_buf_alloc_want++;
mbstat.sf_allocwait++;
error = msleep(&sf_buf_freelist, &sf_buf_lock,
(flags & SFB_CATCH) ? PCATCH | PVM : PVM, "sfbufa", 0);
sf_buf_alloc_want--;
/*
* If we got a signal, don't risk going back to sleep.
*/
if (error)
goto done;
}
TAILQ_REMOVE(&sf_buf_freelist, sf, free_entry);
if (sf->m != NULL)
LIST_REMOVE(sf, list_entry);
LIST_INSERT_HEAD(hash_list, sf, list_entry);
sf->ref_count = 1;
sf->m = m;
nsfbufsused++;
nsfbufspeak = imax(nsfbufspeak, nsfbufsused);
pmap_qenter(sf->kva, &sf->m, 1);
done:
mtx_unlock(&sf_buf_lock);
return (sf);
}
/*
* Detatch mapped page and release resources back to the system.
*
* Remove a reference from the given sf_buf, adding it to the free
* list when its reference count reaches zero. A freed sf_buf still,
* however, retains its virtual-to-physical mapping until it is
* recycled or reactivated by sf_buf_alloc(9).
*/
void
sf_buf_free(struct sf_buf *sf)
{
if (hw_direct_map)
return;
mtx_lock(&sf_buf_lock);
sf->ref_count--;
if (sf->ref_count == 0) {
TAILQ_INSERT_TAIL(&sf_buf_freelist, sf, free_entry);
nsfbufsused--;
if (sf_buf_alloc_want > 0)
wakeup_one(&sf_buf_freelist);
}
mtx_unlock(&sf_buf_lock);
}
/*

View file

@ -176,6 +176,9 @@ int cacheline_size = 32;
SYSCTL_INT(_machdep, CPU_CACHELINE, cacheline_size,
CTLFLAG_RD, &cacheline_size, 0, "");
int hw_direct_map = 0;
int ppc64 = 0;
static void cpu_e500_startup(void *);
SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_e500_startup, NULL);

View file

@ -47,6 +47,7 @@
#define HID0_SLEEP 0x00200000 /* Enable sleep mode */
#define HID0_DPM 0x00100000 /* Enable Dynamic power management */
#define HID0_RISEG 0x00080000 /* Read I-SEG */
#define HID0_TG 0x00040000 /* Timebase Granularity (OEA64) */
#define HID0_BHTCLR 0x00040000 /* Clear branch history table (7450) */
#define HID0_EIEC 0x00040000 /* Enable internal error checking */
#define HID0_XAEN 0x00020000 /* Enable eXtended Addressing (7450) */

View file

@ -46,6 +46,8 @@ extern u_long ns_per_tick;
extern int powerpc_pow_enabled;
extern int cacheline_size;
extern int ppc64;
extern int hw_direct_map;
void __syncicache(void *, int);

View file

@ -32,33 +32,9 @@
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/vm_page.h>
#include <machine/md_var.h>
#include <sys/queue.h>
#if defined(AIM)
/*
* On this machine, the only purpose for which sf_buf is used is to implement
* an opaque pointer required by the machine-independent parts of the kernel.
* That pointer references the vm_page that is "mapped" by the sf_buf. The
* actual mapping is provided by the direct virtual-to-physical mapping.
*/
struct sf_buf;
static __inline vm_offset_t
sf_buf_kva(struct sf_buf *sf)
{
return (VM_PAGE_TO_PHYS((vm_page_t)sf));
}
static __inline vm_page_t
sf_buf_page(struct sf_buf *sf)
{
return ((vm_page_t)sf);
}
#elif defined(E500)
struct vm_page;
struct sf_buf {
@ -69,9 +45,22 @@ struct sf_buf {
int ref_count; /* usage of this mapping */
};
/*
* On 32-bit OEA, the only purpose for which sf_buf is used is to implement
* an opaque pointer required by the machine-independent parts of the kernel.
* That pointer references the vm_page that is "mapped" by the sf_buf. The
* actual mapping is provided by the direct virtual-to-physical mapping.
*
* On OEA64 and Book-E, we need to do something a little more complicated. Use
* the runtime-detected hw_direct_map to pick between the two cases. Our
* friends in vm_machdep.c will do the same to ensure nothing gets confused.
*/
static __inline vm_offset_t
sf_buf_kva(struct sf_buf *sf)
{
if (hw_direct_map)
return (VM_PAGE_TO_PHYS((vm_page_t)sf));
return (sf->kva);
}
@ -79,10 +68,10 @@ sf_buf_kva(struct sf_buf *sf)
static __inline struct vm_page *
sf_buf_page(struct sf_buf *sf)
{
if (hw_direct_map)
return ((vm_page_t)sf);
return (sf->m);
}
#endif
#endif /* !_MACHINE_SF_BUF_H_ */

View file

@ -43,6 +43,44 @@
( { register_t val; \
__asm __volatile("mfspr %0,%1" : "=r"(val) : "K"(reg)); \
val; } )
/* The following routines allow manipulation of the full 64-bit width
* of SPRs on 64 bit CPUs in bridge mode */
#define mtspr64(reg,valhi,vallo,scratch) \
__asm __volatile(" \
mfmsr %0; \
insrdi %0,1,1,0; \
mtmsrd %0; \
isync; \
\
sld %1,%1,%4; \
or %1,%1,%2; \
mtspr %3,%1; \
srd %1,%1,%4; \
\
clrldi %0,%0,1; \
mtmsrd %0; \
isync;" \
: "=r"(scratch), "=r"(valhi) : "r"(vallo), "K"(reg), "r"(32))
#define mfspr64upper(reg,scratch) \
( { register_t val; \
__asm __volatile(" \
mfmsr %0; \
insrdi %0,1,1,0; \
mtmsrd %0; \
isync; \
\
mfspr %1,%2; \
srd %1,%1,%3; \
\
clrldi %0,%0,1; \
mtmsrd %0; \
isync;" \
: "=r"(scratch), "=r"(val) : "K"(reg), "r"(32)); \
val; } )
#endif /* _LOCORE */
/*
@ -112,7 +150,11 @@
#define IBM401E2 0x0025
#define IBM401F2 0x0026
#define IBM401G2 0x0027
#define IBM970 0x0039
#define IBM970FX 0x003c
#define IBMPOWER3 0x0041
#define IBM970MP 0x0044
#define IBM970GX 0x0045
#define MPC860 0x0050
#define MPC8240 0x0081
#define IBM405GP 0x4011

View file

@ -106,6 +106,13 @@
*/
#define UMA_MD_SMALL_ALLOC
/*
* On 64-bit systems in bridge mode, we have no direct map, so we fake
* the small_alloc() calls. But we need the VM to be in a reasonable
* state first.
*/
#define UMA_MD_SMALL_ALLOC_NEEDS_VM
#else
/*

View file

@ -216,6 +216,7 @@ ofwfb_configure(int flags)
phandle_t chosen;
ihandle_t stdout;
phandle_t node;
bus_addr_t fb_phys;
int depth;
int disable;
int len;
@ -270,10 +271,16 @@ ofwfb_configure(int flags)
OF_getprop(node, "linebytes", &sc->sc_stride, sizeof(sc->sc_stride));
/*
* XXX the physical address of the frame buffer is assumed to be
* BAT-mapped so it can be accessed directly
* Grab the physical address of the framebuffer, and then map it
* into our memory space. If the MMU is not yet up, it will be
* remapped for us when relocation turns on.
*
* XXX We assume #address-cells is 1 at this point.
*/
OF_getprop(node, "address", &sc->sc_addr, sizeof(sc->sc_addr));
OF_getprop(node, "address", &fb_phys, sizeof(fb_phys));
bus_space_map(&bs_be_tag, fb_phys, sc->sc_height * sc->sc_stride,
0, &sc->sc_addr);
/*
* Get the PCI addresses of the adapter. The node may be the
@ -283,8 +290,8 @@ ofwfb_configure(int flags)
len = OF_getprop(node, "assigned-addresses", sc->sc_pciaddrs,
sizeof(sc->sc_pciaddrs));
if (len == -1) {
len = OF_getprop(OF_parent(node), "assigned-addresses", sc->sc_pciaddrs,
sizeof(sc->sc_pciaddrs));
len = OF_getprop(OF_parent(node), "assigned-addresses",
sc->sc_pciaddrs, sizeof(sc->sc_pciaddrs));
}
if (len != -1) {
@ -941,13 +948,17 @@ ofwfb_scidentify(driver_t *driver, device_t parent)
static int
ofwfb_scprobe(device_t dev)
{
/* This is a fake device, so make sure there is no OF node for it */
if (ofw_bus_get_node(dev) != -1)
return ENXIO;
int error;
device_set_desc(dev, "System console");
return (sc_probe_unit(device_get_unit(dev),
device_get_flags(dev) | SC_AUTODETECT_KBD));
error = sc_probe_unit(device_get_unit(dev),
device_get_flags(dev) | SC_AUTODETECT_KBD);
if (error != 0)
return (error);
/* This is a fake device, so make sure we added it ourselves */
return (BUS_PROBE_NOWILDCARD);
}
static int

View file

@ -0,0 +1,625 @@
/*-
* Copyright (C) 2008 Nathan Whitehorn
* 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 TOOLS GMBH 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$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_pci.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <machine/bus.h>
#include <machine/md_var.h>
#include <machine/pio.h>
#include <machine/resource.h>
#include <sys/rman.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <powerpc/powermac/cpchtvar.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include "pcib_if.h"
#include "opt_isa.h"
#ifdef DEV_ISA
#include <isa/isavar.h>
#endif
static MALLOC_DEFINE(M_CPCHT, "cpcht", "CPC HT device information");
/*
* HT Driver methods.
*/
static int cpcht_probe(device_t);
static int cpcht_attach(device_t);
static ofw_bus_get_devinfo_t cpcht_get_devinfo;
static device_method_t cpcht_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, cpcht_probe),
DEVMETHOD(device_attach, cpcht_attach),
/* Bus interface */
DEVMETHOD(bus_print_child, bus_generic_print_child),
DEVMETHOD(bus_read_ivar, bus_generic_read_ivar),
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
DEVMETHOD(bus_release_resource, bus_generic_release_resource),
DEVMETHOD(bus_activate_resource,bus_generic_activate_resource),
/* ofw_bus interface */
DEVMETHOD(ofw_bus_get_devinfo, cpcht_get_devinfo),
DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat),
DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model),
DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name),
DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node),
DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type),
{ 0, 0 }
};
static driver_t cpcht_driver = {
"cpcht",
cpcht_methods,
0
};
static devclass_t cpcht_devclass;
DRIVER_MODULE(cpcht, nexus, cpcht_driver, cpcht_devclass, 0, 0);
static int
cpcht_probe(device_t dev)
{
const char *type, *compatible;
type = ofw_bus_get_type(dev);
compatible = ofw_bus_get_compat(dev);
if (type == NULL || compatible == NULL)
return (ENXIO);
if (strcmp(type, "ht") != 0)
return (ENXIO);
if (strcmp(compatible, "u3-ht") == 0) {
device_set_desc(dev, "IBM CPC925 HyperTransport Tunnel");
return (0);
} else if (strcmp(compatible,"u4-ht") == 0) {
device_set_desc(dev, "IBM CPC945 HyperTransport Tunnel");
return (0);
}
return (ENXIO);
}
static int
cpcht_attach(device_t dev)
{
phandle_t root, child;
device_t cdev;
struct ofw_bus_devinfo *dinfo;
u_int32_t reg[6];
root = ofw_bus_get_node(dev);
if (OF_getprop(root, "reg", reg, sizeof(reg)) < 8)
return (ENXIO);
for (child = OF_child(root); child != 0; child = OF_peer(child)) {
dinfo = malloc(sizeof(*dinfo), M_CPCHT, M_WAITOK | M_ZERO);
if (ofw_bus_gen_setup_devinfo(dinfo, child) != 0) {
free(dinfo, M_CPCHT);
continue;
}
cdev = device_add_child(dev, NULL, -1);
if (cdev == NULL) {
device_printf(dev, "<%s>: device_add_child failed\n",
dinfo->obd_name);
ofw_bus_gen_destroy_devinfo(dinfo);
free(dinfo, M_CPCHT);
continue;
}
device_set_ivars(cdev, dinfo);
}
return (bus_generic_attach(dev));
}
static const struct ofw_bus_devinfo *
cpcht_get_devinfo(device_t dev, device_t child)
{
return (device_get_ivars(child));
}
#ifdef DEV_ISA
/*
* CPC ISA Device interface.
*/
static int cpcisa_probe(device_t);
/*
* Driver methods.
*/
static device_method_t cpcisa_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, cpcisa_probe),
DEVMETHOD(device_attach, isab_attach),
/* Bus interface */
DEVMETHOD(bus_print_child, bus_generic_print_child),
DEVMETHOD(bus_read_ivar, bus_generic_read_ivar),
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
DEVMETHOD(bus_release_resource, bus_generic_release_resource),
DEVMETHOD(bus_activate_resource,bus_generic_activate_resource),
{0,0}
};
static driver_t cpcisa_driver = {
"isab",
cpcisa_methods,
0
};
DRIVER_MODULE(cpcisa, cpcht, cpcisa_driver, isab_devclass, 0, 0);
static int
cpcisa_probe(device_t dev)
{
const char *type;
type = ofw_bus_get_type(dev);
if (type == NULL)
return (ENXIO);
if (strcmp(type, "isa") != 0)
return (ENXIO);
device_set_desc(dev, "HyperTransport-ISA bridge");
return (0);
}
#endif /* DEV_ISA */
/*
* CPC PCI Device interface.
*/
static int cpcpci_probe(device_t);
static int cpcpci_attach(device_t);
/*
* Bus interface.
*/
static int cpcpci_read_ivar(device_t, device_t, int,
uintptr_t *);
static struct resource * cpcpci_alloc_resource(device_t bus,
device_t child, int type, int *rid, u_long start,
u_long end, u_long count, u_int flags);
static int cpcpci_activate_resource(device_t bus, device_t child,
int type, int rid, struct resource *res);
/*
* pcib interface.
*/
static int cpcpci_maxslots(device_t);
static u_int32_t cpcpci_read_config(device_t, u_int, u_int, u_int,
u_int, int);
static void cpcpci_write_config(device_t, u_int, u_int, u_int,
u_int, u_int32_t, int);
static int cpcpci_route_interrupt(device_t, device_t, int);
/*
* ofw_bus interface
*/
static phandle_t cpcpci_get_node(device_t bus, device_t child);
/*
* Driver methods.
*/
static device_method_t cpcpci_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, cpcpci_probe),
DEVMETHOD(device_attach, cpcpci_attach),
/* Bus interface */
DEVMETHOD(bus_print_child, bus_generic_print_child),
DEVMETHOD(bus_read_ivar, cpcpci_read_ivar),
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
DEVMETHOD(bus_alloc_resource, cpcpci_alloc_resource),
DEVMETHOD(bus_activate_resource, cpcpci_activate_resource),
/* pcib interface */
DEVMETHOD(pcib_maxslots, cpcpci_maxslots),
DEVMETHOD(pcib_read_config, cpcpci_read_config),
DEVMETHOD(pcib_write_config, cpcpci_write_config),
DEVMETHOD(pcib_route_interrupt, cpcpci_route_interrupt),
/* ofw_bus interface */
DEVMETHOD(ofw_bus_get_node, cpcpci_get_node),
{ 0, 0 }
};
static driver_t cpcpci_driver = {
"pcib",
cpcpci_methods,
sizeof(struct cpcpci_softc)
};
static devclass_t cpcpci_devclass;
DRIVER_MODULE(cpcpci, cpcht, cpcpci_driver, cpcpci_devclass, 0, 0);
static int
cpcpci_probe(device_t dev)
{
const char *type;
type = ofw_bus_get_type(dev);
if (type == NULL)
return (ENXIO);
if (strcmp(type, "pci") != 0)
return (ENXIO);
device_set_desc(dev, "HyperTransport-PCI bridge");
return (0);
}
static int
cpcpci_attach(device_t dev)
{
struct cpcpci_softc *sc;
phandle_t node;
u_int32_t reg[2], busrange[2], config_base;
struct cpcpci_range *rp, *io, *mem[2];
struct cpcpci_range fakeio;
int nmem, i;
node = ofw_bus_get_node(dev);
sc = device_get_softc(dev);
if (OF_getprop(OF_parent(node), "reg", reg, sizeof(reg)) < 8)
return (ENXIO);
if (OF_getprop(node, "bus-range", busrange, sizeof(busrange)) != 8)
return (ENXIO);
sc->sc_dev = dev;
sc->sc_node = node;
sc->sc_bus = busrange[0];
config_base = reg[1];
if (sc->sc_bus)
config_base += 0x01000000UL + (sc->sc_bus << 16);
sc->sc_data = (vm_offset_t)pmap_mapdev(config_base, PAGE_SIZE << 4);
bzero(sc->sc_range, sizeof(sc->sc_range));
sc->sc_nrange = OF_getprop(node, "ranges", sc->sc_range,
sizeof(sc->sc_range));
if (sc->sc_nrange == -1) {
device_printf(dev, "could not get ranges\n");
return (ENXIO);
}
sc->sc_range[6].pci_hi = 0;
io = NULL;
nmem = 0;
for (rp = sc->sc_range; rp->pci_hi != 0; rp++) {
switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
case OFW_PCI_PHYS_HI_SPACE_CONFIG:
break;
case OFW_PCI_PHYS_HI_SPACE_IO:
io = rp;
break;
case OFW_PCI_PHYS_HI_SPACE_MEM32:
mem[nmem] = rp;
nmem++;
break;
case OFW_PCI_PHYS_HI_SPACE_MEM64:
break;
}
}
if (io == NULL) {
/*
* On at least some machines, the I/O port range is
* not exported in the OF device tree. So hardcode it.
*/
fakeio.host_lo = 0;
fakeio.pci_lo = reg[1];
fakeio.size_lo = 0x00400000;
if (sc->sc_bus)
fakeio.pci_lo += 0x02000000UL + (sc->sc_bus << 14);
io = &fakeio;
}
sc->sc_io_rman.rm_type = RMAN_ARRAY;
sc->sc_io_rman.rm_descr = "CPC 9xx PCI I/O Ports";
sc->sc_iostart = io->host_lo;
if (rman_init(&sc->sc_io_rman) != 0 ||
rman_manage_region(&sc->sc_io_rman, io->pci_lo,
io->pci_lo + io->size_lo - 1) != 0) {
device_printf(dev, "failed to set up io range management\n");
return (ENXIO);
}
if (nmem == 0) {
device_printf(dev, "can't find mem ranges\n");
return (ENXIO);
}
sc->sc_mem_rman.rm_type = RMAN_ARRAY;
sc->sc_mem_rman.rm_descr = "CPC 9xx PCI Memory";
if (rman_init(&sc->sc_mem_rman) != 0) {
device_printf(dev,
"failed to init mem range resources\n");
return (ENXIO);
}
for (i = 0; i < nmem; i++) {
if (rman_manage_region(&sc->sc_mem_rman, mem[i]->pci_lo,
mem[i]->pci_lo + mem[i]->size_lo - 1) != 0) {
device_printf(dev,
"failed to set up memory range management\n");
return (ENXIO);
}
}
ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(cell_t));
device_add_child(dev, "pci", device_get_unit(dev));
return (bus_generic_attach(dev));
}
static int
cpcpci_maxslots(device_t dev)
{
return (PCI_SLOTMAX);
}
static u_int32_t
cpcpci_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
int width)
{
struct cpcpci_softc *sc;
vm_offset_t caoff;
sc = device_get_softc(dev);
caoff = sc->sc_data +
(((((slot & 0x1f) << 3) | (func & 0x07)) << 8) | reg);
switch (width) {
case 1:
return (in8rb(caoff));
break;
case 2:
return (in16rb(caoff));
break;
case 4:
return (in32rb(caoff));
break;
}
return (0xffffffff);
}
static void
cpcpci_write_config(device_t dev, u_int bus, u_int slot, u_int func,
u_int reg, u_int32_t val, int width)
{
struct cpcpci_softc *sc;
vm_offset_t caoff;
sc = device_get_softc(dev);
caoff = sc->sc_data +
(((((slot & 0x1f) << 3) | (func & 0x07)) << 8) | reg);
switch (width) {
case 1:
out8rb(caoff, val);
break;
case 2:
out16rb(caoff, val);
break;
case 4:
out32rb(caoff, val);
break;
}
}
static int
cpcpci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
{
struct cpcpci_softc *sc;
sc = device_get_softc(dev);
switch (which) {
case PCIB_IVAR_DOMAIN:
*result = device_get_unit(dev);
return (0);
case PCIB_IVAR_BUS:
*result = sc->sc_bus;
return (0);
}
return (ENOENT);
}
static struct resource *
cpcpci_alloc_resource(device_t bus, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
{
struct cpcpci_softc *sc;
struct resource *rv;
struct rman *rm;
int needactivate;
needactivate = flags & RF_ACTIVE;
flags &= ~RF_ACTIVE;
sc = device_get_softc(bus);
switch (type) {
case SYS_RES_MEMORY:
rm = &sc->sc_mem_rman;
break;
case SYS_RES_IOPORT:
rm = &sc->sc_io_rman;
if (rm == NULL)
return (NULL);
break;
case SYS_RES_IRQ:
return (bus_alloc_resource(bus, type, rid, start, end, count,
flags));
default:
device_printf(bus, "unknown resource request from %s\n",
device_get_nameunit(child));
return (NULL);
}
rv = rman_reserve_resource(rm, start, end, count, flags, child);
if (rv == NULL) {
device_printf(bus, "failed to reserve resource for %s\n",
device_get_nameunit(child));
return (NULL);
}
rman_set_rid(rv, *rid);
if (needactivate) {
if (bus_activate_resource(child, type, *rid, rv) != 0) {
device_printf(bus,
"failed to activate resource for %s\n",
device_get_nameunit(child));
rman_release_resource(rv);
return (NULL);
}
}
return (rv);
}
static int
cpcpci_activate_resource(device_t bus, device_t child, int type, int rid,
struct resource *res)
{
void *p;
struct cpcpci_softc *sc;
sc = device_get_softc(bus);
if (type == SYS_RES_IRQ)
return (bus_activate_resource(bus, type, rid, res));
if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
vm_offset_t start;
start = (vm_offset_t)rman_get_start(res);
/*
* For i/o-ports, convert the start address to the
* CPC PCI i/o window
*/
if (type == SYS_RES_IOPORT)
start += sc->sc_iostart;
if (bootverbose)
printf("cpcpci mapdev: start %x, len %ld\n", start,
rman_get_size(res));
p = pmap_mapdev(start, (vm_size_t)rman_get_size(res));
if (p == NULL)
return (ENOMEM);
rman_set_virtual(res, p);
rman_set_bustag(res, &bs_le_tag);
rman_set_bushandle(res, (u_long)p);
}
return (rman_activate_resource(res));
}
static phandle_t
cpcpci_get_node(device_t bus, device_t dev)
{
struct cpcpci_softc *sc;
sc = device_get_softc(bus);
/* We only have one child, the PCI bus, which needs our own node. */
return (sc->sc_node);
}
static int
cpcpci_route_interrupt(device_t bus, device_t dev, int pin)
{
struct cpcpci_softc *sc;
struct ofw_pci_register reg;
uint32_t pintr, mintr;
uint8_t maskbuf[sizeof(reg) + sizeof(pintr)];
sc = device_get_softc(bus);
pintr = pin;
if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, &reg,
sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), maskbuf))
return (mintr);
/* Maybe it's a real interrupt, not an intpin */
if (pin > 4)
return (pin);
device_printf(bus, "could not route pin %d for device %d.%d\n",
pin, pci_get_slot(dev), pci_get_function(dev));
return (PCI_INVALID_IRQ);
}

View file

@ -0,0 +1,58 @@
/*-
* Copyright (C) 2008 Nathan Whitehorn
* 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 TOOLS GMBH 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$
*/
#ifndef _POWERPC_POWERMAC_CPCHTVAR_H_
#define _POWERPC_POWERMAC_CPCHTVAR_H_
struct cpcpci_range {
u_int32_t pci_hi;
u_int32_t pci_mid;
u_int32_t pci_lo;
u_int32_t junk;
u_int32_t host_hi;
u_int32_t host_lo;
u_int32_t size_hi;
u_int32_t size_lo;
};
struct cpcpci_softc {
device_t sc_dev;
phandle_t sc_node;
vm_offset_t sc_data;
int sc_bus;
struct cpcpci_range sc_range[6];
int sc_nrange;
int sc_iostart;
struct rman sc_io_rman;
struct rman sc_mem_rman;
bus_space_tag_t sc_iot;
bus_space_tag_t sc_memt;
bus_dma_tag_t sc_dmat;
struct ofw_bus_iinfo sc_pci_iinfo;
};
#endif /* _POWERPC_POWERMAC_CPCHTVAR_H_ */

View file

@ -42,12 +42,25 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <machine/bus.h>
#include <machine/pio.h>
#include <machine/md_var.h>
#define TODO panic("%s: not implemented", __func__)
#define MAX_EARLYBOOT_MAPPINGS 6
static struct {
bus_addr_t addr;
bus_size_t size;
} earlyboot_mappings[MAX_EARLYBOOT_MAPPINGS];
static int earlyboot_map_idx = 0;
void bs_remap_earlyboot(void);
static __inline void *
__ppc_ba(bus_space_handle_t bsh, bus_size_t ofs)
{
@ -58,10 +71,44 @@ static int
bs_gen_map(bus_addr_t addr, bus_size_t size __unused, int flags __unused,
bus_space_handle_t *bshp)
{
*bshp = addr;
/*
* Record what we did if we haven't enabled the MMU yet. We
* will need to remap it as soon as the MMU comes up.
*/
if (!pmap_bootstrapped) {
KASSERT(earlyboot_map_idx < MAX_EARLYBOOT_MAPPINGS,
("%s: too many early boot mapping requests", __func__));
earlyboot_mappings[earlyboot_map_idx].addr = addr;
earlyboot_mappings[earlyboot_map_idx].size = size;
earlyboot_map_idx++;
*bshp = addr;
} else {
*bshp = (bus_space_handle_t)pmap_mapdev(addr,size);
}
return (0);
}
void
bs_remap_earlyboot(void)
{
int i;
vm_offset_t pa, spa;
if (hw_direct_map)
return;
for (i = 0; i < earlyboot_map_idx; i++) {
spa = earlyboot_mappings[i].addr;
pa = trunc_page(spa);
while (pa < spa + earlyboot_mappings[i].size) {
pmap_kenter(pa,pa);
pa += PAGE_SIZE;
}
}
}
static void
bs_gen_unmap(bus_size_t size __unused)
{

View file

@ -91,6 +91,10 @@ static const struct cputab models[] = {
{ "Motorola PowerPC 620", MPC620, REVFMT_HEX },
{ "Motorola PowerPC 750", MPC750, REVFMT_MAJMIN },
{ "IBM PowerPC 750FX", IBM750FX, REVFMT_MAJMIN },
{ "IBM PowerPC 970", IBM970, REVFMT_MAJMIN },
{ "IBM PowerPC 970FX", IBM970FX, REVFMT_MAJMIN },
{ "IBM PowerPC 970GX", IBM970GX, REVFMT_MAJMIN },
{ "IBM PowerPC 970MP", IBM970MP, REVFMT_MAJMIN },
{ "Motorola PowerPC 7400", MPC7400, REVFMT_MAJMIN },
{ "Motorola PowerPC 7410", MPC7410, REVFMT_MAJMIN },
{ "Motorola PowerPC 7450", MPC7450, REVFMT_MAJMIN },

View file

@ -64,6 +64,7 @@ __FBSDID("$FreeBSD$");
#include <vm/vm.h>
#include <vm/pmap.h>
#include <vm/vm_extern.h>
#include <vm/vm_page.h>
#include <machine/memdev.h>
@ -77,6 +78,8 @@ memrw(struct cdev *dev, struct uio *uio, int flags)
int error = 0;
vm_offset_t va, eva, off, v;
vm_prot_t prot;
struct vm_page m;
vm_page_t marr;
vm_size_t cnt;
cnt = 0;
@ -102,14 +105,18 @@ kmem_direct_mapped: v = uio->uio_offset;
cnt = min(cnt, PAGE_SIZE - off);
cnt = min(cnt, iov->iov_len);
if (mem_valid(v, cnt)
&& pmap_dev_direct_mapped(v, cnt)) {
if (mem_valid(v, cnt)) {
error = EFAULT;
break;
}
uiomove((void *)v, cnt, uio);
break;
if (!pmap_dev_direct_mapped(v, cnt)) {
error = uiomove((void *)v, cnt, uio);
} else {
m.phys_addr = trunc_page(v);
marr = &m;
error = uiomove_fromphys(&marr, off, cnt, uio);
}
}
else if (dev2unit(dev) == CDEV_MINOR_KMEM) {
va = uio->uio_offset;

View file

@ -697,6 +697,18 @@ METHOD void bootstrap {
vm_offset_t _end;
};
/**
* @brief Set up the MMU on the current CPU. Only called by the PMAP layer
* for alternate CPUs on SMP systems.
*
* @param _ap Set to 1 if the CPU being set up is an AP
*
*/
METHOD void cpu_bootstrap {
mmu_t _mmu;
int _ap;
};
/**
* @brief Create a kernel mapping for a given physical address range.

View file

@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_page.h>
#include <machine/mmuvar.h>
#include <machine/smp.h>
#include "mmu_if.h"
@ -406,6 +407,16 @@ pmap_bootstrap(vm_offset_t start, vm_offset_t end)
MMU_BOOTSTRAP(mmu_obj, start, end);
}
void
pmap_cpu_bootstrap(int ap)
{
/*
* No KTR here because our console probably doesn't work yet
*/
return (MMU_CPU_BOOTSTRAP(mmu_obj, ap));
}
void *
pmap_mapdev(vm_offset_t pa, vm_size_t size)
{