1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * This file contains PCI HotPlug functionality that is compatible with the 28 * PCI SHPC specification 1.x. 29 * 30 * NOTE: This file is compiled and delivered through misc/pcie module. 31 */ 32 33 #include <sys/note.h> 34 #include <sys/conf.h> 35 #include <sys/kmem.h> 36 #include <sys/kstat.h> 37 #include <sys/debug.h> 38 #include <sys/vtrace.h> 39 #include <sys/autoconf.h> 40 #include <sys/varargs.h> 41 #include <sys/hwconf.h> 42 #include <sys/ddi_impldefs.h> 43 #include <sys/callb.h> 44 #include <sys/ddi.h> 45 #include <sys/sunddi.h> 46 #include <sys/sunndi.h> 47 #include <sys/sysevent/dr.h> 48 #include <sys/ndi_impldefs.h> 49 #include <sys/pci_impl.h> 50 #include <sys/hotplug/pci/pcie_hp.h> 51 #include <sys/hotplug/pci/pcishpc.h> 52 53 typedef struct pcishpc_prop { 54 char *prop_name; 55 char *prop_value; 56 } pcishpc_prop_t; 57 58 static pcishpc_prop_t pcishpc_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 /* reset delay to 1 sec. */ 69 static int pcishpc_reset_delay = 1000000; 70 71 /* Local function prototype */ 72 static pcie_hp_ctrl_t *pcishpc_create_controller(dev_info_t *dip); 73 static int pcishpc_setup_controller(pcie_hp_ctrl_t *ctrl_p); 74 static int pcishpc_destroy_controller(dev_info_t *dip); 75 static pcie_hp_slot_t *pcishpc_create_slot(pcie_hp_ctrl_t *ctrl_p); 76 static int pcishpc_register_slot(pcie_hp_ctrl_t *ctrl_p, int slot); 77 static int pcishpc_destroy_slots(pcie_hp_ctrl_t *ctrl_p); 78 static int pcishpc_enable_irqs(pcie_hp_ctrl_t *ctrl_p); 79 static int pcishpc_disable_irqs(pcie_hp_ctrl_t *ctrl_p); 80 static int pcishpc_slot_get_property(pcie_hp_slot_t *slot_p, 81 ddi_hp_property_t *arg, ddi_hp_property_t *rval); 82 static int pcishpc_slot_set_property(pcie_hp_slot_t *slot_p, 83 ddi_hp_property_t *arg, ddi_hp_property_t *rval); 84 static int pcishpc_issue_command(pcie_hp_ctrl_t *ctrl_p, 85 uint32_t cmd_code); 86 static int pcishpc_wait_busy(pcie_hp_ctrl_t *ctrl_p); 87 static void pcishpc_attn_btn_handler(pcie_hp_slot_t *slot_p); 88 static void pcishpc_get_slot_state(pcie_hp_slot_t *slot_p); 89 static int pcishpc_set_slot_state(pcie_hp_slot_t *slot_p, 90 ddi_hp_cn_state_t new_slot_state); 91 static void pcishpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p, int slot); 92 static int pcishpc_set_bus_speed(pcie_hp_slot_t *slot_p); 93 static int pcishpc_setled(pcie_hp_slot_t *slot_p, pcie_hp_led_t led, 94 pcie_hp_led_state_t state); 95 static int pcishpc_led_shpc_to_hpc(int state); 96 static int pcishpc_led_hpc_to_shpc(int state); 97 static int pcishpc_slot_shpc_to_hpc(int shpc_state); 98 static int pcishpc_slot_hpc_to_shpc(int state); 99 static char *pcishpc_slot_textslotstate(ddi_hp_cn_state_t state); 100 static char *pcishpc_slot_textledstate(pcie_hp_led_state_t state); 101 102 static uint32_t pcishpc_read_reg(pcie_hp_ctrl_t *ctrl_p, int reg); 103 static void pcishpc_write_reg(pcie_hp_ctrl_t *ctrl_p, int reg, 104 uint32_t data); 105 106 static int pcishpc_upgrade_slot_state(pcie_hp_slot_t *slot_p, 107 ddi_hp_cn_state_t target_state); 108 static int pcishpc_downgrade_slot_state(pcie_hp_slot_t *slot_p, 109 ddi_hp_cn_state_t target_state); 110 static int pcishpc_change_slot_state(pcie_hp_slot_t *slot_p, 111 ddi_hp_cn_state_t target_state); 112 113 static int pcishpc_slot_poweron(pcie_hp_slot_t *slot_p, 114 ddi_hp_cn_state_t *result_state); 115 static int pcishpc_slot_poweroff(pcie_hp_slot_t *slot_p, 116 ddi_hp_cn_state_t *result_state); 117 static int pcishpc_slot_probe(pcie_hp_slot_t *slot_p); 118 static int pcishpc_slot_unprobe(pcie_hp_slot_t *slot_p); 119 #ifdef DEBUG 120 static void pcishpc_dump_regs(pcie_hp_ctrl_t *ctrl_p); 121 #endif /* DEBUG */ 122 123 124 /* 125 * Global functions (called by other drivers/modules) 126 */ 127 128 /* 129 * pcishpc_init() 130 * 131 * Install and configure an SHPC controller and register the HotPlug slots 132 * with the Solaris HotPlug framework. This function is usually called by 133 * a PCI bridge Nexus driver that has a built in SHPC controller. 134 */ 135 int 136 pcishpc_init(dev_info_t *dip) 137 { 138 pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 139 pcie_hp_ctrl_t *ctrl_p; 140 int i; 141 142 PCIE_DBG("pcishpc_init() called from %s#%d\n", 143 ddi_driver_name(dip), ddi_get_instance(dip)); 144 145 if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) != NULL) { 146 PCIE_DBG("pcishpc_init() shpc instance already " 147 "initialized!\n"); 148 return (DDI_SUCCESS); 149 } 150 151 /* Initialize soft state structure for the SHPC instance. */ 152 ctrl_p = pcishpc_create_controller(dip); 153 154 if (ctrl_p == NULL) { 155 PCIE_DBG("pcishpc_init() failed to create shpc softstate\n"); 156 return (DDI_FAILURE); 157 } 158 159 if (pcishpc_setup_controller(ctrl_p) != DDI_SUCCESS) { 160 PCIE_DBG("pcishpc_init() failed to setup controller\n"); 161 goto cleanup; 162 } 163 164 /* 165 * Setup resource maps for this bus node. 166 */ 167 (void) pci_resource_setup(dip); 168 169 #ifdef DEBUG 170 PCIE_DBG("%s%d: P2P bridge register dump:\n", 171 ddi_driver_name(dip), ddi_get_instance(dip)); 172 173 for (i = 0; i < 0x100; i += 4) { 174 PCIE_DBG("SHPC Cfg reg 0x%02x: %08x\n", i, 175 pci_config_get32(bus_p->bus_cfg_hdl, i)); 176 } 177 #endif /* DEBUG */ 178 179 /* Setup each HotPlug slot on this SHPC controller. */ 180 for (i = 0; i < ctrl_p->hc_num_slots_impl; i++) { 181 if (pcishpc_register_slot(ctrl_p, i) != DDI_SUCCESS) { 182 PCIE_DBG("pcishpc_init() failed to register " 183 "slot %d\n", i); 184 goto cleanup1; 185 } 186 if (pcie_create_minor_node(ctrl_p, i) != DDI_SUCCESS) { 187 PCIE_DBG("pcishpc_init() failed to create " 188 "minor node for slot %d\n", i); 189 goto cleanup1; 190 } 191 } 192 193 (void) pcishpc_enable_irqs(ctrl_p); 194 195 #ifdef DEBUG 196 /* Dump out the SHPC registers. */ 197 pcishpc_dump_regs(ctrl_p); 198 #endif /* DEBUG */ 199 200 PCIE_DBG("pcishpc_init() success(dip=%p)\n", dip); 201 return (DDI_SUCCESS); 202 203 cleanup1: 204 for (i = 0; i < ctrl_p->hc_num_slots_impl; i++) { 205 if (ctrl_p->hc_slots[i] == NULL) 206 continue; 207 208 pcie_remove_minor_node(ctrl_p, i); 209 } 210 (void) pci_resource_destroy(dip); 211 cleanup: 212 (void) pcishpc_destroy_controller(dip); 213 return (DDI_FAILURE); 214 } 215 216 /* 217 * pcishpc_uninit() 218 * Unload the HogPlug controller driver and deallocate all resources. 219 */ 220 int 221 pcishpc_uninit(dev_info_t *dip) 222 { 223 pcie_hp_ctrl_t *ctrl_p; 224 int i; 225 226 PCIE_DBG("pcishpc_uninit() called(dip=%p)\n", dip); 227 228 ctrl_p = PCIE_GET_HP_CTRL(dip); 229 230 if (!ctrl_p) { 231 PCIE_DBG("pcishpc_uninit() Unable to find softstate\n"); 232 return (DDI_FAILURE); 233 } 234 235 for (i = 0; i < PCIE_HP_MAX_SLOTS; i++) { 236 if (ctrl_p->hc_slots[i] == NULL) 237 continue; 238 239 pcie_remove_minor_node(ctrl_p, i); 240 } 241 242 (void) pcishpc_disable_irqs(ctrl_p); 243 ctrl_p->hc_flags = 0; 244 245 /* 246 * Destroy resource maps for this bus node. 247 */ 248 (void) pci_resource_destroy(dip); 249 250 (void) pcishpc_destroy_controller(dip); 251 252 PCIE_DBG("pcishpc_uninit() success(dip=%p)\n", dip); 253 254 return (DDI_SUCCESS); 255 } 256 257 /* 258 * pcishpc_intr() 259 * 260 * This is the SHPC controller interrupt handler. 261 */ 262 int 263 pcishpc_intr(dev_info_t *dip) 264 { 265 pcie_hp_ctrl_t *ctrl_p; 266 uint32_t irq_locator, irq_serr_locator, reg; 267 int slot; 268 269 PCIE_DBG("pcishpc_intr() called\n"); 270 271 /* get the soft state structure for this dip */ 272 if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) 273 return (DDI_INTR_UNCLAIMED); 274 275 mutex_enter(&ctrl_p->hc_mutex); 276 277 if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) { 278 PCIE_DBG("pcishpc_intr() unclaimed\n"); 279 mutex_exit(&ctrl_p->hc_mutex); 280 return (DDI_INTR_UNCLAIMED); 281 } 282 283 PCIE_DBG("pcishpc_intr() interrupt received\n"); 284 285 reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG); 286 287 if (reg & PCI_HP_SERR_INT_CMD_COMPLETE_IRQ) { 288 PCIE_DBG("pcishpc_intr() " 289 "PCI_HP_SERR_INT_CMD_COMPLETE_IRQ detected\n"); 290 ctrl_p->hc_cmd_pending = B_FALSE; 291 cv_signal(&ctrl_p->hc_cmd_comp_cv); 292 } 293 294 if (reg & PCI_HP_SERR_INT_ARBITER_IRQ) { 295 PCIE_DBG("pcishpc_intr() PCI_HP_SERR_INT_ARBITER_IRQ " 296 "detected\n"); 297 ctrl_p->hc_arbiter_timeout = B_TRUE; 298 } 299 300 /* Write back the SERR INT register to acknowledge the IRQs. */ 301 pcishpc_write_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG, reg); 302 303 irq_locator = pcishpc_read_reg(ctrl_p, PCI_HP_IRQ_LOCATOR_REG); 304 irq_serr_locator = pcishpc_read_reg(ctrl_p, PCI_HP_SERR_LOCATOR_REG); 305 306 /* Check for slot events that might have occured. */ 307 for (slot = 0; slot < ctrl_p->hc_num_slots_impl; slot++) { 308 if ((irq_locator & (PCI_HP_IRQ_SLOT_N_PENDING<<slot)) || 309 (irq_serr_locator & 310 (PCI_HP_IRQ_SERR_SLOT_N_PENDING<<slot))) { 311 PCIE_DBG("pcishpc_intr() slot %d and " 312 "pending IRQ\n", slot+1); 313 314 reg = pcishpc_read_reg(ctrl_p, 315 PCI_HP_LOGICAL_SLOT_REGS+slot); 316 317 if (reg & PCI_HP_SLOT_PRESENCE_DETECTED) 318 PCIE_DBG("slot %d: " 319 "PCI_HP_SLOT_PRESENCE_DETECTED\n", 320 slot+1); 321 322 if (reg & PCI_HP_SLOT_ISO_PWR_DETECTED) 323 PCIE_DBG("slot %d: " 324 "PCI_HP_SLOT_ISO_PWR_DETECTED\n", 325 slot+1); 326 327 if (reg & PCI_HP_SLOT_ATTN_DETECTED) { 328 PCIE_DBG("slot %d: " 329 "PCI_HP_SLOT_ATTN_DETECTED\n", slot+1); 330 331 /* 332 * if ATTN button event is still pending 333 * then cancel it 334 */ 335 if (ctrl_p->hc_slots[slot]-> 336 hs_attn_btn_pending == B_TRUE) 337 ctrl_p->hc_slots[slot]-> 338 hs_attn_btn_pending = B_FALSE; 339 340 /* wake up the ATTN event handler */ 341 cv_signal(&ctrl_p->hc_slots[slot]-> 342 hs_attn_btn_cv); 343 } 344 345 if (reg & PCI_HP_SLOT_MRL_DETECTED) 346 PCIE_DBG("slot %d: " 347 "PCI_HP_SLOT_MRL_DETECTED\n", slot+1); 348 349 if (reg & PCI_HP_SLOT_POWER_DETECTED) 350 PCIE_DBG("slot %d: " 351 "PCI_HP_SLOT_POWER_DETECTED\n", slot+1); 352 353 /* Acknoledge any slot interrupts */ 354 pcishpc_write_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot, 355 reg); 356 } 357 } 358 359 mutex_exit(&ctrl_p->hc_mutex); 360 361 PCIE_DBG("pcishpc_intr() claimed\n"); 362 363 return (DDI_INTR_CLAIMED); 364 } 365 366 int 367 pcishpc_slot_get_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg, 368 ddi_hp_property_t *rval) 369 { 370 ddi_hp_property_t request, result; 371 #ifdef _SYSCALL32_IMPL 372 ddi_hp_property32_t request32, result32; 373 #endif 374 pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; 375 nvlist_t *prop_list; 376 nvlist_t *prop_rlist; /* nvlist for return values */ 377 nvpair_t *prop_pair; 378 char *name, *value; 379 int ret = DDI_SUCCESS; 380 int i, n; 381 boolean_t get_all_prop = B_FALSE; 382 383 if (get_udatamodel() == DATAMODEL_NATIVE) { 384 if (copyin(arg, &request, sizeof (ddi_hp_property_t)) || 385 copyin(rval, &result, sizeof (ddi_hp_property_t))) 386 return (DDI_FAILURE); 387 } 388 #ifdef _SYSCALL32_IMPL 389 else { 390 bzero(&request, sizeof (request)); 391 bzero(&result, sizeof (result)); 392 if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)) || 393 copyin(rval, &result32, sizeof (ddi_hp_property32_t))) 394 return (DDI_FAILURE); 395 request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf; 396 request.buf_size = request32.buf_size; 397 result.nvlist_buf = (char *)(uintptr_t)result32.nvlist_buf; 398 result.buf_size = result32.buf_size; 399 } 400 #endif 401 402 if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size, 403 &prop_list)) != DDI_SUCCESS) 404 return (ret); 405 406 if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) { 407 ret = DDI_ENOMEM; 408 goto get_prop_cleanup; 409 } 410 411 /* check whether the requested property is "all" or "help" */ 412 prop_pair = nvlist_next_nvpair(prop_list, NULL); 413 if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair)) { 414 name = nvpair_name(prop_pair); 415 n = sizeof (pcishpc_props) / sizeof (pcishpc_prop_t); 416 417 if (strcmp(name, PCIEHPC_PROP_ALL) == 0) { 418 (void) nvlist_remove_all(prop_list, PCIEHPC_PROP_ALL); 419 420 /* 421 * Add all properties into the request list, so that we 422 * will get the values in the following for loop. 423 */ 424 for (i = 0; i < n; i++) { 425 if (nvlist_add_string(prop_list, 426 pcishpc_props[i].prop_name, "") != 0) { 427 ret = DDI_FAILURE; 428 goto get_prop_cleanup1; 429 } 430 } 431 get_all_prop = B_TRUE; 432 } else if (strcmp(name, PCIEHPC_PROP_HELP) == 0) { 433 /* 434 * Empty the request list, and add help strings into the 435 * return list. We will pass the following for loop. 436 */ 437 (void) nvlist_remove_all(prop_list, PCIEHPC_PROP_HELP); 438 439 for (i = 0; i < n; i++) { 440 if (nvlist_add_string(prop_rlist, 441 pcishpc_props[i].prop_name, 442 pcishpc_props[i].prop_value) != 0) { 443 ret = DDI_FAILURE; 444 goto get_prop_cleanup1; 445 } 446 } 447 } 448 } 449 450 mutex_enter(&ctrl_p->hc_mutex); 451 452 /* get the current slot state */ 453 pcishpc_get_slot_state(slot_p); 454 455 /* for each requested property, get the value and add it to nvlist */ 456 prop_pair = NULL; 457 while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) { 458 name = nvpair_name(prop_pair); 459 460 if (strcmp(name, PCIEHPC_PROP_LED_FAULT) == 0) { 461 value = pcie_led_state_text( 462 slot_p->hs_fault_led_state); 463 } else if (strcmp(name, PCIEHPC_PROP_LED_POWER) == 0) { 464 value = pcie_led_state_text( 465 slot_p->hs_power_led_state); 466 } else if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) { 467 value = pcie_led_state_text( 468 slot_p->hs_attn_led_state); 469 } else if (strcmp(name, PCIEHPC_PROP_LED_ACTIVE) == 0) { 470 value = pcie_led_state_text( 471 slot_p->hs_active_led_state); 472 } else if (strcmp(name, PCIEHPC_PROP_CARD_TYPE) == 0) { 473 ddi_acc_handle_t handle; 474 dev_info_t *cdip; 475 uint8_t prog_class, base_class, sub_class; 476 int i; 477 478 mutex_exit(&ctrl_p->hc_mutex); 479 cdip = pcie_hp_devi_find( 480 ctrl_p->hc_dip, slot_p->hs_device_num, 0); 481 mutex_enter(&ctrl_p->hc_mutex); 482 483 if ((slot_p->hs_info.cn_state != 484 DDI_HP_CN_STATE_ENABLED) || (cdip == NULL)) { 485 /* 486 * When getting all properties, just ignore the 487 * one that's not available under certain state. 488 */ 489 if (get_all_prop) 490 continue; 491 492 ret = DDI_ENOTSUP; 493 goto get_prop_cleanup2; 494 } 495 496 if (pci_config_setup(cdip, &handle) != DDI_SUCCESS) { 497 ret = DDI_FAILURE; 498 goto get_prop_cleanup2; 499 } 500 501 prog_class = pci_config_get8(handle, 502 PCI_CONF_PROGCLASS); 503 base_class = pci_config_get8(handle, PCI_CONF_BASCLASS); 504 sub_class = pci_config_get8(handle, PCI_CONF_SUBCLASS); 505 pci_config_teardown(&handle); 506 507 for (i = 0; i < class_pci_items; i++) { 508 if ((base_class == class_pci[i].base_class) && 509 (sub_class == class_pci[i].sub_class) && 510 (prog_class == class_pci[i].prog_class)) { 511 value = class_pci[i].short_desc; 512 break; 513 } 514 } 515 if (i == class_pci_items) 516 value = PCIEHPC_PROP_VALUE_UNKNOWN; 517 } else if (strcmp(name, PCIEHPC_PROP_BOARD_TYPE) == 0) { 518 if (slot_p->hs_info.cn_state <= DDI_HP_CN_STATE_EMPTY) 519 value = PCIEHPC_PROP_VALUE_UNKNOWN; 520 else 521 value = PCIEHPC_PROP_VALUE_PCIHOTPLUG; 522 } else if (strcmp(name, PCIEHPC_PROP_SLOT_CONDITION) == 0) { 523 value = pcie_slot_condition_text(slot_p->hs_condition); 524 } else { 525 /* unsupported property */ 526 cmn_err(CE_WARN, "Unsupported property: %s\n", name); 527 528 ret = DDI_ENOTSUP; 529 goto get_prop_cleanup2; 530 } 531 if (nvlist_add_string(prop_rlist, name, value) != 0) { 532 ret = DDI_FAILURE; 533 goto get_prop_cleanup2; 534 } 535 } 536 537 // pack nvlist and copyout 538 if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf, 539 &result.buf_size)) != DDI_SUCCESS) { 540 goto get_prop_cleanup2; 541 } 542 if (get_udatamodel() == DATAMODEL_NATIVE) { 543 if (copyout(&result, rval, sizeof (ddi_hp_property_t))) { 544 ret = DDI_FAILURE; 545 goto get_prop_cleanup2; 546 } 547 } 548 #ifdef _SYSCALL32_IMPL 549 else { 550 if (result.buf_size > UINT32_MAX) { 551 ret = DDI_FAILURE; 552 } else { 553 result32.buf_size = (uint32_t)result.buf_size; 554 if (copyout(&result32, rval, 555 sizeof (ddi_hp_property32_t))) 556 ret = DDI_FAILURE; 557 } 558 } 559 #endif 560 561 get_prop_cleanup2: 562 mutex_exit(&ctrl_p->hc_mutex); 563 get_prop_cleanup1: 564 nvlist_free(prop_rlist); 565 get_prop_cleanup: 566 nvlist_free(prop_list); 567 return (ret); 568 } 569 570 int 571 pcishpc_slot_set_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg, 572 ddi_hp_property_t *rval) 573 { 574 ddi_hp_property_t request, result; 575 #ifdef _SYSCALL32_IMPL 576 ddi_hp_property32_t request32, result32; 577 #endif 578 pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; 579 nvlist_t *prop_list; 580 nvlist_t *prop_rlist; 581 nvpair_t *prop_pair; 582 char *name, *value; 583 pcie_hp_led_state_t led_state; 584 int ret = DDI_SUCCESS; 585 586 if (get_udatamodel() == DATAMODEL_NATIVE) { 587 if (copyin(arg, &request, sizeof (ddi_hp_property_t))) 588 return (DDI_FAILURE); 589 if (rval && 590 copyin(rval, &result, sizeof (ddi_hp_property_t))) 591 return (DDI_FAILURE); 592 } 593 #ifdef _SYSCALL32_IMPL 594 else { 595 bzero(&request, sizeof (request)); 596 bzero(&result, sizeof (result)); 597 if (copyin(arg, &request32, sizeof (ddi_hp_property32_t))) 598 return (DDI_FAILURE); 599 if (rval && 600 copyin(rval, &result32, sizeof (ddi_hp_property32_t))) 601 return (DDI_FAILURE); 602 request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf; 603 request.buf_size = request32.buf_size; 604 if (rval) { 605 result.nvlist_buf = 606 (char *)(uintptr_t)result32.nvlist_buf; 607 result.buf_size = result32.buf_size; 608 } 609 } 610 #endif 611 612 if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size, 613 &prop_list)) != DDI_SUCCESS) 614 return (ret); 615 616 /* check whether the requested property is "help" */ 617 prop_pair = nvlist_next_nvpair(prop_list, NULL); 618 if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair) && 619 (strcmp(nvpair_name(prop_pair), PCIEHPC_PROP_HELP) == 0)) { 620 if (!rval) { 621 ret = DDI_ENOTSUP; 622 goto set_prop_cleanup; 623 } 624 625 if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) { 626 ret = DDI_ENOMEM; 627 goto set_prop_cleanup; 628 } 629 if (nvlist_add_string(prop_rlist, PCIEHPC_PROP_LED_ATTN, 630 PCIEHPC_PROP_VALUE_LED) != 0) { 631 ret = DDI_FAILURE; 632 goto set_prop_cleanup1; 633 } 634 635 if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf, 636 &result.buf_size)) != DDI_SUCCESS) { 637 goto set_prop_cleanup1; 638 } 639 if (get_udatamodel() == DATAMODEL_NATIVE) { 640 if (copyout(&result, rval, 641 sizeof (ddi_hp_property_t))) { 642 ret = DDI_FAILURE; 643 goto set_prop_cleanup1; 644 } 645 } 646 #ifdef _SYSCALL32_IMPL 647 else { 648 if (result.buf_size > UINT32_MAX) { 649 ret = DDI_FAILURE; 650 goto set_prop_cleanup1; 651 } else { 652 result32.buf_size = (uint32_t)result.buf_size; 653 if (copyout(&result32, rval, 654 sizeof (ddi_hp_property32_t))) { 655 ret = DDI_FAILURE; 656 goto set_prop_cleanup1; 657 } 658 } 659 } 660 #endif 661 set_prop_cleanup1: 662 nvlist_free(prop_rlist); 663 nvlist_free(prop_list); 664 return (ret); 665 } 666 667 /* Validate the request */ 668 prop_pair = NULL; 669 while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) { 670 name = nvpair_name(prop_pair); 671 if (nvpair_type(prop_pair) != DATA_TYPE_STRING) { 672 cmn_err(CE_WARN, "Unexpected data type of setting " 673 "property %s.\n", name); 674 ret = DDI_EINVAL; 675 goto set_prop_cleanup; 676 } 677 if (nvpair_value_string(prop_pair, &value)) { 678 cmn_err(CE_WARN, "Get string value failed for property " 679 "%s.\n", name); 680 ret = DDI_FAILURE; 681 goto set_prop_cleanup; 682 } 683 684 if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) { 685 if ((strcmp(value, PCIEHPC_PROP_VALUE_ON) != 0) && 686 (strcmp(value, PCIEHPC_PROP_VALUE_OFF) != 0) && 687 (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) != 0)) { 688 cmn_err(CE_WARN, "Unsupported value of setting " 689 "property %s\n", name); 690 ret = DDI_ENOTSUP; 691 goto set_prop_cleanup; 692 } 693 } else { 694 cmn_err(CE_WARN, "Unsupported property: %s\n", name); 695 ret = DDI_ENOTSUP; 696 goto set_prop_cleanup; 697 } 698 } 699 700 mutex_enter(&ctrl_p->hc_mutex); 701 702 /* get the current slot state */ 703 pcishpc_get_slot_state(slot_p); 704 705 // set each property 706 prop_pair = NULL; 707 while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) { 708 name = nvpair_name(prop_pair); 709 710 if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) { 711 if (strcmp(value, PCIEHPC_PROP_VALUE_ON) == 0) 712 led_state = PCIE_HP_LED_ON; 713 else if (strcmp(value, PCIEHPC_PROP_VALUE_OFF) == 0) 714 led_state = PCIE_HP_LED_OFF; 715 else if (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) == 0) 716 led_state = PCIE_HP_LED_BLINK; 717 718 (void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, 719 led_state); 720 } 721 } 722 723 mutex_exit(&ctrl_p->hc_mutex); 724 set_prop_cleanup: 725 nvlist_free(prop_list); 726 return (ret); 727 } 728 729 /* 730 * pcishpc_hp_ops() 731 * 732 * Handle hotplug commands 733 * 734 * Note: This function is called by DDI HP framework at kernel context only 735 */ 736 /* ARGSUSED */ 737 int 738 pcishpc_hp_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op, 739 void *arg, void *result) 740 { 741 pcie_hp_slot_t *slot_p = NULL; 742 pcie_hp_ctrl_t *ctrl_p; 743 int ret = DDI_SUCCESS, i; 744 745 PCIE_DBG("pcishpc_hp_ops: dip=%p cn_name=%s op=%x arg=%p\n", 746 dip, cn_name, op, arg); 747 748 if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) 749 return (DDI_FAILURE); 750 751 for (i = 0; i < PCIE_HP_MAX_SLOTS && ctrl_p->hc_slots[i]; i++) { 752 if (strcmp(ctrl_p->hc_slots[i]->hs_info.cn_name, cn_name) 753 == 0) { 754 /* Match with a physical slot, found */ 755 slot_p = ctrl_p->hc_slots[i]; 756 break; 757 } 758 } 759 if (!slot_p) { 760 PCIE_DBG("pcishpc_hp_ops: Failed to find the slot under" 761 "dip %p with name: %s; op=%x arg=%p\n", 762 dip, cn_name, op, arg); 763 return (DDI_EINVAL); 764 } 765 switch (op) { 766 case DDI_HPOP_CN_GET_STATE: 767 { 768 mutex_enter(&ctrl_p->hc_mutex); 769 770 /* get the current slot state */ 771 pcishpc_get_slot_state(slot_p); 772 773 *((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state; 774 775 mutex_exit(&ctrl_p->hc_mutex); 776 break; 777 } 778 case DDI_HPOP_CN_CHANGE_STATE: 779 { 780 ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg; 781 782 mutex_enter(&slot_p->hs_ctrl->hc_mutex); 783 784 ret = pcishpc_change_slot_state(slot_p, target_state); 785 *((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state; 786 787 mutex_exit(&slot_p->hs_ctrl->hc_mutex); 788 break; 789 } 790 case DDI_HPOP_CN_PROBE: 791 ret = pcishpc_slot_probe(slot_p); 792 793 break; 794 case DDI_HPOP_CN_UNPROBE: 795 ret = pcishpc_slot_unprobe(slot_p); 796 797 break; 798 case DDI_HPOP_CN_GET_PROPERTY: 799 ret = pcishpc_slot_get_property(slot_p, 800 (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result); 801 break; 802 case DDI_HPOP_CN_SET_PROPERTY: 803 ret = pcishpc_slot_set_property(slot_p, 804 (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result); 805 break; 806 default: 807 ret = DDI_ENOTSUP; 808 break; 809 } 810 811 return (ret); 812 } 813 814 /* 815 * Local functions (called within this file) 816 */ 817 818 /* 819 * pcishpc_create_controller() 820 * 821 * This function allocates and creates an SHPC controller state structure 822 * and adds it to the linked list of controllers. 823 */ 824 static pcie_hp_ctrl_t * 825 pcishpc_create_controller(dev_info_t *dip) 826 { 827 pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 828 pcie_hp_ctrl_t *ctrl_p; 829 830 PCIE_DBG("pcishpc: create controller for %s#%d\n", 831 ddi_driver_name(dip), ddi_get_instance(dip)); 832 833 ctrl_p = kmem_zalloc(sizeof (pcie_hp_ctrl_t), KM_SLEEP); 834 ctrl_p->hc_dip = dip; 835 836 cv_init(&ctrl_p->hc_cmd_comp_cv, NULL, CV_DRIVER, NULL); 837 838 /* Init the shpc controller's mutex. */ 839 mutex_init(&ctrl_p->hc_mutex, NULL, MUTEX_DRIVER, NULL); 840 841 /* HPC initialization is complete now */ 842 ctrl_p->hc_flags = PCIE_HP_INITIALIZED_FLAG; 843 bus_p->bus_hp_curr_mode = PCIE_PCI_HP_MODE; 844 845 PCIE_SET_HP_CTRL(dip, ctrl_p); 846 847 PCIE_DBG("pcishpc_create_controller() success\n"); 848 849 return (ctrl_p); 850 } 851 852 853 /* 854 * pcishpc_setup_controller() 855 * 856 * Get the number of HotPlug Slots, and the PCI device information 857 * for this HotPlug controller. 858 */ 859 static int 860 pcishpc_setup_controller(pcie_hp_ctrl_t *ctrl_p) 861 { 862 uint32_t config; 863 dev_info_t *ppdip; 864 865 config = pcishpc_read_reg(ctrl_p, PCI_HP_SLOT_CONFIGURATION_REG); 866 867 /* Get the number of HotPlug slots implemented */ 868 ctrl_p->hc_num_slots_impl = ((config)&31); 869 870 /* 871 * Initilize the current bus speed and number of hotplug slots 872 * currently connected. 873 */ 874 ctrl_p->hc_curr_bus_speed = -1; 875 ctrl_p->hc_num_slots_connected = 0; 876 877 /* 878 * Get the first PCI device Number used. 879 * 880 * PCI-X I/O boat workaround. 881 * The register doesn't set up the correct value. 882 */ 883 ppdip = ddi_get_parent(ddi_get_parent(ctrl_p->hc_dip)); 884 if ((ddi_prop_get_int(DDI_DEV_T_ANY, ppdip, DDI_PROP_DONTPASS, 885 "vendor-id", -1) == 0x108e) && 886 (ddi_prop_get_int(DDI_DEV_T_ANY, ppdip, DDI_PROP_DONTPASS, 887 "device-id", -1) == 0x9010)) 888 ctrl_p->hc_device_start = 4; 889 else 890 ctrl_p->hc_device_start = ((config>>8)&31); 891 892 /* Get the first Physical device number. */ 893 ctrl_p->hc_phys_start = ((config>>16)&0x7ff); 894 895 /* Check if the device numbers increase or decrease. */ 896 ctrl_p->hc_device_increases = ((config>>29)&0x1); 897 898 ctrl_p->hc_has_attn = 899 (config & PCI_HP_SLOT_CONFIG_ATTN_BUTTON) ? B_TRUE : B_FALSE; 900 ctrl_p->hc_has_mrl = 901 (config & PCI_HP_SLOT_CONFIG_MRL_SENSOR) ? B_TRUE : B_FALSE; 902 903 ctrl_p->hc_cmd_pending = B_FALSE; 904 ctrl_p->hc_arbiter_timeout = B_FALSE; 905 906 if (ctrl_p->hc_num_slots_impl > PCIE_HP_MAX_SLOTS) { 907 PCIE_DBG("pcishpc_setup_controller() too many SHPC " 908 "slots error\n"); 909 return (DDI_FAILURE); 910 } 911 912 return (DDI_SUCCESS); 913 } 914 915 916 /* 917 * pcishpc_destroy_controller() 918 * 919 * This function deallocates all of the SHPC controller resources. 920 */ 921 static int 922 pcishpc_destroy_controller(dev_info_t *dip) 923 { 924 pcie_hp_ctrl_t *ctrl_p; 925 pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 926 927 PCIE_DBG("pcishpc_destroy_controller() called(dip=%p)\n", dip); 928 929 /* get the soft state structure for this dip */ 930 if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) { 931 PCIE_DBG("pcishpc_destroy_controller() not found\n"); 932 return (DDI_FAILURE); 933 } 934 935 /* 936 * Deallocate the slot state structures for this controller. 937 */ 938 (void) pcishpc_destroy_slots(ctrl_p); 939 cv_destroy(&ctrl_p->hc_cmd_comp_cv); 940 mutex_destroy(&ctrl_p->hc_mutex); 941 kmem_free(ctrl_p, sizeof (pcie_hp_ctrl_t)); 942 bus_p->bus_hp_curr_mode = PCIE_NONE_HP_MODE; 943 944 PCIE_DBG("pcishpc_destroy_controller() success\n"); 945 return (DDI_SUCCESS); 946 } 947 948 /* 949 * pcishpc_create_slot() 950 * 951 * Allocate and add a new HotPlug slot state structure to the linked list. 952 */ 953 static pcie_hp_slot_t * 954 pcishpc_create_slot(pcie_hp_ctrl_t *ctrl_p) 955 { 956 pcie_hp_slot_t *slot_p; 957 958 PCIE_DBG("pcishpc_create_slot() called(ctrl_p=%x)\n", ctrl_p); 959 960 /* Allocate a new slot structure. */ 961 slot_p = kmem_zalloc(sizeof (pcie_hp_slot_t), KM_SLEEP); 962 slot_p->hs_ctrl = ctrl_p; 963 964 /* Assign an initial value */ 965 slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY; 966 967 PCIE_DBG("pcishpc_create_slot() success\n"); 968 return (slot_p); 969 } 970 971 /* 972 * pcishpc_register_slot() 973 * 974 * Create and register a slot with the Solaris HotPlug framework. 975 */ 976 static int 977 pcishpc_register_slot(pcie_hp_ctrl_t *ctrl_p, int slot) 978 { 979 dev_info_t *dip = ctrl_p->hc_dip; 980 pcie_hp_slot_t *slot_p; 981 982 slot_p = pcishpc_create_slot(ctrl_p); 983 ctrl_p->hc_slots[slot] = slot_p; 984 slot_p->hs_num = slot; 985 986 /* Setup the PCI device # for this SHPC slot. */ 987 if (ctrl_p->hc_device_increases) 988 slot_p->hs_device_num = ctrl_p->hc_device_start + 989 slot_p->hs_num; 990 else 991 slot_p->hs_device_num = ctrl_p->hc_device_start - 992 slot_p->hs_num; 993 994 /* Setup the DDI HP framework slot information. */ 995 slot_p->hs_info.cn_type = DDI_HP_CN_TYPE_PCI; 996 slot_p->hs_info.cn_type_str = PCIE_PCI_HP_TYPE; 997 slot_p->hs_info.cn_child = NULL; 998 999 slot_p->hs_minor = PCI_MINOR_NUM( 1000 ddi_get_instance(dip), slot_p->hs_device_num); 1001 slot_p->hs_condition = AP_COND_UNKNOWN; 1002 1003 /* setup thread for handling ATTN button events */ 1004 if (ctrl_p->hc_has_attn) { 1005 PCIE_DBG("pcishpc_register_slot: " 1006 "setting up ATTN button event " 1007 "handler thread for slot %d\n", slot); 1008 1009 cv_init(&slot_p->hs_attn_btn_cv, NULL, CV_DRIVER, NULL); 1010 slot_p->hs_attn_btn_pending = B_FALSE; 1011 slot_p->hs_attn_btn_threadp = thread_create(NULL, 0, 1012 pcishpc_attn_btn_handler, 1013 (void *)slot_p, 0, &p0, TS_RUN, minclsyspri); 1014 slot_p->hs_attn_btn_thread_exit = B_FALSE; 1015 } 1016 1017 /* setup the slot name (used for ap-id) */ 1018 pcishpc_set_slot_name(ctrl_p, slot); 1019 1020 pcishpc_get_slot_state(slot_p); 1021 if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_ENABLED) 1022 slot_p->hs_condition = AP_COND_OK; 1023 1024 /* register the slot with DDI HP framework */ 1025 if (ndi_hp_register(dip, &slot_p->hs_info) != NDI_SUCCESS) { 1026 PCIE_DBG("pciehpc_register_slot() failed to register slot %d\n", 1027 slot_p->hs_phy_slot_num); 1028 return (DDI_FAILURE); 1029 } 1030 1031 pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip), 1032 slot_p->hs_minor), slot_p->hs_device_num); 1033 1034 PCIE_DBG("pcishpc_register_slot() success for slot %d\n", slot); 1035 1036 return (DDI_SUCCESS); 1037 } 1038 1039 /* 1040 * pcishpc_destroy_slots() 1041 * 1042 * Free up all of the slot resources for this controller. 1043 */ 1044 static int 1045 pcishpc_destroy_slots(pcie_hp_ctrl_t *ctrl_p) 1046 { 1047 dev_info_t *dip = ctrl_p->hc_dip; 1048 pcie_hp_slot_t *slot_p; 1049 int i; 1050 1051 PCIE_DBG("pcishpc_destroy_slots() called(ctrl_p=%p)\n", ctrl_p); 1052 1053 for (i = 0; i < PCIE_HP_MAX_SLOTS; i++) { 1054 if ((slot_p = ctrl_p->hc_slots[i]) == NULL) 1055 continue; 1056 1057 if (slot_p->hs_attn_btn_threadp != NULL) { 1058 mutex_enter(&ctrl_p->hc_mutex); 1059 slot_p->hs_attn_btn_thread_exit = B_TRUE; 1060 cv_signal(&slot_p->hs_attn_btn_cv); 1061 PCIE_DBG("pcishpc_destroy_slots: " 1062 "waiting for ATTN thread exit\n"); 1063 cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex); 1064 PCIE_DBG("pcishpc_destroy_slots: " 1065 "ATTN thread exit\n"); 1066 cv_destroy(&slot_p->hs_attn_btn_cv); 1067 slot_p->hs_attn_btn_threadp = NULL; 1068 mutex_exit(&ctrl_p->hc_mutex); 1069 } 1070 1071 PCIE_DBG("pcishpc_destroy_slots() (shpc_p=%p)\n" 1072 "destroyed", slot_p); 1073 1074 pcie_hp_delete_occupant_props(dip, 1075 makedevice(ddi_driver_major(dip), 1076 slot_p->hs_minor)); 1077 1078 /* unregister the slot with DDI HP framework */ 1079 if (ndi_hp_unregister(dip, slot_p->hs_info.cn_name) != 1080 NDI_SUCCESS) { 1081 PCIE_DBG("pcishpc_destroy_slots() " 1082 "failed to unregister slot %d\n", 1083 slot_p->hs_phy_slot_num); 1084 return (DDI_FAILURE); 1085 } 1086 kmem_free(slot_p->hs_info.cn_name, 1087 strlen(slot_p->hs_info.cn_name) + 1); 1088 kmem_free(slot_p, sizeof (pcie_hp_slot_t)); 1089 } 1090 1091 return (DDI_SUCCESS); 1092 } 1093 1094 /* 1095 * pcishpc_enable_irqs() 1096 * 1097 * Enable/unmask the different IRQ's we support from the SHPC controller. 1098 */ 1099 static int 1100 pcishpc_enable_irqs(pcie_hp_ctrl_t *ctrl_p) 1101 { 1102 uint32_t reg; 1103 int slot; 1104 1105 reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG); 1106 1107 /* Enable all interrupts. */ 1108 reg &= ~PCI_HP_SERR_INT_MASK_ALL; 1109 1110 pcishpc_write_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG, reg); 1111 1112 /* Unmask the interrupts for each slot. */ 1113 for (slot = 0; slot < ctrl_p->hc_num_slots_impl; slot++) { 1114 reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot); 1115 if ((reg & PCI_HP_SLOT_STATE_MASK) == PCI_HP_SLOT_ENABLED) { 1116 reg &= ~(PCI_HP_SLOT_MASK_ALL | 1117 PCI_HP_SLOT_MRL_SERR_MASK); 1118 ctrl_p->hc_num_slots_connected++; 1119 if (ctrl_p->hc_curr_bus_speed == -1) 1120 ctrl_p->hc_curr_bus_speed = 1121 pcishpc_read_reg(ctrl_p, 1122 PCI_HP_PROF_IF_SBCR_REG) & 1123 PCI_HP_SBCR_SPEED_MASK; 1124 } else { 1125 reg &= ~(PCI_HP_SLOT_MASK_ALL); 1126 } 1127 1128 /* Enable/Unmask all slot interrupts. */ 1129 pcishpc_write_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot, reg); 1130 } 1131 1132 PCIE_DBG("pcishpc_enable_irqs: ctrl_p 0x%p, " 1133 "current bus speed 0x%x, slots connected 0x%x\n", ctrl_p, 1134 ctrl_p->hc_curr_bus_speed, ctrl_p->hc_num_slots_connected); 1135 1136 return (DDI_SUCCESS); 1137 } 1138 1139 1140 /* 1141 * pcishpc_disable_irqs() 1142 * 1143 * Disable/Mask the different IRQ's we support from the SHPC controller. 1144 */ 1145 static int 1146 pcishpc_disable_irqs(pcie_hp_ctrl_t *ctrl_p) 1147 { 1148 uint32_t reg; 1149 int slot; 1150 1151 reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG); 1152 1153 /* Mask all interrupts. */ 1154 reg |= PCI_HP_SERR_INT_MASK_ALL; 1155 1156 pcishpc_write_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG, reg); 1157 1158 /* Unmask the interrupts for each slot. */ 1159 for (slot = 0; slot < ctrl_p->hc_num_slots_impl; slot++) { 1160 reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot); 1161 1162 /* Disable/Mask all slot interrupts. */ 1163 reg |= PCI_HP_SLOT_MASK_ALL; 1164 1165 pcishpc_write_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot, reg); 1166 } 1167 1168 PCIE_DBG("pcishpc_disable_irqs: ctrl_p 0x%p, " 1169 "current bus speed 0x%x, slots connected 0x%x\n", ctrl_p, 1170 ctrl_p->hc_curr_bus_speed, ctrl_p->hc_num_slots_connected); 1171 1172 return (DDI_SUCCESS); 1173 } 1174 1175 /* 1176 * pcishpc_slot_poweron() 1177 * 1178 * Poweron/Enable the slot. 1179 * 1180 * Note: This function is called by DDI HP framework at kernel context only 1181 */ 1182 /*ARGSUSED*/ 1183 static int 1184 pcishpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result_state) 1185 { 1186 uint32_t status; 1187 1188 PCIE_DBG("pcishpc_slot_poweron called()\n"); 1189 1190 ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex)); 1191 1192 /* get the current slot state */ 1193 pcishpc_get_slot_state(slot_p); 1194 1195 /* check if the slot is already in the 'enabled' state */ 1196 if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) { 1197 /* slot is already in the 'enabled' state */ 1198 PCIE_DBG("pcishpc_slot_poweron() slot %d already enabled\n", 1199 slot_p->hs_phy_slot_num); 1200 1201 *result_state = slot_p->hs_info.cn_state; 1202 return (DDI_SUCCESS); 1203 } 1204 1205 if (slot_p->hs_info.cn_state == DDI_HP_CN_STATE_EMPTY) { 1206 PCIE_DBG("pcishpc_slot_poweron() slot in empty state\n"); 1207 goto cleanup; 1208 } 1209 1210 /* make sure the MRL sensor is closed */ 1211 status = pcishpc_read_reg(slot_p->hs_ctrl, 1212 PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num); 1213 1214 if (status & PCI_HP_SLOT_MRL_STATE_MASK) { 1215 PCIE_DBG("pcishpc_slot_poweron() failed: MRL open\n"); 1216 goto cleanup; 1217 } 1218 1219 /* Set the Power LED to blink */ 1220 (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK); 1221 1222 /* Turn all other LEDS off */ 1223 (void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF); 1224 (void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF); 1225 (void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF); 1226 1227 /* Set the bus speed only if the bus segment is not running */ 1228 if (pcishpc_set_bus_speed(slot_p) != DDI_SUCCESS) { 1229 PCIE_DBG("pcishpc_slot_poweron() setting speed failed\n"); 1230 goto cleanup; 1231 } 1232 1233 slot_p->hs_ctrl->hc_num_slots_connected++; 1234 1235 PCIE_DBG("pcishpc_slot_poweron(): slot_p 0x%p, slot state 0x%x, " 1236 "current bus speed 0x%x, slots connected 0x%x\n", slot_p, 1237 slot_p->hs_info.cn_state, slot_p->hs_ctrl->hc_curr_bus_speed, 1238 slot_p->hs_ctrl->hc_num_slots_connected); 1239 1240 /* Mask or Unmask MRL Sensor SEER bit based on new slot state */ 1241 if (slot_p->hs_ctrl->hc_has_mrl == B_TRUE) { 1242 uint32_t reg; 1243 1244 reg = pcishpc_read_reg(slot_p->hs_ctrl, 1245 PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num); 1246 1247 pcishpc_write_reg(slot_p->hs_ctrl, 1248 PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num, 1249 reg & ~PCI_HP_SLOT_MRL_SERR_MASK); 1250 } 1251 1252 /* Update the hardware slot state. */ 1253 if (pcishpc_set_slot_state(slot_p, 1254 DDI_HP_CN_STATE_ENABLED) != DDI_SUCCESS) { 1255 PCIE_DBG("pcishpc_slot_poweron() failed\n"); 1256 1257 pcishpc_get_slot_state(slot_p); 1258 goto cleanup; 1259 } 1260 /* Update the current state. It will be used in pcishpc_setled() */ 1261 slot_p->hs_info.cn_state = DDI_HP_CN_STATE_ENABLED; 1262 1263 /* Turn the Power LED ON for a enabled slot. */ 1264 (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_ON); 1265 1266 /* Turn all other LEDS off. */ 1267 (void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF); 1268 (void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF); 1269 (void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF); 1270 1271 /* delay after powerON to let the device initialize itself */ 1272 delay(drv_usectohz(pcishpc_reset_delay)); 1273 1274 PCIE_DBG("pcishpc_slot_poweron() success!\n"); 1275 1276 /* 1277 * Want to show up as POWERED state for now. It will be updated to 1278 * ENABLED state when user explicitly enable the slot. 1279 */ 1280 slot_p->hs_info.cn_state = DDI_HP_CN_STATE_POWERED; 1281 1282 /* get the current slot state */ 1283 pcishpc_get_slot_state(slot_p); 1284 /* 1285 * It should be poweron'ed now. Have a check here in case any 1286 * hardware problems. 1287 */ 1288 if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) { 1289 PCIE_DBG("pcishpc_slot_poweron() failed after hardware" 1290 " registers all programmed.\n"); 1291 1292 goto cleanup; 1293 } 1294 1295 *result_state = slot_p->hs_info.cn_state; 1296 1297 return (DDI_SUCCESS); 1298 1299 cleanup: 1300 (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF); 1301 return (DDI_FAILURE); 1302 } 1303 1304 /*ARGSUSED*/ 1305 static int 1306 pcishpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result_state) 1307 { 1308 PCIE_DBG("pcishpc_slot_poweroff called()\n"); 1309 1310 ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex)); 1311 1312 /* get the current slot state */ 1313 pcishpc_get_slot_state(slot_p); 1314 1315 /* check if the slot is not in the "enabled" or "powered" state */ 1316 if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) { 1317 /* slot is in the 'disabled' state */ 1318 PCIE_DBG("pcishpc_slot_poweroff(): " 1319 "slot %d already disabled\n", slot_p->hs_phy_slot_num); 1320 1321 *result_state = slot_p->hs_info.cn_state; 1322 return (DDI_SUCCESS); 1323 } 1324 1325 /* Set the Power LED to blink */ 1326 (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK); 1327 1328 /* Turn all other LEDS off */ 1329 (void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF); 1330 (void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF); 1331 (void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF); 1332 1333 if (--slot_p->hs_ctrl->hc_num_slots_connected == 0) 1334 slot_p->hs_ctrl->hc_curr_bus_speed = -1; 1335 1336 PCIE_DBG("pcishpc_slot_poweroff(): slot_p 0x%p, slot state 0x%x, " 1337 "current bus speed 0x%x, slots connected 0x%x\n", slot_p, 1338 slot_p->hs_info.cn_state, slot_p->hs_ctrl->hc_curr_bus_speed, 1339 slot_p->hs_ctrl->hc_num_slots_connected); 1340 1341 /* Mask or Unmask MRL Sensor SEER bit based on new slot state */ 1342 if (slot_p->hs_ctrl->hc_has_mrl == B_TRUE) { 1343 uint32_t reg; 1344 1345 reg = pcishpc_read_reg(slot_p->hs_ctrl, 1346 PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num); 1347 1348 pcishpc_write_reg(slot_p->hs_ctrl, 1349 PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num, 1350 reg | PCI_HP_SLOT_MRL_SERR_MASK); 1351 } 1352 1353 /* Update the hardware slot state. */ 1354 if (pcishpc_set_slot_state(slot_p, DDI_HP_CN_STATE_PRESENT) != 1355 DDI_SUCCESS) { 1356 PCIE_DBG("pcishpc_slot_poweroff() failed\n"); 1357 1358 pcishpc_get_slot_state(slot_p); 1359 goto cleanup; 1360 } 1361 1362 /* Update the current state. It will be used in pcishpc_setled() */ 1363 slot_p->hs_info.cn_state = DDI_HP_CN_STATE_PRESENT; 1364 1365 /* Turn the Power LED OFF for a disabled slot. */ 1366 (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF); 1367 1368 /* Turn all other LEDS off. */ 1369 (void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF); 1370 (void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF); 1371 (void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF); 1372 1373 /* delay after powerON to let the device initialize itself */ 1374 delay(drv_usectohz(pcishpc_reset_delay)); 1375 1376 pcishpc_get_slot_state(slot_p); 1377 /* 1378 * It should be poweroff'ed now. Have a check here in case any 1379 * hardware problems. 1380 */ 1381 if (slot_p->hs_info.cn_state > DDI_HP_CN_STATE_PRESENT) { 1382 PCIE_DBG("pcishpc_slot_poweroff() failed after hardware" 1383 " registers all programmed.\n"); 1384 1385 goto cleanup; 1386 } 1387 1388 PCIE_DBG("pcishpc_slot_poweroff() success!\n"); 1389 1390 *result_state = slot_p->hs_info.cn_state; 1391 return (DDI_SUCCESS); 1392 1393 cleanup: 1394 (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF); 1395 return (DDI_FAILURE); 1396 } 1397 1398 /* 1399 * pcishpc_slot_probe() 1400 * 1401 * Probe the slot. 1402 * 1403 * Note: This function is called by DDI HP framework at kernel context only 1404 */ 1405 /*ARGSUSED*/ 1406 static int 1407 pcishpc_slot_probe(pcie_hp_slot_t *slot_p) 1408 { 1409 mutex_enter(&slot_p->hs_ctrl->hc_mutex); 1410 1411 PCIE_DBG("pcishpc_slot_probe called()\n"); 1412 1413 /* get the current slot state */ 1414 pcishpc_get_slot_state(slot_p); 1415 1416 /* 1417 * Probe a given PCI Hotplug Connection (CN). 1418 */ 1419 if (pcie_hp_probe(slot_p) != DDI_SUCCESS) { 1420 (void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, 1421 PCIE_HP_LED_BLINK); 1422 1423 PCIE_DBG("pcishpc_slot_probe() failed\n"); 1424 1425 mutex_exit(&slot_p->hs_ctrl->hc_mutex); 1426 return (DDI_FAILURE); 1427 } 1428 1429 PCIE_DBG("pcishpc_slot_probe() success!\n"); 1430 1431 /* get the current slot state */ 1432 pcishpc_get_slot_state(slot_p); 1433 1434 mutex_exit(&slot_p->hs_ctrl->hc_mutex); 1435 return (DDI_SUCCESS); 1436 } 1437 1438 /* 1439 * pcishpc_slot_unprobe() 1440 * 1441 * Unprobe the slot. 1442 * 1443 * Note: This function is called by DDI HP framework at kernel context only 1444 */ 1445 /*ARGSUSED*/ 1446 static int 1447 pcishpc_slot_unprobe(pcie_hp_slot_t *slot_p) 1448 { 1449 mutex_enter(&slot_p->hs_ctrl->hc_mutex); 1450 1451 PCIE_DBG("pcishpc_slot_unprobe called()\n"); 1452 1453 /* get the current slot state */ 1454 pcishpc_get_slot_state(slot_p); 1455 1456 /* 1457 * Unprobe a given PCI Hotplug Connection (CN). 1458 */ 1459 if (pcie_hp_unprobe(slot_p) != DDI_SUCCESS) { 1460 (void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, 1461 PCIE_HP_LED_BLINK); 1462 1463 PCIE_DBG("pcishpc_slot_unprobe() failed\n"); 1464 1465 mutex_exit(&slot_p->hs_ctrl->hc_mutex); 1466 return (DDI_FAILURE); 1467 } 1468 1469 PCIE_DBG("pcishpc_slot_unprobe() success!\n"); 1470 1471 /* get the current slot state */ 1472 pcishpc_get_slot_state(slot_p); 1473 1474 mutex_exit(&slot_p->hs_ctrl->hc_mutex); 1475 return (DDI_SUCCESS); 1476 } 1477 1478 static int 1479 pcishpc_upgrade_slot_state(pcie_hp_slot_t *slot_p, 1480 ddi_hp_cn_state_t target_state) 1481 { 1482 ddi_hp_cn_state_t curr_state; 1483 int rv = DDI_SUCCESS; 1484 1485 if (target_state > DDI_HP_CN_STATE_ENABLED) { 1486 return (DDI_EINVAL); 1487 } 1488 1489 curr_state = slot_p->hs_info.cn_state; 1490 while ((curr_state < target_state) && (rv == DDI_SUCCESS)) { 1491 1492 switch (curr_state) { 1493 case DDI_HP_CN_STATE_EMPTY: 1494 /* 1495 * From EMPTY to PRESENT, just check the hardware 1496 * slot state. 1497 */ 1498 pcishpc_get_slot_state(slot_p); 1499 curr_state = slot_p->hs_info.cn_state; 1500 if (curr_state < DDI_HP_CN_STATE_PRESENT) 1501 rv = DDI_FAILURE; 1502 break; 1503 case DDI_HP_CN_STATE_PRESENT: 1504 rv = pcishpc_slot_poweron(slot_p, &curr_state); 1505 break; 1506 case DDI_HP_CN_STATE_POWERED: 1507 curr_state = slot_p->hs_info.cn_state = 1508 DDI_HP_CN_STATE_ENABLED; 1509 break; 1510 default: 1511 /* should never reach here */ 1512 ASSERT("unknown devinfo state"); 1513 } 1514 } 1515 1516 return (rv); 1517 } 1518 1519 static int 1520 pcishpc_downgrade_slot_state(pcie_hp_slot_t *slot_p, 1521 ddi_hp_cn_state_t target_state) 1522 { 1523 ddi_hp_cn_state_t curr_state; 1524 int rv = DDI_SUCCESS; 1525 1526 1527 curr_state = slot_p->hs_info.cn_state; 1528 while ((curr_state > target_state) && (rv == DDI_SUCCESS)) { 1529 1530 switch (curr_state) { 1531 case DDI_HP_CN_STATE_PRESENT: 1532 /* 1533 * From PRESENT to EMPTY, just check hardware 1534 * slot state. 1535 */ 1536 pcishpc_get_slot_state(slot_p); 1537 curr_state = slot_p->hs_info.cn_state; 1538 if (curr_state >= DDI_HP_CN_STATE_PRESENT) 1539 rv = DDI_FAILURE; 1540 break; 1541 case DDI_HP_CN_STATE_POWERED: 1542 rv = pcishpc_slot_poweroff(slot_p, &curr_state); 1543 1544 break; 1545 case DDI_HP_CN_STATE_ENABLED: 1546 curr_state = slot_p->hs_info.cn_state = 1547 DDI_HP_CN_STATE_POWERED; 1548 1549 break; 1550 default: 1551 /* should never reach here */ 1552 ASSERT("unknown devinfo state"); 1553 } 1554 } 1555 1556 return (rv); 1557 } 1558 1559 /* Change slot state to a target state */ 1560 static int 1561 pcishpc_change_slot_state(pcie_hp_slot_t *slot_p, 1562 ddi_hp_cn_state_t target_state) 1563 { 1564 ddi_hp_cn_state_t curr_state; 1565 int rv; 1566 1567 pcishpc_get_slot_state(slot_p); 1568 curr_state = slot_p->hs_info.cn_state; 1569 1570 if (curr_state == target_state) { 1571 return (DDI_SUCCESS); 1572 } 1573 if (curr_state < target_state) { 1574 1575 rv = pcishpc_upgrade_slot_state(slot_p, target_state); 1576 } else { 1577 rv = pcishpc_downgrade_slot_state(slot_p, target_state); 1578 } 1579 1580 return (rv); 1581 } 1582 1583 /* 1584 * pcishpc_issue_command() 1585 * 1586 * Sends a command to the SHPC controller. 1587 */ 1588 static int 1589 pcishpc_issue_command(pcie_hp_ctrl_t *ctrl_p, uint32_t cmd_code) 1590 { 1591 int retCode; 1592 1593 ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex)); 1594 1595 PCIE_DBG("pcishpc_issue_command() cmd_code=%02x\n", cmd_code); 1596 1597 ctrl_p->hc_cmd_pending = B_TRUE; 1598 1599 /* Write the command to the SHPC controller. */ 1600 pcishpc_write_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG, cmd_code); 1601 1602 while (ctrl_p->hc_cmd_pending == B_TRUE) 1603 cv_wait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex); 1604 1605 /* Wait until the SHPC controller processes the command. */ 1606 retCode = pcishpc_wait_busy(ctrl_p); 1607 1608 /* Make sure the command completed. */ 1609 if (retCode == DDI_SUCCESS) { 1610 /* Did the command fail to generate the command complete IRQ? */ 1611 if (ctrl_p->hc_cmd_pending != B_FALSE) { 1612 PCIE_DBG("pcishpc_issue_command() Failed on " 1613 "generate cmd complete IRQ\n"); 1614 retCode = DDI_FAILURE; 1615 } 1616 } 1617 1618 if (retCode == DDI_FAILURE) 1619 PCIE_DBG("pcishpc_issue_command() Failed on cmd_code=%02x\n", 1620 cmd_code); 1621 else 1622 PCIE_DBG("pcishpc_issue_command() Success on " 1623 "cmd_code=%02x\n", cmd_code); 1624 1625 return (retCode); 1626 } 1627 1628 /* 1629 * pcishpc_wait_busy() 1630 * 1631 * Wait until the SHPC controller is not busy. 1632 */ 1633 static int 1634 pcishpc_wait_busy(pcie_hp_ctrl_t *ctrl_p) 1635 { 1636 uint32_t status; 1637 1638 /* Wait until SHPC controller is NOT busy */ 1639 for (;;) { 1640 status = pcishpc_read_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG); 1641 1642 /* Is there an MRL Sensor error? */ 1643 if ((status & PCI_HP_COMM_STS_ERR_MASK) == 1644 PCI_HP_COMM_STS_ERR_MRL_OPEN) { 1645 PCIE_DBG("pcishpc_wait_busy() ERROR: " 1646 "MRL Sensor error\n"); 1647 break; 1648 } 1649 1650 /* Is there an Invalid command error? */ 1651 if ((status & PCI_HP_COMM_STS_ERR_MASK) == 1652 PCI_HP_COMM_STS_ERR_INVALID_COMMAND) { 1653 PCIE_DBG("pcishpc_wait_busy() ERROR: Invalid " 1654 "command error\n"); 1655 break; 1656 } 1657 1658 /* Is there an Invalid Speed/Mode error? */ 1659 if ((status & PCI_HP_COMM_STS_ERR_MASK) == 1660 PCI_HP_COMM_STS_ERR_INVALID_SPEED) { 1661 PCIE_DBG("pcishpc_wait_busy() ERROR: Invalid " 1662 "Speed/Mode error\n"); 1663 break; 1664 } 1665 1666 /* Is the SHPC controller not BUSY? */ 1667 if (!(status & PCI_HP_COMM_STS_CTRL_BUSY)) { 1668 /* Return Success. */ 1669 return (DDI_SUCCESS); 1670 } 1671 1672 PCIE_DBG("pcishpc_wait_busy() SHPC controller busy. Waiting\n"); 1673 1674 /* Wait before polling the status register again. */ 1675 delay(drv_usectohz(PCIE_HP_CMD_WAIT_TIME)); 1676 } 1677 1678 return (DDI_FAILURE); 1679 } 1680 1681 static void 1682 pcishpc_attn_btn_handler(pcie_hp_slot_t *slot_p) 1683 { 1684 pcie_hp_led_state_t hs_power_led_state; 1685 callb_cpr_t cprinfo; 1686 1687 PCIE_DBG("pcishpc_attn_btn_handler: thread started\n"); 1688 1689 CALLB_CPR_INIT(&cprinfo, &slot_p->hs_ctrl->hc_mutex, 1690 callb_generic_cpr, "pcishpc_attn_btn_handler"); 1691 1692 mutex_enter(&slot_p->hs_ctrl->hc_mutex); 1693 1694 /* wait for ATTN button event */ 1695 cv_wait(&slot_p->hs_attn_btn_cv, &slot_p->hs_ctrl->hc_mutex); 1696 1697 while (slot_p->hs_attn_btn_thread_exit == B_FALSE) { 1698 if (slot_p->hs_attn_btn_pending == B_TRUE) { 1699 /* get the current state of power LED */ 1700 hs_power_led_state = slot_p->hs_power_led_state; 1701 1702 /* Blink the Power LED while we wait for 5 seconds */ 1703 (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, 1704 PCIE_HP_LED_BLINK); 1705 1706 /* wait for 5 seconds before taking any action */ 1707 if (cv_timedwait(&slot_p->hs_attn_btn_cv, 1708 &slot_p->hs_ctrl->hc_mutex, 1709 ddi_get_lbolt() + SEC_TO_TICK(5)) == -1) { 1710 /* 1711 * It is a time out; 1712 * make sure the ATTN pending flag is 1713 * still ON before sending the event 1714 * to DDI HP framework. 1715 */ 1716 if (slot_p->hs_attn_btn_pending == B_TRUE) { 1717 int hint; 1718 1719 /* restore the power LED state */ 1720 (void) pcishpc_setled(slot_p, 1721 PCIE_HP_POWER_LED, 1722 hs_power_led_state); 1723 /* 1724 * send the ATTN button event 1725 * to DDI HP framework 1726 */ 1727 slot_p->hs_attn_btn_pending = B_FALSE; 1728 1729 pcishpc_get_slot_state(slot_p); 1730 1731 if (slot_p->hs_info.cn_state <= 1732 DDI_HP_CN_STATE_PRESENT) { 1733 /* 1734 * Insertion. 1735 */ 1736 hint = SE_INCOMING_RES; 1737 } else { 1738 /* 1739 * Want to remove; 1740 */ 1741 hint = SE_OUTGOING_RES; 1742 } 1743 pcie_hp_gen_sysevent_req( 1744 slot_p->hs_info.cn_name, 1745 hint, 1746 slot_p->hs_ctrl->hc_dip, 1747 KM_SLEEP); 1748 1749 continue; 1750 } 1751 } 1752 1753 /* restore the power LED state */ 1754 (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, 1755 hs_power_led_state); 1756 continue; 1757 } 1758 1759 /* wait for another ATTN button event */ 1760 cv_wait(&slot_p->hs_attn_btn_cv, &slot_p->hs_ctrl->hc_mutex); 1761 } 1762 1763 PCIE_DBG("pcishpc_attn_btn_handler: thread exit\n"); 1764 cv_signal(&slot_p->hs_attn_btn_cv); 1765 CALLB_CPR_EXIT(&cprinfo); 1766 thread_exit(); 1767 } 1768 1769 /* 1770 * pcishpc_get_slot_state() 1771 * 1772 * Get the state of the slot. 1773 * The slot state should have been initialized before this function gets called. 1774 */ 1775 static void 1776 pcishpc_get_slot_state(pcie_hp_slot_t *slot_p) 1777 { 1778 uint32_t reg; 1779 ddi_hp_cn_state_t curr_state = slot_p->hs_info.cn_state; 1780 1781 /* Read the logical slot register for this Slot. */ 1782 reg = pcishpc_read_reg(slot_p->hs_ctrl, 1783 PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num); 1784 1785 /* Convert from the SHPC slot state to the HPC slot state. */ 1786 slot_p->hs_info.cn_state = pcishpc_slot_shpc_to_hpc(reg); 1787 if (curr_state == DDI_HP_CN_STATE_POWERED && 1788 slot_p->hs_info.cn_state > DDI_HP_CN_STATE_POWERED) { 1789 /* 1790 * Keep POWERED state if it is currently POWERED state because 1791 * this driver does not really implement enable/disable 1792 * slot operations. That is, when poweron, it actually enables 1793 * the slot also. 1794 * So, from hardware view, POWERED == ENABLED. 1795 * But, when user explicitly change to POWERED state, it should 1796 * be kept until user explicitly change to other states later. 1797 */ 1798 slot_p->hs_info.cn_state = DDI_HP_CN_STATE_POWERED; 1799 } 1800 1801 /* Convert from the SHPC Power LED state to the HPC Power LED state. */ 1802 slot_p->hs_power_led_state = pcishpc_led_shpc_to_hpc((reg>>2)&3); 1803 1804 /* Convert from the SHPC Attn LED state to the HPC Attn LED state. */ 1805 slot_p->hs_attn_led_state = pcishpc_led_shpc_to_hpc((reg>>4)&3); 1806 1807 /* We don't have a fault LED so just default it to OFF. */ 1808 slot_p->hs_fault_led_state = PCIE_HP_LED_OFF; 1809 1810 /* We don't have an active LED so just default it to OFF. */ 1811 slot_p->hs_active_led_state = PCIE_HP_LED_OFF; 1812 } 1813 1814 /* 1815 * pcishpc_set_slot_state() 1816 * 1817 * Updates the slot's state and leds. 1818 */ 1819 static int 1820 pcishpc_set_slot_state(pcie_hp_slot_t *slot_p, 1821 ddi_hp_cn_state_t new_slot_state) 1822 { 1823 uint32_t reg, cmd_code; 1824 ddi_hp_cn_state_t curr_state; 1825 1826 ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex)); 1827 1828 reg = pcishpc_read_reg(slot_p->hs_ctrl, 1829 PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num); 1830 1831 /* Default all states to unchanged. */ 1832 cmd_code = ((1 + slot_p->hs_num) << 8); 1833 1834 /* Has the slot state changed? */ 1835 curr_state = pcishpc_slot_shpc_to_hpc(reg); 1836 if (curr_state != new_slot_state) { 1837 PCIE_DBG("pcishpc_set_slot_state() Slot State changed"); 1838 1839 /* Set the new slot state in the Slot operation command. */ 1840 cmd_code |= pcishpc_slot_hpc_to_shpc(new_slot_state); 1841 } 1842 1843 /* Has the Power LED state changed? */ 1844 if (slot_p->hs_power_led_state != pcishpc_led_shpc_to_hpc((reg>>2)&3)) { 1845 PCIE_DBG("pcishpc_set_slot_state() Power LED State changed\n"); 1846 1847 /* Set the new power led state in the Slot operation command. */ 1848 cmd_code |= 1849 (pcishpc_led_hpc_to_shpc(slot_p->hs_power_led_state) << 2); 1850 } 1851 1852 /* Has the Attn LED state changed? */ 1853 if (slot_p->hs_attn_led_state != pcishpc_led_shpc_to_hpc((reg>>4)&3)) { 1854 PCIE_DBG("pcishpc_set_slot_state() Attn LED State changed\n"); 1855 1856 /* Set the new attn led state in the Slot operation command. */ 1857 cmd_code |= 1858 (pcishpc_led_hpc_to_shpc(slot_p->hs_attn_led_state) << 4); 1859 } 1860 1861 return (pcishpc_issue_command(slot_p->hs_ctrl, cmd_code)); 1862 } 1863 1864 /* 1865 * setup slot name/slot-number info. 1866 */ 1867 static void 1868 pcishpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p, int slot) 1869 { 1870 pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[slot]; 1871 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 1872 uchar_t *slotname_data; 1873 int *slotnum; 1874 uint_t count; 1875 int len; 1876 uchar_t *s; 1877 uint32_t bit_mask; 1878 int pci_id_cnt, pci_id_bit; 1879 int slots_before, found; 1880 int invalid_slotnum = 0; 1881 1882 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ctrl_p->hc_dip, 1883 DDI_PROP_DONTPASS, "physical-slot#", &slotnum, &count) == 1884 DDI_PROP_SUCCESS) { 1885 slot_p->hs_phy_slot_num = slotnum[0]; 1886 ddi_prop_free(slotnum); 1887 } else { 1888 if (ctrl_p->hc_device_increases) 1889 slot_p->hs_phy_slot_num = ctrl_p->hc_phys_start + slot; 1890 else 1891 slot_p->hs_phy_slot_num = ctrl_p->hc_phys_start - slot; 1892 1893 if ((ndi_prop_update_int(DDI_DEV_T_NONE, ctrl_p->hc_dip, 1894 "physical-slot#", slot_p->hs_phy_slot_num)) != DDI_SUCCESS) 1895 PCIE_DBG("pcishpc_set_slot_name(): failed to " 1896 "create phyical-slot#%d\n", 1897 slot_p->hs_phy_slot_num); 1898 } 1899 1900 /* Platform may not have initialized it */ 1901 if (!slot_p->hs_phy_slot_num) { 1902 slot_p->hs_phy_slot_num = pci_config_get8(bus_p->bus_cfg_hdl, 1903 PCI_BCNF_SECBUS); 1904 invalid_slotnum = 1; 1905 } 1906 slot_p->hs_info.cn_num = slot_p->hs_phy_slot_num; 1907 slot_p->hs_info.cn_num_dpd_on = DDI_HP_CN_NUM_NONE; 1908 1909 /* 1910 * construct the slot_name: 1911 * if "slot-names" property exists then use that name 1912 * else if valid slot number exists then it is "pci<slot-num>". 1913 * else it will be "pci<sec-bus-number>dev<dev-number>" 1914 */ 1915 if (ddi_getlongprop(DDI_DEV_T_ANY, ctrl_p->hc_dip, DDI_PROP_DONTPASS, 1916 "slot-names", (caddr_t)&slotname_data, &len) == DDI_PROP_SUCCESS) { 1917 bit_mask = slotname_data[3] | (slotname_data[2] << 8) | 1918 (slotname_data[1] << 16) | (slotname_data[0] << 24); 1919 1920 pci_id_bit = 1; 1921 pci_id_cnt = slots_before = found = 0; 1922 1923 /* 1924 * Walk the bit mask until we find the bit that corresponds 1925 * to our slots device number. We count how many bits 1926 * we find before we find our slot's bit. 1927 */ 1928 while (!found && (pci_id_cnt < 32)) { 1929 while (slot_p->hs_device_num != pci_id_cnt) { 1930 1931 /* 1932 * Find the next bit set. 1933 */ 1934 while (!(bit_mask & pci_id_bit) && 1935 (pci_id_cnt < 32)) { 1936 pci_id_bit = pci_id_bit << 1; 1937 pci_id_cnt++; 1938 } 1939 1940 if (slot_p->hs_device_num != pci_id_cnt) 1941 slots_before++; 1942 else 1943 found = 1; 1944 } 1945 } 1946 1947 if (pci_id_cnt < 32) { 1948 1949 /* 1950 * Set ptr to first string. 1951 */ 1952 s = slotname_data + 4; 1953 1954 /* 1955 * Increment past all the strings for the slots 1956 * before ours. 1957 */ 1958 while (slots_before) { 1959 while (*s != NULL) 1960 s++; 1961 s++; 1962 slots_before--; 1963 } 1964 1965 slot_p->hs_info.cn_name = i_ddi_strdup((char *)s, 1966 KM_SLEEP); 1967 kmem_free(slotname_data, len); 1968 return; 1969 } 1970 1971 /* slot-names entry not found */ 1972 PCIE_DBG("pcishpc_set_slot_name(): " 1973 "No slot-names entry found for slot #%d\n", 1974 slot_p->hs_phy_slot_num); 1975 kmem_free(slotname_data, len); 1976 } 1977 1978 if (invalid_slotnum) { 1979 char tmp_name[256]; 1980 1981 (void) snprintf(tmp_name, sizeof (tmp_name), "pci%d", 1982 slot_p->hs_device_num); 1983 slot_p->hs_info.cn_name = i_ddi_strdup(tmp_name, KM_SLEEP); 1984 } else { 1985 char tmp_name[256]; 1986 1987 (void) snprintf(tmp_name, sizeof (tmp_name), "pci%d", 1988 slot_p->hs_phy_slot_num); 1989 slot_p->hs_info.cn_name = i_ddi_strdup(tmp_name, KM_SLEEP); 1990 } 1991 } 1992 1993 /* 1994 * pcishpc_set_bus_speed() 1995 * 1996 * Set the bus speed and mode. 1997 */ 1998 static int 1999 pcishpc_set_bus_speed(pcie_hp_slot_t *slot_p) 2000 { 2001 pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; 2002 int curr_speed = ctrl_p->hc_curr_bus_speed; 2003 int speed = -1; 2004 int avail_slots; 2005 uint32_t status, slots_avail1_reg, slots_avail2_reg; 2006 2007 ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex)); 2008 2009 /* Make sure that the slot is in a correct state */ 2010 status = pcishpc_read_reg(ctrl_p, 2011 PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num); 2012 2013 /* Return failure if the slot is empty */ 2014 if ((status & PCI_HP_SLOT_CARD_EMPTY_MASK) == 2015 PCI_HP_SLOT_CARD_EMPTY_MASK) { 2016 PCIE_DBG("pcishpc_set_bus_speed() failed: " 2017 "the slot is empty\n"); 2018 return (DDI_FAILURE); 2019 } 2020 2021 /* Return failure if the slot is not in disabled state */ 2022 if ((status & PCI_HP_SLOT_STATE_MASK) != PCI_HP_SLOT_DISABLED) { 2023 PCIE_DBG("pcishpc_set_bus_speed() failed: " 2024 "incorrect slot state\n"); 2025 return (DDI_FAILURE); 2026 } 2027 2028 /* Set the "power-only" mode for the slot */ 2029 if (pcishpc_issue_command(ctrl_p, ((1+slot_p->hs_num)<<8) | 2030 PCI_HP_SLOT_POWER_ONLY) != DDI_SUCCESS) { 2031 PCIE_DBG("pcishpc_set_bus_speed() failed to set " 2032 "the slot %d in the power-only mode\n", slot_p->hs_num); 2033 return (DDI_FAILURE); 2034 } 2035 2036 /* Wait for power good */ 2037 delay(drv_usectohz(PCIE_HP_POWER_GOOD_WAIT_TIME)); 2038 2039 /* Make sure that the slot is in "power-only" state */ 2040 status = pcishpc_read_reg(ctrl_p, 2041 PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num); 2042 2043 if ((status & PCI_HP_SLOT_STATE_MASK) != PCI_HP_SLOT_POWER_ONLY) { 2044 PCIE_DBG("pcishpc_set_bus_speed() " 2045 "power-only failed: incorrect slot state\n"); 2046 return (DDI_FAILURE); 2047 } 2048 2049 slots_avail1_reg = pcishpc_read_reg(ctrl_p, 2050 PCI_HP_SLOTS_AVAIL_I_REG); 2051 slots_avail2_reg = pcishpc_read_reg(ctrl_p, 2052 PCI_HP_SLOTS_AVAIL_II_REG); 2053 2054 /* 2055 * Check if SHPC has available slots and select the highest 2056 * available bus speed for the slot. 2057 * 2058 * The bus speed codes are: 2059 * 100 - 133Mhz; <--+ 2060 * 011 - 100Mhz; <--+ PCI-X 2061 * 010 - 66Mhz; <--+ 2062 * 2063 * 001 - 66Mhz; <--+ 2064 * 000 - 33Mhz <--+ Conv PCI 2065 */ 2066 switch (status & PCI_HP_SLOT_PCIX_CAPABLE_MASK) { 2067 case PCI_HP_SLOT_133MHZ_PCIX_CAPABLE: 2068 avail_slots = (slots_avail1_reg >> 2069 PCI_HP_AVAIL_133MHZ_PCIX_SPEED_SHIFT) & 2070 PCI_HP_AVAIL_SPEED_MASK; 2071 2072 if (((curr_speed == -1) && avail_slots) || 2073 (curr_speed == PCI_HP_SBCR_133MHZ_PCIX_SPEED)) { 2074 speed = PCI_HP_SBCR_133MHZ_PCIX_SPEED; 2075 break; 2076 } 2077 /* FALLTHROUGH */ 2078 case PCI_HP_SLOT_100MHZ_PCIX_CAPABLE: 2079 avail_slots = (slots_avail1_reg >> 2080 PCI_HP_AVAIL_100MHZ_PCIX_SPEED_SHIFT) & 2081 PCI_HP_AVAIL_SPEED_MASK; 2082 2083 if (((curr_speed == -1) && avail_slots) || 2084 (curr_speed == PCI_HP_SBCR_100MHZ_PCIX_SPEED)) { 2085 speed = PCI_HP_SBCR_100MHZ_PCIX_SPEED; 2086 break; 2087 } 2088 /* FALLTHROUGH */ 2089 case PCI_HP_SLOT_66MHZ_PCIX_CAPABLE: 2090 avail_slots = (slots_avail1_reg >> 2091 PCI_HP_AVAIL_66MHZ_PCIX_SPEED_SHIFT) & 2092 PCI_HP_AVAIL_SPEED_MASK; 2093 2094 if (((curr_speed == -1) && avail_slots) || 2095 (curr_speed == PCI_HP_SBCR_66MHZ_PCIX_SPEED)) { 2096 speed = PCI_HP_SBCR_66MHZ_PCIX_SPEED; 2097 break; 2098 } 2099 /* FALLTHROUGH */ 2100 default: 2101 avail_slots = (slots_avail2_reg >> 2102 PCI_HP_AVAIL_66MHZ_CONV_SPEED_SHIFT) & 2103 PCI_HP_AVAIL_SPEED_MASK; 2104 2105 if ((status & PCI_HP_SLOT_66MHZ_CONV_CAPABLE) && 2106 (((curr_speed == -1) && avail_slots) || 2107 (curr_speed == PCI_HP_SBCR_66MHZ_CONV_SPEED))) { 2108 speed = PCI_HP_SBCR_66MHZ_CONV_SPEED; 2109 } else { 2110 avail_slots = (slots_avail1_reg >> 2111 PCI_HP_AVAIL_33MHZ_CONV_SPEED_SHIFT) & 2112 PCI_HP_AVAIL_SPEED_MASK; 2113 2114 if (((curr_speed == -1) && (avail_slots)) || 2115 (curr_speed == PCI_HP_SBCR_33MHZ_CONV_SPEED)) { 2116 speed = PCI_HP_SBCR_33MHZ_CONV_SPEED; 2117 } else { 2118 PCIE_DBG("pcishpc_set_bus_speed() " 2119 " failed to set the bus speed, slot# %d\n", 2120 slot_p->hs_num); 2121 return (DDI_FAILURE); 2122 } 2123 } 2124 break; 2125 } 2126 2127 /* 2128 * If the bus segment is already running, check to see the card 2129 * in the slot can support the current bus speed. 2130 */ 2131 if (curr_speed == speed) { 2132 /* 2133 * Check to see there is any slot available for the current 2134 * bus speed. Otherwise, we need fail the current slot connect 2135 * request. 2136 */ 2137 return ((avail_slots <= ctrl_p->hc_num_slots_connected) ? 2138 DDI_FAILURE : DDI_SUCCESS); 2139 } 2140 2141 /* Set the bus speed */ 2142 if (pcishpc_issue_command(ctrl_p, PCI_HP_COMM_STS_SET_SPEED | 2143 speed) == DDI_FAILURE) { 2144 PCIE_DBG("pcishpc_set_bus_speed() failed " 2145 "to set bus %d speed\n", slot_p->hs_num); 2146 return (DDI_FAILURE); 2147 } 2148 2149 /* Check the current bus speed */ 2150 status = pcishpc_read_reg(ctrl_p, PCI_HP_PROF_IF_SBCR_REG) & 2151 PCI_HP_SBCR_SPEED_MASK; 2152 if ((status & PCI_HP_SBCR_SPEED_MASK) != speed) { 2153 PCIE_DBG("pcishpc_set_bus_speed() an incorrect " 2154 "bus speed, slot = 0x%x, speed = 0x%x\n", 2155 slot_p->hs_num, status & PCI_HP_SBCR_SPEED_MASK); 2156 return (DDI_FAILURE); 2157 } 2158 2159 2160 /* Save the current bus speed */ 2161 ctrl_p->hc_curr_bus_speed = speed; 2162 2163 return (DDI_SUCCESS); 2164 } 2165 2166 /* 2167 * pcishpc_setled() 2168 * 2169 * Change the state of a slot's LED. 2170 */ 2171 static int 2172 pcishpc_setled(pcie_hp_slot_t *slot_p, pcie_hp_led_t led, 2173 pcie_hp_led_state_t state) 2174 { 2175 ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex)); 2176 2177 switch (led) { 2178 case PCIE_HP_FAULT_LED: 2179 PCIE_DBG("pcishpc_setled() - PCIE_HP_FAULT_LED " 2180 "(set %s)\n", pcishpc_slot_textledstate(state)); 2181 slot_p->hs_fault_led_state = state; 2182 break; 2183 2184 case PCIE_HP_POWER_LED: 2185 PCIE_DBG("pcishpc_setled() - PCIE_HP_POWER_LED " 2186 "(set %s)\n", pcishpc_slot_textledstate(state)); 2187 slot_p->hs_power_led_state = state; 2188 break; 2189 2190 case PCIE_HP_ATTN_LED: 2191 PCIE_DBG("pcishpc_setled() - PCIE_HP_ATTN_LED " 2192 "(set %s)\n", pcishpc_slot_textledstate(state)); 2193 slot_p->hs_attn_led_state = state; 2194 break; 2195 2196 case PCIE_HP_ACTIVE_LED: 2197 PCIE_DBG("pcishpc_setled() - PCIE_HP_ACTIVE_LED " 2198 "(set %s)\n", pcishpc_slot_textledstate(state)); 2199 slot_p->hs_active_led_state = state; 2200 break; 2201 } 2202 2203 return (pcishpc_set_slot_state(slot_p, slot_p->hs_info.cn_state)); 2204 } 2205 2206 /* 2207 * pcishpc_led_shpc_to_hpc() 2208 * 2209 * Convert from SHPC indicator status to HPC indicator status. 2210 */ 2211 static int 2212 pcishpc_led_shpc_to_hpc(int state) 2213 { 2214 switch (state) { 2215 case 1: /* SHPC On bits b01 */ 2216 return (PCIE_HP_LED_ON); 2217 case 2: /* SHPC Blink bits b10 */ 2218 return (PCIE_HP_LED_BLINK); 2219 case 3: /* SHPC Off bits b11 */ 2220 return (PCIE_HP_LED_OFF); 2221 } 2222 2223 return (PCIE_HP_LED_OFF); 2224 } 2225 2226 2227 /* 2228 * pcishpc_led_hpc_to_shpc() 2229 * 2230 * Convert from HPC indicator status to SHPC indicator status. 2231 */ 2232 static int 2233 pcishpc_led_hpc_to_shpc(int state) 2234 { 2235 switch (state) { 2236 case PCIE_HP_LED_ON: 2237 return (1); /* SHPC On bits b01 */ 2238 case PCIE_HP_LED_BLINK: 2239 return (2); /* SHPC Blink bits b10 */ 2240 case PCIE_HP_LED_OFF: 2241 return (3); /* SHPC Off bits b11 */ 2242 } 2243 2244 return (3); /* SHPC Off bits b11 */ 2245 } 2246 2247 /* 2248 * pcishpc_slot_shpc_to_hpc() 2249 * 2250 * Convert from SHPC slot state to HPC slot state. 2251 * The argument shpc_state is expected to be read from the slot register. 2252 */ 2253 static int 2254 pcishpc_slot_shpc_to_hpc(int shpc_state) 2255 { 2256 if ((shpc_state & PCI_HP_SLOT_CARD_EMPTY_MASK) == 2257 PCI_HP_SLOT_CARD_EMPTY_MASK) 2258 return (DDI_HP_CN_STATE_EMPTY); 2259 2260 switch (shpc_state & PCI_HP_SLOT_STATE_MASK) { 2261 case PCI_HP_SLOT_POWER_ONLY: /* SHPC Powered Only */ 2262 return (DDI_HP_CN_STATE_POWERED); 2263 2264 case PCI_HP_SLOT_ENABLED: /* SHPC Enabled */ 2265 return (DDI_HP_CN_STATE_ENABLED); 2266 2267 case PCI_HP_SLOT_DISABLED: /* SHPC Disabled */ 2268 default : /* SHPC Reserved */ 2269 return (DDI_HP_CN_STATE_PRESENT); 2270 } 2271 } 2272 2273 /* 2274 * pcishpc_slot_hpc_to_shpc() 2275 * 2276 * Convert from HPC slot state to SHPC slot state. 2277 */ 2278 static int 2279 pcishpc_slot_hpc_to_shpc(int state) 2280 { 2281 switch (state) { 2282 case DDI_HP_CN_STATE_EMPTY: 2283 return (0); 2284 2285 case DDI_HP_CN_STATE_POWERED: 2286 return (PCI_HP_SLOT_POWER_ONLY); 2287 2288 case DDI_HP_CN_STATE_ENABLED: 2289 return (PCI_HP_SLOT_ENABLED); 2290 2291 default: 2292 return (PCI_HP_SLOT_DISABLED); 2293 } 2294 } 2295 2296 /* 2297 * pcishpc_slot_textslotstate() 2298 * 2299 * Convert the request into a text message. 2300 */ 2301 static char * 2302 pcishpc_slot_textslotstate(ddi_hp_cn_state_t state) 2303 { 2304 /* Convert an HPC slot state into a textual string. */ 2305 if (state == DDI_HP_CN_STATE_EMPTY) 2306 return ("HPC_SLOT_EMPTY"); 2307 else if (state == DDI_HP_CN_STATE_ENABLED) 2308 return ("HPC_SLOT_ENABLED"); 2309 else if (state == DDI_HP_CN_STATE_POWERED) 2310 return ("HPC_SLOT_POWERED_ONLY"); 2311 else 2312 return ("HPC_SLOT_DISABLED"); 2313 } 2314 2315 2316 /* 2317 * pcishpc_slot_textledstate() 2318 * 2319 * Convert the led state into a text message. 2320 */ 2321 static char * 2322 pcishpc_slot_textledstate(pcie_hp_led_state_t state) 2323 { 2324 /* Convert an HPC led state into a textual string. */ 2325 switch (state) { 2326 case PCIE_HP_LED_OFF: 2327 return ("off"); 2328 2329 case PCIE_HP_LED_ON: 2330 return ("on"); 2331 2332 case PCIE_HP_LED_BLINK: 2333 return ("blink"); 2334 } 2335 return ("unknown"); 2336 } 2337 2338 2339 /* 2340 * pcishpc_read_reg() 2341 * 2342 * Read from a SHPC controller register. 2343 */ 2344 static uint32_t 2345 pcishpc_read_reg(pcie_hp_ctrl_t *ctrl_p, int reg) 2346 { 2347 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 2348 2349 /* Setup the SHPC dword select register. */ 2350 pci_config_put8(bus_p->bus_cfg_hdl, 2351 bus_p->bus_pci_hp_off + PCI_HP_DWORD_SELECT_OFF, (uint8_t)reg); 2352 2353 /* Read back the SHPC dword select register and verify. */ 2354 if (pci_config_get8(bus_p->bus_cfg_hdl, bus_p->bus_pci_hp_off + 2355 PCI_HP_DWORD_SELECT_OFF) != (uint8_t)reg) { 2356 PCIE_DBG("pcishpc_read_reg() - Failed writing DWORD " 2357 "select reg\n"); 2358 return (0xFFFFFFFF); 2359 } 2360 2361 /* Read from the SHPC dword data register. */ 2362 return (pci_config_get32(bus_p->bus_cfg_hdl, 2363 bus_p->bus_pci_hp_off + PCI_HP_DWORD_DATA_OFF)); 2364 } 2365 2366 2367 /* 2368 * pcishpc_write_reg() 2369 * 2370 * Write to a SHPC controller register. 2371 */ 2372 static void 2373 pcishpc_write_reg(pcie_hp_ctrl_t *ctrl_p, int reg, uint32_t data) 2374 { 2375 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 2376 2377 /* Setup the SHPC dword select register. */ 2378 pci_config_put8(bus_p->bus_cfg_hdl, 2379 bus_p->bus_pci_hp_off + PCI_HP_DWORD_SELECT_OFF, (uint8_t)reg); 2380 2381 /* Read back the SHPC dword select register and verify. */ 2382 if (pci_config_get8(bus_p->bus_cfg_hdl, bus_p->bus_pci_hp_off + 2383 PCI_HP_DWORD_SELECT_OFF) != (uint8_t)reg) { 2384 PCIE_DBG("pcishpc_write_reg() - Failed writing " 2385 "DWORD select reg\n"); 2386 return; 2387 } 2388 2389 /* Write to the SHPC dword data register. */ 2390 pci_config_put32(bus_p->bus_cfg_hdl, 2391 bus_p->bus_pci_hp_off + PCI_HP_DWORD_DATA_OFF, data); 2392 2393 /* 2394 * Issue a read of the VendorID/DeviceID just to force the previous 2395 * write to complete. This is probably not necessary, but it does 2396 * help enforce ordering if there is an issue. 2397 */ 2398 (void) pci_config_get16(bus_p->bus_cfg_hdl, PCI_CONF_VENID); 2399 } 2400 2401 2402 #ifdef DEBUG 2403 /* 2404 * pcishpc_dump_regs() 2405 * 2406 * Dumps all of the SHPC controller registers. 2407 */ 2408 static void 2409 pcishpc_dump_regs(pcie_hp_ctrl_t *ctrl_p) 2410 { 2411 int slot, numSlots; 2412 uint32_t reg; 2413 char *state; 2414 2415 if (!pcie_debug_flags) 2416 return; 2417 2418 PCIE_DBG("pcishpc_dump_regs() called:\n"); 2419 PCIE_DBG("=========================================================="); 2420 2421 PCIE_DBG("SHPC Base Offset " 2422 ": 0x%08x\n", pcishpc_read_reg(ctrl_p, PCI_HP_BASE_OFFSET_REG)); 2423 2424 reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOTS_AVAIL_I_REG); 2425 2426 PCIE_DBG("Number of PCIX slots avail (33 Mhz) : %d\n", 2427 (reg & 31)); 2428 2429 PCIE_DBG("Number of PCIX slots avail (66 Mhz) : %d\n", 2430 ((reg>>8) & 31)); 2431 2432 PCIE_DBG("Number of PCIX slots avail (100 Mhz) : %d\n", 2433 ((reg>>16) & 31)); 2434 2435 PCIE_DBG("Number of PCIX slots avail (133 Mhz) : %d\n", 2436 ((reg>>24) & 31)); 2437 2438 reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOTS_AVAIL_II_REG); 2439 2440 PCIE_DBG("Number of conventional PCI slots (66 Mhz) : %d\n", 2441 (reg & 31)); 2442 2443 reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOT_CONFIGURATION_REG); 2444 2445 numSlots = (reg & 31); 2446 2447 PCIE_DBG("Number of Slots connected to this port : %d\n", 2448 numSlots); 2449 2450 PCIE_DBG("PCI Device # for First HotPlug Slot : %d\n", 2451 ((reg>>8) & 31)); 2452 2453 PCIE_DBG("Physical Slot # for First PCI Device # : %d\n", 2454 ((reg>>16) & 0x7ff)); 2455 2456 PCIE_DBG("Physical Slot Number Up/Down : %d\n", 2457 ((reg>>29) & 0x1)); 2458 2459 PCIE_DBG("MRL Sensor Implemented : %s\n", 2460 (reg & PCI_HP_SLOT_CONFIG_MRL_SENSOR) ? "Yes" : "No"); 2461 2462 PCIE_DBG("Attention Button Implemented : %s\n", 2463 (reg & PCI_HP_SLOT_CONFIG_ATTN_BUTTON) ? "Yes" : "No"); 2464 2465 reg = pcishpc_read_reg(ctrl_p, PCI_HP_PROF_IF_SBCR_REG); 2466 2467 switch (reg & 7) { 2468 case 0: 2469 state = "33Mhz Conventional PCI"; 2470 break; 2471 case 1: 2472 state = "66Mhz Conventional PCI"; 2473 break; 2474 case 2: 2475 state = "66Mhz PCI-X"; 2476 break; 2477 case 3: 2478 state = "100Mhz PCI-X"; 2479 break; 2480 case 4: 2481 state = "133Mhz PCI-X"; 2482 break; 2483 default: 2484 state = "Reserved (Error)"; 2485 break; 2486 } 2487 2488 PCIE_DBG("Current Port Operation Mode : %s\n", state); 2489 2490 PCIE_DBG("SHPC Interrupt Message Number : %d\n", 2491 ((reg>>16) &31)); 2492 2493 PCIE_DBG("SHPC Programming Interface : %d\n", 2494 ((reg>>24) & 0xff)); 2495 2496 reg = pcishpc_read_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG); 2497 2498 PCIE_DBG("SHPC Command Code : %d\n", 2499 (reg & 0xff)); 2500 2501 PCIE_DBG("SHPC Target Slot : %d\n", 2502 ((reg>>8) & 31)); 2503 2504 PCIE_DBG("SHPC Controller Busy : %s\n", 2505 ((reg>>16) & 1) ? "Yes" : "No"); 2506 2507 PCIE_DBG("SHPC Controller Err: MRL Sensor : %s\n", 2508 ((reg>>17) & 1) ? "Yes" : "No"); 2509 2510 PCIE_DBG("SHPC Controller Err: Invalid Command : %s\n", 2511 ((reg>>18) & 1) ? "Yes" : "No"); 2512 2513 PCIE_DBG("SHPC Controller Err: Invalid Speed/Mode : %s\n", 2514 ((reg>>19) & 1) ? "Yes" : "No"); 2515 2516 reg = pcishpc_read_reg(ctrl_p, PCI_HP_IRQ_LOCATOR_REG); 2517 2518 PCIE_DBG("Command Completion Interrupt Pending : %s\n", 2519 (reg & PCI_HP_IRQ_CMD_COMPLETE) ? "Yes" : "No"); 2520 2521 for (slot = 0; slot < numSlots; slot++) { 2522 PCIE_DBG("Slot %d Interrupt Pending : %s\n", slot+1, 2523 (reg & (PCI_HP_IRQ_SLOT_N_PENDING<<slot)) ? "Yes" : "No"); 2524 } 2525 2526 reg = pcishpc_read_reg(ctrl_p, PCI_HP_SERR_LOCATOR_REG); 2527 2528 PCIE_DBG("Arbiter SERR Pending : %s\n", 2529 (reg & PCI_HP_IRQ_SERR_ARBITER_PENDING) ? "Yes" : "No"); 2530 2531 for (slot = 0; slot < numSlots; slot++) { 2532 PCIE_DBG("Slot %d SERR Pending : %s\n", 2533 slot+1, (reg & 2534 (PCI_HP_IRQ_SERR_SLOT_N_PENDING<<slot)) ? "Yes" : "No"); 2535 } 2536 2537 reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG); 2538 2539 PCIE_DBG("Global Interrupt Mask : %s\n", 2540 (reg & PCI_HP_SERR_INT_GLOBAL_IRQ_MASK) ? "Yes" : "No"); 2541 2542 PCIE_DBG("Global SERR Mask : %s\n", 2543 (reg & PCI_HP_SERR_INT_GLOBAL_SERR_MASK) ? "Yes" : "No"); 2544 2545 PCIE_DBG("Command Completion Interrupt Mask : %s\n", 2546 (reg & PCI_HP_SERR_INT_CMD_COMPLETE_MASK) ? "Yes" : "No"); 2547 2548 PCIE_DBG("Arbiter SERR Mask : %s\n", 2549 (reg & PCI_HP_SERR_INT_ARBITER_SERR_MASK) ? "Yes" : "No"); 2550 2551 PCIE_DBG("Command Completion Detected : %s\n", 2552 (reg & PCI_HP_SERR_INT_CMD_COMPLETE_IRQ) ? "Yes" : "No"); 2553 2554 PCIE_DBG("Arbiter Timeout Detected : %s\n", 2555 (reg & PCI_HP_SERR_INT_ARBITER_IRQ) ? "Yes" : "No"); 2556 2557 for (slot = 0; slot < numSlots; slot++) { 2558 PCIE_DBG("Logical Slot %d Registers:\n", slot+1); 2559 PCIE_DBG("------------------------------------\n"); 2560 2561 reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot); 2562 2563 PCIE_DBG("Slot %d state : %s\n", slot+1, 2564 pcishpc_slot_textslotstate(pcishpc_slot_shpc_to_hpc(reg))); 2565 2566 PCIE_DBG("Slot %d Power Indicator State : %s\n", slot+1, 2567 pcishpc_slot_textledstate(pcishpc_led_shpc_to_hpc( 2568 (reg>>2) &3))); 2569 2570 PCIE_DBG("Slot %d Attention Indicator State : %s\n", slot+1, 2571 pcishpc_slot_textledstate(pcishpc_led_shpc_to_hpc( 2572 (reg>>4)&3))); 2573 2574 PCIE_DBG("Slot %d Power Fault : %s\n", slot+1, 2575 ((reg>>6)&1) ? "Fault Detected" : "No Fault"); 2576 PCIE_DBG("Slot %d Attention Button : %s\n", slot+1, 2577 ((reg>>7)&1) ? "Depressed" : "Not Depressed"); 2578 PCIE_DBG("Slot %d MRL Sensor : %s\n", slot+1, 2579 ((reg>>8)&1) ? "Not Closed" : "Closed"); 2580 PCIE_DBG("Slot %d 66mhz Capable : %s\n", slot+1, 2581 ((reg>>9)&1) ? "66mhz" : "33mgz"); 2582 2583 switch ((reg>>10)&3) { 2584 case 0: 2585 state = "Card Present 7.5W"; 2586 break; 2587 case 1: 2588 state = "Card Present 15W"; 2589 break; 2590 case 2: 2591 state = "Card Present 25W"; 2592 break; 2593 case 3: 2594 state = "Slot Empty"; 2595 break; 2596 } 2597 2598 PCIE_DBG("Slot %d PRSNT1#/PRSNT2# : %s\n", slot+1, 2599 state); 2600 2601 switch ((reg>>12)&3) { 2602 case 0: 2603 state = "Non PCI-X"; 2604 break; 2605 case 1: 2606 state = "66mhz PCI-X"; 2607 break; 2608 case 2: 2609 state = "Reserved"; 2610 break; 2611 case 3: 2612 state = "133mhz PCI-X"; 2613 break; 2614 } 2615 2616 PCIE_DBG("Slot %d Card Presence Change Detected : %s\n", 2617 slot+1, (reg & PCI_HP_SLOT_PRESENCE_DETECTED) ? "Yes" : 2618 "No"); 2619 PCIE_DBG("Slot %d Isolated Power Fault Detected : %s\n", 2620 slot+1, (reg & PCI_HP_SLOT_ISO_PWR_DETECTED) ? "Yes" : 2621 "No"); 2622 PCIE_DBG("Slot %d Attention Button Press Detected : %s\n", 2623 slot+1, (reg & PCI_HP_SLOT_ATTN_DETECTED) ? "Yes" : "No"); 2624 PCIE_DBG("Slot %d MRL Sensor Change Detected : %s\n", 2625 slot+1, (reg & PCI_HP_SLOT_MRL_DETECTED) ? "Yes" : "No"); 2626 PCIE_DBG("Slot %d Connected Power Fault Detected : %s\n", 2627 slot+1, (reg & PCI_HP_SLOT_POWER_DETECTED) ? "Yes" : "No"); 2628 2629 PCIE_DBG("Slot %d Card Presence IRQ Masked : %s\n", 2630 slot+1, (reg & PCI_HP_SLOT_PRESENCE_MASK) ? "Yes" : "No"); 2631 PCIE_DBG("Slot %d Isolated Power Fault IRQ Masked : %s\n", 2632 slot+1, (reg & PCI_HP_SLOT_ISO_PWR_MASK) ? "Yes" : "No"); 2633 PCIE_DBG("Slot %d Attention Button IRQ Masked : %s\n", 2634 slot+1, (reg & PCI_HP_SLOT_ATTN_MASK) ? "Yes" : "No"); 2635 PCIE_DBG("Slot %d MRL Sensor IRQ Masked : %s\n", 2636 slot+1, (reg & PCI_HP_SLOT_MRL_MASK) ? "Yes" : "No"); 2637 PCIE_DBG("Slot %d Connected Power Fault IRQ Masked : %s\n", 2638 slot+1, (reg & PCI_HP_SLOT_POWER_MASK) ? "Yes" : "No"); 2639 PCIE_DBG("Slot %d MRL Sensor SERR Masked : %s\n", 2640 slot+1, (reg & PCI_HP_SLOT_MRL_SERR_MASK) ? "Yes" : "No"); 2641 PCIE_DBG("Slot %d Connected Power Fault SERR Masked : %s\n", 2642 slot+1, (reg & PCI_HP_SLOT_POWER_SERR_MASK) ? "Yes" : "No"); 2643 } 2644 } 2645 #endif /* DEBUG */ 2646