4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * pm This driver now only handles the ioctl interface. The scanning
28 * and policy stuff now lives in kernel/os/sunpm.c.
32 #include <sys/types.h>
33 #include <sys/errno.h>
34 #include <sys/modctl.h>
35 #include <sys/callb.h> /* callback registration for cpu_deep_idle */
36 #include <sys/conf.h> /* driver flags and functions */
37 #include <sys/open.h> /* OTYP_CHR definition */
38 #include <sys/stat.h> /* S_IFCHR definition */
39 #include <sys/pathname.h> /* name -> dev_info xlation */
40 #include <sys/kmem.h> /* memory alloc stuff */
41 #include <sys/debug.h>
44 #include <sys/sunddi.h>
48 #include <sys/mkdev.h>
49 #include <sys/promif.h>
50 #include <sys/consdev.h>
51 #include <sys/ddi_impldefs.h>
54 #include <sys/taskq.h>
55 #include <sys/policy.h>
56 #include <sys/cpu_pm.h>
59 * Minor number is instance<<8 + clone minor from range 1-254; (0 reserved
62 #define PM_MINOR_TO_CLONE(minor) ((minor) & (PM_MAX_CLONE -1))
64 #define PM_NUMCMPTS(dip) (DEVI(dip)->devi_pm_num_components)
65 #define PM_IS_CFB(dip) (DEVI(dip)->devi_pm_flags & PMC_CONSOLE_FB)
66 #define PM_MAJOR(dip) ddi_driver_major(dip)
67 #define PM_RELE(dip) ddi_release_devi(dip)
69 #define PM_IDLEDOWN_TIME 10
70 #define MAXSMBIOSSTRLEN 64 /* from SMBIOS spec */
71 #define MAXCOPYBUF (MAXSMBIOSSTRLEN + 1)
73 extern kmutex_t pm_scan_lock
; /* protects autopm_enable, pm_scans_disabled */
74 extern kmutex_t pm_clone_lock
; /* protects pm_clones array */
75 extern int autopm_enabled
;
76 extern pm_cpupm_t cpupm
;
77 extern pm_cpupm_t cpupm_default_mode
;
78 extern int pm_default_idle_threshold
;
79 extern int pm_system_idle_threshold
;
80 extern int pm_cpu_idle_threshold
;
81 extern kcondvar_t pm_clones_cv
[PM_MAX_CLONE
];
82 extern uint_t pm_poll_cnt
[PM_MAX_CLONE
];
83 extern int autoS3_enabled
;
84 extern void pm_record_thresh(pm_thresh_rec_t
*);
85 extern void pm_register_watcher(int, dev_info_t
*);
86 extern int pm_get_current_power(dev_info_t
*, int, int *);
87 extern int pm_interest_registered(int);
88 extern void pm_all_to_default_thresholds(void);
89 extern int pm_current_threshold(dev_info_t
*, int, int *);
90 extern void pm_deregister_watcher(int, dev_info_t
*);
91 extern void pm_unrecord_threshold(char *);
92 extern int pm_S3_enabled
;
93 extern int pm_ppm_searchlist(pm_searchargs_t
*);
94 extern psce_t
*pm_psc_clone_to_direct(int);
95 extern psce_t
*pm_psc_clone_to_interest(int);
98 * The soft state of the power manager. Since there will only
99 * one of these, just reference it through a static pointer.
101 static struct pmstate
{
102 dev_info_t
*pm_dip
; /* ptr to our dev_info node */
103 int pm_instance
; /* for ddi_get_instance() */
104 timeout_id_t pm_idledown_id
; /* pm idledown timeout id */
105 uchar_t pm_clones
[PM_MAX_CLONE
]; /* uniqueify multiple opens */
106 struct cred
*pm_cred
[PM_MAX_CLONE
]; /* cred for each unique open */
107 } pm_state
= { NULL
, -1, (timeout_id_t
)0 };
108 typedef struct pmstate
*pm_state_t
;
109 static pm_state_t pmstp
= &pm_state
;
111 static int pm_open(dev_t
*, int, int, cred_t
*);
112 static int pm_close(dev_t
, int, int, cred_t
*);
113 static int pm_ioctl(dev_t
, int, intptr_t, int, cred_t
*, int *);
114 static int pm_chpoll(dev_t
, short, int, short *, struct pollhead
**);
116 static struct cb_ops pm_cb_ops
= {
118 pm_close
, /* close */
119 nodev
, /* strategy */
124 pm_ioctl
, /* ioctl */
128 pm_chpoll
, /* poll */
129 ddi_prop_op
, /* prop_op */
130 NULL
, /* streamtab */
131 D_NEW
| D_MP
/* driver compatibility flag */
134 static int pm_getinfo(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
,
136 static int pm_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
);
137 static int pm_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
);
139 static struct dev_ops pm_ops
= {
140 DEVO_REV
, /* devo_rev */
142 pm_getinfo
, /* info */
143 nulldev
, /* identify */
145 pm_attach
, /* attach */
146 pm_detach
, /* detach */
148 &pm_cb_ops
, /* driver operations */
149 NULL
, /* bus operations */
151 ddi_quiesce_not_needed
, /* quiesce */
154 static struct modldrv modldrv
= {
156 "power management driver",
160 static struct modlinkage modlinkage
= {
161 MODREV_1
, &modldrv
, 0
164 /* Local functions */
166 static int print_info(dev_info_t
*, void *);
173 return (mod_install(&modlinkage
));
179 return (mod_remove(&modlinkage
));
183 _info(struct modinfo
*modinfop
)
185 return (mod_info(&modlinkage
, modinfop
));
189 pm_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
196 if (pmstp
->pm_instance
!= -1) /* Only allow one instance */
197 return (DDI_FAILURE
);
198 pmstp
->pm_instance
= ddi_get_instance(dip
);
199 if (ddi_create_minor_node(dip
, "pm", S_IFCHR
,
200 (pmstp
->pm_instance
<< 8) + 0,
201 DDI_PSEUDO
, 0) != DDI_SUCCESS
) {
202 return (DDI_FAILURE
);
204 pmstp
->pm_dip
= dip
; /* pm_init and getinfo depend on it */
206 for (i
= 0; i
< PM_MAX_CLONE
; i
++)
207 cv_init(&pm_clones_cv
[i
], NULL
, CV_DEFAULT
, NULL
);
210 return (DDI_SUCCESS
);
213 return (DDI_FAILURE
);
219 pm_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
226 * Don't detach while idledown timeout is pending. Note that
227 * we already know we're not in pm_ioctl() due to framework
228 * synchronization, so this is a sufficient test
230 if (pmstp
->pm_idledown_id
)
231 return (DDI_FAILURE
);
233 for (i
= 0; i
< PM_MAX_CLONE
; i
++)
234 cv_destroy(&pm_clones_cv
[i
]);
236 ddi_remove_minor_node(dip
, NULL
);
237 pmstp
->pm_instance
= -1;
238 return (DDI_SUCCESS
);
241 return (DDI_FAILURE
);
246 pm_close_direct_pm_device(dev_info_t
*dip
, void *arg
)
250 pm_info_t
*info
= PM_GET_PM_INFO(dip
);
252 clone
= *((int *)arg
);
255 return (DDI_WALK_CONTINUE
);
257 pathbuf
= kmem_alloc(MAXPATHLEN
, KM_SLEEP
);
259 if (clone
== info
->pmi_clone
) {
260 PMD(PMD_CLOSE
, ("pm_close: found %s@%s(%s#%d)\n",
262 ASSERT(PM_ISDIRECT(dip
));
263 info
->pmi_dev_pm_state
&= ~PM_DIRECT
;
265 pm_proceed(dip
, PMP_RELEASE
, -1, -1);
266 /* Bring ourselves up if there is a keeper that is up */
267 (void) ddi_pathname(dip
, pathbuf
);
268 pm_dispatch_to_dep_thread(PM_DEP_WK_BRINGUP_SELF
, NULL
,
269 pathbuf
, PM_DEP_NOWAIT
, NULL
, 0);
276 kmem_free(pathbuf
, MAXPATHLEN
);
278 /* restart autopm on device released from direct pm */
281 return (DDI_WALK_CONTINUE
);
293 #define CHECKPERMS 0x001
299 #define INDATAINT 0x002
300 #define INDATASTRING 0x004
302 #define INDATAOUT 0x010
303 #define INDATA (INDATAOUT | INDATAINT | INDATASTRING | INDEP)
306 int cmd
; /* command code */
307 char *name
; /* printable string */
308 int supported
; /* true if still supported */
309 int str_type
; /* PM_REQ or NOSTRUCT */
310 int inargs
; /* INWHO, INDATAINT, INDATASTRING, INDEP, */
312 int diptype
; /* DIP or NODIP */
313 int deptype
; /* DEP or NODEP */
314 int permission
; /* SU, GU, or CHECKPERMS */
323 * Returns true if permission granted by credentials
326 pm_perms(int perm
, cred_t
*cr
)
328 if (perm
== 0) /* no restrictions */
330 if (perm
== CHECKPERMS
) /* ok for now (is checked later) */
332 if ((perm
& SU
) && secpolicy_power_mgmt(cr
) == 0) /* privileged? */
334 if ((perm
& SG
) && (crgetgid(cr
) == 0)) /* group 0 is ok */
341 print_info(dev_info_t
*dip
, void *arg
)
343 _NOTE(ARGUNUSED(arg
))
346 struct pm_component
*cp
;
347 extern int pm_cur_power(pm_component_t
*cp
);
349 info
= PM_GET_PM_INFO(dip
);
351 return (DDI_WALK_CONTINUE
);
352 cmn_err(CE_CONT
, "pm_info for %s\n", ddi_node_name(dip
));
353 for (i
= 0; i
< PM_NUMCMPTS(dip
); i
++) {
355 cmn_err(CE_CONT
, "\tThresholds[%d] =", i
);
356 for (j
= 0; j
< cp
->pmc_comp
.pmc_numlevels
; j
++)
357 cmn_err(CE_CONT
, " %d", cp
->pmc_comp
.pmc_thresh
[i
]);
358 cmn_err(CE_CONT
, "\n");
359 cmn_err(CE_CONT
, "\tCurrent power[%d] = %d\n", i
,
362 if (PM_ISDIRECT(dip
))
363 cmn_err(CE_CONT
, "\tDirect power management\n");
364 return (DDI_WALK_CONTINUE
);
369 * command, name, supported, str_type, inargs, diptype, deptype, permission
371 static struct pm_cmd_info pmci
[] = {
372 {PM_SCHEDULE
, "PM_SCHEDULE", 0},
373 {PM_GET_IDLE_TIME
, "PM_GET_IDLE_TIME", 0},
374 {PM_GET_NUM_CMPTS
, "PM_GET_NUM_CMPTS", 0},
375 {PM_GET_THRESHOLD
, "PM_GET_THRESHOLD", 0},
376 {PM_SET_THRESHOLD
, "PM_SET_THRESHOLD", 0},
377 {PM_GET_NORM_PWR
, "PM_GET_NORM_PWR", 0},
378 {PM_SET_CUR_PWR
, "PM_SET_CUR_PWR", 0},
379 {PM_GET_CUR_PWR
, "PM_GET_CUR_PWR", 0},
380 {PM_GET_NUM_DEPS
, "PM_GET_NUM_DEPS", 0},
381 {PM_GET_DEP
, "PM_GET_DEP", 0},
382 {PM_ADD_DEP
, "PM_ADD_DEP", 0},
383 {PM_REM_DEP
, "PM_REM_DEP", 0},
384 {PM_REM_DEVICE
, "PM_REM_DEVICE", 0},
385 {PM_REM_DEVICES
, "PM_REM_DEVICES", 0},
386 {PM_REPARSE_PM_PROPS
, "PM_REPARSE_PM_PROPS", 1, PM_REQ
, INWHO
, DIP
,
388 {PM_DISABLE_AUTOPM
, "PM_DISABLE_AUTOPM", 0},
389 {PM_REENABLE_AUTOPM
, "PM_REENABLE_AUTOPM", 0},
390 {PM_SET_NORM_PWR
, "PM_SET_NORM_PWR", 0 },
391 {PM_SET_DEVICE_THRESHOLD
, "PM_SET_DEVICE_THRESHOLD", 1, PM_REQ
,
392 INWHO
, NODIP
, NODEP
, SU
},
393 {PM_GET_SYSTEM_THRESHOLD
, "PM_GET_SYSTEM_THRESHOLD", 1, NOSTRUCT
},
394 {PM_GET_DEFAULT_SYSTEM_THRESHOLD
, "PM_GET_DEFAULT_SYSTEM_THRESHOLD",
396 {PM_SET_SYSTEM_THRESHOLD
, "PM_SET_SYSTEM_THRESHOLD", 1, NOSTRUCT
,
398 {PM_START_PM
, "PM_START_PM", 1, NOSTRUCT
, 0, 0, 0, SU
},
399 {PM_STOP_PM
, "PM_STOP_PM", 1, NOSTRUCT
, 0, 0, 0, SU
},
400 {PM_RESET_PM
, "PM_RESET_PM", 1, NOSTRUCT
, 0, 0, 0, SU
},
401 {PM_GET_STATS
, "PM_GET_STATS", 1, PM_REQ
, INWHO
| INDATAOUT
,
403 {PM_GET_DEVICE_THRESHOLD
, "PM_GET_DEVICE_THRESHOLD", 1, PM_REQ
, INWHO
,
405 {PM_GET_POWER_NAME
, "PM_GET_POWER_NAME", 1, PM_REQ
, INWHO
| INDATAOUT
,
407 {PM_GET_POWER_LEVELS
, "PM_GET_POWER_LEVELS", 1, PM_REQ
,
408 INWHO
| INDATAOUT
, DIP
, NODEP
},
409 {PM_GET_NUM_COMPONENTS
, "PM_GET_NUM_COMPONENTS", 1, PM_REQ
, INWHO
,
411 {PM_GET_COMPONENT_NAME
, "PM_GET_COMPONENT_NAME", 1, PM_REQ
,
412 INWHO
| INDATAOUT
, DIP
, NODEP
},
413 {PM_GET_NUM_POWER_LEVELS
, "PM_GET_NUM_POWER_LEVELS", 1, PM_REQ
, INWHO
,
415 {PM_GET_STATE_CHANGE
, "PM_GET_STATE_CHANGE", 1, PM_PSC
},
416 {PM_GET_STATE_CHANGE_WAIT
, "PM_GET_STATE_CHANGE_WAIT", 1, PM_PSC
},
417 {PM_DIRECT_PM
, "PM_DIRECT_PM", 1, PM_REQ
, INWHO
, DIP
, NODEP
,
419 {PM_RELEASE_DIRECT_PM
, "PM_RELEASE_DIRECT_PM", 1, PM_REQ
, INWHO
,
421 {PM_DIRECT_NOTIFY
, "PM_DIRECT_NOTIFY", 1, PM_PSC
},
422 {PM_DIRECT_NOTIFY_WAIT
, "PM_DIRECT_NOTIFY_WAIT", 1, PM_PSC
},
423 {PM_RESET_DEVICE_THRESHOLD
, "PM_RESET_DEVICE_THRESHOLD", 1, PM_REQ
,
424 INWHO
, DIP
, NODEP
, SU
},
425 {PM_GET_PM_STATE
, "PM_GET_PM_STATE", 1, NOSTRUCT
},
426 {PM_GET_AUTOS3_STATE
, "PM_GET_AUTOS3_STATE", 1, NOSTRUCT
},
427 {PM_GET_S3_SUPPORT_STATE
, "PM_GET_S3_SUPPORT_STATE", 1, NOSTRUCT
},
428 {PM_GET_DEVICE_TYPE
, "PM_GET_DEVICE_TYPE", 1, PM_REQ
, INWHO
,
430 {PM_SET_COMPONENT_THRESHOLDS
, "PM_SET_COMPONENT_THRESHOLDS", 1, PM_REQ
,
431 INWHO
| INDATAINT
, NODIP
, NODEP
, SU
},
432 {PM_GET_COMPONENT_THRESHOLDS
, "PM_GET_COMPONENT_THRESHOLDS", 1, PM_REQ
,
433 INWHO
| INDATAOUT
, DIP
, NODEP
},
434 {PM_IDLE_DOWN
, "PM_IDLE_DOWN", 1, NOSTRUCT
, 0, 0, 0, SU
},
435 {PM_GET_DEVICE_THRESHOLD_BASIS
, "PM_GET_DEVICE_THRESHOLD_BASIS", 1,
436 PM_REQ
, INWHO
, DIP
, NODEP
},
437 {PM_SET_CURRENT_POWER
, "PM_SET_CURRENT_POWER", 1, PM_REQ
, INWHO
, DIP
,
439 {PM_GET_CURRENT_POWER
, "PM_GET_CURRENT_POWER", 1, PM_REQ
, INWHO
, DIP
,
441 {PM_GET_FULL_POWER
, "PM_GET_FULL_POWER", 1, PM_REQ
, INWHO
, DIP
,
443 {PM_ADD_DEPENDENT
, "PM_ADD_DEPENDENT", 1, PM_REQ
, INWHO
| INDATASTRING
,
445 {PM_GET_TIME_IDLE
, "PM_GET_TIME_IDLE", 1, PM_REQ
, INWHO
, DIP
, NODEP
},
446 {PM_ADD_DEPENDENT_PROPERTY
, "PM_ADD_DEPENDENT_PROPERTY", 1, PM_REQ
,
447 INWHO
| INDATASTRING
, NODIP
, DEP
, SU
},
448 {PM_START_CPUPM
, "PM_START_CPUPM", 1, NOSTRUCT
, 0, 0, 0, SU
},
449 {PM_START_CPUPM_EV
, "PM_START_CPUPM_EV", 1, NOSTRUCT
, 0,
451 {PM_START_CPUPM_POLL
, "PM_START_CPUPM_POLL", 1, NOSTRUCT
, 0,
453 {PM_STOP_CPUPM
, "PM_STOP_CPUPM", 1, NOSTRUCT
, 0, 0, 0, SU
},
454 {PM_GET_CPU_THRESHOLD
, "PM_GET_CPU_THRESHOLD", 1, NOSTRUCT
},
455 {PM_SET_CPU_THRESHOLD
, "PM_SET_CPU_THRESHOLD", 1, NOSTRUCT
,
457 {PM_GET_CPUPM_STATE
, "PM_GET_CPUPM_STATE", 1, NOSTRUCT
},
458 {PM_START_AUTOS3
, "PM_START_AUTOS3", 1, NOSTRUCT
, 0, 0, 0, SU
},
459 {PM_STOP_AUTOS3
, "PM_STOP_AUTOS3", 1, NOSTRUCT
, 0, 0, 0, SU
},
460 {PM_ENABLE_S3
, "PM_ENABLE_S3", 1, NOSTRUCT
, 0, 0, 0, SU
},
461 {PM_DISABLE_S3
, "PM_DISABLE_S3", 1, NOSTRUCT
, 0, 0, 0, SU
},
462 {PM_ENTER_S3
, "PM_ENTER_S3", 1, NOSTRUCT
, 0, 0, 0, SU
},
463 {PM_SEARCH_LIST
, "PM_SEARCH_LIST", 1, PM_SRCH
, 0, 0, 0, SU
},
464 {PM_GET_CMD_NAME
, "PM_GET_CMD_NAME", 1, PM_REQ
, INDATAOUT
, NODIP
,
466 {PM_DISABLE_CPU_DEEP_IDLE
, "PM_DISABLE_CPU_DEEP_IDLE", 1, NOSTRUCT
, 0,
468 {PM_ENABLE_CPU_DEEP_IDLE
, "PM_START_CPU_DEEP_IDLE", 1, NOSTRUCT
, 0,
470 {PM_DEFAULT_CPU_DEEP_IDLE
, "PM_DFLT_CPU_DEEP_IDLE", 1, NOSTRUCT
, 0,
478 struct pm_cmd_info
*pcip
;
480 for (pcip
= pmci
; pcip
->name
; pcip
++) {
481 if (cmd
== pcip
->cmd
)
488 pm_decode_cmd(int cmd
)
490 static char invbuf
[64];
491 struct pm_cmd_info
*pcip
= pc_info(cmd
);
494 (void) sprintf(invbuf
, "ioctl: invalid command %d\n", cmd
);
499 * Allocate scan resource, create taskq, then dispatch scan,
500 * called only if autopm is enabled.
503 pm_start_pm_walk(dev_info_t
*dip
, void *arg
)
505 int cmd
= *((int *)arg
);
507 char *cmdstr
= pm_decode_cmd(cmd
);
510 if (!PM_GET_PM_INFO(dip
) || PM_ISBC(dip
))
511 return (DDI_WALK_CONTINUE
);
515 case PM_START_CPUPM_POLL
:
517 return (DDI_WALK_CONTINUE
);
518 mutex_enter(&pm_scan_lock
);
519 if (!PM_CPUPM_DISABLED
&& !PM_EVENT_CPUPM
)
521 mutex_exit(&pm_scan_lock
);
524 mutex_enter(&pm_scan_lock
);
525 if (PM_ISCPU(dip
) && (PM_CPUPM_DISABLED
|| PM_EVENT_CPUPM
)) {
526 mutex_exit(&pm_scan_lock
);
527 return (DDI_WALK_CONTINUE
);
531 mutex_exit(&pm_scan_lock
);
536 * Start doing pm on device: ensure pm_scan data structure initiated,
537 * no need to guarantee a successful scan run.
539 PMD(PMD_SCAN
| PMD_IOCTL
, ("ioctl: %s: scan %s@%s(%s#%d)\n", cmdstr
,
543 return (DDI_WALK_CONTINUE
);
547 * Bring devices to full power level, then stop scan
550 pm_stop_pm_walk(dev_info_t
*dip
, void *arg
)
552 pm_info_t
*info
= PM_GET_PM_INFO(dip
);
553 int cmd
= *((int *)arg
);
555 char *cmdstr
= pm_decode_cmd(cmd
);
559 return (DDI_WALK_CONTINUE
);
564 * If CPU devices are being managed independently, then don't
565 * stop them as part of PM_STOP_PM. Only stop them as part of
566 * PM_STOP_CPUPM and PM_RESET_PM.
568 if (PM_ISCPU(dip
) && PM_POLLING_CPUPM
)
569 return (DDI_WALK_CONTINUE
);
573 * If stopping CPU devices and this device is not marked
574 * as a CPU device, then skip.
577 return (DDI_WALK_CONTINUE
);
582 * Stop the current scan, and then bring it back to normal power.
585 PMD(PMD_SCAN
| PMD_IOCTL
, ("ioctl: %s: stop scan for "
586 "%s@%s(%s#%d)\n", cmdstr
, PM_DEVICE(dip
)))
590 if (!PM_ISBC(dip
) && !PM_ISDIRECT(dip
) &&
591 !pm_all_at_normal(dip
)) {
593 if (info
->pmi_dev_pm_state
& PM_DETACHING
) {
594 PMD(PMD_ALLNORM
, ("ioctl: %s: deferring "
595 "all_to_normal because %s@%s(%s#%d) is detaching\n",
596 cmdstr
, PM_DEVICE(dip
)))
597 info
->pmi_dev_pm_state
|= PM_ALLNORM_DEFERRED
;
599 return (DDI_WALK_CONTINUE
);
602 if (pm_all_to_normal(dip
, PM_CANBLOCK_FAIL
) != DDI_SUCCESS
) {
603 PMD(PMD_ERROR
, ("ioctl: %s: could not bring %s@%s"
604 "(%s#%d) to normal\n", cmdstr
, PM_DEVICE(dip
)))
608 return (DDI_WALK_CONTINUE
);
612 pm_start_idledown(dev_info_t
*dip
, void *arg
)
614 int flag
= (int)(intptr_t)arg
;
615 pm_scan_t
*scanp
= PM_GET_PM_SCAN(dip
);
618 return (DDI_WALK_CONTINUE
);
621 scanp
->ps_idle_down
|= flag
;
625 return (DDI_WALK_CONTINUE
);
630 pm_end_idledown(dev_info_t
*dip
, void *ignore
)
632 pm_scan_t
*scanp
= PM_GET_PM_SCAN(dip
);
635 return (DDI_WALK_CONTINUE
);
639 * The PMID_TIMERS bits are place holder till idledown expires.
640 * The bits are also the base for regenerating PMID_SCANS bits.
641 * While it's up to scan thread to clear up the PMID_SCANS bits
642 * after each scan run, PMID_TIMERS ensure aggressive scan down
643 * performance throughout the idledown period.
645 scanp
->ps_idle_down
&= ~PMID_TIMERS
;
648 return (DDI_WALK_CONTINUE
);
653 pm_end_idledown_walk(void *ignore
)
655 PMD(PMD_IDLEDOWN
, ("ioctl: end_idledown: idledown_id(%lx) timer is "
656 "off\n", (ulong_t
)pmstp
->pm_idledown_id
));
658 mutex_enter(&pm_scan_lock
);
659 pmstp
->pm_idledown_id
= 0;
660 mutex_exit(&pm_scan_lock
);
662 ddi_walk_devs(ddi_root_node(), pm_end_idledown
, NULL
);
666 * pm_timeout_idledown - keep idledown effect for 10 seconds.
668 * Return 0 if another competing caller scheduled idledown timeout,
669 * otherwise, return idledown timeout_id.
672 pm_timeout_idledown(void)
677 * Keep idle-down in effect for either 10 seconds
678 * or length of a scan interval, which ever is greater.
680 mutex_enter(&pm_scan_lock
);
681 if (pmstp
->pm_idledown_id
!= 0) {
682 to_id
= pmstp
->pm_idledown_id
;
683 pmstp
->pm_idledown_id
= 0;
684 mutex_exit(&pm_scan_lock
);
685 (void) untimeout(to_id
);
686 mutex_enter(&pm_scan_lock
);
687 if (pmstp
->pm_idledown_id
!= 0) {
688 PMD(PMD_IDLEDOWN
, ("ioctl: timeout_idledown: "
689 "another caller got it, idledown_id(%lx)!\n",
690 (ulong_t
)pmstp
->pm_idledown_id
))
691 mutex_exit(&pm_scan_lock
);
695 pmstp
->pm_idledown_id
= timeout(pm_end_idledown_walk
, NULL
,
696 PM_IDLEDOWN_TIME
* hz
);
697 PMD(PMD_IDLEDOWN
, ("ioctl: timeout_idledown: idledown_id(%lx)\n",
698 (ulong_t
)pmstp
->pm_idledown_id
))
699 mutex_exit(&pm_scan_lock
);
701 return (pmstp
->pm_idledown_id
);
705 pm_chpoll(dev_t dev
, short events
, int anyyet
, short *reventsp
,
706 struct pollhead
**phpp
)
708 extern struct pollhead pm_pollhead
; /* kernel/os/sunpm.c */
711 clone
= PM_MINOR_TO_CLONE(getminor(dev
));
712 PMD(PMD_IOCTL
, ("ioctl: pm_chpoll: clone %d\n", clone
))
713 if ((events
& (POLLIN
| POLLRDNORM
)) && pm_poll_cnt
[clone
]) {
714 *reventsp
|= (POLLIN
| POLLRDNORM
);
715 PMD(PMD_IOCTL
, ("ioctl: pm_chpoll: reventsp set\n"))
719 PMD(PMD_IOCTL
, ("ioctl: pm_chpoll: not anyyet\n"))
720 *phpp
= &pm_pollhead
;
724 PMD(PMD_IOCTL
, ("ioctl: pm_chpoll: anyyet\n"))
732 * called by pm_dicard_entries to free up the memory. It also decrements
733 * pm_poll_cnt, if direct is non zero.
736 pm_free_entries(psce_t
*pscep
, int clone
, int direct
)
738 pm_state_change_t
*p
;
744 PMD(PMD_IOCTL
, ("ioctl: discard: "
745 "pm_poll_cnt[%d] is %d before "
748 ASSERT(pm_poll_cnt
[clone
]);
749 pm_poll_cnt
[clone
]--;
751 kmem_free(p
->physpath
, p
->size
);
753 if (p
== pscep
->psce_last
)
754 p
= pscep
->psce_first
;
758 pscep
->psce_out
= pscep
->psce_first
;
759 pscep
->psce_in
= pscep
->psce_first
;
760 mutex_exit(&pscep
->psce_lock
);
765 * Discard entries for this clone. Calls pm_free_entries to free up memory.
768 pm_discard_entries(int clone
)
773 mutex_enter(&pm_clone_lock
);
774 if ((pscep
= pm_psc_clone_to_direct(clone
)) != NULL
)
776 pm_free_entries(pscep
, clone
, direct
);
777 pscep
= pm_psc_clone_to_interest(clone
);
778 pm_free_entries(pscep
, clone
, 0);
779 mutex_exit(&pm_clone_lock
);
784 pm_set_idle_threshold(dev_info_t
*dip
, int thresh
, int flag
)
786 if (!PM_ISBC(dip
) && !PM_ISDIRECT(dip
)) {
787 switch (DEVI(dip
)->devi_pm_flags
& PMC_THRESH_ALL
) {
790 PMD(PMD_IOCTL
, ("ioctl: set_idle_threshold: set "
791 "%s@%s(%s#%d) default thresh to 0t%d\n",
792 PM_DEVICE(dip
), thresh
))
793 pm_set_device_threshold(dip
, thresh
, flag
);
802 pm_set_idle_thresh_walk(dev_info_t
*dip
, void *arg
)
804 int cmd
= *((int *)arg
);
806 if (!PM_GET_PM_INFO(dip
))
807 return (DDI_WALK_CONTINUE
);
810 case PM_SET_SYSTEM_THRESHOLD
:
811 if (DEVI(dip
)->devi_pm_flags
& PMC_CPU_THRESH
)
813 pm_set_idle_threshold(dip
, pm_system_idle_threshold
,
817 case PM_SET_CPU_THRESHOLD
:
820 pm_set_idle_threshold(dip
, pm_cpu_idle_threshold
,
826 return (DDI_WALK_CONTINUE
);
831 pm_getinfo(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
, void **result
)
837 case DDI_INFO_DEVT2DEVINFO
:
838 if (pmstp
->pm_instance
== -1)
839 return (DDI_FAILURE
);
840 *result
= pmstp
->pm_dip
;
841 return (DDI_SUCCESS
);
843 case DDI_INFO_DEVT2INSTANCE
:
845 instance
= getminor(dev
) >> 8;
846 *result
= (void *)(uintptr_t)instance
;
847 return (DDI_SUCCESS
);
850 return (DDI_FAILURE
);
857 pm_open(dev_t
*devp
, int flag
, int otyp
, cred_t
*cr
)
861 if (otyp
!= OTYP_CHR
)
864 mutex_enter(&pm_clone_lock
);
865 for (clone
= 1; clone
< PM_MAX_CLONE
; clone
++)
866 if (!pmstp
->pm_clones
[clone
])
869 if (clone
== PM_MAX_CLONE
) {
870 mutex_exit(&pm_clone_lock
);
873 pmstp
->pm_cred
[clone
] = cr
;
876 *devp
= makedevice(getmajor(*devp
), (pmstp
->pm_instance
<< 8) + clone
);
877 pmstp
->pm_clones
[clone
] = 1;
878 mutex_exit(&pm_clone_lock
);
885 pm_close(dev_t dev
, int flag
, int otyp
, cred_t
*cr
)
889 if (otyp
!= OTYP_CHR
)
892 clone
= PM_MINOR_TO_CLONE(getminor(dev
));
893 PMD(PMD_CLOSE
, ("pm_close: minor %x, clone %x\n", getminor(dev
),
897 * Walk the entire device tree to find the corresponding
898 * device and operate on it.
900 ddi_walk_devs(ddi_root_node(), pm_close_direct_pm_device
,
903 crfree(pmstp
->pm_cred
[clone
]);
904 pmstp
->pm_cred
[clone
] = 0;
905 pmstp
->pm_clones
[clone
] = 0;
906 pm_discard_entries(clone
);
907 ASSERT(pm_poll_cnt
[clone
] == 0);
908 pm_deregister_watcher(clone
, NULL
);
914 pm_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
, cred_t
*cr
, int *rval_p
)
916 struct pm_cmd_info
*pc_info(int);
917 struct pm_cmd_info
*pcip
= pc_info(cmd
);
919 dev_info_t
*dip
= NULL
;
920 pm_info_t
*info
= NULL
;
922 char *cmdstr
= pm_decode_cmd(cmd
);
924 * To keep devinfo nodes from going away while we're holding a
925 * pointer to their dip, pm_name_to_dip() optionally holds
926 * the devinfo node. If we've done that, we set dipheld
927 * so we know at the end of the ioctl processing to release the
937 char who
[MAXNAMELEN
];
938 size_t wholen
; /* copyinstr length */
939 size_t deplen
= MAXNAMELEN
;
940 char *dep
, i_dep_buf
[MAXNAMELEN
];
941 char pathbuf
[MAXNAMELEN
];
942 struct pm_component
*cp
;
943 #ifdef _MULTI_DATAMODEL
944 pm_state_change32_t
*pscp32
;
945 pm_state_change32_t psc32
;
946 pm_searchargs32_t psa32
;
949 pm_state_change_t
*pscp
;
950 pm_state_change_t psc
;
952 char listname
[MAXCOPYBUF
];
953 char manufacturer
[MAXCOPYBUF
];
954 char product
[MAXCOPYBUF
];
957 PMD(PMD_IOCTL
, ("ioctl: %s: begin\n", cmdstr
))
961 ddi_walk_devs(ddi_root_node(), print_info
, NULL
);
964 ret
= 0x0badcafe; /* sanity checking */
965 pm_cmd
= cmd
; /* for ASSERT debugging */
966 pm_cmd_string
= cmdstr
; /* for ASSERT debugging */
971 PMD(PMD_ERROR
, ("ioctl: unknown command %d\n", cmd
))
974 if (pcip
== NULL
|| pcip
->supported
== 0) {
975 PMD(PMD_ERROR
, ("ioctl: command %s no longer supported\n",
983 clone
= PM_MINOR_TO_CLONE(getminor(dev
));
984 if (!pm_perms(pcip
->permission
, pmstp
->pm_cred
[clone
])) {
988 switch (pcip
->str_type
) {
991 #ifdef _MULTI_DATAMODEL
992 if ((mode
& DATAMODEL_MASK
) == DATAMODEL_ILP32
) {
995 if (ddi_copyin((caddr_t
)arg
, &req32
,
996 sizeof (req32
), mode
) != 0) {
997 PMD(PMD_ERROR
, ("ioctl: %s: ddi_copyin "
998 "EFAULT\n\n", cmdstr
))
1002 req
.component
= req32
.component
;
1003 req
.value
= req32
.value
;
1004 req
.datasize
= req32
.datasize
;
1005 if (pcip
->inargs
& INWHO
) {
1006 ret
= copyinstr((char *)(uintptr_t)
1007 req32
.physpath
, who
, MAXNAMELEN
, &wholen
);
1009 PMD(PMD_ERROR
, ("ioctl: %s: "
1010 "copyinstr fails returning %d\n",
1015 PMD(PMD_IOCTL
, ("ioctl: %s: physpath=%s\n",
1016 cmdstr
, req
.physpath
))
1018 if (pcip
->inargs
& INDATA
) {
1019 req
.data
= (void *)(uintptr_t)req32
.data
;
1020 req
.datasize
= req32
.datasize
;
1025 switch (pcip
->diptype
) {
1028 pm_name_to_dip(req
.physpath
, 1))) {
1029 PMD(PMD_ERROR
, ("ioctl: %s: "
1030 "pm_name_to_dip for %s failed\n",
1031 cmdstr
, req
.physpath
))
1041 * Internal error, invalid ioctl description
1042 * force debug entry even if pm_debug not set
1045 pm_log("invalid diptype %d for cmd %d (%s)\n",
1046 pcip
->diptype
, cmd
, pcip
->name
);
1051 if (pcip
->inargs
& INDATAINT
) {
1055 icount
= req32
.datasize
/ sizeof (int32_t);
1057 PMD(PMD_ERROR
, ("ioctl: %s: datasize"
1058 " 0 or neg EFAULT\n\n", cmdstr
))
1062 ASSERT(!(pcip
->inargs
& INDATASTRING
));
1063 req
.datasize
= icount
* sizeof (int);
1064 req
.data
= kmem_alloc(req
.datasize
, KM_SLEEP
);
1068 i32p
= (int32_t *)(uintptr_t)req32
.data
;
1069 i
< icount
; i
++, i32p
++) {
1070 if (ddi_copyin((void *)i32p
, &int32buf
,
1071 sizeof (int32_t), mode
)) {
1074 PMD(PMD_ERROR
, ("ioctl: %s: "
1075 "entry %d EFAULT\n",
1080 *ip
++ = (int)int32buf
;
1085 if (pcip
->inargs
& INDATASTRING
) {
1086 ASSERT(!(pcip
->inargs
& INDATAINT
));
1087 ASSERT(pcip
->deptype
== DEP
);
1088 if (req32
.data
!= (uintptr_t)NULL
) {
1089 if (copyinstr((void *)(uintptr_t)
1090 req32
.data
, dep
, deplen
, NULL
)) {
1091 PMD(PMD_ERROR
, ("ioctl: %s: "
1092 "0x%p dep size %lx, EFAULT"
1094 (void *)req
.data
, deplen
))
1100 PMD(PMD_DEP
, ("ioctl: %s: "
1101 "dep %s\n", cmdstr
, dep
))
1105 PMD(PMD_ERROR
, ("ioctl: %s: no "
1106 "dependent\n", cmdstr
))
1112 #endif /* _MULTI_DATAMODEL */
1114 if (ddi_copyin((caddr_t
)arg
,
1115 &req
, sizeof (req
), mode
) != 0) {
1116 PMD(PMD_ERROR
, ("ioctl: %s: ddi_copyin "
1117 "EFAULT\n\n", cmdstr
))
1121 if (pcip
->inargs
& INWHO
) {
1122 ret
= copyinstr((char *)req
.physpath
, who
,
1123 MAXNAMELEN
, &wholen
);
1125 PMD(PMD_ERROR
, ("ioctl: %s copyinstr"
1126 " fails returning %d\n", cmdstr
,
1131 PMD(PMD_IOCTL
, ("ioctl: %s: physpath=%s\n",
1132 cmdstr
, req
.physpath
))
1134 if (!(pcip
->inargs
& INDATA
)) {
1138 switch (pcip
->diptype
) {
1141 pm_name_to_dip(req
.physpath
, 1))) {
1142 PMD(PMD_ERROR
, ("ioctl: %s: "
1143 "pm_name_to_dip for %s failed\n",
1144 cmdstr
, req
.physpath
))
1154 * Internal error, invalid ioctl description
1155 * force debug entry even if pm_debug not set
1158 pm_log("invalid diptype %d for cmd %d (%s)\n",
1159 pcip
->diptype
, cmd
, pcip
->name
);
1164 if (pcip
->inargs
& INDATAINT
) {
1167 ASSERT(!(pcip
->inargs
& INDATASTRING
));
1169 icount
= req
.datasize
/ sizeof (int);
1171 PMD(PMD_ERROR
, ("ioctl: %s: datasize"
1172 " 0 or neg EFAULT\n\n", cmdstr
))
1176 req
.data
= kmem_alloc(req
.datasize
, KM_SLEEP
);
1177 if (ddi_copyin((caddr_t
)ip
, req
.data
,
1178 req
.datasize
, mode
) != 0) {
1179 PMD(PMD_ERROR
, ("ioctl: %s: ddi_copyin "
1180 "EFAULT\n\n", cmdstr
))
1185 if (pcip
->inargs
& INDATASTRING
) {
1186 ASSERT(!(pcip
->inargs
& INDATAINT
));
1187 ASSERT(pcip
->deptype
== DEP
);
1188 if (req
.data
!= NULL
) {
1189 if (copyinstr((caddr_t
)req
.data
,
1190 dep
, deplen
, NULL
)) {
1191 PMD(PMD_ERROR
, ("ioctl: %s: "
1192 "0x%p dep size %lu, "
1194 (void *)req
.data
, deplen
))
1200 PMD(PMD_DEP
, ("ioctl: %s: "
1201 "dep %s\n", cmdstr
, dep
))
1205 PMD(PMD_ERROR
, ("ioctl: %s: no "
1206 "dependent\n", cmdstr
))
1213 * Now we've got all the args in for the commands that
1214 * use the new pm_req struct.
1217 case PM_REPARSE_PM_PROPS
:
1219 struct dev_ops
*drv
;
1224 * This ioctl is provided only for the ddivs pm test.
1225 * We only do it to a driver which explicitly allows
1226 * us to do so by exporting a pm-reparse-ok property.
1227 * We only care whether the property exists or not.
1229 if ((drv
= ddi_get_driver(dip
)) == NULL
) {
1233 if ((cb
= drv
->devo_cb_ops
) != NULL
) {
1234 if ((*cb
->cb_prop_op
)(DDI_DEV_T_ANY
, dip
,
1235 PROP_LEN_AND_VAL_ALLOC
, (DDI_PROP_CANSLEEP
|
1236 DDI_PROP_DONTPASS
| DDI_PROP_NOTPROM
),
1237 "pm-reparse-ok", (caddr_t
)&propval
,
1238 &length
) != DDI_SUCCESS
) {
1242 } else if (ddi_prop_op(DDI_DEV_T_ANY
, dip
,
1243 PROP_LEN_AND_VAL_ALLOC
, (DDI_PROP_CANSLEEP
|
1244 DDI_PROP_DONTPASS
| DDI_PROP_NOTPROM
),
1245 "pm-reparse-ok", (caddr_t
)&propval
,
1246 &length
) != DDI_SUCCESS
) {
1250 kmem_free(propval
, length
);
1251 ret
= e_new_pm_props(dip
);
1255 case PM_GET_DEVICE_THRESHOLD
:
1258 if (!PM_GET_PM_INFO(dip
) || PM_ISBC(dip
)) {
1260 PMD(PMD_ERROR
, ("ioctl: %s: ENODEV\n",
1265 *rval_p
= DEVI(dip
)->devi_pm_dev_thresh
;
1274 if ((info
= PM_GET_PM_INFO(dip
)) == NULL
) {
1275 PMD(PMD_ERROR
| PMD_DPM
, ("ioctl: %s: "
1276 "ENODEV\n", cmdstr
))
1281 * Check to see if we are there is a dependency on
1282 * this kept device, if so, return EBUSY.
1284 (void) ddi_pathname(dip
, pathbuf
);
1285 pm_dispatch_to_dep_thread(PM_DEP_WK_CHECK_KEPT
,
1286 NULL
, pathbuf
, PM_DEP_WAIT
, &has_dep
, 0);
1288 PMD(PMD_ERROR
| PMD_DPM
, ("%s EBUSY\n",
1294 if (PM_ISDIRECT(dip
) || (info
->pmi_clone
!= 0)) {
1295 PMD(PMD_ERROR
| PMD_DPM
, ("ioctl: %s: "
1296 "%s@%s(%s#%d): EBUSY\n", cmdstr
,
1302 info
->pmi_dev_pm_state
|= PM_DIRECT
;
1303 info
->pmi_clone
= clone
;
1305 PMD(PMD_DPM
, ("ioctl: %s: info %p, pmi_clone %d\n",
1306 cmdstr
, (void *)info
, clone
))
1307 mutex_enter(&pm_clone_lock
);
1308 pm_register_watcher(clone
, dip
);
1309 mutex_exit(&pm_clone_lock
);
1314 case PM_RELEASE_DIRECT_PM
:
1316 if ((info
= PM_GET_PM_INFO(dip
)) == NULL
) {
1317 PMD(PMD_ERROR
| PMD_DPM
, ("ioctl: %s: "
1318 "ENODEV\n", cmdstr
))
1323 if (info
->pmi_clone
!= clone
) {
1324 PMD(PMD_ERROR
| PMD_DPM
, ("ioctl: %s: "
1325 "%s@%s(%s#%d) EINVAL\n", cmdstr
,
1331 ASSERT(PM_ISDIRECT(dip
));
1332 info
->pmi_dev_pm_state
&= ~PM_DIRECT
;
1334 /* Bring ourselves up if there is a keeper. */
1335 (void) ddi_pathname(dip
, pathbuf
);
1336 pm_dispatch_to_dep_thread(PM_DEP_WK_BRINGUP_SELF
,
1337 NULL
, pathbuf
, PM_DEP_WAIT
, NULL
, 0);
1338 pm_discard_entries(clone
);
1339 pm_deregister_watcher(clone
, dip
);
1341 * Now we could let the other threads that are
1342 * trying to do a DIRECT_PM thru
1345 info
->pmi_clone
= 0;
1347 pm_proceed(dip
, PMP_RELEASE
, -1, -1);
1348 PMD(PMD_RESCAN
| PMD_DPM
, ("ioctl: %s: rescan\n",
1355 case PM_SET_CURRENT_POWER
:
1357 int comp
= req
.component
;
1358 int value
= req
.value
;
1359 PMD(PMD_DPM
, ("ioctl: %s: %s component %d to value "
1360 "%d\n", cmdstr
, req
.physpath
, comp
, value
))
1361 if (!e_pm_valid_comp(dip
, comp
, NULL
) ||
1362 !e_pm_valid_power(dip
, comp
, value
)) {
1363 PMD(PMD_ERROR
| PMD_DPM
, ("ioctl: %s: "
1364 "physpath=%s, comp=%d, level=%d, fails\n",
1365 cmdstr
, req
.physpath
, comp
, value
))
1370 if ((info
= PM_GET_PM_INFO(dip
)) == NULL
) {
1371 PMD(PMD_ERROR
| PMD_DPM
, ("ioctl: %s: "
1372 "ENODEV\n", cmdstr
))
1376 if (info
->pmi_clone
!= clone
) {
1377 PMD(PMD_ERROR
| PMD_DPM
, ("ioctl: %s: "
1378 "(not owner) %s fails; clone %d, owner %d"
1379 "\n", cmdstr
, req
.physpath
, clone
,
1384 ASSERT(PM_ISDIRECT(dip
));
1386 if (pm_set_power(dip
, comp
, value
, PM_LEVEL_EXACT
,
1387 PM_CANBLOCK_BLOCK
, 0, &ret
) != DDI_SUCCESS
) {
1388 PMD(PMD_ERROR
| PMD_DPM
, ("ioctl: %s: "
1389 "pm_set_power for %s fails, errno=%d\n",
1390 cmdstr
, req
.physpath
, ret
))
1394 pm_proceed(dip
, PMP_SETPOWER
, comp
, value
);
1397 * Power down all idle components if console framebuffer
1400 if (PM_IS_CFB(dip
) && (pm_system_idle_threshold
==
1401 pm_default_idle_threshold
)) {
1402 dev_info_t
*root
= ddi_root_node();
1404 if (comp
== 0 && value
== 0 &&
1405 (pm_timeout_idledown() != 0)) {
1412 for (i
= 0; i
< PM_NUMCMPTS(dip
); i
++) {
1413 ret
= pm_get_current_power(dip
,
1415 if (ret
== DDI_SUCCESS
&&
1419 if ((count
== PM_NUMCMPTS(dip
)) &&
1420 (pm_timeout_idledown() != 0)) {
1428 PMD(PMD_RESCAN
| PMD_DPM
, ("ioctl: %s: rescan\n",
1436 case PM_GET_FULL_POWER
:
1440 PMD(PMD_NORM
, ("ioctl: %s: %s component %d\n",
1441 cmdstr
, req
.physpath
, req
.component
))
1442 normal
= pm_get_normal_power(dip
, req
.component
);
1444 if (normal
== DDI_FAILURE
) {
1445 PMD(PMD_ERROR
| PMD_NORM
, ("ioctl: %s: "
1446 "returns EINVAL\n", cmdstr
))
1451 PMD(PMD_NORM
, ("ioctl: %s: returns %d\n",
1457 case PM_GET_CURRENT_POWER
:
1459 if (pm_get_current_power(dip
, req
.component
,
1460 rval_p
) != DDI_SUCCESS
) {
1461 PMD(PMD_ERROR
| PMD_DPM
, ("ioctl: %s "
1462 "EINVAL\n", cmdstr
))
1466 PMD(PMD_DPM
, ("ioctl: %s: %s comp %d returns %d\n",
1467 cmdstr
, req
.physpath
, req
.component
, *rval_p
))
1468 if (*rval_p
== PM_LEVEL_UNKNOWN
)
1475 case PM_GET_TIME_IDLE
:
1478 int comp
= req
.component
;
1480 if (!e_pm_valid_comp(dip
, comp
, &cp
)) {
1481 PMD(PMD_ERROR
, ("ioctl: %s: %s@%s(%s#%d) "
1482 "component %d > numcmpts - 1 %d--EINVAL\n",
1483 cmdstr
, PM_DEVICE(dip
), comp
,
1484 PM_NUMCMPTS(dip
) - 1))
1488 timestamp
= cp
->pmc_timestamp
;
1491 (void) drv_getparm(TIME
, &now
);
1492 *rval_p
= (now
- timestamp
);
1500 case PM_ADD_DEPENDENT
:
1502 dev_info_t
*kept_dip
;
1504 PMD(PMD_KEEPS
, ("%s, kept %s, keeper %s\n", cmdstr
,
1508 * hold and install kept while processing dependency
1509 * keeper (in .physpath) has already been held.
1511 if (dep
[0] == '\0') {
1512 PMD(PMD_ERROR
, ("kept NULL or null\n"))
1515 } else if ((kept_dip
=
1516 pm_name_to_dip(dep
, 1)) == NULL
) {
1517 PMD(PMD_ERROR
, ("no dip for kept %s\n", dep
))
1520 } else if (kept_dip
== dip
) {
1521 PMD(PMD_ERROR
, ("keeper(%s, %p) - kept(%s, %p) "
1522 "self-dependency not allowed.\n",
1523 dep
, (void *)kept_dip
, req
.physpath
,
1525 PM_RELE(dip
); /* release "double" hold */
1529 ASSERT(!(strcmp(req
.physpath
, (char *)dep
) == 0));
1532 * record dependency, then walk through device tree
1533 * independently on behalf of kept and keeper to
1534 * establish newly created dependency.
1536 pm_dispatch_to_dep_thread(PM_DEP_WK_RECORD_KEEPER
,
1537 req
.physpath
, dep
, PM_DEP_WAIT
, NULL
, 0);
1540 * release kept after establishing dependency, keeper
1541 * is released as part of ioctl exit processing.
1549 case PM_ADD_DEPENDENT_PROPERTY
:
1551 char *keeper
, *kept
;
1553 if (dep
[0] == '\0') {
1554 PMD(PMD_ERROR
, ("ioctl: %s: dep NULL or "
1560 keeper
= req
.physpath
;
1562 * record keeper - kept dependency, then walk through
1563 * device tree to find out all attached keeper, walk
1564 * through again to apply dependency to all the
1567 pm_dispatch_to_dep_thread(
1568 PM_DEP_WK_RECORD_KEEPER_PROP
, keeper
, kept
,
1569 PM_DEP_WAIT
, NULL
, 0);
1576 case PM_SET_DEVICE_THRESHOLD
:
1578 pm_thresh_rec_t
*rp
;
1579 pm_pte_t
*ep
; /* threshold header storage */
1580 int *tp
; /* threshold storage */
1582 extern int pm_thresh_specd(dev_info_t
*);
1585 * The header struct plus one entry struct plus one
1586 * threshold plus the length of the string
1588 size
= sizeof (pm_thresh_rec_t
) +
1589 (sizeof (pm_pte_t
) * 1) +
1590 (1 * sizeof (int)) +
1591 strlen(req
.physpath
) + 1;
1593 rp
= kmem_zalloc(size
, KM_SLEEP
);
1594 rp
->ptr_size
= size
;
1595 rp
->ptr_numcomps
= 0; /* means device threshold */
1596 ep
= (pm_pte_t
*)((intptr_t)rp
+ sizeof (*rp
));
1597 rp
->ptr_entries
= ep
;
1598 tp
= (int *)((intptr_t)ep
+
1599 (1 * sizeof (pm_pte_t
)));
1600 ep
->pte_numthresh
= 1;
1601 ep
->pte_thresh
= tp
;
1603 (void) strcat((char *)tp
, req
.physpath
);
1604 rp
->ptr_physpath
= (char *)tp
;
1605 ASSERT((intptr_t)tp
+ strlen(req
.physpath
) + 1 ==
1606 (intptr_t)rp
+ rp
->ptr_size
);
1607 PMD(PMD_THRESH
, ("ioctl: %s: record thresh %d for "
1608 "%s\n", cmdstr
, req
.value
, req
.physpath
))
1609 pm_record_thresh(rp
);
1611 * Don't free rp, pm_record_thresh() keeps it.
1612 * We don't try to apply it ourselves because we'd need
1613 * to know too much about locking. Since we don't
1614 * hold a lock the entry could be removed before
1617 ASSERT(dip
== NULL
);
1618 ret
= 0; /* can't fail now */
1619 if (!(dip
= pm_name_to_dip(req
.physpath
, 1))) {
1622 (void) pm_thresh_specd(dip
);
1623 PMD(PMD_DHR
, ("ioctl: %s: releasing %s@%s(%s#%d)\n",
1624 cmdstr
, PM_DEVICE(dip
)))
1629 case PM_RESET_DEVICE_THRESHOLD
:
1632 * This only applies to a currently attached and power
1636 * We don't do this to old-style drivers
1638 info
= PM_GET_PM_INFO(dip
);
1640 PMD(PMD_ERROR
, ("ioctl: %s: %s not power "
1641 "managed\n", cmdstr
, req
.physpath
))
1646 PMD(PMD_ERROR
, ("ioctl: %s: %s is BC\n",
1647 cmdstr
, req
.physpath
))
1651 pm_unrecord_threshold(req
.physpath
);
1652 if (DEVI(dip
)->devi_pm_flags
& PMC_CPU_THRESH
)
1653 pm_set_device_threshold(dip
,
1654 pm_cpu_idle_threshold
, PMC_CPU_THRESH
);
1656 pm_set_device_threshold(dip
,
1657 pm_system_idle_threshold
, PMC_DEF_THRESH
);
1662 case PM_GET_NUM_COMPONENTS
:
1665 *rval_p
= PM_NUMCMPTS(dip
);
1669 case PM_GET_DEVICE_TYPE
:
1672 if ((info
= PM_GET_PM_INFO(dip
)) == NULL
) {
1673 PMD(PMD_ERROR
, ("ioctl: %s: "
1674 "PM_NO_PM_COMPONENTS\n", cmdstr
))
1675 *rval_p
= PM_NO_PM_COMPONENTS
;
1679 *rval_p
= PM_CREATE_COMPONENTS
;
1681 *rval_p
= PM_AUTOPM
;
1686 case PM_SET_COMPONENT_THRESHOLDS
:
1689 int *end
= (int *)req
.data
+ icount
;
1690 pm_thresh_rec_t
*rp
;
1691 pm_pte_t
*ep
; /* threshold header storage */
1692 int *tp
; /* threshold storage */
1696 extern int pm_thresh_specd(dev_info_t
*);
1697 extern int pm_valid_thresh(dev_info_t
*,
1700 for (ip
= req
.data
; *ip
; ip
++) {
1706 /* skip over indicated number of entries */
1707 for (j
= *ip
; j
; j
--) {
1718 if ((intptr_t)ip
!= (intptr_t)end
- sizeof (int)) {
1719 /* did not exactly fill buffer */
1724 PMD(PMD_ERROR
, ("ioctl: %s: %s 0 components"
1725 "--EINVAL\n", cmdstr
, req
.physpath
))
1730 * The header struct plus one entry struct per component
1731 * plus the size of the lists minus the counts
1732 * plus the length of the string
1734 size
= sizeof (pm_thresh_rec_t
) +
1735 (sizeof (pm_pte_t
) * comps
) + req
.datasize
-
1736 ((comps
+ 1) * sizeof (int)) +
1737 strlen(req
.physpath
) + 1;
1739 rp
= kmem_zalloc(size
, KM_SLEEP
);
1740 rp
->ptr_size
= size
;
1741 rp
->ptr_numcomps
= comps
;
1742 ep
= (pm_pte_t
*)((intptr_t)rp
+ sizeof (*rp
));
1743 rp
->ptr_entries
= ep
;
1744 tp
= (int *)((intptr_t)ep
+
1745 (comps
* sizeof (pm_pte_t
)));
1746 for (ip
= req
.data
; *ip
; ep
++) {
1747 ep
->pte_numthresh
= *ip
;
1748 ep
->pte_thresh
= tp
;
1749 for (j
= *ip
++; j
; j
--) {
1753 (void) strcat((char *)tp
, req
.physpath
);
1754 rp
->ptr_physpath
= (char *)tp
;
1755 ASSERT((intptr_t)end
== (intptr_t)ip
+ sizeof (int));
1756 ASSERT((intptr_t)tp
+ strlen(req
.physpath
) + 1 ==
1757 (intptr_t)rp
+ rp
->ptr_size
);
1759 ASSERT(dip
== NULL
);
1761 * If this is not a currently power managed node,
1762 * then we can't check for validity of the thresholds
1764 if (!(dip
= pm_name_to_dip(req
.physpath
, 1))) {
1765 /* don't free rp, pm_record_thresh uses it */
1766 pm_record_thresh(rp
);
1767 PMD(PMD_ERROR
, ("ioctl: %s: pm_name_to_dip "
1768 "for %s failed\n", cmdstr
, req
.physpath
))
1775 if (!pm_valid_thresh(dip
, rp
)) {
1776 PMD(PMD_ERROR
, ("ioctl: %s: invalid thresh "
1777 "for %s@%s(%s#%d)\n", cmdstr
,
1779 kmem_free(rp
, size
);
1784 * We don't just apply it ourselves because we'd need
1785 * to know too much about locking. Since we don't
1786 * hold a lock the entry could be removed before
1789 pm_record_thresh(rp
);
1790 (void) pm_thresh_specd(dip
);
1795 case PM_GET_COMPONENT_THRESHOLDS
:
1798 int numthresholds
= 0;
1801 caddr_t uaddr
= req
.data
; /* user address */
1802 int val
; /* int value to be copied out */
1803 int32_t val32
; /* int32 value to be copied out */
1804 caddr_t vaddr
; /* address to copyout from */
1807 #ifdef _MULTI_DATAMODEL
1808 if ((mode
& DATAMODEL_MASK
) == DATAMODEL_ILP32
) {
1809 wordsize
= sizeof (int32_t);
1811 #endif /* _MULTI_DATAMODEL */
1813 wordsize
= sizeof (int);
1818 numcomps
= PM_NUMCMPTS(dip
);
1819 for (i
= 0; i
< numcomps
; i
++) {
1821 numthresholds
+= cp
->pmc_comp
.pmc_numlevels
- 1;
1823 musthave
= (numthresholds
+ numcomps
+ 1) * wordsize
;
1824 if (req
.datasize
< musthave
) {
1825 PMD(PMD_ERROR
, ("ioctl: %s: size %ld, need "
1826 "%d--EINVAL\n", cmdstr
, req
.datasize
,
1832 for (i
= 0; i
< numcomps
; i
++) {
1835 thp
= cp
->pmc_comp
.pmc_thresh
;
1836 /* first copyout the count */
1837 if (wordsize
== sizeof (int32_t)) {
1838 val32
= cp
->pmc_comp
.pmc_numlevels
- 1;
1839 vaddr
= (caddr_t
)&val32
;
1841 val
= cp
->pmc_comp
.pmc_numlevels
- 1;
1842 vaddr
= (caddr_t
)&val
;
1844 if (ddi_copyout(vaddr
, (void *)uaddr
,
1845 wordsize
, mode
) != 0) {
1847 PMD(PMD_ERROR
, ("ioctl: %s: %s@%s"
1848 "(%s#%d) vaddr %p EFAULT\n",
1849 cmdstr
, PM_DEVICE(dip
),
1856 uaddr
= (caddr_t
)vaddr
;
1857 /* then copyout each threshold value */
1858 for (j
= 0; j
< cp
->pmc_comp
.pmc_numlevels
- 1;
1860 if (wordsize
== sizeof (int32_t)) {
1862 vaddr
= (caddr_t
)&val32
;
1865 vaddr
= (caddr_t
)&val
;
1867 if (ddi_copyout(vaddr
, (void *) uaddr
,
1868 wordsize
, mode
) != 0) {
1870 PMD(PMD_ERROR
, ("ioctl: %s: "
1871 "%s@%s(%s#%d) uaddr %p "
1880 uaddr
= (caddr_t
)vaddr
;
1885 /* last copyout a terminating 0 count */
1886 if (wordsize
== sizeof (int32_t)) {
1888 vaddr
= (caddr_t
)&val32
;
1890 ASSERT(wordsize
== sizeof (int));
1892 vaddr
= (caddr_t
)&val
;
1894 if (ddi_copyout(vaddr
, uaddr
, wordsize
, mode
) != 0) {
1896 PMD(PMD_ERROR
, ("ioctl: %s: %s@%s(%s#%d) "
1897 "vaddr %p (0 count) EFAULT\n", cmdstr
,
1898 PM_DEVICE(dip
), (void *)vaddr
))
1902 /* finished, so don't need to increment addresses */
1912 extern int pm_cur_power(pm_component_t
*cp
);
1916 #ifdef _MULTI_DATAMODEL
1917 if ((mode
& DATAMODEL_MASK
) == DATAMODEL_ILP32
) {
1918 wordsize
= sizeof (int32_t);
1920 #endif /* _MULTI_DATAMODEL */
1922 wordsize
= sizeof (int);
1925 comps
= PM_NUMCMPTS(dip
);
1926 if (comps
== 0 || PM_GET_PM_INFO(dip
) == NULL
) {
1927 PMD(PMD_ERROR
, ("ioctl: %s: %s no components"
1928 " or not power managed--EINVAL\n", cmdstr
,
1933 musthave
= comps
* 2 * wordsize
;
1934 if (req
.datasize
< musthave
) {
1935 PMD(PMD_ERROR
, ("ioctl: %s: size %lu, need "
1936 "%d--EINVAL\n", cmdstr
, req
.datasize
,
1943 (void) drv_getparm(TIME
, &now
);
1944 timestamp
= kmem_zalloc(comps
* sizeof (time_t),
1946 pm_get_timestamps(dip
, timestamp
);
1948 * First the current power levels
1950 for (i
= 0; i
< comps
; i
++) {
1956 if (wordsize
== sizeof (int)) {
1957 curpwr
= pm_cur_power(cp
);
1958 cpaddr
= (caddr_t
)&curpwr
;
1960 ASSERT(wordsize
== sizeof (int32_t));
1961 curpwr32
= pm_cur_power(cp
);
1962 cpaddr
= (caddr_t
)&curpwr32
;
1964 if (ddi_copyout(cpaddr
, (void *) req
.data
,
1965 wordsize
, mode
) != 0) {
1967 PMD(PMD_ERROR
, ("ioctl: %s: %s@%s"
1968 "(%s#%d) req.data %p EFAULT\n",
1969 cmdstr
, PM_DEVICE(dip
),
1974 cpaddr
= (caddr_t
)req
.data
;
1979 * Then the times remaining
1981 for (i
= 0; i
< comps
; i
++) {
1988 curpwr
= cp
->pmc_cur_pwr
;
1989 if (curpwr
== 0 || timestamp
[i
] == 0) {
1990 PMD(PMD_STATS
, ("ioctl: %s: "
1991 "cur_pwer %x, timestamp %lx\n",
1992 cmdstr
, curpwr
, timestamp
[i
]))
1996 (void) pm_current_threshold(dip
, i
,
1998 retval
= thresh
- (now
- timestamp
[i
]);
1999 PMD(PMD_STATS
, ("ioctl: %s: current "
2000 "thresh %x, now %lx, timestamp %lx,"
2001 " retval %x\n", cmdstr
, thresh
, now
,
2002 timestamp
[i
], retval
))
2004 if (wordsize
== sizeof (int)) {
2005 rvaddr
= (caddr_t
)&retval
;
2007 ASSERT(wordsize
== sizeof (int32_t));
2009 rvaddr
= (caddr_t
)&retval32
;
2011 if (ddi_copyout(rvaddr
, (void *) req
.data
,
2012 wordsize
, mode
) != 0) {
2014 PMD(PMD_ERROR
, ("ioctl: %s: %s@%s"
2015 "(%s#%d) req.data %p EFAULT\n",
2016 cmdstr
, PM_DEVICE(dip
),
2019 kmem_free(timestamp
,
2020 comps
* sizeof (time_t));
2023 rvaddr
= (caddr_t
)req
.data
;
2025 req
.data
= (int *)rvaddr
;
2030 kmem_free(timestamp
, comps
* sizeof (time_t));
2034 case PM_GET_CMD_NAME
:
2036 PMD(PMD_IOCTL
, ("%s: %s\n", cmdstr
,
2037 pm_decode_cmd(req
.value
)))
2038 if (ret
= copyoutstr(pm_decode_cmd(req
.value
),
2039 (char *)req
.data
, req
.datasize
, &lencopied
)) {
2040 PMD(PMD_ERROR
, ("ioctl: %s: %s@%s(%s#%d) "
2041 "copyoutstr %p failed--EFAULT\n", cmdstr
,
2042 PM_DEVICE(dip
), (void *)req
.data
))
2045 *rval_p
= lencopied
;
2050 case PM_GET_COMPONENT_NAME
:
2053 if (!e_pm_valid_comp(dip
, req
.component
, &cp
)) {
2054 PMD(PMD_ERROR
, ("ioctl: %s: %s@%s(%s#%d) "
2055 "component %d > numcmpts - 1 %d--EINVAL\n",
2056 cmdstr
, PM_DEVICE(dip
), req
.component
,
2057 PM_NUMCMPTS(dip
) - 1))
2061 if (ret
= copyoutstr(cp
->pmc_comp
.pmc_name
,
2062 (char *)req
.data
, req
.datasize
, &lencopied
)) {
2063 PMD(PMD_ERROR
, ("ioctl: %s: %s@%s(%s#%d) "
2064 "copyoutstr %p failed--EFAULT\n", cmdstr
,
2065 PM_DEVICE(dip
), (void *)req
.data
))
2068 *rval_p
= lencopied
;
2073 case PM_GET_POWER_NAME
:
2078 if (!e_pm_valid_comp(dip
, req
.component
, &cp
)) {
2079 PMD(PMD_ERROR
, ("ioctl: %s: %s@%s(%s#%d) "
2080 "component %d > numcmpts - 1 %d--EINVAL\n",
2081 cmdstr
, PM_DEVICE(dip
), req
.component
,
2082 PM_NUMCMPTS(dip
) - 1))
2086 if ((i
= req
.value
) < 0 ||
2087 i
> cp
->pmc_comp
.pmc_numlevels
- 1) {
2088 PMD(PMD_ERROR
, ("ioctl: %s: %s@%s(%s#%d) "
2089 "value %d > num_levels - 1 %d--EINVAL\n",
2090 cmdstr
, PM_DEVICE(dip
), req
.value
,
2091 cp
->pmc_comp
.pmc_numlevels
- 1))
2095 dep
= cp
->pmc_comp
.pmc_lnames
[req
.value
];
2096 if (ret
= copyoutstr(dep
,
2097 req
.data
, req
.datasize
, &lencopied
)) {
2098 PMD(PMD_ERROR
, ("ioctl: %s: %s@%s(%s#%d) "
2099 "copyoutstr %p failed--EFAULT\n", cmdstr
,
2100 PM_DEVICE(dip
), (void *)req
.data
))
2103 *rval_p
= lencopied
;
2108 case PM_GET_POWER_LEVELS
:
2114 #ifdef _MULTI_DATAMODEL
2115 if ((mode
& DATAMODEL_MASK
) == DATAMODEL_ILP32
) {
2116 wordsize
= sizeof (int32_t);
2118 #endif /* _MULTI_DATAMODEL */
2120 wordsize
= sizeof (int);
2124 if (!e_pm_valid_comp(dip
, req
.component
, &cp
)) {
2125 PMD(PMD_ERROR
, ("ioctl: %s: %s@%s(%s#%d) "
2126 "has %d components, component %d requested"
2127 "--EINVAL\n", cmdstr
, PM_DEVICE(dip
),
2128 PM_NUMCMPTS(dip
), req
.component
))
2132 numlevels
= cp
->pmc_comp
.pmc_numlevels
;
2133 musthave
= numlevels
* wordsize
;
2134 if (req
.datasize
< musthave
) {
2135 PMD(PMD_ERROR
, ("ioctl: %s: size %lu, need "
2136 "%d--EINVAL\n", cmdstr
, req
.datasize
,
2142 for (i
= 0; i
< numlevels
; i
++) {
2147 if (wordsize
== sizeof (int)) {
2148 level
= cp
->pmc_comp
.pmc_lvals
[i
];
2149 laddr
= (caddr_t
)&level
;
2151 level32
= cp
->pmc_comp
.pmc_lvals
[i
];
2152 laddr
= (caddr_t
)&level32
;
2154 if (ddi_copyout(laddr
, (void *) req
.data
,
2155 wordsize
, mode
) != 0) {
2157 PMD(PMD_ERROR
, ("ioctl: %s: %s@%s"
2158 "(%s#%d) laddr %p EFAULT\n",
2159 cmdstr
, PM_DEVICE(dip
),
2164 laddr
= (caddr_t
)req
.data
;
2166 req
.data
= (int *)laddr
;
2169 *rval_p
= numlevels
;
2175 case PM_GET_NUM_POWER_LEVELS
:
2177 if (!e_pm_valid_comp(dip
, req
.component
, &cp
)) {
2178 PMD(PMD_ERROR
, ("ioctl: %s: %s@%s(%s#%d) "
2179 "component %d > numcmpts - 1 %d--EINVAL\n",
2180 cmdstr
, PM_DEVICE(dip
), req
.component
,
2181 PM_NUMCMPTS(dip
) - 1))
2185 *rval_p
= cp
->pmc_comp
.pmc_numlevels
;
2190 case PM_GET_DEVICE_THRESHOLD_BASIS
:
2194 if ((info
= PM_GET_PM_INFO(dip
)) == NULL
) {
2196 PMD(PMD_ERROR
, ("ioctl: %s: "
2197 "PM_NO_PM_COMPONENTS\n", cmdstr
))
2198 *rval_p
= PM_NO_PM_COMPONENTS
;
2201 if (PM_ISDIRECT(dip
)) {
2203 *rval_p
= PM_DIRECTLY_MANAGED
;
2206 switch (DEVI(dip
)->devi_pm_flags
& PMC_THRESH_ALL
) {
2207 case PMC_DEF_THRESH
:
2208 case PMC_NEXDEF_THRESH
:
2209 *rval_p
= PM_DEFAULT_THRESHOLD
;
2211 case PMC_DEV_THRESH
:
2212 *rval_p
= PM_DEVICE_THRESHOLD
;
2214 case PMC_COMP_THRESH
:
2215 *rval_p
= PM_COMPONENT_THRESHOLD
;
2217 case PMC_CPU_THRESH
:
2218 *rval_p
= PM_CPU_THRESHOLD
;
2222 *rval_p
= PM_OLD_THRESHOLD
;
2225 PMD(PMD_ERROR
, ("ioctl: %s: default, not "
2226 "BC--EINVAL", cmdstr
))
2235 * Internal error, invalid ioctl description
2236 * force debug entry even if pm_debug not set
2239 pm_log("invalid diptype %d for cmd %d (%s)\n",
2240 pcip
->diptype
, cmd
, pcip
->name
);
2251 * Commands that require pm_state_change_t as arg
2253 #ifdef _MULTI_DATAMODEL
2254 if ((mode
& DATAMODEL_MASK
) == DATAMODEL_ILP32
) {
2255 pscp32
= (pm_state_change32_t
*)arg
;
2256 if (ddi_copyin((caddr_t
)arg
, &psc32
,
2257 sizeof (psc32
), mode
) != 0) {
2258 PMD(PMD_ERROR
, ("ioctl: %s: ddi_copyin "
2259 "EFAULT\n\n", cmdstr
))
2263 psc
.physpath
= (caddr_t
)(uintptr_t)psc32
.physpath
;
2264 psc
.size
= psc32
.size
;
2266 #endif /* _MULTI_DATAMODEL */
2268 pscp
= (pm_state_change_t
*)arg
;
2269 if (ddi_copyin((caddr_t
)arg
, &psc
,
2270 sizeof (psc
), mode
) != 0) {
2271 PMD(PMD_ERROR
, ("ioctl: %s: ddi_copyin "
2272 "EFAULT\n\n", cmdstr
))
2279 case PM_GET_STATE_CHANGE
:
2280 case PM_GET_STATE_CHANGE_WAIT
:
2283 pm_state_change_t
*p
;
2288 * We want to know if any device has changed state.
2289 * We look up by clone. In case we have another thread
2290 * from the same process, we loop.
2291 * pm_psc_clone_to_interest() returns a locked entry.
2292 * We create an internal copy of the event entry prior
2293 * to copyout to user space because we don't want to
2294 * hold the psce_lock while doing copyout as we might
2295 * hit page fault which eventually brings us back
2296 * here requesting the same lock.
2298 mutex_enter(&pm_clone_lock
);
2299 if (!pm_interest_registered(clone
))
2300 pm_register_watcher(clone
, NULL
);
2302 pm_psc_clone_to_interest(clone
)) == NULL
) {
2303 if (cmd
== PM_GET_STATE_CHANGE
) {
2304 PMD(PMD_IOCTL
, ("ioctl: %s: "
2305 "EWOULDBLOCK\n", cmdstr
))
2306 mutex_exit(&pm_clone_lock
);
2308 return (EWOULDBLOCK
);
2310 if (cv_wait_sig(&pm_clones_cv
[clone
],
2311 &pm_clone_lock
) == 0) {
2312 mutex_exit(&pm_clone_lock
);
2313 PMD(PMD_ERROR
, ("ioctl: %s "
2320 mutex_exit(&pm_clone_lock
);
2322 physlen
= pscep
->psce_out
->size
;
2325 * If we were unable to store the path while bringing
2326 * up the console fb upon entering the prom, we give
2327 * a "" name with the overrun event set
2329 if (physlen
== (size_t)-1) { /* kmemalloc failed */
2330 physpath
= kmem_zalloc(1, KM_SLEEP
);
2333 if ((psc
.physpath
== NULL
) || (psc
.size
< physlen
)) {
2334 PMD(PMD_ERROR
, ("ioctl: %s: EFAULT\n", cmdstr
))
2335 mutex_exit(&pscep
->psce_lock
);
2339 if (physpath
== NULL
) {
2340 physpath
= kmem_zalloc(physlen
, KM_SLEEP
);
2341 bcopy((const void *) pscep
->psce_out
->physpath
,
2342 (void *) physpath
, physlen
);
2345 p
= pscep
->psce_out
;
2346 #ifdef _MULTI_DATAMODEL
2347 if ((mode
& DATAMODEL_MASK
) == DATAMODEL_ILP32
) {
2351 psc32
.flags
= (ushort_t
)p
->flags
;
2352 psc32
.event
= (ushort_t
)p
->event
;
2353 psc32
.timestamp
= (int32_t)p
->timestamp
;
2354 psc32
.component
= (int32_t)p
->component
;
2355 psc32
.old_level
= (int32_t)p
->old_level
;
2356 psc32
.new_level
= (int32_t)p
->new_level
;
2357 copysize32
= ((intptr_t)&psc32
.size
-
2358 (intptr_t)&psc32
.component
);
2360 usrcopysize
= ((intptr_t)&pscp32
->size
-
2361 (intptr_t)&pscp32
->component
);
2362 ASSERT(usrcopysize
== copysize32
);
2365 #endif /* _MULTI_DATAMODEL */
2367 psc
.flags
= p
->flags
;
2368 psc
.event
= p
->event
;
2369 psc
.timestamp
= p
->timestamp
;
2370 psc
.component
= p
->component
;
2371 psc
.old_level
= p
->old_level
;
2372 psc
.new_level
= p
->new_level
;
2373 copysize
= ((long)&p
->size
-
2374 (long)&p
->component
);
2376 if (p
->size
!= (size_t)-1)
2377 kmem_free(p
->physpath
, p
->size
);
2380 if (pscep
->psce_out
== pscep
->psce_last
)
2381 p
= pscep
->psce_first
;
2384 pscep
->psce_out
= p
;
2385 mutex_exit(&pscep
->psce_lock
);
2387 ret
= copyoutstr(physpath
, psc
.physpath
,
2388 physlen
, &lencopied
);
2389 kmem_free(physpath
, physlen
);
2391 PMD(PMD_ERROR
, ("ioctl: %s: copyoutstr %p "
2392 "failed--EFAULT\n", cmdstr
,
2393 (void *)psc
.physpath
))
2397 #ifdef _MULTI_DATAMODEL
2398 if ((mode
& DATAMODEL_MASK
) == DATAMODEL_ILP32
) {
2399 if (ddi_copyout(&psc32
.component
,
2400 &pscp32
->component
, copysize32
, mode
)
2402 PMD(PMD_ERROR
, ("ioctl: %s: copyout "
2403 "failed--EFAULT\n", cmdstr
))
2408 #endif /* _MULTI_DATAMODEL */
2410 if (ddi_copyout(&psc
.component
,
2411 &pscp
->component
, copysize
, mode
) != 0) {
2412 PMD(PMD_ERROR
, ("ioctl: %s: copyout "
2413 "failed--EFAULT\n", cmdstr
))
2422 case PM_DIRECT_NOTIFY
:
2423 case PM_DIRECT_NOTIFY_WAIT
:
2426 pm_state_change_t
*p
;
2430 * We want to know if any direct device of ours has
2431 * something we should know about. We look up by clone.
2432 * In case we have another thread from the same process,
2434 * pm_psc_clone_to_direct() returns a locked entry.
2436 mutex_enter(&pm_clone_lock
);
2437 while (pm_poll_cnt
[clone
] == 0 ||
2438 (pscep
= pm_psc_clone_to_direct(clone
)) == NULL
) {
2439 if (cmd
== PM_DIRECT_NOTIFY
) {
2440 PMD(PMD_IOCTL
, ("ioctl: %s: "
2441 "EWOULDBLOCK\n", cmdstr
))
2442 mutex_exit(&pm_clone_lock
);
2444 return (EWOULDBLOCK
);
2446 if (cv_wait_sig(&pm_clones_cv
[clone
],
2447 &pm_clone_lock
) == 0) {
2448 mutex_exit(&pm_clone_lock
);
2449 PMD(PMD_ERROR
, ("ioctl: %s: "
2456 mutex_exit(&pm_clone_lock
);
2457 physlen
= pscep
->psce_out
->size
;
2458 if ((psc
.physpath
== NULL
) || (psc
.size
< physlen
)) {
2459 mutex_exit(&pscep
->psce_lock
);
2460 PMD(PMD_ERROR
, ("ioctl: %s: EFAULT\n",
2465 physpath
= kmem_zalloc(physlen
, KM_SLEEP
);
2466 bcopy((const void *) pscep
->psce_out
->physpath
,
2467 (void *) physpath
, physlen
);
2469 p
= pscep
->psce_out
;
2470 #ifdef _MULTI_DATAMODEL
2471 if ((mode
& DATAMODEL_MASK
) == DATAMODEL_ILP32
) {
2475 psc32
.component
= (int32_t)p
->component
;
2476 psc32
.flags
= (ushort_t
)p
->flags
;
2477 psc32
.event
= (ushort_t
)p
->event
;
2478 psc32
.timestamp
= (int32_t)p
->timestamp
;
2479 psc32
.old_level
= (int32_t)p
->old_level
;
2480 psc32
.new_level
= (int32_t)p
->new_level
;
2481 copysize32
= (intptr_t)&psc32
.size
-
2482 (intptr_t)&psc32
.component
;
2483 PMD(PMD_DPM
, ("ioctl: %s: PDN32 %s, comp %d "
2484 "%d -> %d\n", cmdstr
, physpath
,
2485 p
->component
, p
->old_level
, p
->new_level
))
2487 usrcopysize
= (intptr_t)&pscp32
->size
-
2488 (intptr_t)&pscp32
->component
;
2489 ASSERT(usrcopysize
== copysize32
);
2494 psc
.component
= p
->component
;
2495 psc
.flags
= p
->flags
;
2496 psc
.event
= p
->event
;
2497 psc
.timestamp
= p
->timestamp
;
2498 psc
.old_level
= p
->old_level
;
2499 psc
.new_level
= p
->new_level
;
2500 copysize
= (intptr_t)&p
->size
-
2501 (intptr_t)&p
->component
;
2502 PMD(PMD_DPM
, ("ioctl: %s: PDN %s, comp %d "
2503 "%d -> %d\n", cmdstr
, physpath
,
2504 p
->component
, p
->old_level
, p
->new_level
))
2506 mutex_enter(&pm_clone_lock
);
2507 PMD(PMD_IOCTL
, ("ioctl: %s: pm_poll_cnt[%d] is %d "
2508 "before decrement\n", cmdstr
, clone
,
2509 pm_poll_cnt
[clone
]))
2510 pm_poll_cnt
[clone
]--;
2511 mutex_exit(&pm_clone_lock
);
2512 kmem_free(p
->physpath
, p
->size
);
2515 if (pscep
->psce_out
== pscep
->psce_last
)
2516 p
= pscep
->psce_first
;
2519 pscep
->psce_out
= p
;
2520 mutex_exit(&pscep
->psce_lock
);
2522 ret
= copyoutstr(physpath
, psc
.physpath
,
2523 physlen
, &lencopied
);
2524 kmem_free(physpath
, physlen
);
2526 PMD(PMD_ERROR
, ("ioctl: %s: copyoutstr %p "
2527 "failed--EFAULT\n", cmdstr
,
2528 (void *)psc
.physpath
))
2532 #ifdef _MULTI_DATAMODEL
2533 if ((mode
& DATAMODEL_MASK
) == DATAMODEL_ILP32
) {
2534 if (ddi_copyout(&psc32
.component
,
2535 &pscp32
->component
, copysize32
, mode
)
2537 PMD(PMD_ERROR
, ("ioctl: %s: copyout "
2538 "failed--EFAULT\n", cmdstr
))
2543 #endif /* _MULTI_DATAMODEL */
2545 if (ddi_copyout(&psc
.component
,
2546 &pscp
->component
, copysize
, mode
) != 0) {
2547 PMD(PMD_ERROR
, ("ioctl: %s: copyout "
2548 "failed--EFAULT\n", cmdstr
))
2558 * Internal error, invalid ioctl description
2559 * force debug entry even if pm_debug not set
2562 pm_log("invalid diptype %d for cmd %d (%s)\n",
2563 pcip
->diptype
, cmd
, pcip
->name
);
2571 case PM_SRCH
: /* command that takes a pm_searchargs_t arg */
2574 * If no ppm, then there is nothing to search.
2576 if (DEVI(ddi_root_node())->devi_pm_ppm
== NULL
) {
2581 #ifdef _MULTI_DATAMODEL
2582 if ((mode
& DATAMODEL_MASK
) == DATAMODEL_ILP32
) {
2583 if (ddi_copyin((caddr_t
)arg
, &psa32
,
2584 sizeof (psa32
), mode
) != 0) {
2585 PMD(PMD_ERROR
, ("ioctl: %s: ddi_copyin "
2586 "EFAULT\n\n", cmdstr
))
2589 if (copyinstr((void *)(uintptr_t)psa32
.pms_listname
,
2590 listname
, MAXCOPYBUF
, NULL
)) {
2591 PMD(PMD_ERROR
, ("ioctl: %s: 0x%p MAXCOPYBUF "
2592 "%d, " "EFAULT\n", cmdstr
,
2593 (void *)(uintptr_t)psa32
.pms_listname
,
2598 if (copyinstr((void *)(uintptr_t)psa32
.pms_manufacturer
,
2599 manufacturer
, MAXCOPYBUF
, NULL
)) {
2600 PMD(PMD_ERROR
, ("ioctl: %s: 0x%p MAXCOPYBUF "
2601 "%d, " "EFAULT\n", cmdstr
,
2602 (void *)(uintptr_t)psa32
.pms_manufacturer
,
2607 if (copyinstr((void *)(uintptr_t)psa32
.pms_product
,
2608 product
, MAXCOPYBUF
, NULL
)) {
2609 PMD(PMD_ERROR
, ("ioctl: %s: 0x%p MAXCOPYBUF "
2610 "%d, " "EFAULT\n", cmdstr
,
2611 (void *)(uintptr_t)psa32
.pms_product
,
2617 #endif /* _MULTI_DATAMODEL */
2619 if (ddi_copyin((caddr_t
)arg
, &psa
,
2620 sizeof (psa
), mode
) != 0) {
2621 PMD(PMD_ERROR
, ("ioctl: %s: ddi_copyin "
2622 "EFAULT\n\n", cmdstr
))
2625 if (copyinstr(psa
.pms_listname
,
2626 listname
, MAXCOPYBUF
, NULL
)) {
2627 PMD(PMD_ERROR
, ("ioctl: %s: 0x%p MAXCOPYBUF "
2628 "%d, " "EFAULT\n", cmdstr
,
2629 (void *)psa
.pms_listname
, MAXCOPYBUF
))
2633 if (copyinstr(psa
.pms_manufacturer
,
2634 manufacturer
, MAXCOPYBUF
, NULL
)) {
2635 PMD(PMD_ERROR
, ("ioctl: %s: 0x%p MAXCOPYBUF "
2636 "%d, " "EFAULT\n", cmdstr
,
2637 (void *)psa
.pms_manufacturer
, MAXCOPYBUF
))
2641 if (copyinstr(psa
.pms_product
,
2642 product
, MAXCOPYBUF
, NULL
)) {
2643 PMD(PMD_ERROR
, ("ioctl: %s: 0x%p MAXCOPYBUF "
2644 "%d, " "EFAULT\n", cmdstr
,
2645 (void *)psa
.pms_product
, MAXCOPYBUF
))
2650 psa
.pms_listname
= listname
;
2651 psa
.pms_manufacturer
= manufacturer
;
2652 psa
.pms_product
= product
;
2654 case PM_SEARCH_LIST
:
2655 ret
= pm_ppm_searchlist(&psa
);
2660 * Internal error, invalid ioctl description
2661 * force debug entry even if pm_debug not set
2664 pm_log("invalid diptype %d for cmd %d (%s)\n",
2665 pcip
->diptype
, cmd
, pcip
->name
);
2677 case PM_START_CPUPM
:
2678 case PM_START_CPUPM_EV
:
2679 case PM_START_CPUPM_POLL
:
2681 pm_cpupm_t new_mode
= PM_CPUPM_NOTSET
;
2682 pm_cpupm_t old_mode
= PM_CPUPM_NOTSET
;
2685 mutex_enter(&pm_scan_lock
);
2686 if ((cmd
== PM_START_PM
&& autopm_enabled
) ||
2687 (cmd
== PM_START_CPUPM
&& PM_DEFAULT_CPUPM
) ||
2688 (cmd
== PM_START_CPUPM_EV
&& PM_EVENT_CPUPM
) ||
2689 (cmd
== PM_START_CPUPM_POLL
&& PM_POLLING_CPUPM
)) {
2690 mutex_exit(&pm_scan_lock
);
2691 PMD(PMD_ERROR
, ("ioctl: %s: EBUSY\n", cmdstr
))
2696 if (cmd
== PM_START_PM
) {
2698 } else if (cmd
== PM_START_CPUPM
) {
2700 new_mode
= cpupm
= cpupm_default_mode
;
2701 } else if (cmd
== PM_START_CPUPM_EV
) {
2703 new_mode
= cpupm
= PM_CPUPM_EVENT
;
2704 } else if (cmd
== PM_START_CPUPM_POLL
) {
2706 new_mode
= cpupm
= PM_CPUPM_POLLING
;
2709 mutex_exit(&pm_scan_lock
);
2712 * If we are changing CPUPM modes, and it is active,
2713 * then stop it from operating in the old mode.
2715 if (old_mode
== PM_CPUPM_POLLING
) {
2716 int c
= PM_STOP_CPUPM
;
2717 ddi_walk_devs(ddi_root_node(), pm_stop_pm_walk
,
2719 } else if (old_mode
== PM_CPUPM_EVENT
) {
2720 r
= cpupm_set_policy(CPUPM_POLICY_DISABLED
);
2723 * Disabling CPUPM policy should always
2730 * If we are changing to event based CPUPM, enable it.
2731 * In the event it's not supported, fall back to
2732 * polling based CPUPM.
2734 if (new_mode
== PM_CPUPM_EVENT
&&
2735 cpupm_set_policy(CPUPM_POLICY_ELASTIC
) < 0) {
2736 mutex_enter(&pm_scan_lock
);
2737 new_mode
= cpupm
= PM_CPUPM_POLLING
;
2738 cmd
= PM_START_CPUPM_POLL
;
2739 mutex_exit(&pm_scan_lock
);
2741 if (new_mode
== PM_CPUPM_POLLING
||
2742 cmd
== PM_START_PM
) {
2743 ddi_walk_devs(ddi_root_node(), pm_start_pm_walk
,
2754 extern void pm_discard_thresholds(void);
2755 pm_cpupm_t old_mode
= PM_CPUPM_NOTSET
;
2757 mutex_enter(&pm_scan_lock
);
2758 if ((cmd
== PM_STOP_PM
&& !autopm_enabled
) ||
2759 (cmd
== PM_STOP_CPUPM
&& PM_CPUPM_DISABLED
)) {
2760 mutex_exit(&pm_scan_lock
);
2761 PMD(PMD_ERROR
, ("ioctl: %s: EINVAL\n",
2767 if (cmd
== PM_STOP_PM
) {
2771 } else if (cmd
== PM_STOP_CPUPM
) {
2773 cpupm
= PM_CPUPM_DISABLE
;
2778 cpupm
= PM_CPUPM_NOTSET
;
2780 mutex_exit(&pm_scan_lock
);
2783 * bring devices to full power level, stop scan
2784 * If CPUPM was operating in event driven mode, disable
2787 if (old_mode
== PM_CPUPM_EVENT
) {
2788 (void) cpupm_set_policy(CPUPM_POLICY_DISABLED
);
2790 ddi_walk_devs(ddi_root_node(), pm_stop_pm_walk
, &cmd
);
2792 if (cmd
== PM_STOP_PM
|| cmd
== PM_STOP_CPUPM
)
2795 * Now do only PM_RESET_PM stuff.
2797 pm_system_idle_threshold
= pm_default_idle_threshold
;
2798 pm_cpu_idle_threshold
= 0;
2799 pm_discard_thresholds();
2800 pm_all_to_default_thresholds();
2801 pm_dispatch_to_dep_thread(PM_DEP_WK_REMOVE_DEP
,
2802 NULL
, NULL
, PM_DEP_WAIT
, NULL
, 0);
2806 case PM_GET_SYSTEM_THRESHOLD
:
2808 *rval_p
= pm_system_idle_threshold
;
2813 case PM_GET_DEFAULT_SYSTEM_THRESHOLD
:
2815 *rval_p
= pm_default_idle_threshold
;
2820 case PM_GET_CPU_THRESHOLD
:
2822 *rval_p
= pm_cpu_idle_threshold
;
2827 case PM_SET_SYSTEM_THRESHOLD
:
2828 case PM_SET_CPU_THRESHOLD
:
2831 PMD(PMD_ERROR
, ("ioctl: %s: arg 0x%x < 0"
2832 "--EINVAL\n", cmdstr
, (int)arg
))
2836 PMD(PMD_IOCTL
, ("ioctl: %s: 0x%x 0t%d\n", cmdstr
,
2837 (int)arg
, (int)arg
))
2838 if (cmd
== PM_SET_SYSTEM_THRESHOLD
)
2839 pm_system_idle_threshold
= (int)arg
;
2841 pm_cpu_idle_threshold
= (int)arg
;
2843 ddi_walk_devs(ddi_root_node(), pm_set_idle_thresh_walk
,
2852 if (pm_timeout_idledown() != 0) {
2853 ddi_walk_devs(ddi_root_node(),
2854 pm_start_idledown
, (void *)PMID_IOC
);
2860 case PM_GET_PM_STATE
:
2862 if (autopm_enabled
) {
2863 *rval_p
= PM_SYSTEM_PM_ENABLED
;
2865 *rval_p
= PM_SYSTEM_PM_DISABLED
;
2871 case PM_GET_CPUPM_STATE
:
2873 if (PM_POLLING_CPUPM
|| PM_EVENT_CPUPM
)
2874 *rval_p
= PM_CPU_PM_ENABLED
;
2875 else if (PM_CPUPM_DISABLED
)
2876 *rval_p
= PM_CPU_PM_DISABLED
;
2878 *rval_p
= PM_CPU_PM_NOTSET
;
2883 case PM_GET_AUTOS3_STATE
:
2885 if (autoS3_enabled
) {
2886 *rval_p
= PM_AUTOS3_ENABLED
;
2888 *rval_p
= PM_AUTOS3_DISABLED
;
2894 case PM_GET_S3_SUPPORT_STATE
:
2896 if (pm_S3_enabled
) {
2897 *rval_p
= PM_S3_SUPPORT_ENABLED
;
2899 *rval_p
= PM_S3_SUPPORT_DISABLED
;
2906 * pmconfig tells us if the platform supports S3
2910 mutex_enter(&pm_scan_lock
);
2911 if (pm_S3_enabled
) {
2912 mutex_exit(&pm_scan_lock
);
2913 PMD(PMD_ERROR
, ("ioctl: %s: EBUSY\n",
2919 mutex_exit(&pm_scan_lock
);
2926 mutex_enter(&pm_scan_lock
);
2928 mutex_exit(&pm_scan_lock
);
2933 case PM_START_AUTOS3
:
2935 mutex_enter(&pm_scan_lock
);
2936 if (autoS3_enabled
) {
2937 mutex_exit(&pm_scan_lock
);
2938 PMD(PMD_ERROR
, ("ioctl: %s: EBUSY\n",
2944 mutex_exit(&pm_scan_lock
);
2949 case PM_STOP_AUTOS3
:
2951 mutex_enter(&pm_scan_lock
);
2953 mutex_exit(&pm_scan_lock
);
2958 case PM_ENABLE_CPU_DEEP_IDLE
:
2960 if (callb_execute_class(CB_CL_CPU_DEEP_IDLE
,
2961 PM_ENABLE_CPU_DEEP_IDLE
) == NULL
)
2967 case PM_DISABLE_CPU_DEEP_IDLE
:
2969 if (callb_execute_class(CB_CL_CPU_DEEP_IDLE
,
2970 PM_DISABLE_CPU_DEEP_IDLE
) == NULL
)
2976 case PM_DEFAULT_CPU_DEEP_IDLE
:
2978 if (callb_execute_class(CB_CL_CPU_DEEP_IDLE
,
2979 PM_DEFAULT_CPU_DEEP_IDLE
) == NULL
)
2988 * Internal error, invalid ioctl description
2989 * force debug entry even if pm_debug not set
2992 pm_log("invalid diptype %d for cmd %d (%s)\n",
2993 pcip
->diptype
, cmd
, pcip
->name
);
3003 * Internal error, invalid ioctl description
3004 * force debug entry even if pm_debug not set
3007 pm_log("ioctl: invalid str_type %d for cmd %d (%s)\n",
3008 pcip
->str_type
, cmd
, pcip
->name
);
3013 ASSERT(ret
!= 0x0badcafe); /* some cmd in wrong case! */
3016 PMD(PMD_DHR
, ("ioctl: %s: releasing %s@%s(%s#%d) for "
3017 "exiting pm_ioctl\n", cmdstr
, PM_DEVICE(dip
)))
3020 PMD(PMD_IOCTL
, ("ioctl: %s: end, ret=%d\n", cmdstr
, ret
))