xref: /titanic_51/usr/src/uts/common/io/ppm/ppm_subr.c (revision c3a641501f830e76826a0f416dd952d282d30ae7)
15cff7825Smh27603 /*
25cff7825Smh27603  * CDDL HEADER START
35cff7825Smh27603  *
45cff7825Smh27603  * The contents of this file are subject to the terms of the
55cff7825Smh27603  * Common Development and Distribution License (the "License").
65cff7825Smh27603  * You may not use this file except in compliance with the License.
75cff7825Smh27603  *
85cff7825Smh27603  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95cff7825Smh27603  * or http://www.opensolaris.org/os/licensing.
105cff7825Smh27603  * See the License for the specific language governing permissions
115cff7825Smh27603  * and limitations under the License.
125cff7825Smh27603  *
135cff7825Smh27603  * When distributing Covered Code, include this CDDL HEADER in each
145cff7825Smh27603  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155cff7825Smh27603  * If applicable, add the following below this CDDL HEADER, with the
165cff7825Smh27603  * fields enclosed by brackets "[]" replaced with your own identifying
175cff7825Smh27603  * information: Portions Copyright [yyyy] [name of copyright owner]
185cff7825Smh27603  *
195cff7825Smh27603  * CDDL HEADER END
205cff7825Smh27603  */
215cff7825Smh27603 /*
22*c3a64150SMargot Miller  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
235cff7825Smh27603  * Use is subject to license terms.
245cff7825Smh27603  */
255cff7825Smh27603 
265cff7825Smh27603 /*
275cff7825Smh27603  * ppm driver subroutines
285cff7825Smh27603  */
295cff7825Smh27603 
305cff7825Smh27603 #include <sys/open.h>
315cff7825Smh27603 #include <sys/file.h>
325cff7825Smh27603 #include <sys/conf.h>
335cff7825Smh27603 #include <sys/epm.h>
345cff7825Smh27603 #include <sys/sunldi.h>
355cff7825Smh27603 #include <sys/ppmvar.h>
365cff7825Smh27603 #include <sys/ppmio.h>
375cff7825Smh27603 #include <sys/promif.h>
385cff7825Smh27603 #include <sys/ddi_impldefs.h>
395cff7825Smh27603 #include <sys/ddi.h>
405cff7825Smh27603 #include <sys/sunddi.h>
415cff7825Smh27603 /*
425cff7825Smh27603  * Append address to the device path, if it is set.  Routine
435cff7825Smh27603  * ddi_pathname does not look for device address if the node is in
445cff7825Smh27603  * DS_INITIALIZED state.
455cff7825Smh27603  */
465cff7825Smh27603 #define	PPM_GET_PATHNAME(dip, path)				\
475cff7825Smh27603 	(void) ddi_pathname((dip), (path));			\
485cff7825Smh27603 	if ((i_ddi_node_state((dip)) < DS_INITIALIZED) &&	\
495cff7825Smh27603 	    (ddi_get_name_addr((dip)) != NULL)) {		\
505cff7825Smh27603 		(void) strcat((path), "@");			\
515cff7825Smh27603 		(void) strcat((path), ddi_get_name_addr((dip)));\
525cff7825Smh27603 	}
535cff7825Smh27603 
545cff7825Smh27603 int	ppm_parse_dc(char **, ppm_dc_t *);
555cff7825Smh27603 int	ppm_match_devs(char *, ppm_db_t *);
565cff7825Smh27603 ppm_db_t *ppm_parse_pattern(struct ppm_db **, char *);
575cff7825Smh27603 int	ppm_count_char(char *, char);
585cff7825Smh27603 int	ppm_stoi(char *, uint_t *);
595cff7825Smh27603 int	ppm_convert(char *, uint_t *);
605cff7825Smh27603 void	ppm_prop_free(struct ppm_cdata **);
615cff7825Smh27603 
625cff7825Smh27603 /*
635cff7825Smh27603  * lookup string property from configuration file ppm.conf
645cff7825Smh27603  */
655cff7825Smh27603 static int
665cff7825Smh27603 ppm_get_confdata(struct ppm_cdata **cdp, dev_info_t *dip)
675cff7825Smh27603 {
685cff7825Smh27603 #ifdef	DEBUG
695cff7825Smh27603 	char *str = "ppm_get_confdata";
705cff7825Smh27603 #endif
715cff7825Smh27603 	struct ppm_cdata *cinfo;
725cff7825Smh27603 	int err;
735cff7825Smh27603 
745cff7825Smh27603 	for (; (cinfo = *cdp) != NULL; cdp++) {
755cff7825Smh27603 		err = ddi_prop_lookup_string_array(
765cff7825Smh27603 		    DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
775cff7825Smh27603 		    cinfo->name, &cinfo->strings, &cinfo->cnt);
785cff7825Smh27603 		if (err != DDI_PROP_SUCCESS) {
795cff7825Smh27603 			PPMD(D_ERROR, ("%s: no %s found, err(%d)\n",
805cff7825Smh27603 			    str, cinfo->name, err))
815cff7825Smh27603 			break;
825cff7825Smh27603 		}
835cff7825Smh27603 	}
845cff7825Smh27603 	return (err);
855cff7825Smh27603 }
865cff7825Smh27603 
875cff7825Smh27603 void
885cff7825Smh27603 ppm_prop_free(struct ppm_cdata **cdp)
895cff7825Smh27603 {
905cff7825Smh27603 	if (cdp) {
915cff7825Smh27603 		for (; *cdp; cdp++) {
925cff7825Smh27603 			if ((*cdp)->name) {
935cff7825Smh27603 				kmem_free((*cdp)->name,
945cff7825Smh27603 				    strlen((*cdp)->name) + 1);
955cff7825Smh27603 				(*cdp)->name = NULL;
965cff7825Smh27603 			}
975cff7825Smh27603 			if ((*cdp)->strings) {
985cff7825Smh27603 				ddi_prop_free((*cdp)->strings);
995cff7825Smh27603 				(*cdp)->strings = NULL;
1005cff7825Smh27603 			}
1015cff7825Smh27603 		}
1025cff7825Smh27603 	}
1035cff7825Smh27603 }
1045cff7825Smh27603 
1055cff7825Smh27603 
1065cff7825Smh27603 /*
1075cff7825Smh27603  * free ddi prop strings. Under error condition, free ppm_db_t lists as well.
1085cff7825Smh27603  */
1095cff7825Smh27603 static int
1105cff7825Smh27603 ppm_attach_err(struct ppm_cdata **cdp, int err)
1115cff7825Smh27603 {
1125cff7825Smh27603 	ppm_domain_t *domp;
1135cff7825Smh27603 	ppm_db_t *db, *tmp;
1145cff7825Smh27603 
1155cff7825Smh27603 	ppm_prop_free(cdp);
1165cff7825Smh27603 	if (err != DDI_SUCCESS) {
1175cff7825Smh27603 		for (domp = ppm_domain_p; domp; domp = domp->next) {
1185cff7825Smh27603 			for (db = domp->conflist; (tmp = db) != NULL; ) {
1195cff7825Smh27603 				db = db->next;
1205cff7825Smh27603 				kmem_free(tmp->name, strlen(tmp->name) + 1);
1215cff7825Smh27603 				kmem_free(tmp, sizeof (*tmp));
1225cff7825Smh27603 			}
1235cff7825Smh27603 			domp->conflist = NULL;
1245cff7825Smh27603 		}
1255cff7825Smh27603 		err = DDI_FAILURE;
1265cff7825Smh27603 	}
1275cff7825Smh27603 
1285cff7825Smh27603 	return (err);
1295cff7825Smh27603 }
1305cff7825Smh27603 
1315cff7825Smh27603 
1325cff7825Smh27603 ppm_domain_t *
1335cff7825Smh27603 ppm_lookup_domain(char *dname)
1345cff7825Smh27603 {
1355cff7825Smh27603 	ppm_domain_t	*domp;
1365cff7825Smh27603 
1375cff7825Smh27603 	for (domp = ppm_domain_p; domp; domp = domp->next) {
1385cff7825Smh27603 		if (strcmp(dname, domp->name) == 0)
1395cff7825Smh27603 			break;
1405cff7825Smh27603 	}
1415cff7825Smh27603 	return (domp);
1425cff7825Smh27603 }
1435cff7825Smh27603 
1445cff7825Smh27603 
1455cff7825Smh27603 /*
1465cff7825Smh27603  * for the purpose of optimizing we search for identical dc->path
1475cff7825Smh27603  * that has been opened per previous visit here.  If search results
1485cff7825Smh27603  * in a hit, copy the device handle, else open the device.
1495cff7825Smh27603  */
1505cff7825Smh27603 ppm_dc_t *
1515cff7825Smh27603 ppm_lookup_hndl(int model, ppm_dc_t *key_dc)
1525cff7825Smh27603 {
1535cff7825Smh27603 #ifdef	DEBUG
1545cff7825Smh27603 	char *str = "ppm_lookup_hndl";
1555cff7825Smh27603 #endif
1565cff7825Smh27603 	char *key_path = key_dc->path;
1575cff7825Smh27603 	ppm_domain_t *domp;
1585cff7825Smh27603 	ppm_dc_t *dc;
1595cff7825Smh27603 
1605cff7825Smh27603 	/* search domain by domain.model */
1615cff7825Smh27603 	for (domp = ppm_domain_p; domp; domp = domp->next) {
1625cff7825Smh27603 		if (domp->model == model)
1635cff7825Smh27603 			break;
1645cff7825Smh27603 	}
1655cff7825Smh27603 
1665cff7825Smh27603 	/* lookup hndl from same domain model */
1675cff7825Smh27603 	if (domp && PPM_DOMAIN_UP(domp)) {
1685cff7825Smh27603 		for (dc = domp->dc; dc; dc = dc->next) {
1695cff7825Smh27603 			if ((strcmp(dc->path, key_path) == 0) &&
1705cff7825Smh27603 			    (dc->lh != NULL)) {
1715cff7825Smh27603 				PPMD(D_PPMDC, ("%s: Hit(dc_path:%s) from SAME "
1725cff7825Smh27603 				    "domain %s.\n", str, key_path, domp->name))
1735cff7825Smh27603 				key_dc->lh = dc->lh;
1745cff7825Smh27603 				return (key_dc);
1755cff7825Smh27603 			}
1765cff7825Smh27603 		}
1775cff7825Smh27603 	}
1785cff7825Smh27603 
1795cff7825Smh27603 	/* otherwise, check other domains */
1805cff7825Smh27603 	for (domp = ppm_domain_p;
1815cff7825Smh27603 	    domp && (domp->model != model); domp = domp->next) {
1825cff7825Smh27603 		if (PPM_DOMAIN_UP(domp)) {
1835cff7825Smh27603 			for (dc = domp->dc; dc; dc = dc->next) {
1845cff7825Smh27603 				if ((strcmp(dc->path, key_path) == 0) &&
1855cff7825Smh27603 				    (dc->lh != NULL)) {
1865cff7825Smh27603 					PPMD(D_PPMDC, ("%s: Hit(dc_path:%s) "
1875cff7825Smh27603 					    "from domain %s\n",
1885cff7825Smh27603 					    str, key_path, domp->name))
1895cff7825Smh27603 					key_dc->lh = dc->lh;
1905cff7825Smh27603 					return (key_dc);
1915cff7825Smh27603 				}
1925cff7825Smh27603 			}
1935cff7825Smh27603 		}
1945cff7825Smh27603 	}
1955cff7825Smh27603 
1965cff7825Smh27603 	PPMD(D_PPMDC, ("%s: Miss(dc_path:%s)\n", str, key_path))
1975cff7825Smh27603 	return (NULL);
1985cff7825Smh27603 }
1995cff7825Smh27603 
2005cff7825Smh27603 
2015cff7825Smh27603 #define	PPM_DOMAIN_PROP			"ppm-domains"
2025cff7825Smh27603 #define	PPM_DEV_PROP_SUFFIX		"-devices"
2035cff7825Smh27603 #define	PPM_MODEL_PROP_SUFFIX		"-model"
2045cff7825Smh27603 #define	PPM_PROPNAME_PROP_SUFFIX	"-propname"
2055cff7825Smh27603 #define	PPM_CTRL_PROP_SUFFIX		"-control"
2065cff7825Smh27603 
2075cff7825Smh27603 struct ppm_domit ppm_domit_data[] = {
2082df1fe9cSrandyf 	"SX",  PPMD_SX, 0, PPMD_ON,
2095cff7825Smh27603 	"CPU", PPMD_CPU, PPMD_LOCK_ALL, PPMD_ON,
2105cff7825Smh27603 	"FET", PPMD_FET, PPMD_LOCK_ONE, PPMD_ON,
2115cff7825Smh27603 	"PCI", PPMD_PCI, PPMD_LOCK_ONE, PPMD_ON,
2125cff7825Smh27603 	"PCI_PROP", PPMD_PCI_PROP, PPMD_LOCK_ONE, PPMD_ON,
2135cff7825Smh27603 	"LED", PPMD_LED, 0, PPMD_ON,
2145cff7825Smh27603 	"PCIE", PPMD_PCIE, PPMD_LOCK_ONE, PPMD_ON,
2155cff7825Smh27603 	NULL
2165cff7825Smh27603 };
2175cff7825Smh27603 
2185cff7825Smh27603 /*
2195cff7825Smh27603  * store up platform dependent information provided by ppm.conf file
2205cff7825Smh27603  * into private data base
2215cff7825Smh27603  */
2225cff7825Smh27603 int
2235cff7825Smh27603 ppm_create_db(dev_info_t *dip)
2245cff7825Smh27603 {
2255cff7825Smh27603 #ifdef	DEBUG
2265cff7825Smh27603 	char *str = "ppm_create_db";
2275cff7825Smh27603 #endif
2285cff7825Smh27603 	ppm_domain_t *domp;
2295cff7825Smh27603 	ppm_db_t *db;
2305cff7825Smh27603 	ppm_dc_t *dc;
2315cff7825Smh27603 	struct ppm_cdata domdata;	/* hold "ppm-domains" property */
2325cff7825Smh27603 	struct ppm_cdata modeldata;	/* hold "domain_xy-model" property */
2335cff7825Smh27603 	struct ppm_cdata propnamedata;	/* hold "domain_xy-propname" property */
2345cff7825Smh27603 	struct ppm_cdata devdata;	/* hold "domain_xy-devices" property */
2355cff7825Smh27603 	struct ppm_cdata dcdata;	/* hold "domain_xy-control" property */
2365cff7825Smh27603 	struct ppm_cdata *cdata[2];
2375cff7825Smh27603 	char **dom_namep, **model_namep, **dev_namep, **dc_namep;
2385cff7825Smh27603 	struct ppm_domit	*domit_p;
2395cff7825Smh27603 	int err;
2405cff7825Smh27603 
2415cff7825Smh27603 	/*
2425cff7825Smh27603 	 * get "ppm-domains" property
2435cff7825Smh27603 	 */
2445cff7825Smh27603 	bzero(&domdata, sizeof (domdata));
2455cff7825Smh27603 	domdata.name = kmem_zalloc(strlen(PPM_DOMAIN_PROP) + 1, KM_SLEEP);
2465cff7825Smh27603 	(void) strcpy(domdata.name, PPM_DOMAIN_PROP);
2475cff7825Smh27603 	cdata[0] = &domdata;
2485cff7825Smh27603 	cdata[1] = NULL;
2495cff7825Smh27603 	if (err = ppm_get_confdata(cdata, dip)) {
2505cff7825Smh27603 		PPMD(D_CREATEDB, ("%s: failed to get prop \"%s\"!\n",
2515cff7825Smh27603 		    str, PPM_DOMAIN_PROP))
2525cff7825Smh27603 		return (ppm_attach_err(cdata, err));
2535cff7825Smh27603 	}
2545cff7825Smh27603 
2555cff7825Smh27603 	for (dom_namep = domdata.strings; *dom_namep; dom_namep++) {
2565cff7825Smh27603 		domp = kmem_zalloc(sizeof (*domp), KM_SLEEP);
2575cff7825Smh27603 		domp->name = kmem_zalloc(strlen(*dom_namep) + 1, KM_SLEEP);
2585cff7825Smh27603 		(void) strcpy(domp->name, *dom_namep);
2595cff7825Smh27603 		mutex_init(&domp->lock, NULL, MUTEX_DRIVER, NULL);
2605cff7825Smh27603 		if (ppm_domain_p == NULL)
2615cff7825Smh27603 			ppm_domain_p = domp;
2625cff7825Smh27603 		else {
2635cff7825Smh27603 			domp->next = ppm_domain_p;
2645cff7825Smh27603 			ppm_domain_p = domp;
2655cff7825Smh27603 		}
2665cff7825Smh27603 	}
2675cff7825Smh27603 	ppm_prop_free(cdata);
2685cff7825Smh27603 
2695cff7825Smh27603 	/*
2705cff7825Smh27603 	 * more per domain property strings in ppm.conf file tell us
2715cff7825Smh27603 	 * what the nature of domain, how to performe domain control, etc.
2725cff7825Smh27603 	 * Even the property names of those per domain properties are
2735cff7825Smh27603 	 * formed consisting its domain name string.
2745cff7825Smh27603 	 * Here we walk through our domain list, and fullfill the details.
2755cff7825Smh27603 	 */
2765cff7825Smh27603 	for (domp = ppm_domain_p; domp; domp = domp->next) {
2775cff7825Smh27603 		size_t	plen;
2785cff7825Smh27603 
2795cff7825Smh27603 		/*
2805cff7825Smh27603 		 * get "domain_xy-model" property
2815cff7825Smh27603 		 */
2825cff7825Smh27603 		bzero(&modeldata, sizeof (modeldata));
2835cff7825Smh27603 		plen = strlen(domp->name) + strlen(PPM_MODEL_PROP_SUFFIX) + 1;
2845cff7825Smh27603 		modeldata.name = kmem_zalloc(plen, KM_SLEEP);
2855cff7825Smh27603 		(void) sprintf(modeldata.name, "%s%s",
2865cff7825Smh27603 		    domp->name, PPM_MODEL_PROP_SUFFIX);
2875cff7825Smh27603 
2885cff7825Smh27603 		cdata[0] = &modeldata;
2895cff7825Smh27603 		cdata[1] = NULL;
2905cff7825Smh27603 		if (err = ppm_get_confdata(cdata, dip)) {
2915cff7825Smh27603 			PPMD(D_CREATEDB, ("%s: Can't read property %s!\n",
2925cff7825Smh27603 			    str, modeldata.name))
2935cff7825Smh27603 			return (ppm_attach_err(cdata, err));
2945cff7825Smh27603 		}
2955cff7825Smh27603 
2965cff7825Smh27603 		model_namep = modeldata.strings;
2975cff7825Smh27603 		for (domit_p = ppm_domit_data; domit_p->name; domit_p++) {
2985cff7825Smh27603 			if (strcmp(domit_p->name,  *model_namep) == 0) {
2995cff7825Smh27603 				domp->model = domit_p->model;
3005cff7825Smh27603 				domp->dflags = domit_p->dflags;
3015cff7825Smh27603 				domp->status = domit_p->status;
3025cff7825Smh27603 				break;
3035cff7825Smh27603 			}
3045cff7825Smh27603 		}
3055cff7825Smh27603 		ASSERT(domit_p);
3065cff7825Smh27603 
3075cff7825Smh27603 		ppm_prop_free(cdata);
3085cff7825Smh27603 
3095cff7825Smh27603 
3105cff7825Smh27603 		/* get "domain_xy-propname" property */
3115cff7825Smh27603 		bzero(&propnamedata, sizeof (propnamedata));
3125cff7825Smh27603 		plen = strlen(domp->name) +
3135cff7825Smh27603 		    strlen(PPM_PROPNAME_PROP_SUFFIX) + 1;
3145cff7825Smh27603 		propnamedata.name = kmem_zalloc(plen, KM_SLEEP);
3155cff7825Smh27603 		(void) sprintf(propnamedata.name, "%s%s",
3165cff7825Smh27603 		    domp->name, PPM_PROPNAME_PROP_SUFFIX);
3175cff7825Smh27603 
3185cff7825Smh27603 		cdata[0] = &propnamedata;
3195cff7825Smh27603 		cdata[1] = NULL;
3205cff7825Smh27603 		if (ppm_get_confdata(cdata, dip) == DDI_PROP_SUCCESS) {
3215cff7825Smh27603 			domp->propname = kmem_zalloc(
3225cff7825Smh27603 			    (strlen(*propnamedata.strings) + 1), KM_SLEEP);
3235cff7825Smh27603 			(void) strcpy(domp->propname, *propnamedata.strings);
3245cff7825Smh27603 			PPMD(D_CREATEDB, ("%s: %s has property name: %s\n",
3255cff7825Smh27603 			    str, domp->name, domp->propname))
3265cff7825Smh27603 		}
3275cff7825Smh27603 		ppm_prop_free(cdata);
3285cff7825Smh27603 
3295cff7825Smh27603 
3305cff7825Smh27603 		/* get "domain_xy-devices" property */
3315cff7825Smh27603 		bzero(&devdata, sizeof (devdata));
3325cff7825Smh27603 		plen = strlen(domp->name) + strlen(PPM_DEV_PROP_SUFFIX) + 1;
3335cff7825Smh27603 		devdata.name = kmem_zalloc(plen, KM_SLEEP);
3345cff7825Smh27603 		(void) sprintf(devdata.name, "%s%s",
3355cff7825Smh27603 		    domp->name, PPM_DEV_PROP_SUFFIX);
3365cff7825Smh27603 
3375cff7825Smh27603 		cdata[0] = &devdata;
3385cff7825Smh27603 		cdata[1] = NULL;
3395cff7825Smh27603 		if (err = ppm_get_confdata(cdata, dip)) {
3405cff7825Smh27603 			PPMD(D_CREATEDB, ("%s: Can't read property %s!\n",
3415cff7825Smh27603 			    str, devdata.name))
3425cff7825Smh27603 			return (ppm_attach_err(cdata, err));
3435cff7825Smh27603 		}
3445cff7825Smh27603 
3455cff7825Smh27603 		for (dev_namep = devdata.strings; *dev_namep; dev_namep++) {
3465cff7825Smh27603 			if (!ppm_parse_pattern(&db, *dev_namep))
3475cff7825Smh27603 				return (ppm_attach_err(cdata, err));
3485cff7825Smh27603 			db->next = domp->conflist;
3495cff7825Smh27603 			domp->conflist = db;
3505cff7825Smh27603 			PPMD(D_CREATEDB, ("%s: %s add pattern: %s \n",
3515cff7825Smh27603 			    str, devdata.name, db->name))
3525cff7825Smh27603 		}
3535cff7825Smh27603 		PPMD(D_CREATEDB, ("\n"))
3545cff7825Smh27603 		ppm_prop_free(cdata);
3555cff7825Smh27603 
3565cff7825Smh27603 
3575cff7825Smh27603 		/* get "domain_xy-control" property */
3585cff7825Smh27603 		bzero(&dcdata, sizeof (dcdata));
3595cff7825Smh27603 		plen = strlen(domp->name) + strlen(PPM_CTRL_PROP_SUFFIX) + 1;
3605cff7825Smh27603 		dcdata.name = kmem_zalloc(plen, KM_SLEEP);
3615cff7825Smh27603 		(void) sprintf(dcdata.name, "%s%s",
3625cff7825Smh27603 		    domp->name, PPM_CTRL_PROP_SUFFIX);
3635cff7825Smh27603 
3645cff7825Smh27603 		cdata[0] = &dcdata;
3655cff7825Smh27603 		cdata[1] = NULL;
3665cff7825Smh27603 		if (ppm_get_confdata(cdata, dip) == DDI_PROP_SUCCESS) {
3675cff7825Smh27603 			for (dc_namep = dcdata.strings; *dc_namep;
3685cff7825Smh27603 			    dc_namep++) {
3695cff7825Smh27603 				dc = kmem_zalloc(sizeof (*dc), KM_SLEEP);
3705cff7825Smh27603 				dc->next = domp->dc;
3715cff7825Smh27603 				domp->dc = dc;
3725cff7825Smh27603 				err = ppm_parse_dc(dc_namep, domp->dc);
3735cff7825Smh27603 				if (err != DDI_SUCCESS)
3745cff7825Smh27603 					return (ppm_attach_err(cdata, err));
3755cff7825Smh27603 			}
3765cff7825Smh27603 		}
3775cff7825Smh27603 		ppm_prop_free(cdata);
3785cff7825Smh27603 #ifdef	DEBUG
3795cff7825Smh27603 		dc = domp->dc;
3805cff7825Smh27603 		while (dc) {
3815cff7825Smh27603 			ppm_print_dc(dc);
3825cff7825Smh27603 			dc = dc->next;
3835cff7825Smh27603 		}
3845cff7825Smh27603 #endif
3855cff7825Smh27603 	}
3865cff7825Smh27603 
3875cff7825Smh27603 	return (DDI_SUCCESS);
3885cff7825Smh27603 }
3895cff7825Smh27603 
3905cff7825Smh27603 
3915cff7825Smh27603 /*
3925cff7825Smh27603  * scan conf devices within each domain for a matching device name
3935cff7825Smh27603  */
3945cff7825Smh27603 ppm_domain_t *
3955cff7825Smh27603 ppm_lookup_dev(dev_info_t *dip)
3965cff7825Smh27603 {
3975cff7825Smh27603 	char path[MAXNAMELEN];
3985cff7825Smh27603 	ppm_domain_t *domp;
3995cff7825Smh27603 	ppm_db_t *dbp;
400b72d5b75SMichael Corcoran #ifdef	__x86
401b72d5b75SMichael Corcoran 	char *devtype = NULL;
402b72d5b75SMichael Corcoran #endif	/* __x86 */
4035cff7825Smh27603 
4045cff7825Smh27603 	PPM_GET_PATHNAME(dip, path);
4055cff7825Smh27603 	for (domp = ppm_domain_p; domp; domp = domp->next) {
4062df1fe9cSrandyf 		if (PPM_DOMAIN_UP(domp)) {
4075cff7825Smh27603 			for (dbp = domp->conflist; dbp; dbp = dbp->next) {
4082df1fe9cSrandyf 				/*
4092df1fe9cSrandyf 				 * allow claiming root without knowing
4102df1fe9cSrandyf 				 * its full name
4112df1fe9cSrandyf 				 */
4122df1fe9cSrandyf 				if (dip == ddi_root_node() &&
4132df1fe9cSrandyf 				    strcmp(dbp->name, "/") == 0)
4142df1fe9cSrandyf 					return (domp);
415b72d5b75SMichael Corcoran 
416b72d5b75SMichael Corcoran #ifdef	__x86
417b72d5b75SMichael Corcoran 				/*
418b72d5b75SMichael Corcoran 				 * Special rule to catch all CPU devices on x86.
419b72d5b75SMichael Corcoran 				 */
420b72d5b75SMichael Corcoran 				if (domp->model == PPMD_CPU &&
421b72d5b75SMichael Corcoran 				    strcmp(dbp->name, "/") == 0 &&
422b72d5b75SMichael Corcoran 				    ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
423b72d5b75SMichael Corcoran 				    DDI_PROP_DONTPASS, "device_type",
424b72d5b75SMichael Corcoran 				    &devtype) == DDI_SUCCESS) {
425b72d5b75SMichael Corcoran 					if (strcmp(devtype, "cpu") == 0) {
426b72d5b75SMichael Corcoran 						ddi_prop_free(devtype);
427b72d5b75SMichael Corcoran 						return (domp);
428b72d5b75SMichael Corcoran 					} else {
429b72d5b75SMichael Corcoran 						ddi_prop_free(devtype);
430b72d5b75SMichael Corcoran 					}
431b72d5b75SMichael Corcoran 				}
432b72d5b75SMichael Corcoran #endif	/* __x86 */
433b72d5b75SMichael Corcoran 
4345cff7825Smh27603 				if (ppm_match_devs(path, dbp) == 0)
4355cff7825Smh27603 					return (domp);
4365cff7825Smh27603 			}
4375cff7825Smh27603 		}
4382df1fe9cSrandyf 	}
4395cff7825Smh27603 
4405cff7825Smh27603 	return (NULL);
4415cff7825Smh27603 }
4425cff7825Smh27603 
4435cff7825Smh27603 
4445cff7825Smh27603 /*
4455cff7825Smh27603  * check ppm.conf file domain device pathname syntax, if correct,
4465cff7825Smh27603  * create device match pattern.
4475cff7825Smh27603  * return 1 for good, -1 for bad.
4485cff7825Smh27603  */
4495cff7825Smh27603 ppm_db_t *
4505cff7825Smh27603 ppm_parse_pattern(struct ppm_db **dbpp, char *dev_path)
4515cff7825Smh27603 {
4525cff7825Smh27603 	char path[MAXNAMELEN];
4535cff7825Smh27603 	int	wccnt, i;
4545cff7825Smh27603 	int	wcpos[2];
4555cff7825Smh27603 	int	pos;
4565cff7825Smh27603 	char	*cp;
4575cff7825Smh27603 	ppm_db_t *dbp;
4585cff7825Smh27603 
4595cff7825Smh27603 	(void) strcpy(path, dev_path);
4605cff7825Smh27603 	if ((wccnt = ppm_count_char(path, '*')) > 2)
4615cff7825Smh27603 		return (NULL);
4625cff7825Smh27603 
4635cff7825Smh27603 	for (i = 0, cp = path, pos = 0; i < wccnt; i++, cp++, pos++) {
4645cff7825Smh27603 		for (; *cp; cp++, pos++)
4655cff7825Smh27603 			if (*cp == '*')
4665cff7825Smh27603 				break;
4675cff7825Smh27603 		wcpos[i] = pos;
4685cff7825Smh27603 		PPMD(D_CREATEDB, ("    wildcard #%d, pos %d\n",
4695cff7825Smh27603 		    (i + 1), wcpos[i]))
4705cff7825Smh27603 	}
4715cff7825Smh27603 
4725cff7825Smh27603 #ifdef	DEBUG
4735cff7825Smh27603 	/* first '*', if exists, don't go beyond the string */
4745cff7825Smh27603 	if (wccnt > 0)
4755cff7825Smh27603 		ASSERT(wcpos[0] < strlen(path));
4765cff7825Smh27603 
4775cff7825Smh27603 	/* second '*', if exists, better be the last character */
4785cff7825Smh27603 	if (wccnt == 2)
4795cff7825Smh27603 		ASSERT(wcpos[1] == (strlen(path) - 1));
4805cff7825Smh27603 #endif
4815cff7825Smh27603 
4825cff7825Smh27603 	/*
4835cff7825Smh27603 	 * first '*', if followed by any char, must be immediately
4845cff7825Smh27603 	 * followed by '@' and the rest better be bound by
4855cff7825Smh27603 	 * ['0-9', 'a-f', A-F'] until ended '0' or second '*''0'.
4865cff7825Smh27603 	 */
4875cff7825Smh27603 	if ((wccnt > 0) && (wcpos[0] < (strlen(path) - 1))) {
4885cff7825Smh27603 		cp = path + wcpos[0] + 1;
4895cff7825Smh27603 		if (*cp != '@')
4905cff7825Smh27603 			return (NULL);
4915cff7825Smh27603 
4925cff7825Smh27603 		if (!(((*(++cp) > '0') && (*cp < '9')) ||
4935cff7825Smh27603 		    ((*cp > 'a') && (*cp < 'f')) ||
4945cff7825Smh27603 		    ((*cp > 'A') && (*cp < 'F'))))
4955cff7825Smh27603 			return (NULL);
4965cff7825Smh27603 	}
4975cff7825Smh27603 
4985cff7825Smh27603 	dbp = kmem_zalloc(sizeof (struct ppm_db), KM_SLEEP);
4995cff7825Smh27603 	dbp->name = kmem_zalloc((strlen(path) + 1), KM_SLEEP);
5005cff7825Smh27603 	(void) strcpy(dbp->name, path);
5015cff7825Smh27603 	dbp->wccnt = wccnt;
5025cff7825Smh27603 	dbp->wcpos[0] = (wccnt > 0) ? wcpos[0] : -1;
5035cff7825Smh27603 	dbp->wcpos[1] = (wccnt == 2) ? wcpos[1] : -1;
5045cff7825Smh27603 
5055cff7825Smh27603 	return (*dbpp = dbp);
5065cff7825Smh27603 }
5075cff7825Smh27603 
5085cff7825Smh27603 
5095cff7825Smh27603 /*
5105cff7825Smh27603  * match given device "path" to domain device pathname
5115cff7825Smh27603  * pattern dbp->name that contains one or two '*' character(s).
5125cff7825Smh27603  * Matching policy:
5135cff7825Smh27603  *   1). If one wildcard terminates match pattern, need exact match
5145cff7825Smh27603  *       up to (but exclude) the wildcard;
5155cff7825Smh27603  *   2). If one wildcard does not terminate match pattern, it is to
5165cff7825Smh27603  *       match driver name (terminates with '@') and must be followed
5175cff7825Smh27603  *       by exact match of rest of pattern;
5185cff7825Smh27603  *   3). If two wildcards, first is to match driver name as in 2),
5195cff7825Smh27603  *       second is to match fcnid (terminates with '/' or '\0') and
5205cff7825Smh27603  *       must the last char of pattern.
5215cff7825Smh27603  *
5225cff7825Smh27603  * return  0  if match, and
5235cff7825Smh27603  *        non 0  if mismatch
5245cff7825Smh27603  */
5255cff7825Smh27603 int
5265cff7825Smh27603 ppm_match_devs(char *dev_path, ppm_db_t *dbp)
5275cff7825Smh27603 {
5285cff7825Smh27603 	char path[MAXNAMELEN];
5295cff7825Smh27603 	char *cp;	/* points into "path", real device pathname */
5305cff7825Smh27603 	char *np;	/* points into "dbp->name", the pattern */
5315cff7825Smh27603 	int  len;
5325cff7825Smh27603 
5335cff7825Smh27603 	if (dbp->wccnt == 0)
5345cff7825Smh27603 		return (strcmp(dev_path, dbp->name));
5355cff7825Smh27603 
5365cff7825Smh27603 	(void) strcpy(path, dev_path);
5375cff7825Smh27603 
5385cff7825Smh27603 	/* match upto the first '*' regardless */
5395cff7825Smh27603 	if (strncmp(path, dbp->name, dbp->wcpos[0]) != 0)
5405cff7825Smh27603 		return (-1);
5415cff7825Smh27603 
5425cff7825Smh27603 
5435cff7825Smh27603 	/* "<exact match>*"	*/
5445cff7825Smh27603 	if (dbp->name[dbp->wcpos[0] + 1] == 0) {
5455cff7825Smh27603 		cp = path + dbp->wcpos[0];
5462df1fe9cSrandyf 		while (*cp && (*cp++ != '/'))
5472df1fe9cSrandyf 			;
5485cff7825Smh27603 		return ((*cp == 0) ? 0 : -1);
5495cff7825Smh27603 	}
5505cff7825Smh27603 
5515cff7825Smh27603 
5525cff7825Smh27603 	/* locate '@'	*/
5535cff7825Smh27603 	cp = path + dbp->wcpos[0] + 1;
5545cff7825Smh27603 	while (*cp && *cp != '@')
5555cff7825Smh27603 		cp++;
5565cff7825Smh27603 
5575cff7825Smh27603 	np = dbp->name + dbp->wcpos[0] + 1;
5585cff7825Smh27603 
5595cff7825Smh27603 	/* if one wildcard, match the rest in the pattern */
5605cff7825Smh27603 	if (dbp->wccnt == 1)
5615cff7825Smh27603 		return ((strcmp(cp, np) == 0) ? 0 : (-1));
5625cff7825Smh27603 
5635cff7825Smh27603 
5645cff7825Smh27603 	/* must have exact match after first wildcard up to second */
5655cff7825Smh27603 	ASSERT(dbp->wccnt == 2);
5665cff7825Smh27603 	len = dbp->wcpos[1] - dbp->wcpos[0] - 1;
5675cff7825Smh27603 	if (strncmp(cp, np, len) != 0)
5685cff7825Smh27603 		return (-1);
5695cff7825Smh27603 
5705cff7825Smh27603 	/* second wildcard match terminates with '/' or '\0' */
5715cff7825Smh27603 	/* but only termination with '\0' is a successful match */
5725cff7825Smh27603 	cp += len;
5735cff7825Smh27603 	while (*cp && (*cp != '/'))
5745cff7825Smh27603 		cp++;
5755cff7825Smh27603 	return ((*cp == 0) ? 0 : -1);
5765cff7825Smh27603 }
5775cff7825Smh27603 
5785cff7825Smh27603 
5795cff7825Smh27603 /*
5805cff7825Smh27603  * By claiming a device, ppm gets involved in its power change
5815cff7825Smh27603  * process: handles additional issues prior and/or post its
5825cff7825Smh27603  * power(9e) call.
5835cff7825Smh27603  *
5845cff7825Smh27603  * If 'dip' is a PCI device, this is the time to ask its parent
5855cff7825Smh27603  * what PCI bus speed it is running.
5865cff7825Smh27603  *
5875cff7825Smh27603  * returns 1 (claimed), 0 (not claimed)
5885cff7825Smh27603  */
5895cff7825Smh27603 int
5905cff7825Smh27603 ppm_claim_dev(dev_info_t *dip)
5915cff7825Smh27603 {
5925cff7825Smh27603 	ppm_domain_t	*domp;
5935cff7825Smh27603 	dev_info_t	*pdip;
5945cff7825Smh27603 	uint_t		pciclk;
5955cff7825Smh27603 	int		claimed = -1;
5965cff7825Smh27603 
5975cff7825Smh27603 	domp = ppm_lookup_dev(dip);
5985cff7825Smh27603 	if (!domp)
5995cff7825Smh27603 		claimed = 0;
6005cff7825Smh27603 
6015cff7825Smh27603 	if (domp && PPMD_IS_PCI(domp->model) &&
6025cff7825Smh27603 	    ! (domp->dflags & (PPMD_PCI33MHZ | PPMD_PCI66MHZ))) {
6035cff7825Smh27603 		pdip = ddi_get_parent(dip);
6045cff7825Smh27603 		ASSERT(pdip);
6055cff7825Smh27603 		pciclk = ddi_prop_get_int(DDI_DEV_T_ANY, pdip,
6065cff7825Smh27603 		    DDI_PROP_DONTPASS, "clock-frequency", -1);
6075cff7825Smh27603 
6085cff7825Smh27603 		switch (pciclk) {
6095cff7825Smh27603 		case 33000000:
6105cff7825Smh27603 			domp->dflags |= PPMD_PCI33MHZ;
6115cff7825Smh27603 			claimed = 1;
6125cff7825Smh27603 			break;
6135cff7825Smh27603 		case 66000000:
6145cff7825Smh27603 			domp->dflags |= PPMD_PCI66MHZ;
6155cff7825Smh27603 			claimed = 1;
6165cff7825Smh27603 			break;
6175cff7825Smh27603 		default:
6185cff7825Smh27603 			claimed = 0;
6195cff7825Smh27603 			break;
6205cff7825Smh27603 		}
6215cff7825Smh27603 	}
6225cff7825Smh27603 
6235cff7825Smh27603 	if (domp && (claimed == -1))
6245cff7825Smh27603 		claimed = 1;
6255cff7825Smh27603 
6265cff7825Smh27603 #ifdef DEBUG
6275cff7825Smh27603 	if (claimed) {
6285cff7825Smh27603 		char path[MAXNAMELEN];
6295cff7825Smh27603 		PPMD(D_CLAIMDEV, ("ppm_claim_dev: %s into domain %s\n",
6305cff7825Smh27603 		    ddi_pathname(dip, path), domp->name))
6315cff7825Smh27603 	}
6325cff7825Smh27603 
6335cff7825Smh27603 #endif
6345cff7825Smh27603 
6355cff7825Smh27603 	return (claimed);
6365cff7825Smh27603 }
6375cff7825Smh27603 
6385cff7825Smh27603 /*
6395cff7825Smh27603  * add a device to the list of domain's owned devices (if it is not already
6405cff7825Smh27603  * on the list).
6415cff7825Smh27603  */
6425cff7825Smh27603 ppm_owned_t *
6435cff7825Smh27603 ppm_add_owned(dev_info_t *dip, ppm_domain_t *domp)
6445cff7825Smh27603 {
6455cff7825Smh27603 	char path[MAXNAMELEN];
6465cff7825Smh27603 	ppm_owned_t *owned, *new_owned;
6475cff7825Smh27603 
6485cff7825Smh27603 	ASSERT(MUTEX_HELD(&domp->lock));
6495cff7825Smh27603 	PPM_GET_PATHNAME(dip, path);
6505cff7825Smh27603 	for (owned = domp->owned; owned; owned = owned->next)
6515cff7825Smh27603 		if (strcmp(path, owned->path) == 0)
6525cff7825Smh27603 			return (owned);
6535cff7825Smh27603 
6545cff7825Smh27603 	new_owned = kmem_zalloc(sizeof (*new_owned), KM_SLEEP);
6555cff7825Smh27603 	new_owned->path = kmem_zalloc(strlen(path) + 1, KM_SLEEP);
6565cff7825Smh27603 	(void) strcpy(new_owned->path, path);
6575cff7825Smh27603 	new_owned->next = domp->owned;
6585cff7825Smh27603 	domp->owned = new_owned;
6595cff7825Smh27603 
6605cff7825Smh27603 	return (domp->owned);
6615cff7825Smh27603 }
6625cff7825Smh27603 
6635cff7825Smh27603 /*
6645cff7825Smh27603  * create/init a new ppm device and link into the domain
6655cff7825Smh27603  */
6665cff7825Smh27603 ppm_dev_t *
6675cff7825Smh27603 ppm_add_dev(dev_info_t *dip, ppm_domain_t *domp)
6685cff7825Smh27603 {
6695cff7825Smh27603 	char path[MAXNAMELEN];
6705cff7825Smh27603 	ppm_dev_t *new = NULL;
6715cff7825Smh27603 	int cmpt;
6725cff7825Smh27603 	ppm_owned_t *owned;
6735cff7825Smh27603 
6745cff7825Smh27603 	ASSERT(MUTEX_HELD(&domp->lock));
6755cff7825Smh27603 	(void) ddi_pathname(dip, path);
6765cff7825Smh27603 	/*
6775cff7825Smh27603 	 * For devs which have exported "pm-components" we want to create
6785cff7825Smh27603 	 * a data structure for each component.  When a driver chooses not
6795cff7825Smh27603 	 * to export the prop we treat its device as having a single
6805cff7825Smh27603 	 * component and build a structure for it anyway.  All other ppm
6815cff7825Smh27603 	 * logic will act as if this device were always up and can thus
6825cff7825Smh27603 	 * make correct decisions about it in relation to other devices
6835cff7825Smh27603 	 * in its domain.
6845cff7825Smh27603 	 */
6855cff7825Smh27603 	for (cmpt = PM_GET_PM_INFO(dip) ? PM_NUMCMPTS(dip) : 1; cmpt--; ) {
6865cff7825Smh27603 		new = kmem_zalloc(sizeof (*new), KM_SLEEP);
6875cff7825Smh27603 		new->path = kmem_zalloc(strlen(path) + 1, KM_SLEEP);
6885cff7825Smh27603 		(void) strcpy(new->path, path);
6895cff7825Smh27603 		new->domp = domp;
6905cff7825Smh27603 		new->dip = dip;
6915cff7825Smh27603 		new->cmpt = cmpt;
6925cff7825Smh27603 		ppm_dev_init(new);
6935cff7825Smh27603 		new->next = domp->devlist;
6945cff7825Smh27603 		domp->devlist = new;
6955cff7825Smh27603 		PPMD(D_ADDDEV,
6965cff7825Smh27603 		    ("ppm_add_dev: %s to domain %s: ppm_dev(0x%p)\n",
6975cff7825Smh27603 		    new->path, domp->name, (void *)new))
6985cff7825Smh27603 	}
6995cff7825Smh27603 
7005cff7825Smh27603 	ASSERT(new != NULL);
7015cff7825Smh27603 	/*
7025cff7825Smh27603 	 * devi_pm_ppm_private should be set only after all
7035cff7825Smh27603 	 * ppm_dev s related to all components have been
7045cff7825Smh27603 	 * initialized and domain's pwr_cnt is incremented
7055cff7825Smh27603 	 * for each of them.
7065cff7825Smh27603 	 */
7075cff7825Smh27603 	PPM_SET_PRIVATE(dip, new);
7085cff7825Smh27603 
7095cff7825Smh27603 	/* remember this device forever */
7105cff7825Smh27603 	owned = ppm_add_owned(dip, domp);
7115cff7825Smh27603 
7125cff7825Smh27603 	/*
7135cff7825Smh27603 	 * Initializing flag is set for devices which have gone through
7145cff7825Smh27603 	 * PPM_PMR_INIT_CHILD ctlop.  By this point, these devices have
7155cff7825Smh27603 	 * been added to ppm structures and could participate in pm
7165cff7825Smh27603 	 * decision making, so clear the initializing flag.
7175cff7825Smh27603 	 */
7185cff7825Smh27603 	if (owned->initializing) {
7195cff7825Smh27603 		owned->initializing = 0;
7205cff7825Smh27603 		PPMD(D_ADDDEV, ("ppm_add_dev: cleared initializing flag "
7215cff7825Smh27603 		    "for %s@%s\n", PM_NAME(dip),
7225cff7825Smh27603 		    (PM_ADDR(dip) == NULL) ? "" : PM_ADDR(dip)))
7235cff7825Smh27603 	}
7245cff7825Smh27603 
7255cff7825Smh27603 	return (new);
7265cff7825Smh27603 }
7275cff7825Smh27603 
7285cff7825Smh27603 
7295cff7825Smh27603 /*
7305cff7825Smh27603  * returns an existing or newly created ppm device reference
7315cff7825Smh27603  */
7325cff7825Smh27603 ppm_dev_t *
7335cff7825Smh27603 ppm_get_dev(dev_info_t *dip, ppm_domain_t *domp)
7345cff7825Smh27603 {
7355cff7825Smh27603 	ppm_dev_t *pdp;
7365cff7825Smh27603 
7375cff7825Smh27603 	mutex_enter(&domp->lock);
7385cff7825Smh27603 	pdp = PPM_GET_PRIVATE(dip);
7395cff7825Smh27603 	if (pdp == NULL)
7405cff7825Smh27603 		pdp = ppm_add_dev(dip, domp);
7415cff7825Smh27603 	mutex_exit(&domp->lock);
7425cff7825Smh27603 
7435cff7825Smh27603 	return (pdp);
7445cff7825Smh27603 }
7455cff7825Smh27603 
7465cff7825Smh27603 
7475cff7825Smh27603 /*
7485cff7825Smh27603  * scan a domain's device list and remove those with .dip
7495cff7825Smh27603  * matching the arg *dip; we need to scan the entire list
7505cff7825Smh27603  * for the case of devices with multiple components
7515cff7825Smh27603  */
7525cff7825Smh27603 void
7535cff7825Smh27603 ppm_rem_dev(dev_info_t *dip)
7545cff7825Smh27603 {
7555cff7825Smh27603 	ppm_dev_t *pdp, **devpp;
7565cff7825Smh27603 	ppm_domain_t *domp;
7575cff7825Smh27603 
7585cff7825Smh27603 	pdp = PPM_GET_PRIVATE(dip);
7595cff7825Smh27603 	ASSERT(pdp);
7605cff7825Smh27603 	domp = pdp->domp;
7615cff7825Smh27603 	ASSERT(domp);
7625cff7825Smh27603 
7635cff7825Smh27603 	mutex_enter(&domp->lock);
7645cff7825Smh27603 	for (devpp = &domp->devlist; (pdp = *devpp) != NULL; ) {
7655cff7825Smh27603 		if (pdp->dip != dip) {
7665cff7825Smh27603 			devpp = &pdp->next;
7675cff7825Smh27603 			continue;
7685cff7825Smh27603 		}
7695cff7825Smh27603 
7705cff7825Smh27603 		PPMD(D_REMDEV, ("ppm_rem_dev: path \"%s\", ppm_dev 0x%p\n",
7715cff7825Smh27603 		    pdp->path, (void *)pdp))
7725cff7825Smh27603 
7735cff7825Smh27603 		PPM_SET_PRIVATE(dip, NULL);
7745cff7825Smh27603 		*devpp = pdp->next;
7755cff7825Smh27603 		ppm_dev_fini(pdp);
7765cff7825Smh27603 		kmem_free(pdp->path, strlen(pdp->path) + 1);
7775cff7825Smh27603 		kmem_free(pdp, sizeof (*pdp));
7785cff7825Smh27603 	}
7795cff7825Smh27603 	mutex_exit(&domp->lock);
7805cff7825Smh27603 }
7815cff7825Smh27603 
7825cff7825Smh27603 /*
7835cff7825Smh27603  * prepare kernel ioctl calls:
7845cff7825Smh27603  */
7855cff7825Smh27603 void
7865cff7825Smh27603 ppm_init_cb(dev_info_t *dip)
7875cff7825Smh27603 {
7885cff7825Smh27603 	char		*str = "ppm_init_cb";
7895cff7825Smh27603 	ppm_domain_t	*domp;
7905cff7825Smh27603 	ppm_dc_t	*dc;
7915cff7825Smh27603 
7925cff7825Smh27603 	for (domp = ppm_domain_p; domp != NULL; domp = domp->next) {
7935cff7825Smh27603 		for (dc = domp->dc; dc; dc = dc->next) {
7942df1fe9cSrandyf 			/*
7952df1fe9cSrandyf 			 * Warning: This code is rather confusing.
7962df1fe9cSrandyf 			 *
7972df1fe9cSrandyf 			 * It intends to ensure that ppm_init_lyr() is only
7982df1fe9cSrandyf 			 * called ONCE for a device that may be associated
7992df1fe9cSrandyf 			 * with more than one domain control.
8002df1fe9cSrandyf 			 * So, what it does is first to check to see if
8012df1fe9cSrandyf 			 * there is a handle, and then if not it goes on
8022df1fe9cSrandyf 			 * to call the init_lyr() routine.
8032df1fe9cSrandyf 			 *
8042df1fe9cSrandyf 			 * The non-obvious thing is that the ppm_init_lyr()
8052df1fe9cSrandyf 			 * routine, in addition to opening the device
8062df1fe9cSrandyf 			 * associated with the dc (domain control) in
8072df1fe9cSrandyf 			 * question, has the side-effect of creating the
8082df1fe9cSrandyf 			 * handle for that dc as well.
8092df1fe9cSrandyf 			 */
8105cff7825Smh27603 			if (ppm_lookup_hndl(domp->model, dc) != NULL)
8115cff7825Smh27603 				continue;
8125cff7825Smh27603 
8135cff7825Smh27603 			if (ppm_init_lyr(dc, dip) != DDI_SUCCESS) {
8145cff7825Smh27603 				domp->dflags |= PPMD_OFFLINE;
8155cff7825Smh27603 				cmn_err(CE_WARN, "%s: ppm domain %s will "
8165cff7825Smh27603 				    "be offline.", str, domp->name);
8175cff7825Smh27603 				break;
8185cff7825Smh27603 			}
8195cff7825Smh27603 		}
8205cff7825Smh27603 	}
8215cff7825Smh27603 }
8225cff7825Smh27603 
8235cff7825Smh27603 
8245cff7825Smh27603 /*
8255cff7825Smh27603  *  ppm_init_lyr - initializing layered ioctl
8265cff7825Smh27603  * Return:
8275cff7825Smh27603  *     DDI_SUCCESS  - succeeded
8285cff7825Smh27603  *     DDI_FAILURE  - failed
8295cff7825Smh27603  *
8305cff7825Smh27603  */
8315cff7825Smh27603 int
8325cff7825Smh27603 ppm_init_lyr(ppm_dc_t	*dc, dev_info_t *dip)
8335cff7825Smh27603 {
8345cff7825Smh27603 	char 			*str = "ppm_init_lyr";
8355cff7825Smh27603 	int			err = 0;
8365cff7825Smh27603 	ldi_ident_t		li;
8375cff7825Smh27603 
8385cff7825Smh27603 	ASSERT(dc && dc->path);
8395cff7825Smh27603 
8405cff7825Smh27603 	if (err = ldi_ident_from_dip(dip, &li)) {
8415cff7825Smh27603 		cmn_err(CE_WARN, "%s: get ldi identifier "
8425cff7825Smh27603 		    "failed (err=%d)", str, err);
8435cff7825Smh27603 	}
8445cff7825Smh27603 
8455cff7825Smh27603 	err = ldi_open_by_name(dc->path, FWRITE|FREAD, kcred, &(dc->lh), li);
8465cff7825Smh27603 
8475cff7825Smh27603 	(void) ldi_ident_release(li);
8485cff7825Smh27603 
8495cff7825Smh27603 	if (err != 0) {
8505cff7825Smh27603 		cmn_err(CE_WARN, "Failed to open device(%s), rv(%d)",
8515cff7825Smh27603 		    dc->path, err);
8525cff7825Smh27603 		return (err);
8535cff7825Smh27603 	}
8545cff7825Smh27603 
8555cff7825Smh27603 	return (DDI_SUCCESS);
8565cff7825Smh27603 }
8575cff7825Smh27603 
8585cff7825Smh27603 /*
8595cff7825Smh27603  * lock, unlock, or trylock for one power mutex
8605cff7825Smh27603  */
8615cff7825Smh27603 void
8625cff7825Smh27603 ppm_lock_one(ppm_dev_t *ppmd, power_req_t *reqp, int *iresp)
8635cff7825Smh27603 {
8645cff7825Smh27603 	switch (reqp->request_type) {
8655cff7825Smh27603 	case PMR_PPM_LOCK_POWER:
8665cff7825Smh27603 		pm_lock_power_single(ppmd->dip,
8675cff7825Smh27603 		    reqp->req.ppm_lock_power_req.circp);
8685cff7825Smh27603 		break;
8695cff7825Smh27603 
8705cff7825Smh27603 	case PMR_PPM_UNLOCK_POWER:
8715cff7825Smh27603 		pm_unlock_power_single(ppmd->dip,
8725cff7825Smh27603 		    reqp->req.ppm_unlock_power_req.circ);
8735cff7825Smh27603 		break;
8745cff7825Smh27603 
8755cff7825Smh27603 	case PMR_PPM_TRY_LOCK_POWER:
8765cff7825Smh27603 		*iresp = pm_try_locking_power_single(ppmd->dip,
8775cff7825Smh27603 		    reqp->req.ppm_lock_power_req.circp);
8785cff7825Smh27603 		break;
8795cff7825Smh27603 	}
8805cff7825Smh27603 }
8815cff7825Smh27603 
8825cff7825Smh27603 
8835cff7825Smh27603 /*
8845cff7825Smh27603  * lock, unlock, or trylock for all power mutexes within a domain
8855cff7825Smh27603  */
8865cff7825Smh27603 void
8875cff7825Smh27603 ppm_lock_all(ppm_domain_t *domp, power_req_t *reqp, int *iresp)
8885cff7825Smh27603 {
8895cff7825Smh27603 	/*
8905cff7825Smh27603 	 * To simplify the implementation we let all the devices
8915cff7825Smh27603 	 * in the domain be represented by a single device (dip).
8925cff7825Smh27603 	 * We use the first device in the domain's devlist.  This
8935cff7825Smh27603 	 * is safe because we return with the domain lock held
8945cff7825Smh27603 	 * which prevents the list from changing.
8955cff7825Smh27603 	 */
8965cff7825Smh27603 	if (reqp->request_type == PMR_PPM_LOCK_POWER) {
8975cff7825Smh27603 		if (!MUTEX_HELD(&domp->lock))
8985cff7825Smh27603 			mutex_enter(&domp->lock);
8995cff7825Smh27603 		domp->refcnt++;
9005cff7825Smh27603 		ASSERT(domp->devlist != NULL);
9015cff7825Smh27603 		pm_lock_power_single(domp->devlist->dip,
9025cff7825Smh27603 		    reqp->req.ppm_lock_power_req.circp);
9035cff7825Smh27603 		/* domain lock remains held */
9045cff7825Smh27603 		return;
9055cff7825Smh27603 	} else if (reqp->request_type == PMR_PPM_UNLOCK_POWER) {
9065cff7825Smh27603 		ASSERT(MUTEX_HELD(&domp->lock));
9075cff7825Smh27603 		ASSERT(domp->devlist != NULL);
9085cff7825Smh27603 		pm_unlock_power_single(domp->devlist->dip,
9095cff7825Smh27603 		    reqp->req.ppm_unlock_power_req.circ);
9105cff7825Smh27603 		if (--domp->refcnt == 0)
9115cff7825Smh27603 			mutex_exit(&domp->lock);
9125cff7825Smh27603 		return;
9135cff7825Smh27603 	}
9145cff7825Smh27603 
9155cff7825Smh27603 	ASSERT(reqp->request_type == PMR_PPM_TRY_LOCK_POWER);
9165cff7825Smh27603 	if (!MUTEX_HELD(&domp->lock))
9175cff7825Smh27603 		if (!mutex_tryenter(&domp->lock)) {
9185cff7825Smh27603 			*iresp = 0;
9195cff7825Smh27603 			return;
9205cff7825Smh27603 		}
9215cff7825Smh27603 	*iresp = pm_try_locking_power_single(domp->devlist->dip,
9225cff7825Smh27603 	    reqp->req.ppm_lock_power_req.circp);
9235cff7825Smh27603 	if (*iresp)
9245cff7825Smh27603 		domp->refcnt++;
9255cff7825Smh27603 	else
9265cff7825Smh27603 		mutex_exit(&domp->lock);
9275cff7825Smh27603 }
9285cff7825Smh27603 
9295cff7825Smh27603 
9305cff7825Smh27603 /*
9315cff7825Smh27603  * return FALSE: if any detached device during its previous life exported
9325cff7825Smh27603  *   the "no-involuntary-power-cycles" property and detached with its
9335cff7825Smh27603  *   power level not at its lowest, or there is a device in the process
9345cff7825Smh27603  *   of being installed/attached; if a PCI domain has devices that have not
9355cff7825Smh27603  *   exported a property that it can tolerate clock off while bus is not
9365cff7825Smh27603  *   quiescent; if a 66mhz PCI domain has devices that do not support stopping
9375cff7825Smh27603  *   clock at D3; either one would count as a power holder.
9385cff7825Smh27603  * return TRUE: otherwise.
9395cff7825Smh27603  */
9405cff7825Smh27603 boolean_t
9415cff7825Smh27603 ppm_none_else_holds_power(ppm_domain_t *domp)
9425cff7825Smh27603 {
9435cff7825Smh27603 	ppm_dev_t  *ppmd;
9445cff7825Smh27603 	ppm_owned_t *owned;
9455cff7825Smh27603 	int	i = 0;
9465cff7825Smh27603 
9475cff7825Smh27603 	if (PPMD_IS_PCI(domp->model)) {
9485cff7825Smh27603 		for (ppmd = domp->devlist; ppmd; ppmd = ppmd->next) {
9495cff7825Smh27603 			if ((domp->model == PPMD_PCI_PROP) &&
9505cff7825Smh27603 			    !(ppmd->flags & PPMDEV_PCI_PROP_CLKPM))
9515cff7825Smh27603 				return (B_FALSE);
9525cff7825Smh27603 			if ((domp->dflags & PPMD_PCI66MHZ) &&
9535cff7825Smh27603 			    !(ppmd->flags & PPMDEV_PCI66_D2))
9545cff7825Smh27603 				return (B_FALSE);
9555cff7825Smh27603 		}
9565cff7825Smh27603 	}
9575cff7825Smh27603 
9585cff7825Smh27603 	for (owned = domp->owned; owned; owned = owned->next)
9595cff7825Smh27603 		if (pm_noinvol_detached(owned->path) || owned->initializing)
9605cff7825Smh27603 			i++;
9615cff7825Smh27603 	return (i == 0);
9625cff7825Smh27603 }
9635cff7825Smh27603 
9645cff7825Smh27603 
9655cff7825Smh27603 /*
9665cff7825Smh27603  * return the number of char 'c' occurrences in string s
9675cff7825Smh27603  */
9685cff7825Smh27603 int
9695cff7825Smh27603 ppm_count_char(char *s, char c)
9705cff7825Smh27603 {
9715cff7825Smh27603 	int	i = 0;
9725cff7825Smh27603 	char	*cp = s;
9735cff7825Smh27603 
9745cff7825Smh27603 	while (*cp) {
9755cff7825Smh27603 		if (*cp == c)
9765cff7825Smh27603 			i++;
9775cff7825Smh27603 		cp++;
9785cff7825Smh27603 	}
9795cff7825Smh27603 
9805cff7825Smh27603 	return (i);
9815cff7825Smh27603 }
9825cff7825Smh27603 
9835cff7825Smh27603 
9845cff7825Smh27603 /*
9855cff7825Smh27603  * extract and convert a substring from input string "ss" in form of
9865cff7825Smh27603  * "name=value" into an hex or decimal integer
9875cff7825Smh27603  */
9885cff7825Smh27603 #define	X_BASE	16
9895cff7825Smh27603 #define	D_BASE	10
9905cff7825Smh27603 int
9915cff7825Smh27603 ppm_stoi(char *ss, uint_t *val)
9925cff7825Smh27603 {
9935cff7825Smh27603 	char *cp;
9945cff7825Smh27603 	int  hex_ = 0, base = D_BASE;
9955cff7825Smh27603 	int  digit;
9965cff7825Smh27603 
9975cff7825Smh27603 	if ((cp = strchr(ss, '=')) == NULL)
9985cff7825Smh27603 		return (*val = (uint_t)-1);
9995cff7825Smh27603 
10005cff7825Smh27603 	cp++;
10015cff7825Smh27603 	if ((*cp == '0') && (*++cp == 'x')) {
10025cff7825Smh27603 		hex_++;
10035cff7825Smh27603 		cp++;
10045cff7825Smh27603 		base = X_BASE;
10055cff7825Smh27603 	}
10065cff7825Smh27603 
10075cff7825Smh27603 	for (digit = 0; *cp; cp++) {
10085cff7825Smh27603 		if (hex_ && ((*cp >= 'A') && (*cp <= 'F')))
10095cff7825Smh27603 			digit = (digit * base) + ((*cp - 'A') + D_BASE);
10105cff7825Smh27603 		else if (hex_ && ((*cp >= 'a') && (*cp <= 'f')))
10115cff7825Smh27603 			digit = (digit * base) + ((*cp - 'a') + D_BASE);
10125cff7825Smh27603 		else
10135cff7825Smh27603 			digit = (digit * base) + (*cp - '0');
10145cff7825Smh27603 	}
10155cff7825Smh27603 
10165cff7825Smh27603 	return (*val = digit);
10175cff7825Smh27603 }
10185cff7825Smh27603 
10195cff7825Smh27603 /*
10205cff7825Smh27603  * ppm_convert - convert a #define symbol to its integer value,
10215cff7825Smh27603  * only the #defines for ppm_dc.cmd and ppm_dc.method fields in
10225cff7825Smh27603  * ppmvar.h file are recognized.
10235cff7825Smh27603  */
10245cff7825Smh27603 struct ppm_confdefs {
10255cff7825Smh27603 	char	*sym;
10265cff7825Smh27603 	int	val;
10275cff7825Smh27603 } ppm_confdefs_table[] = {
10282df1fe9cSrandyf 	"ENTER_S3", PPMDC_ENTER_S3,
10292df1fe9cSrandyf 	"EXIT_S3", PPMDC_EXIT_S3,
10305cff7825Smh27603 	"CPU_NEXT", PPMDC_CPU_NEXT,
10315cff7825Smh27603 	"PRE_CHNG", PPMDC_PRE_CHNG,
10325cff7825Smh27603 	"CPU_GO", PPMDC_CPU_GO,
10335cff7825Smh27603 	"POST_CHNG", PPMDC_POST_CHNG,
10345cff7825Smh27603 	"FET_ON", PPMDC_FET_ON,
10355cff7825Smh27603 	"FET_OFF", PPMDC_FET_OFF,
10365cff7825Smh27603 	"CLK_OFF", PPMDC_CLK_OFF,
10375cff7825Smh27603 	"CLK_ON", PPMDC_CLK_ON,
10385cff7825Smh27603 	"LED_ON", PPMDC_LED_ON,
10395cff7825Smh27603 	"LED_OFF", PPMDC_LED_OFF,
10405cff7825Smh27603 	"KIO", PPMDC_KIO,
10415cff7825Smh27603 	"VCORE", PPMDC_VCORE,
10422df1fe9cSrandyf #ifdef sun4u
10435cff7825Smh27603 	"I2CKIO", PPMDC_I2CKIO,
10442df1fe9cSrandyf #endif
10455cff7825Smh27603 	"CPUSPEEDKIO", PPMDC_CPUSPEEDKIO,
10465cff7825Smh27603 	"PRE_PWR_OFF", PPMDC_PRE_PWR_OFF,
10475cff7825Smh27603 	"PRE_PWR_ON", PPMDC_PRE_PWR_ON,
10485cff7825Smh27603 	"POST_PWR_ON", PPMDC_POST_PWR_ON,
10495cff7825Smh27603 	"PWR_OFF", PPMDC_PWR_OFF,
10505cff7825Smh27603 	"PWR_ON", PPMDC_PWR_ON,
10515cff7825Smh27603 	"RESET_OFF", PPMDC_RESET_OFF,
10525cff7825Smh27603 	"RESET_ON", PPMDC_RESET_ON,
10535cff7825Smh27603 	NULL
10545cff7825Smh27603 };
10555cff7825Smh27603 
10565cff7825Smh27603 
10575cff7825Smh27603 /*
10585cff7825Smh27603  * convert a #define'd symbol to its integer value where
10595cff7825Smh27603  * input "symbol" is expected to be in form of "SYMBOL=value"
10605cff7825Smh27603  */
10615cff7825Smh27603 int
10625cff7825Smh27603 ppm_convert(char *symbol, uint_t *val)
10635cff7825Smh27603 {
10645cff7825Smh27603 	char *s;
10655cff7825Smh27603 	struct ppm_confdefs *pcfp;
10665cff7825Smh27603 
10675cff7825Smh27603 	if ((s = strchr(symbol, '=')) == NULL) {
10685cff7825Smh27603 		cmn_err(CE_WARN, "ppm_convert: token \"%s\" syntax error in "
1069*c3a64150SMargot Miller 		    "ppm.conf file", symbol);
10705cff7825Smh27603 		return (*val = (uint_t)-1);
10715cff7825Smh27603 	}
10725cff7825Smh27603 	s++;
10735cff7825Smh27603 
10745cff7825Smh27603 	for (pcfp = ppm_confdefs_table; (pcfp->sym != NULL); pcfp++) {
10755cff7825Smh27603 		if (strcmp(s, pcfp->sym) == 0)
10765cff7825Smh27603 			return (*val = pcfp->val);
10775cff7825Smh27603 	}
10785cff7825Smh27603 
10795cff7825Smh27603 	cmn_err(CE_WARN, "ppm_convert: Unrecognizable token \"%s\" "
1080*c3a64150SMargot Miller 	    "in ppm.conf file", symbol);
10815cff7825Smh27603 	return (*val = (uint_t)-1);
10825cff7825Smh27603 }
10835cff7825Smh27603 
10845cff7825Smh27603 
10855cff7825Smh27603 /*
10865cff7825Smh27603  * parse a domain control property string into data structure struct ppm_dc
10875cff7825Smh27603  */
10885cff7825Smh27603 int
10895cff7825Smh27603 ppm_parse_dc(char **dc_namep, ppm_dc_t *dc)
10905cff7825Smh27603 {
10915cff7825Smh27603 	char	*str = "ppm_parse_dc";
10925cff7825Smh27603 	char	*line;
10935cff7825Smh27603 	char	*f, *b;
10945cff7825Smh27603 	char    **dclist;	/* list of ppm_dc_t fields */
10955cff7825Smh27603 	int	count;		/* the # of '=' indicates the # of items */
10965cff7825Smh27603 	size_t	len;		/* length of line being parsed */
10975cff7825Smh27603 	boolean_t done;
10985cff7825Smh27603 	int	i;
10995cff7825Smh27603 	int	err;
11005cff7825Smh27603 
11015cff7825Smh27603 	len = strlen(*dc_namep);
11025cff7825Smh27603 	line = kmem_alloc(len + 1, KM_SLEEP);
11035cff7825Smh27603 	(void) strcpy(line, *dc_namep);
11045cff7825Smh27603 
11055cff7825Smh27603 	count = ppm_count_char(line, '=');
11065cff7825Smh27603 	ASSERT((count - ppm_count_char(line, ' ')) == 1);
11075cff7825Smh27603 
11085cff7825Smh27603 	dclist = (char **)
11095cff7825Smh27603 	    kmem_zalloc((sizeof (char *) * (count + 1)), KM_SLEEP);
11105cff7825Smh27603 	for (i = 0, f = b = line, done = B_FALSE; !done; i++, f = ++b) {
11115cff7825Smh27603 		while (*b != ' ' && *b != 0)
11125cff7825Smh27603 			b++;
11135cff7825Smh27603 		if (*b == 0)
11145cff7825Smh27603 			done = B_TRUE;
11155cff7825Smh27603 		else
11165cff7825Smh27603 			*b = 0;
11175cff7825Smh27603 		dclist[i] = f;
11185cff7825Smh27603 	}
11195cff7825Smh27603 
11205cff7825Smh27603 	for (i = 0; i < count; i++) {
11215cff7825Smh27603 		if (strstr(dclist[i], "cmd=")) {
11225cff7825Smh27603 			err = ppm_convert(dclist[i], &dc->cmd);
11235cff7825Smh27603 			if (err == -1)
11245cff7825Smh27603 				return (err);
11255cff7825Smh27603 			continue;
11265cff7825Smh27603 		}
11275cff7825Smh27603 		if ((f = strstr(dclist[i], "path=")) != NULL) {
11285cff7825Smh27603 			f += strlen("path=");
11295cff7825Smh27603 			dc->path = kmem_zalloc((strlen(f) + 1), KM_SLEEP);
11305cff7825Smh27603 			(void) strcpy(dc->path, f);
11315cff7825Smh27603 			continue;
11325cff7825Smh27603 		}
11335cff7825Smh27603 		if (strstr(dclist[i], "method=")) {
11345cff7825Smh27603 			err = ppm_convert(dclist[i], &dc->method);
11355cff7825Smh27603 			if (err == -1)
11365cff7825Smh27603 				return (err);
11375cff7825Smh27603 			continue;
11385cff7825Smh27603 		}
11395cff7825Smh27603 		if (strstr(dclist[i], "iowr=")) {
11405cff7825Smh27603 			(void) ppm_stoi(dclist[i], &dc->m_un.kio.iowr);
11415cff7825Smh27603 			continue;
11425cff7825Smh27603 		}
11435cff7825Smh27603 		if (strstr(dclist[i], "iord=")) {
11445cff7825Smh27603 			(void) ppm_stoi(dclist[i], &dc->m_un.kio.iord);
11455cff7825Smh27603 			continue;
11465cff7825Smh27603 		}
11475cff7825Smh27603 		if (strstr(dclist[i], "val=")) {
11485cff7825Smh27603 			(void) ppm_stoi(dclist[i], &dc->m_un.kio.val);
11495cff7825Smh27603 			continue;
11505cff7825Smh27603 		}
11515cff7825Smh27603 		if (strstr(dclist[i], "speeds=")) {
11525cff7825Smh27603 			ASSERT(dc->method == PPMDC_CPUSPEEDKIO);
11535cff7825Smh27603 			(void) ppm_stoi(dclist[i], &dc->m_un.cpu.speeds);
11545cff7825Smh27603 			continue;
11555cff7825Smh27603 		}
11562df1fe9cSrandyf #ifdef sun4u
11575cff7825Smh27603 		if (strstr(dclist[i], "mask=")) {
11585cff7825Smh27603 			(void) ppm_stoi(dclist[i], &dc->m_un.i2c.mask);
11595cff7825Smh27603 			continue;
11605cff7825Smh27603 		}
11612df1fe9cSrandyf #endif
11625cff7825Smh27603 		/* This must be before the if statement for delay */
11635cff7825Smh27603 		if (strstr(dclist[i], "post_delay=")) {
11642df1fe9cSrandyf #ifdef sun4u
11655cff7825Smh27603 			ASSERT(dc->method == PPMDC_KIO ||
11665cff7825Smh27603 			    dc->method == PPMDC_I2CKIO);
11672df1fe9cSrandyf #else
11682df1fe9cSrandyf 			ASSERT(dc->method == PPMDC_KIO);
11692df1fe9cSrandyf #endif
11705cff7825Smh27603 			/*
11715cff7825Smh27603 			 * all delays are uint_t type instead of clock_t.
11725cff7825Smh27603 			 * If the delay is too long, it might get truncated.
11735cff7825Smh27603 			 * But, we don't expect delay to be too long.
11745cff7825Smh27603 			 */
11755cff7825Smh27603 			switch (dc->method) {
11765cff7825Smh27603 			case PPMDC_KIO:
11775cff7825Smh27603 				(void) ppm_stoi(dclist[i],
11785cff7825Smh27603 				    &dc->m_un.kio.post_delay);
11795cff7825Smh27603 				break;
11805cff7825Smh27603 
11812df1fe9cSrandyf #ifdef sun4u
11825cff7825Smh27603 			case PPMDC_I2CKIO:
11835cff7825Smh27603 				(void) ppm_stoi(dclist[i],
11845cff7825Smh27603 				    &dc->m_un.i2c.post_delay);
11855cff7825Smh27603 				break;
11862df1fe9cSrandyf #endif
11875cff7825Smh27603 
11885cff7825Smh27603 			default:
11895cff7825Smh27603 				break;
11905cff7825Smh27603 			}
11915cff7825Smh27603 			continue;
11925cff7825Smh27603 		}
11935cff7825Smh27603 		if (strstr(dclist[i], "delay=")) {
11942df1fe9cSrandyf #ifdef sun4u
11955cff7825Smh27603 			ASSERT(dc->method == PPMDC_VCORE ||
11965cff7825Smh27603 			    dc->method == PPMDC_KIO ||
11975cff7825Smh27603 			    dc->method == PPMDC_I2CKIO);
11982df1fe9cSrandyf #else
11992df1fe9cSrandyf 			ASSERT(dc->method == PPMDC_VCORE ||
12002df1fe9cSrandyf 			    dc->method == PPMDC_KIO);
12012df1fe9cSrandyf #endif
12025cff7825Smh27603 
12035cff7825Smh27603 			/*
12045cff7825Smh27603 			 * all delays are uint_t type instead of clock_t.
12055cff7825Smh27603 			 * If the delay is too long, it might get truncated.
12065cff7825Smh27603 			 * But, we don't expect delay to be too long.
12075cff7825Smh27603 			 */
12085cff7825Smh27603 
12095cff7825Smh27603 			switch (dc->method) {
12105cff7825Smh27603 			case PPMDC_KIO:
12115cff7825Smh27603 				(void) ppm_stoi(dclist[i], &dc->m_un.kio.delay);
12125cff7825Smh27603 				break;
12135cff7825Smh27603 
12142df1fe9cSrandyf #ifdef sun4u
12155cff7825Smh27603 			case PPMDC_I2CKIO:
12165cff7825Smh27603 				(void) ppm_stoi(dclist[i], &dc->m_un.i2c.delay);
12175cff7825Smh27603 				break;
12182df1fe9cSrandyf #endif
12195cff7825Smh27603 
12205cff7825Smh27603 			case PPMDC_VCORE:
12215cff7825Smh27603 				(void) ppm_stoi(dclist[i], &dc->m_un.cpu.delay);
12225cff7825Smh27603 				break;
12235cff7825Smh27603 
12245cff7825Smh27603 			default:
12255cff7825Smh27603 				break;
12265cff7825Smh27603 			}
12275cff7825Smh27603 			continue;
12285cff7825Smh27603 		}
12295cff7825Smh27603 
12305cff7825Smh27603 		/* we encounted unrecognized field, flag error */
12315cff7825Smh27603 		cmn_err(CE_WARN, "%s: Unrecognized token \"%s\" in ppm.conf "
1232*c3a64150SMargot Miller 		    "file!", str, dclist[i]);
12335cff7825Smh27603 		return (-1);
12345cff7825Smh27603 	}
12355cff7825Smh27603 
12365cff7825Smh27603 	kmem_free(dclist, sizeof (char *) * (count + 1));
12375cff7825Smh27603 	kmem_free(line, len + 1);
12385cff7825Smh27603 
12395cff7825Smh27603 	return (DDI_SUCCESS);
12405cff7825Smh27603 }
12415cff7825Smh27603 
12425cff7825Smh27603 
12435cff7825Smh27603 /*
12445cff7825Smh27603  * search for domain control handle for a claimed device coupled with a
12455cff7825Smh27603  * domain control command.  NULL device may indicate LED domain.
12465cff7825Smh27603  */
12475cff7825Smh27603 ppm_dc_t *
12485cff7825Smh27603 ppm_lookup_dc(ppm_domain_t *domp, int cmd)
12495cff7825Smh27603 {
12505cff7825Smh27603 #ifdef	DEBUG
12515cff7825Smh27603 	char *str = "ppm_lookup_dc";
12525cff7825Smh27603 #endif
12535cff7825Smh27603 	ppm_dc_t	*dc;
12545cff7825Smh27603 
12555cff7825Smh27603 	/*
12565cff7825Smh27603 	 *  For convenience, we accept 'domp' as NULL for searching
12575cff7825Smh27603 	 *  LED domain control operation.
12585cff7825Smh27603 	 */
12595cff7825Smh27603 	if ((cmd == PPMDC_LED_OFF) || (cmd == PPMDC_LED_ON)) {
12605cff7825Smh27603 		for (domp = ppm_domain_p; domp; domp = domp->next)
12615cff7825Smh27603 			if (domp->model == PPMD_LED)
12625cff7825Smh27603 				break;
12635cff7825Smh27603 		if (!domp || !domp->dc || !domp->dc->lh || !domp->dc->next) {
12645cff7825Smh27603 			PPMD(D_LED, ("\tinsufficient led domain control "
12655cff7825Smh27603 			    "information.\n"))
12665cff7825Smh27603 			return (NULL);
12675cff7825Smh27603 		}
12685cff7825Smh27603 		if (cmd == domp->dc->cmd)
12695cff7825Smh27603 			return (domp->dc);
12705cff7825Smh27603 		else
12715cff7825Smh27603 			return (domp->dc->next);
12725cff7825Smh27603 	}
12735cff7825Smh27603 
12745cff7825Smh27603 
12755cff7825Smh27603 	/*
12765cff7825Smh27603 	 * for the rest of ppm domains, lookup ppm_dc starting from domp
12775cff7825Smh27603 	 */
12785cff7825Smh27603 	ASSERT(domp != NULL);
12795cff7825Smh27603 	switch (cmd) {
12805cff7825Smh27603 	case PPMDC_CPU_NEXT:
12815cff7825Smh27603 	case PPMDC_PRE_CHNG:
12825cff7825Smh27603 	case PPMDC_CPU_GO:
12835cff7825Smh27603 	case PPMDC_POST_CHNG:
12845cff7825Smh27603 	case PPMDC_FET_OFF:
12855cff7825Smh27603 	case PPMDC_FET_ON:
12865cff7825Smh27603 	case PPMDC_CLK_OFF:
12875cff7825Smh27603 	case PPMDC_CLK_ON:
12885cff7825Smh27603 	case PPMDC_PRE_PWR_OFF:
12895cff7825Smh27603 	case PPMDC_PRE_PWR_ON:
12905cff7825Smh27603 	case PPMDC_POST_PWR_ON:
12915cff7825Smh27603 	case PPMDC_PWR_OFF:
12925cff7825Smh27603 	case PPMDC_PWR_ON:
12935cff7825Smh27603 	case PPMDC_RESET_OFF:
12945cff7825Smh27603 	case PPMDC_RESET_ON:
12952df1fe9cSrandyf 	case PPMDC_ENTER_S3:
12962df1fe9cSrandyf 	case PPMDC_EXIT_S3:
12975cff7825Smh27603 		break;
12985cff7825Smh27603 	default:
12995cff7825Smh27603 		PPMD(D_PPMDC, ("%s: cmd(%d) unrecognized\n", str, cmd))
13005cff7825Smh27603 		return (NULL);
13015cff7825Smh27603 	}
13025cff7825Smh27603 
13035cff7825Smh27603 	for (dc = domp->dc; dc; dc = dc->next) {
13042df1fe9cSrandyf 		if (dc->cmd == cmd) {
13055cff7825Smh27603 			return (dc);
13065cff7825Smh27603 		}
13072df1fe9cSrandyf 	}
13082df1fe9cSrandyf 
13095cff7825Smh27603 	return (NULL);
13105cff7825Smh27603 }
13115cff7825Smh27603 
13125cff7825Smh27603 #include <sys/esunddi.h>
13135cff7825Smh27603 
13145cff7825Smh27603 ppm_domain_t *
13155cff7825Smh27603 ppm_get_domain_by_dev(const char *p)
13165cff7825Smh27603 {
13175cff7825Smh27603 	dev_info_t *dip;
13185cff7825Smh27603 	ppm_domain_t	*domp;
13195cff7825Smh27603 	ppm_dev_t	*pdev;
13205cff7825Smh27603 	boolean_t	found = B_FALSE;
13215cff7825Smh27603 
13225cff7825Smh27603 	if ((dip = e_ddi_hold_devi_by_path((char *)p, 0)) == NULL)
13235cff7825Smh27603 		return (NULL);
13245cff7825Smh27603 
13255cff7825Smh27603 	for (domp = ppm_domain_p; domp; domp = domp->next) {
13265cff7825Smh27603 		for (pdev = domp->devlist; pdev; pdev = pdev->next) {
13275cff7825Smh27603 			if (pdev->dip == dip) {
13285cff7825Smh27603 				found = B_TRUE;
13295cff7825Smh27603 				break;
13305cff7825Smh27603 			}
13315cff7825Smh27603 		}
13325cff7825Smh27603 		if (found)
13335cff7825Smh27603 			break;
13345cff7825Smh27603 	}
13355cff7825Smh27603 	ddi_release_devi(dip);
13365cff7825Smh27603 	return (domp);
13375cff7825Smh27603 }
13385cff7825Smh27603 
13395cff7825Smh27603 
13405cff7825Smh27603 #ifdef DEBUG
13415cff7825Smh27603 #define	FLINTSTR(flags, sym) { flags, sym, #sym }
13425cff7825Smh27603 #define	PMR_UNKNOWN -1
13435cff7825Smh27603 /*
13445cff7825Smh27603  * convert a ctlop integer to a char string.  this helps printing
13455cff7825Smh27603  * meaningful info when cltops are received from the pm framework.
13465cff7825Smh27603  * since some ctlops are so frequent, we use mask to limit output:
13475cff7825Smh27603  * a valid string is returned when ctlop is found and when
13485cff7825Smh27603  * (cmd.flags & mask) is true; otherwise NULL is returned.
13495cff7825Smh27603  */
13505cff7825Smh27603 char *
13515cff7825Smh27603 ppm_get_ctlstr(int ctlop, uint_t mask)
13525cff7825Smh27603 {
13535cff7825Smh27603 	struct ctlop_cmd {
13545cff7825Smh27603 		uint_t flags;
13555cff7825Smh27603 		int ctlop;
13565cff7825Smh27603 		char *str;
13575cff7825Smh27603 	};
13585cff7825Smh27603 
13595cff7825Smh27603 	struct ctlop_cmd *ccp;
13605cff7825Smh27603 	static struct ctlop_cmd cmds[] = {
13615cff7825Smh27603 		FLINTSTR(D_SETPWR, PMR_SET_POWER),
13625cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_SUSPEND),
13635cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_RESUME),
13645cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_PRE_SET_POWER),
13655cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_POST_SET_POWER),
13665cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_PPM_SET_POWER),
13675cff7825Smh27603 		FLINTSTR(0, PMR_PPM_ATTACH),
13685cff7825Smh27603 		FLINTSTR(0, PMR_PPM_DETACH),
13695cff7825Smh27603 		FLINTSTR(D_CTLOPS1, PMR_PPM_POWER_CHANGE_NOTIFY),
13705cff7825Smh27603 		FLINTSTR(D_CTLOPS1, PMR_REPORT_PMCAP),
13715cff7825Smh27603 		FLINTSTR(D_CTLOPS1, PMR_CHANGED_POWER),
13725cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_PPM_INIT_CHILD),
13735cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_PPM_UNINIT_CHILD),
13745cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_PROBE),
13755cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_PPM_POST_PROBE),
13765cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_ATTACH),
13775cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_PPM_POST_ATTACH),
13785cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_DETACH),
13795cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_PPM_POST_DETACH),
13805cff7825Smh27603 		FLINTSTR(D_CTLOPS1, PMR_PPM_UNMANAGE),
13815cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_RESUME),
13825cff7825Smh27603 		FLINTSTR(D_CTLOPS1, PMR_PPM_ALL_LOWEST),
13835cff7825Smh27603 		FLINTSTR(D_LOCKS, PMR_PPM_LOCK_POWER),
13845cff7825Smh27603 		FLINTSTR(D_LOCKS, PMR_PPM_UNLOCK_POWER),
13855cff7825Smh27603 		FLINTSTR(D_LOCKS, PMR_PPM_TRY_LOCK_POWER),
13865cff7825Smh27603 		FLINTSTR(D_LOCKS, PMR_PPM_POWER_LOCK_OWNER),
13872df1fe9cSrandyf 		FLINTSTR(D_CTLOPS1 | D_CTLOPS2, PMR_PPM_ENTER_SX),
13885cff7825Smh27603 		FLINTSTR(D_CTLOPS1 | D_CTLOPS2, PMR_UNKNOWN),
13895cff7825Smh27603 	};
13905cff7825Smh27603 
13915cff7825Smh27603 	for (ccp = cmds; ccp->ctlop != PMR_UNKNOWN; ccp++)
13925cff7825Smh27603 		if (ctlop == ccp->ctlop)
13935cff7825Smh27603 			break;
13945cff7825Smh27603 
13955cff7825Smh27603 	if (ccp->flags & mask)
13965cff7825Smh27603 		return (ccp->str);
13975cff7825Smh27603 	return (NULL);
13985cff7825Smh27603 }
13995cff7825Smh27603 
14005cff7825Smh27603 void
14015cff7825Smh27603 ppm_print_dc(ppm_dc_t *dc)
14025cff7825Smh27603 {
14035cff7825Smh27603 	ppm_dc_t	*d = dc;
14045cff7825Smh27603 
14055cff7825Smh27603 	PPMD(D_PPMDC, ("\nAdds ppm_dc: path(%s),\n     cmd(%x), "
14065cff7825Smh27603 	    "method(%x), ", d->path, d->cmd, d->method))
14072df1fe9cSrandyf 	if (d->method == PPMDC_KIO) {
14082df1fe9cSrandyf 		PPMD(D_PPMDC, ("kio.iowr(%x), kio.val(0x%X)",
14092df1fe9cSrandyf 		    d->m_un.kio.iowr, d->m_un.kio.val))
14102df1fe9cSrandyf #ifdef sun4u
14112df1fe9cSrandyf 	} else if (d->method == PPMDC_I2CKIO) {
14125cff7825Smh27603 		PPMD(D_PPMDC, ("i2c.iowr(%x), i2c.val(0x%X), "
14135cff7825Smh27603 		    "i2c.mask(0x%X)", d->m_un.i2c.iowr,
14145cff7825Smh27603 		    d->m_un.i2c.val,  d->m_un.i2c.mask))
14152df1fe9cSrandyf #endif
14165cff7825Smh27603 	} else if (d->method == PPMDC_VCORE) {
14175cff7825Smh27603 		PPMD(D_PPMDC, ("cpu: .iord(%x), .iowr(%x), .val(0x%X), "
14185cff7825Smh27603 		    ".delay(0x%x)",
14195cff7825Smh27603 		    d->m_un.cpu.iord, d->m_un.cpu.iowr, d->m_un.cpu.val,
14205cff7825Smh27603 		    d->m_un.cpu.delay))
14215cff7825Smh27603 	} else if (d->method == PPMDC_CPUSPEEDKIO) {
14225cff7825Smh27603 		PPMD(D_PPMDC, ("cpu.iowr(%x), cpu.speeds(0x%X)",
14235cff7825Smh27603 		    d->m_un.cpu.iowr, d->m_un.cpu.speeds))
14245cff7825Smh27603 	}
14255cff7825Smh27603 	PPMD(D_PPMDC, ("\n"))
14265cff7825Smh27603 }
14275cff7825Smh27603 #endif	/* DEBUG */
1428