10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 53028Smh27603 * Common Development and Distribution License (the "License"). 63028Smh27603 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*8906SEric.Saxe@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* 270Sstevel@tonic-gate * pm This driver now only handles the ioctl interface. The scanning 280Sstevel@tonic-gate * and policy stuff now lives in common/os/sunpm.c. 290Sstevel@tonic-gate * Not DDI compliant 300Sstevel@tonic-gate */ 310Sstevel@tonic-gate 320Sstevel@tonic-gate #include <sys/types.h> 330Sstevel@tonic-gate #include <sys/errno.h> 340Sstevel@tonic-gate #include <sys/modctl.h> 35*8906SEric.Saxe@Sun.COM #include <sys/callb.h> /* callback registration for cpu_deep_idle */ 360Sstevel@tonic-gate #include <sys/conf.h> /* driver flags and functions */ 370Sstevel@tonic-gate #include <sys/open.h> /* OTYP_CHR definition */ 380Sstevel@tonic-gate #include <sys/stat.h> /* S_IFCHR definition */ 390Sstevel@tonic-gate #include <sys/pathname.h> /* name -> dev_info xlation */ 400Sstevel@tonic-gate #include <sys/kmem.h> /* memory alloc stuff */ 410Sstevel@tonic-gate #include <sys/debug.h> 420Sstevel@tonic-gate #include <sys/pm.h> 430Sstevel@tonic-gate #include <sys/ddi.h> 440Sstevel@tonic-gate #include <sys/sunddi.h> 450Sstevel@tonic-gate #include <sys/epm.h> 460Sstevel@tonic-gate #include <sys/vfs.h> 470Sstevel@tonic-gate #include <sys/mode.h> 480Sstevel@tonic-gate #include <sys/mkdev.h> 490Sstevel@tonic-gate #include <sys/promif.h> 500Sstevel@tonic-gate #include <sys/consdev.h> 510Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 520Sstevel@tonic-gate #include <sys/poll.h> 530Sstevel@tonic-gate #include <sys/note.h> 540Sstevel@tonic-gate #include <sys/taskq.h> 550Sstevel@tonic-gate #include <sys/policy.h> 56*8906SEric.Saxe@Sun.COM #include <sys/cpu_pm.h> 570Sstevel@tonic-gate 580Sstevel@tonic-gate /* 595295Srandyf * Minor number is instance<<8 + clone minor from range 1-254; (0 reserved 605295Srandyf * for "original") 610Sstevel@tonic-gate */ 625295Srandyf #define PM_MINOR_TO_CLONE(minor) ((minor) & (PM_MAX_CLONE -1)) 630Sstevel@tonic-gate 640Sstevel@tonic-gate #define PM_NUMCMPTS(dip) (DEVI(dip)->devi_pm_num_components) 650Sstevel@tonic-gate #define PM_IS_CFB(dip) (DEVI(dip)->devi_pm_flags & PMC_CONSOLE_FB) 660Sstevel@tonic-gate #define PM_MAJOR(dip) ddi_driver_major(dip) 670Sstevel@tonic-gate #define PM_RELE(dip) ddi_release_devi(dip) 680Sstevel@tonic-gate 690Sstevel@tonic-gate #define PM_IDLEDOWN_TIME 10 705295Srandyf #define MAXSMBIOSSTRLEN 64 /* from SMBIOS spec */ 715295Srandyf #define MAXCOPYBUF (MAXSMBIOSSTRLEN + 1) 720Sstevel@tonic-gate 730Sstevel@tonic-gate extern kmutex_t pm_scan_lock; /* protects autopm_enable, pm_scans_disabled */ 740Sstevel@tonic-gate extern kmutex_t pm_clone_lock; /* protects pm_clones array */ 750Sstevel@tonic-gate extern int autopm_enabled; 763028Smh27603 extern pm_cpupm_t cpupm; 77*8906SEric.Saxe@Sun.COM extern pm_cpupm_t cpupm_default_mode; 783028Smh27603 extern int pm_default_idle_threshold; 793028Smh27603 extern int pm_system_idle_threshold; 803028Smh27603 extern int pm_cpu_idle_threshold; 810Sstevel@tonic-gate extern kcondvar_t pm_clones_cv[PM_MAX_CLONE]; 820Sstevel@tonic-gate extern uint_t pm_poll_cnt[PM_MAX_CLONE]; 835295Srandyf extern int autoS3_enabled; 845295Srandyf extern void pm_record_thresh(pm_thresh_rec_t *); 855295Srandyf extern void pm_register_watcher(int, dev_info_t *); 865295Srandyf extern int pm_get_current_power(dev_info_t *, int, int *); 875295Srandyf extern int pm_interest_registered(int); 885295Srandyf extern void pm_all_to_default_thresholds(void); 895295Srandyf extern int pm_current_threshold(dev_info_t *, int, int *); 905295Srandyf extern void pm_deregister_watcher(int, dev_info_t *); 915295Srandyf extern void pm_unrecord_threshold(char *); 925295Srandyf extern int pm_S3_enabled; 935295Srandyf extern int pm_ppm_searchlist(pm_searchargs_t *); 945295Srandyf extern psce_t *pm_psc_clone_to_direct(int); 955295Srandyf extern psce_t *pm_psc_clone_to_interest(int); 960Sstevel@tonic-gate 970Sstevel@tonic-gate /* 980Sstevel@tonic-gate * The soft state of the power manager. Since there will only 990Sstevel@tonic-gate * one of these, just reference it through a static pointer. 1000Sstevel@tonic-gate */ 1010Sstevel@tonic-gate static struct pmstate { 1020Sstevel@tonic-gate dev_info_t *pm_dip; /* ptr to our dev_info node */ 1030Sstevel@tonic-gate int pm_instance; /* for ddi_get_instance() */ 1040Sstevel@tonic-gate timeout_id_t pm_idledown_id; /* pm idledown timeout id */ 1050Sstevel@tonic-gate uchar_t pm_clones[PM_MAX_CLONE]; /* uniqueify multiple opens */ 1060Sstevel@tonic-gate struct cred *pm_cred[PM_MAX_CLONE]; /* cred for each unique open */ 1070Sstevel@tonic-gate } pm_state = { NULL, -1, (timeout_id_t)0 }; 1080Sstevel@tonic-gate typedef struct pmstate *pm_state_t; 1090Sstevel@tonic-gate static pm_state_t pmstp = &pm_state; 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate static int pm_open(dev_t *, int, int, cred_t *); 1120Sstevel@tonic-gate static int pm_close(dev_t, int, int, cred_t *); 1130Sstevel@tonic-gate static int pm_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 1140Sstevel@tonic-gate static int pm_chpoll(dev_t, short, int, short *, struct pollhead **); 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate static struct cb_ops pm_cb_ops = { 1170Sstevel@tonic-gate pm_open, /* open */ 1180Sstevel@tonic-gate pm_close, /* close */ 1190Sstevel@tonic-gate nodev, /* strategy */ 1200Sstevel@tonic-gate nodev, /* print */ 1210Sstevel@tonic-gate nodev, /* dump */ 1220Sstevel@tonic-gate nodev, /* read */ 1230Sstevel@tonic-gate nodev, /* write */ 1240Sstevel@tonic-gate pm_ioctl, /* ioctl */ 1250Sstevel@tonic-gate nodev, /* devmap */ 1260Sstevel@tonic-gate nodev, /* mmap */ 1270Sstevel@tonic-gate nodev, /* segmap */ 1280Sstevel@tonic-gate pm_chpoll, /* poll */ 1290Sstevel@tonic-gate ddi_prop_op, /* prop_op */ 1300Sstevel@tonic-gate NULL, /* streamtab */ 1310Sstevel@tonic-gate D_NEW | D_MP /* driver compatibility flag */ 1320Sstevel@tonic-gate }; 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate static int pm_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 1350Sstevel@tonic-gate void **result); 1360Sstevel@tonic-gate static int pm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 1370Sstevel@tonic-gate static int pm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 1380Sstevel@tonic-gate 1390Sstevel@tonic-gate static struct dev_ops pm_ops = { 1400Sstevel@tonic-gate DEVO_REV, /* devo_rev */ 1410Sstevel@tonic-gate 0, /* refcnt */ 1420Sstevel@tonic-gate pm_getinfo, /* info */ 1430Sstevel@tonic-gate nulldev, /* identify */ 1440Sstevel@tonic-gate nulldev, /* probe */ 1450Sstevel@tonic-gate pm_attach, /* attach */ 1460Sstevel@tonic-gate pm_detach, /* detach */ 1470Sstevel@tonic-gate nodev, /* reset */ 1480Sstevel@tonic-gate &pm_cb_ops, /* driver operations */ 1490Sstevel@tonic-gate NULL, /* bus operations */ 1507656SSherry.Moore@Sun.COM NULL, /* power */ 1517656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */ 1520Sstevel@tonic-gate }; 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate static struct modldrv modldrv = { 1550Sstevel@tonic-gate &mod_driverops, 1567656SSherry.Moore@Sun.COM "power management driver", 1570Sstevel@tonic-gate &pm_ops 1580Sstevel@tonic-gate }; 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate static struct modlinkage modlinkage = { 1610Sstevel@tonic-gate MODREV_1, &modldrv, 0 1620Sstevel@tonic-gate }; 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate /* Local functions */ 1650Sstevel@tonic-gate #ifdef DEBUG 1660Sstevel@tonic-gate static int print_info(dev_info_t *, void *); 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate #endif 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate int 1710Sstevel@tonic-gate _init(void) 1720Sstevel@tonic-gate { 1730Sstevel@tonic-gate return (mod_install(&modlinkage)); 1740Sstevel@tonic-gate } 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate int 1770Sstevel@tonic-gate _fini(void) 1780Sstevel@tonic-gate { 1790Sstevel@tonic-gate return (mod_remove(&modlinkage)); 1800Sstevel@tonic-gate } 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate int 1830Sstevel@tonic-gate _info(struct modinfo *modinfop) 1840Sstevel@tonic-gate { 1850Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1860Sstevel@tonic-gate } 1870Sstevel@tonic-gate 1880Sstevel@tonic-gate static int 1890Sstevel@tonic-gate pm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 1900Sstevel@tonic-gate { 1910Sstevel@tonic-gate int i; 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate switch (cmd) { 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate case DDI_ATTACH: 1960Sstevel@tonic-gate if (pmstp->pm_instance != -1) /* Only allow one instance */ 1970Sstevel@tonic-gate return (DDI_FAILURE); 1980Sstevel@tonic-gate pmstp->pm_instance = ddi_get_instance(dip); 1990Sstevel@tonic-gate if (ddi_create_minor_node(dip, "pm", S_IFCHR, 2000Sstevel@tonic-gate (pmstp->pm_instance << 8) + 0, 2015295Srandyf DDI_PSEUDO, 0) != DDI_SUCCESS) { 2020Sstevel@tonic-gate return (DDI_FAILURE); 2030Sstevel@tonic-gate } 2040Sstevel@tonic-gate pmstp->pm_dip = dip; /* pm_init and getinfo depend on it */ 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate for (i = 0; i < PM_MAX_CLONE; i++) 2070Sstevel@tonic-gate cv_init(&pm_clones_cv[i], NULL, CV_DEFAULT, NULL); 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate ddi_report_dev(dip); 2100Sstevel@tonic-gate return (DDI_SUCCESS); 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate default: 2130Sstevel@tonic-gate return (DDI_FAILURE); 2140Sstevel@tonic-gate } 2150Sstevel@tonic-gate } 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate /* ARGSUSED */ 2180Sstevel@tonic-gate static int 2190Sstevel@tonic-gate pm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2200Sstevel@tonic-gate { 2210Sstevel@tonic-gate int i; 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate switch (cmd) { 2240Sstevel@tonic-gate case DDI_DETACH: 2250Sstevel@tonic-gate /* 2260Sstevel@tonic-gate * Don't detach while idledown timeout is pending. Note that 2270Sstevel@tonic-gate * we already know we're not in pm_ioctl() due to framework 2280Sstevel@tonic-gate * synchronization, so this is a sufficient test 2290Sstevel@tonic-gate */ 2300Sstevel@tonic-gate if (pmstp->pm_idledown_id) 2310Sstevel@tonic-gate return (DDI_FAILURE); 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate for (i = 0; i < PM_MAX_CLONE; i++) 2340Sstevel@tonic-gate cv_destroy(&pm_clones_cv[i]); 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 2370Sstevel@tonic-gate pmstp->pm_instance = -1; 2380Sstevel@tonic-gate return (DDI_SUCCESS); 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate default: 2410Sstevel@tonic-gate return (DDI_FAILURE); 2420Sstevel@tonic-gate } 2430Sstevel@tonic-gate } 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate static int 2460Sstevel@tonic-gate pm_close_direct_pm_device(dev_info_t *dip, void *arg) 2470Sstevel@tonic-gate { 2480Sstevel@tonic-gate int clone; 2490Sstevel@tonic-gate char *pathbuf; 2500Sstevel@tonic-gate pm_info_t *info = PM_GET_PM_INFO(dip); 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate clone = *((int *)arg); 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate if (!info) 2550Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 2580Sstevel@tonic-gate PM_LOCK_DIP(dip); 2590Sstevel@tonic-gate if (clone == info->pmi_clone) { 2600Sstevel@tonic-gate PMD(PMD_CLOSE, ("pm_close: found %s@%s(%s#%d)\n", 2610Sstevel@tonic-gate PM_DEVICE(dip))) 2620Sstevel@tonic-gate ASSERT(PM_ISDIRECT(dip)); 2630Sstevel@tonic-gate info->pmi_dev_pm_state &= ~PM_DIRECT; 2640Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 2650Sstevel@tonic-gate pm_proceed(dip, PMP_RELEASE, -1, -1); 2660Sstevel@tonic-gate /* Bring ourselves up if there is a keeper that is up */ 2670Sstevel@tonic-gate (void) ddi_pathname(dip, pathbuf); 2680Sstevel@tonic-gate pm_dispatch_to_dep_thread(PM_DEP_WK_BRINGUP_SELF, NULL, 2690Sstevel@tonic-gate pathbuf, PM_DEP_NOWAIT, NULL, 0); 2700Sstevel@tonic-gate PM_LOCK_DIP(dip); 2710Sstevel@tonic-gate info->pmi_clone = 0; 2720Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 2730Sstevel@tonic-gate } else { 2740Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 2750Sstevel@tonic-gate } 2760Sstevel@tonic-gate kmem_free(pathbuf, MAXPATHLEN); 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate /* restart autopm on device released from direct pm */ 2790Sstevel@tonic-gate pm_rescan(dip); 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate #define PM_REQ 1 2850Sstevel@tonic-gate #define NOSTRUCT 2 2860Sstevel@tonic-gate #define DIP 3 2870Sstevel@tonic-gate #define NODIP 4 2880Sstevel@tonic-gate #define NODEP 5 2890Sstevel@tonic-gate #define DEP 6 2900Sstevel@tonic-gate #define PM_PSC 7 2915295Srandyf #define PM_SRCH 8 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate #define CHECKPERMS 0x001 2940Sstevel@tonic-gate #define SU 0x002 2950Sstevel@tonic-gate #define SG 0x004 2960Sstevel@tonic-gate #define OWNER 0x008 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate #define INWHO 0x001 2990Sstevel@tonic-gate #define INDATAINT 0x002 3000Sstevel@tonic-gate #define INDATASTRING 0x004 3010Sstevel@tonic-gate #define INDEP 0x008 3020Sstevel@tonic-gate #define INDATAOUT 0x010 3030Sstevel@tonic-gate #define INDATA (INDATAOUT | INDATAINT | INDATASTRING | INDEP) 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate struct pm_cmd_info { 3060Sstevel@tonic-gate int cmd; /* command code */ 3070Sstevel@tonic-gate char *name; /* printable string */ 3080Sstevel@tonic-gate int supported; /* true if still supported */ 3090Sstevel@tonic-gate int str_type; /* PM_REQ or NOSTRUCT */ 3100Sstevel@tonic-gate int inargs; /* INWHO, INDATAINT, INDATASTRING, INDEP, */ 3110Sstevel@tonic-gate /* INDATAOUT */ 3120Sstevel@tonic-gate int diptype; /* DIP or NODIP */ 3130Sstevel@tonic-gate int deptype; /* DEP or NODEP */ 3140Sstevel@tonic-gate int permission; /* SU, GU, or CHECKPERMS */ 3150Sstevel@tonic-gate }; 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate #ifdef DEBUG 3180Sstevel@tonic-gate char *pm_cmd_string; 3190Sstevel@tonic-gate int pm_cmd; 3200Sstevel@tonic-gate #endif 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate /* 3230Sstevel@tonic-gate * Returns true if permission granted by credentials 3240Sstevel@tonic-gate */ 3250Sstevel@tonic-gate static int 3260Sstevel@tonic-gate pm_perms(int perm, cred_t *cr) 3270Sstevel@tonic-gate { 3280Sstevel@tonic-gate if (perm == 0) /* no restrictions */ 3290Sstevel@tonic-gate return (1); 3300Sstevel@tonic-gate if (perm == CHECKPERMS) /* ok for now (is checked later) */ 3310Sstevel@tonic-gate return (1); 3320Sstevel@tonic-gate if ((perm & SU) && secpolicy_power_mgmt(cr) == 0) /* privileged? */ 3330Sstevel@tonic-gate return (1); 3340Sstevel@tonic-gate if ((perm & SG) && (crgetgid(cr) == 0)) /* group 0 is ok */ 3350Sstevel@tonic-gate return (1); 3360Sstevel@tonic-gate return (0); 3370Sstevel@tonic-gate } 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate #ifdef DEBUG 3400Sstevel@tonic-gate static int 3410Sstevel@tonic-gate print_info(dev_info_t *dip, void *arg) 3420Sstevel@tonic-gate { 3430Sstevel@tonic-gate _NOTE(ARGUNUSED(arg)) 3440Sstevel@tonic-gate pm_info_t *info; 3450Sstevel@tonic-gate int i, j; 3460Sstevel@tonic-gate struct pm_component *cp; 3470Sstevel@tonic-gate extern int pm_cur_power(pm_component_t *cp); 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate info = PM_GET_PM_INFO(dip); 3500Sstevel@tonic-gate if (!info) 3510Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 3520Sstevel@tonic-gate cmn_err(CE_CONT, "pm_info for %s\n", ddi_node_name(dip)); 3530Sstevel@tonic-gate for (i = 0; i < PM_NUMCMPTS(dip); i++) { 3540Sstevel@tonic-gate cp = PM_CP(dip, i); 3550Sstevel@tonic-gate cmn_err(CE_CONT, "\tThresholds[%d] =", i); 3560Sstevel@tonic-gate for (j = 0; j < cp->pmc_comp.pmc_numlevels; j++) 3570Sstevel@tonic-gate cmn_err(CE_CONT, " %d", cp->pmc_comp.pmc_thresh[i]); 3580Sstevel@tonic-gate cmn_err(CE_CONT, "\n"); 3590Sstevel@tonic-gate cmn_err(CE_CONT, "\tCurrent power[%d] = %d\n", i, 3600Sstevel@tonic-gate pm_cur_power(cp)); 3610Sstevel@tonic-gate } 3620Sstevel@tonic-gate if (PM_ISDIRECT(dip)) 3630Sstevel@tonic-gate cmn_err(CE_CONT, "\tDirect power management\n"); 3640Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 3650Sstevel@tonic-gate } 3660Sstevel@tonic-gate #endif 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate /* 3690Sstevel@tonic-gate * command, name, supported, str_type, inargs, diptype, deptype, permission 3700Sstevel@tonic-gate */ 3710Sstevel@tonic-gate static struct pm_cmd_info pmci[] = { 3720Sstevel@tonic-gate {PM_SCHEDULE, "PM_SCHEDULE", 0}, 3730Sstevel@tonic-gate {PM_GET_IDLE_TIME, "PM_GET_IDLE_TIME", 0}, 3740Sstevel@tonic-gate {PM_GET_NUM_CMPTS, "PM_GET_NUM_CMPTS", 0}, 3750Sstevel@tonic-gate {PM_GET_THRESHOLD, "PM_GET_THRESHOLD", 0}, 3760Sstevel@tonic-gate {PM_SET_THRESHOLD, "PM_SET_THRESHOLD", 0}, 3770Sstevel@tonic-gate {PM_GET_NORM_PWR, "PM_GET_NORM_PWR", 0}, 3780Sstevel@tonic-gate {PM_SET_CUR_PWR, "PM_SET_CUR_PWR", 0}, 3790Sstevel@tonic-gate {PM_GET_CUR_PWR, "PM_GET_CUR_PWR", 0}, 3800Sstevel@tonic-gate {PM_GET_NUM_DEPS, "PM_GET_NUM_DEPS", 0}, 3810Sstevel@tonic-gate {PM_GET_DEP, "PM_GET_DEP", 0}, 3820Sstevel@tonic-gate {PM_ADD_DEP, "PM_ADD_DEP", 0}, 3830Sstevel@tonic-gate {PM_REM_DEP, "PM_REM_DEP", 0}, 3840Sstevel@tonic-gate {PM_REM_DEVICE, "PM_REM_DEVICE", 0}, 3850Sstevel@tonic-gate {PM_REM_DEVICES, "PM_REM_DEVICES", 0}, 3860Sstevel@tonic-gate {PM_REPARSE_PM_PROPS, "PM_REPARSE_PM_PROPS", 1, PM_REQ, INWHO, DIP, 3870Sstevel@tonic-gate NODEP}, 3880Sstevel@tonic-gate {PM_DISABLE_AUTOPM, "PM_DISABLE_AUTOPM", 0}, 3890Sstevel@tonic-gate {PM_REENABLE_AUTOPM, "PM_REENABLE_AUTOPM", 0}, 3900Sstevel@tonic-gate {PM_SET_NORM_PWR, "PM_SET_NORM_PWR", 0 }, 3910Sstevel@tonic-gate {PM_SET_DEVICE_THRESHOLD, "PM_SET_DEVICE_THRESHOLD", 1, PM_REQ, 3920Sstevel@tonic-gate INWHO, NODIP, NODEP, SU}, 3930Sstevel@tonic-gate {PM_GET_SYSTEM_THRESHOLD, "PM_GET_SYSTEM_THRESHOLD", 1, NOSTRUCT}, 3940Sstevel@tonic-gate {PM_GET_DEFAULT_SYSTEM_THRESHOLD, "PM_GET_DEFAULT_SYSTEM_THRESHOLD", 3950Sstevel@tonic-gate 1, NOSTRUCT}, 3960Sstevel@tonic-gate {PM_SET_SYSTEM_THRESHOLD, "PM_SET_SYSTEM_THRESHOLD", 1, NOSTRUCT, 3970Sstevel@tonic-gate 0, 0, 0, SU}, 3980Sstevel@tonic-gate {PM_START_PM, "PM_START_PM", 1, NOSTRUCT, 0, 0, 0, SU}, 3990Sstevel@tonic-gate {PM_STOP_PM, "PM_STOP_PM", 1, NOSTRUCT, 0, 0, 0, SU}, 4000Sstevel@tonic-gate {PM_RESET_PM, "PM_RESET_PM", 1, NOSTRUCT, 0, 0, 0, SU}, 4010Sstevel@tonic-gate {PM_GET_STATS, "PM_GET_STATS", 1, PM_REQ, INWHO | INDATAOUT, 4020Sstevel@tonic-gate DIP, NODEP}, 4030Sstevel@tonic-gate {PM_GET_DEVICE_THRESHOLD, "PM_GET_DEVICE_THRESHOLD", 1, PM_REQ, INWHO, 4040Sstevel@tonic-gate DIP, NODEP}, 4050Sstevel@tonic-gate {PM_GET_POWER_NAME, "PM_GET_POWER_NAME", 1, PM_REQ, INWHO | INDATAOUT, 4060Sstevel@tonic-gate DIP, NODEP}, 4070Sstevel@tonic-gate {PM_GET_POWER_LEVELS, "PM_GET_POWER_LEVELS", 1, PM_REQ, 4080Sstevel@tonic-gate INWHO | INDATAOUT, DIP, NODEP}, 4090Sstevel@tonic-gate {PM_GET_NUM_COMPONENTS, "PM_GET_NUM_COMPONENTS", 1, PM_REQ, INWHO, 4100Sstevel@tonic-gate DIP, NODEP}, 4110Sstevel@tonic-gate {PM_GET_COMPONENT_NAME, "PM_GET_COMPONENT_NAME", 1, PM_REQ, 4120Sstevel@tonic-gate INWHO | INDATAOUT, DIP, NODEP}, 4130Sstevel@tonic-gate {PM_GET_NUM_POWER_LEVELS, "PM_GET_NUM_POWER_LEVELS", 1, PM_REQ, INWHO, 4140Sstevel@tonic-gate DIP, NODEP}, 4150Sstevel@tonic-gate {PM_GET_STATE_CHANGE, "PM_GET_STATE_CHANGE", 1, PM_PSC}, 4160Sstevel@tonic-gate {PM_GET_STATE_CHANGE_WAIT, "PM_GET_STATE_CHANGE_WAIT", 1, PM_PSC}, 4170Sstevel@tonic-gate {PM_DIRECT_PM, "PM_DIRECT_PM", 1, PM_REQ, INWHO, DIP, NODEP, 4180Sstevel@tonic-gate (SU | SG)}, 4190Sstevel@tonic-gate {PM_RELEASE_DIRECT_PM, "PM_RELEASE_DIRECT_PM", 1, PM_REQ, INWHO, 4200Sstevel@tonic-gate DIP, NODEP}, 4210Sstevel@tonic-gate {PM_DIRECT_NOTIFY, "PM_DIRECT_NOTIFY", 1, PM_PSC}, 4220Sstevel@tonic-gate {PM_DIRECT_NOTIFY_WAIT, "PM_DIRECT_NOTIFY_WAIT", 1, PM_PSC}, 4230Sstevel@tonic-gate {PM_RESET_DEVICE_THRESHOLD, "PM_RESET_DEVICE_THRESHOLD", 1, PM_REQ, 4240Sstevel@tonic-gate INWHO, DIP, NODEP, SU}, 4250Sstevel@tonic-gate {PM_GET_PM_STATE, "PM_GET_PM_STATE", 1, NOSTRUCT}, 4265295Srandyf {PM_GET_AUTOS3_STATE, "PM_GET_AUTOS3_STATE", 1, NOSTRUCT}, 4275295Srandyf {PM_GET_S3_SUPPORT_STATE, "PM_GET_S3_SUPPORT_STATE", 1, NOSTRUCT}, 4280Sstevel@tonic-gate {PM_GET_DEVICE_TYPE, "PM_GET_DEVICE_TYPE", 1, PM_REQ, INWHO, 4290Sstevel@tonic-gate DIP, NODEP}, 4300Sstevel@tonic-gate {PM_SET_COMPONENT_THRESHOLDS, "PM_SET_COMPONENT_THRESHOLDS", 1, PM_REQ, 4310Sstevel@tonic-gate INWHO | INDATAINT, NODIP, NODEP, SU}, 4320Sstevel@tonic-gate {PM_GET_COMPONENT_THRESHOLDS, "PM_GET_COMPONENT_THRESHOLDS", 1, PM_REQ, 4330Sstevel@tonic-gate INWHO | INDATAOUT, DIP, NODEP}, 4340Sstevel@tonic-gate {PM_IDLE_DOWN, "PM_IDLE_DOWN", 1, NOSTRUCT, 0, 0, 0, SU}, 4350Sstevel@tonic-gate {PM_GET_DEVICE_THRESHOLD_BASIS, "PM_GET_DEVICE_THRESHOLD_BASIS", 1, 4360Sstevel@tonic-gate PM_REQ, INWHO, DIP, NODEP}, 4370Sstevel@tonic-gate {PM_SET_CURRENT_POWER, "PM_SET_CURRENT_POWER", 1, PM_REQ, INWHO, DIP, 4380Sstevel@tonic-gate NODEP}, 4390Sstevel@tonic-gate {PM_GET_CURRENT_POWER, "PM_GET_CURRENT_POWER", 1, PM_REQ, INWHO, DIP, 4400Sstevel@tonic-gate NODEP}, 4410Sstevel@tonic-gate {PM_GET_FULL_POWER, "PM_GET_FULL_POWER", 1, PM_REQ, INWHO, DIP, 4420Sstevel@tonic-gate NODEP}, 4430Sstevel@tonic-gate {PM_ADD_DEPENDENT, "PM_ADD_DEPENDENT", 1, PM_REQ, INWHO | INDATASTRING, 4440Sstevel@tonic-gate DIP, DEP, SU}, 4450Sstevel@tonic-gate {PM_GET_TIME_IDLE, "PM_GET_TIME_IDLE", 1, PM_REQ, INWHO, DIP, NODEP}, 4460Sstevel@tonic-gate {PM_ADD_DEPENDENT_PROPERTY, "PM_ADD_DEPENDENT_PROPERTY", 1, PM_REQ, 4470Sstevel@tonic-gate INWHO | INDATASTRING, NODIP, DEP, SU}, 4483028Smh27603 {PM_START_CPUPM, "PM_START_CPUPM", 1, NOSTRUCT, 0, 0, 0, SU}, 449*8906SEric.Saxe@Sun.COM {PM_START_CPUPM_EV, "PM_START_CPUPM_EV", 1, NOSTRUCT, 0, 450*8906SEric.Saxe@Sun.COM 0, 0, SU}, 451*8906SEric.Saxe@Sun.COM {PM_START_CPUPM_POLL, "PM_START_CPUPM_POLL", 1, NOSTRUCT, 0, 452*8906SEric.Saxe@Sun.COM 0, 0, SU}, 4533028Smh27603 {PM_STOP_CPUPM, "PM_STOP_CPUPM", 1, NOSTRUCT, 0, 0, 0, SU}, 4543028Smh27603 {PM_GET_CPU_THRESHOLD, "PM_GET_CPU_THRESHOLD", 1, NOSTRUCT}, 4553028Smh27603 {PM_SET_CPU_THRESHOLD, "PM_SET_CPU_THRESHOLD", 1, NOSTRUCT, 4563028Smh27603 0, 0, 0, SU}, 4573028Smh27603 {PM_GET_CPUPM_STATE, "PM_GET_CPUPM_STATE", 1, NOSTRUCT}, 4585295Srandyf {PM_START_AUTOS3, "PM_START_AUTOS3", 1, NOSTRUCT, 0, 0, 0, SU}, 4595295Srandyf {PM_STOP_AUTOS3, "PM_STOP_AUTOS3", 1, NOSTRUCT, 0, 0, 0, SU}, 4605295Srandyf {PM_ENABLE_S3, "PM_ENABLE_S3", 1, NOSTRUCT, 0, 0, 0, SU}, 4615295Srandyf {PM_DISABLE_S3, "PM_DISABLE_S3", 1, NOSTRUCT, 0, 0, 0, SU}, 4625295Srandyf {PM_ENTER_S3, "PM_ENTER_S3", 1, NOSTRUCT, 0, 0, 0, SU}, 4635295Srandyf {PM_SEARCH_LIST, "PM_SEARCH_LIST", 1, PM_SRCH, 0, 0, 0, SU}, 4645295Srandyf {PM_GET_CMD_NAME, "PM_GET_CMD_NAME", 1, PM_REQ, INDATAOUT, NODIP, 4655295Srandyf NODEP, 0}, 466*8906SEric.Saxe@Sun.COM {PM_DISABLE_CPU_DEEP_IDLE, "PM_DISABLE_CPU_DEEP_IDLE", 1, NOSTRUCT, 0, 467*8906SEric.Saxe@Sun.COM 0, 0, SU}, 468*8906SEric.Saxe@Sun.COM {PM_ENABLE_CPU_DEEP_IDLE, "PM_START_CPU_DEEP_IDLE", 1, NOSTRUCT, 0, 469*8906SEric.Saxe@Sun.COM 0, 0, SU}, 470*8906SEric.Saxe@Sun.COM {PM_DEFAULT_CPU_DEEP_IDLE, "PM_DFLT_CPU_DEEP_IDLE", 1, NOSTRUCT, 0, 471*8906SEric.Saxe@Sun.COM 0, 0, SU}, 4720Sstevel@tonic-gate {0, NULL} 4730Sstevel@tonic-gate }; 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate struct pm_cmd_info * 4760Sstevel@tonic-gate pc_info(int cmd) 4770Sstevel@tonic-gate { 4780Sstevel@tonic-gate struct pm_cmd_info *pcip; 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate for (pcip = pmci; pcip->name; pcip++) { 4810Sstevel@tonic-gate if (cmd == pcip->cmd) 4820Sstevel@tonic-gate return (pcip); 4830Sstevel@tonic-gate } 4840Sstevel@tonic-gate return (NULL); 4850Sstevel@tonic-gate } 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate static char * 4880Sstevel@tonic-gate pm_decode_cmd(int cmd) 4890Sstevel@tonic-gate { 4900Sstevel@tonic-gate static char invbuf[64]; 4910Sstevel@tonic-gate struct pm_cmd_info *pcip = pc_info(cmd); 4920Sstevel@tonic-gate if (pcip != NULL) 4930Sstevel@tonic-gate return (pcip->name); 4940Sstevel@tonic-gate (void) sprintf(invbuf, "ioctl: invalid command %d\n", cmd); 4950Sstevel@tonic-gate return (invbuf); 4960Sstevel@tonic-gate } 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate /* 4990Sstevel@tonic-gate * Allocate scan resource, create taskq, then dispatch scan, 5000Sstevel@tonic-gate * called only if autopm is enabled. 5010Sstevel@tonic-gate */ 5020Sstevel@tonic-gate int 5030Sstevel@tonic-gate pm_start_pm_walk(dev_info_t *dip, void *arg) 5040Sstevel@tonic-gate { 5053028Smh27603 int cmd = *((int *)arg); 5063839Skchow #ifdef PMDDEBUG 5073028Smh27603 char *cmdstr = pm_decode_cmd(cmd); 5083839Skchow #endif 5090Sstevel@tonic-gate 5100Sstevel@tonic-gate if (!PM_GET_PM_INFO(dip) || PM_ISBC(dip)) 5110Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 5120Sstevel@tonic-gate 5133028Smh27603 switch (cmd) { 5143028Smh27603 case PM_START_CPUPM: 515*8906SEric.Saxe@Sun.COM case PM_START_CPUPM_POLL: 5163028Smh27603 if (!PM_ISCPU(dip)) 5173028Smh27603 return (DDI_WALK_CONTINUE); 5183028Smh27603 mutex_enter(&pm_scan_lock); 519*8906SEric.Saxe@Sun.COM if (!PM_CPUPM_DISABLED && !PM_EVENT_CPUPM) 5203028Smh27603 pm_scan_init(dip); 5213028Smh27603 mutex_exit(&pm_scan_lock); 5223028Smh27603 break; 5233028Smh27603 case PM_START_PM: 5243028Smh27603 mutex_enter(&pm_scan_lock); 525*8906SEric.Saxe@Sun.COM if (PM_ISCPU(dip) && (PM_CPUPM_DISABLED || PM_EVENT_CPUPM)) { 5263028Smh27603 mutex_exit(&pm_scan_lock); 5273028Smh27603 return (DDI_WALK_CONTINUE); 5283028Smh27603 } 5293028Smh27603 if (autopm_enabled) 5303028Smh27603 pm_scan_init(dip); 5313028Smh27603 mutex_exit(&pm_scan_lock); 5323028Smh27603 break; 5333028Smh27603 } 5340Sstevel@tonic-gate 5350Sstevel@tonic-gate /* 5360Sstevel@tonic-gate * Start doing pm on device: ensure pm_scan data structure initiated, 5373028Smh27603 * no need to guarantee a successful scan run. 5380Sstevel@tonic-gate */ 5390Sstevel@tonic-gate PMD(PMD_SCAN | PMD_IOCTL, ("ioctl: %s: scan %s@%s(%s#%d)\n", cmdstr, 5400Sstevel@tonic-gate PM_DEVICE(dip))) 5410Sstevel@tonic-gate pm_rescan(dip); 5420Sstevel@tonic-gate 5430Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 5440Sstevel@tonic-gate } 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate /* 5470Sstevel@tonic-gate * Bring devices to full power level, then stop scan 5480Sstevel@tonic-gate */ 5490Sstevel@tonic-gate int 5500Sstevel@tonic-gate pm_stop_pm_walk(dev_info_t *dip, void *arg) 5510Sstevel@tonic-gate { 5520Sstevel@tonic-gate pm_info_t *info = PM_GET_PM_INFO(dip); 5533028Smh27603 int cmd = *((int *)arg); 5543839Skchow #ifdef PMDDEBUG 5553028Smh27603 char *cmdstr = pm_decode_cmd(cmd); 5563839Skchow #endif 5570Sstevel@tonic-gate 5580Sstevel@tonic-gate if (!info) 5590Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 5603028Smh27603 5613028Smh27603 switch (cmd) { 5623028Smh27603 case PM_STOP_PM: 5633028Smh27603 /* 5643028Smh27603 * If CPU devices are being managed independently, then don't 5653028Smh27603 * stop them as part of PM_STOP_PM. Only stop them as part of 5663028Smh27603 * PM_STOP_CPUPM and PM_RESET_PM. 5673028Smh27603 */ 568*8906SEric.Saxe@Sun.COM if (PM_ISCPU(dip) && PM_POLLING_CPUPM) 5693028Smh27603 return (DDI_WALK_CONTINUE); 5703028Smh27603 break; 5713028Smh27603 case PM_STOP_CPUPM: 5723028Smh27603 /* 5733028Smh27603 * If stopping CPU devices and this device is not marked 5743028Smh27603 * as a CPU device, then skip. 5753028Smh27603 */ 5763028Smh27603 if (!PM_ISCPU(dip)) 5773028Smh27603 return (DDI_WALK_CONTINUE); 5783028Smh27603 break; 5793028Smh27603 } 5803028Smh27603 5810Sstevel@tonic-gate /* 5820Sstevel@tonic-gate * Stop the current scan, and then bring it back to normal power. 5830Sstevel@tonic-gate */ 5840Sstevel@tonic-gate if (!PM_ISBC(dip)) { 5850Sstevel@tonic-gate PMD(PMD_SCAN | PMD_IOCTL, ("ioctl: %s: stop scan for " 5860Sstevel@tonic-gate "%s@%s(%s#%d)\n", cmdstr, PM_DEVICE(dip))) 5870Sstevel@tonic-gate pm_scan_stop(dip); 5880Sstevel@tonic-gate } 5890Sstevel@tonic-gate 5900Sstevel@tonic-gate if (!PM_ISBC(dip) && !PM_ISDIRECT(dip) && 5910Sstevel@tonic-gate !pm_all_at_normal(dip)) { 5920Sstevel@tonic-gate PM_LOCK_DIP(dip); 5930Sstevel@tonic-gate if (info->pmi_dev_pm_state & PM_DETACHING) { 5940Sstevel@tonic-gate PMD(PMD_ALLNORM, ("ioctl: %s: deferring " 5950Sstevel@tonic-gate "all_to_normal because %s@%s(%s#%d) is detaching\n", 5960Sstevel@tonic-gate cmdstr, PM_DEVICE(dip))) 5970Sstevel@tonic-gate info->pmi_dev_pm_state |= PM_ALLNORM_DEFERRED; 5980Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 5990Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 6000Sstevel@tonic-gate } 6010Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 6020Sstevel@tonic-gate if (pm_all_to_normal(dip, PM_CANBLOCK_FAIL) != DDI_SUCCESS) { 6030Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: could not bring %s@%s" 6040Sstevel@tonic-gate "(%s#%d) to normal\n", cmdstr, PM_DEVICE(dip))) 6050Sstevel@tonic-gate } 6060Sstevel@tonic-gate } 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 6090Sstevel@tonic-gate } 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate static int 6120Sstevel@tonic-gate pm_start_idledown(dev_info_t *dip, void *arg) 6130Sstevel@tonic-gate { 6140Sstevel@tonic-gate int flag = (int)(intptr_t)arg; 6150Sstevel@tonic-gate pm_scan_t *scanp = PM_GET_PM_SCAN(dip); 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate if (!scanp) 6180Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate PM_LOCK_DIP(dip); 6210Sstevel@tonic-gate scanp->ps_idle_down |= flag; 6220Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 6230Sstevel@tonic-gate pm_rescan(dip); 6240Sstevel@tonic-gate 6250Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 6260Sstevel@tonic-gate } 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate /*ARGSUSED*/ 6290Sstevel@tonic-gate static int 6300Sstevel@tonic-gate pm_end_idledown(dev_info_t *dip, void *ignore) 6310Sstevel@tonic-gate { 6320Sstevel@tonic-gate pm_scan_t *scanp = PM_GET_PM_SCAN(dip); 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate if (!scanp) 6350Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate PM_LOCK_DIP(dip); 6380Sstevel@tonic-gate /* 6390Sstevel@tonic-gate * The PMID_TIMERS bits are place holder till idledown expires. 6400Sstevel@tonic-gate * The bits are also the base for regenerating PMID_SCANS bits. 6410Sstevel@tonic-gate * While it's up to scan thread to clear up the PMID_SCANS bits 6420Sstevel@tonic-gate * after each scan run, PMID_TIMERS ensure aggressive scan down 6430Sstevel@tonic-gate * performance throughout the idledown period. 6440Sstevel@tonic-gate */ 6450Sstevel@tonic-gate scanp->ps_idle_down &= ~PMID_TIMERS; 6460Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 6490Sstevel@tonic-gate } 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate /*ARGSUSED*/ 6520Sstevel@tonic-gate static void 6530Sstevel@tonic-gate pm_end_idledown_walk(void *ignore) 6540Sstevel@tonic-gate { 6550Sstevel@tonic-gate PMD(PMD_IDLEDOWN, ("ioctl: end_idledown: idledown_id(%lx) timer is " 6560Sstevel@tonic-gate "off\n", (ulong_t)pmstp->pm_idledown_id)); 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate mutex_enter(&pm_scan_lock); 6590Sstevel@tonic-gate pmstp->pm_idledown_id = 0; 6600Sstevel@tonic-gate mutex_exit(&pm_scan_lock); 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate ddi_walk_devs(ddi_root_node(), pm_end_idledown, NULL); 6630Sstevel@tonic-gate } 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate /* 6660Sstevel@tonic-gate * pm_timeout_idledown - keep idledown effect for 10 seconds. 6670Sstevel@tonic-gate * 6680Sstevel@tonic-gate * Return 0 if another competing caller scheduled idledown timeout, 6690Sstevel@tonic-gate * otherwise, return idledown timeout_id. 6700Sstevel@tonic-gate */ 6710Sstevel@tonic-gate static timeout_id_t 6720Sstevel@tonic-gate pm_timeout_idledown(void) 6730Sstevel@tonic-gate { 6740Sstevel@tonic-gate timeout_id_t to_id; 6750Sstevel@tonic-gate 6760Sstevel@tonic-gate /* 6770Sstevel@tonic-gate * Keep idle-down in effect for either 10 seconds 6780Sstevel@tonic-gate * or length of a scan interval, which ever is greater. 6790Sstevel@tonic-gate */ 6800Sstevel@tonic-gate mutex_enter(&pm_scan_lock); 6810Sstevel@tonic-gate if (pmstp->pm_idledown_id != 0) { 6820Sstevel@tonic-gate to_id = pmstp->pm_idledown_id; 6830Sstevel@tonic-gate pmstp->pm_idledown_id = 0; 6840Sstevel@tonic-gate mutex_exit(&pm_scan_lock); 6850Sstevel@tonic-gate (void) untimeout(to_id); 6860Sstevel@tonic-gate mutex_enter(&pm_scan_lock); 6870Sstevel@tonic-gate if (pmstp->pm_idledown_id != 0) { 6880Sstevel@tonic-gate PMD(PMD_IDLEDOWN, ("ioctl: timeout_idledown: " 6890Sstevel@tonic-gate "another caller got it, idledown_id(%lx)!\n", 6900Sstevel@tonic-gate (ulong_t)pmstp->pm_idledown_id)) 6910Sstevel@tonic-gate mutex_exit(&pm_scan_lock); 6920Sstevel@tonic-gate return (0); 6930Sstevel@tonic-gate } 6940Sstevel@tonic-gate } 6950Sstevel@tonic-gate pmstp->pm_idledown_id = timeout(pm_end_idledown_walk, NULL, 6960Sstevel@tonic-gate PM_IDLEDOWN_TIME * hz); 6970Sstevel@tonic-gate PMD(PMD_IDLEDOWN, ("ioctl: timeout_idledown: idledown_id(%lx)\n", 6980Sstevel@tonic-gate (ulong_t)pmstp->pm_idledown_id)) 6990Sstevel@tonic-gate mutex_exit(&pm_scan_lock); 7000Sstevel@tonic-gate 7010Sstevel@tonic-gate return (pmstp->pm_idledown_id); 7020Sstevel@tonic-gate } 7030Sstevel@tonic-gate 7040Sstevel@tonic-gate static int 7050Sstevel@tonic-gate pm_chpoll(dev_t dev, short events, int anyyet, short *reventsp, 7060Sstevel@tonic-gate struct pollhead **phpp) 7070Sstevel@tonic-gate { 7080Sstevel@tonic-gate extern struct pollhead pm_pollhead; /* common/os/sunpm.c */ 7090Sstevel@tonic-gate int clone; 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate clone = PM_MINOR_TO_CLONE(getminor(dev)); 7120Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: pm_chpoll: clone %d\n", clone)) 7130Sstevel@tonic-gate if ((events & (POLLIN | POLLRDNORM)) && pm_poll_cnt[clone]) { 7140Sstevel@tonic-gate *reventsp |= (POLLIN | POLLRDNORM); 7150Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: pm_chpoll: reventsp set\n")) 7160Sstevel@tonic-gate } else { 7170Sstevel@tonic-gate *reventsp = 0; 7180Sstevel@tonic-gate if (!anyyet) { 7190Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: pm_chpoll: not anyyet\n")) 7200Sstevel@tonic-gate *phpp = &pm_pollhead; 7210Sstevel@tonic-gate } 7220Sstevel@tonic-gate #ifdef DEBUG 7230Sstevel@tonic-gate else { 7240Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: pm_chpoll: anyyet\n")) 7250Sstevel@tonic-gate } 7260Sstevel@tonic-gate #endif 7270Sstevel@tonic-gate } 7280Sstevel@tonic-gate return (0); 7290Sstevel@tonic-gate } 7300Sstevel@tonic-gate 7310Sstevel@tonic-gate /* 7320Sstevel@tonic-gate * called by pm_dicard_entries to free up the memory. It also decrements 7330Sstevel@tonic-gate * pm_poll_cnt, if direct is non zero. 7340Sstevel@tonic-gate */ 7350Sstevel@tonic-gate static void 7360Sstevel@tonic-gate pm_free_entries(psce_t *pscep, int clone, int direct) 7370Sstevel@tonic-gate { 7380Sstevel@tonic-gate pm_state_change_t *p; 7390Sstevel@tonic-gate 7400Sstevel@tonic-gate if (pscep) { 7410Sstevel@tonic-gate p = pscep->psce_out; 7420Sstevel@tonic-gate while (p->size) { 7430Sstevel@tonic-gate if (direct) { 7440Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: discard: " 7450Sstevel@tonic-gate "pm_poll_cnt[%d] is %d before " 7460Sstevel@tonic-gate "ASSERT\n", clone, 7470Sstevel@tonic-gate pm_poll_cnt[clone])) 7480Sstevel@tonic-gate ASSERT(pm_poll_cnt[clone]); 7490Sstevel@tonic-gate pm_poll_cnt[clone]--; 7500Sstevel@tonic-gate } 7510Sstevel@tonic-gate kmem_free(p->physpath, p->size); 7520Sstevel@tonic-gate p->size = 0; 7530Sstevel@tonic-gate if (p == pscep->psce_last) 7540Sstevel@tonic-gate p = pscep->psce_first; 7550Sstevel@tonic-gate else 7560Sstevel@tonic-gate p++; 7570Sstevel@tonic-gate } 7580Sstevel@tonic-gate pscep->psce_out = pscep->psce_first; 7590Sstevel@tonic-gate pscep->psce_in = pscep->psce_first; 7600Sstevel@tonic-gate mutex_exit(&pscep->psce_lock); 7610Sstevel@tonic-gate } 7620Sstevel@tonic-gate } 7630Sstevel@tonic-gate 7640Sstevel@tonic-gate /* 7650Sstevel@tonic-gate * Discard entries for this clone. Calls pm_free_entries to free up memory. 7660Sstevel@tonic-gate */ 7670Sstevel@tonic-gate static void 7680Sstevel@tonic-gate pm_discard_entries(int clone) 7690Sstevel@tonic-gate { 7700Sstevel@tonic-gate psce_t *pscep; 7710Sstevel@tonic-gate int direct = 0; 7720Sstevel@tonic-gate 7730Sstevel@tonic-gate mutex_enter(&pm_clone_lock); 7740Sstevel@tonic-gate if ((pscep = pm_psc_clone_to_direct(clone)) != NULL) 7750Sstevel@tonic-gate direct = 1; 7760Sstevel@tonic-gate pm_free_entries(pscep, clone, direct); 7770Sstevel@tonic-gate pscep = pm_psc_clone_to_interest(clone); 7780Sstevel@tonic-gate pm_free_entries(pscep, clone, 0); 7790Sstevel@tonic-gate mutex_exit(&pm_clone_lock); 7800Sstevel@tonic-gate } 7810Sstevel@tonic-gate 7823028Smh27603 7833028Smh27603 static void 7843028Smh27603 pm_set_idle_threshold(dev_info_t *dip, int thresh, int flag) 7850Sstevel@tonic-gate { 7860Sstevel@tonic-gate if (!PM_ISBC(dip) && !PM_ISDIRECT(dip)) { 7870Sstevel@tonic-gate switch (DEVI(dip)->devi_pm_flags & PMC_THRESH_ALL) { 7880Sstevel@tonic-gate case PMC_DEF_THRESH: 7893028Smh27603 case PMC_CPU_THRESH: 7903028Smh27603 PMD(PMD_IOCTL, ("ioctl: set_idle_threshold: set " 7910Sstevel@tonic-gate "%s@%s(%s#%d) default thresh to 0t%d\n", 7923028Smh27603 PM_DEVICE(dip), thresh)) 7933028Smh27603 pm_set_device_threshold(dip, thresh, flag); 7940Sstevel@tonic-gate break; 7950Sstevel@tonic-gate default: 7960Sstevel@tonic-gate break; 7970Sstevel@tonic-gate } 7980Sstevel@tonic-gate } 7993028Smh27603 } 8000Sstevel@tonic-gate 8013028Smh27603 static int 8023028Smh27603 pm_set_idle_thresh_walk(dev_info_t *dip, void *arg) 8033028Smh27603 { 8043028Smh27603 int cmd = *((int *)arg); 8053028Smh27603 8063028Smh27603 if (!PM_GET_PM_INFO(dip)) 8073028Smh27603 return (DDI_WALK_CONTINUE); 8083028Smh27603 8093028Smh27603 switch (cmd) { 8103028Smh27603 case PM_SET_SYSTEM_THRESHOLD: 8113028Smh27603 if (DEVI(dip)->devi_pm_flags & PMC_CPU_THRESH) 8123028Smh27603 break; 8133028Smh27603 pm_set_idle_threshold(dip, pm_system_idle_threshold, 8143028Smh27603 PMC_DEF_THRESH); 8150Sstevel@tonic-gate pm_rescan(dip); 8163028Smh27603 break; 8173028Smh27603 case PM_SET_CPU_THRESHOLD: 8183028Smh27603 if (!PM_ISCPU(dip)) 8193028Smh27603 break; 8203028Smh27603 pm_set_idle_threshold(dip, pm_cpu_idle_threshold, 8213028Smh27603 PMC_CPU_THRESH); 8223028Smh27603 pm_rescan(dip); 8233028Smh27603 break; 8243028Smh27603 } 8250Sstevel@tonic-gate 8260Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 8270Sstevel@tonic-gate } 8280Sstevel@tonic-gate 8290Sstevel@tonic-gate /*ARGSUSED*/ 8300Sstevel@tonic-gate static int 8310Sstevel@tonic-gate pm_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 8320Sstevel@tonic-gate { 8330Sstevel@tonic-gate dev_t dev; 8340Sstevel@tonic-gate int instance; 8350Sstevel@tonic-gate 8360Sstevel@tonic-gate switch (infocmd) { 8370Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 8380Sstevel@tonic-gate if (pmstp->pm_instance == -1) 8390Sstevel@tonic-gate return (DDI_FAILURE); 8400Sstevel@tonic-gate *result = pmstp->pm_dip; 8410Sstevel@tonic-gate return (DDI_SUCCESS); 8420Sstevel@tonic-gate 8430Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 8440Sstevel@tonic-gate dev = (dev_t)arg; 8450Sstevel@tonic-gate instance = getminor(dev) >> 8; 8460Sstevel@tonic-gate *result = (void *)(uintptr_t)instance; 8470Sstevel@tonic-gate return (DDI_SUCCESS); 8480Sstevel@tonic-gate 8490Sstevel@tonic-gate default: 8500Sstevel@tonic-gate return (DDI_FAILURE); 8510Sstevel@tonic-gate } 8520Sstevel@tonic-gate } 8530Sstevel@tonic-gate 8540Sstevel@tonic-gate 8550Sstevel@tonic-gate /*ARGSUSED1*/ 8560Sstevel@tonic-gate static int 8570Sstevel@tonic-gate pm_open(dev_t *devp, int flag, int otyp, cred_t *cr) 8580Sstevel@tonic-gate { 8590Sstevel@tonic-gate int clone; 8600Sstevel@tonic-gate 8610Sstevel@tonic-gate if (otyp != OTYP_CHR) 8620Sstevel@tonic-gate return (EINVAL); 8630Sstevel@tonic-gate 8640Sstevel@tonic-gate mutex_enter(&pm_clone_lock); 8650Sstevel@tonic-gate for (clone = 1; clone < PM_MAX_CLONE; clone++) 8660Sstevel@tonic-gate if (!pmstp->pm_clones[clone]) 8670Sstevel@tonic-gate break; 8680Sstevel@tonic-gate 8690Sstevel@tonic-gate if (clone == PM_MAX_CLONE) { 8700Sstevel@tonic-gate mutex_exit(&pm_clone_lock); 8710Sstevel@tonic-gate return (ENXIO); 8720Sstevel@tonic-gate } 8730Sstevel@tonic-gate pmstp->pm_cred[clone] = cr; 8740Sstevel@tonic-gate crhold(cr); 8750Sstevel@tonic-gate 8760Sstevel@tonic-gate *devp = makedevice(getmajor(*devp), (pmstp->pm_instance << 8) + clone); 8770Sstevel@tonic-gate pmstp->pm_clones[clone] = 1; 8780Sstevel@tonic-gate mutex_exit(&pm_clone_lock); 8790Sstevel@tonic-gate 8800Sstevel@tonic-gate return (0); 8810Sstevel@tonic-gate } 8820Sstevel@tonic-gate 8830Sstevel@tonic-gate /*ARGSUSED1*/ 8840Sstevel@tonic-gate static int 8850Sstevel@tonic-gate pm_close(dev_t dev, int flag, int otyp, cred_t *cr) 8860Sstevel@tonic-gate { 8870Sstevel@tonic-gate int clone; 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate if (otyp != OTYP_CHR) 8900Sstevel@tonic-gate return (EINVAL); 8910Sstevel@tonic-gate 8920Sstevel@tonic-gate clone = PM_MINOR_TO_CLONE(getminor(dev)); 8930Sstevel@tonic-gate PMD(PMD_CLOSE, ("pm_close: minor %x, clone %x\n", getminor(dev), 8940Sstevel@tonic-gate clone)) 8950Sstevel@tonic-gate 8960Sstevel@tonic-gate /* 8970Sstevel@tonic-gate * Walk the entire device tree to find the corresponding 8980Sstevel@tonic-gate * device and operate on it. 8990Sstevel@tonic-gate */ 9000Sstevel@tonic-gate ddi_walk_devs(ddi_root_node(), pm_close_direct_pm_device, 9010Sstevel@tonic-gate (void *) &clone); 9020Sstevel@tonic-gate 9030Sstevel@tonic-gate crfree(pmstp->pm_cred[clone]); 9040Sstevel@tonic-gate pmstp->pm_cred[clone] = 0; 9050Sstevel@tonic-gate pmstp->pm_clones[clone] = 0; 9060Sstevel@tonic-gate pm_discard_entries(clone); 9070Sstevel@tonic-gate ASSERT(pm_poll_cnt[clone] == 0); 9080Sstevel@tonic-gate pm_deregister_watcher(clone, NULL); 9090Sstevel@tonic-gate return (0); 9100Sstevel@tonic-gate } 9110Sstevel@tonic-gate 9120Sstevel@tonic-gate /*ARGSUSED*/ 9130Sstevel@tonic-gate static int 9140Sstevel@tonic-gate pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p) 9150Sstevel@tonic-gate { 9160Sstevel@tonic-gate struct pm_cmd_info *pc_info(int); 9170Sstevel@tonic-gate struct pm_cmd_info *pcip = pc_info(cmd); 9180Sstevel@tonic-gate pm_req_t req; 9190Sstevel@tonic-gate dev_info_t *dip = NULL; 9200Sstevel@tonic-gate pm_info_t *info = NULL; 9210Sstevel@tonic-gate int clone; 9220Sstevel@tonic-gate char *cmdstr = pm_decode_cmd(cmd); 9230Sstevel@tonic-gate /* 9240Sstevel@tonic-gate * To keep devinfo nodes from going away while we're holding a 9250Sstevel@tonic-gate * pointer to their dip, pm_name_to_dip() optionally holds 9260Sstevel@tonic-gate * the devinfo node. If we've done that, we set dipheld 9270Sstevel@tonic-gate * so we know at the end of the ioctl processing to release the 9280Sstevel@tonic-gate * node again. 9290Sstevel@tonic-gate */ 9300Sstevel@tonic-gate int dipheld = 0; 9310Sstevel@tonic-gate int icount = 0; 9320Sstevel@tonic-gate int i; 9330Sstevel@tonic-gate int comps; 9340Sstevel@tonic-gate size_t lencopied; 9350Sstevel@tonic-gate int ret = ENOTTY; 9360Sstevel@tonic-gate int curpower; 9370Sstevel@tonic-gate char who[MAXNAMELEN]; 9380Sstevel@tonic-gate size_t wholen; /* copyinstr length */ 9390Sstevel@tonic-gate size_t deplen = MAXNAMELEN; 9400Sstevel@tonic-gate char *dep, i_dep_buf[MAXNAMELEN]; 9415295Srandyf char pathbuf[MAXNAMELEN]; 9420Sstevel@tonic-gate struct pm_component *cp; 9430Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 9440Sstevel@tonic-gate pm_state_change32_t *pscp32; 9450Sstevel@tonic-gate pm_state_change32_t psc32; 9465295Srandyf pm_searchargs32_t psa32; 9470Sstevel@tonic-gate size_t copysize32; 9480Sstevel@tonic-gate #endif 9490Sstevel@tonic-gate pm_state_change_t *pscp; 9500Sstevel@tonic-gate pm_state_change_t psc; 9515295Srandyf pm_searchargs_t psa; 9525295Srandyf char listname[MAXCOPYBUF]; 9535295Srandyf char manufacturer[MAXCOPYBUF]; 9545295Srandyf char product[MAXCOPYBUF]; 9550Sstevel@tonic-gate size_t copysize; 9560Sstevel@tonic-gate 9570Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: %s: begin\n", cmdstr)) 9580Sstevel@tonic-gate 9590Sstevel@tonic-gate #ifdef DEBUG 9600Sstevel@tonic-gate if (cmd == 666) { 9610Sstevel@tonic-gate ddi_walk_devs(ddi_root_node(), print_info, NULL); 9620Sstevel@tonic-gate return (0); 9630Sstevel@tonic-gate } 9640Sstevel@tonic-gate ret = 0x0badcafe; /* sanity checking */ 9650Sstevel@tonic-gate pm_cmd = cmd; /* for ASSERT debugging */ 9660Sstevel@tonic-gate pm_cmd_string = cmdstr; /* for ASSERT debugging */ 9670Sstevel@tonic-gate #endif 9680Sstevel@tonic-gate 9690Sstevel@tonic-gate 9700Sstevel@tonic-gate if (pcip == NULL) { 9710Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: unknown command %d\n", cmd)) 9720Sstevel@tonic-gate return (ENOTTY); 9730Sstevel@tonic-gate } 9740Sstevel@tonic-gate if (pcip == NULL || pcip->supported == 0) { 9750Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: command %s no longer supported\n", 9760Sstevel@tonic-gate pcip->name)) 9770Sstevel@tonic-gate return (ENOTTY); 9780Sstevel@tonic-gate } 9790Sstevel@tonic-gate 9800Sstevel@tonic-gate wholen = 0; 9810Sstevel@tonic-gate dep = i_dep_buf; 9820Sstevel@tonic-gate i_dep_buf[0] = 0; 9830Sstevel@tonic-gate clone = PM_MINOR_TO_CLONE(getminor(dev)); 9840Sstevel@tonic-gate if (!pm_perms(pcip->permission, pmstp->pm_cred[clone])) { 9850Sstevel@tonic-gate ret = EPERM; 9860Sstevel@tonic-gate return (ret); 9870Sstevel@tonic-gate } 9880Sstevel@tonic-gate switch (pcip->str_type) { 9890Sstevel@tonic-gate case PM_REQ: 9905295Srandyf { 9910Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 9920Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) { 9930Sstevel@tonic-gate pm_req32_t req32; 9940Sstevel@tonic-gate 9950Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg, &req32, 9960Sstevel@tonic-gate sizeof (req32), mode) != 0) { 9970Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin " 9980Sstevel@tonic-gate "EFAULT\n\n", cmdstr)) 9990Sstevel@tonic-gate ret = EFAULT; 10000Sstevel@tonic-gate break; 10010Sstevel@tonic-gate } 10020Sstevel@tonic-gate req.component = req32.component; 10030Sstevel@tonic-gate req.value = req32.value; 10040Sstevel@tonic-gate req.datasize = req32.datasize; 10050Sstevel@tonic-gate if (pcip->inargs & INWHO) { 10060Sstevel@tonic-gate ret = copyinstr((char *)(uintptr_t) 10070Sstevel@tonic-gate req32.physpath, who, MAXNAMELEN, &wholen); 10080Sstevel@tonic-gate if (ret) { 10090Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: " 10100Sstevel@tonic-gate "copyinstr fails returning %d\n", 10110Sstevel@tonic-gate cmdstr, ret)) 10120Sstevel@tonic-gate break; 10130Sstevel@tonic-gate } 10140Sstevel@tonic-gate req.physpath = who; 10155295Srandyf PMD(PMD_IOCTL, ("ioctl: %s: physpath=%s\n", 10165295Srandyf cmdstr, req.physpath)) 10170Sstevel@tonic-gate } 10180Sstevel@tonic-gate if (pcip->inargs & INDATA) { 10190Sstevel@tonic-gate req.data = (void *)(uintptr_t)req32.data; 10200Sstevel@tonic-gate req.datasize = req32.datasize; 10210Sstevel@tonic-gate } else { 10220Sstevel@tonic-gate req.data = NULL; 10230Sstevel@tonic-gate req.datasize = 0; 10240Sstevel@tonic-gate } 10250Sstevel@tonic-gate switch (pcip->diptype) { 10260Sstevel@tonic-gate case DIP: 10270Sstevel@tonic-gate if (!(dip = 10280Sstevel@tonic-gate pm_name_to_dip(req.physpath, 1))) { 10290Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: " 10300Sstevel@tonic-gate "pm_name_to_dip for %s failed\n", 10310Sstevel@tonic-gate cmdstr, req.physpath)) 10320Sstevel@tonic-gate return (ENODEV); 10330Sstevel@tonic-gate } 10340Sstevel@tonic-gate ASSERT(!dipheld); 10350Sstevel@tonic-gate dipheld++; 10360Sstevel@tonic-gate break; 10370Sstevel@tonic-gate case NODIP: 10380Sstevel@tonic-gate break; 10390Sstevel@tonic-gate default: 10400Sstevel@tonic-gate /* 10410Sstevel@tonic-gate * Internal error, invalid ioctl description 10420Sstevel@tonic-gate * force debug entry even if pm_debug not set 10430Sstevel@tonic-gate */ 10440Sstevel@tonic-gate #ifdef DEBUG 10450Sstevel@tonic-gate pm_log("invalid diptype %d for cmd %d (%s)\n", 10460Sstevel@tonic-gate pcip->diptype, cmd, pcip->name); 10470Sstevel@tonic-gate #endif 10480Sstevel@tonic-gate ASSERT(0); 10490Sstevel@tonic-gate return (EIO); 10500Sstevel@tonic-gate } 10510Sstevel@tonic-gate if (pcip->inargs & INDATAINT) { 10520Sstevel@tonic-gate int32_t int32buf; 10530Sstevel@tonic-gate int32_t *i32p; 10540Sstevel@tonic-gate int *ip; 10550Sstevel@tonic-gate icount = req32.datasize / sizeof (int32_t); 10560Sstevel@tonic-gate if (icount <= 0) { 10570Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: datasize" 10580Sstevel@tonic-gate " 0 or neg EFAULT\n\n", cmdstr)) 10590Sstevel@tonic-gate ret = EFAULT; 10600Sstevel@tonic-gate break; 10610Sstevel@tonic-gate } 10620Sstevel@tonic-gate ASSERT(!(pcip->inargs & INDATASTRING)); 10630Sstevel@tonic-gate req.datasize = icount * sizeof (int); 10640Sstevel@tonic-gate req.data = kmem_alloc(req.datasize, KM_SLEEP); 10650Sstevel@tonic-gate ip = req.data; 10660Sstevel@tonic-gate ret = 0; 10670Sstevel@tonic-gate for (i = 0, 10680Sstevel@tonic-gate i32p = (int32_t *)(uintptr_t)req32.data; 10690Sstevel@tonic-gate i < icount; i++, i32p++) { 10700Sstevel@tonic-gate if (ddi_copyin((void *)i32p, &int32buf, 10710Sstevel@tonic-gate sizeof (int32_t), mode)) { 10720Sstevel@tonic-gate kmem_free(req.data, 10730Sstevel@tonic-gate req.datasize); 10740Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: " 10750Sstevel@tonic-gate "entry %d EFAULT\n", 10760Sstevel@tonic-gate cmdstr, i)) 10770Sstevel@tonic-gate ret = EFAULT; 10780Sstevel@tonic-gate break; 10790Sstevel@tonic-gate } 10800Sstevel@tonic-gate *ip++ = (int)int32buf; 10810Sstevel@tonic-gate } 10820Sstevel@tonic-gate if (ret) 10830Sstevel@tonic-gate break; 10840Sstevel@tonic-gate } 10850Sstevel@tonic-gate if (pcip->inargs & INDATASTRING) { 10860Sstevel@tonic-gate ASSERT(!(pcip->inargs & INDATAINT)); 10870Sstevel@tonic-gate ASSERT(pcip->deptype == DEP); 10880Sstevel@tonic-gate if (req32.data != NULL) { 10890Sstevel@tonic-gate if (copyinstr((void *)(uintptr_t) 10905295Srandyf req32.data, dep, deplen, NULL)) { 10910Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: " 10920Sstevel@tonic-gate "0x%p dep size %lx, EFAULT" 10930Sstevel@tonic-gate "\n", cmdstr, 10940Sstevel@tonic-gate (void *)req.data, deplen)) 10950Sstevel@tonic-gate ret = EFAULT; 10960Sstevel@tonic-gate break; 10970Sstevel@tonic-gate } 10980Sstevel@tonic-gate #ifdef DEBUG 10990Sstevel@tonic-gate else { 11000Sstevel@tonic-gate PMD(PMD_DEP, ("ioctl: %s: " 11010Sstevel@tonic-gate "dep %s\n", cmdstr, dep)) 11020Sstevel@tonic-gate } 11030Sstevel@tonic-gate #endif 11040Sstevel@tonic-gate } else { 11050Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: no " 11060Sstevel@tonic-gate "dependent\n", cmdstr)) 11070Sstevel@tonic-gate ret = EINVAL; 11080Sstevel@tonic-gate break; 11090Sstevel@tonic-gate } 11100Sstevel@tonic-gate } 11110Sstevel@tonic-gate } else 11120Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 11130Sstevel@tonic-gate { 11140Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg, 11150Sstevel@tonic-gate &req, sizeof (req), mode) != 0) { 11160Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin " 11170Sstevel@tonic-gate "EFAULT\n\n", cmdstr)) 11180Sstevel@tonic-gate ret = EFAULT; 11190Sstevel@tonic-gate break; 11200Sstevel@tonic-gate } 11210Sstevel@tonic-gate if (pcip->inargs & INWHO) { 11220Sstevel@tonic-gate ret = copyinstr((char *)req.physpath, who, 11230Sstevel@tonic-gate MAXNAMELEN, &wholen); 11240Sstevel@tonic-gate if (ret) { 11250Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s copyinstr" 11260Sstevel@tonic-gate " fails returning %d\n", cmdstr, 11270Sstevel@tonic-gate ret)) 11280Sstevel@tonic-gate break; 11290Sstevel@tonic-gate } 11300Sstevel@tonic-gate req.physpath = who; 11315295Srandyf PMD(PMD_IOCTL, ("ioctl: %s: physpath=%s\n", 11325295Srandyf cmdstr, req.physpath)) 11330Sstevel@tonic-gate } 11340Sstevel@tonic-gate if (!(pcip->inargs & INDATA)) { 11350Sstevel@tonic-gate req.data = NULL; 11360Sstevel@tonic-gate req.datasize = 0; 11370Sstevel@tonic-gate } 11380Sstevel@tonic-gate switch (pcip->diptype) { 11390Sstevel@tonic-gate case DIP: 11400Sstevel@tonic-gate if (!(dip = 11410Sstevel@tonic-gate pm_name_to_dip(req.physpath, 1))) { 11420Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: " 11430Sstevel@tonic-gate "pm_name_to_dip for %s failed\n", 11440Sstevel@tonic-gate cmdstr, req.physpath)) 11450Sstevel@tonic-gate return (ENODEV); 11460Sstevel@tonic-gate } 11470Sstevel@tonic-gate ASSERT(!dipheld); 11480Sstevel@tonic-gate dipheld++; 11490Sstevel@tonic-gate break; 11500Sstevel@tonic-gate case NODIP: 11510Sstevel@tonic-gate break; 11520Sstevel@tonic-gate default: 11530Sstevel@tonic-gate /* 11540Sstevel@tonic-gate * Internal error, invalid ioctl description 11550Sstevel@tonic-gate * force debug entry even if pm_debug not set 11560Sstevel@tonic-gate */ 11570Sstevel@tonic-gate #ifdef DEBUG 11580Sstevel@tonic-gate pm_log("invalid diptype %d for cmd %d (%s)\n", 11590Sstevel@tonic-gate pcip->diptype, cmd, pcip->name); 11600Sstevel@tonic-gate #endif 11610Sstevel@tonic-gate ASSERT(0); 11620Sstevel@tonic-gate return (EIO); 11630Sstevel@tonic-gate } 11640Sstevel@tonic-gate if (pcip->inargs & INDATAINT) { 11650Sstevel@tonic-gate int *ip; 11660Sstevel@tonic-gate 11670Sstevel@tonic-gate ASSERT(!(pcip->inargs & INDATASTRING)); 11680Sstevel@tonic-gate ip = req.data; 11690Sstevel@tonic-gate icount = req.datasize / sizeof (int); 11700Sstevel@tonic-gate if (icount <= 0) { 11710Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: datasize" 11720Sstevel@tonic-gate " 0 or neg EFAULT\n\n", cmdstr)) 11730Sstevel@tonic-gate ret = EFAULT; 11740Sstevel@tonic-gate break; 11750Sstevel@tonic-gate } 11760Sstevel@tonic-gate req.data = kmem_alloc(req.datasize, KM_SLEEP); 11770Sstevel@tonic-gate if (ddi_copyin((caddr_t)ip, req.data, 11780Sstevel@tonic-gate req.datasize, mode) != 0) { 11790Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin " 11800Sstevel@tonic-gate "EFAULT\n\n", cmdstr)) 11810Sstevel@tonic-gate ret = EFAULT; 11820Sstevel@tonic-gate break; 11830Sstevel@tonic-gate } 11840Sstevel@tonic-gate } 11850Sstevel@tonic-gate if (pcip->inargs & INDATASTRING) { 11860Sstevel@tonic-gate ASSERT(!(pcip->inargs & INDATAINT)); 11870Sstevel@tonic-gate ASSERT(pcip->deptype == DEP); 11880Sstevel@tonic-gate if (req.data != NULL) { 11890Sstevel@tonic-gate if (copyinstr((caddr_t)req.data, 11905295Srandyf dep, deplen, NULL)) { 11910Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: " 11920Sstevel@tonic-gate "0x%p dep size %lu, " 11930Sstevel@tonic-gate "EFAULT\n", cmdstr, 11940Sstevel@tonic-gate (void *)req.data, deplen)) 11950Sstevel@tonic-gate ret = EFAULT; 11960Sstevel@tonic-gate break; 11970Sstevel@tonic-gate } 11980Sstevel@tonic-gate #ifdef DEBUG 11990Sstevel@tonic-gate else { 12000Sstevel@tonic-gate PMD(PMD_DEP, ("ioctl: %s: " 12010Sstevel@tonic-gate "dep %s\n", cmdstr, dep)) 12020Sstevel@tonic-gate } 12030Sstevel@tonic-gate #endif 12040Sstevel@tonic-gate } else { 12050Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: no " 12060Sstevel@tonic-gate "dependent\n", cmdstr)) 12070Sstevel@tonic-gate ret = EINVAL; 12080Sstevel@tonic-gate break; 12090Sstevel@tonic-gate } 12100Sstevel@tonic-gate } 12110Sstevel@tonic-gate } 12120Sstevel@tonic-gate /* 12130Sstevel@tonic-gate * Now we've got all the args in for the commands that 12140Sstevel@tonic-gate * use the new pm_req struct. 12150Sstevel@tonic-gate */ 12160Sstevel@tonic-gate switch (cmd) { 12170Sstevel@tonic-gate case PM_REPARSE_PM_PROPS: 12180Sstevel@tonic-gate { 12190Sstevel@tonic-gate struct dev_ops *drv; 12200Sstevel@tonic-gate struct cb_ops *cb; 12210Sstevel@tonic-gate void *propval; 12220Sstevel@tonic-gate int length; 12230Sstevel@tonic-gate /* 12240Sstevel@tonic-gate * This ioctl is provided only for the ddivs pm test. 12250Sstevel@tonic-gate * We only do it to a driver which explicitly allows 12260Sstevel@tonic-gate * us to do so by exporting a pm-reparse-ok property. 12270Sstevel@tonic-gate * We only care whether the property exists or not. 12280Sstevel@tonic-gate */ 12290Sstevel@tonic-gate if ((drv = ddi_get_driver(dip)) == NULL) { 12300Sstevel@tonic-gate ret = EINVAL; 12310Sstevel@tonic-gate break; 12320Sstevel@tonic-gate } 12330Sstevel@tonic-gate if ((cb = drv->devo_cb_ops) != NULL) { 12340Sstevel@tonic-gate if ((*cb->cb_prop_op)(DDI_DEV_T_ANY, dip, 12350Sstevel@tonic-gate PROP_LEN_AND_VAL_ALLOC, (DDI_PROP_CANSLEEP | 12360Sstevel@tonic-gate DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), 12370Sstevel@tonic-gate "pm-reparse-ok", (caddr_t)&propval, 12380Sstevel@tonic-gate &length) != DDI_SUCCESS) { 12390Sstevel@tonic-gate ret = EINVAL; 12400Sstevel@tonic-gate break; 12410Sstevel@tonic-gate } 12420Sstevel@tonic-gate } else if (ddi_prop_op(DDI_DEV_T_ANY, dip, 12430Sstevel@tonic-gate PROP_LEN_AND_VAL_ALLOC, (DDI_PROP_CANSLEEP | 12440Sstevel@tonic-gate DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), 12450Sstevel@tonic-gate "pm-reparse-ok", (caddr_t)&propval, 12460Sstevel@tonic-gate &length) != DDI_SUCCESS) { 12470Sstevel@tonic-gate ret = EINVAL; 12480Sstevel@tonic-gate break; 12490Sstevel@tonic-gate } 12500Sstevel@tonic-gate kmem_free(propval, length); 12510Sstevel@tonic-gate ret = e_new_pm_props(dip); 12520Sstevel@tonic-gate break; 12530Sstevel@tonic-gate } 12540Sstevel@tonic-gate 12550Sstevel@tonic-gate case PM_GET_DEVICE_THRESHOLD: 12565295Srandyf { 12570Sstevel@tonic-gate PM_LOCK_DIP(dip); 12580Sstevel@tonic-gate if (!PM_GET_PM_INFO(dip) || PM_ISBC(dip)) { 12590Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 12600Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: ENODEV\n", 12610Sstevel@tonic-gate cmdstr)) 12620Sstevel@tonic-gate ret = ENODEV; 12630Sstevel@tonic-gate break; 12640Sstevel@tonic-gate } 12650Sstevel@tonic-gate *rval_p = DEVI(dip)->devi_pm_dev_thresh; 12660Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 12670Sstevel@tonic-gate ret = 0; 12680Sstevel@tonic-gate break; 12695295Srandyf } 12700Sstevel@tonic-gate 12710Sstevel@tonic-gate case PM_DIRECT_PM: 12720Sstevel@tonic-gate { 12730Sstevel@tonic-gate int has_dep; 12740Sstevel@tonic-gate if ((info = PM_GET_PM_INFO(dip)) == NULL) { 12750Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: " 12760Sstevel@tonic-gate "ENODEV\n", cmdstr)) 12770Sstevel@tonic-gate ret = ENODEV; 12780Sstevel@tonic-gate break; 12790Sstevel@tonic-gate } 12800Sstevel@tonic-gate /* 12810Sstevel@tonic-gate * Check to see if we are there is a dependency on 12820Sstevel@tonic-gate * this kept device, if so, return EBUSY. 12830Sstevel@tonic-gate */ 12840Sstevel@tonic-gate (void) ddi_pathname(dip, pathbuf); 12850Sstevel@tonic-gate pm_dispatch_to_dep_thread(PM_DEP_WK_CHECK_KEPT, 12860Sstevel@tonic-gate NULL, pathbuf, PM_DEP_WAIT, &has_dep, 0); 12870Sstevel@tonic-gate if (has_dep) { 12880Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("%s EBUSY\n", 12890Sstevel@tonic-gate cmdstr)) 12900Sstevel@tonic-gate ret = EBUSY; 12910Sstevel@tonic-gate break; 12920Sstevel@tonic-gate } 12930Sstevel@tonic-gate PM_LOCK_DIP(dip); 12940Sstevel@tonic-gate if (PM_ISDIRECT(dip) || (info->pmi_clone != 0)) { 12950Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: " 12960Sstevel@tonic-gate "%s@%s(%s#%d): EBUSY\n", cmdstr, 12970Sstevel@tonic-gate PM_DEVICE(dip))) 12980Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 12990Sstevel@tonic-gate ret = EBUSY; 13000Sstevel@tonic-gate break; 13010Sstevel@tonic-gate } 13020Sstevel@tonic-gate info->pmi_dev_pm_state |= PM_DIRECT; 13030Sstevel@tonic-gate info->pmi_clone = clone; 13040Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 13050Sstevel@tonic-gate PMD(PMD_DPM, ("ioctl: %s: info %p, pmi_clone %d\n", 13060Sstevel@tonic-gate cmdstr, (void *)info, clone)) 13070Sstevel@tonic-gate mutex_enter(&pm_clone_lock); 13080Sstevel@tonic-gate pm_register_watcher(clone, dip); 13090Sstevel@tonic-gate mutex_exit(&pm_clone_lock); 13100Sstevel@tonic-gate ret = 0; 13110Sstevel@tonic-gate break; 13120Sstevel@tonic-gate } 13130Sstevel@tonic-gate 13140Sstevel@tonic-gate case PM_RELEASE_DIRECT_PM: 13150Sstevel@tonic-gate { 13160Sstevel@tonic-gate if ((info = PM_GET_PM_INFO(dip)) == NULL) { 13170Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: " 13180Sstevel@tonic-gate "ENODEV\n", cmdstr)) 13190Sstevel@tonic-gate ret = ENODEV; 13200Sstevel@tonic-gate break; 13210Sstevel@tonic-gate } 13220Sstevel@tonic-gate PM_LOCK_DIP(dip); 13230Sstevel@tonic-gate if (info->pmi_clone != clone) { 13240Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: " 13250Sstevel@tonic-gate "%s@%s(%s#%d) EINVAL\n", cmdstr, 13260Sstevel@tonic-gate PM_DEVICE(dip))) 13270Sstevel@tonic-gate ret = EINVAL; 13280Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 13290Sstevel@tonic-gate break; 13300Sstevel@tonic-gate } 13310Sstevel@tonic-gate ASSERT(PM_ISDIRECT(dip)); 13320Sstevel@tonic-gate info->pmi_dev_pm_state &= ~PM_DIRECT; 13330Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 13340Sstevel@tonic-gate /* Bring ourselves up if there is a keeper. */ 13350Sstevel@tonic-gate (void) ddi_pathname(dip, pathbuf); 13360Sstevel@tonic-gate pm_dispatch_to_dep_thread(PM_DEP_WK_BRINGUP_SELF, 13370Sstevel@tonic-gate NULL, pathbuf, PM_DEP_WAIT, NULL, 0); 13380Sstevel@tonic-gate pm_discard_entries(clone); 13390Sstevel@tonic-gate pm_deregister_watcher(clone, dip); 13400Sstevel@tonic-gate /* 13410Sstevel@tonic-gate * Now we could let the other threads that are 13420Sstevel@tonic-gate * trying to do a DIRECT_PM thru 13430Sstevel@tonic-gate */ 13440Sstevel@tonic-gate PM_LOCK_DIP(dip); 13450Sstevel@tonic-gate info->pmi_clone = 0; 13460Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 13470Sstevel@tonic-gate pm_proceed(dip, PMP_RELEASE, -1, -1); 13480Sstevel@tonic-gate PMD(PMD_RESCAN | PMD_DPM, ("ioctl: %s: rescan\n", 13490Sstevel@tonic-gate cmdstr)) 13500Sstevel@tonic-gate pm_rescan(dip); 13510Sstevel@tonic-gate ret = 0; 13520Sstevel@tonic-gate break; 13530Sstevel@tonic-gate } 13540Sstevel@tonic-gate 13550Sstevel@tonic-gate case PM_SET_CURRENT_POWER: 13560Sstevel@tonic-gate { 13570Sstevel@tonic-gate int comp = req.component; 13580Sstevel@tonic-gate int value = req.value; 13590Sstevel@tonic-gate PMD(PMD_DPM, ("ioctl: %s: %s component %d to value " 13600Sstevel@tonic-gate "%d\n", cmdstr, req.physpath, comp, value)) 13610Sstevel@tonic-gate if (!e_pm_valid_comp(dip, comp, NULL) || 13620Sstevel@tonic-gate !e_pm_valid_power(dip, comp, value)) { 13630Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: " 13640Sstevel@tonic-gate "physpath=%s, comp=%d, level=%d, fails\n", 13650Sstevel@tonic-gate cmdstr, req.physpath, comp, value)) 13660Sstevel@tonic-gate ret = EINVAL; 13670Sstevel@tonic-gate break; 13680Sstevel@tonic-gate } 13690Sstevel@tonic-gate 13700Sstevel@tonic-gate if ((info = PM_GET_PM_INFO(dip)) == NULL) { 13710Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: " 13720Sstevel@tonic-gate "ENODEV\n", cmdstr)) 13730Sstevel@tonic-gate ret = ENODEV; 13740Sstevel@tonic-gate break; 13750Sstevel@tonic-gate } 13760Sstevel@tonic-gate if (info->pmi_clone != clone) { 13770Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: " 13780Sstevel@tonic-gate "(not owner) %s fails; clone %d, owner %d" 13790Sstevel@tonic-gate "\n", cmdstr, req.physpath, clone, 13800Sstevel@tonic-gate info->pmi_clone)) 13810Sstevel@tonic-gate ret = EINVAL; 13820Sstevel@tonic-gate break; 13830Sstevel@tonic-gate } 13840Sstevel@tonic-gate ASSERT(PM_ISDIRECT(dip)); 13850Sstevel@tonic-gate 13860Sstevel@tonic-gate if (pm_set_power(dip, comp, value, PM_LEVEL_EXACT, 13870Sstevel@tonic-gate PM_CANBLOCK_BLOCK, 0, &ret) != DDI_SUCCESS) { 13880Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: " 13890Sstevel@tonic-gate "pm_set_power for %s fails, errno=%d\n", 13900Sstevel@tonic-gate cmdstr, req.physpath, ret)) 13910Sstevel@tonic-gate break; 13920Sstevel@tonic-gate } 13930Sstevel@tonic-gate 13940Sstevel@tonic-gate pm_proceed(dip, PMP_SETPOWER, comp, value); 13950Sstevel@tonic-gate 13960Sstevel@tonic-gate /* 13970Sstevel@tonic-gate * Power down all idle components if console framebuffer 13980Sstevel@tonic-gate * is powered off. 13990Sstevel@tonic-gate */ 14000Sstevel@tonic-gate if (PM_IS_CFB(dip) && (pm_system_idle_threshold == 14010Sstevel@tonic-gate pm_default_idle_threshold)) { 14020Sstevel@tonic-gate dev_info_t *root = ddi_root_node(); 14030Sstevel@tonic-gate if (PM_ISBC(dip)) { 14040Sstevel@tonic-gate if (comp == 0 && value == 0 && 14050Sstevel@tonic-gate (pm_timeout_idledown() != 0)) { 14060Sstevel@tonic-gate ddi_walk_devs(root, 14070Sstevel@tonic-gate pm_start_idledown, 14080Sstevel@tonic-gate (void *)PMID_CFB); 14090Sstevel@tonic-gate } 14100Sstevel@tonic-gate } else { 14110Sstevel@tonic-gate int count = 0; 14120Sstevel@tonic-gate for (i = 0; i < PM_NUMCMPTS(dip); i++) { 14130Sstevel@tonic-gate ret = pm_get_current_power(dip, 14140Sstevel@tonic-gate i, &curpower); 14150Sstevel@tonic-gate if (ret == DDI_SUCCESS && 14160Sstevel@tonic-gate curpower == 0) 14170Sstevel@tonic-gate count++; 14180Sstevel@tonic-gate } 14190Sstevel@tonic-gate if ((count == PM_NUMCMPTS(dip)) && 14200Sstevel@tonic-gate (pm_timeout_idledown() != 0)) { 14210Sstevel@tonic-gate ddi_walk_devs(root, 14220Sstevel@tonic-gate pm_start_idledown, 14230Sstevel@tonic-gate (void *)PMID_CFB); 14240Sstevel@tonic-gate } 14250Sstevel@tonic-gate } 14260Sstevel@tonic-gate } 14270Sstevel@tonic-gate 14280Sstevel@tonic-gate PMD(PMD_RESCAN | PMD_DPM, ("ioctl: %s: rescan\n", 14290Sstevel@tonic-gate cmdstr)) 14300Sstevel@tonic-gate pm_rescan(dip); 14310Sstevel@tonic-gate *rval_p = 0; 14320Sstevel@tonic-gate ret = 0; 14330Sstevel@tonic-gate break; 14340Sstevel@tonic-gate } 14350Sstevel@tonic-gate 14360Sstevel@tonic-gate case PM_GET_FULL_POWER: 14370Sstevel@tonic-gate { 14380Sstevel@tonic-gate int normal; 14390Sstevel@tonic-gate ASSERT(dip); 14400Sstevel@tonic-gate PMD(PMD_NORM, ("ioctl: %s: %s component %d\n", 14410Sstevel@tonic-gate cmdstr, req.physpath, req.component)) 14420Sstevel@tonic-gate normal = pm_get_normal_power(dip, req.component); 14430Sstevel@tonic-gate 14440Sstevel@tonic-gate if (normal == DDI_FAILURE) { 14450Sstevel@tonic-gate PMD(PMD_ERROR | PMD_NORM, ("ioctl: %s: " 14460Sstevel@tonic-gate "returns EINVAL\n", cmdstr)) 14470Sstevel@tonic-gate ret = EINVAL; 14480Sstevel@tonic-gate break; 14490Sstevel@tonic-gate } 14500Sstevel@tonic-gate *rval_p = normal; 14510Sstevel@tonic-gate PMD(PMD_NORM, ("ioctl: %s: returns %d\n", 14520Sstevel@tonic-gate cmdstr, normal)) 14530Sstevel@tonic-gate ret = 0; 14540Sstevel@tonic-gate break; 14550Sstevel@tonic-gate } 14560Sstevel@tonic-gate 14570Sstevel@tonic-gate case PM_GET_CURRENT_POWER: 14585295Srandyf { 14590Sstevel@tonic-gate if (pm_get_current_power(dip, req.component, 14600Sstevel@tonic-gate rval_p) != DDI_SUCCESS) { 14610Sstevel@tonic-gate PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s " 14620Sstevel@tonic-gate "EINVAL\n", cmdstr)) 14630Sstevel@tonic-gate ret = EINVAL; 14640Sstevel@tonic-gate break; 14650Sstevel@tonic-gate } 14660Sstevel@tonic-gate PMD(PMD_DPM, ("ioctl: %s: %s comp %d returns %d\n", 14670Sstevel@tonic-gate cmdstr, req.physpath, req.component, *rval_p)) 14680Sstevel@tonic-gate if (*rval_p == PM_LEVEL_UNKNOWN) 14690Sstevel@tonic-gate ret = EAGAIN; 14700Sstevel@tonic-gate else 14710Sstevel@tonic-gate ret = 0; 14720Sstevel@tonic-gate break; 14735295Srandyf } 14740Sstevel@tonic-gate 14750Sstevel@tonic-gate case PM_GET_TIME_IDLE: 14760Sstevel@tonic-gate { 14770Sstevel@tonic-gate time_t timestamp; 14780Sstevel@tonic-gate int comp = req.component; 14790Sstevel@tonic-gate pm_component_t *cp; 14800Sstevel@tonic-gate if (!e_pm_valid_comp(dip, comp, &cp)) { 14810Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) " 14820Sstevel@tonic-gate "component %d > numcmpts - 1 %d--EINVAL\n", 14830Sstevel@tonic-gate cmdstr, PM_DEVICE(dip), comp, 14840Sstevel@tonic-gate PM_NUMCMPTS(dip) - 1)) 14850Sstevel@tonic-gate ret = EINVAL; 14860Sstevel@tonic-gate break; 14870Sstevel@tonic-gate } 14880Sstevel@tonic-gate timestamp = cp->pmc_timestamp; 14890Sstevel@tonic-gate if (timestamp) { 14900Sstevel@tonic-gate time_t now; 14910Sstevel@tonic-gate (void) drv_getparm(TIME, &now); 14920Sstevel@tonic-gate *rval_p = (now - timestamp); 14930Sstevel@tonic-gate } else { 14940Sstevel@tonic-gate *rval_p = 0; 14950Sstevel@tonic-gate } 14960Sstevel@tonic-gate ret = 0; 14970Sstevel@tonic-gate break; 14980Sstevel@tonic-gate } 14990Sstevel@tonic-gate 15000Sstevel@tonic-gate case PM_ADD_DEPENDENT: 15010Sstevel@tonic-gate { 15020Sstevel@tonic-gate dev_info_t *kept_dip; 15030Sstevel@tonic-gate 15040Sstevel@tonic-gate PMD(PMD_KEEPS, ("%s, kept %s, keeper %s\n", cmdstr, 15050Sstevel@tonic-gate dep, req.physpath)) 15060Sstevel@tonic-gate 15070Sstevel@tonic-gate /* 15080Sstevel@tonic-gate * hold and install kept while processing dependency 15090Sstevel@tonic-gate * keeper (in .physpath) has already been held. 15100Sstevel@tonic-gate */ 15110Sstevel@tonic-gate if (dep[0] == '\0') { 15120Sstevel@tonic-gate PMD(PMD_ERROR, ("kept NULL or null\n")) 15130Sstevel@tonic-gate ret = EINVAL; 15140Sstevel@tonic-gate break; 15150Sstevel@tonic-gate } else if ((kept_dip = 15160Sstevel@tonic-gate pm_name_to_dip(dep, 1)) == NULL) { 15170Sstevel@tonic-gate PMD(PMD_ERROR, ("no dip for kept %s\n", dep)) 15180Sstevel@tonic-gate ret = ENODEV; 15190Sstevel@tonic-gate break; 15200Sstevel@tonic-gate } else if (kept_dip == dip) { 15210Sstevel@tonic-gate PMD(PMD_ERROR, ("keeper(%s, %p) - kept(%s, %p) " 15220Sstevel@tonic-gate "self-dependency not allowed.\n", 15230Sstevel@tonic-gate dep, (void *)kept_dip, req.physpath, 15240Sstevel@tonic-gate (void *) dip)) 15250Sstevel@tonic-gate PM_RELE(dip); /* release "double" hold */ 15260Sstevel@tonic-gate ret = EINVAL; 15270Sstevel@tonic-gate break; 15280Sstevel@tonic-gate } 15290Sstevel@tonic-gate ASSERT(!(strcmp(req.physpath, (char *)dep) == 0)); 15300Sstevel@tonic-gate 15310Sstevel@tonic-gate /* 15320Sstevel@tonic-gate * record dependency, then walk through device tree 15330Sstevel@tonic-gate * independently on behalf of kept and keeper to 15340Sstevel@tonic-gate * establish newly created dependency. 15350Sstevel@tonic-gate */ 15360Sstevel@tonic-gate pm_dispatch_to_dep_thread(PM_DEP_WK_RECORD_KEEPER, 15370Sstevel@tonic-gate req.physpath, dep, PM_DEP_WAIT, NULL, 0); 15380Sstevel@tonic-gate 15390Sstevel@tonic-gate /* 15400Sstevel@tonic-gate * release kept after establishing dependency, keeper 15410Sstevel@tonic-gate * is released as part of ioctl exit processing. 15420Sstevel@tonic-gate */ 15430Sstevel@tonic-gate PM_RELE(kept_dip); 15440Sstevel@tonic-gate *rval_p = 0; 15450Sstevel@tonic-gate ret = 0; 15460Sstevel@tonic-gate break; 15470Sstevel@tonic-gate } 15480Sstevel@tonic-gate 15490Sstevel@tonic-gate case PM_ADD_DEPENDENT_PROPERTY: 15500Sstevel@tonic-gate { 15510Sstevel@tonic-gate char *keeper, *kept; 15520Sstevel@tonic-gate 15530Sstevel@tonic-gate if (dep[0] == '\0') { 15540Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: dep NULL or " 15550Sstevel@tonic-gate "null\n", cmdstr)) 15560Sstevel@tonic-gate ret = EINVAL; 15570Sstevel@tonic-gate break; 15580Sstevel@tonic-gate } 15590Sstevel@tonic-gate kept = dep; 15600Sstevel@tonic-gate keeper = req.physpath; 15610Sstevel@tonic-gate /* 15620Sstevel@tonic-gate * record keeper - kept dependency, then walk through 15630Sstevel@tonic-gate * device tree to find out all attached keeper, walk 15640Sstevel@tonic-gate * through again to apply dependency to all the 15650Sstevel@tonic-gate * potential kept. 15660Sstevel@tonic-gate */ 15670Sstevel@tonic-gate pm_dispatch_to_dep_thread( 15680Sstevel@tonic-gate PM_DEP_WK_RECORD_KEEPER_PROP, keeper, kept, 15690Sstevel@tonic-gate PM_DEP_WAIT, NULL, 0); 15700Sstevel@tonic-gate 15710Sstevel@tonic-gate *rval_p = 0; 15720Sstevel@tonic-gate ret = 0; 15730Sstevel@tonic-gate break; 15740Sstevel@tonic-gate } 15750Sstevel@tonic-gate 15760Sstevel@tonic-gate case PM_SET_DEVICE_THRESHOLD: 15770Sstevel@tonic-gate { 15780Sstevel@tonic-gate pm_thresh_rec_t *rp; 15790Sstevel@tonic-gate pm_pte_t *ep; /* threshold header storage */ 15800Sstevel@tonic-gate int *tp; /* threshold storage */ 15810Sstevel@tonic-gate size_t size; 15820Sstevel@tonic-gate extern int pm_thresh_specd(dev_info_t *); 15830Sstevel@tonic-gate 15840Sstevel@tonic-gate /* 15850Sstevel@tonic-gate * The header struct plus one entry struct plus one 15860Sstevel@tonic-gate * threshold plus the length of the string 15870Sstevel@tonic-gate */ 15880Sstevel@tonic-gate size = sizeof (pm_thresh_rec_t) + 15890Sstevel@tonic-gate (sizeof (pm_pte_t) * 1) + 15900Sstevel@tonic-gate (1 * sizeof (int)) + 15910Sstevel@tonic-gate strlen(req.physpath) + 1; 15920Sstevel@tonic-gate 15930Sstevel@tonic-gate rp = kmem_zalloc(size, KM_SLEEP); 15940Sstevel@tonic-gate rp->ptr_size = size; 15950Sstevel@tonic-gate rp->ptr_numcomps = 0; /* means device threshold */ 15960Sstevel@tonic-gate ep = (pm_pte_t *)((intptr_t)rp + sizeof (*rp)); 15970Sstevel@tonic-gate rp->ptr_entries = ep; 15980Sstevel@tonic-gate tp = (int *)((intptr_t)ep + 15990Sstevel@tonic-gate (1 * sizeof (pm_pte_t))); 16000Sstevel@tonic-gate ep->pte_numthresh = 1; 16010Sstevel@tonic-gate ep->pte_thresh = tp; 16020Sstevel@tonic-gate *tp++ = req.value; 16030Sstevel@tonic-gate (void) strcat((char *)tp, req.physpath); 16040Sstevel@tonic-gate rp->ptr_physpath = (char *)tp; 16050Sstevel@tonic-gate ASSERT((intptr_t)tp + strlen(req.physpath) + 1 == 16060Sstevel@tonic-gate (intptr_t)rp + rp->ptr_size); 16070Sstevel@tonic-gate PMD(PMD_THRESH, ("ioctl: %s: record thresh %d for " 16080Sstevel@tonic-gate "%s\n", cmdstr, req.value, req.physpath)) 16090Sstevel@tonic-gate pm_record_thresh(rp); 16100Sstevel@tonic-gate /* 16110Sstevel@tonic-gate * Don't free rp, pm_record_thresh() keeps it. 16120Sstevel@tonic-gate * We don't try to apply it ourselves because we'd need 16130Sstevel@tonic-gate * to know too much about locking. Since we don't 16140Sstevel@tonic-gate * hold a lock the entry could be removed before 16150Sstevel@tonic-gate * we get here 16160Sstevel@tonic-gate */ 16170Sstevel@tonic-gate ASSERT(dip == NULL); 16180Sstevel@tonic-gate ret = 0; /* can't fail now */ 16190Sstevel@tonic-gate if (!(dip = pm_name_to_dip(req.physpath, 1))) { 16200Sstevel@tonic-gate break; 16210Sstevel@tonic-gate } 16220Sstevel@tonic-gate (void) pm_thresh_specd(dip); 16230Sstevel@tonic-gate PMD(PMD_DHR, ("ioctl: %s: releasing %s@%s(%s#%d)\n", 16240Sstevel@tonic-gate cmdstr, PM_DEVICE(dip))) 16250Sstevel@tonic-gate PM_RELE(dip); 16260Sstevel@tonic-gate break; 16270Sstevel@tonic-gate } 16280Sstevel@tonic-gate 16290Sstevel@tonic-gate case PM_RESET_DEVICE_THRESHOLD: 16300Sstevel@tonic-gate { 16310Sstevel@tonic-gate /* 16320Sstevel@tonic-gate * This only applies to a currently attached and power 16330Sstevel@tonic-gate * managed node 16340Sstevel@tonic-gate */ 16350Sstevel@tonic-gate /* 16360Sstevel@tonic-gate * We don't do this to old-style drivers 16370Sstevel@tonic-gate */ 16380Sstevel@tonic-gate info = PM_GET_PM_INFO(dip); 16390Sstevel@tonic-gate if (info == NULL) { 16400Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s not power " 16410Sstevel@tonic-gate "managed\n", cmdstr, req.physpath)) 16420Sstevel@tonic-gate ret = EINVAL; 16430Sstevel@tonic-gate break; 16440Sstevel@tonic-gate } 16450Sstevel@tonic-gate if (PM_ISBC(dip)) { 16460Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s is BC\n", 16470Sstevel@tonic-gate cmdstr, req.physpath)) 16480Sstevel@tonic-gate ret = EINVAL; 16490Sstevel@tonic-gate break; 16500Sstevel@tonic-gate } 16510Sstevel@tonic-gate pm_unrecord_threshold(req.physpath); 16523028Smh27603 if (DEVI(dip)->devi_pm_flags & PMC_CPU_THRESH) 16533028Smh27603 pm_set_device_threshold(dip, 16543028Smh27603 pm_cpu_idle_threshold, PMC_CPU_THRESH); 16553028Smh27603 else 16563028Smh27603 pm_set_device_threshold(dip, 16573028Smh27603 pm_system_idle_threshold, PMC_DEF_THRESH); 16580Sstevel@tonic-gate ret = 0; 16590Sstevel@tonic-gate break; 16600Sstevel@tonic-gate } 16610Sstevel@tonic-gate 16620Sstevel@tonic-gate case PM_GET_NUM_COMPONENTS: 16635295Srandyf { 16640Sstevel@tonic-gate ret = 0; 16650Sstevel@tonic-gate *rval_p = PM_NUMCMPTS(dip); 16660Sstevel@tonic-gate break; 16675295Srandyf } 16680Sstevel@tonic-gate 16690Sstevel@tonic-gate case PM_GET_DEVICE_TYPE: 16705295Srandyf { 16710Sstevel@tonic-gate ret = 0; 16720Sstevel@tonic-gate if ((info = PM_GET_PM_INFO(dip)) == NULL) { 16730Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: " 16740Sstevel@tonic-gate "PM_NO_PM_COMPONENTS\n", cmdstr)) 16750Sstevel@tonic-gate *rval_p = PM_NO_PM_COMPONENTS; 16760Sstevel@tonic-gate break; 16770Sstevel@tonic-gate } 16780Sstevel@tonic-gate if (PM_ISBC(dip)) { 16790Sstevel@tonic-gate *rval_p = PM_CREATE_COMPONENTS; 16800Sstevel@tonic-gate } else { 16810Sstevel@tonic-gate *rval_p = PM_AUTOPM; 16820Sstevel@tonic-gate } 16830Sstevel@tonic-gate break; 16845295Srandyf } 16850Sstevel@tonic-gate 16860Sstevel@tonic-gate case PM_SET_COMPONENT_THRESHOLDS: 16870Sstevel@tonic-gate { 16880Sstevel@tonic-gate int comps = 0; 16890Sstevel@tonic-gate int *end = (int *)req.data + icount; 16900Sstevel@tonic-gate pm_thresh_rec_t *rp; 16910Sstevel@tonic-gate pm_pte_t *ep; /* threshold header storage */ 16920Sstevel@tonic-gate int *tp; /* threshold storage */ 16930Sstevel@tonic-gate int *ip; 16940Sstevel@tonic-gate int j; 16950Sstevel@tonic-gate size_t size; 16960Sstevel@tonic-gate extern int pm_thresh_specd(dev_info_t *); 16970Sstevel@tonic-gate extern int pm_valid_thresh(dev_info_t *, 16980Sstevel@tonic-gate pm_thresh_rec_t *); 16990Sstevel@tonic-gate 17000Sstevel@tonic-gate for (ip = req.data; *ip; ip++) { 17010Sstevel@tonic-gate if (ip >= end) { 17020Sstevel@tonic-gate ret = EFAULT; 17030Sstevel@tonic-gate break; 17040Sstevel@tonic-gate } 17050Sstevel@tonic-gate comps++; 17060Sstevel@tonic-gate /* skip over indicated number of entries */ 17070Sstevel@tonic-gate for (j = *ip; j; j--) { 17080Sstevel@tonic-gate if (++ip >= end) { 17090Sstevel@tonic-gate ret = EFAULT; 17100Sstevel@tonic-gate break; 17110Sstevel@tonic-gate } 17120Sstevel@tonic-gate } 17130Sstevel@tonic-gate if (ret) 17140Sstevel@tonic-gate break; 17150Sstevel@tonic-gate } 17160Sstevel@tonic-gate if (ret) 17170Sstevel@tonic-gate break; 17180Sstevel@tonic-gate if ((intptr_t)ip != (intptr_t)end - sizeof (int)) { 17190Sstevel@tonic-gate /* did not exactly fill buffer */ 17200Sstevel@tonic-gate ret = EINVAL; 17210Sstevel@tonic-gate break; 17220Sstevel@tonic-gate } 17230Sstevel@tonic-gate if (comps == 0) { 17240Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s 0 components" 17250Sstevel@tonic-gate "--EINVAL\n", cmdstr, req.physpath)) 17260Sstevel@tonic-gate ret = EINVAL; 17270Sstevel@tonic-gate break; 17280Sstevel@tonic-gate } 17290Sstevel@tonic-gate /* 17300Sstevel@tonic-gate * The header struct plus one entry struct per component 17310Sstevel@tonic-gate * plus the size of the lists minus the counts 17320Sstevel@tonic-gate * plus the length of the string 17330Sstevel@tonic-gate */ 17340Sstevel@tonic-gate size = sizeof (pm_thresh_rec_t) + 17350Sstevel@tonic-gate (sizeof (pm_pte_t) * comps) + req.datasize - 17360Sstevel@tonic-gate ((comps + 1) * sizeof (int)) + 17370Sstevel@tonic-gate strlen(req.physpath) + 1; 17380Sstevel@tonic-gate 17390Sstevel@tonic-gate rp = kmem_zalloc(size, KM_SLEEP); 17400Sstevel@tonic-gate rp->ptr_size = size; 17410Sstevel@tonic-gate rp->ptr_numcomps = comps; 17420Sstevel@tonic-gate ep = (pm_pte_t *)((intptr_t)rp + sizeof (*rp)); 17430Sstevel@tonic-gate rp->ptr_entries = ep; 17440Sstevel@tonic-gate tp = (int *)((intptr_t)ep + 17450Sstevel@tonic-gate (comps * sizeof (pm_pte_t))); 17460Sstevel@tonic-gate for (ip = req.data; *ip; ep++) { 17470Sstevel@tonic-gate ep->pte_numthresh = *ip; 17480Sstevel@tonic-gate ep->pte_thresh = tp; 17490Sstevel@tonic-gate for (j = *ip++; j; j--) { 17500Sstevel@tonic-gate *tp++ = *ip++; 17510Sstevel@tonic-gate } 17520Sstevel@tonic-gate } 17530Sstevel@tonic-gate (void) strcat((char *)tp, req.physpath); 17540Sstevel@tonic-gate rp->ptr_physpath = (char *)tp; 17550Sstevel@tonic-gate ASSERT((intptr_t)end == (intptr_t)ip + sizeof (int)); 17560Sstevel@tonic-gate ASSERT((intptr_t)tp + strlen(req.physpath) + 1 == 17570Sstevel@tonic-gate (intptr_t)rp + rp->ptr_size); 17580Sstevel@tonic-gate 17590Sstevel@tonic-gate ASSERT(dip == NULL); 17600Sstevel@tonic-gate /* 17610Sstevel@tonic-gate * If this is not a currently power managed node, 17620Sstevel@tonic-gate * then we can't check for validity of the thresholds 17630Sstevel@tonic-gate */ 17640Sstevel@tonic-gate if (!(dip = pm_name_to_dip(req.physpath, 1))) { 17650Sstevel@tonic-gate /* don't free rp, pm_record_thresh uses it */ 17660Sstevel@tonic-gate pm_record_thresh(rp); 17670Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: pm_name_to_dip " 17680Sstevel@tonic-gate "for %s failed\n", cmdstr, req.physpath)) 17690Sstevel@tonic-gate ret = 0; 17700Sstevel@tonic-gate break; 17710Sstevel@tonic-gate } 17720Sstevel@tonic-gate ASSERT(!dipheld); 17730Sstevel@tonic-gate dipheld++; 17740Sstevel@tonic-gate 17750Sstevel@tonic-gate if (!pm_valid_thresh(dip, rp)) { 17760Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: invalid thresh " 17770Sstevel@tonic-gate "for %s@%s(%s#%d)\n", cmdstr, 17780Sstevel@tonic-gate PM_DEVICE(dip))) 17790Sstevel@tonic-gate kmem_free(rp, size); 17800Sstevel@tonic-gate ret = EINVAL; 17810Sstevel@tonic-gate break; 17820Sstevel@tonic-gate } 17830Sstevel@tonic-gate /* 17840Sstevel@tonic-gate * We don't just apply it ourselves because we'd need 17850Sstevel@tonic-gate * to know too much about locking. Since we don't 17860Sstevel@tonic-gate * hold a lock the entry could be removed before 17870Sstevel@tonic-gate * we get here 17880Sstevel@tonic-gate */ 17890Sstevel@tonic-gate pm_record_thresh(rp); 17900Sstevel@tonic-gate (void) pm_thresh_specd(dip); 17910Sstevel@tonic-gate ret = 0; 17920Sstevel@tonic-gate break; 17930Sstevel@tonic-gate } 17940Sstevel@tonic-gate 17950Sstevel@tonic-gate case PM_GET_COMPONENT_THRESHOLDS: 17960Sstevel@tonic-gate { 17970Sstevel@tonic-gate int musthave; 17980Sstevel@tonic-gate int numthresholds = 0; 17990Sstevel@tonic-gate int wordsize; 18000Sstevel@tonic-gate int numcomps; 18010Sstevel@tonic-gate caddr_t uaddr = req.data; /* user address */ 18020Sstevel@tonic-gate int val; /* int value to be copied out */ 18030Sstevel@tonic-gate int32_t val32; /* int32 value to be copied out */ 18040Sstevel@tonic-gate caddr_t vaddr; /* address to copyout from */ 18050Sstevel@tonic-gate int j; 18060Sstevel@tonic-gate 18070Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 18080Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) { 18090Sstevel@tonic-gate wordsize = sizeof (int32_t); 18100Sstevel@tonic-gate } else 18110Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 18120Sstevel@tonic-gate { 18130Sstevel@tonic-gate wordsize = sizeof (int); 18140Sstevel@tonic-gate } 18150Sstevel@tonic-gate 18160Sstevel@tonic-gate ASSERT(dip); 18170Sstevel@tonic-gate 18180Sstevel@tonic-gate numcomps = PM_NUMCMPTS(dip); 18190Sstevel@tonic-gate for (i = 0; i < numcomps; i++) { 18200Sstevel@tonic-gate cp = PM_CP(dip, i); 18210Sstevel@tonic-gate numthresholds += cp->pmc_comp.pmc_numlevels - 1; 18220Sstevel@tonic-gate } 18230Sstevel@tonic-gate musthave = (numthresholds + numcomps + 1) * wordsize; 18240Sstevel@tonic-gate if (req.datasize < musthave) { 18250Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: size %ld, need " 18260Sstevel@tonic-gate "%d--EINVAL\n", cmdstr, req.datasize, 18270Sstevel@tonic-gate musthave)) 18280Sstevel@tonic-gate ret = EINVAL; 18290Sstevel@tonic-gate break; 18300Sstevel@tonic-gate } 18310Sstevel@tonic-gate PM_LOCK_DIP(dip); 18320Sstevel@tonic-gate for (i = 0; i < numcomps; i++) { 18330Sstevel@tonic-gate int *thp; 18340Sstevel@tonic-gate cp = PM_CP(dip, i); 18350Sstevel@tonic-gate thp = cp->pmc_comp.pmc_thresh; 18360Sstevel@tonic-gate /* first copyout the count */ 18370Sstevel@tonic-gate if (wordsize == sizeof (int32_t)) { 18380Sstevel@tonic-gate val32 = cp->pmc_comp.pmc_numlevels - 1; 18390Sstevel@tonic-gate vaddr = (caddr_t)&val32; 18400Sstevel@tonic-gate } else { 18410Sstevel@tonic-gate val = cp->pmc_comp.pmc_numlevels - 1; 18420Sstevel@tonic-gate vaddr = (caddr_t)&val; 18430Sstevel@tonic-gate } 18440Sstevel@tonic-gate if (ddi_copyout(vaddr, (void *)uaddr, 18450Sstevel@tonic-gate wordsize, mode) != 0) { 18460Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 18470Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s" 18480Sstevel@tonic-gate "(%s#%d) vaddr %p EFAULT\n", 18490Sstevel@tonic-gate cmdstr, PM_DEVICE(dip), 18500Sstevel@tonic-gate (void*)vaddr)) 18510Sstevel@tonic-gate ret = EFAULT; 18520Sstevel@tonic-gate break; 18530Sstevel@tonic-gate } 18540Sstevel@tonic-gate vaddr = uaddr; 18550Sstevel@tonic-gate vaddr += wordsize; 18560Sstevel@tonic-gate uaddr = (caddr_t)vaddr; 18570Sstevel@tonic-gate /* then copyout each threshold value */ 18580Sstevel@tonic-gate for (j = 0; j < cp->pmc_comp.pmc_numlevels - 1; 18590Sstevel@tonic-gate j++) { 18600Sstevel@tonic-gate if (wordsize == sizeof (int32_t)) { 18610Sstevel@tonic-gate val32 = thp[j + 1]; 18620Sstevel@tonic-gate vaddr = (caddr_t)&val32; 18630Sstevel@tonic-gate } else { 18640Sstevel@tonic-gate val = thp[i + 1]; 18650Sstevel@tonic-gate vaddr = (caddr_t)&val; 18660Sstevel@tonic-gate } 18670Sstevel@tonic-gate if (ddi_copyout(vaddr, (void *) uaddr, 18680Sstevel@tonic-gate wordsize, mode) != 0) { 18690Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 18700Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: " 18710Sstevel@tonic-gate "%s@%s(%s#%d) uaddr %p " 18720Sstevel@tonic-gate "EFAULT\n", cmdstr, 18730Sstevel@tonic-gate PM_DEVICE(dip), 18740Sstevel@tonic-gate (void *)uaddr)) 18750Sstevel@tonic-gate ret = EFAULT; 18760Sstevel@tonic-gate break; 18770Sstevel@tonic-gate } 18780Sstevel@tonic-gate vaddr = uaddr; 18790Sstevel@tonic-gate vaddr += wordsize; 18800Sstevel@tonic-gate uaddr = (caddr_t)vaddr; 18810Sstevel@tonic-gate } 18820Sstevel@tonic-gate } 18830Sstevel@tonic-gate if (ret) 18840Sstevel@tonic-gate break; 18850Sstevel@tonic-gate /* last copyout a terminating 0 count */ 18860Sstevel@tonic-gate if (wordsize == sizeof (int32_t)) { 18870Sstevel@tonic-gate val32 = 0; 18880Sstevel@tonic-gate vaddr = (caddr_t)&val32; 18890Sstevel@tonic-gate } else { 18900Sstevel@tonic-gate ASSERT(wordsize == sizeof (int)); 18910Sstevel@tonic-gate val = 0; 18920Sstevel@tonic-gate vaddr = (caddr_t)&val; 18930Sstevel@tonic-gate } 18940Sstevel@tonic-gate if (ddi_copyout(vaddr, uaddr, wordsize, mode) != 0) { 18950Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 18960Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) " 18970Sstevel@tonic-gate "vaddr %p (0 count) EFAULT\n", cmdstr, 18980Sstevel@tonic-gate PM_DEVICE(dip), (void *)vaddr)) 18990Sstevel@tonic-gate ret = EFAULT; 19000Sstevel@tonic-gate break; 19010Sstevel@tonic-gate } 19020Sstevel@tonic-gate /* finished, so don't need to increment addresses */ 19030Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 19040Sstevel@tonic-gate ret = 0; 19050Sstevel@tonic-gate break; 19060Sstevel@tonic-gate } 19070Sstevel@tonic-gate 19080Sstevel@tonic-gate case PM_GET_STATS: 19090Sstevel@tonic-gate { 19100Sstevel@tonic-gate time_t now; 19110Sstevel@tonic-gate time_t *timestamp; 19120Sstevel@tonic-gate extern int pm_cur_power(pm_component_t *cp); 19130Sstevel@tonic-gate int musthave; 19140Sstevel@tonic-gate int wordsize; 19150Sstevel@tonic-gate 19160Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 19170Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) { 19180Sstevel@tonic-gate wordsize = sizeof (int32_t); 19190Sstevel@tonic-gate } else 19200Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 19210Sstevel@tonic-gate { 19220Sstevel@tonic-gate wordsize = sizeof (int); 19230Sstevel@tonic-gate } 19240Sstevel@tonic-gate 19250Sstevel@tonic-gate comps = PM_NUMCMPTS(dip); 19260Sstevel@tonic-gate if (comps == 0 || PM_GET_PM_INFO(dip) == NULL) { 19270Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s no components" 19280Sstevel@tonic-gate " or not power managed--EINVAL\n", cmdstr, 19290Sstevel@tonic-gate req.physpath)) 19300Sstevel@tonic-gate ret = EINVAL; 19310Sstevel@tonic-gate break; 19320Sstevel@tonic-gate } 19330Sstevel@tonic-gate musthave = comps * 2 * wordsize; 19340Sstevel@tonic-gate if (req.datasize < musthave) { 19350Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: size %lu, need " 19360Sstevel@tonic-gate "%d--EINVAL\n", cmdstr, req.datasize, 19370Sstevel@tonic-gate musthave)) 19380Sstevel@tonic-gate ret = EINVAL; 19390Sstevel@tonic-gate break; 19400Sstevel@tonic-gate } 19410Sstevel@tonic-gate 19420Sstevel@tonic-gate PM_LOCK_DIP(dip); 19430Sstevel@tonic-gate (void) drv_getparm(TIME, &now); 19440Sstevel@tonic-gate timestamp = kmem_zalloc(comps * sizeof (time_t), 19450Sstevel@tonic-gate KM_SLEEP); 19460Sstevel@tonic-gate pm_get_timestamps(dip, timestamp); 19470Sstevel@tonic-gate /* 19480Sstevel@tonic-gate * First the current power levels 19490Sstevel@tonic-gate */ 19500Sstevel@tonic-gate for (i = 0; i < comps; i++) { 19510Sstevel@tonic-gate int curpwr; 19520Sstevel@tonic-gate int32_t curpwr32; 19530Sstevel@tonic-gate caddr_t cpaddr; 19540Sstevel@tonic-gate 19550Sstevel@tonic-gate cp = PM_CP(dip, i); 19560Sstevel@tonic-gate if (wordsize == sizeof (int)) { 19570Sstevel@tonic-gate curpwr = pm_cur_power(cp); 19580Sstevel@tonic-gate cpaddr = (caddr_t)&curpwr; 19590Sstevel@tonic-gate } else { 19600Sstevel@tonic-gate ASSERT(wordsize == sizeof (int32_t)); 19610Sstevel@tonic-gate curpwr32 = pm_cur_power(cp); 19620Sstevel@tonic-gate cpaddr = (caddr_t)&curpwr32; 19630Sstevel@tonic-gate } 19640Sstevel@tonic-gate if (ddi_copyout(cpaddr, (void *) req.data, 19650Sstevel@tonic-gate wordsize, mode) != 0) { 19660Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 19670Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s" 19680Sstevel@tonic-gate "(%s#%d) req.data %p EFAULT\n", 19690Sstevel@tonic-gate cmdstr, PM_DEVICE(dip), 19700Sstevel@tonic-gate (void *)req.data)) 19710Sstevel@tonic-gate ASSERT(!dipheld); 19720Sstevel@tonic-gate return (EFAULT); 19730Sstevel@tonic-gate } 19740Sstevel@tonic-gate cpaddr = (caddr_t)req.data; 19750Sstevel@tonic-gate cpaddr += wordsize; 19760Sstevel@tonic-gate req.data = cpaddr; 19770Sstevel@tonic-gate } 19780Sstevel@tonic-gate /* 19790Sstevel@tonic-gate * Then the times remaining 19800Sstevel@tonic-gate */ 19810Sstevel@tonic-gate for (i = 0; i < comps; i++) { 19820Sstevel@tonic-gate int retval; 19830Sstevel@tonic-gate int32_t retval32; 19840Sstevel@tonic-gate caddr_t rvaddr; 19850Sstevel@tonic-gate int curpwr; 19860Sstevel@tonic-gate 19870Sstevel@tonic-gate cp = PM_CP(dip, i); 19880Sstevel@tonic-gate curpwr = cp->pmc_cur_pwr; 19890Sstevel@tonic-gate if (curpwr == 0 || timestamp[i] == 0) { 19900Sstevel@tonic-gate PMD(PMD_STATS, ("ioctl: %s: " 19910Sstevel@tonic-gate "cur_pwer %x, timestamp %lx\n", 19920Sstevel@tonic-gate cmdstr, curpwr, timestamp[i])) 19930Sstevel@tonic-gate retval = INT_MAX; 19940Sstevel@tonic-gate } else { 19950Sstevel@tonic-gate int thresh; 19960Sstevel@tonic-gate (void) pm_current_threshold(dip, i, 19970Sstevel@tonic-gate &thresh); 19980Sstevel@tonic-gate retval = thresh - (now - timestamp[i]); 19990Sstevel@tonic-gate PMD(PMD_STATS, ("ioctl: %s: current " 20000Sstevel@tonic-gate "thresh %x, now %lx, timestamp %lx," 20010Sstevel@tonic-gate " retval %x\n", cmdstr, thresh, now, 20020Sstevel@tonic-gate timestamp[i], retval)) 20030Sstevel@tonic-gate } 20040Sstevel@tonic-gate if (wordsize == sizeof (int)) { 20050Sstevel@tonic-gate rvaddr = (caddr_t)&retval; 20060Sstevel@tonic-gate } else { 20070Sstevel@tonic-gate ASSERT(wordsize == sizeof (int32_t)); 20080Sstevel@tonic-gate retval32 = retval; 20090Sstevel@tonic-gate rvaddr = (caddr_t)&retval32; 20100Sstevel@tonic-gate } 20110Sstevel@tonic-gate if (ddi_copyout(rvaddr, (void *) req.data, 20120Sstevel@tonic-gate wordsize, mode) != 0) { 20130Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 20140Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s" 20150Sstevel@tonic-gate "(%s#%d) req.data %p EFAULT\n", 20160Sstevel@tonic-gate cmdstr, PM_DEVICE(dip), 20170Sstevel@tonic-gate (void *)req.data)) 20180Sstevel@tonic-gate ASSERT(!dipheld); 20195295Srandyf kmem_free(timestamp, 20205295Srandyf comps * sizeof (time_t)); 20210Sstevel@tonic-gate return (EFAULT); 20220Sstevel@tonic-gate } 20230Sstevel@tonic-gate rvaddr = (caddr_t)req.data; 20240Sstevel@tonic-gate rvaddr += wordsize; 20250Sstevel@tonic-gate req.data = (int *)rvaddr; 20260Sstevel@tonic-gate } 20270Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 20280Sstevel@tonic-gate *rval_p = comps; 20290Sstevel@tonic-gate ret = 0; 20300Sstevel@tonic-gate kmem_free(timestamp, comps * sizeof (time_t)); 20310Sstevel@tonic-gate break; 20320Sstevel@tonic-gate } 20330Sstevel@tonic-gate 20345295Srandyf case PM_GET_CMD_NAME: 20355295Srandyf { 20365295Srandyf PMD(PMD_IOCTL, ("%s: %s\n", cmdstr, 20375295Srandyf pm_decode_cmd(req.value))) 20385295Srandyf if (ret = copyoutstr(pm_decode_cmd(req.value), 20395295Srandyf (char *)req.data, req.datasize, &lencopied)) { 20405295Srandyf PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) " 20415295Srandyf "copyoutstr %p failed--EFAULT\n", cmdstr, 20425295Srandyf PM_DEVICE(dip), (void *)req.data)) 20435295Srandyf break; 20445295Srandyf } 20455295Srandyf *rval_p = lencopied; 20465295Srandyf ret = 0; 20475295Srandyf break; 20485295Srandyf } 20495295Srandyf 20500Sstevel@tonic-gate case PM_GET_COMPONENT_NAME: 20515295Srandyf { 20520Sstevel@tonic-gate ASSERT(dip); 20530Sstevel@tonic-gate if (!e_pm_valid_comp(dip, req.component, &cp)) { 20540Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) " 20550Sstevel@tonic-gate "component %d > numcmpts - 1 %d--EINVAL\n", 20560Sstevel@tonic-gate cmdstr, PM_DEVICE(dip), req.component, 20570Sstevel@tonic-gate PM_NUMCMPTS(dip) - 1)) 20580Sstevel@tonic-gate ret = EINVAL; 20590Sstevel@tonic-gate break; 20600Sstevel@tonic-gate } 20610Sstevel@tonic-gate if (ret = copyoutstr(cp->pmc_comp.pmc_name, 20620Sstevel@tonic-gate (char *)req.data, req.datasize, &lencopied)) { 20630Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) " 20640Sstevel@tonic-gate "copyoutstr %p failed--EFAULT\n", cmdstr, 20650Sstevel@tonic-gate PM_DEVICE(dip), (void *)req.data)) 20660Sstevel@tonic-gate break; 20670Sstevel@tonic-gate } 20680Sstevel@tonic-gate *rval_p = lencopied; 20690Sstevel@tonic-gate ret = 0; 20700Sstevel@tonic-gate break; 20715295Srandyf } 20720Sstevel@tonic-gate 20730Sstevel@tonic-gate case PM_GET_POWER_NAME: 20740Sstevel@tonic-gate { 20750Sstevel@tonic-gate int i; 20760Sstevel@tonic-gate 20770Sstevel@tonic-gate ASSERT(dip); 20780Sstevel@tonic-gate if (!e_pm_valid_comp(dip, req.component, &cp)) { 20790Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) " 20800Sstevel@tonic-gate "component %d > numcmpts - 1 %d--EINVAL\n", 20810Sstevel@tonic-gate cmdstr, PM_DEVICE(dip), req.component, 20820Sstevel@tonic-gate PM_NUMCMPTS(dip) - 1)) 20830Sstevel@tonic-gate ret = EINVAL; 20840Sstevel@tonic-gate break; 20850Sstevel@tonic-gate } 20860Sstevel@tonic-gate if ((i = req.value) < 0 || 20870Sstevel@tonic-gate i > cp->pmc_comp.pmc_numlevels - 1) { 20880Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) " 20890Sstevel@tonic-gate "value %d > num_levels - 1 %d--EINVAL\n", 20900Sstevel@tonic-gate cmdstr, PM_DEVICE(dip), req.value, 20910Sstevel@tonic-gate cp->pmc_comp.pmc_numlevels - 1)) 20920Sstevel@tonic-gate ret = EINVAL; 20930Sstevel@tonic-gate break; 20940Sstevel@tonic-gate } 20950Sstevel@tonic-gate dep = cp->pmc_comp.pmc_lnames[req.value]; 20960Sstevel@tonic-gate if (ret = copyoutstr(dep, 20970Sstevel@tonic-gate req.data, req.datasize, &lencopied)) { 20980Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) " 20990Sstevel@tonic-gate "copyoutstr %p failed--EFAULT\n", cmdstr, 21000Sstevel@tonic-gate PM_DEVICE(dip), (void *)req.data)) 21010Sstevel@tonic-gate break; 21020Sstevel@tonic-gate } 21030Sstevel@tonic-gate *rval_p = lencopied; 21040Sstevel@tonic-gate ret = 0; 21050Sstevel@tonic-gate break; 21060Sstevel@tonic-gate } 21070Sstevel@tonic-gate 21080Sstevel@tonic-gate case PM_GET_POWER_LEVELS: 21090Sstevel@tonic-gate { 21100Sstevel@tonic-gate int musthave; 21110Sstevel@tonic-gate int numlevels; 21120Sstevel@tonic-gate int wordsize; 21130Sstevel@tonic-gate 21140Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 21150Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) { 21160Sstevel@tonic-gate wordsize = sizeof (int32_t); 21170Sstevel@tonic-gate } else 21180Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 21190Sstevel@tonic-gate { 21200Sstevel@tonic-gate wordsize = sizeof (int); 21210Sstevel@tonic-gate } 21220Sstevel@tonic-gate ASSERT(dip); 21230Sstevel@tonic-gate 21240Sstevel@tonic-gate if (!e_pm_valid_comp(dip, req.component, &cp)) { 21250Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) " 21260Sstevel@tonic-gate "has %d components, component %d requested" 21270Sstevel@tonic-gate "--EINVAL\n", cmdstr, PM_DEVICE(dip), 21280Sstevel@tonic-gate PM_NUMCMPTS(dip), req.component)) 21290Sstevel@tonic-gate ret = EINVAL; 21300Sstevel@tonic-gate break; 21310Sstevel@tonic-gate } 21320Sstevel@tonic-gate numlevels = cp->pmc_comp.pmc_numlevels; 21330Sstevel@tonic-gate musthave = numlevels * wordsize; 21340Sstevel@tonic-gate if (req.datasize < musthave) { 21350Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: size %lu, need " 21360Sstevel@tonic-gate "%d--EINVAL\n", cmdstr, req.datasize, 21370Sstevel@tonic-gate musthave)) 21380Sstevel@tonic-gate ret = EINVAL; 21390Sstevel@tonic-gate break; 21400Sstevel@tonic-gate } 21410Sstevel@tonic-gate PM_LOCK_DIP(dip); 21420Sstevel@tonic-gate for (i = 0; i < numlevels; i++) { 21430Sstevel@tonic-gate int level; 21440Sstevel@tonic-gate int32_t level32; 21450Sstevel@tonic-gate caddr_t laddr; 21460Sstevel@tonic-gate 21470Sstevel@tonic-gate if (wordsize == sizeof (int)) { 21480Sstevel@tonic-gate level = cp->pmc_comp.pmc_lvals[i]; 21490Sstevel@tonic-gate laddr = (caddr_t)&level; 21500Sstevel@tonic-gate } else { 21510Sstevel@tonic-gate level32 = cp->pmc_comp.pmc_lvals[i]; 21520Sstevel@tonic-gate laddr = (caddr_t)&level32; 21530Sstevel@tonic-gate } 21540Sstevel@tonic-gate if (ddi_copyout(laddr, (void *) req.data, 21550Sstevel@tonic-gate wordsize, mode) != 0) { 21560Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 21570Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s" 21580Sstevel@tonic-gate "(%s#%d) laddr %p EFAULT\n", 21590Sstevel@tonic-gate cmdstr, PM_DEVICE(dip), 21600Sstevel@tonic-gate (void *)laddr)) 21610Sstevel@tonic-gate ASSERT(!dipheld); 21620Sstevel@tonic-gate return (EFAULT); 21630Sstevel@tonic-gate } 21640Sstevel@tonic-gate laddr = (caddr_t)req.data; 21650Sstevel@tonic-gate laddr += wordsize; 21660Sstevel@tonic-gate req.data = (int *)laddr; 21670Sstevel@tonic-gate } 21680Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 21690Sstevel@tonic-gate *rval_p = numlevels; 21700Sstevel@tonic-gate ret = 0; 21710Sstevel@tonic-gate break; 21720Sstevel@tonic-gate } 21730Sstevel@tonic-gate 21740Sstevel@tonic-gate 21750Sstevel@tonic-gate case PM_GET_NUM_POWER_LEVELS: 21765295Srandyf { 21770Sstevel@tonic-gate if (!e_pm_valid_comp(dip, req.component, &cp)) { 21780Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) " 21790Sstevel@tonic-gate "component %d > numcmpts - 1 %d--EINVAL\n", 21800Sstevel@tonic-gate cmdstr, PM_DEVICE(dip), req.component, 21810Sstevel@tonic-gate PM_NUMCMPTS(dip) - 1)) 21820Sstevel@tonic-gate ret = EINVAL; 21830Sstevel@tonic-gate break; 21840Sstevel@tonic-gate } 21850Sstevel@tonic-gate *rval_p = cp->pmc_comp.pmc_numlevels; 21860Sstevel@tonic-gate ret = 0; 21870Sstevel@tonic-gate break; 21885295Srandyf } 21890Sstevel@tonic-gate 21900Sstevel@tonic-gate case PM_GET_DEVICE_THRESHOLD_BASIS: 21915295Srandyf { 21920Sstevel@tonic-gate ret = 0; 21930Sstevel@tonic-gate PM_LOCK_DIP(dip); 21940Sstevel@tonic-gate if ((info = PM_GET_PM_INFO(dip)) == NULL) { 21950Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 21960Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: " 21970Sstevel@tonic-gate "PM_NO_PM_COMPONENTS\n", cmdstr)) 21980Sstevel@tonic-gate *rval_p = PM_NO_PM_COMPONENTS; 21990Sstevel@tonic-gate break; 22000Sstevel@tonic-gate } 22010Sstevel@tonic-gate if (PM_ISDIRECT(dip)) { 22020Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 22030Sstevel@tonic-gate *rval_p = PM_DIRECTLY_MANAGED; 22040Sstevel@tonic-gate break; 22050Sstevel@tonic-gate } 22060Sstevel@tonic-gate switch (DEVI(dip)->devi_pm_flags & PMC_THRESH_ALL) { 22070Sstevel@tonic-gate case PMC_DEF_THRESH: 22080Sstevel@tonic-gate case PMC_NEXDEF_THRESH: 22090Sstevel@tonic-gate *rval_p = PM_DEFAULT_THRESHOLD; 22100Sstevel@tonic-gate break; 22110Sstevel@tonic-gate case PMC_DEV_THRESH: 22120Sstevel@tonic-gate *rval_p = PM_DEVICE_THRESHOLD; 22130Sstevel@tonic-gate break; 22140Sstevel@tonic-gate case PMC_COMP_THRESH: 22150Sstevel@tonic-gate *rval_p = PM_COMPONENT_THRESHOLD; 22160Sstevel@tonic-gate break; 22173028Smh27603 case PMC_CPU_THRESH: 22183028Smh27603 *rval_p = PM_CPU_THRESHOLD; 22193028Smh27603 break; 22200Sstevel@tonic-gate default: 22210Sstevel@tonic-gate if (PM_ISBC(dip)) { 22220Sstevel@tonic-gate *rval_p = PM_OLD_THRESHOLD; 22230Sstevel@tonic-gate break; 22240Sstevel@tonic-gate } 22250Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: default, not " 22260Sstevel@tonic-gate "BC--EINVAL", cmdstr)) 22270Sstevel@tonic-gate ret = EINVAL; 22280Sstevel@tonic-gate break; 22290Sstevel@tonic-gate } 22300Sstevel@tonic-gate PM_UNLOCK_DIP(dip); 22310Sstevel@tonic-gate break; 22320Sstevel@tonic-gate } 22335295Srandyf default: 22345295Srandyf /* 22355295Srandyf * Internal error, invalid ioctl description 22365295Srandyf * force debug entry even if pm_debug not set 22375295Srandyf */ 22385295Srandyf #ifdef DEBUG 22395295Srandyf pm_log("invalid diptype %d for cmd %d (%s)\n", 22405295Srandyf pcip->diptype, cmd, pcip->name); 22415295Srandyf #endif 22425295Srandyf ASSERT(0); 22435295Srandyf return (EIO); 22445295Srandyf } 22450Sstevel@tonic-gate break; 22465295Srandyf } 22470Sstevel@tonic-gate 22480Sstevel@tonic-gate case PM_PSC: 22495295Srandyf { 22500Sstevel@tonic-gate /* 22510Sstevel@tonic-gate * Commands that require pm_state_change_t as arg 22520Sstevel@tonic-gate */ 22530Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 22540Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) { 22550Sstevel@tonic-gate pscp32 = (pm_state_change32_t *)arg; 22560Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg, &psc32, 22570Sstevel@tonic-gate sizeof (psc32), mode) != 0) { 22580Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin " 22590Sstevel@tonic-gate "EFAULT\n\n", cmdstr)) 22600Sstevel@tonic-gate ASSERT(!dipheld); 22610Sstevel@tonic-gate return (EFAULT); 22620Sstevel@tonic-gate } 22630Sstevel@tonic-gate psc.physpath = (caddr_t)(uintptr_t)psc32.physpath; 22640Sstevel@tonic-gate psc.size = psc32.size; 22650Sstevel@tonic-gate } else 22660Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 22670Sstevel@tonic-gate { 22680Sstevel@tonic-gate pscp = (pm_state_change_t *)arg; 22690Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg, &psc, 22700Sstevel@tonic-gate sizeof (psc), mode) != 0) { 22710Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin " 22720Sstevel@tonic-gate "EFAULT\n\n", cmdstr)) 22730Sstevel@tonic-gate ASSERT(!dipheld); 22740Sstevel@tonic-gate return (EFAULT); 22750Sstevel@tonic-gate } 22760Sstevel@tonic-gate } 22770Sstevel@tonic-gate switch (cmd) { 22780Sstevel@tonic-gate 22790Sstevel@tonic-gate case PM_GET_STATE_CHANGE: 22800Sstevel@tonic-gate case PM_GET_STATE_CHANGE_WAIT: 22810Sstevel@tonic-gate { 22820Sstevel@tonic-gate psce_t *pscep; 22830Sstevel@tonic-gate pm_state_change_t *p; 22840Sstevel@tonic-gate caddr_t physpath; 22850Sstevel@tonic-gate size_t physlen; 22860Sstevel@tonic-gate 22870Sstevel@tonic-gate /* 22880Sstevel@tonic-gate * We want to know if any device has changed state. 22890Sstevel@tonic-gate * We look up by clone. In case we have another thread 22900Sstevel@tonic-gate * from the same process, we loop. 22910Sstevel@tonic-gate * pm_psc_clone_to_interest() returns a locked entry. 22920Sstevel@tonic-gate * We create an internal copy of the event entry prior 22930Sstevel@tonic-gate * to copyout to user space because we don't want to 22940Sstevel@tonic-gate * hold the psce_lock while doing copyout as we might 22950Sstevel@tonic-gate * hit page fault which eventually brings us back 22960Sstevel@tonic-gate * here requesting the same lock. 22970Sstevel@tonic-gate */ 22980Sstevel@tonic-gate mutex_enter(&pm_clone_lock); 22990Sstevel@tonic-gate if (!pm_interest_registered(clone)) 23000Sstevel@tonic-gate pm_register_watcher(clone, NULL); 23010Sstevel@tonic-gate while ((pscep = 23020Sstevel@tonic-gate pm_psc_clone_to_interest(clone)) == NULL) { 23030Sstevel@tonic-gate if (cmd == PM_GET_STATE_CHANGE) { 23040Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: %s: " 23050Sstevel@tonic-gate "EWOULDBLOCK\n", cmdstr)) 23060Sstevel@tonic-gate mutex_exit(&pm_clone_lock); 23070Sstevel@tonic-gate ASSERT(!dipheld); 23080Sstevel@tonic-gate return (EWOULDBLOCK); 23090Sstevel@tonic-gate } else { 23100Sstevel@tonic-gate if (cv_wait_sig(&pm_clones_cv[clone], 23110Sstevel@tonic-gate &pm_clone_lock) == 0) { 23120Sstevel@tonic-gate mutex_exit(&pm_clone_lock); 23130Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s " 23140Sstevel@tonic-gate "EINTR\n", cmdstr)) 23150Sstevel@tonic-gate ASSERT(!dipheld); 23160Sstevel@tonic-gate return (EINTR); 23170Sstevel@tonic-gate } 23180Sstevel@tonic-gate } 23190Sstevel@tonic-gate } 23200Sstevel@tonic-gate mutex_exit(&pm_clone_lock); 23210Sstevel@tonic-gate 23220Sstevel@tonic-gate physlen = pscep->psce_out->size; 23230Sstevel@tonic-gate physpath = NULL; 23240Sstevel@tonic-gate /* 23250Sstevel@tonic-gate * If we were unable to store the path while bringing 23260Sstevel@tonic-gate * up the console fb upon entering the prom, we give 23270Sstevel@tonic-gate * a "" name with the overrun event set 23280Sstevel@tonic-gate */ 23290Sstevel@tonic-gate if (physlen == (size_t)-1) { /* kmemalloc failed */ 23300Sstevel@tonic-gate physpath = kmem_zalloc(1, KM_SLEEP); 23310Sstevel@tonic-gate physlen = 1; 23320Sstevel@tonic-gate } 23330Sstevel@tonic-gate if ((psc.physpath == NULL) || (psc.size < physlen)) { 23340Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: EFAULT\n", cmdstr)) 23350Sstevel@tonic-gate mutex_exit(&pscep->psce_lock); 23360Sstevel@tonic-gate ret = EFAULT; 23370Sstevel@tonic-gate break; 23380Sstevel@tonic-gate } 23390Sstevel@tonic-gate if (physpath == NULL) { 23400Sstevel@tonic-gate physpath = kmem_zalloc(physlen, KM_SLEEP); 23410Sstevel@tonic-gate bcopy((const void *) pscep->psce_out->physpath, 23420Sstevel@tonic-gate (void *) physpath, physlen); 23430Sstevel@tonic-gate } 23440Sstevel@tonic-gate 23450Sstevel@tonic-gate p = pscep->psce_out; 23460Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 23470Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) { 23480Sstevel@tonic-gate #ifdef DEBUG 23490Sstevel@tonic-gate size_t usrcopysize; 23500Sstevel@tonic-gate #endif 23510Sstevel@tonic-gate psc32.flags = (ushort_t)p->flags; 23520Sstevel@tonic-gate psc32.event = (ushort_t)p->event; 23530Sstevel@tonic-gate psc32.timestamp = (int32_t)p->timestamp; 23540Sstevel@tonic-gate psc32.component = (int32_t)p->component; 23550Sstevel@tonic-gate psc32.old_level = (int32_t)p->old_level; 23560Sstevel@tonic-gate psc32.new_level = (int32_t)p->new_level; 23570Sstevel@tonic-gate copysize32 = ((intptr_t)&psc32.size - 23580Sstevel@tonic-gate (intptr_t)&psc32.component); 23590Sstevel@tonic-gate #ifdef DEBUG 23600Sstevel@tonic-gate usrcopysize = ((intptr_t)&pscp32->size - 23610Sstevel@tonic-gate (intptr_t)&pscp32->component); 23620Sstevel@tonic-gate ASSERT(usrcopysize == copysize32); 23630Sstevel@tonic-gate #endif 23640Sstevel@tonic-gate } else 23650Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 23660Sstevel@tonic-gate { 23670Sstevel@tonic-gate psc.flags = p->flags; 23680Sstevel@tonic-gate psc.event = p->event; 23690Sstevel@tonic-gate psc.timestamp = p->timestamp; 23700Sstevel@tonic-gate psc.component = p->component; 23710Sstevel@tonic-gate psc.old_level = p->old_level; 23720Sstevel@tonic-gate psc.new_level = p->new_level; 23730Sstevel@tonic-gate copysize = ((long)&p->size - 23740Sstevel@tonic-gate (long)&p->component); 23750Sstevel@tonic-gate } 23760Sstevel@tonic-gate if (p->size != (size_t)-1) 23770Sstevel@tonic-gate kmem_free(p->physpath, p->size); 23780Sstevel@tonic-gate p->size = 0; 23790Sstevel@tonic-gate p->physpath = NULL; 23800Sstevel@tonic-gate if (pscep->psce_out == pscep->psce_last) 23810Sstevel@tonic-gate p = pscep->psce_first; 23820Sstevel@tonic-gate else 23830Sstevel@tonic-gate p++; 23840Sstevel@tonic-gate pscep->psce_out = p; 23850Sstevel@tonic-gate mutex_exit(&pscep->psce_lock); 23860Sstevel@tonic-gate 23870Sstevel@tonic-gate ret = copyoutstr(physpath, psc.physpath, 23880Sstevel@tonic-gate physlen, &lencopied); 23890Sstevel@tonic-gate kmem_free(physpath, physlen); 23900Sstevel@tonic-gate if (ret) { 23910Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: copyoutstr %p " 23920Sstevel@tonic-gate "failed--EFAULT\n", cmdstr, 23930Sstevel@tonic-gate (void *)psc.physpath)) 23940Sstevel@tonic-gate break; 23950Sstevel@tonic-gate } 23960Sstevel@tonic-gate 23970Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 23980Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) { 23990Sstevel@tonic-gate if (ddi_copyout(&psc32.component, 24000Sstevel@tonic-gate &pscp32->component, copysize32, mode) 24010Sstevel@tonic-gate != 0) { 24020Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: copyout " 24030Sstevel@tonic-gate "failed--EFAULT\n", cmdstr)) 24040Sstevel@tonic-gate ret = EFAULT; 24050Sstevel@tonic-gate break; 24060Sstevel@tonic-gate } 24070Sstevel@tonic-gate } else 24080Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 24090Sstevel@tonic-gate { 24100Sstevel@tonic-gate if (ddi_copyout(&psc.component, 24110Sstevel@tonic-gate &pscp->component, copysize, mode) != 0) { 24120Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: copyout " 24130Sstevel@tonic-gate "failed--EFAULT\n", cmdstr)) 24140Sstevel@tonic-gate ret = EFAULT; 24150Sstevel@tonic-gate break; 24160Sstevel@tonic-gate } 24170Sstevel@tonic-gate } 24180Sstevel@tonic-gate ret = 0; 24190Sstevel@tonic-gate break; 24200Sstevel@tonic-gate } 24210Sstevel@tonic-gate 24220Sstevel@tonic-gate case PM_DIRECT_NOTIFY: 24230Sstevel@tonic-gate case PM_DIRECT_NOTIFY_WAIT: 24240Sstevel@tonic-gate { 24250Sstevel@tonic-gate psce_t *pscep; 24260Sstevel@tonic-gate pm_state_change_t *p; 24270Sstevel@tonic-gate caddr_t physpath; 24280Sstevel@tonic-gate size_t physlen; 24290Sstevel@tonic-gate /* 24300Sstevel@tonic-gate * We want to know if any direct device of ours has 24310Sstevel@tonic-gate * something we should know about. We look up by clone. 24320Sstevel@tonic-gate * In case we have another thread from the same process, 24330Sstevel@tonic-gate * we loop. 24340Sstevel@tonic-gate * pm_psc_clone_to_direct() returns a locked entry. 24350Sstevel@tonic-gate */ 24360Sstevel@tonic-gate mutex_enter(&pm_clone_lock); 24370Sstevel@tonic-gate while (pm_poll_cnt[clone] == 0 || 24380Sstevel@tonic-gate (pscep = pm_psc_clone_to_direct(clone)) == NULL) { 24390Sstevel@tonic-gate if (cmd == PM_DIRECT_NOTIFY) { 24400Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: %s: " 24410Sstevel@tonic-gate "EWOULDBLOCK\n", cmdstr)) 24420Sstevel@tonic-gate mutex_exit(&pm_clone_lock); 24430Sstevel@tonic-gate ASSERT(!dipheld); 24440Sstevel@tonic-gate return (EWOULDBLOCK); 24450Sstevel@tonic-gate } else { 24460Sstevel@tonic-gate if (cv_wait_sig(&pm_clones_cv[clone], 24470Sstevel@tonic-gate &pm_clone_lock) == 0) { 24480Sstevel@tonic-gate mutex_exit(&pm_clone_lock); 24490Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: " 24500Sstevel@tonic-gate "EINTR\n", cmdstr)) 24510Sstevel@tonic-gate ASSERT(!dipheld); 24520Sstevel@tonic-gate return (EINTR); 24530Sstevel@tonic-gate } 24540Sstevel@tonic-gate } 24550Sstevel@tonic-gate } 24560Sstevel@tonic-gate mutex_exit(&pm_clone_lock); 24570Sstevel@tonic-gate physlen = pscep->psce_out->size; 24580Sstevel@tonic-gate if ((psc.physpath == NULL) || (psc.size < physlen)) { 24590Sstevel@tonic-gate mutex_exit(&pscep->psce_lock); 24600Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: EFAULT\n", 24610Sstevel@tonic-gate cmdstr)) 24620Sstevel@tonic-gate ret = EFAULT; 24630Sstevel@tonic-gate break; 24640Sstevel@tonic-gate } 24650Sstevel@tonic-gate physpath = kmem_zalloc(physlen, KM_SLEEP); 24660Sstevel@tonic-gate bcopy((const void *) pscep->psce_out->physpath, 24670Sstevel@tonic-gate (void *) physpath, physlen); 24680Sstevel@tonic-gate 24690Sstevel@tonic-gate p = pscep->psce_out; 24700Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 24710Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) { 24720Sstevel@tonic-gate #ifdef DEBUG 24730Sstevel@tonic-gate size_t usrcopysize; 24740Sstevel@tonic-gate #endif 24750Sstevel@tonic-gate psc32.component = (int32_t)p->component; 24760Sstevel@tonic-gate psc32.flags = (ushort_t)p->flags; 24770Sstevel@tonic-gate psc32.event = (ushort_t)p->event; 24780Sstevel@tonic-gate psc32.timestamp = (int32_t)p->timestamp; 24790Sstevel@tonic-gate psc32.old_level = (int32_t)p->old_level; 24800Sstevel@tonic-gate psc32.new_level = (int32_t)p->new_level; 24810Sstevel@tonic-gate copysize32 = (intptr_t)&psc32.size - 24820Sstevel@tonic-gate (intptr_t)&psc32.component; 24830Sstevel@tonic-gate PMD(PMD_DPM, ("ioctl: %s: PDN32 %s, comp %d " 24840Sstevel@tonic-gate "%d -> %d\n", cmdstr, physpath, 24850Sstevel@tonic-gate p->component, p->old_level, p->new_level)) 24860Sstevel@tonic-gate #ifdef DEBUG 24870Sstevel@tonic-gate usrcopysize = (intptr_t)&pscp32->size - 24880Sstevel@tonic-gate (intptr_t)&pscp32->component; 24890Sstevel@tonic-gate ASSERT(usrcopysize == copysize32); 24900Sstevel@tonic-gate #endif 24910Sstevel@tonic-gate } else 24920Sstevel@tonic-gate #endif 24930Sstevel@tonic-gate { 24940Sstevel@tonic-gate psc.component = p->component; 24950Sstevel@tonic-gate psc.flags = p->flags; 24960Sstevel@tonic-gate psc.event = p->event; 24970Sstevel@tonic-gate psc.timestamp = p->timestamp; 24980Sstevel@tonic-gate psc.old_level = p->old_level; 24990Sstevel@tonic-gate psc.new_level = p->new_level; 25000Sstevel@tonic-gate copysize = (intptr_t)&p->size - 25010Sstevel@tonic-gate (intptr_t)&p->component; 25020Sstevel@tonic-gate PMD(PMD_DPM, ("ioctl: %s: PDN %s, comp %d " 25030Sstevel@tonic-gate "%d -> %d\n", cmdstr, physpath, 25040Sstevel@tonic-gate p->component, p->old_level, p->new_level)) 25050Sstevel@tonic-gate } 25060Sstevel@tonic-gate mutex_enter(&pm_clone_lock); 25070Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: %s: pm_poll_cnt[%d] is %d " 25080Sstevel@tonic-gate "before decrement\n", cmdstr, clone, 25090Sstevel@tonic-gate pm_poll_cnt[clone])) 25100Sstevel@tonic-gate pm_poll_cnt[clone]--; 25110Sstevel@tonic-gate mutex_exit(&pm_clone_lock); 25120Sstevel@tonic-gate kmem_free(p->physpath, p->size); 25130Sstevel@tonic-gate p->size = 0; 25140Sstevel@tonic-gate p->physpath = NULL; 25150Sstevel@tonic-gate if (pscep->psce_out == pscep->psce_last) 25160Sstevel@tonic-gate p = pscep->psce_first; 25170Sstevel@tonic-gate else 25180Sstevel@tonic-gate p++; 25190Sstevel@tonic-gate pscep->psce_out = p; 25200Sstevel@tonic-gate mutex_exit(&pscep->psce_lock); 25210Sstevel@tonic-gate 25220Sstevel@tonic-gate ret = copyoutstr(physpath, psc.physpath, 25230Sstevel@tonic-gate physlen, &lencopied); 25240Sstevel@tonic-gate kmem_free(physpath, physlen); 25250Sstevel@tonic-gate if (ret) { 25260Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: copyoutstr %p " 25270Sstevel@tonic-gate "failed--EFAULT\n", cmdstr, 25280Sstevel@tonic-gate (void *)psc.physpath)) 25290Sstevel@tonic-gate break; 25300Sstevel@tonic-gate } 25310Sstevel@tonic-gate 25320Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 25330Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) { 25340Sstevel@tonic-gate if (ddi_copyout(&psc32.component, 25350Sstevel@tonic-gate &pscp32->component, copysize32, mode) 25365295Srandyf != 0) { 25370Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: copyout " 25380Sstevel@tonic-gate "failed--EFAULT\n", cmdstr)) 25390Sstevel@tonic-gate ret = EFAULT; 25400Sstevel@tonic-gate break; 25410Sstevel@tonic-gate } 25420Sstevel@tonic-gate } else 25430Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 25440Sstevel@tonic-gate { 25450Sstevel@tonic-gate if (ddi_copyout(&psc.component, 25460Sstevel@tonic-gate &pscp->component, copysize, mode) != 0) { 25470Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: copyout " 25480Sstevel@tonic-gate "failed--EFAULT\n", cmdstr)) 25490Sstevel@tonic-gate ret = EFAULT; 25500Sstevel@tonic-gate break; 25510Sstevel@tonic-gate } 25520Sstevel@tonic-gate } 25530Sstevel@tonic-gate ret = 0; 25540Sstevel@tonic-gate break; 25550Sstevel@tonic-gate } 25560Sstevel@tonic-gate default: 25575295Srandyf /* 25585295Srandyf * Internal error, invalid ioctl description 25595295Srandyf * force debug entry even if pm_debug not set 25605295Srandyf */ 25615295Srandyf #ifdef DEBUG 25625295Srandyf pm_log("invalid diptype %d for cmd %d (%s)\n", 25635295Srandyf pcip->diptype, cmd, pcip->name); 25645295Srandyf #endif 25650Sstevel@tonic-gate ASSERT(0); 25665295Srandyf return (EIO); 25670Sstevel@tonic-gate } 25680Sstevel@tonic-gate break; 25695295Srandyf } 25705295Srandyf 25715295Srandyf case PM_SRCH: /* command that takes a pm_searchargs_t arg */ 25725295Srandyf { 25735295Srandyf /* 25745295Srandyf * If no ppm, then there is nothing to search. 25755295Srandyf */ 25765295Srandyf if (DEVI(ddi_root_node())->devi_pm_ppm == NULL) { 25775295Srandyf ret = ENODEV; 25785295Srandyf break; 25795295Srandyf } 25805295Srandyf 25815295Srandyf #ifdef _MULTI_DATAMODEL 25825295Srandyf if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) { 25835295Srandyf if (ddi_copyin((caddr_t)arg, &psa32, 25845295Srandyf sizeof (psa32), mode) != 0) { 25855295Srandyf PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin " 25865295Srandyf "EFAULT\n\n", cmdstr)) 25875295Srandyf return (EFAULT); 25885295Srandyf } 25895295Srandyf if (copyinstr((void *)(uintptr_t)psa32.pms_listname, 25905295Srandyf listname, MAXCOPYBUF, NULL)) { 25915295Srandyf PMD(PMD_ERROR, ("ioctl: %s: 0x%p MAXCOPYBUF " 25925295Srandyf "%d, " "EFAULT\n", cmdstr, 25935295Srandyf (void *)(uintptr_t)psa32.pms_listname, 25945295Srandyf MAXCOPYBUF)) 25955295Srandyf ret = EFAULT; 25965295Srandyf break; 25975295Srandyf } 25985295Srandyf if (copyinstr((void *)(uintptr_t)psa32.pms_manufacturer, 25995295Srandyf manufacturer, MAXCOPYBUF, NULL)) { 26005295Srandyf PMD(PMD_ERROR, ("ioctl: %s: 0x%p MAXCOPYBUF " 26015295Srandyf "%d, " "EFAULT\n", cmdstr, 26025295Srandyf (void *)(uintptr_t)psa32.pms_manufacturer, 26035295Srandyf MAXCOPYBUF)) 26045295Srandyf ret = EFAULT; 26055295Srandyf break; 26065295Srandyf } 26075295Srandyf if (copyinstr((void *)(uintptr_t)psa32.pms_product, 26085295Srandyf product, MAXCOPYBUF, NULL)) { 26095295Srandyf PMD(PMD_ERROR, ("ioctl: %s: 0x%p MAXCOPYBUF " 26105295Srandyf "%d, " "EFAULT\n", cmdstr, 26115295Srandyf (void *)(uintptr_t)psa32.pms_product, 26125295Srandyf MAXCOPYBUF)) 26135295Srandyf ret = EFAULT; 26145295Srandyf break; 26155295Srandyf } 26165295Srandyf } else 26175295Srandyf #endif /* _MULTI_DATAMODEL */ 26185295Srandyf { 26195295Srandyf if (ddi_copyin((caddr_t)arg, &psa, 26205295Srandyf sizeof (psa), mode) != 0) { 26215295Srandyf PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin " 26225295Srandyf "EFAULT\n\n", cmdstr)) 26235295Srandyf return (EFAULT); 26245295Srandyf } 26255295Srandyf if (copyinstr(psa.pms_listname, 26265295Srandyf listname, MAXCOPYBUF, NULL)) { 26275295Srandyf PMD(PMD_ERROR, ("ioctl: %s: 0x%p MAXCOPYBUF " 26285295Srandyf "%d, " "EFAULT\n", cmdstr, 26295295Srandyf (void *)psa.pms_listname, MAXCOPYBUF)) 26305295Srandyf ret = EFAULT; 26315295Srandyf break; 26325295Srandyf } 26335295Srandyf if (copyinstr(psa.pms_manufacturer, 26345295Srandyf manufacturer, MAXCOPYBUF, NULL)) { 26355295Srandyf PMD(PMD_ERROR, ("ioctl: %s: 0x%p MAXCOPYBUF " 26365295Srandyf "%d, " "EFAULT\n", cmdstr, 26375295Srandyf (void *)psa.pms_manufacturer, MAXCOPYBUF)) 26385295Srandyf ret = EFAULT; 26395295Srandyf break; 26405295Srandyf } 26415295Srandyf if (copyinstr(psa.pms_product, 26425295Srandyf product, MAXCOPYBUF, NULL)) { 26435295Srandyf PMD(PMD_ERROR, ("ioctl: %s: 0x%p MAXCOPYBUF " 26445295Srandyf "%d, " "EFAULT\n", cmdstr, 26455295Srandyf (void *)psa.pms_product, MAXCOPYBUF)) 26465295Srandyf ret = EFAULT; 26475295Srandyf break; 26485295Srandyf } 26495295Srandyf } 26505295Srandyf psa.pms_listname = listname; 26515295Srandyf psa.pms_manufacturer = manufacturer; 26525295Srandyf psa.pms_product = product; 26535295Srandyf switch (cmd) { 26545295Srandyf case PM_SEARCH_LIST: 26555295Srandyf ret = pm_ppm_searchlist(&psa); 26565295Srandyf break; 26575295Srandyf 26585295Srandyf default: 26595295Srandyf /* 26605295Srandyf * Internal error, invalid ioctl description 26615295Srandyf * force debug entry even if pm_debug not set 26625295Srandyf */ 26635295Srandyf #ifdef DEBUG 26645295Srandyf pm_log("invalid diptype %d for cmd %d (%s)\n", 26655295Srandyf pcip->diptype, cmd, pcip->name); 26665295Srandyf #endif 26675295Srandyf ASSERT(0); 26685295Srandyf return (EIO); 26695295Srandyf } 26705295Srandyf break; 26715295Srandyf } 26720Sstevel@tonic-gate 26730Sstevel@tonic-gate case NOSTRUCT: 26745295Srandyf { 26750Sstevel@tonic-gate switch (cmd) { 26760Sstevel@tonic-gate case PM_START_PM: 26773028Smh27603 case PM_START_CPUPM: 2678*8906SEric.Saxe@Sun.COM case PM_START_CPUPM_EV: 2679*8906SEric.Saxe@Sun.COM case PM_START_CPUPM_POLL: 26805295Srandyf { 2681*8906SEric.Saxe@Sun.COM pm_cpupm_t new_mode = PM_CPUPM_NOTSET; 2682*8906SEric.Saxe@Sun.COM pm_cpupm_t old_mode = PM_CPUPM_NOTSET; 2683*8906SEric.Saxe@Sun.COM int r; 2684*8906SEric.Saxe@Sun.COM 26850Sstevel@tonic-gate mutex_enter(&pm_scan_lock); 26863028Smh27603 if ((cmd == PM_START_PM && autopm_enabled) || 2687*8906SEric.Saxe@Sun.COM (cmd == PM_START_CPUPM && PM_DEFAULT_CPUPM) || 2688*8906SEric.Saxe@Sun.COM (cmd == PM_START_CPUPM_EV && PM_EVENT_CPUPM) || 2689*8906SEric.Saxe@Sun.COM (cmd == PM_START_CPUPM_POLL && PM_POLLING_CPUPM)) { 26900Sstevel@tonic-gate mutex_exit(&pm_scan_lock); 2691*8906SEric.Saxe@Sun.COM PMD(PMD_ERROR, ("ioctl: %s: EBUSY\n", cmdstr)) 26920Sstevel@tonic-gate ret = EBUSY; 26930Sstevel@tonic-gate break; 26940Sstevel@tonic-gate } 2695*8906SEric.Saxe@Sun.COM 2696*8906SEric.Saxe@Sun.COM if (cmd == PM_START_PM) { 26975295Srandyf autopm_enabled = 1; 2698*8906SEric.Saxe@Sun.COM } else if (cmd == PM_START_CPUPM) { 2699*8906SEric.Saxe@Sun.COM old_mode = cpupm; 2700*8906SEric.Saxe@Sun.COM new_mode = cpupm = cpupm_default_mode; 2701*8906SEric.Saxe@Sun.COM } else if (cmd == PM_START_CPUPM_EV) { 2702*8906SEric.Saxe@Sun.COM old_mode = cpupm; 2703*8906SEric.Saxe@Sun.COM new_mode = cpupm = PM_CPUPM_EVENT; 2704*8906SEric.Saxe@Sun.COM } else if (cmd == PM_START_CPUPM_POLL) { 2705*8906SEric.Saxe@Sun.COM old_mode = cpupm; 2706*8906SEric.Saxe@Sun.COM new_mode = cpupm = PM_CPUPM_POLLING; 2707*8906SEric.Saxe@Sun.COM } 2708*8906SEric.Saxe@Sun.COM 27090Sstevel@tonic-gate mutex_exit(&pm_scan_lock); 2710*8906SEric.Saxe@Sun.COM 2711*8906SEric.Saxe@Sun.COM /* 2712*8906SEric.Saxe@Sun.COM * If we are changing CPUPM modes, and it is active, 2713*8906SEric.Saxe@Sun.COM * then stop it from operating in the old mode. 2714*8906SEric.Saxe@Sun.COM */ 2715*8906SEric.Saxe@Sun.COM if (old_mode == PM_CPUPM_POLLING) { 2716*8906SEric.Saxe@Sun.COM int c = PM_STOP_CPUPM; 2717*8906SEric.Saxe@Sun.COM ddi_walk_devs(ddi_root_node(), pm_stop_pm_walk, 2718*8906SEric.Saxe@Sun.COM &c); 2719*8906SEric.Saxe@Sun.COM } else if (old_mode == PM_CPUPM_EVENT) { 2720*8906SEric.Saxe@Sun.COM r = cpupm_set_policy(CPUPM_POLICY_DISABLED); 2721*8906SEric.Saxe@Sun.COM 2722*8906SEric.Saxe@Sun.COM /* 2723*8906SEric.Saxe@Sun.COM * Disabling CPUPM policy should always 2724*8906SEric.Saxe@Sun.COM * succeed 2725*8906SEric.Saxe@Sun.COM */ 2726*8906SEric.Saxe@Sun.COM ASSERT(r == 0); 2727*8906SEric.Saxe@Sun.COM } 2728*8906SEric.Saxe@Sun.COM 2729*8906SEric.Saxe@Sun.COM /* 2730*8906SEric.Saxe@Sun.COM * If we are changing to event based CPUPM, enable it. 2731*8906SEric.Saxe@Sun.COM * In the event it's not supported, fall back to 2732*8906SEric.Saxe@Sun.COM * polling based CPUPM. 2733*8906SEric.Saxe@Sun.COM */ 2734*8906SEric.Saxe@Sun.COM if (new_mode == PM_CPUPM_EVENT && 2735*8906SEric.Saxe@Sun.COM cpupm_set_policy(CPUPM_POLICY_ELASTIC) < 0) { 2736*8906SEric.Saxe@Sun.COM mutex_enter(&pm_scan_lock); 2737*8906SEric.Saxe@Sun.COM new_mode = cpupm = PM_CPUPM_POLLING; 2738*8906SEric.Saxe@Sun.COM cmd = PM_START_CPUPM_POLL; 2739*8906SEric.Saxe@Sun.COM mutex_exit(&pm_scan_lock); 2740*8906SEric.Saxe@Sun.COM } 2741*8906SEric.Saxe@Sun.COM if (new_mode == PM_CPUPM_POLLING || 2742*8906SEric.Saxe@Sun.COM cmd == PM_START_PM) { 2743*8906SEric.Saxe@Sun.COM ddi_walk_devs(ddi_root_node(), pm_start_pm_walk, 2744*8906SEric.Saxe@Sun.COM &cmd); 2745*8906SEric.Saxe@Sun.COM } 27460Sstevel@tonic-gate ret = 0; 27470Sstevel@tonic-gate break; 27485295Srandyf } 27490Sstevel@tonic-gate 27500Sstevel@tonic-gate case PM_RESET_PM: 27510Sstevel@tonic-gate case PM_STOP_PM: 27523028Smh27603 case PM_STOP_CPUPM: 27530Sstevel@tonic-gate { 27540Sstevel@tonic-gate extern void pm_discard_thresholds(void); 2755*8906SEric.Saxe@Sun.COM pm_cpupm_t old_mode = PM_CPUPM_NOTSET; 27560Sstevel@tonic-gate 27570Sstevel@tonic-gate mutex_enter(&pm_scan_lock); 27583028Smh27603 if ((cmd == PM_STOP_PM && !autopm_enabled) || 27593028Smh27603 (cmd == PM_STOP_CPUPM && PM_CPUPM_DISABLED)) { 27600Sstevel@tonic-gate mutex_exit(&pm_scan_lock); 27610Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: EINVAL\n", 27620Sstevel@tonic-gate cmdstr)) 27630Sstevel@tonic-gate ret = EINVAL; 27640Sstevel@tonic-gate break; 27650Sstevel@tonic-gate } 2766*8906SEric.Saxe@Sun.COM 27675295Srandyf if (cmd == PM_STOP_PM) { 27685295Srandyf autopm_enabled = 0; 27695295Srandyf pm_S3_enabled = 0; 27705295Srandyf autoS3_enabled = 0; 27715295Srandyf } else if (cmd == PM_STOP_CPUPM) { 2772*8906SEric.Saxe@Sun.COM old_mode = cpupm; 27735295Srandyf cpupm = PM_CPUPM_DISABLE; 27745295Srandyf } else { 27755295Srandyf autopm_enabled = 0; 27765295Srandyf autoS3_enabled = 0; 2777*8906SEric.Saxe@Sun.COM old_mode = cpupm; 27785295Srandyf cpupm = PM_CPUPM_NOTSET; 27793028Smh27603 } 27800Sstevel@tonic-gate mutex_exit(&pm_scan_lock); 27813028Smh27603 27820Sstevel@tonic-gate /* 27830Sstevel@tonic-gate * bring devices to full power level, stop scan 2784*8906SEric.Saxe@Sun.COM * If CPUPM was operating in event driven mode, disable 2785*8906SEric.Saxe@Sun.COM * that. 27860Sstevel@tonic-gate */ 2787*8906SEric.Saxe@Sun.COM if (old_mode == PM_CPUPM_EVENT) { 2788*8906SEric.Saxe@Sun.COM (void) cpupm_set_policy(CPUPM_POLICY_DISABLED); 2789*8906SEric.Saxe@Sun.COM } 27900Sstevel@tonic-gate ddi_walk_devs(ddi_root_node(), pm_stop_pm_walk, &cmd); 27910Sstevel@tonic-gate ret = 0; 27923028Smh27603 if (cmd == PM_STOP_PM || cmd == PM_STOP_CPUPM) 27930Sstevel@tonic-gate break; 27940Sstevel@tonic-gate /* 27950Sstevel@tonic-gate * Now do only PM_RESET_PM stuff. 27960Sstevel@tonic-gate */ 27970Sstevel@tonic-gate pm_system_idle_threshold = pm_default_idle_threshold; 27983028Smh27603 pm_cpu_idle_threshold = 0; 27990Sstevel@tonic-gate pm_discard_thresholds(); 28000Sstevel@tonic-gate pm_all_to_default_thresholds(); 28010Sstevel@tonic-gate pm_dispatch_to_dep_thread(PM_DEP_WK_REMOVE_DEP, 28020Sstevel@tonic-gate NULL, NULL, PM_DEP_WAIT, NULL, 0); 28030Sstevel@tonic-gate break; 28040Sstevel@tonic-gate } 28050Sstevel@tonic-gate 28060Sstevel@tonic-gate case PM_GET_SYSTEM_THRESHOLD: 28075295Srandyf { 28080Sstevel@tonic-gate *rval_p = pm_system_idle_threshold; 28090Sstevel@tonic-gate ret = 0; 28100Sstevel@tonic-gate break; 28115295Srandyf } 28120Sstevel@tonic-gate 28130Sstevel@tonic-gate case PM_GET_DEFAULT_SYSTEM_THRESHOLD: 28145295Srandyf { 28150Sstevel@tonic-gate *rval_p = pm_default_idle_threshold; 28160Sstevel@tonic-gate ret = 0; 28170Sstevel@tonic-gate break; 28185295Srandyf } 28190Sstevel@tonic-gate 28203028Smh27603 case PM_GET_CPU_THRESHOLD: 28215295Srandyf { 28223028Smh27603 *rval_p = pm_cpu_idle_threshold; 28233028Smh27603 ret = 0; 28243028Smh27603 break; 28255295Srandyf } 28263028Smh27603 28270Sstevel@tonic-gate case PM_SET_SYSTEM_THRESHOLD: 28283028Smh27603 case PM_SET_CPU_THRESHOLD: 28295295Srandyf { 28300Sstevel@tonic-gate if ((int)arg < 0) { 28310Sstevel@tonic-gate PMD(PMD_ERROR, ("ioctl: %s: arg 0x%x < 0" 28320Sstevel@tonic-gate "--EINVAL\n", cmdstr, (int)arg)) 28330Sstevel@tonic-gate ret = EINVAL; 28340Sstevel@tonic-gate break; 28350Sstevel@tonic-gate } 28360Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: %s: 0x%x 0t%d\n", cmdstr, 28370Sstevel@tonic-gate (int)arg, (int)arg)) 28383028Smh27603 if (cmd == PM_SET_SYSTEM_THRESHOLD) 28393028Smh27603 pm_system_idle_threshold = (int)arg; 28403028Smh27603 else { 28413028Smh27603 pm_cpu_idle_threshold = (int)arg; 28423028Smh27603 } 28433028Smh27603 ddi_walk_devs(ddi_root_node(), pm_set_idle_thresh_walk, 28445295Srandyf (void *) &cmd); 28453028Smh27603 28460Sstevel@tonic-gate ret = 0; 28470Sstevel@tonic-gate break; 28485295Srandyf } 28490Sstevel@tonic-gate 28500Sstevel@tonic-gate case PM_IDLE_DOWN: 28515295Srandyf { 28520Sstevel@tonic-gate if (pm_timeout_idledown() != 0) { 28530Sstevel@tonic-gate ddi_walk_devs(ddi_root_node(), 28540Sstevel@tonic-gate pm_start_idledown, (void *)PMID_IOC); 28550Sstevel@tonic-gate } 28560Sstevel@tonic-gate ret = 0; 28570Sstevel@tonic-gate break; 28585295Srandyf } 28590Sstevel@tonic-gate 28600Sstevel@tonic-gate case PM_GET_PM_STATE: 28615295Srandyf { 28620Sstevel@tonic-gate if (autopm_enabled) { 28630Sstevel@tonic-gate *rval_p = PM_SYSTEM_PM_ENABLED; 28640Sstevel@tonic-gate } else { 28650Sstevel@tonic-gate *rval_p = PM_SYSTEM_PM_DISABLED; 28660Sstevel@tonic-gate } 28670Sstevel@tonic-gate ret = 0; 28680Sstevel@tonic-gate break; 28695295Srandyf } 28703028Smh27603 28713028Smh27603 case PM_GET_CPUPM_STATE: 28725295Srandyf { 2873*8906SEric.Saxe@Sun.COM if (PM_POLLING_CPUPM || PM_EVENT_CPUPM) 28743028Smh27603 *rval_p = PM_CPU_PM_ENABLED; 28753028Smh27603 else if (PM_CPUPM_DISABLED) 28763028Smh27603 *rval_p = PM_CPU_PM_DISABLED; 28773028Smh27603 else 28783028Smh27603 *rval_p = PM_CPU_PM_NOTSET; 28793028Smh27603 ret = 0; 28803028Smh27603 break; 28810Sstevel@tonic-gate } 28825295Srandyf 28835295Srandyf case PM_GET_AUTOS3_STATE: 28845295Srandyf { 28855295Srandyf if (autoS3_enabled) { 28865295Srandyf *rval_p = PM_AUTOS3_ENABLED; 28875295Srandyf } else { 28885295Srandyf *rval_p = PM_AUTOS3_DISABLED; 28895295Srandyf } 28905295Srandyf ret = 0; 28915295Srandyf break; 28925295Srandyf } 28935295Srandyf 28945295Srandyf case PM_GET_S3_SUPPORT_STATE: 28955295Srandyf { 28965295Srandyf if (pm_S3_enabled) { 28975295Srandyf *rval_p = PM_S3_SUPPORT_ENABLED; 28985295Srandyf } else { 28995295Srandyf *rval_p = PM_S3_SUPPORT_DISABLED; 29005295Srandyf } 29015295Srandyf ret = 0; 29025295Srandyf break; 29035295Srandyf } 29045295Srandyf 29055295Srandyf /* 29065295Srandyf * pmconfig tells us if the platform supports S3 29075295Srandyf */ 29085295Srandyf case PM_ENABLE_S3: 29095295Srandyf { 29105295Srandyf mutex_enter(&pm_scan_lock); 29115295Srandyf if (pm_S3_enabled) { 29125295Srandyf mutex_exit(&pm_scan_lock); 29135295Srandyf PMD(PMD_ERROR, ("ioctl: %s: EBUSY\n", 29145295Srandyf cmdstr)) 29155295Srandyf ret = EBUSY; 29165295Srandyf break; 29175295Srandyf } 29185295Srandyf pm_S3_enabled = 1; 29195295Srandyf mutex_exit(&pm_scan_lock); 29205295Srandyf ret = 0; 29215295Srandyf break; 29225295Srandyf } 29235295Srandyf 29245295Srandyf case PM_DISABLE_S3: 29255295Srandyf { 29265295Srandyf mutex_enter(&pm_scan_lock); 29275295Srandyf pm_S3_enabled = 0; 29285295Srandyf mutex_exit(&pm_scan_lock); 29295295Srandyf ret = 0; 29305295Srandyf break; 29315295Srandyf } 29325295Srandyf 29335295Srandyf case PM_START_AUTOS3: 29345295Srandyf { 29355295Srandyf mutex_enter(&pm_scan_lock); 29365295Srandyf if (autoS3_enabled) { 29375295Srandyf mutex_exit(&pm_scan_lock); 29385295Srandyf PMD(PMD_ERROR, ("ioctl: %s: EBUSY\n", 29395295Srandyf cmdstr)) 29405295Srandyf ret = EBUSY; 29415295Srandyf break; 29425295Srandyf } 29435295Srandyf autoS3_enabled = 1; 29445295Srandyf mutex_exit(&pm_scan_lock); 29455295Srandyf ret = 0; 29465295Srandyf break; 29475295Srandyf } 29485295Srandyf 29495295Srandyf case PM_STOP_AUTOS3: 29505295Srandyf { 29515295Srandyf mutex_enter(&pm_scan_lock); 29525295Srandyf autoS3_enabled = 0; 29535295Srandyf mutex_exit(&pm_scan_lock); 29545295Srandyf ret = 0; 29555295Srandyf break; 29565295Srandyf } 29575295Srandyf 2958*8906SEric.Saxe@Sun.COM case PM_ENABLE_CPU_DEEP_IDLE: 2959*8906SEric.Saxe@Sun.COM { 2960*8906SEric.Saxe@Sun.COM if (callb_execute_class(CB_CL_CPU_DEEP_IDLE, 2961*8906SEric.Saxe@Sun.COM PM_ENABLE_CPU_DEEP_IDLE) == NULL) 2962*8906SEric.Saxe@Sun.COM ret = 0; 2963*8906SEric.Saxe@Sun.COM else 2964*8906SEric.Saxe@Sun.COM ret = EBUSY; 2965*8906SEric.Saxe@Sun.COM break; 2966*8906SEric.Saxe@Sun.COM } 2967*8906SEric.Saxe@Sun.COM case PM_DISABLE_CPU_DEEP_IDLE: 2968*8906SEric.Saxe@Sun.COM { 2969*8906SEric.Saxe@Sun.COM if (callb_execute_class(CB_CL_CPU_DEEP_IDLE, 2970*8906SEric.Saxe@Sun.COM PM_DISABLE_CPU_DEEP_IDLE) == NULL) 2971*8906SEric.Saxe@Sun.COM ret = 0; 2972*8906SEric.Saxe@Sun.COM else 2973*8906SEric.Saxe@Sun.COM ret = EINVAL; 2974*8906SEric.Saxe@Sun.COM break; 2975*8906SEric.Saxe@Sun.COM } 2976*8906SEric.Saxe@Sun.COM case PM_DEFAULT_CPU_DEEP_IDLE: 2977*8906SEric.Saxe@Sun.COM { 2978*8906SEric.Saxe@Sun.COM if (callb_execute_class(CB_CL_CPU_DEEP_IDLE, 2979*8906SEric.Saxe@Sun.COM PM_DEFAULT_CPU_DEEP_IDLE) == NULL) 2980*8906SEric.Saxe@Sun.COM ret = 0; 2981*8906SEric.Saxe@Sun.COM else 2982*8906SEric.Saxe@Sun.COM ret = EBUSY; 2983*8906SEric.Saxe@Sun.COM break; 2984*8906SEric.Saxe@Sun.COM } 2985*8906SEric.Saxe@Sun.COM 29865295Srandyf default: 29875295Srandyf /* 29885295Srandyf * Internal error, invalid ioctl description 29895295Srandyf * force debug entry even if pm_debug not set 29905295Srandyf */ 29915295Srandyf #ifdef DEBUG 29925295Srandyf pm_log("invalid diptype %d for cmd %d (%s)\n", 29935295Srandyf pcip->diptype, cmd, pcip->name); 29945295Srandyf #endif 29955295Srandyf ASSERT(0); 29965295Srandyf return (EIO); 29975295Srandyf } 29980Sstevel@tonic-gate break; 29995295Srandyf } 30000Sstevel@tonic-gate 3001*8906SEric.Saxe@Sun.COM default: 30020Sstevel@tonic-gate /* 30030Sstevel@tonic-gate * Internal error, invalid ioctl description 30040Sstevel@tonic-gate * force debug entry even if pm_debug not set 30050Sstevel@tonic-gate */ 30060Sstevel@tonic-gate #ifdef DEBUG 30070Sstevel@tonic-gate pm_log("ioctl: invalid str_type %d for cmd %d (%s)\n", 30080Sstevel@tonic-gate pcip->str_type, cmd, pcip->name); 30090Sstevel@tonic-gate #endif 30100Sstevel@tonic-gate ASSERT(0); 30110Sstevel@tonic-gate return (EIO); 30120Sstevel@tonic-gate } 30130Sstevel@tonic-gate ASSERT(ret != 0x0badcafe); /* some cmd in wrong case! */ 30140Sstevel@tonic-gate if (dipheld) { 30150Sstevel@tonic-gate ASSERT(dip); 30160Sstevel@tonic-gate PMD(PMD_DHR, ("ioctl: %s: releasing %s@%s(%s#%d) for " 30170Sstevel@tonic-gate "exiting pm_ioctl\n", cmdstr, PM_DEVICE(dip))) 30180Sstevel@tonic-gate PM_RELE(dip); 30190Sstevel@tonic-gate } 30200Sstevel@tonic-gate PMD(PMD_IOCTL, ("ioctl: %s: end, ret=%d\n", cmdstr, ret)) 30210Sstevel@tonic-gate return (ret); 30220Sstevel@tonic-gate } 3023