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 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 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 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 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 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 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 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 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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