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 /* 23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2019 Joyent, Inc. 25 * Copyright 2023 Oxide Computer Company 26 */ 27 28 /* 29 * This file contains Standard PCI Express HotPlug functionality that is 30 * compatible with the PCI Express ver 1.1 specification. 31 * 32 * NOTE: This file is compiled and delivered through misc/pcie module. 33 */ 34 35 #include <sys/types.h> 36 #include <sys/note.h> 37 #include <sys/conf.h> 38 #include <sys/kmem.h> 39 #include <sys/debug.h> 40 #include <sys/vtrace.h> 41 #include <sys/autoconf.h> 42 #include <sys/varargs.h> 43 #include <sys/ddi_impldefs.h> 44 #include <sys/time.h> 45 #include <sys/callb.h> 46 #include <sys/ddi.h> 47 #include <sys/sunddi.h> 48 #include <sys/sunndi.h> 49 #include <sys/sysevent/dr.h> 50 #include <sys/pci_impl.h> 51 #include <sys/hotplug/pci/pcie_hp.h> 52 #include <sys/hotplug/pci/pciehpc.h> 53 54 typedef struct pciehpc_prop { 55 char *prop_name; 56 char *prop_value; 57 } pciehpc_prop_t; 58 59 static pciehpc_prop_t pciehpc_props[] = { 60 { PCIEHPC_PROP_LED_FAULT, PCIEHPC_PROP_VALUE_LED }, 61 { PCIEHPC_PROP_LED_POWER, PCIEHPC_PROP_VALUE_LED }, 62 { PCIEHPC_PROP_LED_ATTN, PCIEHPC_PROP_VALUE_LED }, 63 { PCIEHPC_PROP_LED_ACTIVE, PCIEHPC_PROP_VALUE_LED }, 64 { PCIEHPC_PROP_CARD_TYPE, PCIEHPC_PROP_VALUE_TYPE }, 65 { PCIEHPC_PROP_BOARD_TYPE, PCIEHPC_PROP_VALUE_TYPE }, 66 { PCIEHPC_PROP_SLOT_CONDITION, PCIEHPC_PROP_VALUE_TYPE } 67 }; 68 69 /* Local functions prototype */ 70 static int pciehpc_hpc_init(pcie_hp_ctrl_t *ctrl_p); 71 static int pciehpc_hpc_uninit(pcie_hp_ctrl_t *ctrl_p); 72 static int pciehpc_slotinfo_init(pcie_hp_ctrl_t *ctrl_p); 73 static int pciehpc_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p); 74 static int pciehpc_enable_intr(pcie_hp_ctrl_t *ctrl_p); 75 static int pciehpc_disable_intr(pcie_hp_ctrl_t *ctrl_p); 76 static pcie_hp_ctrl_t *pciehpc_create_controller(dev_info_t *dip); 77 static void pciehpc_destroy_controller(dev_info_t *dip); 78 static int pciehpc_register_slot(pcie_hp_ctrl_t *ctrl_p); 79 static int pciehpc_unregister_slot(pcie_hp_ctrl_t *ctrl_p); 80 static int pciehpc_slot_get_property(pcie_hp_slot_t *slot_p, 81 ddi_hp_property_t *arg, ddi_hp_property_t *rval); 82 static int pciehpc_slot_set_property(pcie_hp_slot_t *slot_p, 83 ddi_hp_property_t *arg, ddi_hp_property_t *rval); 84 static void pciehpc_issue_hpc_command(pcie_hp_ctrl_t *ctrl_p, uint16_t control); 85 static void pciehpc_attn_btn_handler(pcie_hp_ctrl_t *ctrl_p); 86 static pcie_hp_led_state_t pciehpc_led_state_to_hpc(uint16_t state); 87 static pcie_hp_led_state_t pciehpc_get_led_state(pcie_hp_ctrl_t *ctrl_p, 88 pcie_hp_led_t led); 89 static void pciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led, 90 pcie_hp_led_state_t state); 91 92 static int pciehpc_upgrade_slot_state(pcie_hp_slot_t *slot_p, 93 ddi_hp_cn_state_t target_state); 94 static int pciehpc_downgrade_slot_state(pcie_hp_slot_t *slot_p, 95 ddi_hp_cn_state_t target_state); 96 static int pciehpc_change_slot_state(pcie_hp_slot_t *slot_p, 97 ddi_hp_cn_state_t target_state); 98 static int 99 pciehpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result); 100 static int 101 pciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result); 102 static int pciehpc_slot_probe(pcie_hp_slot_t *slot_p); 103 static int pciehpc_slot_unprobe(pcie_hp_slot_t *slot_p); 104 static void pciehpc_handle_power_fault(dev_info_t *dip); 105 static void pciehpc_power_fault_handler(void *arg); 106 107 #ifdef DEBUG 108 static void pciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p); 109 #endif /* DEBUG */ 110 111 /* 112 * Global functions (called by other drivers/modules) 113 */ 114 115 /* 116 * Initialize Hot Plug Controller if present. The arguments are: 117 * dip - Devinfo node pointer to the hot plug bus node 118 * regops - register ops to access HPC registers for non-standard 119 * HPC hw implementations (e.g: HPC in host PCI-E brdiges) 120 * This is NULL for standard HPC in PCIe bridges. 121 * Returns: 122 * DDI_SUCCESS for successful HPC initialization 123 * DDI_FAILURE for errors or if HPC hw not found 124 */ 125 int 126 pciehpc_init(dev_info_t *dip, caddr_t arg) 127 { 128 pcie_hp_regops_t *regops = (pcie_hp_regops_t *)(void *)arg; 129 pcie_hp_ctrl_t *ctrl_p; 130 131 PCIE_DBG("pciehpc_init() called (dip=%p)\n", (void *)dip); 132 133 /* Make sure that it is not already initialized */ 134 if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) != NULL) { 135 PCIE_DBG("%s%d: pciehpc instance already initialized!\n", 136 ddi_driver_name(dip), ddi_get_instance(dip)); 137 return (DDI_SUCCESS); 138 } 139 140 /* Allocate a new hotplug controller and slot structures */ 141 ctrl_p = pciehpc_create_controller(dip); 142 143 /* setup access handle for HPC regs */ 144 if (regops != NULL) { 145 /* HPC access is non-standard; use the supplied reg ops */ 146 ctrl_p->hc_regops = *regops; 147 } 148 149 /* 150 * Setup resource maps for this bus node. 151 */ 152 (void) pci_resource_setup(dip); 153 154 PCIE_DISABLE_ERRORS(dip); 155 156 /* 157 * Set the platform specific hot plug mode. 158 */ 159 ctrl_p->hc_ops.init_hpc_hw = pciehpc_hpc_init; 160 ctrl_p->hc_ops.uninit_hpc_hw = pciehpc_hpc_uninit; 161 ctrl_p->hc_ops.init_hpc_slotinfo = pciehpc_slotinfo_init; 162 ctrl_p->hc_ops.uninit_hpc_slotinfo = pciehpc_slotinfo_uninit; 163 ctrl_p->hc_ops.poweron_hpc_slot = pciehpc_slot_poweron; 164 ctrl_p->hc_ops.poweroff_hpc_slot = pciehpc_slot_poweroff; 165 166 ctrl_p->hc_ops.enable_hpc_intr = pciehpc_enable_intr; 167 ctrl_p->hc_ops.disable_hpc_intr = pciehpc_disable_intr; 168 169 #if defined(__x86) 170 pciehpc_update_ops(ctrl_p); 171 #endif 172 173 /* initialize hot plug controller hw */ 174 if ((ctrl_p->hc_ops.init_hpc_hw)(ctrl_p) != DDI_SUCCESS) 175 goto cleanup1; 176 177 /* initialize slot information soft state structure */ 178 if ((ctrl_p->hc_ops.init_hpc_slotinfo)(ctrl_p) != DDI_SUCCESS) 179 goto cleanup2; 180 181 /* register the hot plug slot with DDI HP framework */ 182 if (pciehpc_register_slot(ctrl_p) != DDI_SUCCESS) 183 goto cleanup3; 184 185 /* create minor node for this slot */ 186 if (pcie_create_minor_node(ctrl_p, 0) != DDI_SUCCESS) 187 goto cleanup4; 188 189 /* HPC initialization is complete now */ 190 ctrl_p->hc_flags = PCIE_HP_INITIALIZED_FLAG; 191 192 #ifdef DEBUG 193 /* For debug, dump the HPC registers */ 194 pciehpc_dump_hpregs(ctrl_p); 195 #endif /* DEBUG */ 196 197 return (DDI_SUCCESS); 198 cleanup4: 199 (void) pciehpc_unregister_slot(ctrl_p); 200 cleanup3: 201 (void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p); 202 203 cleanup2: 204 (void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p); 205 206 cleanup1: 207 PCIE_ENABLE_ERRORS(dip); 208 (void) pci_resource_destroy(dip); 209 210 pciehpc_destroy_controller(dip); 211 return (DDI_FAILURE); 212 } 213 214 /* 215 * Uninitialize HPC soft state structure and free up any resources 216 * used for the HPC instance. 217 */ 218 int 219 pciehpc_uninit(dev_info_t *dip) 220 { 221 pcie_hp_ctrl_t *ctrl_p; 222 223 PCIE_DBG("pciehpc_uninit() called (dip=%p)\n", (void *)dip); 224 225 /* get the soft state structure for this dip */ 226 if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) { 227 return (DDI_FAILURE); 228 } 229 230 pcie_remove_minor_node(ctrl_p, 0); 231 232 /* unregister the slot */ 233 (void) pciehpc_unregister_slot(ctrl_p); 234 235 /* uninit any slot info data structures */ 236 (void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p); 237 238 /* uninitialize hpc, remove interrupt handler, etc. */ 239 (void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p); 240 241 PCIE_ENABLE_ERRORS(dip); 242 243 /* 244 * Destroy resource maps for this bus node. 245 */ 246 (void) pci_resource_destroy(dip); 247 248 /* destroy the soft state structure */ 249 pciehpc_destroy_controller(dip); 250 251 return (DDI_SUCCESS); 252 } 253 254 /* 255 * pciehpc_intr() 256 * 257 * Interrupt handler for PCI-E Hot plug controller interrupts. 258 * 259 * Note: This is only for native mode hot plug. This is called 260 * by the nexus driver at interrupt context. Interrupt Service Routine 261 * registration is done by the nexus driver for both hot plug and 262 * non-hot plug interrupts. This function is called from the ISR 263 * of the nexus driver to handle hot-plug interrupts. 264 */ 265 int 266 pciehpc_intr(dev_info_t *dip) 267 { 268 pcie_hp_ctrl_t *ctrl_p; 269 pcie_hp_slot_t *slot_p; 270 pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 271 uint16_t status, control; 272 273 /* get the soft state structure for this dip */ 274 if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) 275 return (DDI_INTR_UNCLAIMED); 276 277 mutex_enter(&ctrl_p->hc_mutex); 278 279 /* make sure the controller soft state is initialized */ 280 if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) { 281 mutex_exit(&ctrl_p->hc_mutex); 282 return (DDI_INTR_UNCLAIMED); 283 } 284 285 /* if it is not NATIVE hot plug mode then return */ 286 if (bus_p->bus_hp_curr_mode != PCIE_NATIVE_HP_MODE) { 287 mutex_exit(&ctrl_p->hc_mutex); 288 return (DDI_INTR_UNCLAIMED); 289 } 290 291 slot_p = ctrl_p->hc_slots[0]; 292 293 /* read the current slot status register */ 294 status = pciehpc_reg_get16(ctrl_p, 295 bus_p->bus_pcie_off + PCIE_SLOTSTS); 296 297 /* check if there are any hot plug interrupts occurred */ 298 if (!(status & PCIE_SLOTSTS_STATUS_EVENTS)) { 299 /* no hot plug events occurred */ 300 mutex_exit(&ctrl_p->hc_mutex); 301 return (DDI_INTR_UNCLAIMED); 302 } 303 304 /* clear the interrupt status bits */ 305 pciehpc_reg_put16(ctrl_p, 306 bus_p->bus_pcie_off + PCIE_SLOTSTS, status); 307 308 /* check for CMD COMPLETE interrupt */ 309 if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) { 310 PCIE_DBG("pciehpc_intr(): CMD COMPLETED interrupt received\n"); 311 /* wake up any one waiting for Command Completion event */ 312 cv_signal(&ctrl_p->hc_cmd_comp_cv); 313 } 314 315 /* check for ATTN button interrupt */ 316 if (status & PCIE_SLOTSTS_ATTN_BTN_PRESSED) { 317 PCIE_DBG("pciehpc_intr(): ATTN BUTTON interrupt received\n"); 318 319 /* if ATTN button event is still pending then cancel it */ 320 if (slot_p->hs_attn_btn_pending == B_TRUE) 321 slot_p->hs_attn_btn_pending = B_FALSE; 322 else 323 slot_p->hs_attn_btn_pending = B_TRUE; 324 325 /* wake up the ATTN event handler */ 326 cv_signal(&slot_p->hs_attn_btn_cv); 327 } 328 329 /* check for power fault interrupt */ 330 if (status & PCIE_SLOTSTS_PWR_FAULT_DETECTED) { 331 332 PCIE_DBG("pciehpc_intr(): POWER FAULT interrupt received" 333 " on slot %d\n", slot_p->hs_phy_slot_num); 334 control = pciehpc_reg_get16(ctrl_p, 335 bus_p->bus_pcie_off + PCIE_SLOTCTL); 336 337 if (control & PCIE_SLOTCTL_PWR_FAULT_EN) { 338 slot_p->hs_condition = AP_COND_FAILED; 339 340 /* disable power fault detction interrupt */ 341 pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + 342 PCIE_SLOTCTL, control & ~PCIE_SLOTCTL_PWR_FAULT_EN); 343 344 pciehpc_handle_power_fault(dip); 345 } 346 } 347 348 /* check for MRL SENSOR CHANGED interrupt */ 349 if (status & PCIE_SLOTSTS_MRL_SENSOR_CHANGED) { 350 /* For now (phase-I), no action is taken on this event */ 351 PCIE_DBG("pciehpc_intr(): MRL SENSOR CHANGED interrupt received" 352 " on slot %d\n", slot_p->hs_phy_slot_num); 353 } 354 355 /* check for PRESENCE CHANGED interrupt */ 356 if (status & PCIE_SLOTSTS_PRESENCE_CHANGED) { 357 358 PCIE_DBG("pciehpc_intr(): PRESENCE CHANGED interrupt received" 359 " on slot %d\n", slot_p->hs_phy_slot_num); 360 361 if (status & PCIE_SLOTSTS_PRESENCE_DETECTED) { 362 /* 363 * card is inserted into the slot, ask DDI Hotplug 364 * framework to change state to Present. 365 */ 366 cmn_err(CE_NOTE, "pciehpc (%s%d): card is inserted" 367 " in the slot %s", 368 ddi_driver_name(dip), 369 ddi_get_instance(dip), 370 slot_p->hs_info.cn_name); 371 372 (void) ndi_hp_state_change_req(dip, 373 slot_p->hs_info.cn_name, 374 DDI_HP_CN_STATE_PRESENT, 375 DDI_HP_REQ_ASYNC); 376 } else { /* card is removed from the slot */ 377 cmn_err(CE_NOTE, "pciehpc (%s%d): card is removed" 378 " from the slot %s", 379 ddi_driver_name(dip), 380 ddi_get_instance(dip), 381 slot_p->hs_info.cn_name); 382 383 if (slot_p->hs_info.cn_state == 384 DDI_HP_CN_STATE_ENABLED) { 385 /* Card is removed when slot is enabled */ 386 slot_p->hs_condition = AP_COND_FAILED; 387 } else { 388 slot_p->hs_condition = AP_COND_UNKNOWN; 389 } 390 /* make sure to disable power fault detction intr */ 391 control = pciehpc_reg_get16(ctrl_p, 392 bus_p->bus_pcie_off + PCIE_SLOTCTL); 393 394 if (control & PCIE_SLOTCTL_PWR_FAULT_EN) 395 pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + 396 PCIE_SLOTCTL, 397 control & ~PCIE_SLOTCTL_PWR_FAULT_EN); 398 399 /* 400 * If supported, notify the child device driver that the 401 * device is being removed. 402 */ 403 dev_info_t *cdip = ddi_get_child(dip); 404 if (cdip != NULL) { 405 ddi_eventcookie_t rm_cookie; 406 if (ddi_get_eventcookie(cdip, 407 DDI_DEVI_REMOVE_EVENT, 408 &rm_cookie) == DDI_SUCCESS) { 409 ndi_post_event(dip, cdip, rm_cookie, 410 NULL); 411 } 412 } 413 414 /* 415 * Ask DDI Hotplug framework to change state to Empty 416 */ 417 (void) ndi_hp_state_change_req(dip, 418 slot_p->hs_info.cn_name, 419 DDI_HP_CN_STATE_EMPTY, 420 DDI_HP_REQ_ASYNC); 421 } 422 } 423 424 /* check for DLL state changed interrupt */ 425 if (ctrl_p->hc_dll_active_rep && 426 (status & PCIE_SLOTSTS_DLL_STATE_CHANGED)) { 427 PCIE_DBG("pciehpc_intr(): DLL STATE CHANGED interrupt received" 428 " on slot %d\n", slot_p->hs_phy_slot_num); 429 430 cv_signal(&slot_p->hs_dll_active_cv); 431 } 432 433 mutex_exit(&ctrl_p->hc_mutex); 434 435 return (DDI_INTR_CLAIMED); 436 } 437 438 /* 439 * Handle hotplug commands 440 * 441 * Note: This function is called by DDI HP framework at kernel context only 442 */ 443 /* ARGSUSED */ 444 int 445 pciehpc_hp_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op, 446 void *arg, void *result) 447 { 448 pcie_hp_ctrl_t *ctrl_p; 449 pcie_hp_slot_t *slot_p; 450 int ret = DDI_SUCCESS; 451 452 PCIE_DBG("pciehpc_hp_ops: dip=%p cn_name=%s op=%x arg=%p\n", 453 dip, cn_name, op, arg); 454 455 if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) 456 return (DDI_FAILURE); 457 458 slot_p = ctrl_p->hc_slots[0]; 459 460 if (strcmp(cn_name, slot_p->hs_info.cn_name) != 0) 461 return (DDI_EINVAL); 462 463 switch (op) { 464 case DDI_HPOP_CN_GET_STATE: 465 { 466 mutex_enter(&slot_p->hs_ctrl->hc_mutex); 467 468 /* get the current slot state */ 469 pciehpc_get_slot_state(slot_p); 470 471 *((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state; 472 473 mutex_exit(&slot_p->hs_ctrl->hc_mutex); 474 break; 475 } 476 case DDI_HPOP_CN_CHANGE_STATE: 477 { 478 ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg; 479 480 mutex_enter(&slot_p->hs_ctrl->hc_mutex); 481 482 ret = pciehpc_change_slot_state(slot_p, target_state); 483 *(ddi_hp_cn_state_t *)result = slot_p->hs_info.cn_state; 484 485 mutex_exit(&slot_p->hs_ctrl->hc_mutex); 486 break; 487 } 488 case DDI_HPOP_CN_PROBE: 489 490 ret = pciehpc_slot_probe(slot_p); 491 492 break; 493 case DDI_HPOP_CN_UNPROBE: 494 ret = pciehpc_slot_unprobe(slot_p); 495 496 break; 497 case DDI_HPOP_CN_GET_PROPERTY: 498 ret = pciehpc_slot_get_property(slot_p, 499 (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result); 500 break; 501 case DDI_HPOP_CN_SET_PROPERTY: 502 ret = pciehpc_slot_set_property(slot_p, 503 (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result); 504 break; 505 default: 506 ret = DDI_ENOTSUP; 507 break; 508 } 509 510 return (ret); 511 } 512 513 /* 514 * Get the current state of the slot from the hw. 515 * 516 * The slot state should have been initialized before this function gets called. 517 */ 518 void 519 pciehpc_get_slot_state(pcie_hp_slot_t *slot_p) 520 { 521 pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; 522 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 523 uint16_t control, status; 524 ddi_hp_cn_state_t curr_state = slot_p->hs_info.cn_state; 525 526 /* read the Slot Control Register */ 527 control = pciehpc_reg_get16(ctrl_p, 528 bus_p->bus_pcie_off + PCIE_SLOTCTL); 529 530 slot_p->hs_fault_led_state = PCIE_HP_LED_OFF; /* no fault led */ 531 slot_p->hs_active_led_state = PCIE_HP_LED_OFF; /* no active led */ 532 533 /* read the current Slot Status Register */ 534 status = pciehpc_reg_get16(ctrl_p, 535 bus_p->bus_pcie_off + PCIE_SLOTSTS); 536 537 /* get POWER led state */ 538 slot_p->hs_power_led_state = 539 pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control)); 540 541 /* get ATTN led state */ 542 slot_p->hs_attn_led_state = 543 pciehpc_led_state_to_hpc(pcie_slotctl_attn_indicator_get(control)); 544 545 if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) { 546 /* no device present; slot is empty */ 547 slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY; 548 549 return; 550 } 551 552 /* device is present */ 553 slot_p->hs_info.cn_state = DDI_HP_CN_STATE_PRESENT; 554 555 if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) { 556 /* 557 * Device is powered on. Set to "ENABLED" state (skip 558 * POWERED state) because there is not a explicit "enable" 559 * action exists for PCIe. 560 * If it is already in "POWERED" state, then keep it until 561 * user explicitly change it to other states. 562 */ 563 if (curr_state == DDI_HP_CN_STATE_POWERED) { 564 slot_p->hs_info.cn_state = curr_state; 565 } else { 566 slot_p->hs_info.cn_state = DDI_HP_CN_STATE_ENABLED; 567 } 568 } 569 } 570 571 /* 572 * setup slot name/slot-number info. 573 */ 574 void 575 pciehpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p) 576 { 577 pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; 578 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 579 uchar_t *slotname_data; 580 int *slotnum; 581 uint_t count; 582 int len; 583 int invalid_slotnum = 0; 584 uint32_t slot_capabilities; 585 586 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ctrl_p->hc_dip, 587 DDI_PROP_DONTPASS, "physical-slot#", &slotnum, &count) == 588 DDI_PROP_SUCCESS) { 589 slot_p->hs_phy_slot_num = slotnum[0]; 590 ddi_prop_free(slotnum); 591 } else { 592 slot_capabilities = pciehpc_reg_get32(ctrl_p, 593 bus_p->bus_pcie_off + PCIE_SLOTCAP); 594 slot_p->hs_phy_slot_num = 595 PCIE_SLOTCAP_PHY_SLOT_NUM(slot_capabilities); 596 } 597 598 /* platform may not have initialized it */ 599 if (!slot_p->hs_phy_slot_num) { 600 PCIE_DBG("%s#%d: Invalid slot number!\n", 601 ddi_driver_name(ctrl_p->hc_dip), 602 ddi_get_instance(ctrl_p->hc_dip)); 603 slot_p->hs_phy_slot_num = pciehpc_reg_get8(ctrl_p, 604 PCI_BCNF_SECBUS); 605 invalid_slotnum = 1; 606 } 607 slot_p->hs_info.cn_num = slot_p->hs_phy_slot_num; 608 slot_p->hs_info.cn_num_dpd_on = DDI_HP_CN_NUM_NONE; 609 610 /* 611 * construct the slot_name: 612 * if "slot-names" property exists then use that name 613 * else if valid slot number exists then it is "pcie<slot-num>". 614 * else it will be "pcie<sec-bus-number>dev0" 615 */ 616 if (ddi_getlongprop(DDI_DEV_T_ANY, ctrl_p->hc_dip, DDI_PROP_DONTPASS, 617 "slot-names", (caddr_t)&slotname_data, &len) == DDI_PROP_SUCCESS) { 618 char tmp_name[256]; 619 620 /* 621 * Note: for PCI-E slots, the device number is always 0 so the 622 * first (and only) string is the slot name for this slot. 623 */ 624 (void) snprintf(tmp_name, sizeof (tmp_name), 625 (char *)slotname_data + 4); 626 slot_p->hs_info.cn_name = ddi_strdup(tmp_name, KM_SLEEP); 627 kmem_free(slotname_data, len); 628 } else { 629 if (invalid_slotnum) { 630 /* use device number ie. 0 */ 631 slot_p->hs_info.cn_name = ddi_strdup("pcie0", 632 KM_SLEEP); 633 } else { 634 char tmp_name[256]; 635 636 (void) snprintf(tmp_name, sizeof (tmp_name), "pcie%d", 637 slot_p->hs_phy_slot_num); 638 slot_p->hs_info.cn_name = ddi_strdup(tmp_name, 639 KM_SLEEP); 640 } 641 } 642 } 643 644 /* 645 * Read/Write access to HPC registers. If platform nexus has non-standard 646 * HPC access mechanism then regops functions are used to do reads/writes. 647 */ 648 uint8_t 649 pciehpc_reg_get8(pcie_hp_ctrl_t *ctrl_p, uint_t off) 650 { 651 if (ctrl_p->hc_regops.get != NULL) { 652 return ((uint8_t)ctrl_p->hc_regops.get( 653 ctrl_p->hc_regops.cookie, (off_t)off)); 654 } else { 655 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 656 657 return (pci_config_get8(bus_p->bus_cfg_hdl, off)); 658 } 659 } 660 661 uint16_t 662 pciehpc_reg_get16(pcie_hp_ctrl_t *ctrl_p, uint_t off) 663 { 664 if (ctrl_p->hc_regops.get != NULL) { 665 return ((uint16_t)ctrl_p->hc_regops.get( 666 ctrl_p->hc_regops.cookie, (off_t)off)); 667 } else { 668 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 669 670 return (pci_config_get16(bus_p->bus_cfg_hdl, off)); 671 } 672 } 673 674 uint32_t 675 pciehpc_reg_get32(pcie_hp_ctrl_t *ctrl_p, uint_t off) 676 { 677 if (ctrl_p->hc_regops.get != NULL) { 678 return ((uint32_t)ctrl_p->hc_regops.get( 679 ctrl_p->hc_regops.cookie, (off_t)off)); 680 } else { 681 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 682 683 return (pci_config_get32(bus_p->bus_cfg_hdl, off)); 684 } 685 } 686 687 void 688 pciehpc_reg_put8(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint8_t val) 689 { 690 if (ctrl_p->hc_regops.put != NULL) { 691 ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie, 692 (off_t)off, (uint_t)val); 693 } else { 694 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 695 696 pci_config_put8(bus_p->bus_cfg_hdl, off, val); 697 } 698 } 699 700 void 701 pciehpc_reg_put16(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint16_t val) 702 { 703 if (ctrl_p->hc_regops.put != NULL) { 704 ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie, 705 (off_t)off, (uint_t)val); 706 } else { 707 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 708 709 pci_config_put16(bus_p->bus_cfg_hdl, off, val); 710 } 711 } 712 713 void 714 pciehpc_reg_put32(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint32_t val) 715 { 716 if (ctrl_p->hc_regops.put != NULL) { 717 ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie, 718 (off_t)off, (uint_t)val); 719 } else { 720 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 721 722 pci_config_put32(bus_p->bus_cfg_hdl, off, val); 723 } 724 } 725 726 /* 727 * ************************************************************************ 728 * *** Local functions (called within this file) 729 * *** PCIe Native Hotplug mode specific functions 730 * ************************************************************************ 731 */ 732 733 /* 734 * Initialize HPC hardware, install interrupt handler, etc. It doesn't 735 * enable hot plug interrupts. 736 * 737 * (Note: It is called only from pciehpc_init().) 738 */ 739 static int 740 pciehpc_hpc_init(pcie_hp_ctrl_t *ctrl_p) 741 { 742 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 743 uint16_t reg; 744 745 /* read the Slot Control Register */ 746 reg = pciehpc_reg_get16(ctrl_p, 747 bus_p->bus_pcie_off + PCIE_SLOTCTL); 748 749 /* disable all interrupts */ 750 reg &= ~(PCIE_SLOTCTL_INTR_MASK); 751 pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + 752 PCIE_SLOTCTL, reg); 753 754 /* clear any interrupt status bits */ 755 reg = pciehpc_reg_get16(ctrl_p, 756 bus_p->bus_pcie_off + PCIE_SLOTSTS); 757 pciehpc_reg_put16(ctrl_p, 758 bus_p->bus_pcie_off + PCIE_SLOTSTS, reg); 759 760 return (DDI_SUCCESS); 761 } 762 763 /* 764 * Uninitialize HPC hardware, uninstall interrupt handler, etc. 765 * 766 * (Note: It is called only from pciehpc_uninit().) 767 */ 768 static int 769 pciehpc_hpc_uninit(pcie_hp_ctrl_t *ctrl_p) 770 { 771 /* disable interrupts */ 772 (void) pciehpc_disable_intr(ctrl_p); 773 774 return (DDI_SUCCESS); 775 } 776 777 /* 778 * Setup slot information for use with DDI HP framework. 779 */ 780 static int 781 pciehpc_slotinfo_init(pcie_hp_ctrl_t *ctrl_p) 782 { 783 uint32_t slot_capabilities, link_capabilities; 784 pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; 785 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 786 787 mutex_enter(&ctrl_p->hc_mutex); 788 /* 789 * setup DDI HP framework slot information structure 790 */ 791 slot_p->hs_device_num = 0; 792 793 slot_p->hs_info.cn_type = DDI_HP_CN_TYPE_PCIE; 794 slot_p->hs_info.cn_type_str = (ctrl_p->hc_regops.get == NULL) ? 795 PCIE_NATIVE_HP_TYPE : PCIE_PROP_HP_TYPE; 796 slot_p->hs_info.cn_child = NULL; 797 798 slot_p->hs_minor = 799 PCI_MINOR_NUM(ddi_get_instance(ctrl_p->hc_dip), 800 slot_p->hs_device_num); 801 slot_p->hs_condition = AP_COND_UNKNOWN; 802 803 /* read Slot Capabilities Register */ 804 slot_capabilities = pciehpc_reg_get32(ctrl_p, 805 bus_p->bus_pcie_off + PCIE_SLOTCAP); 806 807 /* set slot-name/slot-number info */ 808 pciehpc_set_slot_name(ctrl_p); 809 810 /* check if Attn Button present */ 811 ctrl_p->hc_has_attn = (slot_capabilities & PCIE_SLOTCAP_ATTN_BUTTON) ? 812 B_TRUE : B_FALSE; 813 814 /* check if Manual Retention Latch sensor present */ 815 ctrl_p->hc_has_mrl = (slot_capabilities & PCIE_SLOTCAP_MRL_SENSOR) ? 816 B_TRUE : B_FALSE; 817 818 /* 819 * Contrary to what one might expect, not all systems actually have 820 * power control despite having hot-swap capabilities. This is most 821 * commonly due to the Enterprise SSD specification which doesn't call 822 * for power-control in the PCIe native hotplug implementation. 823 */ 824 ctrl_p->hc_has_pwr = (slot_capabilities & 825 PCIE_SLOTCAP_POWER_CONTROLLER) ? B_TRUE: B_FALSE; 826 827 /* 828 * PCI-E version 1.1 defines EMI Lock Present bit 829 * in Slot Capabilities register. Check for it. 830 */ 831 ctrl_p->hc_has_emi_lock = (slot_capabilities & 832 PCIE_SLOTCAP_EMI_LOCK_PRESENT) ? B_TRUE : B_FALSE; 833 834 link_capabilities = pciehpc_reg_get32(ctrl_p, 835 bus_p->bus_pcie_off + PCIE_LINKCAP); 836 ctrl_p->hc_dll_active_rep = (link_capabilities & 837 PCIE_LINKCAP_DLL_ACTIVE_REP_CAPABLE) ? B_TRUE : B_FALSE; 838 if (ctrl_p->hc_dll_active_rep) 839 cv_init(&slot_p->hs_dll_active_cv, NULL, CV_DRIVER, NULL); 840 841 /* setup thread for handling ATTN button events */ 842 if (ctrl_p->hc_has_attn) { 843 PCIE_DBG("pciehpc_slotinfo_init: setting up ATTN button event " 844 "handler thread for slot %d\n", slot_p->hs_phy_slot_num); 845 846 cv_init(&slot_p->hs_attn_btn_cv, NULL, CV_DRIVER, NULL); 847 slot_p->hs_attn_btn_pending = B_FALSE; 848 slot_p->hs_attn_btn_threadp = thread_create(NULL, 0, 849 pciehpc_attn_btn_handler, 850 (void *)ctrl_p, 0, &p0, TS_RUN, minclsyspri); 851 slot_p->hs_attn_btn_thread_exit = B_FALSE; 852 } 853 854 /* get current slot state from the hw */ 855 slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY; 856 pciehpc_get_slot_state(slot_p); 857 if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_ENABLED) 858 slot_p->hs_condition = AP_COND_OK; 859 860 mutex_exit(&ctrl_p->hc_mutex); 861 862 return (DDI_SUCCESS); 863 } 864 865 /*ARGSUSED*/ 866 static int 867 pciehpc_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p) 868 { 869 pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; 870 871 if (slot_p->hs_attn_btn_threadp != NULL) { 872 mutex_enter(&ctrl_p->hc_mutex); 873 slot_p->hs_attn_btn_thread_exit = B_TRUE; 874 cv_signal(&slot_p->hs_attn_btn_cv); 875 PCIE_DBG("pciehpc_slotinfo_uninit: " 876 "waiting for ATTN thread exit\n"); 877 cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex); 878 PCIE_DBG("pciehpc_slotinfo_uninit: ATTN thread exit\n"); 879 cv_destroy(&slot_p->hs_attn_btn_cv); 880 slot_p->hs_attn_btn_threadp = NULL; 881 mutex_exit(&ctrl_p->hc_mutex); 882 } 883 884 if (ctrl_p->hc_dll_active_rep) 885 cv_destroy(&slot_p->hs_dll_active_cv); 886 if (slot_p->hs_info.cn_name) 887 kmem_free(slot_p->hs_info.cn_name, 888 strlen(slot_p->hs_info.cn_name) + 1); 889 890 return (DDI_SUCCESS); 891 } 892 893 /* 894 * Enable hot plug interrupts. 895 * Note: this is only for Native hot plug mode. 896 */ 897 static int 898 pciehpc_enable_intr(pcie_hp_ctrl_t *ctrl_p) 899 { 900 pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; 901 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 902 uint16_t reg; 903 uint16_t intr_mask = PCIE_SLOTCTL_INTR_MASK; 904 905 /* 906 * power fault detection interrupt is enabled only 907 * when the slot is powered ON 908 */ 909 if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) 910 intr_mask &= ~PCIE_SLOTCTL_PWR_FAULT_EN; 911 912 /* 913 * enable interrupt sources but leave the top-level 914 * interrupt disabled. some sources may generate a 915 * spurrious event when they are first enabled. 916 * by leaving the top-level interrupt disabled, those 917 * can be cleared first. 918 */ 919 reg = pciehpc_reg_get16(ctrl_p, 920 bus_p->bus_pcie_off + PCIE_SLOTCTL); 921 pciehpc_reg_put16(ctrl_p, 922 bus_p->bus_pcie_off + PCIE_SLOTCTL, 923 reg | (intr_mask & ~PCIE_SLOTCTL_HP_INTR_EN)); 924 925 /* clear any interrupt status bits */ 926 reg = pciehpc_reg_get16(ctrl_p, 927 bus_p->bus_pcie_off + PCIE_SLOTSTS); 928 pciehpc_reg_put16(ctrl_p, 929 bus_p->bus_pcie_off + PCIE_SLOTSTS, reg); 930 931 /* enable top-level interrupt */ 932 reg = pciehpc_reg_get16(ctrl_p, 933 bus_p->bus_pcie_off + PCIE_SLOTCTL); 934 pciehpc_reg_put16(ctrl_p, 935 bus_p->bus_pcie_off + PCIE_SLOTCTL, 936 reg | intr_mask); 937 938 return (DDI_SUCCESS); 939 } 940 941 /* 942 * Disable hot plug interrupts. 943 * Note: this is only for Native hot plug mode. 944 */ 945 static int 946 pciehpc_disable_intr(pcie_hp_ctrl_t *ctrl_p) 947 { 948 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 949 uint16_t reg; 950 951 /* read the Slot Control Register */ 952 reg = pciehpc_reg_get16(ctrl_p, 953 bus_p->bus_pcie_off + PCIE_SLOTCTL); 954 955 /* disable all interrupts */ 956 reg &= ~(PCIE_SLOTCTL_INTR_MASK); 957 pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTCTL, reg); 958 959 /* clear any interrupt status bits */ 960 reg = pciehpc_reg_get16(ctrl_p, 961 bus_p->bus_pcie_off + PCIE_SLOTSTS); 962 pciehpc_reg_put16(ctrl_p, 963 bus_p->bus_pcie_off + PCIE_SLOTSTS, reg); 964 965 return (DDI_SUCCESS); 966 } 967 968 /* 969 * Allocate a new hotplug controller and slot structures for HPC 970 * associated with this dip. 971 */ 972 static pcie_hp_ctrl_t * 973 pciehpc_create_controller(dev_info_t *dip) 974 { 975 pcie_hp_ctrl_t *ctrl_p; 976 pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 977 978 ctrl_p = kmem_zalloc(sizeof (pcie_hp_ctrl_t), KM_SLEEP); 979 ctrl_p->hc_dip = dip; 980 981 /* Allocate a new slot structure. */ 982 ctrl_p->hc_slots[0] = kmem_zalloc(sizeof (pcie_hp_slot_t), KM_SLEEP); 983 ctrl_p->hc_slots[0]->hs_num = 0; 984 ctrl_p->hc_slots[0]->hs_ctrl = ctrl_p; 985 986 /* Initialize the interrupt mutex */ 987 mutex_init(&ctrl_p->hc_mutex, NULL, MUTEX_DRIVER, 988 (void *)PCIE_INTR_PRI); 989 990 /* Initialize synchronization conditional variable */ 991 cv_init(&ctrl_p->hc_cmd_comp_cv, NULL, CV_DRIVER, NULL); 992 ctrl_p->hc_cmd_pending = B_FALSE; 993 994 bus_p->bus_hp_curr_mode = PCIE_NATIVE_HP_MODE; 995 PCIE_SET_HP_CTRL(dip, ctrl_p); 996 997 return (ctrl_p); 998 } 999 1000 /* 1001 * Remove the HPC controller and slot structures 1002 */ 1003 static void 1004 pciehpc_destroy_controller(dev_info_t *dip) 1005 { 1006 pcie_hp_ctrl_t *ctrl_p; 1007 pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 1008 1009 /* get the soft state structure for this dip */ 1010 if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) 1011 return; 1012 1013 PCIE_SET_HP_CTRL(dip, NULL); 1014 bus_p->bus_hp_curr_mode = PCIE_NONE_HP_MODE; 1015 1016 mutex_destroy(&ctrl_p->hc_mutex); 1017 cv_destroy(&ctrl_p->hc_cmd_comp_cv); 1018 kmem_free(ctrl_p->hc_slots[0], sizeof (pcie_hp_slot_t)); 1019 kmem_free(ctrl_p, sizeof (pcie_hp_ctrl_t)); 1020 } 1021 1022 /* 1023 * Register the PCI-E hot plug slot with DDI HP framework. 1024 */ 1025 static int 1026 pciehpc_register_slot(pcie_hp_ctrl_t *ctrl_p) 1027 { 1028 pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; 1029 dev_info_t *dip = ctrl_p->hc_dip; 1030 1031 /* register the slot with DDI HP framework */ 1032 if (ndi_hp_register(dip, &slot_p->hs_info) != NDI_SUCCESS) { 1033 PCIE_DBG("pciehpc_register_slot() failed to register slot %d\n", 1034 slot_p->hs_phy_slot_num); 1035 return (DDI_FAILURE); 1036 } 1037 1038 pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip), 1039 slot_p->hs_minor), slot_p->hs_device_num); 1040 1041 PCIE_DBG("pciehpc_register_slot(): registered slot %d\n", 1042 slot_p->hs_phy_slot_num); 1043 1044 return (DDI_SUCCESS); 1045 } 1046 1047 /* 1048 * Unregister the PCI-E hot plug slot from DDI HP framework. 1049 */ 1050 static int 1051 pciehpc_unregister_slot(pcie_hp_ctrl_t *ctrl_p) 1052 { 1053 pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; 1054 dev_info_t *dip = ctrl_p->hc_dip; 1055 1056 pcie_hp_delete_occupant_props(dip, makedevice(ddi_driver_major(dip), 1057 slot_p->hs_minor)); 1058 1059 /* unregister the slot with DDI HP framework */ 1060 if (ndi_hp_unregister(dip, slot_p->hs_info.cn_name) != NDI_SUCCESS) { 1061 PCIE_DBG("pciehpc_unregister_slot() " 1062 "failed to unregister slot %d\n", slot_p->hs_phy_slot_num); 1063 return (DDI_FAILURE); 1064 } 1065 1066 PCIE_DBG("pciehpc_unregister_slot(): unregistered slot %d\n", 1067 slot_p->hs_phy_slot_num); 1068 1069 return (DDI_SUCCESS); 1070 } 1071 1072 /* 1073 * pciehpc_slot_poweron() 1074 * 1075 * Poweron/Enable the slot. 1076 * 1077 * Note: This function is called by DDI HP framework at kernel context only 1078 */ 1079 /*ARGSUSED*/ 1080 static int 1081 pciehpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result) 1082 { 1083 pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; 1084 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 1085 uint16_t status, control; 1086 1087 ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex)); 1088 1089 /* get the current state of the slot */ 1090 pciehpc_get_slot_state(slot_p); 1091 1092 /* check if the slot is already in the 'enabled' state */ 1093 if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) { 1094 /* slot is already in the 'enabled' state */ 1095 PCIE_DBG("pciehpc_slot_poweron() slot %d already enabled\n", 1096 slot_p->hs_phy_slot_num); 1097 1098 *result = slot_p->hs_info.cn_state; 1099 return (DDI_SUCCESS); 1100 } 1101 1102 /* read the Slot Status Register */ 1103 status = pciehpc_reg_get16(ctrl_p, 1104 bus_p->bus_pcie_off + PCIE_SLOTSTS); 1105 1106 /* make sure the MRL switch is closed if present */ 1107 if ((ctrl_p->hc_has_mrl) && (status & PCIE_SLOTSTS_MRL_SENSOR_OPEN)) { 1108 /* MRL switch is open */ 1109 cmn_err(CE_WARN, "MRL switch is open on slot %d\n", 1110 slot_p->hs_phy_slot_num); 1111 goto cleanup; 1112 } 1113 1114 /* make sure the slot has a device present */ 1115 if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) { 1116 /* slot is empty */ 1117 PCIE_DBG("slot %d is empty\n", slot_p->hs_phy_slot_num); 1118 goto cleanup; 1119 } 1120 1121 /* 1122 * If the hardware doesn't have support for a power controller, then 1123 * that generally means that power is already on or at the least there 1124 * isn't very much else we can do and the PCIe spec says it's the 1125 * responsibility of the controller to have turned it on if a device is 1126 * present. Given that we checked for presence above, in such a case we 1127 * just return. Note, we still indicate that is a failure since we can't 1128 * change it and instead rely on code executing the actual state machine 1129 * to figure out how to handle this. 1130 */ 1131 if (!ctrl_p->hc_has_pwr) { 1132 PCIE_DBG("slot %d has no power, but was asked to power on\n", 1133 slot_p->hs_phy_slot_num); 1134 return (DDI_FAILURE); 1135 } 1136 1137 /* get the current state of Slot Control Register */ 1138 control = pciehpc_reg_get16(ctrl_p, 1139 bus_p->bus_pcie_off + PCIE_SLOTCTL); 1140 1141 /* 1142 * Enable power to the slot involves: 1143 * 1. Set power LED to blink and ATTN led to OFF. 1144 * 2. Set power control ON in Slot Control Reigster and 1145 * wait for Command Completed Interrupt or 1 sec timeout. 1146 * 3. If Data Link Layer State Changed events are supported 1147 * then wait for the event to indicate Data Layer Link 1148 * is active. The time out value for this event is 1 second. 1149 * This is specified in PCI-E version 1.1. 1150 * 4. Set power LED to be ON. 1151 */ 1152 1153 /* 1. set power LED to blink & ATTN led to OFF */ 1154 pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK); 1155 pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF); 1156 1157 /* 2. set power control to ON */ 1158 control = pciehpc_reg_get16(ctrl_p, 1159 bus_p->bus_pcie_off + PCIE_SLOTCTL); 1160 control &= ~PCIE_SLOTCTL_PWR_CONTROL; 1161 pciehpc_issue_hpc_command(ctrl_p, control); 1162 1163 /* 3. wait for DLL State Change event, if it's supported */ 1164 if (ctrl_p->hc_dll_active_rep) { 1165 clock_t deadline; 1166 1167 /* wait 1 sec for the DLL State Changed event */ 1168 status = pciehpc_reg_get16(ctrl_p, 1169 bus_p->bus_pcie_off + PCIE_LINKSTS); 1170 1171 deadline = ddi_get_lbolt() + 1172 SEC_TO_TICK(PCIE_HP_DLL_STATE_CHANGE_TIMEOUT); 1173 1174 while ((status & PCIE_LINKSTS_DLL_LINK_ACTIVE) == 0 && 1175 ddi_get_lbolt() < deadline) { 1176 (void) cv_timedwait(&slot_p->hs_dll_active_cv, 1177 &ctrl_p->hc_mutex, deadline); 1178 1179 /* check Link status */ 1180 status = pciehpc_reg_get16(ctrl_p, 1181 bus_p->bus_pcie_off + 1182 PCIE_LINKSTS); 1183 } 1184 1185 if ((status & PCIE_LINKSTS_DLL_LINK_ACTIVE) == 0) 1186 goto cleanup2; 1187 } else { 1188 /* wait 1 sec for link to come up */ 1189 delay(drv_usectohz(1000000)); 1190 } 1191 1192 /* check power is really turned ON */ 1193 control = pciehpc_reg_get16(ctrl_p, 1194 bus_p->bus_pcie_off + PCIE_SLOTCTL); 1195 1196 if (control & PCIE_SLOTCTL_PWR_CONTROL) { 1197 PCIE_DBG("slot %d fails to turn on power on connect\n", 1198 slot_p->hs_phy_slot_num); 1199 1200 goto cleanup1; 1201 } 1202 1203 /* clear power fault status */ 1204 status = pciehpc_reg_get16(ctrl_p, 1205 bus_p->bus_pcie_off + PCIE_SLOTSTS); 1206 status |= PCIE_SLOTSTS_PWR_FAULT_DETECTED; 1207 pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTSTS, 1208 status); 1209 1210 /* enable power fault detection interrupt */ 1211 control |= PCIE_SLOTCTL_PWR_FAULT_EN; 1212 pciehpc_issue_hpc_command(ctrl_p, control); 1213 1214 /* 4. Set power LED to be ON */ 1215 pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_ON); 1216 1217 /* if EMI is present, turn it ON */ 1218 if (ctrl_p->hc_has_emi_lock) { 1219 status = pciehpc_reg_get16(ctrl_p, 1220 bus_p->bus_pcie_off + PCIE_SLOTSTS); 1221 1222 if (!(status & PCIE_SLOTSTS_EMI_LOCK_SET)) { 1223 control = pciehpc_reg_get16(ctrl_p, 1224 bus_p->bus_pcie_off + PCIE_SLOTCTL); 1225 control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL; 1226 pciehpc_issue_hpc_command(ctrl_p, control); 1227 1228 /* wait 1 sec after toggling the state of EMI lock */ 1229 delay(drv_usectohz(1000000)); 1230 } 1231 } 1232 1233 *result = slot_p->hs_info.cn_state = 1234 DDI_HP_CN_STATE_POWERED; 1235 1236 return (DDI_SUCCESS); 1237 1238 cleanup2: 1239 control = pciehpc_reg_get16(ctrl_p, 1240 bus_p->bus_pcie_off + PCIE_SLOTCTL); 1241 1242 /* if power is ON, set power control to OFF */ 1243 if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) { 1244 control |= PCIE_SLOTCTL_PWR_CONTROL; 1245 pciehpc_issue_hpc_command(ctrl_p, control); 1246 } 1247 1248 cleanup1: 1249 /* set power led to OFF */ 1250 pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF); 1251 1252 cleanup: 1253 return (DDI_FAILURE); 1254 } 1255 1256 /*ARGSUSED*/ 1257 static int 1258 pciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result) 1259 { 1260 pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; 1261 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 1262 uint16_t status, control; 1263 1264 ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex)); 1265 1266 /* get the current state of the slot */ 1267 pciehpc_get_slot_state(slot_p); 1268 1269 /* check if the slot is not in the "enabled' state */ 1270 if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) { 1271 /* slot is in the 'disabled' state */ 1272 PCIE_DBG("pciehpc_slot_poweroff(): " 1273 "slot %d already disabled\n", slot_p->hs_phy_slot_num); 1274 ASSERT(slot_p->hs_power_led_state == PCIE_HP_LED_OFF); 1275 1276 *result = slot_p->hs_info.cn_state; 1277 return (DDI_SUCCESS); 1278 } 1279 1280 /* read the Slot Status Register */ 1281 status = pciehpc_reg_get16(ctrl_p, 1282 bus_p->bus_pcie_off + PCIE_SLOTSTS); 1283 1284 /* make sure the slot has a device present */ 1285 if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) { 1286 /* slot is empty */ 1287 PCIE_DBG("pciehpc_slot_poweroff(): slot %d is empty\n", 1288 slot_p->hs_phy_slot_num); 1289 goto cleanup; 1290 } 1291 1292 /* 1293 * Some devices do not have a power controller. In such cases we need to 1294 * fail any request to power it off. If a device is being pulled, the 1295 * state will generally have automatically been updated; however, if 1296 * someone is asking for us to do something via an explicit request, 1297 * then this will fail. Note, this is after the presence check to ensure 1298 * that an empty slot is accounted for correctly. 1299 */ 1300 if (!ctrl_p->hc_has_pwr) { 1301 PCIE_DBG("pciehpc_slot_poweroff(): slot %d doesn't have a " 1302 "power controller\n", 1303 slot_p->hs_phy_slot_num); 1304 return (DDI_ENOTSUP); 1305 } 1306 1307 /* 1308 * Disable power to the slot involves: 1309 * 1. Set power LED to blink. 1310 * 2. Set power control OFF in Slot Control Reigster and 1311 * wait for Command Completed Interrupt or 1 sec timeout. 1312 * 3. Set POWER led and ATTN led to be OFF. 1313 */ 1314 1315 /* 1. set power LED to blink */ 1316 pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK); 1317 1318 /* disable power fault detection interrupt */ 1319 control = pciehpc_reg_get16(ctrl_p, 1320 bus_p->bus_pcie_off + PCIE_SLOTCTL); 1321 control &= ~PCIE_SLOTCTL_PWR_FAULT_EN; 1322 pciehpc_issue_hpc_command(ctrl_p, control); 1323 1324 /* 2. set power control to OFF */ 1325 control = pciehpc_reg_get16(ctrl_p, 1326 bus_p->bus_pcie_off + PCIE_SLOTCTL); 1327 control |= PCIE_SLOTCTL_PWR_CONTROL; 1328 pciehpc_issue_hpc_command(ctrl_p, control); 1329 1330 #ifdef DEBUG 1331 /* check for power control bit to be OFF */ 1332 control = pciehpc_reg_get16(ctrl_p, 1333 bus_p->bus_pcie_off + PCIE_SLOTCTL); 1334 ASSERT(control & PCIE_SLOTCTL_PWR_CONTROL); 1335 #endif 1336 1337 /* 3. Set power LED to be OFF */ 1338 pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF); 1339 pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF); 1340 1341 /* if EMI is present, turn it OFF */ 1342 if (ctrl_p->hc_has_emi_lock) { 1343 status = pciehpc_reg_get16(ctrl_p, 1344 bus_p->bus_pcie_off + PCIE_SLOTSTS); 1345 1346 if (status & PCIE_SLOTSTS_EMI_LOCK_SET) { 1347 control = pciehpc_reg_get16(ctrl_p, 1348 bus_p->bus_pcie_off + PCIE_SLOTCTL); 1349 control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL; 1350 pciehpc_issue_hpc_command(ctrl_p, control); 1351 1352 /* wait 1 sec after toggling the state of EMI lock */ 1353 delay(drv_usectohz(1000000)); 1354 } 1355 } 1356 1357 /* get the current state of the slot */ 1358 pciehpc_get_slot_state(slot_p); 1359 1360 *result = slot_p->hs_info.cn_state; 1361 1362 return (DDI_SUCCESS); 1363 1364 cleanup: 1365 return (DDI_FAILURE); 1366 } 1367 1368 /* 1369 * pciehpc_slot_probe() 1370 * 1371 * Probe the slot. 1372 * 1373 * Note: This function is called by DDI HP framework at kernel context only 1374 */ 1375 /*ARGSUSED*/ 1376 static int 1377 pciehpc_slot_probe(pcie_hp_slot_t *slot_p) 1378 { 1379 pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; 1380 int ret = DDI_SUCCESS; 1381 1382 mutex_enter(&ctrl_p->hc_mutex); 1383 1384 /* get the current state of the slot */ 1385 pciehpc_get_slot_state(slot_p); 1386 1387 /* 1388 * Probe a given PCIe Hotplug Connection (CN). 1389 */ 1390 PCIE_DISABLE_ERRORS(ctrl_p->hc_dip); 1391 ret = pcie_hp_probe(slot_p); 1392 1393 if (ret != DDI_SUCCESS) { 1394 PCIE_DBG("pciehpc_slot_probe() failed\n"); 1395 1396 /* turn the ATTN led ON for configure failure */ 1397 pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_ON); 1398 1399 /* if power to the slot is still on then set Power led to ON */ 1400 if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) 1401 pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, 1402 PCIE_HP_LED_ON); 1403 1404 mutex_exit(&ctrl_p->hc_mutex); 1405 return (DDI_FAILURE); 1406 } 1407 1408 PCIE_ENABLE_ERRORS(ctrl_p->hc_dip); 1409 1410 /* get the current state of the slot */ 1411 pciehpc_get_slot_state(slot_p); 1412 1413 mutex_exit(&ctrl_p->hc_mutex); 1414 return (DDI_SUCCESS); 1415 } 1416 1417 /* 1418 * pciehpc_slot_unprobe() 1419 * 1420 * Unprobe the slot. 1421 * 1422 * Note: This function is called by DDI HP framework at kernel context only 1423 */ 1424 /*ARGSUSED*/ 1425 static int 1426 pciehpc_slot_unprobe(pcie_hp_slot_t *slot_p) 1427 { 1428 pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; 1429 int ret; 1430 1431 mutex_enter(&ctrl_p->hc_mutex); 1432 1433 /* get the current state of the slot */ 1434 pciehpc_get_slot_state(slot_p); 1435 1436 /* 1437 * Unprobe a given PCIe Hotplug Connection (CN). 1438 */ 1439 PCIE_DISABLE_ERRORS(ctrl_p->hc_dip); 1440 ret = pcie_hp_unprobe(slot_p); 1441 1442 if (ret != DDI_SUCCESS) { 1443 PCIE_DBG("pciehpc_slot_unprobe() failed\n"); 1444 1445 /* if power to the slot is still on then set Power led to ON */ 1446 if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) 1447 pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, 1448 PCIE_HP_LED_ON); 1449 1450 PCIE_ENABLE_ERRORS(ctrl_p->hc_dip); 1451 1452 mutex_exit(&ctrl_p->hc_mutex); 1453 return (DDI_FAILURE); 1454 } 1455 1456 /* get the current state of the slot */ 1457 pciehpc_get_slot_state(slot_p); 1458 1459 mutex_exit(&ctrl_p->hc_mutex); 1460 return (DDI_SUCCESS); 1461 } 1462 1463 static int 1464 pciehpc_upgrade_slot_state(pcie_hp_slot_t *slot_p, 1465 ddi_hp_cn_state_t target_state) 1466 { 1467 ddi_hp_cn_state_t curr_state; 1468 int rv = DDI_SUCCESS; 1469 1470 if (target_state > DDI_HP_CN_STATE_ENABLED) { 1471 return (DDI_EINVAL); 1472 } 1473 1474 curr_state = slot_p->hs_info.cn_state; 1475 while ((curr_state < target_state) && (rv == DDI_SUCCESS)) { 1476 1477 switch (curr_state) { 1478 case DDI_HP_CN_STATE_EMPTY: 1479 /* 1480 * From EMPTY to PRESENT, just check the hardware 1481 * slot state. 1482 */ 1483 pciehpc_get_slot_state(slot_p); 1484 curr_state = slot_p->hs_info.cn_state; 1485 if (curr_state < DDI_HP_CN_STATE_PRESENT) 1486 rv = DDI_FAILURE; 1487 break; 1488 case DDI_HP_CN_STATE_PRESENT: 1489 if (!slot_p->hs_ctrl->hc_has_pwr) { 1490 pciehpc_get_slot_state(slot_p); 1491 curr_state = slot_p->hs_info.cn_state; 1492 if (curr_state < DDI_HP_CN_STATE_POWERED) 1493 rv = DDI_FAILURE; 1494 break; 1495 } 1496 1497 rv = (slot_p->hs_ctrl->hc_ops.poweron_hpc_slot)(slot_p, 1498 &curr_state); 1499 1500 break; 1501 case DDI_HP_CN_STATE_POWERED: 1502 curr_state = slot_p->hs_info.cn_state = 1503 DDI_HP_CN_STATE_ENABLED; 1504 break; 1505 default: 1506 /* should never reach here */ 1507 ASSERT("unknown devinfo state"); 1508 } 1509 } 1510 1511 return (rv); 1512 } 1513 1514 static int 1515 pciehpc_downgrade_slot_state(pcie_hp_slot_t *slot_p, 1516 ddi_hp_cn_state_t target_state) 1517 { 1518 ddi_hp_cn_state_t curr_state; 1519 int rv = DDI_SUCCESS; 1520 1521 1522 curr_state = slot_p->hs_info.cn_state; 1523 while ((curr_state > target_state) && (rv == DDI_SUCCESS)) { 1524 1525 switch (curr_state) { 1526 case DDI_HP_CN_STATE_PRESENT: 1527 /* 1528 * From PRESENT to EMPTY, just check hardware slot 1529 * state. 1530 */ 1531 pciehpc_get_slot_state(slot_p); 1532 curr_state = slot_p->hs_info.cn_state; 1533 if (curr_state >= DDI_HP_CN_STATE_PRESENT) 1534 rv = DDI_FAILURE; 1535 break; 1536 case DDI_HP_CN_STATE_POWERED: 1537 /* 1538 * If the device doesn't have power control then we 1539 * cannot ask it to power off the slot. However, a 1540 * device may have been removed and therefore we need to 1541 * manually check if the device was removed by getting 1542 * the state. Otherwise we let power control do 1543 * everything. 1544 */ 1545 if (!slot_p->hs_ctrl->hc_has_pwr) { 1546 pciehpc_get_slot_state(slot_p); 1547 curr_state = slot_p->hs_info.cn_state; 1548 if (curr_state >= DDI_HP_CN_STATE_POWERED) 1549 rv = DDI_FAILURE; 1550 break; 1551 } 1552 1553 rv = (slot_p->hs_ctrl->hc_ops.poweroff_hpc_slot)( 1554 slot_p, &curr_state); 1555 1556 break; 1557 case DDI_HP_CN_STATE_ENABLED: 1558 curr_state = slot_p->hs_info.cn_state = 1559 DDI_HP_CN_STATE_POWERED; 1560 1561 break; 1562 default: 1563 /* should never reach here */ 1564 ASSERT("unknown devinfo state"); 1565 } 1566 } 1567 1568 return (rv); 1569 } 1570 1571 /* Change slot state to a target state */ 1572 static int 1573 pciehpc_change_slot_state(pcie_hp_slot_t *slot_p, 1574 ddi_hp_cn_state_t target_state) 1575 { 1576 ddi_hp_cn_state_t curr_state; 1577 int rv; 1578 1579 pciehpc_get_slot_state(slot_p); 1580 curr_state = slot_p->hs_info.cn_state; 1581 1582 if (curr_state == target_state) { 1583 return (DDI_SUCCESS); 1584 } 1585 if (curr_state < target_state) { 1586 1587 rv = pciehpc_upgrade_slot_state(slot_p, target_state); 1588 } else { 1589 rv = pciehpc_downgrade_slot_state(slot_p, target_state); 1590 } 1591 1592 return (rv); 1593 } 1594 1595 int 1596 pciehpc_slot_get_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg, 1597 ddi_hp_property_t *rval) 1598 { 1599 ddi_hp_property_t request, result; 1600 #ifdef _SYSCALL32_IMPL 1601 ddi_hp_property32_t request32, result32; 1602 #endif 1603 pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; 1604 nvlist_t *prop_list; 1605 nvlist_t *prop_rlist; /* nvlist for return values */ 1606 nvpair_t *prop_pair; 1607 char *name, *value; 1608 int ret = DDI_SUCCESS; 1609 int i, n; 1610 boolean_t get_all_prop = B_FALSE; 1611 1612 if (get_udatamodel() == DATAMODEL_NATIVE) { 1613 if (copyin(arg, &request, sizeof (ddi_hp_property_t)) || 1614 copyin(rval, &result, sizeof (ddi_hp_property_t))) 1615 return (DDI_FAILURE); 1616 } 1617 #ifdef _SYSCALL32_IMPL 1618 else { 1619 bzero(&request, sizeof (request)); 1620 bzero(&result, sizeof (result)); 1621 if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)) || 1622 copyin(rval, &result32, sizeof (ddi_hp_property32_t))) 1623 return (DDI_FAILURE); 1624 request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf; 1625 request.buf_size = request32.buf_size; 1626 result.nvlist_buf = (char *)(uintptr_t)result32.nvlist_buf; 1627 result.buf_size = result32.buf_size; 1628 } 1629 #endif 1630 1631 if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size, 1632 &prop_list)) != DDI_SUCCESS) 1633 return (ret); 1634 1635 if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) { 1636 ret = DDI_ENOMEM; 1637 goto get_prop_cleanup; 1638 } 1639 1640 /* check whether the requested property is "all" or "help" */ 1641 prop_pair = nvlist_next_nvpair(prop_list, NULL); 1642 if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair)) { 1643 name = nvpair_name(prop_pair); 1644 n = sizeof (pciehpc_props) / sizeof (pciehpc_prop_t); 1645 1646 if (strcmp(name, PCIEHPC_PROP_ALL) == 0) { 1647 (void) nvlist_remove_all(prop_list, PCIEHPC_PROP_ALL); 1648 1649 /* 1650 * Add all properties into the request list, so that we 1651 * will get the values in the following for loop. 1652 */ 1653 for (i = 0; i < n; i++) { 1654 if (nvlist_add_string(prop_list, 1655 pciehpc_props[i].prop_name, "") != 0) { 1656 ret = DDI_FAILURE; 1657 goto get_prop_cleanup1; 1658 } 1659 } 1660 get_all_prop = B_TRUE; 1661 } else if (strcmp(name, PCIEHPC_PROP_HELP) == 0) { 1662 /* 1663 * Empty the request list, and add help strings into the 1664 * return list. We will pass the following for loop. 1665 */ 1666 (void) nvlist_remove_all(prop_list, PCIEHPC_PROP_HELP); 1667 1668 for (i = 0; i < n; i++) { 1669 if (nvlist_add_string(prop_rlist, 1670 pciehpc_props[i].prop_name, 1671 pciehpc_props[i].prop_value) != 0) { 1672 ret = DDI_FAILURE; 1673 goto get_prop_cleanup1; 1674 } 1675 } 1676 } 1677 } 1678 1679 mutex_enter(&ctrl_p->hc_mutex); 1680 1681 /* get the current slot state */ 1682 pciehpc_get_slot_state(slot_p); 1683 1684 /* for each requested property, get the value and add it to nvlist */ 1685 prop_pair = NULL; 1686 while ((prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) != NULL) { 1687 name = nvpair_name(prop_pair); 1688 value = NULL; 1689 1690 if (strcmp(name, PCIEHPC_PROP_LED_FAULT) == 0) { 1691 value = pcie_led_state_text( 1692 slot_p->hs_fault_led_state); 1693 } else if (strcmp(name, PCIEHPC_PROP_LED_POWER) == 0) { 1694 value = pcie_led_state_text( 1695 slot_p->hs_power_led_state); 1696 } else if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) { 1697 value = pcie_led_state_text( 1698 slot_p->hs_attn_led_state); 1699 } else if (strcmp(name, PCIEHPC_PROP_LED_ACTIVE) == 0) { 1700 value = pcie_led_state_text( 1701 slot_p->hs_active_led_state); 1702 } else if (strcmp(name, PCIEHPC_PROP_CARD_TYPE) == 0) { 1703 ddi_acc_handle_t handle; 1704 dev_info_t *cdip; 1705 uint8_t prog_class, base_class, sub_class; 1706 int i; 1707 1708 mutex_exit(&ctrl_p->hc_mutex); 1709 cdip = pcie_hp_devi_find( 1710 ctrl_p->hc_dip, slot_p->hs_device_num, 0); 1711 mutex_enter(&ctrl_p->hc_mutex); 1712 1713 if ((slot_p->hs_info.cn_state 1714 != DDI_HP_CN_STATE_ENABLED) || (cdip == NULL)) { 1715 /* 1716 * When getting all properties, just ignore the 1717 * one that's not available under certain state. 1718 */ 1719 if (get_all_prop) 1720 continue; 1721 1722 ret = DDI_ENOTSUP; 1723 goto get_prop_cleanup2; 1724 } 1725 1726 if (pci_config_setup(cdip, &handle) != DDI_SUCCESS) { 1727 ret = DDI_FAILURE; 1728 goto get_prop_cleanup2; 1729 } 1730 1731 prog_class = pci_config_get8(handle, 1732 PCI_CONF_PROGCLASS); 1733 base_class = pci_config_get8(handle, PCI_CONF_BASCLASS); 1734 sub_class = pci_config_get8(handle, PCI_CONF_SUBCLASS); 1735 pci_config_teardown(&handle); 1736 1737 for (i = 0; i < class_pci_items; i++) { 1738 if ((base_class == class_pci[i].base_class) && 1739 (sub_class == class_pci[i].sub_class) && 1740 (prog_class == class_pci[i].prog_class)) { 1741 value = class_pci[i].short_desc; 1742 break; 1743 } 1744 } 1745 if (i == class_pci_items) 1746 value = PCIEHPC_PROP_VALUE_UNKNOWN; 1747 } else if (strcmp(name, PCIEHPC_PROP_BOARD_TYPE) == 0) { 1748 if (slot_p->hs_info.cn_state <= DDI_HP_CN_STATE_EMPTY) 1749 value = PCIEHPC_PROP_VALUE_UNKNOWN; 1750 else 1751 value = PCIEHPC_PROP_VALUE_PCIHOTPLUG; 1752 } else if (strcmp(name, PCIEHPC_PROP_SLOT_CONDITION) == 0) { 1753 value = pcie_slot_condition_text(slot_p->hs_condition); 1754 } else { 1755 /* unsupported property */ 1756 PCIE_DBG("Unsupported property: %s\n", name); 1757 1758 ret = DDI_ENOTSUP; 1759 goto get_prop_cleanup2; 1760 } 1761 if (nvlist_add_string(prop_rlist, name, value) != 0) { 1762 ret = DDI_FAILURE; 1763 goto get_prop_cleanup2; 1764 } 1765 } 1766 1767 /* pack nvlist and copyout */ 1768 if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf, 1769 &result.buf_size)) != DDI_SUCCESS) { 1770 goto get_prop_cleanup2; 1771 } 1772 if (get_udatamodel() == DATAMODEL_NATIVE) { 1773 if (copyout(&result, rval, sizeof (ddi_hp_property_t))) 1774 ret = DDI_FAILURE; 1775 } 1776 #ifdef _SYSCALL32_IMPL 1777 else { 1778 if (result.buf_size > UINT32_MAX) { 1779 ret = DDI_FAILURE; 1780 } else { 1781 result32.buf_size = (uint32_t)result.buf_size; 1782 if (copyout(&result32, rval, 1783 sizeof (ddi_hp_property32_t))) 1784 ret = DDI_FAILURE; 1785 } 1786 } 1787 #endif 1788 1789 get_prop_cleanup2: 1790 mutex_exit(&ctrl_p->hc_mutex); 1791 get_prop_cleanup1: 1792 nvlist_free(prop_rlist); 1793 get_prop_cleanup: 1794 nvlist_free(prop_list); 1795 return (ret); 1796 } 1797 1798 int 1799 pciehpc_slot_set_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg, 1800 ddi_hp_property_t *rval) 1801 { 1802 ddi_hp_property_t request, result; 1803 #ifdef _SYSCALL32_IMPL 1804 ddi_hp_property32_t request32, result32; 1805 #endif 1806 pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; 1807 nvlist_t *prop_list; 1808 nvlist_t *prop_rlist; 1809 nvpair_t *prop_pair; 1810 char *name, *value; 1811 pcie_hp_led_state_t led_state; 1812 int ret = DDI_SUCCESS; 1813 1814 if (get_udatamodel() == DATAMODEL_NATIVE) { 1815 if (copyin(arg, &request, sizeof (ddi_hp_property_t))) 1816 return (DDI_FAILURE); 1817 if (rval && 1818 copyin(rval, &result, sizeof (ddi_hp_property_t))) 1819 return (DDI_FAILURE); 1820 } 1821 #ifdef _SYSCALL32_IMPL 1822 else { 1823 bzero(&request, sizeof (request)); 1824 bzero(&result, sizeof (result)); 1825 if (copyin(arg, &request32, sizeof (ddi_hp_property32_t))) 1826 return (DDI_FAILURE); 1827 if (rval && 1828 copyin(rval, &result32, sizeof (ddi_hp_property32_t))) 1829 return (DDI_FAILURE); 1830 request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf; 1831 request.buf_size = request32.buf_size; 1832 if (rval) { 1833 result.nvlist_buf = 1834 (char *)(uintptr_t)result32.nvlist_buf; 1835 result.buf_size = result32.buf_size; 1836 } 1837 } 1838 #endif 1839 1840 if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size, 1841 &prop_list)) != DDI_SUCCESS) 1842 return (ret); 1843 1844 /* check whether the requested property is "help" */ 1845 prop_pair = nvlist_next_nvpair(prop_list, NULL); 1846 if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair) && 1847 (strcmp(nvpair_name(prop_pair), PCIEHPC_PROP_HELP) == 0)) { 1848 if (!rval) { 1849 ret = DDI_ENOTSUP; 1850 goto set_prop_cleanup; 1851 } 1852 1853 if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) { 1854 ret = DDI_ENOMEM; 1855 goto set_prop_cleanup; 1856 } 1857 if (nvlist_add_string(prop_rlist, PCIEHPC_PROP_LED_ATTN, 1858 PCIEHPC_PROP_VALUE_LED) != 0) { 1859 ret = DDI_FAILURE; 1860 goto set_prop_cleanup1; 1861 } 1862 1863 if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf, 1864 &result.buf_size)) != DDI_SUCCESS) { 1865 goto set_prop_cleanup1; 1866 } 1867 if (get_udatamodel() == DATAMODEL_NATIVE) { 1868 if (copyout(&result, rval, 1869 sizeof (ddi_hp_property_t))) { 1870 ret = DDI_FAILURE; 1871 goto set_prop_cleanup1; 1872 } 1873 } 1874 #ifdef _SYSCALL32_IMPL 1875 else { 1876 if (result.buf_size > UINT32_MAX) { 1877 ret = DDI_FAILURE; 1878 goto set_prop_cleanup1; 1879 } else { 1880 result32.buf_size = (uint32_t)result.buf_size; 1881 if (copyout(&result32, rval, 1882 sizeof (ddi_hp_property32_t))) { 1883 ret = DDI_FAILURE; 1884 goto set_prop_cleanup1; 1885 } 1886 } 1887 } 1888 #endif 1889 set_prop_cleanup1: 1890 nvlist_free(prop_rlist); 1891 nvlist_free(prop_list); 1892 return (ret); 1893 } 1894 1895 /* Validate the request */ 1896 prop_pair = NULL; 1897 while ((prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) != NULL) { 1898 name = nvpair_name(prop_pair); 1899 if (nvpair_type(prop_pair) != DATA_TYPE_STRING) { 1900 PCIE_DBG("Unexpected data type of setting " 1901 "property %s.\n", name); 1902 ret = DDI_EINVAL; 1903 goto set_prop_cleanup; 1904 } 1905 if (nvpair_value_string(prop_pair, &value)) { 1906 PCIE_DBG("Get string value failed for property %s.\n", 1907 name); 1908 ret = DDI_FAILURE; 1909 goto set_prop_cleanup; 1910 } 1911 1912 if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) { 1913 if ((strcmp(value, PCIEHPC_PROP_VALUE_ON) != 0) && 1914 (strcmp(value, PCIEHPC_PROP_VALUE_OFF) != 0) && 1915 (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) != 0)) { 1916 PCIE_DBG("Unsupported value of setting " 1917 "property %s\n", name); 1918 ret = DDI_ENOTSUP; 1919 goto set_prop_cleanup; 1920 } 1921 } else { 1922 PCIE_DBG("Unsupported property: %s\n", name); 1923 ret = DDI_ENOTSUP; 1924 goto set_prop_cleanup; 1925 } 1926 } 1927 mutex_enter(&ctrl_p->hc_mutex); 1928 1929 /* get the current slot state */ 1930 pciehpc_get_slot_state(slot_p); 1931 1932 /* set each property */ 1933 prop_pair = NULL; 1934 while ((prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) != NULL) { 1935 name = nvpair_name(prop_pair); 1936 1937 /* 1938 * The validity of the property was checked above. 1939 */ 1940 if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) { 1941 if (strcmp(value, PCIEHPC_PROP_VALUE_ON) == 0) 1942 led_state = PCIE_HP_LED_ON; 1943 else if (strcmp(value, PCIEHPC_PROP_VALUE_OFF) == 0) 1944 led_state = PCIE_HP_LED_OFF; 1945 else if (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) == 0) 1946 led_state = PCIE_HP_LED_BLINK; 1947 else 1948 continue; 1949 1950 pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, 1951 led_state); 1952 } 1953 } 1954 if (rval) { 1955 if (get_udatamodel() == DATAMODEL_NATIVE) { 1956 result.buf_size = 0; 1957 if (copyout(&result, rval, sizeof (ddi_hp_property_t))) 1958 ret = DDI_FAILURE; 1959 } 1960 #ifdef _SYSCALL32_IMPL 1961 else { 1962 result32.buf_size = 0; 1963 if (copyout(&result32, rval, 1964 sizeof (ddi_hp_property32_t))) 1965 ret = DDI_FAILURE; 1966 } 1967 #endif 1968 } 1969 1970 mutex_exit(&ctrl_p->hc_mutex); 1971 set_prop_cleanup: 1972 nvlist_free(prop_list); 1973 return (ret); 1974 } 1975 1976 /* 1977 * Send a command to the PCI-E Hot Plug Controller. 1978 * 1979 * NOTES: The PCI-E spec defines the following semantics for issuing hot plug 1980 * commands. 1981 * 1) If Command Complete events/interrupts are supported then software 1982 * waits for Command Complete event after issuing a command (i.e writing 1983 * to the Slot Control register). The command completion could take as 1984 * long as 1 second so software should be prepared to wait for 1 second 1985 * before issuing another command. 1986 * 1987 * 2) If Command Complete events/interrupts are not supported then 1988 * software could issue multiple Slot Control writes without any delay 1989 * between writes. 1990 */ 1991 static void 1992 pciehpc_issue_hpc_command(pcie_hp_ctrl_t *ctrl_p, uint16_t control) 1993 { 1994 pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; 1995 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 1996 uint16_t status; 1997 uint32_t slot_cap; 1998 1999 /* 2000 * PCI-E version 1.1 spec defines No Command Completed 2001 * Support bit (bit#18) in Slot Capabilities register. If this 2002 * bit is set then slot doesn't support notification of command 2003 * completion events. 2004 */ 2005 slot_cap = pciehpc_reg_get32(ctrl_p, 2006 bus_p->bus_pcie_off + PCIE_SLOTCAP); 2007 2008 /* 2009 * If no Command Completion event is supported or it is ACPI 2010 * hot plug mode then just issue the command and return. 2011 */ 2012 if ((slot_cap & PCIE_SLOTCAP_NO_CMD_COMP_SUPP) || 2013 (bus_p->bus_hp_curr_mode == PCIE_ACPI_HP_MODE)) { 2014 pciehpc_reg_put16(ctrl_p, 2015 bus_p->bus_pcie_off + PCIE_SLOTCTL, control); 2016 return; 2017 } 2018 2019 /* 2020 * ************************************** 2021 * Command Complete events are supported. 2022 * ************************************** 2023 */ 2024 2025 /* 2026 * If HPC is not yet initialized then just poll for the Command 2027 * Completion interrupt. 2028 */ 2029 if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) { 2030 int retry = PCIE_HP_CMD_WAIT_RETRY; 2031 2032 /* write the command to the HPC */ 2033 pciehpc_reg_put16(ctrl_p, 2034 bus_p->bus_pcie_off + PCIE_SLOTCTL, control); 2035 2036 /* poll for status completion */ 2037 while (retry--) { 2038 /* wait for 10 msec before checking the status */ 2039 delay(drv_usectohz(PCIE_HP_CMD_WAIT_TIME)); 2040 2041 status = pciehpc_reg_get16(ctrl_p, 2042 bus_p->bus_pcie_off + PCIE_SLOTSTS); 2043 2044 if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) { 2045 /* clear the status bits */ 2046 pciehpc_reg_put16(ctrl_p, 2047 bus_p->bus_pcie_off + PCIE_SLOTSTS, status); 2048 break; 2049 } 2050 } 2051 return; 2052 } 2053 2054 /* HPC is already initialized */ 2055 2056 ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex)); 2057 2058 /* 2059 * If previous command is still pending then wait for its 2060 * completion. i.e cv_wait() 2061 */ 2062 2063 while (ctrl_p->hc_cmd_pending == B_TRUE) 2064 cv_wait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex); 2065 2066 /* 2067 * Issue the command and wait for Command Completion or 2068 * the 1 sec timeout. 2069 */ 2070 pciehpc_reg_put16(ctrl_p, 2071 bus_p->bus_pcie_off + PCIE_SLOTCTL, control); 2072 2073 ctrl_p->hc_cmd_pending = B_TRUE; 2074 2075 if (cv_timedwait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex, 2076 ddi_get_lbolt() + SEC_TO_TICK(1)) == -1) { 2077 2078 /* it is a timeout */ 2079 PCIE_DBG("pciehpc_issue_hpc_command: Command Complete" 2080 " interrupt is not received for slot %d\n", 2081 slot_p->hs_phy_slot_num); 2082 2083 /* clear the status info in case interrupts are disabled? */ 2084 status = pciehpc_reg_get16(ctrl_p, 2085 bus_p->bus_pcie_off + PCIE_SLOTSTS); 2086 2087 if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) { 2088 /* clear the status bits */ 2089 pciehpc_reg_put16(ctrl_p, 2090 bus_p->bus_pcie_off + PCIE_SLOTSTS, status); 2091 } 2092 } 2093 2094 ctrl_p->hc_cmd_pending = B_FALSE; 2095 2096 /* wake up any one waiting for issuing another command to HPC */ 2097 cv_signal(&ctrl_p->hc_cmd_comp_cv); 2098 } 2099 2100 /* 2101 * pciehcp_attn_btn_handler() 2102 * 2103 * This handles ATTN button pressed event as per the PCI-E 1.1 spec. 2104 */ 2105 static void 2106 pciehpc_attn_btn_handler(pcie_hp_ctrl_t *ctrl_p) 2107 { 2108 pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; 2109 pcie_hp_led_state_t power_led_state; 2110 callb_cpr_t cprinfo; 2111 2112 PCIE_DBG("pciehpc_attn_btn_handler: thread started\n"); 2113 2114 CALLB_CPR_INIT(&cprinfo, &ctrl_p->hc_mutex, callb_generic_cpr, 2115 "pciehpc_attn_btn_handler"); 2116 2117 mutex_enter(&ctrl_p->hc_mutex); 2118 2119 /* wait for ATTN button event */ 2120 cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex); 2121 2122 while (slot_p->hs_attn_btn_thread_exit == B_FALSE) { 2123 if (slot_p->hs_attn_btn_pending == B_TRUE) { 2124 /* get the current state of power LED */ 2125 power_led_state = pciehpc_get_led_state(ctrl_p, 2126 PCIE_HP_POWER_LED); 2127 2128 /* Blink the Power LED while we wait for 5 seconds */ 2129 pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, 2130 PCIE_HP_LED_BLINK); 2131 2132 /* wait for 5 seconds before taking any action */ 2133 if (cv_timedwait(&slot_p->hs_attn_btn_cv, 2134 &ctrl_p->hc_mutex, 2135 ddi_get_lbolt() + SEC_TO_TICK(5)) == -1) { 2136 /* 2137 * It is a time out; make sure the ATTN pending 2138 * flag is still ON before sending the event to 2139 * DDI HP framework. 2140 */ 2141 if (slot_p->hs_attn_btn_pending == B_TRUE) { 2142 int hint; 2143 2144 slot_p->hs_attn_btn_pending = B_FALSE; 2145 pciehpc_get_slot_state(slot_p); 2146 2147 if (slot_p->hs_info.cn_state <= 2148 DDI_HP_CN_STATE_PRESENT) { 2149 /* 2150 * Insertion. 2151 */ 2152 hint = SE_INCOMING_RES; 2153 } else { 2154 /* 2155 * Want to remove; 2156 */ 2157 hint = SE_OUTGOING_RES; 2158 } 2159 2160 /* 2161 * We can't call ddihp_cn_gen_sysevent 2162 * here since it's not a DDI interface. 2163 */ 2164 pcie_hp_gen_sysevent_req( 2165 slot_p->hs_info.cn_name, 2166 hint, 2167 ctrl_p->hc_dip, 2168 KM_SLEEP); 2169 } 2170 } 2171 2172 /* restore the power LED state */ 2173 pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, 2174 power_led_state); 2175 continue; 2176 } 2177 2178 /* wait for another ATTN button event */ 2179 cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex); 2180 } 2181 2182 PCIE_DBG("pciehpc_attn_btn_handler: thread exit\n"); 2183 cv_signal(&slot_p->hs_attn_btn_cv); 2184 CALLB_CPR_EXIT(&cprinfo); 2185 thread_exit(); 2186 } 2187 2188 /* 2189 * convert LED state from PCIE HPC definition to pcie_hp_led_state_t 2190 * definition. 2191 */ 2192 static pcie_hp_led_state_t 2193 pciehpc_led_state_to_hpc(uint16_t state) 2194 { 2195 switch (state) { 2196 case PCIE_SLOTCTL_INDICATOR_STATE_ON: 2197 return (PCIE_HP_LED_ON); 2198 case PCIE_SLOTCTL_INDICATOR_STATE_BLINK: 2199 return (PCIE_HP_LED_BLINK); 2200 case PCIE_SLOTCTL_INDICATOR_STATE_OFF: 2201 default: 2202 return (PCIE_HP_LED_OFF); 2203 } 2204 } 2205 2206 /* 2207 * Get the state of an LED. 2208 */ 2209 static pcie_hp_led_state_t 2210 pciehpc_get_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led) 2211 { 2212 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 2213 uint16_t control, state; 2214 2215 /* get the current state of Slot Control register */ 2216 control = pciehpc_reg_get16(ctrl_p, 2217 bus_p->bus_pcie_off + PCIE_SLOTCTL); 2218 2219 switch (led) { 2220 case PCIE_HP_POWER_LED: 2221 state = pcie_slotctl_pwr_indicator_get(control); 2222 break; 2223 case PCIE_HP_ATTN_LED: 2224 state = pcie_slotctl_attn_indicator_get(control); 2225 break; 2226 default: 2227 PCIE_DBG("pciehpc_get_led_state() invalid LED %d\n", led); 2228 return (PCIE_HP_LED_OFF); 2229 } 2230 2231 switch (state) { 2232 case PCIE_SLOTCTL_INDICATOR_STATE_ON: 2233 return (PCIE_HP_LED_ON); 2234 2235 case PCIE_SLOTCTL_INDICATOR_STATE_BLINK: 2236 return (PCIE_HP_LED_BLINK); 2237 2238 case PCIE_SLOTCTL_INDICATOR_STATE_OFF: 2239 default: 2240 return (PCIE_HP_LED_OFF); 2241 } 2242 } 2243 2244 /* 2245 * Set the state of an LED. It updates both hw and sw state. 2246 */ 2247 static void 2248 pciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led, 2249 pcie_hp_led_state_t state) 2250 { 2251 pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; 2252 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 2253 uint16_t control; 2254 2255 /* get the current state of Slot Control register */ 2256 control = pciehpc_reg_get16(ctrl_p, 2257 bus_p->bus_pcie_off + PCIE_SLOTCTL); 2258 2259 switch (led) { 2260 case PCIE_HP_POWER_LED: 2261 /* clear led mask */ 2262 control &= ~PCIE_SLOTCTL_PWR_INDICATOR_MASK; 2263 slot_p->hs_power_led_state = state; 2264 break; 2265 case PCIE_HP_ATTN_LED: 2266 /* clear led mask */ 2267 control &= ~PCIE_SLOTCTL_ATTN_INDICATOR_MASK; 2268 slot_p->hs_attn_led_state = state; 2269 break; 2270 default: 2271 PCIE_DBG("pciehpc_set_led_state() invalid LED %d\n", led); 2272 return; 2273 } 2274 2275 switch (state) { 2276 case PCIE_HP_LED_ON: 2277 if (led == PCIE_HP_POWER_LED) 2278 control = pcie_slotctl_pwr_indicator_set(control, 2279 PCIE_SLOTCTL_INDICATOR_STATE_ON); 2280 else if (led == PCIE_HP_ATTN_LED) 2281 control = pcie_slotctl_attn_indicator_set(control, 2282 PCIE_SLOTCTL_INDICATOR_STATE_ON); 2283 break; 2284 case PCIE_HP_LED_OFF: 2285 if (led == PCIE_HP_POWER_LED) 2286 control = pcie_slotctl_pwr_indicator_set(control, 2287 PCIE_SLOTCTL_INDICATOR_STATE_OFF); 2288 else if (led == PCIE_HP_ATTN_LED) 2289 control = pcie_slotctl_attn_indicator_set(control, 2290 PCIE_SLOTCTL_INDICATOR_STATE_OFF); 2291 break; 2292 case PCIE_HP_LED_BLINK: 2293 if (led == PCIE_HP_POWER_LED) 2294 control = pcie_slotctl_pwr_indicator_set(control, 2295 PCIE_SLOTCTL_INDICATOR_STATE_BLINK); 2296 else if (led == PCIE_HP_ATTN_LED) 2297 control = pcie_slotctl_attn_indicator_set(control, 2298 PCIE_SLOTCTL_INDICATOR_STATE_BLINK); 2299 break; 2300 2301 default: 2302 PCIE_DBG("pciehpc_set_led_state() invalid LED state %d\n", 2303 state); 2304 return; 2305 } 2306 2307 /* update the Slot Control Register */ 2308 pciehpc_issue_hpc_command(ctrl_p, control); 2309 2310 #ifdef DEBUG 2311 /* get the current state of Slot Control register */ 2312 control = pciehpc_reg_get16(ctrl_p, 2313 bus_p->bus_pcie_off + PCIE_SLOTCTL); 2314 2315 PCIE_DBG("pciehpc_set_led_state: slot %d power-led %s attn-led %s\n", 2316 slot_p->hs_phy_slot_num, pcie_led_state_text( 2317 pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control))), 2318 pcie_led_state_text(pciehpc_led_state_to_hpc( 2319 pcie_slotctl_attn_indicator_get(control)))); 2320 #endif 2321 } 2322 2323 static void 2324 pciehpc_handle_power_fault(dev_info_t *dip) 2325 { 2326 /* 2327 * Hold the parent's ref so that it won't disappear when the taskq is 2328 * scheduled to run. 2329 */ 2330 ndi_hold_devi(dip); 2331 2332 if (taskq_dispatch(system_taskq, pciehpc_power_fault_handler, dip, 2333 TQ_NOSLEEP) == TASKQID_INVALID) { 2334 ndi_rele_devi(dip); 2335 PCIE_DBG("pciehpc_intr(): " 2336 "Failed to dispatch power fault handler, dip %p\n", dip); 2337 } 2338 } 2339 2340 static void 2341 pciehpc_power_fault_handler(void *arg) 2342 { 2343 dev_info_t *dip = (dev_info_t *)arg; 2344 pcie_hp_ctrl_t *ctrl_p; 2345 pcie_hp_slot_t *slot_p; 2346 2347 /* get the soft state structure for this dip */ 2348 if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) { 2349 ndi_rele_devi(dip); 2350 return; 2351 } 2352 slot_p = ctrl_p->hc_slots[0]; 2353 2354 /* 2355 * Send the event to DDI Hotplug framework, power off 2356 * the slot 2357 */ 2358 (void) ndi_hp_state_change_req(dip, 2359 slot_p->hs_info.cn_name, 2360 DDI_HP_CN_STATE_EMPTY, DDI_HP_REQ_SYNC); 2361 2362 mutex_enter(&ctrl_p->hc_mutex); 2363 pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, 2364 PCIE_HP_LED_ON); 2365 mutex_exit(&ctrl_p->hc_mutex); 2366 ndi_rele_devi(dip); 2367 } 2368 2369 #ifdef DEBUG 2370 /* 2371 * Dump PCI-E Hot Plug registers. 2372 */ 2373 static void 2374 pciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p) 2375 { 2376 pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; 2377 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 2378 uint16_t control; 2379 uint32_t capabilities; 2380 2381 if (!pcie_debug_flags) 2382 return; 2383 2384 capabilities = pciehpc_reg_get32(ctrl_p, 2385 bus_p->bus_pcie_off + PCIE_SLOTCAP); 2386 2387 control = pciehpc_reg_get16(ctrl_p, 2388 bus_p->bus_pcie_off + PCIE_SLOTCTL); 2389 2390 PCIE_DBG("pciehpc_dump_hpregs: Found PCI-E hot plug slot %d\n", 2391 slot_p->hs_phy_slot_num); 2392 2393 PCIE_DBG("Attention Button Present = %s\n", 2394 capabilities & PCIE_SLOTCAP_ATTN_BUTTON ? "Yes":"No"); 2395 2396 PCIE_DBG("Power controller Present = %s\n", 2397 capabilities & PCIE_SLOTCAP_POWER_CONTROLLER ? "Yes":"No"); 2398 2399 PCIE_DBG("MRL Sensor Present = %s\n", 2400 capabilities & PCIE_SLOTCAP_MRL_SENSOR ? "Yes":"No"); 2401 2402 PCIE_DBG("Attn Indicator Present = %s\n", 2403 capabilities & PCIE_SLOTCAP_ATTN_INDICATOR ? "Yes":"No"); 2404 2405 PCIE_DBG("Power Indicator Present = %s\n", 2406 capabilities & PCIE_SLOTCAP_PWR_INDICATOR ? "Yes":"No"); 2407 2408 PCIE_DBG("HotPlug Surprise = %s\n", 2409 capabilities & PCIE_SLOTCAP_HP_SURPRISE ? "Yes":"No"); 2410 2411 PCIE_DBG("HotPlug Capable = %s\n", 2412 capabilities & PCIE_SLOTCAP_HP_CAPABLE ? "Yes":"No"); 2413 2414 PCIE_DBG("Physical Slot Number = %d\n", 2415 PCIE_SLOTCAP_PHY_SLOT_NUM(capabilities)); 2416 2417 PCIE_DBG("Attn Button interrupt Enabled = %s\n", 2418 control & PCIE_SLOTCTL_ATTN_BTN_EN ? "Yes":"No"); 2419 2420 PCIE_DBG("Power Fault interrupt Enabled = %s\n", 2421 control & PCIE_SLOTCTL_PWR_FAULT_EN ? "Yes":"No"); 2422 2423 PCIE_DBG("MRL Sensor INTR Enabled = %s\n", 2424 control & PCIE_SLOTCTL_MRL_SENSOR_EN ? "Yes":"No"); 2425 2426 PCIE_DBG("Presence interrupt Enabled = %s\n", 2427 control & PCIE_SLOTCTL_PRESENCE_CHANGE_EN ? "Yes":"No"); 2428 2429 PCIE_DBG("Cmd Complete interrupt Enabled = %s\n", 2430 control & PCIE_SLOTCTL_CMD_INTR_EN ? "Yes":"No"); 2431 2432 PCIE_DBG("HotPlug interrupt Enabled = %s\n", 2433 control & PCIE_SLOTCTL_HP_INTR_EN ? "Yes":"No"); 2434 2435 PCIE_DBG("Power Indicator LED = %s", pcie_led_state_text( 2436 pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control)))); 2437 2438 PCIE_DBG("Attn Indicator LED = %s\n", 2439 pcie_led_state_text(pciehpc_led_state_to_hpc( 2440 pcie_slotctl_attn_indicator_get(control)))); 2441 } 2442 #endif /* DEBUG */ 2443