1*4667Smh27603 /* 2*4667Smh27603 * CDDL HEADER START 3*4667Smh27603 * 4*4667Smh27603 * The contents of this file are subject to the terms of the 5*4667Smh27603 * Common Development and Distribution License (the "License"). 6*4667Smh27603 * You may not use this file except in compliance with the License. 7*4667Smh27603 * 8*4667Smh27603 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*4667Smh27603 * or http://www.opensolaris.org/os/licensing. 10*4667Smh27603 * See the License for the specific language governing permissions 11*4667Smh27603 * and limitations under the License. 12*4667Smh27603 * 13*4667Smh27603 * When distributing Covered Code, include this CDDL HEADER in each 14*4667Smh27603 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*4667Smh27603 * If applicable, add the following below this CDDL HEADER, with the 16*4667Smh27603 * fields enclosed by brackets "[]" replaced with your own identifying 17*4667Smh27603 * information: Portions Copyright [yyyy] [name of copyright owner] 18*4667Smh27603 * 19*4667Smh27603 * CDDL HEADER END 20*4667Smh27603 */ 21*4667Smh27603 /* 22*4667Smh27603 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*4667Smh27603 * Use is subject to license terms. 24*4667Smh27603 */ 25*4667Smh27603 26*4667Smh27603 #pragma ident "%Z%%M% %I% %E% SMI" 27*4667Smh27603 28*4667Smh27603 /* 29*4667Smh27603 * ppm driver subroutines 30*4667Smh27603 */ 31*4667Smh27603 32*4667Smh27603 #include <sys/open.h> 33*4667Smh27603 #include <sys/file.h> 34*4667Smh27603 #include <sys/conf.h> 35*4667Smh27603 #include <sys/epm.h> 36*4667Smh27603 #include <sys/sunldi.h> 37*4667Smh27603 #include <sys/ppmvar.h> 38*4667Smh27603 #include <sys/ppmio.h> 39*4667Smh27603 #include <sys/promif.h> 40*4667Smh27603 #include <sys/ddi_impldefs.h> 41*4667Smh27603 #include <sys/ddi.h> 42*4667Smh27603 #include <sys/sunddi.h> 43*4667Smh27603 /* 44*4667Smh27603 * Append address to the device path, if it is set. Routine 45*4667Smh27603 * ddi_pathname does not look for device address if the node is in 46*4667Smh27603 * DS_INITIALIZED state. 47*4667Smh27603 */ 48*4667Smh27603 #define PPM_GET_PATHNAME(dip, path) \ 49*4667Smh27603 (void) ddi_pathname((dip), (path)); \ 50*4667Smh27603 if ((i_ddi_node_state((dip)) < DS_INITIALIZED) && \ 51*4667Smh27603 (ddi_get_name_addr((dip)) != NULL)) { \ 52*4667Smh27603 (void) strcat((path), "@"); \ 53*4667Smh27603 (void) strcat((path), ddi_get_name_addr((dip)));\ 54*4667Smh27603 } 55*4667Smh27603 56*4667Smh27603 int ppm_parse_dc(char **, ppm_dc_t *); 57*4667Smh27603 int ppm_match_devs(char *, ppm_db_t *); 58*4667Smh27603 ppm_db_t *ppm_parse_pattern(struct ppm_db **, char *); 59*4667Smh27603 int ppm_count_char(char *, char); 60*4667Smh27603 int ppm_stoi(char *, uint_t *); 61*4667Smh27603 int ppm_convert(char *, uint_t *); 62*4667Smh27603 void ppm_prop_free(struct ppm_cdata **); 63*4667Smh27603 64*4667Smh27603 /* 65*4667Smh27603 * lookup string property from configuration file ppm.conf 66*4667Smh27603 */ 67*4667Smh27603 static int 68*4667Smh27603 ppm_get_confdata(struct ppm_cdata **cdp, dev_info_t *dip) 69*4667Smh27603 { 70*4667Smh27603 #ifdef DEBUG 71*4667Smh27603 char *str = "ppm_get_confdata"; 72*4667Smh27603 #endif 73*4667Smh27603 struct ppm_cdata *cinfo; 74*4667Smh27603 int err; 75*4667Smh27603 76*4667Smh27603 for (; (cinfo = *cdp) != NULL; cdp++) { 77*4667Smh27603 err = ddi_prop_lookup_string_array( 78*4667Smh27603 DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 79*4667Smh27603 cinfo->name, &cinfo->strings, &cinfo->cnt); 80*4667Smh27603 if (err != DDI_PROP_SUCCESS) { 81*4667Smh27603 PPMD(D_ERROR, ("%s: no %s found, err(%d)\n", 82*4667Smh27603 str, cinfo->name, err)) 83*4667Smh27603 break; 84*4667Smh27603 } 85*4667Smh27603 } 86*4667Smh27603 return (err); 87*4667Smh27603 } 88*4667Smh27603 89*4667Smh27603 void 90*4667Smh27603 ppm_prop_free(struct ppm_cdata **cdp) 91*4667Smh27603 { 92*4667Smh27603 if (cdp) { 93*4667Smh27603 for (; *cdp; cdp++) { 94*4667Smh27603 if ((*cdp)->name) { 95*4667Smh27603 kmem_free((*cdp)->name, 96*4667Smh27603 strlen((*cdp)->name) + 1); 97*4667Smh27603 (*cdp)->name = NULL; 98*4667Smh27603 } 99*4667Smh27603 if ((*cdp)->strings) { 100*4667Smh27603 ddi_prop_free((*cdp)->strings); 101*4667Smh27603 (*cdp)->strings = NULL; 102*4667Smh27603 } 103*4667Smh27603 } 104*4667Smh27603 } 105*4667Smh27603 } 106*4667Smh27603 107*4667Smh27603 108*4667Smh27603 /* 109*4667Smh27603 * free ddi prop strings. Under error condition, free ppm_db_t lists as well. 110*4667Smh27603 */ 111*4667Smh27603 static int 112*4667Smh27603 ppm_attach_err(struct ppm_cdata **cdp, int err) 113*4667Smh27603 { 114*4667Smh27603 ppm_domain_t *domp; 115*4667Smh27603 ppm_db_t *db, *tmp; 116*4667Smh27603 117*4667Smh27603 ppm_prop_free(cdp); 118*4667Smh27603 if (err != DDI_SUCCESS) { 119*4667Smh27603 for (domp = ppm_domain_p; domp; domp = domp->next) { 120*4667Smh27603 for (db = domp->conflist; (tmp = db) != NULL; ) { 121*4667Smh27603 db = db->next; 122*4667Smh27603 kmem_free(tmp->name, strlen(tmp->name) + 1); 123*4667Smh27603 kmem_free(tmp, sizeof (*tmp)); 124*4667Smh27603 } 125*4667Smh27603 domp->conflist = NULL; 126*4667Smh27603 } 127*4667Smh27603 err = DDI_FAILURE; 128*4667Smh27603 } 129*4667Smh27603 130*4667Smh27603 return (err); 131*4667Smh27603 } 132*4667Smh27603 133*4667Smh27603 134*4667Smh27603 ppm_domain_t * 135*4667Smh27603 ppm_lookup_domain(char *dname) 136*4667Smh27603 { 137*4667Smh27603 ppm_domain_t *domp; 138*4667Smh27603 139*4667Smh27603 for (domp = ppm_domain_p; domp; domp = domp->next) { 140*4667Smh27603 if (strcmp(dname, domp->name) == 0) 141*4667Smh27603 break; 142*4667Smh27603 } 143*4667Smh27603 return (domp); 144*4667Smh27603 } 145*4667Smh27603 146*4667Smh27603 147*4667Smh27603 /* 148*4667Smh27603 * for the purpose of optimizing we search for identical dc->path 149*4667Smh27603 * that has been opened per previous visit here. If search results 150*4667Smh27603 * in a hit, copy the device handle, else open the device. 151*4667Smh27603 */ 152*4667Smh27603 ppm_dc_t * 153*4667Smh27603 ppm_lookup_hndl(int model, ppm_dc_t *key_dc) 154*4667Smh27603 { 155*4667Smh27603 #ifdef DEBUG 156*4667Smh27603 char *str = "ppm_lookup_hndl"; 157*4667Smh27603 #endif 158*4667Smh27603 char *key_path = key_dc->path; 159*4667Smh27603 ppm_domain_t *domp; 160*4667Smh27603 ppm_dc_t *dc; 161*4667Smh27603 162*4667Smh27603 /* search domain by domain.model */ 163*4667Smh27603 for (domp = ppm_domain_p; domp; domp = domp->next) { 164*4667Smh27603 if (domp->model == model) 165*4667Smh27603 break; 166*4667Smh27603 } 167*4667Smh27603 168*4667Smh27603 /* lookup hndl from same domain model */ 169*4667Smh27603 if (domp && PPM_DOMAIN_UP(domp)) { 170*4667Smh27603 for (dc = domp->dc; dc; dc = dc->next) { 171*4667Smh27603 if ((strcmp(dc->path, key_path) == 0) && 172*4667Smh27603 (dc->lh != NULL)) { 173*4667Smh27603 PPMD(D_PPMDC, ("%s: Hit(dc_path:%s) from SAME " 174*4667Smh27603 "domain %s.\n", str, key_path, domp->name)) 175*4667Smh27603 key_dc->lh = dc->lh; 176*4667Smh27603 return (key_dc); 177*4667Smh27603 } 178*4667Smh27603 } 179*4667Smh27603 } 180*4667Smh27603 181*4667Smh27603 /* otherwise, check other domains */ 182*4667Smh27603 for (domp = ppm_domain_p; 183*4667Smh27603 domp && (domp->model != model); domp = domp->next) { 184*4667Smh27603 if (PPM_DOMAIN_UP(domp)) { 185*4667Smh27603 for (dc = domp->dc; dc; dc = dc->next) { 186*4667Smh27603 if ((strcmp(dc->path, key_path) == 0) && 187*4667Smh27603 (dc->lh != NULL)) { 188*4667Smh27603 PPMD(D_PPMDC, ("%s: Hit(dc_path:%s) " 189*4667Smh27603 "from domain %s\n", 190*4667Smh27603 str, key_path, domp->name)) 191*4667Smh27603 key_dc->lh = dc->lh; 192*4667Smh27603 return (key_dc); 193*4667Smh27603 } 194*4667Smh27603 } 195*4667Smh27603 } 196*4667Smh27603 } 197*4667Smh27603 198*4667Smh27603 PPMD(D_PPMDC, ("%s: Miss(dc_path:%s)\n", str, key_path)) 199*4667Smh27603 return (NULL); 200*4667Smh27603 } 201*4667Smh27603 202*4667Smh27603 203*4667Smh27603 #define PPM_DOMAIN_PROP "ppm-domains" 204*4667Smh27603 #define PPM_DEV_PROP_SUFFIX "-devices" 205*4667Smh27603 #define PPM_MODEL_PROP_SUFFIX "-model" 206*4667Smh27603 #define PPM_PROPNAME_PROP_SUFFIX "-propname" 207*4667Smh27603 #define PPM_CTRL_PROP_SUFFIX "-control" 208*4667Smh27603 209*4667Smh27603 struct ppm_domit ppm_domit_data[] = { 210*4667Smh27603 "CPU", PPMD_CPU, PPMD_LOCK_ALL, PPMD_ON, 211*4667Smh27603 "FET", PPMD_FET, PPMD_LOCK_ONE, PPMD_ON, 212*4667Smh27603 "PCI", PPMD_PCI, PPMD_LOCK_ONE, PPMD_ON, 213*4667Smh27603 "PCI_PROP", PPMD_PCI_PROP, PPMD_LOCK_ONE, PPMD_ON, 214*4667Smh27603 "LED", PPMD_LED, 0, PPMD_ON, 215*4667Smh27603 "PCIE", PPMD_PCIE, PPMD_LOCK_ONE, PPMD_ON, 216*4667Smh27603 NULL 217*4667Smh27603 }; 218*4667Smh27603 219*4667Smh27603 /* 220*4667Smh27603 * store up platform dependent information provided by ppm.conf file 221*4667Smh27603 * into private data base 222*4667Smh27603 */ 223*4667Smh27603 int 224*4667Smh27603 ppm_create_db(dev_info_t *dip) 225*4667Smh27603 { 226*4667Smh27603 #ifdef DEBUG 227*4667Smh27603 char *str = "ppm_create_db"; 228*4667Smh27603 #endif 229*4667Smh27603 ppm_domain_t *domp; 230*4667Smh27603 ppm_db_t *db; 231*4667Smh27603 ppm_dc_t *dc; 232*4667Smh27603 struct ppm_cdata domdata; /* hold "ppm-domains" property */ 233*4667Smh27603 struct ppm_cdata modeldata; /* hold "domain_xy-model" property */ 234*4667Smh27603 struct ppm_cdata propnamedata; /* hold "domain_xy-propname" property */ 235*4667Smh27603 struct ppm_cdata devdata; /* hold "domain_xy-devices" property */ 236*4667Smh27603 struct ppm_cdata dcdata; /* hold "domain_xy-control" property */ 237*4667Smh27603 struct ppm_cdata *cdata[2]; 238*4667Smh27603 char **dom_namep, **model_namep, **dev_namep, **dc_namep; 239*4667Smh27603 struct ppm_domit *domit_p; 240*4667Smh27603 int err; 241*4667Smh27603 242*4667Smh27603 /* 243*4667Smh27603 * get "ppm-domains" property 244*4667Smh27603 */ 245*4667Smh27603 bzero(&domdata, sizeof (domdata)); 246*4667Smh27603 domdata.name = kmem_zalloc(strlen(PPM_DOMAIN_PROP) + 1, KM_SLEEP); 247*4667Smh27603 (void) strcpy(domdata.name, PPM_DOMAIN_PROP); 248*4667Smh27603 cdata[0] = &domdata; 249*4667Smh27603 cdata[1] = NULL; 250*4667Smh27603 if (err = ppm_get_confdata(cdata, dip)) { 251*4667Smh27603 PPMD(D_CREATEDB, ("%s: failed to get prop \"%s\"!\n", 252*4667Smh27603 str, PPM_DOMAIN_PROP)) 253*4667Smh27603 return (ppm_attach_err(cdata, err)); 254*4667Smh27603 } 255*4667Smh27603 256*4667Smh27603 for (dom_namep = domdata.strings; *dom_namep; dom_namep++) { 257*4667Smh27603 domp = kmem_zalloc(sizeof (*domp), KM_SLEEP); 258*4667Smh27603 domp->name = kmem_zalloc(strlen(*dom_namep) + 1, KM_SLEEP); 259*4667Smh27603 (void) strcpy(domp->name, *dom_namep); 260*4667Smh27603 mutex_init(&domp->lock, NULL, MUTEX_DRIVER, NULL); 261*4667Smh27603 if (ppm_domain_p == NULL) 262*4667Smh27603 ppm_domain_p = domp; 263*4667Smh27603 else { 264*4667Smh27603 domp->next = ppm_domain_p; 265*4667Smh27603 ppm_domain_p = domp; 266*4667Smh27603 } 267*4667Smh27603 } 268*4667Smh27603 ppm_prop_free(cdata); 269*4667Smh27603 270*4667Smh27603 /* 271*4667Smh27603 * more per domain property strings in ppm.conf file tell us 272*4667Smh27603 * what the nature of domain, how to performe domain control, etc. 273*4667Smh27603 * Even the property names of those per domain properties are 274*4667Smh27603 * formed consisting its domain name string. 275*4667Smh27603 * Here we walk through our domain list, and fullfill the details. 276*4667Smh27603 */ 277*4667Smh27603 for (domp = ppm_domain_p; domp; domp = domp->next) { 278*4667Smh27603 size_t plen; 279*4667Smh27603 280*4667Smh27603 /* 281*4667Smh27603 * get "domain_xy-model" property 282*4667Smh27603 */ 283*4667Smh27603 bzero(&modeldata, sizeof (modeldata)); 284*4667Smh27603 plen = strlen(domp->name) + strlen(PPM_MODEL_PROP_SUFFIX) + 1; 285*4667Smh27603 modeldata.name = kmem_zalloc(plen, KM_SLEEP); 286*4667Smh27603 (void) sprintf(modeldata.name, "%s%s", 287*4667Smh27603 domp->name, PPM_MODEL_PROP_SUFFIX); 288*4667Smh27603 289*4667Smh27603 cdata[0] = &modeldata; 290*4667Smh27603 cdata[1] = NULL; 291*4667Smh27603 if (err = ppm_get_confdata(cdata, dip)) { 292*4667Smh27603 PPMD(D_CREATEDB, ("%s: Can't read property %s!\n", 293*4667Smh27603 str, modeldata.name)) 294*4667Smh27603 return (ppm_attach_err(cdata, err)); 295*4667Smh27603 } 296*4667Smh27603 297*4667Smh27603 model_namep = modeldata.strings; 298*4667Smh27603 for (domit_p = ppm_domit_data; domit_p->name; domit_p++) { 299*4667Smh27603 if (strcmp(domit_p->name, *model_namep) == 0) { 300*4667Smh27603 domp->model = domit_p->model; 301*4667Smh27603 domp->dflags = domit_p->dflags; 302*4667Smh27603 domp->status = domit_p->status; 303*4667Smh27603 break; 304*4667Smh27603 } 305*4667Smh27603 } 306*4667Smh27603 ASSERT(domit_p); 307*4667Smh27603 308*4667Smh27603 ppm_prop_free(cdata); 309*4667Smh27603 310*4667Smh27603 311*4667Smh27603 /* get "domain_xy-propname" property */ 312*4667Smh27603 bzero(&propnamedata, sizeof (propnamedata)); 313*4667Smh27603 plen = strlen(domp->name) + 314*4667Smh27603 strlen(PPM_PROPNAME_PROP_SUFFIX) + 1; 315*4667Smh27603 propnamedata.name = kmem_zalloc(plen, KM_SLEEP); 316*4667Smh27603 (void) sprintf(propnamedata.name, "%s%s", 317*4667Smh27603 domp->name, PPM_PROPNAME_PROP_SUFFIX); 318*4667Smh27603 319*4667Smh27603 cdata[0] = &propnamedata; 320*4667Smh27603 cdata[1] = NULL; 321*4667Smh27603 if (ppm_get_confdata(cdata, dip) == DDI_PROP_SUCCESS) { 322*4667Smh27603 domp->propname = kmem_zalloc( 323*4667Smh27603 (strlen(*propnamedata.strings) + 1), KM_SLEEP); 324*4667Smh27603 (void) strcpy(domp->propname, *propnamedata.strings); 325*4667Smh27603 PPMD(D_CREATEDB, ("%s: %s has property name: %s\n", 326*4667Smh27603 str, domp->name, domp->propname)) 327*4667Smh27603 } 328*4667Smh27603 ppm_prop_free(cdata); 329*4667Smh27603 330*4667Smh27603 331*4667Smh27603 /* get "domain_xy-devices" property */ 332*4667Smh27603 bzero(&devdata, sizeof (devdata)); 333*4667Smh27603 plen = strlen(domp->name) + strlen(PPM_DEV_PROP_SUFFIX) + 1; 334*4667Smh27603 devdata.name = kmem_zalloc(plen, KM_SLEEP); 335*4667Smh27603 (void) sprintf(devdata.name, "%s%s", 336*4667Smh27603 domp->name, PPM_DEV_PROP_SUFFIX); 337*4667Smh27603 338*4667Smh27603 cdata[0] = &devdata; 339*4667Smh27603 cdata[1] = NULL; 340*4667Smh27603 if (err = ppm_get_confdata(cdata, dip)) { 341*4667Smh27603 PPMD(D_CREATEDB, ("%s: Can't read property %s!\n", 342*4667Smh27603 str, devdata.name)) 343*4667Smh27603 return (ppm_attach_err(cdata, err)); 344*4667Smh27603 } 345*4667Smh27603 346*4667Smh27603 for (dev_namep = devdata.strings; *dev_namep; dev_namep++) { 347*4667Smh27603 if (!ppm_parse_pattern(&db, *dev_namep)) 348*4667Smh27603 return (ppm_attach_err(cdata, err)); 349*4667Smh27603 db->next = domp->conflist; 350*4667Smh27603 domp->conflist = db; 351*4667Smh27603 PPMD(D_CREATEDB, ("%s: %s add pattern: %s \n", 352*4667Smh27603 str, devdata.name, db->name)) 353*4667Smh27603 } 354*4667Smh27603 PPMD(D_CREATEDB, ("\n")) 355*4667Smh27603 ppm_prop_free(cdata); 356*4667Smh27603 357*4667Smh27603 358*4667Smh27603 /* get "domain_xy-control" property */ 359*4667Smh27603 bzero(&dcdata, sizeof (dcdata)); 360*4667Smh27603 plen = strlen(domp->name) + strlen(PPM_CTRL_PROP_SUFFIX) + 1; 361*4667Smh27603 dcdata.name = kmem_zalloc(plen, KM_SLEEP); 362*4667Smh27603 (void) sprintf(dcdata.name, "%s%s", 363*4667Smh27603 domp->name, PPM_CTRL_PROP_SUFFIX); 364*4667Smh27603 365*4667Smh27603 cdata[0] = &dcdata; 366*4667Smh27603 cdata[1] = NULL; 367*4667Smh27603 if (ppm_get_confdata(cdata, dip) == DDI_PROP_SUCCESS) { 368*4667Smh27603 for (dc_namep = dcdata.strings; *dc_namep; 369*4667Smh27603 dc_namep++) { 370*4667Smh27603 dc = kmem_zalloc(sizeof (*dc), KM_SLEEP); 371*4667Smh27603 dc->next = domp->dc; 372*4667Smh27603 domp->dc = dc; 373*4667Smh27603 err = ppm_parse_dc(dc_namep, domp->dc); 374*4667Smh27603 if (err != DDI_SUCCESS) 375*4667Smh27603 return (ppm_attach_err(cdata, err)); 376*4667Smh27603 } 377*4667Smh27603 } 378*4667Smh27603 ppm_prop_free(cdata); 379*4667Smh27603 #ifdef DEBUG 380*4667Smh27603 dc = domp->dc; 381*4667Smh27603 while (dc) { 382*4667Smh27603 ppm_print_dc(dc); 383*4667Smh27603 dc = dc->next; 384*4667Smh27603 } 385*4667Smh27603 #endif 386*4667Smh27603 } 387*4667Smh27603 388*4667Smh27603 return (DDI_SUCCESS); 389*4667Smh27603 } 390*4667Smh27603 391*4667Smh27603 392*4667Smh27603 /* 393*4667Smh27603 * scan conf devices within each domain for a matching device name 394*4667Smh27603 */ 395*4667Smh27603 ppm_domain_t * 396*4667Smh27603 ppm_lookup_dev(dev_info_t *dip) 397*4667Smh27603 { 398*4667Smh27603 char path[MAXNAMELEN]; 399*4667Smh27603 ppm_domain_t *domp; 400*4667Smh27603 ppm_db_t *dbp; 401*4667Smh27603 402*4667Smh27603 PPM_GET_PATHNAME(dip, path); 403*4667Smh27603 for (domp = ppm_domain_p; domp; domp = domp->next) { 404*4667Smh27603 if (PPM_DOMAIN_UP(domp)) 405*4667Smh27603 for (dbp = domp->conflist; dbp; dbp = dbp->next) { 406*4667Smh27603 if (ppm_match_devs(path, dbp) == 0) 407*4667Smh27603 return (domp); 408*4667Smh27603 } 409*4667Smh27603 } 410*4667Smh27603 411*4667Smh27603 return (NULL); 412*4667Smh27603 } 413*4667Smh27603 414*4667Smh27603 415*4667Smh27603 /* 416*4667Smh27603 * check ppm.conf file domain device pathname syntax, if correct, 417*4667Smh27603 * create device match pattern. 418*4667Smh27603 * return 1 for good, -1 for bad. 419*4667Smh27603 */ 420*4667Smh27603 ppm_db_t * 421*4667Smh27603 ppm_parse_pattern(struct ppm_db **dbpp, char *dev_path) 422*4667Smh27603 { 423*4667Smh27603 char path[MAXNAMELEN]; 424*4667Smh27603 int wccnt, i; 425*4667Smh27603 int wcpos[2]; 426*4667Smh27603 int pos; 427*4667Smh27603 char *cp; 428*4667Smh27603 ppm_db_t *dbp; 429*4667Smh27603 430*4667Smh27603 (void) strcpy(path, dev_path); 431*4667Smh27603 if ((wccnt = ppm_count_char(path, '*')) > 2) 432*4667Smh27603 return (NULL); 433*4667Smh27603 434*4667Smh27603 for (i = 0, cp = path, pos = 0; i < wccnt; i++, cp++, pos++) { 435*4667Smh27603 for (; *cp; cp++, pos++) 436*4667Smh27603 if (*cp == '*') 437*4667Smh27603 break; 438*4667Smh27603 wcpos[i] = pos; 439*4667Smh27603 PPMD(D_CREATEDB, (" wildcard #%d, pos %d\n", 440*4667Smh27603 (i + 1), wcpos[i])) 441*4667Smh27603 } 442*4667Smh27603 443*4667Smh27603 #ifdef DEBUG 444*4667Smh27603 /* first '*', if exists, don't go beyond the string */ 445*4667Smh27603 if (wccnt > 0) 446*4667Smh27603 ASSERT(wcpos[0] < strlen(path)); 447*4667Smh27603 448*4667Smh27603 /* second '*', if exists, better be the last character */ 449*4667Smh27603 if (wccnt == 2) 450*4667Smh27603 ASSERT(wcpos[1] == (strlen(path) - 1)); 451*4667Smh27603 #endif 452*4667Smh27603 453*4667Smh27603 /* 454*4667Smh27603 * first '*', if followed by any char, must be immediately 455*4667Smh27603 * followed by '@' and the rest better be bound by 456*4667Smh27603 * ['0-9', 'a-f', A-F'] until ended '0' or second '*''0'. 457*4667Smh27603 */ 458*4667Smh27603 if ((wccnt > 0) && (wcpos[0] < (strlen(path) - 1))) { 459*4667Smh27603 cp = path + wcpos[0] + 1; 460*4667Smh27603 if (*cp != '@') 461*4667Smh27603 return (NULL); 462*4667Smh27603 463*4667Smh27603 if (!(((*(++cp) > '0') && (*cp < '9')) || 464*4667Smh27603 ((*cp > 'a') && (*cp < 'f')) || 465*4667Smh27603 ((*cp > 'A') && (*cp < 'F')))) 466*4667Smh27603 return (NULL); 467*4667Smh27603 } 468*4667Smh27603 469*4667Smh27603 dbp = kmem_zalloc(sizeof (struct ppm_db), KM_SLEEP); 470*4667Smh27603 dbp->name = kmem_zalloc((strlen(path) + 1), KM_SLEEP); 471*4667Smh27603 (void) strcpy(dbp->name, path); 472*4667Smh27603 dbp->wccnt = wccnt; 473*4667Smh27603 dbp->wcpos[0] = (wccnt > 0) ? wcpos[0] : -1; 474*4667Smh27603 dbp->wcpos[1] = (wccnt == 2) ? wcpos[1] : -1; 475*4667Smh27603 476*4667Smh27603 return (*dbpp = dbp); 477*4667Smh27603 } 478*4667Smh27603 479*4667Smh27603 480*4667Smh27603 /* 481*4667Smh27603 * match given device "path" to domain device pathname 482*4667Smh27603 * pattern dbp->name that contains one or two '*' character(s). 483*4667Smh27603 * Matching policy: 484*4667Smh27603 * 1). If one wildcard terminates match pattern, need exact match 485*4667Smh27603 * up to (but exclude) the wildcard; 486*4667Smh27603 * 2). If one wildcard does not terminate match pattern, it is to 487*4667Smh27603 * match driver name (terminates with '@') and must be followed 488*4667Smh27603 * by exact match of rest of pattern; 489*4667Smh27603 * 3). If two wildcards, first is to match driver name as in 2), 490*4667Smh27603 * second is to match fcnid (terminates with '/' or '\0') and 491*4667Smh27603 * must the last char of pattern. 492*4667Smh27603 * 493*4667Smh27603 * return 0 if match, and 494*4667Smh27603 * non 0 if mismatch 495*4667Smh27603 */ 496*4667Smh27603 int 497*4667Smh27603 ppm_match_devs(char *dev_path, ppm_db_t *dbp) 498*4667Smh27603 { 499*4667Smh27603 char path[MAXNAMELEN]; 500*4667Smh27603 char *cp; /* points into "path", real device pathname */ 501*4667Smh27603 char *np; /* points into "dbp->name", the pattern */ 502*4667Smh27603 int len; 503*4667Smh27603 504*4667Smh27603 if (dbp->wccnt == 0) 505*4667Smh27603 return (strcmp(dev_path, dbp->name)); 506*4667Smh27603 507*4667Smh27603 (void) strcpy(path, dev_path); 508*4667Smh27603 509*4667Smh27603 /* match upto the first '*' regardless */ 510*4667Smh27603 if (strncmp(path, dbp->name, dbp->wcpos[0]) != 0) 511*4667Smh27603 return (-1); 512*4667Smh27603 513*4667Smh27603 514*4667Smh27603 /* "<exact match>*" */ 515*4667Smh27603 if (dbp->name[dbp->wcpos[0] + 1] == 0) { 516*4667Smh27603 cp = path + dbp->wcpos[0]; 517*4667Smh27603 while (*cp && (*cp++ != '/')); 518*4667Smh27603 return ((*cp == 0) ? 0 : -1); 519*4667Smh27603 } 520*4667Smh27603 521*4667Smh27603 522*4667Smh27603 /* locate '@' */ 523*4667Smh27603 cp = path + dbp->wcpos[0] + 1; 524*4667Smh27603 while (*cp && *cp != '@') 525*4667Smh27603 cp++; 526*4667Smh27603 527*4667Smh27603 np = dbp->name + dbp->wcpos[0] + 1; 528*4667Smh27603 529*4667Smh27603 /* if one wildcard, match the rest in the pattern */ 530*4667Smh27603 if (dbp->wccnt == 1) 531*4667Smh27603 return ((strcmp(cp, np) == 0) ? 0 : (-1)); 532*4667Smh27603 533*4667Smh27603 534*4667Smh27603 /* must have exact match after first wildcard up to second */ 535*4667Smh27603 ASSERT(dbp->wccnt == 2); 536*4667Smh27603 len = dbp->wcpos[1] - dbp->wcpos[0] - 1; 537*4667Smh27603 if (strncmp(cp, np, len) != 0) 538*4667Smh27603 return (-1); 539*4667Smh27603 540*4667Smh27603 /* second wildcard match terminates with '/' or '\0' */ 541*4667Smh27603 /* but only termination with '\0' is a successful match */ 542*4667Smh27603 cp += len; 543*4667Smh27603 while (*cp && (*cp != '/')) 544*4667Smh27603 cp++; 545*4667Smh27603 return ((*cp == 0) ? 0 : -1); 546*4667Smh27603 } 547*4667Smh27603 548*4667Smh27603 549*4667Smh27603 /* 550*4667Smh27603 * By claiming a device, ppm gets involved in its power change 551*4667Smh27603 * process: handles additional issues prior and/or post its 552*4667Smh27603 * power(9e) call. 553*4667Smh27603 * 554*4667Smh27603 * If 'dip' is a PCI device, this is the time to ask its parent 555*4667Smh27603 * what PCI bus speed it is running. 556*4667Smh27603 * 557*4667Smh27603 * returns 1 (claimed), 0 (not claimed) 558*4667Smh27603 */ 559*4667Smh27603 int 560*4667Smh27603 ppm_claim_dev(dev_info_t *dip) 561*4667Smh27603 { 562*4667Smh27603 ppm_domain_t *domp; 563*4667Smh27603 dev_info_t *pdip; 564*4667Smh27603 uint_t pciclk; 565*4667Smh27603 int claimed = -1; 566*4667Smh27603 567*4667Smh27603 domp = ppm_lookup_dev(dip); 568*4667Smh27603 if (!domp) 569*4667Smh27603 claimed = 0; 570*4667Smh27603 571*4667Smh27603 if (domp && PPMD_IS_PCI(domp->model) && 572*4667Smh27603 ! (domp->dflags & (PPMD_PCI33MHZ | PPMD_PCI66MHZ))) { 573*4667Smh27603 pdip = ddi_get_parent(dip); 574*4667Smh27603 ASSERT(pdip); 575*4667Smh27603 pciclk = ddi_prop_get_int(DDI_DEV_T_ANY, pdip, 576*4667Smh27603 DDI_PROP_DONTPASS, "clock-frequency", -1); 577*4667Smh27603 578*4667Smh27603 switch (pciclk) { 579*4667Smh27603 case 33000000: 580*4667Smh27603 domp->dflags |= PPMD_PCI33MHZ; 581*4667Smh27603 claimed = 1; 582*4667Smh27603 break; 583*4667Smh27603 case 66000000: 584*4667Smh27603 domp->dflags |= PPMD_PCI66MHZ; 585*4667Smh27603 claimed = 1; 586*4667Smh27603 break; 587*4667Smh27603 default: 588*4667Smh27603 claimed = 0; 589*4667Smh27603 break; 590*4667Smh27603 } 591*4667Smh27603 } 592*4667Smh27603 593*4667Smh27603 if (domp && (claimed == -1)) 594*4667Smh27603 claimed = 1; 595*4667Smh27603 596*4667Smh27603 #ifdef DEBUG 597*4667Smh27603 if (claimed) { 598*4667Smh27603 char path[MAXNAMELEN]; 599*4667Smh27603 PPMD(D_CLAIMDEV, ("ppm_claim_dev: %s into domain %s\n", 600*4667Smh27603 ddi_pathname(dip, path), domp->name)) 601*4667Smh27603 } 602*4667Smh27603 603*4667Smh27603 #endif 604*4667Smh27603 605*4667Smh27603 return (claimed); 606*4667Smh27603 } 607*4667Smh27603 608*4667Smh27603 /* 609*4667Smh27603 * add a device to the list of domain's owned devices (if it is not already 610*4667Smh27603 * on the list). 611*4667Smh27603 */ 612*4667Smh27603 ppm_owned_t * 613*4667Smh27603 ppm_add_owned(dev_info_t *dip, ppm_domain_t *domp) 614*4667Smh27603 { 615*4667Smh27603 char path[MAXNAMELEN]; 616*4667Smh27603 ppm_owned_t *owned, *new_owned; 617*4667Smh27603 618*4667Smh27603 ASSERT(MUTEX_HELD(&domp->lock)); 619*4667Smh27603 PPM_GET_PATHNAME(dip, path); 620*4667Smh27603 for (owned = domp->owned; owned; owned = owned->next) 621*4667Smh27603 if (strcmp(path, owned->path) == 0) 622*4667Smh27603 return (owned); 623*4667Smh27603 624*4667Smh27603 new_owned = kmem_zalloc(sizeof (*new_owned), KM_SLEEP); 625*4667Smh27603 new_owned->path = kmem_zalloc(strlen(path) + 1, KM_SLEEP); 626*4667Smh27603 (void) strcpy(new_owned->path, path); 627*4667Smh27603 new_owned->next = domp->owned; 628*4667Smh27603 domp->owned = new_owned; 629*4667Smh27603 630*4667Smh27603 return (domp->owned); 631*4667Smh27603 } 632*4667Smh27603 633*4667Smh27603 /* 634*4667Smh27603 * create/init a new ppm device and link into the domain 635*4667Smh27603 */ 636*4667Smh27603 ppm_dev_t * 637*4667Smh27603 ppm_add_dev(dev_info_t *dip, ppm_domain_t *domp) 638*4667Smh27603 { 639*4667Smh27603 char path[MAXNAMELEN]; 640*4667Smh27603 ppm_dev_t *new = NULL; 641*4667Smh27603 int cmpt; 642*4667Smh27603 ppm_owned_t *owned; 643*4667Smh27603 644*4667Smh27603 ASSERT(MUTEX_HELD(&domp->lock)); 645*4667Smh27603 (void) ddi_pathname(dip, path); 646*4667Smh27603 /* 647*4667Smh27603 * For devs which have exported "pm-components" we want to create 648*4667Smh27603 * a data structure for each component. When a driver chooses not 649*4667Smh27603 * to export the prop we treat its device as having a single 650*4667Smh27603 * component and build a structure for it anyway. All other ppm 651*4667Smh27603 * logic will act as if this device were always up and can thus 652*4667Smh27603 * make correct decisions about it in relation to other devices 653*4667Smh27603 * in its domain. 654*4667Smh27603 */ 655*4667Smh27603 for (cmpt = PM_GET_PM_INFO(dip) ? PM_NUMCMPTS(dip) : 1; cmpt--; ) { 656*4667Smh27603 new = kmem_zalloc(sizeof (*new), KM_SLEEP); 657*4667Smh27603 new->path = kmem_zalloc(strlen(path) + 1, KM_SLEEP); 658*4667Smh27603 (void) strcpy(new->path, path); 659*4667Smh27603 new->domp = domp; 660*4667Smh27603 new->dip = dip; 661*4667Smh27603 new->cmpt = cmpt; 662*4667Smh27603 ppm_dev_init(new); 663*4667Smh27603 new->next = domp->devlist; 664*4667Smh27603 domp->devlist = new; 665*4667Smh27603 PPMD(D_ADDDEV, 666*4667Smh27603 ("ppm_add_dev: %s to domain %s: ppm_dev(0x%p)\n", 667*4667Smh27603 new->path, domp->name, (void *)new)) 668*4667Smh27603 } 669*4667Smh27603 670*4667Smh27603 ASSERT(new != NULL); 671*4667Smh27603 /* 672*4667Smh27603 * devi_pm_ppm_private should be set only after all 673*4667Smh27603 * ppm_dev s related to all components have been 674*4667Smh27603 * initialized and domain's pwr_cnt is incremented 675*4667Smh27603 * for each of them. 676*4667Smh27603 */ 677*4667Smh27603 PPM_SET_PRIVATE(dip, new); 678*4667Smh27603 679*4667Smh27603 /* remember this device forever */ 680*4667Smh27603 owned = ppm_add_owned(dip, domp); 681*4667Smh27603 682*4667Smh27603 /* 683*4667Smh27603 * Initializing flag is set for devices which have gone through 684*4667Smh27603 * PPM_PMR_INIT_CHILD ctlop. By this point, these devices have 685*4667Smh27603 * been added to ppm structures and could participate in pm 686*4667Smh27603 * decision making, so clear the initializing flag. 687*4667Smh27603 */ 688*4667Smh27603 if (owned->initializing) { 689*4667Smh27603 owned->initializing = 0; 690*4667Smh27603 PPMD(D_ADDDEV, ("ppm_add_dev: cleared initializing flag " 691*4667Smh27603 "for %s@%s\n", PM_NAME(dip), 692*4667Smh27603 (PM_ADDR(dip) == NULL) ? "" : PM_ADDR(dip))) 693*4667Smh27603 } 694*4667Smh27603 695*4667Smh27603 return (new); 696*4667Smh27603 } 697*4667Smh27603 698*4667Smh27603 699*4667Smh27603 /* 700*4667Smh27603 * returns an existing or newly created ppm device reference 701*4667Smh27603 */ 702*4667Smh27603 ppm_dev_t * 703*4667Smh27603 ppm_get_dev(dev_info_t *dip, ppm_domain_t *domp) 704*4667Smh27603 { 705*4667Smh27603 ppm_dev_t *pdp; 706*4667Smh27603 707*4667Smh27603 mutex_enter(&domp->lock); 708*4667Smh27603 pdp = PPM_GET_PRIVATE(dip); 709*4667Smh27603 if (pdp == NULL) 710*4667Smh27603 pdp = ppm_add_dev(dip, domp); 711*4667Smh27603 mutex_exit(&domp->lock); 712*4667Smh27603 713*4667Smh27603 return (pdp); 714*4667Smh27603 } 715*4667Smh27603 716*4667Smh27603 717*4667Smh27603 /* 718*4667Smh27603 * scan a domain's device list and remove those with .dip 719*4667Smh27603 * matching the arg *dip; we need to scan the entire list 720*4667Smh27603 * for the case of devices with multiple components 721*4667Smh27603 */ 722*4667Smh27603 void 723*4667Smh27603 ppm_rem_dev(dev_info_t *dip) 724*4667Smh27603 { 725*4667Smh27603 ppm_dev_t *pdp, **devpp; 726*4667Smh27603 ppm_domain_t *domp; 727*4667Smh27603 728*4667Smh27603 pdp = PPM_GET_PRIVATE(dip); 729*4667Smh27603 ASSERT(pdp); 730*4667Smh27603 domp = pdp->domp; 731*4667Smh27603 ASSERT(domp); 732*4667Smh27603 733*4667Smh27603 mutex_enter(&domp->lock); 734*4667Smh27603 for (devpp = &domp->devlist; (pdp = *devpp) != NULL; ) { 735*4667Smh27603 if (pdp->dip != dip) { 736*4667Smh27603 devpp = &pdp->next; 737*4667Smh27603 continue; 738*4667Smh27603 } 739*4667Smh27603 740*4667Smh27603 PPMD(D_REMDEV, ("ppm_rem_dev: path \"%s\", ppm_dev 0x%p\n", 741*4667Smh27603 pdp->path, (void *)pdp)) 742*4667Smh27603 743*4667Smh27603 PPM_SET_PRIVATE(dip, NULL); 744*4667Smh27603 *devpp = pdp->next; 745*4667Smh27603 ppm_dev_fini(pdp); 746*4667Smh27603 kmem_free(pdp->path, strlen(pdp->path) + 1); 747*4667Smh27603 kmem_free(pdp, sizeof (*pdp)); 748*4667Smh27603 } 749*4667Smh27603 mutex_exit(&domp->lock); 750*4667Smh27603 } 751*4667Smh27603 752*4667Smh27603 /* 753*4667Smh27603 * prepare kernel ioctl calls: 754*4667Smh27603 */ 755*4667Smh27603 void 756*4667Smh27603 ppm_init_cb(dev_info_t *dip) 757*4667Smh27603 { 758*4667Smh27603 char *str = "ppm_init_cb"; 759*4667Smh27603 ppm_domain_t *domp; 760*4667Smh27603 ppm_dc_t *dc; 761*4667Smh27603 762*4667Smh27603 for (domp = ppm_domain_p; domp != NULL; domp = domp->next) { 763*4667Smh27603 for (dc = domp->dc; dc; dc = dc->next) { 764*4667Smh27603 if (ppm_lookup_hndl(domp->model, dc) != NULL) 765*4667Smh27603 continue; 766*4667Smh27603 767*4667Smh27603 if (ppm_init_lyr(dc, dip) != DDI_SUCCESS) { 768*4667Smh27603 domp->dflags |= PPMD_OFFLINE; 769*4667Smh27603 cmn_err(CE_WARN, "%s: ppm domain %s will " 770*4667Smh27603 "be offline.", str, domp->name); 771*4667Smh27603 break; 772*4667Smh27603 } 773*4667Smh27603 } 774*4667Smh27603 } 775*4667Smh27603 } 776*4667Smh27603 777*4667Smh27603 778*4667Smh27603 /* 779*4667Smh27603 * ppm_init_lyr - initializing layered ioctl 780*4667Smh27603 * Return: 781*4667Smh27603 * DDI_SUCCESS - succeeded 782*4667Smh27603 * DDI_FAILURE - failed 783*4667Smh27603 * 784*4667Smh27603 */ 785*4667Smh27603 int 786*4667Smh27603 ppm_init_lyr(ppm_dc_t *dc, dev_info_t *dip) 787*4667Smh27603 { 788*4667Smh27603 char *str = "ppm_init_lyr"; 789*4667Smh27603 int err = 0; 790*4667Smh27603 ldi_ident_t li; 791*4667Smh27603 792*4667Smh27603 ASSERT(dc && dc->path); 793*4667Smh27603 794*4667Smh27603 if (err = ldi_ident_from_dip(dip, &li)) { 795*4667Smh27603 cmn_err(CE_WARN, "%s: get ldi identifier " 796*4667Smh27603 "failed (err=%d)", str, err); 797*4667Smh27603 } 798*4667Smh27603 799*4667Smh27603 err = ldi_open_by_name(dc->path, FWRITE|FREAD, kcred, &(dc->lh), li); 800*4667Smh27603 801*4667Smh27603 (void) ldi_ident_release(li); 802*4667Smh27603 803*4667Smh27603 if (err != 0) { 804*4667Smh27603 cmn_err(CE_WARN, "Failed to open device(%s), rv(%d)", 805*4667Smh27603 dc->path, err); 806*4667Smh27603 return (err); 807*4667Smh27603 } 808*4667Smh27603 809*4667Smh27603 return (DDI_SUCCESS); 810*4667Smh27603 } 811*4667Smh27603 812*4667Smh27603 /* 813*4667Smh27603 * lock, unlock, or trylock for one power mutex 814*4667Smh27603 */ 815*4667Smh27603 void 816*4667Smh27603 ppm_lock_one(ppm_dev_t *ppmd, power_req_t *reqp, int *iresp) 817*4667Smh27603 { 818*4667Smh27603 switch (reqp->request_type) { 819*4667Smh27603 case PMR_PPM_LOCK_POWER: 820*4667Smh27603 pm_lock_power_single(ppmd->dip, 821*4667Smh27603 reqp->req.ppm_lock_power_req.circp); 822*4667Smh27603 break; 823*4667Smh27603 824*4667Smh27603 case PMR_PPM_UNLOCK_POWER: 825*4667Smh27603 pm_unlock_power_single(ppmd->dip, 826*4667Smh27603 reqp->req.ppm_unlock_power_req.circ); 827*4667Smh27603 break; 828*4667Smh27603 829*4667Smh27603 case PMR_PPM_TRY_LOCK_POWER: 830*4667Smh27603 *iresp = pm_try_locking_power_single(ppmd->dip, 831*4667Smh27603 reqp->req.ppm_lock_power_req.circp); 832*4667Smh27603 break; 833*4667Smh27603 } 834*4667Smh27603 } 835*4667Smh27603 836*4667Smh27603 837*4667Smh27603 /* 838*4667Smh27603 * lock, unlock, or trylock for all power mutexes within a domain 839*4667Smh27603 */ 840*4667Smh27603 void 841*4667Smh27603 ppm_lock_all(ppm_domain_t *domp, power_req_t *reqp, int *iresp) 842*4667Smh27603 { 843*4667Smh27603 /* 844*4667Smh27603 * To simplify the implementation we let all the devices 845*4667Smh27603 * in the domain be represented by a single device (dip). 846*4667Smh27603 * We use the first device in the domain's devlist. This 847*4667Smh27603 * is safe because we return with the domain lock held 848*4667Smh27603 * which prevents the list from changing. 849*4667Smh27603 */ 850*4667Smh27603 if (reqp->request_type == PMR_PPM_LOCK_POWER) { 851*4667Smh27603 if (!MUTEX_HELD(&domp->lock)) 852*4667Smh27603 mutex_enter(&domp->lock); 853*4667Smh27603 domp->refcnt++; 854*4667Smh27603 ASSERT(domp->devlist != NULL); 855*4667Smh27603 pm_lock_power_single(domp->devlist->dip, 856*4667Smh27603 reqp->req.ppm_lock_power_req.circp); 857*4667Smh27603 /* domain lock remains held */ 858*4667Smh27603 return; 859*4667Smh27603 } else if (reqp->request_type == PMR_PPM_UNLOCK_POWER) { 860*4667Smh27603 ASSERT(MUTEX_HELD(&domp->lock)); 861*4667Smh27603 ASSERT(domp->devlist != NULL); 862*4667Smh27603 pm_unlock_power_single(domp->devlist->dip, 863*4667Smh27603 reqp->req.ppm_unlock_power_req.circ); 864*4667Smh27603 if (--domp->refcnt == 0) 865*4667Smh27603 mutex_exit(&domp->lock); 866*4667Smh27603 return; 867*4667Smh27603 } 868*4667Smh27603 869*4667Smh27603 ASSERT(reqp->request_type == PMR_PPM_TRY_LOCK_POWER); 870*4667Smh27603 if (!MUTEX_HELD(&domp->lock)) 871*4667Smh27603 if (!mutex_tryenter(&domp->lock)) { 872*4667Smh27603 *iresp = 0; 873*4667Smh27603 return; 874*4667Smh27603 } 875*4667Smh27603 *iresp = pm_try_locking_power_single(domp->devlist->dip, 876*4667Smh27603 reqp->req.ppm_lock_power_req.circp); 877*4667Smh27603 if (*iresp) 878*4667Smh27603 domp->refcnt++; 879*4667Smh27603 else 880*4667Smh27603 mutex_exit(&domp->lock); 881*4667Smh27603 } 882*4667Smh27603 883*4667Smh27603 884*4667Smh27603 /* 885*4667Smh27603 * return FALSE: if any detached device during its previous life exported 886*4667Smh27603 * the "no-involuntary-power-cycles" property and detached with its 887*4667Smh27603 * power level not at its lowest, or there is a device in the process 888*4667Smh27603 * of being installed/attached; if a PCI domain has devices that have not 889*4667Smh27603 * exported a property that it can tolerate clock off while bus is not 890*4667Smh27603 * quiescent; if a 66mhz PCI domain has devices that do not support stopping 891*4667Smh27603 * clock at D3; either one would count as a power holder. 892*4667Smh27603 * return TRUE: otherwise. 893*4667Smh27603 */ 894*4667Smh27603 boolean_t 895*4667Smh27603 ppm_none_else_holds_power(ppm_domain_t *domp) 896*4667Smh27603 { 897*4667Smh27603 ppm_dev_t *ppmd; 898*4667Smh27603 ppm_owned_t *owned; 899*4667Smh27603 int i = 0; 900*4667Smh27603 901*4667Smh27603 if (PPMD_IS_PCI(domp->model)) { 902*4667Smh27603 for (ppmd = domp->devlist; ppmd; ppmd = ppmd->next) { 903*4667Smh27603 if ((domp->model == PPMD_PCI_PROP) && 904*4667Smh27603 !(ppmd->flags & PPMDEV_PCI_PROP_CLKPM)) 905*4667Smh27603 return (B_FALSE); 906*4667Smh27603 if ((domp->dflags & PPMD_PCI66MHZ) && 907*4667Smh27603 !(ppmd->flags & PPMDEV_PCI66_D2)) 908*4667Smh27603 return (B_FALSE); 909*4667Smh27603 } 910*4667Smh27603 } 911*4667Smh27603 912*4667Smh27603 for (owned = domp->owned; owned; owned = owned->next) 913*4667Smh27603 if (pm_noinvol_detached(owned->path) || owned->initializing) 914*4667Smh27603 i++; 915*4667Smh27603 return (i == 0); 916*4667Smh27603 } 917*4667Smh27603 918*4667Smh27603 919*4667Smh27603 /* 920*4667Smh27603 * return the number of char 'c' occurrences in string s 921*4667Smh27603 */ 922*4667Smh27603 int 923*4667Smh27603 ppm_count_char(char *s, char c) 924*4667Smh27603 { 925*4667Smh27603 int i = 0; 926*4667Smh27603 char *cp = s; 927*4667Smh27603 928*4667Smh27603 while (*cp) { 929*4667Smh27603 if (*cp == c) 930*4667Smh27603 i++; 931*4667Smh27603 cp++; 932*4667Smh27603 } 933*4667Smh27603 934*4667Smh27603 return (i); 935*4667Smh27603 } 936*4667Smh27603 937*4667Smh27603 938*4667Smh27603 /* 939*4667Smh27603 * extract and convert a substring from input string "ss" in form of 940*4667Smh27603 * "name=value" into an hex or decimal integer 941*4667Smh27603 */ 942*4667Smh27603 #define X_BASE 16 943*4667Smh27603 #define D_BASE 10 944*4667Smh27603 int 945*4667Smh27603 ppm_stoi(char *ss, uint_t *val) 946*4667Smh27603 { 947*4667Smh27603 char *cp; 948*4667Smh27603 int hex_ = 0, base = D_BASE; 949*4667Smh27603 int digit; 950*4667Smh27603 951*4667Smh27603 if ((cp = strchr(ss, '=')) == NULL) 952*4667Smh27603 return (*val = (uint_t)-1); 953*4667Smh27603 954*4667Smh27603 cp++; 955*4667Smh27603 if ((*cp == '0') && (*++cp == 'x')) { 956*4667Smh27603 hex_++; 957*4667Smh27603 cp++; 958*4667Smh27603 base = X_BASE; 959*4667Smh27603 } 960*4667Smh27603 961*4667Smh27603 for (digit = 0; *cp; cp++) { 962*4667Smh27603 if (hex_ && ((*cp >= 'A') && (*cp <= 'F'))) 963*4667Smh27603 digit = (digit * base) + ((*cp - 'A') + D_BASE); 964*4667Smh27603 else if (hex_ && ((*cp >= 'a') && (*cp <= 'f'))) 965*4667Smh27603 digit = (digit * base) + ((*cp - 'a') + D_BASE); 966*4667Smh27603 else 967*4667Smh27603 digit = (digit * base) + (*cp - '0'); 968*4667Smh27603 } 969*4667Smh27603 970*4667Smh27603 return (*val = digit); 971*4667Smh27603 } 972*4667Smh27603 973*4667Smh27603 /* 974*4667Smh27603 * ppm_convert - convert a #define symbol to its integer value, 975*4667Smh27603 * only the #defines for ppm_dc.cmd and ppm_dc.method fields in 976*4667Smh27603 * ppmvar.h file are recognized. 977*4667Smh27603 */ 978*4667Smh27603 struct ppm_confdefs { 979*4667Smh27603 char *sym; 980*4667Smh27603 int val; 981*4667Smh27603 } ppm_confdefs_table[] = { 982*4667Smh27603 "CPU_NEXT", PPMDC_CPU_NEXT, 983*4667Smh27603 "PRE_CHNG", PPMDC_PRE_CHNG, 984*4667Smh27603 "CPU_GO", PPMDC_CPU_GO, 985*4667Smh27603 "POST_CHNG", PPMDC_POST_CHNG, 986*4667Smh27603 "FET_ON", PPMDC_FET_ON, 987*4667Smh27603 "FET_OFF", PPMDC_FET_OFF, 988*4667Smh27603 "CLK_OFF", PPMDC_CLK_OFF, 989*4667Smh27603 "CLK_ON", PPMDC_CLK_ON, 990*4667Smh27603 "LED_ON", PPMDC_LED_ON, 991*4667Smh27603 "LED_OFF", PPMDC_LED_OFF, 992*4667Smh27603 "KIO", PPMDC_KIO, 993*4667Smh27603 "VCORE", PPMDC_VCORE, 994*4667Smh27603 "I2CKIO", PPMDC_I2CKIO, 995*4667Smh27603 "CPUSPEEDKIO", PPMDC_CPUSPEEDKIO, 996*4667Smh27603 "PRE_PWR_OFF", PPMDC_PRE_PWR_OFF, 997*4667Smh27603 "PRE_PWR_ON", PPMDC_PRE_PWR_ON, 998*4667Smh27603 "POST_PWR_ON", PPMDC_POST_PWR_ON, 999*4667Smh27603 "PWR_OFF", PPMDC_PWR_OFF, 1000*4667Smh27603 "PWR_ON", PPMDC_PWR_ON, 1001*4667Smh27603 "RESET_OFF", PPMDC_RESET_OFF, 1002*4667Smh27603 "RESET_ON", PPMDC_RESET_ON, 1003*4667Smh27603 NULL 1004*4667Smh27603 }; 1005*4667Smh27603 1006*4667Smh27603 1007*4667Smh27603 /* 1008*4667Smh27603 * convert a #define'd symbol to its integer value where 1009*4667Smh27603 * input "symbol" is expected to be in form of "SYMBOL=value" 1010*4667Smh27603 */ 1011*4667Smh27603 int 1012*4667Smh27603 ppm_convert(char *symbol, uint_t *val) 1013*4667Smh27603 { 1014*4667Smh27603 char *s; 1015*4667Smh27603 struct ppm_confdefs *pcfp; 1016*4667Smh27603 1017*4667Smh27603 if ((s = strchr(symbol, '=')) == NULL) { 1018*4667Smh27603 cmn_err(CE_WARN, "ppm_convert: token \"%s\" syntax error in " 1019*4667Smh27603 "ppm.conf file, line(%d)", symbol, __LINE__); 1020*4667Smh27603 return (*val = (uint_t)-1); 1021*4667Smh27603 } 1022*4667Smh27603 s++; 1023*4667Smh27603 1024*4667Smh27603 for (pcfp = ppm_confdefs_table; (pcfp->sym != NULL); pcfp++) { 1025*4667Smh27603 if (strcmp(s, pcfp->sym) == 0) 1026*4667Smh27603 return (*val = pcfp->val); 1027*4667Smh27603 } 1028*4667Smh27603 1029*4667Smh27603 cmn_err(CE_WARN, "ppm_convert: Unrecognizable token \"%s\" " 1030*4667Smh27603 "in ppm.conf file, line %d", symbol, __LINE__); 1031*4667Smh27603 return (*val = (uint_t)-1); 1032*4667Smh27603 } 1033*4667Smh27603 1034*4667Smh27603 1035*4667Smh27603 /* 1036*4667Smh27603 * parse a domain control property string into data structure struct ppm_dc 1037*4667Smh27603 */ 1038*4667Smh27603 int 1039*4667Smh27603 ppm_parse_dc(char **dc_namep, ppm_dc_t *dc) 1040*4667Smh27603 { 1041*4667Smh27603 char *str = "ppm_parse_dc"; 1042*4667Smh27603 char *line; 1043*4667Smh27603 char *f, *b; 1044*4667Smh27603 char **dclist; /* list of ppm_dc_t fields */ 1045*4667Smh27603 int count; /* the # of '=' indicates the # of items */ 1046*4667Smh27603 size_t len; /* length of line being parsed */ 1047*4667Smh27603 boolean_t done; 1048*4667Smh27603 int i; 1049*4667Smh27603 int err; 1050*4667Smh27603 1051*4667Smh27603 len = strlen(*dc_namep); 1052*4667Smh27603 line = kmem_alloc(len + 1, KM_SLEEP); 1053*4667Smh27603 (void) strcpy(line, *dc_namep); 1054*4667Smh27603 1055*4667Smh27603 count = ppm_count_char(line, '='); 1056*4667Smh27603 ASSERT((count - ppm_count_char(line, ' ')) == 1); 1057*4667Smh27603 1058*4667Smh27603 dclist = (char **) 1059*4667Smh27603 kmem_zalloc((sizeof (char *) * (count + 1)), KM_SLEEP); 1060*4667Smh27603 for (i = 0, f = b = line, done = B_FALSE; !done; i++, f = ++b) { 1061*4667Smh27603 while (*b != ' ' && *b != 0) 1062*4667Smh27603 b++; 1063*4667Smh27603 if (*b == 0) 1064*4667Smh27603 done = B_TRUE; 1065*4667Smh27603 else 1066*4667Smh27603 *b = 0; 1067*4667Smh27603 dclist[i] = f; 1068*4667Smh27603 } 1069*4667Smh27603 1070*4667Smh27603 for (i = 0; i < count; i++) { 1071*4667Smh27603 if (strstr(dclist[i], "cmd=")) { 1072*4667Smh27603 err = ppm_convert(dclist[i], &dc->cmd); 1073*4667Smh27603 if (err == -1) 1074*4667Smh27603 return (err); 1075*4667Smh27603 continue; 1076*4667Smh27603 } 1077*4667Smh27603 if ((f = strstr(dclist[i], "path=")) != NULL) { 1078*4667Smh27603 f += strlen("path="); 1079*4667Smh27603 dc->path = kmem_zalloc((strlen(f) + 1), KM_SLEEP); 1080*4667Smh27603 (void) strcpy(dc->path, f); 1081*4667Smh27603 continue; 1082*4667Smh27603 } 1083*4667Smh27603 if (strstr(dclist[i], "method=")) { 1084*4667Smh27603 err = ppm_convert(dclist[i], &dc->method); 1085*4667Smh27603 if (err == -1) 1086*4667Smh27603 return (err); 1087*4667Smh27603 continue; 1088*4667Smh27603 } 1089*4667Smh27603 if (strstr(dclist[i], "iowr=")) { 1090*4667Smh27603 (void) ppm_stoi(dclist[i], &dc->m_un.kio.iowr); 1091*4667Smh27603 continue; 1092*4667Smh27603 } 1093*4667Smh27603 if (strstr(dclist[i], "iord=")) { 1094*4667Smh27603 (void) ppm_stoi(dclist[i], &dc->m_un.kio.iord); 1095*4667Smh27603 continue; 1096*4667Smh27603 } 1097*4667Smh27603 if (strstr(dclist[i], "val=")) { 1098*4667Smh27603 (void) ppm_stoi(dclist[i], &dc->m_un.kio.val); 1099*4667Smh27603 continue; 1100*4667Smh27603 } 1101*4667Smh27603 if (strstr(dclist[i], "speeds=")) { 1102*4667Smh27603 ASSERT(dc->method == PPMDC_CPUSPEEDKIO); 1103*4667Smh27603 (void) ppm_stoi(dclist[i], &dc->m_un.cpu.speeds); 1104*4667Smh27603 continue; 1105*4667Smh27603 } 1106*4667Smh27603 if (strstr(dclist[i], "mask=")) { 1107*4667Smh27603 (void) ppm_stoi(dclist[i], &dc->m_un.i2c.mask); 1108*4667Smh27603 continue; 1109*4667Smh27603 } 1110*4667Smh27603 /* This must be before the if statement for delay */ 1111*4667Smh27603 if (strstr(dclist[i], "post_delay=")) { 1112*4667Smh27603 ASSERT(dc->method == PPMDC_KIO || 1113*4667Smh27603 dc->method == PPMDC_I2CKIO); 1114*4667Smh27603 /* 1115*4667Smh27603 * all delays are uint_t type instead of clock_t. 1116*4667Smh27603 * If the delay is too long, it might get truncated. 1117*4667Smh27603 * But, we don't expect delay to be too long. 1118*4667Smh27603 */ 1119*4667Smh27603 switch (dc->method) { 1120*4667Smh27603 case PPMDC_KIO: 1121*4667Smh27603 (void) ppm_stoi(dclist[i], 1122*4667Smh27603 &dc->m_un.kio.post_delay); 1123*4667Smh27603 break; 1124*4667Smh27603 1125*4667Smh27603 case PPMDC_I2CKIO: 1126*4667Smh27603 (void) ppm_stoi(dclist[i], 1127*4667Smh27603 &dc->m_un.i2c.post_delay); 1128*4667Smh27603 break; 1129*4667Smh27603 1130*4667Smh27603 default: 1131*4667Smh27603 break; 1132*4667Smh27603 } 1133*4667Smh27603 continue; 1134*4667Smh27603 } 1135*4667Smh27603 if (strstr(dclist[i], "delay=")) { 1136*4667Smh27603 ASSERT(dc->method == PPMDC_VCORE || 1137*4667Smh27603 dc->method == PPMDC_KIO || 1138*4667Smh27603 dc->method == PPMDC_I2CKIO); 1139*4667Smh27603 1140*4667Smh27603 /* 1141*4667Smh27603 * all delays are uint_t type instead of clock_t. 1142*4667Smh27603 * If the delay is too long, it might get truncated. 1143*4667Smh27603 * But, we don't expect delay to be too long. 1144*4667Smh27603 */ 1145*4667Smh27603 1146*4667Smh27603 switch (dc->method) { 1147*4667Smh27603 case PPMDC_KIO: 1148*4667Smh27603 (void) ppm_stoi(dclist[i], &dc->m_un.kio.delay); 1149*4667Smh27603 break; 1150*4667Smh27603 1151*4667Smh27603 case PPMDC_I2CKIO: 1152*4667Smh27603 (void) ppm_stoi(dclist[i], &dc->m_un.i2c.delay); 1153*4667Smh27603 break; 1154*4667Smh27603 1155*4667Smh27603 case PPMDC_VCORE: 1156*4667Smh27603 (void) ppm_stoi(dclist[i], &dc->m_un.cpu.delay); 1157*4667Smh27603 break; 1158*4667Smh27603 1159*4667Smh27603 default: 1160*4667Smh27603 break; 1161*4667Smh27603 } 1162*4667Smh27603 continue; 1163*4667Smh27603 } 1164*4667Smh27603 1165*4667Smh27603 /* we encounted unrecognized field, flag error */ 1166*4667Smh27603 cmn_err(CE_WARN, "%s: Unrecognized token \"%s\" in ppm.conf " 1167*4667Smh27603 "file, line(%d)!", str, dclist[i], __LINE__); 1168*4667Smh27603 return (-1); 1169*4667Smh27603 } 1170*4667Smh27603 1171*4667Smh27603 kmem_free(dclist, sizeof (char *) * (count + 1)); 1172*4667Smh27603 kmem_free(line, len + 1); 1173*4667Smh27603 1174*4667Smh27603 return (DDI_SUCCESS); 1175*4667Smh27603 } 1176*4667Smh27603 1177*4667Smh27603 1178*4667Smh27603 /* 1179*4667Smh27603 * search for domain control handle for a claimed device coupled with a 1180*4667Smh27603 * domain control command. NULL device may indicate LED domain. 1181*4667Smh27603 */ 1182*4667Smh27603 ppm_dc_t * 1183*4667Smh27603 ppm_lookup_dc(ppm_domain_t *domp, int cmd) 1184*4667Smh27603 { 1185*4667Smh27603 #ifdef DEBUG 1186*4667Smh27603 char *str = "ppm_lookup_dc"; 1187*4667Smh27603 #endif 1188*4667Smh27603 ppm_dc_t *dc; 1189*4667Smh27603 1190*4667Smh27603 /* 1191*4667Smh27603 * For convenience, we accept 'domp' as NULL for searching 1192*4667Smh27603 * LED domain control operation. 1193*4667Smh27603 */ 1194*4667Smh27603 if ((cmd == PPMDC_LED_OFF) || (cmd == PPMDC_LED_ON)) { 1195*4667Smh27603 for (domp = ppm_domain_p; domp; domp = domp->next) 1196*4667Smh27603 if (domp->model == PPMD_LED) 1197*4667Smh27603 break; 1198*4667Smh27603 if (!domp || !domp->dc || !domp->dc->lh || !domp->dc->next) { 1199*4667Smh27603 PPMD(D_LED, ("\tinsufficient led domain control " 1200*4667Smh27603 "information.\n")) 1201*4667Smh27603 return (NULL); 1202*4667Smh27603 } 1203*4667Smh27603 if (cmd == domp->dc->cmd) 1204*4667Smh27603 return (domp->dc); 1205*4667Smh27603 else 1206*4667Smh27603 return (domp->dc->next); 1207*4667Smh27603 } 1208*4667Smh27603 1209*4667Smh27603 1210*4667Smh27603 /* 1211*4667Smh27603 * for the rest of ppm domains, lookup ppm_dc starting from domp 1212*4667Smh27603 */ 1213*4667Smh27603 ASSERT(domp != NULL); 1214*4667Smh27603 switch (cmd) { 1215*4667Smh27603 case PPMDC_CPU_NEXT: 1216*4667Smh27603 case PPMDC_PRE_CHNG: 1217*4667Smh27603 case PPMDC_CPU_GO: 1218*4667Smh27603 case PPMDC_POST_CHNG: 1219*4667Smh27603 case PPMDC_FET_OFF: 1220*4667Smh27603 case PPMDC_FET_ON: 1221*4667Smh27603 case PPMDC_CLK_OFF: 1222*4667Smh27603 case PPMDC_CLK_ON: 1223*4667Smh27603 case PPMDC_PRE_PWR_OFF: 1224*4667Smh27603 case PPMDC_PRE_PWR_ON: 1225*4667Smh27603 case PPMDC_POST_PWR_ON: 1226*4667Smh27603 case PPMDC_PWR_OFF: 1227*4667Smh27603 case PPMDC_PWR_ON: 1228*4667Smh27603 case PPMDC_RESET_OFF: 1229*4667Smh27603 case PPMDC_RESET_ON: 1230*4667Smh27603 break; 1231*4667Smh27603 default: 1232*4667Smh27603 PPMD(D_PPMDC, ("%s: cmd(%d) unrecognized\n", str, cmd)) 1233*4667Smh27603 return (NULL); 1234*4667Smh27603 } 1235*4667Smh27603 1236*4667Smh27603 for (dc = domp->dc; dc; dc = dc->next) { 1237*4667Smh27603 if (dc->cmd == cmd) 1238*4667Smh27603 return (dc); 1239*4667Smh27603 } 1240*4667Smh27603 return (NULL); 1241*4667Smh27603 } 1242*4667Smh27603 1243*4667Smh27603 #include <sys/esunddi.h> 1244*4667Smh27603 1245*4667Smh27603 ppm_domain_t * 1246*4667Smh27603 ppm_get_domain_by_dev(const char *p) 1247*4667Smh27603 { 1248*4667Smh27603 dev_info_t *dip; 1249*4667Smh27603 ppm_domain_t *domp; 1250*4667Smh27603 ppm_dev_t *pdev; 1251*4667Smh27603 boolean_t found = B_FALSE; 1252*4667Smh27603 1253*4667Smh27603 if ((dip = e_ddi_hold_devi_by_path((char *)p, 0)) == NULL) 1254*4667Smh27603 return (NULL); 1255*4667Smh27603 1256*4667Smh27603 for (domp = ppm_domain_p; domp; domp = domp->next) { 1257*4667Smh27603 for (pdev = domp->devlist; pdev; pdev = pdev->next) { 1258*4667Smh27603 if (pdev->dip == dip) { 1259*4667Smh27603 found = B_TRUE; 1260*4667Smh27603 break; 1261*4667Smh27603 } 1262*4667Smh27603 } 1263*4667Smh27603 if (found) 1264*4667Smh27603 break; 1265*4667Smh27603 } 1266*4667Smh27603 ddi_release_devi(dip); 1267*4667Smh27603 return (domp); 1268*4667Smh27603 } 1269*4667Smh27603 1270*4667Smh27603 1271*4667Smh27603 #ifdef DEBUG 1272*4667Smh27603 #define FLINTSTR(flags, sym) { flags, sym, #sym } 1273*4667Smh27603 #define PMR_UNKNOWN -1 1274*4667Smh27603 /* 1275*4667Smh27603 * convert a ctlop integer to a char string. this helps printing 1276*4667Smh27603 * meaningful info when cltops are received from the pm framework. 1277*4667Smh27603 * since some ctlops are so frequent, we use mask to limit output: 1278*4667Smh27603 * a valid string is returned when ctlop is found and when 1279*4667Smh27603 * (cmd.flags & mask) is true; otherwise NULL is returned. 1280*4667Smh27603 */ 1281*4667Smh27603 char * 1282*4667Smh27603 ppm_get_ctlstr(int ctlop, uint_t mask) 1283*4667Smh27603 { 1284*4667Smh27603 struct ctlop_cmd { 1285*4667Smh27603 uint_t flags; 1286*4667Smh27603 int ctlop; 1287*4667Smh27603 char *str; 1288*4667Smh27603 }; 1289*4667Smh27603 1290*4667Smh27603 struct ctlop_cmd *ccp; 1291*4667Smh27603 static struct ctlop_cmd cmds[] = { 1292*4667Smh27603 FLINTSTR(D_SETPWR, PMR_SET_POWER), 1293*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_SUSPEND), 1294*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_RESUME), 1295*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PRE_SET_POWER), 1296*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_POST_SET_POWER), 1297*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_SET_POWER), 1298*4667Smh27603 FLINTSTR(0, PMR_PPM_ATTACH), 1299*4667Smh27603 FLINTSTR(0, PMR_PPM_DETACH), 1300*4667Smh27603 FLINTSTR(D_CTLOPS1, PMR_PPM_POWER_CHANGE_NOTIFY), 1301*4667Smh27603 FLINTSTR(D_CTLOPS1, PMR_REPORT_PMCAP), 1302*4667Smh27603 FLINTSTR(D_CTLOPS1, PMR_CHANGED_POWER), 1303*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_INIT_CHILD), 1304*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_UNINIT_CHILD), 1305*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_PROBE), 1306*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_POST_PROBE), 1307*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_ATTACH), 1308*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_POST_ATTACH), 1309*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_DETACH), 1310*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_POST_DETACH), 1311*4667Smh27603 FLINTSTR(D_CTLOPS1, PMR_PPM_UNMANAGE), 1312*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_RESUME), 1313*4667Smh27603 FLINTSTR(D_CTLOPS1, PMR_PPM_ALL_LOWEST), 1314*4667Smh27603 FLINTSTR(D_LOCKS, PMR_PPM_LOCK_POWER), 1315*4667Smh27603 FLINTSTR(D_LOCKS, PMR_PPM_UNLOCK_POWER), 1316*4667Smh27603 FLINTSTR(D_LOCKS, PMR_PPM_TRY_LOCK_POWER), 1317*4667Smh27603 FLINTSTR(D_LOCKS, PMR_PPM_POWER_LOCK_OWNER), 1318*4667Smh27603 FLINTSTR(D_CTLOPS1 | D_CTLOPS2, PMR_UNKNOWN), 1319*4667Smh27603 }; 1320*4667Smh27603 1321*4667Smh27603 for (ccp = cmds; ccp->ctlop != PMR_UNKNOWN; ccp++) 1322*4667Smh27603 if (ctlop == ccp->ctlop) 1323*4667Smh27603 break; 1324*4667Smh27603 1325*4667Smh27603 if (ccp->flags & mask) 1326*4667Smh27603 return (ccp->str); 1327*4667Smh27603 return (NULL); 1328*4667Smh27603 } 1329*4667Smh27603 1330*4667Smh27603 void 1331*4667Smh27603 ppm_print_dc(ppm_dc_t *dc) 1332*4667Smh27603 { 1333*4667Smh27603 ppm_dc_t *d = dc; 1334*4667Smh27603 1335*4667Smh27603 PPMD(D_PPMDC, ("\nAdds ppm_dc: path(%s),\n cmd(%x), " 1336*4667Smh27603 "method(%x), ", d->path, d->cmd, d->method)) 1337*4667Smh27603 if (d->method == PPMDC_I2CKIO) { 1338*4667Smh27603 PPMD(D_PPMDC, ("i2c.iowr(%x), i2c.val(0x%X), " 1339*4667Smh27603 "i2c.mask(0x%X)", d->m_un.i2c.iowr, 1340*4667Smh27603 d->m_un.i2c.val, d->m_un.i2c.mask)) 1341*4667Smh27603 } else if (d->method == PPMDC_KIO) { 1342*4667Smh27603 PPMD(D_PPMDC, ("kio.iowr(%x), kio.val(0x%X)", 1343*4667Smh27603 d->m_un.kio.iowr, d->m_un.kio.val)) 1344*4667Smh27603 } else if (d->method == PPMDC_VCORE) { 1345*4667Smh27603 PPMD(D_PPMDC, ("cpu: .iord(%x), .iowr(%x), .val(0x%X), " 1346*4667Smh27603 ".delay(0x%x)", 1347*4667Smh27603 d->m_un.cpu.iord, d->m_un.cpu.iowr, d->m_un.cpu.val, 1348*4667Smh27603 d->m_un.cpu.delay)) 1349*4667Smh27603 } else if (d->method == PPMDC_CPUSPEEDKIO) { 1350*4667Smh27603 PPMD(D_PPMDC, ("cpu.iowr(%x), cpu.speeds(0x%X)", 1351*4667Smh27603 d->m_un.cpu.iowr, d->m_un.cpu.speeds)) 1352*4667Smh27603 } 1353*4667Smh27603 PPMD(D_PPMDC, ("\n")) 1354*4667Smh27603 } 1355*4667Smh27603 #endif /* DEBUG */ 1356