diff --git a/sys/dev/ofw/ofw_if.m b/sys/dev/ofw/ofw_if.m index 902f071aa40..d2d323bf4cb 100644 --- a/sys/dev/ofw/ofw_if.m +++ b/sys/dev/ofw/ofw_if.m @@ -339,6 +339,13 @@ METHOD void release { # Commands for returning control to the firmware +/** + * @brief Turn off firmware background activities + */ +METHOD void quiesce { + ofw_t _ofw; +}; + /** * @brief Temporarily return control to firmware. */ diff --git a/sys/dev/ofw/ofw_standard.c b/sys/dev/ofw/ofw_standard.c index e521fa059d3..5eecf773b2b 100644 --- a/sys/dev/ofw/ofw_standard.c +++ b/sys/dev/ofw/ofw_standard.c @@ -105,6 +105,7 @@ static ssize_t ofw_std_write(ofw_t ofw, ihandle_t instance, const void *addr, static int ofw_std_seek(ofw_t ofw, ihandle_t instance, uint64_t pos); static caddr_t ofw_std_claim(ofw_t ofw, void *virt, size_t size, u_int align); static void ofw_std_release(ofw_t ofw, void *virt, size_t size); +static void ofw_std_quiesce(ofw_t ofw); static void ofw_std_enter(ofw_t ofw); static void ofw_std_exit(ofw_t ofw); @@ -133,6 +134,7 @@ static ofw_method_t ofw_std_methods[] = { OFWMETHOD(ofw_seek, ofw_std_seek), OFWMETHOD(ofw_claim, ofw_std_claim), OFWMETHOD(ofw_release, ofw_std_release), + OFWMETHOD(ofw_quiesce, ofw_std_quiesce), OFWMETHOD(ofw_enter, ofw_std_enter), OFWMETHOD(ofw_exit, ofw_std_exit), @@ -730,6 +732,23 @@ ofw_std_release(ofw_t ofw, void *virt, size_t size) * Control transfer functions */ +/* Turn off OF background tasks */ +static void +ofw_std_quiesce(ofw_t ofw) +{ + struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + } args = { + (cell_t)"quiesce", + 0, + 0, + }; + + openfirmware(&args); +} + /* Suspend and drop back to the Open Firmware interface. */ static void ofw_std_enter(ofw_t ofw) diff --git a/sys/dev/ofw/openfirm.c b/sys/dev/ofw/openfirm.c index 17cda68678a..a560e93770a 100644 --- a/sys/dev/ofw/openfirm.c +++ b/sys/dev/ofw/openfirm.c @@ -409,6 +409,15 @@ OF_release(void *virt, size_t size) * Control transfer functions */ +/* Turn off OF background tasks */ +void +OF_quiesce() +{ + + OFW_QUIESCE(ofw_obj); +} + + /* Suspend and drop back to the Open Firmware interface. */ void OF_enter() diff --git a/sys/dev/ofw/openfirm.h b/sys/dev/ofw/openfirm.h index 10e8aad80ac..08cbaf3a585 100644 --- a/sys/dev/ofw/openfirm.h +++ b/sys/dev/ofw/openfirm.h @@ -133,6 +133,7 @@ void *OF_claim(void *virtrequest, size_t size, u_int align); void OF_release(void *virt, size_t size); /* Control transfer functions */ +void OF_quiesce(void); void OF_enter(void); void OF_exit(void) __attribute__((noreturn)); diff --git a/sys/powerpc/aim/ofw_machdep.c b/sys/powerpc/aim/ofw_machdep.c index 6e98f3e4fba..6a869b4d205 100644 --- a/sys/powerpc/aim/ofw_machdep.c +++ b/sys/powerpc/aim/ofw_machdep.c @@ -281,6 +281,8 @@ OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)) boolean_t OF_bootstrap() { + char model[32]; + phandle_t rootnode; boolean_t status = FALSE; mtx_init(&ofw_mutex, "open firmware", NULL, MTX_DEF); @@ -295,6 +297,17 @@ OF_bootstrap() return status; OF_init(openfirmware); + + /* + * On some machines, we need to quiesce OF to turn off + * background processes. + */ + rootnode = OF_finddevice("/"); + if (OF_getprop(rootnode, "model", model, sizeof(model)) > 0) { + if (strcmp(model, "PowerMac11,2") == 0 || + strcmp(model, "PowerMac12,1") == 0) + OF_quiesce(); + } } else { status = OF_install(OFW_FDT, 0); diff --git a/sys/powerpc/ofw/ofw_real.c b/sys/powerpc/ofw/ofw_real.c index 4425ad1bc5d..1590eb644a3 100644 --- a/sys/powerpc/ofw/ofw_real.c +++ b/sys/powerpc/ofw/ofw_real.c @@ -106,6 +106,7 @@ static ssize_t ofw_real_write(ofw_t, ihandle_t instance, const void *addr, static int ofw_real_seek(ofw_t, ihandle_t instance, u_int64_t pos); static caddr_t ofw_real_claim(ofw_t, void *virt, size_t size, u_int align); static void ofw_real_release(ofw_t, void *virt, size_t size); +static void ofw_real_quiesce(ofw_t); static void ofw_real_enter(ofw_t); static void ofw_real_exit(ofw_t); @@ -133,6 +134,7 @@ static ofw_method_t ofw_real_methods[] = { OFWMETHOD(ofw_seek, ofw_real_seek), OFWMETHOD(ofw_claim, ofw_real_claim), OFWMETHOD(ofw_release, ofw_real_release), + OFWMETHOD(ofw_quiesce, ofw_real_quiesce), OFWMETHOD(ofw_enter, ofw_real_enter), OFWMETHOD(ofw_exit, ofw_real_exit), @@ -889,6 +891,27 @@ ofw_real_release(ofw_t ofw, void *virt, size_t size) * Control transfer functions */ +/* Turn off OF background tasks */ +static void +ofw_real_quiesce(ofw_t ofw) +{ + vm_offset_t argsptr; + struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + } args; + + args.name = (cell_t)(uintptr_t)"quiesce"; + args.nargs = 0; + args.nreturns = 0; + + ofw_real_start(); + argsptr = ofw_real_map(&args, sizeof(args)); + openfirmware((void *)argsptr); + ofw_real_stop(); +} + /* Suspend and drop back to the Open Firmware interface. */ static void ofw_real_enter(ofw_t ofw)