17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5c42872d4Smh27603 * Common Development and Distribution License (the "License").
6c42872d4Smh27603 * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22*0e751525SEric Saxe * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate * pm This driver now only handles the ioctl interface. The scanning
287c478bd9Sstevel@tonic-gate * and policy stuff now lives in common/os/sunpm.c.
297c478bd9Sstevel@tonic-gate * Not DDI compliant
307c478bd9Sstevel@tonic-gate */
317c478bd9Sstevel@tonic-gate
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/errno.h>
347c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
35*0e751525SEric Saxe #include <sys/callb.h> /* callback registration for cpu_deep_idle */
367c478bd9Sstevel@tonic-gate #include <sys/conf.h> /* driver flags and functions */
377c478bd9Sstevel@tonic-gate #include <sys/open.h> /* OTYP_CHR definition */
387c478bd9Sstevel@tonic-gate #include <sys/stat.h> /* S_IFCHR definition */
397c478bd9Sstevel@tonic-gate #include <sys/pathname.h> /* name -> dev_info xlation */
407c478bd9Sstevel@tonic-gate #include <sys/kmem.h> /* memory alloc stuff */
417c478bd9Sstevel@tonic-gate #include <sys/debug.h>
427c478bd9Sstevel@tonic-gate #include <sys/pm.h>
437c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
447c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
457c478bd9Sstevel@tonic-gate #include <sys/epm.h>
467c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
477c478bd9Sstevel@tonic-gate #include <sys/mode.h>
487c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
497c478bd9Sstevel@tonic-gate #include <sys/promif.h>
507c478bd9Sstevel@tonic-gate #include <sys/consdev.h>
517c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
527c478bd9Sstevel@tonic-gate #include <sys/poll.h>
537c478bd9Sstevel@tonic-gate #include <sys/note.h>
547c478bd9Sstevel@tonic-gate #include <sys/taskq.h>
557c478bd9Sstevel@tonic-gate #include <sys/policy.h>
56*0e751525SEric Saxe #include <sys/cpu_pm.h>
577c478bd9Sstevel@tonic-gate
587c478bd9Sstevel@tonic-gate /*
592df1fe9cSrandyf * Minor number is instance<<8 + clone minor from range 1-254; (0 reserved
602df1fe9cSrandyf * for "original")
617c478bd9Sstevel@tonic-gate */
627c478bd9Sstevel@tonic-gate #define PM_MINOR_TO_CLONE(minor) ((minor) & (PM_MAX_CLONE -1))
637c478bd9Sstevel@tonic-gate
647c478bd9Sstevel@tonic-gate #define PM_NUMCMPTS(dip) (DEVI(dip)->devi_pm_num_components)
657c478bd9Sstevel@tonic-gate #define PM_IS_CFB(dip) (DEVI(dip)->devi_pm_flags & PMC_CONSOLE_FB)
667c478bd9Sstevel@tonic-gate #define PM_MAJOR(dip) ddi_driver_major(dip)
677c478bd9Sstevel@tonic-gate #define PM_RELE(dip) ddi_release_devi(dip)
687c478bd9Sstevel@tonic-gate
697c478bd9Sstevel@tonic-gate #define PM_IDLEDOWN_TIME 10
702df1fe9cSrandyf #define MAXSMBIOSSTRLEN 64 /* from SMBIOS spec */
712df1fe9cSrandyf #define MAXCOPYBUF (MAXSMBIOSSTRLEN + 1)
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gate extern kmutex_t pm_scan_lock; /* protects autopm_enable, pm_scans_disabled */
747c478bd9Sstevel@tonic-gate extern kmutex_t pm_clone_lock; /* protects pm_clones array */
757c478bd9Sstevel@tonic-gate extern int autopm_enabled;
76c42872d4Smh27603 extern pm_cpupm_t cpupm;
77*0e751525SEric Saxe extern pm_cpupm_t cpupm_default_mode;
78c42872d4Smh27603 extern int pm_default_idle_threshold;
79c42872d4Smh27603 extern int pm_system_idle_threshold;
80c42872d4Smh27603 extern int pm_cpu_idle_threshold;
817c478bd9Sstevel@tonic-gate extern kcondvar_t pm_clones_cv[PM_MAX_CLONE];
827c478bd9Sstevel@tonic-gate extern uint_t pm_poll_cnt[PM_MAX_CLONE];
832df1fe9cSrandyf extern int autoS3_enabled;
842df1fe9cSrandyf extern void pm_record_thresh(pm_thresh_rec_t *);
852df1fe9cSrandyf extern void pm_register_watcher(int, dev_info_t *);
862df1fe9cSrandyf extern int pm_get_current_power(dev_info_t *, int, int *);
872df1fe9cSrandyf extern int pm_interest_registered(int);
882df1fe9cSrandyf extern void pm_all_to_default_thresholds(void);
892df1fe9cSrandyf extern int pm_current_threshold(dev_info_t *, int, int *);
902df1fe9cSrandyf extern void pm_deregister_watcher(int, dev_info_t *);
912df1fe9cSrandyf extern void pm_unrecord_threshold(char *);
922df1fe9cSrandyf extern int pm_S3_enabled;
932df1fe9cSrandyf extern int pm_ppm_searchlist(pm_searchargs_t *);
942df1fe9cSrandyf extern psce_t *pm_psc_clone_to_direct(int);
952df1fe9cSrandyf extern psce_t *pm_psc_clone_to_interest(int);
967c478bd9Sstevel@tonic-gate
977c478bd9Sstevel@tonic-gate /*
987c478bd9Sstevel@tonic-gate * The soft state of the power manager. Since there will only
997c478bd9Sstevel@tonic-gate * one of these, just reference it through a static pointer.
1007c478bd9Sstevel@tonic-gate */
1017c478bd9Sstevel@tonic-gate static struct pmstate {
1027c478bd9Sstevel@tonic-gate dev_info_t *pm_dip; /* ptr to our dev_info node */
1037c478bd9Sstevel@tonic-gate int pm_instance; /* for ddi_get_instance() */
1047c478bd9Sstevel@tonic-gate timeout_id_t pm_idledown_id; /* pm idledown timeout id */
1057c478bd9Sstevel@tonic-gate uchar_t pm_clones[PM_MAX_CLONE]; /* uniqueify multiple opens */
1067c478bd9Sstevel@tonic-gate struct cred *pm_cred[PM_MAX_CLONE]; /* cred for each unique open */
1077c478bd9Sstevel@tonic-gate } pm_state = { NULL, -1, (timeout_id_t)0 };
1087c478bd9Sstevel@tonic-gate typedef struct pmstate *pm_state_t;
1097c478bd9Sstevel@tonic-gate static pm_state_t pmstp = &pm_state;
1107c478bd9Sstevel@tonic-gate
1117c478bd9Sstevel@tonic-gate static int pm_open(dev_t *, int, int, cred_t *);
1127c478bd9Sstevel@tonic-gate static int pm_close(dev_t, int, int, cred_t *);
1137c478bd9Sstevel@tonic-gate static int pm_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
1147c478bd9Sstevel@tonic-gate static int pm_chpoll(dev_t, short, int, short *, struct pollhead **);
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate static struct cb_ops pm_cb_ops = {
1177c478bd9Sstevel@tonic-gate pm_open, /* open */
1187c478bd9Sstevel@tonic-gate pm_close, /* close */
1197c478bd9Sstevel@tonic-gate nodev, /* strategy */
1207c478bd9Sstevel@tonic-gate nodev, /* print */
1217c478bd9Sstevel@tonic-gate nodev, /* dump */
1227c478bd9Sstevel@tonic-gate nodev, /* read */
1237c478bd9Sstevel@tonic-gate nodev, /* write */
1247c478bd9Sstevel@tonic-gate pm_ioctl, /* ioctl */
1257c478bd9Sstevel@tonic-gate nodev, /* devmap */
1267c478bd9Sstevel@tonic-gate nodev, /* mmap */
1277c478bd9Sstevel@tonic-gate nodev, /* segmap */
1287c478bd9Sstevel@tonic-gate pm_chpoll, /* poll */
1297c478bd9Sstevel@tonic-gate ddi_prop_op, /* prop_op */
1307c478bd9Sstevel@tonic-gate NULL, /* streamtab */
1317c478bd9Sstevel@tonic-gate D_NEW | D_MP /* driver compatibility flag */
1327c478bd9Sstevel@tonic-gate };
1337c478bd9Sstevel@tonic-gate
1347c478bd9Sstevel@tonic-gate static int pm_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
1357c478bd9Sstevel@tonic-gate void **result);
1367c478bd9Sstevel@tonic-gate static int pm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
1377c478bd9Sstevel@tonic-gate static int pm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
1387c478bd9Sstevel@tonic-gate
1397c478bd9Sstevel@tonic-gate static struct dev_ops pm_ops = {
1407c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev */
1417c478bd9Sstevel@tonic-gate 0, /* refcnt */
1427c478bd9Sstevel@tonic-gate pm_getinfo, /* info */
1437c478bd9Sstevel@tonic-gate nulldev, /* identify */
1447c478bd9Sstevel@tonic-gate nulldev, /* probe */
1457c478bd9Sstevel@tonic-gate pm_attach, /* attach */
1467c478bd9Sstevel@tonic-gate pm_detach, /* detach */
1477c478bd9Sstevel@tonic-gate nodev, /* reset */
1487c478bd9Sstevel@tonic-gate &pm_cb_ops, /* driver operations */
1497c478bd9Sstevel@tonic-gate NULL, /* bus operations */
15019397407SSherry Moore NULL, /* power */
15119397407SSherry Moore ddi_quiesce_not_needed, /* quiesce */
1527c478bd9Sstevel@tonic-gate };
1537c478bd9Sstevel@tonic-gate
1547c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
1557c478bd9Sstevel@tonic-gate &mod_driverops,
15619397407SSherry Moore "power management driver",
1577c478bd9Sstevel@tonic-gate &pm_ops
1587c478bd9Sstevel@tonic-gate };
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1617c478bd9Sstevel@tonic-gate MODREV_1, &modldrv, 0
1627c478bd9Sstevel@tonic-gate };
1637c478bd9Sstevel@tonic-gate
1647c478bd9Sstevel@tonic-gate /* Local functions */
1657c478bd9Sstevel@tonic-gate #ifdef DEBUG
1667c478bd9Sstevel@tonic-gate static int print_info(dev_info_t *, void *);
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate #endif
1697c478bd9Sstevel@tonic-gate
1707c478bd9Sstevel@tonic-gate int
_init(void)1717c478bd9Sstevel@tonic-gate _init(void)
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage));
1747c478bd9Sstevel@tonic-gate }
1757c478bd9Sstevel@tonic-gate
1767c478bd9Sstevel@tonic-gate int
_fini(void)1777c478bd9Sstevel@tonic-gate _fini(void)
1787c478bd9Sstevel@tonic-gate {
1797c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage));
1807c478bd9Sstevel@tonic-gate }
1817c478bd9Sstevel@tonic-gate
1827c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1837c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1847c478bd9Sstevel@tonic-gate {
1857c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate
1887c478bd9Sstevel@tonic-gate static int
pm_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)1897c478bd9Sstevel@tonic-gate pm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1907c478bd9Sstevel@tonic-gate {
1917c478bd9Sstevel@tonic-gate int i;
1927c478bd9Sstevel@tonic-gate
1937c478bd9Sstevel@tonic-gate switch (cmd) {
1947c478bd9Sstevel@tonic-gate
1957c478bd9Sstevel@tonic-gate case DDI_ATTACH:
1967c478bd9Sstevel@tonic-gate if (pmstp->pm_instance != -1) /* Only allow one instance */
1977c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
1987c478bd9Sstevel@tonic-gate pmstp->pm_instance = ddi_get_instance(dip);
1997c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dip, "pm", S_IFCHR,
2007c478bd9Sstevel@tonic-gate (pmstp->pm_instance << 8) + 0,
2017c478bd9Sstevel@tonic-gate DDI_PSEUDO, 0) != DDI_SUCCESS) {
2027c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
2037c478bd9Sstevel@tonic-gate }
2047c478bd9Sstevel@tonic-gate pmstp->pm_dip = dip; /* pm_init and getinfo depend on it */
2057c478bd9Sstevel@tonic-gate
2067c478bd9Sstevel@tonic-gate for (i = 0; i < PM_MAX_CLONE; i++)
2077c478bd9Sstevel@tonic-gate cv_init(&pm_clones_cv[i], NULL, CV_DEFAULT, NULL);
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate ddi_report_dev(dip);
2107c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
2117c478bd9Sstevel@tonic-gate
2127c478bd9Sstevel@tonic-gate default:
2137c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
2147c478bd9Sstevel@tonic-gate }
2157c478bd9Sstevel@tonic-gate }
2167c478bd9Sstevel@tonic-gate
2177c478bd9Sstevel@tonic-gate /* ARGSUSED */
2187c478bd9Sstevel@tonic-gate static int
pm_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)2197c478bd9Sstevel@tonic-gate pm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2207c478bd9Sstevel@tonic-gate {
2217c478bd9Sstevel@tonic-gate int i;
2227c478bd9Sstevel@tonic-gate
2237c478bd9Sstevel@tonic-gate switch (cmd) {
2247c478bd9Sstevel@tonic-gate case DDI_DETACH:
2257c478bd9Sstevel@tonic-gate /*
2267c478bd9Sstevel@tonic-gate * Don't detach while idledown timeout is pending. Note that
2277c478bd9Sstevel@tonic-gate * we already know we're not in pm_ioctl() due to framework
2287c478bd9Sstevel@tonic-gate * synchronization, so this is a sufficient test
2297c478bd9Sstevel@tonic-gate */
2307c478bd9Sstevel@tonic-gate if (pmstp->pm_idledown_id)
2317c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
2327c478bd9Sstevel@tonic-gate
2337c478bd9Sstevel@tonic-gate for (i = 0; i < PM_MAX_CLONE; i++)
2347c478bd9Sstevel@tonic-gate cv_destroy(&pm_clones_cv[i]);
2357c478bd9Sstevel@tonic-gate
2367c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL);
2377c478bd9Sstevel@tonic-gate pmstp->pm_instance = -1;
2387c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
2397c478bd9Sstevel@tonic-gate
2407c478bd9Sstevel@tonic-gate default:
2417c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
2427c478bd9Sstevel@tonic-gate }
2437c478bd9Sstevel@tonic-gate }
2447c478bd9Sstevel@tonic-gate
2457c478bd9Sstevel@tonic-gate static int
pm_close_direct_pm_device(dev_info_t * dip,void * arg)2467c478bd9Sstevel@tonic-gate pm_close_direct_pm_device(dev_info_t *dip, void *arg)
2477c478bd9Sstevel@tonic-gate {
2487c478bd9Sstevel@tonic-gate int clone;
2497c478bd9Sstevel@tonic-gate char *pathbuf;
2507c478bd9Sstevel@tonic-gate pm_info_t *info = PM_GET_PM_INFO(dip);
2517c478bd9Sstevel@tonic-gate
2527c478bd9Sstevel@tonic-gate clone = *((int *)arg);
2537c478bd9Sstevel@tonic-gate
2547c478bd9Sstevel@tonic-gate if (!info)
2557c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE);
2567c478bd9Sstevel@tonic-gate
2577c478bd9Sstevel@tonic-gate pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
2587c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip);
2597c478bd9Sstevel@tonic-gate if (clone == info->pmi_clone) {
2607c478bd9Sstevel@tonic-gate PMD(PMD_CLOSE, ("pm_close: found %s@%s(%s#%d)\n",
2617c478bd9Sstevel@tonic-gate PM_DEVICE(dip)))
2627c478bd9Sstevel@tonic-gate ASSERT(PM_ISDIRECT(dip));
2637c478bd9Sstevel@tonic-gate info->pmi_dev_pm_state &= ~PM_DIRECT;
2647c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
2657c478bd9Sstevel@tonic-gate pm_proceed(dip, PMP_RELEASE, -1, -1);
2667c478bd9Sstevel@tonic-gate /* Bring ourselves up if there is a keeper that is up */
2677c478bd9Sstevel@tonic-gate (void) ddi_pathname(dip, pathbuf);
2687c478bd9Sstevel@tonic-gate pm_dispatch_to_dep_thread(PM_DEP_WK_BRINGUP_SELF, NULL,
2697c478bd9Sstevel@tonic-gate pathbuf, PM_DEP_NOWAIT, NULL, 0);
2707c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip);
2717c478bd9Sstevel@tonic-gate info->pmi_clone = 0;
2727c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
2737c478bd9Sstevel@tonic-gate } else {
2747c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
2757c478bd9Sstevel@tonic-gate }
2767c478bd9Sstevel@tonic-gate kmem_free(pathbuf, MAXPATHLEN);
2777c478bd9Sstevel@tonic-gate
2787c478bd9Sstevel@tonic-gate /* restart autopm on device released from direct pm */
2797c478bd9Sstevel@tonic-gate pm_rescan(dip);
2807c478bd9Sstevel@tonic-gate
2817c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE);
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate
2847c478bd9Sstevel@tonic-gate #define PM_REQ 1
2857c478bd9Sstevel@tonic-gate #define NOSTRUCT 2
2867c478bd9Sstevel@tonic-gate #define DIP 3
2877c478bd9Sstevel@tonic-gate #define NODIP 4
2887c478bd9Sstevel@tonic-gate #define NODEP 5
2897c478bd9Sstevel@tonic-gate #define DEP 6
2907c478bd9Sstevel@tonic-gate #define PM_PSC 7
2912df1fe9cSrandyf #define PM_SRCH 8
2927c478bd9Sstevel@tonic-gate
2937c478bd9Sstevel@tonic-gate #define CHECKPERMS 0x001
2947c478bd9Sstevel@tonic-gate #define SU 0x002
2957c478bd9Sstevel@tonic-gate #define SG 0x004
2967c478bd9Sstevel@tonic-gate #define OWNER 0x008
2977c478bd9Sstevel@tonic-gate
2987c478bd9Sstevel@tonic-gate #define INWHO 0x001
2997c478bd9Sstevel@tonic-gate #define INDATAINT 0x002
3007c478bd9Sstevel@tonic-gate #define INDATASTRING 0x004
3017c478bd9Sstevel@tonic-gate #define INDEP 0x008
3027c478bd9Sstevel@tonic-gate #define INDATAOUT 0x010
3037c478bd9Sstevel@tonic-gate #define INDATA (INDATAOUT | INDATAINT | INDATASTRING | INDEP)
3047c478bd9Sstevel@tonic-gate
3057c478bd9Sstevel@tonic-gate struct pm_cmd_info {
3067c478bd9Sstevel@tonic-gate int cmd; /* command code */
3077c478bd9Sstevel@tonic-gate char *name; /* printable string */
3087c478bd9Sstevel@tonic-gate int supported; /* true if still supported */
3097c478bd9Sstevel@tonic-gate int str_type; /* PM_REQ or NOSTRUCT */
3107c478bd9Sstevel@tonic-gate int inargs; /* INWHO, INDATAINT, INDATASTRING, INDEP, */
3117c478bd9Sstevel@tonic-gate /* INDATAOUT */
3127c478bd9Sstevel@tonic-gate int diptype; /* DIP or NODIP */
3137c478bd9Sstevel@tonic-gate int deptype; /* DEP or NODEP */
3147c478bd9Sstevel@tonic-gate int permission; /* SU, GU, or CHECKPERMS */
3157c478bd9Sstevel@tonic-gate };
3167c478bd9Sstevel@tonic-gate
3177c478bd9Sstevel@tonic-gate #ifdef DEBUG
3187c478bd9Sstevel@tonic-gate char *pm_cmd_string;
3197c478bd9Sstevel@tonic-gate int pm_cmd;
3207c478bd9Sstevel@tonic-gate #endif
3217c478bd9Sstevel@tonic-gate
3227c478bd9Sstevel@tonic-gate /*
3237c478bd9Sstevel@tonic-gate * Returns true if permission granted by credentials
3247c478bd9Sstevel@tonic-gate */
3257c478bd9Sstevel@tonic-gate static int
pm_perms(int perm,cred_t * cr)3267c478bd9Sstevel@tonic-gate pm_perms(int perm, cred_t *cr)
3277c478bd9Sstevel@tonic-gate {
3287c478bd9Sstevel@tonic-gate if (perm == 0) /* no restrictions */
3297c478bd9Sstevel@tonic-gate return (1);
3307c478bd9Sstevel@tonic-gate if (perm == CHECKPERMS) /* ok for now (is checked later) */
3317c478bd9Sstevel@tonic-gate return (1);
3327c478bd9Sstevel@tonic-gate if ((perm & SU) && secpolicy_power_mgmt(cr) == 0) /* privileged? */
3337c478bd9Sstevel@tonic-gate return (1);
3347c478bd9Sstevel@tonic-gate if ((perm & SG) && (crgetgid(cr) == 0)) /* group 0 is ok */
3357c478bd9Sstevel@tonic-gate return (1);
3367c478bd9Sstevel@tonic-gate return (0);
3377c478bd9Sstevel@tonic-gate }
3387c478bd9Sstevel@tonic-gate
3397c478bd9Sstevel@tonic-gate #ifdef DEBUG
3407c478bd9Sstevel@tonic-gate static int
print_info(dev_info_t * dip,void * arg)3417c478bd9Sstevel@tonic-gate print_info(dev_info_t *dip, void *arg)
3427c478bd9Sstevel@tonic-gate {
3437c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(arg))
3447c478bd9Sstevel@tonic-gate pm_info_t *info;
3457c478bd9Sstevel@tonic-gate int i, j;
3467c478bd9Sstevel@tonic-gate struct pm_component *cp;
3477c478bd9Sstevel@tonic-gate extern int pm_cur_power(pm_component_t *cp);
3487c478bd9Sstevel@tonic-gate
3497c478bd9Sstevel@tonic-gate info = PM_GET_PM_INFO(dip);
3507c478bd9Sstevel@tonic-gate if (!info)
3517c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE);
3527c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pm_info for %s\n", ddi_node_name(dip));
3537c478bd9Sstevel@tonic-gate for (i = 0; i < PM_NUMCMPTS(dip); i++) {
3547c478bd9Sstevel@tonic-gate cp = PM_CP(dip, i);
3557c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tThresholds[%d] =", i);
3567c478bd9Sstevel@tonic-gate for (j = 0; j < cp->pmc_comp.pmc_numlevels; j++)
3577c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, " %d", cp->pmc_comp.pmc_thresh[i]);
3587c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\n");
3597c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tCurrent power[%d] = %d\n", i,
3607c478bd9Sstevel@tonic-gate pm_cur_power(cp));
3617c478bd9Sstevel@tonic-gate }
3627c478bd9Sstevel@tonic-gate if (PM_ISDIRECT(dip))
3637c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tDirect power management\n");
3647c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE);
3657c478bd9Sstevel@tonic-gate }
3667c478bd9Sstevel@tonic-gate #endif
3677c478bd9Sstevel@tonic-gate
3687c478bd9Sstevel@tonic-gate /*
3697c478bd9Sstevel@tonic-gate * command, name, supported, str_type, inargs, diptype, deptype, permission
3707c478bd9Sstevel@tonic-gate */
3717c478bd9Sstevel@tonic-gate static struct pm_cmd_info pmci[] = {
3727c478bd9Sstevel@tonic-gate {PM_SCHEDULE, "PM_SCHEDULE", 0},
3737c478bd9Sstevel@tonic-gate {PM_GET_IDLE_TIME, "PM_GET_IDLE_TIME", 0},
3747c478bd9Sstevel@tonic-gate {PM_GET_NUM_CMPTS, "PM_GET_NUM_CMPTS", 0},
3757c478bd9Sstevel@tonic-gate {PM_GET_THRESHOLD, "PM_GET_THRESHOLD", 0},
3767c478bd9Sstevel@tonic-gate {PM_SET_THRESHOLD, "PM_SET_THRESHOLD", 0},
3777c478bd9Sstevel@tonic-gate {PM_GET_NORM_PWR, "PM_GET_NORM_PWR", 0},
3787c478bd9Sstevel@tonic-gate {PM_SET_CUR_PWR, "PM_SET_CUR_PWR", 0},
3797c478bd9Sstevel@tonic-gate {PM_GET_CUR_PWR, "PM_GET_CUR_PWR", 0},
3807c478bd9Sstevel@tonic-gate {PM_GET_NUM_DEPS, "PM_GET_NUM_DEPS", 0},
3817c478bd9Sstevel@tonic-gate {PM_GET_DEP, "PM_GET_DEP", 0},
3827c478bd9Sstevel@tonic-gate {PM_ADD_DEP, "PM_ADD_DEP", 0},
3837c478bd9Sstevel@tonic-gate {PM_REM_DEP, "PM_REM_DEP", 0},
3847c478bd9Sstevel@tonic-gate {PM_REM_DEVICE, "PM_REM_DEVICE", 0},
3857c478bd9Sstevel@tonic-gate {PM_REM_DEVICES, "PM_REM_DEVICES", 0},
3867c478bd9Sstevel@tonic-gate {PM_REPARSE_PM_PROPS, "PM_REPARSE_PM_PROPS", 1, PM_REQ, INWHO, DIP,
3877c478bd9Sstevel@tonic-gate NODEP},
3887c478bd9Sstevel@tonic-gate {PM_DISABLE_AUTOPM, "PM_DISABLE_AUTOPM", 0},
3897c478bd9Sstevel@tonic-gate {PM_REENABLE_AUTOPM, "PM_REENABLE_AUTOPM", 0},
3907c478bd9Sstevel@tonic-gate {PM_SET_NORM_PWR, "PM_SET_NORM_PWR", 0 },
3917c478bd9Sstevel@tonic-gate {PM_SET_DEVICE_THRESHOLD, "PM_SET_DEVICE_THRESHOLD", 1, PM_REQ,
3927c478bd9Sstevel@tonic-gate INWHO, NODIP, NODEP, SU},
3937c478bd9Sstevel@tonic-gate {PM_GET_SYSTEM_THRESHOLD, "PM_GET_SYSTEM_THRESHOLD", 1, NOSTRUCT},
3947c478bd9Sstevel@tonic-gate {PM_GET_DEFAULT_SYSTEM_THRESHOLD, "PM_GET_DEFAULT_SYSTEM_THRESHOLD",
3957c478bd9Sstevel@tonic-gate 1, NOSTRUCT},
3967c478bd9Sstevel@tonic-gate {PM_SET_SYSTEM_THRESHOLD, "PM_SET_SYSTEM_THRESHOLD", 1, NOSTRUCT,
3977c478bd9Sstevel@tonic-gate 0, 0, 0, SU},
3987c478bd9Sstevel@tonic-gate {PM_START_PM, "PM_START_PM", 1, NOSTRUCT, 0, 0, 0, SU},
3997c478bd9Sstevel@tonic-gate {PM_STOP_PM, "PM_STOP_PM", 1, NOSTRUCT, 0, 0, 0, SU},
4007c478bd9Sstevel@tonic-gate {PM_RESET_PM, "PM_RESET_PM", 1, NOSTRUCT, 0, 0, 0, SU},
4017c478bd9Sstevel@tonic-gate {PM_GET_STATS, "PM_GET_STATS", 1, PM_REQ, INWHO | INDATAOUT,
4027c478bd9Sstevel@tonic-gate DIP, NODEP},
4037c478bd9Sstevel@tonic-gate {PM_GET_DEVICE_THRESHOLD, "PM_GET_DEVICE_THRESHOLD", 1, PM_REQ, INWHO,
4047c478bd9Sstevel@tonic-gate DIP, NODEP},
4057c478bd9Sstevel@tonic-gate {PM_GET_POWER_NAME, "PM_GET_POWER_NAME", 1, PM_REQ, INWHO | INDATAOUT,
4067c478bd9Sstevel@tonic-gate DIP, NODEP},
4077c478bd9Sstevel@tonic-gate {PM_GET_POWER_LEVELS, "PM_GET_POWER_LEVELS", 1, PM_REQ,
4087c478bd9Sstevel@tonic-gate INWHO | INDATAOUT, DIP, NODEP},
4097c478bd9Sstevel@tonic-gate {PM_GET_NUM_COMPONENTS, "PM_GET_NUM_COMPONENTS", 1, PM_REQ, INWHO,
4107c478bd9Sstevel@tonic-gate DIP, NODEP},
4117c478bd9Sstevel@tonic-gate {PM_GET_COMPONENT_NAME, "PM_GET_COMPONENT_NAME", 1, PM_REQ,
4127c478bd9Sstevel@tonic-gate INWHO | INDATAOUT, DIP, NODEP},
4137c478bd9Sstevel@tonic-gate {PM_GET_NUM_POWER_LEVELS, "PM_GET_NUM_POWER_LEVELS", 1, PM_REQ, INWHO,
4147c478bd9Sstevel@tonic-gate DIP, NODEP},
4157c478bd9Sstevel@tonic-gate {PM_GET_STATE_CHANGE, "PM_GET_STATE_CHANGE", 1, PM_PSC},
4167c478bd9Sstevel@tonic-gate {PM_GET_STATE_CHANGE_WAIT, "PM_GET_STATE_CHANGE_WAIT", 1, PM_PSC},
4177c478bd9Sstevel@tonic-gate {PM_DIRECT_PM, "PM_DIRECT_PM", 1, PM_REQ, INWHO, DIP, NODEP,
4187c478bd9Sstevel@tonic-gate (SU | SG)},
4197c478bd9Sstevel@tonic-gate {PM_RELEASE_DIRECT_PM, "PM_RELEASE_DIRECT_PM", 1, PM_REQ, INWHO,
4207c478bd9Sstevel@tonic-gate DIP, NODEP},
4217c478bd9Sstevel@tonic-gate {PM_DIRECT_NOTIFY, "PM_DIRECT_NOTIFY", 1, PM_PSC},
4227c478bd9Sstevel@tonic-gate {PM_DIRECT_NOTIFY_WAIT, "PM_DIRECT_NOTIFY_WAIT", 1, PM_PSC},
4237c478bd9Sstevel@tonic-gate {PM_RESET_DEVICE_THRESHOLD, "PM_RESET_DEVICE_THRESHOLD", 1, PM_REQ,
4247c478bd9Sstevel@tonic-gate INWHO, DIP, NODEP, SU},
4257c478bd9Sstevel@tonic-gate {PM_GET_PM_STATE, "PM_GET_PM_STATE", 1, NOSTRUCT},
4262df1fe9cSrandyf {PM_GET_AUTOS3_STATE, "PM_GET_AUTOS3_STATE", 1, NOSTRUCT},
4272df1fe9cSrandyf {PM_GET_S3_SUPPORT_STATE, "PM_GET_S3_SUPPORT_STATE", 1, NOSTRUCT},
4287c478bd9Sstevel@tonic-gate {PM_GET_DEVICE_TYPE, "PM_GET_DEVICE_TYPE", 1, PM_REQ, INWHO,
4297c478bd9Sstevel@tonic-gate DIP, NODEP},
4307c478bd9Sstevel@tonic-gate {PM_SET_COMPONENT_THRESHOLDS, "PM_SET_COMPONENT_THRESHOLDS", 1, PM_REQ,
4317c478bd9Sstevel@tonic-gate INWHO | INDATAINT, NODIP, NODEP, SU},
4327c478bd9Sstevel@tonic-gate {PM_GET_COMPONENT_THRESHOLDS, "PM_GET_COMPONENT_THRESHOLDS", 1, PM_REQ,
4337c478bd9Sstevel@tonic-gate INWHO | INDATAOUT, DIP, NODEP},
4347c478bd9Sstevel@tonic-gate {PM_IDLE_DOWN, "PM_IDLE_DOWN", 1, NOSTRUCT, 0, 0, 0, SU},
4357c478bd9Sstevel@tonic-gate {PM_GET_DEVICE_THRESHOLD_BASIS, "PM_GET_DEVICE_THRESHOLD_BASIS", 1,
4367c478bd9Sstevel@tonic-gate PM_REQ, INWHO, DIP, NODEP},
4377c478bd9Sstevel@tonic-gate {PM_SET_CURRENT_POWER, "PM_SET_CURRENT_POWER", 1, PM_REQ, INWHO, DIP,
4387c478bd9Sstevel@tonic-gate NODEP},
4397c478bd9Sstevel@tonic-gate {PM_GET_CURRENT_POWER, "PM_GET_CURRENT_POWER", 1, PM_REQ, INWHO, DIP,
4407c478bd9Sstevel@tonic-gate NODEP},
4417c478bd9Sstevel@tonic-gate {PM_GET_FULL_POWER, "PM_GET_FULL_POWER", 1, PM_REQ, INWHO, DIP,
4427c478bd9Sstevel@tonic-gate NODEP},
4437c478bd9Sstevel@tonic-gate {PM_ADD_DEPENDENT, "PM_ADD_DEPENDENT", 1, PM_REQ, INWHO | INDATASTRING,
4447c478bd9Sstevel@tonic-gate DIP, DEP, SU},
4457c478bd9Sstevel@tonic-gate {PM_GET_TIME_IDLE, "PM_GET_TIME_IDLE", 1, PM_REQ, INWHO, DIP, NODEP},
4467c478bd9Sstevel@tonic-gate {PM_ADD_DEPENDENT_PROPERTY, "PM_ADD_DEPENDENT_PROPERTY", 1, PM_REQ,
4477c478bd9Sstevel@tonic-gate INWHO | INDATASTRING, NODIP, DEP, SU},
448c42872d4Smh27603 {PM_START_CPUPM, "PM_START_CPUPM", 1, NOSTRUCT, 0, 0, 0, SU},
449*0e751525SEric Saxe {PM_START_CPUPM_EV, "PM_START_CPUPM_EV", 1, NOSTRUCT, 0,
450*0e751525SEric Saxe 0, 0, SU},
451*0e751525SEric Saxe {PM_START_CPUPM_POLL, "PM_START_CPUPM_POLL", 1, NOSTRUCT, 0,
452*0e751525SEric Saxe 0, 0, SU},
453c42872d4Smh27603 {PM_STOP_CPUPM, "PM_STOP_CPUPM", 1, NOSTRUCT, 0, 0, 0, SU},
454c42872d4Smh27603 {PM_GET_CPU_THRESHOLD, "PM_GET_CPU_THRESHOLD", 1, NOSTRUCT},
455c42872d4Smh27603 {PM_SET_CPU_THRESHOLD, "PM_SET_CPU_THRESHOLD", 1, NOSTRUCT,
456c42872d4Smh27603 0, 0, 0, SU},
457c42872d4Smh27603 {PM_GET_CPUPM_STATE, "PM_GET_CPUPM_STATE", 1, NOSTRUCT},
4582df1fe9cSrandyf {PM_START_AUTOS3, "PM_START_AUTOS3", 1, NOSTRUCT, 0, 0, 0, SU},
4592df1fe9cSrandyf {PM_STOP_AUTOS3, "PM_STOP_AUTOS3", 1, NOSTRUCT, 0, 0, 0, SU},
4602df1fe9cSrandyf {PM_ENABLE_S3, "PM_ENABLE_S3", 1, NOSTRUCT, 0, 0, 0, SU},
4612df1fe9cSrandyf {PM_DISABLE_S3, "PM_DISABLE_S3", 1, NOSTRUCT, 0, 0, 0, SU},
4622df1fe9cSrandyf {PM_ENTER_S3, "PM_ENTER_S3", 1, NOSTRUCT, 0, 0, 0, SU},
4632df1fe9cSrandyf {PM_SEARCH_LIST, "PM_SEARCH_LIST", 1, PM_SRCH, 0, 0, 0, SU},
4642df1fe9cSrandyf {PM_GET_CMD_NAME, "PM_GET_CMD_NAME", 1, PM_REQ, INDATAOUT, NODIP,
4652df1fe9cSrandyf NODEP, 0},
466*0e751525SEric Saxe {PM_DISABLE_CPU_DEEP_IDLE, "PM_DISABLE_CPU_DEEP_IDLE", 1, NOSTRUCT, 0,
467*0e751525SEric Saxe 0, 0, SU},
468*0e751525SEric Saxe {PM_ENABLE_CPU_DEEP_IDLE, "PM_START_CPU_DEEP_IDLE", 1, NOSTRUCT, 0,
469*0e751525SEric Saxe 0, 0, SU},
470*0e751525SEric Saxe {PM_DEFAULT_CPU_DEEP_IDLE, "PM_DFLT_CPU_DEEP_IDLE", 1, NOSTRUCT, 0,
471*0e751525SEric Saxe 0, 0, SU},
4727c478bd9Sstevel@tonic-gate {0, NULL}
4737c478bd9Sstevel@tonic-gate };
4747c478bd9Sstevel@tonic-gate
4757c478bd9Sstevel@tonic-gate struct pm_cmd_info *
pc_info(int cmd)4767c478bd9Sstevel@tonic-gate pc_info(int cmd)
4777c478bd9Sstevel@tonic-gate {
4787c478bd9Sstevel@tonic-gate struct pm_cmd_info *pcip;
4797c478bd9Sstevel@tonic-gate
4807c478bd9Sstevel@tonic-gate for (pcip = pmci; pcip->name; pcip++) {
4817c478bd9Sstevel@tonic-gate if (cmd == pcip->cmd)
4827c478bd9Sstevel@tonic-gate return (pcip);
4837c478bd9Sstevel@tonic-gate }
4847c478bd9Sstevel@tonic-gate return (NULL);
4857c478bd9Sstevel@tonic-gate }
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate static char *
pm_decode_cmd(int cmd)4887c478bd9Sstevel@tonic-gate pm_decode_cmd(int cmd)
4897c478bd9Sstevel@tonic-gate {
4907c478bd9Sstevel@tonic-gate static char invbuf[64];
4917c478bd9Sstevel@tonic-gate struct pm_cmd_info *pcip = pc_info(cmd);
4927c478bd9Sstevel@tonic-gate if (pcip != NULL)
4937c478bd9Sstevel@tonic-gate return (pcip->name);
4947c478bd9Sstevel@tonic-gate (void) sprintf(invbuf, "ioctl: invalid command %d\n", cmd);
4957c478bd9Sstevel@tonic-gate return (invbuf);
4967c478bd9Sstevel@tonic-gate }
4977c478bd9Sstevel@tonic-gate
4987c478bd9Sstevel@tonic-gate /*
4997c478bd9Sstevel@tonic-gate * Allocate scan resource, create taskq, then dispatch scan,
5007c478bd9Sstevel@tonic-gate * called only if autopm is enabled.
5017c478bd9Sstevel@tonic-gate */
5027c478bd9Sstevel@tonic-gate int
pm_start_pm_walk(dev_info_t * dip,void * arg)5037c478bd9Sstevel@tonic-gate pm_start_pm_walk(dev_info_t *dip, void *arg)
5047c478bd9Sstevel@tonic-gate {
505c42872d4Smh27603 int cmd = *((int *)arg);
5069681b4a1Skchow #ifdef PMDDEBUG
507c42872d4Smh27603 char *cmdstr = pm_decode_cmd(cmd);
5089681b4a1Skchow #endif
5097c478bd9Sstevel@tonic-gate
5107c478bd9Sstevel@tonic-gate if (!PM_GET_PM_INFO(dip) || PM_ISBC(dip))
5117c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE);
5127c478bd9Sstevel@tonic-gate
513c42872d4Smh27603 switch (cmd) {
514c42872d4Smh27603 case PM_START_CPUPM:
515*0e751525SEric Saxe case PM_START_CPUPM_POLL:
516c42872d4Smh27603 if (!PM_ISCPU(dip))
517c42872d4Smh27603 return (DDI_WALK_CONTINUE);
5187c478bd9Sstevel@tonic-gate mutex_enter(&pm_scan_lock);
519*0e751525SEric Saxe if (!PM_CPUPM_DISABLED && !PM_EVENT_CPUPM)
520c42872d4Smh27603 pm_scan_init(dip);
521c42872d4Smh27603 mutex_exit(&pm_scan_lock);
522c42872d4Smh27603 break;
523c42872d4Smh27603 case PM_START_PM:
524c42872d4Smh27603 mutex_enter(&pm_scan_lock);
525*0e751525SEric Saxe if (PM_ISCPU(dip) && (PM_CPUPM_DISABLED || PM_EVENT_CPUPM)) {
526c42872d4Smh27603 mutex_exit(&pm_scan_lock);
527c42872d4Smh27603 return (DDI_WALK_CONTINUE);
528c42872d4Smh27603 }
5297c478bd9Sstevel@tonic-gate if (autopm_enabled)
5307c478bd9Sstevel@tonic-gate pm_scan_init(dip);
5317c478bd9Sstevel@tonic-gate mutex_exit(&pm_scan_lock);
532c42872d4Smh27603 break;
533c42872d4Smh27603 }
5347c478bd9Sstevel@tonic-gate
5357c478bd9Sstevel@tonic-gate /*
5367c478bd9Sstevel@tonic-gate * Start doing pm on device: ensure pm_scan data structure initiated,
537c42872d4Smh27603 * no need to guarantee a successful scan run.
5387c478bd9Sstevel@tonic-gate */
5397c478bd9Sstevel@tonic-gate PMD(PMD_SCAN | PMD_IOCTL, ("ioctl: %s: scan %s@%s(%s#%d)\n", cmdstr,
5407c478bd9Sstevel@tonic-gate PM_DEVICE(dip)))
5417c478bd9Sstevel@tonic-gate pm_rescan(dip);
5427c478bd9Sstevel@tonic-gate
5437c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE);
5447c478bd9Sstevel@tonic-gate }
5457c478bd9Sstevel@tonic-gate
5467c478bd9Sstevel@tonic-gate /*
5477c478bd9Sstevel@tonic-gate * Bring devices to full power level, then stop scan
5487c478bd9Sstevel@tonic-gate */
5497c478bd9Sstevel@tonic-gate int
pm_stop_pm_walk(dev_info_t * dip,void * arg)5507c478bd9Sstevel@tonic-gate pm_stop_pm_walk(dev_info_t *dip, void *arg)
5517c478bd9Sstevel@tonic-gate {
5527c478bd9Sstevel@tonic-gate pm_info_t *info = PM_GET_PM_INFO(dip);
553c42872d4Smh27603 int cmd = *((int *)arg);
5549681b4a1Skchow #ifdef PMDDEBUG
555c42872d4Smh27603 char *cmdstr = pm_decode_cmd(cmd);
5569681b4a1Skchow #endif
5577c478bd9Sstevel@tonic-gate
5587c478bd9Sstevel@tonic-gate if (!info)
5597c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE);
560c42872d4Smh27603
561c42872d4Smh27603 switch (cmd) {
562c42872d4Smh27603 case PM_STOP_PM:
563c42872d4Smh27603 /*
564c42872d4Smh27603 * If CPU devices are being managed independently, then don't
565c42872d4Smh27603 * stop them as part of PM_STOP_PM. Only stop them as part of
566c42872d4Smh27603 * PM_STOP_CPUPM and PM_RESET_PM.
567c42872d4Smh27603 */
568*0e751525SEric Saxe if (PM_ISCPU(dip) && PM_POLLING_CPUPM)
569c42872d4Smh27603 return (DDI_WALK_CONTINUE);
570c42872d4Smh27603 break;
571c42872d4Smh27603 case PM_STOP_CPUPM:
572c42872d4Smh27603 /*
573c42872d4Smh27603 * If stopping CPU devices and this device is not marked
574c42872d4Smh27603 * as a CPU device, then skip.
575c42872d4Smh27603 */
576c42872d4Smh27603 if (!PM_ISCPU(dip))
577c42872d4Smh27603 return (DDI_WALK_CONTINUE);
578c42872d4Smh27603 break;
579c42872d4Smh27603 }
580c42872d4Smh27603
5817c478bd9Sstevel@tonic-gate /*
5827c478bd9Sstevel@tonic-gate * Stop the current scan, and then bring it back to normal power.
5837c478bd9Sstevel@tonic-gate */
5847c478bd9Sstevel@tonic-gate if (!PM_ISBC(dip)) {
5857c478bd9Sstevel@tonic-gate PMD(PMD_SCAN | PMD_IOCTL, ("ioctl: %s: stop scan for "
5867c478bd9Sstevel@tonic-gate "%s@%s(%s#%d)\n", cmdstr, PM_DEVICE(dip)))
5877c478bd9Sstevel@tonic-gate pm_scan_stop(dip);
5887c478bd9Sstevel@tonic-gate }
5897c478bd9Sstevel@tonic-gate
5907c478bd9Sstevel@tonic-gate if (!PM_ISBC(dip) && !PM_ISDIRECT(dip) &&
5917c478bd9Sstevel@tonic-gate !pm_all_at_normal(dip)) {
5927c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip);
5937c478bd9Sstevel@tonic-gate if (info->pmi_dev_pm_state & PM_DETACHING) {
5947c478bd9Sstevel@tonic-gate PMD(PMD_ALLNORM, ("ioctl: %s: deferring "
5957c478bd9Sstevel@tonic-gate "all_to_normal because %s@%s(%s#%d) is detaching\n",
5967c478bd9Sstevel@tonic-gate cmdstr, PM_DEVICE(dip)))
5977c478bd9Sstevel@tonic-gate info->pmi_dev_pm_state |= PM_ALLNORM_DEFERRED;
5987c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
5997c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE);
6007c478bd9Sstevel@tonic-gate }
6017c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
6027c478bd9Sstevel@tonic-gate if (pm_all_to_normal(dip, PM_CANBLOCK_FAIL) != DDI_SUCCESS) {
6037c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: could not bring %s@%s"
6047c478bd9Sstevel@tonic-gate "(%s#%d) to normal\n", cmdstr, PM_DEVICE(dip)))
6057c478bd9Sstevel@tonic-gate }
6067c478bd9Sstevel@tonic-gate }
6077c478bd9Sstevel@tonic-gate
6087c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE);
6097c478bd9Sstevel@tonic-gate }
6107c478bd9Sstevel@tonic-gate
6117c478bd9Sstevel@tonic-gate static int
pm_start_idledown(dev_info_t * dip,void * arg)6127c478bd9Sstevel@tonic-gate pm_start_idledown(dev_info_t *dip, void *arg)
6137c478bd9Sstevel@tonic-gate {
6147c478bd9Sstevel@tonic-gate int flag = (int)(intptr_t)arg;
6157c478bd9Sstevel@tonic-gate pm_scan_t *scanp = PM_GET_PM_SCAN(dip);
6167c478bd9Sstevel@tonic-gate
6177c478bd9Sstevel@tonic-gate if (!scanp)
6187c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE);
6197c478bd9Sstevel@tonic-gate
6207c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip);
6217c478bd9Sstevel@tonic-gate scanp->ps_idle_down |= flag;
6227c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
6237c478bd9Sstevel@tonic-gate pm_rescan(dip);
6247c478bd9Sstevel@tonic-gate
6257c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE);
6267c478bd9Sstevel@tonic-gate }
6277c478bd9Sstevel@tonic-gate
6287c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6297c478bd9Sstevel@tonic-gate static int
pm_end_idledown(dev_info_t * dip,void * ignore)6307c478bd9Sstevel@tonic-gate pm_end_idledown(dev_info_t *dip, void *ignore)
6317c478bd9Sstevel@tonic-gate {
6327c478bd9Sstevel@tonic-gate pm_scan_t *scanp = PM_GET_PM_SCAN(dip);
6337c478bd9Sstevel@tonic-gate
6347c478bd9Sstevel@tonic-gate if (!scanp)
6357c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE);
6367c478bd9Sstevel@tonic-gate
6377c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip);
6387c478bd9Sstevel@tonic-gate /*
6397c478bd9Sstevel@tonic-gate * The PMID_TIMERS bits are place holder till idledown expires.
6407c478bd9Sstevel@tonic-gate * The bits are also the base for regenerating PMID_SCANS bits.
6417c478bd9Sstevel@tonic-gate * While it's up to scan thread to clear up the PMID_SCANS bits
6427c478bd9Sstevel@tonic-gate * after each scan run, PMID_TIMERS ensure aggressive scan down
6437c478bd9Sstevel@tonic-gate * performance throughout the idledown period.
6447c478bd9Sstevel@tonic-gate */
6457c478bd9Sstevel@tonic-gate scanp->ps_idle_down &= ~PMID_TIMERS;
6467c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
6477c478bd9Sstevel@tonic-gate
6487c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE);
6497c478bd9Sstevel@tonic-gate }
6507c478bd9Sstevel@tonic-gate
6517c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6527c478bd9Sstevel@tonic-gate static void
pm_end_idledown_walk(void * ignore)6537c478bd9Sstevel@tonic-gate pm_end_idledown_walk(void *ignore)
6547c478bd9Sstevel@tonic-gate {
6557c478bd9Sstevel@tonic-gate PMD(PMD_IDLEDOWN, ("ioctl: end_idledown: idledown_id(%lx) timer is "
6567c478bd9Sstevel@tonic-gate "off\n", (ulong_t)pmstp->pm_idledown_id));
6577c478bd9Sstevel@tonic-gate
6587c478bd9Sstevel@tonic-gate mutex_enter(&pm_scan_lock);
6597c478bd9Sstevel@tonic-gate pmstp->pm_idledown_id = 0;
6607c478bd9Sstevel@tonic-gate mutex_exit(&pm_scan_lock);
6617c478bd9Sstevel@tonic-gate
6627c478bd9Sstevel@tonic-gate ddi_walk_devs(ddi_root_node(), pm_end_idledown, NULL);
6637c478bd9Sstevel@tonic-gate }
6647c478bd9Sstevel@tonic-gate
6657c478bd9Sstevel@tonic-gate /*
6667c478bd9Sstevel@tonic-gate * pm_timeout_idledown - keep idledown effect for 10 seconds.
6677c478bd9Sstevel@tonic-gate *
6687c478bd9Sstevel@tonic-gate * Return 0 if another competing caller scheduled idledown timeout,
6697c478bd9Sstevel@tonic-gate * otherwise, return idledown timeout_id.
6707c478bd9Sstevel@tonic-gate */
6717c478bd9Sstevel@tonic-gate static timeout_id_t
pm_timeout_idledown(void)6727c478bd9Sstevel@tonic-gate pm_timeout_idledown(void)
6737c478bd9Sstevel@tonic-gate {
6747c478bd9Sstevel@tonic-gate timeout_id_t to_id;
6757c478bd9Sstevel@tonic-gate
6767c478bd9Sstevel@tonic-gate /*
6777c478bd9Sstevel@tonic-gate * Keep idle-down in effect for either 10 seconds
6787c478bd9Sstevel@tonic-gate * or length of a scan interval, which ever is greater.
6797c478bd9Sstevel@tonic-gate */
6807c478bd9Sstevel@tonic-gate mutex_enter(&pm_scan_lock);
6817c478bd9Sstevel@tonic-gate if (pmstp->pm_idledown_id != 0) {
6827c478bd9Sstevel@tonic-gate to_id = pmstp->pm_idledown_id;
6837c478bd9Sstevel@tonic-gate pmstp->pm_idledown_id = 0;
6847c478bd9Sstevel@tonic-gate mutex_exit(&pm_scan_lock);
6857c478bd9Sstevel@tonic-gate (void) untimeout(to_id);
6867c478bd9Sstevel@tonic-gate mutex_enter(&pm_scan_lock);
6877c478bd9Sstevel@tonic-gate if (pmstp->pm_idledown_id != 0) {
6887c478bd9Sstevel@tonic-gate PMD(PMD_IDLEDOWN, ("ioctl: timeout_idledown: "
6897c478bd9Sstevel@tonic-gate "another caller got it, idledown_id(%lx)!\n",
6907c478bd9Sstevel@tonic-gate (ulong_t)pmstp->pm_idledown_id))
6917c478bd9Sstevel@tonic-gate mutex_exit(&pm_scan_lock);
6927c478bd9Sstevel@tonic-gate return (0);
6937c478bd9Sstevel@tonic-gate }
6947c478bd9Sstevel@tonic-gate }
6957c478bd9Sstevel@tonic-gate pmstp->pm_idledown_id = timeout(pm_end_idledown_walk, NULL,
6967c478bd9Sstevel@tonic-gate PM_IDLEDOWN_TIME * hz);
6977c478bd9Sstevel@tonic-gate PMD(PMD_IDLEDOWN, ("ioctl: timeout_idledown: idledown_id(%lx)\n",
6987c478bd9Sstevel@tonic-gate (ulong_t)pmstp->pm_idledown_id))
6997c478bd9Sstevel@tonic-gate mutex_exit(&pm_scan_lock);
7007c478bd9Sstevel@tonic-gate
7017c478bd9Sstevel@tonic-gate return (pmstp->pm_idledown_id);
7027c478bd9Sstevel@tonic-gate }
7037c478bd9Sstevel@tonic-gate
7047c478bd9Sstevel@tonic-gate static int
pm_chpoll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)7057c478bd9Sstevel@tonic-gate pm_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
7067c478bd9Sstevel@tonic-gate struct pollhead **phpp)
7077c478bd9Sstevel@tonic-gate {
7087c478bd9Sstevel@tonic-gate extern struct pollhead pm_pollhead; /* common/os/sunpm.c */
7097c478bd9Sstevel@tonic-gate int clone;
7107c478bd9Sstevel@tonic-gate
7117c478bd9Sstevel@tonic-gate clone = PM_MINOR_TO_CLONE(getminor(dev));
7127c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: pm_chpoll: clone %d\n", clone))
7137c478bd9Sstevel@tonic-gate if ((events & (POLLIN | POLLRDNORM)) && pm_poll_cnt[clone]) {
7147c478bd9Sstevel@tonic-gate *reventsp |= (POLLIN | POLLRDNORM);
7157c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: pm_chpoll: reventsp set\n"))
7167c478bd9Sstevel@tonic-gate } else {
7177c478bd9Sstevel@tonic-gate *reventsp = 0;
7187c478bd9Sstevel@tonic-gate if (!anyyet) {
7197c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: pm_chpoll: not anyyet\n"))
7207c478bd9Sstevel@tonic-gate *phpp = &pm_pollhead;
7217c478bd9Sstevel@tonic-gate }
7227c478bd9Sstevel@tonic-gate #ifdef DEBUG
7237c478bd9Sstevel@tonic-gate else {
7247c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: pm_chpoll: anyyet\n"))
7257c478bd9Sstevel@tonic-gate }
7267c478bd9Sstevel@tonic-gate #endif
7277c478bd9Sstevel@tonic-gate }
7287c478bd9Sstevel@tonic-gate return (0);
7297c478bd9Sstevel@tonic-gate }
7307c478bd9Sstevel@tonic-gate
7317c478bd9Sstevel@tonic-gate /*
7327c478bd9Sstevel@tonic-gate * called by pm_dicard_entries to free up the memory. It also decrements
7337c478bd9Sstevel@tonic-gate * pm_poll_cnt, if direct is non zero.
7347c478bd9Sstevel@tonic-gate */
7357c478bd9Sstevel@tonic-gate static void
pm_free_entries(psce_t * pscep,int clone,int direct)7367c478bd9Sstevel@tonic-gate pm_free_entries(psce_t *pscep, int clone, int direct)
7377c478bd9Sstevel@tonic-gate {
7387c478bd9Sstevel@tonic-gate pm_state_change_t *p;
7397c478bd9Sstevel@tonic-gate
7407c478bd9Sstevel@tonic-gate if (pscep) {
7417c478bd9Sstevel@tonic-gate p = pscep->psce_out;
7427c478bd9Sstevel@tonic-gate while (p->size) {
7437c478bd9Sstevel@tonic-gate if (direct) {
7447c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: discard: "
7457c478bd9Sstevel@tonic-gate "pm_poll_cnt[%d] is %d before "
7467c478bd9Sstevel@tonic-gate "ASSERT\n", clone,
7477c478bd9Sstevel@tonic-gate pm_poll_cnt[clone]))
7487c478bd9Sstevel@tonic-gate ASSERT(pm_poll_cnt[clone]);
7497c478bd9Sstevel@tonic-gate pm_poll_cnt[clone]--;
7507c478bd9Sstevel@tonic-gate }
7517c478bd9Sstevel@tonic-gate kmem_free(p->physpath, p->size);
7527c478bd9Sstevel@tonic-gate p->size = 0;
7537c478bd9Sstevel@tonic-gate if (p == pscep->psce_last)
7547c478bd9Sstevel@tonic-gate p = pscep->psce_first;
7557c478bd9Sstevel@tonic-gate else
7567c478bd9Sstevel@tonic-gate p++;
7577c478bd9Sstevel@tonic-gate }
7587c478bd9Sstevel@tonic-gate pscep->psce_out = pscep->psce_first;
7597c478bd9Sstevel@tonic-gate pscep->psce_in = pscep->psce_first;
7607c478bd9Sstevel@tonic-gate mutex_exit(&pscep->psce_lock);
7617c478bd9Sstevel@tonic-gate }
7627c478bd9Sstevel@tonic-gate }
7637c478bd9Sstevel@tonic-gate
7647c478bd9Sstevel@tonic-gate /*
7657c478bd9Sstevel@tonic-gate * Discard entries for this clone. Calls pm_free_entries to free up memory.
7667c478bd9Sstevel@tonic-gate */
7677c478bd9Sstevel@tonic-gate static void
pm_discard_entries(int clone)7687c478bd9Sstevel@tonic-gate pm_discard_entries(int clone)
7697c478bd9Sstevel@tonic-gate {
7707c478bd9Sstevel@tonic-gate psce_t *pscep;
7717c478bd9Sstevel@tonic-gate int direct = 0;
7727c478bd9Sstevel@tonic-gate
7737c478bd9Sstevel@tonic-gate mutex_enter(&pm_clone_lock);
7747c478bd9Sstevel@tonic-gate if ((pscep = pm_psc_clone_to_direct(clone)) != NULL)
7757c478bd9Sstevel@tonic-gate direct = 1;
7767c478bd9Sstevel@tonic-gate pm_free_entries(pscep, clone, direct);
7777c478bd9Sstevel@tonic-gate pscep = pm_psc_clone_to_interest(clone);
7787c478bd9Sstevel@tonic-gate pm_free_entries(pscep, clone, 0);
7797c478bd9Sstevel@tonic-gate mutex_exit(&pm_clone_lock);
7807c478bd9Sstevel@tonic-gate }
7817c478bd9Sstevel@tonic-gate
782c42872d4Smh27603
783c42872d4Smh27603 static void
pm_set_idle_threshold(dev_info_t * dip,int thresh,int flag)784c42872d4Smh27603 pm_set_idle_threshold(dev_info_t *dip, int thresh, int flag)
7857c478bd9Sstevel@tonic-gate {
7867c478bd9Sstevel@tonic-gate if (!PM_ISBC(dip) && !PM_ISDIRECT(dip)) {
7877c478bd9Sstevel@tonic-gate switch (DEVI(dip)->devi_pm_flags & PMC_THRESH_ALL) {
7887c478bd9Sstevel@tonic-gate case PMC_DEF_THRESH:
789c42872d4Smh27603 case PMC_CPU_THRESH:
790c42872d4Smh27603 PMD(PMD_IOCTL, ("ioctl: set_idle_threshold: set "
7917c478bd9Sstevel@tonic-gate "%s@%s(%s#%d) default thresh to 0t%d\n",
792c42872d4Smh27603 PM_DEVICE(dip), thresh))
793c42872d4Smh27603 pm_set_device_threshold(dip, thresh, flag);
7947c478bd9Sstevel@tonic-gate break;
7957c478bd9Sstevel@tonic-gate default:
7967c478bd9Sstevel@tonic-gate break;
7977c478bd9Sstevel@tonic-gate }
7987c478bd9Sstevel@tonic-gate }
799c42872d4Smh27603 }
8007c478bd9Sstevel@tonic-gate
801c42872d4Smh27603 static int
pm_set_idle_thresh_walk(dev_info_t * dip,void * arg)802c42872d4Smh27603 pm_set_idle_thresh_walk(dev_info_t *dip, void *arg)
803c42872d4Smh27603 {
804c42872d4Smh27603 int cmd = *((int *)arg);
805c42872d4Smh27603
806c42872d4Smh27603 if (!PM_GET_PM_INFO(dip))
807c42872d4Smh27603 return (DDI_WALK_CONTINUE);
808c42872d4Smh27603
809c42872d4Smh27603 switch (cmd) {
810c42872d4Smh27603 case PM_SET_SYSTEM_THRESHOLD:
811c42872d4Smh27603 if (DEVI(dip)->devi_pm_flags & PMC_CPU_THRESH)
812c42872d4Smh27603 break;
813c42872d4Smh27603 pm_set_idle_threshold(dip, pm_system_idle_threshold,
814c42872d4Smh27603 PMC_DEF_THRESH);
8157c478bd9Sstevel@tonic-gate pm_rescan(dip);
816c42872d4Smh27603 break;
817c42872d4Smh27603 case PM_SET_CPU_THRESHOLD:
818c42872d4Smh27603 if (!PM_ISCPU(dip))
819c42872d4Smh27603 break;
820c42872d4Smh27603 pm_set_idle_threshold(dip, pm_cpu_idle_threshold,
821c42872d4Smh27603 PMC_CPU_THRESH);
822c42872d4Smh27603 pm_rescan(dip);
823c42872d4Smh27603 break;
824c42872d4Smh27603 }
8257c478bd9Sstevel@tonic-gate
8267c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE);
8277c478bd9Sstevel@tonic-gate }
8287c478bd9Sstevel@tonic-gate
8297c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8307c478bd9Sstevel@tonic-gate static int
pm_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)8317c478bd9Sstevel@tonic-gate pm_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
8327c478bd9Sstevel@tonic-gate {
8337c478bd9Sstevel@tonic-gate dev_t dev;
8347c478bd9Sstevel@tonic-gate int instance;
8357c478bd9Sstevel@tonic-gate
8367c478bd9Sstevel@tonic-gate switch (infocmd) {
8377c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO:
8387c478bd9Sstevel@tonic-gate if (pmstp->pm_instance == -1)
8397c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
8407c478bd9Sstevel@tonic-gate *result = pmstp->pm_dip;
8417c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
8427c478bd9Sstevel@tonic-gate
8437c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE:
8447c478bd9Sstevel@tonic-gate dev = (dev_t)arg;
8457c478bd9Sstevel@tonic-gate instance = getminor(dev) >> 8;
8467c478bd9Sstevel@tonic-gate *result = (void *)(uintptr_t)instance;
8477c478bd9Sstevel@tonic-gate return (DDI_SUCCESS);
8487c478bd9Sstevel@tonic-gate
8497c478bd9Sstevel@tonic-gate default:
8507c478bd9Sstevel@tonic-gate return (DDI_FAILURE);
8517c478bd9Sstevel@tonic-gate }
8527c478bd9Sstevel@tonic-gate }
8537c478bd9Sstevel@tonic-gate
8547c478bd9Sstevel@tonic-gate
8557c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
8567c478bd9Sstevel@tonic-gate static int
pm_open(dev_t * devp,int flag,int otyp,cred_t * cr)8577c478bd9Sstevel@tonic-gate pm_open(dev_t *devp, int flag, int otyp, cred_t *cr)
8587c478bd9Sstevel@tonic-gate {
8597c478bd9Sstevel@tonic-gate int clone;
8607c478bd9Sstevel@tonic-gate
8617c478bd9Sstevel@tonic-gate if (otyp != OTYP_CHR)
8627c478bd9Sstevel@tonic-gate return (EINVAL);
8637c478bd9Sstevel@tonic-gate
8647c478bd9Sstevel@tonic-gate mutex_enter(&pm_clone_lock);
8657c478bd9Sstevel@tonic-gate for (clone = 1; clone < PM_MAX_CLONE; clone++)
8667c478bd9Sstevel@tonic-gate if (!pmstp->pm_clones[clone])
8677c478bd9Sstevel@tonic-gate break;
8687c478bd9Sstevel@tonic-gate
8697c478bd9Sstevel@tonic-gate if (clone == PM_MAX_CLONE) {
8707c478bd9Sstevel@tonic-gate mutex_exit(&pm_clone_lock);
8717c478bd9Sstevel@tonic-gate return (ENXIO);
8727c478bd9Sstevel@tonic-gate }
8737c478bd9Sstevel@tonic-gate pmstp->pm_cred[clone] = cr;
8747c478bd9Sstevel@tonic-gate crhold(cr);
8757c478bd9Sstevel@tonic-gate
8767c478bd9Sstevel@tonic-gate *devp = makedevice(getmajor(*devp), (pmstp->pm_instance << 8) + clone);
8777c478bd9Sstevel@tonic-gate pmstp->pm_clones[clone] = 1;
8787c478bd9Sstevel@tonic-gate mutex_exit(&pm_clone_lock);
8797c478bd9Sstevel@tonic-gate
8807c478bd9Sstevel@tonic-gate return (0);
8817c478bd9Sstevel@tonic-gate }
8827c478bd9Sstevel@tonic-gate
8837c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
8847c478bd9Sstevel@tonic-gate static int
pm_close(dev_t dev,int flag,int otyp,cred_t * cr)8857c478bd9Sstevel@tonic-gate pm_close(dev_t dev, int flag, int otyp, cred_t *cr)
8867c478bd9Sstevel@tonic-gate {
8877c478bd9Sstevel@tonic-gate int clone;
8887c478bd9Sstevel@tonic-gate
8897c478bd9Sstevel@tonic-gate if (otyp != OTYP_CHR)
8907c478bd9Sstevel@tonic-gate return (EINVAL);
8917c478bd9Sstevel@tonic-gate
8927c478bd9Sstevel@tonic-gate clone = PM_MINOR_TO_CLONE(getminor(dev));
8937c478bd9Sstevel@tonic-gate PMD(PMD_CLOSE, ("pm_close: minor %x, clone %x\n", getminor(dev),
8947c478bd9Sstevel@tonic-gate clone))
8957c478bd9Sstevel@tonic-gate
8967c478bd9Sstevel@tonic-gate /*
8977c478bd9Sstevel@tonic-gate * Walk the entire device tree to find the corresponding
8987c478bd9Sstevel@tonic-gate * device and operate on it.
8997c478bd9Sstevel@tonic-gate */
9007c478bd9Sstevel@tonic-gate ddi_walk_devs(ddi_root_node(), pm_close_direct_pm_device,
9017c478bd9Sstevel@tonic-gate (void *) &clone);
9027c478bd9Sstevel@tonic-gate
9037c478bd9Sstevel@tonic-gate crfree(pmstp->pm_cred[clone]);
9047c478bd9Sstevel@tonic-gate pmstp->pm_cred[clone] = 0;
9057c478bd9Sstevel@tonic-gate pmstp->pm_clones[clone] = 0;
9067c478bd9Sstevel@tonic-gate pm_discard_entries(clone);
9077c478bd9Sstevel@tonic-gate ASSERT(pm_poll_cnt[clone] == 0);
9087c478bd9Sstevel@tonic-gate pm_deregister_watcher(clone, NULL);
9097c478bd9Sstevel@tonic-gate return (0);
9107c478bd9Sstevel@tonic-gate }
9117c478bd9Sstevel@tonic-gate
9127c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9137c478bd9Sstevel@tonic-gate static int
pm_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cr,int * rval_p)9147c478bd9Sstevel@tonic-gate pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)
9157c478bd9Sstevel@tonic-gate {
9167c478bd9Sstevel@tonic-gate struct pm_cmd_info *pc_info(int);
9177c478bd9Sstevel@tonic-gate struct pm_cmd_info *pcip = pc_info(cmd);
9187c478bd9Sstevel@tonic-gate pm_req_t req;
9197c478bd9Sstevel@tonic-gate dev_info_t *dip = NULL;
9207c478bd9Sstevel@tonic-gate pm_info_t *info = NULL;
9217c478bd9Sstevel@tonic-gate int clone;
9227c478bd9Sstevel@tonic-gate char *cmdstr = pm_decode_cmd(cmd);
9237c478bd9Sstevel@tonic-gate /*
9247c478bd9Sstevel@tonic-gate * To keep devinfo nodes from going away while we're holding a
9257c478bd9Sstevel@tonic-gate * pointer to their dip, pm_name_to_dip() optionally holds
9267c478bd9Sstevel@tonic-gate * the devinfo node. If we've done that, we set dipheld
9277c478bd9Sstevel@tonic-gate * so we know at the end of the ioctl processing to release the
9287c478bd9Sstevel@tonic-gate * node again.
9297c478bd9Sstevel@tonic-gate */
9307c478bd9Sstevel@tonic-gate int dipheld = 0;
9317c478bd9Sstevel@tonic-gate int icount = 0;
9327c478bd9Sstevel@tonic-gate int i;
9337c478bd9Sstevel@tonic-gate int comps;
9347c478bd9Sstevel@tonic-gate size_t lencopied;
9357c478bd9Sstevel@tonic-gate int ret = ENOTTY;
9367c478bd9Sstevel@tonic-gate int curpower;
9377c478bd9Sstevel@tonic-gate char who[MAXNAMELEN];
9387c478bd9Sstevel@tonic-gate size_t wholen; /* copyinstr length */
9397c478bd9Sstevel@tonic-gate size_t deplen = MAXNAMELEN;
9407c478bd9Sstevel@tonic-gate char *dep, i_dep_buf[MAXNAMELEN];
9412df1fe9cSrandyf char pathbuf[MAXNAMELEN];
9427c478bd9Sstevel@tonic-gate struct pm_component *cp;
9437c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
9447c478bd9Sstevel@tonic-gate pm_state_change32_t *pscp32;
9457c478bd9Sstevel@tonic-gate pm_state_change32_t psc32;
9462df1fe9cSrandyf pm_searchargs32_t psa32;
9477c478bd9Sstevel@tonic-gate size_t copysize32;
9487c478bd9Sstevel@tonic-gate #endif
9497c478bd9Sstevel@tonic-gate pm_state_change_t *pscp;
9507c478bd9Sstevel@tonic-gate pm_state_change_t psc;
9512df1fe9cSrandyf pm_searchargs_t psa;
9522df1fe9cSrandyf char listname[MAXCOPYBUF];
9532df1fe9cSrandyf char manufacturer[MAXCOPYBUF];
9542df1fe9cSrandyf char product[MAXCOPYBUF];
9557c478bd9Sstevel@tonic-gate size_t copysize;
9567c478bd9Sstevel@tonic-gate
9577c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: %s: begin\n", cmdstr))
9587c478bd9Sstevel@tonic-gate
9597c478bd9Sstevel@tonic-gate #ifdef DEBUG
9607c478bd9Sstevel@tonic-gate if (cmd == 666) {
9617c478bd9Sstevel@tonic-gate ddi_walk_devs(ddi_root_node(), print_info, NULL);
9627c478bd9Sstevel@tonic-gate return (0);
9637c478bd9Sstevel@tonic-gate }
9647c478bd9Sstevel@tonic-gate ret = 0x0badcafe; /* sanity checking */
9657c478bd9Sstevel@tonic-gate pm_cmd = cmd; /* for ASSERT debugging */
9667c478bd9Sstevel@tonic-gate pm_cmd_string = cmdstr; /* for ASSERT debugging */
9677c478bd9Sstevel@tonic-gate #endif
9687c478bd9Sstevel@tonic-gate
9697c478bd9Sstevel@tonic-gate
9707c478bd9Sstevel@tonic-gate if (pcip == NULL) {
9717c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: unknown command %d\n", cmd))
9727c478bd9Sstevel@tonic-gate return (ENOTTY);
9737c478bd9Sstevel@tonic-gate }
9747c478bd9Sstevel@tonic-gate if (pcip == NULL || pcip->supported == 0) {
9757c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: command %s no longer supported\n",
9767c478bd9Sstevel@tonic-gate pcip->name))
9777c478bd9Sstevel@tonic-gate return (ENOTTY);
9787c478bd9Sstevel@tonic-gate }
9797c478bd9Sstevel@tonic-gate
9807c478bd9Sstevel@tonic-gate wholen = 0;
9817c478bd9Sstevel@tonic-gate dep = i_dep_buf;
9827c478bd9Sstevel@tonic-gate i_dep_buf[0] = 0;
9837c478bd9Sstevel@tonic-gate clone = PM_MINOR_TO_CLONE(getminor(dev));
9847c478bd9Sstevel@tonic-gate if (!pm_perms(pcip->permission, pmstp->pm_cred[clone])) {
9857c478bd9Sstevel@tonic-gate ret = EPERM;
9867c478bd9Sstevel@tonic-gate return (ret);
9877c478bd9Sstevel@tonic-gate }
9887c478bd9Sstevel@tonic-gate switch (pcip->str_type) {
9897c478bd9Sstevel@tonic-gate case PM_REQ:
9902df1fe9cSrandyf {
9917c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
9927c478bd9Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
9937c478bd9Sstevel@tonic-gate pm_req32_t req32;
9947c478bd9Sstevel@tonic-gate
9957c478bd9Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg, &req32,
9967c478bd9Sstevel@tonic-gate sizeof (req32), mode) != 0) {
9977c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin "
9987c478bd9Sstevel@tonic-gate "EFAULT\n\n", cmdstr))
9997c478bd9Sstevel@tonic-gate ret = EFAULT;
10007c478bd9Sstevel@tonic-gate break;
10017c478bd9Sstevel@tonic-gate }
10027c478bd9Sstevel@tonic-gate req.component = req32.component;
10037c478bd9Sstevel@tonic-gate req.value = req32.value;
10047c478bd9Sstevel@tonic-gate req.datasize = req32.datasize;
10057c478bd9Sstevel@tonic-gate if (pcip->inargs & INWHO) {
10067c478bd9Sstevel@tonic-gate ret = copyinstr((char *)(uintptr_t)
10077c478bd9Sstevel@tonic-gate req32.physpath, who, MAXNAMELEN, &wholen);
10087c478bd9Sstevel@tonic-gate if (ret) {
10097c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: "
10107c478bd9Sstevel@tonic-gate "copyinstr fails returning %d\n",
10117c478bd9Sstevel@tonic-gate cmdstr, ret))
10127c478bd9Sstevel@tonic-gate break;
10137c478bd9Sstevel@tonic-gate }
10147c478bd9Sstevel@tonic-gate req.physpath = who;
10152df1fe9cSrandyf PMD(PMD_IOCTL, ("ioctl: %s: physpath=%s\n",
10162df1fe9cSrandyf cmdstr, req.physpath))
10177c478bd9Sstevel@tonic-gate }
10187c478bd9Sstevel@tonic-gate if (pcip->inargs & INDATA) {
10197c478bd9Sstevel@tonic-gate req.data = (void *)(uintptr_t)req32.data;
10207c478bd9Sstevel@tonic-gate req.datasize = req32.datasize;
10217c478bd9Sstevel@tonic-gate } else {
10227c478bd9Sstevel@tonic-gate req.data = NULL;
10237c478bd9Sstevel@tonic-gate req.datasize = 0;
10247c478bd9Sstevel@tonic-gate }
10257c478bd9Sstevel@tonic-gate switch (pcip->diptype) {
10267c478bd9Sstevel@tonic-gate case DIP:
10277c478bd9Sstevel@tonic-gate if (!(dip =
10287c478bd9Sstevel@tonic-gate pm_name_to_dip(req.physpath, 1))) {
10297c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: "
10307c478bd9Sstevel@tonic-gate "pm_name_to_dip for %s failed\n",
10317c478bd9Sstevel@tonic-gate cmdstr, req.physpath))
10327c478bd9Sstevel@tonic-gate return (ENODEV);
10337c478bd9Sstevel@tonic-gate }
10347c478bd9Sstevel@tonic-gate ASSERT(!dipheld);
10357c478bd9Sstevel@tonic-gate dipheld++;
10367c478bd9Sstevel@tonic-gate break;
10377c478bd9Sstevel@tonic-gate case NODIP:
10387c478bd9Sstevel@tonic-gate break;
10397c478bd9Sstevel@tonic-gate default:
10407c478bd9Sstevel@tonic-gate /*
10417c478bd9Sstevel@tonic-gate * Internal error, invalid ioctl description
10427c478bd9Sstevel@tonic-gate * force debug entry even if pm_debug not set
10437c478bd9Sstevel@tonic-gate */
10447c478bd9Sstevel@tonic-gate #ifdef DEBUG
10457c478bd9Sstevel@tonic-gate pm_log("invalid diptype %d for cmd %d (%s)\n",
10467c478bd9Sstevel@tonic-gate pcip->diptype, cmd, pcip->name);
10477c478bd9Sstevel@tonic-gate #endif
10487c478bd9Sstevel@tonic-gate ASSERT(0);
10497c478bd9Sstevel@tonic-gate return (EIO);
10507c478bd9Sstevel@tonic-gate }
10517c478bd9Sstevel@tonic-gate if (pcip->inargs & INDATAINT) {
10527c478bd9Sstevel@tonic-gate int32_t int32buf;
10537c478bd9Sstevel@tonic-gate int32_t *i32p;
10547c478bd9Sstevel@tonic-gate int *ip;
10557c478bd9Sstevel@tonic-gate icount = req32.datasize / sizeof (int32_t);
10567c478bd9Sstevel@tonic-gate if (icount <= 0) {
10577c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: datasize"
10587c478bd9Sstevel@tonic-gate " 0 or neg EFAULT\n\n", cmdstr))
10597c478bd9Sstevel@tonic-gate ret = EFAULT;
10607c478bd9Sstevel@tonic-gate break;
10617c478bd9Sstevel@tonic-gate }
10627c478bd9Sstevel@tonic-gate ASSERT(!(pcip->inargs & INDATASTRING));
10637c478bd9Sstevel@tonic-gate req.datasize = icount * sizeof (int);
10647c478bd9Sstevel@tonic-gate req.data = kmem_alloc(req.datasize, KM_SLEEP);
10657c478bd9Sstevel@tonic-gate ip = req.data;
10667c478bd9Sstevel@tonic-gate ret = 0;
10677c478bd9Sstevel@tonic-gate for (i = 0,
10687c478bd9Sstevel@tonic-gate i32p = (int32_t *)(uintptr_t)req32.data;
10697c478bd9Sstevel@tonic-gate i < icount; i++, i32p++) {
10707c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)i32p, &int32buf,
10717c478bd9Sstevel@tonic-gate sizeof (int32_t), mode)) {
10727c478bd9Sstevel@tonic-gate kmem_free(req.data,
10737c478bd9Sstevel@tonic-gate req.datasize);
10747c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: "
10757c478bd9Sstevel@tonic-gate "entry %d EFAULT\n",
10767c478bd9Sstevel@tonic-gate cmdstr, i))
10777c478bd9Sstevel@tonic-gate ret = EFAULT;
10787c478bd9Sstevel@tonic-gate break;
10797c478bd9Sstevel@tonic-gate }
10807c478bd9Sstevel@tonic-gate *ip++ = (int)int32buf;
10817c478bd9Sstevel@tonic-gate }
10827c478bd9Sstevel@tonic-gate if (ret)
10837c478bd9Sstevel@tonic-gate break;
10847c478bd9Sstevel@tonic-gate }
10857c478bd9Sstevel@tonic-gate if (pcip->inargs & INDATASTRING) {
10867c478bd9Sstevel@tonic-gate ASSERT(!(pcip->inargs & INDATAINT));
10877c478bd9Sstevel@tonic-gate ASSERT(pcip->deptype == DEP);
10887c478bd9Sstevel@tonic-gate if (req32.data != NULL) {
10897c478bd9Sstevel@tonic-gate if (copyinstr((void *)(uintptr_t)
10902df1fe9cSrandyf req32.data, dep, deplen, NULL)) {
10917c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: "
10927c478bd9Sstevel@tonic-gate "0x%p dep size %lx, EFAULT"
10937c478bd9Sstevel@tonic-gate "\n", cmdstr,
10947c478bd9Sstevel@tonic-gate (void *)req.data, deplen))
10957c478bd9Sstevel@tonic-gate ret = EFAULT;
10967c478bd9Sstevel@tonic-gate break;
10977c478bd9Sstevel@tonic-gate }
10987c478bd9Sstevel@tonic-gate #ifdef DEBUG
10997c478bd9Sstevel@tonic-gate else {
11007c478bd9Sstevel@tonic-gate PMD(PMD_DEP, ("ioctl: %s: "
11017c478bd9Sstevel@tonic-gate "dep %s\n", cmdstr, dep))
11027c478bd9Sstevel@tonic-gate }
11037c478bd9Sstevel@tonic-gate #endif
11047c478bd9Sstevel@tonic-gate } else {
11057c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: no "
11067c478bd9Sstevel@tonic-gate "dependent\n", cmdstr))
11077c478bd9Sstevel@tonic-gate ret = EINVAL;
11087c478bd9Sstevel@tonic-gate break;
11097c478bd9Sstevel@tonic-gate }
11107c478bd9Sstevel@tonic-gate }
11117c478bd9Sstevel@tonic-gate } else
11127c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
11137c478bd9Sstevel@tonic-gate {
11147c478bd9Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg,
11157c478bd9Sstevel@tonic-gate &req, sizeof (req), mode) != 0) {
11167c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin "
11177c478bd9Sstevel@tonic-gate "EFAULT\n\n", cmdstr))
11187c478bd9Sstevel@tonic-gate ret = EFAULT;
11197c478bd9Sstevel@tonic-gate break;
11207c478bd9Sstevel@tonic-gate }
11217c478bd9Sstevel@tonic-gate if (pcip->inargs & INWHO) {
11227c478bd9Sstevel@tonic-gate ret = copyinstr((char *)req.physpath, who,
11237c478bd9Sstevel@tonic-gate MAXNAMELEN, &wholen);
11247c478bd9Sstevel@tonic-gate if (ret) {
11257c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s copyinstr"
11267c478bd9Sstevel@tonic-gate " fails returning %d\n", cmdstr,
11277c478bd9Sstevel@tonic-gate ret))
11287c478bd9Sstevel@tonic-gate break;
11297c478bd9Sstevel@tonic-gate }
11307c478bd9Sstevel@tonic-gate req.physpath = who;
11312df1fe9cSrandyf PMD(PMD_IOCTL, ("ioctl: %s: physpath=%s\n",
11322df1fe9cSrandyf cmdstr, req.physpath))
11337c478bd9Sstevel@tonic-gate }
11347c478bd9Sstevel@tonic-gate if (!(pcip->inargs & INDATA)) {
11357c478bd9Sstevel@tonic-gate req.data = NULL;
11367c478bd9Sstevel@tonic-gate req.datasize = 0;
11377c478bd9Sstevel@tonic-gate }
11387c478bd9Sstevel@tonic-gate switch (pcip->diptype) {
11397c478bd9Sstevel@tonic-gate case DIP:
11407c478bd9Sstevel@tonic-gate if (!(dip =
11417c478bd9Sstevel@tonic-gate pm_name_to_dip(req.physpath, 1))) {
11427c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: "
11437c478bd9Sstevel@tonic-gate "pm_name_to_dip for %s failed\n",
11447c478bd9Sstevel@tonic-gate cmdstr, req.physpath))
11457c478bd9Sstevel@tonic-gate return (ENODEV);
11467c478bd9Sstevel@tonic-gate }
11477c478bd9Sstevel@tonic-gate ASSERT(!dipheld);
11487c478bd9Sstevel@tonic-gate dipheld++;
11497c478bd9Sstevel@tonic-gate break;
11507c478bd9Sstevel@tonic-gate case NODIP:
11517c478bd9Sstevel@tonic-gate break;
11527c478bd9Sstevel@tonic-gate default:
11537c478bd9Sstevel@tonic-gate /*
11547c478bd9Sstevel@tonic-gate * Internal error, invalid ioctl description
11557c478bd9Sstevel@tonic-gate * force debug entry even if pm_debug not set
11567c478bd9Sstevel@tonic-gate */
11577c478bd9Sstevel@tonic-gate #ifdef DEBUG
11587c478bd9Sstevel@tonic-gate pm_log("invalid diptype %d for cmd %d (%s)\n",
11597c478bd9Sstevel@tonic-gate pcip->diptype, cmd, pcip->name);
11607c478bd9Sstevel@tonic-gate #endif
11617c478bd9Sstevel@tonic-gate ASSERT(0);
11627c478bd9Sstevel@tonic-gate return (EIO);
11637c478bd9Sstevel@tonic-gate }
11647c478bd9Sstevel@tonic-gate if (pcip->inargs & INDATAINT) {
11657c478bd9Sstevel@tonic-gate int *ip;
11667c478bd9Sstevel@tonic-gate
11677c478bd9Sstevel@tonic-gate ASSERT(!(pcip->inargs & INDATASTRING));
11687c478bd9Sstevel@tonic-gate ip = req.data;
11697c478bd9Sstevel@tonic-gate icount = req.datasize / sizeof (int);
11707c478bd9Sstevel@tonic-gate if (icount <= 0) {
11717c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: datasize"
11727c478bd9Sstevel@tonic-gate " 0 or neg EFAULT\n\n", cmdstr))
11737c478bd9Sstevel@tonic-gate ret = EFAULT;
11747c478bd9Sstevel@tonic-gate break;
11757c478bd9Sstevel@tonic-gate }
11767c478bd9Sstevel@tonic-gate req.data = kmem_alloc(req.datasize, KM_SLEEP);
11777c478bd9Sstevel@tonic-gate if (ddi_copyin((caddr_t)ip, req.data,
11787c478bd9Sstevel@tonic-gate req.datasize, mode) != 0) {
11797c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin "
11807c478bd9Sstevel@tonic-gate "EFAULT\n\n", cmdstr))
11817c478bd9Sstevel@tonic-gate ret = EFAULT;
11827c478bd9Sstevel@tonic-gate break;
11837c478bd9Sstevel@tonic-gate }
11847c478bd9Sstevel@tonic-gate }
11857c478bd9Sstevel@tonic-gate if (pcip->inargs & INDATASTRING) {
11867c478bd9Sstevel@tonic-gate ASSERT(!(pcip->inargs & INDATAINT));
11877c478bd9Sstevel@tonic-gate ASSERT(pcip->deptype == DEP);
11887c478bd9Sstevel@tonic-gate if (req.data != NULL) {
11897c478bd9Sstevel@tonic-gate if (copyinstr((caddr_t)req.data,
11902df1fe9cSrandyf dep, deplen, NULL)) {
11917c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: "
11927c478bd9Sstevel@tonic-gate "0x%p dep size %lu, "
11937c478bd9Sstevel@tonic-gate "EFAULT\n", cmdstr,
11947c478bd9Sstevel@tonic-gate (void *)req.data, deplen))
11957c478bd9Sstevel@tonic-gate ret = EFAULT;
11967c478bd9Sstevel@tonic-gate break;
11977c478bd9Sstevel@tonic-gate }
11987c478bd9Sstevel@tonic-gate #ifdef DEBUG
11997c478bd9Sstevel@tonic-gate else {
12007c478bd9Sstevel@tonic-gate PMD(PMD_DEP, ("ioctl: %s: "
12017c478bd9Sstevel@tonic-gate "dep %s\n", cmdstr, dep))
12027c478bd9Sstevel@tonic-gate }
12037c478bd9Sstevel@tonic-gate #endif
12047c478bd9Sstevel@tonic-gate } else {
12057c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: no "
12067c478bd9Sstevel@tonic-gate "dependent\n", cmdstr))
12077c478bd9Sstevel@tonic-gate ret = EINVAL;
12087c478bd9Sstevel@tonic-gate break;
12097c478bd9Sstevel@tonic-gate }
12107c478bd9Sstevel@tonic-gate }
12117c478bd9Sstevel@tonic-gate }
12127c478bd9Sstevel@tonic-gate /*
12137c478bd9Sstevel@tonic-gate * Now we've got all the args in for the commands that
12147c478bd9Sstevel@tonic-gate * use the new pm_req struct.
12157c478bd9Sstevel@tonic-gate */
12167c478bd9Sstevel@tonic-gate switch (cmd) {
12177c478bd9Sstevel@tonic-gate case PM_REPARSE_PM_PROPS:
12187c478bd9Sstevel@tonic-gate {
12197c478bd9Sstevel@tonic-gate struct dev_ops *drv;
12207c478bd9Sstevel@tonic-gate struct cb_ops *cb;
12217c478bd9Sstevel@tonic-gate void *propval;
12227c478bd9Sstevel@tonic-gate int length;
12237c478bd9Sstevel@tonic-gate /*
12247c478bd9Sstevel@tonic-gate * This ioctl is provided only for the ddivs pm test.
12257c478bd9Sstevel@tonic-gate * We only do it to a driver which explicitly allows
12267c478bd9Sstevel@tonic-gate * us to do so by exporting a pm-reparse-ok property.
12277c478bd9Sstevel@tonic-gate * We only care whether the property exists or not.
12287c478bd9Sstevel@tonic-gate */
12297c478bd9Sstevel@tonic-gate if ((drv = ddi_get_driver(dip)) == NULL) {
12307c478bd9Sstevel@tonic-gate ret = EINVAL;
12317c478bd9Sstevel@tonic-gate break;
12327c478bd9Sstevel@tonic-gate }
12337c478bd9Sstevel@tonic-gate if ((cb = drv->devo_cb_ops) != NULL) {
12347c478bd9Sstevel@tonic-gate if ((*cb->cb_prop_op)(DDI_DEV_T_ANY, dip,
12357c478bd9Sstevel@tonic-gate PROP_LEN_AND_VAL_ALLOC, (DDI_PROP_CANSLEEP |
12367c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
12377c478bd9Sstevel@tonic-gate "pm-reparse-ok", (caddr_t)&propval,
12387c478bd9Sstevel@tonic-gate &length) != DDI_SUCCESS) {
12397c478bd9Sstevel@tonic-gate ret = EINVAL;
12407c478bd9Sstevel@tonic-gate break;
12417c478bd9Sstevel@tonic-gate }
12427c478bd9Sstevel@tonic-gate } else if (ddi_prop_op(DDI_DEV_T_ANY, dip,
12437c478bd9Sstevel@tonic-gate PROP_LEN_AND_VAL_ALLOC, (DDI_PROP_CANSLEEP |
12447c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
12457c478bd9Sstevel@tonic-gate "pm-reparse-ok", (caddr_t)&propval,
12467c478bd9Sstevel@tonic-gate &length) != DDI_SUCCESS) {
12477c478bd9Sstevel@tonic-gate ret = EINVAL;
12487c478bd9Sstevel@tonic-gate break;
12497c478bd9Sstevel@tonic-gate }
12507c478bd9Sstevel@tonic-gate kmem_free(propval, length);
12517c478bd9Sstevel@tonic-gate ret = e_new_pm_props(dip);
12527c478bd9Sstevel@tonic-gate break;
12537c478bd9Sstevel@tonic-gate }
12547c478bd9Sstevel@tonic-gate
12557c478bd9Sstevel@tonic-gate case PM_GET_DEVICE_THRESHOLD:
12562df1fe9cSrandyf {
12577c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip);
12587c478bd9Sstevel@tonic-gate if (!PM_GET_PM_INFO(dip) || PM_ISBC(dip)) {
12597c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
12607c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: ENODEV\n",
12617c478bd9Sstevel@tonic-gate cmdstr))
12627c478bd9Sstevel@tonic-gate ret = ENODEV;
12637c478bd9Sstevel@tonic-gate break;
12647c478bd9Sstevel@tonic-gate }
12657c478bd9Sstevel@tonic-gate *rval_p = DEVI(dip)->devi_pm_dev_thresh;
12667c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
12677c478bd9Sstevel@tonic-gate ret = 0;
12687c478bd9Sstevel@tonic-gate break;
12692df1fe9cSrandyf }
12707c478bd9Sstevel@tonic-gate
12717c478bd9Sstevel@tonic-gate case PM_DIRECT_PM:
12727c478bd9Sstevel@tonic-gate {
12737c478bd9Sstevel@tonic-gate int has_dep;
12747c478bd9Sstevel@tonic-gate if ((info = PM_GET_PM_INFO(dip)) == NULL) {
12757c478bd9Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: "
12767c478bd9Sstevel@tonic-gate "ENODEV\n", cmdstr))
12777c478bd9Sstevel@tonic-gate ret = ENODEV;
12787c478bd9Sstevel@tonic-gate break;
12797c478bd9Sstevel@tonic-gate }
12807c478bd9Sstevel@tonic-gate /*
12817c478bd9Sstevel@tonic-gate * Check to see if we are there is a dependency on
12827c478bd9Sstevel@tonic-gate * this kept device, if so, return EBUSY.
12837c478bd9Sstevel@tonic-gate */
12847c478bd9Sstevel@tonic-gate (void) ddi_pathname(dip, pathbuf);
12857c478bd9Sstevel@tonic-gate pm_dispatch_to_dep_thread(PM_DEP_WK_CHECK_KEPT,
12867c478bd9Sstevel@tonic-gate NULL, pathbuf, PM_DEP_WAIT, &has_dep, 0);
12877c478bd9Sstevel@tonic-gate if (has_dep) {
12887c478bd9Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("%s EBUSY\n",
12897c478bd9Sstevel@tonic-gate cmdstr))
12907c478bd9Sstevel@tonic-gate ret = EBUSY;
12917c478bd9Sstevel@tonic-gate break;
12927c478bd9Sstevel@tonic-gate }
12937c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip);
12947c478bd9Sstevel@tonic-gate if (PM_ISDIRECT(dip) || (info->pmi_clone != 0)) {
12957c478bd9Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: "
12967c478bd9Sstevel@tonic-gate "%s@%s(%s#%d): EBUSY\n", cmdstr,
12977c478bd9Sstevel@tonic-gate PM_DEVICE(dip)))
12987c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
12997c478bd9Sstevel@tonic-gate ret = EBUSY;
13007c478bd9Sstevel@tonic-gate break;
13017c478bd9Sstevel@tonic-gate }
13027c478bd9Sstevel@tonic-gate info->pmi_dev_pm_state |= PM_DIRECT;
13037c478bd9Sstevel@tonic-gate info->pmi_clone = clone;
13047c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
13057c478bd9Sstevel@tonic-gate PMD(PMD_DPM, ("ioctl: %s: info %p, pmi_clone %d\n",
13067c478bd9Sstevel@tonic-gate cmdstr, (void *)info, clone))
13077c478bd9Sstevel@tonic-gate mutex_enter(&pm_clone_lock);
13087c478bd9Sstevel@tonic-gate pm_register_watcher(clone, dip);
13097c478bd9Sstevel@tonic-gate mutex_exit(&pm_clone_lock);
13107c478bd9Sstevel@tonic-gate ret = 0;
13117c478bd9Sstevel@tonic-gate break;
13127c478bd9Sstevel@tonic-gate }
13137c478bd9Sstevel@tonic-gate
13147c478bd9Sstevel@tonic-gate case PM_RELEASE_DIRECT_PM:
13157c478bd9Sstevel@tonic-gate {
13167c478bd9Sstevel@tonic-gate if ((info = PM_GET_PM_INFO(dip)) == NULL) {
13177c478bd9Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: "
13187c478bd9Sstevel@tonic-gate "ENODEV\n", cmdstr))
13197c478bd9Sstevel@tonic-gate ret = ENODEV;
13207c478bd9Sstevel@tonic-gate break;
13217c478bd9Sstevel@tonic-gate }
13227c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip);
13237c478bd9Sstevel@tonic-gate if (info->pmi_clone != clone) {
13247c478bd9Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: "
13257c478bd9Sstevel@tonic-gate "%s@%s(%s#%d) EINVAL\n", cmdstr,
13267c478bd9Sstevel@tonic-gate PM_DEVICE(dip)))
13277c478bd9Sstevel@tonic-gate ret = EINVAL;
13287c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
13297c478bd9Sstevel@tonic-gate break;
13307c478bd9Sstevel@tonic-gate }
13317c478bd9Sstevel@tonic-gate ASSERT(PM_ISDIRECT(dip));
13327c478bd9Sstevel@tonic-gate info->pmi_dev_pm_state &= ~PM_DIRECT;
13337c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
13347c478bd9Sstevel@tonic-gate /* Bring ourselves up if there is a keeper. */
13357c478bd9Sstevel@tonic-gate (void) ddi_pathname(dip, pathbuf);
13367c478bd9Sstevel@tonic-gate pm_dispatch_to_dep_thread(PM_DEP_WK_BRINGUP_SELF,
13377c478bd9Sstevel@tonic-gate NULL, pathbuf, PM_DEP_WAIT, NULL, 0);
13387c478bd9Sstevel@tonic-gate pm_discard_entries(clone);
13397c478bd9Sstevel@tonic-gate pm_deregister_watcher(clone, dip);
13407c478bd9Sstevel@tonic-gate /*
13417c478bd9Sstevel@tonic-gate * Now we could let the other threads that are
13427c478bd9Sstevel@tonic-gate * trying to do a DIRECT_PM thru
13437c478bd9Sstevel@tonic-gate */
13447c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip);
13457c478bd9Sstevel@tonic-gate info->pmi_clone = 0;
13467c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
13477c478bd9Sstevel@tonic-gate pm_proceed(dip, PMP_RELEASE, -1, -1);
13487c478bd9Sstevel@tonic-gate PMD(PMD_RESCAN | PMD_DPM, ("ioctl: %s: rescan\n",
13497c478bd9Sstevel@tonic-gate cmdstr))
13507c478bd9Sstevel@tonic-gate pm_rescan(dip);
13517c478bd9Sstevel@tonic-gate ret = 0;
13527c478bd9Sstevel@tonic-gate break;
13537c478bd9Sstevel@tonic-gate }
13547c478bd9Sstevel@tonic-gate
13557c478bd9Sstevel@tonic-gate case PM_SET_CURRENT_POWER:
13567c478bd9Sstevel@tonic-gate {
13577c478bd9Sstevel@tonic-gate int comp = req.component;
13587c478bd9Sstevel@tonic-gate int value = req.value;
13597c478bd9Sstevel@tonic-gate PMD(PMD_DPM, ("ioctl: %s: %s component %d to value "
13607c478bd9Sstevel@tonic-gate "%d\n", cmdstr, req.physpath, comp, value))
13617c478bd9Sstevel@tonic-gate if (!e_pm_valid_comp(dip, comp, NULL) ||
13627c478bd9Sstevel@tonic-gate !e_pm_valid_power(dip, comp, value)) {
13637c478bd9Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: "
13647c478bd9Sstevel@tonic-gate "physpath=%s, comp=%d, level=%d, fails\n",
13657c478bd9Sstevel@tonic-gate cmdstr, req.physpath, comp, value))
13667c478bd9Sstevel@tonic-gate ret = EINVAL;
13677c478bd9Sstevel@tonic-gate break;
13687c478bd9Sstevel@tonic-gate }
13697c478bd9Sstevel@tonic-gate
13707c478bd9Sstevel@tonic-gate if ((info = PM_GET_PM_INFO(dip)) == NULL) {
13717c478bd9Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: "
13727c478bd9Sstevel@tonic-gate "ENODEV\n", cmdstr))
13737c478bd9Sstevel@tonic-gate ret = ENODEV;
13747c478bd9Sstevel@tonic-gate break;
13757c478bd9Sstevel@tonic-gate }
13767c478bd9Sstevel@tonic-gate if (info->pmi_clone != clone) {
13777c478bd9Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: "
13787c478bd9Sstevel@tonic-gate "(not owner) %s fails; clone %d, owner %d"
13797c478bd9Sstevel@tonic-gate "\n", cmdstr, req.physpath, clone,
13807c478bd9Sstevel@tonic-gate info->pmi_clone))
13817c478bd9Sstevel@tonic-gate ret = EINVAL;
13827c478bd9Sstevel@tonic-gate break;
13837c478bd9Sstevel@tonic-gate }
13847c478bd9Sstevel@tonic-gate ASSERT(PM_ISDIRECT(dip));
13857c478bd9Sstevel@tonic-gate
13867c478bd9Sstevel@tonic-gate if (pm_set_power(dip, comp, value, PM_LEVEL_EXACT,
13877c478bd9Sstevel@tonic-gate PM_CANBLOCK_BLOCK, 0, &ret) != DDI_SUCCESS) {
13887c478bd9Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: "
13897c478bd9Sstevel@tonic-gate "pm_set_power for %s fails, errno=%d\n",
13907c478bd9Sstevel@tonic-gate cmdstr, req.physpath, ret))
13917c478bd9Sstevel@tonic-gate break;
13927c478bd9Sstevel@tonic-gate }
13937c478bd9Sstevel@tonic-gate
13947c478bd9Sstevel@tonic-gate pm_proceed(dip, PMP_SETPOWER, comp, value);
13957c478bd9Sstevel@tonic-gate
13967c478bd9Sstevel@tonic-gate /*
13977c478bd9Sstevel@tonic-gate * Power down all idle components if console framebuffer
13987c478bd9Sstevel@tonic-gate * is powered off.
13997c478bd9Sstevel@tonic-gate */
14007c478bd9Sstevel@tonic-gate if (PM_IS_CFB(dip) && (pm_system_idle_threshold ==
14017c478bd9Sstevel@tonic-gate pm_default_idle_threshold)) {
14027c478bd9Sstevel@tonic-gate dev_info_t *root = ddi_root_node();
14037c478bd9Sstevel@tonic-gate if (PM_ISBC(dip)) {
14047c478bd9Sstevel@tonic-gate if (comp == 0 && value == 0 &&
14057c478bd9Sstevel@tonic-gate (pm_timeout_idledown() != 0)) {
14067c478bd9Sstevel@tonic-gate ddi_walk_devs(root,
14077c478bd9Sstevel@tonic-gate pm_start_idledown,
14087c478bd9Sstevel@tonic-gate (void *)PMID_CFB);
14097c478bd9Sstevel@tonic-gate }
14107c478bd9Sstevel@tonic-gate } else {
14117c478bd9Sstevel@tonic-gate int count = 0;
14127c478bd9Sstevel@tonic-gate for (i = 0; i < PM_NUMCMPTS(dip); i++) {
14137c478bd9Sstevel@tonic-gate ret = pm_get_current_power(dip,
14147c478bd9Sstevel@tonic-gate i, &curpower);
14157c478bd9Sstevel@tonic-gate if (ret == DDI_SUCCESS &&
14167c478bd9Sstevel@tonic-gate curpower == 0)
14177c478bd9Sstevel@tonic-gate count++;
14187c478bd9Sstevel@tonic-gate }
14197c478bd9Sstevel@tonic-gate if ((count == PM_NUMCMPTS(dip)) &&
14207c478bd9Sstevel@tonic-gate (pm_timeout_idledown() != 0)) {
14217c478bd9Sstevel@tonic-gate ddi_walk_devs(root,
14227c478bd9Sstevel@tonic-gate pm_start_idledown,
14237c478bd9Sstevel@tonic-gate (void *)PMID_CFB);
14247c478bd9Sstevel@tonic-gate }
14257c478bd9Sstevel@tonic-gate }
14267c478bd9Sstevel@tonic-gate }
14277c478bd9Sstevel@tonic-gate
14287c478bd9Sstevel@tonic-gate PMD(PMD_RESCAN | PMD_DPM, ("ioctl: %s: rescan\n",
14297c478bd9Sstevel@tonic-gate cmdstr))
14307c478bd9Sstevel@tonic-gate pm_rescan(dip);
14317c478bd9Sstevel@tonic-gate *rval_p = 0;
14327c478bd9Sstevel@tonic-gate ret = 0;
14337c478bd9Sstevel@tonic-gate break;
14347c478bd9Sstevel@tonic-gate }
14357c478bd9Sstevel@tonic-gate
14367c478bd9Sstevel@tonic-gate case PM_GET_FULL_POWER:
14377c478bd9Sstevel@tonic-gate {
14387c478bd9Sstevel@tonic-gate int normal;
14397c478bd9Sstevel@tonic-gate ASSERT(dip);
14407c478bd9Sstevel@tonic-gate PMD(PMD_NORM, ("ioctl: %s: %s component %d\n",
14417c478bd9Sstevel@tonic-gate cmdstr, req.physpath, req.component))
14427c478bd9Sstevel@tonic-gate normal = pm_get_normal_power(dip, req.component);
14437c478bd9Sstevel@tonic-gate
14447c478bd9Sstevel@tonic-gate if (normal == DDI_FAILURE) {
14457c478bd9Sstevel@tonic-gate PMD(PMD_ERROR | PMD_NORM, ("ioctl: %s: "
14467c478bd9Sstevel@tonic-gate "returns EINVAL\n", cmdstr))
14477c478bd9Sstevel@tonic-gate ret = EINVAL;
14487c478bd9Sstevel@tonic-gate break;
14497c478bd9Sstevel@tonic-gate }
14507c478bd9Sstevel@tonic-gate *rval_p = normal;
14517c478bd9Sstevel@tonic-gate PMD(PMD_NORM, ("ioctl: %s: returns %d\n",
14527c478bd9Sstevel@tonic-gate cmdstr, normal))
14537c478bd9Sstevel@tonic-gate ret = 0;
14547c478bd9Sstevel@tonic-gate break;
14557c478bd9Sstevel@tonic-gate }
14567c478bd9Sstevel@tonic-gate
14577c478bd9Sstevel@tonic-gate case PM_GET_CURRENT_POWER:
14582df1fe9cSrandyf {
14597c478bd9Sstevel@tonic-gate if (pm_get_current_power(dip, req.component,
14607c478bd9Sstevel@tonic-gate rval_p) != DDI_SUCCESS) {
14617c478bd9Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s "
14627c478bd9Sstevel@tonic-gate "EINVAL\n", cmdstr))
14637c478bd9Sstevel@tonic-gate ret = EINVAL;
14647c478bd9Sstevel@tonic-gate break;
14657c478bd9Sstevel@tonic-gate }
14667c478bd9Sstevel@tonic-gate PMD(PMD_DPM, ("ioctl: %s: %s comp %d returns %d\n",
14677c478bd9Sstevel@tonic-gate cmdstr, req.physpath, req.component, *rval_p))
14687c478bd9Sstevel@tonic-gate if (*rval_p == PM_LEVEL_UNKNOWN)
14697c478bd9Sstevel@tonic-gate ret = EAGAIN;
14707c478bd9Sstevel@tonic-gate else
14717c478bd9Sstevel@tonic-gate ret = 0;
14727c478bd9Sstevel@tonic-gate break;
14732df1fe9cSrandyf }
14747c478bd9Sstevel@tonic-gate
14757c478bd9Sstevel@tonic-gate case PM_GET_TIME_IDLE:
14767c478bd9Sstevel@tonic-gate {
14777c478bd9Sstevel@tonic-gate time_t timestamp;
14787c478bd9Sstevel@tonic-gate int comp = req.component;
14797c478bd9Sstevel@tonic-gate pm_component_t *cp;
14807c478bd9Sstevel@tonic-gate if (!e_pm_valid_comp(dip, comp, &cp)) {
14817c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) "
14827c478bd9Sstevel@tonic-gate "component %d > numcmpts - 1 %d--EINVAL\n",
14837c478bd9Sstevel@tonic-gate cmdstr, PM_DEVICE(dip), comp,
14847c478bd9Sstevel@tonic-gate PM_NUMCMPTS(dip) - 1))
14857c478bd9Sstevel@tonic-gate ret = EINVAL;
14867c478bd9Sstevel@tonic-gate break;
14877c478bd9Sstevel@tonic-gate }
14887c478bd9Sstevel@tonic-gate timestamp = cp->pmc_timestamp;
14897c478bd9Sstevel@tonic-gate if (timestamp) {
14907c478bd9Sstevel@tonic-gate time_t now;
14917c478bd9Sstevel@tonic-gate (void) drv_getparm(TIME, &now);
14927c478bd9Sstevel@tonic-gate *rval_p = (now - timestamp);
14937c478bd9Sstevel@tonic-gate } else {
14947c478bd9Sstevel@tonic-gate *rval_p = 0;
14957c478bd9Sstevel@tonic-gate }
14967c478bd9Sstevel@tonic-gate ret = 0;
14977c478bd9Sstevel@tonic-gate break;
14987c478bd9Sstevel@tonic-gate }
14997c478bd9Sstevel@tonic-gate
15007c478bd9Sstevel@tonic-gate case PM_ADD_DEPENDENT:
15017c478bd9Sstevel@tonic-gate {
15027c478bd9Sstevel@tonic-gate dev_info_t *kept_dip;
15037c478bd9Sstevel@tonic-gate
15047c478bd9Sstevel@tonic-gate PMD(PMD_KEEPS, ("%s, kept %s, keeper %s\n", cmdstr,
15057c478bd9Sstevel@tonic-gate dep, req.physpath))
15067c478bd9Sstevel@tonic-gate
15077c478bd9Sstevel@tonic-gate /*
15087c478bd9Sstevel@tonic-gate * hold and install kept while processing dependency
15097c478bd9Sstevel@tonic-gate * keeper (in .physpath) has already been held.
15107c478bd9Sstevel@tonic-gate */
15117c478bd9Sstevel@tonic-gate if (dep[0] == '\0') {
15127c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("kept NULL or null\n"))
15137c478bd9Sstevel@tonic-gate ret = EINVAL;
15147c478bd9Sstevel@tonic-gate break;
15157c478bd9Sstevel@tonic-gate } else if ((kept_dip =
15167c478bd9Sstevel@tonic-gate pm_name_to_dip(dep, 1)) == NULL) {
15177c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("no dip for kept %s\n", dep))
15187c478bd9Sstevel@tonic-gate ret = ENODEV;
15197c478bd9Sstevel@tonic-gate break;
15207c478bd9Sstevel@tonic-gate } else if (kept_dip == dip) {
15217c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("keeper(%s, %p) - kept(%s, %p) "
15227c478bd9Sstevel@tonic-gate "self-dependency not allowed.\n",
15237c478bd9Sstevel@tonic-gate dep, (void *)kept_dip, req.physpath,
15247c478bd9Sstevel@tonic-gate (void *) dip))
15257c478bd9Sstevel@tonic-gate PM_RELE(dip); /* release "double" hold */
15267c478bd9Sstevel@tonic-gate ret = EINVAL;
15277c478bd9Sstevel@tonic-gate break;
15287c478bd9Sstevel@tonic-gate }
15297c478bd9Sstevel@tonic-gate ASSERT(!(strcmp(req.physpath, (char *)dep) == 0));
15307c478bd9Sstevel@tonic-gate
15317c478bd9Sstevel@tonic-gate /*
15327c478bd9Sstevel@tonic-gate * record dependency, then walk through device tree
15337c478bd9Sstevel@tonic-gate * independently on behalf of kept and keeper to
15347c478bd9Sstevel@tonic-gate * establish newly created dependency.
15357c478bd9Sstevel@tonic-gate */
15367c478bd9Sstevel@tonic-gate pm_dispatch_to_dep_thread(PM_DEP_WK_RECORD_KEEPER,
15377c478bd9Sstevel@tonic-gate req.physpath, dep, PM_DEP_WAIT, NULL, 0);
15387c478bd9Sstevel@tonic-gate
15397c478bd9Sstevel@tonic-gate /*
15407c478bd9Sstevel@tonic-gate * release kept after establishing dependency, keeper
15417c478bd9Sstevel@tonic-gate * is released as part of ioctl exit processing.
15427c478bd9Sstevel@tonic-gate */
15437c478bd9Sstevel@tonic-gate PM_RELE(kept_dip);
15447c478bd9Sstevel@tonic-gate *rval_p = 0;
15457c478bd9Sstevel@tonic-gate ret = 0;
15467c478bd9Sstevel@tonic-gate break;
15477c478bd9Sstevel@tonic-gate }
15487c478bd9Sstevel@tonic-gate
15497c478bd9Sstevel@tonic-gate case PM_ADD_DEPENDENT_PROPERTY:
15507c478bd9Sstevel@tonic-gate {
15517c478bd9Sstevel@tonic-gate char *keeper, *kept;
15527c478bd9Sstevel@tonic-gate
15537c478bd9Sstevel@tonic-gate if (dep[0] == '\0') {
15547c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: dep NULL or "
15557c478bd9Sstevel@tonic-gate "null\n", cmdstr))
15567c478bd9Sstevel@tonic-gate ret = EINVAL;
15577c478bd9Sstevel@tonic-gate break;
15587c478bd9Sstevel@tonic-gate }
15597c478bd9Sstevel@tonic-gate kept = dep;
15607c478bd9Sstevel@tonic-gate keeper = req.physpath;
15617c478bd9Sstevel@tonic-gate /*
15627c478bd9Sstevel@tonic-gate * record keeper - kept dependency, then walk through
15637c478bd9Sstevel@tonic-gate * device tree to find out all attached keeper, walk
15647c478bd9Sstevel@tonic-gate * through again to apply dependency to all the
15657c478bd9Sstevel@tonic-gate * potential kept.
15667c478bd9Sstevel@tonic-gate */
15677c478bd9Sstevel@tonic-gate pm_dispatch_to_dep_thread(
15687c478bd9Sstevel@tonic-gate PM_DEP_WK_RECORD_KEEPER_PROP, keeper, kept,
15697c478bd9Sstevel@tonic-gate PM_DEP_WAIT, NULL, 0);
15707c478bd9Sstevel@tonic-gate
15717c478bd9Sstevel@tonic-gate *rval_p = 0;
15727c478bd9Sstevel@tonic-gate ret = 0;
15737c478bd9Sstevel@tonic-gate break;
15747c478bd9Sstevel@tonic-gate }
15757c478bd9Sstevel@tonic-gate
15767c478bd9Sstevel@tonic-gate case PM_SET_DEVICE_THRESHOLD:
15777c478bd9Sstevel@tonic-gate {
15787c478bd9Sstevel@tonic-gate pm_thresh_rec_t *rp;
15797c478bd9Sstevel@tonic-gate pm_pte_t *ep; /* threshold header storage */
15807c478bd9Sstevel@tonic-gate int *tp; /* threshold storage */
15817c478bd9Sstevel@tonic-gate size_t size;
15827c478bd9Sstevel@tonic-gate extern int pm_thresh_specd(dev_info_t *);
15837c478bd9Sstevel@tonic-gate
15847c478bd9Sstevel@tonic-gate /*
15857c478bd9Sstevel@tonic-gate * The header struct plus one entry struct plus one
15867c478bd9Sstevel@tonic-gate * threshold plus the length of the string
15877c478bd9Sstevel@tonic-gate */
15887c478bd9Sstevel@tonic-gate size = sizeof (pm_thresh_rec_t) +
15897c478bd9Sstevel@tonic-gate (sizeof (pm_pte_t) * 1) +
15907c478bd9Sstevel@tonic-gate (1 * sizeof (int)) +
15917c478bd9Sstevel@tonic-gate strlen(req.physpath) + 1;
15927c478bd9Sstevel@tonic-gate
15937c478bd9Sstevel@tonic-gate rp = kmem_zalloc(size, KM_SLEEP);
15947c478bd9Sstevel@tonic-gate rp->ptr_size = size;
15957c478bd9Sstevel@tonic-gate rp->ptr_numcomps = 0; /* means device threshold */
15967c478bd9Sstevel@tonic-gate ep = (pm_pte_t *)((intptr_t)rp + sizeof (*rp));
15977c478bd9Sstevel@tonic-gate rp->ptr_entries = ep;
15987c478bd9Sstevel@tonic-gate tp = (int *)((intptr_t)ep +
15997c478bd9Sstevel@tonic-gate (1 * sizeof (pm_pte_t)));
16007c478bd9Sstevel@tonic-gate ep->pte_numthresh = 1;
16017c478bd9Sstevel@tonic-gate ep->pte_thresh = tp;
16027c478bd9Sstevel@tonic-gate *tp++ = req.value;
16037c478bd9Sstevel@tonic-gate (void) strcat((char *)tp, req.physpath);
16047c478bd9Sstevel@tonic-gate rp->ptr_physpath = (char *)tp;
16057c478bd9Sstevel@tonic-gate ASSERT((intptr_t)tp + strlen(req.physpath) + 1 ==
16067c478bd9Sstevel@tonic-gate (intptr_t)rp + rp->ptr_size);
16077c478bd9Sstevel@tonic-gate PMD(PMD_THRESH, ("ioctl: %s: record thresh %d for "
16087c478bd9Sstevel@tonic-gate "%s\n", cmdstr, req.value, req.physpath))
16097c478bd9Sstevel@tonic-gate pm_record_thresh(rp);
16107c478bd9Sstevel@tonic-gate /*
16117c478bd9Sstevel@tonic-gate * Don't free rp, pm_record_thresh() keeps it.
16127c478bd9Sstevel@tonic-gate * We don't try to apply it ourselves because we'd need
16137c478bd9Sstevel@tonic-gate * to know too much about locking. Since we don't
16147c478bd9Sstevel@tonic-gate * hold a lock the entry could be removed before
16157c478bd9Sstevel@tonic-gate * we get here
16167c478bd9Sstevel@tonic-gate */
16177c478bd9Sstevel@tonic-gate ASSERT(dip == NULL);
16187c478bd9Sstevel@tonic-gate ret = 0; /* can't fail now */
16197c478bd9Sstevel@tonic-gate if (!(dip = pm_name_to_dip(req.physpath, 1))) {
16207c478bd9Sstevel@tonic-gate break;
16217c478bd9Sstevel@tonic-gate }
16227c478bd9Sstevel@tonic-gate (void) pm_thresh_specd(dip);
16237c478bd9Sstevel@tonic-gate PMD(PMD_DHR, ("ioctl: %s: releasing %s@%s(%s#%d)\n",
16247c478bd9Sstevel@tonic-gate cmdstr, PM_DEVICE(dip)))
16257c478bd9Sstevel@tonic-gate PM_RELE(dip);
16267c478bd9Sstevel@tonic-gate break;
16277c478bd9Sstevel@tonic-gate }
16287c478bd9Sstevel@tonic-gate
16297c478bd9Sstevel@tonic-gate case PM_RESET_DEVICE_THRESHOLD:
16307c478bd9Sstevel@tonic-gate {
16317c478bd9Sstevel@tonic-gate /*
16327c478bd9Sstevel@tonic-gate * This only applies to a currently attached and power
16337c478bd9Sstevel@tonic-gate * managed node
16347c478bd9Sstevel@tonic-gate */
16357c478bd9Sstevel@tonic-gate /*
16367c478bd9Sstevel@tonic-gate * We don't do this to old-style drivers
16377c478bd9Sstevel@tonic-gate */
16387c478bd9Sstevel@tonic-gate info = PM_GET_PM_INFO(dip);
16397c478bd9Sstevel@tonic-gate if (info == NULL) {
16407c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s not power "
16417c478bd9Sstevel@tonic-gate "managed\n", cmdstr, req.physpath))
16427c478bd9Sstevel@tonic-gate ret = EINVAL;
16437c478bd9Sstevel@tonic-gate break;
16447c478bd9Sstevel@tonic-gate }
16457c478bd9Sstevel@tonic-gate if (PM_ISBC(dip)) {
16467c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s is BC\n",
16477c478bd9Sstevel@tonic-gate cmdstr, req.physpath))
16487c478bd9Sstevel@tonic-gate ret = EINVAL;
16497c478bd9Sstevel@tonic-gate break;
16507c478bd9Sstevel@tonic-gate }
16517c478bd9Sstevel@tonic-gate pm_unrecord_threshold(req.physpath);
1652c42872d4Smh27603 if (DEVI(dip)->devi_pm_flags & PMC_CPU_THRESH)
1653c42872d4Smh27603 pm_set_device_threshold(dip,
1654c42872d4Smh27603 pm_cpu_idle_threshold, PMC_CPU_THRESH);
1655c42872d4Smh27603 else
1656c42872d4Smh27603 pm_set_device_threshold(dip,
1657c42872d4Smh27603 pm_system_idle_threshold, PMC_DEF_THRESH);
16587c478bd9Sstevel@tonic-gate ret = 0;
16597c478bd9Sstevel@tonic-gate break;
16607c478bd9Sstevel@tonic-gate }
16617c478bd9Sstevel@tonic-gate
16627c478bd9Sstevel@tonic-gate case PM_GET_NUM_COMPONENTS:
16632df1fe9cSrandyf {
16647c478bd9Sstevel@tonic-gate ret = 0;
16657c478bd9Sstevel@tonic-gate *rval_p = PM_NUMCMPTS(dip);
16667c478bd9Sstevel@tonic-gate break;
16672df1fe9cSrandyf }
16687c478bd9Sstevel@tonic-gate
16697c478bd9Sstevel@tonic-gate case PM_GET_DEVICE_TYPE:
16702df1fe9cSrandyf {
16717c478bd9Sstevel@tonic-gate ret = 0;
16727c478bd9Sstevel@tonic-gate if ((info = PM_GET_PM_INFO(dip)) == NULL) {
16737c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: "
16747c478bd9Sstevel@tonic-gate "PM_NO_PM_COMPONENTS\n", cmdstr))
16757c478bd9Sstevel@tonic-gate *rval_p = PM_NO_PM_COMPONENTS;
16767c478bd9Sstevel@tonic-gate break;
16777c478bd9Sstevel@tonic-gate }
16787c478bd9Sstevel@tonic-gate if (PM_ISBC(dip)) {
16797c478bd9Sstevel@tonic-gate *rval_p = PM_CREATE_COMPONENTS;
16807c478bd9Sstevel@tonic-gate } else {
16817c478bd9Sstevel@tonic-gate *rval_p = PM_AUTOPM;
16827c478bd9Sstevel@tonic-gate }
16837c478bd9Sstevel@tonic-gate break;
16842df1fe9cSrandyf }
16857c478bd9Sstevel@tonic-gate
16867c478bd9Sstevel@tonic-gate case PM_SET_COMPONENT_THRESHOLDS:
16877c478bd9Sstevel@tonic-gate {
16887c478bd9Sstevel@tonic-gate int comps = 0;
16897c478bd9Sstevel@tonic-gate int *end = (int *)req.data + icount;
16907c478bd9Sstevel@tonic-gate pm_thresh_rec_t *rp;
16917c478bd9Sstevel@tonic-gate pm_pte_t *ep; /* threshold header storage */
16927c478bd9Sstevel@tonic-gate int *tp; /* threshold storage */
16937c478bd9Sstevel@tonic-gate int *ip;
16947c478bd9Sstevel@tonic-gate int j;
16957c478bd9Sstevel@tonic-gate size_t size;
16967c478bd9Sstevel@tonic-gate extern int pm_thresh_specd(dev_info_t *);
16977c478bd9Sstevel@tonic-gate extern int pm_valid_thresh(dev_info_t *,
16987c478bd9Sstevel@tonic-gate pm_thresh_rec_t *);
16997c478bd9Sstevel@tonic-gate
17007c478bd9Sstevel@tonic-gate for (ip = req.data; *ip; ip++) {
17017c478bd9Sstevel@tonic-gate if (ip >= end) {
17027c478bd9Sstevel@tonic-gate ret = EFAULT;
17037c478bd9Sstevel@tonic-gate break;
17047c478bd9Sstevel@tonic-gate }
17057c478bd9Sstevel@tonic-gate comps++;
17067c478bd9Sstevel@tonic-gate /* skip over indicated number of entries */
17077c478bd9Sstevel@tonic-gate for (j = *ip; j; j--) {
17087c478bd9Sstevel@tonic-gate if (++ip >= end) {
17097c478bd9Sstevel@tonic-gate ret = EFAULT;
17107c478bd9Sstevel@tonic-gate break;
17117c478bd9Sstevel@tonic-gate }
17127c478bd9Sstevel@tonic-gate }
17137c478bd9Sstevel@tonic-gate if (ret)
17147c478bd9Sstevel@tonic-gate break;
17157c478bd9Sstevel@tonic-gate }
17167c478bd9Sstevel@tonic-gate if (ret)
17177c478bd9Sstevel@tonic-gate break;
17187c478bd9Sstevel@tonic-gate if ((intptr_t)ip != (intptr_t)end - sizeof (int)) {
17197c478bd9Sstevel@tonic-gate /* did not exactly fill buffer */
17207c478bd9Sstevel@tonic-gate ret = EINVAL;
17217c478bd9Sstevel@tonic-gate break;
17227c478bd9Sstevel@tonic-gate }
17237c478bd9Sstevel@tonic-gate if (comps == 0) {
17247c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s 0 components"
17257c478bd9Sstevel@tonic-gate "--EINVAL\n", cmdstr, req.physpath))
17267c478bd9Sstevel@tonic-gate ret = EINVAL;
17277c478bd9Sstevel@tonic-gate break;
17287c478bd9Sstevel@tonic-gate }
17297c478bd9Sstevel@tonic-gate /*
17307c478bd9Sstevel@tonic-gate * The header struct plus one entry struct per component
17317c478bd9Sstevel@tonic-gate * plus the size of the lists minus the counts
17327c478bd9Sstevel@tonic-gate * plus the length of the string
17337c478bd9Sstevel@tonic-gate */
17347c478bd9Sstevel@tonic-gate size = sizeof (pm_thresh_rec_t) +
17357c478bd9Sstevel@tonic-gate (sizeof (pm_pte_t) * comps) + req.datasize -
17367c478bd9Sstevel@tonic-gate ((comps + 1) * sizeof (int)) +
17377c478bd9Sstevel@tonic-gate strlen(req.physpath) + 1;
17387c478bd9Sstevel@tonic-gate
17397c478bd9Sstevel@tonic-gate rp = kmem_zalloc(size, KM_SLEEP);
17407c478bd9Sstevel@tonic-gate rp->ptr_size = size;
17417c478bd9Sstevel@tonic-gate rp->ptr_numcomps = comps;
17427c478bd9Sstevel@tonic-gate ep = (pm_pte_t *)((intptr_t)rp + sizeof (*rp));
17437c478bd9Sstevel@tonic-gate rp->ptr_entries = ep;
17447c478bd9Sstevel@tonic-gate tp = (int *)((intptr_t)ep +
17457c478bd9Sstevel@tonic-gate (comps * sizeof (pm_pte_t)));
17467c478bd9Sstevel@tonic-gate for (ip = req.data; *ip; ep++) {
17477c478bd9Sstevel@tonic-gate ep->pte_numthresh = *ip;
17487c478bd9Sstevel@tonic-gate ep->pte_thresh = tp;
17497c478bd9Sstevel@tonic-gate for (j = *ip++; j; j--) {
17507c478bd9Sstevel@tonic-gate *tp++ = *ip++;
17517c478bd9Sstevel@tonic-gate }
17527c478bd9Sstevel@tonic-gate }
17537c478bd9Sstevel@tonic-gate (void) strcat((char *)tp, req.physpath);
17547c478bd9Sstevel@tonic-gate rp->ptr_physpath = (char *)tp;
17557c478bd9Sstevel@tonic-gate ASSERT((intptr_t)end == (intptr_t)ip + sizeof (int));
17567c478bd9Sstevel@tonic-gate ASSERT((intptr_t)tp + strlen(req.physpath) + 1 ==
17577c478bd9Sstevel@tonic-gate (intptr_t)rp + rp->ptr_size);
17587c478bd9Sstevel@tonic-gate
17597c478bd9Sstevel@tonic-gate ASSERT(dip == NULL);
17607c478bd9Sstevel@tonic-gate /*
17617c478bd9Sstevel@tonic-gate * If this is not a currently power managed node,
17627c478bd9Sstevel@tonic-gate * then we can't check for validity of the thresholds
17637c478bd9Sstevel@tonic-gate */
17647c478bd9Sstevel@tonic-gate if (!(dip = pm_name_to_dip(req.physpath, 1))) {
17657c478bd9Sstevel@tonic-gate /* don't free rp, pm_record_thresh uses it */
17667c478bd9Sstevel@tonic-gate pm_record_thresh(rp);
17677c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: pm_name_to_dip "
17687c478bd9Sstevel@tonic-gate "for %s failed\n", cmdstr, req.physpath))
17697c478bd9Sstevel@tonic-gate ret = 0;
17707c478bd9Sstevel@tonic-gate break;
17717c478bd9Sstevel@tonic-gate }
17727c478bd9Sstevel@tonic-gate ASSERT(!dipheld);
17737c478bd9Sstevel@tonic-gate dipheld++;
17747c478bd9Sstevel@tonic-gate
17757c478bd9Sstevel@tonic-gate if (!pm_valid_thresh(dip, rp)) {
17767c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: invalid thresh "
17777c478bd9Sstevel@tonic-gate "for %s@%s(%s#%d)\n", cmdstr,
17787c478bd9Sstevel@tonic-gate PM_DEVICE(dip)))
17797c478bd9Sstevel@tonic-gate kmem_free(rp, size);
17807c478bd9Sstevel@tonic-gate ret = EINVAL;
17817c478bd9Sstevel@tonic-gate break;
17827c478bd9Sstevel@tonic-gate }
17837c478bd9Sstevel@tonic-gate /*
17847c478bd9Sstevel@tonic-gate * We don't just apply it ourselves because we'd need
17857c478bd9Sstevel@tonic-gate * to know too much about locking. Since we don't
17867c478bd9Sstevel@tonic-gate * hold a lock the entry could be removed before
17877c478bd9Sstevel@tonic-gate * we get here
17887c478bd9Sstevel@tonic-gate */
17897c478bd9Sstevel@tonic-gate pm_record_thresh(rp);
17907c478bd9Sstevel@tonic-gate (void) pm_thresh_specd(dip);
17917c478bd9Sstevel@tonic-gate ret = 0;
17927c478bd9Sstevel@tonic-gate break;
17937c478bd9Sstevel@tonic-gate }
17947c478bd9Sstevel@tonic-gate
17957c478bd9Sstevel@tonic-gate case PM_GET_COMPONENT_THRESHOLDS:
17967c478bd9Sstevel@tonic-gate {
17977c478bd9Sstevel@tonic-gate int musthave;
17987c478bd9Sstevel@tonic-gate int numthresholds = 0;
17997c478bd9Sstevel@tonic-gate int wordsize;
18007c478bd9Sstevel@tonic-gate int numcomps;
18017c478bd9Sstevel@tonic-gate caddr_t uaddr = req.data; /* user address */
18027c478bd9Sstevel@tonic-gate int val; /* int value to be copied out */
18037c478bd9Sstevel@tonic-gate int32_t val32; /* int32 value to be copied out */
18047c478bd9Sstevel@tonic-gate caddr_t vaddr; /* address to copyout from */
18057c478bd9Sstevel@tonic-gate int j;
18067c478bd9Sstevel@tonic-gate
18077c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
18087c478bd9Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
18097c478bd9Sstevel@tonic-gate wordsize = sizeof (int32_t);
18107c478bd9Sstevel@tonic-gate } else
18117c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
18127c478bd9Sstevel@tonic-gate {
18137c478bd9Sstevel@tonic-gate wordsize = sizeof (int);
18147c478bd9Sstevel@tonic-gate }
18157c478bd9Sstevel@tonic-gate
18167c478bd9Sstevel@tonic-gate ASSERT(dip);
18177c478bd9Sstevel@tonic-gate
18187c478bd9Sstevel@tonic-gate numcomps = PM_NUMCMPTS(dip);
18197c478bd9Sstevel@tonic-gate for (i = 0; i < numcomps; i++) {
18207c478bd9Sstevel@tonic-gate cp = PM_CP(dip, i);
18217c478bd9Sstevel@tonic-gate numthresholds += cp->pmc_comp.pmc_numlevels - 1;
18227c478bd9Sstevel@tonic-gate }
18237c478bd9Sstevel@tonic-gate musthave = (numthresholds + numcomps + 1) * wordsize;
18247c478bd9Sstevel@tonic-gate if (req.datasize < musthave) {
18257c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: size %ld, need "
18267c478bd9Sstevel@tonic-gate "%d--EINVAL\n", cmdstr, req.datasize,
18277c478bd9Sstevel@tonic-gate musthave))
18287c478bd9Sstevel@tonic-gate ret = EINVAL;
18297c478bd9Sstevel@tonic-gate break;
18307c478bd9Sstevel@tonic-gate }
18317c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip);
18327c478bd9Sstevel@tonic-gate for (i = 0; i < numcomps; i++) {
18337c478bd9Sstevel@tonic-gate int *thp;
18347c478bd9Sstevel@tonic-gate cp = PM_CP(dip, i);
18357c478bd9Sstevel@tonic-gate thp = cp->pmc_comp.pmc_thresh;
18367c478bd9Sstevel@tonic-gate /* first copyout the count */
18377c478bd9Sstevel@tonic-gate if (wordsize == sizeof (int32_t)) {
18387c478bd9Sstevel@tonic-gate val32 = cp->pmc_comp.pmc_numlevels - 1;
18397c478bd9Sstevel@tonic-gate vaddr = (caddr_t)&val32;
18407c478bd9Sstevel@tonic-gate } else {
18417c478bd9Sstevel@tonic-gate val = cp->pmc_comp.pmc_numlevels - 1;
18427c478bd9Sstevel@tonic-gate vaddr = (caddr_t)&val;
18437c478bd9Sstevel@tonic-gate }
18447c478bd9Sstevel@tonic-gate if (ddi_copyout(vaddr, (void *)uaddr,
18457c478bd9Sstevel@tonic-gate wordsize, mode) != 0) {
18467c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
18477c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s"
18487c478bd9Sstevel@tonic-gate "(%s#%d) vaddr %p EFAULT\n",
18497c478bd9Sstevel@tonic-gate cmdstr, PM_DEVICE(dip),
18507c478bd9Sstevel@tonic-gate (void*)vaddr))
18517c478bd9Sstevel@tonic-gate ret = EFAULT;
18527c478bd9Sstevel@tonic-gate break;
18537c478bd9Sstevel@tonic-gate }
18547c478bd9Sstevel@tonic-gate vaddr = uaddr;
18557c478bd9Sstevel@tonic-gate vaddr += wordsize;
18567c478bd9Sstevel@tonic-gate uaddr = (caddr_t)vaddr;
18577c478bd9Sstevel@tonic-gate /* then copyout each threshold value */
18587c478bd9Sstevel@tonic-gate for (j = 0; j < cp->pmc_comp.pmc_numlevels - 1;
18597c478bd9Sstevel@tonic-gate j++) {
18607c478bd9Sstevel@tonic-gate if (wordsize == sizeof (int32_t)) {
18617c478bd9Sstevel@tonic-gate val32 = thp[j + 1];
18627c478bd9Sstevel@tonic-gate vaddr = (caddr_t)&val32;
18637c478bd9Sstevel@tonic-gate } else {
18647c478bd9Sstevel@tonic-gate val = thp[i + 1];
18657c478bd9Sstevel@tonic-gate vaddr = (caddr_t)&val;
18667c478bd9Sstevel@tonic-gate }
18677c478bd9Sstevel@tonic-gate if (ddi_copyout(vaddr, (void *) uaddr,
18687c478bd9Sstevel@tonic-gate wordsize, mode) != 0) {
18697c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
18707c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: "
18717c478bd9Sstevel@tonic-gate "%s@%s(%s#%d) uaddr %p "
18727c478bd9Sstevel@tonic-gate "EFAULT\n", cmdstr,
18737c478bd9Sstevel@tonic-gate PM_DEVICE(dip),
18747c478bd9Sstevel@tonic-gate (void *)uaddr))
18757c478bd9Sstevel@tonic-gate ret = EFAULT;
18767c478bd9Sstevel@tonic-gate break;
18777c478bd9Sstevel@tonic-gate }
18787c478bd9Sstevel@tonic-gate vaddr = uaddr;
18797c478bd9Sstevel@tonic-gate vaddr += wordsize;
18807c478bd9Sstevel@tonic-gate uaddr = (caddr_t)vaddr;
18817c478bd9Sstevel@tonic-gate }
18827c478bd9Sstevel@tonic-gate }
18837c478bd9Sstevel@tonic-gate if (ret)
18847c478bd9Sstevel@tonic-gate break;
18857c478bd9Sstevel@tonic-gate /* last copyout a terminating 0 count */
18867c478bd9Sstevel@tonic-gate if (wordsize == sizeof (int32_t)) {
18877c478bd9Sstevel@tonic-gate val32 = 0;
18887c478bd9Sstevel@tonic-gate vaddr = (caddr_t)&val32;
18897c478bd9Sstevel@tonic-gate } else {
18907c478bd9Sstevel@tonic-gate ASSERT(wordsize == sizeof (int));
18917c478bd9Sstevel@tonic-gate val = 0;
18927c478bd9Sstevel@tonic-gate vaddr = (caddr_t)&val;
18937c478bd9Sstevel@tonic-gate }
18947c478bd9Sstevel@tonic-gate if (ddi_copyout(vaddr, uaddr, wordsize, mode) != 0) {
18957c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
18967c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) "
18977c478bd9Sstevel@tonic-gate "vaddr %p (0 count) EFAULT\n", cmdstr,
18987c478bd9Sstevel@tonic-gate PM_DEVICE(dip), (void *)vaddr))
18997c478bd9Sstevel@tonic-gate ret = EFAULT;
19007c478bd9Sstevel@tonic-gate break;
19017c478bd9Sstevel@tonic-gate }
19027c478bd9Sstevel@tonic-gate /* finished, so don't need to increment addresses */
19037c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
19047c478bd9Sstevel@tonic-gate ret = 0;
19057c478bd9Sstevel@tonic-gate break;
19067c478bd9Sstevel@tonic-gate }
19077c478bd9Sstevel@tonic-gate
19087c478bd9Sstevel@tonic-gate case PM_GET_STATS:
19097c478bd9Sstevel@tonic-gate {
19107c478bd9Sstevel@tonic-gate time_t now;
19117c478bd9Sstevel@tonic-gate time_t *timestamp;
19127c478bd9Sstevel@tonic-gate extern int pm_cur_power(pm_component_t *cp);
19137c478bd9Sstevel@tonic-gate int musthave;
19147c478bd9Sstevel@tonic-gate int wordsize;
19157c478bd9Sstevel@tonic-gate
19167c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
19177c478bd9Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
19187c478bd9Sstevel@tonic-gate wordsize = sizeof (int32_t);
19197c478bd9Sstevel@tonic-gate } else
19207c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
19217c478bd9Sstevel@tonic-gate {
19227c478bd9Sstevel@tonic-gate wordsize = sizeof (int);
19237c478bd9Sstevel@tonic-gate }
19247c478bd9Sstevel@tonic-gate
19257c478bd9Sstevel@tonic-gate comps = PM_NUMCMPTS(dip);
19267c478bd9Sstevel@tonic-gate if (comps == 0 || PM_GET_PM_INFO(dip) == NULL) {
19277c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s no components"
19287c478bd9Sstevel@tonic-gate " or not power managed--EINVAL\n", cmdstr,
19297c478bd9Sstevel@tonic-gate req.physpath))
19307c478bd9Sstevel@tonic-gate ret = EINVAL;
19317c478bd9Sstevel@tonic-gate break;
19327c478bd9Sstevel@tonic-gate }
19337c478bd9Sstevel@tonic-gate musthave = comps * 2 * wordsize;
19347c478bd9Sstevel@tonic-gate if (req.datasize < musthave) {
19357c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: size %lu, need "
19367c478bd9Sstevel@tonic-gate "%d--EINVAL\n", cmdstr, req.datasize,
19377c478bd9Sstevel@tonic-gate musthave))
19387c478bd9Sstevel@tonic-gate ret = EINVAL;
19397c478bd9Sstevel@tonic-gate break;
19407c478bd9Sstevel@tonic-gate }
19417c478bd9Sstevel@tonic-gate
19427c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip);
19437c478bd9Sstevel@tonic-gate (void) drv_getparm(TIME, &now);
19447c478bd9Sstevel@tonic-gate timestamp = kmem_zalloc(comps * sizeof (time_t),
19457c478bd9Sstevel@tonic-gate KM_SLEEP);
19467c478bd9Sstevel@tonic-gate pm_get_timestamps(dip, timestamp);
19477c478bd9Sstevel@tonic-gate /*
19487c478bd9Sstevel@tonic-gate * First the current power levels
19497c478bd9Sstevel@tonic-gate */
19507c478bd9Sstevel@tonic-gate for (i = 0; i < comps; i++) {
19517c478bd9Sstevel@tonic-gate int curpwr;
19527c478bd9Sstevel@tonic-gate int32_t curpwr32;
19537c478bd9Sstevel@tonic-gate caddr_t cpaddr;
19547c478bd9Sstevel@tonic-gate
19557c478bd9Sstevel@tonic-gate cp = PM_CP(dip, i);
19567c478bd9Sstevel@tonic-gate if (wordsize == sizeof (int)) {
19577c478bd9Sstevel@tonic-gate curpwr = pm_cur_power(cp);
19587c478bd9Sstevel@tonic-gate cpaddr = (caddr_t)&curpwr;
19597c478bd9Sstevel@tonic-gate } else {
19607c478bd9Sstevel@tonic-gate ASSERT(wordsize == sizeof (int32_t));
19617c478bd9Sstevel@tonic-gate curpwr32 = pm_cur_power(cp);
19627c478bd9Sstevel@tonic-gate cpaddr = (caddr_t)&curpwr32;
19637c478bd9Sstevel@tonic-gate }
19647c478bd9Sstevel@tonic-gate if (ddi_copyout(cpaddr, (void *) req.data,
19657c478bd9Sstevel@tonic-gate wordsize, mode) != 0) {
19667c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
19677c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s"
19687c478bd9Sstevel@tonic-gate "(%s#%d) req.data %p EFAULT\n",
19697c478bd9Sstevel@tonic-gate cmdstr, PM_DEVICE(dip),
19707c478bd9Sstevel@tonic-gate (void *)req.data))
19717c478bd9Sstevel@tonic-gate ASSERT(!dipheld);
19727c478bd9Sstevel@tonic-gate return (EFAULT);
19737c478bd9Sstevel@tonic-gate }
19747c478bd9Sstevel@tonic-gate cpaddr = (caddr_t)req.data;
19757c478bd9Sstevel@tonic-gate cpaddr += wordsize;
19767c478bd9Sstevel@tonic-gate req.data = cpaddr;
19777c478bd9Sstevel@tonic-gate }
19787c478bd9Sstevel@tonic-gate /*
19797c478bd9Sstevel@tonic-gate * Then the times remaining
19807c478bd9Sstevel@tonic-gate */
19817c478bd9Sstevel@tonic-gate for (i = 0; i < comps; i++) {
19827c478bd9Sstevel@tonic-gate int retval;
19837c478bd9Sstevel@tonic-gate int32_t retval32;
19847c478bd9Sstevel@tonic-gate caddr_t rvaddr;
19857c478bd9Sstevel@tonic-gate int curpwr;
19867c478bd9Sstevel@tonic-gate
19877c478bd9Sstevel@tonic-gate cp = PM_CP(dip, i);
19887c478bd9Sstevel@tonic-gate curpwr = cp->pmc_cur_pwr;
19897c478bd9Sstevel@tonic-gate if (curpwr == 0 || timestamp[i] == 0) {
19907c478bd9Sstevel@tonic-gate PMD(PMD_STATS, ("ioctl: %s: "
19917c478bd9Sstevel@tonic-gate "cur_pwer %x, timestamp %lx\n",
19927c478bd9Sstevel@tonic-gate cmdstr, curpwr, timestamp[i]))
19937c478bd9Sstevel@tonic-gate retval = INT_MAX;
19947c478bd9Sstevel@tonic-gate } else {
19957c478bd9Sstevel@tonic-gate int thresh;
19967c478bd9Sstevel@tonic-gate (void) pm_current_threshold(dip, i,
19977c478bd9Sstevel@tonic-gate &thresh);
19987c478bd9Sstevel@tonic-gate retval = thresh - (now - timestamp[i]);
19997c478bd9Sstevel@tonic-gate PMD(PMD_STATS, ("ioctl: %s: current "
20007c478bd9Sstevel@tonic-gate "thresh %x, now %lx, timestamp %lx,"
20017c478bd9Sstevel@tonic-gate " retval %x\n", cmdstr, thresh, now,
20027c478bd9Sstevel@tonic-gate timestamp[i], retval))
20037c478bd9Sstevel@tonic-gate }
20047c478bd9Sstevel@tonic-gate if (wordsize == sizeof (int)) {
20057c478bd9Sstevel@tonic-gate rvaddr = (caddr_t)&retval;
20067c478bd9Sstevel@tonic-gate } else {
20077c478bd9Sstevel@tonic-gate ASSERT(wordsize == sizeof (int32_t));
20087c478bd9Sstevel@tonic-gate retval32 = retval;
20097c478bd9Sstevel@tonic-gate rvaddr = (caddr_t)&retval32;
20107c478bd9Sstevel@tonic-gate }
20117c478bd9Sstevel@tonic-gate if (ddi_copyout(rvaddr, (void *) req.data,
20127c478bd9Sstevel@tonic-gate wordsize, mode) != 0) {
20137c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
20147c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s"
20157c478bd9Sstevel@tonic-gate "(%s#%d) req.data %p EFAULT\n",
20167c478bd9Sstevel@tonic-gate cmdstr, PM_DEVICE(dip),
20177c478bd9Sstevel@tonic-gate (void *)req.data))
20187c478bd9Sstevel@tonic-gate ASSERT(!dipheld);
20192df1fe9cSrandyf kmem_free(timestamp,
20202df1fe9cSrandyf comps * sizeof (time_t));
20217c478bd9Sstevel@tonic-gate return (EFAULT);
20227c478bd9Sstevel@tonic-gate }
20237c478bd9Sstevel@tonic-gate rvaddr = (caddr_t)req.data;
20247c478bd9Sstevel@tonic-gate rvaddr += wordsize;
20257c478bd9Sstevel@tonic-gate req.data = (int *)rvaddr;
20267c478bd9Sstevel@tonic-gate }
20277c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
20287c478bd9Sstevel@tonic-gate *rval_p = comps;
20297c478bd9Sstevel@tonic-gate ret = 0;
20307c478bd9Sstevel@tonic-gate kmem_free(timestamp, comps * sizeof (time_t));
20317c478bd9Sstevel@tonic-gate break;
20327c478bd9Sstevel@tonic-gate }
20337c478bd9Sstevel@tonic-gate
20342df1fe9cSrandyf case PM_GET_CMD_NAME:
20352df1fe9cSrandyf {
20362df1fe9cSrandyf PMD(PMD_IOCTL, ("%s: %s\n", cmdstr,
20372df1fe9cSrandyf pm_decode_cmd(req.value)))
20382df1fe9cSrandyf if (ret = copyoutstr(pm_decode_cmd(req.value),
20392df1fe9cSrandyf (char *)req.data, req.datasize, &lencopied)) {
20402df1fe9cSrandyf PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) "
20412df1fe9cSrandyf "copyoutstr %p failed--EFAULT\n", cmdstr,
20422df1fe9cSrandyf PM_DEVICE(dip), (void *)req.data))
20432df1fe9cSrandyf break;
20442df1fe9cSrandyf }
20452df1fe9cSrandyf *rval_p = lencopied;
20462df1fe9cSrandyf ret = 0;
20472df1fe9cSrandyf break;
20482df1fe9cSrandyf }
20492df1fe9cSrandyf
20507c478bd9Sstevel@tonic-gate case PM_GET_COMPONENT_NAME:
20512df1fe9cSrandyf {
20527c478bd9Sstevel@tonic-gate ASSERT(dip);
20537c478bd9Sstevel@tonic-gate if (!e_pm_valid_comp(dip, req.component, &cp)) {
20547c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) "
20557c478bd9Sstevel@tonic-gate "component %d > numcmpts - 1 %d--EINVAL\n",
20567c478bd9Sstevel@tonic-gate cmdstr, PM_DEVICE(dip), req.component,
20577c478bd9Sstevel@tonic-gate PM_NUMCMPTS(dip) - 1))
20587c478bd9Sstevel@tonic-gate ret = EINVAL;
20597c478bd9Sstevel@tonic-gate break;
20607c478bd9Sstevel@tonic-gate }
20617c478bd9Sstevel@tonic-gate if (ret = copyoutstr(cp->pmc_comp.pmc_name,
20627c478bd9Sstevel@tonic-gate (char *)req.data, req.datasize, &lencopied)) {
20637c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) "
20647c478bd9Sstevel@tonic-gate "copyoutstr %p failed--EFAULT\n", cmdstr,
20657c478bd9Sstevel@tonic-gate PM_DEVICE(dip), (void *)req.data))
20667c478bd9Sstevel@tonic-gate break;
20677c478bd9Sstevel@tonic-gate }
20687c478bd9Sstevel@tonic-gate *rval_p = lencopied;
20697c478bd9Sstevel@tonic-gate ret = 0;
20707c478bd9Sstevel@tonic-gate break;
20712df1fe9cSrandyf }
20727c478bd9Sstevel@tonic-gate
20737c478bd9Sstevel@tonic-gate case PM_GET_POWER_NAME:
20747c478bd9Sstevel@tonic-gate {
20757c478bd9Sstevel@tonic-gate int i;
20767c478bd9Sstevel@tonic-gate
20777c478bd9Sstevel@tonic-gate ASSERT(dip);
20787c478bd9Sstevel@tonic-gate if (!e_pm_valid_comp(dip, req.component, &cp)) {
20797c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) "
20807c478bd9Sstevel@tonic-gate "component %d > numcmpts - 1 %d--EINVAL\n",
20817c478bd9Sstevel@tonic-gate cmdstr, PM_DEVICE(dip), req.component,
20827c478bd9Sstevel@tonic-gate PM_NUMCMPTS(dip) - 1))
20837c478bd9Sstevel@tonic-gate ret = EINVAL;
20847c478bd9Sstevel@tonic-gate break;
20857c478bd9Sstevel@tonic-gate }
20867c478bd9Sstevel@tonic-gate if ((i = req.value) < 0 ||
20877c478bd9Sstevel@tonic-gate i > cp->pmc_comp.pmc_numlevels - 1) {
20887c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) "
20897c478bd9Sstevel@tonic-gate "value %d > num_levels - 1 %d--EINVAL\n",
20907c478bd9Sstevel@tonic-gate cmdstr, PM_DEVICE(dip), req.value,
20917c478bd9Sstevel@tonic-gate cp->pmc_comp.pmc_numlevels - 1))
20927c478bd9Sstevel@tonic-gate ret = EINVAL;
20937c478bd9Sstevel@tonic-gate break;
20947c478bd9Sstevel@tonic-gate }
20957c478bd9Sstevel@tonic-gate dep = cp->pmc_comp.pmc_lnames[req.value];
20967c478bd9Sstevel@tonic-gate if (ret = copyoutstr(dep,
20977c478bd9Sstevel@tonic-gate req.data, req.datasize, &lencopied)) {
20987c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) "
20997c478bd9Sstevel@tonic-gate "copyoutstr %p failed--EFAULT\n", cmdstr,
21007c478bd9Sstevel@tonic-gate PM_DEVICE(dip), (void *)req.data))
21017c478bd9Sstevel@tonic-gate break;
21027c478bd9Sstevel@tonic-gate }
21037c478bd9Sstevel@tonic-gate *rval_p = lencopied;
21047c478bd9Sstevel@tonic-gate ret = 0;
21057c478bd9Sstevel@tonic-gate break;
21067c478bd9Sstevel@tonic-gate }
21077c478bd9Sstevel@tonic-gate
21087c478bd9Sstevel@tonic-gate case PM_GET_POWER_LEVELS:
21097c478bd9Sstevel@tonic-gate {
21107c478bd9Sstevel@tonic-gate int musthave;
21117c478bd9Sstevel@tonic-gate int numlevels;
21127c478bd9Sstevel@tonic-gate int wordsize;
21137c478bd9Sstevel@tonic-gate
21147c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
21157c478bd9Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
21167c478bd9Sstevel@tonic-gate wordsize = sizeof (int32_t);
21177c478bd9Sstevel@tonic-gate } else
21187c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
21197c478bd9Sstevel@tonic-gate {
21207c478bd9Sstevel@tonic-gate wordsize = sizeof (int);
21217c478bd9Sstevel@tonic-gate }
21227c478bd9Sstevel@tonic-gate ASSERT(dip);
21237c478bd9Sstevel@tonic-gate
21247c478bd9Sstevel@tonic-gate if (!e_pm_valid_comp(dip, req.component, &cp)) {
21257c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) "
21267c478bd9Sstevel@tonic-gate "has %d components, component %d requested"
21277c478bd9Sstevel@tonic-gate "--EINVAL\n", cmdstr, PM_DEVICE(dip),
21287c478bd9Sstevel@tonic-gate PM_NUMCMPTS(dip), req.component))
21297c478bd9Sstevel@tonic-gate ret = EINVAL;
21307c478bd9Sstevel@tonic-gate break;
21317c478bd9Sstevel@tonic-gate }
21327c478bd9Sstevel@tonic-gate numlevels = cp->pmc_comp.pmc_numlevels;
21337c478bd9Sstevel@tonic-gate musthave = numlevels * wordsize;
21347c478bd9Sstevel@tonic-gate if (req.datasize < musthave) {
21357c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: size %lu, need "
21367c478bd9Sstevel@tonic-gate "%d--EINVAL\n", cmdstr, req.datasize,
21377c478bd9Sstevel@tonic-gate musthave))
21387c478bd9Sstevel@tonic-gate ret = EINVAL;
21397c478bd9Sstevel@tonic-gate break;
21407c478bd9Sstevel@tonic-gate }
21417c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip);
21427c478bd9Sstevel@tonic-gate for (i = 0; i < numlevels; i++) {
21437c478bd9Sstevel@tonic-gate int level;
21447c478bd9Sstevel@tonic-gate int32_t level32;
21457c478bd9Sstevel@tonic-gate caddr_t laddr;
21467c478bd9Sstevel@tonic-gate
21477c478bd9Sstevel@tonic-gate if (wordsize == sizeof (int)) {
21487c478bd9Sstevel@tonic-gate level = cp->pmc_comp.pmc_lvals[i];
21497c478bd9Sstevel@tonic-gate laddr = (caddr_t)&level;
21507c478bd9Sstevel@tonic-gate } else {
21517c478bd9Sstevel@tonic-gate level32 = cp->pmc_comp.pmc_lvals[i];
21527c478bd9Sstevel@tonic-gate laddr = (caddr_t)&level32;
21537c478bd9Sstevel@tonic-gate }
21547c478bd9Sstevel@tonic-gate if (ddi_copyout(laddr, (void *) req.data,
21557c478bd9Sstevel@tonic-gate wordsize, mode) != 0) {
21567c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
21577c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s"
21587c478bd9Sstevel@tonic-gate "(%s#%d) laddr %p EFAULT\n",
21597c478bd9Sstevel@tonic-gate cmdstr, PM_DEVICE(dip),
21607c478bd9Sstevel@tonic-gate (void *)laddr))
21617c478bd9Sstevel@tonic-gate ASSERT(!dipheld);
21627c478bd9Sstevel@tonic-gate return (EFAULT);
21637c478bd9Sstevel@tonic-gate }
21647c478bd9Sstevel@tonic-gate laddr = (caddr_t)req.data;
21657c478bd9Sstevel@tonic-gate laddr += wordsize;
21667c478bd9Sstevel@tonic-gate req.data = (int *)laddr;
21677c478bd9Sstevel@tonic-gate }
21687c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
21697c478bd9Sstevel@tonic-gate *rval_p = numlevels;
21707c478bd9Sstevel@tonic-gate ret = 0;
21717c478bd9Sstevel@tonic-gate break;
21727c478bd9Sstevel@tonic-gate }
21737c478bd9Sstevel@tonic-gate
21747c478bd9Sstevel@tonic-gate
21757c478bd9Sstevel@tonic-gate case PM_GET_NUM_POWER_LEVELS:
21762df1fe9cSrandyf {
21777c478bd9Sstevel@tonic-gate if (!e_pm_valid_comp(dip, req.component, &cp)) {
21787c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) "
21797c478bd9Sstevel@tonic-gate "component %d > numcmpts - 1 %d--EINVAL\n",
21807c478bd9Sstevel@tonic-gate cmdstr, PM_DEVICE(dip), req.component,
21817c478bd9Sstevel@tonic-gate PM_NUMCMPTS(dip) - 1))
21827c478bd9Sstevel@tonic-gate ret = EINVAL;
21837c478bd9Sstevel@tonic-gate break;
21847c478bd9Sstevel@tonic-gate }
21857c478bd9Sstevel@tonic-gate *rval_p = cp->pmc_comp.pmc_numlevels;
21867c478bd9Sstevel@tonic-gate ret = 0;
21877c478bd9Sstevel@tonic-gate break;
21882df1fe9cSrandyf }
21897c478bd9Sstevel@tonic-gate
21907c478bd9Sstevel@tonic-gate case PM_GET_DEVICE_THRESHOLD_BASIS:
21912df1fe9cSrandyf {
21927c478bd9Sstevel@tonic-gate ret = 0;
21937c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip);
21947c478bd9Sstevel@tonic-gate if ((info = PM_GET_PM_INFO(dip)) == NULL) {
21957c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
21967c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: "
21977c478bd9Sstevel@tonic-gate "PM_NO_PM_COMPONENTS\n", cmdstr))
21987c478bd9Sstevel@tonic-gate *rval_p = PM_NO_PM_COMPONENTS;
21997c478bd9Sstevel@tonic-gate break;
22007c478bd9Sstevel@tonic-gate }
22017c478bd9Sstevel@tonic-gate if (PM_ISDIRECT(dip)) {
22027c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
22037c478bd9Sstevel@tonic-gate *rval_p = PM_DIRECTLY_MANAGED;
22047c478bd9Sstevel@tonic-gate break;
22057c478bd9Sstevel@tonic-gate }
22067c478bd9Sstevel@tonic-gate switch (DEVI(dip)->devi_pm_flags & PMC_THRESH_ALL) {
22077c478bd9Sstevel@tonic-gate case PMC_DEF_THRESH:
22087c478bd9Sstevel@tonic-gate case PMC_NEXDEF_THRESH:
22097c478bd9Sstevel@tonic-gate *rval_p = PM_DEFAULT_THRESHOLD;
22107c478bd9Sstevel@tonic-gate break;
22117c478bd9Sstevel@tonic-gate case PMC_DEV_THRESH:
22127c478bd9Sstevel@tonic-gate *rval_p = PM_DEVICE_THRESHOLD;
22137c478bd9Sstevel@tonic-gate break;
22147c478bd9Sstevel@tonic-gate case PMC_COMP_THRESH:
22157c478bd9Sstevel@tonic-gate *rval_p = PM_COMPONENT_THRESHOLD;
22167c478bd9Sstevel@tonic-gate break;
2217c42872d4Smh27603 case PMC_CPU_THRESH:
2218c42872d4Smh27603 *rval_p = PM_CPU_THRESHOLD;
2219c42872d4Smh27603 break;
22207c478bd9Sstevel@tonic-gate default:
22217c478bd9Sstevel@tonic-gate if (PM_ISBC(dip)) {
22227c478bd9Sstevel@tonic-gate *rval_p = PM_OLD_THRESHOLD;
22237c478bd9Sstevel@tonic-gate break;
22247c478bd9Sstevel@tonic-gate }
22257c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: default, not "
22267c478bd9Sstevel@tonic-gate "BC--EINVAL", cmdstr))
22277c478bd9Sstevel@tonic-gate ret = EINVAL;
22287c478bd9Sstevel@tonic-gate break;
22297c478bd9Sstevel@tonic-gate }
22307c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip);
22317c478bd9Sstevel@tonic-gate break;
22327c478bd9Sstevel@tonic-gate }
22332df1fe9cSrandyf default:
22342df1fe9cSrandyf /*
22352df1fe9cSrandyf * Internal error, invalid ioctl description
22362df1fe9cSrandyf * force debug entry even if pm_debug not set
22372df1fe9cSrandyf */
22382df1fe9cSrandyf #ifdef DEBUG
22392df1fe9cSrandyf pm_log("invalid diptype %d for cmd %d (%s)\n",
22402df1fe9cSrandyf pcip->diptype, cmd, pcip->name);
22412df1fe9cSrandyf #endif
22422df1fe9cSrandyf ASSERT(0);
22432df1fe9cSrandyf return (EIO);
22442df1fe9cSrandyf }
22457c478bd9Sstevel@tonic-gate break;
22462df1fe9cSrandyf }
22477c478bd9Sstevel@tonic-gate
22487c478bd9Sstevel@tonic-gate case PM_PSC:
22492df1fe9cSrandyf {
22507c478bd9Sstevel@tonic-gate /*
22517c478bd9Sstevel@tonic-gate * Commands that require pm_state_change_t as arg
22527c478bd9Sstevel@tonic-gate */
22537c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
22547c478bd9Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
22557c478bd9Sstevel@tonic-gate pscp32 = (pm_state_change32_t *)arg;
22567c478bd9Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg, &psc32,
22577c478bd9Sstevel@tonic-gate sizeof (psc32), mode) != 0) {
22587c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin "
22597c478bd9Sstevel@tonic-gate "EFAULT\n\n", cmdstr))
22607c478bd9Sstevel@tonic-gate ASSERT(!dipheld);
22617c478bd9Sstevel@tonic-gate return (EFAULT);
22627c478bd9Sstevel@tonic-gate }
22637c478bd9Sstevel@tonic-gate psc.physpath = (caddr_t)(uintptr_t)psc32.physpath;
22647c478bd9Sstevel@tonic-gate psc.size = psc32.size;
22657c478bd9Sstevel@tonic-gate } else
22667c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
22677c478bd9Sstevel@tonic-gate {
22687c478bd9Sstevel@tonic-gate pscp = (pm_state_change_t *)arg;
22697c478bd9Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg, &psc,
22707c478bd9Sstevel@tonic-gate sizeof (psc), mode) != 0) {
22717c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin "
22727c478bd9Sstevel@tonic-gate "EFAULT\n\n", cmdstr))
22737c478bd9Sstevel@tonic-gate ASSERT(!dipheld);
22747c478bd9Sstevel@tonic-gate return (EFAULT);
22757c478bd9Sstevel@tonic-gate }
22767c478bd9Sstevel@tonic-gate }
22777c478bd9Sstevel@tonic-gate switch (cmd) {
22787c478bd9Sstevel@tonic-gate
22797c478bd9Sstevel@tonic-gate case PM_GET_STATE_CHANGE:
22807c478bd9Sstevel@tonic-gate case PM_GET_STATE_CHANGE_WAIT:
22817c478bd9Sstevel@tonic-gate {
22827c478bd9Sstevel@tonic-gate psce_t *pscep;
22837c478bd9Sstevel@tonic-gate pm_state_change_t *p;
22847c478bd9Sstevel@tonic-gate caddr_t physpath;
22857c478bd9Sstevel@tonic-gate size_t physlen;
22867c478bd9Sstevel@tonic-gate
22877c478bd9Sstevel@tonic-gate /*
22887c478bd9Sstevel@tonic-gate * We want to know if any device has changed state.
22897c478bd9Sstevel@tonic-gate * We look up by clone. In case we have another thread
22907c478bd9Sstevel@tonic-gate * from the same process, we loop.
22917c478bd9Sstevel@tonic-gate * pm_psc_clone_to_interest() returns a locked entry.
22927c478bd9Sstevel@tonic-gate * We create an internal copy of the event entry prior
22937c478bd9Sstevel@tonic-gate * to copyout to user space because we don't want to
22947c478bd9Sstevel@tonic-gate * hold the psce_lock while doing copyout as we might
22957c478bd9Sstevel@tonic-gate * hit page fault which eventually brings us back
22967c478bd9Sstevel@tonic-gate * here requesting the same lock.
22977c478bd9Sstevel@tonic-gate */
22987c478bd9Sstevel@tonic-gate mutex_enter(&pm_clone_lock);
22997c478bd9Sstevel@tonic-gate if (!pm_interest_registered(clone))
23007c478bd9Sstevel@tonic-gate pm_register_watcher(clone, NULL);
23017c478bd9Sstevel@tonic-gate while ((pscep =
23027c478bd9Sstevel@tonic-gate pm_psc_clone_to_interest(clone)) == NULL) {
23037c478bd9Sstevel@tonic-gate if (cmd == PM_GET_STATE_CHANGE) {
23047c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: %s: "
23057c478bd9Sstevel@tonic-gate "EWOULDBLOCK\n", cmdstr))
23067c478bd9Sstevel@tonic-gate mutex_exit(&pm_clone_lock);
23077c478bd9Sstevel@tonic-gate ASSERT(!dipheld);
23087c478bd9Sstevel@tonic-gate return (EWOULDBLOCK);
23097c478bd9Sstevel@tonic-gate } else {
23107c478bd9Sstevel@tonic-gate if (cv_wait_sig(&pm_clones_cv[clone],
23117c478bd9Sstevel@tonic-gate &pm_clone_lock) == 0) {
23127c478bd9Sstevel@tonic-gate mutex_exit(&pm_clone_lock);
23137c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s "
23147c478bd9Sstevel@tonic-gate "EINTR\n", cmdstr))
23157c478bd9Sstevel@tonic-gate ASSERT(!dipheld);
23167c478bd9Sstevel@tonic-gate return (EINTR);
23177c478bd9Sstevel@tonic-gate }
23187c478bd9Sstevel@tonic-gate }
23197c478bd9Sstevel@tonic-gate }
23207c478bd9Sstevel@tonic-gate mutex_exit(&pm_clone_lock);
23217c478bd9Sstevel@tonic-gate
23227c478bd9Sstevel@tonic-gate physlen = pscep->psce_out->size;
23237c478bd9Sstevel@tonic-gate physpath = NULL;
23247c478bd9Sstevel@tonic-gate /*
23257c478bd9Sstevel@tonic-gate * If we were unable to store the path while bringing
23267c478bd9Sstevel@tonic-gate * up the console fb upon entering the prom, we give
23277c478bd9Sstevel@tonic-gate * a "" name with the overrun event set
23287c478bd9Sstevel@tonic-gate */
23297c478bd9Sstevel@tonic-gate if (physlen == (size_t)-1) { /* kmemalloc failed */
23307c478bd9Sstevel@tonic-gate physpath = kmem_zalloc(1, KM_SLEEP);
23317c478bd9Sstevel@tonic-gate physlen = 1;
23327c478bd9Sstevel@tonic-gate }
23337c478bd9Sstevel@tonic-gate if ((psc.physpath == NULL) || (psc.size < physlen)) {
23347c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: EFAULT\n", cmdstr))
23357c478bd9Sstevel@tonic-gate mutex_exit(&pscep->psce_lock);
23367c478bd9Sstevel@tonic-gate ret = EFAULT;
23377c478bd9Sstevel@tonic-gate break;
23387c478bd9Sstevel@tonic-gate }
23397c478bd9Sstevel@tonic-gate if (physpath == NULL) {
23407c478bd9Sstevel@tonic-gate physpath = kmem_zalloc(physlen, KM_SLEEP);
23417c478bd9Sstevel@tonic-gate bcopy((const void *) pscep->psce_out->physpath,
23427c478bd9Sstevel@tonic-gate (void *) physpath, physlen);
23437c478bd9Sstevel@tonic-gate }
23447c478bd9Sstevel@tonic-gate
23457c478bd9Sstevel@tonic-gate p = pscep->psce_out;
23467c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
23477c478bd9Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
23487c478bd9Sstevel@tonic-gate #ifdef DEBUG
23497c478bd9Sstevel@tonic-gate size_t usrcopysize;
23507c478bd9Sstevel@tonic-gate #endif
23517c478bd9Sstevel@tonic-gate psc32.flags = (ushort_t)p->flags;
23527c478bd9Sstevel@tonic-gate psc32.event = (ushort_t)p->event;
23537c478bd9Sstevel@tonic-gate psc32.timestamp = (int32_t)p->timestamp;
23547c478bd9Sstevel@tonic-gate psc32.component = (int32_t)p->component;
23557c478bd9Sstevel@tonic-gate psc32.old_level = (int32_t)p->old_level;
23567c478bd9Sstevel@tonic-gate psc32.new_level = (int32_t)p->new_level;
23577c478bd9Sstevel@tonic-gate copysize32 = ((intptr_t)&psc32.size -
23587c478bd9Sstevel@tonic-gate (intptr_t)&psc32.component);
23597c478bd9Sstevel@tonic-gate #ifdef DEBUG
23607c478bd9Sstevel@tonic-gate usrcopysize = ((intptr_t)&pscp32->size -
23617c478bd9Sstevel@tonic-gate (intptr_t)&pscp32->component);
23627c478bd9Sstevel@tonic-gate ASSERT(usrcopysize == copysize32);
23637c478bd9Sstevel@tonic-gate #endif
23647c478bd9Sstevel@tonic-gate } else
23657c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
23667c478bd9Sstevel@tonic-gate {
23677c478bd9Sstevel@tonic-gate psc.flags = p->flags;
23687c478bd9Sstevel@tonic-gate psc.event = p->event;
23697c478bd9Sstevel@tonic-gate psc.timestamp = p->timestamp;
23707c478bd9Sstevel@tonic-gate psc.component = p->component;
23717c478bd9Sstevel@tonic-gate psc.old_level = p->old_level;
23727c478bd9Sstevel@tonic-gate psc.new_level = p->new_level;
23737c478bd9Sstevel@tonic-gate copysize = ((long)&p->size -
23747c478bd9Sstevel@tonic-gate (long)&p->component);
23757c478bd9Sstevel@tonic-gate }
23767c478bd9Sstevel@tonic-gate if (p->size != (size_t)-1)
23777c478bd9Sstevel@tonic-gate kmem_free(p->physpath, p->size);
23787c478bd9Sstevel@tonic-gate p->size = 0;
23797c478bd9Sstevel@tonic-gate p->physpath = NULL;
23807c478bd9Sstevel@tonic-gate if (pscep->psce_out == pscep->psce_last)
23817c478bd9Sstevel@tonic-gate p = pscep->psce_first;
23827c478bd9Sstevel@tonic-gate else
23837c478bd9Sstevel@tonic-gate p++;
23847c478bd9Sstevel@tonic-gate pscep->psce_out = p;
23857c478bd9Sstevel@tonic-gate mutex_exit(&pscep->psce_lock);
23867c478bd9Sstevel@tonic-gate
23877c478bd9Sstevel@tonic-gate ret = copyoutstr(physpath, psc.physpath,
23887c478bd9Sstevel@tonic-gate physlen, &lencopied);
23897c478bd9Sstevel@tonic-gate kmem_free(physpath, physlen);
23907c478bd9Sstevel@tonic-gate if (ret) {
23917c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: copyoutstr %p "
23927c478bd9Sstevel@tonic-gate "failed--EFAULT\n", cmdstr,
23937c478bd9Sstevel@tonic-gate (void *)psc.physpath))
23947c478bd9Sstevel@tonic-gate break;
23957c478bd9Sstevel@tonic-gate }
23967c478bd9Sstevel@tonic-gate
23977c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
23987c478bd9Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
23997c478bd9Sstevel@tonic-gate if (ddi_copyout(&psc32.component,
24007c478bd9Sstevel@tonic-gate &pscp32->component, copysize32, mode)
24017c478bd9Sstevel@tonic-gate != 0) {
24027c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: copyout "
24037c478bd9Sstevel@tonic-gate "failed--EFAULT\n", cmdstr))
24047c478bd9Sstevel@tonic-gate ret = EFAULT;
24057c478bd9Sstevel@tonic-gate break;
24067c478bd9Sstevel@tonic-gate }
24077c478bd9Sstevel@tonic-gate } else
24087c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
24097c478bd9Sstevel@tonic-gate {
24107c478bd9Sstevel@tonic-gate if (ddi_copyout(&psc.component,
24117c478bd9Sstevel@tonic-gate &pscp->component, copysize, mode) != 0) {
24127c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: copyout "
24137c478bd9Sstevel@tonic-gate "failed--EFAULT\n", cmdstr))
24147c478bd9Sstevel@tonic-gate ret = EFAULT;
24157c478bd9Sstevel@tonic-gate break;
24167c478bd9Sstevel@tonic-gate }
24177c478bd9Sstevel@tonic-gate }
24187c478bd9Sstevel@tonic-gate ret = 0;
24197c478bd9Sstevel@tonic-gate break;
24207c478bd9Sstevel@tonic-gate }
24217c478bd9Sstevel@tonic-gate
24227c478bd9Sstevel@tonic-gate case PM_DIRECT_NOTIFY:
24237c478bd9Sstevel@tonic-gate case PM_DIRECT_NOTIFY_WAIT:
24247c478bd9Sstevel@tonic-gate {
24257c478bd9Sstevel@tonic-gate psce_t *pscep;
24267c478bd9Sstevel@tonic-gate pm_state_change_t *p;
24277c478bd9Sstevel@tonic-gate caddr_t physpath;
24287c478bd9Sstevel@tonic-gate size_t physlen;
24297c478bd9Sstevel@tonic-gate /*
24307c478bd9Sstevel@tonic-gate * We want to know if any direct device of ours has
24317c478bd9Sstevel@tonic-gate * something we should know about. We look up by clone.
24327c478bd9Sstevel@tonic-gate * In case we have another thread from the same process,
24337c478bd9Sstevel@tonic-gate * we loop.
24347c478bd9Sstevel@tonic-gate * pm_psc_clone_to_direct() returns a locked entry.
24357c478bd9Sstevel@tonic-gate */
24367c478bd9Sstevel@tonic-gate mutex_enter(&pm_clone_lock);
24377c478bd9Sstevel@tonic-gate while (pm_poll_cnt[clone] == 0 ||
24387c478bd9Sstevel@tonic-gate (pscep = pm_psc_clone_to_direct(clone)) == NULL) {
24397c478bd9Sstevel@tonic-gate if (cmd == PM_DIRECT_NOTIFY) {
24407c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: %s: "
24417c478bd9Sstevel@tonic-gate "EWOULDBLOCK\n", cmdstr))
24427c478bd9Sstevel@tonic-gate mutex_exit(&pm_clone_lock);
24437c478bd9Sstevel@tonic-gate ASSERT(!dipheld);
24447c478bd9Sstevel@tonic-gate return (EWOULDBLOCK);
24457c478bd9Sstevel@tonic-gate } else {
24467c478bd9Sstevel@tonic-gate if (cv_wait_sig(&pm_clones_cv[clone],
24477c478bd9Sstevel@tonic-gate &pm_clone_lock) == 0) {
24487c478bd9Sstevel@tonic-gate mutex_exit(&pm_clone_lock);
24497c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: "
24507c478bd9Sstevel@tonic-gate "EINTR\n", cmdstr))
24517c478bd9Sstevel@tonic-gate ASSERT(!dipheld);
24527c478bd9Sstevel@tonic-gate return (EINTR);
24537c478bd9Sstevel@tonic-gate }
24547c478bd9Sstevel@tonic-gate }
24557c478bd9Sstevel@tonic-gate }
24567c478bd9Sstevel@tonic-gate mutex_exit(&pm_clone_lock);
24577c478bd9Sstevel@tonic-gate physlen = pscep->psce_out->size;
24587c478bd9Sstevel@tonic-gate if ((psc.physpath == NULL) || (psc.size < physlen)) {
24597c478bd9Sstevel@tonic-gate mutex_exit(&pscep->psce_lock);
24607c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: EFAULT\n",
24617c478bd9Sstevel@tonic-gate cmdstr))
24627c478bd9Sstevel@tonic-gate ret = EFAULT;
24637c478bd9Sstevel@tonic-gate break;
24647c478bd9Sstevel@tonic-gate }
24657c478bd9Sstevel@tonic-gate physpath = kmem_zalloc(physlen, KM_SLEEP);
24667c478bd9Sstevel@tonic-gate bcopy((const void *) pscep->psce_out->physpath,
24677c478bd9Sstevel@tonic-gate (void *) physpath, physlen);
24687c478bd9Sstevel@tonic-gate
24697c478bd9Sstevel@tonic-gate p = pscep->psce_out;
24707c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
24717c478bd9Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
24727c478bd9Sstevel@tonic-gate #ifdef DEBUG
24737c478bd9Sstevel@tonic-gate size_t usrcopysize;
24747c478bd9Sstevel@tonic-gate #endif
24757c478bd9Sstevel@tonic-gate psc32.component = (int32_t)p->component;
24767c478bd9Sstevel@tonic-gate psc32.flags = (ushort_t)p->flags;
24777c478bd9Sstevel@tonic-gate psc32.event = (ushort_t)p->event;
24787c478bd9Sstevel@tonic-gate psc32.timestamp = (int32_t)p->timestamp;
24797c478bd9Sstevel@tonic-gate psc32.old_level = (int32_t)p->old_level;
24807c478bd9Sstevel@tonic-gate psc32.new_level = (int32_t)p->new_level;
24817c478bd9Sstevel@tonic-gate copysize32 = (intptr_t)&psc32.size -
24827c478bd9Sstevel@tonic-gate (intptr_t)&psc32.component;
24837c478bd9Sstevel@tonic-gate PMD(PMD_DPM, ("ioctl: %s: PDN32 %s, comp %d "
24847c478bd9Sstevel@tonic-gate "%d -> %d\n", cmdstr, physpath,
24857c478bd9Sstevel@tonic-gate p->component, p->old_level, p->new_level))
24867c478bd9Sstevel@tonic-gate #ifdef DEBUG
24877c478bd9Sstevel@tonic-gate usrcopysize = (intptr_t)&pscp32->size -
24887c478bd9Sstevel@tonic-gate (intptr_t)&pscp32->component;
24897c478bd9Sstevel@tonic-gate ASSERT(usrcopysize == copysize32);
24907c478bd9Sstevel@tonic-gate #endif
24917c478bd9Sstevel@tonic-gate } else
24927c478bd9Sstevel@tonic-gate #endif
24937c478bd9Sstevel@tonic-gate {
24947c478bd9Sstevel@tonic-gate psc.component = p->component;
24957c478bd9Sstevel@tonic-gate psc.flags = p->flags;
24967c478bd9Sstevel@tonic-gate psc.event = p->event;
24977c478bd9Sstevel@tonic-gate psc.timestamp = p->timestamp;
24987c478bd9Sstevel@tonic-gate psc.old_level = p->old_level;
24997c478bd9Sstevel@tonic-gate psc.new_level = p->new_level;
25007c478bd9Sstevel@tonic-gate copysize = (intptr_t)&p->size -
25017c478bd9Sstevel@tonic-gate (intptr_t)&p->component;
25027c478bd9Sstevel@tonic-gate PMD(PMD_DPM, ("ioctl: %s: PDN %s, comp %d "
25037c478bd9Sstevel@tonic-gate "%d -> %d\n", cmdstr, physpath,
25047c478bd9Sstevel@tonic-gate p->component, p->old_level, p->new_level))
25057c478bd9Sstevel@tonic-gate }
25067c478bd9Sstevel@tonic-gate mutex_enter(&pm_clone_lock);
25077c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: %s: pm_poll_cnt[%d] is %d "
25087c478bd9Sstevel@tonic-gate "before decrement\n", cmdstr, clone,
25097c478bd9Sstevel@tonic-gate pm_poll_cnt[clone]))
25107c478bd9Sstevel@tonic-gate pm_poll_cnt[clone]--;
25117c478bd9Sstevel@tonic-gate mutex_exit(&pm_clone_lock);
25127c478bd9Sstevel@tonic-gate kmem_free(p->physpath, p->size);
25137c478bd9Sstevel@tonic-gate p->size = 0;
25147c478bd9Sstevel@tonic-gate p->physpath = NULL;
25157c478bd9Sstevel@tonic-gate if (pscep->psce_out == pscep->psce_last)
25167c478bd9Sstevel@tonic-gate p = pscep->psce_first;
25177c478bd9Sstevel@tonic-gate else
25187c478bd9Sstevel@tonic-gate p++;
25197c478bd9Sstevel@tonic-gate pscep->psce_out = p;
25207c478bd9Sstevel@tonic-gate mutex_exit(&pscep->psce_lock);
25217c478bd9Sstevel@tonic-gate
25227c478bd9Sstevel@tonic-gate ret = copyoutstr(physpath, psc.physpath,
25237c478bd9Sstevel@tonic-gate physlen, &lencopied);
25247c478bd9Sstevel@tonic-gate kmem_free(physpath, physlen);
25257c478bd9Sstevel@tonic-gate if (ret) {
25267c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: copyoutstr %p "
25277c478bd9Sstevel@tonic-gate "failed--EFAULT\n", cmdstr,
25287c478bd9Sstevel@tonic-gate (void *)psc.physpath))
25297c478bd9Sstevel@tonic-gate break;
25307c478bd9Sstevel@tonic-gate }
25317c478bd9Sstevel@tonic-gate
25327c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
25337c478bd9Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
25347c478bd9Sstevel@tonic-gate if (ddi_copyout(&psc32.component,
25357c478bd9Sstevel@tonic-gate &pscp32->component, copysize32, mode)
25367c478bd9Sstevel@tonic-gate != 0) {
25377c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: copyout "
25387c478bd9Sstevel@tonic-gate "failed--EFAULT\n", cmdstr))
25397c478bd9Sstevel@tonic-gate ret = EFAULT;
25407c478bd9Sstevel@tonic-gate break;
25417c478bd9Sstevel@tonic-gate }
25427c478bd9Sstevel@tonic-gate } else
25437c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
25447c478bd9Sstevel@tonic-gate {
25457c478bd9Sstevel@tonic-gate if (ddi_copyout(&psc.component,
25467c478bd9Sstevel@tonic-gate &pscp->component, copysize, mode) != 0) {
25477c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: copyout "
25487c478bd9Sstevel@tonic-gate "failed--EFAULT\n", cmdstr))
25497c478bd9Sstevel@tonic-gate ret = EFAULT;
25507c478bd9Sstevel@tonic-gate break;
25517c478bd9Sstevel@tonic-gate }
25527c478bd9Sstevel@tonic-gate }
25537c478bd9Sstevel@tonic-gate ret = 0;
25547c478bd9Sstevel@tonic-gate break;
25557c478bd9Sstevel@tonic-gate }
25567c478bd9Sstevel@tonic-gate default:
25572df1fe9cSrandyf /*
25582df1fe9cSrandyf * Internal error, invalid ioctl description
25592df1fe9cSrandyf * force debug entry even if pm_debug not set
25602df1fe9cSrandyf */
25612df1fe9cSrandyf #ifdef DEBUG
25622df1fe9cSrandyf pm_log("invalid diptype %d for cmd %d (%s)\n",
25632df1fe9cSrandyf pcip->diptype, cmd, pcip->name);
25642df1fe9cSrandyf #endif
25657c478bd9Sstevel@tonic-gate ASSERT(0);
25662df1fe9cSrandyf return (EIO);
25677c478bd9Sstevel@tonic-gate }
25687c478bd9Sstevel@tonic-gate break;
25692df1fe9cSrandyf }
25702df1fe9cSrandyf
25712df1fe9cSrandyf case PM_SRCH: /* command that takes a pm_searchargs_t arg */
25722df1fe9cSrandyf {
25732df1fe9cSrandyf /*
25742df1fe9cSrandyf * If no ppm, then there is nothing to search.
25752df1fe9cSrandyf */
25762df1fe9cSrandyf if (DEVI(ddi_root_node())->devi_pm_ppm == NULL) {
25772df1fe9cSrandyf ret = ENODEV;
25782df1fe9cSrandyf break;
25792df1fe9cSrandyf }
25802df1fe9cSrandyf
25812df1fe9cSrandyf #ifdef _MULTI_DATAMODEL
25822df1fe9cSrandyf if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
25832df1fe9cSrandyf if (ddi_copyin((caddr_t)arg, &psa32,
25842df1fe9cSrandyf sizeof (psa32), mode) != 0) {
25852df1fe9cSrandyf PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin "
25862df1fe9cSrandyf "EFAULT\n\n", cmdstr))
25872df1fe9cSrandyf return (EFAULT);
25882df1fe9cSrandyf }
25892df1fe9cSrandyf if (copyinstr((void *)(uintptr_t)psa32.pms_listname,
25902df1fe9cSrandyf listname, MAXCOPYBUF, NULL)) {
25912df1fe9cSrandyf PMD(PMD_ERROR, ("ioctl: %s: 0x%p MAXCOPYBUF "
25922df1fe9cSrandyf "%d, " "EFAULT\n", cmdstr,
25932df1fe9cSrandyf (void *)(uintptr_t)psa32.pms_listname,
25942df1fe9cSrandyf MAXCOPYBUF))
25952df1fe9cSrandyf ret = EFAULT;
25962df1fe9cSrandyf break;
25972df1fe9cSrandyf }
25982df1fe9cSrandyf if (copyinstr((void *)(uintptr_t)psa32.pms_manufacturer,
25992df1fe9cSrandyf manufacturer, MAXCOPYBUF, NULL)) {
26002df1fe9cSrandyf PMD(PMD_ERROR, ("ioctl: %s: 0x%p MAXCOPYBUF "
26012df1fe9cSrandyf "%d, " "EFAULT\n", cmdstr,
26022df1fe9cSrandyf (void *)(uintptr_t)psa32.pms_manufacturer,
26032df1fe9cSrandyf MAXCOPYBUF))
26042df1fe9cSrandyf ret = EFAULT;
26052df1fe9cSrandyf break;
26062df1fe9cSrandyf }
26072df1fe9cSrandyf if (copyinstr((void *)(uintptr_t)psa32.pms_product,
26082df1fe9cSrandyf product, MAXCOPYBUF, NULL)) {
26092df1fe9cSrandyf PMD(PMD_ERROR, ("ioctl: %s: 0x%p MAXCOPYBUF "
26102df1fe9cSrandyf "%d, " "EFAULT\n", cmdstr,
26112df1fe9cSrandyf (void *)(uintptr_t)psa32.pms_product,
26122df1fe9cSrandyf MAXCOPYBUF))
26132df1fe9cSrandyf ret = EFAULT;
26142df1fe9cSrandyf break;
26152df1fe9cSrandyf }
26162df1fe9cSrandyf } else
26172df1fe9cSrandyf #endif /* _MULTI_DATAMODEL */
26182df1fe9cSrandyf {
26192df1fe9cSrandyf if (ddi_copyin((caddr_t)arg, &psa,
26202df1fe9cSrandyf sizeof (psa), mode) != 0) {
26212df1fe9cSrandyf PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin "
26222df1fe9cSrandyf "EFAULT\n\n", cmdstr))
26232df1fe9cSrandyf return (EFAULT);
26242df1fe9cSrandyf }
26252df1fe9cSrandyf if (copyinstr(psa.pms_listname,
26262df1fe9cSrandyf listname, MAXCOPYBUF, NULL)) {
26272df1fe9cSrandyf PMD(PMD_ERROR, ("ioctl: %s: 0x%p MAXCOPYBUF "
26282df1fe9cSrandyf "%d, " "EFAULT\n", cmdstr,
26292df1fe9cSrandyf (void *)psa.pms_listname, MAXCOPYBUF))
26302df1fe9cSrandyf ret = EFAULT;
26312df1fe9cSrandyf break;
26322df1fe9cSrandyf }
26332df1fe9cSrandyf if (copyinstr(psa.pms_manufacturer,
26342df1fe9cSrandyf manufacturer, MAXCOPYBUF, NULL)) {
26352df1fe9cSrandyf PMD(PMD_ERROR, ("ioctl: %s: 0x%p MAXCOPYBUF "
26362df1fe9cSrandyf "%d, " "EFAULT\n", cmdstr,
26372df1fe9cSrandyf (void *)psa.pms_manufacturer, MAXCOPYBUF))
26382df1fe9cSrandyf ret = EFAULT;
26392df1fe9cSrandyf break;
26402df1fe9cSrandyf }
26412df1fe9cSrandyf if (copyinstr(psa.pms_product,
26422df1fe9cSrandyf product, MAXCOPYBUF, NULL)) {
26432df1fe9cSrandyf PMD(PMD_ERROR, ("ioctl: %s: 0x%p MAXCOPYBUF "
26442df1fe9cSrandyf "%d, " "EFAULT\n", cmdstr,
26452df1fe9cSrandyf (void *)psa.pms_product, MAXCOPYBUF))
26462df1fe9cSrandyf ret = EFAULT;
26472df1fe9cSrandyf break;
26482df1fe9cSrandyf }
26492df1fe9cSrandyf }
26502df1fe9cSrandyf psa.pms_listname = listname;
26512df1fe9cSrandyf psa.pms_manufacturer = manufacturer;
26522df1fe9cSrandyf psa.pms_product = product;
26532df1fe9cSrandyf switch (cmd) {
26542df1fe9cSrandyf case PM_SEARCH_LIST:
26552df1fe9cSrandyf ret = pm_ppm_searchlist(&psa);
26562df1fe9cSrandyf break;
26572df1fe9cSrandyf
26582df1fe9cSrandyf default:
26592df1fe9cSrandyf /*
26602df1fe9cSrandyf * Internal error, invalid ioctl description
26612df1fe9cSrandyf * force debug entry even if pm_debug not set
26622df1fe9cSrandyf */
26632df1fe9cSrandyf #ifdef DEBUG
26642df1fe9cSrandyf pm_log("invalid diptype %d for cmd %d (%s)\n",
26652df1fe9cSrandyf pcip->diptype, cmd, pcip->name);
26662df1fe9cSrandyf #endif
26672df1fe9cSrandyf ASSERT(0);
26682df1fe9cSrandyf return (EIO);
26692df1fe9cSrandyf }
26702df1fe9cSrandyf break;
26712df1fe9cSrandyf }
26727c478bd9Sstevel@tonic-gate
26737c478bd9Sstevel@tonic-gate case NOSTRUCT:
26742df1fe9cSrandyf {
26757c478bd9Sstevel@tonic-gate switch (cmd) {
26767c478bd9Sstevel@tonic-gate case PM_START_PM:
2677c42872d4Smh27603 case PM_START_CPUPM:
2678*0e751525SEric Saxe case PM_START_CPUPM_EV:
2679*0e751525SEric Saxe case PM_START_CPUPM_POLL:
26802df1fe9cSrandyf {
2681*0e751525SEric Saxe pm_cpupm_t new_mode = PM_CPUPM_NOTSET;
2682*0e751525SEric Saxe pm_cpupm_t old_mode = PM_CPUPM_NOTSET;
2683*0e751525SEric Saxe int r;
2684*0e751525SEric Saxe
26857c478bd9Sstevel@tonic-gate mutex_enter(&pm_scan_lock);
2686c42872d4Smh27603 if ((cmd == PM_START_PM && autopm_enabled) ||
2687*0e751525SEric Saxe (cmd == PM_START_CPUPM && PM_DEFAULT_CPUPM) ||
2688*0e751525SEric Saxe (cmd == PM_START_CPUPM_EV && PM_EVENT_CPUPM) ||
2689*0e751525SEric Saxe (cmd == PM_START_CPUPM_POLL && PM_POLLING_CPUPM)) {
26907c478bd9Sstevel@tonic-gate mutex_exit(&pm_scan_lock);
2691*0e751525SEric Saxe PMD(PMD_ERROR, ("ioctl: %s: EBUSY\n", cmdstr))
26927c478bd9Sstevel@tonic-gate ret = EBUSY;
26937c478bd9Sstevel@tonic-gate break;
26947c478bd9Sstevel@tonic-gate }
2695*0e751525SEric Saxe
2696*0e751525SEric Saxe if (cmd == PM_START_PM) {
26977c478bd9Sstevel@tonic-gate autopm_enabled = 1;
2698*0e751525SEric Saxe } else if (cmd == PM_START_CPUPM) {
2699*0e751525SEric Saxe old_mode = cpupm;
2700*0e751525SEric Saxe new_mode = cpupm = cpupm_default_mode;
2701*0e751525SEric Saxe } else if (cmd == PM_START_CPUPM_EV) {
2702*0e751525SEric Saxe old_mode = cpupm;
2703*0e751525SEric Saxe new_mode = cpupm = PM_CPUPM_EVENT;
2704*0e751525SEric Saxe } else if (cmd == PM_START_CPUPM_POLL) {
2705*0e751525SEric Saxe old_mode = cpupm;
2706*0e751525SEric Saxe new_mode = cpupm = PM_CPUPM_POLLING;
2707*0e751525SEric Saxe }
2708*0e751525SEric Saxe
27097c478bd9Sstevel@tonic-gate mutex_exit(&pm_scan_lock);
2710*0e751525SEric Saxe
2711*0e751525SEric Saxe /*
2712*0e751525SEric Saxe * If we are changing CPUPM modes, and it is active,
2713*0e751525SEric Saxe * then stop it from operating in the old mode.
2714*0e751525SEric Saxe */
2715*0e751525SEric Saxe if (old_mode == PM_CPUPM_POLLING) {
2716*0e751525SEric Saxe int c = PM_STOP_CPUPM;
2717*0e751525SEric Saxe ddi_walk_devs(ddi_root_node(), pm_stop_pm_walk,
2718*0e751525SEric Saxe &c);
2719*0e751525SEric Saxe } else if (old_mode == PM_CPUPM_EVENT) {
2720*0e751525SEric Saxe r = cpupm_set_policy(CPUPM_POLICY_DISABLED);
2721*0e751525SEric Saxe
2722*0e751525SEric Saxe /*
2723*0e751525SEric Saxe * Disabling CPUPM policy should always
2724*0e751525SEric Saxe * succeed
2725*0e751525SEric Saxe */
2726*0e751525SEric Saxe ASSERT(r == 0);
2727*0e751525SEric Saxe }
2728*0e751525SEric Saxe
2729*0e751525SEric Saxe /*
2730*0e751525SEric Saxe * If we are changing to event based CPUPM, enable it.
2731*0e751525SEric Saxe * In the event it's not supported, fall back to
2732*0e751525SEric Saxe * polling based CPUPM.
2733*0e751525SEric Saxe */
2734*0e751525SEric Saxe if (new_mode == PM_CPUPM_EVENT &&
2735*0e751525SEric Saxe cpupm_set_policy(CPUPM_POLICY_ELASTIC) < 0) {
2736*0e751525SEric Saxe mutex_enter(&pm_scan_lock);
2737*0e751525SEric Saxe new_mode = cpupm = PM_CPUPM_POLLING;
2738*0e751525SEric Saxe cmd = PM_START_CPUPM_POLL;
2739*0e751525SEric Saxe mutex_exit(&pm_scan_lock);
2740*0e751525SEric Saxe }
2741*0e751525SEric Saxe if (new_mode == PM_CPUPM_POLLING ||
2742*0e751525SEric Saxe cmd == PM_START_PM) {
2743*0e751525SEric Saxe ddi_walk_devs(ddi_root_node(), pm_start_pm_walk,
2744*0e751525SEric Saxe &cmd);
2745*0e751525SEric Saxe }
27467c478bd9Sstevel@tonic-gate ret = 0;
27477c478bd9Sstevel@tonic-gate break;
27482df1fe9cSrandyf }
27497c478bd9Sstevel@tonic-gate
27507c478bd9Sstevel@tonic-gate case PM_RESET_PM:
27517c478bd9Sstevel@tonic-gate case PM_STOP_PM:
2752c42872d4Smh27603 case PM_STOP_CPUPM:
27537c478bd9Sstevel@tonic-gate {
27547c478bd9Sstevel@tonic-gate extern void pm_discard_thresholds(void);
2755*0e751525SEric Saxe pm_cpupm_t old_mode = PM_CPUPM_NOTSET;
27567c478bd9Sstevel@tonic-gate
27577c478bd9Sstevel@tonic-gate mutex_enter(&pm_scan_lock);
2758c42872d4Smh27603 if ((cmd == PM_STOP_PM && !autopm_enabled) ||
2759c42872d4Smh27603 (cmd == PM_STOP_CPUPM && PM_CPUPM_DISABLED)) {
27607c478bd9Sstevel@tonic-gate mutex_exit(&pm_scan_lock);
27617c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: EINVAL\n",
27627c478bd9Sstevel@tonic-gate cmdstr))
27637c478bd9Sstevel@tonic-gate ret = EINVAL;
27647c478bd9Sstevel@tonic-gate break;
27657c478bd9Sstevel@tonic-gate }
2766*0e751525SEric Saxe
27672df1fe9cSrandyf if (cmd == PM_STOP_PM) {
27687c478bd9Sstevel@tonic-gate autopm_enabled = 0;
27692df1fe9cSrandyf pm_S3_enabled = 0;
27702df1fe9cSrandyf autoS3_enabled = 0;
27712df1fe9cSrandyf } else if (cmd == PM_STOP_CPUPM) {
2772*0e751525SEric Saxe old_mode = cpupm;
2773c42872d4Smh27603 cpupm = PM_CPUPM_DISABLE;
27742df1fe9cSrandyf } else {
2775c42872d4Smh27603 autopm_enabled = 0;
27762df1fe9cSrandyf autoS3_enabled = 0;
2777*0e751525SEric Saxe old_mode = cpupm;
2778c42872d4Smh27603 cpupm = PM_CPUPM_NOTSET;
2779c42872d4Smh27603 }
27807c478bd9Sstevel@tonic-gate mutex_exit(&pm_scan_lock);
2781c42872d4Smh27603
27827c478bd9Sstevel@tonic-gate /*
27837c478bd9Sstevel@tonic-gate * bring devices to full power level, stop scan
2784*0e751525SEric Saxe * If CPUPM was operating in event driven mode, disable
2785*0e751525SEric Saxe * that.
27867c478bd9Sstevel@tonic-gate */
2787*0e751525SEric Saxe if (old_mode == PM_CPUPM_EVENT) {
2788*0e751525SEric Saxe (void) cpupm_set_policy(CPUPM_POLICY_DISABLED);
2789*0e751525SEric Saxe }
27907c478bd9Sstevel@tonic-gate ddi_walk_devs(ddi_root_node(), pm_stop_pm_walk, &cmd);
27917c478bd9Sstevel@tonic-gate ret = 0;
2792c42872d4Smh27603 if (cmd == PM_STOP_PM || cmd == PM_STOP_CPUPM)
27937c478bd9Sstevel@tonic-gate break;
27947c478bd9Sstevel@tonic-gate /*
27957c478bd9Sstevel@tonic-gate * Now do only PM_RESET_PM stuff.
27967c478bd9Sstevel@tonic-gate */
27977c478bd9Sstevel@tonic-gate pm_system_idle_threshold = pm_default_idle_threshold;
2798c42872d4Smh27603 pm_cpu_idle_threshold = 0;
27997c478bd9Sstevel@tonic-gate pm_discard_thresholds();
28007c478bd9Sstevel@tonic-gate pm_all_to_default_thresholds();
28017c478bd9Sstevel@tonic-gate pm_dispatch_to_dep_thread(PM_DEP_WK_REMOVE_DEP,
28027c478bd9Sstevel@tonic-gate NULL, NULL, PM_DEP_WAIT, NULL, 0);
28037c478bd9Sstevel@tonic-gate break;
28047c478bd9Sstevel@tonic-gate }
28057c478bd9Sstevel@tonic-gate
28067c478bd9Sstevel@tonic-gate case PM_GET_SYSTEM_THRESHOLD:
28072df1fe9cSrandyf {
28087c478bd9Sstevel@tonic-gate *rval_p = pm_system_idle_threshold;
28097c478bd9Sstevel@tonic-gate ret = 0;
28107c478bd9Sstevel@tonic-gate break;
28112df1fe9cSrandyf }
28127c478bd9Sstevel@tonic-gate
28137c478bd9Sstevel@tonic-gate case PM_GET_DEFAULT_SYSTEM_THRESHOLD:
28142df1fe9cSrandyf {
28157c478bd9Sstevel@tonic-gate *rval_p = pm_default_idle_threshold;
28167c478bd9Sstevel@tonic-gate ret = 0;
28177c478bd9Sstevel@tonic-gate break;
28182df1fe9cSrandyf }
28197c478bd9Sstevel@tonic-gate
2820c42872d4Smh27603 case PM_GET_CPU_THRESHOLD:
28212df1fe9cSrandyf {
2822c42872d4Smh27603 *rval_p = pm_cpu_idle_threshold;
2823c42872d4Smh27603 ret = 0;
2824c42872d4Smh27603 break;
28252df1fe9cSrandyf }
2826c42872d4Smh27603
28277c478bd9Sstevel@tonic-gate case PM_SET_SYSTEM_THRESHOLD:
2828c42872d4Smh27603 case PM_SET_CPU_THRESHOLD:
28292df1fe9cSrandyf {
28307c478bd9Sstevel@tonic-gate if ((int)arg < 0) {
28317c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: arg 0x%x < 0"
28327c478bd9Sstevel@tonic-gate "--EINVAL\n", cmdstr, (int)arg))
28337c478bd9Sstevel@tonic-gate ret = EINVAL;
28347c478bd9Sstevel@tonic-gate break;
28357c478bd9Sstevel@tonic-gate }
28367c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: %s: 0x%x 0t%d\n", cmdstr,
28377c478bd9Sstevel@tonic-gate (int)arg, (int)arg))
2838c42872d4Smh27603 if (cmd == PM_SET_SYSTEM_THRESHOLD)
28397c478bd9Sstevel@tonic-gate pm_system_idle_threshold = (int)arg;
2840c42872d4Smh27603 else {
2841c42872d4Smh27603 pm_cpu_idle_threshold = (int)arg;
2842c42872d4Smh27603 }
2843c42872d4Smh27603 ddi_walk_devs(ddi_root_node(), pm_set_idle_thresh_walk,
2844c42872d4Smh27603 (void *) &cmd);
2845c42872d4Smh27603
28467c478bd9Sstevel@tonic-gate ret = 0;
28477c478bd9Sstevel@tonic-gate break;
28482df1fe9cSrandyf }
28497c478bd9Sstevel@tonic-gate
28507c478bd9Sstevel@tonic-gate case PM_IDLE_DOWN:
28512df1fe9cSrandyf {
28527c478bd9Sstevel@tonic-gate if (pm_timeout_idledown() != 0) {
28537c478bd9Sstevel@tonic-gate ddi_walk_devs(ddi_root_node(),
28547c478bd9Sstevel@tonic-gate pm_start_idledown, (void *)PMID_IOC);
28557c478bd9Sstevel@tonic-gate }
28567c478bd9Sstevel@tonic-gate ret = 0;
28577c478bd9Sstevel@tonic-gate break;
28582df1fe9cSrandyf }
28597c478bd9Sstevel@tonic-gate
28607c478bd9Sstevel@tonic-gate case PM_GET_PM_STATE:
28612df1fe9cSrandyf {
28627c478bd9Sstevel@tonic-gate if (autopm_enabled) {
28637c478bd9Sstevel@tonic-gate *rval_p = PM_SYSTEM_PM_ENABLED;
28647c478bd9Sstevel@tonic-gate } else {
28657c478bd9Sstevel@tonic-gate *rval_p = PM_SYSTEM_PM_DISABLED;
28667c478bd9Sstevel@tonic-gate }
28677c478bd9Sstevel@tonic-gate ret = 0;
28687c478bd9Sstevel@tonic-gate break;
28692df1fe9cSrandyf }
2870c42872d4Smh27603
2871c42872d4Smh27603 case PM_GET_CPUPM_STATE:
28722df1fe9cSrandyf {
2873*0e751525SEric Saxe if (PM_POLLING_CPUPM || PM_EVENT_CPUPM)
2874c42872d4Smh27603 *rval_p = PM_CPU_PM_ENABLED;
2875c42872d4Smh27603 else if (PM_CPUPM_DISABLED)
2876c42872d4Smh27603 *rval_p = PM_CPU_PM_DISABLED;
2877c42872d4Smh27603 else
2878c42872d4Smh27603 *rval_p = PM_CPU_PM_NOTSET;
2879c42872d4Smh27603 ret = 0;
2880c42872d4Smh27603 break;
28817c478bd9Sstevel@tonic-gate }
28822df1fe9cSrandyf
28832df1fe9cSrandyf case PM_GET_AUTOS3_STATE:
28842df1fe9cSrandyf {
28852df1fe9cSrandyf if (autoS3_enabled) {
28862df1fe9cSrandyf *rval_p = PM_AUTOS3_ENABLED;
28872df1fe9cSrandyf } else {
28882df1fe9cSrandyf *rval_p = PM_AUTOS3_DISABLED;
28892df1fe9cSrandyf }
28902df1fe9cSrandyf ret = 0;
28917c478bd9Sstevel@tonic-gate break;
28922df1fe9cSrandyf }
28932df1fe9cSrandyf
28942df1fe9cSrandyf case PM_GET_S3_SUPPORT_STATE:
28952df1fe9cSrandyf {
28962df1fe9cSrandyf if (pm_S3_enabled) {
28972df1fe9cSrandyf *rval_p = PM_S3_SUPPORT_ENABLED;
28982df1fe9cSrandyf } else {
28992df1fe9cSrandyf *rval_p = PM_S3_SUPPORT_DISABLED;
29002df1fe9cSrandyf }
29012df1fe9cSrandyf ret = 0;
29022df1fe9cSrandyf break;
29032df1fe9cSrandyf }
29042df1fe9cSrandyf
29052df1fe9cSrandyf /*
29062df1fe9cSrandyf * pmconfig tells us if the platform supports S3
29072df1fe9cSrandyf */
29082df1fe9cSrandyf case PM_ENABLE_S3:
29092df1fe9cSrandyf {
29102df1fe9cSrandyf mutex_enter(&pm_scan_lock);
29112df1fe9cSrandyf if (pm_S3_enabled) {
29122df1fe9cSrandyf mutex_exit(&pm_scan_lock);
29132df1fe9cSrandyf PMD(PMD_ERROR, ("ioctl: %s: EBUSY\n",
29142df1fe9cSrandyf cmdstr))
29152df1fe9cSrandyf ret = EBUSY;
29162df1fe9cSrandyf break;
29172df1fe9cSrandyf }
29182df1fe9cSrandyf pm_S3_enabled = 1;
29192df1fe9cSrandyf mutex_exit(&pm_scan_lock);
29202df1fe9cSrandyf ret = 0;
29212df1fe9cSrandyf break;
29222df1fe9cSrandyf }
29232df1fe9cSrandyf
29242df1fe9cSrandyf case PM_DISABLE_S3:
29252df1fe9cSrandyf {
29262df1fe9cSrandyf mutex_enter(&pm_scan_lock);
29272df1fe9cSrandyf pm_S3_enabled = 0;
29282df1fe9cSrandyf mutex_exit(&pm_scan_lock);
29292df1fe9cSrandyf ret = 0;
29302df1fe9cSrandyf break;
29312df1fe9cSrandyf }
29322df1fe9cSrandyf
29332df1fe9cSrandyf case PM_START_AUTOS3:
29342df1fe9cSrandyf {
29352df1fe9cSrandyf mutex_enter(&pm_scan_lock);
29362df1fe9cSrandyf if (autoS3_enabled) {
29372df1fe9cSrandyf mutex_exit(&pm_scan_lock);
29382df1fe9cSrandyf PMD(PMD_ERROR, ("ioctl: %s: EBUSY\n",
29392df1fe9cSrandyf cmdstr))
29402df1fe9cSrandyf ret = EBUSY;
29412df1fe9cSrandyf break;
29422df1fe9cSrandyf }
29432df1fe9cSrandyf autoS3_enabled = 1;
29442df1fe9cSrandyf mutex_exit(&pm_scan_lock);
29452df1fe9cSrandyf ret = 0;
29462df1fe9cSrandyf break;
29472df1fe9cSrandyf }
29482df1fe9cSrandyf
29492df1fe9cSrandyf case PM_STOP_AUTOS3:
29502df1fe9cSrandyf {
29512df1fe9cSrandyf mutex_enter(&pm_scan_lock);
29522df1fe9cSrandyf autoS3_enabled = 0;
29532df1fe9cSrandyf mutex_exit(&pm_scan_lock);
29542df1fe9cSrandyf ret = 0;
29552df1fe9cSrandyf break;
29562df1fe9cSrandyf }
29572df1fe9cSrandyf
2958*0e751525SEric Saxe case PM_ENABLE_CPU_DEEP_IDLE:
2959*0e751525SEric Saxe {
2960*0e751525SEric Saxe if (callb_execute_class(CB_CL_CPU_DEEP_IDLE,
2961*0e751525SEric Saxe PM_ENABLE_CPU_DEEP_IDLE) == NULL)
2962*0e751525SEric Saxe ret = 0;
2963*0e751525SEric Saxe else
2964*0e751525SEric Saxe ret = EBUSY;
2965*0e751525SEric Saxe break;
2966*0e751525SEric Saxe }
2967*0e751525SEric Saxe case PM_DISABLE_CPU_DEEP_IDLE:
2968*0e751525SEric Saxe {
2969*0e751525SEric Saxe if (callb_execute_class(CB_CL_CPU_DEEP_IDLE,
2970*0e751525SEric Saxe PM_DISABLE_CPU_DEEP_IDLE) == NULL)
2971*0e751525SEric Saxe ret = 0;
2972*0e751525SEric Saxe else
2973*0e751525SEric Saxe ret = EINVAL;
2974*0e751525SEric Saxe break;
2975*0e751525SEric Saxe }
2976*0e751525SEric Saxe case PM_DEFAULT_CPU_DEEP_IDLE:
2977*0e751525SEric Saxe {
2978*0e751525SEric Saxe if (callb_execute_class(CB_CL_CPU_DEEP_IDLE,
2979*0e751525SEric Saxe PM_DEFAULT_CPU_DEEP_IDLE) == NULL)
2980*0e751525SEric Saxe ret = 0;
2981*0e751525SEric Saxe else
2982*0e751525SEric Saxe ret = EBUSY;
2983*0e751525SEric Saxe break;
2984*0e751525SEric Saxe }
2985*0e751525SEric Saxe
29862df1fe9cSrandyf default:
29872df1fe9cSrandyf /*
29882df1fe9cSrandyf * Internal error, invalid ioctl description
29892df1fe9cSrandyf * force debug entry even if pm_debug not set
29902df1fe9cSrandyf */
29912df1fe9cSrandyf #ifdef DEBUG
29922df1fe9cSrandyf pm_log("invalid diptype %d for cmd %d (%s)\n",
29932df1fe9cSrandyf pcip->diptype, cmd, pcip->name);
29942df1fe9cSrandyf #endif
29952df1fe9cSrandyf ASSERT(0);
29962df1fe9cSrandyf return (EIO);
29972df1fe9cSrandyf }
29982df1fe9cSrandyf break;
29992df1fe9cSrandyf }
30007c478bd9Sstevel@tonic-gate
30017c478bd9Sstevel@tonic-gate default:
30027c478bd9Sstevel@tonic-gate /*
30037c478bd9Sstevel@tonic-gate * Internal error, invalid ioctl description
30047c478bd9Sstevel@tonic-gate * force debug entry even if pm_debug not set
30057c478bd9Sstevel@tonic-gate */
30067c478bd9Sstevel@tonic-gate #ifdef DEBUG
30077c478bd9Sstevel@tonic-gate pm_log("ioctl: invalid str_type %d for cmd %d (%s)\n",
30087c478bd9Sstevel@tonic-gate pcip->str_type, cmd, pcip->name);
30097c478bd9Sstevel@tonic-gate #endif
30107c478bd9Sstevel@tonic-gate ASSERT(0);
30117c478bd9Sstevel@tonic-gate return (EIO);
30127c478bd9Sstevel@tonic-gate }
30137c478bd9Sstevel@tonic-gate ASSERT(ret != 0x0badcafe); /* some cmd in wrong case! */
30147c478bd9Sstevel@tonic-gate if (dipheld) {
30157c478bd9Sstevel@tonic-gate ASSERT(dip);
30167c478bd9Sstevel@tonic-gate PMD(PMD_DHR, ("ioctl: %s: releasing %s@%s(%s#%d) for "
30177c478bd9Sstevel@tonic-gate "exiting pm_ioctl\n", cmdstr, PM_DEVICE(dip)))
30187c478bd9Sstevel@tonic-gate PM_RELE(dip);
30197c478bd9Sstevel@tonic-gate }
30207c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: %s: end, ret=%d\n", cmdstr, ret))
30217c478bd9Sstevel@tonic-gate return (ret);
30227c478bd9Sstevel@tonic-gate }
3023