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