diff options
| author | mh27603 <none@none> | 2006-11-01 12:29:40 -0800 |
|---|---|---|
| committer | mh27603 <none@none> | 2006-11-01 12:29:40 -0800 |
| commit | c42872d4489d6f0fbccfabe2a62f3c976ee1e5d6 (patch) | |
| tree | d75c27324c2799748fb32ff7639c78182148b054 | |
| parent | 9aa9fab90ce3f906a8a5591b744a385ed10a510e (diff) | |
| download | illumos-joyent-c42872d4489d6f0fbccfabe2a62f3c976ee1e5d6.tar.gz | |
6260724 PSARC/2005/067 CPU Power Management independent of autopm
6483153 pmconfig/dtpower/sysidpm should be lint-clean
| -rw-r--r-- | usr/src/Makefile.lint | 1 | ||||
| -rw-r--r-- | usr/src/cmd/power/handlers.c | 71 | ||||
| -rw-r--r-- | usr/src/cmd/power/parse.c | 9 | ||||
| -rw-r--r-- | usr/src/cmd/power/pmconfig.h | 9 | ||||
| -rw-r--r-- | usr/src/cmd/power/power_all.xcl | 9 | ||||
| -rw-r--r-- | usr/src/cmd/power/powerd.c | 41 | ||||
| -rw-r--r-- | usr/src/cmd/power/sysstat.c | 10 | ||||
| -rw-r--r-- | usr/src/uts/common/io/pm.c | 186 | ||||
| -rw-r--r-- | usr/src/uts/common/os/sunpm.c | 103 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/epm.h | 41 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/pm.h | 20 | ||||
| -rw-r--r-- | usr/src/uts/sun4u/io/us_drv.c | 14 |
12 files changed, 383 insertions, 131 deletions
diff --git a/usr/src/Makefile.lint b/usr/src/Makefile.lint index 1743cfebc3..e11d7f0c1c 100644 --- a/usr/src/Makefile.lint +++ b/usr/src/Makefile.lint @@ -207,6 +207,7 @@ COMMON_SUBDIRS = \ cmd/picl/prtpicl \ cmd/plockstat \ cmd/pools \ + cmd/power \ cmd/ppgsz \ cmd/praudit \ cmd/prctl \ diff --git a/usr/src/cmd/power/handlers.c b/usr/src/cmd/power/handlers.c index 1c3b2ff00e..44df1f5c30 100644 --- a/usr/src/cmd/power/handlers.c +++ b/usr/src/cmd/power/handlers.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -56,6 +55,42 @@ static char always_on[] = "always-on"; /* + * Check for valid cpupm behavior and communicate it to the kernel. + */ +int +cpupm(void) +{ + struct btoc { + char *behavior; + int cmd; + int Errno; + }; + static struct btoc blist[] = { + "disable", PM_STOP_CPUPM, EINVAL, + "enable", PM_START_CPUPM, EBUSY, + NULL, 0, 0 + }; + struct btoc *bp; + char *behavior; + + for (behavior = LINEARG(1), bp = blist; bp->cmd; bp++) { + if (strcmp(behavior, bp->behavior) == 0) + break; + } + if (bp->cmd == 0) { + mesg(MERR, "invalid cpupm behavior \"%s\"\n", behavior); + return (NOUP); + } + if (ioctl(pm_fd, bp->cmd, NULL) == -1 && errno != bp->Errno) { + mesg(MERR, "cpupm %s failed, %s\n", + behavior, strerror(errno)); + return (NOUP); + } + return (OKUP); +} + + +/* * Check for valid autopm behavior and save after ioctl success. */ int @@ -673,10 +708,10 @@ sfpath(void) /* - * Try setting system threshold. + * Common function to set a system or cpu threshold. */ -int -systhr(void) +static int +cmnthr(int req) { int value, nerr = 0, upval = OKUP; char *thresh = LINEARG(1); @@ -688,11 +723,31 @@ systhr(void) upval = NOUP; } if (upval == OKUP) - (void) ioctl(pm_fd, PM_SET_SYSTEM_THRESHOLD, value); + (void) ioctl(pm_fd, req, value); return (upval); } +/* + * Try setting system threshold. + */ +int +systhr(void) +{ + return (cmnthr(PM_SET_SYSTEM_THRESHOLD)); +} + + +/* + * Try setting cpu threshold. + */ +int +cputhr(void) +{ + return (cmnthr(PM_SET_CPU_THRESHOLD)); +} + + int tchars(void) { diff --git a/usr/src/cmd/power/parse.c b/usr/src/cmd/power/parse.c index 0d291f9257..650e2154cb 100644 --- a/usr/src/cmd/power/parse.c +++ b/usr/src/cmd/power/parse.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -56,6 +55,8 @@ prmup_t pm_status = { 0, OKUP, "pm" }; static cinfo_t conftab[] = { "autopm", autopm, &pm_status, NULL, 2, 0, 1, "autoshutdown", autosd, &cpr_status, as_cmt, 5, 0, 1, + "cpu-threshold", cputhr, &pm_status, NULL, 2, 0, 1, + "cpupm", cpupm, &pm_status, NULL, 2, 0, 1, "device-dependency-property", ddprop, &pm_status, NULL, 3, 1, 1, "device-dependency", devdep, &pm_status, NULL, 3, 1, 1, diff --git a/usr/src/cmd/power/pmconfig.h b/usr/src/cmd/power/pmconfig.h index db59d2adf5..e48c9a0289 100644 --- a/usr/src/cmd/power/pmconfig.h +++ b/usr/src/cmd/power/pmconfig.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2002 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -121,6 +120,8 @@ extern void parse_conf_file(char *, vact_t); */ extern int autopm(void); extern int autosd(void); +extern int cpupm(void); +extern int cputhr(void); extern int ddprop(void); extern int devdep(void); extern int devthr(void); diff --git a/usr/src/cmd/power/power_all.xcl b/usr/src/cmd/power/power_all.xcl index d8c0221c71..61baf7b7a4 100644 --- a/usr/src/cmd/power/power_all.xcl +++ b/usr/src/cmd/power/power_all.xcl @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -112,3 +111,5 @@ msgid "pm ioctl, cmd %d, errno %d\n" msgid "got scaled value %d\n" msgid "threshold list" msgid "idle path" +msgid "cpu-threshold" +msgid "cpupm" diff --git a/usr/src/cmd/power/powerd.c b/usr/src/cmd/power/powerd.c index de58520025..19e137ce02 100644 --- a/usr/src/cmd/power/powerd.c +++ b/usr/src/cmd/power/powerd.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -109,7 +108,9 @@ static int autoshutdown_en; static int do_idlecheck; static int got_sighup; static int estar_v2_prop; +#ifdef sparc static int estar_v3_prop; +#endif static int log_power_cycles_error = 0; static int log_system_board_date_error = 0; static int log_no_autoshutdown_warning = 0; @@ -139,7 +140,7 @@ static void check_idleness(time_t *, hrtime_t *); static int last_system_activity(hrtime_t *); static int run_idlecheck(void); static void set_alarm(time_t); -static int poweroff(char *, char **); +static int poweroff(const char *, char **); static int is_ok2shutdown(time_t *); static int get_prom(int, prom_node_t, char *, char *, size_t); static void power_button_monitor(void *); @@ -153,9 +154,9 @@ static void *attach_devices(void *); #endif -/* VARARGS0 */ +/* PRINTFLIKE1 */ static void -logerror(char *fmt, ...) +logerror(const char *fmt, ...) { va_list args; @@ -217,7 +218,7 @@ main(int argc, char *argv[]) pm_fd = open(PM, O_RDWR); if (pm_fd == -1) { - (void) sprintf(errmsg, "%s: %s", prog, PM); + (void) snprintf(errmsg, sizeof (errmsg), "%s: %s", prog, PM); perror(errmsg); exit(EXIT_FAILURE); } @@ -234,7 +235,7 @@ main(int argc, char *argv[]) } if ((info = (pwr_info_t *)malloc(sizeof (pwr_info_t))) == NULL) { - (void) sprintf(errmsg, "%s: malloc", prog); + (void) snprintf(errmsg, sizeof (errmsg), "%s: malloc", prog); perror(errmsg); exit(EXIT_FAILURE); } @@ -720,7 +721,7 @@ is_ok2shutdown(time_t *now) /* * Allow 10% of power_cycle_limit as free cycles. */ - free_cycles = power_cycle_limit * 0.1; + free_cycles = power_cycle_limit / 10; power_cycles = atoi(power_cycles_st); if (power_cycles < 0) @@ -758,8 +759,8 @@ is_ok2shutdown(time_t *now) * need to spread (power_cycle_limit - free_cycles) over the entire * 7-year life span instead of (lifetime - date free_cycles ended). */ - scaled_cycles = ((float)life_passed / (float)LIFETIME_SECS) * - (power_cycle_limit - free_cycles); + scaled_cycles = (int)(((float)life_passed / (float)LIFETIME_SECS) * + (power_cycle_limit - free_cycles)); if (no_power_cycles) goto ckdone; @@ -912,7 +913,7 @@ set_alarm(time_t now) } static int -poweroff(char *msg, char **cmd_argv) +poweroff(const char *msg, char **cmd_argv) { struct stat statbuf; pid_t pid, child; @@ -1193,14 +1194,14 @@ static int open_pidfile(char *me) { int fd; - char *e1 = "%s: Cannot open pid file for read: "; - char *e2 = "%s: Cannot unlink obsolete pid file: "; - char *e3 = "%s: Cannot open /proc for pid %ld: "; - char *e4 = "%s: Cannot read /proc for pid %ld: "; - char *e5 = "%s: Another instance (pid %ld) is trying to exit" + const char *e1 = "%s: Cannot open pid file for read: "; + const char *e2 = "%s: Cannot unlink obsolete pid file: "; + const char *e3 = "%s: Cannot open /proc for pid %ld: "; + const char *e4 = "%s: Cannot read /proc for pid %ld: "; + const char *e5 = "%s: Another instance (pid %ld) is trying to exit" "and may be hung. Please contact sysadmin.\n"; - char *e6 = "%s: Another daemon is running\n"; - char *e7 = "%s: Cannot create pid file: "; + const char *e6 = "%s: Another daemon is running\n"; + const char *e7 = "%s: Cannot create pid file: "; again: if ((fd = open(pidpath, O_CREAT | O_EXCL | O_WRONLY, 0444)) == -1) { diff --git a/usr/src/cmd/power/sysstat.c b/usr/src/cmd/power/sysstat.c index c1b0806665..a6bc12d1b0 100644 --- a/usr/src/cmd/power/sysstat.c +++ b/usr/src/cmd/power/sysstat.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 1995-2002 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -589,6 +588,7 @@ static void fail(char *fmt, ...) { char new_fmt[256]; + const char *fmtptr = new_fmt; va_list args; size_t len; @@ -597,7 +597,7 @@ fail(char *fmt, ...) if (snprintf(new_fmt, len, "powerd: %s", fmt) > len) syslog(LOG_ERR, "powerd: syslog message too large"); else - vsyslog(LOG_ERR, new_fmt, args); + vsyslog(LOG_ERR, fmtptr, args); va_end(args); thr_exit((void *) 0); diff --git a/usr/src/uts/common/io/pm.c b/usr/src/uts/common/io/pm.c index b98022ca8b..c46ad7ea0a 100644 --- a/usr/src/uts/common/io/pm.c +++ b/usr/src/uts/common/io/pm.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -72,6 +71,10 @@ extern kmutex_t pm_scan_lock; /* protects autopm_enable, pm_scans_disabled */ extern kmutex_t pm_clone_lock; /* protects pm_clones array */ extern int autopm_enabled; +extern pm_cpupm_t cpupm; +extern int pm_default_idle_threshold; +extern int pm_system_idle_threshold; +extern int pm_cpu_idle_threshold; extern kcondvar_t pm_clones_cv[PM_MAX_CLONE]; extern uint_t pm_poll_cnt[PM_MAX_CLONE]; @@ -422,6 +425,12 @@ static struct pm_cmd_info pmci[] = { {PM_GET_TIME_IDLE, "PM_GET_TIME_IDLE", 1, PM_REQ, INWHO, DIP, NODEP}, {PM_ADD_DEPENDENT_PROPERTY, "PM_ADD_DEPENDENT_PROPERTY", 1, PM_REQ, INWHO | INDATASTRING, NODIP, DEP, SU}, + {PM_START_CPUPM, "PM_START_CPUPM", 1, NOSTRUCT, 0, 0, 0, SU}, + {PM_STOP_CPUPM, "PM_STOP_CPUPM", 1, NOSTRUCT, 0, 0, 0, SU}, + {PM_GET_CPU_THRESHOLD, "PM_GET_CPU_THRESHOLD", 1, NOSTRUCT}, + {PM_SET_CPU_THRESHOLD, "PM_SET_CPU_THRESHOLD", 1, NOSTRUCT, + 0, 0, 0, SU}, + {PM_GET_CPUPM_STATE, "PM_GET_CPUPM_STATE", 1, NOSTRUCT}, {0, NULL} }; @@ -455,22 +464,36 @@ pm_decode_cmd(int cmd) int pm_start_pm_walk(dev_info_t *dip, void *arg) { - char *cmdstr = pm_decode_cmd(*((int *)arg)); + int cmd = *((int *)arg); + char *cmdstr = pm_decode_cmd(cmd); if (!PM_GET_PM_INFO(dip) || PM_ISBC(dip)) return (DDI_WALK_CONTINUE); - /* - * Construct per dip scan taskq - */ - mutex_enter(&pm_scan_lock); - if (autopm_enabled) - pm_scan_init(dip); - mutex_exit(&pm_scan_lock); + switch (cmd) { + case PM_START_CPUPM: + if (!PM_ISCPU(dip)) + return (DDI_WALK_CONTINUE); + mutex_enter(&pm_scan_lock); + if (!PM_CPUPM_DISABLED) + pm_scan_init(dip); + mutex_exit(&pm_scan_lock); + break; + case PM_START_PM: + mutex_enter(&pm_scan_lock); + if (PM_ISCPU(dip) && PM_CPUPM_DISABLED) { + mutex_exit(&pm_scan_lock); + return (DDI_WALK_CONTINUE); + } + if (autopm_enabled) + pm_scan_init(dip); + mutex_exit(&pm_scan_lock); + break; + } /* * Start doing pm on device: ensure pm_scan data structure initiated, - * no need to gurantee a successful scan run. + * no need to guarantee a successful scan run. */ PMD(PMD_SCAN | PMD_IOCTL, ("ioctl: %s: scan %s@%s(%s#%d)\n", cmdstr, PM_DEVICE(dip))) @@ -486,10 +509,32 @@ int pm_stop_pm_walk(dev_info_t *dip, void *arg) { pm_info_t *info = PM_GET_PM_INFO(dip); - char *cmdstr = pm_decode_cmd(*((int *)arg)); + int cmd = *((int *)arg); + char *cmdstr = pm_decode_cmd(cmd); if (!info) return (DDI_WALK_CONTINUE); + + switch (cmd) { + case PM_STOP_PM: + /* + * If CPU devices are being managed independently, then don't + * stop them as part of PM_STOP_PM. Only stop them as part of + * PM_STOP_CPUPM and PM_RESET_PM. + */ + if (PM_ISCPU(dip) && PM_CPUPM_ENABLED) + return (DDI_WALK_CONTINUE); + break; + case PM_STOP_CPUPM: + /* + * If stopping CPU devices and this device is not marked + * as a CPU device, then skip. + */ + if (!PM_ISCPU(dip)) + return (DDI_WALK_CONTINUE); + break; + } + /* * Stop the current scan, and then bring it back to normal power. */ @@ -693,33 +738,49 @@ pm_discard_entries(int clone) mutex_exit(&pm_clone_lock); } -int -pm_set_sys_threshold(dev_info_t *dip, void *arg) -{ - int pm_system_idle_threshold = *((int *)arg); - pm_info_t *info = PM_GET_PM_INFO(dip); - int processed = 0; - - if (!info) - return (DDI_WALK_CONTINUE); +static void +pm_set_idle_threshold(dev_info_t *dip, int thresh, int flag) +{ if (!PM_ISBC(dip) && !PM_ISDIRECT(dip)) { switch (DEVI(dip)->devi_pm_flags & PMC_THRESH_ALL) { case PMC_DEF_THRESH: - PMD(PMD_IOCTL, ("ioctl: set_sys_threshold: set " + case PMC_CPU_THRESH: + PMD(PMD_IOCTL, ("ioctl: set_idle_threshold: set " "%s@%s(%s#%d) default thresh to 0t%d\n", - PM_DEVICE(dip), pm_system_idle_threshold)) - pm_set_device_threshold(dip, pm_system_idle_threshold, - PMC_DEF_THRESH); - processed++; + PM_DEVICE(dip), thresh)) + pm_set_device_threshold(dip, thresh, flag); break; default: break; } } +} + +static int +pm_set_idle_thresh_walk(dev_info_t *dip, void *arg) +{ + int cmd = *((int *)arg); + + if (!PM_GET_PM_INFO(dip)) + return (DDI_WALK_CONTINUE); - if (processed && autopm_enabled) + switch (cmd) { + case PM_SET_SYSTEM_THRESHOLD: + if (DEVI(dip)->devi_pm_flags & PMC_CPU_THRESH) + break; + pm_set_idle_threshold(dip, pm_system_idle_threshold, + PMC_DEF_THRESH); + pm_rescan(dip); + break; + case PM_SET_CPU_THRESHOLD: + if (!PM_ISCPU(dip)) + break; + pm_set_idle_threshold(dip, pm_cpu_idle_threshold, + PMC_CPU_THRESH); pm_rescan(dip); + break; + } return (DDI_WALK_CONTINUE); } @@ -846,8 +907,6 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p) pm_state_change_t *pscp; pm_state_change_t psc; size_t copysize; - extern int pm_default_idle_threshold; - extern int pm_system_idle_threshold; extern void pm_record_thresh(pm_thresh_rec_t *); psce_t *pm_psc_clone_to_direct(int); psce_t *pm_psc_clone_to_interest(int); @@ -1555,8 +1614,12 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p) break; } pm_unrecord_threshold(req.physpath); - pm_set_device_threshold(dip, pm_system_idle_threshold, - PMC_DEF_THRESH); + if (DEVI(dip)->devi_pm_flags & PMC_CPU_THRESH) + pm_set_device_threshold(dip, + pm_cpu_idle_threshold, PMC_CPU_THRESH); + else + pm_set_device_threshold(dip, + pm_system_idle_threshold, PMC_DEF_THRESH); ret = 0; break; } @@ -2089,6 +2152,9 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p) case PMC_COMP_THRESH: *rval_p = PM_COMPONENT_THRESHOLD; break; + case PMC_CPU_THRESH: + *rval_p = PM_CPU_THRESHOLD; + break; default: if (PM_ISBC(dip)) { *rval_p = PM_OLD_THRESHOLD; @@ -2419,15 +2485,20 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p) case NOSTRUCT: switch (cmd) { case PM_START_PM: + case PM_START_CPUPM: mutex_enter(&pm_scan_lock); - if (autopm_enabled) { + if ((cmd == PM_START_PM && autopm_enabled) || + (cmd == PM_START_CPUPM && PM_CPUPM_ENABLED)) { mutex_exit(&pm_scan_lock); PMD(PMD_ERROR, ("ioctl: %s: EBUSY\n", cmdstr)) ret = EBUSY; break; } - autopm_enabled = 1; + if (cmd == PM_START_PM) + autopm_enabled = 1; + else + cpupm = PM_CPUPM_ENABLE; mutex_exit(&pm_scan_lock); ddi_walk_devs(ddi_root_node(), pm_start_pm_walk, &cmd); ret = 0; @@ -2435,30 +2506,41 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p) case PM_RESET_PM: case PM_STOP_PM: + case PM_STOP_CPUPM: { extern void pm_discard_thresholds(void); mutex_enter(&pm_scan_lock); - if (!autopm_enabled && cmd != PM_RESET_PM) { + if ((cmd == PM_STOP_PM && !autopm_enabled) || + (cmd == PM_STOP_CPUPM && PM_CPUPM_DISABLED)) { mutex_exit(&pm_scan_lock); PMD(PMD_ERROR, ("ioctl: %s: EINVAL\n", cmdstr)) ret = EINVAL; break; } - autopm_enabled = 0; + if (cmd == PM_STOP_PM) + autopm_enabled = 0; + else if (cmd == PM_STOP_CPUPM) + cpupm = PM_CPUPM_DISABLE; + else { + autopm_enabled = 0; + cpupm = PM_CPUPM_NOTSET; + } mutex_exit(&pm_scan_lock); + /* * bring devices to full power level, stop scan */ ddi_walk_devs(ddi_root_node(), pm_stop_pm_walk, &cmd); ret = 0; - if (cmd == PM_STOP_PM) + if (cmd == PM_STOP_PM || cmd == PM_STOP_CPUPM) break; /* * Now do only PM_RESET_PM stuff. */ pm_system_idle_threshold = pm_default_idle_threshold; + pm_cpu_idle_threshold = 0; pm_discard_thresholds(); pm_all_to_default_thresholds(); pm_dispatch_to_dep_thread(PM_DEP_WK_REMOVE_DEP, @@ -2476,7 +2558,13 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p) ret = 0; break; + case PM_GET_CPU_THRESHOLD: + *rval_p = pm_cpu_idle_threshold; + ret = 0; + break; + case PM_SET_SYSTEM_THRESHOLD: + case PM_SET_CPU_THRESHOLD: if ((int)arg < 0) { PMD(PMD_ERROR, ("ioctl: %s: arg 0x%x < 0" "--EINVAL\n", cmdstr, (int)arg)) @@ -2485,9 +2573,14 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p) } PMD(PMD_IOCTL, ("ioctl: %s: 0x%x 0t%d\n", cmdstr, (int)arg, (int)arg)) - pm_system_idle_threshold = (int)arg; - ddi_walk_devs(ddi_root_node(), pm_set_sys_threshold, - (void *) &pm_system_idle_threshold); + if (cmd == PM_SET_SYSTEM_THRESHOLD) + pm_system_idle_threshold = (int)arg; + else { + pm_cpu_idle_threshold = (int)arg; + } + ddi_walk_devs(ddi_root_node(), pm_set_idle_thresh_walk, + (void *) &cmd); + ret = 0; break; @@ -2507,10 +2600,19 @@ pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p) } ret = 0; break; + + case PM_GET_CPUPM_STATE: + if (PM_CPUPM_ENABLED) + *rval_p = PM_CPU_PM_ENABLED; + else if (PM_CPUPM_DISABLED) + *rval_p = PM_CPU_PM_DISABLED; + else + *rval_p = PM_CPU_PM_NOTSET; + ret = 0; + break; } break; - default: /* * Internal error, invalid ioctl description diff --git a/usr/src/uts/common/os/sunpm.c b/usr/src/uts/common/os/sunpm.c index 997ca125dd..193a8598c1 100644 --- a/usr/src/uts/common/os/sunpm.c +++ b/usr/src/uts/common/os/sunpm.c @@ -61,10 +61,14 @@ * readable strings (currently unused) for each component name and power state. * Devices which export pm-components(9P) are automatically power managed * whenever autopm is enabled (via PM_START_PM ioctl issued by pmconfig(1M) - * after parsing power.conf(4)). - * For these devices, all components are considered independent of each other, - * and it is up to the driver to decide when a transition requires saving or - * restoring hardware state. + * after parsing power.conf(4)). The exception to this rule is that power + * manageable CPU devices may be automatically managed independently of autopm + * by either enabling or disabling (via PM_START_CPUPM and PM_STOP_CPUPM + * ioctls) cpupm. If the CPU devices are not managed independently, then they + * are managed by autopm. In either case, for automatically power managed + * devices, all components are considered independent of each other, and it is + * up to the driver to decide when a transition requires saving or restoring + * hardware state. * * Each device component also has a threshold time associated with each power * transition (see power.conf(4)), and a busy/idle state maintained by the @@ -78,8 +82,9 @@ * -set threshold values (defaults if none provided by pmconfig) * -set dependencies among devices * -enable/disable autopm - * -turn down idle components based on thresholds (if autopm is enabled) - * (aka scanning) + * -enable/disable cpupm + * -turn down idle components based on thresholds (if autopm or cpupm is + * enabled) (aka scanning) * -maintain power states based on dependencies among devices * -upon request, or when the frame buffer powers off, attempt to turn off * all components that are idle or become idle over the next (10 sec) @@ -99,9 +104,10 @@ * property * * Scanning: - * Whenever autopm is enabled, the framework attempts to bring each component - * of each device to its lowest power based on the threshold of idleness - * associated with each transition and the busy/idle state of the component. + * Whenever autopm or cpupm is enabled, the framework attempts to bring each + * component of each managed device to its lowest power based on the threshold + * of idleness associated with each transition and the busy/idle state of the + * component. * * The actual work of this is done by pm_scan_dev(), which cycles through each * component of a device, checking its idleness against its current threshold, @@ -177,8 +183,8 @@ * * pm_scan_lock: * It protects the timeout id of the scan thread, and the value - * of autopm_enabled. This lock is not held concurrently with - * any other PM locks. + * of autopm_enabled and cpupm. This lock is not held + * concurrently with any other PM locks. * * pm_clone_lock: Protects the clone list and count of poll events * pending for the pm driver. @@ -326,6 +332,13 @@ pm_dep_wk_t *pm_dep_thread_tail = NULL; int autopm_enabled; /* + * cpupm is turned on and off, by the PM_START_CPUPM and PM_STOP_CPUPM ioctls, + * to define the power management behavior of CPU devices separate from + * autopm. Protected by pm_scan_lock. + */ +pm_cpupm_t cpupm = PM_CPUPM_NOTSET; + +/* * This flag is true while processes are stopped for a checkpoint/resume. * Controlling processes of direct pm'd devices are not available to * participate in power level changes, so we bypass them when this is set. @@ -379,6 +392,8 @@ kmutex_t pm_remdrv_lock; int pm_default_idle_threshold = PM_DEFAULT_SYS_IDLENESS; int pm_system_idle_threshold; +int pm_cpu_idle_threshold; + /* * By default nexus has 0 threshold, and depends on its children to keep it up */ @@ -521,6 +536,7 @@ pm_cpr_callb(void *arg, int code) { _NOTE(ARGUNUSED(arg)) static int auto_save; + static pm_cpupm_t cpupm_save; static int pm_reset_timestamps(dev_info_t *, void *); switch (code) { @@ -535,12 +551,15 @@ pm_cpr_callb(void *arg, int code) pm_scans_disabled = 1; auto_save = autopm_enabled; autopm_enabled = 0; + cpupm_save = cpupm; + cpupm = PM_CPUPM_NOTSET; mutex_exit(&pm_scan_lock); ddi_walk_devs(ddi_root_node(), pm_scan_stop_walk, NULL); break; case CB_CODE_CPR_RESUME: ASSERT(!autopm_enabled); + ASSERT(cpupm == PM_CPUPM_NOTSET); ASSERT(pm_scans_disabled); pm_scans_disabled = 0; /* @@ -553,6 +572,7 @@ pm_cpr_callb(void *arg, int code) ddi_walk_devs(ddi_root_node(), pm_reset_timestamps, NULL); autopm_enabled = auto_save; + cpupm = cpupm_save; /* * If there is any auto-pm device, get the scanning * going. Otherwise don't bother. @@ -598,6 +618,7 @@ pm_init(void) pm_comps_notlowest = 0; pm_system_idle_threshold = pm_default_idle_threshold; + pm_cpu_idle_threshold = 0; pm_cpr_cb_id = callb_add(pm_cpr_callb, (void *)NULL, CB_CL_CPR_PM, "pm_cpr"); @@ -628,10 +649,10 @@ pm_init(void) } /* - * pm_scan_init - create pm scan data structure. Called (if autopm enabled) - * when device becomes power managed or after a failed detach and when autopm - * is started via PM_START_PM ioctl, and after a CPR resume to get all the - * devices scanning again. + * pm_scan_init - create pm scan data structure. Called (if autopm or cpupm + * enabled) when device becomes power managed or after a failed detach and + * when autopm is started via PM_START_PM or PM_START_CPUPM ioctls, and after + * a CPR resume to get all the devices scanning again. */ void pm_scan_init(dev_info_t *dip) @@ -873,7 +894,7 @@ pm_rescan(void *arg) PM_LOCK_DIP(dip); info = PM_GET_PM_INFO(dip); scanp = PM_GET_PM_SCAN(dip); - if (pm_scans_disabled || !autopm_enabled || !info || !scanp || + if (pm_scans_disabled || !PM_SCANABLE(dip) || !info || !scanp || (scanp->ps_scan_flags & PM_SCAN_STOP)) { PM_UNLOCK_DIP(dip); return; @@ -955,7 +976,7 @@ pm_scan(void *arg) scanp = PM_GET_PM_SCAN(dip); ASSERT(scanp && PM_GET_PM_INFO(dip)); - if (pm_scans_disabled || !autopm_enabled || + if (pm_scans_disabled || !PM_SCANABLE(dip) || (scanp->ps_scan_flags & PM_SCAN_STOP)) { scanp->ps_scan_flags &= ~(PM_SCAN_AGAIN | PM_SCAN_DISPATCHED); PM_UNLOCK_DIP(dip); @@ -1130,15 +1151,16 @@ pm_scan_dev(dev_info_t *dip) PM_KUC(dip))) /* no scan under the following conditions */ - if (pm_scans_disabled || !autopm_enabled || + if (pm_scans_disabled || !PM_SCANABLE(dip) || (scanp->ps_scan_flags & PM_SCAN_STOP) || (PM_KUC(dip) != 0) || PM_ISDIRECT(dip) || pm_noinvol(dip)) { PM_UNLOCK_DIP(dip); PMD(PMD_SCAN, ("%s: [END, %s@%s(%s#%d)] no scan, " - "scan_disabled(%d), apm_enabled(%d), kuc(%d), " - "%s directpm, %s pm_noinvol\n", pmf, PM_DEVICE(dip), - pm_scans_disabled, autopm_enabled, PM_KUC(dip), + "scan_disabled(%d), apm_enabled(%d), cpupm(%d), " + "kuc(%d), %s directpm, %s pm_noinvol\n", + pmf, PM_DEVICE(dip), pm_scans_disabled, autopm_enabled, + cpupm, PM_KUC(dip), PM_ISDIRECT(dip) ? "is" : "is not", pm_noinvol(dip) ? "is" : "is not")) return (LONG_MAX); @@ -2461,9 +2483,12 @@ pm_lower_power(dev_info_t *dip, int comp, int level) * If we don't care about saving power, or we're treating this node * specially, then this is a no-op */ - if (!autopm_enabled || pm_noinvol(dip)) { - PMD(PMD_FAIL, ("%s: %s@%s(%s#%d) %s%s\n", pmf, PM_DEVICE(dip), + if (!PM_SCANABLE(dip) || pm_noinvol(dip)) { + PMD(PMD_FAIL, ("%s: %s@%s(%s#%d) %s%s%s%s\n", + pmf, PM_DEVICE(dip), !autopm_enabled ? "!autopm_enabled " : "", + !PM_CPUPM_ENABLED ? "!cpupm_enabled " : "", + PM_CPUPM_DISABLED ? "cpupm_disabled " : "", pm_noinvol(dip) ? "pm_noinvol()" : "")) return (DDI_SUCCESS); } @@ -3258,7 +3283,7 @@ pm_detach_failed(dev_info_t *dip) } if (!PM_ISBC(dip)) { mutex_enter(&pm_scan_lock); - if (autopm_enabled) + if (PM_SCANABLE(dip)) pm_scan_init(dip); mutex_exit(&pm_scan_lock); pm_rescan(dip); @@ -3387,8 +3412,12 @@ pm_premanage(dev_info_t *dip, int style) ASSERT(PM_CP(dip, i)->pmc_cur_pwr == 0); e_pm_set_cur_pwr(dip, PM_CP(dip, i), PM_LEVEL_UNKNOWN); } - pm_set_device_threshold(dip, pm_system_idle_threshold, - PMC_DEF_THRESH); + if (DEVI(dip)->devi_pm_flags & PMC_CPU_THRESH) + pm_set_device_threshold(dip, pm_cpu_idle_threshold, + PMC_CPU_THRESH); + else + pm_set_device_threshold(dip, pm_system_idle_threshold, + PMC_DEF_THRESH); kmem_free(compp, cmpts * sizeof (pm_comp_t)); } return (DDI_SUCCESS); @@ -3448,7 +3477,7 @@ e_pm_manage(dev_info_t *dip, int style) if (!PM_ISBC(dip)) { mutex_enter(&pm_scan_lock); - if (autopm_enabled) { + if (PM_SCANABLE(dip)) { pm_scan_init(dip); mutex_exit(&pm_scan_lock); pm_rescan(dip); @@ -3508,6 +3537,8 @@ cur_threshold(dev_info_t *dip, int comp) int thresh; if (DEVI(dip)->devi_pm_flags & PMC_NEXDEF_THRESH) thresh = pm_default_nexus_threshold; + else if (DEVI(dip)->devi_pm_flags & PMC_CPU_THRESH) + thresh = pm_cpu_idle_threshold; else thresh = pm_system_idle_threshold; return (thresh); @@ -4634,6 +4665,20 @@ e_pm_props(dev_info_t *dip) if (ddi_prop_exists(DDI_DEV_T_ANY, dip, propflag, "no-involuntary-power-cycles")) flags |= PMC_NO_INVOL; + /* + * Is the device a CPU device? + */ + if (ddi_getlongprop(DDI_DEV_T_ANY, dip, propflag, "pm-class", + (caddr_t)&pp, &len) == DDI_PROP_SUCCESS) { + if (strcmp(pp, "CPU") == 0) { + flags |= PMC_CPU_DEVICE; + } else { + cmn_err(CE_NOTE, "!device %s@%s has unrecognized " + "%s property value '%s'", PM_NAME(dip), + PM_ADDR(dip), "pm-class", pp); + } + kmem_free(pp, len); + } /* devfs single threads us */ DEVI(dip)->devi_pm_flags |= flags; } @@ -5912,7 +5957,7 @@ pm_apply_recorded_thresh(dev_info_t *dip, pm_thresh_rec_t *rp) pmf, PM_DEVICE(dip), ep->pte_thresh[0])) PM_UNLOCK_DIP(dip); pm_set_device_threshold(dip, ep->pte_thresh[0], PMC_DEV_THRESH); - if (autopm_enabled) + if (PM_SCANABLE(dip)) pm_rescan(dip); return; } @@ -5930,7 +5975,7 @@ pm_apply_recorded_thresh(dev_info_t *dip, pm_thresh_rec_t *rp) DEVI(dip)->devi_pm_flags |= PMC_COMP_THRESH; PM_UNLOCK_DIP(dip); - if (autopm_enabled) + if (PM_SCANABLE(dip)) pm_rescan(dip); } diff --git a/usr/src/uts/common/sys/epm.h b/usr/src/uts/common/sys/epm.h index 2088d3be4d..7d80cf2ac5 100644 --- a/usr/src/uts/common/sys/epm.h +++ b/usr/src/uts/common/sys/epm.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -81,9 +80,11 @@ int e_new_pm_props(dev_info_t *); #define PMC_CONSOLE_FB 0x10000 /* console framebuffer */ #define PMC_NOINVOL_DONE 0x20000 /* processed by pm_noinvol_specd() */ #define PMC_DRIVER_REMOVED 0x40000 /* driver is removed */ +#define PMC_CPU_DEVICE 0x80000 /* device is a power manageable CPU */ +#define PMC_CPU_THRESH 0x100000 /* cpu threshold set */ #define PMC_THRESH_ALL (PMC_DEF_THRESH | PMC_DEV_THRESH | \ - PMC_COMP_THRESH | PMC_NEXDEF_THRESH) + PMC_COMP_THRESH | PMC_NEXDEF_THRESH | PMC_CPU_THRESH) #define PMC_THRESH_NONE ~(PMC_THRESH_ALL) /* Flags for the component */ @@ -217,6 +218,13 @@ typedef enum pm_canblock PM_CANBLOCK_BYPASS /* don't wait, ignore controlling process */ } pm_canblock_t; +typedef enum pm_cpupm +{ + PM_CPUPM_NOTSET, /* no specific treatment of CPU devices */ + PM_CPUPM_ENABLE, /* power manage CPU devices */ + PM_CPUPM_DISABLE /* do not power manage CPU devices */ +} pm_cpupm_t; + /* * The power request struct uses for the DDI_CTLOPS_POWER busctl. * @@ -546,6 +554,29 @@ typedef struct pm_thresh_rec { */ #define PM_SKBU(dip) (DEVI(dip)->devi_pm_flags & PMC_SKIP_BRINGUP) +/* + * Returns true if device specified by dip is a power manageable CPU. + */ +#define PM_ISCPU(dip) (DEVI(dip)->devi_pm_flags & PMC_CPU_DEVICE) + +/* + * Returns true if cpupm is enabled. + */ +#define PM_CPUPM_ENABLED (cpupm == PM_CPUPM_ENABLE) + +/* + * Returns true if is disabled. + */ +#define PM_CPUPM_DISABLED (cpupm == PM_CPUPM_DISABLE) + +/* + * If (autopm is enabled and + * (CPUs are not disabled, or it isn't a cpu)) OR + * (CPUs are enabled and it is one) + */ +#define PM_SCANABLE(dip) ((autopm_enabled && \ +(!PM_CPUPM_DISABLED || !PM_ISCPU(dip))) || (PM_CPUPM_ENABLED && PM_ISCPU(dip))) + #define PM_NOT_ALL_LOWEST 0x0 /* not all components are at lowest */ #define PM_ALL_LOWEST 0x1 /* all components are at lowest lvl */ diff --git a/usr/src/uts/common/sys/pm.h b/usr/src/uts/common/sys/pm.h index 3169e165fb..a65075b3a5 100644 --- a/usr/src/uts/common/sys/pm.h +++ b/usr/src/uts/common/sys/pm.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -91,7 +90,12 @@ typedef enum { PM_ADD_DEPENDENT, /* replaces PM_ADD_DEP */ PM_GET_TIME_IDLE, /* replaces PM_IDLE_TIME */ PM_GET_DEFAULT_SYSTEM_THRESHOLD, - PM_ADD_DEPENDENT_PROPERTY + PM_ADD_DEPENDENT_PROPERTY, + PM_START_CPUPM, + PM_STOP_CPUPM, + PM_GET_CPU_THRESHOLD, + PM_SET_CPU_THRESHOLD, + PM_GET_CPUPM_STATE } pm_cmds; /* @@ -220,7 +224,11 @@ typedef enum { PM_DEVICE_THRESHOLD, PM_COMPONENT_THRESHOLD, PM_OLD_THRESHOLD, - PM_DIRECTLY_MANAGED + PM_DIRECTLY_MANAGED, + PM_CPU_THRESHOLD, + PM_CPU_PM_ENABLED, + PM_CPU_PM_DISABLED, + PM_CPU_PM_NOTSET } pm_states; diff --git a/usr/src/uts/sun4u/io/us_drv.c b/usr/src/uts/sun4u/io/us_drv.c index 781a7e1e21..6a4c825a3a 100644 --- a/usr/src/uts/sun4u/io/us_drv.c +++ b/usr/src/uts/sun4u/io/us_drv.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -269,6 +268,13 @@ us_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) return (DDI_FAILURE); } + if (ddi_prop_update_string(DDI_DEV_T_NONE, + usdsp->dip, "pm-class", "CPU") != DDI_PROP_SUCCESS) { + us_pm_free(usdsp); + ddi_soft_state_free(us_state, instance); + return (DDI_FAILURE); + } + /* * Taskq is used to dispatch routine to monitor CPU activities. */ |
