1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * pm This driver now only handles the ioctl interface. The scanning 31*7c478bd9Sstevel@tonic-gate * and policy stuff now lives in common/os/sunpm.c. 32*7c478bd9Sstevel@tonic-gate * Not DDI compliant 33*7c478bd9Sstevel@tonic-gate */ 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/conf.h> /* driver flags and functions */ 39*7c478bd9Sstevel@tonic-gate #include <sys/open.h> /* OTYP_CHR definition */ 40*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> /* S_IFCHR definition */ 41*7c478bd9Sstevel@tonic-gate #include <sys/pathname.h> /* name -> dev_info xlation */ 42*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> /* memory alloc stuff */ 43*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/pm.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/epm.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/mode.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/promif.h> 52*7c478bd9Sstevel@tonic-gate #include <sys/consdev.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/poll.h> 55*7c478bd9Sstevel@tonic-gate #include <sys/note.h> 56*7c478bd9Sstevel@tonic-gate #include <sys/taskq.h> 57*7c478bd9Sstevel@tonic-gate #include <sys/policy.h> 58*7c478bd9Sstevel@tonic-gate 59*7c478bd9Sstevel@tonic-gate /* 60*7c478bd9Sstevel@tonic-gate * Minor number is instance<<8 + clone minor from range 1-255; (0 reserved 61*7c478bd9Sstevel@tonic-gate * for "original" 62*7c478bd9Sstevel@tonic-gate */ 63*7c478bd9Sstevel@tonic-gate #define PM_MINOR_TO_CLONE(minor) ((minor) & (PM_MAX_CLONE - 1)) 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate #define PM_NUMCMPTS(dip) (DEVI(dip)->devi_pm_num_components) 66*7c478bd9Sstevel@tonic-gate #define PM_IS_CFB(dip) (DEVI(dip)->devi_pm_flags & PMC_CONSOLE_FB) 67*7c478bd9Sstevel@tonic-gate #define PM_MAJOR(dip) ddi_driver_major(dip) 68*7c478bd9Sstevel@tonic-gate #define PM_RELE(dip) ddi_release_devi(dip) 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate #define PM_IDLEDOWN_TIME 10 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate extern kmutex_t pm_scan_lock; /* protects autopm_enable, pm_scans_disabled */ 73*7c478bd9Sstevel@tonic-gate extern kmutex_t pm_clone_lock; /* protects pm_clones array */ 74*7c478bd9Sstevel@tonic-gate extern int autopm_enabled; 75*7c478bd9Sstevel@tonic-gate extern kcondvar_t pm_clones_cv[PM_MAX_CLONE]; 76*7c478bd9Sstevel@tonic-gate extern uint_t pm_poll_cnt[PM_MAX_CLONE]; 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate /* 79*7c478bd9Sstevel@tonic-gate * The soft state of the power manager. Since there will only 80*7c478bd9Sstevel@tonic-gate * one of these, just reference it through a static pointer. 81*7c478bd9Sstevel@tonic-gate */ 82*7c478bd9Sstevel@tonic-gate static struct pmstate { 83*7c478bd9Sstevel@tonic-gate dev_info_t *pm_dip; /* ptr to our dev_info node */ 84*7c478bd9Sstevel@tonic-gate int pm_instance; /* for ddi_get_instance() */ 85*7c478bd9Sstevel@tonic-gate timeout_id_t pm_idledown_id; /* pm idledown timeout id */ 86*7c478bd9Sstevel@tonic-gate uchar_t pm_clones[PM_MAX_CLONE]; /* uniqueify multiple opens */ 87*7c478bd9Sstevel@tonic-gate struct cred *pm_cred[PM_MAX_CLONE]; /* cred for each unique open */ 88*7c478bd9Sstevel@tonic-gate } pm_state = { NULL, -1, (timeout_id_t)0 }; 89*7c478bd9Sstevel@tonic-gate typedef struct pmstate *pm_state_t; 90*7c478bd9Sstevel@tonic-gate static pm_state_t pmstp = &pm_state; 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate static int pm_open(dev_t *, int, int, cred_t *); 93*7c478bd9Sstevel@tonic-gate static int pm_close(dev_t, int, int, cred_t *); 94*7c478bd9Sstevel@tonic-gate static int pm_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 95*7c478bd9Sstevel@tonic-gate static int pm_chpoll(dev_t, short, int, short *, struct pollhead **); 96*7c478bd9Sstevel@tonic-gate 97*7c478bd9Sstevel@tonic-gate static struct cb_ops pm_cb_ops = { 98*7c478bd9Sstevel@tonic-gate pm_open, /* open */ 99*7c478bd9Sstevel@tonic-gate pm_close, /* close */ 100*7c478bd9Sstevel@tonic-gate nodev, /* strategy */ 101*7c478bd9Sstevel@tonic-gate nodev, /* print */ 102*7c478bd9Sstevel@tonic-gate nodev, /* dump */ 103*7c478bd9Sstevel@tonic-gate nodev, /* read */ 104*7c478bd9Sstevel@tonic-gate nodev, /* write */ 105*7c478bd9Sstevel@tonic-gate pm_ioctl, /* ioctl */ 106*7c478bd9Sstevel@tonic-gate nodev, /* devmap */ 107*7c478bd9Sstevel@tonic-gate nodev, /* mmap */ 108*7c478bd9Sstevel@tonic-gate nodev, /* segmap */ 109*7c478bd9Sstevel@tonic-gate pm_chpoll, /* poll */ 110*7c478bd9Sstevel@tonic-gate ddi_prop_op, /* prop_op */ 111*7c478bd9Sstevel@tonic-gate NULL, /* streamtab */ 112*7c478bd9Sstevel@tonic-gate D_NEW | D_MP /* driver compatibility flag */ 113*7c478bd9Sstevel@tonic-gate }; 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate static int pm_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 116*7c478bd9Sstevel@tonic-gate void **result); 117*7c478bd9Sstevel@tonic-gate static int pm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 118*7c478bd9Sstevel@tonic-gate static int pm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 119*7c478bd9Sstevel@tonic-gate 120*7c478bd9Sstevel@tonic-gate static struct dev_ops pm_ops = { 121*7c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev */ 122*7c478bd9Sstevel@tonic-gate 0, /* refcnt */ 123*7c478bd9Sstevel@tonic-gate pm_getinfo, /* info */ 124*7c478bd9Sstevel@tonic-gate nulldev, /* identify */ 125*7c478bd9Sstevel@tonic-gate nulldev, /* probe */ 126*7c478bd9Sstevel@tonic-gate pm_attach, /* attach */ 127*7c478bd9Sstevel@tonic-gate pm_detach, /* detach */ 128*7c478bd9Sstevel@tonic-gate nodev, /* reset */ 129*7c478bd9Sstevel@tonic-gate &pm_cb_ops, /* driver operations */ 130*7c478bd9Sstevel@tonic-gate NULL, /* bus operations */ 131*7c478bd9Sstevel@tonic-gate NULL /* power */ 132*7c478bd9Sstevel@tonic-gate }; 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 135*7c478bd9Sstevel@tonic-gate &mod_driverops, 136*7c478bd9Sstevel@tonic-gate "power management driver v%I%", 137*7c478bd9Sstevel@tonic-gate &pm_ops 138*7c478bd9Sstevel@tonic-gate }; 139*7c478bd9Sstevel@tonic-gate 140*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 141*7c478bd9Sstevel@tonic-gate MODREV_1, &modldrv, 0 142*7c478bd9Sstevel@tonic-gate }; 143*7c478bd9Sstevel@tonic-gate 144*7c478bd9Sstevel@tonic-gate /* Local functions */ 145*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 146*7c478bd9Sstevel@tonic-gate static int print_info(dev_info_t *, void *); 147*7c478bd9Sstevel@tonic-gate 148*7c478bd9Sstevel@tonic-gate #endif 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate int 151*7c478bd9Sstevel@tonic-gate _init(void) 152*7c478bd9Sstevel@tonic-gate { 153*7c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage)); 154*7c478bd9Sstevel@tonic-gate } 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate int 157*7c478bd9Sstevel@tonic-gate _fini(void) 158*7c478bd9Sstevel@tonic-gate { 159*7c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage)); 160*7c478bd9Sstevel@tonic-gate } 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate int 163*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 164*7c478bd9Sstevel@tonic-gate { 165*7c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 166*7c478bd9Sstevel@tonic-gate } 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate static int 169*7c478bd9Sstevel@tonic-gate pm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 170*7c478bd9Sstevel@tonic-gate { 171*7c478bd9Sstevel@tonic-gate int i; 172*7c478bd9Sstevel@tonic-gate 173*7c478bd9Sstevel@tonic-gate switch (cmd) { 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate case DDI_ATTACH: 176*7c478bd9Sstevel@tonic-gate if (pmstp->pm_instance != -1) /* Only allow one instance */ 177*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 178*7c478bd9Sstevel@tonic-gate pmstp->pm_instance = ddi_get_instance(dip); 179*7c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dip, "pm", S_IFCHR, 180*7c478bd9Sstevel@tonic-gate (pmstp->pm_instance << 8) + 0, 181*7c478bd9Sstevel@tonic-gate DDI_PSEUDO, 0) != DDI_SUCCESS) { 182*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 183*7c478bd9Sstevel@tonic-gate } 184*7c478bd9Sstevel@tonic-gate pmstp->pm_dip = dip; /* pm_init and getinfo depend on it */ 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate for (i = 0; i < PM_MAX_CLONE; i++) 187*7c478bd9Sstevel@tonic-gate cv_init(&pm_clones_cv[i], NULL, CV_DEFAULT, NULL); 188*7c478bd9Sstevel@tonic-gate 189*7c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 190*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate default: 193*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 194*7c478bd9Sstevel@tonic-gate } 195*7c478bd9Sstevel@tonic-gate } 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 198*7c478bd9Sstevel@tonic-gate static int 199*7c478bd9Sstevel@tonic-gate pm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 200*7c478bd9Sstevel@tonic-gate { 201*7c478bd9Sstevel@tonic-gate int i; 202*7c478bd9Sstevel@tonic-gate 203*7c478bd9Sstevel@tonic-gate switch (cmd) { 204*7c478bd9Sstevel@tonic-gate case DDI_DETACH: 205*7c478bd9Sstevel@tonic-gate /* 206*7c478bd9Sstevel@tonic-gate * Don't detach while idledown timeout is pending. Note that 207*7c478bd9Sstevel@tonic-gate * we already know we're not in pm_ioctl() due to framework 208*7c478bd9Sstevel@tonic-gate * synchronization, so this is a sufficient test 209*7c478bd9Sstevel@tonic-gate */ 210*7c478bd9Sstevel@tonic-gate if (pmstp->pm_idledown_id) 211*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate for (i = 0; i < PM_MAX_CLONE; i++) 214*7c478bd9Sstevel@tonic-gate cv_destroy(&pm_clones_cv[i]); 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 217*7c478bd9Sstevel@tonic-gate pmstp->pm_instance = -1; 218*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 219*7c478bd9Sstevel@tonic-gate 220*7c478bd9Sstevel@tonic-gate default: 221*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 222*7c478bd9Sstevel@tonic-gate } 223*7c478bd9Sstevel@tonic-gate } 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate static int 226*7c478bd9Sstevel@tonic-gate pm_close_direct_pm_device(dev_info_t *dip, void *arg) 227*7c478bd9Sstevel@tonic-gate { 228*7c478bd9Sstevel@tonic-gate int clone; 229*7c478bd9Sstevel@tonic-gate char *pathbuf; 230*7c478bd9Sstevel@tonic-gate pm_info_t *info = PM_GET_PM_INFO(dip); 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate clone = *((int *)arg); 233*7c478bd9Sstevel@tonic-gate 234*7c478bd9Sstevel@tonic-gate if (!info) 235*7c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 238*7c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip); 239*7c478bd9Sstevel@tonic-gate if (clone == info->pmi_clone) { 240*7c478bd9Sstevel@tonic-gate PMD(PMD_CLOSE, ("pm_close: found %s@%s(%s#%d)\n", 241*7c478bd9Sstevel@tonic-gate PM_DEVICE(dip))) 242*7c478bd9Sstevel@tonic-gate ASSERT(PM_ISDIRECT(dip)); 243*7c478bd9Sstevel@tonic-gate info->pmi_dev_pm_state &= ~PM_DIRECT; 244*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 245*7c478bd9Sstevel@tonic-gate pm_proceed(dip, PMP_RELEASE, -1, -1); 246*7c478bd9Sstevel@tonic-gate /* Bring ourselves up if there is a keeper that is up */ 247*7c478bd9Sstevel@tonic-gate (void) ddi_pathname(dip, pathbuf); 248*7c478bd9Sstevel@tonic-gate pm_dispatch_to_dep_thread(PM_DEP_WK_BRINGUP_SELF, NULL, 249*7c478bd9Sstevel@tonic-gate pathbuf, PM_DEP_NOWAIT, NULL, 0); 250*7c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip); 251*7c478bd9Sstevel@tonic-gate info->pmi_clone = 0; 252*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 253*7c478bd9Sstevel@tonic-gate } else { 254*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 255*7c478bd9Sstevel@tonic-gate } 256*7c478bd9Sstevel@tonic-gate kmem_free(pathbuf, MAXPATHLEN); 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate /* restart autopm on device released from direct pm */ 259*7c478bd9Sstevel@tonic-gate pm_rescan(dip); 260*7c478bd9Sstevel@tonic-gate 261*7c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 262*7c478bd9Sstevel@tonic-gate } 263*7c478bd9Sstevel@tonic-gate 264*7c478bd9Sstevel@tonic-gate #define PM_REQ 1 265*7c478bd9Sstevel@tonic-gate #define NOSTRUCT 2 266*7c478bd9Sstevel@tonic-gate #define DIP 3 267*7c478bd9Sstevel@tonic-gate #define NODIP 4 268*7c478bd9Sstevel@tonic-gate #define NODEP 5 269*7c478bd9Sstevel@tonic-gate #define DEP 6 270*7c478bd9Sstevel@tonic-gate #define PM_PSC 7 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate #define CHECKPERMS 0x001 273*7c478bd9Sstevel@tonic-gate #define SU 0x002 274*7c478bd9Sstevel@tonic-gate #define SG 0x004 275*7c478bd9Sstevel@tonic-gate #define OWNER 0x008 276*7c478bd9Sstevel@tonic-gate 277*7c478bd9Sstevel@tonic-gate #define INWHO 0x001 278*7c478bd9Sstevel@tonic-gate #define INDATAINT 0x002 279*7c478bd9Sstevel@tonic-gate #define INDATASTRING 0x004 280*7c478bd9Sstevel@tonic-gate #define INDEP 0x008 281*7c478bd9Sstevel@tonic-gate #define INDATAOUT 0x010 282*7c478bd9Sstevel@tonic-gate #define INDATA (INDATAOUT | INDATAINT | INDATASTRING | INDEP) 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate struct pm_cmd_info { 285*7c478bd9Sstevel@tonic-gate int cmd; /* command code */ 286*7c478bd9Sstevel@tonic-gate char *name; /* printable string */ 287*7c478bd9Sstevel@tonic-gate int supported; /* true if still supported */ 288*7c478bd9Sstevel@tonic-gate int str_type; /* PM_REQ or NOSTRUCT */ 289*7c478bd9Sstevel@tonic-gate int inargs; /* INWHO, INDATAINT, INDATASTRING, INDEP, */ 290*7c478bd9Sstevel@tonic-gate /* INDATAOUT */ 291*7c478bd9Sstevel@tonic-gate int diptype; /* DIP or NODIP */ 292*7c478bd9Sstevel@tonic-gate int deptype; /* DEP or NODEP */ 293*7c478bd9Sstevel@tonic-gate int permission; /* SU, GU, or CHECKPERMS */ 294*7c478bd9Sstevel@tonic-gate }; 295*7c478bd9Sstevel@tonic-gate 296*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 297*7c478bd9Sstevel@tonic-gate char *pm_cmd_string; 298*7c478bd9Sstevel@tonic-gate int pm_cmd; 299*7c478bd9Sstevel@tonic-gate #endif 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate /* 302*7c478bd9Sstevel@tonic-gate * Returns true if permission granted by credentials 303*7c478bd9Sstevel@tonic-gate */ 304*7c478bd9Sstevel@tonic-gate static int 305*7c478bd9Sstevel@tonic-gate pm_perms(int perm, cred_t *cr) 306*7c478bd9Sstevel@tonic-gate { 307*7c478bd9Sstevel@tonic-gate if (perm == 0) /* no restrictions */ 308*7c478bd9Sstevel@tonic-gate return (1); 309*7c478bd9Sstevel@tonic-gate if (perm == CHECKPERMS) /* ok for now (is checked later) */ 310*7c478bd9Sstevel@tonic-gate return (1); 311*7c478bd9Sstevel@tonic-gate if ((perm & SU) && secpolicy_power_mgmt(cr) == 0) /* privileged? */ 312*7c478bd9Sstevel@tonic-gate return (1); 313*7c478bd9Sstevel@tonic-gate if ((perm & SG) && (crgetgid(cr) == 0)) /* group 0 is ok */ 314*7c478bd9Sstevel@tonic-gate return (1); 315*7c478bd9Sstevel@tonic-gate return (0); 316*7c478bd9Sstevel@tonic-gate } 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 319*7c478bd9Sstevel@tonic-gate static int 320*7c478bd9Sstevel@tonic-gate print_info(dev_info_t *dip, void *arg) 321*7c478bd9Sstevel@tonic-gate { 322*7c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(arg)) 323*7c478bd9Sstevel@tonic-gate pm_info_t *info; 324*7c478bd9Sstevel@tonic-gate int i, j; 325*7c478bd9Sstevel@tonic-gate struct pm_component *cp; 326*7c478bd9Sstevel@tonic-gate extern int pm_cur_power(pm_component_t *cp); 327*7c478bd9Sstevel@tonic-gate 328*7c478bd9Sstevel@tonic-gate info = PM_GET_PM_INFO(dip); 329*7c478bd9Sstevel@tonic-gate if (!info) 330*7c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 331*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pm_info for %s\n", ddi_node_name(dip)); 332*7c478bd9Sstevel@tonic-gate for (i = 0; i < PM_NUMCMPTS(dip); i++) { 333*7c478bd9Sstevel@tonic-gate cp = PM_CP(dip, i); 334*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tThresholds[%d] =", i); 335*7c478bd9Sstevel@tonic-gate for (j = 0; j < cp->pmc_comp.pmc_numlevels; j++) 336*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, " %d", cp->pmc_comp.pmc_thresh[i]); 337*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\n"); 338*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tCurrent power[%d] = %d\n", i, 339*7c478bd9Sstevel@tonic-gate pm_cur_power(cp)); 340*7c478bd9Sstevel@tonic-gate } 341*7c478bd9Sstevel@tonic-gate if (PM_ISDIRECT(dip)) 342*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "\tDirect power management\n"); 343*7c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 344*7c478bd9Sstevel@tonic-gate } 345*7c478bd9Sstevel@tonic-gate #endif 346*7c478bd9Sstevel@tonic-gate 347*7c478bd9Sstevel@tonic-gate /* 348*7c478bd9Sstevel@tonic-gate * command, name, supported, str_type, inargs, diptype, deptype, permission 349*7c478bd9Sstevel@tonic-gate */ 350*7c478bd9Sstevel@tonic-gate static struct pm_cmd_info pmci[] = { 351*7c478bd9Sstevel@tonic-gate {PM_SCHEDULE, "PM_SCHEDULE", 0}, 352*7c478bd9Sstevel@tonic-gate {PM_GET_IDLE_TIME, "PM_GET_IDLE_TIME", 0}, 353*7c478bd9Sstevel@tonic-gate {PM_GET_NUM_CMPTS, "PM_GET_NUM_CMPTS", 0}, 354*7c478bd9Sstevel@tonic-gate {PM_GET_THRESHOLD, "PM_GET_THRESHOLD", 0}, 355*7c478bd9Sstevel@tonic-gate {PM_SET_THRESHOLD, "PM_SET_THRESHOLD", 0}, 356*7c478bd9Sstevel@tonic-gate {PM_GET_NORM_PWR, "PM_GET_NORM_PWR", 0}, 357*7c478bd9Sstevel@tonic-gate {PM_SET_CUR_PWR, "PM_SET_CUR_PWR", 0}, 358*7c478bd9Sstevel@tonic-gate {PM_GET_CUR_PWR, "PM_GET_CUR_PWR", 0}, 359*7c478bd9Sstevel@tonic-gate {PM_GET_NUM_DEPS, "PM_GET_NUM_DEPS", 0}, 360*7c478bd9Sstevel@tonic-gate {PM_GET_DEP, "PM_GET_DEP", 0}, 361*7c478bd9Sstevel@tonic-gate {PM_ADD_DEP, "PM_ADD_DEP", 0}, 362*7c478bd9Sstevel@tonic-gate {PM_REM_DEP, "PM_REM_DEP", 0}, 363*7c478bd9Sstevel@tonic-gate {PM_REM_DEVICE, "PM_REM_DEVICE", 0}, 364*7c478bd9Sstevel@tonic-gate {PM_REM_DEVICES, "PM_REM_DEVICES", 0}, 365*7c478bd9Sstevel@tonic-gate {PM_REPARSE_PM_PROPS, "PM_REPARSE_PM_PROPS", 1, PM_REQ, INWHO, DIP, 366*7c478bd9Sstevel@tonic-gate NODEP}, 367*7c478bd9Sstevel@tonic-gate {PM_DISABLE_AUTOPM, "PM_DISABLE_AUTOPM", 0}, 368*7c478bd9Sstevel@tonic-gate {PM_REENABLE_AUTOPM, "PM_REENABLE_AUTOPM", 0}, 369*7c478bd9Sstevel@tonic-gate {PM_SET_NORM_PWR, "PM_SET_NORM_PWR", 0 }, 370*7c478bd9Sstevel@tonic-gate {PM_SET_DEVICE_THRESHOLD, "PM_SET_DEVICE_THRESHOLD", 1, PM_REQ, 371*7c478bd9Sstevel@tonic-gate INWHO, NODIP, NODEP, SU}, 372*7c478bd9Sstevel@tonic-gate {PM_GET_SYSTEM_THRESHOLD, "PM_GET_SYSTEM_THRESHOLD", 1, NOSTRUCT}, 373*7c478bd9Sstevel@tonic-gate {PM_GET_DEFAULT_SYSTEM_THRESHOLD, "PM_GET_DEFAULT_SYSTEM_THRESHOLD", 374*7c478bd9Sstevel@tonic-gate 1, NOSTRUCT}, 375*7c478bd9Sstevel@tonic-gate {PM_SET_SYSTEM_THRESHOLD, "PM_SET_SYSTEM_THRESHOLD", 1, NOSTRUCT, 376*7c478bd9Sstevel@tonic-gate 0, 0, 0, SU}, 377*7c478bd9Sstevel@tonic-gate {PM_START_PM, "PM_START_PM", 1, NOSTRUCT, 0, 0, 0, SU}, 378*7c478bd9Sstevel@tonic-gate {PM_STOP_PM, "PM_STOP_PM", 1, NOSTRUCT, 0, 0, 0, SU}, 379*7c478bd9Sstevel@tonic-gate {PM_RESET_PM, "PM_RESET_PM", 1, NOSTRUCT, 0, 0, 0, SU}, 380*7c478bd9Sstevel@tonic-gate {PM_GET_STATS, "PM_GET_STATS", 1, PM_REQ, INWHO | INDATAOUT, 381*7c478bd9Sstevel@tonic-gate DIP, NODEP}, 382*7c478bd9Sstevel@tonic-gate {PM_GET_DEVICE_THRESHOLD, "PM_GET_DEVICE_THRESHOLD", 1, PM_REQ, INWHO, 383*7c478bd9Sstevel@tonic-gate DIP, NODEP}, 384*7c478bd9Sstevel@tonic-gate {PM_GET_POWER_NAME, "PM_GET_POWER_NAME", 1, PM_REQ, INWHO | INDATAOUT, 385*7c478bd9Sstevel@tonic-gate DIP, NODEP}, 386*7c478bd9Sstevel@tonic-gate {PM_GET_POWER_LEVELS, "PM_GET_POWER_LEVELS", 1, PM_REQ, 387*7c478bd9Sstevel@tonic-gate INWHO | INDATAOUT, DIP, NODEP}, 388*7c478bd9Sstevel@tonic-gate {PM_GET_NUM_COMPONENTS, "PM_GET_NUM_COMPONENTS", 1, PM_REQ, INWHO, 389*7c478bd9Sstevel@tonic-gate DIP, NODEP}, 390*7c478bd9Sstevel@tonic-gate {PM_GET_COMPONENT_NAME, "PM_GET_COMPONENT_NAME", 1, PM_REQ, 391*7c478bd9Sstevel@tonic-gate INWHO | INDATAOUT, DIP, NODEP}, 392*7c478bd9Sstevel@tonic-gate {PM_GET_NUM_POWER_LEVELS, "PM_GET_NUM_POWER_LEVELS", 1, PM_REQ, INWHO, 393*7c478bd9Sstevel@tonic-gate DIP, NODEP}, 394*7c478bd9Sstevel@tonic-gate {PM_GET_STATE_CHANGE, "PM_GET_STATE_CHANGE", 1, PM_PSC}, 395*7c478bd9Sstevel@tonic-gate {PM_GET_STATE_CHANGE_WAIT, "PM_GET_STATE_CHANGE_WAIT", 1, PM_PSC}, 396*7c478bd9Sstevel@tonic-gate {PM_DIRECT_PM, "PM_DIRECT_PM", 1, PM_REQ, INWHO, DIP, NODEP, 397*7c478bd9Sstevel@tonic-gate (SU | SG)}, 398*7c478bd9Sstevel@tonic-gate {PM_RELEASE_DIRECT_PM, "PM_RELEASE_DIRECT_PM", 1, PM_REQ, INWHO, 399*7c478bd9Sstevel@tonic-gate DIP, NODEP}, 400*7c478bd9Sstevel@tonic-gate {PM_DIRECT_NOTIFY, "PM_DIRECT_NOTIFY", 1, PM_PSC}, 401*7c478bd9Sstevel@tonic-gate {PM_DIRECT_NOTIFY_WAIT, "PM_DIRECT_NOTIFY_WAIT", 1, PM_PSC}, 402*7c478bd9Sstevel@tonic-gate {PM_RESET_DEVICE_THRESHOLD, "PM_RESET_DEVICE_THRESHOLD", 1, PM_REQ, 403*7c478bd9Sstevel@tonic-gate INWHO, DIP, NODEP, SU}, 404*7c478bd9Sstevel@tonic-gate {PM_GET_PM_STATE, "PM_GET_PM_STATE", 1, NOSTRUCT}, 405*7c478bd9Sstevel@tonic-gate {PM_GET_DEVICE_TYPE, "PM_GET_DEVICE_TYPE", 1, PM_REQ, INWHO, 406*7c478bd9Sstevel@tonic-gate DIP, NODEP}, 407*7c478bd9Sstevel@tonic-gate {PM_SET_COMPONENT_THRESHOLDS, "PM_SET_COMPONENT_THRESHOLDS", 1, PM_REQ, 408*7c478bd9Sstevel@tonic-gate INWHO | INDATAINT, NODIP, NODEP, SU}, 409*7c478bd9Sstevel@tonic-gate {PM_GET_COMPONENT_THRESHOLDS, "PM_GET_COMPONENT_THRESHOLDS", 1, PM_REQ, 410*7c478bd9Sstevel@tonic-gate INWHO | INDATAOUT, DIP, NODEP}, 411*7c478bd9Sstevel@tonic-gate {PM_IDLE_DOWN, "PM_IDLE_DOWN", 1, NOSTRUCT, 0, 0, 0, SU}, 412*7c478bd9Sstevel@tonic-gate {PM_GET_DEVICE_THRESHOLD_BASIS, "PM_GET_DEVICE_THRESHOLD_BASIS", 1, 413*7c478bd9Sstevel@tonic-gate PM_REQ, INWHO, DIP, NODEP}, 414*7c478bd9Sstevel@tonic-gate {PM_SET_CURRENT_POWER, "PM_SET_CURRENT_POWER", 1, PM_REQ, INWHO, DIP, 415*7c478bd9Sstevel@tonic-gate NODEP}, 416*7c478bd9Sstevel@tonic-gate {PM_GET_CURRENT_POWER, "PM_GET_CURRENT_POWER", 1, PM_REQ, INWHO, DIP, 417*7c478bd9Sstevel@tonic-gate NODEP}, 418*7c478bd9Sstevel@tonic-gate {PM_GET_FULL_POWER, "PM_GET_FULL_POWER", 1, PM_REQ, INWHO, DIP, 419*7c478bd9Sstevel@tonic-gate NODEP}, 420*7c478bd9Sstevel@tonic-gate {PM_ADD_DEPENDENT, "PM_ADD_DEPENDENT", 1, PM_REQ, INWHO | INDATASTRING, 421*7c478bd9Sstevel@tonic-gate DIP, DEP, SU}, 422*7c478bd9Sstevel@tonic-gate {PM_GET_TIME_IDLE, "PM_GET_TIME_IDLE", 1, PM_REQ, INWHO, DIP, NODEP}, 423*7c478bd9Sstevel@tonic-gate {PM_ADD_DEPENDENT_PROPERTY, "PM_ADD_DEPENDENT_PROPERTY", 1, PM_REQ, 424*7c478bd9Sstevel@tonic-gate INWHO | INDATASTRING, NODIP, DEP, SU}, 425*7c478bd9Sstevel@tonic-gate {0, NULL} 426*7c478bd9Sstevel@tonic-gate }; 427*7c478bd9Sstevel@tonic-gate 428*7c478bd9Sstevel@tonic-gate struct pm_cmd_info * 429*7c478bd9Sstevel@tonic-gate pc_info(int cmd) 430*7c478bd9Sstevel@tonic-gate { 431*7c478bd9Sstevel@tonic-gate struct pm_cmd_info *pcip; 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate for (pcip = pmci; pcip->name; pcip++) { 434*7c478bd9Sstevel@tonic-gate if (cmd == pcip->cmd) 435*7c478bd9Sstevel@tonic-gate return (pcip); 436*7c478bd9Sstevel@tonic-gate } 437*7c478bd9Sstevel@tonic-gate return (NULL); 438*7c478bd9Sstevel@tonic-gate } 439*7c478bd9Sstevel@tonic-gate 440*7c478bd9Sstevel@tonic-gate static char * 441*7c478bd9Sstevel@tonic-gate pm_decode_cmd(int cmd) 442*7c478bd9Sstevel@tonic-gate { 443*7c478bd9Sstevel@tonic-gate static char invbuf[64]; 444*7c478bd9Sstevel@tonic-gate struct pm_cmd_info *pcip = pc_info(cmd); 445*7c478bd9Sstevel@tonic-gate if (pcip != NULL) 446*7c478bd9Sstevel@tonic-gate return (pcip->name); 447*7c478bd9Sstevel@tonic-gate (void) sprintf(invbuf, "ioctl: invalid command %d\n", cmd); 448*7c478bd9Sstevel@tonic-gate return (invbuf); 449*7c478bd9Sstevel@tonic-gate } 450*7c478bd9Sstevel@tonic-gate 451*7c478bd9Sstevel@tonic-gate /* 452*7c478bd9Sstevel@tonic-gate * Allocate scan resource, create taskq, then dispatch scan, 453*7c478bd9Sstevel@tonic-gate * called only if autopm is enabled. 454*7c478bd9Sstevel@tonic-gate */ 455*7c478bd9Sstevel@tonic-gate int 456*7c478bd9Sstevel@tonic-gate pm_start_pm_walk(dev_info_t *dip, void *arg) 457*7c478bd9Sstevel@tonic-gate { 458*7c478bd9Sstevel@tonic-gate char *cmdstr = pm_decode_cmd(*((int *)arg)); 459*7c478bd9Sstevel@tonic-gate 460*7c478bd9Sstevel@tonic-gate if (!PM_GET_PM_INFO(dip) || PM_ISBC(dip)) 461*7c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 462*7c478bd9Sstevel@tonic-gate 463*7c478bd9Sstevel@tonic-gate /* 464*7c478bd9Sstevel@tonic-gate * Construct per dip scan taskq 465*7c478bd9Sstevel@tonic-gate */ 466*7c478bd9Sstevel@tonic-gate mutex_enter(&pm_scan_lock); 467*7c478bd9Sstevel@tonic-gate if (autopm_enabled) 468*7c478bd9Sstevel@tonic-gate pm_scan_init(dip); 469*7c478bd9Sstevel@tonic-gate mutex_exit(&pm_scan_lock); 470*7c478bd9Sstevel@tonic-gate 471*7c478bd9Sstevel@tonic-gate /* 472*7c478bd9Sstevel@tonic-gate * Start doing pm on device: ensure pm_scan data structure initiated, 473*7c478bd9Sstevel@tonic-gate * no need to gurantee a successful scan run. 474*7c478bd9Sstevel@tonic-gate */ 475*7c478bd9Sstevel@tonic-gate PMD(PMD_SCAN | PMD_IOCTL, ("ioctl: %s: scan %s@%s(%s#%d)\n", cmdstr, 476*7c478bd9Sstevel@tonic-gate PM_DEVICE(dip))) 477*7c478bd9Sstevel@tonic-gate pm_rescan(dip); 478*7c478bd9Sstevel@tonic-gate 479*7c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 480*7c478bd9Sstevel@tonic-gate } 481*7c478bd9Sstevel@tonic-gate 482*7c478bd9Sstevel@tonic-gate /* 483*7c478bd9Sstevel@tonic-gate * Bring devices to full power level, then stop scan 484*7c478bd9Sstevel@tonic-gate */ 485*7c478bd9Sstevel@tonic-gate int 486*7c478bd9Sstevel@tonic-gate pm_stop_pm_walk(dev_info_t *dip, void *arg) 487*7c478bd9Sstevel@tonic-gate { 488*7c478bd9Sstevel@tonic-gate pm_info_t *info = PM_GET_PM_INFO(dip); 489*7c478bd9Sstevel@tonic-gate char *cmdstr = pm_decode_cmd(*((int *)arg)); 490*7c478bd9Sstevel@tonic-gate 491*7c478bd9Sstevel@tonic-gate if (!info) 492*7c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 493*7c478bd9Sstevel@tonic-gate /* 494*7c478bd9Sstevel@tonic-gate * Stop the current scan, and then bring it back to normal power. 495*7c478bd9Sstevel@tonic-gate */ 496*7c478bd9Sstevel@tonic-gate if (!PM_ISBC(dip)) { 497*7c478bd9Sstevel@tonic-gate PMD(PMD_SCAN | PMD_IOCTL, ("ioctl: %s: stop scan for " 498*7c478bd9Sstevel@tonic-gate "%s@%s(%s#%d)\n", cmdstr, PM_DEVICE(dip))) 499*7c478bd9Sstevel@tonic-gate pm_scan_stop(dip); 500*7c478bd9Sstevel@tonic-gate } 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate if (!PM_ISBC(dip) && !PM_ISDIRECT(dip) && 503*7c478bd9Sstevel@tonic-gate !pm_all_at_normal(dip)) { 504*7c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip); 505*7c478bd9Sstevel@tonic-gate if (info->pmi_dev_pm_state & PM_DETACHING) { 506*7c478bd9Sstevel@tonic-gate PMD(PMD_ALLNORM, ("ioctl: %s: deferring " 507*7c478bd9Sstevel@tonic-gate "all_to_normal because %s@%s(%s#%d) is detaching\n", 508*7c478bd9Sstevel@tonic-gate cmdstr, PM_DEVICE(dip))) 509*7c478bd9Sstevel@tonic-gate info->pmi_dev_pm_state |= PM_ALLNORM_DEFERRED; 510*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 511*7c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 512*7c478bd9Sstevel@tonic-gate } 513*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 514*7c478bd9Sstevel@tonic-gate if (pm_all_to_normal(dip, PM_CANBLOCK_FAIL) != DDI_SUCCESS) { 515*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: could not bring %s@%s" 516*7c478bd9Sstevel@tonic-gate "(%s#%d) to normal\n", cmdstr, PM_DEVICE(dip))) 517*7c478bd9Sstevel@tonic-gate } 518*7c478bd9Sstevel@tonic-gate } 519*7c478bd9Sstevel@tonic-gate 520*7c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 521*7c478bd9Sstevel@tonic-gate } 522*7c478bd9Sstevel@tonic-gate 523*7c478bd9Sstevel@tonic-gate static int 524*7c478bd9Sstevel@tonic-gate pm_start_idledown(dev_info_t *dip, void *arg) 525*7c478bd9Sstevel@tonic-gate { 526*7c478bd9Sstevel@tonic-gate int flag = (int)(intptr_t)arg; 527*7c478bd9Sstevel@tonic-gate pm_scan_t *scanp = PM_GET_PM_SCAN(dip); 528*7c478bd9Sstevel@tonic-gate 529*7c478bd9Sstevel@tonic-gate if (!scanp) 530*7c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 531*7c478bd9Sstevel@tonic-gate 532*7c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip); 533*7c478bd9Sstevel@tonic-gate scanp->ps_idle_down |= flag; 534*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 535*7c478bd9Sstevel@tonic-gate pm_rescan(dip); 536*7c478bd9Sstevel@tonic-gate 537*7c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 538*7c478bd9Sstevel@tonic-gate } 539*7c478bd9Sstevel@tonic-gate 540*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 541*7c478bd9Sstevel@tonic-gate static int 542*7c478bd9Sstevel@tonic-gate pm_end_idledown(dev_info_t *dip, void *ignore) 543*7c478bd9Sstevel@tonic-gate { 544*7c478bd9Sstevel@tonic-gate pm_scan_t *scanp = PM_GET_PM_SCAN(dip); 545*7c478bd9Sstevel@tonic-gate 546*7c478bd9Sstevel@tonic-gate if (!scanp) 547*7c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 548*7c478bd9Sstevel@tonic-gate 549*7c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip); 550*7c478bd9Sstevel@tonic-gate /* 551*7c478bd9Sstevel@tonic-gate * The PMID_TIMERS bits are place holder till idledown expires. 552*7c478bd9Sstevel@tonic-gate * The bits are also the base for regenerating PMID_SCANS bits. 553*7c478bd9Sstevel@tonic-gate * While it's up to scan thread to clear up the PMID_SCANS bits 554*7c478bd9Sstevel@tonic-gate * after each scan run, PMID_TIMERS ensure aggressive scan down 555*7c478bd9Sstevel@tonic-gate * performance throughout the idledown period. 556*7c478bd9Sstevel@tonic-gate */ 557*7c478bd9Sstevel@tonic-gate scanp->ps_idle_down &= ~PMID_TIMERS; 558*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 559*7c478bd9Sstevel@tonic-gate 560*7c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 561*7c478bd9Sstevel@tonic-gate } 562*7c478bd9Sstevel@tonic-gate 563*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 564*7c478bd9Sstevel@tonic-gate static void 565*7c478bd9Sstevel@tonic-gate pm_end_idledown_walk(void *ignore) 566*7c478bd9Sstevel@tonic-gate { 567*7c478bd9Sstevel@tonic-gate PMD(PMD_IDLEDOWN, ("ioctl: end_idledown: idledown_id(%lx) timer is " 568*7c478bd9Sstevel@tonic-gate "off\n", (ulong_t)pmstp->pm_idledown_id)); 569*7c478bd9Sstevel@tonic-gate 570*7c478bd9Sstevel@tonic-gate mutex_enter(&pm_scan_lock); 571*7c478bd9Sstevel@tonic-gate pmstp->pm_idledown_id = 0; 572*7c478bd9Sstevel@tonic-gate mutex_exit(&pm_scan_lock); 573*7c478bd9Sstevel@tonic-gate 574*7c478bd9Sstevel@tonic-gate ddi_walk_devs(ddi_root_node(), pm_end_idledown, NULL); 575*7c478bd9Sstevel@tonic-gate } 576*7c478bd9Sstevel@tonic-gate 577*7c478bd9Sstevel@tonic-gate /* 578*7c478bd9Sstevel@tonic-gate * pm_timeout_idledown - keep idledown effect for 10 seconds. 579*7c478bd9Sstevel@tonic-gate * 580*7c478bd9Sstevel@tonic-gate * Return 0 if another competing caller scheduled idledown timeout, 581*7c478bd9Sstevel@tonic-gate * otherwise, return idledown timeout_id. 582*7c478bd9Sstevel@tonic-gate */ 583*7c478bd9Sstevel@tonic-gate static timeout_id_t 584*7c478bd9Sstevel@tonic-gate pm_timeout_idledown(void) 585*7c478bd9Sstevel@tonic-gate { 586*7c478bd9Sstevel@tonic-gate timeout_id_t to_id; 587*7c478bd9Sstevel@tonic-gate 588*7c478bd9Sstevel@tonic-gate /* 589*7c478bd9Sstevel@tonic-gate * Keep idle-down in effect for either 10 seconds 590*7c478bd9Sstevel@tonic-gate * or length of a scan interval, which ever is greater. 591*7c478bd9Sstevel@tonic-gate */ 592*7c478bd9Sstevel@tonic-gate mutex_enter(&pm_scan_lock); 593*7c478bd9Sstevel@tonic-gate if (pmstp->pm_idledown_id != 0) { 594*7c478bd9Sstevel@tonic-gate to_id = pmstp->pm_idledown_id; 595*7c478bd9Sstevel@tonic-gate pmstp->pm_idledown_id = 0; 596*7c478bd9Sstevel@tonic-gate mutex_exit(&pm_scan_lock); 597*7c478bd9Sstevel@tonic-gate (void) untimeout(to_id); 598*7c478bd9Sstevel@tonic-gate mutex_enter(&pm_scan_lock); 599*7c478bd9Sstevel@tonic-gate if (pmstp->pm_idledown_id != 0) { 600*7c478bd9Sstevel@tonic-gate PMD(PMD_IDLEDOWN, ("ioctl: timeout_idledown: " 601*7c478bd9Sstevel@tonic-gate "another caller got it, idledown_id(%lx)!\n", 602*7c478bd9Sstevel@tonic-gate (ulong_t)pmstp->pm_idledown_id)) 603*7c478bd9Sstevel@tonic-gate mutex_exit(&pm_scan_lock); 604*7c478bd9Sstevel@tonic-gate return (0); 605*7c478bd9Sstevel@tonic-gate } 606*7c478bd9Sstevel@tonic-gate } 607*7c478bd9Sstevel@tonic-gate pmstp->pm_idledown_id = timeout(pm_end_idledown_walk, NULL, 608*7c478bd9Sstevel@tonic-gate PM_IDLEDOWN_TIME * hz); 609*7c478bd9Sstevel@tonic-gate PMD(PMD_IDLEDOWN, ("ioctl: timeout_idledown: idledown_id(%lx)\n", 610*7c478bd9Sstevel@tonic-gate (ulong_t)pmstp->pm_idledown_id)) 611*7c478bd9Sstevel@tonic-gate mutex_exit(&pm_scan_lock); 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate return (pmstp->pm_idledown_id); 614*7c478bd9Sstevel@tonic-gate } 615*7c478bd9Sstevel@tonic-gate 616*7c478bd9Sstevel@tonic-gate static int 617*7c478bd9Sstevel@tonic-gate pm_chpoll(dev_t dev, short events, int anyyet, short *reventsp, 618*7c478bd9Sstevel@tonic-gate struct pollhead **phpp) 619*7c478bd9Sstevel@tonic-gate { 620*7c478bd9Sstevel@tonic-gate extern struct pollhead pm_pollhead; /* common/os/sunpm.c */ 621*7c478bd9Sstevel@tonic-gate int clone; 622*7c478bd9Sstevel@tonic-gate 623*7c478bd9Sstevel@tonic-gate clone = PM_MINOR_TO_CLONE(getminor(dev)); 624*7c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: pm_chpoll: clone %d\n", clone)) 625*7c478bd9Sstevel@tonic-gate if ((events & (POLLIN | POLLRDNORM)) && pm_poll_cnt[clone]) { 626*7c478bd9Sstevel@tonic-gate *reventsp |= (POLLIN | POLLRDNORM); 627*7c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: pm_chpoll: reventsp set\n")) 628*7c478bd9Sstevel@tonic-gate } else { 629*7c478bd9Sstevel@tonic-gate *reventsp = 0; 630*7c478bd9Sstevel@tonic-gate if (!anyyet) { 631*7c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: pm_chpoll: not anyyet\n")) 632*7c478bd9Sstevel@tonic-gate *phpp = &pm_pollhead; 633*7c478bd9Sstevel@tonic-gate } 634*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 635*7c478bd9Sstevel@tonic-gate else { 636*7c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: pm_chpoll: anyyet\n")) 637*7c478bd9Sstevel@tonic-gate } 638*7c478bd9Sstevel@tonic-gate #endif 639*7c478bd9Sstevel@tonic-gate } 640*7c478bd9Sstevel@tonic-gate return (0); 641*7c478bd9Sstevel@tonic-gate } 642*7c478bd9Sstevel@tonic-gate 643*7c478bd9Sstevel@tonic-gate /* 644*7c478bd9Sstevel@tonic-gate * called by pm_dicard_entries to free up the memory. It also decrements 645*7c478bd9Sstevel@tonic-gate * pm_poll_cnt, if direct is non zero. 646*7c478bd9Sstevel@tonic-gate */ 647*7c478bd9Sstevel@tonic-gate static void 648*7c478bd9Sstevel@tonic-gate pm_free_entries(psce_t *pscep, int clone, int direct) 649*7c478bd9Sstevel@tonic-gate { 650*7c478bd9Sstevel@tonic-gate pm_state_change_t *p; 651*7c478bd9Sstevel@tonic-gate 652*7c478bd9Sstevel@tonic-gate if (pscep) { 653*7c478bd9Sstevel@tonic-gate p = pscep->psce_out; 654*7c478bd9Sstevel@tonic-gate while (p->size) { 655*7c478bd9Sstevel@tonic-gate if (direct) { 656*7c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: discard: " 657*7c478bd9Sstevel@tonic-gate "pm_poll_cnt[%d] is %d before " 658*7c478bd9Sstevel@tonic-gate "ASSERT\n", clone, 659*7c478bd9Sstevel@tonic-gate pm_poll_cnt[clone])) 660*7c478bd9Sstevel@tonic-gate ASSERT(pm_poll_cnt[clone]); 661*7c478bd9Sstevel@tonic-gate pm_poll_cnt[clone]--; 662*7c478bd9Sstevel@tonic-gate } 663*7c478bd9Sstevel@tonic-gate kmem_free(p->physpath, p->size); 664*7c478bd9Sstevel@tonic-gate p->size = 0; 665*7c478bd9Sstevel@tonic-gate if (p == pscep->psce_last) 666*7c478bd9Sstevel@tonic-gate p = pscep->psce_first; 667*7c478bd9Sstevel@tonic-gate else 668*7c478bd9Sstevel@tonic-gate p++; 669*7c478bd9Sstevel@tonic-gate } 670*7c478bd9Sstevel@tonic-gate pscep->psce_out = pscep->psce_first; 671*7c478bd9Sstevel@tonic-gate pscep->psce_in = pscep->psce_first; 672*7c478bd9Sstevel@tonic-gate mutex_exit(&pscep->psce_lock); 673*7c478bd9Sstevel@tonic-gate } 674*7c478bd9Sstevel@tonic-gate } 675*7c478bd9Sstevel@tonic-gate 676*7c478bd9Sstevel@tonic-gate /* 677*7c478bd9Sstevel@tonic-gate * Discard entries for this clone. Calls pm_free_entries to free up memory. 678*7c478bd9Sstevel@tonic-gate */ 679*7c478bd9Sstevel@tonic-gate static void 680*7c478bd9Sstevel@tonic-gate pm_discard_entries(int clone) 681*7c478bd9Sstevel@tonic-gate { 682*7c478bd9Sstevel@tonic-gate psce_t *pscep; 683*7c478bd9Sstevel@tonic-gate psce_t *pm_psc_clone_to_direct(int); 684*7c478bd9Sstevel@tonic-gate psce_t *pm_psc_clone_to_interest(int); 685*7c478bd9Sstevel@tonic-gate int direct = 0; 686*7c478bd9Sstevel@tonic-gate 687*7c478bd9Sstevel@tonic-gate mutex_enter(&pm_clone_lock); 688*7c478bd9Sstevel@tonic-gate if ((pscep = pm_psc_clone_to_direct(clone)) != NULL) 689*7c478bd9Sstevel@tonic-gate direct = 1; 690*7c478bd9Sstevel@tonic-gate pm_free_entries(pscep, clone, direct); 691*7c478bd9Sstevel@tonic-gate pscep = pm_psc_clone_to_interest(clone); 692*7c478bd9Sstevel@tonic-gate pm_free_entries(pscep, clone, 0); 693*7c478bd9Sstevel@tonic-gate mutex_exit(&pm_clone_lock); 694*7c478bd9Sstevel@tonic-gate } 695*7c478bd9Sstevel@tonic-gate 696*7c478bd9Sstevel@tonic-gate int 697*7c478bd9Sstevel@tonic-gate pm_set_sys_threshold(dev_info_t *dip, void *arg) 698*7c478bd9Sstevel@tonic-gate { 699*7c478bd9Sstevel@tonic-gate int pm_system_idle_threshold = *((int *)arg); 700*7c478bd9Sstevel@tonic-gate pm_info_t *info = PM_GET_PM_INFO(dip); 701*7c478bd9Sstevel@tonic-gate int processed = 0; 702*7c478bd9Sstevel@tonic-gate 703*7c478bd9Sstevel@tonic-gate if (!info) 704*7c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 705*7c478bd9Sstevel@tonic-gate 706*7c478bd9Sstevel@tonic-gate if (!PM_ISBC(dip) && !PM_ISDIRECT(dip)) { 707*7c478bd9Sstevel@tonic-gate switch (DEVI(dip)->devi_pm_flags & PMC_THRESH_ALL) { 708*7c478bd9Sstevel@tonic-gate case PMC_DEF_THRESH: 709*7c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: set_sys_threshold: set " 710*7c478bd9Sstevel@tonic-gate "%s@%s(%s#%d) default thresh to 0t%d\n", 711*7c478bd9Sstevel@tonic-gate PM_DEVICE(dip), pm_system_idle_threshold)) 712*7c478bd9Sstevel@tonic-gate pm_set_device_threshold(dip, pm_system_idle_threshold, 713*7c478bd9Sstevel@tonic-gate PMC_DEF_THRESH); 714*7c478bd9Sstevel@tonic-gate processed++; 715*7c478bd9Sstevel@tonic-gate break; 716*7c478bd9Sstevel@tonic-gate default: 717*7c478bd9Sstevel@tonic-gate break; 718*7c478bd9Sstevel@tonic-gate } 719*7c478bd9Sstevel@tonic-gate } 720*7c478bd9Sstevel@tonic-gate 721*7c478bd9Sstevel@tonic-gate if (processed && autopm_enabled) 722*7c478bd9Sstevel@tonic-gate pm_rescan(dip); 723*7c478bd9Sstevel@tonic-gate 724*7c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 725*7c478bd9Sstevel@tonic-gate } 726*7c478bd9Sstevel@tonic-gate 727*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 728*7c478bd9Sstevel@tonic-gate static int 729*7c478bd9Sstevel@tonic-gate pm_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 730*7c478bd9Sstevel@tonic-gate { 731*7c478bd9Sstevel@tonic-gate dev_t dev; 732*7c478bd9Sstevel@tonic-gate int instance; 733*7c478bd9Sstevel@tonic-gate 734*7c478bd9Sstevel@tonic-gate switch (infocmd) { 735*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 736*7c478bd9Sstevel@tonic-gate if (pmstp->pm_instance == -1) 737*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 738*7c478bd9Sstevel@tonic-gate *result = pmstp->pm_dip; 739*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 740*7c478bd9Sstevel@tonic-gate 741*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 742*7c478bd9Sstevel@tonic-gate dev = (dev_t)arg; 743*7c478bd9Sstevel@tonic-gate instance = getminor(dev) >> 8; 744*7c478bd9Sstevel@tonic-gate *result = (void *)(uintptr_t)instance; 745*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 746*7c478bd9Sstevel@tonic-gate 747*7c478bd9Sstevel@tonic-gate default: 748*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 749*7c478bd9Sstevel@tonic-gate } 750*7c478bd9Sstevel@tonic-gate } 751*7c478bd9Sstevel@tonic-gate 752*7c478bd9Sstevel@tonic-gate 753*7c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 754*7c478bd9Sstevel@tonic-gate static int 755*7c478bd9Sstevel@tonic-gate pm_open(dev_t *devp, int flag, int otyp, cred_t *cr) 756*7c478bd9Sstevel@tonic-gate { 757*7c478bd9Sstevel@tonic-gate int clone; 758*7c478bd9Sstevel@tonic-gate 759*7c478bd9Sstevel@tonic-gate if (otyp != OTYP_CHR) 760*7c478bd9Sstevel@tonic-gate return (EINVAL); 761*7c478bd9Sstevel@tonic-gate 762*7c478bd9Sstevel@tonic-gate mutex_enter(&pm_clone_lock); 763*7c478bd9Sstevel@tonic-gate for (clone = 1; clone < PM_MAX_CLONE; clone++) 764*7c478bd9Sstevel@tonic-gate if (!pmstp->pm_clones[clone]) 765*7c478bd9Sstevel@tonic-gate break; 766*7c478bd9Sstevel@tonic-gate 767*7c478bd9Sstevel@tonic-gate if (clone == PM_MAX_CLONE) { 768*7c478bd9Sstevel@tonic-gate mutex_exit(&pm_clone_lock); 769*7c478bd9Sstevel@tonic-gate return (ENXIO); 770*7c478bd9Sstevel@tonic-gate } 771*7c478bd9Sstevel@tonic-gate pmstp->pm_cred[clone] = cr; 772*7c478bd9Sstevel@tonic-gate crhold(cr); 773*7c478bd9Sstevel@tonic-gate 774*7c478bd9Sstevel@tonic-gate *devp = makedevice(getmajor(*devp), (pmstp->pm_instance << 8) + clone); 775*7c478bd9Sstevel@tonic-gate pmstp->pm_clones[clone] = 1; 776*7c478bd9Sstevel@tonic-gate mutex_exit(&pm_clone_lock); 777*7c478bd9Sstevel@tonic-gate 778*7c478bd9Sstevel@tonic-gate return (0); 779*7c478bd9Sstevel@tonic-gate } 780*7c478bd9Sstevel@tonic-gate 781*7c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 782*7c478bd9Sstevel@tonic-gate static int 783*7c478bd9Sstevel@tonic-gate pm_close(dev_t dev, int flag, int otyp, cred_t *cr) 784*7c478bd9Sstevel@tonic-gate { 785*7c478bd9Sstevel@tonic-gate int clone; 786*7c478bd9Sstevel@tonic-gate 787*7c478bd9Sstevel@tonic-gate if (otyp != OTYP_CHR) 788*7c478bd9Sstevel@tonic-gate return (EINVAL); 789*7c478bd9Sstevel@tonic-gate 790*7c478bd9Sstevel@tonic-gate clone = PM_MINOR_TO_CLONE(getminor(dev)); 791*7c478bd9Sstevel@tonic-gate PMD(PMD_CLOSE, ("pm_close: minor %x, clone %x\n", getminor(dev), 792*7c478bd9Sstevel@tonic-gate clone)) 793*7c478bd9Sstevel@tonic-gate 794*7c478bd9Sstevel@tonic-gate /* 795*7c478bd9Sstevel@tonic-gate * Walk the entire device tree to find the corresponding 796*7c478bd9Sstevel@tonic-gate * device and operate on it. 797*7c478bd9Sstevel@tonic-gate */ 798*7c478bd9Sstevel@tonic-gate ddi_walk_devs(ddi_root_node(), pm_close_direct_pm_device, 799*7c478bd9Sstevel@tonic-gate (void *) &clone); 800*7c478bd9Sstevel@tonic-gate 801*7c478bd9Sstevel@tonic-gate crfree(pmstp->pm_cred[clone]); 802*7c478bd9Sstevel@tonic-gate pmstp->pm_cred[clone] = 0; 803*7c478bd9Sstevel@tonic-gate pmstp->pm_clones[clone] = 0; 804*7c478bd9Sstevel@tonic-gate pm_discard_entries(clone); 805*7c478bd9Sstevel@tonic-gate ASSERT(pm_poll_cnt[clone] == 0); 806*7c478bd9Sstevel@tonic-gate pm_deregister_watcher(clone, NULL); 807*7c478bd9Sstevel@tonic-gate return (0); 808*7c478bd9Sstevel@tonic-gate } 809*7c478bd9Sstevel@tonic-gate 810*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 811*7c478bd9Sstevel@tonic-gate static int 812*7c478bd9Sstevel@tonic-gate pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p) 813*7c478bd9Sstevel@tonic-gate { 814*7c478bd9Sstevel@tonic-gate struct pm_cmd_info *pc_info(int); 815*7c478bd9Sstevel@tonic-gate struct pm_cmd_info *pcip = pc_info(cmd); 816*7c478bd9Sstevel@tonic-gate pm_req_t req; 817*7c478bd9Sstevel@tonic-gate dev_info_t *dip = NULL; 818*7c478bd9Sstevel@tonic-gate pm_info_t *info = NULL; 819*7c478bd9Sstevel@tonic-gate int clone; 820*7c478bd9Sstevel@tonic-gate char *cmdstr = pm_decode_cmd(cmd); 821*7c478bd9Sstevel@tonic-gate /* 822*7c478bd9Sstevel@tonic-gate * To keep devinfo nodes from going away while we're holding a 823*7c478bd9Sstevel@tonic-gate * pointer to their dip, pm_name_to_dip() optionally holds 824*7c478bd9Sstevel@tonic-gate * the devinfo node. If we've done that, we set dipheld 825*7c478bd9Sstevel@tonic-gate * so we know at the end of the ioctl processing to release the 826*7c478bd9Sstevel@tonic-gate * node again. 827*7c478bd9Sstevel@tonic-gate */ 828*7c478bd9Sstevel@tonic-gate int dipheld = 0; 829*7c478bd9Sstevel@tonic-gate int icount = 0; 830*7c478bd9Sstevel@tonic-gate int i; 831*7c478bd9Sstevel@tonic-gate int comps; 832*7c478bd9Sstevel@tonic-gate size_t lencopied; 833*7c478bd9Sstevel@tonic-gate int ret = ENOTTY; 834*7c478bd9Sstevel@tonic-gate int curpower; 835*7c478bd9Sstevel@tonic-gate char who[MAXNAMELEN]; 836*7c478bd9Sstevel@tonic-gate size_t wholen; /* copyinstr length */ 837*7c478bd9Sstevel@tonic-gate size_t deplen = MAXNAMELEN; 838*7c478bd9Sstevel@tonic-gate char *dep, i_dep_buf[MAXNAMELEN]; 839*7c478bd9Sstevel@tonic-gate char *pathbuf; 840*7c478bd9Sstevel@tonic-gate struct pm_component *cp; 841*7c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 842*7c478bd9Sstevel@tonic-gate pm_state_change32_t *pscp32; 843*7c478bd9Sstevel@tonic-gate pm_state_change32_t psc32; 844*7c478bd9Sstevel@tonic-gate size_t copysize32; 845*7c478bd9Sstevel@tonic-gate #endif 846*7c478bd9Sstevel@tonic-gate pm_state_change_t *pscp; 847*7c478bd9Sstevel@tonic-gate pm_state_change_t psc; 848*7c478bd9Sstevel@tonic-gate size_t copysize; 849*7c478bd9Sstevel@tonic-gate extern int pm_default_idle_threshold; 850*7c478bd9Sstevel@tonic-gate extern int pm_system_idle_threshold; 851*7c478bd9Sstevel@tonic-gate extern void pm_record_thresh(pm_thresh_rec_t *); 852*7c478bd9Sstevel@tonic-gate psce_t *pm_psc_clone_to_direct(int); 853*7c478bd9Sstevel@tonic-gate psce_t *pm_psc_clone_to_interest(int); 854*7c478bd9Sstevel@tonic-gate extern void pm_register_watcher(int, dev_info_t *); 855*7c478bd9Sstevel@tonic-gate extern int pm_get_current_power(dev_info_t *, int, int *); 856*7c478bd9Sstevel@tonic-gate extern int pm_interest_registered(int); 857*7c478bd9Sstevel@tonic-gate extern void pm_all_to_default_thresholds(void); 858*7c478bd9Sstevel@tonic-gate extern int pm_current_threshold(dev_info_t *, int, int *); 859*7c478bd9Sstevel@tonic-gate extern void pm_deregister_watcher(int, dev_info_t *); 860*7c478bd9Sstevel@tonic-gate extern void pm_unrecord_threshold(char *); 861*7c478bd9Sstevel@tonic-gate 862*7c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: %s: begin\n", cmdstr)) 863*7c478bd9Sstevel@tonic-gate 864*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 865*7c478bd9Sstevel@tonic-gate if (cmd == 666) { 866*7c478bd9Sstevel@tonic-gate ddi_walk_devs(ddi_root_node(), print_info, NULL); 867*7c478bd9Sstevel@tonic-gate return (0); 868*7c478bd9Sstevel@tonic-gate } 869*7c478bd9Sstevel@tonic-gate ret = 0x0badcafe; /* sanity checking */ 870*7c478bd9Sstevel@tonic-gate pm_cmd = cmd; /* for ASSERT debugging */ 871*7c478bd9Sstevel@tonic-gate pm_cmd_string = cmdstr; /* for ASSERT debugging */ 872*7c478bd9Sstevel@tonic-gate #endif 873*7c478bd9Sstevel@tonic-gate 874*7c478bd9Sstevel@tonic-gate 875*7c478bd9Sstevel@tonic-gate if (pcip == NULL) { 876*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: unknown command %d\n", cmd)) 877*7c478bd9Sstevel@tonic-gate return (ENOTTY); 878*7c478bd9Sstevel@tonic-gate } 879*7c478bd9Sstevel@tonic-gate if (pcip == NULL || pcip->supported == 0) { 880*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: command %s no longer supported\n", 881*7c478bd9Sstevel@tonic-gate pcip->name)) 882*7c478bd9Sstevel@tonic-gate return (ENOTTY); 883*7c478bd9Sstevel@tonic-gate } 884*7c478bd9Sstevel@tonic-gate 885*7c478bd9Sstevel@tonic-gate wholen = 0; 886*7c478bd9Sstevel@tonic-gate dep = i_dep_buf; 887*7c478bd9Sstevel@tonic-gate i_dep_buf[0] = 0; 888*7c478bd9Sstevel@tonic-gate clone = PM_MINOR_TO_CLONE(getminor(dev)); 889*7c478bd9Sstevel@tonic-gate if (!pm_perms(pcip->permission, pmstp->pm_cred[clone])) { 890*7c478bd9Sstevel@tonic-gate ret = EPERM; 891*7c478bd9Sstevel@tonic-gate return (ret); 892*7c478bd9Sstevel@tonic-gate } 893*7c478bd9Sstevel@tonic-gate switch (pcip->str_type) { 894*7c478bd9Sstevel@tonic-gate case PM_REQ: 895*7c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 896*7c478bd9Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) { 897*7c478bd9Sstevel@tonic-gate pm_req32_t req32; 898*7c478bd9Sstevel@tonic-gate 899*7c478bd9Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg, &req32, 900*7c478bd9Sstevel@tonic-gate sizeof (req32), mode) != 0) { 901*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin " 902*7c478bd9Sstevel@tonic-gate "EFAULT\n\n", cmdstr)) 903*7c478bd9Sstevel@tonic-gate ret = EFAULT; 904*7c478bd9Sstevel@tonic-gate break; 905*7c478bd9Sstevel@tonic-gate } 906*7c478bd9Sstevel@tonic-gate req.component = req32.component; 907*7c478bd9Sstevel@tonic-gate req.value = req32.value; 908*7c478bd9Sstevel@tonic-gate req.datasize = req32.datasize; 909*7c478bd9Sstevel@tonic-gate if (pcip->inargs & INWHO) { 910*7c478bd9Sstevel@tonic-gate ret = copyinstr((char *)(uintptr_t) 911*7c478bd9Sstevel@tonic-gate req32.physpath, who, MAXNAMELEN, &wholen); 912*7c478bd9Sstevel@tonic-gate if (ret) { 913*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: " 914*7c478bd9Sstevel@tonic-gate "copyinstr fails returning %d\n", 915*7c478bd9Sstevel@tonic-gate cmdstr, ret)) 916*7c478bd9Sstevel@tonic-gate break; 917*7c478bd9Sstevel@tonic-gate } 918*7c478bd9Sstevel@tonic-gate req.physpath = who; 919*7c478bd9Sstevel@tonic-gate } 920*7c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: %s: physpath=%s\n", cmdstr, 921*7c478bd9Sstevel@tonic-gate req.physpath)) 922*7c478bd9Sstevel@tonic-gate if (pcip->inargs & INDATA) { 923*7c478bd9Sstevel@tonic-gate req.data = (void *)(uintptr_t)req32.data; 924*7c478bd9Sstevel@tonic-gate req.datasize = req32.datasize; 925*7c478bd9Sstevel@tonic-gate } else { 926*7c478bd9Sstevel@tonic-gate req.data = NULL; 927*7c478bd9Sstevel@tonic-gate req.datasize = 0; 928*7c478bd9Sstevel@tonic-gate } 929*7c478bd9Sstevel@tonic-gate switch (pcip->diptype) { 930*7c478bd9Sstevel@tonic-gate case DIP: 931*7c478bd9Sstevel@tonic-gate if (!(dip = 932*7c478bd9Sstevel@tonic-gate pm_name_to_dip(req.physpath, 1))) { 933*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: " 934*7c478bd9Sstevel@tonic-gate "pm_name_to_dip for %s failed\n", 935*7c478bd9Sstevel@tonic-gate cmdstr, req.physpath)) 936*7c478bd9Sstevel@tonic-gate return (ENODEV); 937*7c478bd9Sstevel@tonic-gate } 938*7c478bd9Sstevel@tonic-gate ASSERT(!dipheld); 939*7c478bd9Sstevel@tonic-gate dipheld++; 940*7c478bd9Sstevel@tonic-gate break; 941*7c478bd9Sstevel@tonic-gate case NODIP: 942*7c478bd9Sstevel@tonic-gate break; 943*7c478bd9Sstevel@tonic-gate default: 944*7c478bd9Sstevel@tonic-gate /* 945*7c478bd9Sstevel@tonic-gate * Internal error, invalid ioctl description 946*7c478bd9Sstevel@tonic-gate * force debug entry even if pm_debug not set 947*7c478bd9Sstevel@tonic-gate */ 948*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 949*7c478bd9Sstevel@tonic-gate pm_log("invalid diptype %d for cmd %d (%s)\n", 950*7c478bd9Sstevel@tonic-gate pcip->diptype, cmd, pcip->name); 951*7c478bd9Sstevel@tonic-gate #endif 952*7c478bd9Sstevel@tonic-gate ASSERT(0); 953*7c478bd9Sstevel@tonic-gate return (EIO); 954*7c478bd9Sstevel@tonic-gate } 955*7c478bd9Sstevel@tonic-gate if (pcip->inargs & INDATAINT) { 956*7c478bd9Sstevel@tonic-gate int32_t int32buf; 957*7c478bd9Sstevel@tonic-gate int32_t *i32p; 958*7c478bd9Sstevel@tonic-gate int *ip; 959*7c478bd9Sstevel@tonic-gate icount = req32.datasize / sizeof (int32_t); 960*7c478bd9Sstevel@tonic-gate if (icount <= 0) { 961*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: datasize" 962*7c478bd9Sstevel@tonic-gate " 0 or neg EFAULT\n\n", cmdstr)) 963*7c478bd9Sstevel@tonic-gate ret = EFAULT; 964*7c478bd9Sstevel@tonic-gate break; 965*7c478bd9Sstevel@tonic-gate } 966*7c478bd9Sstevel@tonic-gate ASSERT(!(pcip->inargs & INDATASTRING)); 967*7c478bd9Sstevel@tonic-gate req.datasize = icount * sizeof (int); 968*7c478bd9Sstevel@tonic-gate req.data = kmem_alloc(req.datasize, KM_SLEEP); 969*7c478bd9Sstevel@tonic-gate ip = req.data; 970*7c478bd9Sstevel@tonic-gate ret = 0; 971*7c478bd9Sstevel@tonic-gate for (i = 0, 972*7c478bd9Sstevel@tonic-gate i32p = (int32_t *)(uintptr_t)req32.data; 973*7c478bd9Sstevel@tonic-gate i < icount; i++, i32p++) { 974*7c478bd9Sstevel@tonic-gate if (ddi_copyin((void *)i32p, &int32buf, 975*7c478bd9Sstevel@tonic-gate sizeof (int32_t), mode)) { 976*7c478bd9Sstevel@tonic-gate kmem_free(req.data, 977*7c478bd9Sstevel@tonic-gate req.datasize); 978*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: " 979*7c478bd9Sstevel@tonic-gate "entry %d EFAULT\n", 980*7c478bd9Sstevel@tonic-gate cmdstr, i)) 981*7c478bd9Sstevel@tonic-gate ret = EFAULT; 982*7c478bd9Sstevel@tonic-gate break; 983*7c478bd9Sstevel@tonic-gate } 984*7c478bd9Sstevel@tonic-gate *ip++ = (int)int32buf; 985*7c478bd9Sstevel@tonic-gate } 986*7c478bd9Sstevel@tonic-gate if (ret) 987*7c478bd9Sstevel@tonic-gate break; 988*7c478bd9Sstevel@tonic-gate } 989*7c478bd9Sstevel@tonic-gate if (pcip->inargs & INDATASTRING) { 990*7c478bd9Sstevel@tonic-gate ASSERT(!(pcip->inargs & INDATAINT)); 991*7c478bd9Sstevel@tonic-gate ASSERT(pcip->deptype == DEP); 992*7c478bd9Sstevel@tonic-gate if (req32.data != NULL) { 993*7c478bd9Sstevel@tonic-gate size_t dummy; 994*7c478bd9Sstevel@tonic-gate if (copyinstr((void *)(uintptr_t) 995*7c478bd9Sstevel@tonic-gate req32.data, dep, deplen, &dummy)) { 996*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: " 997*7c478bd9Sstevel@tonic-gate "0x%p dep size %lx, EFAULT" 998*7c478bd9Sstevel@tonic-gate "\n", cmdstr, 999*7c478bd9Sstevel@tonic-gate (void *)req.data, deplen)) 1000*7c478bd9Sstevel@tonic-gate ret = EFAULT; 1001*7c478bd9Sstevel@tonic-gate break; 1002*7c478bd9Sstevel@tonic-gate } 1003*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1004*7c478bd9Sstevel@tonic-gate else { 1005*7c478bd9Sstevel@tonic-gate PMD(PMD_DEP, ("ioctl: %s: " 1006*7c478bd9Sstevel@tonic-gate "dep %s\n", cmdstr, dep)) 1007*7c478bd9Sstevel@tonic-gate } 1008*7c478bd9Sstevel@tonic-gate #endif 1009*7c478bd9Sstevel@tonic-gate } else { 1010*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: no " 1011*7c478bd9Sstevel@tonic-gate "dependent\n", cmdstr)) 1012*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1013*7c478bd9Sstevel@tonic-gate break; 1014*7c478bd9Sstevel@tonic-gate } 1015*7c478bd9Sstevel@tonic-gate } 1016*7c478bd9Sstevel@tonic-gate } else 1017*7c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 1018*7c478bd9Sstevel@tonic-gate { 1019*7c478bd9Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg, 1020*7c478bd9Sstevel@tonic-gate &req, sizeof (req), mode) != 0) { 1021*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin " 1022*7c478bd9Sstevel@tonic-gate "EFAULT\n\n", cmdstr)) 1023*7c478bd9Sstevel@tonic-gate ret = EFAULT; 1024*7c478bd9Sstevel@tonic-gate break; 1025*7c478bd9Sstevel@tonic-gate } 1026*7c478bd9Sstevel@tonic-gate if (pcip->inargs & INWHO) { 1027*7c478bd9Sstevel@tonic-gate ret = copyinstr((char *)req.physpath, who, 1028*7c478bd9Sstevel@tonic-gate MAXNAMELEN, &wholen); 1029*7c478bd9Sstevel@tonic-gate if (ret) { 1030*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s copyinstr" 1031*7c478bd9Sstevel@tonic-gate " fails returning %d\n", cmdstr, 1032*7c478bd9Sstevel@tonic-gate ret)) 1033*7c478bd9Sstevel@tonic-gate break; 1034*7c478bd9Sstevel@tonic-gate } 1035*7c478bd9Sstevel@tonic-gate req.physpath = who; 1036*7c478bd9Sstevel@tonic-gate } 1037*7c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: %s: physpath=%s\n", cmdstr, 1038*7c478bd9Sstevel@tonic-gate req.physpath)) 1039*7c478bd9Sstevel@tonic-gate if (!(pcip->inargs & INDATA)) { 1040*7c478bd9Sstevel@tonic-gate req.data = NULL; 1041*7c478bd9Sstevel@tonic-gate req.datasize = 0; 1042*7c478bd9Sstevel@tonic-gate } 1043*7c478bd9Sstevel@tonic-gate switch (pcip->diptype) { 1044*7c478bd9Sstevel@tonic-gate case DIP: 1045*7c478bd9Sstevel@tonic-gate if (!(dip = 1046*7c478bd9Sstevel@tonic-gate pm_name_to_dip(req.physpath, 1))) { 1047*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: " 1048*7c478bd9Sstevel@tonic-gate "pm_name_to_dip for %s failed\n", 1049*7c478bd9Sstevel@tonic-gate cmdstr, req.physpath)) 1050*7c478bd9Sstevel@tonic-gate return (ENODEV); 1051*7c478bd9Sstevel@tonic-gate } 1052*7c478bd9Sstevel@tonic-gate ASSERT(!dipheld); 1053*7c478bd9Sstevel@tonic-gate dipheld++; 1054*7c478bd9Sstevel@tonic-gate break; 1055*7c478bd9Sstevel@tonic-gate case NODIP: 1056*7c478bd9Sstevel@tonic-gate break; 1057*7c478bd9Sstevel@tonic-gate default: 1058*7c478bd9Sstevel@tonic-gate /* 1059*7c478bd9Sstevel@tonic-gate * Internal error, invalid ioctl description 1060*7c478bd9Sstevel@tonic-gate * force debug entry even if pm_debug not set 1061*7c478bd9Sstevel@tonic-gate */ 1062*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1063*7c478bd9Sstevel@tonic-gate pm_log("invalid diptype %d for cmd %d (%s)\n", 1064*7c478bd9Sstevel@tonic-gate pcip->diptype, cmd, pcip->name); 1065*7c478bd9Sstevel@tonic-gate #endif 1066*7c478bd9Sstevel@tonic-gate ASSERT(0); 1067*7c478bd9Sstevel@tonic-gate return (EIO); 1068*7c478bd9Sstevel@tonic-gate } 1069*7c478bd9Sstevel@tonic-gate if (pcip->inargs & INDATAINT) { 1070*7c478bd9Sstevel@tonic-gate int *ip; 1071*7c478bd9Sstevel@tonic-gate 1072*7c478bd9Sstevel@tonic-gate ASSERT(!(pcip->inargs & INDATASTRING)); 1073*7c478bd9Sstevel@tonic-gate ip = req.data; 1074*7c478bd9Sstevel@tonic-gate icount = req.datasize / sizeof (int); 1075*7c478bd9Sstevel@tonic-gate if (icount <= 0) { 1076*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: datasize" 1077*7c478bd9Sstevel@tonic-gate " 0 or neg EFAULT\n\n", cmdstr)) 1078*7c478bd9Sstevel@tonic-gate ret = EFAULT; 1079*7c478bd9Sstevel@tonic-gate break; 1080*7c478bd9Sstevel@tonic-gate } 1081*7c478bd9Sstevel@tonic-gate req.data = kmem_alloc(req.datasize, KM_SLEEP); 1082*7c478bd9Sstevel@tonic-gate if (ddi_copyin((caddr_t)ip, req.data, 1083*7c478bd9Sstevel@tonic-gate req.datasize, mode) != 0) { 1084*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin " 1085*7c478bd9Sstevel@tonic-gate "EFAULT\n\n", cmdstr)) 1086*7c478bd9Sstevel@tonic-gate ret = EFAULT; 1087*7c478bd9Sstevel@tonic-gate break; 1088*7c478bd9Sstevel@tonic-gate } 1089*7c478bd9Sstevel@tonic-gate } 1090*7c478bd9Sstevel@tonic-gate if (pcip->inargs & INDATASTRING) { 1091*7c478bd9Sstevel@tonic-gate ASSERT(!(pcip->inargs & INDATAINT)); 1092*7c478bd9Sstevel@tonic-gate ASSERT(pcip->deptype == DEP); 1093*7c478bd9Sstevel@tonic-gate if (req.data != NULL) { 1094*7c478bd9Sstevel@tonic-gate size_t dummy; 1095*7c478bd9Sstevel@tonic-gate if (copyinstr((caddr_t)req.data, 1096*7c478bd9Sstevel@tonic-gate dep, deplen, &dummy)) { 1097*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: " 1098*7c478bd9Sstevel@tonic-gate "0x%p dep size %lu, " 1099*7c478bd9Sstevel@tonic-gate "EFAULT\n", cmdstr, 1100*7c478bd9Sstevel@tonic-gate (void *)req.data, deplen)) 1101*7c478bd9Sstevel@tonic-gate ret = EFAULT; 1102*7c478bd9Sstevel@tonic-gate break; 1103*7c478bd9Sstevel@tonic-gate } 1104*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1105*7c478bd9Sstevel@tonic-gate else { 1106*7c478bd9Sstevel@tonic-gate PMD(PMD_DEP, ("ioctl: %s: " 1107*7c478bd9Sstevel@tonic-gate "dep %s\n", cmdstr, dep)) 1108*7c478bd9Sstevel@tonic-gate } 1109*7c478bd9Sstevel@tonic-gate #endif 1110*7c478bd9Sstevel@tonic-gate } else { 1111*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: no " 1112*7c478bd9Sstevel@tonic-gate "dependent\n", cmdstr)) 1113*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1114*7c478bd9Sstevel@tonic-gate break; 1115*7c478bd9Sstevel@tonic-gate } 1116*7c478bd9Sstevel@tonic-gate } 1117*7c478bd9Sstevel@tonic-gate } 1118*7c478bd9Sstevel@tonic-gate /* 1119*7c478bd9Sstevel@tonic-gate * Now we've got all the args in for the commands that 1120*7c478bd9Sstevel@tonic-gate * use the new pm_req struct. 1121*7c478bd9Sstevel@tonic-gate */ 1122*7c478bd9Sstevel@tonic-gate switch (cmd) { 1123*7c478bd9Sstevel@tonic-gate case PM_REPARSE_PM_PROPS: 1124*7c478bd9Sstevel@tonic-gate { 1125*7c478bd9Sstevel@tonic-gate struct dev_ops *drv; 1126*7c478bd9Sstevel@tonic-gate struct cb_ops *cb; 1127*7c478bd9Sstevel@tonic-gate void *propval; 1128*7c478bd9Sstevel@tonic-gate int length; 1129*7c478bd9Sstevel@tonic-gate /* 1130*7c478bd9Sstevel@tonic-gate * This ioctl is provided only for the ddivs pm test. 1131*7c478bd9Sstevel@tonic-gate * We only do it to a driver which explicitly allows 1132*7c478bd9Sstevel@tonic-gate * us to do so by exporting a pm-reparse-ok property. 1133*7c478bd9Sstevel@tonic-gate * We only care whether the property exists or not. 1134*7c478bd9Sstevel@tonic-gate */ 1135*7c478bd9Sstevel@tonic-gate if ((drv = ddi_get_driver(dip)) == NULL) { 1136*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1137*7c478bd9Sstevel@tonic-gate break; 1138*7c478bd9Sstevel@tonic-gate } 1139*7c478bd9Sstevel@tonic-gate if ((cb = drv->devo_cb_ops) != NULL) { 1140*7c478bd9Sstevel@tonic-gate if ((*cb->cb_prop_op)(DDI_DEV_T_ANY, dip, 1141*7c478bd9Sstevel@tonic-gate PROP_LEN_AND_VAL_ALLOC, (DDI_PROP_CANSLEEP | 1142*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), 1143*7c478bd9Sstevel@tonic-gate "pm-reparse-ok", (caddr_t)&propval, 1144*7c478bd9Sstevel@tonic-gate &length) != DDI_SUCCESS) { 1145*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1146*7c478bd9Sstevel@tonic-gate break; 1147*7c478bd9Sstevel@tonic-gate } 1148*7c478bd9Sstevel@tonic-gate } else if (ddi_prop_op(DDI_DEV_T_ANY, dip, 1149*7c478bd9Sstevel@tonic-gate PROP_LEN_AND_VAL_ALLOC, (DDI_PROP_CANSLEEP | 1150*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), 1151*7c478bd9Sstevel@tonic-gate "pm-reparse-ok", (caddr_t)&propval, 1152*7c478bd9Sstevel@tonic-gate &length) != DDI_SUCCESS) { 1153*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1154*7c478bd9Sstevel@tonic-gate break; 1155*7c478bd9Sstevel@tonic-gate } 1156*7c478bd9Sstevel@tonic-gate kmem_free(propval, length); 1157*7c478bd9Sstevel@tonic-gate ret = e_new_pm_props(dip); 1158*7c478bd9Sstevel@tonic-gate break; 1159*7c478bd9Sstevel@tonic-gate } 1160*7c478bd9Sstevel@tonic-gate 1161*7c478bd9Sstevel@tonic-gate case PM_GET_DEVICE_THRESHOLD: 1162*7c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip); 1163*7c478bd9Sstevel@tonic-gate if (!PM_GET_PM_INFO(dip) || PM_ISBC(dip)) { 1164*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 1165*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: ENODEV\n", 1166*7c478bd9Sstevel@tonic-gate cmdstr)) 1167*7c478bd9Sstevel@tonic-gate ret = ENODEV; 1168*7c478bd9Sstevel@tonic-gate break; 1169*7c478bd9Sstevel@tonic-gate } 1170*7c478bd9Sstevel@tonic-gate *rval_p = DEVI(dip)->devi_pm_dev_thresh; 1171*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 1172*7c478bd9Sstevel@tonic-gate ret = 0; 1173*7c478bd9Sstevel@tonic-gate break; 1174*7c478bd9Sstevel@tonic-gate 1175*7c478bd9Sstevel@tonic-gate case PM_DIRECT_PM: 1176*7c478bd9Sstevel@tonic-gate { 1177*7c478bd9Sstevel@tonic-gate int has_dep; 1178*7c478bd9Sstevel@tonic-gate if ((info = PM_GET_PM_INFO(dip)) == NULL) { 1179*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: " 1180*7c478bd9Sstevel@tonic-gate "ENODEV\n", cmdstr)) 1181*7c478bd9Sstevel@tonic-gate ret = ENODEV; 1182*7c478bd9Sstevel@tonic-gate break; 1183*7c478bd9Sstevel@tonic-gate } 1184*7c478bd9Sstevel@tonic-gate /* 1185*7c478bd9Sstevel@tonic-gate * Check to see if we are there is a dependency on 1186*7c478bd9Sstevel@tonic-gate * this kept device, if so, return EBUSY. 1187*7c478bd9Sstevel@tonic-gate */ 1188*7c478bd9Sstevel@tonic-gate pathbuf = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 1189*7c478bd9Sstevel@tonic-gate (void) ddi_pathname(dip, pathbuf); 1190*7c478bd9Sstevel@tonic-gate pm_dispatch_to_dep_thread(PM_DEP_WK_CHECK_KEPT, 1191*7c478bd9Sstevel@tonic-gate NULL, pathbuf, PM_DEP_WAIT, &has_dep, 0); 1192*7c478bd9Sstevel@tonic-gate kmem_free(pathbuf, MAXPATHLEN); 1193*7c478bd9Sstevel@tonic-gate if (has_dep) { 1194*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("%s EBUSY\n", 1195*7c478bd9Sstevel@tonic-gate cmdstr)) 1196*7c478bd9Sstevel@tonic-gate ret = EBUSY; 1197*7c478bd9Sstevel@tonic-gate break; 1198*7c478bd9Sstevel@tonic-gate } 1199*7c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip); 1200*7c478bd9Sstevel@tonic-gate if (PM_ISDIRECT(dip) || (info->pmi_clone != 0)) { 1201*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: " 1202*7c478bd9Sstevel@tonic-gate "%s@%s(%s#%d): EBUSY\n", cmdstr, 1203*7c478bd9Sstevel@tonic-gate PM_DEVICE(dip))) 1204*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 1205*7c478bd9Sstevel@tonic-gate ret = EBUSY; 1206*7c478bd9Sstevel@tonic-gate break; 1207*7c478bd9Sstevel@tonic-gate } 1208*7c478bd9Sstevel@tonic-gate info->pmi_dev_pm_state |= PM_DIRECT; 1209*7c478bd9Sstevel@tonic-gate info->pmi_clone = clone; 1210*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 1211*7c478bd9Sstevel@tonic-gate PMD(PMD_DPM, ("ioctl: %s: info %p, pmi_clone %d\n", 1212*7c478bd9Sstevel@tonic-gate cmdstr, (void *)info, clone)) 1213*7c478bd9Sstevel@tonic-gate mutex_enter(&pm_clone_lock); 1214*7c478bd9Sstevel@tonic-gate pm_register_watcher(clone, dip); 1215*7c478bd9Sstevel@tonic-gate mutex_exit(&pm_clone_lock); 1216*7c478bd9Sstevel@tonic-gate ret = 0; 1217*7c478bd9Sstevel@tonic-gate break; 1218*7c478bd9Sstevel@tonic-gate } 1219*7c478bd9Sstevel@tonic-gate 1220*7c478bd9Sstevel@tonic-gate case PM_RELEASE_DIRECT_PM: 1221*7c478bd9Sstevel@tonic-gate { 1222*7c478bd9Sstevel@tonic-gate if ((info = PM_GET_PM_INFO(dip)) == NULL) { 1223*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: " 1224*7c478bd9Sstevel@tonic-gate "ENODEV\n", cmdstr)) 1225*7c478bd9Sstevel@tonic-gate ret = ENODEV; 1226*7c478bd9Sstevel@tonic-gate break; 1227*7c478bd9Sstevel@tonic-gate } 1228*7c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip); 1229*7c478bd9Sstevel@tonic-gate if (info->pmi_clone != clone) { 1230*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: " 1231*7c478bd9Sstevel@tonic-gate "%s@%s(%s#%d) EINVAL\n", cmdstr, 1232*7c478bd9Sstevel@tonic-gate PM_DEVICE(dip))) 1233*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1234*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 1235*7c478bd9Sstevel@tonic-gate break; 1236*7c478bd9Sstevel@tonic-gate } 1237*7c478bd9Sstevel@tonic-gate ASSERT(PM_ISDIRECT(dip)); 1238*7c478bd9Sstevel@tonic-gate info->pmi_dev_pm_state &= ~PM_DIRECT; 1239*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 1240*7c478bd9Sstevel@tonic-gate /* Bring ourselves up if there is a keeper. */ 1241*7c478bd9Sstevel@tonic-gate pathbuf = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 1242*7c478bd9Sstevel@tonic-gate (void) ddi_pathname(dip, pathbuf); 1243*7c478bd9Sstevel@tonic-gate pm_dispatch_to_dep_thread(PM_DEP_WK_BRINGUP_SELF, 1244*7c478bd9Sstevel@tonic-gate NULL, pathbuf, PM_DEP_WAIT, NULL, 0); 1245*7c478bd9Sstevel@tonic-gate kmem_free(pathbuf, MAXPATHLEN); 1246*7c478bd9Sstevel@tonic-gate pm_discard_entries(clone); 1247*7c478bd9Sstevel@tonic-gate pm_deregister_watcher(clone, dip); 1248*7c478bd9Sstevel@tonic-gate /* 1249*7c478bd9Sstevel@tonic-gate * Now we could let the other threads that are 1250*7c478bd9Sstevel@tonic-gate * trying to do a DIRECT_PM thru 1251*7c478bd9Sstevel@tonic-gate */ 1252*7c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip); 1253*7c478bd9Sstevel@tonic-gate info->pmi_clone = 0; 1254*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 1255*7c478bd9Sstevel@tonic-gate pm_proceed(dip, PMP_RELEASE, -1, -1); 1256*7c478bd9Sstevel@tonic-gate PMD(PMD_RESCAN | PMD_DPM, ("ioctl: %s: rescan\n", 1257*7c478bd9Sstevel@tonic-gate cmdstr)) 1258*7c478bd9Sstevel@tonic-gate pm_rescan(dip); 1259*7c478bd9Sstevel@tonic-gate ret = 0; 1260*7c478bd9Sstevel@tonic-gate break; 1261*7c478bd9Sstevel@tonic-gate } 1262*7c478bd9Sstevel@tonic-gate 1263*7c478bd9Sstevel@tonic-gate case PM_SET_CURRENT_POWER: 1264*7c478bd9Sstevel@tonic-gate { 1265*7c478bd9Sstevel@tonic-gate int comp = req.component; 1266*7c478bd9Sstevel@tonic-gate int value = req.value; 1267*7c478bd9Sstevel@tonic-gate PMD(PMD_DPM, ("ioctl: %s: %s component %d to value " 1268*7c478bd9Sstevel@tonic-gate "%d\n", cmdstr, req.physpath, comp, value)) 1269*7c478bd9Sstevel@tonic-gate if (!e_pm_valid_comp(dip, comp, NULL) || 1270*7c478bd9Sstevel@tonic-gate !e_pm_valid_power(dip, comp, value)) { 1271*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: " 1272*7c478bd9Sstevel@tonic-gate "physpath=%s, comp=%d, level=%d, fails\n", 1273*7c478bd9Sstevel@tonic-gate cmdstr, req.physpath, comp, value)) 1274*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1275*7c478bd9Sstevel@tonic-gate break; 1276*7c478bd9Sstevel@tonic-gate } 1277*7c478bd9Sstevel@tonic-gate 1278*7c478bd9Sstevel@tonic-gate if ((info = PM_GET_PM_INFO(dip)) == NULL) { 1279*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: " 1280*7c478bd9Sstevel@tonic-gate "ENODEV\n", cmdstr)) 1281*7c478bd9Sstevel@tonic-gate ret = ENODEV; 1282*7c478bd9Sstevel@tonic-gate break; 1283*7c478bd9Sstevel@tonic-gate } 1284*7c478bd9Sstevel@tonic-gate if (info->pmi_clone != clone) { 1285*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: " 1286*7c478bd9Sstevel@tonic-gate "(not owner) %s fails; clone %d, owner %d" 1287*7c478bd9Sstevel@tonic-gate "\n", cmdstr, req.physpath, clone, 1288*7c478bd9Sstevel@tonic-gate info->pmi_clone)) 1289*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1290*7c478bd9Sstevel@tonic-gate break; 1291*7c478bd9Sstevel@tonic-gate } 1292*7c478bd9Sstevel@tonic-gate ASSERT(PM_ISDIRECT(dip)); 1293*7c478bd9Sstevel@tonic-gate 1294*7c478bd9Sstevel@tonic-gate if (pm_set_power(dip, comp, value, PM_LEVEL_EXACT, 1295*7c478bd9Sstevel@tonic-gate PM_CANBLOCK_BLOCK, 0, &ret) != DDI_SUCCESS) { 1296*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: " 1297*7c478bd9Sstevel@tonic-gate "pm_set_power for %s fails, errno=%d\n", 1298*7c478bd9Sstevel@tonic-gate cmdstr, req.physpath, ret)) 1299*7c478bd9Sstevel@tonic-gate break; 1300*7c478bd9Sstevel@tonic-gate } 1301*7c478bd9Sstevel@tonic-gate 1302*7c478bd9Sstevel@tonic-gate pm_proceed(dip, PMP_SETPOWER, comp, value); 1303*7c478bd9Sstevel@tonic-gate 1304*7c478bd9Sstevel@tonic-gate /* 1305*7c478bd9Sstevel@tonic-gate * Power down all idle components if console framebuffer 1306*7c478bd9Sstevel@tonic-gate * is powered off. 1307*7c478bd9Sstevel@tonic-gate */ 1308*7c478bd9Sstevel@tonic-gate if (PM_IS_CFB(dip) && (pm_system_idle_threshold == 1309*7c478bd9Sstevel@tonic-gate pm_default_idle_threshold)) { 1310*7c478bd9Sstevel@tonic-gate dev_info_t *root = ddi_root_node(); 1311*7c478bd9Sstevel@tonic-gate if (PM_ISBC(dip)) { 1312*7c478bd9Sstevel@tonic-gate if (comp == 0 && value == 0 && 1313*7c478bd9Sstevel@tonic-gate (pm_timeout_idledown() != 0)) { 1314*7c478bd9Sstevel@tonic-gate ddi_walk_devs(root, 1315*7c478bd9Sstevel@tonic-gate pm_start_idledown, 1316*7c478bd9Sstevel@tonic-gate (void *)PMID_CFB); 1317*7c478bd9Sstevel@tonic-gate } 1318*7c478bd9Sstevel@tonic-gate } else { 1319*7c478bd9Sstevel@tonic-gate int count = 0; 1320*7c478bd9Sstevel@tonic-gate for (i = 0; i < PM_NUMCMPTS(dip); i++) { 1321*7c478bd9Sstevel@tonic-gate ret = pm_get_current_power(dip, 1322*7c478bd9Sstevel@tonic-gate i, &curpower); 1323*7c478bd9Sstevel@tonic-gate if (ret == DDI_SUCCESS && 1324*7c478bd9Sstevel@tonic-gate curpower == 0) 1325*7c478bd9Sstevel@tonic-gate count++; 1326*7c478bd9Sstevel@tonic-gate } 1327*7c478bd9Sstevel@tonic-gate if ((count == PM_NUMCMPTS(dip)) && 1328*7c478bd9Sstevel@tonic-gate (pm_timeout_idledown() != 0)) { 1329*7c478bd9Sstevel@tonic-gate ddi_walk_devs(root, 1330*7c478bd9Sstevel@tonic-gate pm_start_idledown, 1331*7c478bd9Sstevel@tonic-gate (void *)PMID_CFB); 1332*7c478bd9Sstevel@tonic-gate } 1333*7c478bd9Sstevel@tonic-gate } 1334*7c478bd9Sstevel@tonic-gate } 1335*7c478bd9Sstevel@tonic-gate 1336*7c478bd9Sstevel@tonic-gate PMD(PMD_RESCAN | PMD_DPM, ("ioctl: %s: rescan\n", 1337*7c478bd9Sstevel@tonic-gate cmdstr)) 1338*7c478bd9Sstevel@tonic-gate pm_rescan(dip); 1339*7c478bd9Sstevel@tonic-gate *rval_p = 0; 1340*7c478bd9Sstevel@tonic-gate ret = 0; 1341*7c478bd9Sstevel@tonic-gate break; 1342*7c478bd9Sstevel@tonic-gate } 1343*7c478bd9Sstevel@tonic-gate 1344*7c478bd9Sstevel@tonic-gate case PM_GET_FULL_POWER: 1345*7c478bd9Sstevel@tonic-gate { 1346*7c478bd9Sstevel@tonic-gate int normal; 1347*7c478bd9Sstevel@tonic-gate ASSERT(dip); 1348*7c478bd9Sstevel@tonic-gate PMD(PMD_NORM, ("ioctl: %s: %s component %d\n", 1349*7c478bd9Sstevel@tonic-gate cmdstr, req.physpath, req.component)) 1350*7c478bd9Sstevel@tonic-gate normal = pm_get_normal_power(dip, req.component); 1351*7c478bd9Sstevel@tonic-gate 1352*7c478bd9Sstevel@tonic-gate if (normal == DDI_FAILURE) { 1353*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR | PMD_NORM, ("ioctl: %s: " 1354*7c478bd9Sstevel@tonic-gate "returns EINVAL\n", cmdstr)) 1355*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1356*7c478bd9Sstevel@tonic-gate break; 1357*7c478bd9Sstevel@tonic-gate } 1358*7c478bd9Sstevel@tonic-gate *rval_p = normal; 1359*7c478bd9Sstevel@tonic-gate PMD(PMD_NORM, ("ioctl: %s: returns %d\n", 1360*7c478bd9Sstevel@tonic-gate cmdstr, normal)) 1361*7c478bd9Sstevel@tonic-gate ret = 0; 1362*7c478bd9Sstevel@tonic-gate break; 1363*7c478bd9Sstevel@tonic-gate } 1364*7c478bd9Sstevel@tonic-gate 1365*7c478bd9Sstevel@tonic-gate case PM_GET_CURRENT_POWER: 1366*7c478bd9Sstevel@tonic-gate if (pm_get_current_power(dip, req.component, 1367*7c478bd9Sstevel@tonic-gate rval_p) != DDI_SUCCESS) { 1368*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s " 1369*7c478bd9Sstevel@tonic-gate "EINVAL\n", cmdstr)) 1370*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1371*7c478bd9Sstevel@tonic-gate break; 1372*7c478bd9Sstevel@tonic-gate } 1373*7c478bd9Sstevel@tonic-gate PMD(PMD_DPM, ("ioctl: %s: %s comp %d returns %d\n", 1374*7c478bd9Sstevel@tonic-gate cmdstr, req.physpath, req.component, *rval_p)) 1375*7c478bd9Sstevel@tonic-gate if (*rval_p == PM_LEVEL_UNKNOWN) 1376*7c478bd9Sstevel@tonic-gate ret = EAGAIN; 1377*7c478bd9Sstevel@tonic-gate else 1378*7c478bd9Sstevel@tonic-gate ret = 0; 1379*7c478bd9Sstevel@tonic-gate break; 1380*7c478bd9Sstevel@tonic-gate 1381*7c478bd9Sstevel@tonic-gate case PM_GET_TIME_IDLE: 1382*7c478bd9Sstevel@tonic-gate { 1383*7c478bd9Sstevel@tonic-gate time_t timestamp; 1384*7c478bd9Sstevel@tonic-gate int comp = req.component; 1385*7c478bd9Sstevel@tonic-gate pm_component_t *cp; 1386*7c478bd9Sstevel@tonic-gate if (!e_pm_valid_comp(dip, comp, &cp)) { 1387*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) " 1388*7c478bd9Sstevel@tonic-gate "component %d > numcmpts - 1 %d--EINVAL\n", 1389*7c478bd9Sstevel@tonic-gate cmdstr, PM_DEVICE(dip), comp, 1390*7c478bd9Sstevel@tonic-gate PM_NUMCMPTS(dip) - 1)) 1391*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1392*7c478bd9Sstevel@tonic-gate break; 1393*7c478bd9Sstevel@tonic-gate } 1394*7c478bd9Sstevel@tonic-gate timestamp = cp->pmc_timestamp; 1395*7c478bd9Sstevel@tonic-gate if (timestamp) { 1396*7c478bd9Sstevel@tonic-gate time_t now; 1397*7c478bd9Sstevel@tonic-gate (void) drv_getparm(TIME, &now); 1398*7c478bd9Sstevel@tonic-gate *rval_p = (now - timestamp); 1399*7c478bd9Sstevel@tonic-gate } else { 1400*7c478bd9Sstevel@tonic-gate *rval_p = 0; 1401*7c478bd9Sstevel@tonic-gate } 1402*7c478bd9Sstevel@tonic-gate ret = 0; 1403*7c478bd9Sstevel@tonic-gate break; 1404*7c478bd9Sstevel@tonic-gate } 1405*7c478bd9Sstevel@tonic-gate 1406*7c478bd9Sstevel@tonic-gate case PM_ADD_DEPENDENT: 1407*7c478bd9Sstevel@tonic-gate { 1408*7c478bd9Sstevel@tonic-gate dev_info_t *kept_dip; 1409*7c478bd9Sstevel@tonic-gate 1410*7c478bd9Sstevel@tonic-gate PMD(PMD_KEEPS, ("%s, kept %s, keeper %s\n", cmdstr, 1411*7c478bd9Sstevel@tonic-gate dep, req.physpath)) 1412*7c478bd9Sstevel@tonic-gate 1413*7c478bd9Sstevel@tonic-gate /* 1414*7c478bd9Sstevel@tonic-gate * hold and install kept while processing dependency 1415*7c478bd9Sstevel@tonic-gate * keeper (in .physpath) has already been held. 1416*7c478bd9Sstevel@tonic-gate */ 1417*7c478bd9Sstevel@tonic-gate if (dep[0] == '\0') { 1418*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("kept NULL or null\n")) 1419*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1420*7c478bd9Sstevel@tonic-gate break; 1421*7c478bd9Sstevel@tonic-gate } else if ((kept_dip = 1422*7c478bd9Sstevel@tonic-gate pm_name_to_dip(dep, 1)) == NULL) { 1423*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("no dip for kept %s\n", dep)) 1424*7c478bd9Sstevel@tonic-gate ret = ENODEV; 1425*7c478bd9Sstevel@tonic-gate break; 1426*7c478bd9Sstevel@tonic-gate } else if (kept_dip == dip) { 1427*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("keeper(%s, %p) - kept(%s, %p) " 1428*7c478bd9Sstevel@tonic-gate "self-dependency not allowed.\n", 1429*7c478bd9Sstevel@tonic-gate dep, (void *)kept_dip, req.physpath, 1430*7c478bd9Sstevel@tonic-gate (void *) dip)) 1431*7c478bd9Sstevel@tonic-gate PM_RELE(dip); /* release "double" hold */ 1432*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1433*7c478bd9Sstevel@tonic-gate break; 1434*7c478bd9Sstevel@tonic-gate } 1435*7c478bd9Sstevel@tonic-gate ASSERT(!(strcmp(req.physpath, (char *)dep) == 0)); 1436*7c478bd9Sstevel@tonic-gate 1437*7c478bd9Sstevel@tonic-gate /* 1438*7c478bd9Sstevel@tonic-gate * record dependency, then walk through device tree 1439*7c478bd9Sstevel@tonic-gate * independently on behalf of kept and keeper to 1440*7c478bd9Sstevel@tonic-gate * establish newly created dependency. 1441*7c478bd9Sstevel@tonic-gate */ 1442*7c478bd9Sstevel@tonic-gate pm_dispatch_to_dep_thread(PM_DEP_WK_RECORD_KEEPER, 1443*7c478bd9Sstevel@tonic-gate req.physpath, dep, PM_DEP_WAIT, NULL, 0); 1444*7c478bd9Sstevel@tonic-gate 1445*7c478bd9Sstevel@tonic-gate /* 1446*7c478bd9Sstevel@tonic-gate * release kept after establishing dependency, keeper 1447*7c478bd9Sstevel@tonic-gate * is released as part of ioctl exit processing. 1448*7c478bd9Sstevel@tonic-gate */ 1449*7c478bd9Sstevel@tonic-gate PM_RELE(kept_dip); 1450*7c478bd9Sstevel@tonic-gate *rval_p = 0; 1451*7c478bd9Sstevel@tonic-gate ret = 0; 1452*7c478bd9Sstevel@tonic-gate break; 1453*7c478bd9Sstevel@tonic-gate } 1454*7c478bd9Sstevel@tonic-gate 1455*7c478bd9Sstevel@tonic-gate case PM_ADD_DEPENDENT_PROPERTY: 1456*7c478bd9Sstevel@tonic-gate { 1457*7c478bd9Sstevel@tonic-gate char *keeper, *kept; 1458*7c478bd9Sstevel@tonic-gate 1459*7c478bd9Sstevel@tonic-gate if (dep[0] == '\0') { 1460*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: dep NULL or " 1461*7c478bd9Sstevel@tonic-gate "null\n", cmdstr)) 1462*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1463*7c478bd9Sstevel@tonic-gate break; 1464*7c478bd9Sstevel@tonic-gate } 1465*7c478bd9Sstevel@tonic-gate kept = dep; 1466*7c478bd9Sstevel@tonic-gate keeper = req.physpath; 1467*7c478bd9Sstevel@tonic-gate /* 1468*7c478bd9Sstevel@tonic-gate * record keeper - kept dependency, then walk through 1469*7c478bd9Sstevel@tonic-gate * device tree to find out all attached keeper, walk 1470*7c478bd9Sstevel@tonic-gate * through again to apply dependency to all the 1471*7c478bd9Sstevel@tonic-gate * potential kept. 1472*7c478bd9Sstevel@tonic-gate */ 1473*7c478bd9Sstevel@tonic-gate pm_dispatch_to_dep_thread( 1474*7c478bd9Sstevel@tonic-gate PM_DEP_WK_RECORD_KEEPER_PROP, keeper, kept, 1475*7c478bd9Sstevel@tonic-gate PM_DEP_WAIT, NULL, 0); 1476*7c478bd9Sstevel@tonic-gate 1477*7c478bd9Sstevel@tonic-gate *rval_p = 0; 1478*7c478bd9Sstevel@tonic-gate ret = 0; 1479*7c478bd9Sstevel@tonic-gate break; 1480*7c478bd9Sstevel@tonic-gate } 1481*7c478bd9Sstevel@tonic-gate 1482*7c478bd9Sstevel@tonic-gate case PM_SET_DEVICE_THRESHOLD: 1483*7c478bd9Sstevel@tonic-gate { 1484*7c478bd9Sstevel@tonic-gate pm_thresh_rec_t *rp; 1485*7c478bd9Sstevel@tonic-gate pm_pte_t *ep; /* threshold header storage */ 1486*7c478bd9Sstevel@tonic-gate int *tp; /* threshold storage */ 1487*7c478bd9Sstevel@tonic-gate size_t size; 1488*7c478bd9Sstevel@tonic-gate extern int pm_thresh_specd(dev_info_t *); 1489*7c478bd9Sstevel@tonic-gate 1490*7c478bd9Sstevel@tonic-gate /* 1491*7c478bd9Sstevel@tonic-gate * The header struct plus one entry struct plus one 1492*7c478bd9Sstevel@tonic-gate * threshold plus the length of the string 1493*7c478bd9Sstevel@tonic-gate */ 1494*7c478bd9Sstevel@tonic-gate size = sizeof (pm_thresh_rec_t) + 1495*7c478bd9Sstevel@tonic-gate (sizeof (pm_pte_t) * 1) + 1496*7c478bd9Sstevel@tonic-gate (1 * sizeof (int)) + 1497*7c478bd9Sstevel@tonic-gate strlen(req.physpath) + 1; 1498*7c478bd9Sstevel@tonic-gate 1499*7c478bd9Sstevel@tonic-gate rp = kmem_zalloc(size, KM_SLEEP); 1500*7c478bd9Sstevel@tonic-gate rp->ptr_size = size; 1501*7c478bd9Sstevel@tonic-gate rp->ptr_numcomps = 0; /* means device threshold */ 1502*7c478bd9Sstevel@tonic-gate ep = (pm_pte_t *)((intptr_t)rp + sizeof (*rp)); 1503*7c478bd9Sstevel@tonic-gate rp->ptr_entries = ep; 1504*7c478bd9Sstevel@tonic-gate tp = (int *)((intptr_t)ep + 1505*7c478bd9Sstevel@tonic-gate (1 * sizeof (pm_pte_t))); 1506*7c478bd9Sstevel@tonic-gate ep->pte_numthresh = 1; 1507*7c478bd9Sstevel@tonic-gate ep->pte_thresh = tp; 1508*7c478bd9Sstevel@tonic-gate *tp++ = req.value; 1509*7c478bd9Sstevel@tonic-gate (void) strcat((char *)tp, req.physpath); 1510*7c478bd9Sstevel@tonic-gate rp->ptr_physpath = (char *)tp; 1511*7c478bd9Sstevel@tonic-gate ASSERT((intptr_t)tp + strlen(req.physpath) + 1 == 1512*7c478bd9Sstevel@tonic-gate (intptr_t)rp + rp->ptr_size); 1513*7c478bd9Sstevel@tonic-gate PMD(PMD_THRESH, ("ioctl: %s: record thresh %d for " 1514*7c478bd9Sstevel@tonic-gate "%s\n", cmdstr, req.value, req.physpath)) 1515*7c478bd9Sstevel@tonic-gate pm_record_thresh(rp); 1516*7c478bd9Sstevel@tonic-gate /* 1517*7c478bd9Sstevel@tonic-gate * Don't free rp, pm_record_thresh() keeps it. 1518*7c478bd9Sstevel@tonic-gate * We don't try to apply it ourselves because we'd need 1519*7c478bd9Sstevel@tonic-gate * to know too much about locking. Since we don't 1520*7c478bd9Sstevel@tonic-gate * hold a lock the entry could be removed before 1521*7c478bd9Sstevel@tonic-gate * we get here 1522*7c478bd9Sstevel@tonic-gate */ 1523*7c478bd9Sstevel@tonic-gate ASSERT(dip == NULL); 1524*7c478bd9Sstevel@tonic-gate ret = 0; /* can't fail now */ 1525*7c478bd9Sstevel@tonic-gate if (!(dip = pm_name_to_dip(req.physpath, 1))) { 1526*7c478bd9Sstevel@tonic-gate break; 1527*7c478bd9Sstevel@tonic-gate } 1528*7c478bd9Sstevel@tonic-gate (void) pm_thresh_specd(dip); 1529*7c478bd9Sstevel@tonic-gate PMD(PMD_DHR, ("ioctl: %s: releasing %s@%s(%s#%d)\n", 1530*7c478bd9Sstevel@tonic-gate cmdstr, PM_DEVICE(dip))) 1531*7c478bd9Sstevel@tonic-gate PM_RELE(dip); 1532*7c478bd9Sstevel@tonic-gate break; 1533*7c478bd9Sstevel@tonic-gate } 1534*7c478bd9Sstevel@tonic-gate 1535*7c478bd9Sstevel@tonic-gate case PM_RESET_DEVICE_THRESHOLD: 1536*7c478bd9Sstevel@tonic-gate { 1537*7c478bd9Sstevel@tonic-gate /* 1538*7c478bd9Sstevel@tonic-gate * This only applies to a currently attached and power 1539*7c478bd9Sstevel@tonic-gate * managed node 1540*7c478bd9Sstevel@tonic-gate */ 1541*7c478bd9Sstevel@tonic-gate /* 1542*7c478bd9Sstevel@tonic-gate * We don't do this to old-style drivers 1543*7c478bd9Sstevel@tonic-gate */ 1544*7c478bd9Sstevel@tonic-gate info = PM_GET_PM_INFO(dip); 1545*7c478bd9Sstevel@tonic-gate if (info == NULL) { 1546*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s not power " 1547*7c478bd9Sstevel@tonic-gate "managed\n", cmdstr, req.physpath)) 1548*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1549*7c478bd9Sstevel@tonic-gate break; 1550*7c478bd9Sstevel@tonic-gate } 1551*7c478bd9Sstevel@tonic-gate if (PM_ISBC(dip)) { 1552*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s is BC\n", 1553*7c478bd9Sstevel@tonic-gate cmdstr, req.physpath)) 1554*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1555*7c478bd9Sstevel@tonic-gate break; 1556*7c478bd9Sstevel@tonic-gate } 1557*7c478bd9Sstevel@tonic-gate pm_unrecord_threshold(req.physpath); 1558*7c478bd9Sstevel@tonic-gate pm_set_device_threshold(dip, pm_system_idle_threshold, 1559*7c478bd9Sstevel@tonic-gate PMC_DEF_THRESH); 1560*7c478bd9Sstevel@tonic-gate ret = 0; 1561*7c478bd9Sstevel@tonic-gate break; 1562*7c478bd9Sstevel@tonic-gate } 1563*7c478bd9Sstevel@tonic-gate 1564*7c478bd9Sstevel@tonic-gate case PM_GET_NUM_COMPONENTS: 1565*7c478bd9Sstevel@tonic-gate ret = 0; 1566*7c478bd9Sstevel@tonic-gate *rval_p = PM_NUMCMPTS(dip); 1567*7c478bd9Sstevel@tonic-gate break; 1568*7c478bd9Sstevel@tonic-gate 1569*7c478bd9Sstevel@tonic-gate case PM_GET_DEVICE_TYPE: 1570*7c478bd9Sstevel@tonic-gate ret = 0; 1571*7c478bd9Sstevel@tonic-gate if ((info = PM_GET_PM_INFO(dip)) == NULL) { 1572*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: " 1573*7c478bd9Sstevel@tonic-gate "PM_NO_PM_COMPONENTS\n", cmdstr)) 1574*7c478bd9Sstevel@tonic-gate *rval_p = PM_NO_PM_COMPONENTS; 1575*7c478bd9Sstevel@tonic-gate break; 1576*7c478bd9Sstevel@tonic-gate } 1577*7c478bd9Sstevel@tonic-gate if (PM_ISBC(dip)) { 1578*7c478bd9Sstevel@tonic-gate *rval_p = PM_CREATE_COMPONENTS; 1579*7c478bd9Sstevel@tonic-gate } else { 1580*7c478bd9Sstevel@tonic-gate *rval_p = PM_AUTOPM; 1581*7c478bd9Sstevel@tonic-gate } 1582*7c478bd9Sstevel@tonic-gate break; 1583*7c478bd9Sstevel@tonic-gate 1584*7c478bd9Sstevel@tonic-gate case PM_SET_COMPONENT_THRESHOLDS: 1585*7c478bd9Sstevel@tonic-gate { 1586*7c478bd9Sstevel@tonic-gate int comps = 0; 1587*7c478bd9Sstevel@tonic-gate int *end = (int *)req.data + icount; 1588*7c478bd9Sstevel@tonic-gate pm_thresh_rec_t *rp; 1589*7c478bd9Sstevel@tonic-gate pm_pte_t *ep; /* threshold header storage */ 1590*7c478bd9Sstevel@tonic-gate int *tp; /* threshold storage */ 1591*7c478bd9Sstevel@tonic-gate int *ip; 1592*7c478bd9Sstevel@tonic-gate int j; 1593*7c478bd9Sstevel@tonic-gate size_t size; 1594*7c478bd9Sstevel@tonic-gate extern int pm_thresh_specd(dev_info_t *); 1595*7c478bd9Sstevel@tonic-gate extern int pm_valid_thresh(dev_info_t *, 1596*7c478bd9Sstevel@tonic-gate pm_thresh_rec_t *); 1597*7c478bd9Sstevel@tonic-gate 1598*7c478bd9Sstevel@tonic-gate for (ip = req.data; *ip; ip++) { 1599*7c478bd9Sstevel@tonic-gate if (ip >= end) { 1600*7c478bd9Sstevel@tonic-gate ret = EFAULT; 1601*7c478bd9Sstevel@tonic-gate break; 1602*7c478bd9Sstevel@tonic-gate } 1603*7c478bd9Sstevel@tonic-gate comps++; 1604*7c478bd9Sstevel@tonic-gate /* skip over indicated number of entries */ 1605*7c478bd9Sstevel@tonic-gate for (j = *ip; j; j--) { 1606*7c478bd9Sstevel@tonic-gate if (++ip >= end) { 1607*7c478bd9Sstevel@tonic-gate ret = EFAULT; 1608*7c478bd9Sstevel@tonic-gate break; 1609*7c478bd9Sstevel@tonic-gate } 1610*7c478bd9Sstevel@tonic-gate } 1611*7c478bd9Sstevel@tonic-gate if (ret) 1612*7c478bd9Sstevel@tonic-gate break; 1613*7c478bd9Sstevel@tonic-gate } 1614*7c478bd9Sstevel@tonic-gate if (ret) 1615*7c478bd9Sstevel@tonic-gate break; 1616*7c478bd9Sstevel@tonic-gate if ((intptr_t)ip != (intptr_t)end - sizeof (int)) { 1617*7c478bd9Sstevel@tonic-gate /* did not exactly fill buffer */ 1618*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1619*7c478bd9Sstevel@tonic-gate break; 1620*7c478bd9Sstevel@tonic-gate } 1621*7c478bd9Sstevel@tonic-gate if (comps == 0) { 1622*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s 0 components" 1623*7c478bd9Sstevel@tonic-gate "--EINVAL\n", cmdstr, req.physpath)) 1624*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1625*7c478bd9Sstevel@tonic-gate break; 1626*7c478bd9Sstevel@tonic-gate } 1627*7c478bd9Sstevel@tonic-gate /* 1628*7c478bd9Sstevel@tonic-gate * The header struct plus one entry struct per component 1629*7c478bd9Sstevel@tonic-gate * plus the size of the lists minus the counts 1630*7c478bd9Sstevel@tonic-gate * plus the length of the string 1631*7c478bd9Sstevel@tonic-gate */ 1632*7c478bd9Sstevel@tonic-gate size = sizeof (pm_thresh_rec_t) + 1633*7c478bd9Sstevel@tonic-gate (sizeof (pm_pte_t) * comps) + req.datasize - 1634*7c478bd9Sstevel@tonic-gate ((comps + 1) * sizeof (int)) + 1635*7c478bd9Sstevel@tonic-gate strlen(req.physpath) + 1; 1636*7c478bd9Sstevel@tonic-gate 1637*7c478bd9Sstevel@tonic-gate rp = kmem_zalloc(size, KM_SLEEP); 1638*7c478bd9Sstevel@tonic-gate rp->ptr_size = size; 1639*7c478bd9Sstevel@tonic-gate rp->ptr_numcomps = comps; 1640*7c478bd9Sstevel@tonic-gate ep = (pm_pte_t *)((intptr_t)rp + sizeof (*rp)); 1641*7c478bd9Sstevel@tonic-gate rp->ptr_entries = ep; 1642*7c478bd9Sstevel@tonic-gate tp = (int *)((intptr_t)ep + 1643*7c478bd9Sstevel@tonic-gate (comps * sizeof (pm_pte_t))); 1644*7c478bd9Sstevel@tonic-gate for (ip = req.data; *ip; ep++) { 1645*7c478bd9Sstevel@tonic-gate ep->pte_numthresh = *ip; 1646*7c478bd9Sstevel@tonic-gate ep->pte_thresh = tp; 1647*7c478bd9Sstevel@tonic-gate for (j = *ip++; j; j--) { 1648*7c478bd9Sstevel@tonic-gate *tp++ = *ip++; 1649*7c478bd9Sstevel@tonic-gate } 1650*7c478bd9Sstevel@tonic-gate } 1651*7c478bd9Sstevel@tonic-gate (void) strcat((char *)tp, req.physpath); 1652*7c478bd9Sstevel@tonic-gate rp->ptr_physpath = (char *)tp; 1653*7c478bd9Sstevel@tonic-gate ASSERT((intptr_t)end == (intptr_t)ip + sizeof (int)); 1654*7c478bd9Sstevel@tonic-gate ASSERT((intptr_t)tp + strlen(req.physpath) + 1 == 1655*7c478bd9Sstevel@tonic-gate (intptr_t)rp + rp->ptr_size); 1656*7c478bd9Sstevel@tonic-gate 1657*7c478bd9Sstevel@tonic-gate ASSERT(dip == NULL); 1658*7c478bd9Sstevel@tonic-gate /* 1659*7c478bd9Sstevel@tonic-gate * If this is not a currently power managed node, 1660*7c478bd9Sstevel@tonic-gate * then we can't check for validity of the thresholds 1661*7c478bd9Sstevel@tonic-gate */ 1662*7c478bd9Sstevel@tonic-gate if (!(dip = pm_name_to_dip(req.physpath, 1))) { 1663*7c478bd9Sstevel@tonic-gate /* don't free rp, pm_record_thresh uses it */ 1664*7c478bd9Sstevel@tonic-gate pm_record_thresh(rp); 1665*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: pm_name_to_dip " 1666*7c478bd9Sstevel@tonic-gate "for %s failed\n", cmdstr, req.physpath)) 1667*7c478bd9Sstevel@tonic-gate ret = 0; 1668*7c478bd9Sstevel@tonic-gate break; 1669*7c478bd9Sstevel@tonic-gate } 1670*7c478bd9Sstevel@tonic-gate ASSERT(!dipheld); 1671*7c478bd9Sstevel@tonic-gate dipheld++; 1672*7c478bd9Sstevel@tonic-gate 1673*7c478bd9Sstevel@tonic-gate if (!pm_valid_thresh(dip, rp)) { 1674*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: invalid thresh " 1675*7c478bd9Sstevel@tonic-gate "for %s@%s(%s#%d)\n", cmdstr, 1676*7c478bd9Sstevel@tonic-gate PM_DEVICE(dip))) 1677*7c478bd9Sstevel@tonic-gate kmem_free(rp, size); 1678*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1679*7c478bd9Sstevel@tonic-gate break; 1680*7c478bd9Sstevel@tonic-gate } 1681*7c478bd9Sstevel@tonic-gate /* 1682*7c478bd9Sstevel@tonic-gate * We don't just apply it ourselves because we'd need 1683*7c478bd9Sstevel@tonic-gate * to know too much about locking. Since we don't 1684*7c478bd9Sstevel@tonic-gate * hold a lock the entry could be removed before 1685*7c478bd9Sstevel@tonic-gate * we get here 1686*7c478bd9Sstevel@tonic-gate */ 1687*7c478bd9Sstevel@tonic-gate pm_record_thresh(rp); 1688*7c478bd9Sstevel@tonic-gate (void) pm_thresh_specd(dip); 1689*7c478bd9Sstevel@tonic-gate ret = 0; 1690*7c478bd9Sstevel@tonic-gate break; 1691*7c478bd9Sstevel@tonic-gate } 1692*7c478bd9Sstevel@tonic-gate 1693*7c478bd9Sstevel@tonic-gate case PM_GET_COMPONENT_THRESHOLDS: 1694*7c478bd9Sstevel@tonic-gate { 1695*7c478bd9Sstevel@tonic-gate int musthave; 1696*7c478bd9Sstevel@tonic-gate int numthresholds = 0; 1697*7c478bd9Sstevel@tonic-gate int wordsize; 1698*7c478bd9Sstevel@tonic-gate int numcomps; 1699*7c478bd9Sstevel@tonic-gate caddr_t uaddr = req.data; /* user address */ 1700*7c478bd9Sstevel@tonic-gate int val; /* int value to be copied out */ 1701*7c478bd9Sstevel@tonic-gate int32_t val32; /* int32 value to be copied out */ 1702*7c478bd9Sstevel@tonic-gate caddr_t vaddr; /* address to copyout from */ 1703*7c478bd9Sstevel@tonic-gate int j; 1704*7c478bd9Sstevel@tonic-gate 1705*7c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 1706*7c478bd9Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) { 1707*7c478bd9Sstevel@tonic-gate wordsize = sizeof (int32_t); 1708*7c478bd9Sstevel@tonic-gate } else 1709*7c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 1710*7c478bd9Sstevel@tonic-gate { 1711*7c478bd9Sstevel@tonic-gate wordsize = sizeof (int); 1712*7c478bd9Sstevel@tonic-gate } 1713*7c478bd9Sstevel@tonic-gate 1714*7c478bd9Sstevel@tonic-gate ASSERT(dip); 1715*7c478bd9Sstevel@tonic-gate 1716*7c478bd9Sstevel@tonic-gate numcomps = PM_NUMCMPTS(dip); 1717*7c478bd9Sstevel@tonic-gate for (i = 0; i < numcomps; i++) { 1718*7c478bd9Sstevel@tonic-gate cp = PM_CP(dip, i); 1719*7c478bd9Sstevel@tonic-gate numthresholds += cp->pmc_comp.pmc_numlevels - 1; 1720*7c478bd9Sstevel@tonic-gate } 1721*7c478bd9Sstevel@tonic-gate musthave = (numthresholds + numcomps + 1) * wordsize; 1722*7c478bd9Sstevel@tonic-gate if (req.datasize < musthave) { 1723*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: size %ld, need " 1724*7c478bd9Sstevel@tonic-gate "%d--EINVAL\n", cmdstr, req.datasize, 1725*7c478bd9Sstevel@tonic-gate musthave)) 1726*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1727*7c478bd9Sstevel@tonic-gate break; 1728*7c478bd9Sstevel@tonic-gate } 1729*7c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip); 1730*7c478bd9Sstevel@tonic-gate for (i = 0; i < numcomps; i++) { 1731*7c478bd9Sstevel@tonic-gate int *thp; 1732*7c478bd9Sstevel@tonic-gate cp = PM_CP(dip, i); 1733*7c478bd9Sstevel@tonic-gate thp = cp->pmc_comp.pmc_thresh; 1734*7c478bd9Sstevel@tonic-gate /* first copyout the count */ 1735*7c478bd9Sstevel@tonic-gate if (wordsize == sizeof (int32_t)) { 1736*7c478bd9Sstevel@tonic-gate val32 = cp->pmc_comp.pmc_numlevels - 1; 1737*7c478bd9Sstevel@tonic-gate vaddr = (caddr_t)&val32; 1738*7c478bd9Sstevel@tonic-gate } else { 1739*7c478bd9Sstevel@tonic-gate val = cp->pmc_comp.pmc_numlevels - 1; 1740*7c478bd9Sstevel@tonic-gate vaddr = (caddr_t)&val; 1741*7c478bd9Sstevel@tonic-gate } 1742*7c478bd9Sstevel@tonic-gate if (ddi_copyout(vaddr, (void *)uaddr, 1743*7c478bd9Sstevel@tonic-gate wordsize, mode) != 0) { 1744*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 1745*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s" 1746*7c478bd9Sstevel@tonic-gate "(%s#%d) vaddr %p EFAULT\n", 1747*7c478bd9Sstevel@tonic-gate cmdstr, PM_DEVICE(dip), 1748*7c478bd9Sstevel@tonic-gate (void*)vaddr)) 1749*7c478bd9Sstevel@tonic-gate ret = EFAULT; 1750*7c478bd9Sstevel@tonic-gate break; 1751*7c478bd9Sstevel@tonic-gate } 1752*7c478bd9Sstevel@tonic-gate vaddr = uaddr; 1753*7c478bd9Sstevel@tonic-gate vaddr += wordsize; 1754*7c478bd9Sstevel@tonic-gate uaddr = (caddr_t)vaddr; 1755*7c478bd9Sstevel@tonic-gate /* then copyout each threshold value */ 1756*7c478bd9Sstevel@tonic-gate for (j = 0; j < cp->pmc_comp.pmc_numlevels - 1; 1757*7c478bd9Sstevel@tonic-gate j++) { 1758*7c478bd9Sstevel@tonic-gate if (wordsize == sizeof (int32_t)) { 1759*7c478bd9Sstevel@tonic-gate val32 = thp[j + 1]; 1760*7c478bd9Sstevel@tonic-gate vaddr = (caddr_t)&val32; 1761*7c478bd9Sstevel@tonic-gate } else { 1762*7c478bd9Sstevel@tonic-gate val = thp[i + 1]; 1763*7c478bd9Sstevel@tonic-gate vaddr = (caddr_t)&val; 1764*7c478bd9Sstevel@tonic-gate } 1765*7c478bd9Sstevel@tonic-gate if (ddi_copyout(vaddr, (void *) uaddr, 1766*7c478bd9Sstevel@tonic-gate wordsize, mode) != 0) { 1767*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 1768*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: " 1769*7c478bd9Sstevel@tonic-gate "%s@%s(%s#%d) uaddr %p " 1770*7c478bd9Sstevel@tonic-gate "EFAULT\n", cmdstr, 1771*7c478bd9Sstevel@tonic-gate PM_DEVICE(dip), 1772*7c478bd9Sstevel@tonic-gate (void *)uaddr)) 1773*7c478bd9Sstevel@tonic-gate ret = EFAULT; 1774*7c478bd9Sstevel@tonic-gate break; 1775*7c478bd9Sstevel@tonic-gate } 1776*7c478bd9Sstevel@tonic-gate vaddr = uaddr; 1777*7c478bd9Sstevel@tonic-gate vaddr += wordsize; 1778*7c478bd9Sstevel@tonic-gate uaddr = (caddr_t)vaddr; 1779*7c478bd9Sstevel@tonic-gate } 1780*7c478bd9Sstevel@tonic-gate } 1781*7c478bd9Sstevel@tonic-gate if (ret) 1782*7c478bd9Sstevel@tonic-gate break; 1783*7c478bd9Sstevel@tonic-gate /* last copyout a terminating 0 count */ 1784*7c478bd9Sstevel@tonic-gate if (wordsize == sizeof (int32_t)) { 1785*7c478bd9Sstevel@tonic-gate val32 = 0; 1786*7c478bd9Sstevel@tonic-gate vaddr = (caddr_t)&val32; 1787*7c478bd9Sstevel@tonic-gate } else { 1788*7c478bd9Sstevel@tonic-gate ASSERT(wordsize == sizeof (int)); 1789*7c478bd9Sstevel@tonic-gate val = 0; 1790*7c478bd9Sstevel@tonic-gate vaddr = (caddr_t)&val; 1791*7c478bd9Sstevel@tonic-gate } 1792*7c478bd9Sstevel@tonic-gate if (ddi_copyout(vaddr, uaddr, wordsize, mode) != 0) { 1793*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 1794*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) " 1795*7c478bd9Sstevel@tonic-gate "vaddr %p (0 count) EFAULT\n", cmdstr, 1796*7c478bd9Sstevel@tonic-gate PM_DEVICE(dip), (void *)vaddr)) 1797*7c478bd9Sstevel@tonic-gate ret = EFAULT; 1798*7c478bd9Sstevel@tonic-gate break; 1799*7c478bd9Sstevel@tonic-gate } 1800*7c478bd9Sstevel@tonic-gate /* finished, so don't need to increment addresses */ 1801*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 1802*7c478bd9Sstevel@tonic-gate ret = 0; 1803*7c478bd9Sstevel@tonic-gate break; 1804*7c478bd9Sstevel@tonic-gate } 1805*7c478bd9Sstevel@tonic-gate 1806*7c478bd9Sstevel@tonic-gate case PM_GET_STATS: 1807*7c478bd9Sstevel@tonic-gate { 1808*7c478bd9Sstevel@tonic-gate time_t now; 1809*7c478bd9Sstevel@tonic-gate time_t *timestamp; 1810*7c478bd9Sstevel@tonic-gate extern int pm_cur_power(pm_component_t *cp); 1811*7c478bd9Sstevel@tonic-gate int musthave; 1812*7c478bd9Sstevel@tonic-gate int wordsize; 1813*7c478bd9Sstevel@tonic-gate 1814*7c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 1815*7c478bd9Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) { 1816*7c478bd9Sstevel@tonic-gate wordsize = sizeof (int32_t); 1817*7c478bd9Sstevel@tonic-gate } else 1818*7c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 1819*7c478bd9Sstevel@tonic-gate { 1820*7c478bd9Sstevel@tonic-gate wordsize = sizeof (int); 1821*7c478bd9Sstevel@tonic-gate } 1822*7c478bd9Sstevel@tonic-gate 1823*7c478bd9Sstevel@tonic-gate comps = PM_NUMCMPTS(dip); 1824*7c478bd9Sstevel@tonic-gate if (comps == 0 || PM_GET_PM_INFO(dip) == NULL) { 1825*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s no components" 1826*7c478bd9Sstevel@tonic-gate " or not power managed--EINVAL\n", cmdstr, 1827*7c478bd9Sstevel@tonic-gate req.physpath)) 1828*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1829*7c478bd9Sstevel@tonic-gate break; 1830*7c478bd9Sstevel@tonic-gate } 1831*7c478bd9Sstevel@tonic-gate musthave = comps * 2 * wordsize; 1832*7c478bd9Sstevel@tonic-gate if (req.datasize < musthave) { 1833*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: size %lu, need " 1834*7c478bd9Sstevel@tonic-gate "%d--EINVAL\n", cmdstr, req.datasize, 1835*7c478bd9Sstevel@tonic-gate musthave)) 1836*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1837*7c478bd9Sstevel@tonic-gate break; 1838*7c478bd9Sstevel@tonic-gate } 1839*7c478bd9Sstevel@tonic-gate 1840*7c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip); 1841*7c478bd9Sstevel@tonic-gate (void) drv_getparm(TIME, &now); 1842*7c478bd9Sstevel@tonic-gate timestamp = kmem_zalloc(comps * sizeof (time_t), 1843*7c478bd9Sstevel@tonic-gate KM_SLEEP); 1844*7c478bd9Sstevel@tonic-gate pm_get_timestamps(dip, timestamp); 1845*7c478bd9Sstevel@tonic-gate /* 1846*7c478bd9Sstevel@tonic-gate * First the current power levels 1847*7c478bd9Sstevel@tonic-gate */ 1848*7c478bd9Sstevel@tonic-gate for (i = 0; i < comps; i++) { 1849*7c478bd9Sstevel@tonic-gate int curpwr; 1850*7c478bd9Sstevel@tonic-gate int32_t curpwr32; 1851*7c478bd9Sstevel@tonic-gate caddr_t cpaddr; 1852*7c478bd9Sstevel@tonic-gate 1853*7c478bd9Sstevel@tonic-gate cp = PM_CP(dip, i); 1854*7c478bd9Sstevel@tonic-gate if (wordsize == sizeof (int)) { 1855*7c478bd9Sstevel@tonic-gate curpwr = pm_cur_power(cp); 1856*7c478bd9Sstevel@tonic-gate cpaddr = (caddr_t)&curpwr; 1857*7c478bd9Sstevel@tonic-gate } else { 1858*7c478bd9Sstevel@tonic-gate ASSERT(wordsize == sizeof (int32_t)); 1859*7c478bd9Sstevel@tonic-gate curpwr32 = pm_cur_power(cp); 1860*7c478bd9Sstevel@tonic-gate cpaddr = (caddr_t)&curpwr32; 1861*7c478bd9Sstevel@tonic-gate } 1862*7c478bd9Sstevel@tonic-gate if (ddi_copyout(cpaddr, (void *) req.data, 1863*7c478bd9Sstevel@tonic-gate wordsize, mode) != 0) { 1864*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 1865*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s" 1866*7c478bd9Sstevel@tonic-gate "(%s#%d) req.data %p EFAULT\n", 1867*7c478bd9Sstevel@tonic-gate cmdstr, PM_DEVICE(dip), 1868*7c478bd9Sstevel@tonic-gate (void *)req.data)) 1869*7c478bd9Sstevel@tonic-gate ASSERT(!dipheld); 1870*7c478bd9Sstevel@tonic-gate return (EFAULT); 1871*7c478bd9Sstevel@tonic-gate } 1872*7c478bd9Sstevel@tonic-gate cpaddr = (caddr_t)req.data; 1873*7c478bd9Sstevel@tonic-gate cpaddr += wordsize; 1874*7c478bd9Sstevel@tonic-gate req.data = cpaddr; 1875*7c478bd9Sstevel@tonic-gate } 1876*7c478bd9Sstevel@tonic-gate /* 1877*7c478bd9Sstevel@tonic-gate * Then the times remaining 1878*7c478bd9Sstevel@tonic-gate */ 1879*7c478bd9Sstevel@tonic-gate for (i = 0; i < comps; i++) { 1880*7c478bd9Sstevel@tonic-gate int retval; 1881*7c478bd9Sstevel@tonic-gate int32_t retval32; 1882*7c478bd9Sstevel@tonic-gate caddr_t rvaddr; 1883*7c478bd9Sstevel@tonic-gate int curpwr; 1884*7c478bd9Sstevel@tonic-gate 1885*7c478bd9Sstevel@tonic-gate cp = PM_CP(dip, i); 1886*7c478bd9Sstevel@tonic-gate curpwr = cp->pmc_cur_pwr; 1887*7c478bd9Sstevel@tonic-gate if (curpwr == 0 || timestamp[i] == 0) { 1888*7c478bd9Sstevel@tonic-gate PMD(PMD_STATS, ("ioctl: %s: " 1889*7c478bd9Sstevel@tonic-gate "cur_pwer %x, timestamp %lx\n", 1890*7c478bd9Sstevel@tonic-gate cmdstr, curpwr, timestamp[i])) 1891*7c478bd9Sstevel@tonic-gate retval = INT_MAX; 1892*7c478bd9Sstevel@tonic-gate } else { 1893*7c478bd9Sstevel@tonic-gate int thresh; 1894*7c478bd9Sstevel@tonic-gate (void) pm_current_threshold(dip, i, 1895*7c478bd9Sstevel@tonic-gate &thresh); 1896*7c478bd9Sstevel@tonic-gate retval = thresh - (now - timestamp[i]); 1897*7c478bd9Sstevel@tonic-gate PMD(PMD_STATS, ("ioctl: %s: current " 1898*7c478bd9Sstevel@tonic-gate "thresh %x, now %lx, timestamp %lx," 1899*7c478bd9Sstevel@tonic-gate " retval %x\n", cmdstr, thresh, now, 1900*7c478bd9Sstevel@tonic-gate timestamp[i], retval)) 1901*7c478bd9Sstevel@tonic-gate } 1902*7c478bd9Sstevel@tonic-gate if (wordsize == sizeof (int)) { 1903*7c478bd9Sstevel@tonic-gate rvaddr = (caddr_t)&retval; 1904*7c478bd9Sstevel@tonic-gate } else { 1905*7c478bd9Sstevel@tonic-gate ASSERT(wordsize == sizeof (int32_t)); 1906*7c478bd9Sstevel@tonic-gate retval32 = retval; 1907*7c478bd9Sstevel@tonic-gate rvaddr = (caddr_t)&retval32; 1908*7c478bd9Sstevel@tonic-gate } 1909*7c478bd9Sstevel@tonic-gate if (ddi_copyout(rvaddr, (void *) req.data, 1910*7c478bd9Sstevel@tonic-gate wordsize, mode) != 0) { 1911*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 1912*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s" 1913*7c478bd9Sstevel@tonic-gate "(%s#%d) req.data %p EFAULT\n", 1914*7c478bd9Sstevel@tonic-gate cmdstr, PM_DEVICE(dip), 1915*7c478bd9Sstevel@tonic-gate (void *)req.data)) 1916*7c478bd9Sstevel@tonic-gate ASSERT(!dipheld); 1917*7c478bd9Sstevel@tonic-gate return (EFAULT); 1918*7c478bd9Sstevel@tonic-gate } 1919*7c478bd9Sstevel@tonic-gate rvaddr = (caddr_t)req.data; 1920*7c478bd9Sstevel@tonic-gate rvaddr += wordsize; 1921*7c478bd9Sstevel@tonic-gate req.data = (int *)rvaddr; 1922*7c478bd9Sstevel@tonic-gate } 1923*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 1924*7c478bd9Sstevel@tonic-gate *rval_p = comps; 1925*7c478bd9Sstevel@tonic-gate ret = 0; 1926*7c478bd9Sstevel@tonic-gate kmem_free(timestamp, comps * sizeof (time_t)); 1927*7c478bd9Sstevel@tonic-gate break; 1928*7c478bd9Sstevel@tonic-gate } 1929*7c478bd9Sstevel@tonic-gate 1930*7c478bd9Sstevel@tonic-gate case PM_GET_COMPONENT_NAME: 1931*7c478bd9Sstevel@tonic-gate ASSERT(dip); 1932*7c478bd9Sstevel@tonic-gate if (!e_pm_valid_comp(dip, req.component, &cp)) { 1933*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) " 1934*7c478bd9Sstevel@tonic-gate "component %d > numcmpts - 1 %d--EINVAL\n", 1935*7c478bd9Sstevel@tonic-gate cmdstr, PM_DEVICE(dip), req.component, 1936*7c478bd9Sstevel@tonic-gate PM_NUMCMPTS(dip) - 1)) 1937*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1938*7c478bd9Sstevel@tonic-gate break; 1939*7c478bd9Sstevel@tonic-gate } 1940*7c478bd9Sstevel@tonic-gate if (ret = copyoutstr(cp->pmc_comp.pmc_name, 1941*7c478bd9Sstevel@tonic-gate (char *)req.data, req.datasize, &lencopied)) { 1942*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) " 1943*7c478bd9Sstevel@tonic-gate "copyoutstr %p failed--EFAULT\n", cmdstr, 1944*7c478bd9Sstevel@tonic-gate PM_DEVICE(dip), (void *)req.data)) 1945*7c478bd9Sstevel@tonic-gate break; 1946*7c478bd9Sstevel@tonic-gate } 1947*7c478bd9Sstevel@tonic-gate *rval_p = lencopied; 1948*7c478bd9Sstevel@tonic-gate ret = 0; 1949*7c478bd9Sstevel@tonic-gate break; 1950*7c478bd9Sstevel@tonic-gate 1951*7c478bd9Sstevel@tonic-gate case PM_GET_POWER_NAME: 1952*7c478bd9Sstevel@tonic-gate { 1953*7c478bd9Sstevel@tonic-gate int i; 1954*7c478bd9Sstevel@tonic-gate 1955*7c478bd9Sstevel@tonic-gate ASSERT(dip); 1956*7c478bd9Sstevel@tonic-gate if (!e_pm_valid_comp(dip, req.component, &cp)) { 1957*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) " 1958*7c478bd9Sstevel@tonic-gate "component %d > numcmpts - 1 %d--EINVAL\n", 1959*7c478bd9Sstevel@tonic-gate cmdstr, PM_DEVICE(dip), req.component, 1960*7c478bd9Sstevel@tonic-gate PM_NUMCMPTS(dip) - 1)) 1961*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1962*7c478bd9Sstevel@tonic-gate break; 1963*7c478bd9Sstevel@tonic-gate } 1964*7c478bd9Sstevel@tonic-gate if ((i = req.value) < 0 || 1965*7c478bd9Sstevel@tonic-gate i > cp->pmc_comp.pmc_numlevels - 1) { 1966*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) " 1967*7c478bd9Sstevel@tonic-gate "value %d > num_levels - 1 %d--EINVAL\n", 1968*7c478bd9Sstevel@tonic-gate cmdstr, PM_DEVICE(dip), req.value, 1969*7c478bd9Sstevel@tonic-gate cp->pmc_comp.pmc_numlevels - 1)) 1970*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1971*7c478bd9Sstevel@tonic-gate break; 1972*7c478bd9Sstevel@tonic-gate } 1973*7c478bd9Sstevel@tonic-gate dep = cp->pmc_comp.pmc_lnames[req.value]; 1974*7c478bd9Sstevel@tonic-gate if (ret = copyoutstr(dep, 1975*7c478bd9Sstevel@tonic-gate req.data, req.datasize, &lencopied)) { 1976*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) " 1977*7c478bd9Sstevel@tonic-gate "copyoutstr %p failed--EFAULT\n", cmdstr, 1978*7c478bd9Sstevel@tonic-gate PM_DEVICE(dip), (void *)req.data)) 1979*7c478bd9Sstevel@tonic-gate break; 1980*7c478bd9Sstevel@tonic-gate } 1981*7c478bd9Sstevel@tonic-gate *rval_p = lencopied; 1982*7c478bd9Sstevel@tonic-gate ret = 0; 1983*7c478bd9Sstevel@tonic-gate break; 1984*7c478bd9Sstevel@tonic-gate } 1985*7c478bd9Sstevel@tonic-gate 1986*7c478bd9Sstevel@tonic-gate case PM_GET_POWER_LEVELS: 1987*7c478bd9Sstevel@tonic-gate { 1988*7c478bd9Sstevel@tonic-gate int musthave; 1989*7c478bd9Sstevel@tonic-gate int numlevels; 1990*7c478bd9Sstevel@tonic-gate int wordsize; 1991*7c478bd9Sstevel@tonic-gate 1992*7c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 1993*7c478bd9Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) { 1994*7c478bd9Sstevel@tonic-gate wordsize = sizeof (int32_t); 1995*7c478bd9Sstevel@tonic-gate } else 1996*7c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 1997*7c478bd9Sstevel@tonic-gate { 1998*7c478bd9Sstevel@tonic-gate wordsize = sizeof (int); 1999*7c478bd9Sstevel@tonic-gate } 2000*7c478bd9Sstevel@tonic-gate ASSERT(dip); 2001*7c478bd9Sstevel@tonic-gate 2002*7c478bd9Sstevel@tonic-gate if (!e_pm_valid_comp(dip, req.component, &cp)) { 2003*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) " 2004*7c478bd9Sstevel@tonic-gate "has %d components, component %d requested" 2005*7c478bd9Sstevel@tonic-gate "--EINVAL\n", cmdstr, PM_DEVICE(dip), 2006*7c478bd9Sstevel@tonic-gate PM_NUMCMPTS(dip), req.component)) 2007*7c478bd9Sstevel@tonic-gate ret = EINVAL; 2008*7c478bd9Sstevel@tonic-gate break; 2009*7c478bd9Sstevel@tonic-gate } 2010*7c478bd9Sstevel@tonic-gate numlevels = cp->pmc_comp.pmc_numlevels; 2011*7c478bd9Sstevel@tonic-gate musthave = numlevels * wordsize; 2012*7c478bd9Sstevel@tonic-gate if (req.datasize < musthave) { 2013*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: size %lu, need " 2014*7c478bd9Sstevel@tonic-gate "%d--EINVAL\n", cmdstr, req.datasize, 2015*7c478bd9Sstevel@tonic-gate musthave)) 2016*7c478bd9Sstevel@tonic-gate ret = EINVAL; 2017*7c478bd9Sstevel@tonic-gate break; 2018*7c478bd9Sstevel@tonic-gate } 2019*7c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip); 2020*7c478bd9Sstevel@tonic-gate for (i = 0; i < numlevels; i++) { 2021*7c478bd9Sstevel@tonic-gate int level; 2022*7c478bd9Sstevel@tonic-gate int32_t level32; 2023*7c478bd9Sstevel@tonic-gate caddr_t laddr; 2024*7c478bd9Sstevel@tonic-gate 2025*7c478bd9Sstevel@tonic-gate if (wordsize == sizeof (int)) { 2026*7c478bd9Sstevel@tonic-gate level = cp->pmc_comp.pmc_lvals[i]; 2027*7c478bd9Sstevel@tonic-gate laddr = (caddr_t)&level; 2028*7c478bd9Sstevel@tonic-gate } else { 2029*7c478bd9Sstevel@tonic-gate level32 = cp->pmc_comp.pmc_lvals[i]; 2030*7c478bd9Sstevel@tonic-gate laddr = (caddr_t)&level32; 2031*7c478bd9Sstevel@tonic-gate } 2032*7c478bd9Sstevel@tonic-gate if (ddi_copyout(laddr, (void *) req.data, 2033*7c478bd9Sstevel@tonic-gate wordsize, mode) != 0) { 2034*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 2035*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s" 2036*7c478bd9Sstevel@tonic-gate "(%s#%d) laddr %p EFAULT\n", 2037*7c478bd9Sstevel@tonic-gate cmdstr, PM_DEVICE(dip), 2038*7c478bd9Sstevel@tonic-gate (void *)laddr)) 2039*7c478bd9Sstevel@tonic-gate ASSERT(!dipheld); 2040*7c478bd9Sstevel@tonic-gate return (EFAULT); 2041*7c478bd9Sstevel@tonic-gate } 2042*7c478bd9Sstevel@tonic-gate laddr = (caddr_t)req.data; 2043*7c478bd9Sstevel@tonic-gate laddr += wordsize; 2044*7c478bd9Sstevel@tonic-gate req.data = (int *)laddr; 2045*7c478bd9Sstevel@tonic-gate } 2046*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 2047*7c478bd9Sstevel@tonic-gate *rval_p = numlevels; 2048*7c478bd9Sstevel@tonic-gate ret = 0; 2049*7c478bd9Sstevel@tonic-gate break; 2050*7c478bd9Sstevel@tonic-gate } 2051*7c478bd9Sstevel@tonic-gate 2052*7c478bd9Sstevel@tonic-gate 2053*7c478bd9Sstevel@tonic-gate case PM_GET_NUM_POWER_LEVELS: 2054*7c478bd9Sstevel@tonic-gate if (!e_pm_valid_comp(dip, req.component, &cp)) { 2055*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) " 2056*7c478bd9Sstevel@tonic-gate "component %d > numcmpts - 1 %d--EINVAL\n", 2057*7c478bd9Sstevel@tonic-gate cmdstr, PM_DEVICE(dip), req.component, 2058*7c478bd9Sstevel@tonic-gate PM_NUMCMPTS(dip) - 1)) 2059*7c478bd9Sstevel@tonic-gate ret = EINVAL; 2060*7c478bd9Sstevel@tonic-gate break; 2061*7c478bd9Sstevel@tonic-gate } 2062*7c478bd9Sstevel@tonic-gate *rval_p = cp->pmc_comp.pmc_numlevels; 2063*7c478bd9Sstevel@tonic-gate ret = 0; 2064*7c478bd9Sstevel@tonic-gate break; 2065*7c478bd9Sstevel@tonic-gate 2066*7c478bd9Sstevel@tonic-gate case PM_GET_DEVICE_THRESHOLD_BASIS: 2067*7c478bd9Sstevel@tonic-gate ret = 0; 2068*7c478bd9Sstevel@tonic-gate PM_LOCK_DIP(dip); 2069*7c478bd9Sstevel@tonic-gate if ((info = PM_GET_PM_INFO(dip)) == NULL) { 2070*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 2071*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: " 2072*7c478bd9Sstevel@tonic-gate "PM_NO_PM_COMPONENTS\n", cmdstr)) 2073*7c478bd9Sstevel@tonic-gate *rval_p = PM_NO_PM_COMPONENTS; 2074*7c478bd9Sstevel@tonic-gate break; 2075*7c478bd9Sstevel@tonic-gate } 2076*7c478bd9Sstevel@tonic-gate if (PM_ISDIRECT(dip)) { 2077*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 2078*7c478bd9Sstevel@tonic-gate *rval_p = PM_DIRECTLY_MANAGED; 2079*7c478bd9Sstevel@tonic-gate break; 2080*7c478bd9Sstevel@tonic-gate } 2081*7c478bd9Sstevel@tonic-gate switch (DEVI(dip)->devi_pm_flags & PMC_THRESH_ALL) { 2082*7c478bd9Sstevel@tonic-gate case PMC_DEF_THRESH: 2083*7c478bd9Sstevel@tonic-gate case PMC_NEXDEF_THRESH: 2084*7c478bd9Sstevel@tonic-gate *rval_p = PM_DEFAULT_THRESHOLD; 2085*7c478bd9Sstevel@tonic-gate break; 2086*7c478bd9Sstevel@tonic-gate case PMC_DEV_THRESH: 2087*7c478bd9Sstevel@tonic-gate *rval_p = PM_DEVICE_THRESHOLD; 2088*7c478bd9Sstevel@tonic-gate break; 2089*7c478bd9Sstevel@tonic-gate case PMC_COMP_THRESH: 2090*7c478bd9Sstevel@tonic-gate *rval_p = PM_COMPONENT_THRESHOLD; 2091*7c478bd9Sstevel@tonic-gate break; 2092*7c478bd9Sstevel@tonic-gate default: 2093*7c478bd9Sstevel@tonic-gate if (PM_ISBC(dip)) { 2094*7c478bd9Sstevel@tonic-gate *rval_p = PM_OLD_THRESHOLD; 2095*7c478bd9Sstevel@tonic-gate break; 2096*7c478bd9Sstevel@tonic-gate } 2097*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: default, not " 2098*7c478bd9Sstevel@tonic-gate "BC--EINVAL", cmdstr)) 2099*7c478bd9Sstevel@tonic-gate ret = EINVAL; 2100*7c478bd9Sstevel@tonic-gate break; 2101*7c478bd9Sstevel@tonic-gate } 2102*7c478bd9Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 2103*7c478bd9Sstevel@tonic-gate break; 2104*7c478bd9Sstevel@tonic-gate } 2105*7c478bd9Sstevel@tonic-gate break; 2106*7c478bd9Sstevel@tonic-gate 2107*7c478bd9Sstevel@tonic-gate case PM_PSC: 2108*7c478bd9Sstevel@tonic-gate /* 2109*7c478bd9Sstevel@tonic-gate * Commands that require pm_state_change_t as arg 2110*7c478bd9Sstevel@tonic-gate */ 2111*7c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 2112*7c478bd9Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) { 2113*7c478bd9Sstevel@tonic-gate pscp32 = (pm_state_change32_t *)arg; 2114*7c478bd9Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg, &psc32, 2115*7c478bd9Sstevel@tonic-gate sizeof (psc32), mode) != 0) { 2116*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin " 2117*7c478bd9Sstevel@tonic-gate "EFAULT\n\n", cmdstr)) 2118*7c478bd9Sstevel@tonic-gate ASSERT(!dipheld); 2119*7c478bd9Sstevel@tonic-gate return (EFAULT); 2120*7c478bd9Sstevel@tonic-gate } 2121*7c478bd9Sstevel@tonic-gate psc.physpath = (caddr_t)(uintptr_t)psc32.physpath; 2122*7c478bd9Sstevel@tonic-gate psc.size = psc32.size; 2123*7c478bd9Sstevel@tonic-gate } else 2124*7c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 2125*7c478bd9Sstevel@tonic-gate { 2126*7c478bd9Sstevel@tonic-gate pscp = (pm_state_change_t *)arg; 2127*7c478bd9Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg, &psc, 2128*7c478bd9Sstevel@tonic-gate sizeof (psc), mode) != 0) { 2129*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin " 2130*7c478bd9Sstevel@tonic-gate "EFAULT\n\n", cmdstr)) 2131*7c478bd9Sstevel@tonic-gate ASSERT(!dipheld); 2132*7c478bd9Sstevel@tonic-gate return (EFAULT); 2133*7c478bd9Sstevel@tonic-gate } 2134*7c478bd9Sstevel@tonic-gate } 2135*7c478bd9Sstevel@tonic-gate switch (cmd) { 2136*7c478bd9Sstevel@tonic-gate 2137*7c478bd9Sstevel@tonic-gate case PM_GET_STATE_CHANGE: 2138*7c478bd9Sstevel@tonic-gate case PM_GET_STATE_CHANGE_WAIT: 2139*7c478bd9Sstevel@tonic-gate { 2140*7c478bd9Sstevel@tonic-gate psce_t *pscep; 2141*7c478bd9Sstevel@tonic-gate pm_state_change_t *p; 2142*7c478bd9Sstevel@tonic-gate caddr_t physpath; 2143*7c478bd9Sstevel@tonic-gate size_t physlen; 2144*7c478bd9Sstevel@tonic-gate 2145*7c478bd9Sstevel@tonic-gate /* 2146*7c478bd9Sstevel@tonic-gate * We want to know if any device has changed state. 2147*7c478bd9Sstevel@tonic-gate * We look up by clone. In case we have another thread 2148*7c478bd9Sstevel@tonic-gate * from the same process, we loop. 2149*7c478bd9Sstevel@tonic-gate * pm_psc_clone_to_interest() returns a locked entry. 2150*7c478bd9Sstevel@tonic-gate * We create an internal copy of the event entry prior 2151*7c478bd9Sstevel@tonic-gate * to copyout to user space because we don't want to 2152*7c478bd9Sstevel@tonic-gate * hold the psce_lock while doing copyout as we might 2153*7c478bd9Sstevel@tonic-gate * hit page fault which eventually brings us back 2154*7c478bd9Sstevel@tonic-gate * here requesting the same lock. 2155*7c478bd9Sstevel@tonic-gate */ 2156*7c478bd9Sstevel@tonic-gate mutex_enter(&pm_clone_lock); 2157*7c478bd9Sstevel@tonic-gate if (!pm_interest_registered(clone)) 2158*7c478bd9Sstevel@tonic-gate pm_register_watcher(clone, NULL); 2159*7c478bd9Sstevel@tonic-gate while ((pscep = 2160*7c478bd9Sstevel@tonic-gate pm_psc_clone_to_interest(clone)) == NULL) { 2161*7c478bd9Sstevel@tonic-gate if (cmd == PM_GET_STATE_CHANGE) { 2162*7c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: %s: " 2163*7c478bd9Sstevel@tonic-gate "EWOULDBLOCK\n", cmdstr)) 2164*7c478bd9Sstevel@tonic-gate mutex_exit(&pm_clone_lock); 2165*7c478bd9Sstevel@tonic-gate ASSERT(!dipheld); 2166*7c478bd9Sstevel@tonic-gate return (EWOULDBLOCK); 2167*7c478bd9Sstevel@tonic-gate } else { 2168*7c478bd9Sstevel@tonic-gate if (cv_wait_sig(&pm_clones_cv[clone], 2169*7c478bd9Sstevel@tonic-gate &pm_clone_lock) == 0) { 2170*7c478bd9Sstevel@tonic-gate mutex_exit(&pm_clone_lock); 2171*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s " 2172*7c478bd9Sstevel@tonic-gate "EINTR\n", cmdstr)) 2173*7c478bd9Sstevel@tonic-gate ASSERT(!dipheld); 2174*7c478bd9Sstevel@tonic-gate return (EINTR); 2175*7c478bd9Sstevel@tonic-gate } 2176*7c478bd9Sstevel@tonic-gate } 2177*7c478bd9Sstevel@tonic-gate } 2178*7c478bd9Sstevel@tonic-gate mutex_exit(&pm_clone_lock); 2179*7c478bd9Sstevel@tonic-gate 2180*7c478bd9Sstevel@tonic-gate physlen = pscep->psce_out->size; 2181*7c478bd9Sstevel@tonic-gate physpath = NULL; 2182*7c478bd9Sstevel@tonic-gate /* 2183*7c478bd9Sstevel@tonic-gate * If we were unable to store the path while bringing 2184*7c478bd9Sstevel@tonic-gate * up the console fb upon entering the prom, we give 2185*7c478bd9Sstevel@tonic-gate * a "" name with the overrun event set 2186*7c478bd9Sstevel@tonic-gate */ 2187*7c478bd9Sstevel@tonic-gate if (physlen == (size_t)-1) { /* kmemalloc failed */ 2188*7c478bd9Sstevel@tonic-gate physpath = kmem_zalloc(1, KM_SLEEP); 2189*7c478bd9Sstevel@tonic-gate physlen = 1; 2190*7c478bd9Sstevel@tonic-gate } 2191*7c478bd9Sstevel@tonic-gate if ((psc.physpath == NULL) || (psc.size < physlen)) { 2192*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: EFAULT\n", cmdstr)) 2193*7c478bd9Sstevel@tonic-gate mutex_exit(&pscep->psce_lock); 2194*7c478bd9Sstevel@tonic-gate ret = EFAULT; 2195*7c478bd9Sstevel@tonic-gate break; 2196*7c478bd9Sstevel@tonic-gate } 2197*7c478bd9Sstevel@tonic-gate if (physpath == NULL) { 2198*7c478bd9Sstevel@tonic-gate physpath = kmem_zalloc(physlen, KM_SLEEP); 2199*7c478bd9Sstevel@tonic-gate bcopy((const void *) pscep->psce_out->physpath, 2200*7c478bd9Sstevel@tonic-gate (void *) physpath, physlen); 2201*7c478bd9Sstevel@tonic-gate } 2202*7c478bd9Sstevel@tonic-gate 2203*7c478bd9Sstevel@tonic-gate p = pscep->psce_out; 2204*7c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 2205*7c478bd9Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) { 2206*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2207*7c478bd9Sstevel@tonic-gate size_t usrcopysize; 2208*7c478bd9Sstevel@tonic-gate #endif 2209*7c478bd9Sstevel@tonic-gate psc32.flags = (ushort_t)p->flags; 2210*7c478bd9Sstevel@tonic-gate psc32.event = (ushort_t)p->event; 2211*7c478bd9Sstevel@tonic-gate psc32.timestamp = (int32_t)p->timestamp; 2212*7c478bd9Sstevel@tonic-gate psc32.component = (int32_t)p->component; 2213*7c478bd9Sstevel@tonic-gate psc32.old_level = (int32_t)p->old_level; 2214*7c478bd9Sstevel@tonic-gate psc32.new_level = (int32_t)p->new_level; 2215*7c478bd9Sstevel@tonic-gate copysize32 = ((intptr_t)&psc32.size - 2216*7c478bd9Sstevel@tonic-gate (intptr_t)&psc32.component); 2217*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2218*7c478bd9Sstevel@tonic-gate usrcopysize = ((intptr_t)&pscp32->size - 2219*7c478bd9Sstevel@tonic-gate (intptr_t)&pscp32->component); 2220*7c478bd9Sstevel@tonic-gate ASSERT(usrcopysize == copysize32); 2221*7c478bd9Sstevel@tonic-gate #endif 2222*7c478bd9Sstevel@tonic-gate } else 2223*7c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 2224*7c478bd9Sstevel@tonic-gate { 2225*7c478bd9Sstevel@tonic-gate psc.flags = p->flags; 2226*7c478bd9Sstevel@tonic-gate psc.event = p->event; 2227*7c478bd9Sstevel@tonic-gate psc.timestamp = p->timestamp; 2228*7c478bd9Sstevel@tonic-gate psc.component = p->component; 2229*7c478bd9Sstevel@tonic-gate psc.old_level = p->old_level; 2230*7c478bd9Sstevel@tonic-gate psc.new_level = p->new_level; 2231*7c478bd9Sstevel@tonic-gate copysize = ((long)&p->size - 2232*7c478bd9Sstevel@tonic-gate (long)&p->component); 2233*7c478bd9Sstevel@tonic-gate } 2234*7c478bd9Sstevel@tonic-gate if (p->size != (size_t)-1) 2235*7c478bd9Sstevel@tonic-gate kmem_free(p->physpath, p->size); 2236*7c478bd9Sstevel@tonic-gate p->size = 0; 2237*7c478bd9Sstevel@tonic-gate p->physpath = NULL; 2238*7c478bd9Sstevel@tonic-gate if (pscep->psce_out == pscep->psce_last) 2239*7c478bd9Sstevel@tonic-gate p = pscep->psce_first; 2240*7c478bd9Sstevel@tonic-gate else 2241*7c478bd9Sstevel@tonic-gate p++; 2242*7c478bd9Sstevel@tonic-gate pscep->psce_out = p; 2243*7c478bd9Sstevel@tonic-gate mutex_exit(&pscep->psce_lock); 2244*7c478bd9Sstevel@tonic-gate 2245*7c478bd9Sstevel@tonic-gate ret = copyoutstr(physpath, psc.physpath, 2246*7c478bd9Sstevel@tonic-gate physlen, &lencopied); 2247*7c478bd9Sstevel@tonic-gate kmem_free(physpath, physlen); 2248*7c478bd9Sstevel@tonic-gate if (ret) { 2249*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: copyoutstr %p " 2250*7c478bd9Sstevel@tonic-gate "failed--EFAULT\n", cmdstr, 2251*7c478bd9Sstevel@tonic-gate (void *)psc.physpath)) 2252*7c478bd9Sstevel@tonic-gate break; 2253*7c478bd9Sstevel@tonic-gate } 2254*7c478bd9Sstevel@tonic-gate 2255*7c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 2256*7c478bd9Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) { 2257*7c478bd9Sstevel@tonic-gate if (ddi_copyout(&psc32.component, 2258*7c478bd9Sstevel@tonic-gate &pscp32->component, copysize32, mode) 2259*7c478bd9Sstevel@tonic-gate != 0) { 2260*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: copyout " 2261*7c478bd9Sstevel@tonic-gate "failed--EFAULT\n", cmdstr)) 2262*7c478bd9Sstevel@tonic-gate ret = EFAULT; 2263*7c478bd9Sstevel@tonic-gate break; 2264*7c478bd9Sstevel@tonic-gate } 2265*7c478bd9Sstevel@tonic-gate } else 2266*7c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 2267*7c478bd9Sstevel@tonic-gate { 2268*7c478bd9Sstevel@tonic-gate if (ddi_copyout(&psc.component, 2269*7c478bd9Sstevel@tonic-gate &pscp->component, copysize, mode) != 0) { 2270*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: copyout " 2271*7c478bd9Sstevel@tonic-gate "failed--EFAULT\n", cmdstr)) 2272*7c478bd9Sstevel@tonic-gate ret = EFAULT; 2273*7c478bd9Sstevel@tonic-gate break; 2274*7c478bd9Sstevel@tonic-gate } 2275*7c478bd9Sstevel@tonic-gate } 2276*7c478bd9Sstevel@tonic-gate ret = 0; 2277*7c478bd9Sstevel@tonic-gate break; 2278*7c478bd9Sstevel@tonic-gate } 2279*7c478bd9Sstevel@tonic-gate 2280*7c478bd9Sstevel@tonic-gate case PM_DIRECT_NOTIFY: 2281*7c478bd9Sstevel@tonic-gate case PM_DIRECT_NOTIFY_WAIT: 2282*7c478bd9Sstevel@tonic-gate { 2283*7c478bd9Sstevel@tonic-gate psce_t *pscep; 2284*7c478bd9Sstevel@tonic-gate pm_state_change_t *p; 2285*7c478bd9Sstevel@tonic-gate caddr_t physpath; 2286*7c478bd9Sstevel@tonic-gate size_t physlen; 2287*7c478bd9Sstevel@tonic-gate /* 2288*7c478bd9Sstevel@tonic-gate * We want to know if any direct device of ours has 2289*7c478bd9Sstevel@tonic-gate * something we should know about. We look up by clone. 2290*7c478bd9Sstevel@tonic-gate * In case we have another thread from the same process, 2291*7c478bd9Sstevel@tonic-gate * we loop. 2292*7c478bd9Sstevel@tonic-gate * pm_psc_clone_to_direct() returns a locked entry. 2293*7c478bd9Sstevel@tonic-gate */ 2294*7c478bd9Sstevel@tonic-gate mutex_enter(&pm_clone_lock); 2295*7c478bd9Sstevel@tonic-gate while (pm_poll_cnt[clone] == 0 || 2296*7c478bd9Sstevel@tonic-gate (pscep = pm_psc_clone_to_direct(clone)) == NULL) { 2297*7c478bd9Sstevel@tonic-gate if (cmd == PM_DIRECT_NOTIFY) { 2298*7c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: %s: " 2299*7c478bd9Sstevel@tonic-gate "EWOULDBLOCK\n", cmdstr)) 2300*7c478bd9Sstevel@tonic-gate mutex_exit(&pm_clone_lock); 2301*7c478bd9Sstevel@tonic-gate ASSERT(!dipheld); 2302*7c478bd9Sstevel@tonic-gate return (EWOULDBLOCK); 2303*7c478bd9Sstevel@tonic-gate } else { 2304*7c478bd9Sstevel@tonic-gate if (cv_wait_sig(&pm_clones_cv[clone], 2305*7c478bd9Sstevel@tonic-gate &pm_clone_lock) == 0) { 2306*7c478bd9Sstevel@tonic-gate mutex_exit(&pm_clone_lock); 2307*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: " 2308*7c478bd9Sstevel@tonic-gate "EINTR\n", cmdstr)) 2309*7c478bd9Sstevel@tonic-gate ASSERT(!dipheld); 2310*7c478bd9Sstevel@tonic-gate return (EINTR); 2311*7c478bd9Sstevel@tonic-gate } 2312*7c478bd9Sstevel@tonic-gate } 2313*7c478bd9Sstevel@tonic-gate } 2314*7c478bd9Sstevel@tonic-gate mutex_exit(&pm_clone_lock); 2315*7c478bd9Sstevel@tonic-gate physlen = pscep->psce_out->size; 2316*7c478bd9Sstevel@tonic-gate if ((psc.physpath == NULL) || (psc.size < physlen)) { 2317*7c478bd9Sstevel@tonic-gate mutex_exit(&pscep->psce_lock); 2318*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: EFAULT\n", 2319*7c478bd9Sstevel@tonic-gate cmdstr)) 2320*7c478bd9Sstevel@tonic-gate ret = EFAULT; 2321*7c478bd9Sstevel@tonic-gate break; 2322*7c478bd9Sstevel@tonic-gate } 2323*7c478bd9Sstevel@tonic-gate physpath = kmem_zalloc(physlen, KM_SLEEP); 2324*7c478bd9Sstevel@tonic-gate bcopy((const void *) pscep->psce_out->physpath, 2325*7c478bd9Sstevel@tonic-gate (void *) physpath, physlen); 2326*7c478bd9Sstevel@tonic-gate 2327*7c478bd9Sstevel@tonic-gate p = pscep->psce_out; 2328*7c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 2329*7c478bd9Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) { 2330*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2331*7c478bd9Sstevel@tonic-gate size_t usrcopysize; 2332*7c478bd9Sstevel@tonic-gate #endif 2333*7c478bd9Sstevel@tonic-gate psc32.component = (int32_t)p->component; 2334*7c478bd9Sstevel@tonic-gate psc32.flags = (ushort_t)p->flags; 2335*7c478bd9Sstevel@tonic-gate psc32.event = (ushort_t)p->event; 2336*7c478bd9Sstevel@tonic-gate psc32.timestamp = (int32_t)p->timestamp; 2337*7c478bd9Sstevel@tonic-gate psc32.old_level = (int32_t)p->old_level; 2338*7c478bd9Sstevel@tonic-gate psc32.new_level = (int32_t)p->new_level; 2339*7c478bd9Sstevel@tonic-gate copysize32 = (intptr_t)&psc32.size - 2340*7c478bd9Sstevel@tonic-gate (intptr_t)&psc32.component; 2341*7c478bd9Sstevel@tonic-gate PMD(PMD_DPM, ("ioctl: %s: PDN32 %s, comp %d " 2342*7c478bd9Sstevel@tonic-gate "%d -> %d\n", cmdstr, physpath, 2343*7c478bd9Sstevel@tonic-gate p->component, p->old_level, p->new_level)) 2344*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2345*7c478bd9Sstevel@tonic-gate usrcopysize = (intptr_t)&pscp32->size - 2346*7c478bd9Sstevel@tonic-gate (intptr_t)&pscp32->component; 2347*7c478bd9Sstevel@tonic-gate ASSERT(usrcopysize == copysize32); 2348*7c478bd9Sstevel@tonic-gate #endif 2349*7c478bd9Sstevel@tonic-gate } else 2350*7c478bd9Sstevel@tonic-gate #endif 2351*7c478bd9Sstevel@tonic-gate { 2352*7c478bd9Sstevel@tonic-gate psc.component = p->component; 2353*7c478bd9Sstevel@tonic-gate psc.flags = p->flags; 2354*7c478bd9Sstevel@tonic-gate psc.event = p->event; 2355*7c478bd9Sstevel@tonic-gate psc.timestamp = p->timestamp; 2356*7c478bd9Sstevel@tonic-gate psc.old_level = p->old_level; 2357*7c478bd9Sstevel@tonic-gate psc.new_level = p->new_level; 2358*7c478bd9Sstevel@tonic-gate copysize = (intptr_t)&p->size - 2359*7c478bd9Sstevel@tonic-gate (intptr_t)&p->component; 2360*7c478bd9Sstevel@tonic-gate PMD(PMD_DPM, ("ioctl: %s: PDN %s, comp %d " 2361*7c478bd9Sstevel@tonic-gate "%d -> %d\n", cmdstr, physpath, 2362*7c478bd9Sstevel@tonic-gate p->component, p->old_level, p->new_level)) 2363*7c478bd9Sstevel@tonic-gate } 2364*7c478bd9Sstevel@tonic-gate mutex_enter(&pm_clone_lock); 2365*7c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: %s: pm_poll_cnt[%d] is %d " 2366*7c478bd9Sstevel@tonic-gate "before decrement\n", cmdstr, clone, 2367*7c478bd9Sstevel@tonic-gate pm_poll_cnt[clone])) 2368*7c478bd9Sstevel@tonic-gate pm_poll_cnt[clone]--; 2369*7c478bd9Sstevel@tonic-gate mutex_exit(&pm_clone_lock); 2370*7c478bd9Sstevel@tonic-gate kmem_free(p->physpath, p->size); 2371*7c478bd9Sstevel@tonic-gate p->size = 0; 2372*7c478bd9Sstevel@tonic-gate p->physpath = NULL; 2373*7c478bd9Sstevel@tonic-gate if (pscep->psce_out == pscep->psce_last) 2374*7c478bd9Sstevel@tonic-gate p = pscep->psce_first; 2375*7c478bd9Sstevel@tonic-gate else 2376*7c478bd9Sstevel@tonic-gate p++; 2377*7c478bd9Sstevel@tonic-gate pscep->psce_out = p; 2378*7c478bd9Sstevel@tonic-gate mutex_exit(&pscep->psce_lock); 2379*7c478bd9Sstevel@tonic-gate 2380*7c478bd9Sstevel@tonic-gate ret = copyoutstr(physpath, psc.physpath, 2381*7c478bd9Sstevel@tonic-gate physlen, &lencopied); 2382*7c478bd9Sstevel@tonic-gate kmem_free(physpath, physlen); 2383*7c478bd9Sstevel@tonic-gate if (ret) { 2384*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: copyoutstr %p " 2385*7c478bd9Sstevel@tonic-gate "failed--EFAULT\n", cmdstr, 2386*7c478bd9Sstevel@tonic-gate (void *)psc.physpath)) 2387*7c478bd9Sstevel@tonic-gate break; 2388*7c478bd9Sstevel@tonic-gate } 2389*7c478bd9Sstevel@tonic-gate 2390*7c478bd9Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 2391*7c478bd9Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) { 2392*7c478bd9Sstevel@tonic-gate if (ddi_copyout(&psc32.component, 2393*7c478bd9Sstevel@tonic-gate &pscp32->component, copysize32, mode) 2394*7c478bd9Sstevel@tonic-gate != 0) { 2395*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: copyout " 2396*7c478bd9Sstevel@tonic-gate "failed--EFAULT\n", cmdstr)) 2397*7c478bd9Sstevel@tonic-gate ret = EFAULT; 2398*7c478bd9Sstevel@tonic-gate break; 2399*7c478bd9Sstevel@tonic-gate } 2400*7c478bd9Sstevel@tonic-gate } else 2401*7c478bd9Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 2402*7c478bd9Sstevel@tonic-gate { 2403*7c478bd9Sstevel@tonic-gate if (ddi_copyout(&psc.component, 2404*7c478bd9Sstevel@tonic-gate &pscp->component, copysize, mode) != 0) { 2405*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: copyout " 2406*7c478bd9Sstevel@tonic-gate "failed--EFAULT\n", cmdstr)) 2407*7c478bd9Sstevel@tonic-gate ret = EFAULT; 2408*7c478bd9Sstevel@tonic-gate break; 2409*7c478bd9Sstevel@tonic-gate } 2410*7c478bd9Sstevel@tonic-gate } 2411*7c478bd9Sstevel@tonic-gate ret = 0; 2412*7c478bd9Sstevel@tonic-gate break; 2413*7c478bd9Sstevel@tonic-gate } 2414*7c478bd9Sstevel@tonic-gate default: 2415*7c478bd9Sstevel@tonic-gate ASSERT(0); 2416*7c478bd9Sstevel@tonic-gate } 2417*7c478bd9Sstevel@tonic-gate break; 2418*7c478bd9Sstevel@tonic-gate 2419*7c478bd9Sstevel@tonic-gate case NOSTRUCT: 2420*7c478bd9Sstevel@tonic-gate switch (cmd) { 2421*7c478bd9Sstevel@tonic-gate case PM_START_PM: 2422*7c478bd9Sstevel@tonic-gate mutex_enter(&pm_scan_lock); 2423*7c478bd9Sstevel@tonic-gate if (autopm_enabled) { 2424*7c478bd9Sstevel@tonic-gate mutex_exit(&pm_scan_lock); 2425*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: EBUSY\n", 2426*7c478bd9Sstevel@tonic-gate cmdstr)) 2427*7c478bd9Sstevel@tonic-gate ret = EBUSY; 2428*7c478bd9Sstevel@tonic-gate break; 2429*7c478bd9Sstevel@tonic-gate } 2430*7c478bd9Sstevel@tonic-gate autopm_enabled = 1; 2431*7c478bd9Sstevel@tonic-gate mutex_exit(&pm_scan_lock); 2432*7c478bd9Sstevel@tonic-gate ddi_walk_devs(ddi_root_node(), pm_start_pm_walk, &cmd); 2433*7c478bd9Sstevel@tonic-gate ret = 0; 2434*7c478bd9Sstevel@tonic-gate break; 2435*7c478bd9Sstevel@tonic-gate 2436*7c478bd9Sstevel@tonic-gate case PM_RESET_PM: 2437*7c478bd9Sstevel@tonic-gate case PM_STOP_PM: 2438*7c478bd9Sstevel@tonic-gate { 2439*7c478bd9Sstevel@tonic-gate extern void pm_discard_thresholds(void); 2440*7c478bd9Sstevel@tonic-gate 2441*7c478bd9Sstevel@tonic-gate mutex_enter(&pm_scan_lock); 2442*7c478bd9Sstevel@tonic-gate if (!autopm_enabled && cmd != PM_RESET_PM) { 2443*7c478bd9Sstevel@tonic-gate mutex_exit(&pm_scan_lock); 2444*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: EINVAL\n", 2445*7c478bd9Sstevel@tonic-gate cmdstr)) 2446*7c478bd9Sstevel@tonic-gate ret = EINVAL; 2447*7c478bd9Sstevel@tonic-gate break; 2448*7c478bd9Sstevel@tonic-gate } 2449*7c478bd9Sstevel@tonic-gate autopm_enabled = 0; 2450*7c478bd9Sstevel@tonic-gate mutex_exit(&pm_scan_lock); 2451*7c478bd9Sstevel@tonic-gate /* 2452*7c478bd9Sstevel@tonic-gate * bring devices to full power level, stop scan 2453*7c478bd9Sstevel@tonic-gate */ 2454*7c478bd9Sstevel@tonic-gate ddi_walk_devs(ddi_root_node(), pm_stop_pm_walk, &cmd); 2455*7c478bd9Sstevel@tonic-gate ret = 0; 2456*7c478bd9Sstevel@tonic-gate if (cmd == PM_STOP_PM) 2457*7c478bd9Sstevel@tonic-gate break; 2458*7c478bd9Sstevel@tonic-gate /* 2459*7c478bd9Sstevel@tonic-gate * Now do only PM_RESET_PM stuff. 2460*7c478bd9Sstevel@tonic-gate */ 2461*7c478bd9Sstevel@tonic-gate pm_system_idle_threshold = pm_default_idle_threshold; 2462*7c478bd9Sstevel@tonic-gate pm_discard_thresholds(); 2463*7c478bd9Sstevel@tonic-gate pm_all_to_default_thresholds(); 2464*7c478bd9Sstevel@tonic-gate pm_dispatch_to_dep_thread(PM_DEP_WK_REMOVE_DEP, 2465*7c478bd9Sstevel@tonic-gate NULL, NULL, PM_DEP_WAIT, NULL, 0); 2466*7c478bd9Sstevel@tonic-gate break; 2467*7c478bd9Sstevel@tonic-gate } 2468*7c478bd9Sstevel@tonic-gate 2469*7c478bd9Sstevel@tonic-gate case PM_GET_SYSTEM_THRESHOLD: 2470*7c478bd9Sstevel@tonic-gate *rval_p = pm_system_idle_threshold; 2471*7c478bd9Sstevel@tonic-gate ret = 0; 2472*7c478bd9Sstevel@tonic-gate break; 2473*7c478bd9Sstevel@tonic-gate 2474*7c478bd9Sstevel@tonic-gate case PM_GET_DEFAULT_SYSTEM_THRESHOLD: 2475*7c478bd9Sstevel@tonic-gate *rval_p = pm_default_idle_threshold; 2476*7c478bd9Sstevel@tonic-gate ret = 0; 2477*7c478bd9Sstevel@tonic-gate break; 2478*7c478bd9Sstevel@tonic-gate 2479*7c478bd9Sstevel@tonic-gate case PM_SET_SYSTEM_THRESHOLD: 2480*7c478bd9Sstevel@tonic-gate if ((int)arg < 0) { 2481*7c478bd9Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: arg 0x%x < 0" 2482*7c478bd9Sstevel@tonic-gate "--EINVAL\n", cmdstr, (int)arg)) 2483*7c478bd9Sstevel@tonic-gate ret = EINVAL; 2484*7c478bd9Sstevel@tonic-gate break; 2485*7c478bd9Sstevel@tonic-gate } 2486*7c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: %s: 0x%x 0t%d\n", cmdstr, 2487*7c478bd9Sstevel@tonic-gate (int)arg, (int)arg)) 2488*7c478bd9Sstevel@tonic-gate pm_system_idle_threshold = (int)arg; 2489*7c478bd9Sstevel@tonic-gate ddi_walk_devs(ddi_root_node(), pm_set_sys_threshold, 2490*7c478bd9Sstevel@tonic-gate (void *) &pm_system_idle_threshold); 2491*7c478bd9Sstevel@tonic-gate ret = 0; 2492*7c478bd9Sstevel@tonic-gate break; 2493*7c478bd9Sstevel@tonic-gate 2494*7c478bd9Sstevel@tonic-gate case PM_IDLE_DOWN: 2495*7c478bd9Sstevel@tonic-gate if (pm_timeout_idledown() != 0) { 2496*7c478bd9Sstevel@tonic-gate ddi_walk_devs(ddi_root_node(), 2497*7c478bd9Sstevel@tonic-gate pm_start_idledown, (void *)PMID_IOC); 2498*7c478bd9Sstevel@tonic-gate } 2499*7c478bd9Sstevel@tonic-gate ret = 0; 2500*7c478bd9Sstevel@tonic-gate break; 2501*7c478bd9Sstevel@tonic-gate 2502*7c478bd9Sstevel@tonic-gate case PM_GET_PM_STATE: 2503*7c478bd9Sstevel@tonic-gate if (autopm_enabled) { 2504*7c478bd9Sstevel@tonic-gate *rval_p = PM_SYSTEM_PM_ENABLED; 2505*7c478bd9Sstevel@tonic-gate } else { 2506*7c478bd9Sstevel@tonic-gate *rval_p = PM_SYSTEM_PM_DISABLED; 2507*7c478bd9Sstevel@tonic-gate } 2508*7c478bd9Sstevel@tonic-gate ret = 0; 2509*7c478bd9Sstevel@tonic-gate break; 2510*7c478bd9Sstevel@tonic-gate } 2511*7c478bd9Sstevel@tonic-gate break; 2512*7c478bd9Sstevel@tonic-gate 2513*7c478bd9Sstevel@tonic-gate 2514*7c478bd9Sstevel@tonic-gate default: 2515*7c478bd9Sstevel@tonic-gate /* 2516*7c478bd9Sstevel@tonic-gate * Internal error, invalid ioctl description 2517*7c478bd9Sstevel@tonic-gate * force debug entry even if pm_debug not set 2518*7c478bd9Sstevel@tonic-gate */ 2519*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2520*7c478bd9Sstevel@tonic-gate pm_log("ioctl: invalid str_type %d for cmd %d (%s)\n", 2521*7c478bd9Sstevel@tonic-gate pcip->str_type, cmd, pcip->name); 2522*7c478bd9Sstevel@tonic-gate #endif 2523*7c478bd9Sstevel@tonic-gate ASSERT(0); 2524*7c478bd9Sstevel@tonic-gate return (EIO); 2525*7c478bd9Sstevel@tonic-gate } 2526*7c478bd9Sstevel@tonic-gate ASSERT(ret != 0x0badcafe); /* some cmd in wrong case! */ 2527*7c478bd9Sstevel@tonic-gate if (dipheld) { 2528*7c478bd9Sstevel@tonic-gate ASSERT(dip); 2529*7c478bd9Sstevel@tonic-gate PMD(PMD_DHR, ("ioctl: %s: releasing %s@%s(%s#%d) for " 2530*7c478bd9Sstevel@tonic-gate "exiting pm_ioctl\n", cmdstr, PM_DEVICE(dip))) 2531*7c478bd9Sstevel@tonic-gate PM_RELE(dip); 2532*7c478bd9Sstevel@tonic-gate } 2533*7c478bd9Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: %s: end, ret=%d\n", cmdstr, ret)) 2534*7c478bd9Sstevel@tonic-gate return (ret); 2535*7c478bd9Sstevel@tonic-gate } 2536