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:
parent
cd5e62f992
commit
1c96bdd146
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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, ®ions, ®ions_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
2443
sys/powerpc/aim/mmu_oea64.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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_ */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
|
625
sys/powerpc/powermac/cpcht.c
Normal file
625
sys/powerpc/powermac/cpcht.c
Normal 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, ®,
|
||||
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);
|
||||
}
|
||||
|
58
sys/powerpc/powermac/cpchtvar.h
Normal file
58
sys/powerpc/powermac/cpchtvar.h
Normal 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_ */
|
@ -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)
|
||||
{
|
||||
|
@ -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 },
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user