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