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