14667Smh27603 /*
24667Smh27603 * CDDL HEADER START
34667Smh27603 *
44667Smh27603 * The contents of this file are subject to the terms of the
54667Smh27603 * Common Development and Distribution License (the "License").
64667Smh27603 * You may not use this file except in compliance with the License.
74667Smh27603 *
84667Smh27603 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94667Smh27603 * or http://www.opensolaris.org/os/licensing.
104667Smh27603 * See the License for the specific language governing permissions
114667Smh27603 * and limitations under the License.
124667Smh27603 *
134667Smh27603 * When distributing Covered Code, include this CDDL HEADER in each
144667Smh27603 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154667Smh27603 * If applicable, add the following below this CDDL HEADER, with the
164667Smh27603 * fields enclosed by brackets "[]" replaced with your own identifying
174667Smh27603 * information: Portions Copyright [yyyy] [name of copyright owner]
184667Smh27603 *
194667Smh27603 * CDDL HEADER END
204667Smh27603 */
214667Smh27603 /*
22*10846SMargot.Miller@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
234667Smh27603 * Use is subject to license terms.
244667Smh27603 */
254667Smh27603
264667Smh27603 /*
274667Smh27603 * ppm driver subroutines
284667Smh27603 */
294667Smh27603
304667Smh27603 #include <sys/open.h>
314667Smh27603 #include <sys/file.h>
324667Smh27603 #include <sys/conf.h>
334667Smh27603 #include <sys/epm.h>
344667Smh27603 #include <sys/sunldi.h>
354667Smh27603 #include <sys/ppmvar.h>
364667Smh27603 #include <sys/ppmio.h>
374667Smh27603 #include <sys/promif.h>
384667Smh27603 #include <sys/ddi_impldefs.h>
394667Smh27603 #include <sys/ddi.h>
404667Smh27603 #include <sys/sunddi.h>
414667Smh27603 /*
424667Smh27603 * Append address to the device path, if it is set. Routine
434667Smh27603 * ddi_pathname does not look for device address if the node is in
444667Smh27603 * DS_INITIALIZED state.
454667Smh27603 */
464667Smh27603 #define PPM_GET_PATHNAME(dip, path) \
474667Smh27603 (void) ddi_pathname((dip), (path)); \
484667Smh27603 if ((i_ddi_node_state((dip)) < DS_INITIALIZED) && \
494667Smh27603 (ddi_get_name_addr((dip)) != NULL)) { \
504667Smh27603 (void) strcat((path), "@"); \
514667Smh27603 (void) strcat((path), ddi_get_name_addr((dip)));\
524667Smh27603 }
534667Smh27603
544667Smh27603 int ppm_parse_dc(char **, ppm_dc_t *);
554667Smh27603 int ppm_match_devs(char *, ppm_db_t *);
564667Smh27603 ppm_db_t *ppm_parse_pattern(struct ppm_db **, char *);
574667Smh27603 int ppm_count_char(char *, char);
584667Smh27603 int ppm_stoi(char *, uint_t *);
594667Smh27603 int ppm_convert(char *, uint_t *);
604667Smh27603 void ppm_prop_free(struct ppm_cdata **);
614667Smh27603
624667Smh27603 /*
634667Smh27603 * lookup string property from configuration file ppm.conf
644667Smh27603 */
654667Smh27603 static int
ppm_get_confdata(struct ppm_cdata ** cdp,dev_info_t * dip)664667Smh27603 ppm_get_confdata(struct ppm_cdata **cdp, dev_info_t *dip)
674667Smh27603 {
684667Smh27603 #ifdef DEBUG
694667Smh27603 char *str = "ppm_get_confdata";
704667Smh27603 #endif
714667Smh27603 struct ppm_cdata *cinfo;
724667Smh27603 int err;
734667Smh27603
744667Smh27603 for (; (cinfo = *cdp) != NULL; cdp++) {
754667Smh27603 err = ddi_prop_lookup_string_array(
764667Smh27603 DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
774667Smh27603 cinfo->name, &cinfo->strings, &cinfo->cnt);
784667Smh27603 if (err != DDI_PROP_SUCCESS) {
794667Smh27603 PPMD(D_ERROR, ("%s: no %s found, err(%d)\n",
804667Smh27603 str, cinfo->name, err))
814667Smh27603 break;
824667Smh27603 }
834667Smh27603 }
844667Smh27603 return (err);
854667Smh27603 }
864667Smh27603
874667Smh27603 void
ppm_prop_free(struct ppm_cdata ** cdp)884667Smh27603 ppm_prop_free(struct ppm_cdata **cdp)
894667Smh27603 {
904667Smh27603 if (cdp) {
914667Smh27603 for (; *cdp; cdp++) {
924667Smh27603 if ((*cdp)->name) {
934667Smh27603 kmem_free((*cdp)->name,
944667Smh27603 strlen((*cdp)->name) + 1);
954667Smh27603 (*cdp)->name = NULL;
964667Smh27603 }
974667Smh27603 if ((*cdp)->strings) {
984667Smh27603 ddi_prop_free((*cdp)->strings);
994667Smh27603 (*cdp)->strings = NULL;
1004667Smh27603 }
1014667Smh27603 }
1024667Smh27603 }
1034667Smh27603 }
1044667Smh27603
1054667Smh27603
1064667Smh27603 /*
1074667Smh27603 * free ddi prop strings. Under error condition, free ppm_db_t lists as well.
1084667Smh27603 */
1094667Smh27603 static int
ppm_attach_err(struct ppm_cdata ** cdp,int err)1104667Smh27603 ppm_attach_err(struct ppm_cdata **cdp, int err)
1114667Smh27603 {
1124667Smh27603 ppm_domain_t *domp;
1134667Smh27603 ppm_db_t *db, *tmp;
1144667Smh27603
1154667Smh27603 ppm_prop_free(cdp);
1164667Smh27603 if (err != DDI_SUCCESS) {
1174667Smh27603 for (domp = ppm_domain_p; domp; domp = domp->next) {
1184667Smh27603 for (db = domp->conflist; (tmp = db) != NULL; ) {
1194667Smh27603 db = db->next;
1204667Smh27603 kmem_free(tmp->name, strlen(tmp->name) + 1);
1214667Smh27603 kmem_free(tmp, sizeof (*tmp));
1224667Smh27603 }
1234667Smh27603 domp->conflist = NULL;
1244667Smh27603 }
1254667Smh27603 err = DDI_FAILURE;
1264667Smh27603 }
1274667Smh27603
1284667Smh27603 return (err);
1294667Smh27603 }
1304667Smh27603
1314667Smh27603
1324667Smh27603 ppm_domain_t *
ppm_lookup_domain(char * dname)1334667Smh27603 ppm_lookup_domain(char *dname)
1344667Smh27603 {
1354667Smh27603 ppm_domain_t *domp;
1364667Smh27603
1374667Smh27603 for (domp = ppm_domain_p; domp; domp = domp->next) {
1384667Smh27603 if (strcmp(dname, domp->name) == 0)
1394667Smh27603 break;
1404667Smh27603 }
1414667Smh27603 return (domp);
1424667Smh27603 }
1434667Smh27603
1444667Smh27603
1454667Smh27603 /*
1464667Smh27603 * for the purpose of optimizing we search for identical dc->path
1474667Smh27603 * that has been opened per previous visit here. If search results
1484667Smh27603 * in a hit, copy the device handle, else open the device.
1494667Smh27603 */
1504667Smh27603 ppm_dc_t *
ppm_lookup_hndl(int model,ppm_dc_t * key_dc)1514667Smh27603 ppm_lookup_hndl(int model, ppm_dc_t *key_dc)
1524667Smh27603 {
1534667Smh27603 #ifdef DEBUG
1544667Smh27603 char *str = "ppm_lookup_hndl";
1554667Smh27603 #endif
1564667Smh27603 char *key_path = key_dc->path;
1574667Smh27603 ppm_domain_t *domp;
1584667Smh27603 ppm_dc_t *dc;
1594667Smh27603
1604667Smh27603 /* search domain by domain.model */
1614667Smh27603 for (domp = ppm_domain_p; domp; domp = domp->next) {
1624667Smh27603 if (domp->model == model)
1634667Smh27603 break;
1644667Smh27603 }
1654667Smh27603
1664667Smh27603 /* lookup hndl from same domain model */
1674667Smh27603 if (domp && PPM_DOMAIN_UP(domp)) {
1684667Smh27603 for (dc = domp->dc; dc; dc = dc->next) {
1694667Smh27603 if ((strcmp(dc->path, key_path) == 0) &&
1704667Smh27603 (dc->lh != NULL)) {
1714667Smh27603 PPMD(D_PPMDC, ("%s: Hit(dc_path:%s) from SAME "
1724667Smh27603 "domain %s.\n", str, key_path, domp->name))
1734667Smh27603 key_dc->lh = dc->lh;
1744667Smh27603 return (key_dc);
1754667Smh27603 }
1764667Smh27603 }
1774667Smh27603 }
1784667Smh27603
1794667Smh27603 /* otherwise, check other domains */
1804667Smh27603 for (domp = ppm_domain_p;
1814667Smh27603 domp && (domp->model != model); domp = domp->next) {
1824667Smh27603 if (PPM_DOMAIN_UP(domp)) {
1834667Smh27603 for (dc = domp->dc; dc; dc = dc->next) {
1844667Smh27603 if ((strcmp(dc->path, key_path) == 0) &&
1854667Smh27603 (dc->lh != NULL)) {
1864667Smh27603 PPMD(D_PPMDC, ("%s: Hit(dc_path:%s) "
1874667Smh27603 "from domain %s\n",
1884667Smh27603 str, key_path, domp->name))
1894667Smh27603 key_dc->lh = dc->lh;
1904667Smh27603 return (key_dc);
1914667Smh27603 }
1924667Smh27603 }
1934667Smh27603 }
1944667Smh27603 }
1954667Smh27603
1964667Smh27603 PPMD(D_PPMDC, ("%s: Miss(dc_path:%s)\n", str, key_path))
1974667Smh27603 return (NULL);
1984667Smh27603 }
1994667Smh27603
2004667Smh27603
2014667Smh27603 #define PPM_DOMAIN_PROP "ppm-domains"
2024667Smh27603 #define PPM_DEV_PROP_SUFFIX "-devices"
2034667Smh27603 #define PPM_MODEL_PROP_SUFFIX "-model"
2044667Smh27603 #define PPM_PROPNAME_PROP_SUFFIX "-propname"
2054667Smh27603 #define PPM_CTRL_PROP_SUFFIX "-control"
2064667Smh27603
2074667Smh27603 struct ppm_domit ppm_domit_data[] = {
2085295Srandyf "SX", PPMD_SX, 0, PPMD_ON,
2094667Smh27603 "CPU", PPMD_CPU, PPMD_LOCK_ALL, PPMD_ON,
2104667Smh27603 "FET", PPMD_FET, PPMD_LOCK_ONE, PPMD_ON,
2114667Smh27603 "PCI", PPMD_PCI, PPMD_LOCK_ONE, PPMD_ON,
2124667Smh27603 "PCI_PROP", PPMD_PCI_PROP, PPMD_LOCK_ONE, PPMD_ON,
2134667Smh27603 "LED", PPMD_LED, 0, PPMD_ON,
2144667Smh27603 "PCIE", PPMD_PCIE, PPMD_LOCK_ONE, PPMD_ON,
2154667Smh27603 NULL
2164667Smh27603 };
2174667Smh27603
2184667Smh27603 /*
2194667Smh27603 * store up platform dependent information provided by ppm.conf file
2204667Smh27603 * into private data base
2214667Smh27603 */
2224667Smh27603 int
ppm_create_db(dev_info_t * dip)2234667Smh27603 ppm_create_db(dev_info_t *dip)
2244667Smh27603 {
2254667Smh27603 #ifdef DEBUG
2264667Smh27603 char *str = "ppm_create_db";
2274667Smh27603 #endif
2284667Smh27603 ppm_domain_t *domp;
2294667Smh27603 ppm_db_t *db;
2304667Smh27603 ppm_dc_t *dc;
2314667Smh27603 struct ppm_cdata domdata; /* hold "ppm-domains" property */
2324667Smh27603 struct ppm_cdata modeldata; /* hold "domain_xy-model" property */
2334667Smh27603 struct ppm_cdata propnamedata; /* hold "domain_xy-propname" property */
2344667Smh27603 struct ppm_cdata devdata; /* hold "domain_xy-devices" property */
2354667Smh27603 struct ppm_cdata dcdata; /* hold "domain_xy-control" property */
2364667Smh27603 struct ppm_cdata *cdata[2];
2374667Smh27603 char **dom_namep, **model_namep, **dev_namep, **dc_namep;
2384667Smh27603 struct ppm_domit *domit_p;
2394667Smh27603 int err;
2404667Smh27603
2414667Smh27603 /*
2424667Smh27603 * get "ppm-domains" property
2434667Smh27603 */
2444667Smh27603 bzero(&domdata, sizeof (domdata));
2454667Smh27603 domdata.name = kmem_zalloc(strlen(PPM_DOMAIN_PROP) + 1, KM_SLEEP);
2464667Smh27603 (void) strcpy(domdata.name, PPM_DOMAIN_PROP);
2474667Smh27603 cdata[0] = &domdata;
2484667Smh27603 cdata[1] = NULL;
2494667Smh27603 if (err = ppm_get_confdata(cdata, dip)) {
2504667Smh27603 PPMD(D_CREATEDB, ("%s: failed to get prop \"%s\"!\n",
2514667Smh27603 str, PPM_DOMAIN_PROP))
2524667Smh27603 return (ppm_attach_err(cdata, err));
2534667Smh27603 }
2544667Smh27603
2554667Smh27603 for (dom_namep = domdata.strings; *dom_namep; dom_namep++) {
2564667Smh27603 domp = kmem_zalloc(sizeof (*domp), KM_SLEEP);
2574667Smh27603 domp->name = kmem_zalloc(strlen(*dom_namep) + 1, KM_SLEEP);
2584667Smh27603 (void) strcpy(domp->name, *dom_namep);
2594667Smh27603 mutex_init(&domp->lock, NULL, MUTEX_DRIVER, NULL);
2604667Smh27603 if (ppm_domain_p == NULL)
2614667Smh27603 ppm_domain_p = domp;
2624667Smh27603 else {
2634667Smh27603 domp->next = ppm_domain_p;
2644667Smh27603 ppm_domain_p = domp;
2654667Smh27603 }
2664667Smh27603 }
2674667Smh27603 ppm_prop_free(cdata);
2684667Smh27603
2694667Smh27603 /*
2704667Smh27603 * more per domain property strings in ppm.conf file tell us
2714667Smh27603 * what the nature of domain, how to performe domain control, etc.
2724667Smh27603 * Even the property names of those per domain properties are
2734667Smh27603 * formed consisting its domain name string.
2744667Smh27603 * Here we walk through our domain list, and fullfill the details.
2754667Smh27603 */
2764667Smh27603 for (domp = ppm_domain_p; domp; domp = domp->next) {
2774667Smh27603 size_t plen;
2784667Smh27603
2794667Smh27603 /*
2804667Smh27603 * get "domain_xy-model" property
2814667Smh27603 */
2824667Smh27603 bzero(&modeldata, sizeof (modeldata));
2834667Smh27603 plen = strlen(domp->name) + strlen(PPM_MODEL_PROP_SUFFIX) + 1;
2844667Smh27603 modeldata.name = kmem_zalloc(plen, KM_SLEEP);
2854667Smh27603 (void) sprintf(modeldata.name, "%s%s",
2864667Smh27603 domp->name, PPM_MODEL_PROP_SUFFIX);
2874667Smh27603
2884667Smh27603 cdata[0] = &modeldata;
2894667Smh27603 cdata[1] = NULL;
2904667Smh27603 if (err = ppm_get_confdata(cdata, dip)) {
2914667Smh27603 PPMD(D_CREATEDB, ("%s: Can't read property %s!\n",
2924667Smh27603 str, modeldata.name))
2934667Smh27603 return (ppm_attach_err(cdata, err));
2944667Smh27603 }
2954667Smh27603
2964667Smh27603 model_namep = modeldata.strings;
2974667Smh27603 for (domit_p = ppm_domit_data; domit_p->name; domit_p++) {
2984667Smh27603 if (strcmp(domit_p->name, *model_namep) == 0) {
2994667Smh27603 domp->model = domit_p->model;
3004667Smh27603 domp->dflags = domit_p->dflags;
3014667Smh27603 domp->status = domit_p->status;
3024667Smh27603 break;
3034667Smh27603 }
3044667Smh27603 }
3054667Smh27603 ASSERT(domit_p);
3064667Smh27603
3074667Smh27603 ppm_prop_free(cdata);
3084667Smh27603
3094667Smh27603
3104667Smh27603 /* get "domain_xy-propname" property */
3114667Smh27603 bzero(&propnamedata, sizeof (propnamedata));
3124667Smh27603 plen = strlen(domp->name) +
3134667Smh27603 strlen(PPM_PROPNAME_PROP_SUFFIX) + 1;
3144667Smh27603 propnamedata.name = kmem_zalloc(plen, KM_SLEEP);
3154667Smh27603 (void) sprintf(propnamedata.name, "%s%s",
3164667Smh27603 domp->name, PPM_PROPNAME_PROP_SUFFIX);
3174667Smh27603
3184667Smh27603 cdata[0] = &propnamedata;
3194667Smh27603 cdata[1] = NULL;
3204667Smh27603 if (ppm_get_confdata(cdata, dip) == DDI_PROP_SUCCESS) {
3214667Smh27603 domp->propname = kmem_zalloc(
3224667Smh27603 (strlen(*propnamedata.strings) + 1), KM_SLEEP);
3234667Smh27603 (void) strcpy(domp->propname, *propnamedata.strings);
3244667Smh27603 PPMD(D_CREATEDB, ("%s: %s has property name: %s\n",
3254667Smh27603 str, domp->name, domp->propname))
3264667Smh27603 }
3274667Smh27603 ppm_prop_free(cdata);
3284667Smh27603
3294667Smh27603
3304667Smh27603 /* get "domain_xy-devices" property */
3314667Smh27603 bzero(&devdata, sizeof (devdata));
3324667Smh27603 plen = strlen(domp->name) + strlen(PPM_DEV_PROP_SUFFIX) + 1;
3334667Smh27603 devdata.name = kmem_zalloc(plen, KM_SLEEP);
3344667Smh27603 (void) sprintf(devdata.name, "%s%s",
3354667Smh27603 domp->name, PPM_DEV_PROP_SUFFIX);
3364667Smh27603
3374667Smh27603 cdata[0] = &devdata;
3384667Smh27603 cdata[1] = NULL;
3394667Smh27603 if (err = ppm_get_confdata(cdata, dip)) {
3404667Smh27603 PPMD(D_CREATEDB, ("%s: Can't read property %s!\n",
3414667Smh27603 str, devdata.name))
3424667Smh27603 return (ppm_attach_err(cdata, err));
3434667Smh27603 }
3444667Smh27603
3454667Smh27603 for (dev_namep = devdata.strings; *dev_namep; dev_namep++) {
3464667Smh27603 if (!ppm_parse_pattern(&db, *dev_namep))
3474667Smh27603 return (ppm_attach_err(cdata, err));
3484667Smh27603 db->next = domp->conflist;
3494667Smh27603 domp->conflist = db;
3504667Smh27603 PPMD(D_CREATEDB, ("%s: %s add pattern: %s \n",
3514667Smh27603 str, devdata.name, db->name))
3524667Smh27603 }
3534667Smh27603 PPMD(D_CREATEDB, ("\n"))
3544667Smh27603 ppm_prop_free(cdata);
3554667Smh27603
3564667Smh27603
3574667Smh27603 /* get "domain_xy-control" property */
3584667Smh27603 bzero(&dcdata, sizeof (dcdata));
3594667Smh27603 plen = strlen(domp->name) + strlen(PPM_CTRL_PROP_SUFFIX) + 1;
3604667Smh27603 dcdata.name = kmem_zalloc(plen, KM_SLEEP);
3614667Smh27603 (void) sprintf(dcdata.name, "%s%s",
3624667Smh27603 domp->name, PPM_CTRL_PROP_SUFFIX);
3634667Smh27603
3644667Smh27603 cdata[0] = &dcdata;
3654667Smh27603 cdata[1] = NULL;
3664667Smh27603 if (ppm_get_confdata(cdata, dip) == DDI_PROP_SUCCESS) {
3674667Smh27603 for (dc_namep = dcdata.strings; *dc_namep;
3684667Smh27603 dc_namep++) {
3694667Smh27603 dc = kmem_zalloc(sizeof (*dc), KM_SLEEP);
3704667Smh27603 dc->next = domp->dc;
3714667Smh27603 domp->dc = dc;
3724667Smh27603 err = ppm_parse_dc(dc_namep, domp->dc);
3734667Smh27603 if (err != DDI_SUCCESS)
3744667Smh27603 return (ppm_attach_err(cdata, err));
3754667Smh27603 }
3764667Smh27603 }
3774667Smh27603 ppm_prop_free(cdata);
3784667Smh27603 #ifdef DEBUG
3794667Smh27603 dc = domp->dc;
3804667Smh27603 while (dc) {
3814667Smh27603 ppm_print_dc(dc);
3824667Smh27603 dc = dc->next;
3834667Smh27603 }
3844667Smh27603 #endif
3854667Smh27603 }
3864667Smh27603
3874667Smh27603 return (DDI_SUCCESS);
3884667Smh27603 }
3894667Smh27603
3904667Smh27603
3914667Smh27603 /*
3924667Smh27603 * scan conf devices within each domain for a matching device name
3934667Smh27603 */
3944667Smh27603 ppm_domain_t *
ppm_lookup_dev(dev_info_t * dip)3954667Smh27603 ppm_lookup_dev(dev_info_t *dip)
3964667Smh27603 {
3974667Smh27603 char path[MAXNAMELEN];
3984667Smh27603 ppm_domain_t *domp;
3994667Smh27603 ppm_db_t *dbp;
40010394SMichael.Corcoran@Sun.COM #ifdef __x86
40110394SMichael.Corcoran@Sun.COM char *devtype = NULL;
40210394SMichael.Corcoran@Sun.COM #endif /* __x86 */
4034667Smh27603
4044667Smh27603 PPM_GET_PATHNAME(dip, path);
4054667Smh27603 for (domp = ppm_domain_p; domp; domp = domp->next) {
4065295Srandyf if (PPM_DOMAIN_UP(domp)) {
4074667Smh27603 for (dbp = domp->conflist; dbp; dbp = dbp->next) {
4085295Srandyf /*
4095295Srandyf * allow claiming root without knowing
4105295Srandyf * its full name
4115295Srandyf */
4125295Srandyf if (dip == ddi_root_node() &&
4135295Srandyf strcmp(dbp->name, "/") == 0)
4145295Srandyf return (domp);
41510394SMichael.Corcoran@Sun.COM
41610394SMichael.Corcoran@Sun.COM #ifdef __x86
41710394SMichael.Corcoran@Sun.COM /*
41810394SMichael.Corcoran@Sun.COM * Special rule to catch all CPU devices on x86.
41910394SMichael.Corcoran@Sun.COM */
42010394SMichael.Corcoran@Sun.COM if (domp->model == PPMD_CPU &&
42110394SMichael.Corcoran@Sun.COM strcmp(dbp->name, "/") == 0 &&
42210394SMichael.Corcoran@Sun.COM ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
42310394SMichael.Corcoran@Sun.COM DDI_PROP_DONTPASS, "device_type",
42410394SMichael.Corcoran@Sun.COM &devtype) == DDI_SUCCESS) {
42510394SMichael.Corcoran@Sun.COM if (strcmp(devtype, "cpu") == 0) {
42610394SMichael.Corcoran@Sun.COM ddi_prop_free(devtype);
42710394SMichael.Corcoran@Sun.COM return (domp);
42810394SMichael.Corcoran@Sun.COM } else {
42910394SMichael.Corcoran@Sun.COM ddi_prop_free(devtype);
43010394SMichael.Corcoran@Sun.COM }
43110394SMichael.Corcoran@Sun.COM }
43210394SMichael.Corcoran@Sun.COM #endif /* __x86 */
43310394SMichael.Corcoran@Sun.COM
4344667Smh27603 if (ppm_match_devs(path, dbp) == 0)
4354667Smh27603 return (domp);
4364667Smh27603 }
4375295Srandyf }
4384667Smh27603 }
4394667Smh27603
4404667Smh27603 return (NULL);
4414667Smh27603 }
4424667Smh27603
4434667Smh27603
4444667Smh27603 /*
4454667Smh27603 * check ppm.conf file domain device pathname syntax, if correct,
4464667Smh27603 * create device match pattern.
4474667Smh27603 * return 1 for good, -1 for bad.
4484667Smh27603 */
4494667Smh27603 ppm_db_t *
ppm_parse_pattern(struct ppm_db ** dbpp,char * dev_path)4504667Smh27603 ppm_parse_pattern(struct ppm_db **dbpp, char *dev_path)
4514667Smh27603 {
4524667Smh27603 char path[MAXNAMELEN];
4534667Smh27603 int wccnt, i;
4544667Smh27603 int wcpos[2];
4554667Smh27603 int pos;
4564667Smh27603 char *cp;
4574667Smh27603 ppm_db_t *dbp;
4584667Smh27603
4594667Smh27603 (void) strcpy(path, dev_path);
4604667Smh27603 if ((wccnt = ppm_count_char(path, '*')) > 2)
4614667Smh27603 return (NULL);
4624667Smh27603
4634667Smh27603 for (i = 0, cp = path, pos = 0; i < wccnt; i++, cp++, pos++) {
4644667Smh27603 for (; *cp; cp++, pos++)
4654667Smh27603 if (*cp == '*')
4664667Smh27603 break;
4674667Smh27603 wcpos[i] = pos;
4684667Smh27603 PPMD(D_CREATEDB, (" wildcard #%d, pos %d\n",
4694667Smh27603 (i + 1), wcpos[i]))
4704667Smh27603 }
4714667Smh27603
4724667Smh27603 #ifdef DEBUG
4734667Smh27603 /* first '*', if exists, don't go beyond the string */
4744667Smh27603 if (wccnt > 0)
4754667Smh27603 ASSERT(wcpos[0] < strlen(path));
4764667Smh27603
4774667Smh27603 /* second '*', if exists, better be the last character */
4784667Smh27603 if (wccnt == 2)
4794667Smh27603 ASSERT(wcpos[1] == (strlen(path) - 1));
4804667Smh27603 #endif
4814667Smh27603
4824667Smh27603 /*
4834667Smh27603 * first '*', if followed by any char, must be immediately
4844667Smh27603 * followed by '@' and the rest better be bound by
4854667Smh27603 * ['0-9', 'a-f', A-F'] until ended '0' or second '*''0'.
4864667Smh27603 */
4874667Smh27603 if ((wccnt > 0) && (wcpos[0] < (strlen(path) - 1))) {
4884667Smh27603 cp = path + wcpos[0] + 1;
4894667Smh27603 if (*cp != '@')
4904667Smh27603 return (NULL);
4914667Smh27603
4924667Smh27603 if (!(((*(++cp) > '0') && (*cp < '9')) ||
4934667Smh27603 ((*cp > 'a') && (*cp < 'f')) ||
4944667Smh27603 ((*cp > 'A') && (*cp < 'F'))))
4954667Smh27603 return (NULL);
4964667Smh27603 }
4974667Smh27603
4984667Smh27603 dbp = kmem_zalloc(sizeof (struct ppm_db), KM_SLEEP);
4994667Smh27603 dbp->name = kmem_zalloc((strlen(path) + 1), KM_SLEEP);
5004667Smh27603 (void) strcpy(dbp->name, path);
5014667Smh27603 dbp->wccnt = wccnt;
5024667Smh27603 dbp->wcpos[0] = (wccnt > 0) ? wcpos[0] : -1;
5034667Smh27603 dbp->wcpos[1] = (wccnt == 2) ? wcpos[1] : -1;
5044667Smh27603
5054667Smh27603 return (*dbpp = dbp);
5064667Smh27603 }
5074667Smh27603
5084667Smh27603
5094667Smh27603 /*
5104667Smh27603 * match given device "path" to domain device pathname
5114667Smh27603 * pattern dbp->name that contains one or two '*' character(s).
5124667Smh27603 * Matching policy:
5134667Smh27603 * 1). If one wildcard terminates match pattern, need exact match
5144667Smh27603 * up to (but exclude) the wildcard;
5154667Smh27603 * 2). If one wildcard does not terminate match pattern, it is to
5164667Smh27603 * match driver name (terminates with '@') and must be followed
5174667Smh27603 * by exact match of rest of pattern;
5184667Smh27603 * 3). If two wildcards, first is to match driver name as in 2),
5194667Smh27603 * second is to match fcnid (terminates with '/' or '\0') and
5204667Smh27603 * must the last char of pattern.
5214667Smh27603 *
5224667Smh27603 * return 0 if match, and
5234667Smh27603 * non 0 if mismatch
5244667Smh27603 */
5254667Smh27603 int
ppm_match_devs(char * dev_path,ppm_db_t * dbp)5264667Smh27603 ppm_match_devs(char *dev_path, ppm_db_t *dbp)
5274667Smh27603 {
5284667Smh27603 char path[MAXNAMELEN];
5294667Smh27603 char *cp; /* points into "path", real device pathname */
5304667Smh27603 char *np; /* points into "dbp->name", the pattern */
5314667Smh27603 int len;
5324667Smh27603
5334667Smh27603 if (dbp->wccnt == 0)
5344667Smh27603 return (strcmp(dev_path, dbp->name));
5354667Smh27603
5364667Smh27603 (void) strcpy(path, dev_path);
5374667Smh27603
5384667Smh27603 /* match upto the first '*' regardless */
5394667Smh27603 if (strncmp(path, dbp->name, dbp->wcpos[0]) != 0)
5404667Smh27603 return (-1);
5414667Smh27603
5424667Smh27603
5434667Smh27603 /* "<exact match>*" */
5444667Smh27603 if (dbp->name[dbp->wcpos[0] + 1] == 0) {
5454667Smh27603 cp = path + dbp->wcpos[0];
5465295Srandyf while (*cp && (*cp++ != '/'))
5475295Srandyf ;
5484667Smh27603 return ((*cp == 0) ? 0 : -1);
5494667Smh27603 }
5504667Smh27603
5514667Smh27603
5524667Smh27603 /* locate '@' */
5534667Smh27603 cp = path + dbp->wcpos[0] + 1;
5544667Smh27603 while (*cp && *cp != '@')
5554667Smh27603 cp++;
5564667Smh27603
5574667Smh27603 np = dbp->name + dbp->wcpos[0] + 1;
5584667Smh27603
5594667Smh27603 /* if one wildcard, match the rest in the pattern */
5604667Smh27603 if (dbp->wccnt == 1)
5614667Smh27603 return ((strcmp(cp, np) == 0) ? 0 : (-1));
5624667Smh27603
5634667Smh27603
5644667Smh27603 /* must have exact match after first wildcard up to second */
5654667Smh27603 ASSERT(dbp->wccnt == 2);
5664667Smh27603 len = dbp->wcpos[1] - dbp->wcpos[0] - 1;
5674667Smh27603 if (strncmp(cp, np, len) != 0)
5684667Smh27603 return (-1);
5694667Smh27603
5704667Smh27603 /* second wildcard match terminates with '/' or '\0' */
5714667Smh27603 /* but only termination with '\0' is a successful match */
5724667Smh27603 cp += len;
5734667Smh27603 while (*cp && (*cp != '/'))
5744667Smh27603 cp++;
5754667Smh27603 return ((*cp == 0) ? 0 : -1);
5764667Smh27603 }
5774667Smh27603
5784667Smh27603
5794667Smh27603 /*
5804667Smh27603 * By claiming a device, ppm gets involved in its power change
5814667Smh27603 * process: handles additional issues prior and/or post its
5824667Smh27603 * power(9e) call.
5834667Smh27603 *
5844667Smh27603 * If 'dip' is a PCI device, this is the time to ask its parent
5854667Smh27603 * what PCI bus speed it is running.
5864667Smh27603 *
5874667Smh27603 * returns 1 (claimed), 0 (not claimed)
5884667Smh27603 */
5894667Smh27603 int
ppm_claim_dev(dev_info_t * dip)5904667Smh27603 ppm_claim_dev(dev_info_t *dip)
5914667Smh27603 {
5924667Smh27603 ppm_domain_t *domp;
5934667Smh27603 dev_info_t *pdip;
5944667Smh27603 uint_t pciclk;
5954667Smh27603 int claimed = -1;
5964667Smh27603
5974667Smh27603 domp = ppm_lookup_dev(dip);
5984667Smh27603 if (!domp)
5994667Smh27603 claimed = 0;
6004667Smh27603
6014667Smh27603 if (domp && PPMD_IS_PCI(domp->model) &&
6024667Smh27603 ! (domp->dflags & (PPMD_PCI33MHZ | PPMD_PCI66MHZ))) {
6034667Smh27603 pdip = ddi_get_parent(dip);
6044667Smh27603 ASSERT(pdip);
6054667Smh27603 pciclk = ddi_prop_get_int(DDI_DEV_T_ANY, pdip,
6064667Smh27603 DDI_PROP_DONTPASS, "clock-frequency", -1);
6074667Smh27603
6084667Smh27603 switch (pciclk) {
6094667Smh27603 case 33000000:
6104667Smh27603 domp->dflags |= PPMD_PCI33MHZ;
6114667Smh27603 claimed = 1;
6124667Smh27603 break;
6134667Smh27603 case 66000000:
6144667Smh27603 domp->dflags |= PPMD_PCI66MHZ;
6154667Smh27603 claimed = 1;
6164667Smh27603 break;
6174667Smh27603 default:
6184667Smh27603 claimed = 0;
6194667Smh27603 break;
6204667Smh27603 }
6214667Smh27603 }
6224667Smh27603
6234667Smh27603 if (domp && (claimed == -1))
6244667Smh27603 claimed = 1;
6254667Smh27603
6264667Smh27603 #ifdef DEBUG
6274667Smh27603 if (claimed) {
6284667Smh27603 char path[MAXNAMELEN];
6294667Smh27603 PPMD(D_CLAIMDEV, ("ppm_claim_dev: %s into domain %s\n",
6304667Smh27603 ddi_pathname(dip, path), domp->name))
6314667Smh27603 }
6324667Smh27603
6334667Smh27603 #endif
6344667Smh27603
6354667Smh27603 return (claimed);
6364667Smh27603 }
6374667Smh27603
6384667Smh27603 /*
6394667Smh27603 * add a device to the list of domain's owned devices (if it is not already
6404667Smh27603 * on the list).
6414667Smh27603 */
6424667Smh27603 ppm_owned_t *
ppm_add_owned(dev_info_t * dip,ppm_domain_t * domp)6434667Smh27603 ppm_add_owned(dev_info_t *dip, ppm_domain_t *domp)
6444667Smh27603 {
6454667Smh27603 char path[MAXNAMELEN];
6464667Smh27603 ppm_owned_t *owned, *new_owned;
6474667Smh27603
6484667Smh27603 ASSERT(MUTEX_HELD(&domp->lock));
6494667Smh27603 PPM_GET_PATHNAME(dip, path);
6504667Smh27603 for (owned = domp->owned; owned; owned = owned->next)
6514667Smh27603 if (strcmp(path, owned->path) == 0)
6524667Smh27603 return (owned);
6534667Smh27603
6544667Smh27603 new_owned = kmem_zalloc(sizeof (*new_owned), KM_SLEEP);
6554667Smh27603 new_owned->path = kmem_zalloc(strlen(path) + 1, KM_SLEEP);
6564667Smh27603 (void) strcpy(new_owned->path, path);
6574667Smh27603 new_owned->next = domp->owned;
6584667Smh27603 domp->owned = new_owned;
6594667Smh27603
6604667Smh27603 return (domp->owned);
6614667Smh27603 }
6624667Smh27603
6634667Smh27603 /*
6644667Smh27603 * create/init a new ppm device and link into the domain
6654667Smh27603 */
6664667Smh27603 ppm_dev_t *
ppm_add_dev(dev_info_t * dip,ppm_domain_t * domp)6674667Smh27603 ppm_add_dev(dev_info_t *dip, ppm_domain_t *domp)
6684667Smh27603 {
6694667Smh27603 char path[MAXNAMELEN];
6704667Smh27603 ppm_dev_t *new = NULL;
6714667Smh27603 int cmpt;
6724667Smh27603 ppm_owned_t *owned;
6734667Smh27603
6744667Smh27603 ASSERT(MUTEX_HELD(&domp->lock));
6754667Smh27603 (void) ddi_pathname(dip, path);
6764667Smh27603 /*
6774667Smh27603 * For devs which have exported "pm-components" we want to create
6784667Smh27603 * a data structure for each component. When a driver chooses not
6794667Smh27603 * to export the prop we treat its device as having a single
6804667Smh27603 * component and build a structure for it anyway. All other ppm
6814667Smh27603 * logic will act as if this device were always up and can thus
6824667Smh27603 * make correct decisions about it in relation to other devices
6834667Smh27603 * in its domain.
6844667Smh27603 */
6854667Smh27603 for (cmpt = PM_GET_PM_INFO(dip) ? PM_NUMCMPTS(dip) : 1; cmpt--; ) {
6864667Smh27603 new = kmem_zalloc(sizeof (*new), KM_SLEEP);
6874667Smh27603 new->path = kmem_zalloc(strlen(path) + 1, KM_SLEEP);
6884667Smh27603 (void) strcpy(new->path, path);
6894667Smh27603 new->domp = domp;
6904667Smh27603 new->dip = dip;
6914667Smh27603 new->cmpt = cmpt;
6924667Smh27603 ppm_dev_init(new);
6934667Smh27603 new->next = domp->devlist;
6944667Smh27603 domp->devlist = new;
6954667Smh27603 PPMD(D_ADDDEV,
6964667Smh27603 ("ppm_add_dev: %s to domain %s: ppm_dev(0x%p)\n",
6974667Smh27603 new->path, domp->name, (void *)new))
6984667Smh27603 }
6994667Smh27603
7004667Smh27603 ASSERT(new != NULL);
7014667Smh27603 /*
7024667Smh27603 * devi_pm_ppm_private should be set only after all
7034667Smh27603 * ppm_dev s related to all components have been
7044667Smh27603 * initialized and domain's pwr_cnt is incremented
7054667Smh27603 * for each of them.
7064667Smh27603 */
7074667Smh27603 PPM_SET_PRIVATE(dip, new);
7084667Smh27603
7094667Smh27603 /* remember this device forever */
7104667Smh27603 owned = ppm_add_owned(dip, domp);
7114667Smh27603
7124667Smh27603 /*
7134667Smh27603 * Initializing flag is set for devices which have gone through
7144667Smh27603 * PPM_PMR_INIT_CHILD ctlop. By this point, these devices have
7154667Smh27603 * been added to ppm structures and could participate in pm
7164667Smh27603 * decision making, so clear the initializing flag.
7174667Smh27603 */
7184667Smh27603 if (owned->initializing) {
7194667Smh27603 owned->initializing = 0;
7204667Smh27603 PPMD(D_ADDDEV, ("ppm_add_dev: cleared initializing flag "
7214667Smh27603 "for %s@%s\n", PM_NAME(dip),
7224667Smh27603 (PM_ADDR(dip) == NULL) ? "" : PM_ADDR(dip)))
7234667Smh27603 }
7244667Smh27603
7254667Smh27603 return (new);
7264667Smh27603 }
7274667Smh27603
7284667Smh27603
7294667Smh27603 /*
7304667Smh27603 * returns an existing or newly created ppm device reference
7314667Smh27603 */
7324667Smh27603 ppm_dev_t *
ppm_get_dev(dev_info_t * dip,ppm_domain_t * domp)7334667Smh27603 ppm_get_dev(dev_info_t *dip, ppm_domain_t *domp)
7344667Smh27603 {
7354667Smh27603 ppm_dev_t *pdp;
7364667Smh27603
7374667Smh27603 mutex_enter(&domp->lock);
7384667Smh27603 pdp = PPM_GET_PRIVATE(dip);
7394667Smh27603 if (pdp == NULL)
7404667Smh27603 pdp = ppm_add_dev(dip, domp);
7414667Smh27603 mutex_exit(&domp->lock);
7424667Smh27603
7434667Smh27603 return (pdp);
7444667Smh27603 }
7454667Smh27603
7464667Smh27603
7474667Smh27603 /*
7484667Smh27603 * scan a domain's device list and remove those with .dip
7494667Smh27603 * matching the arg *dip; we need to scan the entire list
7504667Smh27603 * for the case of devices with multiple components
7514667Smh27603 */
7524667Smh27603 void
ppm_rem_dev(dev_info_t * dip)7534667Smh27603 ppm_rem_dev(dev_info_t *dip)
7544667Smh27603 {
7554667Smh27603 ppm_dev_t *pdp, **devpp;
7564667Smh27603 ppm_domain_t *domp;
7574667Smh27603
7584667Smh27603 pdp = PPM_GET_PRIVATE(dip);
7594667Smh27603 ASSERT(pdp);
7604667Smh27603 domp = pdp->domp;
7614667Smh27603 ASSERT(domp);
7624667Smh27603
7634667Smh27603 mutex_enter(&domp->lock);
7644667Smh27603 for (devpp = &domp->devlist; (pdp = *devpp) != NULL; ) {
7654667Smh27603 if (pdp->dip != dip) {
7664667Smh27603 devpp = &pdp->next;
7674667Smh27603 continue;
7684667Smh27603 }
7694667Smh27603
7704667Smh27603 PPMD(D_REMDEV, ("ppm_rem_dev: path \"%s\", ppm_dev 0x%p\n",
7714667Smh27603 pdp->path, (void *)pdp))
7724667Smh27603
7734667Smh27603 PPM_SET_PRIVATE(dip, NULL);
7744667Smh27603 *devpp = pdp->next;
7754667Smh27603 ppm_dev_fini(pdp);
7764667Smh27603 kmem_free(pdp->path, strlen(pdp->path) + 1);
7774667Smh27603 kmem_free(pdp, sizeof (*pdp));
7784667Smh27603 }
7794667Smh27603 mutex_exit(&domp->lock);
7804667Smh27603 }
7814667Smh27603
7824667Smh27603 /*
7834667Smh27603 * prepare kernel ioctl calls:
7844667Smh27603 */
7854667Smh27603 void
ppm_init_cb(dev_info_t * dip)7864667Smh27603 ppm_init_cb(dev_info_t *dip)
7874667Smh27603 {
7884667Smh27603 char *str = "ppm_init_cb";
7894667Smh27603 ppm_domain_t *domp;
7904667Smh27603 ppm_dc_t *dc;
7914667Smh27603
7924667Smh27603 for (domp = ppm_domain_p; domp != NULL; domp = domp->next) {
7934667Smh27603 for (dc = domp->dc; dc; dc = dc->next) {
7945295Srandyf /*
7955295Srandyf * Warning: This code is rather confusing.
7965295Srandyf *
7975295Srandyf * It intends to ensure that ppm_init_lyr() is only
7985295Srandyf * called ONCE for a device that may be associated
7995295Srandyf * with more than one domain control.
8005295Srandyf * So, what it does is first to check to see if
8015295Srandyf * there is a handle, and then if not it goes on
8025295Srandyf * to call the init_lyr() routine.
8035295Srandyf *
8045295Srandyf * The non-obvious thing is that the ppm_init_lyr()
8055295Srandyf * routine, in addition to opening the device
8065295Srandyf * associated with the dc (domain control) in
8075295Srandyf * question, has the side-effect of creating the
8085295Srandyf * handle for that dc as well.
8095295Srandyf */
8104667Smh27603 if (ppm_lookup_hndl(domp->model, dc) != NULL)
8114667Smh27603 continue;
8124667Smh27603
8134667Smh27603 if (ppm_init_lyr(dc, dip) != DDI_SUCCESS) {
8144667Smh27603 domp->dflags |= PPMD_OFFLINE;
8154667Smh27603 cmn_err(CE_WARN, "%s: ppm domain %s will "
8164667Smh27603 "be offline.", str, domp->name);
8174667Smh27603 break;
8184667Smh27603 }
8194667Smh27603 }
8204667Smh27603 }
8214667Smh27603 }
8224667Smh27603
8234667Smh27603
8244667Smh27603 /*
8254667Smh27603 * ppm_init_lyr - initializing layered ioctl
8264667Smh27603 * Return:
8274667Smh27603 * DDI_SUCCESS - succeeded
8284667Smh27603 * DDI_FAILURE - failed
8294667Smh27603 *
8304667Smh27603 */
8314667Smh27603 int
ppm_init_lyr(ppm_dc_t * dc,dev_info_t * dip)8324667Smh27603 ppm_init_lyr(ppm_dc_t *dc, dev_info_t *dip)
8334667Smh27603 {
8344667Smh27603 char *str = "ppm_init_lyr";
8354667Smh27603 int err = 0;
8364667Smh27603 ldi_ident_t li;
8374667Smh27603
8384667Smh27603 ASSERT(dc && dc->path);
8394667Smh27603
8404667Smh27603 if (err = ldi_ident_from_dip(dip, &li)) {
8414667Smh27603 cmn_err(CE_WARN, "%s: get ldi identifier "
8424667Smh27603 "failed (err=%d)", str, err);
8434667Smh27603 }
8444667Smh27603
8454667Smh27603 err = ldi_open_by_name(dc->path, FWRITE|FREAD, kcred, &(dc->lh), li);
8464667Smh27603
8474667Smh27603 (void) ldi_ident_release(li);
8484667Smh27603
8494667Smh27603 if (err != 0) {
8504667Smh27603 cmn_err(CE_WARN, "Failed to open device(%s), rv(%d)",
8514667Smh27603 dc->path, err);
8524667Smh27603 return (err);
8534667Smh27603 }
8544667Smh27603
8554667Smh27603 return (DDI_SUCCESS);
8564667Smh27603 }
8574667Smh27603
8584667Smh27603 /*
8594667Smh27603 * lock, unlock, or trylock for one power mutex
8604667Smh27603 */
8614667Smh27603 void
ppm_lock_one(ppm_dev_t * ppmd,power_req_t * reqp,int * iresp)8624667Smh27603 ppm_lock_one(ppm_dev_t *ppmd, power_req_t *reqp, int *iresp)
8634667Smh27603 {
8644667Smh27603 switch (reqp->request_type) {
8654667Smh27603 case PMR_PPM_LOCK_POWER:
8664667Smh27603 pm_lock_power_single(ppmd->dip,
8674667Smh27603 reqp->req.ppm_lock_power_req.circp);
8684667Smh27603 break;
8694667Smh27603
8704667Smh27603 case PMR_PPM_UNLOCK_POWER:
8714667Smh27603 pm_unlock_power_single(ppmd->dip,
8724667Smh27603 reqp->req.ppm_unlock_power_req.circ);
8734667Smh27603 break;
8744667Smh27603
8754667Smh27603 case PMR_PPM_TRY_LOCK_POWER:
8764667Smh27603 *iresp = pm_try_locking_power_single(ppmd->dip,
8774667Smh27603 reqp->req.ppm_lock_power_req.circp);
8784667Smh27603 break;
8794667Smh27603 }
8804667Smh27603 }
8814667Smh27603
8824667Smh27603
8834667Smh27603 /*
8844667Smh27603 * lock, unlock, or trylock for all power mutexes within a domain
8854667Smh27603 */
8864667Smh27603 void
ppm_lock_all(ppm_domain_t * domp,power_req_t * reqp,int * iresp)8874667Smh27603 ppm_lock_all(ppm_domain_t *domp, power_req_t *reqp, int *iresp)
8884667Smh27603 {
8894667Smh27603 /*
8904667Smh27603 * To simplify the implementation we let all the devices
8914667Smh27603 * in the domain be represented by a single device (dip).
8924667Smh27603 * We use the first device in the domain's devlist. This
8934667Smh27603 * is safe because we return with the domain lock held
8944667Smh27603 * which prevents the list from changing.
8954667Smh27603 */
8964667Smh27603 if (reqp->request_type == PMR_PPM_LOCK_POWER) {
8974667Smh27603 if (!MUTEX_HELD(&domp->lock))
8984667Smh27603 mutex_enter(&domp->lock);
8994667Smh27603 domp->refcnt++;
9004667Smh27603 ASSERT(domp->devlist != NULL);
9014667Smh27603 pm_lock_power_single(domp->devlist->dip,
9024667Smh27603 reqp->req.ppm_lock_power_req.circp);
9034667Smh27603 /* domain lock remains held */
9044667Smh27603 return;
9054667Smh27603 } else if (reqp->request_type == PMR_PPM_UNLOCK_POWER) {
9064667Smh27603 ASSERT(MUTEX_HELD(&domp->lock));
9074667Smh27603 ASSERT(domp->devlist != NULL);
9084667Smh27603 pm_unlock_power_single(domp->devlist->dip,
9094667Smh27603 reqp->req.ppm_unlock_power_req.circ);
9104667Smh27603 if (--domp->refcnt == 0)
9114667Smh27603 mutex_exit(&domp->lock);
9124667Smh27603 return;
9134667Smh27603 }
9144667Smh27603
9154667Smh27603 ASSERT(reqp->request_type == PMR_PPM_TRY_LOCK_POWER);
9164667Smh27603 if (!MUTEX_HELD(&domp->lock))
9174667Smh27603 if (!mutex_tryenter(&domp->lock)) {
9184667Smh27603 *iresp = 0;
9194667Smh27603 return;
9204667Smh27603 }
9214667Smh27603 *iresp = pm_try_locking_power_single(domp->devlist->dip,
9224667Smh27603 reqp->req.ppm_lock_power_req.circp);
9234667Smh27603 if (*iresp)
9244667Smh27603 domp->refcnt++;
9254667Smh27603 else
9264667Smh27603 mutex_exit(&domp->lock);
9274667Smh27603 }
9284667Smh27603
9294667Smh27603
9304667Smh27603 /*
9314667Smh27603 * return FALSE: if any detached device during its previous life exported
9324667Smh27603 * the "no-involuntary-power-cycles" property and detached with its
9334667Smh27603 * power level not at its lowest, or there is a device in the process
9344667Smh27603 * of being installed/attached; if a PCI domain has devices that have not
9354667Smh27603 * exported a property that it can tolerate clock off while bus is not
9364667Smh27603 * quiescent; if a 66mhz PCI domain has devices that do not support stopping
9374667Smh27603 * clock at D3; either one would count as a power holder.
9384667Smh27603 * return TRUE: otherwise.
9394667Smh27603 */
9404667Smh27603 boolean_t
ppm_none_else_holds_power(ppm_domain_t * domp)9414667Smh27603 ppm_none_else_holds_power(ppm_domain_t *domp)
9424667Smh27603 {
9434667Smh27603 ppm_dev_t *ppmd;
9444667Smh27603 ppm_owned_t *owned;
9454667Smh27603 int i = 0;
9464667Smh27603
9474667Smh27603 if (PPMD_IS_PCI(domp->model)) {
9484667Smh27603 for (ppmd = domp->devlist; ppmd; ppmd = ppmd->next) {
9494667Smh27603 if ((domp->model == PPMD_PCI_PROP) &&
9504667Smh27603 !(ppmd->flags & PPMDEV_PCI_PROP_CLKPM))
9514667Smh27603 return (B_FALSE);
9524667Smh27603 if ((domp->dflags & PPMD_PCI66MHZ) &&
9534667Smh27603 !(ppmd->flags & PPMDEV_PCI66_D2))
9544667Smh27603 return (B_FALSE);
9554667Smh27603 }
9564667Smh27603 }
9574667Smh27603
9584667Smh27603 for (owned = domp->owned; owned; owned = owned->next)
9594667Smh27603 if (pm_noinvol_detached(owned->path) || owned->initializing)
9604667Smh27603 i++;
9614667Smh27603 return (i == 0);
9624667Smh27603 }
9634667Smh27603
9644667Smh27603
9654667Smh27603 /*
9664667Smh27603 * return the number of char 'c' occurrences in string s
9674667Smh27603 */
9684667Smh27603 int
ppm_count_char(char * s,char c)9694667Smh27603 ppm_count_char(char *s, char c)
9704667Smh27603 {
9714667Smh27603 int i = 0;
9724667Smh27603 char *cp = s;
9734667Smh27603
9744667Smh27603 while (*cp) {
9754667Smh27603 if (*cp == c)
9764667Smh27603 i++;
9774667Smh27603 cp++;
9784667Smh27603 }
9794667Smh27603
9804667Smh27603 return (i);
9814667Smh27603 }
9824667Smh27603
9834667Smh27603
9844667Smh27603 /*
9854667Smh27603 * extract and convert a substring from input string "ss" in form of
9864667Smh27603 * "name=value" into an hex or decimal integer
9874667Smh27603 */
9884667Smh27603 #define X_BASE 16
9894667Smh27603 #define D_BASE 10
9904667Smh27603 int
ppm_stoi(char * ss,uint_t * val)9914667Smh27603 ppm_stoi(char *ss, uint_t *val)
9924667Smh27603 {
9934667Smh27603 char *cp;
9944667Smh27603 int hex_ = 0, base = D_BASE;
9954667Smh27603 int digit;
9964667Smh27603
9974667Smh27603 if ((cp = strchr(ss, '=')) == NULL)
9984667Smh27603 return (*val = (uint_t)-1);
9994667Smh27603
10004667Smh27603 cp++;
10014667Smh27603 if ((*cp == '0') && (*++cp == 'x')) {
10024667Smh27603 hex_++;
10034667Smh27603 cp++;
10044667Smh27603 base = X_BASE;
10054667Smh27603 }
10064667Smh27603
10074667Smh27603 for (digit = 0; *cp; cp++) {
10084667Smh27603 if (hex_ && ((*cp >= 'A') && (*cp <= 'F')))
10094667Smh27603 digit = (digit * base) + ((*cp - 'A') + D_BASE);
10104667Smh27603 else if (hex_ && ((*cp >= 'a') && (*cp <= 'f')))
10114667Smh27603 digit = (digit * base) + ((*cp - 'a') + D_BASE);
10124667Smh27603 else
10134667Smh27603 digit = (digit * base) + (*cp - '0');
10144667Smh27603 }
10154667Smh27603
10164667Smh27603 return (*val = digit);
10174667Smh27603 }
10184667Smh27603
10194667Smh27603 /*
10204667Smh27603 * ppm_convert - convert a #define symbol to its integer value,
10214667Smh27603 * only the #defines for ppm_dc.cmd and ppm_dc.method fields in
10224667Smh27603 * ppmvar.h file are recognized.
10234667Smh27603 */
10244667Smh27603 struct ppm_confdefs {
10254667Smh27603 char *sym;
10264667Smh27603 int val;
10274667Smh27603 } ppm_confdefs_table[] = {
10285295Srandyf "ENTER_S3", PPMDC_ENTER_S3,
10295295Srandyf "EXIT_S3", PPMDC_EXIT_S3,
10304667Smh27603 "CPU_NEXT", PPMDC_CPU_NEXT,
10314667Smh27603 "PRE_CHNG", PPMDC_PRE_CHNG,
10324667Smh27603 "CPU_GO", PPMDC_CPU_GO,
10334667Smh27603 "POST_CHNG", PPMDC_POST_CHNG,
10344667Smh27603 "FET_ON", PPMDC_FET_ON,
10354667Smh27603 "FET_OFF", PPMDC_FET_OFF,
10364667Smh27603 "CLK_OFF", PPMDC_CLK_OFF,
10374667Smh27603 "CLK_ON", PPMDC_CLK_ON,
10384667Smh27603 "LED_ON", PPMDC_LED_ON,
10394667Smh27603 "LED_OFF", PPMDC_LED_OFF,
10404667Smh27603 "KIO", PPMDC_KIO,
10414667Smh27603 "VCORE", PPMDC_VCORE,
10425295Srandyf #ifdef sun4u
10434667Smh27603 "I2CKIO", PPMDC_I2CKIO,
10445295Srandyf #endif
10454667Smh27603 "CPUSPEEDKIO", PPMDC_CPUSPEEDKIO,
10464667Smh27603 "PRE_PWR_OFF", PPMDC_PRE_PWR_OFF,
10474667Smh27603 "PRE_PWR_ON", PPMDC_PRE_PWR_ON,
10484667Smh27603 "POST_PWR_ON", PPMDC_POST_PWR_ON,
10494667Smh27603 "PWR_OFF", PPMDC_PWR_OFF,
10504667Smh27603 "PWR_ON", PPMDC_PWR_ON,
10514667Smh27603 "RESET_OFF", PPMDC_RESET_OFF,
10524667Smh27603 "RESET_ON", PPMDC_RESET_ON,
10534667Smh27603 NULL
10544667Smh27603 };
10554667Smh27603
10564667Smh27603
10574667Smh27603 /*
10584667Smh27603 * convert a #define'd symbol to its integer value where
10594667Smh27603 * input "symbol" is expected to be in form of "SYMBOL=value"
10604667Smh27603 */
10614667Smh27603 int
ppm_convert(char * symbol,uint_t * val)10624667Smh27603 ppm_convert(char *symbol, uint_t *val)
10634667Smh27603 {
10644667Smh27603 char *s;
10654667Smh27603 struct ppm_confdefs *pcfp;
10664667Smh27603
10674667Smh27603 if ((s = strchr(symbol, '=')) == NULL) {
10684667Smh27603 cmn_err(CE_WARN, "ppm_convert: token \"%s\" syntax error in "
1069*10846SMargot.Miller@Sun.COM "ppm.conf file", symbol);
10704667Smh27603 return (*val = (uint_t)-1);
10714667Smh27603 }
10724667Smh27603 s++;
10734667Smh27603
10744667Smh27603 for (pcfp = ppm_confdefs_table; (pcfp->sym != NULL); pcfp++) {
10754667Smh27603 if (strcmp(s, pcfp->sym) == 0)
10764667Smh27603 return (*val = pcfp->val);
10774667Smh27603 }
10784667Smh27603
10794667Smh27603 cmn_err(CE_WARN, "ppm_convert: Unrecognizable token \"%s\" "
1080*10846SMargot.Miller@Sun.COM "in ppm.conf file", symbol);
10814667Smh27603 return (*val = (uint_t)-1);
10824667Smh27603 }
10834667Smh27603
10844667Smh27603
10854667Smh27603 /*
10864667Smh27603 * parse a domain control property string into data structure struct ppm_dc
10874667Smh27603 */
10884667Smh27603 int
ppm_parse_dc(char ** dc_namep,ppm_dc_t * dc)10894667Smh27603 ppm_parse_dc(char **dc_namep, ppm_dc_t *dc)
10904667Smh27603 {
10914667Smh27603 char *str = "ppm_parse_dc";
10924667Smh27603 char *line;
10934667Smh27603 char *f, *b;
10944667Smh27603 char **dclist; /* list of ppm_dc_t fields */
10954667Smh27603 int count; /* the # of '=' indicates the # of items */
10964667Smh27603 size_t len; /* length of line being parsed */
10974667Smh27603 boolean_t done;
10984667Smh27603 int i;
10994667Smh27603 int err;
11004667Smh27603
11014667Smh27603 len = strlen(*dc_namep);
11024667Smh27603 line = kmem_alloc(len + 1, KM_SLEEP);
11034667Smh27603 (void) strcpy(line, *dc_namep);
11044667Smh27603
11054667Smh27603 count = ppm_count_char(line, '=');
11064667Smh27603 ASSERT((count - ppm_count_char(line, ' ')) == 1);
11074667Smh27603
11084667Smh27603 dclist = (char **)
11094667Smh27603 kmem_zalloc((sizeof (char *) * (count + 1)), KM_SLEEP);
11104667Smh27603 for (i = 0, f = b = line, done = B_FALSE; !done; i++, f = ++b) {
11114667Smh27603 while (*b != ' ' && *b != 0)
11124667Smh27603 b++;
11134667Smh27603 if (*b == 0)
11144667Smh27603 done = B_TRUE;
11154667Smh27603 else
11164667Smh27603 *b = 0;
11174667Smh27603 dclist[i] = f;
11184667Smh27603 }
11194667Smh27603
11204667Smh27603 for (i = 0; i < count; i++) {
11214667Smh27603 if (strstr(dclist[i], "cmd=")) {
11224667Smh27603 err = ppm_convert(dclist[i], &dc->cmd);
11234667Smh27603 if (err == -1)
11244667Smh27603 return (err);
11254667Smh27603 continue;
11264667Smh27603 }
11274667Smh27603 if ((f = strstr(dclist[i], "path=")) != NULL) {
11284667Smh27603 f += strlen("path=");
11294667Smh27603 dc->path = kmem_zalloc((strlen(f) + 1), KM_SLEEP);
11304667Smh27603 (void) strcpy(dc->path, f);
11314667Smh27603 continue;
11324667Smh27603 }
11334667Smh27603 if (strstr(dclist[i], "method=")) {
11344667Smh27603 err = ppm_convert(dclist[i], &dc->method);
11354667Smh27603 if (err == -1)
11364667Smh27603 return (err);
11374667Smh27603 continue;
11384667Smh27603 }
11394667Smh27603 if (strstr(dclist[i], "iowr=")) {
11404667Smh27603 (void) ppm_stoi(dclist[i], &dc->m_un.kio.iowr);
11414667Smh27603 continue;
11424667Smh27603 }
11434667Smh27603 if (strstr(dclist[i], "iord=")) {
11444667Smh27603 (void) ppm_stoi(dclist[i], &dc->m_un.kio.iord);
11454667Smh27603 continue;
11464667Smh27603 }
11474667Smh27603 if (strstr(dclist[i], "val=")) {
11484667Smh27603 (void) ppm_stoi(dclist[i], &dc->m_un.kio.val);
11494667Smh27603 continue;
11504667Smh27603 }
11514667Smh27603 if (strstr(dclist[i], "speeds=")) {
11524667Smh27603 ASSERT(dc->method == PPMDC_CPUSPEEDKIO);
11534667Smh27603 (void) ppm_stoi(dclist[i], &dc->m_un.cpu.speeds);
11544667Smh27603 continue;
11554667Smh27603 }
11565295Srandyf #ifdef sun4u
11574667Smh27603 if (strstr(dclist[i], "mask=")) {
11584667Smh27603 (void) ppm_stoi(dclist[i], &dc->m_un.i2c.mask);
11594667Smh27603 continue;
11604667Smh27603 }
11615295Srandyf #endif
11624667Smh27603 /* This must be before the if statement for delay */
11634667Smh27603 if (strstr(dclist[i], "post_delay=")) {
11645295Srandyf #ifdef sun4u
11654667Smh27603 ASSERT(dc->method == PPMDC_KIO ||
11664667Smh27603 dc->method == PPMDC_I2CKIO);
11675295Srandyf #else
11685295Srandyf ASSERT(dc->method == PPMDC_KIO);
11695295Srandyf #endif
11704667Smh27603 /*
11714667Smh27603 * all delays are uint_t type instead of clock_t.
11724667Smh27603 * If the delay is too long, it might get truncated.
11734667Smh27603 * But, we don't expect delay to be too long.
11744667Smh27603 */
11754667Smh27603 switch (dc->method) {
11764667Smh27603 case PPMDC_KIO:
11774667Smh27603 (void) ppm_stoi(dclist[i],
11785295Srandyf &dc->m_un.kio.post_delay);
11794667Smh27603 break;
11804667Smh27603
11815295Srandyf #ifdef sun4u
11824667Smh27603 case PPMDC_I2CKIO:
11834667Smh27603 (void) ppm_stoi(dclist[i],
11845295Srandyf &dc->m_un.i2c.post_delay);
11854667Smh27603 break;
11865295Srandyf #endif
11874667Smh27603
11884667Smh27603 default:
11894667Smh27603 break;
11904667Smh27603 }
11914667Smh27603 continue;
11924667Smh27603 }
11934667Smh27603 if (strstr(dclist[i], "delay=")) {
11945295Srandyf #ifdef sun4u
11954667Smh27603 ASSERT(dc->method == PPMDC_VCORE ||
11965295Srandyf dc->method == PPMDC_KIO ||
11975295Srandyf dc->method == PPMDC_I2CKIO);
11985295Srandyf #else
11995295Srandyf ASSERT(dc->method == PPMDC_VCORE ||
12005295Srandyf dc->method == PPMDC_KIO);
12015295Srandyf #endif
12024667Smh27603
12034667Smh27603 /*
12044667Smh27603 * all delays are uint_t type instead of clock_t.
12054667Smh27603 * If the delay is too long, it might get truncated.
12064667Smh27603 * But, we don't expect delay to be too long.
12074667Smh27603 */
12084667Smh27603
12094667Smh27603 switch (dc->method) {
12104667Smh27603 case PPMDC_KIO:
12114667Smh27603 (void) ppm_stoi(dclist[i], &dc->m_un.kio.delay);
12124667Smh27603 break;
12134667Smh27603
12145295Srandyf #ifdef sun4u
12154667Smh27603 case PPMDC_I2CKIO:
12164667Smh27603 (void) ppm_stoi(dclist[i], &dc->m_un.i2c.delay);
12174667Smh27603 break;
12185295Srandyf #endif
12194667Smh27603
12204667Smh27603 case PPMDC_VCORE:
12214667Smh27603 (void) ppm_stoi(dclist[i], &dc->m_un.cpu.delay);
12224667Smh27603 break;
12234667Smh27603
12244667Smh27603 default:
12254667Smh27603 break;
12264667Smh27603 }
12274667Smh27603 continue;
12284667Smh27603 }
12294667Smh27603
12304667Smh27603 /* we encounted unrecognized field, flag error */
12314667Smh27603 cmn_err(CE_WARN, "%s: Unrecognized token \"%s\" in ppm.conf "
1232*10846SMargot.Miller@Sun.COM "file!", str, dclist[i]);
12334667Smh27603 return (-1);
12344667Smh27603 }
12354667Smh27603
12364667Smh27603 kmem_free(dclist, sizeof (char *) * (count + 1));
12374667Smh27603 kmem_free(line, len + 1);
12384667Smh27603
12394667Smh27603 return (DDI_SUCCESS);
12404667Smh27603 }
12414667Smh27603
12424667Smh27603
12434667Smh27603 /*
12444667Smh27603 * search for domain control handle for a claimed device coupled with a
12454667Smh27603 * domain control command. NULL device may indicate LED domain.
12464667Smh27603 */
12474667Smh27603 ppm_dc_t *
ppm_lookup_dc(ppm_domain_t * domp,int cmd)12484667Smh27603 ppm_lookup_dc(ppm_domain_t *domp, int cmd)
12494667Smh27603 {
12504667Smh27603 #ifdef DEBUG
12514667Smh27603 char *str = "ppm_lookup_dc";
12524667Smh27603 #endif
12534667Smh27603 ppm_dc_t *dc;
12544667Smh27603
12554667Smh27603 /*
12564667Smh27603 * For convenience, we accept 'domp' as NULL for searching
12574667Smh27603 * LED domain control operation.
12584667Smh27603 */
12594667Smh27603 if ((cmd == PPMDC_LED_OFF) || (cmd == PPMDC_LED_ON)) {
12604667Smh27603 for (domp = ppm_domain_p; domp; domp = domp->next)
12614667Smh27603 if (domp->model == PPMD_LED)
12624667Smh27603 break;
12634667Smh27603 if (!domp || !domp->dc || !domp->dc->lh || !domp->dc->next) {
12644667Smh27603 PPMD(D_LED, ("\tinsufficient led domain control "
12654667Smh27603 "information.\n"))
12664667Smh27603 return (NULL);
12674667Smh27603 }
12684667Smh27603 if (cmd == domp->dc->cmd)
12694667Smh27603 return (domp->dc);
12704667Smh27603 else
12714667Smh27603 return (domp->dc->next);
12724667Smh27603 }
12734667Smh27603
12744667Smh27603
12754667Smh27603 /*
12764667Smh27603 * for the rest of ppm domains, lookup ppm_dc starting from domp
12774667Smh27603 */
12784667Smh27603 ASSERT(domp != NULL);
12794667Smh27603 switch (cmd) {
12804667Smh27603 case PPMDC_CPU_NEXT:
12814667Smh27603 case PPMDC_PRE_CHNG:
12824667Smh27603 case PPMDC_CPU_GO:
12834667Smh27603 case PPMDC_POST_CHNG:
12844667Smh27603 case PPMDC_FET_OFF:
12854667Smh27603 case PPMDC_FET_ON:
12864667Smh27603 case PPMDC_CLK_OFF:
12874667Smh27603 case PPMDC_CLK_ON:
12884667Smh27603 case PPMDC_PRE_PWR_OFF:
12894667Smh27603 case PPMDC_PRE_PWR_ON:
12904667Smh27603 case PPMDC_POST_PWR_ON:
12914667Smh27603 case PPMDC_PWR_OFF:
12924667Smh27603 case PPMDC_PWR_ON:
12934667Smh27603 case PPMDC_RESET_OFF:
12944667Smh27603 case PPMDC_RESET_ON:
12955295Srandyf case PPMDC_ENTER_S3:
12965295Srandyf case PPMDC_EXIT_S3:
12974667Smh27603 break;
12984667Smh27603 default:
12994667Smh27603 PPMD(D_PPMDC, ("%s: cmd(%d) unrecognized\n", str, cmd))
13004667Smh27603 return (NULL);
13014667Smh27603 }
13024667Smh27603
13034667Smh27603 for (dc = domp->dc; dc; dc = dc->next) {
13045295Srandyf if (dc->cmd == cmd) {
13054667Smh27603 return (dc);
13065295Srandyf }
13074667Smh27603 }
13085295Srandyf
13094667Smh27603 return (NULL);
13104667Smh27603 }
13114667Smh27603
13124667Smh27603 #include <sys/esunddi.h>
13134667Smh27603
13144667Smh27603 ppm_domain_t *
ppm_get_domain_by_dev(const char * p)13154667Smh27603 ppm_get_domain_by_dev(const char *p)
13164667Smh27603 {
13174667Smh27603 dev_info_t *dip;
13184667Smh27603 ppm_domain_t *domp;
13194667Smh27603 ppm_dev_t *pdev;
13204667Smh27603 boolean_t found = B_FALSE;
13214667Smh27603
13224667Smh27603 if ((dip = e_ddi_hold_devi_by_path((char *)p, 0)) == NULL)
13234667Smh27603 return (NULL);
13244667Smh27603
13254667Smh27603 for (domp = ppm_domain_p; domp; domp = domp->next) {
13264667Smh27603 for (pdev = domp->devlist; pdev; pdev = pdev->next) {
13274667Smh27603 if (pdev->dip == dip) {
13284667Smh27603 found = B_TRUE;
13294667Smh27603 break;
13304667Smh27603 }
13314667Smh27603 }
13324667Smh27603 if (found)
13334667Smh27603 break;
13344667Smh27603 }
13354667Smh27603 ddi_release_devi(dip);
13364667Smh27603 return (domp);
13374667Smh27603 }
13384667Smh27603
13394667Smh27603
13404667Smh27603 #ifdef DEBUG
13414667Smh27603 #define FLINTSTR(flags, sym) { flags, sym, #sym }
13424667Smh27603 #define PMR_UNKNOWN -1
13434667Smh27603 /*
13444667Smh27603 * convert a ctlop integer to a char string. this helps printing
13454667Smh27603 * meaningful info when cltops are received from the pm framework.
13464667Smh27603 * since some ctlops are so frequent, we use mask to limit output:
13474667Smh27603 * a valid string is returned when ctlop is found and when
13484667Smh27603 * (cmd.flags & mask) is true; otherwise NULL is returned.
13494667Smh27603 */
13504667Smh27603 char *
ppm_get_ctlstr(int ctlop,uint_t mask)13514667Smh27603 ppm_get_ctlstr(int ctlop, uint_t mask)
13524667Smh27603 {
13534667Smh27603 struct ctlop_cmd {
13544667Smh27603 uint_t flags;
13554667Smh27603 int ctlop;
13564667Smh27603 char *str;
13574667Smh27603 };
13584667Smh27603
13594667Smh27603 struct ctlop_cmd *ccp;
13604667Smh27603 static struct ctlop_cmd cmds[] = {
13614667Smh27603 FLINTSTR(D_SETPWR, PMR_SET_POWER),
13624667Smh27603 FLINTSTR(D_CTLOPS2, PMR_SUSPEND),
13634667Smh27603 FLINTSTR(D_CTLOPS2, PMR_RESUME),
13644667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PRE_SET_POWER),
13654667Smh27603 FLINTSTR(D_CTLOPS2, PMR_POST_SET_POWER),
13664667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_SET_POWER),
13674667Smh27603 FLINTSTR(0, PMR_PPM_ATTACH),
13684667Smh27603 FLINTSTR(0, PMR_PPM_DETACH),
13694667Smh27603 FLINTSTR(D_CTLOPS1, PMR_PPM_POWER_CHANGE_NOTIFY),
13704667Smh27603 FLINTSTR(D_CTLOPS1, PMR_REPORT_PMCAP),
13714667Smh27603 FLINTSTR(D_CTLOPS1, PMR_CHANGED_POWER),
13724667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_INIT_CHILD),
13734667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_UNINIT_CHILD),
13744667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_PROBE),
13754667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_POST_PROBE),
13764667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_ATTACH),
13774667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_POST_ATTACH),
13784667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_DETACH),
13794667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_POST_DETACH),
13804667Smh27603 FLINTSTR(D_CTLOPS1, PMR_PPM_UNMANAGE),
13814667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_RESUME),
13824667Smh27603 FLINTSTR(D_CTLOPS1, PMR_PPM_ALL_LOWEST),
13834667Smh27603 FLINTSTR(D_LOCKS, PMR_PPM_LOCK_POWER),
13844667Smh27603 FLINTSTR(D_LOCKS, PMR_PPM_UNLOCK_POWER),
13854667Smh27603 FLINTSTR(D_LOCKS, PMR_PPM_TRY_LOCK_POWER),
13864667Smh27603 FLINTSTR(D_LOCKS, PMR_PPM_POWER_LOCK_OWNER),
13875295Srandyf FLINTSTR(D_CTLOPS1 | D_CTLOPS2, PMR_PPM_ENTER_SX),
13884667Smh27603 FLINTSTR(D_CTLOPS1 | D_CTLOPS2, PMR_UNKNOWN),
13894667Smh27603 };
13904667Smh27603
13914667Smh27603 for (ccp = cmds; ccp->ctlop != PMR_UNKNOWN; ccp++)
13924667Smh27603 if (ctlop == ccp->ctlop)
13934667Smh27603 break;
13944667Smh27603
13954667Smh27603 if (ccp->flags & mask)
13964667Smh27603 return (ccp->str);
13974667Smh27603 return (NULL);
13984667Smh27603 }
13994667Smh27603
14004667Smh27603 void
ppm_print_dc(ppm_dc_t * dc)14014667Smh27603 ppm_print_dc(ppm_dc_t *dc)
14024667Smh27603 {
14034667Smh27603 ppm_dc_t *d = dc;
14044667Smh27603
14054667Smh27603 PPMD(D_PPMDC, ("\nAdds ppm_dc: path(%s),\n cmd(%x), "
14064667Smh27603 "method(%x), ", d->path, d->cmd, d->method))
14075295Srandyf if (d->method == PPMDC_KIO) {
14085295Srandyf PPMD(D_PPMDC, ("kio.iowr(%x), kio.val(0x%X)",
14095295Srandyf d->m_un.kio.iowr, d->m_un.kio.val))
14105295Srandyf #ifdef sun4u
14115295Srandyf } else if (d->method == PPMDC_I2CKIO) {
14124667Smh27603 PPMD(D_PPMDC, ("i2c.iowr(%x), i2c.val(0x%X), "
14134667Smh27603 "i2c.mask(0x%X)", d->m_un.i2c.iowr,
14144667Smh27603 d->m_un.i2c.val, d->m_un.i2c.mask))
14155295Srandyf #endif
14164667Smh27603 } else if (d->method == PPMDC_VCORE) {
14174667Smh27603 PPMD(D_PPMDC, ("cpu: .iord(%x), .iowr(%x), .val(0x%X), "
14184667Smh27603 ".delay(0x%x)",
14194667Smh27603 d->m_un.cpu.iord, d->m_un.cpu.iowr, d->m_un.cpu.val,
14204667Smh27603 d->m_un.cpu.delay))
14214667Smh27603 } else if (d->method == PPMDC_CPUSPEEDKIO) {
14224667Smh27603 PPMD(D_PPMDC, ("cpu.iowr(%x), cpu.speeds(0x%X)",
14234667Smh27603 d->m_un.cpu.iowr, d->m_un.cpu.speeds))
14244667Smh27603 }
14254667Smh27603 PPMD(D_PPMDC, ("\n"))
14264667Smh27603 }
14274667Smh27603 #endif /* DEBUG */
1428