From 8d321ec61cdef8e60654ef9bb46cea3d32f9a997 Mon Sep 17 00:00:00 2001 From: Tobias Weingartner Date: Sat, 3 Nov 2007 03:37:09 +0000 Subject: APM switchto cleanup diff. This uses the switchto functionality to significantly clean up the APM idle loop things. I actually can make sense of what the APM idle loop is supposed to do. Ok gwk@, beck@, and theo says ramdisks compile. --- sys/arch/i386/i386/apm.c | 116 +++++++++++++++++++++++++------------------ sys/arch/i386/i386/locore.s | 22 ++++++-- sys/arch/i386/i386/machdep.c | 9 +++- sys/arch/i386/include/cpu.h | 7 ++- 4 files changed, 100 insertions(+), 54 deletions(-) (limited to 'sys/arch') diff --git a/sys/arch/i386/i386/apm.c b/sys/arch/i386/i386/apm.c index 665c97e8867..866636a9f25 100644 --- a/sys/arch/i386/i386/apm.c +++ b/sys/arch/i386/i386/apm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: apm.c,v 1.77 2007/10/22 17:11:14 deraadt Exp $ */ +/* $OpenBSD: apm.c,v 1.78 2007/11/03 03:37:08 weingart Exp $ */ /*- * Copyright (c) 1998-2001 Michael Shalayeff. All rights reserved. @@ -84,6 +84,7 @@ struct apm_softc { struct klist sc_note; int sc_flags; int batt_life; + int be_batt; struct proc *sc_thread; struct rwlock sc_lock; }; @@ -143,11 +144,8 @@ int apm_op_inprog; u_int apm_flags; u_char apm_majver; u_char apm_minver; -int apm_dobusy = 0; -int apm_doidle = 0; -int apm_bebatt = 0; -int apm_idle_called = 0; int apm_attached = 0; +static int apm_slow_called = 0; struct { u_int32_t entry; @@ -181,6 +179,7 @@ const char *apm_err_translate(int code); void apm_standby(void); void apm_suspend(void); void apm_resume(struct apm_softc *, struct apmregs *); +void apm_cpu_slow(void); static int __inline apm_get_event(struct apmregs *r) @@ -241,7 +240,7 @@ apm_perror(const char *str, struct apmregs *regs) } void -apm_power_print (struct apm_softc *sc, struct apmregs *regs) +apm_power_print(struct apm_softc *sc, struct apmregs *regs) { #if !defined(APM_NOPRINT) sc->batt_life = BATT_LIFE(regs); @@ -305,7 +304,7 @@ apm_power_print (struct apm_softc *sc, struct apmregs *regs) printf(", charging"); if (BATT_REM_VALID(regs)) { int life = BATT_REMAINING(regs); - if (apm_bebatt) + if (sc->be_batt) life = swap16(life); printf(", estimated %d:%02d hours", life / 60, life % 60); @@ -609,16 +608,31 @@ apm_set_powstate(u_int dev, u_int state) return 0; } +void +apm_cpu_slow(void) +{ + struct apmregs regs; + static u_int64_t call_apm_slow = 0; + + if (call_apm_slow != curcpu()->ci_schedstate.spc_cp_time[CP_IDLE]) { + /* Always call BIOS halt/idle stuff */ + bzero(®s, sizeof(regs)); + if (apmcall(APM_CPU_IDLE, 0, ®s) != 0) { +#ifdef DIAGNOSTIC + apm_perror("set CPU slow", ®s); +#endif + } + apm_slow_called = 1; + call_apm_slow = curcpu()->ci_schedstate.spc_cp_time[CP_IDLE]; + } +} + void apm_cpu_busy(void) { struct apmregs regs; - if (!apm_cd.cd_ndevs) /* No APM device, punt */ - return; - if (!apm_dobusy) - return; - if (!apm_idle_called) + if (!apm_slow_called) return; if (apm_flags & APM_IDLE_SLOWS) { @@ -628,7 +642,7 @@ apm_cpu_busy(void) apm_perror("set CPU busy", ®s); #endif } - apm_idle_called = 0; + apm_slow_called = 0; } } @@ -636,37 +650,27 @@ void apm_cpu_idle(void) { struct apmregs regs; - static u_int64_t call_apm = 0; + static u_int64_t call_apm_idle = 0; - if (!apm_cd.cd_ndevs) { /* No APM device, wait for next interrupt */ - __asm __volatile("sti;hlt"); - return; - } - - if (!apm_doidle) { - __asm __volatile("sti;hlt"); - return; - } - /* * We call the bios APM_IDLE routine here only when we * have been idle for some time - otherwise we just hlt. */ - if (call_apm != curcpu()->ci_schedstate.spc_cp_time[CP_IDLE]) { + if (call_apm_idle != curcpu()->ci_schedstate.spc_cp_time[CP_IDLE]) { /* Always call BIOS halt/idle stuff */ bzero(®s, sizeof(regs)); if (apmcall(APM_CPU_IDLE, 0, ®s) != 0) { -#ifdef APMDEBUG +#ifdef DIAGNOSTIC apm_perror("set CPU idle", ®s); #endif } - apm_idle_called = 1; - /* If BIOS did halt, don't do it again! */ + + /* If BIOS did not halt, halt now! */ if (apm_flags & APM_IDLE_SLOWS) { __asm __volatile("sti;hlt"); } - call_apm = curcpu()->ci_schedstate.spc_cp_time[CP_IDLE]; + call_apm_idle = curcpu()->ci_schedstate.spc_cp_time[CP_IDLE]; } else { __asm __volatile("sti;hlt"); } @@ -713,17 +717,11 @@ apm_set_ver(struct apm_softc *self) } } printf(": Power Management spec V%d.%d", apm_majver, apm_minver); - if (apm_flags & APM_IDLE_SLOWS) { - DPRINTF((" (slowidle)")); - apm_dobusy = 1; - apm_doidle = 1; - } else { - apm_dobusy = 0; - apm_doidle = 1; - } #ifdef DIAGNOSTIC + if (apm_flags & APM_IDLE_SLOWS) + printf(" (slowidle)"); if (apm_flags & APM_BIOS_PM_DISABLED) - printf(" (BIOS mgmt disabled)"); + printf(" (BIOS management disabled)"); if (apm_flags & APM_BIOS_PM_DISENGAGED) printf(" (BIOS managing devices)"); #endif @@ -824,7 +822,7 @@ apmattach(struct device *parent, struct device *self, void *aux) apm_cli = 0; } if (sc->sc_dev.dv_cfdata->cf_flags & APM_BEBATT) - apm_bebatt = 1; + sc->be_batt = 1; apm_ep.seg = GSEL(GAPM32CODE_SEL,SEL_KPL); apm_ep.entry = ap->apm_entry; cbase = min(ap->apm_code32_base, ap->apm_code16_base); @@ -875,10 +873,8 @@ apmattach(struct device *parent, struct device *self, void *aux) if (apm_flags & APM_BIOS_PM_DISABLED) apm_powmgt_enable(1); - /* - * Engage cooperative power mgt (we get to do it) - * on all devices (v1.1). - */ + + /* Engage cooperative power management on all devices (v1.1) */ apm_powmgt_engage(1, APM_DEV_ALLDEVS); bzero(®s, sizeof(regs)); @@ -900,9 +896,26 @@ apmattach(struct device *parent, struct device *self, void *aux) if (apm_periodic_check(sc) == -1) { apm_disconnect(sc); - apm_dobusy = apm_doidle = 0; + + /* Failed, nuke APM idle loop */ + cpu_idle_enter_fcn = NULL; + cpu_idle_cycle_fcn = NULL; + cpu_idle_leave_fcn = NULL; } else { kthread_create_deferred(apm_thread_create, sc); + + /* Setup APM idle loop */ + if (apm_flags & APM_IDLE_SLOWS) { + cpu_idle_enter_fcn = apm_cpu_slow; + cpu_idle_cycle_fcn = NULL; + cpu_idle_leave_fcn = apm_cpu_busy; + } else { + cpu_idle_enter_fcn = NULL; + cpu_idle_cycle_fcn = apm_cpu_idle; + cpu_idle_leave_fcn = NULL; + } + + /* All is well, let the rest of the world know */ apm_attached = 1; } } else { @@ -920,7 +933,12 @@ apm_thread_create(void *v) #ifdef MULTIPROCESSOR if (ncpus > 1) { apm_disconnect(sc); - apm_dobusy = apm_doidle = 0; + + /* Nuke APM idle loop */ + cpu_idle_enter_fcn = NULL; + cpu_idle_cycle_fcn = NULL; + cpu_idle_leave_fcn = NULL; + return; } #endif @@ -930,7 +948,11 @@ apm_thread_create(void *v) apm_disconnect(sc); printf("%s: failed to create kernel thread, disabled", sc->sc_dev.dv_xname); - apm_dobusy = apm_doidle = 0; + + /* Nuke APM idle loop */ + cpu_idle_enter_fcn = NULL; + cpu_idle_cycle_fcn = NULL; + cpu_idle_leave_fcn = NULL; } } @@ -1112,7 +1134,7 @@ apmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) powerp->battery_state = APM_BATT_UNKNOWN; if (BATT_REM_VALID(®s)) { powerp->minutes_left = BATT_REMAINING(®s); - if (apm_bebatt) + if (sc->be_batt) powerp->minutes_left = swap16(powerp->minutes_left); } diff --git a/sys/arch/i386/i386/locore.s b/sys/arch/i386/i386/locore.s index b01c31b93eb..85fe1978414 100644 --- a/sys/arch/i386/i386/locore.s +++ b/sys/arch/i386/i386/locore.s @@ -1,4 +1,4 @@ -/* $OpenBSD: locore.s,v 1.118 2007/11/03 03:06:21 weingart Exp $ */ +/* $OpenBSD: locore.s,v 1.119 2007/11/03 03:37:08 weingart Exp $ */ /* $NetBSD: locore.s,v 1.145 1996/05/03 19:41:19 christos Exp $ */ /*- @@ -1441,18 +1441,30 @@ switch_exited: ret ENTRY(cpu_idle_enter) + movl _C_LABEL(cpu_idle_enter_fcn),%eax + cmpl $0,%eax + je 1f + jmpl *%eax +1: ret ENTRY(cpu_idle_cycle) -#if NAPM > 0 - call _C_LABEL(apm_cpu_idle) -#else + movl _C_LABEL(cpu_idle_cycle_fcn),%eax + cmpl $0,%eax + je 1f + call *%eax + ret +1: sti hlt -#endif ret ENTRY(cpu_idle_leave) + movl _C_LABEL(cpu_idle_leave_fcn),%eax + cmpl $0,%eax + je 1f + jmpl *%eax +1: ret /* diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c index 0bb993a2149..de3e74d43ab 100644 --- a/sys/arch/i386/i386/machdep.c +++ b/sys/arch/i386/i386/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.409 2007/10/31 15:55:44 deraadt Exp $ */ +/* $OpenBSD: machdep.c,v 1.410 2007/11/03 03:37:08 weingart Exp $ */ /* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */ /*- @@ -178,6 +178,13 @@ extern struct proc *npxproc; /* the following is used externally (sysctl_hw) */ char machine[] = MACHINE; +/* + * switchto vectors + */ +void (*cpu_idle_leave_fcn)(void) = NULL; +void (*cpu_idle_cycle_fcn)(void) = NULL; +void (*cpu_idle_enter_fcn)(void) = NULL; + /* * Declare these as initialized data so we can patch them. */ diff --git a/sys/arch/i386/include/cpu.h b/sys/arch/i386/include/cpu.h index 3456277cc71..f796c8061d5 100644 --- a/sys/arch/i386/include/cpu.h +++ b/sys/arch/i386/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.96 2007/09/07 08:37:38 art Exp $ */ +/* $OpenBSD: cpu.h,v 1.97 2007/11/03 03:37:08 weingart Exp $ */ /* $NetBSD: cpu.h,v 1.35 1996/05/05 19:29:26 christos Exp $ */ /*- @@ -312,12 +312,17 @@ extern int cpu_cache_eax; extern int cpu_cache_ebx; extern int cpu_cache_ecx; extern int cpu_cache_edx; + /* machdep.c */ extern int cpu_apmhalt; extern int cpu_class; extern char cpu_model[]; extern const struct cpu_nocpuid_nameclass i386_nocpuid_cpus[]; extern const struct cpu_cpuid_nameclass i386_cpuid_cpus[]; +extern void (*cpu_idle_enter_fcn)(void); +extern void (*cpu_idle_cycle_fcn)(void); +extern void (*cpu_idle_leave_fcn)(void); + /* apm.c */ extern int cpu_apmwarn; -- cgit v1.2.3