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 /*
  23  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 /*
  27  * This file contains Standard PCI Express HotPlug functionality that is
  28  * compatible with the PCI Express ver 1.1 specification.
  29  *
  30  * NOTE: This file is compiled and delivered through misc/pcie module.
  31  */
  32 
  33 #include <sys/types.h>
  34 #include <sys/note.h>
  35 #include <sys/conf.h>
  36 #include <sys/kmem.h>
  37 #include <sys/debug.h>
  38 #include <sys/vtrace.h>
  39 #include <sys/autoconf.h>
  40 #include <sys/varargs.h>
  41 #include <sys/ddi_impldefs.h>
  42 #include <sys/time.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/pci_impl.h>
  49 #include <sys/hotplug/pci/pcie_hp.h>
  50 #include <sys/hotplug/pci/pciehpc.h>
  51 
  52 typedef struct pciehpc_prop {
  53         char    *prop_name;
  54         char    *prop_value;
  55 } pciehpc_prop_t;
  56 
  57 static pciehpc_prop_t   pciehpc_props[] = {
  58         { PCIEHPC_PROP_LED_FAULT,       PCIEHPC_PROP_VALUE_LED },
  59         { PCIEHPC_PROP_LED_POWER,       PCIEHPC_PROP_VALUE_LED },
  60         { PCIEHPC_PROP_LED_ATTN,        PCIEHPC_PROP_VALUE_LED },
  61         { PCIEHPC_PROP_LED_ACTIVE,      PCIEHPC_PROP_VALUE_LED },
  62         { PCIEHPC_PROP_CARD_TYPE,       PCIEHPC_PROP_VALUE_TYPE },
  63         { PCIEHPC_PROP_BOARD_TYPE,      PCIEHPC_PROP_VALUE_TYPE },
  64         { PCIEHPC_PROP_SLOT_CONDITION,  PCIEHPC_PROP_VALUE_TYPE }
  65 };
  66 
  67 /* Local functions prototype */
  68 static int pciehpc_hpc_init(pcie_hp_ctrl_t *ctrl_p);
  69 static int pciehpc_hpc_uninit(pcie_hp_ctrl_t *ctrl_p);
  70 static int pciehpc_slotinfo_init(pcie_hp_ctrl_t *ctrl_p);
  71 static int pciehpc_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p);
  72 static int pciehpc_enable_intr(pcie_hp_ctrl_t *ctrl_p);
  73 static int pciehpc_disable_intr(pcie_hp_ctrl_t *ctrl_p);
  74 static pcie_hp_ctrl_t *pciehpc_create_controller(dev_info_t *dip);
  75 static void pciehpc_destroy_controller(dev_info_t *dip);
  76 static int pciehpc_register_slot(pcie_hp_ctrl_t *ctrl_p);
  77 static int pciehpc_unregister_slot(pcie_hp_ctrl_t *ctrl_p);
  78 static int pciehpc_slot_get_property(pcie_hp_slot_t *slot_p,
  79     ddi_hp_property_t *arg, ddi_hp_property_t *rval);
  80 static int pciehpc_slot_set_property(pcie_hp_slot_t *slot_p,
  81     ddi_hp_property_t *arg, ddi_hp_property_t *rval);
  82 static void pciehpc_issue_hpc_command(pcie_hp_ctrl_t *ctrl_p, uint16_t control);
  83 static void pciehpc_attn_btn_handler(pcie_hp_ctrl_t *ctrl_p);
  84 static pcie_hp_led_state_t pciehpc_led_state_to_hpc(uint16_t state);
  85 static pcie_hp_led_state_t pciehpc_get_led_state(pcie_hp_ctrl_t *ctrl_p,
  86     pcie_hp_led_t led);
  87 static void pciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led,
  88     pcie_hp_led_state_t state);
  89 
  90 static int pciehpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
  91     ddi_hp_cn_state_t target_state);
  92 static int pciehpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
  93     ddi_hp_cn_state_t target_state);
  94 static int pciehpc_change_slot_state(pcie_hp_slot_t *slot_p,
  95     ddi_hp_cn_state_t target_state);
  96 static int
  97     pciehpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result);
  98 static int
  99     pciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result);
 100 static int pciehpc_slot_probe(pcie_hp_slot_t *slot_p);
 101 static int pciehpc_slot_unprobe(pcie_hp_slot_t *slot_p);
 102 static void pciehpc_handle_power_fault(dev_info_t *dip);
 103 static void pciehpc_power_fault_handler(void *arg);
 104 
 105 #ifdef  DEBUG
 106 static void pciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p);
 107 #endif  /* DEBUG */
 108 
 109 /*
 110  * Global functions (called by other drivers/modules)
 111  */
 112 
 113 /*
 114  * Initialize Hot Plug Controller if present. The arguments are:
 115  *      dip     - Devinfo node pointer to the hot plug bus node
 116  *      regops  - register ops to access HPC registers for non-standard
 117  *                HPC hw implementations (e.g: HPC in host PCI-E brdiges)
 118  *                This is NULL for standard HPC in PCIe bridges.
 119  * Returns:
 120  *      DDI_SUCCESS for successful HPC initialization
 121  *      DDI_FAILURE for errors or if HPC hw not found
 122  */
 123 int
 124 pciehpc_init(dev_info_t *dip, caddr_t arg)
 125 {
 126         pcie_hp_regops_t        *regops = (pcie_hp_regops_t *)(void *)arg;
 127         pcie_hp_ctrl_t          *ctrl_p;
 128 
 129         PCIE_DBG("pciehpc_init() called (dip=%p)\n", (void *)dip);
 130 
 131         /* Make sure that it is not already initialized */
 132         if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) != NULL) {
 133                 PCIE_DBG("%s%d: pciehpc instance already initialized!\n",
 134                     ddi_driver_name(dip), ddi_get_instance(dip));
 135                 return (DDI_SUCCESS);
 136         }
 137 
 138         /* Allocate a new hotplug controller and slot structures */
 139         ctrl_p = pciehpc_create_controller(dip);
 140 
 141         /* setup access handle for HPC regs */
 142         if (regops != NULL) {
 143                 /* HPC access is non-standard; use the supplied reg ops */
 144                 ctrl_p->hc_regops = *regops;
 145         }
 146 
 147         /*
 148          * Setup resource maps for this bus node.
 149          */
 150         (void) pci_resource_setup(dip);
 151 
 152         PCIE_DISABLE_ERRORS(dip);
 153 
 154         /*
 155          * Set the platform specific hot plug mode.
 156          */
 157         ctrl_p->hc_ops.init_hpc_hw = pciehpc_hpc_init;
 158         ctrl_p->hc_ops.uninit_hpc_hw = pciehpc_hpc_uninit;
 159         ctrl_p->hc_ops.init_hpc_slotinfo = pciehpc_slotinfo_init;
 160         ctrl_p->hc_ops.uninit_hpc_slotinfo = pciehpc_slotinfo_uninit;
 161         ctrl_p->hc_ops.poweron_hpc_slot = pciehpc_slot_poweron;
 162         ctrl_p->hc_ops.poweroff_hpc_slot = pciehpc_slot_poweroff;
 163 
 164         ctrl_p->hc_ops.enable_hpc_intr = pciehpc_enable_intr;
 165         ctrl_p->hc_ops.disable_hpc_intr = pciehpc_disable_intr;
 166 
 167 #if     defined(__i386) || defined(__amd64)
 168         pciehpc_update_ops(ctrl_p);
 169 #endif
 170 
 171         /* initialize hot plug controller hw */
 172         if ((ctrl_p->hc_ops.init_hpc_hw)(ctrl_p) != DDI_SUCCESS)
 173                 goto cleanup1;
 174 
 175         /* initialize slot information soft state structure */
 176         if ((ctrl_p->hc_ops.init_hpc_slotinfo)(ctrl_p) != DDI_SUCCESS)
 177                 goto cleanup2;
 178 
 179         /* register the hot plug slot with DDI HP framework */
 180         if (pciehpc_register_slot(ctrl_p) != DDI_SUCCESS)
 181                 goto cleanup3;
 182 
 183         /* create minor node for this slot */
 184         if (pcie_create_minor_node(ctrl_p, 0) != DDI_SUCCESS)
 185                 goto cleanup4;
 186 
 187         /* HPC initialization is complete now */
 188         ctrl_p->hc_flags = PCIE_HP_INITIALIZED_FLAG;
 189 
 190 #ifdef  DEBUG
 191         /* For debug, dump the HPC registers */
 192         pciehpc_dump_hpregs(ctrl_p);
 193 #endif  /* DEBUG */
 194 
 195         return (DDI_SUCCESS);
 196 cleanup4:
 197         (void) pciehpc_unregister_slot(ctrl_p);
 198 cleanup3:
 199         (void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p);
 200 
 201 cleanup2:
 202         (void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p);
 203 
 204 cleanup1:
 205         PCIE_ENABLE_ERRORS(dip);
 206         (void) pci_resource_destroy(dip);
 207 
 208         pciehpc_destroy_controller(dip);
 209         return (DDI_FAILURE);
 210 }
 211 
 212 /*
 213  * Uninitialize HPC soft state structure and free up any resources
 214  * used for the HPC instance.
 215  */
 216 int
 217 pciehpc_uninit(dev_info_t *dip)
 218 {
 219         pcie_hp_ctrl_t *ctrl_p;
 220 
 221         PCIE_DBG("pciehpc_uninit() called (dip=%p)\n", (void *)dip);
 222 
 223         /* get the soft state structure for this dip */
 224         if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) {
 225                 return (DDI_FAILURE);
 226         }
 227 
 228         pcie_remove_minor_node(ctrl_p, 0);
 229 
 230         /* unregister the slot */
 231         (void) pciehpc_unregister_slot(ctrl_p);
 232 
 233         /* uninit any slot info data structures */
 234         (void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p);
 235 
 236         /* uninitialize hpc, remove interrupt handler, etc. */
 237         (void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p);
 238 
 239         PCIE_ENABLE_ERRORS(dip);
 240 
 241         /*
 242          * Destroy resource maps for this bus node.
 243          */
 244         (void) pci_resource_destroy(dip);
 245 
 246         /* destroy the soft state structure */
 247         pciehpc_destroy_controller(dip);
 248 
 249         return (DDI_SUCCESS);
 250 }
 251 
 252 /*
 253  * pciehpc_intr()
 254  *
 255  * Interrupt handler for PCI-E Hot plug controller interrupts.
 256  *
 257  * Note: This is only for native mode hot plug. This is called
 258  * by the nexus driver at interrupt context. Interrupt Service Routine
 259  * registration is done by the nexus driver for both hot plug and
 260  * non-hot plug interrupts. This function is called from the ISR
 261  * of the nexus driver to handle hot-plug interrupts.
 262  */
 263 int
 264 pciehpc_intr(dev_info_t *dip)
 265 {
 266         pcie_hp_ctrl_t  *ctrl_p;
 267         pcie_hp_slot_t  *slot_p;
 268         pcie_bus_t      *bus_p = PCIE_DIP2BUS(dip);
 269         uint16_t        status, control;
 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         /* make sure the controller soft state is initialized */
 278         if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
 279                 mutex_exit(&ctrl_p->hc_mutex);
 280                 return (DDI_INTR_UNCLAIMED);
 281         }
 282 
 283         /* if it is not NATIVE hot plug mode then return */
 284         if (bus_p->bus_hp_curr_mode != PCIE_NATIVE_HP_MODE) {
 285                 mutex_exit(&ctrl_p->hc_mutex);
 286                 return (DDI_INTR_UNCLAIMED);
 287         }
 288 
 289         slot_p = ctrl_p->hc_slots[0];
 290 
 291         /* read the current slot status register */
 292         status = pciehpc_reg_get16(ctrl_p,
 293             bus_p->bus_pcie_off + PCIE_SLOTSTS);
 294 
 295         /* check if there are any hot plug interrupts occurred */
 296         if (!(status & PCIE_SLOTSTS_STATUS_EVENTS)) {
 297                 /* no hot plug events occurred */
 298                 mutex_exit(&ctrl_p->hc_mutex);
 299                 return (DDI_INTR_UNCLAIMED);
 300         }
 301 
 302         /* clear the interrupt status bits */
 303         pciehpc_reg_put16(ctrl_p,
 304             bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
 305 
 306         /* check for CMD COMPLETE interrupt */
 307         if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
 308                 PCIE_DBG("pciehpc_intr(): CMD COMPLETED interrupt received\n");
 309                 /* wake up any one waiting for Command Completion event */
 310                 cv_signal(&ctrl_p->hc_cmd_comp_cv);
 311         }
 312 
 313         /* check for ATTN button interrupt */
 314         if (status & PCIE_SLOTSTS_ATTN_BTN_PRESSED) {
 315                 PCIE_DBG("pciehpc_intr(): ATTN BUTTON interrupt received\n");
 316 
 317                 /* if ATTN button event is still pending then cancel it */
 318                 if (slot_p->hs_attn_btn_pending == B_TRUE)
 319                         slot_p->hs_attn_btn_pending = B_FALSE;
 320                 else
 321                         slot_p->hs_attn_btn_pending = B_TRUE;
 322 
 323                 /* wake up the ATTN event handler */
 324                 cv_signal(&slot_p->hs_attn_btn_cv);
 325         }
 326 
 327         /* check for power fault interrupt */
 328         if (status & PCIE_SLOTSTS_PWR_FAULT_DETECTED) {
 329 
 330                 PCIE_DBG("pciehpc_intr(): POWER FAULT interrupt received"
 331                     " on slot %d\n", slot_p->hs_phy_slot_num);
 332                 control =  pciehpc_reg_get16(ctrl_p,
 333                     bus_p->bus_pcie_off + PCIE_SLOTCTL);
 334 
 335                 if (control & PCIE_SLOTCTL_PWR_FAULT_EN) {
 336                         slot_p->hs_condition = AP_COND_FAILED;
 337 
 338                         /* disable power fault detction interrupt */
 339                         pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
 340                             PCIE_SLOTCTL, control & ~PCIE_SLOTCTL_PWR_FAULT_EN);
 341 
 342                         pciehpc_handle_power_fault(dip);
 343                 }
 344         }
 345 
 346         /* check for MRL SENSOR CHANGED interrupt */
 347         if (status & PCIE_SLOTSTS_MRL_SENSOR_CHANGED) {
 348                 /* For now (phase-I), no action is taken on this event */
 349                 PCIE_DBG("pciehpc_intr(): MRL SENSOR CHANGED interrupt received"
 350                     " on slot %d\n", slot_p->hs_phy_slot_num);
 351         }
 352 
 353         /* check for PRESENCE CHANGED interrupt */
 354         if (status & PCIE_SLOTSTS_PRESENCE_CHANGED) {
 355 
 356                 PCIE_DBG("pciehpc_intr(): PRESENCE CHANGED interrupt received"
 357                     " on slot %d\n", slot_p->hs_phy_slot_num);
 358 
 359                 if (status & PCIE_SLOTSTS_PRESENCE_DETECTED) {
 360                         /*
 361                          * card is inserted into the slot, ask DDI Hotplug
 362                          * framework to change state to Present.
 363                          */
 364                         cmn_err(CE_NOTE, "pciehpc (%s%d): card is inserted"
 365                             " in the slot %s",
 366                             ddi_driver_name(dip),
 367                             ddi_get_instance(dip),
 368                             slot_p->hs_info.cn_name);
 369 
 370                         (void) ndi_hp_state_change_req(dip,
 371                             slot_p->hs_info.cn_name,
 372                             DDI_HP_CN_STATE_PRESENT,
 373                             DDI_HP_REQ_ASYNC);
 374                 } else { /* card is removed from the slot */
 375                         cmn_err(CE_NOTE, "pciehpc (%s%d): card is removed"
 376                             " from the slot %s",
 377                             ddi_driver_name(dip),
 378                             ddi_get_instance(dip),
 379                             slot_p->hs_info.cn_name);
 380 
 381                         if (slot_p->hs_info.cn_state ==
 382                             DDI_HP_CN_STATE_ENABLED) {
 383                                 /* Card is removed when slot is enabled */
 384                                 slot_p->hs_condition = AP_COND_FAILED;
 385                         } else {
 386                                 slot_p->hs_condition = AP_COND_UNKNOWN;
 387                         }
 388                         /* make sure to disable power fault detction intr */
 389                         control =  pciehpc_reg_get16(ctrl_p,
 390                             bus_p->bus_pcie_off + PCIE_SLOTCTL);
 391 
 392                         if (control & PCIE_SLOTCTL_PWR_FAULT_EN)
 393                                 pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
 394                                     PCIE_SLOTCTL,
 395                                     control & ~PCIE_SLOTCTL_PWR_FAULT_EN);
 396 
 397                         /*
 398                          * Ask DDI Hotplug framework to change state to Empty
 399                          */
 400                         (void) ndi_hp_state_change_req(dip,
 401                             slot_p->hs_info.cn_name,
 402                             DDI_HP_CN_STATE_EMPTY,
 403                             DDI_HP_REQ_ASYNC);
 404                 }
 405         }
 406 
 407         /* check for DLL state changed interrupt */
 408         if (ctrl_p->hc_dll_active_rep &&
 409             (status & PCIE_SLOTSTS_DLL_STATE_CHANGED)) {
 410                 PCIE_DBG("pciehpc_intr(): DLL STATE CHANGED interrupt received"
 411                     " on slot %d\n", slot_p->hs_phy_slot_num);
 412 
 413                 cv_signal(&slot_p->hs_dll_active_cv);
 414         }
 415 
 416         mutex_exit(&ctrl_p->hc_mutex);
 417 
 418         return (DDI_INTR_CLAIMED);
 419 }
 420 
 421 /*
 422  * Handle hotplug commands
 423  *
 424  * Note: This function is called by DDI HP framework at kernel context only
 425  */
 426 /* ARGSUSED */
 427 int
 428 pciehpc_hp_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op,
 429     void *arg, void *result)
 430 {
 431         pcie_hp_ctrl_t  *ctrl_p;
 432         pcie_hp_slot_t  *slot_p;
 433         int             ret = DDI_SUCCESS;
 434 
 435         PCIE_DBG("pciehpc_hp_ops: dip=%p cn_name=%s op=%x arg=%p\n",
 436             dip, cn_name, op, arg);
 437 
 438         if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
 439                 return (DDI_FAILURE);
 440 
 441         slot_p = ctrl_p->hc_slots[0];
 442 
 443         if (strcmp(cn_name, slot_p->hs_info.cn_name) != 0)
 444                 return (DDI_EINVAL);
 445 
 446         switch (op) {
 447         case DDI_HPOP_CN_GET_STATE:
 448         {
 449                 mutex_enter(&slot_p->hs_ctrl->hc_mutex);
 450 
 451                 /* get the current slot state */
 452                 pciehpc_get_slot_state(slot_p);
 453 
 454                 *((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state;
 455 
 456                 mutex_exit(&slot_p->hs_ctrl->hc_mutex);
 457                 break;
 458         }
 459         case DDI_HPOP_CN_CHANGE_STATE:
 460         {
 461                 ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg;
 462 
 463                 mutex_enter(&slot_p->hs_ctrl->hc_mutex);
 464 
 465                 ret = pciehpc_change_slot_state(slot_p, target_state);
 466                 *(ddi_hp_cn_state_t *)result = slot_p->hs_info.cn_state;
 467 
 468                 mutex_exit(&slot_p->hs_ctrl->hc_mutex);
 469                 break;
 470         }
 471         case DDI_HPOP_CN_PROBE:
 472 
 473                 ret = pciehpc_slot_probe(slot_p);
 474 
 475                 break;
 476         case DDI_HPOP_CN_UNPROBE:
 477                 ret = pciehpc_slot_unprobe(slot_p);
 478 
 479                 break;
 480         case DDI_HPOP_CN_GET_PROPERTY:
 481                 ret = pciehpc_slot_get_property(slot_p,
 482                     (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
 483                 break;
 484         case DDI_HPOP_CN_SET_PROPERTY:
 485                 ret = pciehpc_slot_set_property(slot_p,
 486                     (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
 487                 break;
 488         default:
 489                 ret = DDI_ENOTSUP;
 490                 break;
 491         }
 492 
 493         return (ret);
 494 }
 495 
 496 /*
 497  * Get the current state of the slot from the hw.
 498  *
 499  * The slot state should have been initialized before this function gets called.
 500  */
 501 void
 502 pciehpc_get_slot_state(pcie_hp_slot_t *slot_p)
 503 {
 504         pcie_hp_ctrl_t  *ctrl_p = slot_p->hs_ctrl;
 505         pcie_bus_t      *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
 506         uint16_t        control, status;
 507         ddi_hp_cn_state_t curr_state = slot_p->hs_info.cn_state;
 508 
 509         /* read the Slot Control Register */
 510         control = pciehpc_reg_get16(ctrl_p,
 511             bus_p->bus_pcie_off + PCIE_SLOTCTL);
 512 
 513         slot_p->hs_fault_led_state = PCIE_HP_LED_OFF; /* no fault led */
 514         slot_p->hs_active_led_state = PCIE_HP_LED_OFF; /* no active led */
 515 
 516         /* read the current Slot Status Register */
 517         status = pciehpc_reg_get16(ctrl_p,
 518             bus_p->bus_pcie_off + PCIE_SLOTSTS);
 519 
 520         /* get POWER led state */
 521         slot_p->hs_power_led_state =
 522             pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control));
 523 
 524         /* get ATTN led state */
 525         slot_p->hs_attn_led_state =
 526             pciehpc_led_state_to_hpc(pcie_slotctl_attn_indicator_get(control));
 527 
 528         if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
 529                 /* no device present; slot is empty */
 530                 slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY;
 531 
 532                 return;
 533         }
 534 
 535         /* device is present */
 536         slot_p->hs_info.cn_state = DDI_HP_CN_STATE_PRESENT;
 537 
 538         if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) {
 539                 /*
 540                  * Device is powered on. Set to "ENABLED" state (skip
 541                  * POWERED state) because there is not a explicit "enable"
 542                  * action exists for PCIe.
 543                  * If it is already in "POWERED" state, then keep it until
 544                  * user explicitly change it to other states.
 545                  */
 546                 if (curr_state == DDI_HP_CN_STATE_POWERED) {
 547                         slot_p->hs_info.cn_state = curr_state;
 548                 } else {
 549                         slot_p->hs_info.cn_state = DDI_HP_CN_STATE_ENABLED;
 550                 }
 551         }
 552 }
 553 
 554 /*
 555  * setup slot name/slot-number info.
 556  */
 557 void
 558 pciehpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p)
 559 {
 560         pcie_hp_slot_t  *slot_p = ctrl_p->hc_slots[0];
 561         pcie_bus_t      *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
 562         uchar_t         *slotname_data;
 563         int             *slotnum;
 564         uint_t          count;
 565         int             len;
 566         int             invalid_slotnum = 0;
 567         uint32_t        slot_capabilities;
 568 
 569         if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ctrl_p->hc_dip,
 570             DDI_PROP_DONTPASS, "physical-slot#", &slotnum, &count) ==
 571             DDI_PROP_SUCCESS) {
 572                 slot_p->hs_phy_slot_num = slotnum[0];
 573                 ddi_prop_free(slotnum);
 574         } else {
 575                 slot_capabilities = pciehpc_reg_get32(ctrl_p,
 576                     bus_p->bus_pcie_off + PCIE_SLOTCAP);
 577                 slot_p->hs_phy_slot_num =
 578                     PCIE_SLOTCAP_PHY_SLOT_NUM(slot_capabilities);
 579         }
 580 
 581         /* platform may not have initialized it */
 582         if (!slot_p->hs_phy_slot_num) {
 583                 PCIE_DBG("%s#%d: Invalid slot number!\n",
 584                     ddi_driver_name(ctrl_p->hc_dip),
 585                     ddi_get_instance(ctrl_p->hc_dip));
 586                 slot_p->hs_phy_slot_num = pciehpc_reg_get8(ctrl_p,
 587                     PCI_BCNF_SECBUS);
 588                 invalid_slotnum = 1;
 589         }
 590         slot_p->hs_info.cn_num = slot_p->hs_phy_slot_num;
 591         slot_p->hs_info.cn_num_dpd_on = DDI_HP_CN_NUM_NONE;
 592 
 593         /*
 594          * construct the slot_name:
 595          *      if "slot-names" property exists then use that name
 596          *      else if valid slot number exists then it is "pcie<slot-num>".
 597          *      else it will be "pcie<sec-bus-number>dev0"
 598          */
 599         if (ddi_getlongprop(DDI_DEV_T_ANY, ctrl_p->hc_dip, DDI_PROP_DONTPASS,
 600             "slot-names", (caddr_t)&slotname_data, &len) == DDI_PROP_SUCCESS) {
 601                 char tmp_name[256];
 602 
 603                 /*
 604                  * Note: for PCI-E slots, the device number is always 0 so the
 605                  * first (and only) string is the slot name for this slot.
 606                  */
 607                 (void) snprintf(tmp_name, sizeof (tmp_name),
 608                     (char *)slotname_data + 4);
 609                 slot_p->hs_info.cn_name = ddi_strdup(tmp_name, KM_SLEEP);
 610                 kmem_free(slotname_data, len);
 611         } else {
 612                 if (invalid_slotnum) {
 613                         /* use device number ie. 0 */
 614                         slot_p->hs_info.cn_name = ddi_strdup("pcie0",
 615                             KM_SLEEP);
 616                 } else {
 617                         char tmp_name[256];
 618 
 619                         (void) snprintf(tmp_name, sizeof (tmp_name), "pcie%d",
 620                             slot_p->hs_phy_slot_num);
 621                         slot_p->hs_info.cn_name = ddi_strdup(tmp_name,
 622                             KM_SLEEP);
 623                 }
 624         }
 625 }
 626 
 627 /*
 628  * Read/Write access to HPC registers. If platform nexus has non-standard
 629  * HPC access mechanism then regops functions are used to do reads/writes.
 630  */
 631 uint8_t
 632 pciehpc_reg_get8(pcie_hp_ctrl_t *ctrl_p, uint_t off)
 633 {
 634         if (ctrl_p->hc_regops.get != NULL) {
 635                 return ((uint8_t)ctrl_p->hc_regops.get(
 636                     ctrl_p->hc_regops.cookie, (off_t)off));
 637         } else {
 638                 pcie_bus_t      *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
 639 
 640                 return (pci_config_get8(bus_p->bus_cfg_hdl, off));
 641         }
 642 }
 643 
 644 uint16_t
 645 pciehpc_reg_get16(pcie_hp_ctrl_t *ctrl_p, uint_t off)
 646 {
 647         if (ctrl_p->hc_regops.get != NULL) {
 648                 return ((uint16_t)ctrl_p->hc_regops.get(
 649                     ctrl_p->hc_regops.cookie, (off_t)off));
 650         } else {
 651                 pcie_bus_t      *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
 652 
 653                 return (pci_config_get16(bus_p->bus_cfg_hdl, off));
 654         }
 655 }
 656 
 657 uint32_t
 658 pciehpc_reg_get32(pcie_hp_ctrl_t *ctrl_p, uint_t off)
 659 {
 660         if (ctrl_p->hc_regops.get != NULL) {
 661                 return ((uint32_t)ctrl_p->hc_regops.get(
 662                     ctrl_p->hc_regops.cookie, (off_t)off));
 663         } else {
 664                 pcie_bus_t      *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
 665 
 666                 return (pci_config_get32(bus_p->bus_cfg_hdl, off));
 667         }
 668 }
 669 
 670 void
 671 pciehpc_reg_put8(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint8_t val)
 672 {
 673         if (ctrl_p->hc_regops.put != NULL) {
 674                 ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
 675                     (off_t)off, (uint_t)val);
 676         } else {
 677                 pcie_bus_t      *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
 678 
 679                 pci_config_put8(bus_p->bus_cfg_hdl, off, val);
 680         }
 681 }
 682 
 683 void
 684 pciehpc_reg_put16(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint16_t val)
 685 {
 686         if (ctrl_p->hc_regops.put != NULL) {
 687                 ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
 688                     (off_t)off, (uint_t)val);
 689         } else {
 690                 pcie_bus_t      *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
 691 
 692                 pci_config_put16(bus_p->bus_cfg_hdl, off, val);
 693         }
 694 }
 695 
 696 void
 697 pciehpc_reg_put32(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint32_t val)
 698 {
 699         if (ctrl_p->hc_regops.put != NULL) {
 700                 ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
 701                     (off_t)off, (uint_t)val);
 702         } else {
 703                 pcie_bus_t      *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
 704 
 705                 pci_config_put32(bus_p->bus_cfg_hdl, off, val);
 706         }
 707 }
 708 
 709 /*
 710  * ************************************************************************
 711  * ***  Local functions (called within this file)
 712  * ***  PCIe Native Hotplug mode specific functions
 713  * ************************************************************************
 714  */
 715 
 716 /*
 717  * Initialize HPC hardware, install interrupt handler, etc. It doesn't
 718  * enable hot plug interrupts.
 719  *
 720  * (Note: It is called only from pciehpc_init().)
 721  */
 722 static int
 723 pciehpc_hpc_init(pcie_hp_ctrl_t *ctrl_p)
 724 {
 725         pcie_bus_t      *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
 726         uint16_t        reg;
 727 
 728         /* read the Slot Control Register */
 729         reg = pciehpc_reg_get16(ctrl_p,
 730             bus_p->bus_pcie_off + PCIE_SLOTCTL);
 731 
 732         /* disable all interrupts */
 733         reg &= ~(PCIE_SLOTCTL_INTR_MASK);
 734         pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
 735             PCIE_SLOTCTL, reg);
 736 
 737         /* clear any interrupt status bits */
 738         reg = pciehpc_reg_get16(ctrl_p,
 739             bus_p->bus_pcie_off + PCIE_SLOTSTS);
 740         pciehpc_reg_put16(ctrl_p,
 741             bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
 742 
 743         return (DDI_SUCCESS);
 744 }
 745 
 746 /*
 747  * Uninitialize HPC hardware, uninstall interrupt handler, etc.
 748  *
 749  * (Note: It is called only from pciehpc_uninit().)
 750  */
 751 static int
 752 pciehpc_hpc_uninit(pcie_hp_ctrl_t *ctrl_p)
 753 {
 754         /* disable interrupts */
 755         (void) pciehpc_disable_intr(ctrl_p);
 756 
 757         return (DDI_SUCCESS);
 758 }
 759 
 760 /*
 761  * Setup slot information for use with DDI HP framework.
 762  */
 763 static int
 764 pciehpc_slotinfo_init(pcie_hp_ctrl_t *ctrl_p)
 765 {
 766         uint32_t        slot_capabilities, link_capabilities;
 767         pcie_hp_slot_t  *slot_p = ctrl_p->hc_slots[0];
 768         pcie_bus_t      *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
 769 
 770         mutex_enter(&ctrl_p->hc_mutex);
 771         /*
 772          * setup DDI HP framework slot information structure
 773          */
 774         slot_p->hs_device_num = 0;
 775 
 776         slot_p->hs_info.cn_type = DDI_HP_CN_TYPE_PCIE;
 777         slot_p->hs_info.cn_type_str = (ctrl_p->hc_regops.get == NULL) ?
 778             PCIE_NATIVE_HP_TYPE : PCIE_PROP_HP_TYPE;
 779         slot_p->hs_info.cn_child = NULL;
 780 
 781         slot_p->hs_minor =
 782             PCI_MINOR_NUM(ddi_get_instance(ctrl_p->hc_dip),
 783             slot_p->hs_device_num);
 784         slot_p->hs_condition = AP_COND_UNKNOWN;
 785 
 786         /* read Slot Capabilities Register */
 787         slot_capabilities = pciehpc_reg_get32(ctrl_p,
 788             bus_p->bus_pcie_off + PCIE_SLOTCAP);
 789 
 790         /* set slot-name/slot-number info */
 791         pciehpc_set_slot_name(ctrl_p);
 792 
 793         /* check if Attn Button present */
 794         ctrl_p->hc_has_attn = (slot_capabilities & PCIE_SLOTCAP_ATTN_BUTTON) ?
 795             B_TRUE : B_FALSE;
 796 
 797         /* check if Manual Retention Latch sensor present */
 798         ctrl_p->hc_has_mrl = (slot_capabilities & PCIE_SLOTCAP_MRL_SENSOR) ?
 799             B_TRUE : B_FALSE;
 800 
 801         /*
 802          * PCI-E version 1.1 defines EMI Lock Present bit
 803          * in Slot Capabilities register. Check for it.
 804          */
 805         ctrl_p->hc_has_emi_lock = (slot_capabilities &
 806             PCIE_SLOTCAP_EMI_LOCK_PRESENT) ? B_TRUE : B_FALSE;
 807 
 808         link_capabilities = pciehpc_reg_get32(ctrl_p,
 809             bus_p->bus_pcie_off + PCIE_LINKCAP);
 810         ctrl_p->hc_dll_active_rep = (link_capabilities &
 811             PCIE_LINKCAP_DLL_ACTIVE_REP_CAPABLE) ? B_TRUE : B_FALSE;
 812         if (ctrl_p->hc_dll_active_rep)
 813                 cv_init(&slot_p->hs_dll_active_cv, NULL, CV_DRIVER, NULL);
 814 
 815         /* setup thread for handling ATTN button events */
 816         if (ctrl_p->hc_has_attn) {
 817                 PCIE_DBG("pciehpc_slotinfo_init: setting up ATTN button event "
 818                     "handler thread for slot %d\n", slot_p->hs_phy_slot_num);
 819 
 820                 cv_init(&slot_p->hs_attn_btn_cv, NULL, CV_DRIVER, NULL);
 821                 slot_p->hs_attn_btn_pending = B_FALSE;
 822                 slot_p->hs_attn_btn_threadp = thread_create(NULL, 0,
 823                     pciehpc_attn_btn_handler,
 824                     (void *)ctrl_p, 0, &p0, TS_RUN, minclsyspri);
 825                 slot_p->hs_attn_btn_thread_exit = B_FALSE;
 826         }
 827 
 828         /* get current slot state from the hw */
 829         slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY;
 830         pciehpc_get_slot_state(slot_p);
 831         if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_ENABLED)
 832                 slot_p->hs_condition = AP_COND_OK;
 833 
 834         mutex_exit(&ctrl_p->hc_mutex);
 835 
 836         return (DDI_SUCCESS);
 837 }
 838 
 839 /*ARGSUSED*/
 840 static int
 841 pciehpc_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p)
 842 {
 843         pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
 844 
 845         if (slot_p->hs_attn_btn_threadp != NULL) {
 846                 mutex_enter(&ctrl_p->hc_mutex);
 847                 slot_p->hs_attn_btn_thread_exit = B_TRUE;
 848                 cv_signal(&slot_p->hs_attn_btn_cv);
 849                 PCIE_DBG("pciehpc_slotinfo_uninit: "
 850                     "waiting for ATTN thread exit\n");
 851                 cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
 852                 PCIE_DBG("pciehpc_slotinfo_uninit: ATTN thread exit\n");
 853                 cv_destroy(&slot_p->hs_attn_btn_cv);
 854                 slot_p->hs_attn_btn_threadp = NULL;
 855                 mutex_exit(&ctrl_p->hc_mutex);
 856         }
 857 
 858         if (ctrl_p->hc_dll_active_rep)
 859                 cv_destroy(&slot_p->hs_dll_active_cv);
 860         if (slot_p->hs_info.cn_name)
 861                 kmem_free(slot_p->hs_info.cn_name,
 862                     strlen(slot_p->hs_info.cn_name) + 1);
 863 
 864         return (DDI_SUCCESS);
 865 }
 866 
 867 /*
 868  * Enable hot plug interrupts.
 869  * Note: this is only for Native hot plug mode.
 870  */
 871 static int
 872 pciehpc_enable_intr(pcie_hp_ctrl_t *ctrl_p)
 873 {
 874         pcie_hp_slot_t  *slot_p = ctrl_p->hc_slots[0];
 875         pcie_bus_t      *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
 876         uint16_t        reg;
 877 
 878         /* clear any interrupt status bits */
 879         reg = pciehpc_reg_get16(ctrl_p,
 880             bus_p->bus_pcie_off + PCIE_SLOTSTS);
 881         pciehpc_reg_put16(ctrl_p,
 882             bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
 883 
 884         /* read the Slot Control Register */
 885         reg = pciehpc_reg_get16(ctrl_p,
 886             bus_p->bus_pcie_off + PCIE_SLOTCTL);
 887 
 888         /*
 889          * enable interrupts: power fault detection interrupt is enabled
 890          * only when the slot is powered ON
 891          */
 892         if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
 893                 pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
 894                     PCIE_SLOTCTL, reg | PCIE_SLOTCTL_INTR_MASK);
 895         else
 896                 pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
 897                     PCIE_SLOTCTL, reg | (PCIE_SLOTCTL_INTR_MASK &
 898                     ~PCIE_SLOTCTL_PWR_FAULT_EN));
 899 
 900         return (DDI_SUCCESS);
 901 }
 902 
 903 /*
 904  * Disable hot plug interrupts.
 905  * Note: this is only for Native hot plug mode.
 906  */
 907 static int
 908 pciehpc_disable_intr(pcie_hp_ctrl_t *ctrl_p)
 909 {
 910         pcie_bus_t      *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
 911         uint16_t        reg;
 912 
 913         /* read the Slot Control Register */
 914         reg = pciehpc_reg_get16(ctrl_p,
 915             bus_p->bus_pcie_off + PCIE_SLOTCTL);
 916 
 917         /* disable all interrupts */
 918         reg &= ~(PCIE_SLOTCTL_INTR_MASK);
 919         pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTCTL, reg);
 920 
 921         /* clear any interrupt status bits */
 922         reg = pciehpc_reg_get16(ctrl_p,
 923             bus_p->bus_pcie_off + PCIE_SLOTSTS);
 924         pciehpc_reg_put16(ctrl_p,
 925             bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
 926 
 927         return (DDI_SUCCESS);
 928 }
 929 
 930 /*
 931  * Allocate a new hotplug controller and slot structures for HPC
 932  * associated with this dip.
 933  */
 934 static pcie_hp_ctrl_t *
 935 pciehpc_create_controller(dev_info_t *dip)
 936 {
 937         pcie_hp_ctrl_t  *ctrl_p;
 938         pcie_bus_t      *bus_p = PCIE_DIP2BUS(dip);
 939 
 940         ctrl_p = kmem_zalloc(sizeof (pcie_hp_ctrl_t), KM_SLEEP);
 941         ctrl_p->hc_dip = dip;
 942 
 943         /* Allocate a new slot structure. */
 944         ctrl_p->hc_slots[0] = kmem_zalloc(sizeof (pcie_hp_slot_t), KM_SLEEP);
 945         ctrl_p->hc_slots[0]->hs_num = 0;
 946         ctrl_p->hc_slots[0]->hs_ctrl = ctrl_p;
 947 
 948         /* Initialize the interrupt mutex */
 949         mutex_init(&ctrl_p->hc_mutex, NULL, MUTEX_DRIVER,
 950             (void *)PCIE_INTR_PRI);
 951 
 952         /* Initialize synchronization conditional variable */
 953         cv_init(&ctrl_p->hc_cmd_comp_cv, NULL, CV_DRIVER, NULL);
 954         ctrl_p->hc_cmd_pending = B_FALSE;
 955 
 956         bus_p->bus_hp_curr_mode = PCIE_NATIVE_HP_MODE;
 957         PCIE_SET_HP_CTRL(dip, ctrl_p);
 958 
 959         return (ctrl_p);
 960 }
 961 
 962 /*
 963  * Remove the HPC controller and slot structures
 964  */
 965 static void
 966 pciehpc_destroy_controller(dev_info_t *dip)
 967 {
 968         pcie_hp_ctrl_t  *ctrl_p;
 969         pcie_bus_t      *bus_p = PCIE_DIP2BUS(dip);
 970 
 971         /* get the soft state structure for this dip */
 972         if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
 973                 return;
 974 
 975         PCIE_SET_HP_CTRL(dip, NULL);
 976         bus_p->bus_hp_curr_mode = PCIE_NONE_HP_MODE;
 977 
 978         mutex_destroy(&ctrl_p->hc_mutex);
 979         cv_destroy(&ctrl_p->hc_cmd_comp_cv);
 980         kmem_free(ctrl_p->hc_slots[0], sizeof (pcie_hp_slot_t));
 981         kmem_free(ctrl_p, sizeof (pcie_hp_ctrl_t));
 982 }
 983 
 984 /*
 985  * Register the PCI-E hot plug slot with DDI HP framework.
 986  */
 987 static int
 988 pciehpc_register_slot(pcie_hp_ctrl_t *ctrl_p)
 989 {
 990         pcie_hp_slot_t  *slot_p = ctrl_p->hc_slots[0];
 991         dev_info_t      *dip = ctrl_p->hc_dip;
 992 
 993         /* register the slot with DDI HP framework */
 994         if (ndi_hp_register(dip, &slot_p->hs_info) != NDI_SUCCESS) {
 995                 PCIE_DBG("pciehpc_register_slot() failed to register slot %d\n",
 996                     slot_p->hs_phy_slot_num);
 997                 return (DDI_FAILURE);
 998         }
 999 
1000         pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip),
1001             slot_p->hs_minor), slot_p->hs_device_num);
1002 
1003         PCIE_DBG("pciehpc_register_slot(): registered slot %d\n",
1004             slot_p->hs_phy_slot_num);
1005 
1006         return (DDI_SUCCESS);
1007 }
1008 
1009 /*
1010  * Unregister the PCI-E hot plug slot from DDI HP framework.
1011  */
1012 static int
1013 pciehpc_unregister_slot(pcie_hp_ctrl_t *ctrl_p)
1014 {
1015         pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
1016         dev_info_t      *dip = ctrl_p->hc_dip;
1017 
1018         pcie_hp_delete_occupant_props(dip, makedevice(ddi_driver_major(dip),
1019             slot_p->hs_minor));
1020 
1021         /* unregister the slot with DDI HP framework */
1022         if (ndi_hp_unregister(dip, slot_p->hs_info.cn_name) != NDI_SUCCESS) {
1023                 PCIE_DBG("pciehpc_unregister_slot() "
1024                     "failed to unregister slot %d\n", slot_p->hs_phy_slot_num);
1025                 return (DDI_FAILURE);
1026         }
1027 
1028         PCIE_DBG("pciehpc_unregister_slot(): unregistered slot %d\n",
1029             slot_p->hs_phy_slot_num);
1030 
1031         return (DDI_SUCCESS);
1032 }
1033 
1034 /*
1035  * pciehpc_slot_poweron()
1036  *
1037  * Poweron/Enable the slot.
1038  *
1039  * Note: This function is called by DDI HP framework at kernel context only
1040  */
1041 /*ARGSUSED*/
1042 static int
1043 pciehpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result)
1044 {
1045         pcie_hp_ctrl_t  *ctrl_p = slot_p->hs_ctrl;
1046         pcie_bus_t      *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1047         uint16_t        status, control;
1048 
1049         ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
1050 
1051         /* get the current state of the slot */
1052         pciehpc_get_slot_state(slot_p);
1053 
1054         /* check if the slot is already in the 'enabled' state */
1055         if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) {
1056                 /* slot is already in the 'enabled' state */
1057                 PCIE_DBG("pciehpc_slot_poweron() slot %d already enabled\n",
1058                     slot_p->hs_phy_slot_num);
1059 
1060                 *result = slot_p->hs_info.cn_state;
1061                 return (DDI_SUCCESS);
1062         }
1063 
1064         /* read the Slot Status Register */
1065         status =  pciehpc_reg_get16(ctrl_p,
1066             bus_p->bus_pcie_off + PCIE_SLOTSTS);
1067 
1068         /* make sure the MRL switch is closed if present */
1069         if ((ctrl_p->hc_has_mrl) && (status & PCIE_SLOTSTS_MRL_SENSOR_OPEN)) {
1070                 /* MRL switch is open */
1071                 cmn_err(CE_WARN, "MRL switch is open on slot %d\n",
1072                     slot_p->hs_phy_slot_num);
1073                 goto cleanup;
1074         }
1075 
1076         /* make sure the slot has a device present */
1077         if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
1078                 /* slot is empty */
1079                 PCIE_DBG("slot %d is empty\n", slot_p->hs_phy_slot_num);
1080                 goto cleanup;
1081         }
1082 
1083         /* get the current state of Slot Control Register */
1084         control =  pciehpc_reg_get16(ctrl_p,
1085             bus_p->bus_pcie_off + PCIE_SLOTCTL);
1086 
1087         /*
1088          * Enable power to the slot involves:
1089          *      1. Set power LED to blink and ATTN led to OFF.
1090          *      2. Set power control ON in Slot Control Reigster and
1091          *         wait for Command Completed Interrupt or 1 sec timeout.
1092          *      3. If Data Link Layer State Changed events are supported
1093          *         then wait for the event to indicate Data Layer Link
1094          *         is active. The time out value for this event is 1 second.
1095          *         This is specified in PCI-E version 1.1.
1096          *      4. Set power LED to be ON.
1097          */
1098 
1099         /* 1. set power LED to blink & ATTN led to OFF */
1100         pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
1101         pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
1102 
1103         /* 2. set power control to ON */
1104         control =  pciehpc_reg_get16(ctrl_p,
1105             bus_p->bus_pcie_off + PCIE_SLOTCTL);
1106         control &= ~PCIE_SLOTCTL_PWR_CONTROL;
1107         pciehpc_issue_hpc_command(ctrl_p, control);
1108 
1109         /* 3. wait for DLL State Change event, if it's supported */
1110         if (ctrl_p->hc_dll_active_rep) {
1111                 status =  pciehpc_reg_get16(ctrl_p,
1112                     bus_p->bus_pcie_off + PCIE_LINKSTS);
1113 
1114                 if (!(status & PCIE_LINKSTS_DLL_LINK_ACTIVE)) {
1115                         /* wait 1 sec for the DLL State Changed event */
1116                         (void) cv_timedwait(&slot_p->hs_dll_active_cv,
1117                             &ctrl_p->hc_mutex,
1118                             ddi_get_lbolt() +
1119                             SEC_TO_TICK(PCIE_HP_DLL_STATE_CHANGE_TIMEOUT));
1120 
1121                         /* check Link status */
1122                         status =  pciehpc_reg_get16(ctrl_p,
1123                             bus_p->bus_pcie_off +
1124                             PCIE_LINKSTS);
1125                         if (!(status & PCIE_LINKSTS_DLL_LINK_ACTIVE))
1126                                 goto cleanup2;
1127                 }
1128         }
1129 
1130         /* wait 1 sec for link to come up */
1131         delay(drv_sectohz(1));
1132 
1133         /* check power is really turned ON */
1134         control =  pciehpc_reg_get16(ctrl_p,
1135             bus_p->bus_pcie_off + PCIE_SLOTCTL);
1136 
1137         if (control & PCIE_SLOTCTL_PWR_CONTROL) {
1138                 PCIE_DBG("slot %d fails to turn on power on connect\n",
1139                     slot_p->hs_phy_slot_num);
1140 
1141                 goto cleanup1;
1142         }
1143 
1144         /* clear power fault status */
1145         status =  pciehpc_reg_get16(ctrl_p,
1146             bus_p->bus_pcie_off + PCIE_SLOTSTS);
1147         status |= PCIE_SLOTSTS_PWR_FAULT_DETECTED;
1148         pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTSTS,
1149             status);
1150 
1151         /* enable power fault detection interrupt */
1152         control |= PCIE_SLOTCTL_PWR_FAULT_EN;
1153         pciehpc_issue_hpc_command(ctrl_p, control);
1154 
1155         /* 4. Set power LED to be ON */
1156         pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_ON);
1157 
1158         /* if EMI is present, turn it ON */
1159         if (ctrl_p->hc_has_emi_lock) {
1160                 status =  pciehpc_reg_get16(ctrl_p,
1161                     bus_p->bus_pcie_off + PCIE_SLOTSTS);
1162 
1163                 if (!(status & PCIE_SLOTSTS_EMI_LOCK_SET)) {
1164                         control =  pciehpc_reg_get16(ctrl_p,
1165                             bus_p->bus_pcie_off + PCIE_SLOTCTL);
1166                         control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL;
1167                         pciehpc_issue_hpc_command(ctrl_p, control);
1168 
1169                         /* wait 1 sec after toggling the state of EMI lock */
1170                         delay(drv_sectohz(1));
1171                 }
1172         }
1173 
1174         *result = slot_p->hs_info.cn_state =
1175             DDI_HP_CN_STATE_POWERED;
1176 
1177         return (DDI_SUCCESS);
1178 
1179 cleanup2:
1180         control =  pciehpc_reg_get16(ctrl_p,
1181             bus_p->bus_pcie_off + PCIE_SLOTCTL);
1182 
1183         /* if power is ON, set power control to OFF */
1184         if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) {
1185                 control |= PCIE_SLOTCTL_PWR_CONTROL;
1186                 pciehpc_issue_hpc_command(ctrl_p, control);
1187         }
1188 
1189 cleanup1:
1190         /* set power led to OFF */
1191         pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
1192 
1193 cleanup:
1194         return (DDI_FAILURE);
1195 }
1196 
1197 /*ARGSUSED*/
1198 static int
1199 pciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result)
1200 {
1201         pcie_hp_ctrl_t  *ctrl_p = slot_p->hs_ctrl;
1202         pcie_bus_t      *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1203         uint16_t        status, control;
1204 
1205         ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
1206 
1207         /* get the current state of the slot */
1208         pciehpc_get_slot_state(slot_p);
1209 
1210         /* check if the slot is not in the "enabled' state */
1211         if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) {
1212                 /* slot is in the 'disabled' state */
1213                 PCIE_DBG("pciehpc_slot_poweroff(): "
1214                     "slot %d already disabled\n", slot_p->hs_phy_slot_num);
1215                 ASSERT(slot_p->hs_power_led_state == PCIE_HP_LED_OFF);
1216 
1217                 *result = slot_p->hs_info.cn_state;
1218                 return (DDI_SUCCESS);
1219         }
1220 
1221         /* read the Slot Status Register */
1222         status =  pciehpc_reg_get16(ctrl_p,
1223             bus_p->bus_pcie_off + PCIE_SLOTSTS);
1224 
1225         /* make sure the slot has a device present */
1226         if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
1227                 /* slot is empty */
1228                 PCIE_DBG("pciehpc_slot_poweroff(): slot %d is empty\n",
1229                     slot_p->hs_phy_slot_num);
1230                 goto cleanup;
1231         }
1232 
1233         /*
1234          * Disable power to the slot involves:
1235          *      1. Set power LED to blink.
1236          *      2. Set power control OFF in Slot Control Reigster and
1237          *         wait for Command Completed Interrupt or 1 sec timeout.
1238          *      3. Set POWER led and ATTN led to be OFF.
1239          */
1240 
1241         /* 1. set power LED to blink */
1242         pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
1243 
1244         /* disable power fault detection interrupt */
1245         control = pciehpc_reg_get16(ctrl_p,
1246             bus_p->bus_pcie_off + PCIE_SLOTCTL);
1247         control &= ~PCIE_SLOTCTL_PWR_FAULT_EN;
1248         pciehpc_issue_hpc_command(ctrl_p, control);
1249 
1250         /* 2. set power control to OFF */
1251         control =  pciehpc_reg_get16(ctrl_p,
1252             bus_p->bus_pcie_off + PCIE_SLOTCTL);
1253         control |= PCIE_SLOTCTL_PWR_CONTROL;
1254         pciehpc_issue_hpc_command(ctrl_p, control);
1255 
1256 #ifdef DEBUG
1257         /* check for power control bit to be OFF */
1258         control =  pciehpc_reg_get16(ctrl_p,
1259             bus_p->bus_pcie_off + PCIE_SLOTCTL);
1260         ASSERT(control & PCIE_SLOTCTL_PWR_CONTROL);
1261 #endif
1262 
1263         /* 3. Set power LED to be OFF */
1264         pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
1265         pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
1266 
1267         /* if EMI is present, turn it OFF */
1268         if (ctrl_p->hc_has_emi_lock) {
1269                 status =  pciehpc_reg_get16(ctrl_p,
1270                     bus_p->bus_pcie_off + PCIE_SLOTSTS);
1271 
1272                 if (status & PCIE_SLOTSTS_EMI_LOCK_SET) {
1273                         control =  pciehpc_reg_get16(ctrl_p,
1274                             bus_p->bus_pcie_off + PCIE_SLOTCTL);
1275                         control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL;
1276                         pciehpc_issue_hpc_command(ctrl_p, control);
1277 
1278                         /* wait 1 sec after toggling the state of EMI lock */
1279                         delay(drv_sectohz(1));
1280                 }
1281         }
1282 
1283         /* get the current state of the slot */
1284         pciehpc_get_slot_state(slot_p);
1285 
1286         *result = slot_p->hs_info.cn_state;
1287 
1288         return (DDI_SUCCESS);
1289 
1290 cleanup:
1291         return (DDI_FAILURE);
1292 }
1293 
1294 /*
1295  * pciehpc_slot_probe()
1296  *
1297  * Probe the slot.
1298  *
1299  * Note: This function is called by DDI HP framework at kernel context only
1300  */
1301 /*ARGSUSED*/
1302 static int
1303 pciehpc_slot_probe(pcie_hp_slot_t *slot_p)
1304 {
1305         pcie_hp_ctrl_t  *ctrl_p = slot_p->hs_ctrl;
1306         int             ret = DDI_SUCCESS;
1307 
1308         mutex_enter(&ctrl_p->hc_mutex);
1309 
1310         /* get the current state of the slot */
1311         pciehpc_get_slot_state(slot_p);
1312 
1313         /*
1314          * Probe a given PCIe Hotplug Connection (CN).
1315          */
1316         PCIE_DISABLE_ERRORS(ctrl_p->hc_dip);
1317         ret = pcie_hp_probe(slot_p);
1318 
1319         if (ret != DDI_SUCCESS) {
1320                 PCIE_DBG("pciehpc_slot_probe() failed\n");
1321 
1322                 /* turn the ATTN led ON for configure failure */
1323                 pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_ON);
1324 
1325                 /* if power to the slot is still on then set Power led to ON */
1326                 if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
1327                         pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
1328                             PCIE_HP_LED_ON);
1329 
1330                 mutex_exit(&ctrl_p->hc_mutex);
1331                 return (DDI_FAILURE);
1332         }
1333 
1334         PCIE_ENABLE_ERRORS(ctrl_p->hc_dip);
1335 
1336         /* get the current state of the slot */
1337         pciehpc_get_slot_state(slot_p);
1338 
1339         mutex_exit(&ctrl_p->hc_mutex);
1340         return (DDI_SUCCESS);
1341 }
1342 
1343 /*
1344  * pciehpc_slot_unprobe()
1345  *
1346  * Unprobe the slot.
1347  *
1348  * Note: This function is called by DDI HP framework at kernel context only
1349  */
1350 /*ARGSUSED*/
1351 static int
1352 pciehpc_slot_unprobe(pcie_hp_slot_t *slot_p)
1353 {
1354         pcie_hp_ctrl_t  *ctrl_p = slot_p->hs_ctrl;
1355         int             ret;
1356 
1357         mutex_enter(&ctrl_p->hc_mutex);
1358 
1359         /* get the current state of the slot */
1360         pciehpc_get_slot_state(slot_p);
1361 
1362         /*
1363          * Unprobe a given PCIe Hotplug Connection (CN).
1364          */
1365         PCIE_DISABLE_ERRORS(ctrl_p->hc_dip);
1366         ret = pcie_hp_unprobe(slot_p);
1367 
1368         if (ret != DDI_SUCCESS) {
1369                 PCIE_DBG("pciehpc_slot_unprobe() failed\n");
1370 
1371                 /* if power to the slot is still on then set Power led to ON */
1372                 if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
1373                         pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
1374                             PCIE_HP_LED_ON);
1375 
1376                 PCIE_ENABLE_ERRORS(ctrl_p->hc_dip);
1377 
1378                 mutex_exit(&ctrl_p->hc_mutex);
1379                 return (DDI_FAILURE);
1380         }
1381 
1382         /* get the current state of the slot */
1383         pciehpc_get_slot_state(slot_p);
1384 
1385         mutex_exit(&ctrl_p->hc_mutex);
1386         return (DDI_SUCCESS);
1387 }
1388 
1389 static int
1390 pciehpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
1391     ddi_hp_cn_state_t target_state)
1392 {
1393         ddi_hp_cn_state_t curr_state;
1394         int rv = DDI_SUCCESS;
1395 
1396         if (target_state > DDI_HP_CN_STATE_ENABLED) {
1397                 return (DDI_EINVAL);
1398         }
1399 
1400         curr_state = slot_p->hs_info.cn_state;
1401         while ((curr_state < target_state) && (rv == DDI_SUCCESS)) {
1402 
1403                 switch (curr_state) {
1404                 case DDI_HP_CN_STATE_EMPTY:
1405                         /*
1406                          * From EMPTY to PRESENT, just check the hardware
1407                          * slot state.
1408                          */
1409                         pciehpc_get_slot_state(slot_p);
1410                         curr_state = slot_p->hs_info.cn_state;
1411                         if (curr_state < DDI_HP_CN_STATE_PRESENT)
1412                                 rv = DDI_FAILURE;
1413                         break;
1414                 case DDI_HP_CN_STATE_PRESENT:
1415                         rv = (slot_p->hs_ctrl->hc_ops.poweron_hpc_slot)(slot_p,
1416                             &curr_state);
1417 
1418                         break;
1419                 case DDI_HP_CN_STATE_POWERED:
1420                         curr_state = slot_p->hs_info.cn_state =
1421                             DDI_HP_CN_STATE_ENABLED;
1422                         break;
1423                 default:
1424                         /* should never reach here */
1425                         ASSERT("unknown devinfo state");
1426                 }
1427         }
1428 
1429         return (rv);
1430 }
1431 
1432 static int
1433 pciehpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
1434     ddi_hp_cn_state_t target_state)
1435 {
1436         ddi_hp_cn_state_t curr_state;
1437         int rv = DDI_SUCCESS;
1438 
1439 
1440         curr_state = slot_p->hs_info.cn_state;
1441         while ((curr_state > target_state) && (rv == DDI_SUCCESS)) {
1442 
1443                 switch (curr_state) {
1444                 case DDI_HP_CN_STATE_PRESENT:
1445                         /*
1446                          * From PRESENT to EMPTY, just check hardware slot
1447                          * state.
1448                          */
1449                         pciehpc_get_slot_state(slot_p);
1450                         curr_state = slot_p->hs_info.cn_state;
1451                         if (curr_state >= DDI_HP_CN_STATE_PRESENT)
1452                                 rv = DDI_FAILURE;
1453                         break;
1454                 case DDI_HP_CN_STATE_POWERED:
1455                         rv = (slot_p->hs_ctrl->hc_ops.poweroff_hpc_slot)(
1456                             slot_p, &curr_state);
1457 
1458                         break;
1459                 case DDI_HP_CN_STATE_ENABLED:
1460                         curr_state = slot_p->hs_info.cn_state =
1461                             DDI_HP_CN_STATE_POWERED;
1462 
1463                         break;
1464                 default:
1465                         /* should never reach here */
1466                         ASSERT("unknown devinfo state");
1467                 }
1468         }
1469 
1470         return (rv);
1471 }
1472 
1473 /* Change slot state to a target state */
1474 static int
1475 pciehpc_change_slot_state(pcie_hp_slot_t *slot_p,
1476     ddi_hp_cn_state_t target_state)
1477 {
1478         ddi_hp_cn_state_t curr_state;
1479         int rv;
1480 
1481         pciehpc_get_slot_state(slot_p);
1482         curr_state = slot_p->hs_info.cn_state;
1483 
1484         if (curr_state == target_state) {
1485                 return (DDI_SUCCESS);
1486         }
1487         if (curr_state < target_state) {
1488 
1489                 rv = pciehpc_upgrade_slot_state(slot_p, target_state);
1490         } else {
1491                 rv = pciehpc_downgrade_slot_state(slot_p, target_state);
1492         }
1493 
1494         return (rv);
1495 }
1496 
1497 int
1498 pciehpc_slot_get_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
1499     ddi_hp_property_t *rval)
1500 {
1501         ddi_hp_property_t request, result;
1502 #ifdef _SYSCALL32_IMPL
1503         ddi_hp_property32_t request32, result32;
1504 #endif
1505         pcie_hp_ctrl_t  *ctrl_p = slot_p->hs_ctrl;
1506         nvlist_t        *prop_list;
1507         nvlist_t        *prop_rlist; /* nvlist for return values */
1508         nvpair_t        *prop_pair;
1509         char            *name, *value;
1510         int             ret = DDI_SUCCESS;
1511         int             i, n;
1512         boolean_t       get_all_prop = B_FALSE;
1513 
1514         if (get_udatamodel() == DATAMODEL_NATIVE) {
1515                 if (copyin(arg, &request, sizeof (ddi_hp_property_t)) ||
1516                     copyin(rval, &result, sizeof (ddi_hp_property_t)))
1517                         return (DDI_FAILURE);
1518         }
1519 #ifdef _SYSCALL32_IMPL
1520         else {
1521                 bzero(&request, sizeof (request));
1522                 bzero(&result, sizeof (result));
1523                 if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)) ||
1524                     copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
1525                         return (DDI_FAILURE);
1526                 request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
1527                 request.buf_size = request32.buf_size;
1528                 result.nvlist_buf = (char *)(uintptr_t)result32.nvlist_buf;
1529                 result.buf_size = result32.buf_size;
1530         }
1531 #endif
1532 
1533         if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
1534             &prop_list)) != DDI_SUCCESS)
1535                 return (ret);
1536 
1537         if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
1538                 ret = DDI_ENOMEM;
1539                 goto get_prop_cleanup;
1540         }
1541 
1542         /* check whether the requested property is "all" or "help" */
1543         prop_pair = nvlist_next_nvpair(prop_list, NULL);
1544         if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair)) {
1545                 name = nvpair_name(prop_pair);
1546                 n = sizeof (pciehpc_props) / sizeof (pciehpc_prop_t);
1547 
1548                 if (strcmp(name, PCIEHPC_PROP_ALL) == 0) {
1549                         (void) nvlist_remove_all(prop_list, PCIEHPC_PROP_ALL);
1550 
1551                         /*
1552                          * Add all properties into the request list, so that we
1553                          * will get the values in the following for loop.
1554                          */
1555                         for (i = 0; i < n; i++) {
1556                                 if (nvlist_add_string(prop_list,
1557                                     pciehpc_props[i].prop_name, "") != 0) {
1558                                         ret = DDI_FAILURE;
1559                                         goto get_prop_cleanup1;
1560                                 }
1561                         }
1562                         get_all_prop = B_TRUE;
1563                 } else if (strcmp(name, PCIEHPC_PROP_HELP) == 0) {
1564                         /*
1565                          * Empty the request list, and add help strings into the
1566                          * return list. We will pass the following for loop.
1567                          */
1568                         (void) nvlist_remove_all(prop_list, PCIEHPC_PROP_HELP);
1569 
1570                         for (i = 0; i < n; i++) {
1571                                 if (nvlist_add_string(prop_rlist,
1572                                     pciehpc_props[i].prop_name,
1573                                     pciehpc_props[i].prop_value) != 0) {
1574                                         ret = DDI_FAILURE;
1575                                         goto get_prop_cleanup1;
1576                                 }
1577                         }
1578                 }
1579         }
1580 
1581         mutex_enter(&ctrl_p->hc_mutex);
1582 
1583         /* get the current slot state */
1584         pciehpc_get_slot_state(slot_p);
1585 
1586         /* for each requested property, get the value and add it to nvlist */
1587         prop_pair = NULL;
1588         while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
1589                 name = nvpair_name(prop_pair);
1590 
1591                 if (strcmp(name, PCIEHPC_PROP_LED_FAULT) == 0) {
1592                         value = pcie_led_state_text(
1593                             slot_p->hs_fault_led_state);
1594                 } else if (strcmp(name, PCIEHPC_PROP_LED_POWER) == 0) {
1595                         value = pcie_led_state_text(
1596                             slot_p->hs_power_led_state);
1597                 } else if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
1598                         value = pcie_led_state_text(
1599                             slot_p->hs_attn_led_state);
1600                 } else if (strcmp(name, PCIEHPC_PROP_LED_ACTIVE) == 0) {
1601                         value = pcie_led_state_text(
1602                             slot_p->hs_active_led_state);
1603                 } else if (strcmp(name, PCIEHPC_PROP_CARD_TYPE) == 0) {
1604                         ddi_acc_handle_t handle;
1605                         dev_info_t      *cdip;
1606                         uint8_t         prog_class, base_class, sub_class;
1607                         int             i;
1608 
1609                         mutex_exit(&ctrl_p->hc_mutex);
1610                         cdip = pcie_hp_devi_find(
1611                             ctrl_p->hc_dip, slot_p->hs_device_num, 0);
1612                         mutex_enter(&ctrl_p->hc_mutex);
1613 
1614                         if ((slot_p->hs_info.cn_state
1615                             != DDI_HP_CN_STATE_ENABLED) || (cdip == NULL)) {
1616                                 /*
1617                                  * When getting all properties, just ignore the
1618                                  * one that's not available under certain state.
1619                                  */
1620                                 if (get_all_prop)
1621                                         continue;
1622 
1623                                 ret = DDI_ENOTSUP;
1624                                 goto get_prop_cleanup2;
1625                         }
1626 
1627                         if (pci_config_setup(cdip, &handle) != DDI_SUCCESS) {
1628                                 ret = DDI_FAILURE;
1629                                 goto get_prop_cleanup2;
1630                         }
1631 
1632                         prog_class = pci_config_get8(handle,
1633                             PCI_CONF_PROGCLASS);
1634                         base_class = pci_config_get8(handle, PCI_CONF_BASCLASS);
1635                         sub_class = pci_config_get8(handle, PCI_CONF_SUBCLASS);
1636                         pci_config_teardown(&handle);
1637 
1638                         for (i = 0; i < class_pci_items; i++) {
1639                                 if ((base_class == class_pci[i].base_class) &&
1640                                     (sub_class == class_pci[i].sub_class) &&
1641                                     (prog_class == class_pci[i].prog_class)) {
1642                                         value = class_pci[i].short_desc;
1643                                         break;
1644                                 }
1645                         }
1646                         if (i == class_pci_items)
1647                                 value = PCIEHPC_PROP_VALUE_UNKNOWN;
1648                 } else if (strcmp(name, PCIEHPC_PROP_BOARD_TYPE) == 0) {
1649                         if (slot_p->hs_info.cn_state <= DDI_HP_CN_STATE_EMPTY)
1650                                 value = PCIEHPC_PROP_VALUE_UNKNOWN;
1651                         else
1652                                 value = PCIEHPC_PROP_VALUE_PCIHOTPLUG;
1653                 } else if (strcmp(name, PCIEHPC_PROP_SLOT_CONDITION) == 0) {
1654                         value = pcie_slot_condition_text(slot_p->hs_condition);
1655                 } else {
1656                         /* unsupported property */
1657                         PCIE_DBG("Unsupported property: %s\n", name);
1658 
1659                         ret = DDI_ENOTSUP;
1660                         goto get_prop_cleanup2;
1661                 }
1662                 if (nvlist_add_string(prop_rlist, name, value) != 0) {
1663                         ret = DDI_FAILURE;
1664                         goto get_prop_cleanup2;
1665                 }
1666         }
1667 
1668         /* pack nvlist and copyout */
1669         if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
1670             &result.buf_size)) != DDI_SUCCESS) {
1671                 goto get_prop_cleanup2;
1672         }
1673         if (get_udatamodel() == DATAMODEL_NATIVE) {
1674                 if (copyout(&result, rval, sizeof (ddi_hp_property_t)))
1675                         ret = DDI_FAILURE;
1676         }
1677 #ifdef _SYSCALL32_IMPL
1678         else {
1679                 if (result.buf_size > UINT32_MAX) {
1680                         ret = DDI_FAILURE;
1681                 } else {
1682                         result32.buf_size = (uint32_t)result.buf_size;
1683                         if (copyout(&result32, rval,
1684                             sizeof (ddi_hp_property32_t)))
1685                                 ret = DDI_FAILURE;
1686                 }
1687         }
1688 #endif
1689 
1690 get_prop_cleanup2:
1691         mutex_exit(&ctrl_p->hc_mutex);
1692 get_prop_cleanup1:
1693         nvlist_free(prop_rlist);
1694 get_prop_cleanup:
1695         nvlist_free(prop_list);
1696         return (ret);
1697 }
1698 
1699 int
1700 pciehpc_slot_set_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
1701     ddi_hp_property_t *rval)
1702 {
1703         ddi_hp_property_t       request, result;
1704 #ifdef _SYSCALL32_IMPL
1705         ddi_hp_property32_t     request32, result32;
1706 #endif
1707         pcie_hp_ctrl_t          *ctrl_p = slot_p->hs_ctrl;
1708         nvlist_t                *prop_list;
1709         nvlist_t                *prop_rlist;
1710         nvpair_t                *prop_pair;
1711         char                    *name, *value;
1712         pcie_hp_led_state_t     led_state;
1713         int                     ret = DDI_SUCCESS;
1714 
1715         if (get_udatamodel() == DATAMODEL_NATIVE) {
1716                 if (copyin(arg, &request, sizeof (ddi_hp_property_t)))
1717                         return (DDI_FAILURE);
1718                 if (rval &&
1719                     copyin(rval, &result, sizeof (ddi_hp_property_t)))
1720                         return (DDI_FAILURE);
1721         }
1722 #ifdef _SYSCALL32_IMPL
1723         else {
1724                 bzero(&request, sizeof (request));
1725                 bzero(&result, sizeof (result));
1726                 if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)))
1727                         return (DDI_FAILURE);
1728                 if (rval &&
1729                     copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
1730                         return (DDI_FAILURE);
1731                 request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
1732                 request.buf_size = request32.buf_size;
1733                 if (rval) {
1734                         result.nvlist_buf =
1735                             (char *)(uintptr_t)result32.nvlist_buf;
1736                         result.buf_size = result32.buf_size;
1737                 }
1738         }
1739 #endif
1740 
1741         if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
1742             &prop_list)) != DDI_SUCCESS)
1743                 return (ret);
1744 
1745         /* check whether the requested property is "help" */
1746         prop_pair = nvlist_next_nvpair(prop_list, NULL);
1747         if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair) &&
1748             (strcmp(nvpair_name(prop_pair), PCIEHPC_PROP_HELP) == 0)) {
1749                 if (!rval) {
1750                         ret = DDI_ENOTSUP;
1751                         goto set_prop_cleanup;
1752                 }
1753 
1754                 if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
1755                         ret = DDI_ENOMEM;
1756                         goto set_prop_cleanup;
1757                 }
1758                 if (nvlist_add_string(prop_rlist, PCIEHPC_PROP_LED_ATTN,
1759                     PCIEHPC_PROP_VALUE_LED) != 0) {
1760                         ret = DDI_FAILURE;
1761                         goto set_prop_cleanup1;
1762                 }
1763 
1764                 if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
1765                     &result.buf_size)) != DDI_SUCCESS) {
1766                         goto set_prop_cleanup1;
1767                 }
1768                 if (get_udatamodel() == DATAMODEL_NATIVE) {
1769                         if (copyout(&result, rval,
1770                             sizeof (ddi_hp_property_t))) {
1771                                 ret =  DDI_FAILURE;
1772                                 goto set_prop_cleanup1;
1773                         }
1774                 }
1775 #ifdef _SYSCALL32_IMPL
1776                 else {
1777                         if (result.buf_size > UINT32_MAX) {
1778                                 ret =  DDI_FAILURE;
1779                                 goto set_prop_cleanup1;
1780                         } else {
1781                                 result32.buf_size = (uint32_t)result.buf_size;
1782                                 if (copyout(&result32, rval,
1783                                     sizeof (ddi_hp_property32_t))) {
1784                                         ret =  DDI_FAILURE;
1785                                         goto set_prop_cleanup1;
1786                                 }
1787                         }
1788                 }
1789 #endif
1790 set_prop_cleanup1:
1791                 nvlist_free(prop_rlist);
1792                 nvlist_free(prop_list);
1793                 return (ret);
1794         }
1795 
1796         /* Validate the request */
1797         prop_pair = NULL;
1798         while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
1799                 name = nvpair_name(prop_pair);
1800                 if (nvpair_type(prop_pair) != DATA_TYPE_STRING) {
1801                         PCIE_DBG("Unexpected data type of setting "
1802                             "property %s.\n", name);
1803                         ret = DDI_EINVAL;
1804                         goto set_prop_cleanup;
1805                 }
1806                 if (nvpair_value_string(prop_pair, &value)) {
1807                         PCIE_DBG("Get string value failed for property %s.\n",
1808                             name);
1809                         ret = DDI_FAILURE;
1810                         goto set_prop_cleanup;
1811                 }
1812 
1813                 if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
1814                         if ((strcmp(value, PCIEHPC_PROP_VALUE_ON) != 0) &&
1815                             (strcmp(value, PCIEHPC_PROP_VALUE_OFF) != 0) &&
1816                             (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) != 0)) {
1817                                 PCIE_DBG("Unsupported value of setting "
1818                                     "property %s\n", name);
1819                                 ret = DDI_ENOTSUP;
1820                                 goto set_prop_cleanup;
1821                         }
1822                 } else {
1823                         PCIE_DBG("Unsupported property: %s\n", name);
1824                         ret = DDI_ENOTSUP;
1825                         goto set_prop_cleanup;
1826                 }
1827         }
1828         mutex_enter(&ctrl_p->hc_mutex);
1829 
1830         /* get the current slot state */
1831         pciehpc_get_slot_state(slot_p);
1832 
1833         /* set each property */
1834         prop_pair = NULL;
1835         while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
1836                 name = nvpair_name(prop_pair);
1837 
1838                 if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
1839                         if (strcmp(value, PCIEHPC_PROP_VALUE_ON) == 0)
1840                                 led_state = PCIE_HP_LED_ON;
1841                         else if (strcmp(value, PCIEHPC_PROP_VALUE_OFF) == 0)
1842                                 led_state = PCIE_HP_LED_OFF;
1843                         else if (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) == 0)
1844                                 led_state = PCIE_HP_LED_BLINK;
1845 
1846                         pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED,
1847                             led_state);
1848                 }
1849         }
1850         if (rval) {
1851                 if (get_udatamodel() == DATAMODEL_NATIVE) {
1852                         result.buf_size = 0;
1853                         if (copyout(&result, rval, sizeof (ddi_hp_property_t)))
1854                                 ret =  DDI_FAILURE;
1855                 }
1856 #ifdef _SYSCALL32_IMPL
1857                 else {
1858                         result32.buf_size = 0;
1859                         if (copyout(&result32, rval,
1860                             sizeof (ddi_hp_property32_t)))
1861                                 ret =  DDI_FAILURE;
1862                 }
1863 #endif
1864         }
1865 
1866         mutex_exit(&ctrl_p->hc_mutex);
1867 set_prop_cleanup:
1868         nvlist_free(prop_list);
1869         return (ret);
1870 }
1871 
1872 /*
1873  * Send a command to the PCI-E Hot Plug Controller.
1874  *
1875  * NOTES: The PCI-E spec defines the following semantics for issuing hot plug
1876  * commands.
1877  * 1) If Command Complete events/interrupts are supported then software
1878  *    waits for Command Complete event after issuing a command (i.e writing
1879  *    to the Slot Control register). The command completion could take as
1880  *    long as 1 second so software should be prepared to wait for 1 second
1881  *    before issuing another command.
1882  *
1883  * 2) If Command Complete events/interrupts are not supported then
1884  *    software could issue multiple Slot Control writes without any delay
1885  *    between writes.
1886  */
1887 static void
1888 pciehpc_issue_hpc_command(pcie_hp_ctrl_t *ctrl_p, uint16_t control)
1889 {
1890         pcie_hp_slot_t  *slot_p = ctrl_p->hc_slots[0];
1891         pcie_bus_t      *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1892         uint16_t        status;
1893         uint32_t        slot_cap;
1894 
1895         /*
1896          * PCI-E version 1.1 spec defines No Command Completed
1897          * Support bit (bit#18) in Slot Capabilities register. If this
1898          * bit is set then slot doesn't support notification of command
1899          * completion events.
1900          */
1901         slot_cap =  pciehpc_reg_get32(ctrl_p,
1902             bus_p->bus_pcie_off + PCIE_SLOTCAP);
1903 
1904         /*
1905          * If no Command Completion event is supported or it is ACPI
1906          * hot plug mode then just issue the command and return.
1907          */
1908         if ((slot_cap & PCIE_SLOTCAP_NO_CMD_COMP_SUPP) ||
1909             (bus_p->bus_hp_curr_mode == PCIE_ACPI_HP_MODE)) {
1910                 pciehpc_reg_put16(ctrl_p,
1911                     bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
1912                 return;
1913         }
1914 
1915         /*
1916          * **************************************
1917          * Command Complete events are supported.
1918          * **************************************
1919          */
1920 
1921         /*
1922          * If HPC is not yet initialized then just poll for the Command
1923          * Completion interrupt.
1924          */
1925         if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
1926                 int retry = PCIE_HP_CMD_WAIT_RETRY;
1927 
1928                 /* write the command to the HPC */
1929                 pciehpc_reg_put16(ctrl_p,
1930                     bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
1931 
1932                 /* poll for status completion */
1933                 while (retry--) {
1934                         /* wait for 10 msec before checking the status */
1935                         delay(drv_usectohz(PCIE_HP_CMD_WAIT_TIME));
1936 
1937                         status = pciehpc_reg_get16(ctrl_p,
1938                             bus_p->bus_pcie_off + PCIE_SLOTSTS);
1939 
1940                         if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
1941                                 /* clear the status bits */
1942                                 pciehpc_reg_put16(ctrl_p,
1943                                     bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
1944                                 break;
1945                         }
1946                 }
1947                 return;
1948         }
1949 
1950         /* HPC is already initialized */
1951 
1952         ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
1953 
1954         /*
1955          * If previous command is still pending then wait for its
1956          * completion. i.e cv_wait()
1957          */
1958 
1959         while (ctrl_p->hc_cmd_pending == B_TRUE)
1960                 cv_wait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex);
1961 
1962         /*
1963          * Issue the command and wait for Command Completion or
1964          * the 1 sec timeout.
1965          */
1966         pciehpc_reg_put16(ctrl_p,
1967             bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
1968 
1969         ctrl_p->hc_cmd_pending = B_TRUE;
1970 
1971         if (cv_timedwait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex,
1972             ddi_get_lbolt() + SEC_TO_TICK(1)) == -1) {
1973 
1974                 /* it is a timeout */
1975                 PCIE_DBG("pciehpc_issue_hpc_command: Command Complete"
1976                     " interrupt is not received for slot %d\n",
1977                     slot_p->hs_phy_slot_num);
1978 
1979                 /* clear the status info in case interrupts are disabled? */
1980                 status = pciehpc_reg_get16(ctrl_p,
1981                     bus_p->bus_pcie_off + PCIE_SLOTSTS);
1982 
1983                 if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
1984                         /* clear the status bits */
1985                         pciehpc_reg_put16(ctrl_p,
1986                             bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
1987                 }
1988         }
1989 
1990         ctrl_p->hc_cmd_pending = B_FALSE;
1991 
1992         /* wake up any one waiting for issuing another command to HPC */
1993         cv_signal(&ctrl_p->hc_cmd_comp_cv);
1994 }
1995 
1996 /*
1997  * pciehcp_attn_btn_handler()
1998  *
1999  * This handles ATTN button pressed event as per the PCI-E 1.1 spec.
2000  */
2001 static void
2002 pciehpc_attn_btn_handler(pcie_hp_ctrl_t *ctrl_p)
2003 {
2004         pcie_hp_slot_t          *slot_p = ctrl_p->hc_slots[0];
2005         pcie_hp_led_state_t     power_led_state;
2006         callb_cpr_t             cprinfo;
2007 
2008         PCIE_DBG("pciehpc_attn_btn_handler: thread started\n");
2009 
2010         CALLB_CPR_INIT(&cprinfo, &ctrl_p->hc_mutex, callb_generic_cpr,
2011             "pciehpc_attn_btn_handler");
2012 
2013         mutex_enter(&ctrl_p->hc_mutex);
2014 
2015         /* wait for ATTN button event */
2016         cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
2017 
2018         while (slot_p->hs_attn_btn_thread_exit == B_FALSE) {
2019                 if (slot_p->hs_attn_btn_pending == B_TRUE) {
2020                         /* get the current state of power LED */
2021                         power_led_state = pciehpc_get_led_state(ctrl_p,
2022                             PCIE_HP_POWER_LED);
2023 
2024                         /* Blink the Power LED while we wait for 5 seconds */
2025                         pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
2026                             PCIE_HP_LED_BLINK);
2027 
2028                         /* wait for 5 seconds before taking any action */
2029                         if (cv_timedwait(&slot_p->hs_attn_btn_cv,
2030                             &ctrl_p->hc_mutex,
2031                             ddi_get_lbolt() + SEC_TO_TICK(5)) == -1) {
2032                                 /*
2033                                  * It is a time out; make sure the ATTN pending
2034                                  * flag is still ON before sending the event to
2035                                  * DDI HP framework.
2036                                  */
2037                                 if (slot_p->hs_attn_btn_pending == B_TRUE) {
2038                                         int hint;
2039 
2040                                         slot_p->hs_attn_btn_pending = B_FALSE;
2041                                         pciehpc_get_slot_state(slot_p);
2042 
2043                                         if (slot_p->hs_info.cn_state <=
2044                                             DDI_HP_CN_STATE_PRESENT) {
2045                                                 /*
2046                                                  * Insertion.
2047                                                  */
2048                                                 hint = SE_INCOMING_RES;
2049                                         } else {
2050                                                 /*
2051                                                  * Want to remove;
2052                                                  */
2053                                                 hint = SE_OUTGOING_RES;
2054                                         }
2055 
2056                                         /*
2057                                          * We can't call ddihp_cn_gen_sysevent
2058                                          * here since it's not a DDI interface.
2059                                          */
2060                                         pcie_hp_gen_sysevent_req(
2061                                             slot_p->hs_info.cn_name,
2062                                             hint,
2063                                             ctrl_p->hc_dip,
2064                                             KM_SLEEP);
2065                                 }
2066                         }
2067 
2068                         /* restore the power LED state */
2069                         pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
2070                             power_led_state);
2071                         continue;
2072                 }
2073 
2074                 /* wait for another ATTN button event */
2075                 cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
2076         }
2077 
2078         PCIE_DBG("pciehpc_attn_btn_handler: thread exit\n");
2079         cv_signal(&slot_p->hs_attn_btn_cv);
2080         CALLB_CPR_EXIT(&cprinfo);
2081         thread_exit();
2082 }
2083 
2084 /*
2085  * convert LED state from PCIE HPC definition to pcie_hp_led_state_t
2086  * definition.
2087  */
2088 static pcie_hp_led_state_t
2089 pciehpc_led_state_to_hpc(uint16_t state)
2090 {
2091         switch (state) {
2092         case PCIE_SLOTCTL_INDICATOR_STATE_ON:
2093                 return (PCIE_HP_LED_ON);
2094         case PCIE_SLOTCTL_INDICATOR_STATE_BLINK:
2095                 return (PCIE_HP_LED_BLINK);
2096         case PCIE_SLOTCTL_INDICATOR_STATE_OFF:
2097         default:
2098                 return (PCIE_HP_LED_OFF);
2099         }
2100 }
2101 
2102 /*
2103  * Get the state of an LED.
2104  */
2105 static pcie_hp_led_state_t
2106 pciehpc_get_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led)
2107 {
2108         pcie_bus_t      *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
2109         uint16_t        control, state;
2110 
2111         /* get the current state of Slot Control register */
2112         control =  pciehpc_reg_get16(ctrl_p,
2113             bus_p->bus_pcie_off + PCIE_SLOTCTL);
2114 
2115         switch (led) {
2116         case PCIE_HP_POWER_LED:
2117                 state = pcie_slotctl_pwr_indicator_get(control);
2118                 break;
2119         case PCIE_HP_ATTN_LED:
2120                 state = pcie_slotctl_attn_indicator_get(control);
2121                 break;
2122         default:
2123                 PCIE_DBG("pciehpc_get_led_state() invalid LED %d\n", led);
2124                 return (PCIE_HP_LED_OFF);
2125         }
2126 
2127         switch (state) {
2128         case PCIE_SLOTCTL_INDICATOR_STATE_ON:
2129                 return (PCIE_HP_LED_ON);
2130 
2131         case PCIE_SLOTCTL_INDICATOR_STATE_BLINK:
2132                 return (PCIE_HP_LED_BLINK);
2133 
2134         case PCIE_SLOTCTL_INDICATOR_STATE_OFF:
2135         default:
2136                 return (PCIE_HP_LED_OFF);
2137         }
2138 }
2139 
2140 /*
2141  * Set the state of an LED. It updates both hw and sw state.
2142  */
2143 static void
2144 pciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led,
2145     pcie_hp_led_state_t state)
2146 {
2147         pcie_hp_slot_t  *slot_p = ctrl_p->hc_slots[0];
2148         pcie_bus_t      *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
2149         uint16_t        control;
2150 
2151         /* get the current state of Slot Control register */
2152         control =  pciehpc_reg_get16(ctrl_p,
2153             bus_p->bus_pcie_off + PCIE_SLOTCTL);
2154 
2155         switch (led) {
2156         case PCIE_HP_POWER_LED:
2157                 /* clear led mask */
2158                 control &= ~PCIE_SLOTCTL_PWR_INDICATOR_MASK;
2159                 slot_p->hs_power_led_state = state;
2160                 break;
2161         case PCIE_HP_ATTN_LED:
2162                 /* clear led mask */
2163                 control &= ~PCIE_SLOTCTL_ATTN_INDICATOR_MASK;
2164                 slot_p->hs_attn_led_state = state;
2165                 break;
2166         default:
2167                 PCIE_DBG("pciehpc_set_led_state() invalid LED %d\n", led);
2168                 return;
2169         }
2170 
2171         switch (state) {
2172         case PCIE_HP_LED_ON:
2173                 if (led == PCIE_HP_POWER_LED)
2174                         control = pcie_slotctl_pwr_indicator_set(control,
2175                             PCIE_SLOTCTL_INDICATOR_STATE_ON);
2176                 else if (led == PCIE_HP_ATTN_LED)
2177                         control = pcie_slotctl_attn_indicator_set(control,
2178                             PCIE_SLOTCTL_INDICATOR_STATE_ON);
2179                 break;
2180         case PCIE_HP_LED_OFF:
2181                 if (led == PCIE_HP_POWER_LED)
2182                         control = pcie_slotctl_pwr_indicator_set(control,
2183                             PCIE_SLOTCTL_INDICATOR_STATE_OFF);
2184                 else if (led == PCIE_HP_ATTN_LED)
2185                         control = pcie_slotctl_attn_indicator_set(control,
2186                             PCIE_SLOTCTL_INDICATOR_STATE_OFF);
2187                 break;
2188         case PCIE_HP_LED_BLINK:
2189                 if (led == PCIE_HP_POWER_LED)
2190                         control = pcie_slotctl_pwr_indicator_set(control,
2191                             PCIE_SLOTCTL_INDICATOR_STATE_BLINK);
2192                 else if (led == PCIE_HP_ATTN_LED)
2193                         control = pcie_slotctl_attn_indicator_set(control,
2194                             PCIE_SLOTCTL_INDICATOR_STATE_BLINK);
2195                 break;
2196 
2197         default:
2198                 PCIE_DBG("pciehpc_set_led_state() invalid LED state %d\n",
2199                     state);
2200                 return;
2201         }
2202 
2203         /* update the Slot Control Register */
2204         pciehpc_issue_hpc_command(ctrl_p, control);
2205 
2206 #ifdef DEBUG
2207         /* get the current state of Slot Control register */
2208         control =  pciehpc_reg_get16(ctrl_p,
2209             bus_p->bus_pcie_off + PCIE_SLOTCTL);
2210 
2211         PCIE_DBG("pciehpc_set_led_state: slot %d power-led %s attn-led %s\n",
2212             slot_p->hs_phy_slot_num, pcie_led_state_text(
2213             pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control))),
2214             pcie_led_state_text(pciehpc_led_state_to_hpc(
2215             pcie_slotctl_attn_indicator_get(control))));
2216 #endif
2217 }
2218 
2219 static void
2220 pciehpc_handle_power_fault(dev_info_t *dip)
2221 {
2222         /*
2223          * Hold the parent's ref so that it won't disappear when the taskq is
2224          * scheduled to run.
2225          */
2226         ndi_hold_devi(dip);
2227 
2228         if (!taskq_dispatch(system_taskq, pciehpc_power_fault_handler, dip,
2229             TQ_NOSLEEP)) {
2230                 ndi_rele_devi(dip);
2231                 PCIE_DBG("pciehpc_intr(): "
2232                     "Failed to dispatch power fault handler, dip %p\n", dip);
2233         }
2234 }
2235 
2236 static void
2237 pciehpc_power_fault_handler(void *arg)
2238 {
2239         dev_info_t *dip = (dev_info_t *)arg;
2240         pcie_hp_ctrl_t  *ctrl_p;
2241         pcie_hp_slot_t  *slot_p;
2242 
2243         /* get the soft state structure for this dip */
2244         if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) {
2245                 ndi_rele_devi(dip);
2246                 return;
2247         }
2248         slot_p = ctrl_p->hc_slots[0];
2249 
2250         /*
2251          * Send the event to DDI Hotplug framework, power off
2252          * the slot
2253          */
2254         (void) ndi_hp_state_change_req(dip,
2255             slot_p->hs_info.cn_name,
2256             DDI_HP_CN_STATE_EMPTY, DDI_HP_REQ_SYNC);
2257 
2258         mutex_enter(&ctrl_p->hc_mutex);
2259         pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED,
2260             PCIE_HP_LED_ON);
2261         mutex_exit(&ctrl_p->hc_mutex);
2262         ndi_rele_devi(dip);
2263 }
2264 
2265 #ifdef DEBUG
2266 /*
2267  * Dump PCI-E Hot Plug registers.
2268  */
2269 static void
2270 pciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p)
2271 {
2272         pcie_hp_slot_t  *slot_p = ctrl_p->hc_slots[0];
2273         pcie_bus_t      *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
2274         uint16_t        control;
2275         uint32_t        capabilities;
2276 
2277         if (!pcie_debug_flags)
2278                 return;
2279 
2280         capabilities = pciehpc_reg_get32(ctrl_p,
2281             bus_p->bus_pcie_off + PCIE_SLOTCAP);
2282 
2283         control =  pciehpc_reg_get16(ctrl_p,
2284             bus_p->bus_pcie_off + PCIE_SLOTCTL);
2285 
2286         PCIE_DBG("pciehpc_dump_hpregs: Found PCI-E hot plug slot %d\n",
2287             slot_p->hs_phy_slot_num);
2288 
2289         PCIE_DBG("Attention Button Present = %s\n",
2290             capabilities & PCIE_SLOTCAP_ATTN_BUTTON ? "Yes":"No");
2291 
2292         PCIE_DBG("Power controller Present = %s\n",
2293             capabilities & PCIE_SLOTCAP_POWER_CONTROLLER ? "Yes":"No");
2294 
2295         PCIE_DBG("MRL Sensor Present       = %s\n",
2296             capabilities & PCIE_SLOTCAP_MRL_SENSOR ? "Yes":"No");
2297 
2298         PCIE_DBG("Attn Indicator Present   = %s\n",
2299             capabilities & PCIE_SLOTCAP_ATTN_INDICATOR ? "Yes":"No");
2300 
2301         PCIE_DBG("Power Indicator Present  = %s\n",
2302             capabilities & PCIE_SLOTCAP_PWR_INDICATOR ? "Yes":"No");
2303 
2304         PCIE_DBG("HotPlug Surprise         = %s\n",
2305             capabilities & PCIE_SLOTCAP_HP_SURPRISE ? "Yes":"No");
2306 
2307         PCIE_DBG("HotPlug Capable          = %s\n",
2308             capabilities & PCIE_SLOTCAP_HP_CAPABLE ? "Yes":"No");
2309 
2310         PCIE_DBG("Physical Slot Number     = %d\n",
2311             PCIE_SLOTCAP_PHY_SLOT_NUM(capabilities));
2312 
2313         PCIE_DBG("Attn Button interrupt Enabled  = %s\n",
2314             control & PCIE_SLOTCTL_ATTN_BTN_EN ? "Yes":"No");
2315 
2316         PCIE_DBG("Power Fault interrupt Enabled  = %s\n",
2317             control & PCIE_SLOTCTL_PWR_FAULT_EN ? "Yes":"No");
2318 
2319         PCIE_DBG("MRL Sensor INTR Enabled   = %s\n",
2320             control & PCIE_SLOTCTL_MRL_SENSOR_EN ? "Yes":"No");
2321 
2322         PCIE_DBG("Presence interrupt Enabled     = %s\n",
2323             control & PCIE_SLOTCTL_PRESENCE_CHANGE_EN ? "Yes":"No");
2324 
2325         PCIE_DBG("Cmd Complete interrupt Enabled = %s\n",
2326             control & PCIE_SLOTCTL_CMD_INTR_EN ? "Yes":"No");
2327 
2328         PCIE_DBG("HotPlug interrupt Enabled      = %s\n",
2329             control & PCIE_SLOTCTL_HP_INTR_EN ? "Yes":"No");
2330 
2331         PCIE_DBG("Power Indicator LED = %s", pcie_led_state_text(
2332             pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control))));
2333 
2334         PCIE_DBG("Attn Indicator LED = %s\n",
2335             pcie_led_state_text(pciehpc_led_state_to_hpc(
2336             pcie_slotctl_attn_indicator_get(control))));
2337 }
2338 #endif  /* DEBUG */