From b2a237be5c4031f91743bde57571075ff388e497 Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Tue, 31 Aug 2010 15:27:46 +0000 Subject: [PATCH] Restructure how reset and poweroff are handled on PowerPC systems, since the existing code was very platform specific, and broken for SMP systems trying to reboot from KDB. - Add a new PLATFORM_RESET() method to the platform KOBJ interface, and migrate existing reset functions into platform modules. - Modify the OF_reboot() routine to submit the request by hand to avoid the IPIs involved in the regular openfirmware() routine. This fixes reboot from KDB on SMP machines. - Move non-KDB reset and poweroff functions on the Powermac platform into the relevant power control drivers (cuda, pmu, smu), instead of using them through the Open Firmware backdoor. - Rename platform_chrp to platform_powermac since it has become increasingly Powermac specific. When we gain support for IBM systems, we will grow a new platform_chrp. --- sys/conf/files.powerpc | 2 +- sys/powerpc/aim/machdep.c | 12 ---- sys/powerpc/aim/ofw_machdep.c | 23 +++--- sys/powerpc/aim/vm_machdep.c | 9 --- sys/powerpc/booke/platform_bare.c | 31 ++++++++ sys/powerpc/include/ofw_machdep.h | 1 - sys/powerpc/mpc85xx/mpc85xx.c | 25 ------- sys/powerpc/powermac/cuda.c | 18 +++++ .../platform_powermac.c} | 71 +++++++++++-------- sys/powerpc/powermac/pmu.c | 26 +++++++ sys/powerpc/powermac/smu.c | 26 +++++++ sys/powerpc/powerpc/platform.c | 10 +++ sys/powerpc/powerpc/platform_if.m | 7 ++ 13 files changed, 171 insertions(+), 90 deletions(-) rename sys/powerpc/{aim/platform_chrp.c => powermac/platform_powermac.c} (72%) diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc index 70ca1087132..409554f0e04 100644 --- a/sys/conf/files.powerpc +++ b/sys/conf/files.powerpc @@ -82,7 +82,6 @@ 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/platform_chrp.c optional aim powerpc/aim/slb.c optional aim powerpc64 powerpc/aim/swtch32.S optional aim powerpc powerpc/aim/swtch64.S optional aim powerpc64 @@ -143,6 +142,7 @@ powerpc/powermac/kiic.c optional powermac kiic powerpc/powermac/macgpio.c optional powermac pci powerpc/powermac/macio.c optional powermac pci powerpc/powermac/openpic_macio.c optional powermac pci +powerpc/powermac/platform_powermac.c optional powermac powerpc/powermac/pswitch.c optional powermac pswitch powerpc/powermac/pmu.c optional powermac pmu powerpc/powermac/smu.c optional powermac smu diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c index a2f13efd6ca..fe3939d1f37 100644 --- a/sys/powerpc/aim/machdep.c +++ b/sys/powerpc/aim/machdep.c @@ -167,15 +167,6 @@ struct bat battable[16]; struct kva_md_info kmi; -static void -powerpc_ofw_shutdown(void *junk, int howto) -{ - if (howto & RB_HALT) { - OF_halt(); - } - OF_reboot(); -} - static void cpu_startup(void *dummy) { @@ -233,9 +224,6 @@ cpu_startup(void *dummy) */ bufinit(); vm_pager_bufferinit(); - - EVENTHANDLER_REGISTER(shutdown_final, powerpc_ofw_shutdown, 0, - SHUTDOWN_PRI_LAST); } extern char kernel_text[], _end[]; diff --git a/sys/powerpc/aim/ofw_machdep.c b/sys/powerpc/aim/ofw_machdep.c index 21b88477807..e0bf5057521 100644 --- a/sys/powerpc/aim/ofw_machdep.c +++ b/sys/powerpc/aim/ofw_machdep.c @@ -526,21 +526,22 @@ openfirmware(void *args) return (result); } -void -OF_halt() -{ - int retval; /* dummy, this may not be needed */ - - OF_interpret("shut-down", 1, &retval); - for (;;); /* just in case */ -} - void OF_reboot() { - int retval; /* dummy, this may not be needed */ + struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t arg; + } args; + + args.name = (cell_t)(uintptr_t)"interpret"; + args.nargs = 1; + args.nreturns = 0; + args.arg = (cell_t)(uintptr_t)"reset-all"; + openfirmware_core(&args); /* Don't do rendezvous! */ - OF_interpret("reset-all", 1, &retval); for (;;); /* just in case */ } diff --git a/sys/powerpc/aim/vm_machdep.c b/sys/powerpc/aim/vm_machdep.c index 6ee03fbb8c0..d1d569fc0f8 100644 --- a/sys/powerpc/aim/vm_machdep.c +++ b/sys/powerpc/aim/vm_machdep.c @@ -237,15 +237,6 @@ cpu_exit(td) { } -/* - * Reset back to firmware. - */ -void -cpu_reset() -{ - OF_reboot(); -} - /* * Allocate a pool of sf_bufs (sendfile(2) or "super-fast" if you prefer. :-)) */ diff --git a/sys/powerpc/booke/platform_bare.c b/sys/powerpc/booke/platform_bare.c index 627470d6cce..bdfcbfc41b0 100644 --- a/sys/powerpc/booke/platform_bare.c +++ b/sys/powerpc/booke/platform_bare.c @@ -70,6 +70,8 @@ static int bare_smp_next_cpu(platform_t, struct cpuref *cpuref); static int bare_smp_get_bsp(platform_t, struct cpuref *cpuref); static int bare_smp_start_cpu(platform_t, struct pcpu *cpu); +static void e500_reset(platform_t); + static platform_method_t bare_methods[] = { PLATFORMMETHOD(platform_probe, bare_probe), PLATFORMMETHOD(platform_mem_regions, bare_mem_regions), @@ -80,6 +82,8 @@ static platform_method_t bare_methods[] = { PLATFORMMETHOD(platform_smp_get_bsp, bare_smp_get_bsp), PLATFORMMETHOD(platform_smp_start_cpu, bare_smp_start_cpu), + PLATFORMMETHOD(platform_reset, e500_reset); + { 0, 0 } }; @@ -260,3 +264,30 @@ bare_smp_start_cpu(platform_t plat, struct pcpu *pc) return (ENXIO); #endif } + +static void +e500_reset(platform_t plat) +{ + uint32_t ver = SVR_VER(mfspr(SPR_SVR)); + + if (ver == SVR_MPC8572E || ver == SVR_MPC8572 || + ver == SVR_MPC8548E || ver == SVR_MPC8548) + /* Systems with dedicated reset register */ + ccsr_write4(OCP85XX_RSTCR, 2); + else { + /* Clear DBCR0, disables debug interrupts and events. */ + mtspr(SPR_DBCR0, 0); + __asm __volatile("isync"); + + /* Enable Debug Interrupts in MSR. */ + mtmsr(mfmsr() | PSL_DE); + + /* Enable debug interrupts and issue reset. */ + mtspr(SPR_DBCR0, mfspr(SPR_DBCR0) | DBCR0_IDM | + DBCR0_RST_SYSTEM); + } + + printf("Reset failed...\n"); + while (1); +} + diff --git a/sys/powerpc/include/ofw_machdep.h b/sys/powerpc/include/ofw_machdep.h index bf79224795c..612b45b4bc1 100644 --- a/sys/powerpc/include/ofw_machdep.h +++ b/sys/powerpc/include/ofw_machdep.h @@ -43,7 +43,6 @@ void OF_getetheraddr(device_t dev, u_char *addr); void OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)); boolean_t OF_bootstrap(void); -void OF_halt(void); void OF_reboot(void); void ofw_mem_regions(struct mem_region **, int *, struct mem_region **, int *); diff --git a/sys/powerpc/mpc85xx/mpc85xx.c b/sys/powerpc/mpc85xx/mpc85xx.c index 75304496d2f..564bf84b877 100644 --- a/sys/powerpc/mpc85xx/mpc85xx.c +++ b/sys/powerpc/mpc85xx/mpc85xx.c @@ -164,28 +164,3 @@ law_pci_target(struct resource *res, int *trgt_mem, int *trgt_io) return (rv); } -void -cpu_reset(void) -{ - uint32_t ver = SVR_VER(mfspr(SPR_SVR)); - - if (ver == SVR_MPC8572E || ver == SVR_MPC8572 || - ver == SVR_MPC8548E || ver == SVR_MPC8548) - /* Systems with dedicated reset register */ - ccsr_write4(OCP85XX_RSTCR, 2); - else { - /* Clear DBCR0, disables debug interrupts and events. */ - mtspr(SPR_DBCR0, 0); - __asm __volatile("isync"); - - /* Enable Debug Interrupts in MSR. */ - mtmsr(mfmsr() | PSL_DE); - - /* Enable debug interrupts and issue reset. */ - mtspr(SPR_DBCR0, mfspr(SPR_DBCR0) | DBCR0_IDM | - DBCR0_RST_SYSTEM); - } - - printf("Reset failed...\n"); - while (1); -} diff --git a/sys/powerpc/powermac/cuda.c b/sys/powerpc/powermac/cuda.c index 0499352adec..99a0ea9c461 100644 --- a/sys/powerpc/powermac/cuda.c +++ b/sys/powerpc/powermac/cuda.c @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -72,6 +73,7 @@ static u_int cuda_adb_autopoll(device_t dev, uint16_t mask); static u_int cuda_poll(device_t dev); static void cuda_send_inbound(struct cuda_softc *sc); static void cuda_send_outbound(struct cuda_softc *sc); +static void cuda_shutdown(void *xsc, int howto); /* * Clock interface @@ -249,6 +251,8 @@ cuda_attach(device_t dev) } clock_register(dev, 1000); + EVENTHANDLER_REGISTER(shutdown_final, cuda_shutdown, sc, + SHUTDOWN_PRI_LAST); return (bus_generic_attach(dev)); } @@ -739,6 +743,20 @@ cuda_adb_autopoll(device_t dev, uint16_t mask) { return (0); } +static void +cuda_shutdown(void *xsc, int howto) +{ + struct cuda_softc *sc = xsc; + uint8_t cmd[] = {CUDA_PSEUDO, 0}; + + cmd[1] = (howto & RB_HALT) ? CMD_POWEROFF : CMD_RESET; + cuda_poll(sc->sc_dev); + cuda_send(sc, 1, 2, cmd); + + while (1) + cuda_poll(sc->sc_dev); +} + #define DIFF19041970 2082844800 static int diff --git a/sys/powerpc/aim/platform_chrp.c b/sys/powerpc/powermac/platform_powermac.c similarity index 72% rename from sys/powerpc/aim/platform_chrp.c rename to sys/powerpc/powermac/platform_powermac.c index a49b520eb6d..d495065b1b4 100644 --- a/sys/powerpc/aim/platform_chrp.c +++ b/sys/powerpc/powermac/platform_powermac.c @@ -55,38 +55,41 @@ __FBSDID("$FreeBSD$"); extern void *ap_pcpu; #endif -static int chrp_probe(platform_t); -void chrp_mem_regions(platform_t, struct mem_region **phys, int *physsz, +static int powermac_probe(platform_t); +void powermac_mem_regions(platform_t, struct mem_region **phys, int *physsz, struct mem_region **avail, int *availsz); -static u_long chrp_timebase_freq(platform_t, struct cpuref *cpuref); -static int chrp_smp_first_cpu(platform_t, struct cpuref *cpuref); -static int chrp_smp_next_cpu(platform_t, struct cpuref *cpuref); -static int chrp_smp_get_bsp(platform_t, struct cpuref *cpuref); -static int chrp_smp_start_cpu(platform_t, struct pcpu *cpu); - -static platform_method_t chrp_methods[] = { - PLATFORMMETHOD(platform_probe, chrp_probe), - PLATFORMMETHOD(platform_mem_regions, chrp_mem_regions), - PLATFORMMETHOD(platform_timebase_freq, chrp_timebase_freq), +static u_long powermac_timebase_freq(platform_t, struct cpuref *cpuref); +static int powermac_smp_first_cpu(platform_t, struct cpuref *cpuref); +static int powermac_smp_next_cpu(platform_t, struct cpuref *cpuref); +static int powermac_smp_get_bsp(platform_t, struct cpuref *cpuref); +static int powermac_smp_start_cpu(platform_t, struct pcpu *cpu); +static void powermac_reset(platform_t); + +static platform_method_t powermac_methods[] = { + PLATFORMMETHOD(platform_probe, powermac_probe), + PLATFORMMETHOD(platform_mem_regions, powermac_mem_regions), + PLATFORMMETHOD(platform_timebase_freq, powermac_timebase_freq), - PLATFORMMETHOD(platform_smp_first_cpu, chrp_smp_first_cpu), - PLATFORMMETHOD(platform_smp_next_cpu, chrp_smp_next_cpu), - PLATFORMMETHOD(platform_smp_get_bsp, chrp_smp_get_bsp), - PLATFORMMETHOD(platform_smp_start_cpu, chrp_smp_start_cpu), + PLATFORMMETHOD(platform_smp_first_cpu, powermac_smp_first_cpu), + PLATFORMMETHOD(platform_smp_next_cpu, powermac_smp_next_cpu), + PLATFORMMETHOD(platform_smp_get_bsp, powermac_smp_get_bsp), + PLATFORMMETHOD(platform_smp_start_cpu, powermac_smp_start_cpu), + + PLATFORMMETHOD(platform_reset, powermac_reset), { 0, 0 } }; -static platform_def_t chrp_platform = { - "chrp", - chrp_methods, +static platform_def_t powermac_platform = { + "powermac", + powermac_methods, 0 }; -PLATFORM_DEF(chrp_platform); +PLATFORM_DEF(powermac_platform); static int -chrp_probe(platform_t plat) +powermac_probe(platform_t plat) { if (OF_finddevice("/memory") != -1 || OF_finddevice("/memory@0") != -1) return (BUS_PROBE_GENERIC); @@ -95,14 +98,14 @@ chrp_probe(platform_t plat) } void -chrp_mem_regions(platform_t plat, struct mem_region **phys, int *physsz, +powermac_mem_regions(platform_t plat, struct mem_region **phys, int *physsz, struct mem_region **avail, int *availsz) { ofw_mem_regions(phys,physsz,avail,availsz); } static u_long -chrp_timebase_freq(platform_t plat, struct cpuref *cpuref) +powermac_timebase_freq(platform_t plat, struct cpuref *cpuref) { phandle_t phandle; int32_t ticks = -1; @@ -119,7 +122,7 @@ chrp_timebase_freq(platform_t plat, struct cpuref *cpuref) static int -chrp_smp_fill_cpuref(struct cpuref *cpuref, phandle_t cpu) +powermac_smp_fill_cpuref(struct cpuref *cpuref, phandle_t cpu) { cell_t cpuid, res; @@ -139,7 +142,7 @@ chrp_smp_fill_cpuref(struct cpuref *cpuref, phandle_t cpu) } static int -chrp_smp_first_cpu(platform_t plat, struct cpuref *cpuref) +powermac_smp_first_cpu(platform_t plat, struct cpuref *cpuref) { char buf[8]; phandle_t cpu, dev, root; @@ -175,11 +178,11 @@ chrp_smp_first_cpu(platform_t plat, struct cpuref *cpuref) if (cpu == 0) return (ENOENT); - return (chrp_smp_fill_cpuref(cpuref, cpu)); + return (powermac_smp_fill_cpuref(cpuref, cpu)); } static int -chrp_smp_next_cpu(platform_t plat, struct cpuref *cpuref) +powermac_smp_next_cpu(platform_t plat, struct cpuref *cpuref) { char buf[8]; phandle_t cpu; @@ -195,11 +198,11 @@ chrp_smp_next_cpu(platform_t plat, struct cpuref *cpuref) if (cpu == 0) return (ENOENT); - return (chrp_smp_fill_cpuref(cpuref, cpu)); + return (powermac_smp_fill_cpuref(cpuref, cpu)); } static int -chrp_smp_get_bsp(platform_t plat, struct cpuref *cpuref) +powermac_smp_get_bsp(platform_t plat, struct cpuref *cpuref) { ihandle_t inst; phandle_t bsp, chosen; @@ -214,11 +217,11 @@ chrp_smp_get_bsp(platform_t plat, struct cpuref *cpuref) return (ENXIO); bsp = OF_instance_to_package(inst); - return (chrp_smp_fill_cpuref(cpuref, bsp)); + return (powermac_smp_fill_cpuref(cpuref, bsp)); } static int -chrp_smp_start_cpu(platform_t plat, struct pcpu *pc) +powermac_smp_start_cpu(platform_t plat, struct pcpu *pc) { #ifdef SMP phandle_t cpu; @@ -277,3 +280,9 @@ chrp_smp_start_cpu(platform_t plat, struct pcpu *pc) #endif } +static void +powermac_reset(platform_t platform) +{ + OF_reboot(); +} + diff --git a/sys/powerpc/powermac/pmu.c b/sys/powerpc/powermac/pmu.c index 1fa101d9b4f..d641c9c74f5 100644 --- a/sys/powerpc/powermac/pmu.c +++ b/sys/powerpc/powermac/pmu.c @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -81,6 +82,11 @@ static u_int pmu_adb_send(device_t dev, u_char command_byte, int len, static u_int pmu_adb_autopoll(device_t dev, uint16_t mask); static u_int pmu_poll(device_t dev); +/* + * Power interface + */ + +static void pmu_shutdown(void *xsc, int howto); static void pmu_set_sleepled(void *xsc, int onoff); static int pmu_server_mode(SYSCTL_HANDLER_ARGS); static int pmu_acline_state(SYSCTL_HANDLER_ARGS); @@ -474,6 +480,12 @@ pmu_attach(device_t dev) clock_register(dev, 1000); + /* + * Register power control handler + */ + EVENTHANDLER_REGISTER(shutdown_final, pmu_shutdown, sc, + SHUTDOWN_PRI_LAST); + return (bus_generic_attach(dev)); } @@ -750,6 +762,20 @@ pmu_adb_autopoll(device_t dev, uint16_t mask) return 0; } +static void +pmu_shutdown(void *xsc, int howto) +{ + struct pmu_softc *sc = xsc; + uint8_t cmd[] = {'M', 'A', 'T', 'T'}; + + if (howto & RB_HALT) + pmu_send(sc, PMU_POWER_OFF, 4, cmd, 0, NULL); + else + pmu_send(sc, PMU_RESET_CPU, 0, NULL, 0, NULL); + + for (;;); +} + static void pmu_set_sleepled(void *xsc, int onoff) { diff --git a/sys/powerpc/powermac/smu.c b/sys/powerpc/powermac/smu.c index 7a4fac836b1..28949043bf2 100644 --- a/sys/powerpc/powermac/smu.c +++ b/sys/powerpc/powermac/smu.c @@ -165,6 +165,7 @@ static void smu_manage_fans(device_t smu); static void smu_set_sleepled(void *xdev, int onoff); static int smu_server_mode(SYSCTL_HANDLER_ARGS); static void smu_doorbell_intr(void *xdev); +static void smu_shutdown(void *xdev, int howto); /* where to find the doorbell GPIO */ @@ -391,6 +392,12 @@ smu_attach(device_t dev) */ clock_register(dev, 1000); + /* + * Learn about shutdown events + */ + EVENTHANDLER_REGISTER(shutdown_final, smu_shutdown, dev, + SHUTDOWN_PRI_LAST); + return (bus_generic_attach(dev)); } @@ -1115,6 +1122,25 @@ smu_server_mode(SYSCTL_HANDLER_ARGS) return (smu_run_cmd(smu, &cmd, 1)); } +static void +smu_shutdown(void *xdev, int howto) +{ + device_t smu = xdev; + struct smu_cmd cmd; + + cmd.cmd = SMU_POWER; + if (howto & RB_HALT) + strcpy(cmd.data, "SHUTDOWN"); + else + strcpy(cmd.data, "RESTART"); + + cmd.len = strlen(cmd.data); + + smu_run_cmd(smu, &cmd, 1); + + for (;;); +} + static int smu_gettime(device_t dev, struct timespec *ts) { diff --git a/sys/powerpc/powerpc/platform.c b/sys/powerpc/powerpc/platform.c index 400856375db..2b5c60792db 100644 --- a/sys/powerpc/powerpc/platform.c +++ b/sys/powerpc/powerpc/platform.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -104,6 +105,15 @@ platform_smp_start_cpu(struct pcpu *cpu) return (PLATFORM_SMP_START_CPU(plat_obj, cpu)); } +/* + * Reset back to firmware. + */ +void +cpu_reset() +{ + PLATFORM_RESET(plat_obj); +} + /* * Platform install routines. Highest priority wins, using the same * algorithm as bus attachment. diff --git a/sys/powerpc/powerpc/platform_if.m b/sys/powerpc/powerpc/platform_if.m index 600d14656a5..07e49bc884c 100644 --- a/sys/powerpc/powerpc/platform_if.m +++ b/sys/powerpc/powerpc/platform_if.m @@ -161,3 +161,10 @@ METHOD int smp_start_cpu { struct pcpu *_cpu; }; +/** + * @brief Reset system + */ +METHOD void reset { + platform_t _plat; +}; + -- 2.45.2