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