xref: /illumos-gate/usr/src/uts/common/io/ppm/ppm_subr.c (revision 3fe80ca4)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5055d7c80Scarlsonj  * Common Development and Distribution License (the "License").
6055d7c80Scarlsonj  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22c3a64150SMargot Miller  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
26*3fe80ca4SDan Cross /*
27*3fe80ca4SDan Cross  * Copyright 2023 Oxide Computer Company
28*3fe80ca4SDan Cross  */
29*3fe80ca4SDan Cross 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * ppm driver subroutines
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <sys/open.h>
357c478bd9Sstevel@tonic-gate #include <sys/file.h>
367c478bd9Sstevel@tonic-gate #include <sys/conf.h>
377c478bd9Sstevel@tonic-gate #include <sys/epm.h>
387c478bd9Sstevel@tonic-gate #include <sys/sunldi.h>
397c478bd9Sstevel@tonic-gate #include <sys/ppmvar.h>
407c478bd9Sstevel@tonic-gate #include <sys/ppmio.h>
417c478bd9Sstevel@tonic-gate #include <sys/promif.h>
427c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
437c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
447c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
457c478bd9Sstevel@tonic-gate /*
467c478bd9Sstevel@tonic-gate  * Append address to the device path, if it is set.  Routine
477c478bd9Sstevel@tonic-gate  * ddi_pathname does not look for device address if the node is in
487c478bd9Sstevel@tonic-gate  * DS_INITIALIZED state.
497c478bd9Sstevel@tonic-gate  */
507c478bd9Sstevel@tonic-gate #define	PPM_GET_PATHNAME(dip, path)				\
517c478bd9Sstevel@tonic-gate 	(void) ddi_pathname((dip), (path));			\
527c478bd9Sstevel@tonic-gate 	if ((i_ddi_node_state((dip)) < DS_INITIALIZED) &&	\
537c478bd9Sstevel@tonic-gate 	    (ddi_get_name_addr((dip)) != NULL)) {		\
547c478bd9Sstevel@tonic-gate 		(void) strcat((path), "@");			\
557c478bd9Sstevel@tonic-gate 		(void) strcat((path), ddi_get_name_addr((dip)));\
567c478bd9Sstevel@tonic-gate 	}
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate int	ppm_parse_dc(char **, ppm_dc_t *);
597c478bd9Sstevel@tonic-gate int	ppm_match_devs(char *, ppm_db_t *);
607c478bd9Sstevel@tonic-gate ppm_db_t *ppm_parse_pattern(struct ppm_db **, char *);
617c478bd9Sstevel@tonic-gate int	ppm_count_char(char *, char);
627c478bd9Sstevel@tonic-gate int	ppm_stoi(char *, uint_t *);
637c478bd9Sstevel@tonic-gate int	ppm_convert(char *, uint_t *);
647c478bd9Sstevel@tonic-gate void	ppm_prop_free(struct ppm_cdata **);
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate /*
677c478bd9Sstevel@tonic-gate  * lookup string property from configuration file ppm.conf
687c478bd9Sstevel@tonic-gate  */
697c478bd9Sstevel@tonic-gate static int
ppm_get_confdata(struct ppm_cdata ** cdp,dev_info_t * dip)707c478bd9Sstevel@tonic-gate ppm_get_confdata(struct ppm_cdata **cdp, dev_info_t *dip)
717c478bd9Sstevel@tonic-gate {
727c478bd9Sstevel@tonic-gate #ifdef	DEBUG
737c478bd9Sstevel@tonic-gate 	char *str = "ppm_get_confdata";
747c478bd9Sstevel@tonic-gate #endif
757c478bd9Sstevel@tonic-gate 	struct ppm_cdata *cinfo;
767c478bd9Sstevel@tonic-gate 	int err;
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate 	for (; (cinfo = *cdp) != NULL; cdp++) {
797c478bd9Sstevel@tonic-gate 		err = ddi_prop_lookup_string_array(
807c478bd9Sstevel@tonic-gate 		    DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
817c478bd9Sstevel@tonic-gate 		    cinfo->name, &cinfo->strings, &cinfo->cnt);
827c478bd9Sstevel@tonic-gate 		if (err != DDI_PROP_SUCCESS) {
837c478bd9Sstevel@tonic-gate 			PPMD(D_ERROR, ("%s: no %s found, err(%d)\n",
847c478bd9Sstevel@tonic-gate 			    str, cinfo->name, err))
857c478bd9Sstevel@tonic-gate 			break;
867c478bd9Sstevel@tonic-gate 		}
877c478bd9Sstevel@tonic-gate 	}
887c478bd9Sstevel@tonic-gate 	return (err);
897c478bd9Sstevel@tonic-gate }
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate void
ppm_prop_free(struct ppm_cdata ** cdp)927c478bd9Sstevel@tonic-gate ppm_prop_free(struct ppm_cdata **cdp)
937c478bd9Sstevel@tonic-gate {
947c478bd9Sstevel@tonic-gate 	if (cdp) {
957c478bd9Sstevel@tonic-gate 		for (; *cdp; cdp++) {
967c478bd9Sstevel@tonic-gate 			if ((*cdp)->name) {
975cff7825Smh 				kmem_free((*cdp)->name,
985cff7825Smh 				    strlen((*cdp)->name) + 1);
997c478bd9Sstevel@tonic-gate 				(*cdp)->name = NULL;
1007c478bd9Sstevel@tonic-gate 			}
1017c478bd9Sstevel@tonic-gate 			if ((*cdp)->strings) {
1027c478bd9Sstevel@tonic-gate 				ddi_prop_free((*cdp)->strings);
1037c478bd9Sstevel@tonic-gate 				(*cdp)->strings = NULL;
1047c478bd9Sstevel@tonic-gate 			}
1057c478bd9Sstevel@tonic-gate 		}
1067c478bd9Sstevel@tonic-gate 	}
1077c478bd9Sstevel@tonic-gate }
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate /*
1117c478bd9Sstevel@tonic-gate  * free ddi prop strings. Under error condition, free ppm_db_t lists as well.
1127c478bd9Sstevel@tonic-gate  */
1137c478bd9Sstevel@tonic-gate static int
ppm_attach_err(struct ppm_cdata ** cdp,int err)1147c478bd9Sstevel@tonic-gate ppm_attach_err(struct ppm_cdata **cdp, int err)
1157c478bd9Sstevel@tonic-gate {
1167c478bd9Sstevel@tonic-gate 	ppm_domain_t *domp;
1177c478bd9Sstevel@tonic-gate 	ppm_db_t *db, *tmp;
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 	ppm_prop_free(cdp);
1207c478bd9Sstevel@tonic-gate 	if (err != DDI_SUCCESS) {
1217c478bd9Sstevel@tonic-gate 		for (domp = ppm_domain_p; domp; domp = domp->next) {
1227c478bd9Sstevel@tonic-gate 			for (db = domp->conflist; (tmp = db) != NULL; ) {
1237c478bd9Sstevel@tonic-gate 				db = db->next;
1247c478bd9Sstevel@tonic-gate 				kmem_free(tmp->name, strlen(tmp->name) + 1);
1257c478bd9Sstevel@tonic-gate 				kmem_free(tmp, sizeof (*tmp));
1267c478bd9Sstevel@tonic-gate 			}
1277c478bd9Sstevel@tonic-gate 			domp->conflist = NULL;
1287c478bd9Sstevel@tonic-gate 		}
1297c478bd9Sstevel@tonic-gate 		err = DDI_FAILURE;
1307c478bd9Sstevel@tonic-gate 	}
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	return (err);
1337c478bd9Sstevel@tonic-gate }
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate ppm_domain_t *
ppm_lookup_domain(char * dname)1377c478bd9Sstevel@tonic-gate ppm_lookup_domain(char *dname)
1387c478bd9Sstevel@tonic-gate {
1397c478bd9Sstevel@tonic-gate 	ppm_domain_t	*domp;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	for (domp = ppm_domain_p; domp; domp = domp->next) {
1427c478bd9Sstevel@tonic-gate 		if (strcmp(dname, domp->name) == 0)
1437c478bd9Sstevel@tonic-gate 			break;
1447c478bd9Sstevel@tonic-gate 	}
1457c478bd9Sstevel@tonic-gate 	return (domp);
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate /*
1507c478bd9Sstevel@tonic-gate  * for the purpose of optimizing we search for identical dc->path
1517c478bd9Sstevel@tonic-gate  * that has been opened per previous visit here.  If search results
1527c478bd9Sstevel@tonic-gate  * in a hit, copy the device handle, else open the device.
1537c478bd9Sstevel@tonic-gate  */
1547c478bd9Sstevel@tonic-gate ppm_dc_t *
ppm_lookup_hndl(int model,ppm_dc_t * key_dc)1557c478bd9Sstevel@tonic-gate ppm_lookup_hndl(int model, ppm_dc_t *key_dc)
1567c478bd9Sstevel@tonic-gate {
1577c478bd9Sstevel@tonic-gate #ifdef	DEBUG
1587c478bd9Sstevel@tonic-gate 	char *str = "ppm_lookup_hndl";
1597c478bd9Sstevel@tonic-gate #endif
1607c478bd9Sstevel@tonic-gate 	char *key_path = key_dc->path;
1617c478bd9Sstevel@tonic-gate 	ppm_domain_t *domp;
1627c478bd9Sstevel@tonic-gate 	ppm_dc_t *dc;
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	/* search domain by domain.model */
1657c478bd9Sstevel@tonic-gate 	for (domp = ppm_domain_p; domp; domp = domp->next) {
1667c478bd9Sstevel@tonic-gate 		if (domp->model == model)
1677c478bd9Sstevel@tonic-gate 			break;
1687c478bd9Sstevel@tonic-gate 	}
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	/* lookup hndl from same domain model */
1717c478bd9Sstevel@tonic-gate 	if (domp && PPM_DOMAIN_UP(domp)) {
1727c478bd9Sstevel@tonic-gate 		for (dc = domp->dc; dc; dc = dc->next) {
1737c478bd9Sstevel@tonic-gate 			if ((strcmp(dc->path, key_path) == 0) &&
1747c478bd9Sstevel@tonic-gate 			    (dc->lh != NULL)) {
1757c478bd9Sstevel@tonic-gate 				PPMD(D_PPMDC, ("%s: Hit(dc_path:%s) from SAME "
1767c478bd9Sstevel@tonic-gate 				    "domain %s.\n", str, key_path, domp->name))
1777c478bd9Sstevel@tonic-gate 				key_dc->lh = dc->lh;
1787c478bd9Sstevel@tonic-gate 				return (key_dc);
1797c478bd9Sstevel@tonic-gate 			}
1807c478bd9Sstevel@tonic-gate 		}
1817c478bd9Sstevel@tonic-gate 	}
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	/* otherwise, check other domains */
1847c478bd9Sstevel@tonic-gate 	for (domp = ppm_domain_p;
1857c478bd9Sstevel@tonic-gate 	    domp && (domp->model != model); domp = domp->next) {
1867c478bd9Sstevel@tonic-gate 		if (PPM_DOMAIN_UP(domp)) {
1877c478bd9Sstevel@tonic-gate 			for (dc = domp->dc; dc; dc = dc->next) {
1887c478bd9Sstevel@tonic-gate 				if ((strcmp(dc->path, key_path) == 0) &&
1897c478bd9Sstevel@tonic-gate 				    (dc->lh != NULL)) {
1907c478bd9Sstevel@tonic-gate 					PPMD(D_PPMDC, ("%s: Hit(dc_path:%s) "
1917c478bd9Sstevel@tonic-gate 					    "from domain %s\n",
1927c478bd9Sstevel@tonic-gate 					    str, key_path, domp->name))
1937c478bd9Sstevel@tonic-gate 					key_dc->lh = dc->lh;
1947c478bd9Sstevel@tonic-gate 					return (key_dc);
1957c478bd9Sstevel@tonic-gate 				}
1967c478bd9Sstevel@tonic-gate 			}
1977c478bd9Sstevel@tonic-gate 		}
1987c478bd9Sstevel@tonic-gate 	}
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	PPMD(D_PPMDC, ("%s: Miss(dc_path:%s)\n", str, key_path))
2017c478bd9Sstevel@tonic-gate 	return (NULL);
2027c478bd9Sstevel@tonic-gate }
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate #define	PPM_DOMAIN_PROP			"ppm-domains"
2067c478bd9Sstevel@tonic-gate #define	PPM_DEV_PROP_SUFFIX		"-devices"
2077c478bd9Sstevel@tonic-gate #define	PPM_MODEL_PROP_SUFFIX		"-model"
2087c478bd9Sstevel@tonic-gate #define	PPM_PROPNAME_PROP_SUFFIX	"-propname"
2097c478bd9Sstevel@tonic-gate #define	PPM_CTRL_PROP_SUFFIX		"-control"
2107c478bd9Sstevel@tonic-gate 
2115cff7825Smh struct ppm_domit ppm_domit_data[] = {
2122df1fe9cSrandyf 	"SX",  PPMD_SX, 0, PPMD_ON,
2137c478bd9Sstevel@tonic-gate 	"CPU", PPMD_CPU, PPMD_LOCK_ALL, PPMD_ON,
2147c478bd9Sstevel@tonic-gate 	"FET", PPMD_FET, PPMD_LOCK_ONE, PPMD_ON,
2157c478bd9Sstevel@tonic-gate 	"PCI", PPMD_PCI, PPMD_LOCK_ONE, PPMD_ON,
2167c478bd9Sstevel@tonic-gate 	"PCI_PROP", PPMD_PCI_PROP, PPMD_LOCK_ONE, PPMD_ON,
2177c478bd9Sstevel@tonic-gate 	"LED", PPMD_LED, 0, PPMD_ON,
2187c478bd9Sstevel@tonic-gate 	"PCIE", PPMD_PCIE, PPMD_LOCK_ONE, PPMD_ON,
2197c478bd9Sstevel@tonic-gate 	NULL
2207c478bd9Sstevel@tonic-gate };
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate /*
2237c478bd9Sstevel@tonic-gate  * store up platform dependent information provided by ppm.conf file
2247c478bd9Sstevel@tonic-gate  * into private data base
2257c478bd9Sstevel@tonic-gate  */
2267c478bd9Sstevel@tonic-gate int
ppm_create_db(dev_info_t * dip)2277c478bd9Sstevel@tonic-gate ppm_create_db(dev_info_t *dip)
2287c478bd9Sstevel@tonic-gate {
2297c478bd9Sstevel@tonic-gate #ifdef	DEBUG
2307c478bd9Sstevel@tonic-gate 	char *str = "ppm_create_db";
2317c478bd9Sstevel@tonic-gate #endif
2327c478bd9Sstevel@tonic-gate 	ppm_domain_t *domp;
2337c478bd9Sstevel@tonic-gate 	ppm_db_t *db;
2347c478bd9Sstevel@tonic-gate 	ppm_dc_t *dc;
2357c478bd9Sstevel@tonic-gate 	struct ppm_cdata domdata;	/* hold "ppm-domains" property */
2367c478bd9Sstevel@tonic-gate 	struct ppm_cdata modeldata;	/* hold "domain_xy-model" property */
2377c478bd9Sstevel@tonic-gate 	struct ppm_cdata propnamedata;	/* hold "domain_xy-propname" property */
2387c478bd9Sstevel@tonic-gate 	struct ppm_cdata devdata;	/* hold "domain_xy-devices" property */
2397c478bd9Sstevel@tonic-gate 	struct ppm_cdata dcdata;	/* hold "domain_xy-control" property */
2407c478bd9Sstevel@tonic-gate 	struct ppm_cdata *cdata[2];
2417c478bd9Sstevel@tonic-gate 	char **dom_namep, **model_namep, **dev_namep, **dc_namep;
2427c478bd9Sstevel@tonic-gate 	struct ppm_domit	*domit_p;
2437c478bd9Sstevel@tonic-gate 	int err;
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	/*
2467c478bd9Sstevel@tonic-gate 	 * get "ppm-domains" property
2477c478bd9Sstevel@tonic-gate 	 */
2487c478bd9Sstevel@tonic-gate 	bzero(&domdata, sizeof (domdata));
2497c478bd9Sstevel@tonic-gate 	domdata.name = kmem_zalloc(strlen(PPM_DOMAIN_PROP) + 1, KM_SLEEP);
2507c478bd9Sstevel@tonic-gate 	(void) strcpy(domdata.name, PPM_DOMAIN_PROP);
2517c478bd9Sstevel@tonic-gate 	cdata[0] = &domdata;
2527c478bd9Sstevel@tonic-gate 	cdata[1] = NULL;
2537c478bd9Sstevel@tonic-gate 	if (err = ppm_get_confdata(cdata, dip)) {
2547c478bd9Sstevel@tonic-gate 		PPMD(D_CREATEDB, ("%s: failed to get prop \"%s\"!\n",
2557c478bd9Sstevel@tonic-gate 		    str, PPM_DOMAIN_PROP))
2567c478bd9Sstevel@tonic-gate 		return (ppm_attach_err(cdata, err));
2577c478bd9Sstevel@tonic-gate 	}
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 	for (dom_namep = domdata.strings; *dom_namep; dom_namep++) {
2607c478bd9Sstevel@tonic-gate 		domp = kmem_zalloc(sizeof (*domp), KM_SLEEP);
2617c478bd9Sstevel@tonic-gate 		domp->name = kmem_zalloc(strlen(*dom_namep) + 1, KM_SLEEP);
2627c478bd9Sstevel@tonic-gate 		(void) strcpy(domp->name, *dom_namep);
2637c478bd9Sstevel@tonic-gate 		mutex_init(&domp->lock, NULL, MUTEX_DRIVER, NULL);
2647c478bd9Sstevel@tonic-gate 		if (ppm_domain_p == NULL)
2657c478bd9Sstevel@tonic-gate 			ppm_domain_p = domp;
2667c478bd9Sstevel@tonic-gate 		else {
2677c478bd9Sstevel@tonic-gate 			domp->next = ppm_domain_p;
2687c478bd9Sstevel@tonic-gate 			ppm_domain_p = domp;
2697c478bd9Sstevel@tonic-gate 		}
2707c478bd9Sstevel@tonic-gate 	}
2717c478bd9Sstevel@tonic-gate 	ppm_prop_free(cdata);
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 	/*
2747c478bd9Sstevel@tonic-gate 	 * more per domain property strings in ppm.conf file tell us
2757c478bd9Sstevel@tonic-gate 	 * what the nature of domain, how to performe domain control, etc.
2767c478bd9Sstevel@tonic-gate 	 * Even the property names of those per domain properties are
2777c478bd9Sstevel@tonic-gate 	 * formed consisting its domain name string.
2787c478bd9Sstevel@tonic-gate 	 * Here we walk through our domain list, and fullfill the details.
2797c478bd9Sstevel@tonic-gate 	 */
2807c478bd9Sstevel@tonic-gate 	for (domp = ppm_domain_p; domp; domp = domp->next) {
2817c478bd9Sstevel@tonic-gate 		size_t	plen;
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 		/*
2847c478bd9Sstevel@tonic-gate 		 * get "domain_xy-model" property
2857c478bd9Sstevel@tonic-gate 		 */
2867c478bd9Sstevel@tonic-gate 		bzero(&modeldata, sizeof (modeldata));
2877c478bd9Sstevel@tonic-gate 		plen = strlen(domp->name) + strlen(PPM_MODEL_PROP_SUFFIX) + 1;
2887c478bd9Sstevel@tonic-gate 		modeldata.name = kmem_zalloc(plen, KM_SLEEP);
2897c478bd9Sstevel@tonic-gate 		(void) sprintf(modeldata.name, "%s%s",
2907c478bd9Sstevel@tonic-gate 		    domp->name, PPM_MODEL_PROP_SUFFIX);
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 		cdata[0] = &modeldata;
2937c478bd9Sstevel@tonic-gate 		cdata[1] = NULL;
2947c478bd9Sstevel@tonic-gate 		if (err = ppm_get_confdata(cdata, dip)) {
2957c478bd9Sstevel@tonic-gate 			PPMD(D_CREATEDB, ("%s: Can't read property %s!\n",
2967c478bd9Sstevel@tonic-gate 			    str, modeldata.name))
2977c478bd9Sstevel@tonic-gate 			return (ppm_attach_err(cdata, err));
2987c478bd9Sstevel@tonic-gate 		}
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 		model_namep = modeldata.strings;
3015cff7825Smh 		for (domit_p = ppm_domit_data; domit_p->name; domit_p++) {
3027c478bd9Sstevel@tonic-gate 			if (strcmp(domit_p->name,  *model_namep) == 0) {
3037c478bd9Sstevel@tonic-gate 				domp->model = domit_p->model;
3047c478bd9Sstevel@tonic-gate 				domp->dflags = domit_p->dflags;
3057c478bd9Sstevel@tonic-gate 				domp->status = domit_p->status;
3067c478bd9Sstevel@tonic-gate 				break;
3077c478bd9Sstevel@tonic-gate 			}
3087c478bd9Sstevel@tonic-gate 		}
3097c478bd9Sstevel@tonic-gate 		ASSERT(domit_p);
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 		ppm_prop_free(cdata);
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 		/* get "domain_xy-propname" property */
3157c478bd9Sstevel@tonic-gate 		bzero(&propnamedata, sizeof (propnamedata));
3167c478bd9Sstevel@tonic-gate 		plen = strlen(domp->name) +
3177c478bd9Sstevel@tonic-gate 		    strlen(PPM_PROPNAME_PROP_SUFFIX) + 1;
3187c478bd9Sstevel@tonic-gate 		propnamedata.name = kmem_zalloc(plen, KM_SLEEP);
3197c478bd9Sstevel@tonic-gate 		(void) sprintf(propnamedata.name, "%s%s",
3207c478bd9Sstevel@tonic-gate 		    domp->name, PPM_PROPNAME_PROP_SUFFIX);
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 		cdata[0] = &propnamedata;
3237c478bd9Sstevel@tonic-gate 		cdata[1] = NULL;
3247c478bd9Sstevel@tonic-gate 		if (ppm_get_confdata(cdata, dip) == DDI_PROP_SUCCESS) {
3257c478bd9Sstevel@tonic-gate 			domp->propname = kmem_zalloc(
3267c478bd9Sstevel@tonic-gate 			    (strlen(*propnamedata.strings) + 1), KM_SLEEP);
3277c478bd9Sstevel@tonic-gate 			(void) strcpy(domp->propname, *propnamedata.strings);
3287c478bd9Sstevel@tonic-gate 			PPMD(D_CREATEDB, ("%s: %s has property name: %s\n",
3297c478bd9Sstevel@tonic-gate 			    str, domp->name, domp->propname))
3307c478bd9Sstevel@tonic-gate 		}
3317c478bd9Sstevel@tonic-gate 		ppm_prop_free(cdata);
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 		/* get "domain_xy-devices" property */
3357c478bd9Sstevel@tonic-gate 		bzero(&devdata, sizeof (devdata));
3367c478bd9Sstevel@tonic-gate 		plen = strlen(domp->name) + strlen(PPM_DEV_PROP_SUFFIX) + 1;
3377c478bd9Sstevel@tonic-gate 		devdata.name = kmem_zalloc(plen, KM_SLEEP);
3387c478bd9Sstevel@tonic-gate 		(void) sprintf(devdata.name, "%s%s",
3397c478bd9Sstevel@tonic-gate 		    domp->name, PPM_DEV_PROP_SUFFIX);
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 		cdata[0] = &devdata;
3427c478bd9Sstevel@tonic-gate 		cdata[1] = NULL;
3437c478bd9Sstevel@tonic-gate 		if (err = ppm_get_confdata(cdata, dip)) {
3447c478bd9Sstevel@tonic-gate 			PPMD(D_CREATEDB, ("%s: Can't read property %s!\n",
3457c478bd9Sstevel@tonic-gate 			    str, devdata.name))
3467c478bd9Sstevel@tonic-gate 			return (ppm_attach_err(cdata, err));
3477c478bd9Sstevel@tonic-gate 		}
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 		for (dev_namep = devdata.strings; *dev_namep; dev_namep++) {
3507c478bd9Sstevel@tonic-gate 			if (!ppm_parse_pattern(&db, *dev_namep))
3517c478bd9Sstevel@tonic-gate 				return (ppm_attach_err(cdata, err));
3527c478bd9Sstevel@tonic-gate 			db->next = domp->conflist;
3537c478bd9Sstevel@tonic-gate 			domp->conflist = db;
3547c478bd9Sstevel@tonic-gate 			PPMD(D_CREATEDB, ("%s: %s add pattern: %s \n",
3557c478bd9Sstevel@tonic-gate 			    str, devdata.name, db->name))
3567c478bd9Sstevel@tonic-gate 		}
3577c478bd9Sstevel@tonic-gate 		PPMD(D_CREATEDB, ("\n"))
3587c478bd9Sstevel@tonic-gate 		ppm_prop_free(cdata);
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 		/* get "domain_xy-control" property */
3627c478bd9Sstevel@tonic-gate 		bzero(&dcdata, sizeof (dcdata));
3637c478bd9Sstevel@tonic-gate 		plen = strlen(domp->name) + strlen(PPM_CTRL_PROP_SUFFIX) + 1;
3647c478bd9Sstevel@tonic-gate 		dcdata.name = kmem_zalloc(plen, KM_SLEEP);
3657c478bd9Sstevel@tonic-gate 		(void) sprintf(dcdata.name, "%s%s",
3667c478bd9Sstevel@tonic-gate 		    domp->name, PPM_CTRL_PROP_SUFFIX);
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 		cdata[0] = &dcdata;
3697c478bd9Sstevel@tonic-gate 		cdata[1] = NULL;
3705cff7825Smh 		if (ppm_get_confdata(cdata, dip) == DDI_PROP_SUCCESS) {
3715cff7825Smh 			for (dc_namep = dcdata.strings; *dc_namep;
3725cff7825Smh 			    dc_namep++) {
3735cff7825Smh 				dc = kmem_zalloc(sizeof (*dc), KM_SLEEP);
3745cff7825Smh 				dc->next = domp->dc;
3755cff7825Smh 				domp->dc = dc;
3765cff7825Smh 				err = ppm_parse_dc(dc_namep, domp->dc);
3775cff7825Smh 				if (err != DDI_SUCCESS)
3785cff7825Smh 					return (ppm_attach_err(cdata, err));
3795cff7825Smh 			}
3807c478bd9Sstevel@tonic-gate 		}
3817c478bd9Sstevel@tonic-gate 		ppm_prop_free(cdata);
3827c478bd9Sstevel@tonic-gate #ifdef	DEBUG
3837c478bd9Sstevel@tonic-gate 		dc = domp->dc;
3847c478bd9Sstevel@tonic-gate 		while (dc) {
3857c478bd9Sstevel@tonic-gate 			ppm_print_dc(dc);
3867c478bd9Sstevel@tonic-gate 			dc = dc->next;
3877c478bd9Sstevel@tonic-gate 		}
3887c478bd9Sstevel@tonic-gate #endif
3897c478bd9Sstevel@tonic-gate 	}
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
3927c478bd9Sstevel@tonic-gate }
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate /*
3967c478bd9Sstevel@tonic-gate  * scan conf devices within each domain for a matching device name
3977c478bd9Sstevel@tonic-gate  */
3987c478bd9Sstevel@tonic-gate ppm_domain_t *
ppm_lookup_dev(dev_info_t * dip)3997c478bd9Sstevel@tonic-gate ppm_lookup_dev(dev_info_t *dip)
4007c478bd9Sstevel@tonic-gate {
4017c478bd9Sstevel@tonic-gate 	char path[MAXNAMELEN];
4027c478bd9Sstevel@tonic-gate 	ppm_domain_t *domp;
4037c478bd9Sstevel@tonic-gate 	ppm_db_t *dbp;
404b72d5b75SMichael Corcoran #ifdef	__x86
405b72d5b75SMichael Corcoran 	char *devtype = NULL;
406b72d5b75SMichael Corcoran #endif	/* __x86 */
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	PPM_GET_PATHNAME(dip, path);
4097c478bd9Sstevel@tonic-gate 	for (domp = ppm_domain_p; domp; domp = domp->next) {
4102df1fe9cSrandyf 		if (PPM_DOMAIN_UP(domp)) {
4117c478bd9Sstevel@tonic-gate 			for (dbp = domp->conflist; dbp; dbp = dbp->next) {
4122df1fe9cSrandyf 				/*
4132df1fe9cSrandyf 				 * allow claiming root without knowing
4142df1fe9cSrandyf 				 * its full name
4152df1fe9cSrandyf 				 */
4162df1fe9cSrandyf 				if (dip == ddi_root_node() &&
4172df1fe9cSrandyf 				    strcmp(dbp->name, "/") == 0)
4182df1fe9cSrandyf 					return (domp);
419b72d5b75SMichael Corcoran 
420b72d5b75SMichael Corcoran #ifdef	__x86
421b72d5b75SMichael Corcoran 				/*
422b72d5b75SMichael Corcoran 				 * Special rule to catch all CPU devices on x86.
423b72d5b75SMichael Corcoran 				 */
424b72d5b75SMichael Corcoran 				if (domp->model == PPMD_CPU &&
425b72d5b75SMichael Corcoran 				    strcmp(dbp->name, "/") == 0 &&
426b72d5b75SMichael Corcoran 				    ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
427b72d5b75SMichael Corcoran 				    DDI_PROP_DONTPASS, "device_type",
428b72d5b75SMichael Corcoran 				    &devtype) == DDI_SUCCESS) {
429b72d5b75SMichael Corcoran 					if (strcmp(devtype, "cpu") == 0) {
430b72d5b75SMichael Corcoran 						ddi_prop_free(devtype);
431b72d5b75SMichael Corcoran 						return (domp);
432b72d5b75SMichael Corcoran 					} else {
433b72d5b75SMichael Corcoran 						ddi_prop_free(devtype);
434b72d5b75SMichael Corcoran 					}
435b72d5b75SMichael Corcoran 				}
436b72d5b75SMichael Corcoran #endif	/* __x86 */
437b72d5b75SMichael Corcoran 
4387c478bd9Sstevel@tonic-gate 				if (ppm_match_devs(path, dbp) == 0)
4397c478bd9Sstevel@tonic-gate 					return (domp);
4407c478bd9Sstevel@tonic-gate 			}
4412df1fe9cSrandyf 		}
4427c478bd9Sstevel@tonic-gate 	}
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	return (NULL);
4457c478bd9Sstevel@tonic-gate }
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate /*
4497c478bd9Sstevel@tonic-gate  * check ppm.conf file domain device pathname syntax, if correct,
4507c478bd9Sstevel@tonic-gate  * create device match pattern.
4517c478bd9Sstevel@tonic-gate  * return 1 for good, -1 for bad.
4527c478bd9Sstevel@tonic-gate  */
4537c478bd9Sstevel@tonic-gate ppm_db_t *
ppm_parse_pattern(struct ppm_db ** dbpp,char * dev_path)4547c478bd9Sstevel@tonic-gate ppm_parse_pattern(struct ppm_db **dbpp, char *dev_path)
4557c478bd9Sstevel@tonic-gate {
4567c478bd9Sstevel@tonic-gate 	char path[MAXNAMELEN];
4577c478bd9Sstevel@tonic-gate 	int	wccnt, i;
4587c478bd9Sstevel@tonic-gate 	int	wcpos[2];
4595cff7825Smh 	int	pos;
4607c478bd9Sstevel@tonic-gate 	char	*cp;
4617c478bd9Sstevel@tonic-gate 	ppm_db_t *dbp;
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	(void) strcpy(path, dev_path);
4647c478bd9Sstevel@tonic-gate 	if ((wccnt = ppm_count_char(path, '*')) > 2)
4657c478bd9Sstevel@tonic-gate 		return (NULL);
4667c478bd9Sstevel@tonic-gate 
4675cff7825Smh 	for (i = 0, cp = path, pos = 0; i < wccnt; i++, cp++, pos++) {
4685cff7825Smh 		for (; *cp; cp++, pos++)
4697c478bd9Sstevel@tonic-gate 			if (*cp == '*')
4707c478bd9Sstevel@tonic-gate 				break;
4715cff7825Smh 		wcpos[i] = pos;
4727c478bd9Sstevel@tonic-gate 		PPMD(D_CREATEDB, ("    wildcard #%d, pos %d\n",
4737c478bd9Sstevel@tonic-gate 		    (i + 1), wcpos[i]))
4747c478bd9Sstevel@tonic-gate 	}
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate #ifdef	DEBUG
4777c478bd9Sstevel@tonic-gate 	/* first '*', if exists, don't go beyond the string */
4787c478bd9Sstevel@tonic-gate 	if (wccnt > 0)
4797c478bd9Sstevel@tonic-gate 		ASSERT(wcpos[0] < strlen(path));
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	/* second '*', if exists, better be the last character */
4827c478bd9Sstevel@tonic-gate 	if (wccnt == 2)
4837c478bd9Sstevel@tonic-gate 		ASSERT(wcpos[1] == (strlen(path) - 1));
4847c478bd9Sstevel@tonic-gate #endif
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	/*
4877c478bd9Sstevel@tonic-gate 	 * first '*', if followed by any char, must be immediately
4887c478bd9Sstevel@tonic-gate 	 * followed by '@' and the rest better be bound by
4897c478bd9Sstevel@tonic-gate 	 * ['0-9', 'a-f', A-F'] until ended '0' or second '*''0'.
4907c478bd9Sstevel@tonic-gate 	 */
4917c478bd9Sstevel@tonic-gate 	if ((wccnt > 0) && (wcpos[0] < (strlen(path) - 1))) {
4927c478bd9Sstevel@tonic-gate 		cp = path + wcpos[0] + 1;
4937c478bd9Sstevel@tonic-gate 		if (*cp != '@')
4947c478bd9Sstevel@tonic-gate 			return (NULL);
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 		if (!(((*(++cp) > '0') && (*cp < '9')) ||
4977c478bd9Sstevel@tonic-gate 		    ((*cp > 'a') && (*cp < 'f')) ||
4987c478bd9Sstevel@tonic-gate 		    ((*cp > 'A') && (*cp < 'F'))))
4997c478bd9Sstevel@tonic-gate 			return (NULL);
5007c478bd9Sstevel@tonic-gate 	}
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	dbp = kmem_zalloc(sizeof (struct ppm_db), KM_SLEEP);
5037c478bd9Sstevel@tonic-gate 	dbp->name = kmem_zalloc((strlen(path) + 1), KM_SLEEP);
5047c478bd9Sstevel@tonic-gate 	(void) strcpy(dbp->name, path);
5057c478bd9Sstevel@tonic-gate 	dbp->wccnt = wccnt;
5067c478bd9Sstevel@tonic-gate 	dbp->wcpos[0] = (wccnt > 0) ? wcpos[0] : -1;
5077c478bd9Sstevel@tonic-gate 	dbp->wcpos[1] = (wccnt == 2) ? wcpos[1] : -1;
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	return (*dbpp = dbp);
5107c478bd9Sstevel@tonic-gate }
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate /*
5147c478bd9Sstevel@tonic-gate  * match given device "path" to domain device pathname
5157c478bd9Sstevel@tonic-gate  * pattern dbp->name that contains one or two '*' character(s).
5167c478bd9Sstevel@tonic-gate  * Matching policy:
5177c478bd9Sstevel@tonic-gate  *   1). If one wildcard terminates match pattern, need exact match
5187c478bd9Sstevel@tonic-gate  *       up to (but exclude) the wildcard;
5197c478bd9Sstevel@tonic-gate  *   2). If one wildcard does not terminate match pattern, it is to
5207c478bd9Sstevel@tonic-gate  *       match driver name (terminates with '@') and must be followed
5217c478bd9Sstevel@tonic-gate  *       by exact match of rest of pattern;
5227c478bd9Sstevel@tonic-gate  *   3). If two wildcards, first is to match driver name as in 2),
5237c478bd9Sstevel@tonic-gate  *       second is to match fcnid (terminates with '/' or '\0') and
5247c478bd9Sstevel@tonic-gate  *       must the last char of pattern.
5257c478bd9Sstevel@tonic-gate  *
5267c478bd9Sstevel@tonic-gate  * return  0  if match, and
5277c478bd9Sstevel@tonic-gate  *        non 0  if mismatch
5287c478bd9Sstevel@tonic-gate  */
5297c478bd9Sstevel@tonic-gate int
ppm_match_devs(char * dev_path,ppm_db_t * dbp)5307c478bd9Sstevel@tonic-gate ppm_match_devs(char *dev_path, ppm_db_t *dbp)
5317c478bd9Sstevel@tonic-gate {
5327c478bd9Sstevel@tonic-gate 	char path[MAXNAMELEN];
5337c478bd9Sstevel@tonic-gate 	char *cp;	/* points into "path", real device pathname */
5347c478bd9Sstevel@tonic-gate 	char *np;	/* points into "dbp->name", the pattern */
5357c478bd9Sstevel@tonic-gate 	int  len;
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 	if (dbp->wccnt == 0)
5387c478bd9Sstevel@tonic-gate 		return (strcmp(dev_path, dbp->name));
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	(void) strcpy(path, dev_path);
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	/* match upto the first '*' regardless */
5437c478bd9Sstevel@tonic-gate 	if (strncmp(path, dbp->name, dbp->wcpos[0]) != 0)
5447c478bd9Sstevel@tonic-gate 		return (-1);
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	/* "<exact match>*"	*/
5487c478bd9Sstevel@tonic-gate 	if (dbp->name[dbp->wcpos[0] + 1] == 0) {
5497c478bd9Sstevel@tonic-gate 		cp = path + dbp->wcpos[0];
5502df1fe9cSrandyf 		while (*cp && (*cp++ != '/'))
5512df1fe9cSrandyf 			;
5527c478bd9Sstevel@tonic-gate 		return ((*cp == 0) ? 0 : -1);
5537c478bd9Sstevel@tonic-gate 	}
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	/* locate '@'	*/
5577c478bd9Sstevel@tonic-gate 	cp = path + dbp->wcpos[0] + 1;
5587c478bd9Sstevel@tonic-gate 	while (*cp && *cp != '@')
5597c478bd9Sstevel@tonic-gate 		cp++;
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 	np = dbp->name + dbp->wcpos[0] + 1;
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	/* if one wildcard, match the rest in the pattern */
5647c478bd9Sstevel@tonic-gate 	if (dbp->wccnt == 1)
5657c478bd9Sstevel@tonic-gate 		return ((strcmp(cp, np) == 0) ? 0 : (-1));
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	/* must have exact match after first wildcard up to second */
5697c478bd9Sstevel@tonic-gate 	ASSERT(dbp->wccnt == 2);
5707c478bd9Sstevel@tonic-gate 	len = dbp->wcpos[1] - dbp->wcpos[0] - 1;
5717c478bd9Sstevel@tonic-gate 	if (strncmp(cp, np, len) != 0)
5727c478bd9Sstevel@tonic-gate 		return (-1);
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	/* second wildcard match terminates with '/' or '\0' */
5757c478bd9Sstevel@tonic-gate 	/* but only termination with '\0' is a successful match */
5767c478bd9Sstevel@tonic-gate 	cp += len;
5777c478bd9Sstevel@tonic-gate 	while (*cp && (*cp != '/'))
5787c478bd9Sstevel@tonic-gate 		cp++;
5797c478bd9Sstevel@tonic-gate 	return ((*cp == 0) ? 0 : -1);
5807c478bd9Sstevel@tonic-gate }
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate /*
5847c478bd9Sstevel@tonic-gate  * By claiming a device, ppm gets involved in its power change
5857c478bd9Sstevel@tonic-gate  * process: handles additional issues prior and/or post its
5867c478bd9Sstevel@tonic-gate  * power(9e) call.
5877c478bd9Sstevel@tonic-gate  *
5887c478bd9Sstevel@tonic-gate  * If 'dip' is a PCI device, this is the time to ask its parent
5897c478bd9Sstevel@tonic-gate  * what PCI bus speed it is running.
5907c478bd9Sstevel@tonic-gate  *
5917c478bd9Sstevel@tonic-gate  * returns 1 (claimed), 0 (not claimed)
5927c478bd9Sstevel@tonic-gate  */
5937c478bd9Sstevel@tonic-gate int
ppm_claim_dev(dev_info_t * dip)5947c478bd9Sstevel@tonic-gate ppm_claim_dev(dev_info_t *dip)
5957c478bd9Sstevel@tonic-gate {
5967c478bd9Sstevel@tonic-gate 	ppm_domain_t	*domp;
5977c478bd9Sstevel@tonic-gate 	dev_info_t	*pdip;
5987c478bd9Sstevel@tonic-gate 	uint_t		pciclk;
5997c478bd9Sstevel@tonic-gate 	int		claimed = -1;
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	domp = ppm_lookup_dev(dip);
6027c478bd9Sstevel@tonic-gate 	if (!domp)
6037c478bd9Sstevel@tonic-gate 		claimed = 0;
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	if (domp && PPMD_IS_PCI(domp->model) &&
6067c478bd9Sstevel@tonic-gate 	    ! (domp->dflags & (PPMD_PCI33MHZ | PPMD_PCI66MHZ))) {
6077c478bd9Sstevel@tonic-gate 		pdip = ddi_get_parent(dip);
6087c478bd9Sstevel@tonic-gate 		ASSERT(pdip);
6097c478bd9Sstevel@tonic-gate 		pciclk = ddi_prop_get_int(DDI_DEV_T_ANY, pdip,
6107c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "clock-frequency", -1);
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 		switch (pciclk) {
6137c478bd9Sstevel@tonic-gate 		case 33000000:
6147c478bd9Sstevel@tonic-gate 			domp->dflags |= PPMD_PCI33MHZ;
6157c478bd9Sstevel@tonic-gate 			claimed = 1;
6167c478bd9Sstevel@tonic-gate 			break;
6177c478bd9Sstevel@tonic-gate 		case 66000000:
6187c478bd9Sstevel@tonic-gate 			domp->dflags |= PPMD_PCI66MHZ;
6197c478bd9Sstevel@tonic-gate 			claimed = 1;
6207c478bd9Sstevel@tonic-gate 			break;
6217c478bd9Sstevel@tonic-gate 		default:
6227c478bd9Sstevel@tonic-gate 			claimed = 0;
6237c478bd9Sstevel@tonic-gate 			break;
6247c478bd9Sstevel@tonic-gate 		}
6257c478bd9Sstevel@tonic-gate 	}
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	if (domp && (claimed == -1))
6287c478bd9Sstevel@tonic-gate 		claimed = 1;
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate #ifdef DEBUG
6317c478bd9Sstevel@tonic-gate 	if (claimed) {
6327c478bd9Sstevel@tonic-gate 		char path[MAXNAMELEN];
6337c478bd9Sstevel@tonic-gate 		PPMD(D_CLAIMDEV, ("ppm_claim_dev: %s into domain %s\n",
6347c478bd9Sstevel@tonic-gate 		    ddi_pathname(dip, path), domp->name))
6357c478bd9Sstevel@tonic-gate 	}
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate #endif
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 	return (claimed);
6407c478bd9Sstevel@tonic-gate }
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate /*
6437c478bd9Sstevel@tonic-gate  * add a device to the list of domain's owned devices (if it is not already
6447c478bd9Sstevel@tonic-gate  * on the list).
6457c478bd9Sstevel@tonic-gate  */
6467c478bd9Sstevel@tonic-gate ppm_owned_t *
ppm_add_owned(dev_info_t * dip,ppm_domain_t * domp)6477c478bd9Sstevel@tonic-gate ppm_add_owned(dev_info_t *dip, ppm_domain_t *domp)
6487c478bd9Sstevel@tonic-gate {
6497c478bd9Sstevel@tonic-gate 	char path[MAXNAMELEN];
6507c478bd9Sstevel@tonic-gate 	ppm_owned_t *owned, *new_owned;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&domp->lock));
6537c478bd9Sstevel@tonic-gate 	PPM_GET_PATHNAME(dip, path);
6547c478bd9Sstevel@tonic-gate 	for (owned = domp->owned; owned; owned = owned->next)
6557c478bd9Sstevel@tonic-gate 		if (strcmp(path, owned->path) == 0)
6567c478bd9Sstevel@tonic-gate 			return (owned);
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	new_owned = kmem_zalloc(sizeof (*new_owned), KM_SLEEP);
6597c478bd9Sstevel@tonic-gate 	new_owned->path = kmem_zalloc(strlen(path) + 1, KM_SLEEP);
6607c478bd9Sstevel@tonic-gate 	(void) strcpy(new_owned->path, path);
6617c478bd9Sstevel@tonic-gate 	new_owned->next = domp->owned;
6627c478bd9Sstevel@tonic-gate 	domp->owned = new_owned;
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 	return (domp->owned);
6657c478bd9Sstevel@tonic-gate }
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate /*
6687c478bd9Sstevel@tonic-gate  * create/init a new ppm device and link into the domain
6697c478bd9Sstevel@tonic-gate  */
6705cff7825Smh ppm_dev_t *
ppm_add_dev(dev_info_t * dip,ppm_domain_t * domp)6717c478bd9Sstevel@tonic-gate ppm_add_dev(dev_info_t *dip, ppm_domain_t *domp)
6727c478bd9Sstevel@tonic-gate {
6737c478bd9Sstevel@tonic-gate 	char path[MAXNAMELEN];
6747c478bd9Sstevel@tonic-gate 	ppm_dev_t *new = NULL;
6757c478bd9Sstevel@tonic-gate 	int cmpt;
6767c478bd9Sstevel@tonic-gate 	ppm_owned_t *owned;
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&domp->lock));
6797c478bd9Sstevel@tonic-gate 	(void) ddi_pathname(dip, path);
6807c478bd9Sstevel@tonic-gate 	/*
6817c478bd9Sstevel@tonic-gate 	 * For devs which have exported "pm-components" we want to create
6827c478bd9Sstevel@tonic-gate 	 * a data structure for each component.  When a driver chooses not
6837c478bd9Sstevel@tonic-gate 	 * to export the prop we treat its device as having a single
6847c478bd9Sstevel@tonic-gate 	 * component and build a structure for it anyway.  All other ppm
6857c478bd9Sstevel@tonic-gate 	 * logic will act as if this device were always up and can thus
6867c478bd9Sstevel@tonic-gate 	 * make correct decisions about it in relation to other devices
6877c478bd9Sstevel@tonic-gate 	 * in its domain.
6887c478bd9Sstevel@tonic-gate 	 */
6897c478bd9Sstevel@tonic-gate 	for (cmpt = PM_GET_PM_INFO(dip) ? PM_NUMCMPTS(dip) : 1; cmpt--; ) {
6907c478bd9Sstevel@tonic-gate 		new = kmem_zalloc(sizeof (*new), KM_SLEEP);
6917c478bd9Sstevel@tonic-gate 		new->path = kmem_zalloc(strlen(path) + 1, KM_SLEEP);
6927c478bd9Sstevel@tonic-gate 		(void) strcpy(new->path, path);
6937c478bd9Sstevel@tonic-gate 		new->domp = domp;
6947c478bd9Sstevel@tonic-gate 		new->dip = dip;
6957c478bd9Sstevel@tonic-gate 		new->cmpt = cmpt;
6967c478bd9Sstevel@tonic-gate 		ppm_dev_init(new);
6977c478bd9Sstevel@tonic-gate 		new->next = domp->devlist;
6987c478bd9Sstevel@tonic-gate 		domp->devlist = new;
6997c478bd9Sstevel@tonic-gate 		PPMD(D_ADDDEV,
7007c478bd9Sstevel@tonic-gate 		    ("ppm_add_dev: %s to domain %s: ppm_dev(0x%p)\n",
7017c478bd9Sstevel@tonic-gate 		    new->path, domp->name, (void *)new))
7027c478bd9Sstevel@tonic-gate 	}
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 	ASSERT(new != NULL);
7057c478bd9Sstevel@tonic-gate 	/*
7067c478bd9Sstevel@tonic-gate 	 * devi_pm_ppm_private should be set only after all
7077c478bd9Sstevel@tonic-gate 	 * ppm_dev s related to all components have been
7087c478bd9Sstevel@tonic-gate 	 * initialized and domain's pwr_cnt is incremented
7097c478bd9Sstevel@tonic-gate 	 * for each of them.
7107c478bd9Sstevel@tonic-gate 	 */
7117c478bd9Sstevel@tonic-gate 	PPM_SET_PRIVATE(dip, new);
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	/* remember this device forever */
7147c478bd9Sstevel@tonic-gate 	owned = ppm_add_owned(dip, domp);
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	/*
7177c478bd9Sstevel@tonic-gate 	 * Initializing flag is set for devices which have gone through
7187c478bd9Sstevel@tonic-gate 	 * PPM_PMR_INIT_CHILD ctlop.  By this point, these devices have
7197c478bd9Sstevel@tonic-gate 	 * been added to ppm structures and could participate in pm
7207c478bd9Sstevel@tonic-gate 	 * decision making, so clear the initializing flag.
7217c478bd9Sstevel@tonic-gate 	 */
7227c478bd9Sstevel@tonic-gate 	if (owned->initializing) {
7237c478bd9Sstevel@tonic-gate 		owned->initializing = 0;
7247c478bd9Sstevel@tonic-gate 		PPMD(D_ADDDEV, ("ppm_add_dev: cleared initializing flag "
7257c478bd9Sstevel@tonic-gate 		    "for %s@%s\n", PM_NAME(dip),
7267c478bd9Sstevel@tonic-gate 		    (PM_ADDR(dip) == NULL) ? "" : PM_ADDR(dip)))
7277c478bd9Sstevel@tonic-gate 	}
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	return (new);
7307c478bd9Sstevel@tonic-gate }
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate /*
7347c478bd9Sstevel@tonic-gate  * returns an existing or newly created ppm device reference
7357c478bd9Sstevel@tonic-gate  */
7367c478bd9Sstevel@tonic-gate ppm_dev_t *
ppm_get_dev(dev_info_t * dip,ppm_domain_t * domp)7377c478bd9Sstevel@tonic-gate ppm_get_dev(dev_info_t *dip, ppm_domain_t *domp)
7387c478bd9Sstevel@tonic-gate {
7397c478bd9Sstevel@tonic-gate 	ppm_dev_t *pdp;
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 	mutex_enter(&domp->lock);
7427c478bd9Sstevel@tonic-gate 	pdp = PPM_GET_PRIVATE(dip);
7437c478bd9Sstevel@tonic-gate 	if (pdp == NULL)
7447c478bd9Sstevel@tonic-gate 		pdp = ppm_add_dev(dip, domp);
7457c478bd9Sstevel@tonic-gate 	mutex_exit(&domp->lock);
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 	return (pdp);
7487c478bd9Sstevel@tonic-gate }
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate /*
7527c478bd9Sstevel@tonic-gate  * scan a domain's device list and remove those with .dip
7537c478bd9Sstevel@tonic-gate  * matching the arg *dip; we need to scan the entire list
7547c478bd9Sstevel@tonic-gate  * for the case of devices with multiple components
7557c478bd9Sstevel@tonic-gate  */
7567c478bd9Sstevel@tonic-gate void
ppm_rem_dev(dev_info_t * dip)7577c478bd9Sstevel@tonic-gate ppm_rem_dev(dev_info_t *dip)
7587c478bd9Sstevel@tonic-gate {
7597c478bd9Sstevel@tonic-gate 	ppm_dev_t *pdp, **devpp;
7607c478bd9Sstevel@tonic-gate 	ppm_domain_t *domp;
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 	pdp = PPM_GET_PRIVATE(dip);
7637c478bd9Sstevel@tonic-gate 	ASSERT(pdp);
7647c478bd9Sstevel@tonic-gate 	domp = pdp->domp;
7657c478bd9Sstevel@tonic-gate 	ASSERT(domp);
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 	mutex_enter(&domp->lock);
7687c478bd9Sstevel@tonic-gate 	for (devpp = &domp->devlist; (pdp = *devpp) != NULL; ) {
7697c478bd9Sstevel@tonic-gate 		if (pdp->dip != dip) {
7707c478bd9Sstevel@tonic-gate 			devpp = &pdp->next;
7717c478bd9Sstevel@tonic-gate 			continue;
7727c478bd9Sstevel@tonic-gate 		}
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 		PPMD(D_REMDEV, ("ppm_rem_dev: path \"%s\", ppm_dev 0x%p\n",
7757c478bd9Sstevel@tonic-gate 		    pdp->path, (void *)pdp))
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 		PPM_SET_PRIVATE(dip, NULL);
7787c478bd9Sstevel@tonic-gate 		*devpp = pdp->next;
7797c478bd9Sstevel@tonic-gate 		ppm_dev_fini(pdp);
7807c478bd9Sstevel@tonic-gate 		kmem_free(pdp->path, strlen(pdp->path) + 1);
7817c478bd9Sstevel@tonic-gate 		kmem_free(pdp, sizeof (*pdp));
7827c478bd9Sstevel@tonic-gate 	}
7837c478bd9Sstevel@tonic-gate 	mutex_exit(&domp->lock);
7847c478bd9Sstevel@tonic-gate }
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate /*
7877c478bd9Sstevel@tonic-gate  * prepare kernel ioctl calls:
7887c478bd9Sstevel@tonic-gate  */
7897c478bd9Sstevel@tonic-gate void
ppm_init_cb(dev_info_t * dip)7907c478bd9Sstevel@tonic-gate ppm_init_cb(dev_info_t *dip)
7917c478bd9Sstevel@tonic-gate {
7927c478bd9Sstevel@tonic-gate 	char		*str = "ppm_init_cb";
7937c478bd9Sstevel@tonic-gate 	ppm_domain_t	*domp;
7947c478bd9Sstevel@tonic-gate 	ppm_dc_t	*dc;
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate 	for (domp = ppm_domain_p; domp != NULL; domp = domp->next) {
7975cff7825Smh 		for (dc = domp->dc; dc; dc = dc->next) {
7982df1fe9cSrandyf 			/*
7992df1fe9cSrandyf 			 * Warning: This code is rather confusing.
8002df1fe9cSrandyf 			 *
8012df1fe9cSrandyf 			 * It intends to ensure that ppm_init_lyr() is only
8022df1fe9cSrandyf 			 * called ONCE for a device that may be associated
8032df1fe9cSrandyf 			 * with more than one domain control.
8042df1fe9cSrandyf 			 * So, what it does is first to check to see if
8052df1fe9cSrandyf 			 * there is a handle, and then if not it goes on
8062df1fe9cSrandyf 			 * to call the init_lyr() routine.
8072df1fe9cSrandyf 			 *
8082df1fe9cSrandyf 			 * The non-obvious thing is that the ppm_init_lyr()
8092df1fe9cSrandyf 			 * routine, in addition to opening the device
8102df1fe9cSrandyf 			 * associated with the dc (domain control) in
8112df1fe9cSrandyf 			 * question, has the side-effect of creating the
8122df1fe9cSrandyf 			 * handle for that dc as well.
8132df1fe9cSrandyf 			 */
8147c478bd9Sstevel@tonic-gate 			if (ppm_lookup_hndl(domp->model, dc) != NULL)
8157c478bd9Sstevel@tonic-gate 				continue;
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 			if (ppm_init_lyr(dc, dip) != DDI_SUCCESS) {
8187c478bd9Sstevel@tonic-gate 				domp->dflags |= PPMD_OFFLINE;
8197c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s: ppm domain %s will "
8207c478bd9Sstevel@tonic-gate 				    "be offline.", str, domp->name);
8217c478bd9Sstevel@tonic-gate 				break;
8227c478bd9Sstevel@tonic-gate 			}
8235cff7825Smh 		}
8247c478bd9Sstevel@tonic-gate 	}
8257c478bd9Sstevel@tonic-gate }
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate /*
8297c478bd9Sstevel@tonic-gate  *  ppm_init_lyr - initializing layered ioctl
8307c478bd9Sstevel@tonic-gate  * Return:
8317c478bd9Sstevel@tonic-gate  *     DDI_SUCCESS  - succeeded
8327c478bd9Sstevel@tonic-gate  *     DDI_FAILURE  - failed
8337c478bd9Sstevel@tonic-gate  *
8347c478bd9Sstevel@tonic-gate  */
8357c478bd9Sstevel@tonic-gate int
ppm_init_lyr(ppm_dc_t * dc,dev_info_t * dip)8367c478bd9Sstevel@tonic-gate ppm_init_lyr(ppm_dc_t	*dc, dev_info_t *dip)
8377c478bd9Sstevel@tonic-gate {
83890fd2775SToomas Soome 	char			*str = "ppm_init_lyr";
8397c478bd9Sstevel@tonic-gate 	int			err = 0;
8407c478bd9Sstevel@tonic-gate 	ldi_ident_t		li;
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 	ASSERT(dc && dc->path);
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 	if (err = ldi_ident_from_dip(dip, &li)) {
8457c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s: get ldi identifier "
8467c478bd9Sstevel@tonic-gate 		    "failed (err=%d)", str, err);
8477c478bd9Sstevel@tonic-gate 	}
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	err = ldi_open_by_name(dc->path, FWRITE|FREAD, kcred, &(dc->lh), li);
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	(void) ldi_ident_release(li);
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	if (err != 0) {
8547c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "Failed to open device(%s), rv(%d)",
8557c478bd9Sstevel@tonic-gate 		    dc->path, err);
8567c478bd9Sstevel@tonic-gate 		return (err);
8577c478bd9Sstevel@tonic-gate 	}
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
8607c478bd9Sstevel@tonic-gate }
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate /*
8637c478bd9Sstevel@tonic-gate  * lock, unlock, or trylock for one power mutex
8647c478bd9Sstevel@tonic-gate  */
8657c478bd9Sstevel@tonic-gate void
ppm_lock_one(ppm_dev_t * ppmd,power_req_t * reqp,int * iresp)8667c478bd9Sstevel@tonic-gate ppm_lock_one(ppm_dev_t *ppmd, power_req_t *reqp, int *iresp)
8677c478bd9Sstevel@tonic-gate {
8687c478bd9Sstevel@tonic-gate 	switch (reqp->request_type) {
8697c478bd9Sstevel@tonic-gate 	case PMR_PPM_LOCK_POWER:
870*3fe80ca4SDan Cross 		pm_lock_power_single(ppmd->dip);
8717c478bd9Sstevel@tonic-gate 		break;
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 	case PMR_PPM_UNLOCK_POWER:
874*3fe80ca4SDan Cross 		pm_unlock_power_single(ppmd->dip);
8757c478bd9Sstevel@tonic-gate 		break;
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 	case PMR_PPM_TRY_LOCK_POWER:
878*3fe80ca4SDan Cross 		*iresp = pm_try_locking_power_single(ppmd->dip);
8797c478bd9Sstevel@tonic-gate 		break;
8807c478bd9Sstevel@tonic-gate 	}
8817c478bd9Sstevel@tonic-gate }
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate /*
8857c478bd9Sstevel@tonic-gate  * lock, unlock, or trylock for all power mutexes within a domain
8867c478bd9Sstevel@tonic-gate  */
8877c478bd9Sstevel@tonic-gate void
ppm_lock_all(ppm_domain_t * domp,power_req_t * reqp,int * iresp)8887c478bd9Sstevel@tonic-gate ppm_lock_all(ppm_domain_t *domp, power_req_t *reqp, int *iresp)
8897c478bd9Sstevel@tonic-gate {
8907c478bd9Sstevel@tonic-gate 	/*
8917c478bd9Sstevel@tonic-gate 	 * To simplify the implementation we let all the devices
8927c478bd9Sstevel@tonic-gate 	 * in the domain be represented by a single device (dip).
8937c478bd9Sstevel@tonic-gate 	 * We use the first device in the domain's devlist.  This
8947c478bd9Sstevel@tonic-gate 	 * is safe because we return with the domain lock held
8957c478bd9Sstevel@tonic-gate 	 * which prevents the list from changing.
8967c478bd9Sstevel@tonic-gate 	 */
8977c478bd9Sstevel@tonic-gate 	if (reqp->request_type == PMR_PPM_LOCK_POWER) {
8987c478bd9Sstevel@tonic-gate 		if (!MUTEX_HELD(&domp->lock))
8997c478bd9Sstevel@tonic-gate 			mutex_enter(&domp->lock);
9007c478bd9Sstevel@tonic-gate 		domp->refcnt++;
9017c478bd9Sstevel@tonic-gate 		ASSERT(domp->devlist != NULL);
902*3fe80ca4SDan Cross 		pm_lock_power_single(domp->devlist->dip);
9037c478bd9Sstevel@tonic-gate 		/* domain lock remains held */
9047c478bd9Sstevel@tonic-gate 		return;
9057c478bd9Sstevel@tonic-gate 	} else if (reqp->request_type == PMR_PPM_UNLOCK_POWER) {
9067c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&domp->lock));
9077c478bd9Sstevel@tonic-gate 		ASSERT(domp->devlist != NULL);
908*3fe80ca4SDan Cross 		pm_unlock_power_single(domp->devlist->dip);
9097c478bd9Sstevel@tonic-gate 		if (--domp->refcnt == 0)
9107c478bd9Sstevel@tonic-gate 			mutex_exit(&domp->lock);
9117c478bd9Sstevel@tonic-gate 		return;
9127c478bd9Sstevel@tonic-gate 	}
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	ASSERT(reqp->request_type == PMR_PPM_TRY_LOCK_POWER);
9157c478bd9Sstevel@tonic-gate 	if (!MUTEX_HELD(&domp->lock))
9167c478bd9Sstevel@tonic-gate 		if (!mutex_tryenter(&domp->lock)) {
9177c478bd9Sstevel@tonic-gate 			*iresp = 0;
9187c478bd9Sstevel@tonic-gate 			return;
9197c478bd9Sstevel@tonic-gate 		}
920*3fe80ca4SDan Cross 	*iresp = pm_try_locking_power_single(domp->devlist->dip);
9217c478bd9Sstevel@tonic-gate 	if (*iresp)
9227c478bd9Sstevel@tonic-gate 		domp->refcnt++;
9237c478bd9Sstevel@tonic-gate 	else
9247c478bd9Sstevel@tonic-gate 		mutex_exit(&domp->lock);
9257c478bd9Sstevel@tonic-gate }
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate /*
9297c478bd9Sstevel@tonic-gate  * return FALSE: if any detached device during its previous life exported
9307c478bd9Sstevel@tonic-gate  *   the "no-involuntary-power-cycles" property and detached with its
9317c478bd9Sstevel@tonic-gate  *   power level not at its lowest, or there is a device in the process
9327c478bd9Sstevel@tonic-gate  *   of being installed/attached; if a PCI domain has devices that have not
9337c478bd9Sstevel@tonic-gate  *   exported a property that it can tolerate clock off while bus is not
9347c478bd9Sstevel@tonic-gate  *   quiescent; if a 66mhz PCI domain has devices that do not support stopping
9357c478bd9Sstevel@tonic-gate  *   clock at D3; either one would count as a power holder.
9367c478bd9Sstevel@tonic-gate  * return TRUE: otherwise.
9377c478bd9Sstevel@tonic-gate  */
9387c478bd9Sstevel@tonic-gate boolean_t
ppm_none_else_holds_power(ppm_domain_t * domp)9397c478bd9Sstevel@tonic-gate ppm_none_else_holds_power(ppm_domain_t *domp)
9407c478bd9Sstevel@tonic-gate {
9417c478bd9Sstevel@tonic-gate 	ppm_dev_t  *ppmd;
9427c478bd9Sstevel@tonic-gate 	ppm_owned_t *owned;
9437c478bd9Sstevel@tonic-gate 	int	i = 0;
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	if (PPMD_IS_PCI(domp->model)) {
9467c478bd9Sstevel@tonic-gate 		for (ppmd = domp->devlist; ppmd; ppmd = ppmd->next) {
9477c478bd9Sstevel@tonic-gate 			if ((domp->model == PPMD_PCI_PROP) &&
9487c478bd9Sstevel@tonic-gate 			    !(ppmd->flags & PPMDEV_PCI_PROP_CLKPM))
9497c478bd9Sstevel@tonic-gate 				return (B_FALSE);
9507c478bd9Sstevel@tonic-gate 			if ((domp->dflags & PPMD_PCI66MHZ) &&
9517c478bd9Sstevel@tonic-gate 			    !(ppmd->flags & PPMDEV_PCI66_D2))
9527c478bd9Sstevel@tonic-gate 				return (B_FALSE);
9537c478bd9Sstevel@tonic-gate 		}
9547c478bd9Sstevel@tonic-gate 	}
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate 	for (owned = domp->owned; owned; owned = owned->next)
9577c478bd9Sstevel@tonic-gate 		if (pm_noinvol_detached(owned->path) || owned->initializing)
9587c478bd9Sstevel@tonic-gate 			i++;
9597c478bd9Sstevel@tonic-gate 	return (i == 0);
9607c478bd9Sstevel@tonic-gate }
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate /*
9647c478bd9Sstevel@tonic-gate  * return the number of char 'c' occurrences in string s
9657c478bd9Sstevel@tonic-gate  */
9667c478bd9Sstevel@tonic-gate int
ppm_count_char(char * s,char c)9677c478bd9Sstevel@tonic-gate ppm_count_char(char *s, char c)
9687c478bd9Sstevel@tonic-gate {
9697c478bd9Sstevel@tonic-gate 	int	i = 0;
9707c478bd9Sstevel@tonic-gate 	char	*cp = s;
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 	while (*cp) {
9737c478bd9Sstevel@tonic-gate 		if (*cp == c)
9747c478bd9Sstevel@tonic-gate 			i++;
9757c478bd9Sstevel@tonic-gate 		cp++;
9767c478bd9Sstevel@tonic-gate 	}
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 	return (i);
9797c478bd9Sstevel@tonic-gate }
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate /*
9837c478bd9Sstevel@tonic-gate  * extract and convert a substring from input string "ss" in form of
9847c478bd9Sstevel@tonic-gate  * "name=value" into an hex or decimal integer
9857c478bd9Sstevel@tonic-gate  */
9867c478bd9Sstevel@tonic-gate #define	X_BASE	16
9877c478bd9Sstevel@tonic-gate #define	D_BASE	10
9887c478bd9Sstevel@tonic-gate int
ppm_stoi(char * ss,uint_t * val)9897c478bd9Sstevel@tonic-gate ppm_stoi(char *ss, uint_t *val)
9907c478bd9Sstevel@tonic-gate {
9917c478bd9Sstevel@tonic-gate 	char *cp;
9927c478bd9Sstevel@tonic-gate 	int  hex_ = 0, base = D_BASE;
9937c478bd9Sstevel@tonic-gate 	int  digit;
9947c478bd9Sstevel@tonic-gate 
99590fd2775SToomas Soome 	if ((cp = strchr(ss, '=')) == NULL) {
99690fd2775SToomas Soome 		*val = UINT_MAX;
99790fd2775SToomas Soome 		return (-1);
99890fd2775SToomas Soome 	}
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate 	cp++;
10017c478bd9Sstevel@tonic-gate 	if ((*cp == '0') && (*++cp == 'x')) {
10027c478bd9Sstevel@tonic-gate 		hex_++;
10037c478bd9Sstevel@tonic-gate 		cp++;
10047c478bd9Sstevel@tonic-gate 		base = X_BASE;
10057c478bd9Sstevel@tonic-gate 	}
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 	for (digit = 0; *cp; cp++) {
10087c478bd9Sstevel@tonic-gate 		if (hex_ && ((*cp >= 'A') && (*cp <= 'F')))
10097c478bd9Sstevel@tonic-gate 			digit = (digit * base) + ((*cp - 'A') + D_BASE);
10107c478bd9Sstevel@tonic-gate 		else if (hex_ && ((*cp >= 'a') && (*cp <= 'f')))
10117c478bd9Sstevel@tonic-gate 			digit = (digit * base) + ((*cp - 'a') + D_BASE);
10127c478bd9Sstevel@tonic-gate 		else
10137c478bd9Sstevel@tonic-gate 			digit = (digit * base) + (*cp - '0');
10147c478bd9Sstevel@tonic-gate 	}
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate 	return (*val = digit);
10177c478bd9Sstevel@tonic-gate }
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate /*
10207c478bd9Sstevel@tonic-gate  * ppm_convert - convert a #define symbol to its integer value,
10217c478bd9Sstevel@tonic-gate  * only the #defines for ppm_dc.cmd and ppm_dc.method fields in
10227c478bd9Sstevel@tonic-gate  * ppmvar.h file are recognized.
10237c478bd9Sstevel@tonic-gate  */
10247c478bd9Sstevel@tonic-gate struct ppm_confdefs {
10257c478bd9Sstevel@tonic-gate 	char	*sym;
10267c478bd9Sstevel@tonic-gate 	int	val;
10277c478bd9Sstevel@tonic-gate } ppm_confdefs_table[] = {
10282df1fe9cSrandyf 	"ENTER_S3", PPMDC_ENTER_S3,
10292df1fe9cSrandyf 	"EXIT_S3", PPMDC_EXIT_S3,
10307c478bd9Sstevel@tonic-gate 	"CPU_NEXT", PPMDC_CPU_NEXT,
10317c478bd9Sstevel@tonic-gate 	"PRE_CHNG", PPMDC_PRE_CHNG,
10327c478bd9Sstevel@tonic-gate 	"CPU_GO", PPMDC_CPU_GO,
10337c478bd9Sstevel@tonic-gate 	"POST_CHNG", PPMDC_POST_CHNG,
10347c478bd9Sstevel@tonic-gate 	"FET_ON", PPMDC_FET_ON,
10357c478bd9Sstevel@tonic-gate 	"FET_OFF", PPMDC_FET_OFF,
10367c478bd9Sstevel@tonic-gate 	"CLK_OFF", PPMDC_CLK_OFF,
10377c478bd9Sstevel@tonic-gate 	"CLK_ON", PPMDC_CLK_ON,
10387c478bd9Sstevel@tonic-gate 	"LED_ON", PPMDC_LED_ON,
10397c478bd9Sstevel@tonic-gate 	"LED_OFF", PPMDC_LED_OFF,
10407c478bd9Sstevel@tonic-gate 	"KIO", PPMDC_KIO,
10417c478bd9Sstevel@tonic-gate 	"VCORE", PPMDC_VCORE,
10422df1fe9cSrandyf #ifdef sun4u
10437c478bd9Sstevel@tonic-gate 	"I2CKIO", PPMDC_I2CKIO,
10442df1fe9cSrandyf #endif
10457c478bd9Sstevel@tonic-gate 	"CPUSPEEDKIO", PPMDC_CPUSPEEDKIO,
10467c478bd9Sstevel@tonic-gate 	"PRE_PWR_OFF", PPMDC_PRE_PWR_OFF,
10477c478bd9Sstevel@tonic-gate 	"PRE_PWR_ON", PPMDC_PRE_PWR_ON,
10487c478bd9Sstevel@tonic-gate 	"POST_PWR_ON", PPMDC_POST_PWR_ON,
10497c478bd9Sstevel@tonic-gate 	"PWR_OFF", PPMDC_PWR_OFF,
10507c478bd9Sstevel@tonic-gate 	"PWR_ON", PPMDC_PWR_ON,
10517c478bd9Sstevel@tonic-gate 	"RESET_OFF", PPMDC_RESET_OFF,
10527c478bd9Sstevel@tonic-gate 	"RESET_ON", PPMDC_RESET_ON,
10537c478bd9Sstevel@tonic-gate 	NULL
10547c478bd9Sstevel@tonic-gate };
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate /*
10587c478bd9Sstevel@tonic-gate  * convert a #define'd symbol to its integer value where
10597c478bd9Sstevel@tonic-gate  * input "symbol" is expected to be in form of "SYMBOL=value"
10607c478bd9Sstevel@tonic-gate  */
10617c478bd9Sstevel@tonic-gate int
ppm_convert(char * symbol,uint_t * val)10627c478bd9Sstevel@tonic-gate ppm_convert(char *symbol, uint_t *val)
10637c478bd9Sstevel@tonic-gate {
10647c478bd9Sstevel@tonic-gate 	char *s;
10657c478bd9Sstevel@tonic-gate 	struct ppm_confdefs *pcfp;
10667c478bd9Sstevel@tonic-gate 
106790fd2775SToomas Soome 	*val = UINT_MAX;
10687c478bd9Sstevel@tonic-gate 	if ((s = strchr(symbol, '=')) == NULL) {
10697c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "ppm_convert: token \"%s\" syntax error in "
1070c3a64150SMargot Miller 		    "ppm.conf file", symbol);
107190fd2775SToomas Soome 		return (-1);
10727c478bd9Sstevel@tonic-gate 	}
10737c478bd9Sstevel@tonic-gate 	s++;
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	for (pcfp = ppm_confdefs_table; (pcfp->sym != NULL); pcfp++) {
10767c478bd9Sstevel@tonic-gate 		if (strcmp(s, pcfp->sym) == 0)
10777c478bd9Sstevel@tonic-gate 			return (*val = pcfp->val);
10787c478bd9Sstevel@tonic-gate 	}
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate 	cmn_err(CE_WARN, "ppm_convert: Unrecognizable token \"%s\" "
1081c3a64150SMargot Miller 	    "in ppm.conf file", symbol);
108290fd2775SToomas Soome 	return (-1);
10837c478bd9Sstevel@tonic-gate }
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate /*
10877c478bd9Sstevel@tonic-gate  * parse a domain control property string into data structure struct ppm_dc
10887c478bd9Sstevel@tonic-gate  */
10897c478bd9Sstevel@tonic-gate int
ppm_parse_dc(char ** dc_namep,ppm_dc_t * dc)10907c478bd9Sstevel@tonic-gate ppm_parse_dc(char **dc_namep, ppm_dc_t *dc)
10917c478bd9Sstevel@tonic-gate {
10927c478bd9Sstevel@tonic-gate 	char	*str = "ppm_parse_dc";
10935cff7825Smh 	char	*line;
10947c478bd9Sstevel@tonic-gate 	char	*f, *b;
10957c478bd9Sstevel@tonic-gate 	char    **dclist;	/* list of ppm_dc_t fields */
10967c478bd9Sstevel@tonic-gate 	int	count;		/* the # of '=' indicates the # of items */
10975cff7825Smh 	size_t	len;		/* length of line being parsed */
10985cff7825Smh 	boolean_t done;
10997c478bd9Sstevel@tonic-gate 	int	i;
11007c478bd9Sstevel@tonic-gate 	int	err;
11017c478bd9Sstevel@tonic-gate 
11025cff7825Smh 	len = strlen(*dc_namep);
11035cff7825Smh 	line = kmem_alloc(len + 1, KM_SLEEP);
11045cff7825Smh 	(void) strcpy(line, *dc_namep);
11055cff7825Smh 
11067c478bd9Sstevel@tonic-gate 	count = ppm_count_char(line, '=');
11077c478bd9Sstevel@tonic-gate 	ASSERT((count - ppm_count_char(line, ' ')) == 1);
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	dclist = (char **)
11107c478bd9Sstevel@tonic-gate 	    kmem_zalloc((sizeof (char *) * (count + 1)), KM_SLEEP);
11115cff7825Smh 	for (i = 0, f = b = line, done = B_FALSE; !done; i++, f = ++b) {
11125cff7825Smh 		while (*b != ' ' && *b != 0)
11135cff7825Smh 			b++;
11145cff7825Smh 		if (*b == 0)
11155cff7825Smh 			done = B_TRUE;
11165cff7825Smh 		else
11175cff7825Smh 			*b = 0;
11185cff7825Smh 		dclist[i] = f;
11197c478bd9Sstevel@tonic-gate 	}
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
11227c478bd9Sstevel@tonic-gate 		if (strstr(dclist[i], "cmd=")) {
11237c478bd9Sstevel@tonic-gate 			err = ppm_convert(dclist[i], &dc->cmd);
11247c478bd9Sstevel@tonic-gate 			if (err == -1)
11257c478bd9Sstevel@tonic-gate 				return (err);
11267c478bd9Sstevel@tonic-gate 			continue;
11277c478bd9Sstevel@tonic-gate 		}
11287c478bd9Sstevel@tonic-gate 		if ((f = strstr(dclist[i], "path=")) != NULL) {
11297c478bd9Sstevel@tonic-gate 			f += strlen("path=");
11307c478bd9Sstevel@tonic-gate 			dc->path = kmem_zalloc((strlen(f) + 1), KM_SLEEP);
11317c478bd9Sstevel@tonic-gate 			(void) strcpy(dc->path, f);
11327c478bd9Sstevel@tonic-gate 			continue;
11337c478bd9Sstevel@tonic-gate 		}
11347c478bd9Sstevel@tonic-gate 		if (strstr(dclist[i], "method=")) {
11357c478bd9Sstevel@tonic-gate 			err = ppm_convert(dclist[i], &dc->method);
11367c478bd9Sstevel@tonic-gate 			if (err == -1)
11377c478bd9Sstevel@tonic-gate 				return (err);
11387c478bd9Sstevel@tonic-gate 			continue;
11397c478bd9Sstevel@tonic-gate 		}
11407c478bd9Sstevel@tonic-gate 		if (strstr(dclist[i], "iowr=")) {
11417c478bd9Sstevel@tonic-gate 			(void) ppm_stoi(dclist[i], &dc->m_un.kio.iowr);
11427c478bd9Sstevel@tonic-gate 			continue;
11437c478bd9Sstevel@tonic-gate 		}
11447c478bd9Sstevel@tonic-gate 		if (strstr(dclist[i], "iord=")) {
11457c478bd9Sstevel@tonic-gate 			(void) ppm_stoi(dclist[i], &dc->m_un.kio.iord);
11467c478bd9Sstevel@tonic-gate 			continue;
11477c478bd9Sstevel@tonic-gate 		}
11487c478bd9Sstevel@tonic-gate 		if (strstr(dclist[i], "val=")) {
11497c478bd9Sstevel@tonic-gate 			(void) ppm_stoi(dclist[i], &dc->m_un.kio.val);
11507c478bd9Sstevel@tonic-gate 			continue;
11517c478bd9Sstevel@tonic-gate 		}
11527c478bd9Sstevel@tonic-gate 		if (strstr(dclist[i], "speeds=")) {
11537c478bd9Sstevel@tonic-gate 			ASSERT(dc->method == PPMDC_CPUSPEEDKIO);
11547c478bd9Sstevel@tonic-gate 			(void) ppm_stoi(dclist[i], &dc->m_un.cpu.speeds);
11557c478bd9Sstevel@tonic-gate 			continue;
11567c478bd9Sstevel@tonic-gate 		}
11572df1fe9cSrandyf #ifdef sun4u
11587c478bd9Sstevel@tonic-gate 		if (strstr(dclist[i], "mask=")) {
11597c478bd9Sstevel@tonic-gate 			(void) ppm_stoi(dclist[i], &dc->m_un.i2c.mask);
11607c478bd9Sstevel@tonic-gate 			continue;
11617c478bd9Sstevel@tonic-gate 		}
11622df1fe9cSrandyf #endif
11637c478bd9Sstevel@tonic-gate 		/* This must be before the if statement for delay */
11647c478bd9Sstevel@tonic-gate 		if (strstr(dclist[i], "post_delay=")) {
11652df1fe9cSrandyf #ifdef sun4u
11667c478bd9Sstevel@tonic-gate 			ASSERT(dc->method == PPMDC_KIO ||
11677c478bd9Sstevel@tonic-gate 			    dc->method == PPMDC_I2CKIO);
11682df1fe9cSrandyf #else
11692df1fe9cSrandyf 			ASSERT(dc->method == PPMDC_KIO);
11702df1fe9cSrandyf #endif
11717c478bd9Sstevel@tonic-gate 			/*
11727c478bd9Sstevel@tonic-gate 			 * all delays are uint_t type instead of clock_t.
11737c478bd9Sstevel@tonic-gate 			 * If the delay is too long, it might get truncated.
11747c478bd9Sstevel@tonic-gate 			 * But, we don't expect delay to be too long.
11757c478bd9Sstevel@tonic-gate 			 */
11767c478bd9Sstevel@tonic-gate 			switch (dc->method) {
11777c478bd9Sstevel@tonic-gate 			case PPMDC_KIO:
11787c478bd9Sstevel@tonic-gate 				(void) ppm_stoi(dclist[i],
11792df1fe9cSrandyf 				    &dc->m_un.kio.post_delay);
11807c478bd9Sstevel@tonic-gate 				break;
11817c478bd9Sstevel@tonic-gate 
11822df1fe9cSrandyf #ifdef sun4u
11837c478bd9Sstevel@tonic-gate 			case PPMDC_I2CKIO:
11847c478bd9Sstevel@tonic-gate 				(void) ppm_stoi(dclist[i],
11852df1fe9cSrandyf 				    &dc->m_un.i2c.post_delay);
11867c478bd9Sstevel@tonic-gate 				break;
11872df1fe9cSrandyf #endif
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 			default:
11907c478bd9Sstevel@tonic-gate 				break;
11917c478bd9Sstevel@tonic-gate 			}
11927c478bd9Sstevel@tonic-gate 			continue;
11937c478bd9Sstevel@tonic-gate 		}
11947c478bd9Sstevel@tonic-gate 		if (strstr(dclist[i], "delay=")) {
11952df1fe9cSrandyf #ifdef sun4u
11962df1fe9cSrandyf 			ASSERT(dc->method == PPMDC_VCORE ||
11972df1fe9cSrandyf 			    dc->method == PPMDC_KIO ||
11982df1fe9cSrandyf 			    dc->method == PPMDC_I2CKIO);
11992df1fe9cSrandyf #else
12007c478bd9Sstevel@tonic-gate 			ASSERT(dc->method == PPMDC_VCORE ||
12012df1fe9cSrandyf 			    dc->method == PPMDC_KIO);
12022df1fe9cSrandyf #endif
12037c478bd9Sstevel@tonic-gate 
12047c478bd9Sstevel@tonic-gate 			/*
12057c478bd9Sstevel@tonic-gate 			 * all delays are uint_t type instead of clock_t.
12067c478bd9Sstevel@tonic-gate 			 * If the delay is too long, it might get truncated.
12077c478bd9Sstevel@tonic-gate 			 * But, we don't expect delay to be too long.
12087c478bd9Sstevel@tonic-gate 			 */
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate 			switch (dc->method) {
12117c478bd9Sstevel@tonic-gate 			case PPMDC_KIO:
12127c478bd9Sstevel@tonic-gate 				(void) ppm_stoi(dclist[i], &dc->m_un.kio.delay);
12137c478bd9Sstevel@tonic-gate 				break;
12147c478bd9Sstevel@tonic-gate 
12152df1fe9cSrandyf #ifdef sun4u
12167c478bd9Sstevel@tonic-gate 			case PPMDC_I2CKIO:
12177c478bd9Sstevel@tonic-gate 				(void) ppm_stoi(dclist[i], &dc->m_un.i2c.delay);
12187c478bd9Sstevel@tonic-gate 				break;
12192df1fe9cSrandyf #endif
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate 			case PPMDC_VCORE:
12227c478bd9Sstevel@tonic-gate 				(void) ppm_stoi(dclist[i], &dc->m_un.cpu.delay);
12237c478bd9Sstevel@tonic-gate 				break;
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate 			default:
12267c478bd9Sstevel@tonic-gate 				break;
12277c478bd9Sstevel@tonic-gate 			}
12287c478bd9Sstevel@tonic-gate 			continue;
12297c478bd9Sstevel@tonic-gate 		}
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 		/* we encounted unrecognized field, flag error */
12327c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s: Unrecognized token \"%s\" in ppm.conf "
1233c3a64150SMargot Miller 		    "file!", str, dclist[i]);
12347c478bd9Sstevel@tonic-gate 		return (-1);
12357c478bd9Sstevel@tonic-gate 	}
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate 	kmem_free(dclist, sizeof (char *) * (count + 1));
12385cff7825Smh 	kmem_free(line, len + 1);
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
12417c478bd9Sstevel@tonic-gate }
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate /*
12457c478bd9Sstevel@tonic-gate  * search for domain control handle for a claimed device coupled with a
12467c478bd9Sstevel@tonic-gate  * domain control command.  NULL device may indicate LED domain.
12477c478bd9Sstevel@tonic-gate  */
12487c478bd9Sstevel@tonic-gate ppm_dc_t *
ppm_lookup_dc(ppm_domain_t * domp,int cmd)12497c478bd9Sstevel@tonic-gate ppm_lookup_dc(ppm_domain_t *domp, int cmd)
12507c478bd9Sstevel@tonic-gate {
12517c478bd9Sstevel@tonic-gate #ifdef	DEBUG
12527c478bd9Sstevel@tonic-gate 	char *str = "ppm_lookup_dc";
12537c478bd9Sstevel@tonic-gate #endif
12547c478bd9Sstevel@tonic-gate 	ppm_dc_t	*dc;
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 	/*
12577c478bd9Sstevel@tonic-gate 	 *  For convenience, we accept 'domp' as NULL for searching
12587c478bd9Sstevel@tonic-gate 	 *  LED domain control operation.
12597c478bd9Sstevel@tonic-gate 	 */
12607c478bd9Sstevel@tonic-gate 	if ((cmd == PPMDC_LED_OFF) || (cmd == PPMDC_LED_ON)) {
12617c478bd9Sstevel@tonic-gate 		for (domp = ppm_domain_p; domp; domp = domp->next)
12627c478bd9Sstevel@tonic-gate 			if (domp->model == PPMD_LED)
12637c478bd9Sstevel@tonic-gate 				break;
12647c478bd9Sstevel@tonic-gate 		if (!domp || !domp->dc || !domp->dc->lh || !domp->dc->next) {
12657c478bd9Sstevel@tonic-gate 			PPMD(D_LED, ("\tinsufficient led domain control "
12667c478bd9Sstevel@tonic-gate 			    "information.\n"))
12677c478bd9Sstevel@tonic-gate 			return (NULL);
12687c478bd9Sstevel@tonic-gate 		}
12697c478bd9Sstevel@tonic-gate 		if (cmd == domp->dc->cmd)
12707c478bd9Sstevel@tonic-gate 			return (domp->dc);
12717c478bd9Sstevel@tonic-gate 		else
12727c478bd9Sstevel@tonic-gate 			return (domp->dc->next);
12737c478bd9Sstevel@tonic-gate 	}
12747c478bd9Sstevel@tonic-gate 
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 	/*
12777c478bd9Sstevel@tonic-gate 	 * for the rest of ppm domains, lookup ppm_dc starting from domp
12787c478bd9Sstevel@tonic-gate 	 */
12797c478bd9Sstevel@tonic-gate 	ASSERT(domp != NULL);
12807c478bd9Sstevel@tonic-gate 	switch (cmd) {
12817c478bd9Sstevel@tonic-gate 	case PPMDC_CPU_NEXT:
12827c478bd9Sstevel@tonic-gate 	case PPMDC_PRE_CHNG:
12837c478bd9Sstevel@tonic-gate 	case PPMDC_CPU_GO:
12847c478bd9Sstevel@tonic-gate 	case PPMDC_POST_CHNG:
12857c478bd9Sstevel@tonic-gate 	case PPMDC_FET_OFF:
12867c478bd9Sstevel@tonic-gate 	case PPMDC_FET_ON:
12877c478bd9Sstevel@tonic-gate 	case PPMDC_CLK_OFF:
12887c478bd9Sstevel@tonic-gate 	case PPMDC_CLK_ON:
12897c478bd9Sstevel@tonic-gate 	case PPMDC_PRE_PWR_OFF:
12907c478bd9Sstevel@tonic-gate 	case PPMDC_PRE_PWR_ON:
12917c478bd9Sstevel@tonic-gate 	case PPMDC_POST_PWR_ON:
12927c478bd9Sstevel@tonic-gate 	case PPMDC_PWR_OFF:
12937c478bd9Sstevel@tonic-gate 	case PPMDC_PWR_ON:
12947c478bd9Sstevel@tonic-gate 	case PPMDC_RESET_OFF:
12957c478bd9Sstevel@tonic-gate 	case PPMDC_RESET_ON:
12962df1fe9cSrandyf 	case PPMDC_ENTER_S3:
12972df1fe9cSrandyf 	case PPMDC_EXIT_S3:
12987c478bd9Sstevel@tonic-gate 		break;
12997c478bd9Sstevel@tonic-gate 	default:
13007c478bd9Sstevel@tonic-gate 		PPMD(D_PPMDC, ("%s: cmd(%d) unrecognized\n", str, cmd))
13017c478bd9Sstevel@tonic-gate 		return (NULL);
13027c478bd9Sstevel@tonic-gate 	}
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate 	for (dc = domp->dc; dc; dc = dc->next) {
13052df1fe9cSrandyf 		if (dc->cmd == cmd) {
13067c478bd9Sstevel@tonic-gate 			return (dc);
13072df1fe9cSrandyf 		}
13087c478bd9Sstevel@tonic-gate 	}
13092df1fe9cSrandyf 
13107c478bd9Sstevel@tonic-gate 	return (NULL);
13117c478bd9Sstevel@tonic-gate }
13127c478bd9Sstevel@tonic-gate 
13137c478bd9Sstevel@tonic-gate #include <sys/esunddi.h>
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate ppm_domain_t *
ppm_get_domain_by_dev(const char * p)13167c478bd9Sstevel@tonic-gate ppm_get_domain_by_dev(const char *p)
13177c478bd9Sstevel@tonic-gate {
13187c478bd9Sstevel@tonic-gate 	dev_info_t *dip;
13197c478bd9Sstevel@tonic-gate 	ppm_domain_t	*domp;
13207c478bd9Sstevel@tonic-gate 	ppm_dev_t	*pdev;
13217c478bd9Sstevel@tonic-gate 	boolean_t	found = B_FALSE;
13227c478bd9Sstevel@tonic-gate 
13237c478bd9Sstevel@tonic-gate 	if ((dip = e_ddi_hold_devi_by_path((char *)p, 0)) == NULL)
13247c478bd9Sstevel@tonic-gate 		return (NULL);
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate 	for (domp = ppm_domain_p; domp; domp = domp->next) {
13277c478bd9Sstevel@tonic-gate 		for (pdev = domp->devlist; pdev; pdev = pdev->next) {
13287c478bd9Sstevel@tonic-gate 			if (pdev->dip == dip) {
13297c478bd9Sstevel@tonic-gate 				found = B_TRUE;
13307c478bd9Sstevel@tonic-gate 				break;
13317c478bd9Sstevel@tonic-gate 			}
13327c478bd9Sstevel@tonic-gate 		}
13337c478bd9Sstevel@tonic-gate 		if (found)
13347c478bd9Sstevel@tonic-gate 			break;
13357c478bd9Sstevel@tonic-gate 	}
13367c478bd9Sstevel@tonic-gate 	ddi_release_devi(dip);
13377c478bd9Sstevel@tonic-gate 	return (domp);
13387c478bd9Sstevel@tonic-gate }
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate 
13417c478bd9Sstevel@tonic-gate #ifdef DEBUG
13427c478bd9Sstevel@tonic-gate #define	FLINTSTR(flags, sym) { flags, sym, #sym }
13437c478bd9Sstevel@tonic-gate #define	PMR_UNKNOWN -1
13447c478bd9Sstevel@tonic-gate /*
13457c478bd9Sstevel@tonic-gate  * convert a ctlop integer to a char string.  this helps printing
13467c478bd9Sstevel@tonic-gate  * meaningful info when cltops are received from the pm framework.
13477c478bd9Sstevel@tonic-gate  * since some ctlops are so frequent, we use mask to limit output:
13487c478bd9Sstevel@tonic-gate  * a valid string is returned when ctlop is found and when
13497c478bd9Sstevel@tonic-gate  * (cmd.flags & mask) is true; otherwise NULL is returned.
13507c478bd9Sstevel@tonic-gate  */
13517c478bd9Sstevel@tonic-gate char *
ppm_get_ctlstr(int ctlop,uint_t mask)13527c478bd9Sstevel@tonic-gate ppm_get_ctlstr(int ctlop, uint_t mask)
13537c478bd9Sstevel@tonic-gate {
13547c478bd9Sstevel@tonic-gate 	struct ctlop_cmd {
13557c478bd9Sstevel@tonic-gate 		uint_t flags;
13567c478bd9Sstevel@tonic-gate 		int ctlop;
13577c478bd9Sstevel@tonic-gate 		char *str;
13587c478bd9Sstevel@tonic-gate 	};
13597c478bd9Sstevel@tonic-gate 
13607c478bd9Sstevel@tonic-gate 	struct ctlop_cmd *ccp;
13617c478bd9Sstevel@tonic-gate 	static struct ctlop_cmd cmds[] = {
13627c478bd9Sstevel@tonic-gate 		FLINTSTR(D_SETPWR, PMR_SET_POWER),
13637c478bd9Sstevel@tonic-gate 		FLINTSTR(D_CTLOPS2, PMR_SUSPEND),
13647c478bd9Sstevel@tonic-gate 		FLINTSTR(D_CTLOPS2, PMR_RESUME),
13657c478bd9Sstevel@tonic-gate 		FLINTSTR(D_CTLOPS2, PMR_PRE_SET_POWER),
13667c478bd9Sstevel@tonic-gate 		FLINTSTR(D_CTLOPS2, PMR_POST_SET_POWER),
13677c478bd9Sstevel@tonic-gate 		FLINTSTR(D_CTLOPS2, PMR_PPM_SET_POWER),
13687c478bd9Sstevel@tonic-gate 		FLINTSTR(0, PMR_PPM_ATTACH),
13697c478bd9Sstevel@tonic-gate 		FLINTSTR(0, PMR_PPM_DETACH),
13707c478bd9Sstevel@tonic-gate 		FLINTSTR(D_CTLOPS1, PMR_PPM_POWER_CHANGE_NOTIFY),
13717c478bd9Sstevel@tonic-gate 		FLINTSTR(D_CTLOPS1, PMR_REPORT_PMCAP),
13727c478bd9Sstevel@tonic-gate 		FLINTSTR(D_CTLOPS1, PMR_CHANGED_POWER),
13737c478bd9Sstevel@tonic-gate 		FLINTSTR(D_CTLOPS2, PMR_PPM_INIT_CHILD),
13747c478bd9Sstevel@tonic-gate 		FLINTSTR(D_CTLOPS2, PMR_PPM_UNINIT_CHILD),
13757c478bd9Sstevel@tonic-gate 		FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_PROBE),
13767c478bd9Sstevel@tonic-gate 		FLINTSTR(D_CTLOPS2, PMR_PPM_POST_PROBE),
13777c478bd9Sstevel@tonic-gate 		FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_ATTACH),
13787c478bd9Sstevel@tonic-gate 		FLINTSTR(D_CTLOPS2, PMR_PPM_POST_ATTACH),
13797c478bd9Sstevel@tonic-gate 		FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_DETACH),
13807c478bd9Sstevel@tonic-gate 		FLINTSTR(D_CTLOPS2, PMR_PPM_POST_DETACH),
13817c478bd9Sstevel@tonic-gate 		FLINTSTR(D_CTLOPS1, PMR_PPM_UNMANAGE),
13827c478bd9Sstevel@tonic-gate 		FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_RESUME),
13837c478bd9Sstevel@tonic-gate 		FLINTSTR(D_CTLOPS1, PMR_PPM_ALL_LOWEST),
13847c478bd9Sstevel@tonic-gate 		FLINTSTR(D_LOCKS, PMR_PPM_LOCK_POWER),
13857c478bd9Sstevel@tonic-gate 		FLINTSTR(D_LOCKS, PMR_PPM_UNLOCK_POWER),
13867c478bd9Sstevel@tonic-gate 		FLINTSTR(D_LOCKS, PMR_PPM_TRY_LOCK_POWER),
13877c478bd9Sstevel@tonic-gate 		FLINTSTR(D_LOCKS, PMR_PPM_POWER_LOCK_OWNER),
13882df1fe9cSrandyf 		FLINTSTR(D_CTLOPS1 | D_CTLOPS2, PMR_PPM_ENTER_SX),
13897c478bd9Sstevel@tonic-gate 		FLINTSTR(D_CTLOPS1 | D_CTLOPS2, PMR_UNKNOWN),
13907c478bd9Sstevel@tonic-gate 	};
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate 	for (ccp = cmds; ccp->ctlop != PMR_UNKNOWN; ccp++)
13937c478bd9Sstevel@tonic-gate 		if (ctlop == ccp->ctlop)
13947c478bd9Sstevel@tonic-gate 			break;
13957c478bd9Sstevel@tonic-gate 
13967c478bd9Sstevel@tonic-gate 	if (ccp->flags & mask)
13977c478bd9Sstevel@tonic-gate 		return (ccp->str);
13987c478bd9Sstevel@tonic-gate 	return (NULL);
13997c478bd9Sstevel@tonic-gate }
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate void
ppm_print_dc(ppm_dc_t * dc)14027c478bd9Sstevel@tonic-gate ppm_print_dc(ppm_dc_t *dc)
14037c478bd9Sstevel@tonic-gate {
14047c478bd9Sstevel@tonic-gate 	ppm_dc_t	*d = dc;
14057c478bd9Sstevel@tonic-gate 
14067c478bd9Sstevel@tonic-gate 	PPMD(D_PPMDC, ("\nAdds ppm_dc: path(%s),\n     cmd(%x), "
14077c478bd9Sstevel@tonic-gate 	    "method(%x), ", d->path, d->cmd, d->method))
14082df1fe9cSrandyf 	if (d->method == PPMDC_KIO) {
14092df1fe9cSrandyf 		PPMD(D_PPMDC, ("kio.iowr(%x), kio.val(0x%X)",
14102df1fe9cSrandyf 		    d->m_un.kio.iowr, d->m_un.kio.val))
14112df1fe9cSrandyf #ifdef sun4u
14122df1fe9cSrandyf 	} else if (d->method == PPMDC_I2CKIO) {
14137c478bd9Sstevel@tonic-gate 		PPMD(D_PPMDC, ("i2c.iowr(%x), i2c.val(0x%X), "
14147c478bd9Sstevel@tonic-gate 		    "i2c.mask(0x%X)", d->m_un.i2c.iowr,
14157c478bd9Sstevel@tonic-gate 		    d->m_un.i2c.val,  d->m_un.i2c.mask))
14162df1fe9cSrandyf #endif
14177c478bd9Sstevel@tonic-gate 	} else if (d->method == PPMDC_VCORE) {
14187c478bd9Sstevel@tonic-gate 		PPMD(D_PPMDC, ("cpu: .iord(%x), .iowr(%x), .val(0x%X), "
14197c478bd9Sstevel@tonic-gate 		    ".delay(0x%x)",
14207c478bd9Sstevel@tonic-gate 		    d->m_un.cpu.iord, d->m_un.cpu.iowr, d->m_un.cpu.val,
14217c478bd9Sstevel@tonic-gate 		    d->m_un.cpu.delay))
14227c478bd9Sstevel@tonic-gate 	} else if (d->method == PPMDC_CPUSPEEDKIO) {
14237c478bd9Sstevel@tonic-gate 		PPMD(D_PPMDC, ("cpu.iowr(%x), cpu.speeds(0x%X)",
14247c478bd9Sstevel@tonic-gate 		    d->m_un.cpu.iowr, d->m_un.cpu.speeds))
14257c478bd9Sstevel@tonic-gate 	}
14267c478bd9Sstevel@tonic-gate 	PPMD(D_PPMDC, ("\n"))
14277c478bd9Sstevel@tonic-gate }
14287c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
1429