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 PCIE_DBG("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 PCIE_DBG("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 PCIE_DBG("Get string value failed for property %s.\n", 679 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 PCIE_DBG("Unsupported value of setting " 689 "property %s\n", name); 690 ret = DDI_ENOTSUP; 691 goto set_prop_cleanup; 692 } 693 } else { 694 PCIE_DBG("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 if (rval) { 723 if (get_udatamodel() == DATAMODEL_NATIVE) { 724 result.buf_size = 0; 725 if (copyout(&result, rval, sizeof (ddi_hp_property_t))) 726 ret = DDI_FAILURE; 727 } 728 #ifdef _SYSCALL32_IMPL 729 else { 730 result32.buf_size = 0; 731 if (copyout(&result32, rval, 732 sizeof (ddi_hp_property32_t))) 733 ret = DDI_FAILURE; 734 } 735 #endif 736 } 737 738 mutex_exit(&ctrl_p->hc_mutex); 739 set_prop_cleanup: 740 nvlist_free(prop_list); 741 return (ret); 742 } 743 744 /* 745 * pcishpc_hp_ops() 746 * 747 * Handle hotplug commands 748 * 749 * Note: This function is called by DDI HP framework at kernel context only 750 */ 751 /* ARGSUSED */ 752 int 753 pcishpc_hp_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op, 754 void *arg, void *result) 755 { 756 pcie_hp_slot_t *slot_p = NULL; 757 pcie_hp_ctrl_t *ctrl_p; 758 int ret = DDI_SUCCESS, i; 759 760 PCIE_DBG("pcishpc_hp_ops: dip=%p cn_name=%s op=%x arg=%p\n", 761 dip, cn_name, op, arg); 762 763 if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) 764 return (DDI_FAILURE); 765 766 for (i = 0; i < PCIE_HP_MAX_SLOTS && ctrl_p->hc_slots[i]; i++) { 767 if (strcmp(ctrl_p->hc_slots[i]->hs_info.cn_name, cn_name) 768 == 0) { 769 /* Match with a physical slot, found */ 770 slot_p = ctrl_p->hc_slots[i]; 771 break; 772 } 773 } 774 if (!slot_p) { 775 PCIE_DBG("pcishpc_hp_ops: Failed to find the slot under" 776 "dip %p with name: %s; op=%x arg=%p\n", 777 dip, cn_name, op, arg); 778 return (DDI_EINVAL); 779 } 780 switch (op) { 781 case DDI_HPOP_CN_GET_STATE: 782 { 783 mutex_enter(&ctrl_p->hc_mutex); 784 785 /* get the current slot state */ 786 pcishpc_get_slot_state(slot_p); 787 788 *((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state; 789 790 mutex_exit(&ctrl_p->hc_mutex); 791 break; 792 } 793 case DDI_HPOP_CN_CHANGE_STATE: 794 { 795 ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg; 796 797 mutex_enter(&slot_p->hs_ctrl->hc_mutex); 798 799 ret = pcishpc_change_slot_state(slot_p, target_state); 800 *((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state; 801 802 mutex_exit(&slot_p->hs_ctrl->hc_mutex); 803 break; 804 } 805 case DDI_HPOP_CN_PROBE: 806 ret = pcishpc_slot_probe(slot_p); 807 808 break; 809 case DDI_HPOP_CN_UNPROBE: 810 ret = pcishpc_slot_unprobe(slot_p); 811 812 break; 813 case DDI_HPOP_CN_GET_PROPERTY: 814 ret = pcishpc_slot_get_property(slot_p, 815 (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result); 816 break; 817 case DDI_HPOP_CN_SET_PROPERTY: 818 ret = pcishpc_slot_set_property(slot_p, 819 (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result); 820 break; 821 default: 822 ret = DDI_ENOTSUP; 823 break; 824 } 825 826 return (ret); 827 } 828 829 /* 830 * Local functions (called within this file) 831 */ 832 833 /* 834 * pcishpc_create_controller() 835 * 836 * This function allocates and creates an SHPC controller state structure 837 * and adds it to the linked list of controllers. 838 */ 839 static pcie_hp_ctrl_t * 840 pcishpc_create_controller(dev_info_t *dip) 841 { 842 pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 843 pcie_hp_ctrl_t *ctrl_p; 844 845 PCIE_DBG("pcishpc: create controller for %s#%d\n", 846 ddi_driver_name(dip), ddi_get_instance(dip)); 847 848 ctrl_p = kmem_zalloc(sizeof (pcie_hp_ctrl_t), KM_SLEEP); 849 ctrl_p->hc_dip = dip; 850 851 cv_init(&ctrl_p->hc_cmd_comp_cv, NULL, CV_DRIVER, NULL); 852 853 /* Init the shpc controller's mutex. */ 854 mutex_init(&ctrl_p->hc_mutex, NULL, MUTEX_DRIVER, NULL); 855 856 /* HPC initialization is complete now */ 857 ctrl_p->hc_flags = PCIE_HP_INITIALIZED_FLAG; 858 bus_p->bus_hp_curr_mode = PCIE_PCI_HP_MODE; 859 860 PCIE_SET_HP_CTRL(dip, ctrl_p); 861 862 PCIE_DBG("pcishpc_create_controller() success\n"); 863 864 return (ctrl_p); 865 } 866 867 868 /* 869 * pcishpc_setup_controller() 870 * 871 * Get the number of HotPlug Slots, and the PCI device information 872 * for this HotPlug controller. 873 */ 874 static int 875 pcishpc_setup_controller(pcie_hp_ctrl_t *ctrl_p) 876 { 877 uint32_t config; 878 dev_info_t *ppdip; 879 880 config = pcishpc_read_reg(ctrl_p, PCI_HP_SLOT_CONFIGURATION_REG); 881 882 /* Get the number of HotPlug slots implemented */ 883 ctrl_p->hc_num_slots_impl = ((config)&31); 884 885 /* 886 * Initilize the current bus speed and number of hotplug slots 887 * currently connected. 888 */ 889 ctrl_p->hc_curr_bus_speed = -1; 890 ctrl_p->hc_num_slots_connected = 0; 891 892 /* 893 * Get the first PCI device Number used. 894 * 895 * PCI-X I/O boat workaround. 896 * The register doesn't set up the correct value. 897 */ 898 ppdip = ddi_get_parent(ddi_get_parent(ctrl_p->hc_dip)); 899 if ((ddi_prop_get_int(DDI_DEV_T_ANY, ppdip, DDI_PROP_DONTPASS, 900 "vendor-id", -1) == 0x108e) && 901 (ddi_prop_get_int(DDI_DEV_T_ANY, ppdip, DDI_PROP_DONTPASS, 902 "device-id", -1) == 0x9010)) 903 ctrl_p->hc_device_start = 4; 904 else 905 ctrl_p->hc_device_start = ((config>>8)&31); 906 907 /* Get the first Physical device number. */ 908 ctrl_p->hc_phys_start = ((config>>16)&0x7ff); 909 910 /* Check if the device numbers increase or decrease. */ 911 ctrl_p->hc_device_increases = ((config>>29)&0x1); 912 913 ctrl_p->hc_has_attn = 914 (config & PCI_HP_SLOT_CONFIG_ATTN_BUTTON) ? B_TRUE : B_FALSE; 915 ctrl_p->hc_has_mrl = 916 (config & PCI_HP_SLOT_CONFIG_MRL_SENSOR) ? B_TRUE : B_FALSE; 917 918 ctrl_p->hc_cmd_pending = B_FALSE; 919 ctrl_p->hc_arbiter_timeout = B_FALSE; 920 921 if (ctrl_p->hc_num_slots_impl > PCIE_HP_MAX_SLOTS) { 922 PCIE_DBG("pcishpc_setup_controller() too many SHPC " 923 "slots error\n"); 924 return (DDI_FAILURE); 925 } 926 927 return (DDI_SUCCESS); 928 } 929 930 931 /* 932 * pcishpc_destroy_controller() 933 * 934 * This function deallocates all of the SHPC controller resources. 935 */ 936 static int 937 pcishpc_destroy_controller(dev_info_t *dip) 938 { 939 pcie_hp_ctrl_t *ctrl_p; 940 pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 941 942 PCIE_DBG("pcishpc_destroy_controller() called(dip=%p)\n", dip); 943 944 /* get the soft state structure for this dip */ 945 if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) { 946 PCIE_DBG("pcishpc_destroy_controller() not found\n"); 947 return (DDI_FAILURE); 948 } 949 950 /* 951 * Deallocate the slot state structures for this controller. 952 */ 953 (void) pcishpc_destroy_slots(ctrl_p); 954 cv_destroy(&ctrl_p->hc_cmd_comp_cv); 955 mutex_destroy(&ctrl_p->hc_mutex); 956 kmem_free(ctrl_p, sizeof (pcie_hp_ctrl_t)); 957 bus_p->bus_hp_curr_mode = PCIE_NONE_HP_MODE; 958 959 PCIE_DBG("pcishpc_destroy_controller() success\n"); 960 return (DDI_SUCCESS); 961 } 962 963 /* 964 * pcishpc_create_slot() 965 * 966 * Allocate and add a new HotPlug slot state structure to the linked list. 967 */ 968 static pcie_hp_slot_t * 969 pcishpc_create_slot(pcie_hp_ctrl_t *ctrl_p) 970 { 971 pcie_hp_slot_t *slot_p; 972 973 PCIE_DBG("pcishpc_create_slot() called(ctrl_p=%x)\n", ctrl_p); 974 975 /* Allocate a new slot structure. */ 976 slot_p = kmem_zalloc(sizeof (pcie_hp_slot_t), KM_SLEEP); 977 slot_p->hs_ctrl = ctrl_p; 978 979 /* Assign an initial value */ 980 slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY; 981 982 PCIE_DBG("pcishpc_create_slot() success\n"); 983 return (slot_p); 984 } 985 986 /* 987 * pcishpc_register_slot() 988 * 989 * Create and register a slot with the Solaris HotPlug framework. 990 */ 991 static int 992 pcishpc_register_slot(pcie_hp_ctrl_t *ctrl_p, int slot) 993 { 994 dev_info_t *dip = ctrl_p->hc_dip; 995 pcie_hp_slot_t *slot_p; 996 997 slot_p = pcishpc_create_slot(ctrl_p); 998 ctrl_p->hc_slots[slot] = slot_p; 999 slot_p->hs_num = slot; 1000 1001 /* Setup the PCI device # for this SHPC slot. */ 1002 if (ctrl_p->hc_device_increases) 1003 slot_p->hs_device_num = ctrl_p->hc_device_start + 1004 slot_p->hs_num; 1005 else 1006 slot_p->hs_device_num = ctrl_p->hc_device_start - 1007 slot_p->hs_num; 1008 1009 /* Setup the DDI HP framework slot information. */ 1010 slot_p->hs_info.cn_type = DDI_HP_CN_TYPE_PCI; 1011 slot_p->hs_info.cn_type_str = PCIE_PCI_HP_TYPE; 1012 slot_p->hs_info.cn_child = NULL; 1013 1014 slot_p->hs_minor = PCI_MINOR_NUM( 1015 ddi_get_instance(dip), slot_p->hs_device_num); 1016 slot_p->hs_condition = AP_COND_UNKNOWN; 1017 1018 /* setup thread for handling ATTN button events */ 1019 if (ctrl_p->hc_has_attn) { 1020 PCIE_DBG("pcishpc_register_slot: " 1021 "setting up ATTN button event " 1022 "handler thread for slot %d\n", slot); 1023 1024 cv_init(&slot_p->hs_attn_btn_cv, NULL, CV_DRIVER, NULL); 1025 slot_p->hs_attn_btn_pending = B_FALSE; 1026 slot_p->hs_attn_btn_threadp = thread_create(NULL, 0, 1027 pcishpc_attn_btn_handler, 1028 (void *)slot_p, 0, &p0, TS_RUN, minclsyspri); 1029 slot_p->hs_attn_btn_thread_exit = B_FALSE; 1030 } 1031 1032 /* setup the slot name (used for ap-id) */ 1033 pcishpc_set_slot_name(ctrl_p, slot); 1034 1035 pcishpc_get_slot_state(slot_p); 1036 if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_ENABLED) 1037 slot_p->hs_condition = AP_COND_OK; 1038 1039 /* register the slot with DDI HP framework */ 1040 if (ndi_hp_register(dip, &slot_p->hs_info) != NDI_SUCCESS) { 1041 PCIE_DBG("pciehpc_register_slot() failed to register slot %d\n", 1042 slot_p->hs_phy_slot_num); 1043 return (DDI_FAILURE); 1044 } 1045 1046 pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip), 1047 slot_p->hs_minor), slot_p->hs_device_num); 1048 1049 PCIE_DBG("pcishpc_register_slot() success for slot %d\n", slot); 1050 1051 return (DDI_SUCCESS); 1052 } 1053 1054 /* 1055 * pcishpc_destroy_slots() 1056 * 1057 * Free up all of the slot resources for this controller. 1058 */ 1059 static int 1060 pcishpc_destroy_slots(pcie_hp_ctrl_t *ctrl_p) 1061 { 1062 dev_info_t *dip = ctrl_p->hc_dip; 1063 pcie_hp_slot_t *slot_p; 1064 int i; 1065 1066 PCIE_DBG("pcishpc_destroy_slots() called(ctrl_p=%p)\n", ctrl_p); 1067 1068 for (i = 0; i < PCIE_HP_MAX_SLOTS; i++) { 1069 if ((slot_p = ctrl_p->hc_slots[i]) == NULL) 1070 continue; 1071 1072 if (slot_p->hs_attn_btn_threadp != NULL) { 1073 mutex_enter(&ctrl_p->hc_mutex); 1074 slot_p->hs_attn_btn_thread_exit = B_TRUE; 1075 cv_signal(&slot_p->hs_attn_btn_cv); 1076 PCIE_DBG("pcishpc_destroy_slots: " 1077 "waiting for ATTN thread exit\n"); 1078 cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex); 1079 PCIE_DBG("pcishpc_destroy_slots: " 1080 "ATTN thread exit\n"); 1081 cv_destroy(&slot_p->hs_attn_btn_cv); 1082 slot_p->hs_attn_btn_threadp = NULL; 1083 mutex_exit(&ctrl_p->hc_mutex); 1084 } 1085 1086 PCIE_DBG("pcishpc_destroy_slots() (shpc_p=%p)\n" 1087 "destroyed", slot_p); 1088 1089 pcie_hp_delete_occupant_props(dip, 1090 makedevice(ddi_driver_major(dip), 1091 slot_p->hs_minor)); 1092 1093 /* unregister the slot with DDI HP framework */ 1094 if (ndi_hp_unregister(dip, slot_p->hs_info.cn_name) != 1095 NDI_SUCCESS) { 1096 PCIE_DBG("pcishpc_destroy_slots() " 1097 "failed to unregister slot %d\n", 1098 slot_p->hs_phy_slot_num); 1099 return (DDI_FAILURE); 1100 } 1101 kmem_free(slot_p->hs_info.cn_name, 1102 strlen(slot_p->hs_info.cn_name) + 1); 1103 kmem_free(slot_p, sizeof (pcie_hp_slot_t)); 1104 } 1105 1106 return (DDI_SUCCESS); 1107 } 1108 1109 /* 1110 * pcishpc_enable_irqs() 1111 * 1112 * Enable/unmask the different IRQ's we support from the SHPC controller. 1113 */ 1114 static int 1115 pcishpc_enable_irqs(pcie_hp_ctrl_t *ctrl_p) 1116 { 1117 uint32_t reg; 1118 int slot; 1119 1120 reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG); 1121 1122 /* Enable all interrupts. */ 1123 reg &= ~PCI_HP_SERR_INT_MASK_ALL; 1124 1125 pcishpc_write_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG, reg); 1126 1127 /* Unmask the interrupts for each slot. */ 1128 for (slot = 0; slot < ctrl_p->hc_num_slots_impl; slot++) { 1129 reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot); 1130 if ((reg & PCI_HP_SLOT_STATE_MASK) == PCI_HP_SLOT_ENABLED) { 1131 reg &= ~(PCI_HP_SLOT_MASK_ALL | 1132 PCI_HP_SLOT_MRL_SERR_MASK); 1133 ctrl_p->hc_num_slots_connected++; 1134 if (ctrl_p->hc_curr_bus_speed == -1) 1135 ctrl_p->hc_curr_bus_speed = 1136 pcishpc_read_reg(ctrl_p, 1137 PCI_HP_PROF_IF_SBCR_REG) & 1138 PCI_HP_SBCR_SPEED_MASK; 1139 } else { 1140 reg &= ~(PCI_HP_SLOT_MASK_ALL); 1141 } 1142 1143 /* Enable/Unmask all slot interrupts. */ 1144 pcishpc_write_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot, reg); 1145 } 1146 1147 PCIE_DBG("pcishpc_enable_irqs: ctrl_p 0x%p, " 1148 "current bus speed 0x%x, slots connected 0x%x\n", ctrl_p, 1149 ctrl_p->hc_curr_bus_speed, ctrl_p->hc_num_slots_connected); 1150 1151 return (DDI_SUCCESS); 1152 } 1153 1154 1155 /* 1156 * pcishpc_disable_irqs() 1157 * 1158 * Disable/Mask the different IRQ's we support from the SHPC controller. 1159 */ 1160 static int 1161 pcishpc_disable_irqs(pcie_hp_ctrl_t *ctrl_p) 1162 { 1163 uint32_t reg; 1164 int slot; 1165 1166 reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG); 1167 1168 /* Mask all interrupts. */ 1169 reg |= PCI_HP_SERR_INT_MASK_ALL; 1170 1171 pcishpc_write_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG, reg); 1172 1173 /* Unmask the interrupts for each slot. */ 1174 for (slot = 0; slot < ctrl_p->hc_num_slots_impl; slot++) { 1175 reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot); 1176 1177 /* Disable/Mask all slot interrupts. */ 1178 reg |= PCI_HP_SLOT_MASK_ALL; 1179 1180 pcishpc_write_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot, reg); 1181 } 1182 1183 PCIE_DBG("pcishpc_disable_irqs: ctrl_p 0x%p, " 1184 "current bus speed 0x%x, slots connected 0x%x\n", ctrl_p, 1185 ctrl_p->hc_curr_bus_speed, ctrl_p->hc_num_slots_connected); 1186 1187 return (DDI_SUCCESS); 1188 } 1189 1190 /* 1191 * pcishpc_slot_poweron() 1192 * 1193 * Poweron/Enable the slot. 1194 * 1195 * Note: This function is called by DDI HP framework at kernel context only 1196 */ 1197 /*ARGSUSED*/ 1198 static int 1199 pcishpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result_state) 1200 { 1201 uint32_t status; 1202 1203 PCIE_DBG("pcishpc_slot_poweron called()\n"); 1204 1205 ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex)); 1206 1207 /* get the current slot state */ 1208 pcishpc_get_slot_state(slot_p); 1209 1210 /* check if the slot is already in the 'enabled' state */ 1211 if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) { 1212 /* slot is already in the 'enabled' state */ 1213 PCIE_DBG("pcishpc_slot_poweron() slot %d already enabled\n", 1214 slot_p->hs_phy_slot_num); 1215 1216 *result_state = slot_p->hs_info.cn_state; 1217 return (DDI_SUCCESS); 1218 } 1219 1220 if (slot_p->hs_info.cn_state == DDI_HP_CN_STATE_EMPTY) { 1221 PCIE_DBG("pcishpc_slot_poweron() slot in empty state\n"); 1222 goto cleanup; 1223 } 1224 1225 /* make sure the MRL sensor is closed */ 1226 status = pcishpc_read_reg(slot_p->hs_ctrl, 1227 PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num); 1228 1229 if (status & PCI_HP_SLOT_MRL_STATE_MASK) { 1230 PCIE_DBG("pcishpc_slot_poweron() failed: MRL open\n"); 1231 goto cleanup; 1232 } 1233 1234 /* Set the Power LED to blink */ 1235 (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK); 1236 1237 /* Turn all other LEDS off */ 1238 (void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF); 1239 (void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF); 1240 (void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF); 1241 1242 /* Set the bus speed only if the bus segment is not running */ 1243 if (pcishpc_set_bus_speed(slot_p) != DDI_SUCCESS) { 1244 PCIE_DBG("pcishpc_slot_poweron() setting speed failed\n"); 1245 goto cleanup; 1246 } 1247 1248 slot_p->hs_ctrl->hc_num_slots_connected++; 1249 1250 PCIE_DBG("pcishpc_slot_poweron(): slot_p 0x%p, slot state 0x%x, " 1251 "current bus speed 0x%x, slots connected 0x%x\n", slot_p, 1252 slot_p->hs_info.cn_state, slot_p->hs_ctrl->hc_curr_bus_speed, 1253 slot_p->hs_ctrl->hc_num_slots_connected); 1254 1255 /* Mask or Unmask MRL Sensor SEER bit based on new slot state */ 1256 if (slot_p->hs_ctrl->hc_has_mrl == B_TRUE) { 1257 uint32_t reg; 1258 1259 reg = pcishpc_read_reg(slot_p->hs_ctrl, 1260 PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num); 1261 1262 pcishpc_write_reg(slot_p->hs_ctrl, 1263 PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num, 1264 reg & ~PCI_HP_SLOT_MRL_SERR_MASK); 1265 } 1266 1267 /* Update the hardware slot state. */ 1268 if (pcishpc_set_slot_state(slot_p, 1269 DDI_HP_CN_STATE_ENABLED) != DDI_SUCCESS) { 1270 PCIE_DBG("pcishpc_slot_poweron() failed\n"); 1271 1272 pcishpc_get_slot_state(slot_p); 1273 goto cleanup; 1274 } 1275 /* Update the current state. It will be used in pcishpc_setled() */ 1276 slot_p->hs_info.cn_state = DDI_HP_CN_STATE_ENABLED; 1277 1278 /* Turn the Power LED ON for a enabled slot. */ 1279 (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_ON); 1280 1281 /* Turn all other LEDS off. */ 1282 (void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF); 1283 (void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF); 1284 (void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF); 1285 1286 /* delay after powerON to let the device initialize itself */ 1287 delay(drv_usectohz(pcishpc_reset_delay)); 1288 1289 PCIE_DBG("pcishpc_slot_poweron() success!\n"); 1290 1291 /* 1292 * Want to show up as POWERED state for now. It will be updated to 1293 * ENABLED state when user explicitly enable the slot. 1294 */ 1295 slot_p->hs_info.cn_state = DDI_HP_CN_STATE_POWERED; 1296 1297 /* get the current slot state */ 1298 pcishpc_get_slot_state(slot_p); 1299 /* 1300 * It should be poweron'ed now. Have a check here in case any 1301 * hardware problems. 1302 */ 1303 if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) { 1304 PCIE_DBG("pcishpc_slot_poweron() failed after hardware" 1305 " registers all programmed.\n"); 1306 1307 goto cleanup; 1308 } 1309 1310 *result_state = slot_p->hs_info.cn_state; 1311 1312 return (DDI_SUCCESS); 1313 1314 cleanup: 1315 (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF); 1316 return (DDI_FAILURE); 1317 } 1318 1319 /*ARGSUSED*/ 1320 static int 1321 pcishpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result_state) 1322 { 1323 PCIE_DBG("pcishpc_slot_poweroff called()\n"); 1324 1325 ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex)); 1326 1327 /* get the current slot state */ 1328 pcishpc_get_slot_state(slot_p); 1329 1330 /* check if the slot is not in the "enabled" or "powered" state */ 1331 if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) { 1332 /* slot is in the 'disabled' state */ 1333 PCIE_DBG("pcishpc_slot_poweroff(): " 1334 "slot %d already disabled\n", slot_p->hs_phy_slot_num); 1335 1336 *result_state = slot_p->hs_info.cn_state; 1337 return (DDI_SUCCESS); 1338 } 1339 1340 /* Set the Power LED to blink */ 1341 (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK); 1342 1343 /* Turn all other LEDS off */ 1344 (void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF); 1345 (void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF); 1346 (void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF); 1347 1348 if (--slot_p->hs_ctrl->hc_num_slots_connected == 0) 1349 slot_p->hs_ctrl->hc_curr_bus_speed = -1; 1350 1351 PCIE_DBG("pcishpc_slot_poweroff(): slot_p 0x%p, slot state 0x%x, " 1352 "current bus speed 0x%x, slots connected 0x%x\n", slot_p, 1353 slot_p->hs_info.cn_state, slot_p->hs_ctrl->hc_curr_bus_speed, 1354 slot_p->hs_ctrl->hc_num_slots_connected); 1355 1356 /* Mask or Unmask MRL Sensor SEER bit based on new slot state */ 1357 if (slot_p->hs_ctrl->hc_has_mrl == B_TRUE) { 1358 uint32_t reg; 1359 1360 reg = pcishpc_read_reg(slot_p->hs_ctrl, 1361 PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num); 1362 1363 pcishpc_write_reg(slot_p->hs_ctrl, 1364 PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num, 1365 reg | PCI_HP_SLOT_MRL_SERR_MASK); 1366 } 1367 1368 /* Update the hardware slot state. */ 1369 if (pcishpc_set_slot_state(slot_p, DDI_HP_CN_STATE_PRESENT) != 1370 DDI_SUCCESS) { 1371 PCIE_DBG("pcishpc_slot_poweroff() failed\n"); 1372 1373 pcishpc_get_slot_state(slot_p); 1374 goto cleanup; 1375 } 1376 1377 /* Update the current state. It will be used in pcishpc_setled() */ 1378 slot_p->hs_info.cn_state = DDI_HP_CN_STATE_PRESENT; 1379 1380 /* Turn the Power LED OFF for a disabled slot. */ 1381 (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF); 1382 1383 /* Turn all other LEDS off. */ 1384 (void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF); 1385 (void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF); 1386 (void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF); 1387 1388 /* delay after powerON to let the device initialize itself */ 1389 delay(drv_usectohz(pcishpc_reset_delay)); 1390 1391 pcishpc_get_slot_state(slot_p); 1392 /* 1393 * It should be poweroff'ed now. Have a check here in case any 1394 * hardware problems. 1395 */ 1396 if (slot_p->hs_info.cn_state > DDI_HP_CN_STATE_PRESENT) { 1397 PCIE_DBG("pcishpc_slot_poweroff() failed after hardware" 1398 " registers all programmed.\n"); 1399 1400 goto cleanup; 1401 } 1402 1403 PCIE_DBG("pcishpc_slot_poweroff() success!\n"); 1404 1405 *result_state = slot_p->hs_info.cn_state; 1406 return (DDI_SUCCESS); 1407 1408 cleanup: 1409 (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF); 1410 return (DDI_FAILURE); 1411 } 1412 1413 /* 1414 * pcishpc_slot_probe() 1415 * 1416 * Probe the slot. 1417 * 1418 * Note: This function is called by DDI HP framework at kernel context only 1419 */ 1420 /*ARGSUSED*/ 1421 static int 1422 pcishpc_slot_probe(pcie_hp_slot_t *slot_p) 1423 { 1424 mutex_enter(&slot_p->hs_ctrl->hc_mutex); 1425 1426 PCIE_DBG("pcishpc_slot_probe called()\n"); 1427 1428 /* get the current slot state */ 1429 pcishpc_get_slot_state(slot_p); 1430 1431 /* 1432 * Probe a given PCI Hotplug Connection (CN). 1433 */ 1434 if (pcie_hp_probe(slot_p) != DDI_SUCCESS) { 1435 (void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, 1436 PCIE_HP_LED_BLINK); 1437 1438 PCIE_DBG("pcishpc_slot_probe() failed\n"); 1439 1440 mutex_exit(&slot_p->hs_ctrl->hc_mutex); 1441 return (DDI_FAILURE); 1442 } 1443 1444 PCIE_DBG("pcishpc_slot_probe() success!\n"); 1445 1446 /* get the current slot state */ 1447 pcishpc_get_slot_state(slot_p); 1448 1449 mutex_exit(&slot_p->hs_ctrl->hc_mutex); 1450 return (DDI_SUCCESS); 1451 } 1452 1453 /* 1454 * pcishpc_slot_unprobe() 1455 * 1456 * Unprobe the slot. 1457 * 1458 * Note: This function is called by DDI HP framework at kernel context only 1459 */ 1460 /*ARGSUSED*/ 1461 static int 1462 pcishpc_slot_unprobe(pcie_hp_slot_t *slot_p) 1463 { 1464 mutex_enter(&slot_p->hs_ctrl->hc_mutex); 1465 1466 PCIE_DBG("pcishpc_slot_unprobe called()\n"); 1467 1468 /* get the current slot state */ 1469 pcishpc_get_slot_state(slot_p); 1470 1471 /* 1472 * Unprobe a given PCI Hotplug Connection (CN). 1473 */ 1474 if (pcie_hp_unprobe(slot_p) != DDI_SUCCESS) { 1475 (void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, 1476 PCIE_HP_LED_BLINK); 1477 1478 PCIE_DBG("pcishpc_slot_unprobe() failed\n"); 1479 1480 mutex_exit(&slot_p->hs_ctrl->hc_mutex); 1481 return (DDI_FAILURE); 1482 } 1483 1484 PCIE_DBG("pcishpc_slot_unprobe() success!\n"); 1485 1486 /* get the current slot state */ 1487 pcishpc_get_slot_state(slot_p); 1488 1489 mutex_exit(&slot_p->hs_ctrl->hc_mutex); 1490 return (DDI_SUCCESS); 1491 } 1492 1493 static int 1494 pcishpc_upgrade_slot_state(pcie_hp_slot_t *slot_p, 1495 ddi_hp_cn_state_t target_state) 1496 { 1497 ddi_hp_cn_state_t curr_state; 1498 int rv = DDI_SUCCESS; 1499 1500 if (target_state > DDI_HP_CN_STATE_ENABLED) { 1501 return (DDI_EINVAL); 1502 } 1503 1504 curr_state = slot_p->hs_info.cn_state; 1505 while ((curr_state < target_state) && (rv == DDI_SUCCESS)) { 1506 1507 switch (curr_state) { 1508 case DDI_HP_CN_STATE_EMPTY: 1509 /* 1510 * From EMPTY to PRESENT, just check the hardware 1511 * slot state. 1512 */ 1513 pcishpc_get_slot_state(slot_p); 1514 curr_state = slot_p->hs_info.cn_state; 1515 if (curr_state < DDI_HP_CN_STATE_PRESENT) 1516 rv = DDI_FAILURE; 1517 break; 1518 case DDI_HP_CN_STATE_PRESENT: 1519 rv = pcishpc_slot_poweron(slot_p, &curr_state); 1520 break; 1521 case DDI_HP_CN_STATE_POWERED: 1522 curr_state = slot_p->hs_info.cn_state = 1523 DDI_HP_CN_STATE_ENABLED; 1524 break; 1525 default: 1526 /* should never reach here */ 1527 ASSERT("unknown devinfo state"); 1528 } 1529 } 1530 1531 return (rv); 1532 } 1533 1534 static int 1535 pcishpc_downgrade_slot_state(pcie_hp_slot_t *slot_p, 1536 ddi_hp_cn_state_t target_state) 1537 { 1538 ddi_hp_cn_state_t curr_state; 1539 int rv = DDI_SUCCESS; 1540 1541 1542 curr_state = slot_p->hs_info.cn_state; 1543 while ((curr_state > target_state) && (rv == DDI_SUCCESS)) { 1544 1545 switch (curr_state) { 1546 case DDI_HP_CN_STATE_PRESENT: 1547 /* 1548 * From PRESENT to EMPTY, just check hardware 1549 * slot state. 1550 */ 1551 pcishpc_get_slot_state(slot_p); 1552 curr_state = slot_p->hs_info.cn_state; 1553 if (curr_state >= DDI_HP_CN_STATE_PRESENT) 1554 rv = DDI_FAILURE; 1555 break; 1556 case DDI_HP_CN_STATE_POWERED: 1557 rv = pcishpc_slot_poweroff(slot_p, &curr_state); 1558 1559 break; 1560 case DDI_HP_CN_STATE_ENABLED: 1561 curr_state = slot_p->hs_info.cn_state = 1562 DDI_HP_CN_STATE_POWERED; 1563 1564 break; 1565 default: 1566 /* should never reach here */ 1567 ASSERT("unknown devinfo state"); 1568 } 1569 } 1570 1571 return (rv); 1572 } 1573 1574 /* Change slot state to a target state */ 1575 static int 1576 pcishpc_change_slot_state(pcie_hp_slot_t *slot_p, 1577 ddi_hp_cn_state_t target_state) 1578 { 1579 ddi_hp_cn_state_t curr_state; 1580 int rv; 1581 1582 pcishpc_get_slot_state(slot_p); 1583 curr_state = slot_p->hs_info.cn_state; 1584 1585 if (curr_state == target_state) { 1586 return (DDI_SUCCESS); 1587 } 1588 if (curr_state < target_state) { 1589 1590 rv = pcishpc_upgrade_slot_state(slot_p, target_state); 1591 } else { 1592 rv = pcishpc_downgrade_slot_state(slot_p, target_state); 1593 } 1594 1595 return (rv); 1596 } 1597 1598 /* 1599 * pcishpc_issue_command() 1600 * 1601 * Sends a command to the SHPC controller. 1602 */ 1603 static int 1604 pcishpc_issue_command(pcie_hp_ctrl_t *ctrl_p, uint32_t cmd_code) 1605 { 1606 int retCode; 1607 1608 ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex)); 1609 1610 PCIE_DBG("pcishpc_issue_command() cmd_code=%02x\n", cmd_code); 1611 1612 ctrl_p->hc_cmd_pending = B_TRUE; 1613 1614 /* Write the command to the SHPC controller. */ 1615 pcishpc_write_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG, cmd_code); 1616 1617 while (ctrl_p->hc_cmd_pending == B_TRUE) 1618 cv_wait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex); 1619 1620 /* Wait until the SHPC controller processes the command. */ 1621 retCode = pcishpc_wait_busy(ctrl_p); 1622 1623 /* Make sure the command completed. */ 1624 if (retCode == DDI_SUCCESS) { 1625 /* Did the command fail to generate the command complete IRQ? */ 1626 if (ctrl_p->hc_cmd_pending != B_FALSE) { 1627 PCIE_DBG("pcishpc_issue_command() Failed on " 1628 "generate cmd complete IRQ\n"); 1629 retCode = DDI_FAILURE; 1630 } 1631 } 1632 1633 if (retCode == DDI_FAILURE) 1634 PCIE_DBG("pcishpc_issue_command() Failed on cmd_code=%02x\n", 1635 cmd_code); 1636 else 1637 PCIE_DBG("pcishpc_issue_command() Success on " 1638 "cmd_code=%02x\n", cmd_code); 1639 1640 return (retCode); 1641 } 1642 1643 /* 1644 * pcishpc_wait_busy() 1645 * 1646 * Wait until the SHPC controller is not busy. 1647 */ 1648 static int 1649 pcishpc_wait_busy(pcie_hp_ctrl_t *ctrl_p) 1650 { 1651 uint32_t status; 1652 1653 /* Wait until SHPC controller is NOT busy */ 1654 for (;;) { 1655 status = pcishpc_read_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG); 1656 1657 /* Is there an MRL Sensor error? */ 1658 if ((status & PCI_HP_COMM_STS_ERR_MASK) == 1659 PCI_HP_COMM_STS_ERR_MRL_OPEN) { 1660 PCIE_DBG("pcishpc_wait_busy() ERROR: " 1661 "MRL Sensor error\n"); 1662 break; 1663 } 1664 1665 /* Is there an Invalid command error? */ 1666 if ((status & PCI_HP_COMM_STS_ERR_MASK) == 1667 PCI_HP_COMM_STS_ERR_INVALID_COMMAND) { 1668 PCIE_DBG("pcishpc_wait_busy() ERROR: Invalid " 1669 "command error\n"); 1670 break; 1671 } 1672 1673 /* Is there an Invalid Speed/Mode error? */ 1674 if ((status & PCI_HP_COMM_STS_ERR_MASK) == 1675 PCI_HP_COMM_STS_ERR_INVALID_SPEED) { 1676 PCIE_DBG("pcishpc_wait_busy() ERROR: Invalid " 1677 "Speed/Mode error\n"); 1678 break; 1679 } 1680 1681 /* Is the SHPC controller not BUSY? */ 1682 if (!(status & PCI_HP_COMM_STS_CTRL_BUSY)) { 1683 /* Return Success. */ 1684 return (DDI_SUCCESS); 1685 } 1686 1687 PCIE_DBG("pcishpc_wait_busy() SHPC controller busy. Waiting\n"); 1688 1689 /* Wait before polling the status register again. */ 1690 delay(drv_usectohz(PCIE_HP_CMD_WAIT_TIME)); 1691 } 1692 1693 return (DDI_FAILURE); 1694 } 1695 1696 static void 1697 pcishpc_attn_btn_handler(pcie_hp_slot_t *slot_p) 1698 { 1699 pcie_hp_led_state_t hs_power_led_state; 1700 callb_cpr_t cprinfo; 1701 1702 PCIE_DBG("pcishpc_attn_btn_handler: thread started\n"); 1703 1704 CALLB_CPR_INIT(&cprinfo, &slot_p->hs_ctrl->hc_mutex, 1705 callb_generic_cpr, "pcishpc_attn_btn_handler"); 1706 1707 mutex_enter(&slot_p->hs_ctrl->hc_mutex); 1708 1709 /* wait for ATTN button event */ 1710 cv_wait(&slot_p->hs_attn_btn_cv, &slot_p->hs_ctrl->hc_mutex); 1711 1712 while (slot_p->hs_attn_btn_thread_exit == B_FALSE) { 1713 if (slot_p->hs_attn_btn_pending == B_TRUE) { 1714 /* get the current state of power LED */ 1715 hs_power_led_state = slot_p->hs_power_led_state; 1716 1717 /* Blink the Power LED while we wait for 5 seconds */ 1718 (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, 1719 PCIE_HP_LED_BLINK); 1720 1721 /* wait for 5 seconds before taking any action */ 1722 if (cv_reltimedwait(&slot_p->hs_attn_btn_cv, 1723 &slot_p->hs_ctrl->hc_mutex, 1724 SEC_TO_TICK(5), TR_CLOCK_TICK) == -1) { 1725 /* 1726 * It is a time out; 1727 * make sure the ATTN pending flag is 1728 * still ON before sending the event 1729 * to DDI HP framework. 1730 */ 1731 if (slot_p->hs_attn_btn_pending == B_TRUE) { 1732 int hint; 1733 1734 /* restore the power LED state */ 1735 (void) pcishpc_setled(slot_p, 1736 PCIE_HP_POWER_LED, 1737 hs_power_led_state); 1738 /* 1739 * send the ATTN button event 1740 * to DDI HP framework 1741 */ 1742 slot_p->hs_attn_btn_pending = B_FALSE; 1743 1744 pcishpc_get_slot_state(slot_p); 1745 1746 if (slot_p->hs_info.cn_state <= 1747 DDI_HP_CN_STATE_PRESENT) { 1748 /* 1749 * Insertion. 1750 */ 1751 hint = SE_INCOMING_RES; 1752 } else { 1753 /* 1754 * Want to remove; 1755 */ 1756 hint = SE_OUTGOING_RES; 1757 } 1758 pcie_hp_gen_sysevent_req( 1759 slot_p->hs_info.cn_name, 1760 hint, 1761 slot_p->hs_ctrl->hc_dip, 1762 KM_SLEEP); 1763 1764 continue; 1765 } 1766 } 1767 1768 /* restore the power LED state */ 1769 (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, 1770 hs_power_led_state); 1771 continue; 1772 } 1773 1774 /* wait for another ATTN button event */ 1775 cv_wait(&slot_p->hs_attn_btn_cv, &slot_p->hs_ctrl->hc_mutex); 1776 } 1777 1778 PCIE_DBG("pcishpc_attn_btn_handler: thread exit\n"); 1779 cv_signal(&slot_p->hs_attn_btn_cv); 1780 CALLB_CPR_EXIT(&cprinfo); 1781 thread_exit(); 1782 } 1783 1784 /* 1785 * pcishpc_get_slot_state() 1786 * 1787 * Get the state of the slot. 1788 * The slot state should have been initialized before this function gets called. 1789 */ 1790 static void 1791 pcishpc_get_slot_state(pcie_hp_slot_t *slot_p) 1792 { 1793 uint32_t reg; 1794 ddi_hp_cn_state_t curr_state = slot_p->hs_info.cn_state; 1795 1796 /* Read the logical slot register for this Slot. */ 1797 reg = pcishpc_read_reg(slot_p->hs_ctrl, 1798 PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num); 1799 1800 /* Convert from the SHPC slot state to the HPC slot state. */ 1801 slot_p->hs_info.cn_state = pcishpc_slot_shpc_to_hpc(reg); 1802 if (curr_state == DDI_HP_CN_STATE_POWERED && 1803 slot_p->hs_info.cn_state > DDI_HP_CN_STATE_POWERED) { 1804 /* 1805 * Keep POWERED state if it is currently POWERED state because 1806 * this driver does not really implement enable/disable 1807 * slot operations. That is, when poweron, it actually enables 1808 * the slot also. 1809 * So, from hardware view, POWERED == ENABLED. 1810 * But, when user explicitly change to POWERED state, it should 1811 * be kept until user explicitly change to other states later. 1812 */ 1813 slot_p->hs_info.cn_state = DDI_HP_CN_STATE_POWERED; 1814 } 1815 1816 /* Convert from the SHPC Power LED state to the HPC Power LED state. */ 1817 slot_p->hs_power_led_state = pcishpc_led_shpc_to_hpc((reg>>2)&3); 1818 1819 /* Convert from the SHPC Attn LED state to the HPC Attn LED state. */ 1820 slot_p->hs_attn_led_state = pcishpc_led_shpc_to_hpc((reg>>4)&3); 1821 1822 /* We don't have a fault LED so just default it to OFF. */ 1823 slot_p->hs_fault_led_state = PCIE_HP_LED_OFF; 1824 1825 /* We don't have an active LED so just default it to OFF. */ 1826 slot_p->hs_active_led_state = PCIE_HP_LED_OFF; 1827 } 1828 1829 /* 1830 * pcishpc_set_slot_state() 1831 * 1832 * Updates the slot's state and leds. 1833 */ 1834 static int 1835 pcishpc_set_slot_state(pcie_hp_slot_t *slot_p, 1836 ddi_hp_cn_state_t new_slot_state) 1837 { 1838 uint32_t reg, cmd_code; 1839 ddi_hp_cn_state_t curr_state; 1840 1841 ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex)); 1842 1843 reg = pcishpc_read_reg(slot_p->hs_ctrl, 1844 PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num); 1845 1846 /* Default all states to unchanged. */ 1847 cmd_code = ((1 + slot_p->hs_num) << 8); 1848 1849 /* Has the slot state changed? */ 1850 curr_state = pcishpc_slot_shpc_to_hpc(reg); 1851 if (curr_state != new_slot_state) { 1852 PCIE_DBG("pcishpc_set_slot_state() Slot State changed"); 1853 1854 /* Set the new slot state in the Slot operation command. */ 1855 cmd_code |= pcishpc_slot_hpc_to_shpc(new_slot_state); 1856 } 1857 1858 /* Has the Power LED state changed? */ 1859 if (slot_p->hs_power_led_state != pcishpc_led_shpc_to_hpc((reg>>2)&3)) { 1860 PCIE_DBG("pcishpc_set_slot_state() Power LED State changed\n"); 1861 1862 /* Set the new power led state in the Slot operation command. */ 1863 cmd_code |= 1864 (pcishpc_led_hpc_to_shpc(slot_p->hs_power_led_state) << 2); 1865 } 1866 1867 /* Has the Attn LED state changed? */ 1868 if (slot_p->hs_attn_led_state != pcishpc_led_shpc_to_hpc((reg>>4)&3)) { 1869 PCIE_DBG("pcishpc_set_slot_state() Attn LED State changed\n"); 1870 1871 /* Set the new attn led state in the Slot operation command. */ 1872 cmd_code |= 1873 (pcishpc_led_hpc_to_shpc(slot_p->hs_attn_led_state) << 4); 1874 } 1875 1876 return (pcishpc_issue_command(slot_p->hs_ctrl, cmd_code)); 1877 } 1878 1879 /* 1880 * setup slot name/slot-number info. 1881 */ 1882 static void 1883 pcishpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p, int slot) 1884 { 1885 pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[slot]; 1886 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 1887 uchar_t *slotname_data; 1888 int *slotnum; 1889 uint_t count; 1890 int len; 1891 uchar_t *s; 1892 uint32_t bit_mask; 1893 int pci_id_cnt, pci_id_bit; 1894 int slots_before, found; 1895 int invalid_slotnum = 0; 1896 1897 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ctrl_p->hc_dip, 1898 DDI_PROP_DONTPASS, "physical-slot#", &slotnum, &count) == 1899 DDI_PROP_SUCCESS) { 1900 slot_p->hs_phy_slot_num = slotnum[0]; 1901 ddi_prop_free(slotnum); 1902 } else { 1903 if (ctrl_p->hc_device_increases) 1904 slot_p->hs_phy_slot_num = ctrl_p->hc_phys_start + slot; 1905 else 1906 slot_p->hs_phy_slot_num = ctrl_p->hc_phys_start - slot; 1907 1908 if ((ndi_prop_update_int(DDI_DEV_T_NONE, ctrl_p->hc_dip, 1909 "physical-slot#", slot_p->hs_phy_slot_num)) != DDI_SUCCESS) 1910 PCIE_DBG("pcishpc_set_slot_name(): failed to " 1911 "create phyical-slot#%d\n", 1912 slot_p->hs_phy_slot_num); 1913 } 1914 1915 /* Platform may not have initialized it */ 1916 if (!slot_p->hs_phy_slot_num) { 1917 slot_p->hs_phy_slot_num = pci_config_get8(bus_p->bus_cfg_hdl, 1918 PCI_BCNF_SECBUS); 1919 invalid_slotnum = 1; 1920 } 1921 slot_p->hs_info.cn_num = slot_p->hs_phy_slot_num; 1922 slot_p->hs_info.cn_num_dpd_on = DDI_HP_CN_NUM_NONE; 1923 1924 /* 1925 * construct the slot_name: 1926 * if "slot-names" property exists then use that name 1927 * else if valid slot number exists then it is "pci<slot-num>". 1928 * else it will be "pci<sec-bus-number>dev<dev-number>" 1929 */ 1930 if (ddi_getlongprop(DDI_DEV_T_ANY, ctrl_p->hc_dip, DDI_PROP_DONTPASS, 1931 "slot-names", (caddr_t)&slotname_data, &len) == DDI_PROP_SUCCESS) { 1932 bit_mask = slotname_data[3] | (slotname_data[2] << 8) | 1933 (slotname_data[1] << 16) | (slotname_data[0] << 24); 1934 1935 pci_id_bit = 1; 1936 pci_id_cnt = slots_before = found = 0; 1937 1938 /* 1939 * Walk the bit mask until we find the bit that corresponds 1940 * to our slots device number. We count how many bits 1941 * we find before we find our slot's bit. 1942 */ 1943 while (!found && (pci_id_cnt < 32)) { 1944 while (slot_p->hs_device_num != pci_id_cnt) { 1945 1946 /* 1947 * Find the next bit set. 1948 */ 1949 while (!(bit_mask & pci_id_bit) && 1950 (pci_id_cnt < 32)) { 1951 pci_id_bit = pci_id_bit << 1; 1952 pci_id_cnt++; 1953 } 1954 1955 if (slot_p->hs_device_num != pci_id_cnt) 1956 slots_before++; 1957 else 1958 found = 1; 1959 } 1960 } 1961 1962 if (pci_id_cnt < 32) { 1963 1964 /* 1965 * Set ptr to first string. 1966 */ 1967 s = slotname_data + 4; 1968 1969 /* 1970 * Increment past all the strings for the slots 1971 * before ours. 1972 */ 1973 while (slots_before) { 1974 while (*s != NULL) 1975 s++; 1976 s++; 1977 slots_before--; 1978 } 1979 1980 slot_p->hs_info.cn_name = i_ddi_strdup((char *)s, 1981 KM_SLEEP); 1982 kmem_free(slotname_data, len); 1983 return; 1984 } 1985 1986 /* slot-names entry not found */ 1987 PCIE_DBG("pcishpc_set_slot_name(): " 1988 "No slot-names entry found for slot #%d\n", 1989 slot_p->hs_phy_slot_num); 1990 kmem_free(slotname_data, len); 1991 } 1992 1993 if (invalid_slotnum) { 1994 char tmp_name[256]; 1995 1996 (void) snprintf(tmp_name, sizeof (tmp_name), "pci%d", 1997 slot_p->hs_device_num); 1998 slot_p->hs_info.cn_name = i_ddi_strdup(tmp_name, KM_SLEEP); 1999 } else { 2000 char tmp_name[256]; 2001 2002 (void) snprintf(tmp_name, sizeof (tmp_name), "pci%d", 2003 slot_p->hs_phy_slot_num); 2004 slot_p->hs_info.cn_name = i_ddi_strdup(tmp_name, KM_SLEEP); 2005 } 2006 } 2007 2008 /* 2009 * pcishpc_set_bus_speed() 2010 * 2011 * Set the bus speed and mode. 2012 */ 2013 static int 2014 pcishpc_set_bus_speed(pcie_hp_slot_t *slot_p) 2015 { 2016 pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; 2017 int curr_speed = ctrl_p->hc_curr_bus_speed; 2018 int speed = -1; 2019 int avail_slots; 2020 uint32_t status, slots_avail1_reg, slots_avail2_reg; 2021 2022 ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex)); 2023 2024 /* Make sure that the slot is in a correct state */ 2025 status = pcishpc_read_reg(ctrl_p, 2026 PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num); 2027 2028 /* Return failure if the slot is empty */ 2029 if ((status & PCI_HP_SLOT_CARD_EMPTY_MASK) == 2030 PCI_HP_SLOT_CARD_EMPTY_MASK) { 2031 PCIE_DBG("pcishpc_set_bus_speed() failed: " 2032 "the slot is empty\n"); 2033 return (DDI_FAILURE); 2034 } 2035 2036 /* Return failure if the slot is not in disabled state */ 2037 if ((status & PCI_HP_SLOT_STATE_MASK) != PCI_HP_SLOT_DISABLED) { 2038 PCIE_DBG("pcishpc_set_bus_speed() failed: " 2039 "incorrect slot state\n"); 2040 return (DDI_FAILURE); 2041 } 2042 2043 /* Set the "power-only" mode for the slot */ 2044 if (pcishpc_issue_command(ctrl_p, ((1+slot_p->hs_num)<<8) | 2045 PCI_HP_SLOT_POWER_ONLY) != DDI_SUCCESS) { 2046 PCIE_DBG("pcishpc_set_bus_speed() failed to set " 2047 "the slot %d in the power-only mode\n", slot_p->hs_num); 2048 return (DDI_FAILURE); 2049 } 2050 2051 /* Wait for power good */ 2052 delay(drv_usectohz(PCIE_HP_POWER_GOOD_WAIT_TIME)); 2053 2054 /* Make sure that the slot is in "power-only" state */ 2055 status = pcishpc_read_reg(ctrl_p, 2056 PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num); 2057 2058 if ((status & PCI_HP_SLOT_STATE_MASK) != PCI_HP_SLOT_POWER_ONLY) { 2059 PCIE_DBG("pcishpc_set_bus_speed() " 2060 "power-only failed: incorrect slot state\n"); 2061 return (DDI_FAILURE); 2062 } 2063 2064 slots_avail1_reg = pcishpc_read_reg(ctrl_p, 2065 PCI_HP_SLOTS_AVAIL_I_REG); 2066 slots_avail2_reg = pcishpc_read_reg(ctrl_p, 2067 PCI_HP_SLOTS_AVAIL_II_REG); 2068 2069 /* 2070 * Check if SHPC has available slots and select the highest 2071 * available bus speed for the slot. 2072 * 2073 * The bus speed codes are: 2074 * 100 - 133Mhz; <--+ 2075 * 011 - 100Mhz; <--+ PCI-X 2076 * 010 - 66Mhz; <--+ 2077 * 2078 * 001 - 66Mhz; <--+ 2079 * 000 - 33Mhz <--+ Conv PCI 2080 */ 2081 switch (status & PCI_HP_SLOT_PCIX_CAPABLE_MASK) { 2082 case PCI_HP_SLOT_133MHZ_PCIX_CAPABLE: 2083 avail_slots = (slots_avail1_reg >> 2084 PCI_HP_AVAIL_133MHZ_PCIX_SPEED_SHIFT) & 2085 PCI_HP_AVAIL_SPEED_MASK; 2086 2087 if (((curr_speed == -1) && avail_slots) || 2088 (curr_speed == PCI_HP_SBCR_133MHZ_PCIX_SPEED)) { 2089 speed = PCI_HP_SBCR_133MHZ_PCIX_SPEED; 2090 break; 2091 } 2092 /* FALLTHROUGH */ 2093 case PCI_HP_SLOT_100MHZ_PCIX_CAPABLE: 2094 avail_slots = (slots_avail1_reg >> 2095 PCI_HP_AVAIL_100MHZ_PCIX_SPEED_SHIFT) & 2096 PCI_HP_AVAIL_SPEED_MASK; 2097 2098 if (((curr_speed == -1) && avail_slots) || 2099 (curr_speed == PCI_HP_SBCR_100MHZ_PCIX_SPEED)) { 2100 speed = PCI_HP_SBCR_100MHZ_PCIX_SPEED; 2101 break; 2102 } 2103 /* FALLTHROUGH */ 2104 case PCI_HP_SLOT_66MHZ_PCIX_CAPABLE: 2105 avail_slots = (slots_avail1_reg >> 2106 PCI_HP_AVAIL_66MHZ_PCIX_SPEED_SHIFT) & 2107 PCI_HP_AVAIL_SPEED_MASK; 2108 2109 if (((curr_speed == -1) && avail_slots) || 2110 (curr_speed == PCI_HP_SBCR_66MHZ_PCIX_SPEED)) { 2111 speed = PCI_HP_SBCR_66MHZ_PCIX_SPEED; 2112 break; 2113 } 2114 /* FALLTHROUGH */ 2115 default: 2116 avail_slots = (slots_avail2_reg >> 2117 PCI_HP_AVAIL_66MHZ_CONV_SPEED_SHIFT) & 2118 PCI_HP_AVAIL_SPEED_MASK; 2119 2120 if ((status & PCI_HP_SLOT_66MHZ_CONV_CAPABLE) && 2121 (((curr_speed == -1) && avail_slots) || 2122 (curr_speed == PCI_HP_SBCR_66MHZ_CONV_SPEED))) { 2123 speed = PCI_HP_SBCR_66MHZ_CONV_SPEED; 2124 } else { 2125 avail_slots = (slots_avail1_reg >> 2126 PCI_HP_AVAIL_33MHZ_CONV_SPEED_SHIFT) & 2127 PCI_HP_AVAIL_SPEED_MASK; 2128 2129 if (((curr_speed == -1) && (avail_slots)) || 2130 (curr_speed == PCI_HP_SBCR_33MHZ_CONV_SPEED)) { 2131 speed = PCI_HP_SBCR_33MHZ_CONV_SPEED; 2132 } else { 2133 PCIE_DBG("pcishpc_set_bus_speed() " 2134 " failed to set the bus speed, slot# %d\n", 2135 slot_p->hs_num); 2136 return (DDI_FAILURE); 2137 } 2138 } 2139 break; 2140 } 2141 2142 /* 2143 * If the bus segment is already running, check to see the card 2144 * in the slot can support the current bus speed. 2145 */ 2146 if (curr_speed == speed) { 2147 /* 2148 * Check to see there is any slot available for the current 2149 * bus speed. Otherwise, we need fail the current slot connect 2150 * request. 2151 */ 2152 return ((avail_slots <= ctrl_p->hc_num_slots_connected) ? 2153 DDI_FAILURE : DDI_SUCCESS); 2154 } 2155 2156 /* Set the bus speed */ 2157 if (pcishpc_issue_command(ctrl_p, PCI_HP_COMM_STS_SET_SPEED | 2158 speed) == DDI_FAILURE) { 2159 PCIE_DBG("pcishpc_set_bus_speed() failed " 2160 "to set bus %d speed\n", slot_p->hs_num); 2161 return (DDI_FAILURE); 2162 } 2163 2164 /* Check the current bus speed */ 2165 status = pcishpc_read_reg(ctrl_p, PCI_HP_PROF_IF_SBCR_REG) & 2166 PCI_HP_SBCR_SPEED_MASK; 2167 if ((status & PCI_HP_SBCR_SPEED_MASK) != speed) { 2168 PCIE_DBG("pcishpc_set_bus_speed() an incorrect " 2169 "bus speed, slot = 0x%x, speed = 0x%x\n", 2170 slot_p->hs_num, status & PCI_HP_SBCR_SPEED_MASK); 2171 return (DDI_FAILURE); 2172 } 2173 2174 2175 /* Save the current bus speed */ 2176 ctrl_p->hc_curr_bus_speed = speed; 2177 2178 return (DDI_SUCCESS); 2179 } 2180 2181 /* 2182 * pcishpc_setled() 2183 * 2184 * Change the state of a slot's LED. 2185 */ 2186 static int 2187 pcishpc_setled(pcie_hp_slot_t *slot_p, pcie_hp_led_t led, 2188 pcie_hp_led_state_t state) 2189 { 2190 ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex)); 2191 2192 switch (led) { 2193 case PCIE_HP_FAULT_LED: 2194 PCIE_DBG("pcishpc_setled() - PCIE_HP_FAULT_LED " 2195 "(set %s)\n", pcishpc_slot_textledstate(state)); 2196 slot_p->hs_fault_led_state = state; 2197 break; 2198 2199 case PCIE_HP_POWER_LED: 2200 PCIE_DBG("pcishpc_setled() - PCIE_HP_POWER_LED " 2201 "(set %s)\n", pcishpc_slot_textledstate(state)); 2202 slot_p->hs_power_led_state = state; 2203 break; 2204 2205 case PCIE_HP_ATTN_LED: 2206 PCIE_DBG("pcishpc_setled() - PCIE_HP_ATTN_LED " 2207 "(set %s)\n", pcishpc_slot_textledstate(state)); 2208 slot_p->hs_attn_led_state = state; 2209 break; 2210 2211 case PCIE_HP_ACTIVE_LED: 2212 PCIE_DBG("pcishpc_setled() - PCIE_HP_ACTIVE_LED " 2213 "(set %s)\n", pcishpc_slot_textledstate(state)); 2214 slot_p->hs_active_led_state = state; 2215 break; 2216 } 2217 2218 return (pcishpc_set_slot_state(slot_p, slot_p->hs_info.cn_state)); 2219 } 2220 2221 /* 2222 * pcishpc_led_shpc_to_hpc() 2223 * 2224 * Convert from SHPC indicator status to HPC indicator status. 2225 */ 2226 static int 2227 pcishpc_led_shpc_to_hpc(int state) 2228 { 2229 switch (state) { 2230 case 1: /* SHPC On bits b01 */ 2231 return (PCIE_HP_LED_ON); 2232 case 2: /* SHPC Blink bits b10 */ 2233 return (PCIE_HP_LED_BLINK); 2234 case 3: /* SHPC Off bits b11 */ 2235 return (PCIE_HP_LED_OFF); 2236 } 2237 2238 return (PCIE_HP_LED_OFF); 2239 } 2240 2241 2242 /* 2243 * pcishpc_led_hpc_to_shpc() 2244 * 2245 * Convert from HPC indicator status to SHPC indicator status. 2246 */ 2247 static int 2248 pcishpc_led_hpc_to_shpc(int state) 2249 { 2250 switch (state) { 2251 case PCIE_HP_LED_ON: 2252 return (1); /* SHPC On bits b01 */ 2253 case PCIE_HP_LED_BLINK: 2254 return (2); /* SHPC Blink bits b10 */ 2255 case PCIE_HP_LED_OFF: 2256 return (3); /* SHPC Off bits b11 */ 2257 } 2258 2259 return (3); /* SHPC Off bits b11 */ 2260 } 2261 2262 /* 2263 * pcishpc_slot_shpc_to_hpc() 2264 * 2265 * Convert from SHPC slot state to HPC slot state. 2266 * The argument shpc_state is expected to be read from the slot register. 2267 */ 2268 static int 2269 pcishpc_slot_shpc_to_hpc(int shpc_state) 2270 { 2271 if ((shpc_state & PCI_HP_SLOT_CARD_EMPTY_MASK) == 2272 PCI_HP_SLOT_CARD_EMPTY_MASK) 2273 return (DDI_HP_CN_STATE_EMPTY); 2274 2275 switch (shpc_state & PCI_HP_SLOT_STATE_MASK) { 2276 case PCI_HP_SLOT_POWER_ONLY: /* SHPC Powered Only */ 2277 return (DDI_HP_CN_STATE_POWERED); 2278 2279 case PCI_HP_SLOT_ENABLED: /* SHPC Enabled */ 2280 return (DDI_HP_CN_STATE_ENABLED); 2281 2282 case PCI_HP_SLOT_DISABLED: /* SHPC Disabled */ 2283 default : /* SHPC Reserved */ 2284 return (DDI_HP_CN_STATE_PRESENT); 2285 } 2286 } 2287 2288 /* 2289 * pcishpc_slot_hpc_to_shpc() 2290 * 2291 * Convert from HPC slot state to SHPC slot state. 2292 */ 2293 static int 2294 pcishpc_slot_hpc_to_shpc(int state) 2295 { 2296 switch (state) { 2297 case DDI_HP_CN_STATE_EMPTY: 2298 return (0); 2299 2300 case DDI_HP_CN_STATE_POWERED: 2301 return (PCI_HP_SLOT_POWER_ONLY); 2302 2303 case DDI_HP_CN_STATE_ENABLED: 2304 return (PCI_HP_SLOT_ENABLED); 2305 2306 default: 2307 return (PCI_HP_SLOT_DISABLED); 2308 } 2309 } 2310 2311 /* 2312 * pcishpc_slot_textslotstate() 2313 * 2314 * Convert the request into a text message. 2315 */ 2316 static char * 2317 pcishpc_slot_textslotstate(ddi_hp_cn_state_t state) 2318 { 2319 /* Convert an HPC slot state into a textual string. */ 2320 if (state == DDI_HP_CN_STATE_EMPTY) 2321 return ("HPC_SLOT_EMPTY"); 2322 else if (state == DDI_HP_CN_STATE_ENABLED) 2323 return ("HPC_SLOT_ENABLED"); 2324 else if (state == DDI_HP_CN_STATE_POWERED) 2325 return ("HPC_SLOT_POWERED_ONLY"); 2326 else 2327 return ("HPC_SLOT_DISABLED"); 2328 } 2329 2330 2331 /* 2332 * pcishpc_slot_textledstate() 2333 * 2334 * Convert the led state into a text message. 2335 */ 2336 static char * 2337 pcishpc_slot_textledstate(pcie_hp_led_state_t state) 2338 { 2339 /* Convert an HPC led state into a textual string. */ 2340 switch (state) { 2341 case PCIE_HP_LED_OFF: 2342 return ("off"); 2343 2344 case PCIE_HP_LED_ON: 2345 return ("on"); 2346 2347 case PCIE_HP_LED_BLINK: 2348 return ("blink"); 2349 } 2350 return ("unknown"); 2351 } 2352 2353 2354 /* 2355 * pcishpc_read_reg() 2356 * 2357 * Read from a SHPC controller register. 2358 */ 2359 static uint32_t 2360 pcishpc_read_reg(pcie_hp_ctrl_t *ctrl_p, int reg) 2361 { 2362 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 2363 2364 /* Setup the SHPC dword select register. */ 2365 pci_config_put8(bus_p->bus_cfg_hdl, 2366 bus_p->bus_pci_hp_off + PCI_HP_DWORD_SELECT_OFF, (uint8_t)reg); 2367 2368 /* Read back the SHPC dword select register and verify. */ 2369 if (pci_config_get8(bus_p->bus_cfg_hdl, bus_p->bus_pci_hp_off + 2370 PCI_HP_DWORD_SELECT_OFF) != (uint8_t)reg) { 2371 PCIE_DBG("pcishpc_read_reg() - Failed writing DWORD " 2372 "select reg\n"); 2373 return (0xFFFFFFFF); 2374 } 2375 2376 /* Read from the SHPC dword data register. */ 2377 return (pci_config_get32(bus_p->bus_cfg_hdl, 2378 bus_p->bus_pci_hp_off + PCI_HP_DWORD_DATA_OFF)); 2379 } 2380 2381 2382 /* 2383 * pcishpc_write_reg() 2384 * 2385 * Write to a SHPC controller register. 2386 */ 2387 static void 2388 pcishpc_write_reg(pcie_hp_ctrl_t *ctrl_p, int reg, uint32_t data) 2389 { 2390 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 2391 2392 /* Setup the SHPC dword select register. */ 2393 pci_config_put8(bus_p->bus_cfg_hdl, 2394 bus_p->bus_pci_hp_off + PCI_HP_DWORD_SELECT_OFF, (uint8_t)reg); 2395 2396 /* Read back the SHPC dword select register and verify. */ 2397 if (pci_config_get8(bus_p->bus_cfg_hdl, bus_p->bus_pci_hp_off + 2398 PCI_HP_DWORD_SELECT_OFF) != (uint8_t)reg) { 2399 PCIE_DBG("pcishpc_write_reg() - Failed writing " 2400 "DWORD select reg\n"); 2401 return; 2402 } 2403 2404 /* Write to the SHPC dword data register. */ 2405 pci_config_put32(bus_p->bus_cfg_hdl, 2406 bus_p->bus_pci_hp_off + PCI_HP_DWORD_DATA_OFF, data); 2407 2408 /* 2409 * Issue a read of the VendorID/DeviceID just to force the previous 2410 * write to complete. This is probably not necessary, but it does 2411 * help enforce ordering if there is an issue. 2412 */ 2413 (void) pci_config_get16(bus_p->bus_cfg_hdl, PCI_CONF_VENID); 2414 } 2415 2416 2417 #ifdef DEBUG 2418 /* 2419 * pcishpc_dump_regs() 2420 * 2421 * Dumps all of the SHPC controller registers. 2422 */ 2423 static void 2424 pcishpc_dump_regs(pcie_hp_ctrl_t *ctrl_p) 2425 { 2426 int slot, numSlots; 2427 uint32_t reg; 2428 char *state; 2429 2430 if (!pcie_debug_flags) 2431 return; 2432 2433 PCIE_DBG("pcishpc_dump_regs() called:\n"); 2434 PCIE_DBG("=========================================================="); 2435 2436 PCIE_DBG("SHPC Base Offset " 2437 ": 0x%08x\n", pcishpc_read_reg(ctrl_p, PCI_HP_BASE_OFFSET_REG)); 2438 2439 reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOTS_AVAIL_I_REG); 2440 2441 PCIE_DBG("Number of PCIX slots avail (33 Mhz) : %d\n", 2442 (reg & 31)); 2443 2444 PCIE_DBG("Number of PCIX slots avail (66 Mhz) : %d\n", 2445 ((reg>>8) & 31)); 2446 2447 PCIE_DBG("Number of PCIX slots avail (100 Mhz) : %d\n", 2448 ((reg>>16) & 31)); 2449 2450 PCIE_DBG("Number of PCIX slots avail (133 Mhz) : %d\n", 2451 ((reg>>24) & 31)); 2452 2453 reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOTS_AVAIL_II_REG); 2454 2455 PCIE_DBG("Number of conventional PCI slots (66 Mhz) : %d\n", 2456 (reg & 31)); 2457 2458 reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOT_CONFIGURATION_REG); 2459 2460 numSlots = (reg & 31); 2461 2462 PCIE_DBG("Number of Slots connected to this port : %d\n", 2463 numSlots); 2464 2465 PCIE_DBG("PCI Device # for First HotPlug Slot : %d\n", 2466 ((reg>>8) & 31)); 2467 2468 PCIE_DBG("Physical Slot # for First PCI Device # : %d\n", 2469 ((reg>>16) & 0x7ff)); 2470 2471 PCIE_DBG("Physical Slot Number Up/Down : %d\n", 2472 ((reg>>29) & 0x1)); 2473 2474 PCIE_DBG("MRL Sensor Implemented : %s\n", 2475 (reg & PCI_HP_SLOT_CONFIG_MRL_SENSOR) ? "Yes" : "No"); 2476 2477 PCIE_DBG("Attention Button Implemented : %s\n", 2478 (reg & PCI_HP_SLOT_CONFIG_ATTN_BUTTON) ? "Yes" : "No"); 2479 2480 reg = pcishpc_read_reg(ctrl_p, PCI_HP_PROF_IF_SBCR_REG); 2481 2482 switch (reg & 7) { 2483 case 0: 2484 state = "33Mhz Conventional PCI"; 2485 break; 2486 case 1: 2487 state = "66Mhz Conventional PCI"; 2488 break; 2489 case 2: 2490 state = "66Mhz PCI-X"; 2491 break; 2492 case 3: 2493 state = "100Mhz PCI-X"; 2494 break; 2495 case 4: 2496 state = "133Mhz PCI-X"; 2497 break; 2498 default: 2499 state = "Reserved (Error)"; 2500 break; 2501 } 2502 2503 PCIE_DBG("Current Port Operation Mode : %s\n", state); 2504 2505 PCIE_DBG("SHPC Interrupt Message Number : %d\n", 2506 ((reg>>16) &31)); 2507 2508 PCIE_DBG("SHPC Programming Interface : %d\n", 2509 ((reg>>24) & 0xff)); 2510 2511 reg = pcishpc_read_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG); 2512 2513 PCIE_DBG("SHPC Command Code : %d\n", 2514 (reg & 0xff)); 2515 2516 PCIE_DBG("SHPC Target Slot : %d\n", 2517 ((reg>>8) & 31)); 2518 2519 PCIE_DBG("SHPC Controller Busy : %s\n", 2520 ((reg>>16) & 1) ? "Yes" : "No"); 2521 2522 PCIE_DBG("SHPC Controller Err: MRL Sensor : %s\n", 2523 ((reg>>17) & 1) ? "Yes" : "No"); 2524 2525 PCIE_DBG("SHPC Controller Err: Invalid Command : %s\n", 2526 ((reg>>18) & 1) ? "Yes" : "No"); 2527 2528 PCIE_DBG("SHPC Controller Err: Invalid Speed/Mode : %s\n", 2529 ((reg>>19) & 1) ? "Yes" : "No"); 2530 2531 reg = pcishpc_read_reg(ctrl_p, PCI_HP_IRQ_LOCATOR_REG); 2532 2533 PCIE_DBG("Command Completion Interrupt Pending : %s\n", 2534 (reg & PCI_HP_IRQ_CMD_COMPLETE) ? "Yes" : "No"); 2535 2536 for (slot = 0; slot < numSlots; slot++) { 2537 PCIE_DBG("Slot %d Interrupt Pending : %s\n", slot+1, 2538 (reg & (PCI_HP_IRQ_SLOT_N_PENDING<<slot)) ? "Yes" : "No"); 2539 } 2540 2541 reg = pcishpc_read_reg(ctrl_p, PCI_HP_SERR_LOCATOR_REG); 2542 2543 PCIE_DBG("Arbiter SERR Pending : %s\n", 2544 (reg & PCI_HP_IRQ_SERR_ARBITER_PENDING) ? "Yes" : "No"); 2545 2546 for (slot = 0; slot < numSlots; slot++) { 2547 PCIE_DBG("Slot %d SERR Pending : %s\n", 2548 slot+1, (reg & 2549 (PCI_HP_IRQ_SERR_SLOT_N_PENDING<<slot)) ? "Yes" : "No"); 2550 } 2551 2552 reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG); 2553 2554 PCIE_DBG("Global Interrupt Mask : %s\n", 2555 (reg & PCI_HP_SERR_INT_GLOBAL_IRQ_MASK) ? "Yes" : "No"); 2556 2557 PCIE_DBG("Global SERR Mask : %s\n", 2558 (reg & PCI_HP_SERR_INT_GLOBAL_SERR_MASK) ? "Yes" : "No"); 2559 2560 PCIE_DBG("Command Completion Interrupt Mask : %s\n", 2561 (reg & PCI_HP_SERR_INT_CMD_COMPLETE_MASK) ? "Yes" : "No"); 2562 2563 PCIE_DBG("Arbiter SERR Mask : %s\n", 2564 (reg & PCI_HP_SERR_INT_ARBITER_SERR_MASK) ? "Yes" : "No"); 2565 2566 PCIE_DBG("Command Completion Detected : %s\n", 2567 (reg & PCI_HP_SERR_INT_CMD_COMPLETE_IRQ) ? "Yes" : "No"); 2568 2569 PCIE_DBG("Arbiter Timeout Detected : %s\n", 2570 (reg & PCI_HP_SERR_INT_ARBITER_IRQ) ? "Yes" : "No"); 2571 2572 for (slot = 0; slot < numSlots; slot++) { 2573 PCIE_DBG("Logical Slot %d Registers:\n", slot+1); 2574 PCIE_DBG("------------------------------------\n"); 2575 2576 reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot); 2577 2578 PCIE_DBG("Slot %d state : %s\n", slot+1, 2579 pcishpc_slot_textslotstate(pcishpc_slot_shpc_to_hpc(reg))); 2580 2581 PCIE_DBG("Slot %d Power Indicator State : %s\n", slot+1, 2582 pcishpc_slot_textledstate(pcishpc_led_shpc_to_hpc( 2583 (reg>>2) &3))); 2584 2585 PCIE_DBG("Slot %d Attention Indicator State : %s\n", slot+1, 2586 pcishpc_slot_textledstate(pcishpc_led_shpc_to_hpc( 2587 (reg>>4)&3))); 2588 2589 PCIE_DBG("Slot %d Power Fault : %s\n", slot+1, 2590 ((reg>>6)&1) ? "Fault Detected" : "No Fault"); 2591 PCIE_DBG("Slot %d Attention Button : %s\n", slot+1, 2592 ((reg>>7)&1) ? "Depressed" : "Not Depressed"); 2593 PCIE_DBG("Slot %d MRL Sensor : %s\n", slot+1, 2594 ((reg>>8)&1) ? "Not Closed" : "Closed"); 2595 PCIE_DBG("Slot %d 66mhz Capable : %s\n", slot+1, 2596 ((reg>>9)&1) ? "66mhz" : "33mgz"); 2597 2598 switch ((reg>>10)&3) { 2599 case 0: 2600 state = "Card Present 7.5W"; 2601 break; 2602 case 1: 2603 state = "Card Present 15W"; 2604 break; 2605 case 2: 2606 state = "Card Present 25W"; 2607 break; 2608 case 3: 2609 state = "Slot Empty"; 2610 break; 2611 } 2612 2613 PCIE_DBG("Slot %d PRSNT1#/PRSNT2# : %s\n", slot+1, 2614 state); 2615 2616 switch ((reg>>12)&3) { 2617 case 0: 2618 state = "Non PCI-X"; 2619 break; 2620 case 1: 2621 state = "66mhz PCI-X"; 2622 break; 2623 case 2: 2624 state = "Reserved"; 2625 break; 2626 case 3: 2627 state = "133mhz PCI-X"; 2628 break; 2629 } 2630 2631 PCIE_DBG("Slot %d Card Presence Change Detected : %s\n", 2632 slot+1, (reg & PCI_HP_SLOT_PRESENCE_DETECTED) ? "Yes" : 2633 "No"); 2634 PCIE_DBG("Slot %d Isolated Power Fault Detected : %s\n", 2635 slot+1, (reg & PCI_HP_SLOT_ISO_PWR_DETECTED) ? "Yes" : 2636 "No"); 2637 PCIE_DBG("Slot %d Attention Button Press Detected : %s\n", 2638 slot+1, (reg & PCI_HP_SLOT_ATTN_DETECTED) ? "Yes" : "No"); 2639 PCIE_DBG("Slot %d MRL Sensor Change Detected : %s\n", 2640 slot+1, (reg & PCI_HP_SLOT_MRL_DETECTED) ? "Yes" : "No"); 2641 PCIE_DBG("Slot %d Connected Power Fault Detected : %s\n", 2642 slot+1, (reg & PCI_HP_SLOT_POWER_DETECTED) ? "Yes" : "No"); 2643 2644 PCIE_DBG("Slot %d Card Presence IRQ Masked : %s\n", 2645 slot+1, (reg & PCI_HP_SLOT_PRESENCE_MASK) ? "Yes" : "No"); 2646 PCIE_DBG("Slot %d Isolated Power Fault IRQ Masked : %s\n", 2647 slot+1, (reg & PCI_HP_SLOT_ISO_PWR_MASK) ? "Yes" : "No"); 2648 PCIE_DBG("Slot %d Attention Button IRQ Masked : %s\n", 2649 slot+1, (reg & PCI_HP_SLOT_ATTN_MASK) ? "Yes" : "No"); 2650 PCIE_DBG("Slot %d MRL Sensor IRQ Masked : %s\n", 2651 slot+1, (reg & PCI_HP_SLOT_MRL_MASK) ? "Yes" : "No"); 2652 PCIE_DBG("Slot %d Connected Power Fault IRQ Masked : %s\n", 2653 slot+1, (reg & PCI_HP_SLOT_POWER_MASK) ? "Yes" : "No"); 2654 PCIE_DBG("Slot %d MRL Sensor SERR Masked : %s\n", 2655 slot+1, (reg & PCI_HP_SLOT_MRL_SERR_MASK) ? "Yes" : "No"); 2656 PCIE_DBG("Slot %d Connected Power Fault SERR Masked : %s\n", 2657 slot+1, (reg & PCI_HP_SLOT_POWER_SERR_MASK) ? "Yes" : "No"); 2658 } 2659 } 2660 #endif /* DEBUG */ 2661