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 * Platform Power Management master pseudo driver - 30 * - attaches only when ppm.conf file is present, indicating a 31 * workstation (since Excalibur era ) that is designed to 32 * be MOU-3 EPA compliant and which uses platform-specific 33 * hardware to do so; 34 * - this pseudo driver uses a set of simple satellite 35 * device drivers responsible for accessing platform 36 * specific devices to modify the registers they own. 37 * ppm drivers tells these satellite drivers what to do 38 * according to using command values taken from ppm.conf. 39 */ 40 #include <sys/conf.h> 41 #include <sys/stat.h> 42 #include <sys/file.h> 43 #include <sys/types.h> 44 #include <sys/param.h> 45 #include <sys/open.h> 46 #include <sys/callb.h> 47 #include <sys/va_list.h> 48 #include <sys/errno.h> 49 #include <sys/modctl.h> 50 #include <sys/sysmacros.h> 51 #include <sys/ddi_impldefs.h> 52 #include <sys/promif.h> 53 #include <sys/epm.h> 54 #include <sys/sunpm.h> 55 #include <sys/ppmio.h> 56 #include <sys/sunldi.h> 57 #include <sys/ppmvar.h> 58 #include <sys/ddi.h> 59 #include <sys/sunddi.h> 60 #include <sys/ppm_plat.h> 61 62 /* 63 * Note: When pm_power() is called (directly or indirectly) to change the 64 * power level of a device and the call returns failure, DO NOT assume the 65 * level is unchanged. Doublecheck it against ppmd->level. 66 */ 67 68 /* 69 * cb_ops 70 */ 71 static int ppm_open(dev_t *, int, int, cred_t *); 72 static int ppm_close(dev_t, int, int, cred_t *); 73 static int ppm_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 74 75 static struct cb_ops ppm_cb_ops = { 76 ppm_open, /* open */ 77 ppm_close, /* close */ 78 nodev, /* strategy */ 79 nodev, /* print */ 80 nodev, /* dump */ 81 nodev, /* read */ 82 nodev, /* write */ 83 ppm_ioctl, /* ioctl */ 84 nodev, /* devmap */ 85 nodev, /* mmap */ 86 nodev, /* segmap */ 87 nochpoll, /* poll */ 88 ddi_prop_op, /* prop_op */ 89 NULL, /* streamtab */ 90 D_MP | D_NEW, /* driver compatibility flag */ 91 CB_REV, /* cb_ops revision */ 92 nodev, /* async read */ 93 nodev /* async write */ 94 }; 95 96 /* 97 * bus_ops 98 */ 99 static int ppm_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, 100 void *); 101 102 static struct bus_ops ppm_bus_ops = { 103 BUSO_REV, /* busops_rev */ 104 0, /* bus_map */ 105 0, /* bus_get_intrspec */ 106 0, /* bus_add_intrspec */ 107 0, /* bus_remove_intrspec */ 108 0, /* bus_map_fault */ 109 ddi_no_dma_map, /* bus_dma_map */ 110 ddi_no_dma_allochdl, /* bus_dma_allochdl */ 111 NULL, /* bus_dma_freehdl */ 112 NULL, /* bus_dma_bindhdl */ 113 NULL, /* bus_dma_unbindhdl */ 114 NULL, /* bus_dma_flush */ 115 NULL, /* bus_dma_win */ 116 NULL, /* bus_dma_ctl */ 117 ppm_ctlops, /* bus_ctl */ 118 0, /* bus_prop_op */ 119 0, /* bus_get_eventcookie */ 120 0, /* bus_add_eventcall */ 121 0, /* bus_remove_eventcall */ 122 0, /* bus_post_event */ 123 0 /* bus_intr_ctl */ 124 }; 125 126 /* 127 * dev_ops 128 */ 129 static int ppm_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 130 static int ppm_attach(dev_info_t *, ddi_attach_cmd_t); 131 static int ppm_detach(dev_info_t *, ddi_detach_cmd_t); 132 133 static struct dev_ops ppm_ops = { 134 DEVO_REV, /* devo_rev */ 135 0, /* refcnt */ 136 ppm_getinfo, /* info */ 137 nulldev, /* identify */ 138 nulldev, /* probe */ 139 ppm_attach, /* attach */ 140 ppm_detach, /* detach */ 141 nodev, /* reset */ 142 &ppm_cb_ops, /* cb_ops */ 143 &ppm_bus_ops, /* bus_ops */ 144 nulldev /* power */ 145 }; 146 147 extern struct mod_ops mod_driverops; 148 149 static struct modldrv modldrv = { 150 &mod_driverops, 151 "platform pm driver v%I%", 152 &ppm_ops 153 }; 154 155 static struct modlinkage modlinkage = { 156 MODREV_1, 157 &modldrv, 158 NULL 159 }; 160 161 /* 162 * Global data structure and variables 163 */ 164 int ppm_inst = -1; 165 void *ppm_statep; 166 ppm_domain_t *ppm_domain_p; 167 callb_id_t *ppm_cprcb_id; 168 static kmutex_t ppm_cpr_window_lock; /* guard ppm_cpr_window_flag */ 169 static boolean_t ppm_cpr_window_flag; /* set indicating chpt-resume period */ 170 171 /* LED actions */ 172 #define PPM_LED_SOLIDON 0 173 #define PPM_LED_BLINKING 1 174 175 /* 176 * Debug 177 */ 178 #ifdef DEBUG 179 uint_t ppm_debug = 0; 180 #endif 181 182 /* 183 * Local function prototypes and data 184 */ 185 static boolean_t ppm_cpr_callb(void *, int); 186 static int ppm_fetset(ppm_domain_t *, uint8_t); 187 static int ppm_fetget(ppm_domain_t *, uint8_t *); 188 static int ppm_gpioset(ppm_domain_t *, int); 189 static int ppm_manage_cpus(dev_info_t *, power_req_t *, int *); 190 static int ppm_manage_pci(dev_info_t *, power_req_t *, int *); 191 static int ppm_manage_pcie(dev_info_t *, power_req_t *, int *); 192 static int ppm_manage_fet(dev_info_t *, power_req_t *, int *); 193 static void ppm_manage_led(int); 194 static void ppm_set_led(ppm_domain_t *, int); 195 static void ppm_blink_led(void *); 196 static void ppm_svc_resume_ctlop(dev_info_t *, power_req_t *); 197 static int ppm_set_level(ppm_dev_t *, int, int, boolean_t); 198 static int ppm_change_power_level(ppm_dev_t *, int, int); 199 static int ppm_record_level_change(ppm_dev_t *, int, int); 200 static int ppm_switch_clock(ppm_domain_t *, int); 201 static int ppm_pcie_pwr(ppm_domain_t *, int); 202 static int ppm_power_up_domain(dev_info_t *dip); 203 static int ppm_power_down_domain(dev_info_t *dip); 204 205 int 206 _init(void) 207 { 208 if (ddi_soft_state_init( 209 &ppm_statep, sizeof (ppm_unit_t), 1) != DDI_SUCCESS) 210 return (DDI_FAILURE); 211 212 if (mod_install(&modlinkage) != DDI_SUCCESS) { 213 ddi_soft_state_fini(&ppm_statep); 214 return (DDI_FAILURE); 215 } 216 return (DDI_SUCCESS); 217 } 218 219 220 int 221 _fini(void) 222 { 223 return (mod_remove(&modlinkage)); 224 } 225 226 227 int 228 _info(struct modinfo *modinfop) 229 { 230 return (mod_info(&modlinkage, modinfop)); 231 } 232 233 234 /* ARGSUSED */ 235 int 236 ppm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) 237 { 238 struct ppm_unit *unitp; 239 dev_t dev; 240 int instance; 241 int rval; 242 243 if (ppm_inst == -1) 244 return (DDI_FAILURE); 245 246 switch (cmd) { 247 case DDI_INFO_DEVT2DEVINFO: 248 if (unitp = ddi_get_soft_state(ppm_statep, (dev_t)arg)) { 249 *resultp = unitp->dip; 250 rval = DDI_SUCCESS; 251 } else 252 rval = DDI_FAILURE; 253 254 return (rval); 255 256 case DDI_INFO_DEVT2INSTANCE: 257 dev = (dev_t)arg; 258 instance = getminor(dev); 259 *resultp = (void *)(uintptr_t)instance; 260 return (DDI_SUCCESS); 261 262 default: 263 return (DDI_FAILURE); 264 } 265 } 266 267 268 /* 269 * attach(9E) 270 */ 271 static int 272 ppm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 273 { 274 ppm_unit_t *unitp; 275 int ret; 276 #ifdef DEBUG 277 char *str = "ppm_attach"; 278 #endif 279 280 281 switch (cmd) { 282 case DDI_ATTACH: 283 PPMD(D_ATTACH, ("%s: attaching ...\n", str)) 284 break; 285 286 case DDI_RESUME: 287 PPMD(D_ATTACH, ("%s: Resuming ...\n", str)) 288 unitp = ddi_get_soft_state(ppm_statep, ppm_inst); 289 mutex_enter(&unitp->lock); 290 unitp->states &= ~PPM_STATE_SUSPENDED; 291 mutex_exit(&unitp->lock); 292 return (DDI_SUCCESS); 293 294 default: 295 cmn_err(CE_WARN, "ppm_attach: unknown command %d, dip(0x%p)", 296 cmd, (void *)dip); 297 return (DDI_FAILURE); 298 } 299 300 if (ppm_inst != -1) { 301 PPMD(D_ATTACH, ("%s: Already attached !", str)) 302 return (DDI_FAILURE); 303 } 304 305 ppm_inst = ddi_get_instance(dip); 306 if (ddi_soft_state_zalloc(ppm_statep, ppm_inst) != DDI_SUCCESS) { 307 PPMD(D_ATTACH, ("%s: soft states alloc error!\n", str)) 308 return (DDI_FAILURE); 309 } 310 unitp = ddi_get_soft_state(ppm_statep, ppm_inst); 311 312 ret = ddi_create_minor_node(dip, "ppm", S_IFCHR, ppm_inst, 313 "ddi_ppm", 0); 314 if (ret != DDI_SUCCESS) { 315 PPMD(D_ATTACH, ("%s: can't create minor node!\n", str)) 316 goto fail1; 317 } 318 319 unitp->dip = dip; 320 mutex_init(&unitp->lock, NULL, MUTEX_DRIVER, NULL); 321 322 /* 323 * read ppm.conf, construct ppm_domain data structure and 324 * their sub data structure. 325 */ 326 if ((ret = ppm_create_db(dip)) != DDI_SUCCESS) 327 goto fail2; 328 329 /* 330 * walk down ppm domain control from each domain, initialize 331 * domain control orthogonal function call handle 332 */ 333 ppm_init_cb(dip); 334 335 if ((ret = pm_register_ppm(ppm_claim_dev, dip)) != DDI_SUCCESS) { 336 cmn_err(CE_WARN, "ppm_attach: can't register ppm handler!"); 337 goto fail2; 338 } 339 340 mutex_init(&ppm_cpr_window_lock, NULL, MUTEX_DRIVER, NULL); 341 ppm_cpr_window_flag = B_FALSE; 342 ppm_cprcb_id = callb_add(ppm_cpr_callb, (void *)NULL, 343 CB_CL_CPR_PM, "ppm_cpr"); 344 345 #if defined(__x86) 346 /* 347 * Register callback so that once CPUs have been added to 348 * the device tree, ppm can rebuild CPU domains using ACPI 349 * data. 350 */ 351 cpupm_rebuild_cpu_domains = ppm_rebuild_cpu_domains; 352 353 /* 354 * Register callback so that the ppm can initialize the 355 * topspeed for all CPUs in all domains. 356 */ 357 cpupm_init_topspeed = ppm_init_topspeed; 358 359 /* 360 * Register callback so that whenever max speed throttle requests 361 * are received, ppm can redefine the high power level for 362 * all CPUs in the domain. 363 */ 364 cpupm_redefine_topspeed = ppm_redefine_topspeed; 365 #endif 366 367 ddi_report_dev(dip); 368 return (DDI_SUCCESS); 369 370 fail2: 371 ddi_remove_minor_node(dip, "ddi_ppm"); 372 mutex_destroy(&unitp->lock); 373 fail1: 374 ddi_soft_state_free(ppm_statep, ppm_inst); 375 ppm_inst = -1; 376 return (DDI_FAILURE); 377 } 378 379 380 /* ARGSUSED */ 381 static int 382 ppm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 383 { 384 ppm_unit_t *unitp; 385 #ifdef DEBUG 386 char *str = "ppm_detach"; 387 #endif 388 389 switch (cmd) { 390 case DDI_DETACH: 391 PPMD(D_DETACH, ("%s: detach not allowed.\n", str)) 392 return (DDI_FAILURE); 393 394 case DDI_SUSPEND: 395 PPMD(D_DETACH, ("%s: suspending ...\n", str)) 396 unitp = ddi_get_soft_state(ppm_statep, ppm_inst); 397 mutex_enter(&unitp->lock); 398 unitp->states |= PPM_STATE_SUSPENDED; 399 mutex_exit(&unitp->lock); 400 401 /* 402 * Suspend requires that timeout callouts to be canceled. 403 * Turning off the LED blinking will cancel the timeout. 404 */ 405 ppm_manage_led(PPM_LED_SOLIDON); 406 return (DDI_SUCCESS); 407 408 default: 409 cmn_err(CE_WARN, "ppm_detach: unsupported command %d, dip(%p)", 410 cmd, (void *)dip); 411 return (DDI_FAILURE); 412 } 413 } 414 415 416 /* ARGSUSED */ 417 int 418 ppm_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) 419 { 420 if (otyp != OTYP_CHR) 421 return (EINVAL); 422 PPMD(D_OPEN, ("ppm_open: devp 0x%p, flag 0x%x, otyp %d\n", 423 (void *)devp, flag, otyp)) 424 return (0); 425 } 426 427 428 /* ARGSUSED */ 429 int 430 ppm_close(dev_t dev, int flag, int otyp, cred_t *credp) 431 { 432 PPMD(D_CLOSE, ("ppm_close: dev 0x%lx, flag 0x%x, otyp %d\n", 433 dev, flag, otyp)) 434 return (0); 435 } 436 437 438 /* ARGSUSED */ 439 int 440 ppm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p, 441 int *rval_p) 442 { 443 #ifdef DEBUG 444 char *str = "ppm_ioctl"; 445 #endif 446 ppm_domain_t *domp = NULL; 447 uint8_t level, lvl; 448 int ret = 0; 449 450 PPMD(D_IOCTL, ("%s: dev 0x%lx, cmd 0x%x, mode 0x%x\n", 451 str, dev, cmd, mode)) 452 453 switch (cmd) { 454 case PPMGET_DPWR: 455 { 456 STRUCT_DECL(ppm_dpwr, dpwr); 457 struct ppm_unit *unitp; 458 char *domain; 459 460 STRUCT_INIT(dpwr, mode); 461 ret = ddi_copyin((caddr_t)arg, STRUCT_BUF(dpwr), 462 STRUCT_SIZE(dpwr), mode); 463 if (ret != 0) 464 return (EFAULT); 465 466 /* copyin domain name */ 467 domain = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 468 ret = copyinstr( 469 STRUCT_FGETP(dpwr, domain), domain, MAXNAMELEN, NULL); 470 if (ret != 0) { 471 PPMD(D_IOCTL, ("%s: can't copyin domain, line(%d)\n", 472 str, __LINE__)) 473 ret = EFAULT; 474 goto err_dpwr; 475 } 476 477 /* locate domain */ 478 if ((domp = ppm_lookup_domain(domain)) == NULL) { 479 PPMD(D_IOCTL, ("%s: no such domain %s\n", str, domain)) 480 ret = ENODEV; 481 goto err_dpwr; 482 } 483 484 switch (domp->model) { 485 case PPMD_FET: /* report power fet ON or OFF */ 486 if ((ret = ppm_fetget(domp, &lvl)) != 0) { 487 ret = EIO; 488 goto err_dpwr; 489 } 490 level = (lvl == PPMD_ON) ? 491 PPMIO_POWER_ON : PPMIO_POWER_OFF; 492 break; 493 494 case PPMD_PCI: /* report pci slot clock ON or OFF */ 495 case PPMD_PCI_PROP: 496 case PPMD_PCIE: 497 level = (domp->status == PPMD_ON) ? 498 PPMIO_POWER_ON : PPMIO_POWER_OFF; 499 break; 500 501 case PPMD_LED: /* report LED blinking or solid on */ 502 503 unitp = ddi_get_soft_state(ppm_statep, ppm_inst); 504 if (unitp->led_tid == 0) 505 level = PPMIO_LED_SOLIDON; 506 else 507 level = PPMIO_LED_BLINKING; 508 break; 509 510 case PPMD_CPU: /* report cpu speed divisor */ 511 level = domp->devlist->level; 512 break; 513 514 default: 515 ret = EINVAL; 516 goto err_dpwr; 517 } 518 519 STRUCT_FSET(dpwr, level, level); 520 ret = ddi_copyout(STRUCT_BUF(dpwr), (caddr_t)arg, 521 STRUCT_SIZE(dpwr), mode); 522 if (ret != 0) { 523 PPMD(D_IOCTL, ("%s: can't copyout, line(%d)\n", 524 str, __LINE__)) 525 ret = EFAULT; 526 } 527 err_dpwr: 528 kmem_free(domain, MAXNAMELEN); 529 530 break; 531 } 532 533 case PPMGET_DOMBYDEV: 534 { 535 STRUCT_DECL(ppm_bydev, bydev); 536 char *path = NULL; 537 size_t size, l; 538 539 STRUCT_INIT(bydev, mode); 540 ret = ddi_copyin((caddr_t)arg, STRUCT_BUF(bydev), 541 STRUCT_SIZE(bydev), mode); 542 if (ret != 0) 543 return (EFAULT); 544 545 /* copyin .path */ 546 path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 547 ret = copyinstr( 548 STRUCT_FGETP(bydev, path), path, MAXPATHLEN, NULL); 549 if (ret != 0) { 550 PPMD(D_IOCTL, ("%s: can't copyin path, line(%d)\n", 551 str, __LINE__)) 552 kmem_free(path, MAXPATHLEN); 553 return (EFAULT); 554 } 555 556 /* so far we have up to one domain for a given device */ 557 size = STRUCT_FGET(bydev, size); 558 domp = ppm_get_domain_by_dev(path); 559 kmem_free(path, MAXPATHLEN); 560 if (domp != NULL) { 561 l = strlen(domp->name) + 1; 562 if (l > size) { 563 PPMD(D_IOCTL, ("%s: buffer too small\n", str)) 564 return ((size == 0) ? EINVAL : EFAULT); 565 } 566 } else /* no domain found to be associated with given device */ 567 return (ENODEV); 568 569 ret = copyoutstr( 570 domp->name, STRUCT_FGETP(bydev, domlist), l, &l); 571 if (ret != 0) { 572 PPMD(D_IOCTL, ("%s: can't copyout domlist, line(%d)" 573 " \n", str, __LINE__)) 574 return (EFAULT); 575 } 576 577 break; 578 } 579 580 581 case PPMGET_DEVBYDOM: 582 { 583 STRUCT_DECL(ppm_bydom, bydom); 584 char *domain = NULL; 585 char *devlist = NULL; 586 ppm_dev_t *ppmd; 587 dev_info_t *odip = NULL; 588 char *s, *d; 589 size_t size, l; 590 591 STRUCT_INIT(bydom, mode); 592 ret = ddi_copyin((caddr_t)arg, STRUCT_BUF(bydom), 593 STRUCT_SIZE(bydom), mode); 594 if (ret != 0) 595 return (EFAULT); 596 597 /* copyin .domain */ 598 domain = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 599 ret = copyinstr(STRUCT_FGETP(bydom, domain), domain, 600 MAXNAMELEN, NULL); 601 if (ret != 0) { 602 PPMD(D_IOCTL, ("%s: can't copyin domain, line(%d)\n", 603 str, __LINE__)) 604 ret = EFAULT; 605 goto err_bydom; 606 } 607 608 /* locate domain */ 609 if ((domp = ppm_lookup_domain(domain)) == NULL) { 610 ret = ENODEV; 611 goto err_bydom; 612 } 613 614 l = 0; 615 if ((size = STRUCT_FGET(bydom, size)) == 0) 616 ret = EINVAL; 617 else 618 if ((d = devlist = kmem_zalloc(size, KM_SLEEP)) == NULL) 619 ret = EFAULT; 620 if (ret != 0) 621 goto err_bydom; 622 623 for (ppmd = domp->devlist; ppmd; 624 odip = ppmd->dip, ppmd = ppmd->next) { 625 626 if (ppmd->dip == odip) 627 continue; 628 if (ppmd != domp->devlist) 629 *d++ = ' '; 630 631 l += strlen(ppmd->path) + 1; 632 if (l > size) { 633 PPMD(D_IOCTL, ("%s: buffer overflow\n", str)) 634 ret = EFAULT; 635 goto err_bydom; 636 } 637 638 for (s = ppmd->path; *s != 0; ) 639 *d++ = *s++; 640 } 641 *d = 0; 642 643 if (*devlist == 0) 644 goto err_bydom; 645 646 ret = copyoutstr( 647 devlist, STRUCT_FGETP(bydom, devlist), l, &l); 648 if (ret != 0) { 649 PPMD(D_IOCTL, ("%s: can't copyout devlist, line(%d)" 650 " \n", str, __LINE__)) 651 ret = EFAULT; 652 } 653 654 err_bydom: 655 if (devlist) 656 kmem_free(devlist, size); 657 if (domain) 658 kmem_free(domain, MAXNAMELEN); 659 660 break; 661 } 662 663 #if defined(__x86) 664 /* 665 * Note that these two ioctls exist for test purposes only. 666 * Unfortunately, there really isn't any other good way of 667 * unit testing the dynamic redefinition of the top speed as it 668 * usually occurs due to environmental conditions. 669 */ 670 case PPMGET_NORMAL: 671 case PPMSET_NORMAL: 672 { 673 STRUCT_DECL(ppm_norm, norm); 674 char *path = NULL; 675 struct pm_component *dcomps; 676 struct pm_comp *pm_comp; 677 ppm_dev_t *ppmd; 678 int i; 679 680 STRUCT_INIT(norm, mode); 681 ret = ddi_copyin((caddr_t)arg, STRUCT_BUF(norm), 682 STRUCT_SIZE(norm), mode); 683 if (ret != 0) 684 return (EFAULT); 685 686 /* copyin .path */ 687 path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 688 ret = copyinstr( 689 STRUCT_FGETP(norm, path), path, MAXPATHLEN, NULL); 690 if (ret != 0) { 691 PPMD(D_IOCTL, ("%s: can't copyin path, line(%d)\n", 692 str, __LINE__)) 693 kmem_free(path, MAXPATHLEN); 694 return (EFAULT); 695 } 696 697 domp = ppm_get_domain_by_dev(path); 698 kmem_free(path, MAXPATHLEN); 699 700 if (domp == NULL) 701 return (ENODEV); 702 703 ppmd = domp->devlist; 704 if (cmd == PPMSET_NORMAL) { 705 if (domp->model != PPMD_CPU) 706 return (EINVAL); 707 level = STRUCT_FGET(norm, norm); 708 dcomps = DEVI(ppmd->dip)->devi_pm_components; 709 pm_comp = &dcomps[ppmd->cmpt].pmc_comp; 710 for (i = pm_comp->pmc_numlevels; i > 0; i--) { 711 if (pm_comp->pmc_lvals[i-1] == level) 712 break; 713 } 714 if (i == 0) 715 return (EINVAL); 716 717 ppm_set_topspeed(ppmd, pm_comp->pmc_numlevels - i); 718 } 719 720 level = pm_get_normal_power(ppmd->dip, 0); 721 722 STRUCT_FSET(norm, norm, level); 723 ret = ddi_copyout(STRUCT_BUF(norm), (caddr_t)arg, 724 STRUCT_SIZE(norm), mode); 725 if (ret != 0) { 726 PPMD(D_IOCTL, ("%s: can't copyout, line(%d)\n", 727 str, __LINE__)) 728 ret = EFAULT; 729 } 730 break; 731 } 732 #endif 733 default: 734 PPMD(D_IOCTL, ("%s: unsupported ioctl command(%d)\n", str, cmd)) 735 return (EINVAL); 736 } 737 738 return (ret); 739 } 740 741 742 /* 743 * interface between pm framework and ppm driver 744 */ 745 /* ARGSUSED */ 746 static int 747 ppm_ctlops(dev_info_t *dip, dev_info_t *rdip, 748 ddi_ctl_enum_t ctlop, void *arg, void *result) 749 { 750 power_req_t *reqp = (power_req_t *)arg; 751 ppm_unit_t *unitp; 752 ppm_domain_t *domp; 753 ppm_dev_t *ppmd; 754 char path[MAXNAMELEN]; 755 ppm_owned_t *owned; 756 int mode; 757 int ret = DDI_SUCCESS; 758 759 #ifdef DEBUG 760 char *str = "ppm_ctlops"; 761 int mask = ppm_debug & (D_CTLOPS1 | D_CTLOPS2); 762 char *ctlstr = ppm_get_ctlstr(reqp->request_type, mask); 763 if (mask && ctlstr) 764 PPMD(mask, ("%s: %s, %s\n", 765 str, ddi_binding_name(rdip), ctlstr)) 766 #endif 767 768 if (ctlop != DDI_CTLOPS_POWER) 769 return (DDI_FAILURE); 770 771 unitp = (ppm_unit_t *)ddi_get_soft_state(ppm_statep, ppm_inst); 772 773 switch (reqp->request_type) { 774 775 /* attempt to blink led if indeed all at lowest */ 776 case PMR_PPM_ALL_LOWEST: 777 mode = (reqp->req.ppm_all_lowest_req.mode == PM_ALL_LOWEST); 778 if (!(unitp->states & PPM_STATE_SUSPENDED) && mode) 779 ppm_manage_led(PPM_LED_BLINKING); 780 else 781 ppm_manage_led(PPM_LED_SOLIDON); 782 PPMD(D_LOWEST, ("%s: %sall devices are at lowest power \n", 783 str, mode ? "" : "not ")) 784 return (DDI_SUCCESS); 785 786 /* undo the claiming of 'rdip' at attach time */ 787 case PMR_PPM_POST_DETACH: 788 ASSERT(reqp->req.ppm_set_power_req.who == rdip); 789 mutex_enter(&unitp->lock); 790 if (reqp->req.ppm_config_req.result != DDI_SUCCESS || 791 (PPM_GET_PRIVATE(rdip) == NULL)) { 792 mutex_exit(&unitp->lock); 793 return (DDI_FAILURE); 794 } 795 mutex_exit(&unitp->lock); 796 ppm_rem_dev(rdip); 797 return (DDI_SUCCESS); 798 799 /* chance to adjust pwr_cnt if resume is about to power up rdip */ 800 case PMR_PPM_PRE_RESUME: 801 ppm_svc_resume_ctlop(rdip, reqp); 802 return (DDI_SUCCESS); 803 804 /* 805 * synchronizing, so that only the owner of the power lock is 806 * permitted to change device and component's power level. 807 */ 808 case PMR_PPM_UNLOCK_POWER: 809 case PMR_PPM_TRY_LOCK_POWER: 810 case PMR_PPM_LOCK_POWER: 811 ppmd = PPM_GET_PRIVATE(rdip); 812 if (ppmd) 813 domp = ppmd->domp; 814 else if (reqp->request_type != PMR_PPM_UNLOCK_POWER) { 815 domp = ppm_lookup_dev(rdip); 816 ASSERT(domp); 817 ppmd = ppm_get_dev(rdip, domp); 818 } 819 820 PPMD(D_LOCKS, ("ppm_lock_%s: %s, %s\n", 821 (domp->dflags & PPMD_LOCK_ALL) ? "all" : "one", 822 ppmd->path, ppm_get_ctlstr(reqp->request_type, D_LOCKS))) 823 824 if (domp->dflags & PPMD_LOCK_ALL) 825 ppm_lock_all(domp, reqp, result); 826 else 827 ppm_lock_one(ppmd, reqp, result); 828 return (DDI_SUCCESS); 829 830 case PMR_PPM_POWER_LOCK_OWNER: 831 ASSERT(reqp->req.ppm_power_lock_owner_req.who == rdip); 832 ppmd = PPM_GET_PRIVATE(rdip); 833 if (ppmd) 834 domp = ppmd->domp; 835 else { 836 domp = ppm_lookup_dev(rdip); 837 ASSERT(domp); 838 ppmd = ppm_get_dev(rdip, domp); 839 } 840 841 /* 842 * In case of LOCK_ALL, effective owner of the power lock 843 * is the owner of the domain lock. otherwise, it is the owner 844 * of the power lock. 845 */ 846 if (domp->dflags & PPMD_LOCK_ALL) 847 reqp->req.ppm_power_lock_owner_req.owner = 848 mutex_owner(&domp->lock); 849 else { 850 reqp->req.ppm_power_lock_owner_req.owner = 851 DEVI(rdip)->devi_busy_thread; 852 } 853 return (DDI_SUCCESS); 854 855 case PMR_PPM_INIT_CHILD: 856 ASSERT(reqp->req.ppm_lock_power_req.who == rdip); 857 if ((domp = ppm_lookup_dev(rdip)) == NULL) 858 return (DDI_SUCCESS); 859 860 /* 861 * We keep track of power-manageable devices starting with 862 * initialization process. The initializing flag remains 863 * set until it is cleared by ppm_add_dev(). Power management 864 * policy for some domains are affected even during device 865 * initialization. For example, PCI domains should leave 866 * their clock running meanwhile a device in that domain 867 * is initializing. 868 */ 869 mutex_enter(&domp->lock); 870 owned = ppm_add_owned(rdip, domp); 871 ASSERT(owned->initializing == 0); 872 owned->initializing = 1; 873 874 if (PPMD_IS_PCI(domp->model) && domp->status == PPMD_OFF) { 875 ret = ppm_switch_clock(domp, PPMD_ON); 876 if (ret == DDI_SUCCESS) 877 domp->dflags |= PPMD_INITCHILD_CLKON; 878 } 879 mutex_exit(&domp->lock); 880 return (ret); 881 882 case PMR_PPM_POST_ATTACH: 883 ASSERT(reqp->req.ppm_config_req.who == rdip); 884 domp = ppm_lookup_dev(rdip); 885 ASSERT(domp); 886 ASSERT(domp->status == PPMD_ON); 887 if (reqp->req.ppm_config_req.result == DDI_SUCCESS) { 888 /* 889 * call ppm_get_dev, which will increment the 890 * domain power count by the right number. 891 * Undo the power count increment, done in PRE_PROBE. 892 */ 893 if (PM_GET_PM_INFO(rdip)) 894 ppmd = ppm_get_dev(rdip, domp); 895 mutex_enter(&domp->lock); 896 ASSERT(domp->pwr_cnt > 0); 897 domp->pwr_cnt--; 898 mutex_exit(&domp->lock); 899 return (DDI_SUCCESS); 900 } 901 902 ret = ppm_power_down_domain(rdip); 903 /* FALLTHROUGH */ 904 case PMR_PPM_UNINIT_CHILD: 905 ASSERT(reqp->req.ppm_lock_power_req.who == rdip); 906 if ((domp = ppm_lookup_dev(rdip)) == NULL) 907 return (DDI_SUCCESS); 908 909 (void) ddi_pathname(rdip, path); 910 mutex_enter(&domp->lock); 911 for (owned = domp->owned; owned; owned = owned->next) 912 if (strcmp(owned->path, path) == 0) 913 break; 914 915 /* 916 * In case we didn't go through a complete attach and detach, 917 * the initializing flag will still be set, so clear it. 918 */ 919 if ((owned != NULL) && (owned->initializing)) 920 owned->initializing = 0; 921 922 if (PPMD_IS_PCI(domp->model) && 923 domp->status == PPMD_ON && domp->pwr_cnt == 0 && 924 (domp->dflags & PPMD_INITCHILD_CLKON) && 925 ppm_none_else_holds_power(domp)) { 926 ret = ppm_switch_clock(domp, PPMD_OFF); 927 if (ret == DDI_SUCCESS) 928 domp->dflags &= ~PPMD_INITCHILD_CLKON; 929 } 930 mutex_exit(&domp->lock); 931 return (ret); 932 933 /* place holders */ 934 case PMR_PPM_UNMANAGE: 935 case PMR_PPM_PRE_DETACH: 936 return (DDI_SUCCESS); 937 938 case PMR_PPM_PRE_PROBE: 939 ASSERT(reqp->req.ppm_config_req.who == rdip); 940 return (ppm_power_up_domain(rdip)); 941 942 case PMR_PPM_POST_PROBE: 943 ASSERT(reqp->req.ppm_config_req.who == rdip); 944 if (reqp->req.ppm_config_req.result == DDI_PROBE_SUCCESS || 945 reqp->req.ppm_config_req.result == DDI_PROBE_DONTCARE) 946 return (DDI_SUCCESS); 947 948 /* Probe failed */ 949 PPMD(D_CTLOPS1 | D_CTLOPS2, ("%s: probe failed for %s@%s " 950 "rv %d\n", str, PM_NAME(rdip), PM_ADDR(rdip), 951 reqp->req.ppm_config_req.result)) 952 return (ppm_power_down_domain(rdip)); 953 954 case PMR_PPM_PRE_ATTACH: 955 ASSERT(reqp->req.ppm_config_req.who == rdip); 956 /* Domain has already been powered up in PRE_PROBE */ 957 domp = ppm_lookup_dev(rdip); 958 ASSERT(domp); 959 ASSERT(domp->status == PPMD_ON); 960 return (DDI_SUCCESS); 961 962 /* ppm intercepts power change process to the claimed devices */ 963 case PMR_PPM_SET_POWER: 964 case PMR_PPM_POWER_CHANGE_NOTIFY: 965 if ((ppmd = PPM_GET_PRIVATE(rdip)) == NULL) { 966 domp = ppm_lookup_dev(rdip); 967 ASSERT(domp); 968 ppmd = ppm_get_dev(rdip, domp); 969 } 970 switch (ppmd->domp->model) { 971 case PPMD_CPU: 972 return (ppm_manage_cpus(rdip, reqp, result)); 973 case PPMD_FET: 974 return (ppm_manage_fet(rdip, reqp, result)); 975 case PPMD_PCI: 976 case PPMD_PCI_PROP: 977 return (ppm_manage_pci(rdip, reqp, result)); 978 case PPMD_PCIE: 979 return (ppm_manage_pcie(rdip, reqp, result)); 980 default: 981 cmn_err(CE_WARN, "ppm_ctlops: domain model %d does" 982 " not support PMR_PPM_SET_POWER ctlop", 983 ppmd->domp->model); 984 return (DDI_FAILURE); 985 } 986 987 default: 988 cmn_err(CE_WARN, "ppm_ctlops: unrecognized ctlops req(%d)", 989 reqp->request_type); 990 return (DDI_FAILURE); 991 } 992 } 993 994 995 /* 996 * Raise the power level of a subrange of cpus. Used when cpu driver 997 * failed an attempt to lower the power of a cpu (probably because 998 * it got busy). Need to revert the ones we already changed. 999 * 1000 * ecpup = the ppm_dev_t for the cpu which failed to lower power 1001 * level = power level to reset prior cpus to 1002 */ 1003 int 1004 ppm_revert_cpu_power(ppm_dev_t *ecpup, int level) 1005 { 1006 ppm_dev_t *cpup; 1007 int ret = DDI_SUCCESS; 1008 1009 for (cpup = ecpup->domp->devlist; cpup != ecpup; cpup = cpup->next) { 1010 PPMD(D_CPU, ("ppm_revert_cpu_power: \"%s\", revert to " 1011 "level %d\n", cpup->path, level)) 1012 1013 ret = pm_power(cpup->dip, 0, level); 1014 if (ret == DDI_SUCCESS) { 1015 cpup->level = level; 1016 cpup->rplvl = PM_LEVEL_UNKNOWN; 1017 } 1018 } 1019 return (ret); 1020 } 1021 1022 1023 /* 1024 * ppm_manage_cpus - Process a request to change the power level of a cpu. 1025 * If not all cpus want to be at the same level, OR if we are currently 1026 * refusing slowdown requests due to thermal stress, we cache the request. 1027 * Otherwise, set all cpus to the new power level. 1028 */ 1029 /* ARGSUSED */ 1030 static int 1031 ppm_manage_cpus(dev_info_t *dip, power_req_t *reqp, int *result) 1032 { 1033 #ifdef DEBUG 1034 char *str = "ppm_manage_cpus"; 1035 #endif 1036 int old, new, ret, kmflag; 1037 ppm_dev_t *ppmd, *cpup; 1038 int change_notify = 0; 1039 pm_ppm_devlist_t *devlist = NULL, *p; 1040 int do_rescan = 0; 1041 1042 *result = DDI_SUCCESS; 1043 1044 switch (reqp->request_type) { 1045 case PMR_PPM_SET_POWER: 1046 break; 1047 1048 case PMR_PPM_POWER_CHANGE_NOTIFY: 1049 change_notify = 1; 1050 break; 1051 1052 default: 1053 return (DDI_FAILURE); 1054 } 1055 1056 ppmd = PPM_GET_PRIVATE(dip); 1057 ASSERT(MUTEX_HELD(&ppmd->domp->lock)); 1058 old = reqp->req.ppm_set_power_req.old_level; 1059 new = reqp->req.ppm_set_power_req.new_level; 1060 1061 if (change_notify) { 1062 ppmd->level = new; 1063 ppmd->rplvl = PM_LEVEL_UNKNOWN; 1064 1065 PPMD(D_CPU, ("%s: Notify cpu dip %p power level has changed " 1066 "from %d to %d", str, (void *)dip, old, new)) 1067 return (DDI_SUCCESS); 1068 } 1069 1070 if (ppm_manage_early_cpus(dip, new, result)) 1071 return (*result); 1072 1073 if (new == ppmd->level) { 1074 PPMD(D_CPU, ("%s: already at power level %d\n", str, new)) 1075 return (DDI_SUCCESS); 1076 } 1077 1078 /* 1079 * A request from lower to higher level transition is granted and 1080 * made effective on all cpus. A request from higher to lower must 1081 * be agreed upon by all cpus. 1082 */ 1083 ppmd->rplvl = new; 1084 for (cpup = ppmd->domp->devlist; cpup; cpup = cpup->next) { 1085 if (cpup->rplvl == new) 1086 continue; 1087 1088 if (new < old) { 1089 PPMD(D_SOME, ("%s: not all cpus wants to be at new " 1090 "level %d yet.\n", str, new)) 1091 return (DDI_SUCCESS); 1092 } 1093 1094 /* 1095 * If a single cpu requests power up, honor the request 1096 * powering up all cpus. 1097 */ 1098 if (new > old) { 1099 PPMD(D_SOME, ("%s: powering up device(%s@%s, %p) " 1100 "because of request from dip(%s@%s, %p), " 1101 "need pm_rescan\n", str, PM_NAME(cpup->dip), 1102 PM_ADDR(cpup->dip), (void *)cpup->dip, 1103 PM_NAME(dip), PM_ADDR(dip), (void *)dip)) 1104 do_rescan++; 1105 } 1106 } 1107 1108 PPMD(D_SETLVL, ("%s: \"%s\" set power level old %d, new %d \n", 1109 str, ppmd->path, ppmd->level, new)) 1110 ret = ppm_change_cpu_power(ppmd, new); 1111 *result = ret; 1112 1113 if (ret == DDI_SUCCESS) { 1114 if (reqp->req.ppm_set_power_req.canblock == PM_CANBLOCK_BLOCK) 1115 kmflag = KM_SLEEP; 1116 else 1117 kmflag = KM_NOSLEEP; 1118 1119 for (cpup = ppmd->domp->devlist; cpup; cpup = cpup->next) { 1120 if (cpup->dip == dip) 1121 continue; 1122 1123 if ((p = kmem_zalloc(sizeof (pm_ppm_devlist_t), 1124 kmflag)) == NULL) { 1125 break; 1126 } 1127 p->ppd_who = cpup->dip; 1128 p->ppd_cmpt = cpup->cmpt; 1129 p->ppd_old_level = old; 1130 p->ppd_new_level = new; 1131 p->ppd_next = devlist; 1132 1133 PPMD(D_SETLVL, ("%s: devlist entry[\"%s\"] %d -> %d\n", 1134 str, cpup->path, old, new)) 1135 1136 devlist = p; 1137 } 1138 reqp->req.ppm_set_power_req.cookie = (void *) devlist; 1139 1140 if (do_rescan > 0) { 1141 for (cpup = ppmd->domp->devlist; cpup; 1142 cpup = cpup->next) { 1143 if (cpup->dip == dip) 1144 continue; 1145 pm_rescan(cpup->dip); 1146 } 1147 } 1148 } 1149 1150 return (ret); 1151 } 1152 1153 1154 /* 1155 * ppm_svc_resume_ctlop - this is a small bookkeeping ppm does - 1156 * increments its FET domain power count, in anticipation of that 1157 * the indicated device(dip) would be powered up by its driver as 1158 * a result of cpr resuming. 1159 */ 1160 /* ARGSUSED */ 1161 static void 1162 ppm_svc_resume_ctlop(dev_info_t *dip, power_req_t *reqp) 1163 { 1164 ppm_domain_t *domp; 1165 ppm_dev_t *ppmd; 1166 int powered; /* power up count per dip */ 1167 1168 ppmd = PPM_GET_PRIVATE(dip); 1169 if (ppmd == NULL) 1170 return; 1171 1172 /* 1173 * Maintain correct powered count for domain which cares 1174 */ 1175 powered = 0; 1176 domp = ppmd->domp; 1177 mutex_enter(&domp->lock); 1178 if ((domp->model == PPMD_FET) || PPMD_IS_PCI(domp->model) || 1179 (domp->model == PPMD_PCIE)) { 1180 for (ppmd = domp->devlist; ppmd; ppmd = ppmd->next) { 1181 if (ppmd->dip == dip && ppmd->level) 1182 powered++; 1183 } 1184 1185 /* 1186 * All fets and clocks are held on during suspend - 1187 * resume window regardless their domain devices' power 1188 * level. 1189 */ 1190 ASSERT(domp->status == PPMD_ON); 1191 1192 /* 1193 * The difference indicates the number of components 1194 * being off prior to suspend operation, that is the 1195 * amount needs to be compensated in order to sync up 1196 * bookkeeping with reality, for PROM reset would have 1197 * brought up all devices. 1198 */ 1199 if (powered < PM_NUMCMPTS(dip)) 1200 domp->pwr_cnt += PM_NUMCMPTS(dip) - powered; 1201 } 1202 for (ppmd = domp->devlist; ppmd; ppmd = ppmd->next) { 1203 if (ppmd->dip == dip) 1204 ppmd->level = ppmd->rplvl = PM_LEVEL_UNKNOWN; 1205 } 1206 mutex_exit(&domp->lock); 1207 } 1208 1209 #ifdef DEBUG 1210 static int ppmbringup = 0; 1211 #endif 1212 1213 int 1214 ppm_bringup_domains() 1215 { 1216 #ifdef DEBUG 1217 char *str = "ppm_bringup_domains"; 1218 #endif 1219 ppm_domain_t *domp; 1220 int ret = DDI_SUCCESS; 1221 1222 PPMD(D_CPR, ("%s[%d]: enter\n", str, ++ppmbringup)) 1223 for (domp = ppm_domain_p; domp; domp = domp->next) { 1224 if ((!PPMD_IS_PCI(domp->model) && (domp->model != PPMD_FET) && 1225 (domp->model != PPMD_PCIE)) || (domp->devlist == NULL)) 1226 continue; 1227 1228 mutex_enter(&domp->lock); 1229 if (domp->status == PPMD_ON) { 1230 mutex_exit(&domp->lock); 1231 continue; 1232 } 1233 switch (domp->model) { 1234 case PPMD_FET: 1235 ret = ppm_fetset(domp, PPMD_ON); 1236 break; 1237 case PPMD_PCI: 1238 case PPMD_PCI_PROP: 1239 ret = ppm_switch_clock(domp, PPMD_ON); 1240 break; 1241 case PPMD_PCIE: 1242 ret = ppm_pcie_pwr(domp, PPMD_ON); 1243 break; 1244 default: 1245 break; 1246 } 1247 mutex_exit(&domp->lock); 1248 } 1249 PPMD(D_CPR, ("%s[%d]: exit, ret=%d\n", str, ppmbringup, ret)) 1250 1251 return (ret); 1252 } 1253 1254 #ifdef DEBUG 1255 static int ppmsyncbp = 0; 1256 #endif 1257 1258 int 1259 ppm_sync_bookkeeping() 1260 { 1261 #ifdef DEBUG 1262 char *str = "ppm_sync_bookkeeping"; 1263 #endif 1264 ppm_domain_t *domp; 1265 int ret = DDI_SUCCESS; 1266 1267 PPMD(D_CPR, ("%s[%d]: enter\n", str, ++ppmsyncbp)) 1268 for (domp = ppm_domain_p; domp; domp = domp->next) { 1269 if ((!PPMD_IS_PCI(domp->model) && (domp->model != PPMD_FET) && 1270 (domp->model != PPMD_PCIE)) || (domp->devlist == NULL)) 1271 continue; 1272 1273 mutex_enter(&domp->lock); 1274 if ((domp->pwr_cnt != 0) || !ppm_none_else_holds_power(domp)) { 1275 mutex_exit(&domp->lock); 1276 continue; 1277 } 1278 switch (domp->model) { 1279 case PPMD_FET: 1280 ret = ppm_fetset(domp, PPMD_OFF); 1281 break; 1282 case PPMD_PCI: 1283 case PPMD_PCI_PROP: 1284 ret = ppm_switch_clock(domp, PPMD_OFF); 1285 break; 1286 case PPMD_PCIE: 1287 ret = ppm_pcie_pwr(domp, PPMD_OFF); 1288 break; 1289 default: 1290 break; 1291 } 1292 mutex_exit(&domp->lock); 1293 } 1294 PPMD(D_CPR, ("%s[%d]: exit, ret=%d\n", str, ppmsyncbp, ret)) 1295 1296 return (ret); 1297 } 1298 1299 1300 1301 /* 1302 * pre-suspend window; 1303 * 1304 * power up every FET and PCI clock that are off; 1305 * 1306 * set ppm_cpr_window global flag to indicate 1307 * that even though all pm_scan requested power transitions 1308 * will be honored as usual but that until we're out 1309 * of this window, no FET or clock will be turned off 1310 * for domains with pwr_cnt decremented down to 0. 1311 * Such is to avoid accessing the orthogonal drivers that own 1312 * the FET and clock registers that may not be resumed yet. 1313 * 1314 * at post-resume window, walk through each FET and PCI domains, 1315 * bring pwr_cnt and domp->status to sense: if pwr-cnt == 0, 1316 * and noinvol check okays, power down the FET or PCI. At last, 1317 * clear the global flag ppm_cpr_window. 1318 * 1319 * ASSERT case 1, during cpr window, checks pwr_cnt against power 1320 * transitions; 1321 * ASSERT case 2, out of cpr window, checks four things: 1322 * pwr_cnt <> power transition in/out of 0 1323 * <> status <> record of noinvol device detached 1324 * 1325 */ 1326 /* ARGSUSED */ 1327 static boolean_t 1328 ppm_cpr_callb(void *arg, int code) 1329 { 1330 int ret; 1331 1332 switch (code) { 1333 case CB_CODE_CPR_CHKPT: 1334 1335 /* pre-suspend: start of cpr window */ 1336 mutex_enter(&ppm_cpr_window_lock); 1337 ASSERT(ppm_cpr_window_flag == B_FALSE); 1338 ppm_cpr_window_flag = B_TRUE; 1339 mutex_exit(&ppm_cpr_window_lock); 1340 1341 ret = ppm_bringup_domains(); 1342 1343 break; 1344 1345 case CB_CODE_CPR_RESUME: 1346 1347 /* post-resume: end of cpr window */ 1348 ret = ppm_sync_bookkeeping(); 1349 1350 mutex_enter(&ppm_cpr_window_lock); 1351 ASSERT(ppm_cpr_window_flag == B_TRUE); 1352 ppm_cpr_window_flag = B_FALSE; 1353 mutex_exit(&ppm_cpr_window_lock); 1354 1355 break; 1356 } 1357 1358 return (ret == DDI_SUCCESS); 1359 } 1360 1361 1362 /* 1363 * Initialize our private version of real power level 1364 * as well as lowest and highest levels the device supports; 1365 * relate to ppm_add_dev 1366 */ 1367 void 1368 ppm_dev_init(ppm_dev_t *ppmd) 1369 { 1370 struct pm_component *dcomps; 1371 struct pm_comp *pm_comp; 1372 dev_info_t *dip; 1373 int maxi, i; 1374 1375 ASSERT(MUTEX_HELD(&ppmd->domp->lock)); 1376 ppmd->level = PM_LEVEL_UNKNOWN; 1377 ppmd->rplvl = PM_LEVEL_UNKNOWN; 1378 1379 /* increment pwr_cnt per component */ 1380 if ((ppmd->domp->model == PPMD_FET) || 1381 PPMD_IS_PCI(ppmd->domp->model) || 1382 (ppmd->domp->model == PPMD_PCIE)) 1383 ppmd->domp->pwr_cnt++; 1384 1385 dip = ppmd->dip; 1386 1387 /* 1388 * ppm exists to handle power-manageable devices which require 1389 * special handling on the current platform. However, a 1390 * driver for such a device may choose not to support power 1391 * management on a particular load/attach. In this case we 1392 * we create a structure to represent a single-component device 1393 * for which "level" = PM_LEVEL_UNKNOWN and "lowest" = 0 1394 * are effectively constant. 1395 */ 1396 if (PM_GET_PM_INFO(dip)) { 1397 dcomps = DEVI(dip)->devi_pm_components; 1398 pm_comp = &dcomps[ppmd->cmpt].pmc_comp; 1399 1400 ppmd->lowest = pm_comp->pmc_lvals[0]; 1401 ASSERT(ppmd->lowest >= 0); 1402 maxi = pm_comp->pmc_numlevels - 1; 1403 ppmd->highest = pm_comp->pmc_lvals[maxi]; 1404 1405 /* 1406 * If 66mhz PCI device on pci 66mhz bus supports D2 state 1407 * (config reg PMC bit 10 set), ppm could turn off its bus 1408 * clock once it is at D3hot. 1409 */ 1410 if (ppmd->domp->dflags & PPMD_PCI66MHZ) { 1411 for (i = 0; i < maxi; i++) 1412 if (pm_comp->pmc_lvals[i] == PM_LEVEL_D2) { 1413 ppmd->flags |= PPMDEV_PCI66_D2; 1414 break; 1415 } 1416 } 1417 } 1418 1419 /* 1420 * If device is in PCI_PROP domain and has exported the 1421 * property listed in ppm.conf, its clock will be turned 1422 * off when all pm'able devices in that domain are at D3. 1423 */ 1424 if ((ppmd->domp->model == PPMD_PCI_PROP) && 1425 (ppmd->domp->propname != NULL) && 1426 ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1427 ppmd->domp->propname)) 1428 ppmd->flags |= PPMDEV_PCI_PROP_CLKPM; 1429 } 1430 1431 1432 /* 1433 * relate to ppm_rem_dev 1434 */ 1435 void 1436 ppm_dev_fini(ppm_dev_t *ppmd) 1437 { 1438 ASSERT(MUTEX_HELD(&ppmd->domp->lock)); 1439 1440 /* decrement pwr_cnt per component */ 1441 if ((ppmd->domp->model == PPMD_FET) || 1442 PPMD_IS_PCI(ppmd->domp->model) || 1443 (ppmd->domp->model == PPMD_PCIE)) 1444 if (ppmd->level != ppmd->lowest) 1445 ppmd->domp->pwr_cnt--; 1446 } 1447 1448 /* 1449 * Each power fet controls the power of one or more platform 1450 * device(s) within their domain. Hence domain devices' power 1451 * level change has been monitored, such that once all devices 1452 * are powered off, the fet is turned off to save more power. 1453 * 1454 * To power on any domain device, the domain power fet 1455 * needs to be turned on first. always one fet per domain. 1456 */ 1457 static int 1458 ppm_manage_fet(dev_info_t *dip, power_req_t *reqp, int *result) 1459 { 1460 #ifdef DEBUG 1461 char *str = "ppm_manage_fet"; 1462 #endif 1463 int (*pwr_func)(ppm_dev_t *, int, int); 1464 int new, old, cmpt; 1465 ppm_dev_t *ppmd; 1466 ppm_domain_t *domp; 1467 int incr = 0; 1468 int dummy_ret; 1469 1470 1471 *result = DDI_SUCCESS; 1472 switch (reqp->request_type) { 1473 case PMR_PPM_SET_POWER: 1474 pwr_func = ppm_change_power_level; 1475 old = reqp->req.ppm_set_power_req.old_level; 1476 new = reqp->req.ppm_set_power_req.new_level; 1477 cmpt = reqp->req.ppm_set_power_req.cmpt; 1478 break; 1479 case PMR_PPM_POWER_CHANGE_NOTIFY: 1480 pwr_func = ppm_record_level_change; 1481 old = reqp->req.ppm_notify_level_req.old_level; 1482 new = reqp->req.ppm_notify_level_req.new_level; 1483 cmpt = reqp->req.ppm_notify_level_req.cmpt; 1484 break; 1485 default: 1486 *result = DDI_FAILURE; 1487 PPMD(D_FET, ("%s: unknown request type %d for %s@%s\n", 1488 str, reqp->request_type, PM_NAME(dip), PM_ADDR(dip))) 1489 return (DDI_FAILURE); 1490 } 1491 1492 for (ppmd = PPM_GET_PRIVATE(dip); ppmd; ppmd = ppmd->next) 1493 if (cmpt == ppmd->cmpt) 1494 break; 1495 if (!ppmd) { 1496 PPMD(D_FET, ("%s: dip(%p): old(%d)->new(%d): no ppm_dev" 1497 " found for cmpt(%d)", str, (void *)dip, old, new, cmpt)) 1498 *result = DDI_FAILURE; 1499 return (DDI_FAILURE); 1500 } 1501 domp = ppmd->domp; 1502 PPMD(D_FET, ("%s: %s@%s %s old %d, new %d, c%d, level %d, " 1503 "status %s\n", str, PM_NAME(dip), PM_ADDR(dip), 1504 ppm_get_ctlstr(reqp->request_type, ~0), old, new, cmpt, 1505 ppmd->level, (domp->status == PPMD_OFF ? "off" : "on"))) 1506 1507 1508 ASSERT(old == ppmd->level); 1509 1510 if (new == ppmd->level) { 1511 PPMD(D_FET, ("nop\n")) 1512 return (DDI_SUCCESS); 1513 } 1514 1515 PPM_LOCK_DOMAIN(domp); 1516 1517 /* 1518 * In general, a device's published lowest power level does not 1519 * have to be 0 if power-off is not tolerated. i.e. a device 1520 * instance may export its lowest level > 0. It is reasonable to 1521 * assume that level 0 indicates off state, positive level values 1522 * indicate power states above off, include full power state. 1523 */ 1524 if (new > 0) { /* device powering up or to different positive level */ 1525 if (domp->status == PPMD_OFF) { 1526 1527 /* can not be in (chpt, resume) window */ 1528 ASSERT(ppm_cpr_window_flag == B_FALSE); 1529 1530 ASSERT(old == 0 && domp->pwr_cnt == 0); 1531 1532 PPMD(D_FET, ("About to turn fet on for %s@%s c%d\n", 1533 PM_NAME(dip), PM_ADDR(dip), cmpt)) 1534 1535 *result = ppm_fetset(domp, PPMD_ON); 1536 if (*result != DDI_SUCCESS) { 1537 PPMD(D_FET, ("\tCan't turn on power FET: " 1538 "ret(%d)\n", *result)) 1539 PPM_UNLOCK_DOMAIN(domp); 1540 return (DDI_FAILURE); 1541 } 1542 } 1543 1544 /* 1545 * If powering up, pre-increment the count before 1546 * calling pwr_func, because we are going to release 1547 * the domain lock and another thread might turn off 1548 * domain power otherwise. 1549 */ 1550 if (old == 0) { 1551 domp->pwr_cnt++; 1552 incr = 1; 1553 } 1554 1555 PPMD(D_FET, ("\t%s domain power count: %d\n", 1556 domp->name, domp->pwr_cnt)) 1557 } 1558 1559 1560 PPM_UNLOCK_DOMAIN(domp); 1561 1562 ASSERT(domp->pwr_cnt > 0); 1563 1564 if ((*result = (*pwr_func)(ppmd, cmpt, new)) != DDI_SUCCESS) { 1565 PPMD(D_FET, ("\t%s power change failed: ret(%d)\n", 1566 ppmd->path, *result)) 1567 } 1568 1569 PPM_LOCK_DOMAIN(domp); 1570 1571 /* 1572 * Decr the power count in two cases: 1573 * 1574 * 1) request was to power device down and was successful 1575 * 2) request was to power up (we pre-incremented count), but failed. 1576 */ 1577 if ((*result == DDI_SUCCESS && ppmd->level == 0) || 1578 (*result != DDI_SUCCESS && incr)) { 1579 ASSERT(domp->pwr_cnt > 0); 1580 domp->pwr_cnt--; 1581 } 1582 1583 PPMD(D_FET, ("\t%s domain power count: %d\n", 1584 domp->name, domp->pwr_cnt)) 1585 1586 /* 1587 * call to pwr_func will update ppm data structures, if it 1588 * succeeds. ppm should return whatever is the return value 1589 * from call to pwr_func. This way pm and ppm data structures 1590 * always in sync. Use dummy_ret from here for any further 1591 * return values. 1592 */ 1593 if ((domp->pwr_cnt == 0) && 1594 (ppm_cpr_window_flag == B_FALSE) && 1595 ppm_none_else_holds_power(domp)) { 1596 1597 PPMD(D_FET, ("About to turn FET off for %s@%s c%d\n", 1598 PM_NAME(dip), PM_ADDR(dip), cmpt)) 1599 1600 dummy_ret = ppm_fetset(domp, PPMD_OFF); 1601 if (dummy_ret != DDI_SUCCESS) { 1602 PPMD(D_FET, ("\tCan't turn off FET: ret(%d)\n", 1603 dummy_ret)) 1604 } 1605 } 1606 1607 PPM_UNLOCK_DOMAIN(domp); 1608 ASSERT(domp->pwr_cnt >= 0); 1609 return (*result); 1610 } 1611 1612 1613 /* 1614 * the actual code that turn on or off domain power fet and 1615 * update domain status 1616 */ 1617 static int 1618 ppm_fetset(ppm_domain_t *domp, uint8_t value) 1619 { 1620 char *str = "ppm_fetset"; 1621 int key; 1622 ppm_dc_t *dc; 1623 int ret; 1624 clock_t temp; 1625 clock_t delay = 0; 1626 1627 key = (value == PPMD_ON) ? PPMDC_FET_ON : PPMDC_FET_OFF; 1628 for (dc = domp->dc; dc; dc = dc->next) 1629 if (dc->cmd == key) 1630 break; 1631 if (!dc || !dc->lh) { 1632 PPMD(D_FET, ("%s: %s domain: NULL ppm_dc handle\n", 1633 str, domp->name)) 1634 return (DDI_FAILURE); 1635 } 1636 1637 if (key == PPMDC_FET_ON) { 1638 PPM_GET_IO_DELAY(dc, delay); 1639 if (delay > 0 && domp->last_off_time > 0) { 1640 /* 1641 * provide any delay required before turning on. 1642 * some devices e.g. Samsung DVD require minimum 1643 * of 1 sec between OFF->ON. no delay is required 1644 * for the first time. 1645 */ 1646 temp = ddi_get_lbolt(); 1647 temp -= domp->last_off_time; 1648 temp = drv_hztousec(temp); 1649 1650 if (temp < delay) { 1651 /* 1652 * busy wait untill we meet the 1653 * required delay. Since we maintain 1654 * time stamps in terms of clock ticks 1655 * we might wait for longer than required 1656 */ 1657 PPMD(D_FET, ("%s : waiting %lu micro seconds " 1658 "before on\n", domp->name, 1659 delay - temp)) 1660 drv_usecwait(delay - temp); 1661 } 1662 } 1663 } 1664 switch (dc->method) { 1665 #if !defined(__x86) 1666 case PPMDC_I2CKIO: { 1667 i2c_gpio_t i2c_req; 1668 i2c_req.reg_mask = dc->m_un.i2c.mask; 1669 i2c_req.reg_val = dc->m_un.i2c.val; 1670 ret = ldi_ioctl(dc->lh, dc->m_un.i2c.iowr, 1671 (intptr_t)&i2c_req, FWRITE | FKIOCTL, kcred, NULL); 1672 break; 1673 } 1674 #endif 1675 1676 case PPMDC_KIO: 1677 ret = ldi_ioctl(dc->lh, dc->m_un.kio.iowr, 1678 (intptr_t)&(dc->m_un.kio.val), FWRITE | FKIOCTL, kcred, 1679 NULL); 1680 break; 1681 1682 default: 1683 PPMD(D_FET, ("\t%s: unsupported domain control method %d\n", 1684 str, domp->dc->method)) 1685 return (DDI_FAILURE); 1686 } 1687 1688 PPMD(D_FET, ("%s: %s domain(%s) FET from %s to %s\n", str, 1689 (ret == 0) ? "turned" : "failed to turn", 1690 domp->name, 1691 (domp->status == PPMD_ON) ? "ON" : "OFF", 1692 (value == PPMD_ON) ? "ON" : "OFF")) 1693 1694 if (ret == DDI_SUCCESS) { 1695 domp->status = value; 1696 1697 if (key == PPMDC_FET_OFF) 1698 /* 1699 * record the time, when it is off. time is recorded 1700 * in clock ticks 1701 */ 1702 domp->last_off_time = ddi_get_lbolt(); 1703 1704 /* implement any post op delay. */ 1705 if (key == PPMDC_FET_ON) { 1706 PPM_GET_IO_DELAY(dc, delay); 1707 PPMD(D_FET, ("%s : waiting %lu micro seconds " 1708 "after on\n", domp->name, delay)) 1709 if (delay > 0) 1710 drv_usecwait(delay); 1711 } 1712 } 1713 1714 return (ret); 1715 } 1716 1717 1718 /* 1719 * read power fet status 1720 */ 1721 static int 1722 ppm_fetget(ppm_domain_t *domp, uint8_t *lvl) 1723 { 1724 char *str = "ppm_fetget"; 1725 ppm_dc_t *dc = domp->dc; 1726 uint_t kio_val; 1727 int off_val; 1728 int ret; 1729 1730 if (!dc->lh) { 1731 PPMD(D_FET, ("%s: %s domain NULL ppm_dc layered handle\n", 1732 str, domp->name)) 1733 return (DDI_FAILURE); 1734 } 1735 if (!dc->next) { 1736 cmn_err(CE_WARN, "%s: expect both fet on and fet off ops " 1737 "defined, found only one in domain(%s)", str, domp->name); 1738 return (DDI_FAILURE); 1739 } 1740 1741 switch (dc->method) { 1742 #if !defined(__x86) 1743 case PPMDC_I2CKIO: { 1744 i2c_gpio_t i2c_req; 1745 i2c_req.reg_mask = dc->m_un.i2c.mask; 1746 ret = ldi_ioctl(dc->lh, dc->m_un.i2c.iord, 1747 (intptr_t)&i2c_req, FWRITE | FKIOCTL, kcred, NULL); 1748 1749 if (ret) { 1750 PPMD(D_FET, ("%s: PPMDC_I2CKIO failed: ret(%d)\n", 1751 str, ret)) 1752 return (ret); 1753 } 1754 1755 off_val = (dc->cmd == PPMDC_FET_OFF) ? dc->m_un.i2c.val : 1756 dc->next->m_un.i2c.val; 1757 *lvl = (i2c_req.reg_val == off_val) ? PPMD_OFF : PPMD_ON; 1758 1759 PPMD(D_FET, ("%s: %s domain FET %s\n", str, domp->name, 1760 (i2c_req.reg_val == off_val) ? "OFF" : "ON")) 1761 1762 break; 1763 } 1764 #endif 1765 1766 case PPMDC_KIO: 1767 ret = ldi_ioctl(dc->lh, dc->m_un.kio.iord, 1768 (intptr_t)&kio_val, FWRITE | FKIOCTL, kcred, NULL); 1769 if (ret) { 1770 PPMD(D_FET, ("%s: PPMDC_KIO failed: ret(%d)\n", 1771 str, ret)) 1772 return (ret); 1773 } 1774 1775 off_val = (dc->cmd == PPMDC_FET_OFF) ? dc->m_un.kio.val : 1776 dc->next->m_un.kio.val; 1777 *lvl = (kio_val == off_val) ? PPMD_OFF : PPMD_ON; 1778 1779 PPMD(D_FET, ("%s: %s domain FET %s\n", str, domp->name, 1780 (kio_val == off_val) ? "OFF" : "ON")) 1781 1782 break; 1783 1784 default: 1785 PPMD(D_FET, ("%s: unsupported domain control method %d\n", 1786 str, domp->dc->method)) 1787 return (DDI_FAILURE); 1788 } 1789 1790 return (DDI_SUCCESS); 1791 } 1792 1793 1794 /* 1795 * the actual code that switches pci clock and update domain status 1796 */ 1797 static int 1798 ppm_switch_clock(ppm_domain_t *domp, int onoff) 1799 { 1800 #ifdef DEBUG 1801 char *str = "ppm_switch_clock"; 1802 #endif 1803 int cmd, pio_save; 1804 ppm_dc_t *dc; 1805 int ret; 1806 extern int do_polled_io; 1807 extern uint_t cfb_inuse; 1808 ppm_dev_t *pdev; 1809 1810 cmd = (onoff == PPMD_ON) ? PPMDC_CLK_ON : PPMDC_CLK_OFF; 1811 dc = ppm_lookup_dc(domp, cmd); 1812 if (!dc) { 1813 PPMD(D_PCI, ("%s: no ppm_dc found for domain (%s)\n", 1814 str, domp->name)) 1815 return (DDI_FAILURE); 1816 } 1817 1818 switch (dc->method) { 1819 case PPMDC_KIO: 1820 /* 1821 * If we're powering up cfb on a Stop-A, we only 1822 * want to do polled i/o to turn ON the clock 1823 */ 1824 pio_save = do_polled_io; 1825 if ((cfb_inuse) && (cmd == PPMDC_CLK_ON)) { 1826 for (pdev = domp->devlist; pdev; pdev = pdev->next) { 1827 if (pm_is_cfb(pdev->dip)) { 1828 do_polled_io = 1; 1829 break; 1830 } 1831 } 1832 } 1833 1834 ret = ldi_ioctl(dc->lh, dc->m_un.kio.iowr, 1835 (intptr_t)&(dc->m_un.kio.val), FWRITE | FKIOCTL, 1836 kcred, NULL); 1837 1838 do_polled_io = pio_save; 1839 1840 if (ret == 0) { 1841 if (cmd == PPMDC_CLK_ON) { 1842 domp->status = PPMD_ON; 1843 1844 /* 1845 * PCI PM spec requires 50ms delay 1846 */ 1847 drv_usecwait(50000); 1848 } else 1849 domp->status = PPMD_OFF; 1850 } 1851 1852 PPMD(D_PCI, ("%s: %s pci clock %s for domain (%s)\n", str, 1853 (ret == 0) ? "turned" : "failed to turn", 1854 (cmd == PPMDC_CLK_OFF) ? "OFF" : "ON", 1855 domp->name)) 1856 1857 break; 1858 1859 default: 1860 PPMD(D_PCI, ("%s: unsupported domain control method %d\n", 1861 str, dc->method)) 1862 return (DDI_FAILURE); 1863 } 1864 1865 return (DDI_SUCCESS); 1866 } 1867 1868 1869 /* 1870 * pci slot domain is formed of pci device(s) reside in a pci slot. 1871 * This function monitors domain device's power level change, such 1872 * that, 1873 * when all domain power count has gone to 0, it attempts to turn off 1874 * the pci slot's clock; 1875 * if any domain device is powering up, it'll turn on the pci slot's 1876 * clock as the first thing. 1877 */ 1878 /* ARGUSED */ 1879 static int 1880 ppm_manage_pci(dev_info_t *dip, power_req_t *reqp, int *result) 1881 { 1882 #ifdef DEBUG 1883 char *str = "ppm_manage_pci"; 1884 #endif 1885 int (*pwr_func)(ppm_dev_t *, int, int); 1886 int old, new, cmpt; 1887 ppm_dev_t *ppmd; 1888 ppm_domain_t *domp; 1889 int incr = 0; 1890 int dummy_ret; 1891 1892 *result = DDI_SUCCESS; 1893 switch (reqp->request_type) { 1894 case PMR_PPM_SET_POWER: 1895 pwr_func = ppm_change_power_level; 1896 old = reqp->req.ppm_set_power_req.old_level; 1897 new = reqp->req.ppm_set_power_req.new_level; 1898 cmpt = reqp->req.ppm_set_power_req.cmpt; 1899 break; 1900 1901 case PMR_PPM_POWER_CHANGE_NOTIFY: 1902 pwr_func = ppm_record_level_change; 1903 old = reqp->req.ppm_notify_level_req.old_level; 1904 new = reqp->req.ppm_notify_level_req.new_level; 1905 cmpt = reqp->req.ppm_notify_level_req.cmpt; 1906 break; 1907 1908 default: 1909 *result = DDI_FAILURE; 1910 return (DDI_FAILURE); 1911 } 1912 1913 for (ppmd = PPM_GET_PRIVATE(dip); ppmd; ppmd = ppmd->next) 1914 if (cmpt == ppmd->cmpt) 1915 break; 1916 if (!ppmd) { 1917 PPMD(D_PCI, ("%s: dip(%p): old(%d), new(%d): no ppm_dev" 1918 " found for cmpt(%d)", str, (void *)dip, old, new, cmpt)) 1919 *result = DDI_FAILURE; 1920 return (DDI_FAILURE); 1921 } 1922 domp = ppmd->domp; 1923 PPMD(D_PCI, ("%s: %s, dev(%s), c%d, old %d, new %d\n", str, 1924 ppm_get_ctlstr(reqp->request_type, ~0), 1925 ppmd->path, cmpt, old, new)) 1926 1927 ASSERT(old == ppmd->level); 1928 if (new == ppmd->level) 1929 return (DDI_SUCCESS); 1930 1931 PPM_LOCK_DOMAIN(domp); 1932 1933 if (new > 0) { /* device powering up */ 1934 if (domp->status == PPMD_OFF) { 1935 1936 /* cannot be off during (chpt, resume) window */ 1937 ASSERT(ppm_cpr_window_flag == B_FALSE); 1938 1939 /* either both OFF or both ON */ 1940 ASSERT(!((old == 0) ^ (domp->pwr_cnt == 0))); 1941 1942 PPMD(D_PCI, ("About to turn clock on for %s@%s c%d\n", 1943 PM_NAME(dip), PM_ADDR(dip), cmpt)) 1944 1945 *result = ppm_switch_clock(domp, PPMD_ON); 1946 if (*result != DDI_SUCCESS) { 1947 PPMD(D_PCI, ("\tcan't switch on pci clock: " 1948 "ret(%d)\n", *result)) 1949 PPM_UNLOCK_DOMAIN(domp); 1950 return (DDI_FAILURE); 1951 } 1952 } 1953 1954 if (old == 0) { 1955 domp->pwr_cnt++; 1956 incr = 1; 1957 } 1958 1959 PPMD(D_PCI, ("\t%s domain power count: %d\n", 1960 domp->name, domp->pwr_cnt)) 1961 } 1962 1963 PPM_UNLOCK_DOMAIN(domp); 1964 1965 ASSERT(domp->pwr_cnt > 0); 1966 1967 if ((*result = (*pwr_func)(ppmd, cmpt, new)) != DDI_SUCCESS) { 1968 PPMD(D_PCI, ("\t%s power change failed: ret(%d)\n", 1969 ppmd->path, *result)) 1970 } 1971 1972 PPM_LOCK_DOMAIN(domp); 1973 1974 /* 1975 * Decr the power count in two cases: 1976 * 1977 * 1) request was to power device down and was successful 1978 * 2) request was to power up (we pre-incremented count), but failed. 1979 */ 1980 if ((*result == DDI_SUCCESS && ppmd->level == 0) || 1981 (*result != DDI_SUCCESS && incr)) { 1982 ASSERT(domp->pwr_cnt > 0); 1983 domp->pwr_cnt--; 1984 } 1985 1986 PPMD(D_PCI, ("\t%s domain power count: %d\n", 1987 domp->name, domp->pwr_cnt)) 1988 1989 /* 1990 * call to pwr_func will update ppm data structures, if it 1991 * succeeds. ppm should return whatever is the return value 1992 * from call to pwr_func. This way pm and ppm data structures 1993 * always in sync. Use dummy_ret from here for any further 1994 * return values. 1995 */ 1996 if ((domp->pwr_cnt == 0) && 1997 (ppm_cpr_window_flag == B_FALSE) && 1998 ppm_none_else_holds_power(domp)) { 1999 2000 PPMD(D_PCI, ("About to turn clock off for %s@%s c%d\n", 2001 PM_NAME(dip), PM_ADDR(dip), cmpt)) 2002 2003 dummy_ret = ppm_switch_clock(domp, PPMD_OFF); 2004 if (dummy_ret != DDI_SUCCESS) { 2005 PPMD(D_PCI, ("\tCan't switch clock off: " 2006 "ret(%d)\n", dummy_ret)) 2007 } 2008 } 2009 2010 PPM_UNLOCK_DOMAIN(domp); 2011 ASSERT(domp->pwr_cnt >= 0); 2012 return (*result); 2013 } 2014 2015 /* 2016 * When the driver for the primary PCI-Express child has set the device to 2017 * lowest power (D3hot), we come here to save even more power by transitioning 2018 * the slot to D3cold. Similarly, if the slot is in D3cold and we need to 2019 * power up the child, we come here first to power up the slot. 2020 */ 2021 /* ARGUSED */ 2022 static int 2023 ppm_manage_pcie(dev_info_t *dip, power_req_t *reqp, int *result) 2024 { 2025 #ifdef DEBUG 2026 char *str = "ppm_manage_pcie"; 2027 #endif 2028 int (*pwr_func)(ppm_dev_t *, int, int); 2029 int old, new, cmpt; 2030 ppm_dev_t *ppmd; 2031 ppm_domain_t *domp; 2032 int incr = 0; 2033 int dummy_ret; 2034 2035 *result = DDI_SUCCESS; 2036 switch (reqp->request_type) { 2037 case PMR_PPM_SET_POWER: 2038 pwr_func = ppm_change_power_level; 2039 old = reqp->req.ppm_set_power_req.old_level; 2040 new = reqp->req.ppm_set_power_req.new_level; 2041 cmpt = reqp->req.ppm_set_power_req.cmpt; 2042 break; 2043 2044 case PMR_PPM_POWER_CHANGE_NOTIFY: 2045 pwr_func = ppm_record_level_change; 2046 old = reqp->req.ppm_notify_level_req.old_level; 2047 new = reqp->req.ppm_notify_level_req.new_level; 2048 cmpt = reqp->req.ppm_notify_level_req.cmpt; 2049 break; 2050 2051 default: 2052 *result = DDI_FAILURE; 2053 return (DDI_FAILURE); 2054 } 2055 2056 for (ppmd = PPM_GET_PRIVATE(dip); ppmd; ppmd = ppmd->next) 2057 if (cmpt == ppmd->cmpt) 2058 break; 2059 if (!ppmd) { 2060 PPMD(D_PCI, ("%s: dip(%p): old(%d), new(%d): no ppm_dev" 2061 " found for cmpt(%d)", str, (void *)dip, old, new, cmpt)) 2062 *result = DDI_FAILURE; 2063 return (DDI_FAILURE); 2064 } 2065 domp = ppmd->domp; 2066 PPMD(D_PCI, ("%s: %s, dev(%s), c%d, old %d, new %d\n", str, 2067 ppm_get_ctlstr(reqp->request_type, ~0), 2068 ppmd->path, cmpt, old, new)) 2069 2070 ASSERT(old == ppmd->level); 2071 if (new == ppmd->level) 2072 return (DDI_SUCCESS); 2073 2074 PPM_LOCK_DOMAIN(domp); 2075 2076 if (new > 0) { /* device powering up */ 2077 if (domp->status == PPMD_OFF) { 2078 2079 /* cannot be off during (chpt, resume) window */ 2080 ASSERT(ppm_cpr_window_flag == B_FALSE); 2081 2082 /* either both OFF or both ON */ 2083 ASSERT(!((old == 0) ^ (domp->pwr_cnt == 0))); 2084 2085 PPMD(D_PCI, ("About to turn on pcie slot for " 2086 "%s@%s c%d\n", PM_NAME(dip), PM_ADDR(dip), cmpt)) 2087 2088 *result = ppm_pcie_pwr(domp, PPMD_ON); 2089 if (*result != DDI_SUCCESS) { 2090 PPMD(D_PCI, ("\tcan't switch on pcie slot: " 2091 "ret(%d)\n", *result)) 2092 PPM_UNLOCK_DOMAIN(domp); 2093 return (DDI_FAILURE); 2094 } 2095 } 2096 2097 if (old == 0) { 2098 domp->pwr_cnt++; 2099 incr = 1; 2100 } 2101 2102 PPMD(D_PCI, ("\t%s domain power count: %d\n", 2103 domp->name, domp->pwr_cnt)) 2104 } 2105 2106 PPM_UNLOCK_DOMAIN(domp); 2107 2108 ASSERT(domp->pwr_cnt > 0); 2109 2110 if ((*result = (*pwr_func)(ppmd, cmpt, new)) != DDI_SUCCESS) { 2111 PPMD(D_PCI, ("\t%s power change failed: ret(%d)\n", 2112 ppmd->path, *result)) 2113 } 2114 2115 PPM_LOCK_DOMAIN(domp); 2116 2117 /* 2118 * Decr the power count in two cases: 2119 * 2120 * 1) request was to power device down and was successful 2121 * 2) request was to power up (we pre-incremented count), but failed. 2122 */ 2123 if ((*result == DDI_SUCCESS && ppmd->level == 0) || 2124 (*result != DDI_SUCCESS && incr)) { 2125 ASSERT(domp->pwr_cnt > 0); 2126 domp->pwr_cnt--; 2127 } 2128 2129 PPMD(D_PCI, ("\t%s domain power count: %d\n", 2130 domp->name, domp->pwr_cnt)) 2131 2132 /* 2133 * call to pwr_func will update ppm data structures, if it 2134 * succeeds. ppm should return whatever is the return value 2135 * from call to pwr_func. This way pm and ppm data structures 2136 * always in sync. Use dummy_ret from here for any further 2137 * return values. 2138 */ 2139 if ((domp->pwr_cnt == 0) && 2140 (ppm_cpr_window_flag == B_FALSE) && 2141 ppm_none_else_holds_power(domp)) { 2142 2143 PPMD(D_PCI, ("About to turn off pcie slot for %s@%s c%d\n", 2144 PM_NAME(dip), PM_ADDR(dip), cmpt)) 2145 2146 dummy_ret = ppm_pcie_pwr(domp, PPMD_OFF); 2147 if (dummy_ret != DDI_SUCCESS) { 2148 PPMD(D_PCI, ("\tCan't switch pcie slot off: " 2149 "ret(%d)\n", dummy_ret)) 2150 } 2151 } 2152 2153 PPM_UNLOCK_DOMAIN(domp); 2154 ASSERT(domp->pwr_cnt >= 0); 2155 return (*result); 2156 2157 } 2158 2159 /* 2160 * Set or clear a bit on a GPIO device. These bits are used for various device- 2161 * specific purposes. 2162 */ 2163 static int 2164 ppm_gpioset(ppm_domain_t *domp, int key) 2165 { 2166 #ifdef DEBUG 2167 char *str = "ppm_gpioset"; 2168 #endif 2169 ppm_dc_t *dc; 2170 int ret; 2171 clock_t delay = 0; 2172 2173 for (dc = domp->dc; dc; dc = dc->next) 2174 if (dc->cmd == key) 2175 break; 2176 if (!dc || !dc->lh) { 2177 PPMD(D_GPIO, ("%s: %s domain: NULL ppm_dc handle\n", 2178 str, domp->name)) 2179 return (DDI_FAILURE); 2180 } 2181 2182 PPM_GET_IO_DELAY(dc, delay); 2183 if (delay > 0) { 2184 PPMD(D_GPIO, ("%s : waiting %lu micro seconds " 2185 "before change\n", domp->name, delay)) 2186 drv_usecwait(delay); 2187 } 2188 2189 switch (dc->method) { 2190 #if !defined(__x86) 2191 case PPMDC_I2CKIO: { 2192 i2c_gpio_t i2c_req; 2193 ppm_dev_t *pdev; 2194 int pio_save; 2195 extern int do_polled_io; 2196 extern uint_t cfb_inuse; 2197 i2c_req.reg_mask = dc->m_un.i2c.mask; 2198 i2c_req.reg_val = dc->m_un.i2c.val; 2199 2200 pio_save = do_polled_io; 2201 if (cfb_inuse) { 2202 for (pdev = domp->devlist; pdev; pdev = pdev->next) { 2203 if (pm_is_cfb(pdev->dip)) { 2204 do_polled_io = 1; 2205 PPMD(D_GPIO, ("%s: cfb is in use, " 2206 "i2c transaction is done in " 2207 "poll-mode.\n", str)) 2208 break; 2209 } 2210 } 2211 } 2212 ret = ldi_ioctl(dc->lh, dc->m_un.i2c.iowr, 2213 (intptr_t)&i2c_req, FWRITE | FKIOCTL, kcred, NULL); 2214 do_polled_io = pio_save; 2215 2216 PPMD(D_GPIO, ("%s: %s domain(%s) from %s by writing %x " 2217 "to gpio\n", 2218 str, (ret == 0) ? "turned" : "FAILed to turn", 2219 domp->name, 2220 (domp->status == PPMD_ON) ? "ON" : "OFF", 2221 dc->m_un.i2c.val)) 2222 2223 break; 2224 } 2225 #endif 2226 case PPMDC_KIO: 2227 ret = ldi_ioctl(dc->lh, dc->m_un.kio.iowr, 2228 (intptr_t)&(dc->m_un.kio.val), FWRITE | FKIOCTL, kcred, 2229 NULL); 2230 2231 PPMD(D_GPIO, ("%s: %s domain(%s) from %s by writing %x " 2232 "to gpio\n", 2233 str, (ret == 0) ? "turned" : "FAILed to turn", 2234 domp->name, 2235 (domp->status == PPMD_ON) ? "ON" : "OFF", 2236 dc->m_un.kio.val)) 2237 2238 break; 2239 2240 default: 2241 PPMD(D_GPIO, ("\t%s: unsupported domain control method %d\n", 2242 str, domp->dc->method)) 2243 return (DDI_FAILURE); 2244 } 2245 2246 /* implement any post op delay. */ 2247 PPM_GET_IO_DELAY(dc, delay); 2248 if (delay > 0) { 2249 PPMD(D_GPIO, ("%s : waiting %lu micro seconds " 2250 "after change\n", domp->name, delay)) 2251 drv_usecwait(delay); 2252 } 2253 2254 return (ret); 2255 } 2256 2257 static int 2258 ppm_pcie_pwr(ppm_domain_t *domp, int onoff) 2259 { 2260 #ifdef DEBUG 2261 char *str = "ppm_pcie_pwr"; 2262 #endif 2263 int ret = DDI_FAILURE; 2264 ppm_dc_t *dc; 2265 clock_t delay; 2266 2267 ASSERT(onoff == PPMD_OFF || onoff == PPMD_ON); 2268 2269 dc = ppm_lookup_dc(domp, 2270 onoff == PPMD_ON ? PPMDC_PRE_PWR_ON : PPMDC_PRE_PWR_OFF); 2271 if (dc) { 2272 2273 /* 2274 * Invoke layered ioctl for pcie root complex nexus to 2275 * transition the link 2276 */ 2277 ASSERT(dc->method == PPMDC_KIO); 2278 delay = dc->m_un.kio.delay; 2279 if (delay > 0) { 2280 PPMD(D_GPIO, ("%s : waiting %lu micro seconds " 2281 "before change\n", domp->name, delay)) 2282 drv_usecwait(delay); 2283 } 2284 ret = ldi_ioctl(dc->lh, dc->m_un.kio.iowr, 2285 (intptr_t)&(dc->m_un.kio.val), 2286 FWRITE | FKIOCTL, kcred, NULL); 2287 if (ret == DDI_SUCCESS) { 2288 delay = dc->m_un.kio.post_delay; 2289 if (delay > 0) { 2290 PPMD(D_GPIO, ("%s : waiting %lu micro seconds " 2291 "after change\n", domp->name, delay)) 2292 drv_usecwait(delay); 2293 } 2294 } else { 2295 PPMD(D_PCI, ("%s: ldi_ioctl FAILED for domain(%s)\n", 2296 str, domp->name)) 2297 return (ret); 2298 } 2299 } 2300 2301 switch (onoff) { 2302 case PPMD_OFF: 2303 /* Turn off the clock for this slot. */ 2304 if ((ret = ppm_gpioset(domp, PPMDC_CLK_OFF)) != DDI_SUCCESS) { 2305 PPMD(D_GPIO, 2306 ("%s: failed to turn off domain(%s) clock\n", 2307 str, domp->name)) 2308 return (ret); 2309 } 2310 2311 /* Turn off the power to this slot */ 2312 if ((ret = ppm_gpioset(domp, PPMDC_PWR_OFF)) != DDI_SUCCESS) { 2313 PPMD(D_GPIO, 2314 ("%s: failed to turn off domain(%s) power\n", 2315 str, domp->name)) 2316 return (ret); 2317 } 2318 break; 2319 case PPMD_ON: 2320 /* Assert RESET for this slot. */ 2321 if ((ret = ppm_gpioset(domp, PPMDC_RESET_ON)) != DDI_SUCCESS) { 2322 PPMD(D_GPIO, 2323 ("%s: failed to assert reset for domain(%s)\n", 2324 str, domp->name)) 2325 return (ret); 2326 } 2327 2328 /* Turn on the power to this slot */ 2329 if ((ret = ppm_gpioset(domp, PPMDC_PWR_ON)) != DDI_SUCCESS) { 2330 PPMD(D_GPIO, 2331 ("%s: failed to turn on domain(%s) power\n", 2332 str, domp->name)) 2333 return (ret); 2334 } 2335 2336 /* Turn on the clock for this slot */ 2337 if ((ret = ppm_gpioset(domp, PPMDC_CLK_ON)) != DDI_SUCCESS) { 2338 PPMD(D_GPIO, 2339 ("%s: failed to turn on domain(%s) clock\n", 2340 str, domp->name)) 2341 return (ret); 2342 } 2343 2344 /* De-assert RESET for this slot. */ 2345 if ((ret = ppm_gpioset(domp, PPMDC_RESET_OFF)) != DDI_SUCCESS) { 2346 PPMD(D_GPIO, 2347 ("%s: failed to de-assert reset for domain(%s)\n", 2348 str, domp->name)) 2349 return (ret); 2350 } 2351 2352 dc = ppm_lookup_dc(domp, PPMDC_POST_PWR_ON); 2353 if (dc) { 2354 /* 2355 * Invoke layered ioctl to PCIe root complex nexus 2356 * to transition the link. 2357 */ 2358 ASSERT(dc->method == PPMDC_KIO); 2359 delay = dc->m_un.kio.delay; 2360 if (delay > 0) { 2361 PPMD(D_GPIO, ("%s: waiting %lu micro seconds " 2362 "before change\n", domp->name, delay)) 2363 drv_usecwait(delay); 2364 } 2365 ret = ldi_ioctl(dc->lh, dc->m_un.kio.iowr, 2366 (intptr_t)&(dc->m_un.kio.val), 2367 FWRITE | FKIOCTL, kcred, NULL); 2368 2369 if (ret != DDI_SUCCESS) { 2370 PPMD(D_PCI, ("%s: layered ioctl to PCIe" 2371 "root complex nexus FAILed\n", str)) 2372 return (ret); 2373 } 2374 2375 delay = dc->m_un.kio.post_delay; 2376 if (delay > 0) { 2377 PPMD(D_GPIO, ("%s: waiting %lu micro " 2378 "seconds after change\n", 2379 domp->name, delay)) 2380 drv_usecwait(delay); 2381 } 2382 } 2383 break; 2384 default: 2385 ASSERT(0); 2386 } 2387 2388 PPMD(D_PCI, ("%s: turned domain(%s) PCIe slot power from %s to %s\n", 2389 str, domp->name, (domp->status == PPMD_ON) ? "ON" : "OFF", 2390 onoff == PPMD_ON ? "ON" : "OFF")) 2391 2392 domp->status = onoff; 2393 return (ret); 2394 } 2395 2396 2397 /* 2398 * Change the power level for a component of a device. If the change 2399 * arg is true, we call the framework to actually change the device's 2400 * power; otherwise, we just update our own copy of the power level. 2401 */ 2402 static int 2403 ppm_set_level(ppm_dev_t *ppmd, int cmpt, int level, boolean_t change) 2404 { 2405 #ifdef DEBUG 2406 char *str = "ppm_set_level"; 2407 #endif 2408 int ret; 2409 2410 ret = DDI_SUCCESS; 2411 if (change) 2412 ret = pm_power(ppmd->dip, cmpt, level); 2413 2414 PPMD(D_SETLVL, ("%s: %s change=%d, old %d, new %d, ret %d\n", 2415 str, ppmd->path, change, ppmd->level, level, ret)) 2416 2417 if (ret == DDI_SUCCESS) { 2418 ppmd->level = level; 2419 ppmd->rplvl = PM_LEVEL_UNKNOWN; 2420 } 2421 2422 return (ret); 2423 } 2424 2425 2426 static int 2427 ppm_change_power_level(ppm_dev_t *ppmd, int cmpt, int level) 2428 { 2429 return (ppm_set_level(ppmd, cmpt, level, B_TRUE)); 2430 } 2431 2432 2433 static int 2434 ppm_record_level_change(ppm_dev_t *ppmd, int cmpt, int level) 2435 { 2436 return (ppm_set_level(ppmd, cmpt, level, B_FALSE)); 2437 } 2438 2439 2440 static void 2441 ppm_manage_led(int action) 2442 { 2443 ppm_domain_t *domp; 2444 ppm_unit_t *unitp; 2445 timeout_id_t tid; 2446 2447 2448 PPMD(D_LED, ("ppm_manage_led: action: %s\n", 2449 (action == PPM_LED_BLINKING) ? "PPM_LED_BLINKING" : 2450 "PPM_LED_SOLIDON")) 2451 2452 /* 2453 * test whether led operation is practically supported, 2454 * if not, we waive without pressing for reasons 2455 */ 2456 if (!ppm_lookup_dc(NULL, PPMDC_LED_ON)) 2457 return; 2458 2459 unitp = ddi_get_soft_state(ppm_statep, ppm_inst); 2460 for (domp = ppm_domain_p; (domp && (domp->model != PPMD_LED)); ) 2461 domp = domp->next; 2462 2463 mutex_enter(&unitp->lock); 2464 if (action == PPM_LED_BLINKING) { 2465 ppm_set_led(domp, PPMD_OFF); 2466 unitp->led_tid = timeout( 2467 ppm_blink_led, domp, PPM_LEDOFF_INTERVAL); 2468 2469 } else { /* PPM_LED_SOLIDON */ 2470 ASSERT(action == PPM_LED_SOLIDON); 2471 tid = unitp->led_tid; 2472 unitp->led_tid = 0; 2473 2474 mutex_exit(&unitp->lock); 2475 (void) untimeout(tid); 2476 2477 mutex_enter(&unitp->lock); 2478 ppm_set_led(domp, PPMD_ON); 2479 } 2480 mutex_exit(&unitp->lock); 2481 } 2482 2483 2484 static void 2485 ppm_set_led(ppm_domain_t *domp, int val) 2486 { 2487 int ret; 2488 2489 ret = ppm_gpioset(domp, 2490 (val == PPMD_ON) ? PPMDC_LED_ON : PPMDC_LED_OFF); 2491 2492 PPMD(D_LED, ("ppm_set_led: %s LED from %s\n", 2493 (ret == 0) ? "turned" : "FAILed to turn", 2494 (domp->status == PPMD_ON) ? "ON to OFF" : "OFF to ON")) 2495 2496 if (ret == DDI_SUCCESS) 2497 domp->status = val; 2498 } 2499 2500 2501 static void 2502 ppm_blink_led(void *arg) 2503 { 2504 ppm_unit_t *unitp; 2505 clock_t intvl; 2506 ppm_domain_t *domp = arg; 2507 2508 unitp = ddi_get_soft_state(ppm_statep, ppm_inst); 2509 2510 mutex_enter(&unitp->lock); 2511 if (unitp->led_tid == 0) { 2512 mutex_exit(&unitp->lock); 2513 return; 2514 } 2515 2516 if (domp->status == PPMD_ON) { 2517 ppm_set_led(domp, PPMD_OFF); 2518 intvl = PPM_LEDOFF_INTERVAL; 2519 } else { 2520 ppm_set_led(domp, PPMD_ON); 2521 intvl = PPM_LEDON_INTERVAL; 2522 } 2523 2524 unitp->led_tid = timeout(ppm_blink_led, domp, intvl); 2525 mutex_exit(&unitp->lock); 2526 } 2527 2528 /* 2529 * Function to power up a domain, if required. It also increments the 2530 * domain pwr_cnt to prevent it from going down. 2531 */ 2532 static int 2533 ppm_power_up_domain(dev_info_t *dip) 2534 { 2535 int ret = DDI_SUCCESS; 2536 ppm_domain_t *domp; 2537 char *str = "ppm_power_up_domain"; 2538 2539 domp = ppm_lookup_dev(dip); 2540 ASSERT(domp); 2541 mutex_enter(&domp->lock); 2542 switch (domp->model) { 2543 case PPMD_FET: 2544 if (domp->status == PPMD_OFF) { 2545 if ((ret = ppm_fetset(domp, PPMD_ON)) == 2546 DDI_SUCCESS) { 2547 PPMD(D_FET, ("%s: turned on fet for %s@%s\n", 2548 str, PM_NAME(dip), PM_ADDR(dip))) 2549 } else { 2550 PPMD(D_FET, ("%s: couldn't turn on fet " 2551 "for %s@%s\n", str, PM_NAME(dip), 2552 PM_ADDR(dip))) 2553 } 2554 } 2555 break; 2556 2557 case PPMD_PCI: 2558 case PPMD_PCI_PROP: 2559 if (domp->status == PPMD_OFF) { 2560 if ((ret = ppm_switch_clock(domp, PPMD_ON)) == 2561 DDI_SUCCESS) { 2562 PPMD(D_PCI, ("%s: turned on clock for " 2563 "%s@%s\n", str, PM_NAME(dip), 2564 PM_ADDR(dip))) 2565 } else { 2566 PPMD(D_PCI, ("%s: couldn't turn on clock " 2567 "for %s@%s\n", str, PM_NAME(dip), 2568 PM_ADDR(dip))) 2569 } 2570 } 2571 break; 2572 2573 case PPMD_PCIE: 2574 if (domp->status == PPMD_OFF) { 2575 if ((ret = ppm_pcie_pwr(domp, PPMD_ON)) == 2576 DDI_SUCCESS) { 2577 PPMD(D_PCI, ("%s: turned on link for " 2578 "%s@%s\n", str, PM_NAME(dip), 2579 PM_ADDR(dip))) 2580 } else { 2581 PPMD(D_PCI, ("%s: couldn't turn on link " 2582 "for %s@%s\n", str, PM_NAME(dip), 2583 PM_ADDR(dip))) 2584 } 2585 } 2586 break; 2587 2588 default: 2589 break; 2590 } 2591 if (ret == DDI_SUCCESS) 2592 domp->pwr_cnt++; 2593 mutex_exit(&domp->lock); 2594 return (ret); 2595 } 2596 2597 /* 2598 * Decrements the domain pwr_cnt. if conditions to power down the domain 2599 * are met, powers down the domain,. 2600 */ 2601 static int 2602 ppm_power_down_domain(dev_info_t *dip) 2603 { 2604 int ret = DDI_SUCCESS; 2605 char *str = "ppm_power_down_domain"; 2606 ppm_domain_t *domp; 2607 2608 domp = ppm_lookup_dev(dip); 2609 ASSERT(domp); 2610 mutex_enter(&domp->lock); 2611 ASSERT(domp->pwr_cnt > 0); 2612 domp->pwr_cnt--; 2613 switch (domp->model) { 2614 case PPMD_FET: 2615 if ((domp->pwr_cnt == 0) && 2616 (ppm_cpr_window_flag == B_FALSE) && 2617 ppm_none_else_holds_power(domp)) { 2618 if ((ret = ppm_fetset(domp, PPMD_OFF)) == 2619 DDI_SUCCESS) { 2620 PPMD(D_FET, ("%s: turned off FET for %s@%s \n", 2621 str, PM_NAME(dip), PM_ADDR(dip))) 2622 } else { 2623 PPMD(D_FET, ("%s: couldn't turn off FET for " 2624 " %s@%s\n", str, PM_NAME(dip), 2625 PM_ADDR(dip))) 2626 } 2627 } 2628 break; 2629 2630 case PPMD_PCI: 2631 case PPMD_PCI_PROP: 2632 if ((domp->pwr_cnt == 0) && 2633 (ppm_cpr_window_flag == B_FALSE) && 2634 ppm_none_else_holds_power(domp)) { 2635 if ((ret = ppm_switch_clock(domp, PPMD_OFF)) == 2636 DDI_SUCCESS) { 2637 PPMD(D_PCI, ("%s: turned off clock for %s@%s\n", 2638 str, PM_NAME(dip), PM_ADDR(dip))) 2639 } else { 2640 PPMD(D_PCI, ("%s: couldn't turn off clock " 2641 "for %s@%s\n", str, PM_NAME(dip), 2642 PM_ADDR(dip))) 2643 } 2644 } 2645 break; 2646 2647 case PPMD_PCIE: 2648 if ((domp->pwr_cnt == 0) && 2649 (ppm_cpr_window_flag == B_FALSE) && 2650 ppm_none_else_holds_power(domp)) { 2651 if ((ret = ppm_pcie_pwr(domp, PPMD_OFF)) == 2652 DDI_SUCCESS) { 2653 PPMD(D_PCI, ("%s: turned off link for %s@%s\n", 2654 str, PM_NAME(dip), PM_ADDR(dip))) 2655 } else { 2656 PPMD(D_PCI, ("%s: couldn't turn off link " 2657 "for %s@%s\n", str, PM_NAME(dip), 2658 PM_ADDR(dip))) 2659 } 2660 } 2661 break; 2662 2663 default: 2664 break; 2665 } 2666 mutex_exit(&domp->lock); 2667 return (ret); 2668 } 2669