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