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