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