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