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