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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Copyright 2023 Oxide Computer Company 28 */ 29 30 /* 31 * Platform Power Management driver for SUNW,Sun-Blade-1000 32 */ 33 #include <sys/modctl.h> 34 #include <sys/conf.h> 35 #include <sys/ddi.h> 36 #include <sys/sunddi.h> 37 #include <sys/ddi_impldefs.h> 38 #include <sys/ppmvar.h> 39 #include <sys/ppmio.h> 40 #include <sys/xcalppm_reg.h> 41 #include <sys/xcalppm_var.h> 42 #include <sys/stat.h> 43 #include <sys/epm.h> 44 #include <sys/archsystm.h> 45 #include <sys/cpuvar.h> 46 #include <sys/cheetahregs.h> 47 #include <sys/us3_module.h> 48 49 /* 50 * Locking Considerations 51 * 52 * To look at and/or modify xcppm_domain fields or elements of its list of 53 * xcppm_dev structures the domain_lock for the affected domain must be held. 54 * 55 * When the autopm framework needs to change the power of a component of a 56 * device, it needs to hold the associated power lock (see discussion at 57 * top of uts/common/os/sunpm.c). 58 * 59 * If the framework needs to lock a dev/cmpt for a device which this ppm 60 * has claimed, xcppm_ctlops will be called with PMR_PPM_LOCK_POWER. Ppm 61 * needs to be involved because, due to platform constraints, changing the 62 * power of one device may require that other devices be changed in the same 63 * operation. 64 * 65 * In some domains (e.g., cpus) the power lock must be acquired for all the 66 * affected devices to avoid possible corruption of the power states. The 67 * joint change must be an atomic operation. Ppm handles this by acquiring 68 * the domain lock, then walking the list of affected devices and acquiring 69 * the power lock for each of them. To unlock, the list is traversed and 70 * each of the power locks is freed, followed by freeing the domain lock. 71 * 72 * For other domains ppm will only be changing the power of a single device 73 * that is known to the framework. In these cases, the locking is done by 74 * acquiring the domain lock and directly calling the framework routine for 75 * getting a single power lock. 76 */ 77 78 static int xcppm_attach(dev_info_t *, ddi_attach_cmd_t); 79 static int xcppm_detach(dev_info_t *, ddi_detach_cmd_t); 80 static int xcppm_ctlops(dev_info_t *, dev_info_t *, 81 ddi_ctl_enum_t, void *, void *); 82 static void xcppm_dev_init(ppm_dev_t *); 83 static void xcppm_dev_fini(ppm_dev_t *); 84 static void xcppm_iocset(uint8_t); 85 static uint8_t xcppm_iocget(void); 86 87 /* 88 * Note: 1394 and pciupa were originally required to be LOCK_ALL domains. 89 * However, the underlying nexus drivers aren't able to do power mgmt 90 * (because of hw implementation issues). The locking protocol for these 91 * domains is changed to LOCK_ONE to simplify other code. The domain 92 * code itself will be removed in the future. 93 */ 94 static ppm_domain_t xcppm_1394 = { "domain_1394", PPMD_LOCK_ONE }; 95 static ppm_domain_t xcppm_cpu = { "domain_cpu", PPMD_LOCK_ALL }; 96 static ppm_domain_t xcppm_fet = { "domain_powerfet", PPMD_LOCK_ONE }; 97 static ppm_domain_t xcppm_upa = { "domain_pciupa", PPMD_LOCK_ONE }; 98 99 ppm_domain_t *ppm_domains[] = { 100 &xcppm_1394, 101 &xcppm_cpu, 102 &xcppm_fet, 103 &xcppm_upa, 104 NULL 105 }; 106 107 108 struct ppm_funcs ppmf = { 109 xcppm_dev_init, /* dev_init */ 110 xcppm_dev_fini, /* dev_fini */ 111 xcppm_iocset, /* iocset */ 112 xcppm_iocget, /* iocget */ 113 }; 114 115 116 /* 117 * The order of entries must be from slowest to fastest and in 118 * one-to-one correspondence with the cpu_level array. 119 */ 120 static const uint16_t bbc_estar_control_masks[] = { 121 BBC_ESTAR_SLOW, BBC_ESTAR_MEDIUM, BBC_ESTAR_FAST 122 }; 123 124 int bbc_delay = 10; /* microsec */ 125 126 127 /* 128 * Configuration data structures 129 */ 130 static struct cb_ops xcppm_cb_ops = { 131 ppm_open, /* open */ 132 ppm_close, /* close */ 133 nodev, /* strategy */ 134 nodev, /* print */ 135 nodev, /* dump */ 136 nodev, /* read */ 137 nodev, /* write */ 138 ppm_ioctl, /* ioctl */ 139 nodev, /* devmap */ 140 nodev, /* mmap */ 141 nodev, /* segmap */ 142 nochpoll, /* poll */ 143 ddi_prop_op, /* prop_op */ 144 NULL, /* streamtab */ 145 D_MP | D_NEW, /* driver compatibility flag */ 146 CB_REV, /* cb_ops revision */ 147 nodev, /* async read */ 148 nodev /* async write */ 149 }; 150 151 static struct bus_ops xcppm_bus_ops = { 152 BUSO_REV, 153 0, 154 0, 155 0, 156 0, 157 0, 158 ddi_no_dma_map, 159 ddi_no_dma_allochdl, 160 ddi_no_dma_freehdl, 161 ddi_no_dma_bindhdl, 162 ddi_no_dma_unbindhdl, 163 ddi_no_dma_flush, 164 ddi_no_dma_win, 165 ddi_no_dma_mctl, 166 xcppm_ctlops, 167 0, 168 0, /* (*bus_get_eventcookie)(); */ 169 0, /* (*bus_add_eventcall)(); */ 170 0, /* (*bus_remove_eventcall)(); */ 171 0 /* (*bus_post_event)(); */ 172 }; 173 174 static struct dev_ops xcppm_ops = { 175 DEVO_REV, /* devo_rev */ 176 0, /* refcnt */ 177 ppm_getinfo, /* info */ 178 nulldev, /* identify */ 179 nulldev, /* probe */ 180 xcppm_attach, /* attach */ 181 xcppm_detach, /* detach */ 182 nodev, /* reset */ 183 &xcppm_cb_ops, /* driver operations */ 184 &xcppm_bus_ops, /* bus operations */ 185 NULL, /* power */ 186 ddi_quiesce_not_supported, /* devo_quiesce */ 187 }; 188 189 extern struct mod_ops mod_driverops; 190 191 static struct modldrv modldrv = { 192 &mod_driverops, /* type of module - pseudo */ 193 "platform pm driver", 194 &xcppm_ops 195 }; 196 197 static struct modlinkage modlinkage = { 198 MODREV_1, 199 &modldrv, 200 NULL 201 }; 202 203 204 int 205 _init(void) 206 { 207 return (ppm_init(&modlinkage, sizeof (xcppm_unit_t), "xc")); 208 } 209 210 211 int 212 _fini(void) 213 { 214 return (EBUSY); 215 } 216 217 218 int 219 _info(struct modinfo *modinfop) 220 { 221 return (mod_info(&modlinkage, modinfop)); 222 } 223 224 225 static int 226 xcppm_map_all_regs(dev_info_t *dip) 227 { 228 ddi_device_acc_attr_t attr_be, attr_le; 229 int rv0, rv1, rv2, rv3; 230 xcppm_unit_t *unitp; 231 caddr_t base_addr; 232 uint8_t data8; 233 234 unitp = ddi_get_soft_state(ppm_statep, ppm_inst); 235 attr_be.devacc_attr_version = DDI_DEVICE_ATTR_V0; 236 attr_be.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC; 237 attr_be.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 238 239 attr_le.devacc_attr_version = DDI_DEVICE_ATTR_V0; 240 attr_le.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 241 attr_le.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 242 243 rv0 = ddi_regs_map_setup(dip, 0, &base_addr, 0, 0, &attr_be, 244 &unitp->hndls.bbc_estar_ctrl); 245 246 unitp->regs.bbc_estar_ctrl = (uint16_t *)(base_addr + 247 BBC_ESTAR_CTRL_OFFSET); 248 unitp->regs.bbc_assert_change = (uint32_t *)(base_addr + 249 BBC_ASSERT_CHANGE_OFFSET); 250 unitp->regs.bbc_pll_settle = (uint32_t *)(base_addr + 251 BBC_PLL_SETTLE_OFFSET); 252 253 rv1 = ddi_regs_map_setup(dip, 1, 254 (caddr_t *)&unitp->regs.rio_mode_auxio, 255 0, 0, &attr_le, &unitp->hndls.rio_mode_auxio); 256 257 rv2 = ddi_regs_map_setup(dip, 2, &base_addr, 258 0, 0, &attr_le, &unitp->hndls.gpio_bank_select); 259 260 unitp->regs.gpio_bank_sel_index = (uint8_t *)(base_addr + 261 GPIO_BANK_SEL_INDEX_OFFSET); 262 unitp->regs.gpio_bank_sel_data = (uint8_t *)(base_addr + 263 GPIO_BANK_SEL_DATA_OFFSET); 264 265 rv3 = ddi_regs_map_setup(dip, 3, &base_addr, 0, 0, &attr_le, 266 &unitp->hndls.gpio_data_ports); 267 268 unitp->regs.gpio_port1_data = (uint8_t *)(base_addr + 269 GPIO_PORT1_DATA_OFFSET); 270 unitp->regs.gpio_port2_data = (uint8_t *)(base_addr + 271 GPIO_PORT2_DATA_OFFSET); 272 273 if (rv0 != DDI_SUCCESS || rv1 != DDI_SUCCESS || 274 rv2 != DDI_SUCCESS || rv3 != DDI_SUCCESS) { 275 if (rv0 == DDI_SUCCESS) 276 ddi_regs_map_free(&unitp->hndls.bbc_estar_ctrl); 277 if (rv1 == DDI_SUCCESS) 278 ddi_regs_map_free(&unitp->hndls.rio_mode_auxio); 279 if (rv2 == DDI_SUCCESS) 280 ddi_regs_map_free(&unitp->hndls.gpio_bank_select); 281 if (rv3 == DDI_SUCCESS) 282 ddi_regs_map_free(&unitp->hndls.gpio_data_ports); 283 return (DDI_FAILURE); 284 } 285 286 /* 287 * Ppm uses GPIO bits in Bank 0. Make sure Bank 0 is selected. 288 */ 289 data8 = SIO_CONFIG2_INDEX; 290 XCPPM_SETGET8(unitp->hndls.gpio_bank_select, 291 unitp->regs.gpio_bank_sel_index, data8); 292 data8 = XCPPM_GET8(unitp->hndls.gpio_bank_select, 293 unitp->regs.gpio_bank_sel_data); 294 295 data8 &= 0x7f; /* Set Bit7 to zero */ 296 XCPPM_SETGET8(unitp->hndls.gpio_bank_select, 297 unitp->regs.gpio_bank_sel_data, data8); 298 299 return (DDI_SUCCESS); 300 } 301 302 303 static int 304 xcppm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 305 { 306 #ifdef DEBUG 307 char *str = "xcppm_attach"; 308 #endif 309 xcppm_unit_t *unitp; 310 ppm_domain_t **dompp; 311 int retval; 312 313 DPRINTF(D_ATTACH, ("%s: attach cmd %d\n", str, cmd)); 314 retval = DDI_SUCCESS; 315 316 switch (cmd) { 317 case DDI_ATTACH: 318 if (ppm_inst != -1) { 319 DPRINTF(D_ERROR, 320 ("%s: instance already attached\n", str)); 321 return (DDI_FAILURE); 322 } 323 ppm_inst = ddi_get_instance(dip); 324 325 /* 326 * Allocate and initialize soft state structure 327 */ 328 if (ddi_soft_state_zalloc(ppm_statep, ppm_inst) != 0) 329 return (DDI_FAILURE); 330 unitp = ddi_get_soft_state(ppm_statep, ppm_inst); 331 mutex_init(&unitp->unit_lock, NULL, MUTEX_DRIVER, NULL); 332 mutex_init(&unitp->creator_lock, NULL, MUTEX_DRIVER, NULL); 333 334 if (ddi_create_minor_node(dip, "ppm", S_IFCHR, 335 ppm_inst, "ddi_ppm", 0) == DDI_FAILURE) { 336 ddi_soft_state_free(ppm_statep, ppm_inst); 337 DPRINTF(D_ERROR, 338 ("%s: Can't create minor for 0x%p\n", str, 339 (void *)dip)); 340 return (DDI_FAILURE); 341 } 342 ddi_report_dev(dip); 343 unitp->dip = dip; 344 345 if (retval = ppm_create_db(dip)) 346 return (retval); 347 348 /* 349 * Map all of the registers under the ppm node. 350 */ 351 if (xcppm_map_all_regs(dip) != DDI_SUCCESS) 352 return (DDI_FAILURE); 353 354 if ((retval = 355 pm_register_ppm(ppm_claim_dev, dip)) != DDI_SUCCESS) { 356 DPRINTF(D_ERROR, 357 ("%s: can't register ppm handler\n", str)); 358 return (retval); 359 } 360 361 for (dompp = ppm_domains; *dompp; dompp++) 362 mutex_init(&(*dompp)->lock, NULL, MUTEX_DRIVER, NULL); 363 364 break; 365 366 case DDI_RESUME: 367 unitp = ddi_get_soft_state(ppm_statep, ppm_inst); 368 mutex_enter(&unitp->unit_lock); 369 unitp->state &= ~XCPPM_ST_SUSPENDED; 370 mutex_exit(&unitp->unit_lock); 371 break; 372 373 default: 374 cmn_err(CE_CONT, "xcppm_attach: unknown " 375 "attach command %d, dip 0x%p\n", cmd, (void *)dip); 376 retval = DDI_FAILURE; 377 } 378 379 return (retval); 380 } 381 382 383 /* 384 * set the front panel LED: 385 * PPM_LEDON turns it on, PPM_LEDOFF turns it off. 386 * for GPIO register: 0x0 means led-on, 0x2 means led-off. 387 */ 388 static void 389 xcppm_set_led(int action) 390 { 391 xcppm_unit_t *unitp; 392 uint8_t reg; 393 394 ASSERT(action == PPM_LEDON || action == PPM_LEDOFF); 395 DPRINTF(D_LED, ("xcppm_set_led: Turn LED %s\n", 396 (action == PPM_LEDON) ? "on" : "off")); 397 398 unitp = ddi_get_soft_state(ppm_statep, ppm_inst); 399 reg = XCPPM_GET8(unitp->hndls.gpio_data_ports, 400 unitp->regs.gpio_port1_data); 401 if (action == PPM_LEDON) 402 reg &= ~LED; 403 else 404 reg |= LED; 405 XCPPM_SETGET8(unitp->hndls.gpio_data_ports, 406 unitp->regs.gpio_port1_data, reg); 407 } 408 409 410 static void 411 xcppm_blink_led(void *action) 412 { 413 xcppm_unit_t *unitp; 414 int new_action; 415 clock_t intvl; 416 417 unitp = ddi_get_soft_state(ppm_statep, ppm_inst); 418 mutex_enter(&unitp->unit_lock); 419 if (unitp->led_tid == 0) { 420 mutex_exit(&unitp->unit_lock); 421 return; 422 } 423 424 if ((int)(uintptr_t)action == PPM_LEDON) { 425 new_action = PPM_LEDOFF; 426 intvl = PPM_LEDOFF_INTERVAL; 427 } else { 428 ASSERT((int)(uintptr_t)action == PPM_LEDOFF); 429 new_action = PPM_LEDON; 430 intvl = PPM_LEDON_INTERVAL; 431 } 432 433 xcppm_set_led(new_action); 434 unitp->led_tid = timeout(xcppm_blink_led, (void *)(uintptr_t)new_action, 435 intvl); 436 mutex_exit(&unitp->unit_lock); 437 } 438 439 440 static void 441 xcppm_freeze_led(void *action) 442 { 443 xcppm_unit_t *unitp; 444 timeout_id_t tid; 445 446 DPRINTF(D_LOWEST, ("xcppm_freeze_led: action %d\n", 447 (int)(uintptr_t)action)); 448 unitp = ddi_get_soft_state(ppm_statep, ppm_inst); 449 mutex_enter(&unitp->unit_lock); 450 tid = unitp->led_tid; 451 unitp->led_tid = 0; 452 mutex_exit(&unitp->unit_lock); 453 (void) untimeout(tid); 454 mutex_enter(&unitp->unit_lock); 455 xcppm_set_led((int)(uintptr_t)action); 456 mutex_exit(&unitp->unit_lock); 457 } 458 459 460 /* ARGSUSED */ 461 static int 462 xcppm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 463 { 464 xcppm_unit_t *unitp; 465 466 unitp = ddi_get_soft_state(ppm_statep, ppm_inst); 467 DPRINTF(D_DETACH, ("xcppm_detach: cmd %d\n", cmd)); 468 469 switch (cmd) { 470 case DDI_DETACH: 471 return (DDI_FAILURE); 472 473 case DDI_SUSPEND: 474 mutex_enter(&unitp->unit_lock); 475 unitp->state |= XCPPM_ST_SUSPENDED; 476 mutex_exit(&unitp->unit_lock); 477 478 /* 479 * Suspend requires that timeout callouts to be canceled. 480 * Turning off the LED blinking will cancel the timeout. 481 */ 482 xcppm_freeze_led((void *)PPM_LEDON); 483 return (DDI_SUCCESS); 484 485 default: 486 return (DDI_FAILURE); 487 } 488 } 489 490 491 /* 492 * Device we claimed has detached. We must get rid of 493 * our state which was used to track this device. 494 */ 495 static void 496 xcppm_detach_ctlop(dev_info_t *dip, power_req_t *reqp) 497 { 498 ppm_dev_t *ppmd; 499 500 ppmd = PPM_GET_PRIVATE(dip); 501 if (ppmd == NULL || reqp->req.ppm_config_req.result != DDI_SUCCESS) 502 return; 503 504 ppm_rem_dev(dip); 505 } 506 507 508 /* 509 * The system is being resumed from a cpr suspend operation and this 510 * device's attach entry will be called shortly. The driver will set 511 * the device's power to a conventional starting value, and we need to 512 * stay in sync and set our private copy to the same value. 513 */ 514 /* ARGSUSED */ 515 static void 516 xcppm_resume_ctlop(dev_info_t *dip, power_req_t *reqp) 517 { 518 ppm_domain_t *domp; 519 ppm_dev_t *ppmd; 520 int powered; 521 522 ppmd = PPM_GET_PRIVATE(dip); 523 if (ppmd == NULL) 524 return; 525 526 /* 527 * Maintain correct powered count for domain which cares 528 */ 529 powered = 0; 530 domp = ppmd->domp; 531 mutex_enter(&domp->lock); 532 if (domp == &xcppm_fet) { 533 for (ppmd = domp->devlist; ppmd; ppmd = ppmd->next) { 534 if (ppmd->dip == dip && ppmd->level) 535 powered++; 536 } 537 538 /* 539 * If this device was powered off when the system was 540 * suspended, this resume acts like a power-on transition, 541 * so we adjust the count. 542 */ 543 if (powered == 0) 544 domp->pwr_cnt++; 545 } 546 547 for (ppmd = domp->devlist; ppmd; ppmd = ppmd->next) { 548 if (ppmd->dip == dip) 549 ppmd->level = ppmd->rplvl = PM_LEVEL_UNKNOWN; 550 } 551 mutex_exit(&domp->lock); 552 } 553 554 555 /* 556 * Change the power level for a component of a device. If the change 557 * arg is true, we call the framework to actually change the device's 558 * power; otherwise, we just update our own copy of the power level. 559 */ 560 static int 561 xcppm_set_level(ppm_dev_t *ppmd, int cmpt, int level, boolean_t change) 562 { 563 #ifdef DEBUG 564 char *str = "xcppm_set_level"; 565 #endif 566 int ret; 567 568 ret = DDI_SUCCESS; 569 if (change) 570 ret = pm_power(ppmd->dip, cmpt, level); 571 572 DPRINTF(D_SETLVL, ("%s: \"%s\" change=%d, old %d, new %d, ret %d\n", 573 str, ppmd->path, change, ppmd->level, level, ret)); 574 575 if (ret == DDI_SUCCESS) { 576 ppmd->level = level; 577 ppmd->rplvl = PM_LEVEL_UNKNOWN; 578 } 579 580 return (ret); 581 } 582 583 584 static int 585 xcppm_change_power_level(ppm_dev_t *ppmd, int cmpt, int level) 586 { 587 return (xcppm_set_level(ppmd, cmpt, level, B_TRUE)); 588 } 589 590 591 static int 592 xcppm_record_level_change(ppm_dev_t *ppmd, int cmpt, int level) 593 { 594 return (xcppm_set_level(ppmd, cmpt, level, B_FALSE)); 595 } 596 597 598 static uint8_t 599 xcppm_gpio_port2(int action, uint8_t pos) 600 { 601 #ifdef DEBUG 602 char *str = "xcppm_gpio_port2"; 603 #endif 604 xcppm_unit_t *unitp; 605 uint8_t data8, buf8; 606 uint8_t ret; 607 608 unitp = ddi_get_soft_state(ppm_statep, ppm_inst); 609 mutex_enter(&unitp->gpio_lock); 610 611 data8 = buf8 = XCPPM_GET8(unitp->hndls.gpio_data_ports, 612 unitp->regs.gpio_port2_data); 613 614 switch (action) { 615 case XCPPM_GETBIT: 616 ret = data8 & pos; 617 DPRINTF(D_GPIO, ("%s: READ: GPIO Bank2 value 0x%x\n", 618 str, buf8)); 619 break; 620 621 case XCPPM_SETBIT: 622 case XCPPM_CLRBIT: 623 if (action == XCPPM_SETBIT) 624 data8 |= pos; 625 else 626 data8 &= ~pos; 627 XCPPM_SETGET8(unitp->hndls.gpio_data_ports, 628 unitp->regs.gpio_port2_data, data8); 629 ret = data8 & pos; 630 DPRINTF(D_GPIO, ("%s: %s: GPIO Bank2 " 631 "bit 0x%x changed from 0x%x to 0x%x\n", 632 str, (action == XCPPM_SETBIT) ? "UP" : "DOWN", 633 pos, buf8, data8)); 634 break; 635 636 default: 637 cmn_err(CE_PANIC, "xcalppm: unrecognized register " 638 "IO command %d\n", action); 639 break; 640 } 641 mutex_exit(&unitp->gpio_lock); 642 643 return (ret); 644 } 645 646 647 /* 648 * Raise the power level of a subrange of cpus. Used when cpu driver 649 * failed an attempt to lower the power of a cpu (probably because 650 * it got busy). Need to revert the ones we already changed. 651 * 652 * ecpup = the ppm_dev_t for the cpu which failed to lower power 653 * level = power level to reset prior cpus to 654 */ 655 static void 656 xcppm_revert_cpu_power(ppm_dev_t *ecpup, int level) 657 { 658 ppm_dev_t *cpup; 659 660 for (cpup = xcppm_cpu.devlist; cpup != ecpup; cpup = cpup->next) { 661 DPRINTF(D_CPU, ("xrcp: \"%s\", revert to level %d\n", 662 cpup->path, level)); 663 (void) xcppm_change_power_level(cpup, 0, level); 664 } 665 } 666 667 /* 668 * Switch the DC/DC converter. Clearing the GPIO bit in SuperI/O puts 669 * the converter in low power mode and setting the bit puts it back in 670 * normal mode. 671 */ 672 static void 673 xcppm_switch_dcdc_converter(int action) 674 { 675 int tries = XCPPM_VCL_TRIES; 676 uint_t spl; 677 uint64_t stick_begin, stick_end; 678 uint64_t tick_begin, tick_end; 679 uint64_t cur_speed_ratio, full_speed_ratio; 680 static int xcppm_dcdc_lpm; 681 682 switch (action) { 683 case XCPPM_SETBIT: 684 if (xcppm_dcdc_lpm) { 685 DPRINTF(D_CPU, ("xcppm_switch_dcdc_converter: " 686 "switch to normal power mode.\n")); 687 (void) xcppm_gpio_port2(action, HIGHPWR); 688 xcppm_dcdc_lpm = 0; 689 } 690 break; 691 case XCPPM_CLRBIT: 692 /* 693 * In some fast CPU configurations, DC/DC converter was 694 * put in low power mode before CPUs made the transition 695 * to 1/32 of clock speed. In those cases, system was 696 * shut down by hardware for protection. To resolve that 697 * problem, we make sure CPUs have made the clock transition 698 * before the DC/DC converter has been put to low power mode. 699 */ 700 ASSERT(xcppm_dcdc_lpm == 0); 701 kpreempt_disable(); 702 full_speed_ratio = cpunodes[CPU->cpu_id].clock_freq / 703 sys_tick_freq; 704 while (tries) { 705 spl = ddi_enter_critical(); 706 tick_begin = gettick_counter(); 707 stick_timestamp((int64_t *)&stick_begin); 708 ddi_exit_critical(spl); 709 drv_usecwait(XCPPM_VCL_DELAY); 710 spl = ddi_enter_critical(); 711 tick_end = gettick_counter(); 712 stick_timestamp((int64_t *)&stick_end); 713 ddi_exit_critical(spl); 714 cur_speed_ratio = (tick_end - tick_begin) / 715 (stick_end - stick_begin); 716 717 /* 718 * tick/stick at current speed should at most be 719 * equal to full-speed tick/stick, adjusted with 720 * full/lowest clock speed ratio. If not, speed 721 * transition has not happened yet. 722 */ 723 if (cur_speed_ratio <= ((full_speed_ratio / 724 XCPPM_VCL_DIVISOR) + 1)) { 725 DPRINTF(D_CPU, ("xcppm_switch_dcdc_converter: " 726 "switch to low power mode.\n")); 727 (void) xcppm_gpio_port2(action, HIGHPWR); 728 xcppm_dcdc_lpm = 1; 729 break; 730 } 731 DPRINTF(D_CPU, ("xcppm_switch_dcdc_converter: CPU " 732 "has not made transition to lowest speed yet " 733 "(%d)\n", tries)); 734 tries--; 735 } 736 kpreempt_enable(); 737 break; 738 } 739 } 740 741 static void 742 xcppm_rio_mode(xcppm_unit_t *unitp, int mode) 743 { 744 uint32_t data32, buf32; 745 746 mutex_enter(&unitp->gpio_lock); 747 data32 = buf32 = XCPPM_GET32(unitp->hndls.rio_mode_auxio, 748 unitp->regs.rio_mode_auxio); 749 if (mode == XCPPM_SETBIT) 750 data32 |= RIO_BBC_ESTAR_MODE; 751 else 752 data32 &= ~RIO_BBC_ESTAR_MODE; 753 XCPPM_SETGET32(unitp->hndls.rio_mode_auxio, 754 unitp->regs.rio_mode_auxio, data32); 755 mutex_exit(&unitp->gpio_lock); 756 757 DPRINTF(D_CPU, ("xcppm_rio_mode: %s: change from 0x%x to 0x%x\n", 758 (mode == XCPPM_SETBIT) ? "DOWN" : "UP", buf32, data32)); 759 } 760 761 762 /* 763 * change the power level of all cpus to the arg value; 764 * the caller needs to ensure that a legal transition is requested. 765 */ 766 static int 767 xcppm_change_cpu_power(int newlevel) 768 { 769 #ifdef DEBUG 770 char *str = "xcppm_ccp"; 771 #endif 772 int index, level, oldlevel; 773 int lowest, highest; 774 int undo_flag, ret; 775 int speedup, incr; 776 uint32_t data32; 777 uint16_t data16; 778 xcppm_unit_t *unitp; 779 ppm_dev_t *cpup; 780 dev_info_t *dip; 781 char *chstr; 782 783 unitp = ddi_get_soft_state(ppm_statep, ppm_inst); 784 ASSERT(unitp); 785 cpup = xcppm_cpu.devlist; 786 lowest = cpup->lowest; 787 highest = cpup->highest; 788 789 /* 790 * not all cpus may have transitioned to a known level by this time 791 */ 792 oldlevel = (cpup->level == PM_LEVEL_UNKNOWN) ? highest : cpup->level; 793 dip = cpup->dip; 794 ASSERT(dip); 795 796 DPRINTF(D_CPU, ("%s: old %d, new %d, highest %d, lowest %d\n", 797 str, oldlevel, newlevel, highest, lowest)); 798 799 if (newlevel > oldlevel) { 800 chstr = "UP"; 801 speedup = 1; 802 incr = 1; 803 } else if (newlevel < oldlevel) { 804 chstr = "DOWN"; 805 speedup = 0; 806 incr = -1; 807 } else 808 return (DDI_SUCCESS); 809 810 undo_flag = 0; 811 if (speedup) { 812 /* 813 * If coming up from lowest power level, set the E* 814 * mode bit in GPIO to make power supply efficient 815 * at normal power. 816 */ 817 if (oldlevel == cpup->lowest) { 818 xcppm_switch_dcdc_converter(XCPPM_SETBIT); 819 undo_flag = 1; 820 } 821 } else { 822 /* 823 * set BBC Estar mode bit in RIO AUXIO register 824 */ 825 if (oldlevel == highest) { 826 xcppm_rio_mode(unitp, XCPPM_SETBIT); 827 undo_flag = 1; 828 } 829 } 830 831 /* 832 * this loop will execute 1x or 2x depending on 833 * number of times we need to change clock rates 834 */ 835 for (level = oldlevel+incr; level != newlevel+incr; level += incr) { 836 for (cpup = xcppm_cpu.devlist; cpup; cpup = cpup->next) { 837 if (cpup->level == level) 838 continue; 839 ret = xcppm_change_power_level(cpup, 0, level); 840 DPRINTF(D_CPU, ("%s: \"%s\", %s to level %d, ret %d\n", 841 str, cpup->path, chstr, cpup->level, ret)); 842 if (ret == DDI_SUCCESS) 843 continue; 844 845 /* 846 * if the driver was unable to lower cpu speed, 847 * the cpu probably got busy; set the previous 848 * cpus back to the original level 849 */ 850 if (speedup == 0) 851 xcppm_revert_cpu_power(cpup, level + 1); 852 853 if (undo_flag) { 854 if (speedup) 855 xcppm_switch_dcdc_converter( 856 XCPPM_CLRBIT); 857 else 858 xcppm_rio_mode(unitp, XCPPM_CLRBIT); 859 } 860 return (ret); 861 } 862 863 index = level - 1; 864 spm_change_schizo_speed(index); 865 DPRINTF(D_CPU, ("%s: safari config reg changed\n", str)); 866 867 /* 868 * set the delay times for changing to this rate 869 */ 870 data32 = XCPPM_BBC_DELAY(index); 871 XCPPM_SETGET32(unitp->hndls.bbc_estar_ctrl, 872 (caddr_t)unitp->regs.bbc_assert_change, data32); 873 DPRINTF(D_CPU, ("%s: %s: Wrote E* Assert Change Time " 874 "(t1) = 0x%x\n", str, chstr, data32)); 875 876 data32 = XCPPM_BBC_DELAY(index); 877 XCPPM_SETGET32(unitp->hndls.bbc_estar_ctrl, 878 (caddr_t)unitp->regs.bbc_pll_settle, data32); 879 DPRINTF(D_CPU, ("%s: %s: Wrote E* PLL Settle Time " 880 "(t4) = 0x%x\n", str, chstr, data32)); 881 882 data16 = bbc_estar_control_masks[index]; 883 XCPPM_SETGET16(unitp->hndls.bbc_estar_ctrl, 884 (caddr_t)unitp->regs.bbc_estar_ctrl, data16); 885 DPRINTF(D_CPU, ("%s: %s: Wrote BCC E* Control = 0x%x\n", 886 str, chstr, data16)); 887 } 888 889 /* 890 * clear CPU Estar Mode bit in the gpio register 891 */ 892 if (speedup) { 893 if (newlevel == highest) 894 xcppm_rio_mode(unitp, XCPPM_CLRBIT); 895 } else { 896 if (newlevel == lowest) 897 xcppm_switch_dcdc_converter(XCPPM_CLRBIT); 898 } 899 900 return (DDI_SUCCESS); 901 } 902 903 904 /* 905 * Process a request to change the power level of a cpu. If all cpus 906 * don't want to be at the same power yet, or if we are currently 907 * refusing slowdown requests due to thermal stress, just cache the 908 * request. Otherwise, make the change for all cpus. 909 */ 910 /* ARGSUSED */ 911 static int 912 xcppm_manage_cpus(dev_info_t *dip, power_req_t *reqp, int *result) 913 { 914 #ifdef DEBUG 915 char *str = "xcppm_manage_cpus"; 916 #endif 917 int old, new, ret, kmflag; 918 ppm_dev_t *ppmd; 919 pm_ppm_devlist_t *devlist = NULL, *p; 920 int do_rescan = 0; 921 dev_info_t *rescan_dip; 922 923 *result = DDI_SUCCESS; 924 switch (reqp->request_type) { 925 case PMR_PPM_SET_POWER: 926 break; 927 case PMR_PPM_POWER_CHANGE_NOTIFY: 928 /* cpu driver can`t change cpu power level by itself */ 929 default: 930 return (DDI_FAILURE); 931 } 932 933 ppmd = PPM_GET_PRIVATE(dip); 934 ASSERT(MUTEX_HELD(&ppmd->domp->lock)); 935 old = reqp->req.ppm_set_power_req.old_level; 936 new = reqp->req.ppm_set_power_req.new_level; 937 938 /* 939 * At power on, the cpus are at full speed. There is no hardware 940 * transition needed for going from unknown to full. However, the 941 * state of the pm framework and cpu driver needs to be adjusted. 942 */ 943 if (ppmd->level == PM_LEVEL_UNKNOWN && new == ppmd->highest) { 944 *result = ret = xcppm_change_power_level(ppmd, 0, new); 945 if (ret != DDI_SUCCESS) { 946 DPRINTF(D_CPU, ("%s: Failed to change " 947 "power level to %d\n", str, new)); 948 } 949 return (ret); 950 } 951 952 if (new == ppmd->level) { 953 DPRINTF(D_CPU, ("%s: already at power level %d\n", str, new)); 954 return (DDI_SUCCESS); 955 } 956 957 ppmd->rplvl = new; 958 959 /* 960 * A request from lower to higher level transition is granted and 961 * made effective on both cpus. For more than two cpu platform model, 962 * the following code needs to be modified to remember the rest of 963 * the unsoliciting cpus to be rescan'ed. 964 * A request from higher to lower must be agreed by all cpus. 965 */ 966 for (ppmd = xcppm_cpu.devlist; ppmd; ppmd = ppmd->next) { 967 if (ppmd->rplvl == new) 968 continue; 969 970 if (new < old) { 971 DPRINTF(D_SOME, ("%s: not all cpus want to go down to " 972 "level %d yet\n", str, new)); 973 return (DDI_SUCCESS); 974 } 975 976 /* 977 * If a single cpu requests power up, honor the request 978 * by powering up both cpus. 979 */ 980 if (new > old) { 981 DPRINTF(D_SOME, ("%s: powering up device(%s@%s, %p) " 982 "because of request from dip(%s@%s, %p), " 983 "need pm_rescan\n", str, PM_NAME(ppmd->dip), 984 PM_ADDR(ppmd->dip), (void *)ppmd->dip, 985 PM_NAME(dip), PM_ADDR(dip), (void *)dip)) 986 do_rescan++; 987 rescan_dip = ppmd->dip; 988 break; 989 } 990 } 991 992 ret = xcppm_change_cpu_power(new); 993 *result = ret; 994 995 if (ret == DDI_SUCCESS) { 996 if (reqp->req.ppm_set_power_req.canblock == PM_CANBLOCK_BLOCK) 997 kmflag = KM_SLEEP; 998 else 999 kmflag = KM_NOSLEEP; 1000 1001 for (ppmd = xcppm_cpu.devlist; ppmd; ppmd = ppmd->next) { 1002 if (ppmd->dip == dip) 1003 continue; 1004 1005 if ((p = kmem_zalloc(sizeof (pm_ppm_devlist_t), 1006 kmflag)) == NULL) { 1007 break; 1008 } 1009 p->ppd_who = ppmd->dip; 1010 p->ppd_cmpt = ppmd->cmpt; 1011 p->ppd_old_level = old; 1012 p->ppd_new_level = new; 1013 p->ppd_next = devlist; 1014 1015 devlist = p; 1016 } 1017 reqp->req.ppm_set_power_req.cookie = (void *) devlist; 1018 1019 if (do_rescan > 0) 1020 pm_rescan(rescan_dip); 1021 } 1022 1023 return (ret); 1024 } 1025 1026 1027 /* 1028 * If powering off and all devices in this domain will now be off, 1029 * shut off common power. If powering up and no devices up yet, 1030 * turn on common power. Always make the requested power level 1031 * change for the target device. 1032 */ 1033 static int 1034 xcppm_manage_fet(dev_info_t *dip, power_req_t *reqp, int *result) 1035 { 1036 #ifdef DEBUG 1037 char *str = "xcppm_manage_fet"; 1038 #endif 1039 int (*pwr_func)(ppm_dev_t *, int, int); 1040 int new, old, cmpt, incr = 0; 1041 ppm_dev_t *ppmd; 1042 1043 ppmd = PPM_GET_PRIVATE(dip); 1044 DPRINTF(D_FET, ("%s: \"%s\", req %s\n", str, 1045 ppmd->path, ppm_get_ctlstr(reqp->request_type, ~0))); 1046 1047 *result = DDI_SUCCESS; /* change later for failures */ 1048 switch (reqp->request_type) { 1049 case PMR_PPM_SET_POWER: 1050 pwr_func = xcppm_change_power_level; 1051 old = reqp->req.ppm_set_power_req.old_level; 1052 new = reqp->req.ppm_set_power_req.new_level; 1053 cmpt = reqp->req.ppm_set_power_req.cmpt; 1054 break; 1055 case PMR_PPM_POWER_CHANGE_NOTIFY: 1056 pwr_func = xcppm_record_level_change; 1057 old = reqp->req.ppm_notify_level_req.old_level; 1058 new = reqp->req.ppm_notify_level_req.new_level; 1059 cmpt = reqp->req.ppm_notify_level_req.cmpt; 1060 break; 1061 default: 1062 return (*result = DDI_FAILURE); 1063 1064 } 1065 1066 /* This is common code for SET_POWER and POWER_CHANGE_NOTIFY cases */ 1067 DPRINTF(D_FET, ("%s: \"%s\", old %d, new %d\n", 1068 str, ppmd->path, old, new)); 1069 1070 ASSERT(old == ppmd->level); 1071 if (new == ppmd->level) 1072 return (DDI_SUCCESS); 1073 1074 PPM_LOCK_DOMAIN(ppmd->domp); 1075 /* 1076 * Devices in this domain are known to have 0 (off) as their 1077 * lowest power level. We use this fact to simplify the logic. 1078 */ 1079 if (new > 0) { 1080 if (ppmd->domp->pwr_cnt == 0) 1081 (void) xcppm_gpio_port2(XCPPM_SETBIT, DRVON); 1082 if (old == 0) { 1083 ppmd->domp->pwr_cnt++; 1084 incr = 1; 1085 DPRINTF(D_FET, ("%s: UP cnt = %d\n", 1086 str, ppmd->domp->pwr_cnt)); 1087 } 1088 } 1089 1090 PPM_UNLOCK_DOMAIN(ppmd->domp); 1091 1092 ASSERT(ppmd->domp->pwr_cnt > 0); 1093 1094 if ((*result = (*pwr_func)(ppmd, cmpt, new)) != DDI_SUCCESS) { 1095 DPRINTF(D_FET, ("%s: \"%s\" power change failed \n", 1096 str, ppmd->path)); 1097 } 1098 1099 PPM_LOCK_DOMAIN(ppmd->domp); 1100 1101 /* 1102 * Decr the power count in two cases: 1103 * 1104 * 1) request was to power device down and was successful 1105 * 2) request was to power up (we pre-incremented count), but failed. 1106 */ 1107 if ((*result == DDI_SUCCESS && ppmd->level == 0) || 1108 (*result != DDI_SUCCESS && incr)) { 1109 ASSERT(ppmd->domp->pwr_cnt > 0); 1110 ppmd->domp->pwr_cnt--; 1111 DPRINTF(D_FET, ("%s: DN cnt = %d\n", str, ppmd->domp->pwr_cnt)); 1112 if (ppmd->domp->pwr_cnt == 0) 1113 (void) xcppm_gpio_port2(XCPPM_CLRBIT, DRVON); 1114 } 1115 1116 PPM_UNLOCK_DOMAIN(ppmd->domp); 1117 ASSERT(ppmd->domp->pwr_cnt >= 0); 1118 return (*result == DDI_SUCCESS ? DDI_SUCCESS : DDI_FAILURE); 1119 } 1120 1121 1122 /* 1123 * Since UPA64S relies on PCI B staying at nominal 33MHz in order to 1124 * have its interrupt pulse function properly, we ensure 1125 * - Lowering PCI B only if UPA64S is at low power, otherwise defer 1126 * the action until UPA64S goes down; hence right after UPA64S goes 1127 * down, perform the deferred action for PCI B; 1128 * - Always raise PCI B power prior to raising UPA64S power. 1129 * 1130 * Both UPA64S and PCI B devices are considered each other's dependency 1131 * device whenever actual power transition is handled (PMR_PPM_SET_POWER). 1132 */ 1133 static int 1134 xcppm_manage_pciupa(dev_info_t *dip, power_req_t *reqp, int *result) 1135 { 1136 #ifdef DEBUG 1137 char *str = "xcppm_manage_pciupa"; 1138 #endif 1139 int (*pwr_func)(ppm_dev_t *, int, int); 1140 uint_t flags = 0, co_flags = 0; 1141 ppm_dev_t *ppmd, *codev; 1142 int new, cmpt, retval; 1143 1144 ppmd = PPM_GET_PRIVATE(dip); 1145 DPRINTF(D_PCIUPA, ("%s: \"%s\", req %s\n", str, 1146 ppmd->path, ppm_get_ctlstr(reqp->request_type, ~0))); 1147 1148 *result = DDI_SUCCESS; 1149 1150 switch (reqp->request_type) { 1151 case PMR_PPM_SET_POWER: 1152 pwr_func = xcppm_change_power_level; 1153 new = reqp->req.ppm_set_power_req.new_level; 1154 cmpt = reqp->req.ppm_set_power_req.cmpt; 1155 break; 1156 case PMR_PPM_POWER_CHANGE_NOTIFY: 1157 pwr_func = xcppm_record_level_change; 1158 new = reqp->req.ppm_notify_level_req.new_level; 1159 cmpt = reqp->req.ppm_notify_level_req.cmpt; 1160 break; 1161 default: 1162 *result = DDI_FAILURE; 1163 return (DDI_FAILURE); 1164 } 1165 1166 /* Common code for SET_POWER and POWER_CHANGE_NOTIFY cases */ 1167 ASSERT(ppmd); /* since it should be locked already */ 1168 1169 if (new == ppmd->level) 1170 return (DDI_SUCCESS); 1171 1172 DPRINTF(D_PCIUPA, ("%s: \"%s\", levels: current %d, new %d\n", 1173 str, ppmd->path, ppmd->level, new)); 1174 1175 /* 1176 * find power-wise co-related device 1177 */ 1178 flags = ppmd->flags; 1179 1180 #ifdef DEBUG 1181 if (flags & ~(XCPPMF_PCIB|XCPPMF_UPA)) 1182 DPRINTF(D_ERROR, ("%s: invalid ppmd->flags value 0x%x\n", str, 1183 ppmd->flags)); 1184 #endif 1185 1186 if (flags == XCPPMF_UPA) 1187 co_flags = XCPPMF_PCIB; 1188 else if (flags == XCPPMF_PCIB) 1189 co_flags = XCPPMF_UPA; 1190 1191 for (codev = ppmd->domp->devlist; codev; codev = codev->next) 1192 if ((codev->cmpt == 0) && (codev->flags == co_flags)) 1193 break; 1194 1195 if (new > ppmd->level) { 1196 /* 1197 * Raise power level - 1198 * pre-raising: upa ensure pci is powered up. 1199 */ 1200 if ((flags == XCPPMF_UPA) && codev && 1201 (codev->level != codev->highest)) { 1202 if ((retval = xcppm_change_power_level(codev, 1203 0, codev->highest)) != DDI_SUCCESS && 1204 codev->level != codev->highest) { 1205 *result = retval; 1206 return (DDI_FAILURE); 1207 } 1208 } 1209 if ((retval = (*pwr_func)(ppmd, 0, new)) != DDI_SUCCESS) { 1210 *result = retval; 1211 return (DDI_FAILURE); 1212 } 1213 } else if (new < ppmd->level) { 1214 /* 1215 * Lower power level 1216 * 1217 * once upa is attached, pci checks upa level: 1218 * if upa is at high level, defer the request and return. 1219 * otherwise, set power level then check and lower pci level. 1220 */ 1221 if ((flags == XCPPMF_PCIB) && codev && 1222 (codev->level != codev->lowest)) { 1223 ppmd->rplvl = new; 1224 return (DDI_SUCCESS); 1225 } 1226 if ((retval = (*pwr_func)(ppmd, cmpt, new)) != DDI_SUCCESS && 1227 ppmd->level != new) { 1228 *result = retval; 1229 return (DDI_FAILURE); 1230 } 1231 1232 if (flags == XCPPMF_UPA) { 1233 if (codev && (codev->rplvl != PM_LEVEL_UNKNOWN) && 1234 (codev->rplvl < codev->level)) { 1235 DPRINTF(D_PCIUPA, ("%s: codev \"%s\" " 1236 "rplvl %d level %d\n", str, codev->path, 1237 codev->rplvl, codev->level)); 1238 if ((retval = xcppm_change_power_level( 1239 codev, 0, codev->rplvl)) != DDI_SUCCESS) { 1240 *result = retval; 1241 return (DDI_FAILURE); 1242 } 1243 } 1244 } 1245 } 1246 1247 return (DDI_SUCCESS); 1248 } 1249 1250 1251 /* 1252 * When all of the children of the 1394 nexus are idle, a call will be 1253 * made to the nexus driver's own power entry point to lower power. Ppm 1254 * intercepts this and kills 1394 cable power (since the driver doesn't 1255 * have access to the required register). Similar logic applies when 1256 * coming up from the state where all the children were off. 1257 */ 1258 static int 1259 xcppm_manage_1394(dev_info_t *dip, power_req_t *reqp, int *result) 1260 { 1261 #ifdef DEBUG 1262 char *str = "xcppm_manage_1394"; 1263 #endif 1264 int (*pwr_func)(ppm_dev_t *, int, int); 1265 int new, old, cmpt; 1266 ppm_dev_t *ppmd; 1267 1268 ppmd = PPM_GET_PRIVATE(dip); 1269 DPRINTF(D_1394, ("%s: \"%s\", req %s\n", str, 1270 ppmd->path, ppm_get_ctlstr(reqp->request_type, ~0))); 1271 1272 switch (reqp->request_type) { 1273 case PMR_PPM_SET_POWER: 1274 pwr_func = xcppm_change_power_level; 1275 old = reqp->req.ppm_set_power_req.old_level; 1276 new = reqp->req.ppm_set_power_req.new_level; 1277 cmpt = reqp->req.ppm_set_power_req.cmpt; 1278 break; 1279 case PMR_PPM_POWER_CHANGE_NOTIFY: 1280 pwr_func = xcppm_record_level_change; 1281 old = reqp->req.ppm_notify_level_req.old_level; 1282 new = reqp->req.ppm_notify_level_req.new_level; 1283 cmpt = reqp->req.ppm_notify_level_req.cmpt; 1284 break; 1285 default: 1286 return (*result = DDI_FAILURE); 1287 } 1288 1289 1290 /* Common code for SET_POWER and POWER_CHANGE_NOTIFY cases */ 1291 DPRINTF(D_1394, ("%s: dev %s@%s, old %d new %d\n", str, 1292 ddi_binding_name(dip), ddi_get_name_addr(dip), old, new)); 1293 1294 ASSERT(ppmd); /* since it must already be locked */ 1295 ASSERT(old == ppmd->level); 1296 1297 if (new == ppmd->level) 1298 return (*result = DDI_SUCCESS); 1299 1300 /* the reduce power case */ 1301 if (cmpt == 0 && new < ppmd->level) { 1302 if ((*result = 1303 (*pwr_func)(ppmd, cmpt, new)) != DDI_SUCCESS) { 1304 return (DDI_FAILURE); 1305 } 1306 if (new == ppmd->lowest) 1307 (void) xcppm_gpio_port2(XCPPM_CLRBIT, CPEN); 1308 ppmd->level = new; 1309 return (DDI_SUCCESS); 1310 } 1311 1312 /* the increase power case */ 1313 if (cmpt == 0 && new > ppmd->level) { 1314 if (ppmd->level == ppmd->lowest) { 1315 (void) xcppm_gpio_port2(XCPPM_SETBIT, CPEN); 1316 delay(1); 1317 } 1318 /* 1319 * Even if pwr_func fails we need to check current level again 1320 * because it could have been changed by an intervening 1321 * POWER_CHANGE_NOTIFY operation. 1322 */ 1323 if ((*result = 1324 (*pwr_func)(ppmd, cmpt, new)) != DDI_SUCCESS && 1325 ppmd->level == ppmd->lowest) { 1326 (void) xcppm_gpio_port2(XCPPM_CLRBIT, CPEN); 1327 } else { 1328 ppmd->level = new; 1329 } 1330 1331 return (*result == DDI_SUCCESS ? DDI_SUCCESS : DDI_FAILURE); 1332 } 1333 1334 /* 1335 * We get here if component was non-zero. This is not what we 1336 * expect. Let the device deal with it and just pass back the 1337 * result. 1338 */ 1339 *result = xcppm_change_power_level(ppmd, cmpt, new); 1340 return (*result == DDI_SUCCESS ? DDI_SUCCESS : DDI_FAILURE); 1341 } 1342 1343 1344 /* 1345 * lock, unlock, or trylock for one power mutex 1346 */ 1347 static void 1348 xcppm_lock_one(ppm_dev_t *ppmd, power_req_t *reqp, int *iresp) 1349 { 1350 switch (reqp->request_type) { 1351 case PMR_PPM_LOCK_POWER: 1352 pm_lock_power_single(ppmd->dip); 1353 break; 1354 1355 case PMR_PPM_UNLOCK_POWER: 1356 pm_unlock_power_single(ppmd->dip); 1357 break; 1358 1359 case PMR_PPM_TRY_LOCK_POWER: 1360 *iresp = pm_try_locking_power_single(ppmd->dip); 1361 break; 1362 } 1363 } 1364 1365 1366 /* 1367 * lock, unlock, or trylock all devices within a domain. 1368 */ 1369 static void 1370 xcppm_lock_all(ppm_domain_t *domp, power_req_t *reqp, int *iresp) 1371 { 1372 /* 1373 * To simplify the implementation we let all the devices 1374 * in the domain be represented by a single device (dip). 1375 * We use the first device in the domain's devlist. This 1376 * is safe because we return with the domain lock held 1377 * which prevents the list from changing. 1378 */ 1379 if (reqp->request_type == PMR_PPM_LOCK_POWER) { 1380 if (!MUTEX_HELD(&domp->lock)) 1381 mutex_enter(&domp->lock); 1382 domp->refcnt++; 1383 ASSERT(domp->devlist != NULL); 1384 pm_lock_power_single(domp->devlist->dip); 1385 /* domain lock remains held */ 1386 return; 1387 } else if (reqp->request_type == PMR_PPM_UNLOCK_POWER) { 1388 ASSERT(MUTEX_HELD(&domp->lock)); 1389 ASSERT(domp->devlist != NULL); 1390 pm_unlock_power_single(domp->devlist->dip); 1391 if (--domp->refcnt == 0) 1392 mutex_exit(&domp->lock); 1393 return; 1394 } 1395 1396 ASSERT(reqp->request_type == PMR_PPM_TRY_LOCK_POWER); 1397 if (!MUTEX_HELD(&domp->lock)) 1398 if (!mutex_tryenter(&domp->lock)) { 1399 *iresp = 0; 1400 return; 1401 } 1402 *iresp = pm_try_locking_power_single(domp->devlist->dip); 1403 if (*iresp) 1404 domp->refcnt++; 1405 else 1406 mutex_exit(&domp->lock); 1407 } 1408 1409 1410 /* 1411 * The pm framework calls us here to manage power for a device. 1412 * We maintain state which tells us whether we need to turn off/on 1413 * system board power components based on the status of all the devices 1414 * sharing a component. 1415 * 1416 */ 1417 /* ARGSUSED */ 1418 static int 1419 xcppm_ctlops(dev_info_t *dip, dev_info_t *rdip, 1420 ddi_ctl_enum_t ctlop, void *arg, void *result) 1421 { 1422 power_req_t *reqp = arg; 1423 xcppm_unit_t *unitp; 1424 ppm_domain_t *domp; 1425 ppm_dev_t *ppmd; 1426 1427 #ifdef DEBUG 1428 char path[MAXPATHLEN], *ctlstr, *str = "xcppm_ctlops"; 1429 uint_t mask = ppm_debug & (D_CTLOPS1 | D_CTLOPS2); 1430 if (mask && (ctlstr = ppm_get_ctlstr(reqp->request_type, mask))) { 1431 prom_printf("%s: \"%s\", %s\n", str, 1432 ddi_pathname(rdip, path), ctlstr); 1433 } 1434 #endif 1435 1436 if (ctlop != DDI_CTLOPS_POWER) 1437 return (DDI_FAILURE); 1438 1439 switch (reqp->request_type) { 1440 case PMR_PPM_UNMANAGE: 1441 case PMR_PPM_PRE_PROBE: 1442 case PMR_PPM_POST_PROBE: 1443 case PMR_PPM_PRE_ATTACH: 1444 case PMR_PPM_PRE_DETACH: 1445 return (DDI_SUCCESS); 1446 1447 /* 1448 * There is no hardware configuration required to be done on this 1449 * platform prior to installing drivers. 1450 */ 1451 case PMR_PPM_INIT_CHILD: 1452 case PMR_PPM_UNINIT_CHILD: 1453 return (DDI_SUCCESS); 1454 1455 case PMR_PPM_ALL_LOWEST: 1456 DPRINTF(D_LOWEST, ("%s: all devices at lowest power = %d\n", 1457 str, reqp->req.ppm_all_lowest_req.mode)); 1458 if (reqp->req.ppm_all_lowest_req.mode == PM_ALL_LOWEST) { 1459 unitp = ddi_get_soft_state(ppm_statep, ppm_inst); 1460 mutex_enter(&unitp->unit_lock); 1461 if (unitp->state & XCPPM_ST_SUSPENDED) { 1462 mutex_exit(&unitp->unit_lock); 1463 return (DDI_SUCCESS); 1464 } 1465 1466 xcppm_set_led(PPM_LEDON); 1467 unitp->led_tid = timeout(xcppm_blink_led, 1468 (void *)PPM_LEDON, PPM_LEDON_INTERVAL); 1469 mutex_exit(&unitp->unit_lock); 1470 DPRINTF(D_LOWEST, ("%s: LED blink started\n", str)); 1471 } else { 1472 xcppm_freeze_led((void *)PPM_LEDON); 1473 DPRINTF(D_LOWEST, ("%s: LED freeze ON\n", str)); 1474 } 1475 return (DDI_SUCCESS); 1476 1477 case PMR_PPM_POST_ATTACH: 1478 /* 1479 * After a successful attach, if we haven't already created 1480 * our private data structure for this device, ppm_get_dev() 1481 * will force it to be created. 1482 */ 1483 ppmd = PPM_GET_PRIVATE(rdip); 1484 if (reqp->req.ppm_config_req.result != DDI_SUCCESS) { 1485 if (ppmd) 1486 ppm_rem_dev(rdip); 1487 } else if (!ppmd) { 1488 domp = ppm_lookup_dev(rdip); 1489 ASSERT(domp); 1490 (void) ppm_get_dev(rdip, domp); 1491 } 1492 return (DDI_SUCCESS); 1493 1494 case PMR_PPM_POST_DETACH: 1495 xcppm_detach_ctlop(rdip, reqp); 1496 *(int *)result = DDI_SUCCESS; 1497 return (DDI_SUCCESS); 1498 1499 case PMR_PPM_PRE_RESUME: 1500 xcppm_resume_ctlop(rdip, reqp); 1501 return (DDI_SUCCESS); 1502 1503 case PMR_PPM_UNLOCK_POWER: 1504 case PMR_PPM_TRY_LOCK_POWER: 1505 case PMR_PPM_LOCK_POWER: 1506 ppmd = PPM_GET_PRIVATE(rdip); 1507 if (ppmd) 1508 domp = ppmd->domp; 1509 else if (reqp->request_type != PMR_PPM_UNLOCK_POWER) { 1510 domp = ppm_lookup_dev(rdip); 1511 ASSERT(domp); 1512 ppmd = ppm_get_dev(rdip, domp); 1513 } 1514 1515 ASSERT(domp->dflags == PPMD_LOCK_ALL || 1516 domp->dflags == PPMD_LOCK_ONE); 1517 DPRINTF(D_LOCKS, ("xcppm_lock_%s: \"%s\", %s\n", 1518 (domp->dflags == PPMD_LOCK_ALL) ? "all" : "one", 1519 ppmd->path, ppm_get_ctlstr(reqp->request_type, D_LOCKS))); 1520 1521 if (domp->dflags == PPMD_LOCK_ALL) 1522 xcppm_lock_all(domp, reqp, result); 1523 else 1524 xcppm_lock_one(ppmd, reqp, result); 1525 return (DDI_SUCCESS); 1526 1527 case PMR_PPM_POWER_LOCK_OWNER: 1528 ASSERT(reqp->req.ppm_power_lock_owner_req.who == rdip); 1529 ppmd = PPM_GET_PRIVATE(rdip); 1530 if (ppmd) 1531 domp = ppmd->domp; 1532 else { 1533 domp = ppm_lookup_dev(rdip); 1534 ASSERT(domp); 1535 ppmd = ppm_get_dev(rdip, domp); 1536 } 1537 1538 /* 1539 * In case of LOCK_ALL, effective owner of the power lock 1540 * is the owner of the domain lock. otherwise, it is the owner 1541 * of the power lock. 1542 */ 1543 if (domp->dflags & PPMD_LOCK_ALL) 1544 reqp->req.ppm_power_lock_owner_req.owner = 1545 mutex_owner(&domp->lock); 1546 else { 1547 reqp->req.ppm_power_lock_owner_req.owner = 1548 DEVI(rdip)->devi_busy_thread; 1549 } 1550 return (DDI_SUCCESS); 1551 1552 default: 1553 ppmd = PPM_GET_PRIVATE(rdip); 1554 if (ppmd == NULL) { 1555 domp = ppm_lookup_dev(rdip); 1556 ASSERT(domp); 1557 ppmd = ppm_get_dev(rdip, domp); 1558 } 1559 1560 #ifdef DEBUG 1561 if ((reqp->request_type == PMR_PPM_SET_POWER) && 1562 (ppm_debug & D_SETPWR)) { 1563 prom_printf("%s: \"%s\", PMR_PPM_SET_POWER\n", 1564 str, ppmd->path); 1565 } 1566 #endif 1567 1568 if (ppmd->domp == &xcppm_cpu) 1569 return (xcppm_manage_cpus(rdip, reqp, result)); 1570 else if (ppmd->domp == &xcppm_fet) 1571 return (xcppm_manage_fet(rdip, reqp, result)); 1572 else if (ppmd->domp == &xcppm_upa) 1573 return (xcppm_manage_pciupa(rdip, reqp, result)); 1574 else { 1575 ASSERT(ppmd->domp == &xcppm_1394); 1576 return (xcppm_manage_1394(rdip, reqp, result)); 1577 } 1578 } 1579 } 1580 1581 1582 /* 1583 * Initialize our private version of real power level 1584 * as well as lowest and highest levels the device supports; 1585 * see ppmf and ppm_add_dev 1586 */ 1587 static void 1588 xcppm_dev_init(ppm_dev_t *ppmd) 1589 { 1590 struct pm_component *dcomps; 1591 struct pm_comp *pm_comp; 1592 dev_info_t *dip; 1593 int maxi; 1594 1595 ASSERT(MUTEX_HELD(&ppmd->domp->lock)); 1596 ppmd->level = PM_LEVEL_UNKNOWN; 1597 ppmd->rplvl = PM_LEVEL_UNKNOWN; 1598 1599 dip = ppmd->dip; 1600 /* 1601 * ppm exists to handle power-manageable devices which require 1602 * special handling on the current platform. However, a 1603 * driver for such a device may choose not to support power 1604 * management on a particular load/attach. In this case we 1605 * we create a structure to represent a single-component device 1606 * for which "level" = PM_LEVEL_UNKNOWN and "lowest" = 0 1607 * are effectively constant. 1608 */ 1609 if (PM_GET_PM_INFO(dip)) { 1610 dcomps = DEVI(dip)->devi_pm_components; 1611 pm_comp = &dcomps[ppmd->cmpt].pmc_comp; 1612 1613 ppmd->lowest = pm_comp->pmc_lvals[0]; 1614 ASSERT(ppmd->lowest >= 0); 1615 maxi = pm_comp->pmc_numlevels - 1; 1616 ppmd->highest = pm_comp->pmc_lvals[maxi]; 1617 } 1618 1619 /* 1620 * add any domain-specific initialization here 1621 */ 1622 if (ppmd->domp == &xcppm_fet) { 1623 /* 1624 * when a new device is added to domain_powefet 1625 * it is counted here as being powered up. 1626 */ 1627 ppmd->domp->pwr_cnt++; 1628 DPRINTF(D_FET, ("xcppm_dev_init: UP cnt = %d\n", 1629 ppmd->domp->pwr_cnt)); 1630 } else if (ppmd->domp == &xcppm_upa) { 1631 /* 1632 * There may be a better way to determine the device type 1633 * instead of comparing to hard coded string names. 1634 */ 1635 if (strstr(ppmd->path, "pci@8,700000")) 1636 ppmd->flags = XCPPMF_PCIB; 1637 else if (strstr(ppmd->path, "upa@8,480000")) 1638 ppmd->flags = XCPPMF_UPA; 1639 } 1640 } 1641 1642 1643 /* 1644 * see ppmf and ppm_rem_dev 1645 */ 1646 static void 1647 xcppm_dev_fini(ppm_dev_t *ppmd) 1648 { 1649 ASSERT(MUTEX_HELD(&ppmd->domp->lock)); 1650 if (ppmd->domp == &xcppm_fet) { 1651 if (ppmd->level != ppmd->lowest) { 1652 ppmd->domp->pwr_cnt--; 1653 DPRINTF(D_FET, ("xcppm_dev_fini: DN cnt = %d\n", 1654 ppmd->domp->pwr_cnt)); 1655 }; 1656 } 1657 } 1658 1659 1660 /* 1661 * see ppmf and ppm_ioctl, PPMIOCSET 1662 */ 1663 static void 1664 xcppm_iocset(uint8_t value) 1665 { 1666 int action; 1667 1668 if (value == PPM_IDEV_POWER_ON) 1669 action = XCPPM_SETBIT; 1670 else if (value == PPM_IDEV_POWER_OFF) 1671 action = XCPPM_CLRBIT; 1672 (void) xcppm_gpio_port2(action, DRVON); 1673 } 1674 1675 1676 /* 1677 * see ppmf and ppm_ioctl, PPMIOCGET 1678 */ 1679 static uint8_t 1680 xcppm_iocget(void) 1681 { 1682 uint8_t bit; 1683 1684 bit = xcppm_gpio_port2(XCPPM_GETBIT, DRVON); 1685 return ((bit == DRVON) ? PPM_IDEV_POWER_ON : PPM_IDEV_POWER_OFF); 1686 } 1687