16429Svs195195 /*
26429Svs195195 * CDDL HEADER START
36429Svs195195 *
46429Svs195195 * The contents of this file are subject to the terms of the
56429Svs195195 * Common Development and Distribution License (the "License").
66429Svs195195 * You may not use this file except in compliance with the License.
76429Svs195195 *
86429Svs195195 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96429Svs195195 * or http://www.opensolaris.org/os/licensing.
106429Svs195195 * See the License for the specific language governing permissions
116429Svs195195 * and limitations under the License.
126429Svs195195 *
136429Svs195195 * When distributing Covered Code, include this CDDL HEADER in each
146429Svs195195 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156429Svs195195 * If applicable, add the following below this CDDL HEADER, with the
166429Svs195195 * fields enclosed by brackets "[]" replaced with your own identifying
176429Svs195195 * information: Portions Copyright [yyyy] [name of copyright owner]
186429Svs195195 *
196429Svs195195 * CDDL HEADER END
206429Svs195195 */
216429Svs195195
226429Svs195195 /*
236429Svs195195 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
246429Svs195195 * Use is subject to license terms.
256429Svs195195 */
266429Svs195195
276429Svs195195 #include <stdio.h>
286429Svs195195 #include <sys/types.h>
296429Svs195195 #include <fcntl.h>
306429Svs195195 #include <string.h>
316429Svs195195 #include <stdlib.h>
326429Svs195195 #include <unistd.h>
336429Svs195195 #include <errno.h>
346429Svs195195
356429Svs195195 #include <sys/stat.h>
366429Svs195195 #include <poll.h>
376429Svs195195 #include <signal.h>
386429Svs195195 #include <pthread.h>
396429Svs195195 #include <thread.h>
406429Svs195195 #include <time.h>
416429Svs195195 #include <sys/systeminfo.h>
426429Svs195195 #include <sys/cred.h>
436429Svs195195 #include <dirent.h>
446429Svs195195 #include <libdevinfo.h>
456429Svs195195 #include <sys/pm.h>
466429Svs195195 #include <sys/ppmio.h>
476429Svs195195 #include <locale.h>
486429Svs195195
496429Svs195195 #include "fpsapi.h"
506429Svs195195 #include "fpsd.h"
516429Svs195195 #include "messages.h"
526429Svs195195
536429Svs195195
546429Svs195195 #define DEV_PM "/devices/pseudo/pm@0:pm"
556429Svs195195 #define DEFAULT_CPU_FULL_POWER 3
566429Svs195195
576429Svs195195 int is_estar_system = 0; /* Not an E* system, by default */
586429Svs195195 int sys_pm_state = PM_SYSTEM_PM_DISABLED; /* By default autopm disabled */
596429Svs195195
606429Svs195195
616429Svs195195 static di_node_t fps_di_root = DI_NODE_NIL;
626429Svs195195 static di_prom_handle_t fps_di_prom = DI_PROM_HANDLE_NIL;
636429Svs195195 static char **cpu_dpaths = NULL; /* Used only on E* system */
646429Svs195195 static int *proc_ids = NULL; /* Used only on E* system */
656429Svs195195 static int num_cpus = 0; /* Used only on E* system */
666429Svs195195 static int devpm_fd = -1; /* Used only on E* system */
676429Svs195195 static int full_pwr = DEFAULT_CPU_FULL_POWER;
686429Svs195195
696429Svs195195 /*
706429Svs195195 * Initialize system PM state enable/disable and
716429Svs195195 * enable system default info logging accordingly.
726429Svs195195 * Note: Even for systems for which CPU PM is not enabled by
736429Svs195195 * default, disk PM may be enabled explicitly using power.conf;
746429Svs195195 * If power management is enabled, disable informational logging
756429Svs195195 * by default.
766429Svs195195 * Some platforms don't have /dev/pm entry. It is perfectly OK.
776429Svs195195 * Don't complain if there is no /dev/pm entry.
786429Svs195195 * The platforms on which CPU PM is enabled by default, would
796429Svs195195 * ofcourse have /dev/pm entry.
806429Svs195195 *
816429Svs195195 * Note: open_dev_pm() should have been called initially before
826429Svs195195 * calling this function.
836429Svs195195 *
846429Svs195195 */
856429Svs195195
866429Svs195195 void
update_pm_state()876429Svs195195 update_pm_state()
886429Svs195195 {
896429Svs195195 int pm_stat;
906429Svs195195
916429Svs195195 if (devpm_fd == -1)
926429Svs195195 return;
936429Svs195195
946429Svs195195 pm_stat = ioctl(devpm_fd, PM_GET_PM_STATE);
956429Svs195195
966429Svs195195 if (pm_stat == -1)
976429Svs195195 return;
986429Svs195195
996429Svs195195 sys_pm_state = pm_stat;
1006429Svs195195
1016429Svs195195 }
1026429Svs195195
1036429Svs195195 /*
1046429Svs195195 * Some platforms don't support power management. (neither CPU nor disk)
1056429Svs195195 * Those platforms don't have /dev/pm entry. Don't complain in such case.
1066429Svs195195 * Some platfors support PM only for disks. (they have /dev/pm entry.
1076429Svs195195 * and logging is disabled on those platforms.)
1086429Svs195195 * Some platforms support PM for both disks and CPUs (apart from others).
1096429Svs195195 * Those platforms also have /dev/pm entry.
1106429Svs195195 * Note that even desktops which support CPU PM E* can be custom
1116429Svs195195 * configured to remove power management drivers. In that case,
1126429Svs195195 * there won't be any /dev/pm entry and it is valid config.
1136429Svs195195 *
1146429Svs195195 */
1156429Svs195195
open_dev_pm()1166429Svs195195 static void open_dev_pm()
1176429Svs195195 {
1186429Svs195195 devpm_fd = open(DEV_PM, O_RDWR);
1196429Svs195195
1206429Svs195195 }
1216429Svs195195
1226429Svs195195 /*
1236429Svs195195 * Initialize Estar info database.
1246429Svs195195 *
1256429Svs195195 */
1266429Svs195195
1276429Svs195195 void
init_estar_db()1286429Svs195195 init_estar_db()
1296429Svs195195 {
1306429Svs195195 di_node_t fnode, node;
1316429Svs195195 di_prop_t nextp;
1326429Svs195195 char *path = NULL;
1336429Svs195195 int cpu_i;
1346429Svs195195 int is_pmprop_found = 0;
1356429Svs195195 pm_req_t pmreq;
1366429Svs195195 uchar_t *prop_data = NULL;
1376429Svs195195
1386429Svs195195 /*
1396429Svs195195 * First open /dev/pm and keep it open for later uses.
1406429Svs195195 * Note that this needs to be open on all power management supported
1416429Svs195195 * systems. Some systems support power mgmt on only some
1426429Svs195195 * devices like disk, but not CPU. /dev/pm does not exist on
1436429Svs195195 * some platforms. Also PM drivers can be removed on custom
1446429Svs195195 * configurations.
1456429Svs195195 */
1466429Svs195195 open_dev_pm();
1476429Svs195195
1486429Svs195195 if (devpm_fd == -1)
1496429Svs195195 return;
1506429Svs195195
1516429Svs195195 fps_di_root = di_init("/", DINFOCPYALL);
1526429Svs195195
1536429Svs195195 if (DI_NODE_NIL == fps_di_root) {
154*7435SVaidehi.Rangan@Sun.COM fpsd_message(FPSD_EXIT_ERROR, FPS_WARNING, DI_INIT_FAIL);
1556429Svs195195 }
1566429Svs195195
1576429Svs195195 fps_di_prom = di_prom_init();
1586429Svs195195
1596429Svs195195 if (DI_PROM_HANDLE_NIL == fps_di_prom) {
160*7435SVaidehi.Rangan@Sun.COM fpsd_message(FPSD_EXIT_ERROR, FPS_WARNING, DI_PROM_INIT_FAIL);
1616429Svs195195 di_fini(fps_di_root);
1626429Svs195195 }
1636429Svs195195
1646429Svs195195 if (di_prom_prop_lookup_bytes(fps_di_prom, fps_di_root,
1656429Svs195195 "energystar-v3", &prop_data) == -1)
1666429Svs195195 goto exit_es;
1676429Svs195195
1686429Svs195195 /*
1696429Svs195195 * As a final check, also check for "us" driver property pm-components
1706429Svs195195 * On Estar systems, the driver should define this property.
1716429Svs195195 */
1726429Svs195195
1736429Svs195195 fnode = node = di_drv_first_node("us", fps_di_root);
1746429Svs195195
1756429Svs195195 if (DI_NODE_NIL == node) {
1766429Svs195195 goto exit_es;
1776429Svs195195 }
1786429Svs195195
1796429Svs195195 is_pmprop_found = 0;
1806429Svs195195 for (nextp = di_prop_next(node, DI_PROP_NIL); nextp != DI_PROP_NIL;
1816429Svs195195 nextp = di_prop_next(node, nextp)) {
1826429Svs195195 if (strcmp(di_prop_name(nextp), "pm-components") == 0) {
1836429Svs195195 is_pmprop_found = 1;
1846429Svs195195 break;
1856429Svs195195 }
1866429Svs195195 }
1876429Svs195195
1886429Svs195195 if (!is_pmprop_found)
1896429Svs195195 goto exit_es;
1906429Svs195195
1916429Svs195195 is_estar_system = 1; /* CPU power mgmt supported E* system */
1926429Svs195195
1936429Svs195195 num_cpus = 0;
1946429Svs195195 while (node != DI_NODE_NIL) {
1956429Svs195195 num_cpus++;
1966429Svs195195 node = di_drv_next_node(node);
1976429Svs195195 }
1986429Svs195195
1996429Svs195195 cpu_dpaths = (char **)calloc(num_cpus+1, sizeof (char *));
2006429Svs195195 proc_ids = (int *)calloc(num_cpus+1, sizeof (int));
2016429Svs195195 proc_ids[num_cpus] = -1; /* Terminate processor ids by -1 */
2026429Svs195195
2036429Svs195195 cpu_i = 0;
2046429Svs195195 for (node = fnode; node != DI_NODE_NIL; node = di_drv_next_node(node)) {
2056429Svs195195 proc_ids[cpu_i] = -1;
2066429Svs195195 cpu_dpaths[cpu_i] = NULL;
2076429Svs195195
2086429Svs195195 path = di_devfs_path(node);
2096429Svs195195 if (NULL == path)
2106429Svs195195 continue;
2116429Svs195195 cpu_dpaths[cpu_i] = strdup(path);
2126429Svs195195 di_devfs_path_free(path);
2137346SVaidehi.Rangan@Sun.COM /*
2147346SVaidehi.Rangan@Sun.COM * Keep the mapping between path and processor IDs.
2157346SVaidehi.Rangan@Sun.COM * Currently, processor IDs are not used.
2167346SVaidehi.Rangan@Sun.COM * But may be used in future.
2177346SVaidehi.Rangan@Sun.COM */
2186429Svs195195
2197346SVaidehi.Rangan@Sun.COM /*
2207346SVaidehi.Rangan@Sun.COM * On workstation platforms (where CPU E* supported),
2217346SVaidehi.Rangan@Sun.COM * processor ID and instance numbers are same.
2227346SVaidehi.Rangan@Sun.COM * This may change in future. So watch out.
2237346SVaidehi.Rangan@Sun.COM */
2246429Svs195195
2256429Svs195195 proc_ids[cpu_i] = di_instance(node); /* Currently unused. */
2266429Svs195195 cpu_i++;
2276429Svs195195 }
2286429Svs195195
2296429Svs195195 proc_ids[cpu_i] = -1;
2306429Svs195195 cpu_dpaths[cpu_i] = NULL;
2316429Svs195195
2326429Svs195195 /* Initialize what "FULL POWER" mode is. */
2336429Svs195195 full_pwr = DEFAULT_CPU_FULL_POWER;
2346429Svs195195
2356429Svs195195 pmreq.physpath = cpu_dpaths[0];
2366429Svs195195 pmreq.component = 0;
2376429Svs195195 pmreq.value = 0;
2386429Svs195195 pmreq.data = NULL;
2396429Svs195195 pmreq.datasize = 0;
2406429Svs195195
2416429Svs195195
2426429Svs195195 full_pwr = ioctl(devpm_fd, PM_GET_FULL_POWER, &pmreq);
2436429Svs195195 if (full_pwr == -1)
2446429Svs195195 full_pwr = DEFAULT_CPU_FULL_POWER;
2456429Svs195195 exit_es:
2466429Svs195195
2476429Svs195195 if (fps_di_root != DI_NODE_NIL) {
2486429Svs195195 di_fini(fps_di_root);
2496429Svs195195 fps_di_root = DI_NODE_NIL;
2506429Svs195195 }
2516429Svs195195 if (DI_PROM_HANDLE_NIL != fps_di_prom) {
2526429Svs195195 di_prom_fini(fps_di_prom);
2536429Svs195195 fps_di_prom = DI_PROM_HANDLE_NIL;
2546429Svs195195 }
2556429Svs195195 }
2566429Svs195195
2576429Svs195195 /*
2586429Svs195195 * Return the min(idle_times), min(remaining_times), max(rem_time) for all
2596429Svs195195 * CPUs in full power mode. The "remain time" is the remaining
2606429Svs195195 * threshold time after which the CPU will make next lower level
2616429Svs195195 * power transition if left idle.
2626429Svs195195 * If the CPUs are not in full power mode or could not exactly determine
2636429Svs195195 * the power mode then return -1.
2646429Svs195195 * return 0 if CPUs are in full power mode.
2656429Svs195195 */
2666429Svs195195
2676429Svs195195 int
get_idle_rem_stats(int * min_idle,int * min_rem,int * max_rem)2686429Svs195195 get_idle_rem_stats(int *min_idle, int *min_rem, int *max_rem)
2696429Svs195195 {
2706429Svs195195 int idle_time;
2716429Svs195195 int pmstats[2];
2726429Svs195195 int i;
2736429Svs195195 pm_req_t pmreq;
2746429Svs195195 int ret;
2756429Svs195195
2766429Svs195195 *min_idle = -1;
2776429Svs195195 *min_rem = -1;
2786429Svs195195 *max_rem = -1;
2796429Svs195195
2806429Svs195195 for (i = 0; i < num_cpus; i++) {
2816429Svs195195
2826429Svs195195 pmreq.physpath = cpu_dpaths[i];
2836429Svs195195 pmreq.component = 0;
2846429Svs195195 pmreq.value = 0;
2856429Svs195195 pmreq.data = pmstats;
2866429Svs195195 pmreq.datasize = sizeof (pmstats);
2876429Svs195195 idle_time = ioctl(devpm_fd, PM_GET_TIME_IDLE, &pmreq);
2886429Svs195195 if (idle_time == -1)
2896429Svs195195 continue;
2906429Svs195195 ret = ioctl(devpm_fd, PM_GET_STATS, &pmreq);
2916429Svs195195
2926429Svs195195 /* Now pmstats[0] = cur power level; pmstats[1]=remain time */
2936429Svs195195 if (ret == -1)
2946429Svs195195 continue;
2956429Svs195195 if (pmstats[0] != full_pwr)
2966429Svs195195 continue;
2976429Svs195195
2986429Svs195195 if ((*min_idle == -1) || (idle_time < *min_idle))
2996429Svs195195 *min_idle = idle_time;
3006429Svs195195 if (*min_rem == -1 || pmstats[1] < *min_rem) {
3016429Svs195195 *min_rem = pmstats[1];
3026429Svs195195
3037346SVaidehi.Rangan@Sun.COM /*
3047346SVaidehi.Rangan@Sun.COM * The remain time can be negative if there are 2 cpus
3057346SVaidehi.Rangan@Sun.COM * and 1 cpu is ready to transition
3067346SVaidehi.Rangan@Sun.COM * and the other one is not
3077346SVaidehi.Rangan@Sun.COM */
3086429Svs195195 if (*min_rem < 0)
3096429Svs195195 *min_rem = 0;
3106429Svs195195 }
3116429Svs195195 if (*max_rem == -1 || pmstats[1] > *max_rem)
3126429Svs195195 *max_rem = pmstats[1];
3136429Svs195195 }
3146429Svs195195
3156429Svs195195 return
3166429Svs195195 ((*min_idle == -1 || *min_rem == -1 || *max_rem == -1) ? -1 : 0);
3176429Svs195195 }
3186429Svs195195
3196429Svs195195 /*
3206429Svs195195 * Wait until CPU comes to full power state or timeout occurs.
3216429Svs195195 * If multiple threads call this function, execute the
3226429Svs195195 * PM ioctl system call only once.
3236429Svs195195 * This is better than all 3 threads polling cpu pwr state same time.
3246429Svs195195 *
3256429Svs195195 * Callers of this function should not assume that on returning from
3266429Svs195195 * this function CPU will be in full power state.
3276429Svs195195 * (They should check again).
3286429Svs195195 * This function just optimizes for performance during wait.
3296429Svs195195 *
3306429Svs195195 *
3316429Svs195195 */
3326429Svs195195
3336429Svs195195 void
wait_for_pm_state_change()3346429Svs195195 wait_for_pm_state_change()
3356429Svs195195 {
3366429Svs195195 int res;
3377346SVaidehi.Rangan@Sun.COM static pthread_mutex_t wrlck;
3386429Svs195195 static int is_active = 0;
3396429Svs195195 static pm_req_t pmreq;
3406429Svs195195 static pm_state_change_t pmsc;
3416429Svs195195 static char path[MAXPATHLEN];
3426429Svs195195
3436429Svs195195 int pwr = 0;
3446429Svs195195 int cur_lvl = 0; /* 0 = unknown. 1=low, 3=full power */
3456429Svs195195
3466429Svs195195 pmreq.physpath = cpu_dpaths[0];
3476429Svs195195 pmreq.component = 0;
3486429Svs195195 pmreq.value = 0;
3496429Svs195195 pmreq.data = NULL;
3506429Svs195195 pmreq.datasize = 0;
3516429Svs195195
3526429Svs195195
3537346SVaidehi.Rangan@Sun.COM (void) pthread_mutex_lock(&wrlck);
3546429Svs195195
3556429Svs195195 if (!is_active) { /* This is the first thread trying to wait */
3566429Svs195195 is_active = 1;
3577346SVaidehi.Rangan@Sun.COM (void) pthread_mutex_unlock(&wrlck);
3586429Svs195195
3596429Svs195195 pmsc.physpath = path;
3606429Svs195195 pmsc.size = MAXPATHLEN;
3616429Svs195195 path[0] = 0; /* init not required. Just in case... */
3626429Svs195195
3637346SVaidehi.Rangan@Sun.COM /*
3647346SVaidehi.Rangan@Sun.COM * PM starts buffering the state changes after the first call to
3657346SVaidehi.Rangan@Sun.COM * PM_GET_STATE_CHANGE/PM_GET_STATE_CHANGE_WAIT
3667346SVaidehi.Rangan@Sun.COM *
3677346SVaidehi.Rangan@Sun.COM * The PM_GET_STATE_CHANGE is a non-blocking call where as
3687346SVaidehi.Rangan@Sun.COM * _WAIT is blocking call. The PM_GET_STATE_CHANGE also
3697346SVaidehi.Rangan@Sun.COM * returns all the info * about the latest buffered state
3707346SVaidehi.Rangan@Sun.COM * change if already buffered event is available. So it is
3717346SVaidehi.Rangan@Sun.COM * important to drain out all old events,
3727346SVaidehi.Rangan@Sun.COM * if you are only interested in future events.
3737346SVaidehi.Rangan@Sun.COM *
3747346SVaidehi.Rangan@Sun.COM * After the state changes the exact information/timestamp about
3757346SVaidehi.Rangan@Sun.COM * state changes are reflected in the ioctl struct.
3767346SVaidehi.Rangan@Sun.COM * To keep things simple, after draining out all buffered info,
3777346SVaidehi.Rangan@Sun.COM * we issue get current power to get the current power level and
3787346SVaidehi.Rangan@Sun.COM * then we issue another _WAIT command to get the
3797346SVaidehi.Rangan@Sun.COM * next power change.
3807346SVaidehi.Rangan@Sun.COM *
3817346SVaidehi.Rangan@Sun.COM */
3826429Svs195195
3836429Svs195195 do {
3846429Svs195195
3856429Svs195195 res = ioctl(devpm_fd, PM_GET_STATE_CHANGE, &pmsc);
3866429Svs195195
3876429Svs195195 if (res == -1 && errno != EWOULDBLOCK) {
3886429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_WARNING,
3896429Svs195195 INTERNAL_FAILURE_WARN,
3906429Svs195195 strerror(errno));
3916429Svs195195 /* 1 second sleep. Avoid busy loop */
3926429Svs195195 (void) poll(NULL, 0, 1000);
3936429Svs195195 /* Probably will succeed in next call. */
3946429Svs195195 goto psc_complete;
3956429Svs195195 }
3966429Svs195195
3976429Svs195195 } while (errno != EWOULDBLOCK);
3986429Svs195195
3996429Svs195195 /* drain out all buffered state changes */
4006429Svs195195
4016429Svs195195 /* If current state is full power, then get out. */
4026429Svs195195
4036429Svs195195 do {
4046429Svs195195 pwr = ioctl(devpm_fd, PM_GET_CURRENT_POWER, &pmreq);
4056429Svs195195 if (pwr != -1) break;
4066429Svs195195 if (errno == EAGAIN) {
4076429Svs195195 (void) poll(NULL, 0, 1000); /* 1 sec sleep */
4086429Svs195195 continue;
4096429Svs195195 } else {
4106429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_WARNING,
4116429Svs195195 INTERNAL_FAILURE_WARN1,
4126429Svs195195 strerror(errno));
4136429Svs195195 (void) poll(NULL, 0, 1000); /* 1 sec sleep */
4146429Svs195195 goto psc_complete;
4156429Svs195195 }
4166429Svs195195 /*CONSTCOND*/
4176429Svs195195 } while (1);
4186429Svs195195
4196429Svs195195 if (pwr == full_pwr)
4206429Svs195195 goto psc_complete;
4216429Svs195195
4226429Svs195195 while (cur_lvl != full_pwr) {
4236429Svs195195 pmsc.physpath = path;
4246429Svs195195 pmsc.size = MAXPATHLEN;
4256429Svs195195 path[0] = 0; /* init not required. Just in case... */
4266429Svs195195
4276429Svs195195 do {
4286429Svs195195 res = ioctl(devpm_fd,
4296429Svs195195 PM_GET_STATE_CHANGE_WAIT, &pmsc);
4306429Svs195195 if (res == -1 && errno == EINTR) {
4316429Svs195195 /* 1 second sleep */
4326429Svs195195 (void) poll(NULL, 0, 1000);
4336429Svs195195 }
4346429Svs195195 } while (res == -1 && errno == EINTR);
4356429Svs195195
4366429Svs195195 if (res == -1) {
4376429Svs195195 fpsd_message(FPSD_NO_EXIT, FPS_WARNING,
4386429Svs195195 INTERNAL_FAILURE_WARN2,
4396429Svs195195 strerror(errno));
4407346SVaidehi.Rangan@Sun.COM /*
4417346SVaidehi.Rangan@Sun.COM * If there are failures in state change ioctl,
4427346SVaidehi.Rangan@Sun.COM * just would fall back to normal polling of
4437346SVaidehi.Rangan@Sun.COM * status later. get out quiet.
4447346SVaidehi.Rangan@Sun.COM */
4456429Svs195195 /* avoid busy loop -- 1 second sleep */
4466429Svs195195 (void) poll(NULL, 0, 1000);
4476429Svs195195 goto psc_complete;
4486429Svs195195 }
4496429Svs195195
4506429Svs195195 if (strcmp(pmsc.physpath, cpu_dpaths[0]) == 0 &&
4516429Svs195195 pmsc.new_level == full_pwr)
4526429Svs195195 cur_lvl = full_pwr;
4536429Svs195195 }
4546429Svs195195
4556429Svs195195 psc_complete:
4567346SVaidehi.Rangan@Sun.COM (void) pthread_mutex_lock(&wrlck);
4576429Svs195195 is_active = 0;
4587346SVaidehi.Rangan@Sun.COM (void) pthread_mutex_unlock(&wrlck);
4596429Svs195195
4606429Svs195195 } else {
4616429Svs195195 /* Release the lock first */
4627346SVaidehi.Rangan@Sun.COM (void) pthread_mutex_unlock(&wrlck);
4637346SVaidehi.Rangan@Sun.COM /*
4647346SVaidehi.Rangan@Sun.COM * Already one other thread is active issuing ioctl call.
4657346SVaidehi.Rangan@Sun.COM * Just poll here to check the local flag without any expensive
4667346SVaidehi.Rangan@Sun.COM * ioctl calls until the transition is complete.
4677346SVaidehi.Rangan@Sun.COM */
4686429Svs195195 (void) poll(NULL, 0, 1000); /* first time 1 second wait */
4696429Svs195195 for (;;) {
4707346SVaidehi.Rangan@Sun.COM (void) pthread_mutex_lock(&wrlck);
4716429Svs195195 if (!is_active) {
4727346SVaidehi.Rangan@Sun.COM (void) pthread_mutex_unlock(&wrlck);
4736429Svs195195 break;
4746429Svs195195 }
4757346SVaidehi.Rangan@Sun.COM (void) pthread_mutex_unlock(&wrlck);
4766429Svs195195 (void) poll(NULL, 0, 4000); /* 4 seconds wait */
4776429Svs195195 }
4786429Svs195195 }
4796429Svs195195 }
480