126947304SEvan Yan /* 226947304SEvan Yan * CDDL HEADER START 326947304SEvan Yan * 426947304SEvan Yan * The contents of this file are subject to the terms of the 526947304SEvan Yan * Common Development and Distribution License (the "License"). 626947304SEvan Yan * You may not use this file except in compliance with the License. 726947304SEvan Yan * 826947304SEvan Yan * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 926947304SEvan Yan * or http://www.opensolaris.org/os/licensing. 1026947304SEvan Yan * See the License for the specific language governing permissions 1126947304SEvan Yan * and limitations under the License. 1226947304SEvan Yan * 1326947304SEvan Yan * When distributing Covered Code, include this CDDL HEADER in each 1426947304SEvan Yan * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1526947304SEvan Yan * If applicable, add the following below this CDDL HEADER, with the 1626947304SEvan Yan * fields enclosed by brackets "[]" replaced with your own identifying 1726947304SEvan Yan * information: Portions Copyright [yyyy] [name of copyright owner] 1826947304SEvan Yan * 1926947304SEvan Yan * CDDL HEADER END 2026947304SEvan Yan */ 2126947304SEvan Yan 2226947304SEvan Yan /* 2380dc702dSColin Zou - Sun Microsystems - Beijing China * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24b3d69c05SRobert Mustacchi * Copyright 2019 Joyent, Inc. 25*fe426563SRick Altherr * Copyright 2022 Oxide Computer Company 2626947304SEvan Yan */ 2726947304SEvan Yan 2826947304SEvan Yan /* 2926947304SEvan Yan * This file contains Standard PCI Express HotPlug functionality that is 3026947304SEvan Yan * compatible with the PCI Express ver 1.1 specification. 3126947304SEvan Yan * 3226947304SEvan Yan * NOTE: This file is compiled and delivered through misc/pcie module. 3326947304SEvan Yan */ 3426947304SEvan Yan 3526947304SEvan Yan #include <sys/types.h> 3626947304SEvan Yan #include <sys/note.h> 3726947304SEvan Yan #include <sys/conf.h> 3826947304SEvan Yan #include <sys/kmem.h> 3926947304SEvan Yan #include <sys/debug.h> 4026947304SEvan Yan #include <sys/vtrace.h> 4126947304SEvan Yan #include <sys/autoconf.h> 4226947304SEvan Yan #include <sys/varargs.h> 4326947304SEvan Yan #include <sys/ddi_impldefs.h> 4426947304SEvan Yan #include <sys/time.h> 4526947304SEvan Yan #include <sys/callb.h> 4626947304SEvan Yan #include <sys/ddi.h> 4726947304SEvan Yan #include <sys/sunddi.h> 4826947304SEvan Yan #include <sys/sunndi.h> 4926947304SEvan Yan #include <sys/sysevent/dr.h> 5026947304SEvan Yan #include <sys/pci_impl.h> 5126947304SEvan Yan #include <sys/hotplug/pci/pcie_hp.h> 5226947304SEvan Yan #include <sys/hotplug/pci/pciehpc.h> 5326947304SEvan Yan 5426947304SEvan Yan typedef struct pciehpc_prop { 5526947304SEvan Yan char *prop_name; 5626947304SEvan Yan char *prop_value; 5726947304SEvan Yan } pciehpc_prop_t; 5826947304SEvan Yan 5926947304SEvan Yan static pciehpc_prop_t pciehpc_props[] = { 6026947304SEvan Yan { PCIEHPC_PROP_LED_FAULT, PCIEHPC_PROP_VALUE_LED }, 6126947304SEvan Yan { PCIEHPC_PROP_LED_POWER, PCIEHPC_PROP_VALUE_LED }, 6226947304SEvan Yan { PCIEHPC_PROP_LED_ATTN, PCIEHPC_PROP_VALUE_LED }, 6326947304SEvan Yan { PCIEHPC_PROP_LED_ACTIVE, PCIEHPC_PROP_VALUE_LED }, 6426947304SEvan Yan { PCIEHPC_PROP_CARD_TYPE, PCIEHPC_PROP_VALUE_TYPE }, 6526947304SEvan Yan { PCIEHPC_PROP_BOARD_TYPE, PCIEHPC_PROP_VALUE_TYPE }, 6626947304SEvan Yan { PCIEHPC_PROP_SLOT_CONDITION, PCIEHPC_PROP_VALUE_TYPE } 6726947304SEvan Yan }; 6826947304SEvan Yan 6926947304SEvan Yan /* Local functions prototype */ 7026947304SEvan Yan static int pciehpc_hpc_init(pcie_hp_ctrl_t *ctrl_p); 7126947304SEvan Yan static int pciehpc_hpc_uninit(pcie_hp_ctrl_t *ctrl_p); 7226947304SEvan Yan static int pciehpc_slotinfo_init(pcie_hp_ctrl_t *ctrl_p); 7326947304SEvan Yan static int pciehpc_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p); 7426947304SEvan Yan static int pciehpc_enable_intr(pcie_hp_ctrl_t *ctrl_p); 7526947304SEvan Yan static int pciehpc_disable_intr(pcie_hp_ctrl_t *ctrl_p); 7626947304SEvan Yan static pcie_hp_ctrl_t *pciehpc_create_controller(dev_info_t *dip); 7726947304SEvan Yan static void pciehpc_destroy_controller(dev_info_t *dip); 7826947304SEvan Yan static int pciehpc_register_slot(pcie_hp_ctrl_t *ctrl_p); 7926947304SEvan Yan static int pciehpc_unregister_slot(pcie_hp_ctrl_t *ctrl_p); 8026947304SEvan Yan static int pciehpc_slot_get_property(pcie_hp_slot_t *slot_p, 8126947304SEvan Yan ddi_hp_property_t *arg, ddi_hp_property_t *rval); 8226947304SEvan Yan static int pciehpc_slot_set_property(pcie_hp_slot_t *slot_p, 8326947304SEvan Yan ddi_hp_property_t *arg, ddi_hp_property_t *rval); 8426947304SEvan Yan static void pciehpc_issue_hpc_command(pcie_hp_ctrl_t *ctrl_p, uint16_t control); 8526947304SEvan Yan static void pciehpc_attn_btn_handler(pcie_hp_ctrl_t *ctrl_p); 8626947304SEvan Yan static pcie_hp_led_state_t pciehpc_led_state_to_hpc(uint16_t state); 8726947304SEvan Yan static pcie_hp_led_state_t pciehpc_get_led_state(pcie_hp_ctrl_t *ctrl_p, 8826947304SEvan Yan pcie_hp_led_t led); 8926947304SEvan Yan static void pciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led, 9026947304SEvan Yan pcie_hp_led_state_t state); 9126947304SEvan Yan 9226947304SEvan Yan static int pciehpc_upgrade_slot_state(pcie_hp_slot_t *slot_p, 9326947304SEvan Yan ddi_hp_cn_state_t target_state); 9426947304SEvan Yan static int pciehpc_downgrade_slot_state(pcie_hp_slot_t *slot_p, 9526947304SEvan Yan ddi_hp_cn_state_t target_state); 9626947304SEvan Yan static int pciehpc_change_slot_state(pcie_hp_slot_t *slot_p, 9726947304SEvan Yan ddi_hp_cn_state_t target_state); 9826947304SEvan Yan static int 9926947304SEvan Yan pciehpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result); 10026947304SEvan Yan static int 10126947304SEvan Yan pciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result); 10226947304SEvan Yan static int pciehpc_slot_probe(pcie_hp_slot_t *slot_p); 10326947304SEvan Yan static int pciehpc_slot_unprobe(pcie_hp_slot_t *slot_p); 10480dc702dSColin Zou - Sun Microsystems - Beijing China static void pciehpc_handle_power_fault(dev_info_t *dip); 10580dc702dSColin Zou - Sun Microsystems - Beijing China static void pciehpc_power_fault_handler(void *arg); 10626947304SEvan Yan 10726947304SEvan Yan #ifdef DEBUG 10826947304SEvan Yan static void pciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p); 10926947304SEvan Yan #endif /* DEBUG */ 11026947304SEvan Yan 11126947304SEvan Yan /* 11226947304SEvan Yan * Global functions (called by other drivers/modules) 11326947304SEvan Yan */ 11426947304SEvan Yan 11526947304SEvan Yan /* 11626947304SEvan Yan * Initialize Hot Plug Controller if present. The arguments are: 11726947304SEvan Yan * dip - Devinfo node pointer to the hot plug bus node 11826947304SEvan Yan * regops - register ops to access HPC registers for non-standard 11926947304SEvan Yan * HPC hw implementations (e.g: HPC in host PCI-E brdiges) 12026947304SEvan Yan * This is NULL for standard HPC in PCIe bridges. 12126947304SEvan Yan * Returns: 12226947304SEvan Yan * DDI_SUCCESS for successful HPC initialization 12326947304SEvan Yan * DDI_FAILURE for errors or if HPC hw not found 12426947304SEvan Yan */ 12526947304SEvan Yan int 12626947304SEvan Yan pciehpc_init(dev_info_t *dip, caddr_t arg) 12726947304SEvan Yan { 12826947304SEvan Yan pcie_hp_regops_t *regops = (pcie_hp_regops_t *)(void *)arg; 12926947304SEvan Yan pcie_hp_ctrl_t *ctrl_p; 13026947304SEvan Yan 13126947304SEvan Yan PCIE_DBG("pciehpc_init() called (dip=%p)\n", (void *)dip); 13226947304SEvan Yan 13326947304SEvan Yan /* Make sure that it is not already initialized */ 13426947304SEvan Yan if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) != NULL) { 13526947304SEvan Yan PCIE_DBG("%s%d: pciehpc instance already initialized!\n", 13626947304SEvan Yan ddi_driver_name(dip), ddi_get_instance(dip)); 13726947304SEvan Yan return (DDI_SUCCESS); 13826947304SEvan Yan } 13926947304SEvan Yan 14026947304SEvan Yan /* Allocate a new hotplug controller and slot structures */ 14126947304SEvan Yan ctrl_p = pciehpc_create_controller(dip); 14226947304SEvan Yan 14326947304SEvan Yan /* setup access handle for HPC regs */ 14426947304SEvan Yan if (regops != NULL) { 14526947304SEvan Yan /* HPC access is non-standard; use the supplied reg ops */ 14626947304SEvan Yan ctrl_p->hc_regops = *regops; 14726947304SEvan Yan } 14826947304SEvan Yan 14926947304SEvan Yan /* 15026947304SEvan Yan * Setup resource maps for this bus node. 15126947304SEvan Yan */ 15226947304SEvan Yan (void) pci_resource_setup(dip); 15326947304SEvan Yan 15426947304SEvan Yan PCIE_DISABLE_ERRORS(dip); 15526947304SEvan Yan 15626947304SEvan Yan /* 15726947304SEvan Yan * Set the platform specific hot plug mode. 15826947304SEvan Yan */ 15926947304SEvan Yan ctrl_p->hc_ops.init_hpc_hw = pciehpc_hpc_init; 16026947304SEvan Yan ctrl_p->hc_ops.uninit_hpc_hw = pciehpc_hpc_uninit; 16126947304SEvan Yan ctrl_p->hc_ops.init_hpc_slotinfo = pciehpc_slotinfo_init; 16226947304SEvan Yan ctrl_p->hc_ops.uninit_hpc_slotinfo = pciehpc_slotinfo_uninit; 16326947304SEvan Yan ctrl_p->hc_ops.poweron_hpc_slot = pciehpc_slot_poweron; 16426947304SEvan Yan ctrl_p->hc_ops.poweroff_hpc_slot = pciehpc_slot_poweroff; 16526947304SEvan Yan 16626947304SEvan Yan ctrl_p->hc_ops.enable_hpc_intr = pciehpc_enable_intr; 16726947304SEvan Yan ctrl_p->hc_ops.disable_hpc_intr = pciehpc_disable_intr; 16826947304SEvan Yan 16986ef0a63SRichard Lowe #if defined(__x86) 17026947304SEvan Yan pciehpc_update_ops(ctrl_p); 17126947304SEvan Yan #endif 17226947304SEvan Yan 17326947304SEvan Yan /* initialize hot plug controller hw */ 17426947304SEvan Yan if ((ctrl_p->hc_ops.init_hpc_hw)(ctrl_p) != DDI_SUCCESS) 17526947304SEvan Yan goto cleanup1; 17626947304SEvan Yan 17726947304SEvan Yan /* initialize slot information soft state structure */ 17826947304SEvan Yan if ((ctrl_p->hc_ops.init_hpc_slotinfo)(ctrl_p) != DDI_SUCCESS) 17926947304SEvan Yan goto cleanup2; 18026947304SEvan Yan 18126947304SEvan Yan /* register the hot plug slot with DDI HP framework */ 18226947304SEvan Yan if (pciehpc_register_slot(ctrl_p) != DDI_SUCCESS) 18326947304SEvan Yan goto cleanup3; 18426947304SEvan Yan 18526947304SEvan Yan /* create minor node for this slot */ 18626947304SEvan Yan if (pcie_create_minor_node(ctrl_p, 0) != DDI_SUCCESS) 18726947304SEvan Yan goto cleanup4; 18826947304SEvan Yan 18926947304SEvan Yan /* HPC initialization is complete now */ 19026947304SEvan Yan ctrl_p->hc_flags = PCIE_HP_INITIALIZED_FLAG; 19126947304SEvan Yan 19226947304SEvan Yan #ifdef DEBUG 19326947304SEvan Yan /* For debug, dump the HPC registers */ 19426947304SEvan Yan pciehpc_dump_hpregs(ctrl_p); 19526947304SEvan Yan #endif /* DEBUG */ 19626947304SEvan Yan 19726947304SEvan Yan return (DDI_SUCCESS); 19826947304SEvan Yan cleanup4: 19926947304SEvan Yan (void) pciehpc_unregister_slot(ctrl_p); 20026947304SEvan Yan cleanup3: 20126947304SEvan Yan (void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p); 20226947304SEvan Yan 20326947304SEvan Yan cleanup2: 20426947304SEvan Yan (void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p); 20526947304SEvan Yan 20626947304SEvan Yan cleanup1: 20726947304SEvan Yan PCIE_ENABLE_ERRORS(dip); 20826947304SEvan Yan (void) pci_resource_destroy(dip); 20926947304SEvan Yan 21026947304SEvan Yan pciehpc_destroy_controller(dip); 21126947304SEvan Yan return (DDI_FAILURE); 21226947304SEvan Yan } 21326947304SEvan Yan 21426947304SEvan Yan /* 21526947304SEvan Yan * Uninitialize HPC soft state structure and free up any resources 21626947304SEvan Yan * used for the HPC instance. 21726947304SEvan Yan */ 21826947304SEvan Yan int 21926947304SEvan Yan pciehpc_uninit(dev_info_t *dip) 22026947304SEvan Yan { 22126947304SEvan Yan pcie_hp_ctrl_t *ctrl_p; 22226947304SEvan Yan 22326947304SEvan Yan PCIE_DBG("pciehpc_uninit() called (dip=%p)\n", (void *)dip); 22426947304SEvan Yan 22526947304SEvan Yan /* get the soft state structure for this dip */ 22626947304SEvan Yan if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) { 22726947304SEvan Yan return (DDI_FAILURE); 22826947304SEvan Yan } 22926947304SEvan Yan 23026947304SEvan Yan pcie_remove_minor_node(ctrl_p, 0); 23126947304SEvan Yan 23226947304SEvan Yan /* unregister the slot */ 23326947304SEvan Yan (void) pciehpc_unregister_slot(ctrl_p); 23426947304SEvan Yan 23526947304SEvan Yan /* uninit any slot info data structures */ 23626947304SEvan Yan (void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p); 23726947304SEvan Yan 23826947304SEvan Yan /* uninitialize hpc, remove interrupt handler, etc. */ 23926947304SEvan Yan (void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p); 24026947304SEvan Yan 24126947304SEvan Yan PCIE_ENABLE_ERRORS(dip); 24226947304SEvan Yan 24326947304SEvan Yan /* 24426947304SEvan Yan * Destroy resource maps for this bus node. 24526947304SEvan Yan */ 24626947304SEvan Yan (void) pci_resource_destroy(dip); 24726947304SEvan Yan 24826947304SEvan Yan /* destroy the soft state structure */ 24926947304SEvan Yan pciehpc_destroy_controller(dip); 25026947304SEvan Yan 25126947304SEvan Yan return (DDI_SUCCESS); 25226947304SEvan Yan } 25326947304SEvan Yan 25426947304SEvan Yan /* 25526947304SEvan Yan * pciehpc_intr() 25626947304SEvan Yan * 25726947304SEvan Yan * Interrupt handler for PCI-E Hot plug controller interrupts. 25826947304SEvan Yan * 25926947304SEvan Yan * Note: This is only for native mode hot plug. This is called 26026947304SEvan Yan * by the nexus driver at interrupt context. Interrupt Service Routine 26126947304SEvan Yan * registration is done by the nexus driver for both hot plug and 26226947304SEvan Yan * non-hot plug interrupts. This function is called from the ISR 26326947304SEvan Yan * of the nexus driver to handle hot-plug interrupts. 26426947304SEvan Yan */ 26526947304SEvan Yan int 26626947304SEvan Yan pciehpc_intr(dev_info_t *dip) 26726947304SEvan Yan { 26826947304SEvan Yan pcie_hp_ctrl_t *ctrl_p; 26926947304SEvan Yan pcie_hp_slot_t *slot_p; 27026947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 27126947304SEvan Yan uint16_t status, control; 27226947304SEvan Yan 27326947304SEvan Yan /* get the soft state structure for this dip */ 27426947304SEvan Yan if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) 27526947304SEvan Yan return (DDI_INTR_UNCLAIMED); 27626947304SEvan Yan 27726947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex); 27826947304SEvan Yan 27926947304SEvan Yan /* make sure the controller soft state is initialized */ 28026947304SEvan Yan if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) { 28126947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex); 28226947304SEvan Yan return (DDI_INTR_UNCLAIMED); 28326947304SEvan Yan } 28426947304SEvan Yan 28526947304SEvan Yan /* if it is not NATIVE hot plug mode then return */ 28626947304SEvan Yan if (bus_p->bus_hp_curr_mode != PCIE_NATIVE_HP_MODE) { 28726947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex); 28826947304SEvan Yan return (DDI_INTR_UNCLAIMED); 28926947304SEvan Yan } 29026947304SEvan Yan 29126947304SEvan Yan slot_p = ctrl_p->hc_slots[0]; 29226947304SEvan Yan 29326947304SEvan Yan /* read the current slot status register */ 29426947304SEvan Yan status = pciehpc_reg_get16(ctrl_p, 29526947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS); 29626947304SEvan Yan 29726947304SEvan Yan /* check if there are any hot plug interrupts occurred */ 29826947304SEvan Yan if (!(status & PCIE_SLOTSTS_STATUS_EVENTS)) { 29926947304SEvan Yan /* no hot plug events occurred */ 30026947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex); 30126947304SEvan Yan return (DDI_INTR_UNCLAIMED); 30226947304SEvan Yan } 30326947304SEvan Yan 30426947304SEvan Yan /* clear the interrupt status bits */ 30526947304SEvan Yan pciehpc_reg_put16(ctrl_p, 30626947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS, status); 30726947304SEvan Yan 30826947304SEvan Yan /* check for CMD COMPLETE interrupt */ 30926947304SEvan Yan if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) { 31026947304SEvan Yan PCIE_DBG("pciehpc_intr(): CMD COMPLETED interrupt received\n"); 31126947304SEvan Yan /* wake up any one waiting for Command Completion event */ 31226947304SEvan Yan cv_signal(&ctrl_p->hc_cmd_comp_cv); 31326947304SEvan Yan } 31426947304SEvan Yan 31526947304SEvan Yan /* check for ATTN button interrupt */ 31626947304SEvan Yan if (status & PCIE_SLOTSTS_ATTN_BTN_PRESSED) { 31726947304SEvan Yan PCIE_DBG("pciehpc_intr(): ATTN BUTTON interrupt received\n"); 31826947304SEvan Yan 31926947304SEvan Yan /* if ATTN button event is still pending then cancel it */ 32026947304SEvan Yan if (slot_p->hs_attn_btn_pending == B_TRUE) 32126947304SEvan Yan slot_p->hs_attn_btn_pending = B_FALSE; 32226947304SEvan Yan else 32326947304SEvan Yan slot_p->hs_attn_btn_pending = B_TRUE; 32426947304SEvan Yan 32526947304SEvan Yan /* wake up the ATTN event handler */ 32626947304SEvan Yan cv_signal(&slot_p->hs_attn_btn_cv); 32726947304SEvan Yan } 32826947304SEvan Yan 32926947304SEvan Yan /* check for power fault interrupt */ 33026947304SEvan Yan if (status & PCIE_SLOTSTS_PWR_FAULT_DETECTED) { 33126947304SEvan Yan 33226947304SEvan Yan PCIE_DBG("pciehpc_intr(): POWER FAULT interrupt received" 33326947304SEvan Yan " on slot %d\n", slot_p->hs_phy_slot_num); 33426947304SEvan Yan control = pciehpc_reg_get16(ctrl_p, 33526947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL); 33626947304SEvan Yan 33726947304SEvan Yan if (control & PCIE_SLOTCTL_PWR_FAULT_EN) { 33826947304SEvan Yan slot_p->hs_condition = AP_COND_FAILED; 33926947304SEvan Yan 34026947304SEvan Yan /* disable power fault detction interrupt */ 34126947304SEvan Yan pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + 34226947304SEvan Yan PCIE_SLOTCTL, control & ~PCIE_SLOTCTL_PWR_FAULT_EN); 34326947304SEvan Yan 34480dc702dSColin Zou - Sun Microsystems - Beijing China pciehpc_handle_power_fault(dip); 34526947304SEvan Yan } 34626947304SEvan Yan } 34726947304SEvan Yan 34826947304SEvan Yan /* check for MRL SENSOR CHANGED interrupt */ 34926947304SEvan Yan if (status & PCIE_SLOTSTS_MRL_SENSOR_CHANGED) { 35026947304SEvan Yan /* For now (phase-I), no action is taken on this event */ 35126947304SEvan Yan PCIE_DBG("pciehpc_intr(): MRL SENSOR CHANGED interrupt received" 35226947304SEvan Yan " on slot %d\n", slot_p->hs_phy_slot_num); 35326947304SEvan Yan } 35426947304SEvan Yan 35526947304SEvan Yan /* check for PRESENCE CHANGED interrupt */ 35626947304SEvan Yan if (status & PCIE_SLOTSTS_PRESENCE_CHANGED) { 35726947304SEvan Yan 35826947304SEvan Yan PCIE_DBG("pciehpc_intr(): PRESENCE CHANGED interrupt received" 35926947304SEvan Yan " on slot %d\n", slot_p->hs_phy_slot_num); 36026947304SEvan Yan 36126947304SEvan Yan if (status & PCIE_SLOTSTS_PRESENCE_DETECTED) { 36226947304SEvan Yan /* 36326947304SEvan Yan * card is inserted into the slot, ask DDI Hotplug 36426947304SEvan Yan * framework to change state to Present. 36526947304SEvan Yan */ 36670f83219SEvan Yan cmn_err(CE_NOTE, "pciehpc (%s%d): card is inserted" 36770f83219SEvan Yan " in the slot %s", 36870f83219SEvan Yan ddi_driver_name(dip), 36970f83219SEvan Yan ddi_get_instance(dip), 37070f83219SEvan Yan slot_p->hs_info.cn_name); 37170f83219SEvan Yan 37226947304SEvan Yan (void) ndi_hp_state_change_req(dip, 37326947304SEvan Yan slot_p->hs_info.cn_name, 37426947304SEvan Yan DDI_HP_CN_STATE_PRESENT, 37526947304SEvan Yan DDI_HP_REQ_ASYNC); 37626947304SEvan Yan } else { /* card is removed from the slot */ 37726947304SEvan Yan cmn_err(CE_NOTE, "pciehpc (%s%d): card is removed" 37826947304SEvan Yan " from the slot %s", 37926947304SEvan Yan ddi_driver_name(dip), 38026947304SEvan Yan ddi_get_instance(dip), 38126947304SEvan Yan slot_p->hs_info.cn_name); 38226947304SEvan Yan 38326947304SEvan Yan if (slot_p->hs_info.cn_state == 38426947304SEvan Yan DDI_HP_CN_STATE_ENABLED) { 38526947304SEvan Yan /* Card is removed when slot is enabled */ 38626947304SEvan Yan slot_p->hs_condition = AP_COND_FAILED; 38726947304SEvan Yan } else { 38826947304SEvan Yan slot_p->hs_condition = AP_COND_UNKNOWN; 38926947304SEvan Yan } 39026947304SEvan Yan /* make sure to disable power fault detction intr */ 39126947304SEvan Yan control = pciehpc_reg_get16(ctrl_p, 39226947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL); 39326947304SEvan Yan 39426947304SEvan Yan if (control & PCIE_SLOTCTL_PWR_FAULT_EN) 39526947304SEvan Yan pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + 39626947304SEvan Yan PCIE_SLOTCTL, 39726947304SEvan Yan control & ~PCIE_SLOTCTL_PWR_FAULT_EN); 39826947304SEvan Yan 39926947304SEvan Yan /* 400ffb64830SJordan Paige Hendricks * If supported, notify the child device driver that the 401ffb64830SJordan Paige Hendricks * device is being removed. 402ffb64830SJordan Paige Hendricks */ 403ffb64830SJordan Paige Hendricks dev_info_t *cdip = ddi_get_child(dip); 404ffb64830SJordan Paige Hendricks if (cdip != NULL) { 405ffb64830SJordan Paige Hendricks ddi_eventcookie_t rm_cookie; 406ffb64830SJordan Paige Hendricks if (ddi_get_eventcookie(cdip, 407ffb64830SJordan Paige Hendricks DDI_DEVI_REMOVE_EVENT, 408ffb64830SJordan Paige Hendricks &rm_cookie) == DDI_SUCCESS) { 409ffb64830SJordan Paige Hendricks ndi_post_event(dip, cdip, rm_cookie, 410ffb64830SJordan Paige Hendricks NULL); 411ffb64830SJordan Paige Hendricks } 412ffb64830SJordan Paige Hendricks } 413ffb64830SJordan Paige Hendricks 414ffb64830SJordan Paige Hendricks /* 41526947304SEvan Yan * Ask DDI Hotplug framework to change state to Empty 41626947304SEvan Yan */ 41726947304SEvan Yan (void) ndi_hp_state_change_req(dip, 41826947304SEvan Yan slot_p->hs_info.cn_name, 41926947304SEvan Yan DDI_HP_CN_STATE_EMPTY, 42026947304SEvan Yan DDI_HP_REQ_ASYNC); 42126947304SEvan Yan } 42226947304SEvan Yan } 42326947304SEvan Yan 42426947304SEvan Yan /* check for DLL state changed interrupt */ 42526947304SEvan Yan if (ctrl_p->hc_dll_active_rep && 42626947304SEvan Yan (status & PCIE_SLOTSTS_DLL_STATE_CHANGED)) { 42726947304SEvan Yan PCIE_DBG("pciehpc_intr(): DLL STATE CHANGED interrupt received" 42826947304SEvan Yan " on slot %d\n", slot_p->hs_phy_slot_num); 42926947304SEvan Yan 43026947304SEvan Yan cv_signal(&slot_p->hs_dll_active_cv); 43126947304SEvan Yan } 43226947304SEvan Yan 43326947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex); 43426947304SEvan Yan 43526947304SEvan Yan return (DDI_INTR_CLAIMED); 43626947304SEvan Yan } 43726947304SEvan Yan 43826947304SEvan Yan /* 43926947304SEvan Yan * Handle hotplug commands 44026947304SEvan Yan * 44126947304SEvan Yan * Note: This function is called by DDI HP framework at kernel context only 44226947304SEvan Yan */ 44326947304SEvan Yan /* ARGSUSED */ 44426947304SEvan Yan int 44526947304SEvan Yan pciehpc_hp_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op, 44626947304SEvan Yan void *arg, void *result) 44726947304SEvan Yan { 44826947304SEvan Yan pcie_hp_ctrl_t *ctrl_p; 44926947304SEvan Yan pcie_hp_slot_t *slot_p; 45026947304SEvan Yan int ret = DDI_SUCCESS; 45126947304SEvan Yan 45226947304SEvan Yan PCIE_DBG("pciehpc_hp_ops: dip=%p cn_name=%s op=%x arg=%p\n", 45326947304SEvan Yan dip, cn_name, op, arg); 45426947304SEvan Yan 45526947304SEvan Yan if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) 45626947304SEvan Yan return (DDI_FAILURE); 45726947304SEvan Yan 45826947304SEvan Yan slot_p = ctrl_p->hc_slots[0]; 45926947304SEvan Yan 46026947304SEvan Yan if (strcmp(cn_name, slot_p->hs_info.cn_name) != 0) 46126947304SEvan Yan return (DDI_EINVAL); 46226947304SEvan Yan 46326947304SEvan Yan switch (op) { 46426947304SEvan Yan case DDI_HPOP_CN_GET_STATE: 46526947304SEvan Yan { 46626947304SEvan Yan mutex_enter(&slot_p->hs_ctrl->hc_mutex); 46726947304SEvan Yan 46826947304SEvan Yan /* get the current slot state */ 46926947304SEvan Yan pciehpc_get_slot_state(slot_p); 47026947304SEvan Yan 47126947304SEvan Yan *((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state; 47226947304SEvan Yan 47326947304SEvan Yan mutex_exit(&slot_p->hs_ctrl->hc_mutex); 47426947304SEvan Yan break; 47526947304SEvan Yan } 47626947304SEvan Yan case DDI_HPOP_CN_CHANGE_STATE: 47726947304SEvan Yan { 47826947304SEvan Yan ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg; 47926947304SEvan Yan 48026947304SEvan Yan mutex_enter(&slot_p->hs_ctrl->hc_mutex); 48126947304SEvan Yan 48226947304SEvan Yan ret = pciehpc_change_slot_state(slot_p, target_state); 48326947304SEvan Yan *(ddi_hp_cn_state_t *)result = slot_p->hs_info.cn_state; 48426947304SEvan Yan 48526947304SEvan Yan mutex_exit(&slot_p->hs_ctrl->hc_mutex); 48626947304SEvan Yan break; 48726947304SEvan Yan } 48826947304SEvan Yan case DDI_HPOP_CN_PROBE: 48926947304SEvan Yan 49026947304SEvan Yan ret = pciehpc_slot_probe(slot_p); 49126947304SEvan Yan 49226947304SEvan Yan break; 49326947304SEvan Yan case DDI_HPOP_CN_UNPROBE: 49426947304SEvan Yan ret = pciehpc_slot_unprobe(slot_p); 49526947304SEvan Yan 49626947304SEvan Yan break; 49726947304SEvan Yan case DDI_HPOP_CN_GET_PROPERTY: 49826947304SEvan Yan ret = pciehpc_slot_get_property(slot_p, 49926947304SEvan Yan (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result); 50026947304SEvan Yan break; 50126947304SEvan Yan case DDI_HPOP_CN_SET_PROPERTY: 50226947304SEvan Yan ret = pciehpc_slot_set_property(slot_p, 50326947304SEvan Yan (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result); 50426947304SEvan Yan break; 50526947304SEvan Yan default: 50626947304SEvan Yan ret = DDI_ENOTSUP; 50726947304SEvan Yan break; 50826947304SEvan Yan } 50926947304SEvan Yan 51026947304SEvan Yan return (ret); 51126947304SEvan Yan } 51226947304SEvan Yan 51326947304SEvan Yan /* 51426947304SEvan Yan * Get the current state of the slot from the hw. 51526947304SEvan Yan * 51626947304SEvan Yan * The slot state should have been initialized before this function gets called. 51726947304SEvan Yan */ 51826947304SEvan Yan void 51926947304SEvan Yan pciehpc_get_slot_state(pcie_hp_slot_t *slot_p) 52026947304SEvan Yan { 52126947304SEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; 52226947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 52326947304SEvan Yan uint16_t control, status; 52426947304SEvan Yan ddi_hp_cn_state_t curr_state = slot_p->hs_info.cn_state; 52526947304SEvan Yan 52626947304SEvan Yan /* read the Slot Control Register */ 52726947304SEvan Yan control = pciehpc_reg_get16(ctrl_p, 52826947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL); 52926947304SEvan Yan 53026947304SEvan Yan slot_p->hs_fault_led_state = PCIE_HP_LED_OFF; /* no fault led */ 53126947304SEvan Yan slot_p->hs_active_led_state = PCIE_HP_LED_OFF; /* no active led */ 53226947304SEvan Yan 53326947304SEvan Yan /* read the current Slot Status Register */ 53426947304SEvan Yan status = pciehpc_reg_get16(ctrl_p, 53526947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS); 53626947304SEvan Yan 53726947304SEvan Yan /* get POWER led state */ 53826947304SEvan Yan slot_p->hs_power_led_state = 53926947304SEvan Yan pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control)); 54026947304SEvan Yan 54126947304SEvan Yan /* get ATTN led state */ 54226947304SEvan Yan slot_p->hs_attn_led_state = 54326947304SEvan Yan pciehpc_led_state_to_hpc(pcie_slotctl_attn_indicator_get(control)); 54426947304SEvan Yan 54526947304SEvan Yan if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) { 54626947304SEvan Yan /* no device present; slot is empty */ 54726947304SEvan Yan slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY; 54826947304SEvan Yan 54926947304SEvan Yan return; 55026947304SEvan Yan } 55126947304SEvan Yan 55226947304SEvan Yan /* device is present */ 55326947304SEvan Yan slot_p->hs_info.cn_state = DDI_HP_CN_STATE_PRESENT; 55426947304SEvan Yan 55526947304SEvan Yan if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) { 55626947304SEvan Yan /* 55726947304SEvan Yan * Device is powered on. Set to "ENABLED" state (skip 55826947304SEvan Yan * POWERED state) because there is not a explicit "enable" 55926947304SEvan Yan * action exists for PCIe. 56026947304SEvan Yan * If it is already in "POWERED" state, then keep it until 56126947304SEvan Yan * user explicitly change it to other states. 56226947304SEvan Yan */ 56326947304SEvan Yan if (curr_state == DDI_HP_CN_STATE_POWERED) { 56426947304SEvan Yan slot_p->hs_info.cn_state = curr_state; 56526947304SEvan Yan } else { 56626947304SEvan Yan slot_p->hs_info.cn_state = DDI_HP_CN_STATE_ENABLED; 56726947304SEvan Yan } 56826947304SEvan Yan } 56926947304SEvan Yan } 57026947304SEvan Yan 57126947304SEvan Yan /* 57226947304SEvan Yan * setup slot name/slot-number info. 57326947304SEvan Yan */ 57426947304SEvan Yan void 57526947304SEvan Yan pciehpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p) 57626947304SEvan Yan { 57726947304SEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; 57826947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 57926947304SEvan Yan uchar_t *slotname_data; 58026947304SEvan Yan int *slotnum; 58126947304SEvan Yan uint_t count; 58226947304SEvan Yan int len; 58326947304SEvan Yan int invalid_slotnum = 0; 58426947304SEvan Yan uint32_t slot_capabilities; 58526947304SEvan Yan 58626947304SEvan Yan if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ctrl_p->hc_dip, 58726947304SEvan Yan DDI_PROP_DONTPASS, "physical-slot#", &slotnum, &count) == 58826947304SEvan Yan DDI_PROP_SUCCESS) { 58926947304SEvan Yan slot_p->hs_phy_slot_num = slotnum[0]; 59026947304SEvan Yan ddi_prop_free(slotnum); 59126947304SEvan Yan } else { 59226947304SEvan Yan slot_capabilities = pciehpc_reg_get32(ctrl_p, 59326947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCAP); 59426947304SEvan Yan slot_p->hs_phy_slot_num = 59526947304SEvan Yan PCIE_SLOTCAP_PHY_SLOT_NUM(slot_capabilities); 59626947304SEvan Yan } 59726947304SEvan Yan 59826947304SEvan Yan /* platform may not have initialized it */ 59926947304SEvan Yan if (!slot_p->hs_phy_slot_num) { 60026947304SEvan Yan PCIE_DBG("%s#%d: Invalid slot number!\n", 60126947304SEvan Yan ddi_driver_name(ctrl_p->hc_dip), 60226947304SEvan Yan ddi_get_instance(ctrl_p->hc_dip)); 60326947304SEvan Yan slot_p->hs_phy_slot_num = pciehpc_reg_get8(ctrl_p, 60426947304SEvan Yan PCI_BCNF_SECBUS); 60526947304SEvan Yan invalid_slotnum = 1; 60626947304SEvan Yan } 60726947304SEvan Yan slot_p->hs_info.cn_num = slot_p->hs_phy_slot_num; 60826947304SEvan Yan slot_p->hs_info.cn_num_dpd_on = DDI_HP_CN_NUM_NONE; 60926947304SEvan Yan 61026947304SEvan Yan /* 61126947304SEvan Yan * construct the slot_name: 61226947304SEvan Yan * if "slot-names" property exists then use that name 61326947304SEvan Yan * else if valid slot number exists then it is "pcie<slot-num>". 61426947304SEvan Yan * else it will be "pcie<sec-bus-number>dev0" 61526947304SEvan Yan */ 61626947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, ctrl_p->hc_dip, DDI_PROP_DONTPASS, 61726947304SEvan Yan "slot-names", (caddr_t)&slotname_data, &len) == DDI_PROP_SUCCESS) { 61826947304SEvan Yan char tmp_name[256]; 61926947304SEvan Yan 62026947304SEvan Yan /* 62126947304SEvan Yan * Note: for PCI-E slots, the device number is always 0 so the 62226947304SEvan Yan * first (and only) string is the slot name for this slot. 62326947304SEvan Yan */ 62426947304SEvan Yan (void) snprintf(tmp_name, sizeof (tmp_name), 62526947304SEvan Yan (char *)slotname_data + 4); 62626947304SEvan Yan slot_p->hs_info.cn_name = ddi_strdup(tmp_name, KM_SLEEP); 62726947304SEvan Yan kmem_free(slotname_data, len); 62826947304SEvan Yan } else { 62926947304SEvan Yan if (invalid_slotnum) { 63026947304SEvan Yan /* use device number ie. 0 */ 63126947304SEvan Yan slot_p->hs_info.cn_name = ddi_strdup("pcie0", 63226947304SEvan Yan KM_SLEEP); 63326947304SEvan Yan } else { 63426947304SEvan Yan char tmp_name[256]; 63526947304SEvan Yan 63626947304SEvan Yan (void) snprintf(tmp_name, sizeof (tmp_name), "pcie%d", 63726947304SEvan Yan slot_p->hs_phy_slot_num); 63826947304SEvan Yan slot_p->hs_info.cn_name = ddi_strdup(tmp_name, 63926947304SEvan Yan KM_SLEEP); 64026947304SEvan Yan } 64126947304SEvan Yan } 64226947304SEvan Yan } 64326947304SEvan Yan 64426947304SEvan Yan /* 64526947304SEvan Yan * Read/Write access to HPC registers. If platform nexus has non-standard 64626947304SEvan Yan * HPC access mechanism then regops functions are used to do reads/writes. 64726947304SEvan Yan */ 64826947304SEvan Yan uint8_t 64926947304SEvan Yan pciehpc_reg_get8(pcie_hp_ctrl_t *ctrl_p, uint_t off) 65026947304SEvan Yan { 65126947304SEvan Yan if (ctrl_p->hc_regops.get != NULL) { 65226947304SEvan Yan return ((uint8_t)ctrl_p->hc_regops.get( 65326947304SEvan Yan ctrl_p->hc_regops.cookie, (off_t)off)); 65426947304SEvan Yan } else { 65526947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 65626947304SEvan Yan 65726947304SEvan Yan return (pci_config_get8(bus_p->bus_cfg_hdl, off)); 65826947304SEvan Yan } 65926947304SEvan Yan } 66026947304SEvan Yan 66126947304SEvan Yan uint16_t 66226947304SEvan Yan pciehpc_reg_get16(pcie_hp_ctrl_t *ctrl_p, uint_t off) 66326947304SEvan Yan { 66426947304SEvan Yan if (ctrl_p->hc_regops.get != NULL) { 66526947304SEvan Yan return ((uint16_t)ctrl_p->hc_regops.get( 66626947304SEvan Yan ctrl_p->hc_regops.cookie, (off_t)off)); 66726947304SEvan Yan } else { 66826947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 66926947304SEvan Yan 67026947304SEvan Yan return (pci_config_get16(bus_p->bus_cfg_hdl, off)); 67126947304SEvan Yan } 67226947304SEvan Yan } 67326947304SEvan Yan 67426947304SEvan Yan uint32_t 67526947304SEvan Yan pciehpc_reg_get32(pcie_hp_ctrl_t *ctrl_p, uint_t off) 67626947304SEvan Yan { 67726947304SEvan Yan if (ctrl_p->hc_regops.get != NULL) { 67826947304SEvan Yan return ((uint32_t)ctrl_p->hc_regops.get( 67926947304SEvan Yan ctrl_p->hc_regops.cookie, (off_t)off)); 68026947304SEvan Yan } else { 68126947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 68226947304SEvan Yan 68326947304SEvan Yan return (pci_config_get32(bus_p->bus_cfg_hdl, off)); 68426947304SEvan Yan } 68526947304SEvan Yan } 68626947304SEvan Yan 68726947304SEvan Yan void 68826947304SEvan Yan pciehpc_reg_put8(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint8_t val) 68926947304SEvan Yan { 69026947304SEvan Yan if (ctrl_p->hc_regops.put != NULL) { 69126947304SEvan Yan ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie, 69226947304SEvan Yan (off_t)off, (uint_t)val); 69326947304SEvan Yan } else { 69426947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 69526947304SEvan Yan 69626947304SEvan Yan pci_config_put8(bus_p->bus_cfg_hdl, off, val); 69726947304SEvan Yan } 69826947304SEvan Yan } 69926947304SEvan Yan 70026947304SEvan Yan void 70126947304SEvan Yan pciehpc_reg_put16(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint16_t val) 70226947304SEvan Yan { 70326947304SEvan Yan if (ctrl_p->hc_regops.put != NULL) { 70426947304SEvan Yan ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie, 70526947304SEvan Yan (off_t)off, (uint_t)val); 70626947304SEvan Yan } else { 70726947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 70826947304SEvan Yan 70926947304SEvan Yan pci_config_put16(bus_p->bus_cfg_hdl, off, val); 71026947304SEvan Yan } 71126947304SEvan Yan } 71226947304SEvan Yan 71326947304SEvan Yan void 71426947304SEvan Yan pciehpc_reg_put32(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint32_t val) 71526947304SEvan Yan { 71626947304SEvan Yan if (ctrl_p->hc_regops.put != NULL) { 71726947304SEvan Yan ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie, 71826947304SEvan Yan (off_t)off, (uint_t)val); 71926947304SEvan Yan } else { 72026947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 72126947304SEvan Yan 72226947304SEvan Yan pci_config_put32(bus_p->bus_cfg_hdl, off, val); 72326947304SEvan Yan } 72426947304SEvan Yan } 72526947304SEvan Yan 72626947304SEvan Yan /* 72726947304SEvan Yan * ************************************************************************ 72826947304SEvan Yan * *** Local functions (called within this file) 72926947304SEvan Yan * *** PCIe Native Hotplug mode specific functions 73026947304SEvan Yan * ************************************************************************ 73126947304SEvan Yan */ 73226947304SEvan Yan 73326947304SEvan Yan /* 73426947304SEvan Yan * Initialize HPC hardware, install interrupt handler, etc. It doesn't 73526947304SEvan Yan * enable hot plug interrupts. 73626947304SEvan Yan * 73726947304SEvan Yan * (Note: It is called only from pciehpc_init().) 73826947304SEvan Yan */ 73926947304SEvan Yan static int 74026947304SEvan Yan pciehpc_hpc_init(pcie_hp_ctrl_t *ctrl_p) 74126947304SEvan Yan { 74226947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 74326947304SEvan Yan uint16_t reg; 74426947304SEvan Yan 74526947304SEvan Yan /* read the Slot Control Register */ 74626947304SEvan Yan reg = pciehpc_reg_get16(ctrl_p, 74726947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL); 74826947304SEvan Yan 74926947304SEvan Yan /* disable all interrupts */ 75026947304SEvan Yan reg &= ~(PCIE_SLOTCTL_INTR_MASK); 75126947304SEvan Yan pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + 75226947304SEvan Yan PCIE_SLOTCTL, reg); 75326947304SEvan Yan 75426947304SEvan Yan /* clear any interrupt status bits */ 75526947304SEvan Yan reg = pciehpc_reg_get16(ctrl_p, 75626947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS); 75726947304SEvan Yan pciehpc_reg_put16(ctrl_p, 75826947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS, reg); 75926947304SEvan Yan 76026947304SEvan Yan return (DDI_SUCCESS); 76126947304SEvan Yan } 76226947304SEvan Yan 76326947304SEvan Yan /* 76426947304SEvan Yan * Uninitialize HPC hardware, uninstall interrupt handler, etc. 76526947304SEvan Yan * 76626947304SEvan Yan * (Note: It is called only from pciehpc_uninit().) 76726947304SEvan Yan */ 76826947304SEvan Yan static int 76926947304SEvan Yan pciehpc_hpc_uninit(pcie_hp_ctrl_t *ctrl_p) 77026947304SEvan Yan { 77126947304SEvan Yan /* disable interrupts */ 77226947304SEvan Yan (void) pciehpc_disable_intr(ctrl_p); 77326947304SEvan Yan 77426947304SEvan Yan return (DDI_SUCCESS); 77526947304SEvan Yan } 77626947304SEvan Yan 77726947304SEvan Yan /* 77826947304SEvan Yan * Setup slot information for use with DDI HP framework. 77926947304SEvan Yan */ 78026947304SEvan Yan static int 78126947304SEvan Yan pciehpc_slotinfo_init(pcie_hp_ctrl_t *ctrl_p) 78226947304SEvan Yan { 78326947304SEvan Yan uint32_t slot_capabilities, link_capabilities; 78426947304SEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; 78526947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 78626947304SEvan Yan 78726947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex); 78826947304SEvan Yan /* 78926947304SEvan Yan * setup DDI HP framework slot information structure 79026947304SEvan Yan */ 79126947304SEvan Yan slot_p->hs_device_num = 0; 79226947304SEvan Yan 79326947304SEvan Yan slot_p->hs_info.cn_type = DDI_HP_CN_TYPE_PCIE; 79426947304SEvan Yan slot_p->hs_info.cn_type_str = (ctrl_p->hc_regops.get == NULL) ? 79526947304SEvan Yan PCIE_NATIVE_HP_TYPE : PCIE_PROP_HP_TYPE; 79626947304SEvan Yan slot_p->hs_info.cn_child = NULL; 79726947304SEvan Yan 79826947304SEvan Yan slot_p->hs_minor = 79926947304SEvan Yan PCI_MINOR_NUM(ddi_get_instance(ctrl_p->hc_dip), 80026947304SEvan Yan slot_p->hs_device_num); 80126947304SEvan Yan slot_p->hs_condition = AP_COND_UNKNOWN; 80226947304SEvan Yan 80326947304SEvan Yan /* read Slot Capabilities Register */ 80426947304SEvan Yan slot_capabilities = pciehpc_reg_get32(ctrl_p, 80526947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCAP); 80626947304SEvan Yan 80726947304SEvan Yan /* set slot-name/slot-number info */ 80826947304SEvan Yan pciehpc_set_slot_name(ctrl_p); 80926947304SEvan Yan 81026947304SEvan Yan /* check if Attn Button present */ 81126947304SEvan Yan ctrl_p->hc_has_attn = (slot_capabilities & PCIE_SLOTCAP_ATTN_BUTTON) ? 81226947304SEvan Yan B_TRUE : B_FALSE; 81326947304SEvan Yan 81426947304SEvan Yan /* check if Manual Retention Latch sensor present */ 81526947304SEvan Yan ctrl_p->hc_has_mrl = (slot_capabilities & PCIE_SLOTCAP_MRL_SENSOR) ? 81626947304SEvan Yan B_TRUE : B_FALSE; 81726947304SEvan Yan 81826947304SEvan Yan /* 81926947304SEvan Yan * PCI-E version 1.1 defines EMI Lock Present bit 82026947304SEvan Yan * in Slot Capabilities register. Check for it. 82126947304SEvan Yan */ 82226947304SEvan Yan ctrl_p->hc_has_emi_lock = (slot_capabilities & 82326947304SEvan Yan PCIE_SLOTCAP_EMI_LOCK_PRESENT) ? B_TRUE : B_FALSE; 82426947304SEvan Yan 82526947304SEvan Yan link_capabilities = pciehpc_reg_get32(ctrl_p, 82626947304SEvan Yan bus_p->bus_pcie_off + PCIE_LINKCAP); 82726947304SEvan Yan ctrl_p->hc_dll_active_rep = (link_capabilities & 82826947304SEvan Yan PCIE_LINKCAP_DLL_ACTIVE_REP_CAPABLE) ? B_TRUE : B_FALSE; 82926947304SEvan Yan if (ctrl_p->hc_dll_active_rep) 83026947304SEvan Yan cv_init(&slot_p->hs_dll_active_cv, NULL, CV_DRIVER, NULL); 83126947304SEvan Yan 83226947304SEvan Yan /* setup thread for handling ATTN button events */ 83326947304SEvan Yan if (ctrl_p->hc_has_attn) { 83426947304SEvan Yan PCIE_DBG("pciehpc_slotinfo_init: setting up ATTN button event " 83526947304SEvan Yan "handler thread for slot %d\n", slot_p->hs_phy_slot_num); 83626947304SEvan Yan 83726947304SEvan Yan cv_init(&slot_p->hs_attn_btn_cv, NULL, CV_DRIVER, NULL); 83826947304SEvan Yan slot_p->hs_attn_btn_pending = B_FALSE; 83926947304SEvan Yan slot_p->hs_attn_btn_threadp = thread_create(NULL, 0, 84026947304SEvan Yan pciehpc_attn_btn_handler, 84126947304SEvan Yan (void *)ctrl_p, 0, &p0, TS_RUN, minclsyspri); 84226947304SEvan Yan slot_p->hs_attn_btn_thread_exit = B_FALSE; 84326947304SEvan Yan } 84426947304SEvan Yan 84526947304SEvan Yan /* get current slot state from the hw */ 84626947304SEvan Yan slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY; 84726947304SEvan Yan pciehpc_get_slot_state(slot_p); 84826947304SEvan Yan if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_ENABLED) 84926947304SEvan Yan slot_p->hs_condition = AP_COND_OK; 85026947304SEvan Yan 85126947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex); 85226947304SEvan Yan 85326947304SEvan Yan return (DDI_SUCCESS); 85426947304SEvan Yan } 85526947304SEvan Yan 85626947304SEvan Yan /*ARGSUSED*/ 85726947304SEvan Yan static int 85826947304SEvan Yan pciehpc_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p) 85926947304SEvan Yan { 86026947304SEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; 86126947304SEvan Yan 86226947304SEvan Yan if (slot_p->hs_attn_btn_threadp != NULL) { 86326947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex); 86426947304SEvan Yan slot_p->hs_attn_btn_thread_exit = B_TRUE; 86526947304SEvan Yan cv_signal(&slot_p->hs_attn_btn_cv); 86626947304SEvan Yan PCIE_DBG("pciehpc_slotinfo_uninit: " 86726947304SEvan Yan "waiting for ATTN thread exit\n"); 86826947304SEvan Yan cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex); 86926947304SEvan Yan PCIE_DBG("pciehpc_slotinfo_uninit: ATTN thread exit\n"); 87026947304SEvan Yan cv_destroy(&slot_p->hs_attn_btn_cv); 87126947304SEvan Yan slot_p->hs_attn_btn_threadp = NULL; 87226947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex); 87326947304SEvan Yan } 87426947304SEvan Yan 87526947304SEvan Yan if (ctrl_p->hc_dll_active_rep) 87626947304SEvan Yan cv_destroy(&slot_p->hs_dll_active_cv); 87726947304SEvan Yan if (slot_p->hs_info.cn_name) 87826947304SEvan Yan kmem_free(slot_p->hs_info.cn_name, 87926947304SEvan Yan strlen(slot_p->hs_info.cn_name) + 1); 88026947304SEvan Yan 88126947304SEvan Yan return (DDI_SUCCESS); 88226947304SEvan Yan } 88326947304SEvan Yan 88426947304SEvan Yan /* 88526947304SEvan Yan * Enable hot plug interrupts. 88626947304SEvan Yan * Note: this is only for Native hot plug mode. 88726947304SEvan Yan */ 88826947304SEvan Yan static int 88926947304SEvan Yan pciehpc_enable_intr(pcie_hp_ctrl_t *ctrl_p) 89026947304SEvan Yan { 89126947304SEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; 89226947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 89326947304SEvan Yan uint16_t reg; 894*fe426563SRick Altherr uint16_t intr_mask = PCIE_SLOTCTL_INTR_MASK; 895*fe426563SRick Altherr 896*fe426563SRick Altherr /* 897*fe426563SRick Altherr * power fault detection interrupt is enabled only 898*fe426563SRick Altherr * when the slot is powered ON 899*fe426563SRick Altherr */ 900*fe426563SRick Altherr if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) 901*fe426563SRick Altherr intr_mask &= ~PCIE_SLOTCTL_PWR_FAULT_EN; 902*fe426563SRick Altherr 903*fe426563SRick Altherr /* 904*fe426563SRick Altherr * enable interrupt sources but leave the top-level 905*fe426563SRick Altherr * interrupt disabled. some sources may generate a 906*fe426563SRick Altherr * spurrious event when they are first enabled. 907*fe426563SRick Altherr * by leaving the top-level interrupt disabled, those 908*fe426563SRick Altherr * can be cleared first. 909*fe426563SRick Altherr */ 910*fe426563SRick Altherr reg = pciehpc_reg_get16(ctrl_p, 911*fe426563SRick Altherr bus_p->bus_pcie_off + PCIE_SLOTCTL); 912*fe426563SRick Altherr pciehpc_reg_put16(ctrl_p, 913*fe426563SRick Altherr bus_p->bus_pcie_off + PCIE_SLOTCTL, 914*fe426563SRick Altherr reg | (intr_mask & ~PCIE_SLOTCTL_HP_INTR_EN)); 91526947304SEvan Yan 91626947304SEvan Yan /* clear any interrupt status bits */ 91726947304SEvan Yan reg = pciehpc_reg_get16(ctrl_p, 91826947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS); 91926947304SEvan Yan pciehpc_reg_put16(ctrl_p, 92026947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS, reg); 92126947304SEvan Yan 922*fe426563SRick Altherr /* enable top-level interrupt */ 92326947304SEvan Yan reg = pciehpc_reg_get16(ctrl_p, 92426947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL); 925*fe426563SRick Altherr pciehpc_reg_put16(ctrl_p, 926*fe426563SRick Altherr bus_p->bus_pcie_off + PCIE_SLOTCTL, 927*fe426563SRick Altherr reg | intr_mask); 92826947304SEvan Yan 92926947304SEvan Yan return (DDI_SUCCESS); 93026947304SEvan Yan } 93126947304SEvan Yan 93226947304SEvan Yan /* 93326947304SEvan Yan * Disable hot plug interrupts. 93426947304SEvan Yan * Note: this is only for Native hot plug mode. 93526947304SEvan Yan */ 93626947304SEvan Yan static int 93726947304SEvan Yan pciehpc_disable_intr(pcie_hp_ctrl_t *ctrl_p) 93826947304SEvan Yan { 93926947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 94026947304SEvan Yan uint16_t reg; 94126947304SEvan Yan 94226947304SEvan Yan /* read the Slot Control Register */ 94326947304SEvan Yan reg = pciehpc_reg_get16(ctrl_p, 94426947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL); 94526947304SEvan Yan 94626947304SEvan Yan /* disable all interrupts */ 94726947304SEvan Yan reg &= ~(PCIE_SLOTCTL_INTR_MASK); 94826947304SEvan Yan pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTCTL, reg); 94926947304SEvan Yan 95026947304SEvan Yan /* clear any interrupt status bits */ 95126947304SEvan Yan reg = pciehpc_reg_get16(ctrl_p, 95226947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS); 95326947304SEvan Yan pciehpc_reg_put16(ctrl_p, 95426947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS, reg); 95526947304SEvan Yan 95626947304SEvan Yan return (DDI_SUCCESS); 95726947304SEvan Yan } 95826947304SEvan Yan 95926947304SEvan Yan /* 96026947304SEvan Yan * Allocate a new hotplug controller and slot structures for HPC 96126947304SEvan Yan * associated with this dip. 96226947304SEvan Yan */ 96326947304SEvan Yan static pcie_hp_ctrl_t * 96426947304SEvan Yan pciehpc_create_controller(dev_info_t *dip) 96526947304SEvan Yan { 96626947304SEvan Yan pcie_hp_ctrl_t *ctrl_p; 96726947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 96826947304SEvan Yan 96926947304SEvan Yan ctrl_p = kmem_zalloc(sizeof (pcie_hp_ctrl_t), KM_SLEEP); 97026947304SEvan Yan ctrl_p->hc_dip = dip; 97126947304SEvan Yan 97226947304SEvan Yan /* Allocate a new slot structure. */ 97326947304SEvan Yan ctrl_p->hc_slots[0] = kmem_zalloc(sizeof (pcie_hp_slot_t), KM_SLEEP); 97426947304SEvan Yan ctrl_p->hc_slots[0]->hs_num = 0; 97526947304SEvan Yan ctrl_p->hc_slots[0]->hs_ctrl = ctrl_p; 97626947304SEvan Yan 97726947304SEvan Yan /* Initialize the interrupt mutex */ 97826947304SEvan Yan mutex_init(&ctrl_p->hc_mutex, NULL, MUTEX_DRIVER, 97926947304SEvan Yan (void *)PCIE_INTR_PRI); 98026947304SEvan Yan 98126947304SEvan Yan /* Initialize synchronization conditional variable */ 98226947304SEvan Yan cv_init(&ctrl_p->hc_cmd_comp_cv, NULL, CV_DRIVER, NULL); 98326947304SEvan Yan ctrl_p->hc_cmd_pending = B_FALSE; 98426947304SEvan Yan 98526947304SEvan Yan bus_p->bus_hp_curr_mode = PCIE_NATIVE_HP_MODE; 98626947304SEvan Yan PCIE_SET_HP_CTRL(dip, ctrl_p); 98726947304SEvan Yan 98826947304SEvan Yan return (ctrl_p); 98926947304SEvan Yan } 99026947304SEvan Yan 99126947304SEvan Yan /* 99226947304SEvan Yan * Remove the HPC controller and slot structures 99326947304SEvan Yan */ 99426947304SEvan Yan static void 99526947304SEvan Yan pciehpc_destroy_controller(dev_info_t *dip) 99626947304SEvan Yan { 99726947304SEvan Yan pcie_hp_ctrl_t *ctrl_p; 99826947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 99926947304SEvan Yan 100026947304SEvan Yan /* get the soft state structure for this dip */ 100126947304SEvan Yan if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) 100226947304SEvan Yan return; 100326947304SEvan Yan 100426947304SEvan Yan PCIE_SET_HP_CTRL(dip, NULL); 100526947304SEvan Yan bus_p->bus_hp_curr_mode = PCIE_NONE_HP_MODE; 100626947304SEvan Yan 100726947304SEvan Yan mutex_destroy(&ctrl_p->hc_mutex); 100826947304SEvan Yan cv_destroy(&ctrl_p->hc_cmd_comp_cv); 100926947304SEvan Yan kmem_free(ctrl_p->hc_slots[0], sizeof (pcie_hp_slot_t)); 101026947304SEvan Yan kmem_free(ctrl_p, sizeof (pcie_hp_ctrl_t)); 101126947304SEvan Yan } 101226947304SEvan Yan 101326947304SEvan Yan /* 101426947304SEvan Yan * Register the PCI-E hot plug slot with DDI HP framework. 101526947304SEvan Yan */ 101626947304SEvan Yan static int 101726947304SEvan Yan pciehpc_register_slot(pcie_hp_ctrl_t *ctrl_p) 101826947304SEvan Yan { 101926947304SEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; 102026947304SEvan Yan dev_info_t *dip = ctrl_p->hc_dip; 102126947304SEvan Yan 102226947304SEvan Yan /* register the slot with DDI HP framework */ 102326947304SEvan Yan if (ndi_hp_register(dip, &slot_p->hs_info) != NDI_SUCCESS) { 102426947304SEvan Yan PCIE_DBG("pciehpc_register_slot() failed to register slot %d\n", 102526947304SEvan Yan slot_p->hs_phy_slot_num); 102626947304SEvan Yan return (DDI_FAILURE); 102726947304SEvan Yan } 102826947304SEvan Yan 102926947304SEvan Yan pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip), 103026947304SEvan Yan slot_p->hs_minor), slot_p->hs_device_num); 103126947304SEvan Yan 103226947304SEvan Yan PCIE_DBG("pciehpc_register_slot(): registered slot %d\n", 103326947304SEvan Yan slot_p->hs_phy_slot_num); 103426947304SEvan Yan 103526947304SEvan Yan return (DDI_SUCCESS); 103626947304SEvan Yan } 103726947304SEvan Yan 103826947304SEvan Yan /* 103926947304SEvan Yan * Unregister the PCI-E hot plug slot from DDI HP framework. 104026947304SEvan Yan */ 104126947304SEvan Yan static int 104226947304SEvan Yan pciehpc_unregister_slot(pcie_hp_ctrl_t *ctrl_p) 104326947304SEvan Yan { 104426947304SEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; 104526947304SEvan Yan dev_info_t *dip = ctrl_p->hc_dip; 104626947304SEvan Yan 104726947304SEvan Yan pcie_hp_delete_occupant_props(dip, makedevice(ddi_driver_major(dip), 104826947304SEvan Yan slot_p->hs_minor)); 104926947304SEvan Yan 105026947304SEvan Yan /* unregister the slot with DDI HP framework */ 105126947304SEvan Yan if (ndi_hp_unregister(dip, slot_p->hs_info.cn_name) != NDI_SUCCESS) { 105226947304SEvan Yan PCIE_DBG("pciehpc_unregister_slot() " 105326947304SEvan Yan "failed to unregister slot %d\n", slot_p->hs_phy_slot_num); 105426947304SEvan Yan return (DDI_FAILURE); 105526947304SEvan Yan } 105626947304SEvan Yan 105726947304SEvan Yan PCIE_DBG("pciehpc_unregister_slot(): unregistered slot %d\n", 105826947304SEvan Yan slot_p->hs_phy_slot_num); 105926947304SEvan Yan 106026947304SEvan Yan return (DDI_SUCCESS); 106126947304SEvan Yan } 106226947304SEvan Yan 106326947304SEvan Yan /* 106426947304SEvan Yan * pciehpc_slot_poweron() 106526947304SEvan Yan * 106626947304SEvan Yan * Poweron/Enable the slot. 106726947304SEvan Yan * 106826947304SEvan Yan * Note: This function is called by DDI HP framework at kernel context only 106926947304SEvan Yan */ 107026947304SEvan Yan /*ARGSUSED*/ 107126947304SEvan Yan static int 107226947304SEvan Yan pciehpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result) 107326947304SEvan Yan { 107426947304SEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; 107526947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 107626947304SEvan Yan uint16_t status, control; 107726947304SEvan Yan 107826947304SEvan Yan ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex)); 107926947304SEvan Yan 108026947304SEvan Yan /* get the current state of the slot */ 108126947304SEvan Yan pciehpc_get_slot_state(slot_p); 108226947304SEvan Yan 108326947304SEvan Yan /* check if the slot is already in the 'enabled' state */ 108426947304SEvan Yan if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) { 108526947304SEvan Yan /* slot is already in the 'enabled' state */ 108626947304SEvan Yan PCIE_DBG("pciehpc_slot_poweron() slot %d already enabled\n", 108726947304SEvan Yan slot_p->hs_phy_slot_num); 108826947304SEvan Yan 108926947304SEvan Yan *result = slot_p->hs_info.cn_state; 109026947304SEvan Yan return (DDI_SUCCESS); 109126947304SEvan Yan } 109226947304SEvan Yan 109326947304SEvan Yan /* read the Slot Status Register */ 109426947304SEvan Yan status = pciehpc_reg_get16(ctrl_p, 109526947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS); 109626947304SEvan Yan 109726947304SEvan Yan /* make sure the MRL switch is closed if present */ 109826947304SEvan Yan if ((ctrl_p->hc_has_mrl) && (status & PCIE_SLOTSTS_MRL_SENSOR_OPEN)) { 109926947304SEvan Yan /* MRL switch is open */ 110026947304SEvan Yan cmn_err(CE_WARN, "MRL switch is open on slot %d\n", 110126947304SEvan Yan slot_p->hs_phy_slot_num); 110226947304SEvan Yan goto cleanup; 110326947304SEvan Yan } 110426947304SEvan Yan 110526947304SEvan Yan /* make sure the slot has a device present */ 110626947304SEvan Yan if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) { 110726947304SEvan Yan /* slot is empty */ 110826947304SEvan Yan PCIE_DBG("slot %d is empty\n", slot_p->hs_phy_slot_num); 110926947304SEvan Yan goto cleanup; 111026947304SEvan Yan } 111126947304SEvan Yan 111226947304SEvan Yan /* get the current state of Slot Control Register */ 111326947304SEvan Yan control = pciehpc_reg_get16(ctrl_p, 111426947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL); 111526947304SEvan Yan 111626947304SEvan Yan /* 111726947304SEvan Yan * Enable power to the slot involves: 111826947304SEvan Yan * 1. Set power LED to blink and ATTN led to OFF. 111926947304SEvan Yan * 2. Set power control ON in Slot Control Reigster and 112026947304SEvan Yan * wait for Command Completed Interrupt or 1 sec timeout. 112126947304SEvan Yan * 3. If Data Link Layer State Changed events are supported 112226947304SEvan Yan * then wait for the event to indicate Data Layer Link 112326947304SEvan Yan * is active. The time out value for this event is 1 second. 112426947304SEvan Yan * This is specified in PCI-E version 1.1. 112526947304SEvan Yan * 4. Set power LED to be ON. 112626947304SEvan Yan */ 112726947304SEvan Yan 112826947304SEvan Yan /* 1. set power LED to blink & ATTN led to OFF */ 112926947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK); 113026947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF); 113126947304SEvan Yan 113226947304SEvan Yan /* 2. set power control to ON */ 113326947304SEvan Yan control = pciehpc_reg_get16(ctrl_p, 113426947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL); 113526947304SEvan Yan control &= ~PCIE_SLOTCTL_PWR_CONTROL; 113626947304SEvan Yan pciehpc_issue_hpc_command(ctrl_p, control); 113726947304SEvan Yan 113826947304SEvan Yan /* 3. wait for DLL State Change event, if it's supported */ 113926947304SEvan Yan if (ctrl_p->hc_dll_active_rep) { 114026947304SEvan Yan status = pciehpc_reg_get16(ctrl_p, 114126947304SEvan Yan bus_p->bus_pcie_off + PCIE_LINKSTS); 114226947304SEvan Yan 114326947304SEvan Yan if (!(status & PCIE_LINKSTS_DLL_LINK_ACTIVE)) { 114426947304SEvan Yan /* wait 1 sec for the DLL State Changed event */ 114526947304SEvan Yan (void) cv_timedwait(&slot_p->hs_dll_active_cv, 114626947304SEvan Yan &ctrl_p->hc_mutex, 114726947304SEvan Yan ddi_get_lbolt() + 114826947304SEvan Yan SEC_TO_TICK(PCIE_HP_DLL_STATE_CHANGE_TIMEOUT)); 114926947304SEvan Yan 115026947304SEvan Yan /* check Link status */ 115126947304SEvan Yan status = pciehpc_reg_get16(ctrl_p, 115226947304SEvan Yan bus_p->bus_pcie_off + 115326947304SEvan Yan PCIE_LINKSTS); 115426947304SEvan Yan if (!(status & PCIE_LINKSTS_DLL_LINK_ACTIVE)) 115526947304SEvan Yan goto cleanup2; 115626947304SEvan Yan } 115726947304SEvan Yan } 115826947304SEvan Yan 115926947304SEvan Yan /* wait 1 sec for link to come up */ 116026947304SEvan Yan delay(drv_usectohz(1000000)); 116126947304SEvan Yan 116226947304SEvan Yan /* check power is really turned ON */ 116326947304SEvan Yan control = pciehpc_reg_get16(ctrl_p, 116426947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL); 116526947304SEvan Yan 116626947304SEvan Yan if (control & PCIE_SLOTCTL_PWR_CONTROL) { 116726947304SEvan Yan PCIE_DBG("slot %d fails to turn on power on connect\n", 116826947304SEvan Yan slot_p->hs_phy_slot_num); 116926947304SEvan Yan 117026947304SEvan Yan goto cleanup1; 117126947304SEvan Yan } 117226947304SEvan Yan 117326947304SEvan Yan /* clear power fault status */ 117426947304SEvan Yan status = pciehpc_reg_get16(ctrl_p, 117526947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS); 117626947304SEvan Yan status |= PCIE_SLOTSTS_PWR_FAULT_DETECTED; 117726947304SEvan Yan pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTSTS, 117826947304SEvan Yan status); 117926947304SEvan Yan 118026947304SEvan Yan /* enable power fault detection interrupt */ 118126947304SEvan Yan control |= PCIE_SLOTCTL_PWR_FAULT_EN; 118226947304SEvan Yan pciehpc_issue_hpc_command(ctrl_p, control); 118326947304SEvan Yan 118426947304SEvan Yan /* 4. Set power LED to be ON */ 118526947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_ON); 118626947304SEvan Yan 118726947304SEvan Yan /* if EMI is present, turn it ON */ 118826947304SEvan Yan if (ctrl_p->hc_has_emi_lock) { 118926947304SEvan Yan status = pciehpc_reg_get16(ctrl_p, 119026947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS); 119126947304SEvan Yan 119226947304SEvan Yan if (!(status & PCIE_SLOTSTS_EMI_LOCK_SET)) { 119326947304SEvan Yan control = pciehpc_reg_get16(ctrl_p, 119426947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL); 119526947304SEvan Yan control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL; 119626947304SEvan Yan pciehpc_issue_hpc_command(ctrl_p, control); 119726947304SEvan Yan 119826947304SEvan Yan /* wait 1 sec after toggling the state of EMI lock */ 119926947304SEvan Yan delay(drv_usectohz(1000000)); 120026947304SEvan Yan } 120126947304SEvan Yan } 120226947304SEvan Yan 120326947304SEvan Yan *result = slot_p->hs_info.cn_state = 120426947304SEvan Yan DDI_HP_CN_STATE_POWERED; 120526947304SEvan Yan 120626947304SEvan Yan return (DDI_SUCCESS); 120726947304SEvan Yan 120826947304SEvan Yan cleanup2: 120926947304SEvan Yan control = pciehpc_reg_get16(ctrl_p, 121026947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL); 121126947304SEvan Yan 121226947304SEvan Yan /* if power is ON, set power control to OFF */ 121326947304SEvan Yan if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) { 121426947304SEvan Yan control |= PCIE_SLOTCTL_PWR_CONTROL; 121526947304SEvan Yan pciehpc_issue_hpc_command(ctrl_p, control); 121626947304SEvan Yan } 121726947304SEvan Yan 121826947304SEvan Yan cleanup1: 121926947304SEvan Yan /* set power led to OFF */ 122026947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF); 122126947304SEvan Yan 122226947304SEvan Yan cleanup: 122326947304SEvan Yan return (DDI_FAILURE); 122426947304SEvan Yan } 122526947304SEvan Yan 122626947304SEvan Yan /*ARGSUSED*/ 122726947304SEvan Yan static int 122826947304SEvan Yan pciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result) 122926947304SEvan Yan { 123026947304SEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; 123126947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 123226947304SEvan Yan uint16_t status, control; 123326947304SEvan Yan 123426947304SEvan Yan ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex)); 123526947304SEvan Yan 123626947304SEvan Yan /* get the current state of the slot */ 123726947304SEvan Yan pciehpc_get_slot_state(slot_p); 123826947304SEvan Yan 123926947304SEvan Yan /* check if the slot is not in the "enabled' state */ 124026947304SEvan Yan if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) { 124126947304SEvan Yan /* slot is in the 'disabled' state */ 124226947304SEvan Yan PCIE_DBG("pciehpc_slot_poweroff(): " 124326947304SEvan Yan "slot %d already disabled\n", slot_p->hs_phy_slot_num); 124426947304SEvan Yan ASSERT(slot_p->hs_power_led_state == PCIE_HP_LED_OFF); 124526947304SEvan Yan 124626947304SEvan Yan *result = slot_p->hs_info.cn_state; 124726947304SEvan Yan return (DDI_SUCCESS); 124826947304SEvan Yan } 124926947304SEvan Yan 125026947304SEvan Yan /* read the Slot Status Register */ 125126947304SEvan Yan status = pciehpc_reg_get16(ctrl_p, 125226947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS); 125326947304SEvan Yan 125426947304SEvan Yan /* make sure the slot has a device present */ 125526947304SEvan Yan if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) { 125626947304SEvan Yan /* slot is empty */ 125726947304SEvan Yan PCIE_DBG("pciehpc_slot_poweroff(): slot %d is empty\n", 125826947304SEvan Yan slot_p->hs_phy_slot_num); 125926947304SEvan Yan goto cleanup; 126026947304SEvan Yan } 126126947304SEvan Yan 126226947304SEvan Yan /* 126326947304SEvan Yan * Disable power to the slot involves: 126426947304SEvan Yan * 1. Set power LED to blink. 126526947304SEvan Yan * 2. Set power control OFF in Slot Control Reigster and 126626947304SEvan Yan * wait for Command Completed Interrupt or 1 sec timeout. 126726947304SEvan Yan * 3. Set POWER led and ATTN led to be OFF. 126826947304SEvan Yan */ 126926947304SEvan Yan 127026947304SEvan Yan /* 1. set power LED to blink */ 127126947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK); 127226947304SEvan Yan 127326947304SEvan Yan /* disable power fault detection interrupt */ 127426947304SEvan Yan control = pciehpc_reg_get16(ctrl_p, 127526947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL); 127626947304SEvan Yan control &= ~PCIE_SLOTCTL_PWR_FAULT_EN; 127726947304SEvan Yan pciehpc_issue_hpc_command(ctrl_p, control); 127826947304SEvan Yan 127926947304SEvan Yan /* 2. set power control to OFF */ 128026947304SEvan Yan control = pciehpc_reg_get16(ctrl_p, 128126947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL); 128226947304SEvan Yan control |= PCIE_SLOTCTL_PWR_CONTROL; 128326947304SEvan Yan pciehpc_issue_hpc_command(ctrl_p, control); 128426947304SEvan Yan 128526947304SEvan Yan #ifdef DEBUG 128626947304SEvan Yan /* check for power control bit to be OFF */ 128726947304SEvan Yan control = pciehpc_reg_get16(ctrl_p, 128826947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL); 128926947304SEvan Yan ASSERT(control & PCIE_SLOTCTL_PWR_CONTROL); 129026947304SEvan Yan #endif 129126947304SEvan Yan 129226947304SEvan Yan /* 3. Set power LED to be OFF */ 129326947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF); 129426947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF); 129526947304SEvan Yan 129626947304SEvan Yan /* if EMI is present, turn it OFF */ 129726947304SEvan Yan if (ctrl_p->hc_has_emi_lock) { 129826947304SEvan Yan status = pciehpc_reg_get16(ctrl_p, 129926947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS); 130026947304SEvan Yan 130126947304SEvan Yan if (status & PCIE_SLOTSTS_EMI_LOCK_SET) { 130226947304SEvan Yan control = pciehpc_reg_get16(ctrl_p, 130326947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL); 130426947304SEvan Yan control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL; 130526947304SEvan Yan pciehpc_issue_hpc_command(ctrl_p, control); 130626947304SEvan Yan 130726947304SEvan Yan /* wait 1 sec after toggling the state of EMI lock */ 130826947304SEvan Yan delay(drv_usectohz(1000000)); 130926947304SEvan Yan } 131026947304SEvan Yan } 131126947304SEvan Yan 131226947304SEvan Yan /* get the current state of the slot */ 131326947304SEvan Yan pciehpc_get_slot_state(slot_p); 131426947304SEvan Yan 131526947304SEvan Yan *result = slot_p->hs_info.cn_state; 131626947304SEvan Yan 131726947304SEvan Yan return (DDI_SUCCESS); 131826947304SEvan Yan 131926947304SEvan Yan cleanup: 132026947304SEvan Yan return (DDI_FAILURE); 132126947304SEvan Yan } 132226947304SEvan Yan 132326947304SEvan Yan /* 132426947304SEvan Yan * pciehpc_slot_probe() 132526947304SEvan Yan * 132626947304SEvan Yan * Probe the slot. 132726947304SEvan Yan * 132826947304SEvan Yan * Note: This function is called by DDI HP framework at kernel context only 132926947304SEvan Yan */ 133026947304SEvan Yan /*ARGSUSED*/ 133126947304SEvan Yan static int 133226947304SEvan Yan pciehpc_slot_probe(pcie_hp_slot_t *slot_p) 133326947304SEvan Yan { 133426947304SEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; 133526947304SEvan Yan int ret = DDI_SUCCESS; 133626947304SEvan Yan 133726947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex); 133826947304SEvan Yan 133926947304SEvan Yan /* get the current state of the slot */ 134026947304SEvan Yan pciehpc_get_slot_state(slot_p); 134126947304SEvan Yan 134226947304SEvan Yan /* 134326947304SEvan Yan * Probe a given PCIe Hotplug Connection (CN). 134426947304SEvan Yan */ 134526947304SEvan Yan PCIE_DISABLE_ERRORS(ctrl_p->hc_dip); 134626947304SEvan Yan ret = pcie_hp_probe(slot_p); 134726947304SEvan Yan 134826947304SEvan Yan if (ret != DDI_SUCCESS) { 134926947304SEvan Yan PCIE_DBG("pciehpc_slot_probe() failed\n"); 135026947304SEvan Yan 135126947304SEvan Yan /* turn the ATTN led ON for configure failure */ 135226947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_ON); 135326947304SEvan Yan 135426947304SEvan Yan /* if power to the slot is still on then set Power led to ON */ 135526947304SEvan Yan if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) 135626947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, 135726947304SEvan Yan PCIE_HP_LED_ON); 135826947304SEvan Yan 135926947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex); 136026947304SEvan Yan return (DDI_FAILURE); 136126947304SEvan Yan } 136226947304SEvan Yan 136326947304SEvan Yan PCIE_ENABLE_ERRORS(ctrl_p->hc_dip); 136426947304SEvan Yan 136526947304SEvan Yan /* get the current state of the slot */ 136626947304SEvan Yan pciehpc_get_slot_state(slot_p); 136726947304SEvan Yan 136826947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex); 136926947304SEvan Yan return (DDI_SUCCESS); 137026947304SEvan Yan } 137126947304SEvan Yan 137226947304SEvan Yan /* 137326947304SEvan Yan * pciehpc_slot_unprobe() 137426947304SEvan Yan * 137526947304SEvan Yan * Unprobe the slot. 137626947304SEvan Yan * 137726947304SEvan Yan * Note: This function is called by DDI HP framework at kernel context only 137826947304SEvan Yan */ 137926947304SEvan Yan /*ARGSUSED*/ 138026947304SEvan Yan static int 138126947304SEvan Yan pciehpc_slot_unprobe(pcie_hp_slot_t *slot_p) 138226947304SEvan Yan { 138326947304SEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; 138426947304SEvan Yan int ret; 138526947304SEvan Yan 138626947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex); 138726947304SEvan Yan 138826947304SEvan Yan /* get the current state of the slot */ 138926947304SEvan Yan pciehpc_get_slot_state(slot_p); 139026947304SEvan Yan 139126947304SEvan Yan /* 139226947304SEvan Yan * Unprobe a given PCIe Hotplug Connection (CN). 139326947304SEvan Yan */ 139426947304SEvan Yan PCIE_DISABLE_ERRORS(ctrl_p->hc_dip); 139526947304SEvan Yan ret = pcie_hp_unprobe(slot_p); 139626947304SEvan Yan 139726947304SEvan Yan if (ret != DDI_SUCCESS) { 139826947304SEvan Yan PCIE_DBG("pciehpc_slot_unprobe() failed\n"); 139926947304SEvan Yan 140026947304SEvan Yan /* if power to the slot is still on then set Power led to ON */ 140126947304SEvan Yan if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) 140226947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, 140326947304SEvan Yan PCIE_HP_LED_ON); 140426947304SEvan Yan 140526947304SEvan Yan PCIE_ENABLE_ERRORS(ctrl_p->hc_dip); 140626947304SEvan Yan 140726947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex); 140826947304SEvan Yan return (DDI_FAILURE); 140926947304SEvan Yan } 141026947304SEvan Yan 141126947304SEvan Yan /* get the current state of the slot */ 141226947304SEvan Yan pciehpc_get_slot_state(slot_p); 141326947304SEvan Yan 141426947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex); 141526947304SEvan Yan return (DDI_SUCCESS); 141626947304SEvan Yan } 141726947304SEvan Yan 141826947304SEvan Yan static int 141926947304SEvan Yan pciehpc_upgrade_slot_state(pcie_hp_slot_t *slot_p, 142026947304SEvan Yan ddi_hp_cn_state_t target_state) 142126947304SEvan Yan { 142226947304SEvan Yan ddi_hp_cn_state_t curr_state; 142326947304SEvan Yan int rv = DDI_SUCCESS; 142426947304SEvan Yan 142526947304SEvan Yan if (target_state > DDI_HP_CN_STATE_ENABLED) { 142626947304SEvan Yan return (DDI_EINVAL); 142726947304SEvan Yan } 142826947304SEvan Yan 142926947304SEvan Yan curr_state = slot_p->hs_info.cn_state; 143026947304SEvan Yan while ((curr_state < target_state) && (rv == DDI_SUCCESS)) { 143126947304SEvan Yan 143226947304SEvan Yan switch (curr_state) { 143326947304SEvan Yan case DDI_HP_CN_STATE_EMPTY: 143426947304SEvan Yan /* 143526947304SEvan Yan * From EMPTY to PRESENT, just check the hardware 143626947304SEvan Yan * slot state. 143726947304SEvan Yan */ 143826947304SEvan Yan pciehpc_get_slot_state(slot_p); 143926947304SEvan Yan curr_state = slot_p->hs_info.cn_state; 144026947304SEvan Yan if (curr_state < DDI_HP_CN_STATE_PRESENT) 144126947304SEvan Yan rv = DDI_FAILURE; 144226947304SEvan Yan break; 144326947304SEvan Yan case DDI_HP_CN_STATE_PRESENT: 144426947304SEvan Yan rv = (slot_p->hs_ctrl->hc_ops.poweron_hpc_slot)(slot_p, 144526947304SEvan Yan &curr_state); 144626947304SEvan Yan 144726947304SEvan Yan break; 144826947304SEvan Yan case DDI_HP_CN_STATE_POWERED: 144926947304SEvan Yan curr_state = slot_p->hs_info.cn_state = 145026947304SEvan Yan DDI_HP_CN_STATE_ENABLED; 145126947304SEvan Yan break; 145226947304SEvan Yan default: 145326947304SEvan Yan /* should never reach here */ 145426947304SEvan Yan ASSERT("unknown devinfo state"); 145526947304SEvan Yan } 145626947304SEvan Yan } 145726947304SEvan Yan 145826947304SEvan Yan return (rv); 145926947304SEvan Yan } 146026947304SEvan Yan 146126947304SEvan Yan static int 146226947304SEvan Yan pciehpc_downgrade_slot_state(pcie_hp_slot_t *slot_p, 146326947304SEvan Yan ddi_hp_cn_state_t target_state) 146426947304SEvan Yan { 146526947304SEvan Yan ddi_hp_cn_state_t curr_state; 146626947304SEvan Yan int rv = DDI_SUCCESS; 146726947304SEvan Yan 146826947304SEvan Yan 146926947304SEvan Yan curr_state = slot_p->hs_info.cn_state; 147026947304SEvan Yan while ((curr_state > target_state) && (rv == DDI_SUCCESS)) { 147126947304SEvan Yan 147226947304SEvan Yan switch (curr_state) { 147326947304SEvan Yan case DDI_HP_CN_STATE_PRESENT: 147426947304SEvan Yan /* 147526947304SEvan Yan * From PRESENT to EMPTY, just check hardware slot 147626947304SEvan Yan * state. 147726947304SEvan Yan */ 147826947304SEvan Yan pciehpc_get_slot_state(slot_p); 147926947304SEvan Yan curr_state = slot_p->hs_info.cn_state; 148026947304SEvan Yan if (curr_state >= DDI_HP_CN_STATE_PRESENT) 148126947304SEvan Yan rv = DDI_FAILURE; 148226947304SEvan Yan break; 148326947304SEvan Yan case DDI_HP_CN_STATE_POWERED: 148426947304SEvan Yan rv = (slot_p->hs_ctrl->hc_ops.poweroff_hpc_slot)( 148526947304SEvan Yan slot_p, &curr_state); 148626947304SEvan Yan 148726947304SEvan Yan break; 148826947304SEvan Yan case DDI_HP_CN_STATE_ENABLED: 148926947304SEvan Yan curr_state = slot_p->hs_info.cn_state = 149026947304SEvan Yan DDI_HP_CN_STATE_POWERED; 149126947304SEvan Yan 149226947304SEvan Yan break; 149326947304SEvan Yan default: 149426947304SEvan Yan /* should never reach here */ 149526947304SEvan Yan ASSERT("unknown devinfo state"); 149626947304SEvan Yan } 149726947304SEvan Yan } 149826947304SEvan Yan 149926947304SEvan Yan return (rv); 150026947304SEvan Yan } 150126947304SEvan Yan 150226947304SEvan Yan /* Change slot state to a target state */ 150326947304SEvan Yan static int 150426947304SEvan Yan pciehpc_change_slot_state(pcie_hp_slot_t *slot_p, 150526947304SEvan Yan ddi_hp_cn_state_t target_state) 150626947304SEvan Yan { 150726947304SEvan Yan ddi_hp_cn_state_t curr_state; 150826947304SEvan Yan int rv; 150926947304SEvan Yan 151026947304SEvan Yan pciehpc_get_slot_state(slot_p); 151126947304SEvan Yan curr_state = slot_p->hs_info.cn_state; 151226947304SEvan Yan 151326947304SEvan Yan if (curr_state == target_state) { 151426947304SEvan Yan return (DDI_SUCCESS); 151526947304SEvan Yan } 151626947304SEvan Yan if (curr_state < target_state) { 151726947304SEvan Yan 151826947304SEvan Yan rv = pciehpc_upgrade_slot_state(slot_p, target_state); 151926947304SEvan Yan } else { 152026947304SEvan Yan rv = pciehpc_downgrade_slot_state(slot_p, target_state); 152126947304SEvan Yan } 152226947304SEvan Yan 152326947304SEvan Yan return (rv); 152426947304SEvan Yan } 152526947304SEvan Yan 152626947304SEvan Yan int 152726947304SEvan Yan pciehpc_slot_get_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg, 152826947304SEvan Yan ddi_hp_property_t *rval) 152926947304SEvan Yan { 153026947304SEvan Yan ddi_hp_property_t request, result; 153126947304SEvan Yan #ifdef _SYSCALL32_IMPL 153226947304SEvan Yan ddi_hp_property32_t request32, result32; 153326947304SEvan Yan #endif 153426947304SEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; 153526947304SEvan Yan nvlist_t *prop_list; 153626947304SEvan Yan nvlist_t *prop_rlist; /* nvlist for return values */ 153726947304SEvan Yan nvpair_t *prop_pair; 153826947304SEvan Yan char *name, *value; 153926947304SEvan Yan int ret = DDI_SUCCESS; 154026947304SEvan Yan int i, n; 154126947304SEvan Yan boolean_t get_all_prop = B_FALSE; 154226947304SEvan Yan 154326947304SEvan Yan if (get_udatamodel() == DATAMODEL_NATIVE) { 154426947304SEvan Yan if (copyin(arg, &request, sizeof (ddi_hp_property_t)) || 154526947304SEvan Yan copyin(rval, &result, sizeof (ddi_hp_property_t))) 154626947304SEvan Yan return (DDI_FAILURE); 154726947304SEvan Yan } 154826947304SEvan Yan #ifdef _SYSCALL32_IMPL 154926947304SEvan Yan else { 155026947304SEvan Yan bzero(&request, sizeof (request)); 155126947304SEvan Yan bzero(&result, sizeof (result)); 155226947304SEvan Yan if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)) || 155326947304SEvan Yan copyin(rval, &result32, sizeof (ddi_hp_property32_t))) 155426947304SEvan Yan return (DDI_FAILURE); 155526947304SEvan Yan request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf; 155626947304SEvan Yan request.buf_size = request32.buf_size; 155726947304SEvan Yan result.nvlist_buf = (char *)(uintptr_t)result32.nvlist_buf; 155826947304SEvan Yan result.buf_size = result32.buf_size; 155926947304SEvan Yan } 156026947304SEvan Yan #endif 156126947304SEvan Yan 156226947304SEvan Yan if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size, 156326947304SEvan Yan &prop_list)) != DDI_SUCCESS) 156426947304SEvan Yan return (ret); 156526947304SEvan Yan 156626947304SEvan Yan if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) { 156726947304SEvan Yan ret = DDI_ENOMEM; 156826947304SEvan Yan goto get_prop_cleanup; 156926947304SEvan Yan } 157026947304SEvan Yan 157126947304SEvan Yan /* check whether the requested property is "all" or "help" */ 157226947304SEvan Yan prop_pair = nvlist_next_nvpair(prop_list, NULL); 157326947304SEvan Yan if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair)) { 157426947304SEvan Yan name = nvpair_name(prop_pair); 157526947304SEvan Yan n = sizeof (pciehpc_props) / sizeof (pciehpc_prop_t); 157626947304SEvan Yan 157726947304SEvan Yan if (strcmp(name, PCIEHPC_PROP_ALL) == 0) { 157826947304SEvan Yan (void) nvlist_remove_all(prop_list, PCIEHPC_PROP_ALL); 157926947304SEvan Yan 158026947304SEvan Yan /* 158126947304SEvan Yan * Add all properties into the request list, so that we 158226947304SEvan Yan * will get the values in the following for loop. 158326947304SEvan Yan */ 158426947304SEvan Yan for (i = 0; i < n; i++) { 158526947304SEvan Yan if (nvlist_add_string(prop_list, 158626947304SEvan Yan pciehpc_props[i].prop_name, "") != 0) { 158726947304SEvan Yan ret = DDI_FAILURE; 158826947304SEvan Yan goto get_prop_cleanup1; 158926947304SEvan Yan } 159026947304SEvan Yan } 159126947304SEvan Yan get_all_prop = B_TRUE; 159226947304SEvan Yan } else if (strcmp(name, PCIEHPC_PROP_HELP) == 0) { 159326947304SEvan Yan /* 159426947304SEvan Yan * Empty the request list, and add help strings into the 159526947304SEvan Yan * return list. We will pass the following for loop. 159626947304SEvan Yan */ 159726947304SEvan Yan (void) nvlist_remove_all(prop_list, PCIEHPC_PROP_HELP); 159826947304SEvan Yan 159926947304SEvan Yan for (i = 0; i < n; i++) { 160026947304SEvan Yan if (nvlist_add_string(prop_rlist, 160126947304SEvan Yan pciehpc_props[i].prop_name, 160226947304SEvan Yan pciehpc_props[i].prop_value) != 0) { 160326947304SEvan Yan ret = DDI_FAILURE; 160426947304SEvan Yan goto get_prop_cleanup1; 160526947304SEvan Yan } 160626947304SEvan Yan } 160726947304SEvan Yan } 160826947304SEvan Yan } 160926947304SEvan Yan 161026947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex); 161126947304SEvan Yan 161226947304SEvan Yan /* get the current slot state */ 161326947304SEvan Yan pciehpc_get_slot_state(slot_p); 161426947304SEvan Yan 161526947304SEvan Yan /* for each requested property, get the value and add it to nvlist */ 161626947304SEvan Yan prop_pair = NULL; 1617b3d69c05SRobert Mustacchi while ((prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) != NULL) { 161826947304SEvan Yan name = nvpair_name(prop_pair); 1619b3d69c05SRobert Mustacchi value = NULL; 162026947304SEvan Yan 162126947304SEvan Yan if (strcmp(name, PCIEHPC_PROP_LED_FAULT) == 0) { 162226947304SEvan Yan value = pcie_led_state_text( 162326947304SEvan Yan slot_p->hs_fault_led_state); 162426947304SEvan Yan } else if (strcmp(name, PCIEHPC_PROP_LED_POWER) == 0) { 162526947304SEvan Yan value = pcie_led_state_text( 162626947304SEvan Yan slot_p->hs_power_led_state); 162726947304SEvan Yan } else if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) { 162826947304SEvan Yan value = pcie_led_state_text( 162926947304SEvan Yan slot_p->hs_attn_led_state); 163026947304SEvan Yan } else if (strcmp(name, PCIEHPC_PROP_LED_ACTIVE) == 0) { 163126947304SEvan Yan value = pcie_led_state_text( 163226947304SEvan Yan slot_p->hs_active_led_state); 163326947304SEvan Yan } else if (strcmp(name, PCIEHPC_PROP_CARD_TYPE) == 0) { 163426947304SEvan Yan ddi_acc_handle_t handle; 163526947304SEvan Yan dev_info_t *cdip; 163626947304SEvan Yan uint8_t prog_class, base_class, sub_class; 163726947304SEvan Yan int i; 163826947304SEvan Yan 163926947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex); 164026947304SEvan Yan cdip = pcie_hp_devi_find( 164126947304SEvan Yan ctrl_p->hc_dip, slot_p->hs_device_num, 0); 164226947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex); 164326947304SEvan Yan 164426947304SEvan Yan if ((slot_p->hs_info.cn_state 164526947304SEvan Yan != DDI_HP_CN_STATE_ENABLED) || (cdip == NULL)) { 164626947304SEvan Yan /* 164726947304SEvan Yan * When getting all properties, just ignore the 164826947304SEvan Yan * one that's not available under certain state. 164926947304SEvan Yan */ 165026947304SEvan Yan if (get_all_prop) 165126947304SEvan Yan continue; 165226947304SEvan Yan 165326947304SEvan Yan ret = DDI_ENOTSUP; 165426947304SEvan Yan goto get_prop_cleanup2; 165526947304SEvan Yan } 165626947304SEvan Yan 165726947304SEvan Yan if (pci_config_setup(cdip, &handle) != DDI_SUCCESS) { 165826947304SEvan Yan ret = DDI_FAILURE; 165926947304SEvan Yan goto get_prop_cleanup2; 166026947304SEvan Yan } 166126947304SEvan Yan 166226947304SEvan Yan prog_class = pci_config_get8(handle, 166326947304SEvan Yan PCI_CONF_PROGCLASS); 166426947304SEvan Yan base_class = pci_config_get8(handle, PCI_CONF_BASCLASS); 166526947304SEvan Yan sub_class = pci_config_get8(handle, PCI_CONF_SUBCLASS); 166626947304SEvan Yan pci_config_teardown(&handle); 166726947304SEvan Yan 166826947304SEvan Yan for (i = 0; i < class_pci_items; i++) { 166926947304SEvan Yan if ((base_class == class_pci[i].base_class) && 167026947304SEvan Yan (sub_class == class_pci[i].sub_class) && 167126947304SEvan Yan (prog_class == class_pci[i].prog_class)) { 167226947304SEvan Yan value = class_pci[i].short_desc; 167326947304SEvan Yan break; 167426947304SEvan Yan } 167526947304SEvan Yan } 167626947304SEvan Yan if (i == class_pci_items) 167726947304SEvan Yan value = PCIEHPC_PROP_VALUE_UNKNOWN; 167826947304SEvan Yan } else if (strcmp(name, PCIEHPC_PROP_BOARD_TYPE) == 0) { 167926947304SEvan Yan if (slot_p->hs_info.cn_state <= DDI_HP_CN_STATE_EMPTY) 168026947304SEvan Yan value = PCIEHPC_PROP_VALUE_UNKNOWN; 168126947304SEvan Yan else 168226947304SEvan Yan value = PCIEHPC_PROP_VALUE_PCIHOTPLUG; 168326947304SEvan Yan } else if (strcmp(name, PCIEHPC_PROP_SLOT_CONDITION) == 0) { 168426947304SEvan Yan value = pcie_slot_condition_text(slot_p->hs_condition); 168526947304SEvan Yan } else { 168626947304SEvan Yan /* unsupported property */ 168724fd5dc4SEvan Yan PCIE_DBG("Unsupported property: %s\n", name); 168826947304SEvan Yan 168926947304SEvan Yan ret = DDI_ENOTSUP; 169026947304SEvan Yan goto get_prop_cleanup2; 169126947304SEvan Yan } 169226947304SEvan Yan if (nvlist_add_string(prop_rlist, name, value) != 0) { 169326947304SEvan Yan ret = DDI_FAILURE; 169426947304SEvan Yan goto get_prop_cleanup2; 169526947304SEvan Yan } 169626947304SEvan Yan } 169726947304SEvan Yan 169826947304SEvan Yan /* pack nvlist and copyout */ 169926947304SEvan Yan if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf, 170026947304SEvan Yan &result.buf_size)) != DDI_SUCCESS) { 170126947304SEvan Yan goto get_prop_cleanup2; 170226947304SEvan Yan } 170326947304SEvan Yan if (get_udatamodel() == DATAMODEL_NATIVE) { 170426947304SEvan Yan if (copyout(&result, rval, sizeof (ddi_hp_property_t))) 170526947304SEvan Yan ret = DDI_FAILURE; 170626947304SEvan Yan } 170726947304SEvan Yan #ifdef _SYSCALL32_IMPL 170826947304SEvan Yan else { 170926947304SEvan Yan if (result.buf_size > UINT32_MAX) { 171026947304SEvan Yan ret = DDI_FAILURE; 171126947304SEvan Yan } else { 171226947304SEvan Yan result32.buf_size = (uint32_t)result.buf_size; 171326947304SEvan Yan if (copyout(&result32, rval, 171426947304SEvan Yan sizeof (ddi_hp_property32_t))) 171526947304SEvan Yan ret = DDI_FAILURE; 171626947304SEvan Yan } 171726947304SEvan Yan } 171826947304SEvan Yan #endif 171926947304SEvan Yan 172026947304SEvan Yan get_prop_cleanup2: 172126947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex); 172226947304SEvan Yan get_prop_cleanup1: 172326947304SEvan Yan nvlist_free(prop_rlist); 172426947304SEvan Yan get_prop_cleanup: 172526947304SEvan Yan nvlist_free(prop_list); 172626947304SEvan Yan return (ret); 172726947304SEvan Yan } 172826947304SEvan Yan 172926947304SEvan Yan int 173026947304SEvan Yan pciehpc_slot_set_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg, 173126947304SEvan Yan ddi_hp_property_t *rval) 173226947304SEvan Yan { 173326947304SEvan Yan ddi_hp_property_t request, result; 173426947304SEvan Yan #ifdef _SYSCALL32_IMPL 173526947304SEvan Yan ddi_hp_property32_t request32, result32; 173626947304SEvan Yan #endif 173726947304SEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; 173826947304SEvan Yan nvlist_t *prop_list; 173926947304SEvan Yan nvlist_t *prop_rlist; 174026947304SEvan Yan nvpair_t *prop_pair; 174126947304SEvan Yan char *name, *value; 174226947304SEvan Yan pcie_hp_led_state_t led_state; 174326947304SEvan Yan int ret = DDI_SUCCESS; 174426947304SEvan Yan 174526947304SEvan Yan if (get_udatamodel() == DATAMODEL_NATIVE) { 174626947304SEvan Yan if (copyin(arg, &request, sizeof (ddi_hp_property_t))) 174726947304SEvan Yan return (DDI_FAILURE); 174826947304SEvan Yan if (rval && 174926947304SEvan Yan copyin(rval, &result, sizeof (ddi_hp_property_t))) 175026947304SEvan Yan return (DDI_FAILURE); 175126947304SEvan Yan } 175226947304SEvan Yan #ifdef _SYSCALL32_IMPL 175326947304SEvan Yan else { 175426947304SEvan Yan bzero(&request, sizeof (request)); 175526947304SEvan Yan bzero(&result, sizeof (result)); 175626947304SEvan Yan if (copyin(arg, &request32, sizeof (ddi_hp_property32_t))) 175726947304SEvan Yan return (DDI_FAILURE); 175826947304SEvan Yan if (rval && 175926947304SEvan Yan copyin(rval, &result32, sizeof (ddi_hp_property32_t))) 176026947304SEvan Yan return (DDI_FAILURE); 176126947304SEvan Yan request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf; 176226947304SEvan Yan request.buf_size = request32.buf_size; 176326947304SEvan Yan if (rval) { 176426947304SEvan Yan result.nvlist_buf = 176526947304SEvan Yan (char *)(uintptr_t)result32.nvlist_buf; 176626947304SEvan Yan result.buf_size = result32.buf_size; 176726947304SEvan Yan } 176826947304SEvan Yan } 176926947304SEvan Yan #endif 177026947304SEvan Yan 177126947304SEvan Yan if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size, 177226947304SEvan Yan &prop_list)) != DDI_SUCCESS) 177326947304SEvan Yan return (ret); 177426947304SEvan Yan 177526947304SEvan Yan /* check whether the requested property is "help" */ 177626947304SEvan Yan prop_pair = nvlist_next_nvpair(prop_list, NULL); 177726947304SEvan Yan if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair) && 177826947304SEvan Yan (strcmp(nvpair_name(prop_pair), PCIEHPC_PROP_HELP) == 0)) { 177926947304SEvan Yan if (!rval) { 178026947304SEvan Yan ret = DDI_ENOTSUP; 178126947304SEvan Yan goto set_prop_cleanup; 178226947304SEvan Yan } 178326947304SEvan Yan 178426947304SEvan Yan if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) { 178526947304SEvan Yan ret = DDI_ENOMEM; 178626947304SEvan Yan goto set_prop_cleanup; 178726947304SEvan Yan } 178826947304SEvan Yan if (nvlist_add_string(prop_rlist, PCIEHPC_PROP_LED_ATTN, 178926947304SEvan Yan PCIEHPC_PROP_VALUE_LED) != 0) { 179026947304SEvan Yan ret = DDI_FAILURE; 179126947304SEvan Yan goto set_prop_cleanup1; 179226947304SEvan Yan } 179326947304SEvan Yan 179426947304SEvan Yan if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf, 179526947304SEvan Yan &result.buf_size)) != DDI_SUCCESS) { 179626947304SEvan Yan goto set_prop_cleanup1; 179726947304SEvan Yan } 179826947304SEvan Yan if (get_udatamodel() == DATAMODEL_NATIVE) { 179926947304SEvan Yan if (copyout(&result, rval, 180026947304SEvan Yan sizeof (ddi_hp_property_t))) { 180126947304SEvan Yan ret = DDI_FAILURE; 180226947304SEvan Yan goto set_prop_cleanup1; 180326947304SEvan Yan } 180426947304SEvan Yan } 180526947304SEvan Yan #ifdef _SYSCALL32_IMPL 180626947304SEvan Yan else { 180726947304SEvan Yan if (result.buf_size > UINT32_MAX) { 180826947304SEvan Yan ret = DDI_FAILURE; 180926947304SEvan Yan goto set_prop_cleanup1; 181026947304SEvan Yan } else { 181126947304SEvan Yan result32.buf_size = (uint32_t)result.buf_size; 181226947304SEvan Yan if (copyout(&result32, rval, 181326947304SEvan Yan sizeof (ddi_hp_property32_t))) { 181426947304SEvan Yan ret = DDI_FAILURE; 181526947304SEvan Yan goto set_prop_cleanup1; 181626947304SEvan Yan } 181726947304SEvan Yan } 181826947304SEvan Yan } 181926947304SEvan Yan #endif 182026947304SEvan Yan set_prop_cleanup1: 182126947304SEvan Yan nvlist_free(prop_rlist); 182226947304SEvan Yan nvlist_free(prop_list); 182326947304SEvan Yan return (ret); 182426947304SEvan Yan } 182526947304SEvan Yan 182626947304SEvan Yan /* Validate the request */ 182726947304SEvan Yan prop_pair = NULL; 1828b3d69c05SRobert Mustacchi while ((prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) != NULL) { 182926947304SEvan Yan name = nvpair_name(prop_pair); 183026947304SEvan Yan if (nvpair_type(prop_pair) != DATA_TYPE_STRING) { 183124fd5dc4SEvan Yan PCIE_DBG("Unexpected data type of setting " 183226947304SEvan Yan "property %s.\n", name); 183326947304SEvan Yan ret = DDI_EINVAL; 183426947304SEvan Yan goto set_prop_cleanup; 183526947304SEvan Yan } 183626947304SEvan Yan if (nvpair_value_string(prop_pair, &value)) { 183724fd5dc4SEvan Yan PCIE_DBG("Get string value failed for property %s.\n", 183824fd5dc4SEvan Yan name); 183926947304SEvan Yan ret = DDI_FAILURE; 184026947304SEvan Yan goto set_prop_cleanup; 184126947304SEvan Yan } 184226947304SEvan Yan 184326947304SEvan Yan if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) { 184426947304SEvan Yan if ((strcmp(value, PCIEHPC_PROP_VALUE_ON) != 0) && 184526947304SEvan Yan (strcmp(value, PCIEHPC_PROP_VALUE_OFF) != 0) && 184626947304SEvan Yan (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) != 0)) { 184724fd5dc4SEvan Yan PCIE_DBG("Unsupported value of setting " 184826947304SEvan Yan "property %s\n", name); 184926947304SEvan Yan ret = DDI_ENOTSUP; 185026947304SEvan Yan goto set_prop_cleanup; 185126947304SEvan Yan } 185226947304SEvan Yan } else { 185324fd5dc4SEvan Yan PCIE_DBG("Unsupported property: %s\n", name); 185426947304SEvan Yan ret = DDI_ENOTSUP; 185526947304SEvan Yan goto set_prop_cleanup; 185626947304SEvan Yan } 185726947304SEvan Yan } 185826947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex); 185926947304SEvan Yan 186026947304SEvan Yan /* get the current slot state */ 186126947304SEvan Yan pciehpc_get_slot_state(slot_p); 186226947304SEvan Yan 186326947304SEvan Yan /* set each property */ 186426947304SEvan Yan prop_pair = NULL; 1865b3d69c05SRobert Mustacchi while ((prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) != NULL) { 186626947304SEvan Yan name = nvpair_name(prop_pair); 186726947304SEvan Yan 1868b3d69c05SRobert Mustacchi /* 1869b3d69c05SRobert Mustacchi * The validity of the property was checked above. 1870b3d69c05SRobert Mustacchi */ 187126947304SEvan Yan if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) { 187226947304SEvan Yan if (strcmp(value, PCIEHPC_PROP_VALUE_ON) == 0) 187326947304SEvan Yan led_state = PCIE_HP_LED_ON; 187426947304SEvan Yan else if (strcmp(value, PCIEHPC_PROP_VALUE_OFF) == 0) 187526947304SEvan Yan led_state = PCIE_HP_LED_OFF; 187626947304SEvan Yan else if (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) == 0) 187726947304SEvan Yan led_state = PCIE_HP_LED_BLINK; 1878b3d69c05SRobert Mustacchi else 1879b3d69c05SRobert Mustacchi continue; 188026947304SEvan Yan 188126947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, 188226947304SEvan Yan led_state); 188326947304SEvan Yan } 188426947304SEvan Yan } 188524fd5dc4SEvan Yan if (rval) { 188624fd5dc4SEvan Yan if (get_udatamodel() == DATAMODEL_NATIVE) { 188724fd5dc4SEvan Yan result.buf_size = 0; 188824fd5dc4SEvan Yan if (copyout(&result, rval, sizeof (ddi_hp_property_t))) 188924fd5dc4SEvan Yan ret = DDI_FAILURE; 189024fd5dc4SEvan Yan } 189124fd5dc4SEvan Yan #ifdef _SYSCALL32_IMPL 189224fd5dc4SEvan Yan else { 189324fd5dc4SEvan Yan result32.buf_size = 0; 189424fd5dc4SEvan Yan if (copyout(&result32, rval, 189524fd5dc4SEvan Yan sizeof (ddi_hp_property32_t))) 189624fd5dc4SEvan Yan ret = DDI_FAILURE; 189724fd5dc4SEvan Yan } 189824fd5dc4SEvan Yan #endif 189924fd5dc4SEvan Yan } 190026947304SEvan Yan 190126947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex); 190226947304SEvan Yan set_prop_cleanup: 190326947304SEvan Yan nvlist_free(prop_list); 190426947304SEvan Yan return (ret); 190526947304SEvan Yan } 190626947304SEvan Yan 190726947304SEvan Yan /* 190826947304SEvan Yan * Send a command to the PCI-E Hot Plug Controller. 190926947304SEvan Yan * 191026947304SEvan Yan * NOTES: The PCI-E spec defines the following semantics for issuing hot plug 191126947304SEvan Yan * commands. 191226947304SEvan Yan * 1) If Command Complete events/interrupts are supported then software 191326947304SEvan Yan * waits for Command Complete event after issuing a command (i.e writing 191426947304SEvan Yan * to the Slot Control register). The command completion could take as 191526947304SEvan Yan * long as 1 second so software should be prepared to wait for 1 second 191626947304SEvan Yan * before issuing another command. 191726947304SEvan Yan * 191826947304SEvan Yan * 2) If Command Complete events/interrupts are not supported then 191926947304SEvan Yan * software could issue multiple Slot Control writes without any delay 192026947304SEvan Yan * between writes. 192126947304SEvan Yan */ 192226947304SEvan Yan static void 192326947304SEvan Yan pciehpc_issue_hpc_command(pcie_hp_ctrl_t *ctrl_p, uint16_t control) 192426947304SEvan Yan { 192526947304SEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; 192626947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 192726947304SEvan Yan uint16_t status; 192826947304SEvan Yan uint32_t slot_cap; 192926947304SEvan Yan 193026947304SEvan Yan /* 193126947304SEvan Yan * PCI-E version 1.1 spec defines No Command Completed 193226947304SEvan Yan * Support bit (bit#18) in Slot Capabilities register. If this 193326947304SEvan Yan * bit is set then slot doesn't support notification of command 193426947304SEvan Yan * completion events. 193526947304SEvan Yan */ 193626947304SEvan Yan slot_cap = pciehpc_reg_get32(ctrl_p, 193726947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCAP); 193826947304SEvan Yan 193926947304SEvan Yan /* 194026947304SEvan Yan * If no Command Completion event is supported or it is ACPI 194126947304SEvan Yan * hot plug mode then just issue the command and return. 194226947304SEvan Yan */ 194326947304SEvan Yan if ((slot_cap & PCIE_SLOTCAP_NO_CMD_COMP_SUPP) || 194426947304SEvan Yan (bus_p->bus_hp_curr_mode == PCIE_ACPI_HP_MODE)) { 194526947304SEvan Yan pciehpc_reg_put16(ctrl_p, 194626947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL, control); 194726947304SEvan Yan return; 194826947304SEvan Yan } 194926947304SEvan Yan 195026947304SEvan Yan /* 195126947304SEvan Yan * ************************************** 195226947304SEvan Yan * Command Complete events are supported. 195326947304SEvan Yan * ************************************** 195426947304SEvan Yan */ 195526947304SEvan Yan 195626947304SEvan Yan /* 195726947304SEvan Yan * If HPC is not yet initialized then just poll for the Command 195826947304SEvan Yan * Completion interrupt. 195926947304SEvan Yan */ 196026947304SEvan Yan if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) { 196126947304SEvan Yan int retry = PCIE_HP_CMD_WAIT_RETRY; 196226947304SEvan Yan 196326947304SEvan Yan /* write the command to the HPC */ 196426947304SEvan Yan pciehpc_reg_put16(ctrl_p, 196526947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL, control); 196626947304SEvan Yan 196726947304SEvan Yan /* poll for status completion */ 196826947304SEvan Yan while (retry--) { 196926947304SEvan Yan /* wait for 10 msec before checking the status */ 197026947304SEvan Yan delay(drv_usectohz(PCIE_HP_CMD_WAIT_TIME)); 197126947304SEvan Yan 197226947304SEvan Yan status = pciehpc_reg_get16(ctrl_p, 197326947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS); 197426947304SEvan Yan 197526947304SEvan Yan if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) { 197626947304SEvan Yan /* clear the status bits */ 197726947304SEvan Yan pciehpc_reg_put16(ctrl_p, 197826947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS, status); 197926947304SEvan Yan break; 198026947304SEvan Yan } 198126947304SEvan Yan } 198226947304SEvan Yan return; 198326947304SEvan Yan } 198426947304SEvan Yan 198526947304SEvan Yan /* HPC is already initialized */ 198626947304SEvan Yan 198726947304SEvan Yan ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex)); 198826947304SEvan Yan 198926947304SEvan Yan /* 199026947304SEvan Yan * If previous command is still pending then wait for its 199126947304SEvan Yan * completion. i.e cv_wait() 199226947304SEvan Yan */ 199326947304SEvan Yan 199426947304SEvan Yan while (ctrl_p->hc_cmd_pending == B_TRUE) 199526947304SEvan Yan cv_wait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex); 199626947304SEvan Yan 199726947304SEvan Yan /* 199826947304SEvan Yan * Issue the command and wait for Command Completion or 199926947304SEvan Yan * the 1 sec timeout. 200026947304SEvan Yan */ 200126947304SEvan Yan pciehpc_reg_put16(ctrl_p, 200226947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL, control); 200326947304SEvan Yan 200426947304SEvan Yan ctrl_p->hc_cmd_pending = B_TRUE; 200526947304SEvan Yan 200626947304SEvan Yan if (cv_timedwait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex, 200726947304SEvan Yan ddi_get_lbolt() + SEC_TO_TICK(1)) == -1) { 200826947304SEvan Yan 200926947304SEvan Yan /* it is a timeout */ 201026947304SEvan Yan PCIE_DBG("pciehpc_issue_hpc_command: Command Complete" 201126947304SEvan Yan " interrupt is not received for slot %d\n", 201226947304SEvan Yan slot_p->hs_phy_slot_num); 201326947304SEvan Yan 201426947304SEvan Yan /* clear the status info in case interrupts are disabled? */ 201526947304SEvan Yan status = pciehpc_reg_get16(ctrl_p, 201626947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS); 201726947304SEvan Yan 201826947304SEvan Yan if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) { 201926947304SEvan Yan /* clear the status bits */ 202026947304SEvan Yan pciehpc_reg_put16(ctrl_p, 202126947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS, status); 202226947304SEvan Yan } 202326947304SEvan Yan } 202426947304SEvan Yan 202526947304SEvan Yan ctrl_p->hc_cmd_pending = B_FALSE; 202626947304SEvan Yan 202726947304SEvan Yan /* wake up any one waiting for issuing another command to HPC */ 202826947304SEvan Yan cv_signal(&ctrl_p->hc_cmd_comp_cv); 202926947304SEvan Yan } 203026947304SEvan Yan 203126947304SEvan Yan /* 203226947304SEvan Yan * pciehcp_attn_btn_handler() 203326947304SEvan Yan * 203426947304SEvan Yan * This handles ATTN button pressed event as per the PCI-E 1.1 spec. 203526947304SEvan Yan */ 203626947304SEvan Yan static void 203726947304SEvan Yan pciehpc_attn_btn_handler(pcie_hp_ctrl_t *ctrl_p) 203826947304SEvan Yan { 203926947304SEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; 204026947304SEvan Yan pcie_hp_led_state_t power_led_state; 204126947304SEvan Yan callb_cpr_t cprinfo; 204226947304SEvan Yan 204326947304SEvan Yan PCIE_DBG("pciehpc_attn_btn_handler: thread started\n"); 204426947304SEvan Yan 204526947304SEvan Yan CALLB_CPR_INIT(&cprinfo, &ctrl_p->hc_mutex, callb_generic_cpr, 204626947304SEvan Yan "pciehpc_attn_btn_handler"); 204726947304SEvan Yan 204826947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex); 204926947304SEvan Yan 205026947304SEvan Yan /* wait for ATTN button event */ 205126947304SEvan Yan cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex); 205226947304SEvan Yan 205326947304SEvan Yan while (slot_p->hs_attn_btn_thread_exit == B_FALSE) { 205426947304SEvan Yan if (slot_p->hs_attn_btn_pending == B_TRUE) { 205526947304SEvan Yan /* get the current state of power LED */ 205626947304SEvan Yan power_led_state = pciehpc_get_led_state(ctrl_p, 205726947304SEvan Yan PCIE_HP_POWER_LED); 205826947304SEvan Yan 205926947304SEvan Yan /* Blink the Power LED while we wait for 5 seconds */ 206026947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, 206126947304SEvan Yan PCIE_HP_LED_BLINK); 206226947304SEvan Yan 206326947304SEvan Yan /* wait for 5 seconds before taking any action */ 206426947304SEvan Yan if (cv_timedwait(&slot_p->hs_attn_btn_cv, 206526947304SEvan Yan &ctrl_p->hc_mutex, 206626947304SEvan Yan ddi_get_lbolt() + SEC_TO_TICK(5)) == -1) { 206726947304SEvan Yan /* 206826947304SEvan Yan * It is a time out; make sure the ATTN pending 206926947304SEvan Yan * flag is still ON before sending the event to 207026947304SEvan Yan * DDI HP framework. 207126947304SEvan Yan */ 207226947304SEvan Yan if (slot_p->hs_attn_btn_pending == B_TRUE) { 207326947304SEvan Yan int hint; 207426947304SEvan Yan 207526947304SEvan Yan slot_p->hs_attn_btn_pending = B_FALSE; 207626947304SEvan Yan pciehpc_get_slot_state(slot_p); 207726947304SEvan Yan 207826947304SEvan Yan if (slot_p->hs_info.cn_state <= 207926947304SEvan Yan DDI_HP_CN_STATE_PRESENT) { 208026947304SEvan Yan /* 208126947304SEvan Yan * Insertion. 208226947304SEvan Yan */ 208326947304SEvan Yan hint = SE_INCOMING_RES; 208426947304SEvan Yan } else { 208526947304SEvan Yan /* 208626947304SEvan Yan * Want to remove; 208726947304SEvan Yan */ 208826947304SEvan Yan hint = SE_OUTGOING_RES; 208926947304SEvan Yan } 209026947304SEvan Yan 209126947304SEvan Yan /* 209226947304SEvan Yan * We can't call ddihp_cn_gen_sysevent 209326947304SEvan Yan * here since it's not a DDI interface. 209426947304SEvan Yan */ 209526947304SEvan Yan pcie_hp_gen_sysevent_req( 209626947304SEvan Yan slot_p->hs_info.cn_name, 209726947304SEvan Yan hint, 209826947304SEvan Yan ctrl_p->hc_dip, 209926947304SEvan Yan KM_SLEEP); 210026947304SEvan Yan } 210126947304SEvan Yan } 210226947304SEvan Yan 210326947304SEvan Yan /* restore the power LED state */ 210426947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, 210526947304SEvan Yan power_led_state); 210626947304SEvan Yan continue; 210726947304SEvan Yan } 210826947304SEvan Yan 210926947304SEvan Yan /* wait for another ATTN button event */ 211026947304SEvan Yan cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex); 211126947304SEvan Yan } 211226947304SEvan Yan 211326947304SEvan Yan PCIE_DBG("pciehpc_attn_btn_handler: thread exit\n"); 211426947304SEvan Yan cv_signal(&slot_p->hs_attn_btn_cv); 211526947304SEvan Yan CALLB_CPR_EXIT(&cprinfo); 211626947304SEvan Yan thread_exit(); 211726947304SEvan Yan } 211826947304SEvan Yan 211926947304SEvan Yan /* 212026947304SEvan Yan * convert LED state from PCIE HPC definition to pcie_hp_led_state_t 212126947304SEvan Yan * definition. 212226947304SEvan Yan */ 212326947304SEvan Yan static pcie_hp_led_state_t 212426947304SEvan Yan pciehpc_led_state_to_hpc(uint16_t state) 212526947304SEvan Yan { 212626947304SEvan Yan switch (state) { 212726947304SEvan Yan case PCIE_SLOTCTL_INDICATOR_STATE_ON: 212826947304SEvan Yan return (PCIE_HP_LED_ON); 212926947304SEvan Yan case PCIE_SLOTCTL_INDICATOR_STATE_BLINK: 213026947304SEvan Yan return (PCIE_HP_LED_BLINK); 213126947304SEvan Yan case PCIE_SLOTCTL_INDICATOR_STATE_OFF: 213226947304SEvan Yan default: 213326947304SEvan Yan return (PCIE_HP_LED_OFF); 213426947304SEvan Yan } 213526947304SEvan Yan } 213626947304SEvan Yan 213726947304SEvan Yan /* 213826947304SEvan Yan * Get the state of an LED. 213926947304SEvan Yan */ 214026947304SEvan Yan static pcie_hp_led_state_t 214126947304SEvan Yan pciehpc_get_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led) 214226947304SEvan Yan { 214326947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 214426947304SEvan Yan uint16_t control, state; 214526947304SEvan Yan 214626947304SEvan Yan /* get the current state of Slot Control register */ 214726947304SEvan Yan control = pciehpc_reg_get16(ctrl_p, 214826947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL); 214926947304SEvan Yan 215026947304SEvan Yan switch (led) { 215126947304SEvan Yan case PCIE_HP_POWER_LED: 215226947304SEvan Yan state = pcie_slotctl_pwr_indicator_get(control); 215326947304SEvan Yan break; 215426947304SEvan Yan case PCIE_HP_ATTN_LED: 215526947304SEvan Yan state = pcie_slotctl_attn_indicator_get(control); 215626947304SEvan Yan break; 215726947304SEvan Yan default: 215826947304SEvan Yan PCIE_DBG("pciehpc_get_led_state() invalid LED %d\n", led); 215926947304SEvan Yan return (PCIE_HP_LED_OFF); 216026947304SEvan Yan } 216126947304SEvan Yan 216226947304SEvan Yan switch (state) { 216326947304SEvan Yan case PCIE_SLOTCTL_INDICATOR_STATE_ON: 216426947304SEvan Yan return (PCIE_HP_LED_ON); 216526947304SEvan Yan 216626947304SEvan Yan case PCIE_SLOTCTL_INDICATOR_STATE_BLINK: 216726947304SEvan Yan return (PCIE_HP_LED_BLINK); 216826947304SEvan Yan 216926947304SEvan Yan case PCIE_SLOTCTL_INDICATOR_STATE_OFF: 217026947304SEvan Yan default: 217126947304SEvan Yan return (PCIE_HP_LED_OFF); 217226947304SEvan Yan } 217326947304SEvan Yan } 217426947304SEvan Yan 217526947304SEvan Yan /* 217626947304SEvan Yan * Set the state of an LED. It updates both hw and sw state. 217726947304SEvan Yan */ 217826947304SEvan Yan static void 217926947304SEvan Yan pciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led, 218026947304SEvan Yan pcie_hp_led_state_t state) 218126947304SEvan Yan { 218226947304SEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; 218326947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 218426947304SEvan Yan uint16_t control; 218526947304SEvan Yan 218626947304SEvan Yan /* get the current state of Slot Control register */ 218726947304SEvan Yan control = pciehpc_reg_get16(ctrl_p, 218826947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL); 218926947304SEvan Yan 219026947304SEvan Yan switch (led) { 219126947304SEvan Yan case PCIE_HP_POWER_LED: 219226947304SEvan Yan /* clear led mask */ 219326947304SEvan Yan control &= ~PCIE_SLOTCTL_PWR_INDICATOR_MASK; 219426947304SEvan Yan slot_p->hs_power_led_state = state; 219526947304SEvan Yan break; 219626947304SEvan Yan case PCIE_HP_ATTN_LED: 219726947304SEvan Yan /* clear led mask */ 219826947304SEvan Yan control &= ~PCIE_SLOTCTL_ATTN_INDICATOR_MASK; 219926947304SEvan Yan slot_p->hs_attn_led_state = state; 220026947304SEvan Yan break; 220126947304SEvan Yan default: 220226947304SEvan Yan PCIE_DBG("pciehpc_set_led_state() invalid LED %d\n", led); 220326947304SEvan Yan return; 220426947304SEvan Yan } 220526947304SEvan Yan 220626947304SEvan Yan switch (state) { 220726947304SEvan Yan case PCIE_HP_LED_ON: 220826947304SEvan Yan if (led == PCIE_HP_POWER_LED) 220926947304SEvan Yan control = pcie_slotctl_pwr_indicator_set(control, 221026947304SEvan Yan PCIE_SLOTCTL_INDICATOR_STATE_ON); 221126947304SEvan Yan else if (led == PCIE_HP_ATTN_LED) 221226947304SEvan Yan control = pcie_slotctl_attn_indicator_set(control, 221326947304SEvan Yan PCIE_SLOTCTL_INDICATOR_STATE_ON); 221426947304SEvan Yan break; 221526947304SEvan Yan case PCIE_HP_LED_OFF: 221626947304SEvan Yan if (led == PCIE_HP_POWER_LED) 221726947304SEvan Yan control = pcie_slotctl_pwr_indicator_set(control, 221826947304SEvan Yan PCIE_SLOTCTL_INDICATOR_STATE_OFF); 221926947304SEvan Yan else if (led == PCIE_HP_ATTN_LED) 222026947304SEvan Yan control = pcie_slotctl_attn_indicator_set(control, 222126947304SEvan Yan PCIE_SLOTCTL_INDICATOR_STATE_OFF); 222226947304SEvan Yan break; 222326947304SEvan Yan case PCIE_HP_LED_BLINK: 222426947304SEvan Yan if (led == PCIE_HP_POWER_LED) 222526947304SEvan Yan control = pcie_slotctl_pwr_indicator_set(control, 222626947304SEvan Yan PCIE_SLOTCTL_INDICATOR_STATE_BLINK); 222726947304SEvan Yan else if (led == PCIE_HP_ATTN_LED) 222826947304SEvan Yan control = pcie_slotctl_attn_indicator_set(control, 222926947304SEvan Yan PCIE_SLOTCTL_INDICATOR_STATE_BLINK); 223026947304SEvan Yan break; 223126947304SEvan Yan 223226947304SEvan Yan default: 223326947304SEvan Yan PCIE_DBG("pciehpc_set_led_state() invalid LED state %d\n", 223426947304SEvan Yan state); 223526947304SEvan Yan return; 223626947304SEvan Yan } 223726947304SEvan Yan 223826947304SEvan Yan /* update the Slot Control Register */ 223926947304SEvan Yan pciehpc_issue_hpc_command(ctrl_p, control); 224026947304SEvan Yan 224126947304SEvan Yan #ifdef DEBUG 224226947304SEvan Yan /* get the current state of Slot Control register */ 224326947304SEvan Yan control = pciehpc_reg_get16(ctrl_p, 224426947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL); 224526947304SEvan Yan 224626947304SEvan Yan PCIE_DBG("pciehpc_set_led_state: slot %d power-led %s attn-led %s\n", 224726947304SEvan Yan slot_p->hs_phy_slot_num, pcie_led_state_text( 224826947304SEvan Yan pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control))), 224926947304SEvan Yan pcie_led_state_text(pciehpc_led_state_to_hpc( 225026947304SEvan Yan pcie_slotctl_attn_indicator_get(control)))); 225126947304SEvan Yan #endif 225226947304SEvan Yan } 225326947304SEvan Yan 225480dc702dSColin Zou - Sun Microsystems - Beijing China static void 225580dc702dSColin Zou - Sun Microsystems - Beijing China pciehpc_handle_power_fault(dev_info_t *dip) 225680dc702dSColin Zou - Sun Microsystems - Beijing China { 225780dc702dSColin Zou - Sun Microsystems - Beijing China /* 225880dc702dSColin Zou - Sun Microsystems - Beijing China * Hold the parent's ref so that it won't disappear when the taskq is 225980dc702dSColin Zou - Sun Microsystems - Beijing China * scheduled to run. 226080dc702dSColin Zou - Sun Microsystems - Beijing China */ 226180dc702dSColin Zou - Sun Microsystems - Beijing China ndi_hold_devi(dip); 226280dc702dSColin Zou - Sun Microsystems - Beijing China 2263fc8ae2ecSToomas Soome if (taskq_dispatch(system_taskq, pciehpc_power_fault_handler, dip, 2264fc8ae2ecSToomas Soome TQ_NOSLEEP) == TASKQID_INVALID) { 226580dc702dSColin Zou - Sun Microsystems - Beijing China ndi_rele_devi(dip); 226680dc702dSColin Zou - Sun Microsystems - Beijing China PCIE_DBG("pciehpc_intr(): " 226780dc702dSColin Zou - Sun Microsystems - Beijing China "Failed to dispatch power fault handler, dip %p\n", dip); 226880dc702dSColin Zou - Sun Microsystems - Beijing China } 226980dc702dSColin Zou - Sun Microsystems - Beijing China } 227080dc702dSColin Zou - Sun Microsystems - Beijing China 227180dc702dSColin Zou - Sun Microsystems - Beijing China static void 227280dc702dSColin Zou - Sun Microsystems - Beijing China pciehpc_power_fault_handler(void *arg) 227380dc702dSColin Zou - Sun Microsystems - Beijing China { 227480dc702dSColin Zou - Sun Microsystems - Beijing China dev_info_t *dip = (dev_info_t *)arg; 227580dc702dSColin Zou - Sun Microsystems - Beijing China pcie_hp_ctrl_t *ctrl_p; 227680dc702dSColin Zou - Sun Microsystems - Beijing China pcie_hp_slot_t *slot_p; 227780dc702dSColin Zou - Sun Microsystems - Beijing China 227880dc702dSColin Zou - Sun Microsystems - Beijing China /* get the soft state structure for this dip */ 227980dc702dSColin Zou - Sun Microsystems - Beijing China if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) { 228080dc702dSColin Zou - Sun Microsystems - Beijing China ndi_rele_devi(dip); 228180dc702dSColin Zou - Sun Microsystems - Beijing China return; 228280dc702dSColin Zou - Sun Microsystems - Beijing China } 228380dc702dSColin Zou - Sun Microsystems - Beijing China slot_p = ctrl_p->hc_slots[0]; 228480dc702dSColin Zou - Sun Microsystems - Beijing China 228580dc702dSColin Zou - Sun Microsystems - Beijing China /* 228680dc702dSColin Zou - Sun Microsystems - Beijing China * Send the event to DDI Hotplug framework, power off 228780dc702dSColin Zou - Sun Microsystems - Beijing China * the slot 228880dc702dSColin Zou - Sun Microsystems - Beijing China */ 228980dc702dSColin Zou - Sun Microsystems - Beijing China (void) ndi_hp_state_change_req(dip, 229080dc702dSColin Zou - Sun Microsystems - Beijing China slot_p->hs_info.cn_name, 229180dc702dSColin Zou - Sun Microsystems - Beijing China DDI_HP_CN_STATE_EMPTY, DDI_HP_REQ_SYNC); 229280dc702dSColin Zou - Sun Microsystems - Beijing China 229380dc702dSColin Zou - Sun Microsystems - Beijing China mutex_enter(&ctrl_p->hc_mutex); 229480dc702dSColin Zou - Sun Microsystems - Beijing China pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, 229580dc702dSColin Zou - Sun Microsystems - Beijing China PCIE_HP_LED_ON); 229680dc702dSColin Zou - Sun Microsystems - Beijing China mutex_exit(&ctrl_p->hc_mutex); 229780dc702dSColin Zou - Sun Microsystems - Beijing China ndi_rele_devi(dip); 229880dc702dSColin Zou - Sun Microsystems - Beijing China } 229980dc702dSColin Zou - Sun Microsystems - Beijing China 230026947304SEvan Yan #ifdef DEBUG 230126947304SEvan Yan /* 230226947304SEvan Yan * Dump PCI-E Hot Plug registers. 230326947304SEvan Yan */ 230426947304SEvan Yan static void 230526947304SEvan Yan pciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p) 230626947304SEvan Yan { 230726947304SEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0]; 230826947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 230926947304SEvan Yan uint16_t control; 231026947304SEvan Yan uint32_t capabilities; 231126947304SEvan Yan 231226947304SEvan Yan if (!pcie_debug_flags) 231326947304SEvan Yan return; 231426947304SEvan Yan 231526947304SEvan Yan capabilities = pciehpc_reg_get32(ctrl_p, 231626947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCAP); 231726947304SEvan Yan 231826947304SEvan Yan control = pciehpc_reg_get16(ctrl_p, 231926947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL); 232026947304SEvan Yan 232126947304SEvan Yan PCIE_DBG("pciehpc_dump_hpregs: Found PCI-E hot plug slot %d\n", 232226947304SEvan Yan slot_p->hs_phy_slot_num); 232326947304SEvan Yan 232426947304SEvan Yan PCIE_DBG("Attention Button Present = %s\n", 232526947304SEvan Yan capabilities & PCIE_SLOTCAP_ATTN_BUTTON ? "Yes":"No"); 232626947304SEvan Yan 232726947304SEvan Yan PCIE_DBG("Power controller Present = %s\n", 232826947304SEvan Yan capabilities & PCIE_SLOTCAP_POWER_CONTROLLER ? "Yes":"No"); 232926947304SEvan Yan 233026947304SEvan Yan PCIE_DBG("MRL Sensor Present = %s\n", 233126947304SEvan Yan capabilities & PCIE_SLOTCAP_MRL_SENSOR ? "Yes":"No"); 233226947304SEvan Yan 233326947304SEvan Yan PCIE_DBG("Attn Indicator Present = %s\n", 233426947304SEvan Yan capabilities & PCIE_SLOTCAP_ATTN_INDICATOR ? "Yes":"No"); 233526947304SEvan Yan 233626947304SEvan Yan PCIE_DBG("Power Indicator Present = %s\n", 233726947304SEvan Yan capabilities & PCIE_SLOTCAP_PWR_INDICATOR ? "Yes":"No"); 233826947304SEvan Yan 233926947304SEvan Yan PCIE_DBG("HotPlug Surprise = %s\n", 234026947304SEvan Yan capabilities & PCIE_SLOTCAP_HP_SURPRISE ? "Yes":"No"); 234126947304SEvan Yan 234226947304SEvan Yan PCIE_DBG("HotPlug Capable = %s\n", 234326947304SEvan Yan capabilities & PCIE_SLOTCAP_HP_CAPABLE ? "Yes":"No"); 234426947304SEvan Yan 234526947304SEvan Yan PCIE_DBG("Physical Slot Number = %d\n", 234626947304SEvan Yan PCIE_SLOTCAP_PHY_SLOT_NUM(capabilities)); 234726947304SEvan Yan 234826947304SEvan Yan PCIE_DBG("Attn Button interrupt Enabled = %s\n", 234926947304SEvan Yan control & PCIE_SLOTCTL_ATTN_BTN_EN ? "Yes":"No"); 235026947304SEvan Yan 235126947304SEvan Yan PCIE_DBG("Power Fault interrupt Enabled = %s\n", 235226947304SEvan Yan control & PCIE_SLOTCTL_PWR_FAULT_EN ? "Yes":"No"); 235326947304SEvan Yan 235426947304SEvan Yan PCIE_DBG("MRL Sensor INTR Enabled = %s\n", 235526947304SEvan Yan control & PCIE_SLOTCTL_MRL_SENSOR_EN ? "Yes":"No"); 235626947304SEvan Yan 235726947304SEvan Yan PCIE_DBG("Presence interrupt Enabled = %s\n", 235826947304SEvan Yan control & PCIE_SLOTCTL_PRESENCE_CHANGE_EN ? "Yes":"No"); 235926947304SEvan Yan 236026947304SEvan Yan PCIE_DBG("Cmd Complete interrupt Enabled = %s\n", 236126947304SEvan Yan control & PCIE_SLOTCTL_CMD_INTR_EN ? "Yes":"No"); 236226947304SEvan Yan 236326947304SEvan Yan PCIE_DBG("HotPlug interrupt Enabled = %s\n", 236426947304SEvan Yan control & PCIE_SLOTCTL_HP_INTR_EN ? "Yes":"No"); 236526947304SEvan Yan 236626947304SEvan Yan PCIE_DBG("Power Indicator LED = %s", pcie_led_state_text( 236726947304SEvan Yan pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control)))); 236826947304SEvan Yan 236926947304SEvan Yan PCIE_DBG("Attn Indicator LED = %s\n", 237026947304SEvan Yan pcie_led_state_text(pciehpc_led_state_to_hpc( 237126947304SEvan Yan pcie_slotctl_attn_indicator_get(control)))); 237226947304SEvan Yan } 237326947304SEvan Yan #endif /* DEBUG */ 2374