269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * CDDL HEADER START
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * The contents of this file are subject to the terms of the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Common Development and Distribution License (the "License").
269473047d747f7815af570197e4ef7322d3632cEvan Yan * You may not use this file except in compliance with the License.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
269473047d747f7815af570197e4ef7322d3632cEvan Yan * or http://www.opensolaris.org/os/licensing.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * See the License for the specific language governing permissions
269473047d747f7815af570197e4ef7322d3632cEvan Yan * and limitations under the License.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * When distributing Covered Code, include this CDDL HEADER in each
269473047d747f7815af570197e4ef7322d3632cEvan Yan * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If applicable, add the following below this CDDL HEADER, with the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * fields enclosed by brackets "[]" replaced with your own identifying
269473047d747f7815af570197e4ef7322d3632cEvan Yan * information: Portions Copyright [yyyy] [name of copyright owner]
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * CDDL HEADER END
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * This file contains Standard PCI Express HotPlug functionality that is
269473047d747f7815af570197e4ef7322d3632cEvan Yan * compatible with the PCI Express ver 1.1 specification.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * NOTE: This file is compiled and delivered through misc/pcie module.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/types.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/note.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/conf.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/kmem.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/debug.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/vtrace.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/autoconf.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/varargs.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/ddi_impldefs.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/time.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/callb.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/ddi.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/sunddi.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/sunndi.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/sysevent/dr.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/pci_impl.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/hotplug/pci/pcie_hp.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/hotplug/pci/pciehpc.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yantypedef struct pciehpc_prop {
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *prop_name;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *prop_value;
269473047d747f7815af570197e4ef7322d3632cEvan Yan} pciehpc_prop_t;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic pciehpc_prop_t pciehpc_props[] = {
269473047d747f7815af570197e4ef7322d3632cEvan Yan { PCIEHPC_PROP_LED_FAULT, PCIEHPC_PROP_VALUE_LED },
269473047d747f7815af570197e4ef7322d3632cEvan Yan { PCIEHPC_PROP_LED_POWER, PCIEHPC_PROP_VALUE_LED },
269473047d747f7815af570197e4ef7322d3632cEvan Yan { PCIEHPC_PROP_LED_ATTN, PCIEHPC_PROP_VALUE_LED },
269473047d747f7815af570197e4ef7322d3632cEvan Yan { PCIEHPC_PROP_LED_ACTIVE, PCIEHPC_PROP_VALUE_LED },
269473047d747f7815af570197e4ef7322d3632cEvan Yan { PCIEHPC_PROP_CARD_TYPE, PCIEHPC_PROP_VALUE_TYPE },
269473047d747f7815af570197e4ef7322d3632cEvan Yan { PCIEHPC_PROP_BOARD_TYPE, PCIEHPC_PROP_VALUE_TYPE },
269473047d747f7815af570197e4ef7322d3632cEvan Yan { PCIEHPC_PROP_SLOT_CONDITION, PCIEHPC_PROP_VALUE_TYPE }
269473047d747f7815af570197e4ef7322d3632cEvan Yan};
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/* Local functions prototype */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pciehpc_hpc_init(pcie_hp_ctrl_t *ctrl_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pciehpc_hpc_uninit(pcie_hp_ctrl_t *ctrl_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pciehpc_slotinfo_init(pcie_hp_ctrl_t *ctrl_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pciehpc_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pciehpc_enable_intr(pcie_hp_ctrl_t *ctrl_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pciehpc_disable_intr(pcie_hp_ctrl_t *ctrl_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic pcie_hp_ctrl_t *pciehpc_create_controller(dev_info_t *dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void pciehpc_destroy_controller(dev_info_t *dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pciehpc_register_slot(pcie_hp_ctrl_t *ctrl_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pciehpc_unregister_slot(pcie_hp_ctrl_t *ctrl_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pciehpc_slot_get_property(pcie_hp_slot_t *slot_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_property_t *arg, ddi_hp_property_t *rval);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pciehpc_slot_set_property(pcie_hp_slot_t *slot_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_property_t *arg, ddi_hp_property_t *rval);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void pciehpc_issue_hpc_command(pcie_hp_ctrl_t *ctrl_p, uint16_t control);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void pciehpc_attn_btn_handler(pcie_hp_ctrl_t *ctrl_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic pcie_hp_led_state_t pciehpc_led_state_to_hpc(uint16_t state);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic pcie_hp_led_state_t pciehpc_get_led_state(pcie_hp_ctrl_t *ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_led_t led);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void pciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led,
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_led_state_t state);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pciehpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_state_t target_state);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pciehpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_state_t target_state);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pciehpc_change_slot_state(pcie_hp_slot_t *slot_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_state_t target_state);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pciehpc_slot_probe(pcie_hp_slot_t *slot_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int pciehpc_slot_unprobe(pcie_hp_slot_t *slot_p);
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing Chinastatic void pciehpc_handle_power_fault(dev_info_t *dip);
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing Chinastatic void pciehpc_power_fault_handler(void *arg);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan#ifdef DEBUG
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void pciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan#endif /* DEBUG */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Global functions (called by other drivers/modules)
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Initialize Hot Plug Controller if present. The arguments are:
269473047d747f7815af570197e4ef7322d3632cEvan Yan * dip - Devinfo node pointer to the hot plug bus node
269473047d747f7815af570197e4ef7322d3632cEvan Yan * regops - register ops to access HPC registers for non-standard
269473047d747f7815af570197e4ef7322d3632cEvan Yan * HPC hw implementations (e.g: HPC in host PCI-E brdiges)
269473047d747f7815af570197e4ef7322d3632cEvan Yan * This is NULL for standard HPC in PCIe bridges.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Returns:
269473047d747f7815af570197e4ef7322d3632cEvan Yan * DDI_SUCCESS for successful HPC initialization
269473047d747f7815af570197e4ef7322d3632cEvan Yan * DDI_FAILURE for errors or if HPC hw not found
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_init(dev_info_t *dip, caddr_t arg)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_regops_t *regops = (pcie_hp_regops_t *)(void *)arg;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_ctrl_t *ctrl_p;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_init() called (dip=%p)\n", (void *)dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Make sure that it is not already initialized */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("%s%d: pciehpc instance already initialized!\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_driver_name(dip), ddi_get_instance(dip));
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Allocate a new hotplug controller and slot structures */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p = pciehpc_create_controller(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* setup access handle for HPC regs */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (regops != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* HPC access is non-standard; use the supplied reg ops */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_regops = *regops;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Setup resource maps for this bus node.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) pci_resource_setup(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DISABLE_ERRORS(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Set the platform specific hot plug mode.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_ops.init_hpc_hw = pciehpc_hpc_init;
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_ops.uninit_hpc_hw = pciehpc_hpc_uninit;
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_ops.init_hpc_slotinfo = pciehpc_slotinfo_init;
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_ops.uninit_hpc_slotinfo = pciehpc_slotinfo_uninit;
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_ops.poweron_hpc_slot = pciehpc_slot_poweron;
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_ops.poweroff_hpc_slot = pciehpc_slot_poweroff;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_ops.enable_hpc_intr = pciehpc_enable_intr;
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_ops.disable_hpc_intr = pciehpc_disable_intr;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan#if defined(__i386) || defined(__amd64)
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_update_ops(ctrl_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan#endif
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* initialize hot plug controller hw */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((ctrl_p->hc_ops.init_hpc_hw)(ctrl_p) != DDI_SUCCESS)
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto cleanup1;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* initialize slot information soft state structure */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((ctrl_p->hc_ops.init_hpc_slotinfo)(ctrl_p) != DDI_SUCCESS)
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto cleanup2;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* register the hot plug slot with DDI HP framework */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (pciehpc_register_slot(ctrl_p) != DDI_SUCCESS)
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto cleanup3;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* create minor node for this slot */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (pcie_create_minor_node(ctrl_p, 0) != DDI_SUCCESS)
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto cleanup4;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* HPC initialization is complete now */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_flags = PCIE_HP_INITIALIZED_FLAG;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan#ifdef DEBUG
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* For debug, dump the HPC registers */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_dump_hpregs(ctrl_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan#endif /* DEBUG */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yancleanup4:
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) pciehpc_unregister_slot(ctrl_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yancleanup3:
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yancleanup2:
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yancleanup1:
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_ENABLE_ERRORS(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) pci_resource_destroy(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_destroy_controller(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Uninitialize HPC soft state structure and free up any resources
269473047d747f7815af570197e4ef7322d3632cEvan Yan * used for the HPC instance.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_uninit(dev_info_t *dip)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_ctrl_t *ctrl_p;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_uninit() called (dip=%p)\n", (void *)dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the soft state structure for this dip */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_remove_minor_node(ctrl_p, 0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* unregister the slot */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) pciehpc_unregister_slot(ctrl_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* uninit any slot info data structures */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* uninitialize hpc, remove interrupt handler, etc. */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_ENABLE_ERRORS(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Destroy resource maps for this bus node.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) pci_resource_destroy(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* destroy the soft state structure */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_destroy_controller(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * pciehpc_intr()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Interrupt handler for PCI-E Hot plug controller interrupts.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Note: This is only for native mode hot plug. This is called
269473047d747f7815af570197e4ef7322d3632cEvan Yan * by the nexus driver at interrupt context. Interrupt Service Routine
269473047d747f7815af570197e4ef7322d3632cEvan Yan * registration is done by the nexus driver for both hot plug and
269473047d747f7815af570197e4ef7322d3632cEvan Yan * non-hot plug interrupts. This function is called from the ISR
269473047d747f7815af570197e4ef7322d3632cEvan Yan * of the nexus driver to handle hot-plug interrupts.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_intr(dev_info_t *dip)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_ctrl_t *ctrl_p;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_slot_t *slot_p;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint16_t status, control;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the soft state structure for this dip */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_INTR_UNCLAIMED);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_enter(&ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* make sure the controller soft state is initialized */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_exit(&ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_INTR_UNCLAIMED);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* if it is not NATIVE hot plug mode then return */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (bus_p->bus_hp_curr_mode != PCIE_NATIVE_HP_MODE) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_exit(&ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_INTR_UNCLAIMED);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p = ctrl_p->hc_slots[0];
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* read the current slot status register */
269473047d747f7815af570197e4ef7322d3632cEvan Yan status = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* check if there are any hot plug interrupts occurred */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (!(status & PCIE_SLOTSTS_STATUS_EVENTS)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* no hot plug events occurred */
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_exit(&ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_INTR_UNCLAIMED);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* clear the interrupt status bits */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_reg_put16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* check for CMD COMPLETE interrupt */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_intr(): CMD COMPLETED interrupt received\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* wake up any one waiting for Command Completion event */
269473047d747f7815af570197e4ef7322d3632cEvan Yan cv_signal(&ctrl_p->hc_cmd_comp_cv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* check for ATTN button interrupt */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (status & PCIE_SLOTSTS_ATTN_BTN_PRESSED) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_intr(): ATTN BUTTON interrupt received\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* if ATTN button event is still pending then cancel it */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (slot_p->hs_attn_btn_pending == B_TRUE)
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_attn_btn_pending = B_FALSE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan else
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_attn_btn_pending = B_TRUE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* wake up the ATTN event handler */
269473047d747f7815af570197e4ef7322d3632cEvan Yan cv_signal(&slot_p->hs_attn_btn_cv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* check for power fault interrupt */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (status & PCIE_SLOTSTS_PWR_FAULT_DETECTED) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_intr(): POWER FAULT interrupt received"
269473047d747f7815af570197e4ef7322d3632cEvan Yan " on slot %d\n", slot_p->hs_phy_slot_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan control = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (control & PCIE_SLOTCTL_PWR_FAULT_EN) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_condition = AP_COND_FAILED;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* disable power fault detction interrupt */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_SLOTCTL, control & ~PCIE_SLOTCTL_PWR_FAULT_EN);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China pciehpc_handle_power_fault(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* check for MRL SENSOR CHANGED interrupt */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (status & PCIE_SLOTSTS_MRL_SENSOR_CHANGED) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* For now (phase-I), no action is taken on this event */
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_intr(): MRL SENSOR CHANGED interrupt received"
269473047d747f7815af570197e4ef7322d3632cEvan Yan " on slot %d\n", slot_p->hs_phy_slot_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* check for PRESENCE CHANGED interrupt */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (status & PCIE_SLOTSTS_PRESENCE_CHANGED) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_intr(): PRESENCE CHANGED interrupt received"
269473047d747f7815af570197e4ef7322d3632cEvan Yan " on slot %d\n", slot_p->hs_phy_slot_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (status & PCIE_SLOTSTS_PRESENCE_DETECTED) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * card is inserted into the slot, ask DDI Hotplug
269473047d747f7815af570197e4ef7322d3632cEvan Yan * framework to change state to Present.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
70f83219d49a3acf5c2deeefddb48c720ab5f832Evan Yan cmn_err(CE_NOTE, "pciehpc (%s%d): card is inserted"
70f83219d49a3acf5c2deeefddb48c720ab5f832Evan Yan " in the slot %s",
70f83219d49a3acf5c2deeefddb48c720ab5f832Evan Yan ddi_driver_name(dip),
70f83219d49a3acf5c2deeefddb48c720ab5f832Evan Yan ddi_get_instance(dip),
70f83219d49a3acf5c2deeefddb48c720ab5f832Evan Yan slot_p->hs_info.cn_name);
70f83219d49a3acf5c2deeefddb48c720ab5f832Evan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) ndi_hp_state_change_req(dip,
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_info.cn_name,
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_CN_STATE_PRESENT,
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_REQ_ASYNC);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else { /* card is removed from the slot */
269473047d747f7815af570197e4ef7322d3632cEvan Yan cmn_err(CE_NOTE, "pciehpc (%s%d): card is removed"
269473047d747f7815af570197e4ef7322d3632cEvan Yan " from the slot %s",
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_driver_name(dip),
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_get_instance(dip),
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_info.cn_name);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (slot_p->hs_info.cn_state ==
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_CN_STATE_ENABLED) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Card is removed when slot is enabled */
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_condition = AP_COND_FAILED;
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_condition = AP_COND_UNKNOWN;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* make sure to disable power fault detction intr */
269473047d747f7815af570197e4ef7322d3632cEvan Yan control = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (control & PCIE_SLOTCTL_PWR_FAULT_EN)
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_SLOTCTL,
269473047d747f7815af570197e4ef7322d3632cEvan Yan control & ~PCIE_SLOTCTL_PWR_FAULT_EN);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Ask DDI Hotplug framework to change state to Empty
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) ndi_hp_state_change_req(dip,
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_info.cn_name,
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_CN_STATE_EMPTY,
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_REQ_ASYNC);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* check for DLL state changed interrupt */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ctrl_p->hc_dll_active_rep &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan (status & PCIE_SLOTSTS_DLL_STATE_CHANGED)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_intr(): DLL STATE CHANGED interrupt received"
269473047d747f7815af570197e4ef7322d3632cEvan Yan " on slot %d\n", slot_p->hs_phy_slot_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan cv_signal(&slot_p->hs_dll_active_cv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_exit(&ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_INTR_CLAIMED);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Handle hotplug commands
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Note: This function is called by DDI HP framework at kernel context only
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan/* ARGSUSED */
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_hp_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op,
269473047d747f7815af570197e4ef7322d3632cEvan Yan void *arg, void *result)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_ctrl_t *ctrl_p;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_slot_t *slot_p;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int ret = DDI_SUCCESS;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_hp_ops: dip=%p cn_name=%s op=%x arg=%p\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan dip, cn_name, op, arg);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p = ctrl_p->hc_slots[0];
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (strcmp(cn_name, slot_p->hs_info.cn_name) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan switch (op) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HPOP_CN_GET_STATE:
269473047d747f7815af570197e4ef7322d3632cEvan Yan {
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_enter(&slot_p->hs_ctrl->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the current slot state */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_get_slot_state(slot_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan *((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_exit(&slot_p->hs_ctrl->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HPOP_CN_CHANGE_STATE:
269473047d747f7815af570197e4ef7322d3632cEvan Yan {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_enter(&slot_p->hs_ctrl->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pciehpc_change_slot_state(slot_p, target_state);
269473047d747f7815af570197e4ef7322d3632cEvan Yan *(ddi_hp_cn_state_t *)result = slot_p->hs_info.cn_state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_exit(&slot_p->hs_ctrl->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HPOP_CN_PROBE:
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pciehpc_slot_probe(slot_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HPOP_CN_UNPROBE:
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pciehpc_slot_unprobe(slot_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HPOP_CN_GET_PROPERTY:
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pciehpc_slot_get_property(slot_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HPOP_CN_SET_PROPERTY:
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pciehpc_slot_set_property(slot_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan default:
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_ENOTSUP;
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Get the current state of the slot from the hw.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * The slot state should have been initialized before this function gets called.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanvoid
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_get_slot_state(pcie_hp_slot_t *slot_p)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint16_t control, status;
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_state_t curr_state = slot_p->hs_info.cn_state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* read the Slot Control Register */
269473047d747f7815af570197e4ef7322d3632cEvan Yan control = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_fault_led_state = PCIE_HP_LED_OFF; /* no fault led */
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_active_led_state = PCIE_HP_LED_OFF; /* no active led */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* read the current Slot Status Register */
269473047d747f7815af570197e4ef7322d3632cEvan Yan status = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get POWER led state */
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_power_led_state =
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get ATTN led state */
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_attn_led_state =
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_led_state_to_hpc(pcie_slotctl_attn_indicator_get(control));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* no device present; slot is empty */
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* device is present */
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_info.cn_state = DDI_HP_CN_STATE_PRESENT;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Device is powered on. Set to "ENABLED" state (skip
269473047d747f7815af570197e4ef7322d3632cEvan Yan * POWERED state) because there is not a explicit "enable"
269473047d747f7815af570197e4ef7322d3632cEvan Yan * action exists for PCIe.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If it is already in "POWERED" state, then keep it until
269473047d747f7815af570197e4ef7322d3632cEvan Yan * user explicitly change it to other states.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (curr_state == DDI_HP_CN_STATE_POWERED) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_info.cn_state = curr_state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_info.cn_state = DDI_HP_CN_STATE_ENABLED;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * setup slot name/slot-number info.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanvoid
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan uchar_t *slotname_data;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int *slotnum;
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint_t count;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int len;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int invalid_slotnum = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint32_t slot_capabilities;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ctrl_p->hc_dip,
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_PROP_DONTPASS, "physical-slot#", &slotnum, &count) ==
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_PROP_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_phy_slot_num = slotnum[0];
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_prop_free(slotnum);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_capabilities = pciehpc_reg_get32(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCAP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_phy_slot_num =
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_SLOTCAP_PHY_SLOT_NUM(slot_capabilities);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* platform may not have initialized it */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (!slot_p->hs_phy_slot_num) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("%s#%d: Invalid slot number!\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_driver_name(ctrl_p->hc_dip),
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_get_instance(ctrl_p->hc_dip));
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_phy_slot_num = pciehpc_reg_get8(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCI_BCNF_SECBUS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan invalid_slotnum = 1;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_info.cn_num = slot_p->hs_phy_slot_num;
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_info.cn_num_dpd_on = DDI_HP_CN_NUM_NONE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * construct the slot_name:
269473047d747f7815af570197e4ef7322d3632cEvan Yan * if "slot-names" property exists then use that name
269473047d747f7815af570197e4ef7322d3632cEvan Yan * else if valid slot number exists then it is "pcie<slot-num>".
269473047d747f7815af570197e4ef7322d3632cEvan Yan * else it will be "pcie<sec-bus-number>dev0"
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, ctrl_p->hc_dip, DDI_PROP_DONTPASS,
269473047d747f7815af570197e4ef7322d3632cEvan Yan "slot-names", (caddr_t)&slotname_data, &len) == DDI_PROP_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan char tmp_name[256];
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Note: for PCI-E slots, the device number is always 0 so the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * first (and only) string is the slot name for this slot.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) snprintf(tmp_name, sizeof (tmp_name),
269473047d747f7815af570197e4ef7322d3632cEvan Yan (char *)slotname_data + 4);
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_info.cn_name = ddi_strdup(tmp_name, KM_SLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(slotname_data, len);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (invalid_slotnum) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* use device number ie. 0 */
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_info.cn_name = ddi_strdup("pcie0",
269473047d747f7815af570197e4ef7322d3632cEvan Yan KM_SLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan char tmp_name[256];
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) snprintf(tmp_name, sizeof (tmp_name), "pcie%d",
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_phy_slot_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_info.cn_name = ddi_strdup(tmp_name,
269473047d747f7815af570197e4ef7322d3632cEvan Yan KM_SLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Read/Write access to HPC registers. If platform nexus has non-standard
269473047d747f7815af570197e4ef7322d3632cEvan Yan * HPC access mechanism then regops functions are used to do reads/writes.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanuint8_t
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_reg_get8(pcie_hp_ctrl_t *ctrl_p, uint_t off)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ctrl_p->hc_regops.get != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan return ((uint8_t)ctrl_p->hc_regops.get(
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_regops.cookie, (off_t)off));
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (pci_config_get8(bus_p->bus_cfg_hdl, off));
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanuint16_t
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_reg_get16(pcie_hp_ctrl_t *ctrl_p, uint_t off)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ctrl_p->hc_regops.get != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan return ((uint16_t)ctrl_p->hc_regops.get(
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_regops.cookie, (off_t)off));
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (pci_config_get16(bus_p->bus_cfg_hdl, off));
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanuint32_t
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_reg_get32(pcie_hp_ctrl_t *ctrl_p, uint_t off)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ctrl_p->hc_regops.get != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan return ((uint32_t)ctrl_p->hc_regops.get(
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_regops.cookie, (off_t)off));
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (pci_config_get32(bus_p->bus_cfg_hdl, off));
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanvoid
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_reg_put8(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint8_t val)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ctrl_p->hc_regops.put != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
269473047d747f7815af570197e4ef7322d3632cEvan Yan (off_t)off, (uint_t)val);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan pci_config_put8(bus_p->bus_cfg_hdl, off, val);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanvoid
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_reg_put16(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint16_t val)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ctrl_p->hc_regops.put != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
269473047d747f7815af570197e4ef7322d3632cEvan Yan (off_t)off, (uint_t)val);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan pci_config_put16(bus_p->bus_cfg_hdl, off, val);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanvoid
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_reg_put32(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint32_t val)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ctrl_p->hc_regops.put != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
269473047d747f7815af570197e4ef7322d3632cEvan Yan (off_t)off, (uint_t)val);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan pci_config_put32(bus_p->bus_cfg_hdl, off, val);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * ************************************************************************
269473047d747f7815af570197e4ef7322d3632cEvan Yan * *** Local functions (called within this file)
269473047d747f7815af570197e4ef7322d3632cEvan Yan * *** PCIe Native Hotplug mode specific functions
269473047d747f7815af570197e4ef7322d3632cEvan Yan * ************************************************************************
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Initialize HPC hardware, install interrupt handler, etc. It doesn't
269473047d747f7815af570197e4ef7322d3632cEvan Yan * enable hot plug interrupts.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * (Note: It is called only from pciehpc_init().)
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_hpc_init(pcie_hp_ctrl_t *ctrl_p)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint16_t reg;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* read the Slot Control Register */
269473047d747f7815af570197e4ef7322d3632cEvan Yan reg = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* disable all interrupts */
269473047d747f7815af570197e4ef7322d3632cEvan Yan reg &= ~(PCIE_SLOTCTL_INTR_MASK);
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_SLOTCTL, reg);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* clear any interrupt status bits */
269473047d747f7815af570197e4ef7322d3632cEvan Yan reg = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_reg_put16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Uninitialize HPC hardware, uninstall interrupt handler, etc.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * (Note: It is called only from pciehpc_uninit().)
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_hpc_uninit(pcie_hp_ctrl_t *ctrl_p)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* disable interrupts */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) pciehpc_disable_intr(ctrl_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Setup slot information for use with DDI HP framework.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_slotinfo_init(pcie_hp_ctrl_t *ctrl_p)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint32_t slot_capabilities, link_capabilities;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_enter(&ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * setup DDI HP framework slot information structure
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_device_num = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_info.cn_type = DDI_HP_CN_TYPE_PCIE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_info.cn_type_str = (ctrl_p->hc_regops.get == NULL) ?
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_NATIVE_HP_TYPE : PCIE_PROP_HP_TYPE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_info.cn_child = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_minor =
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCI_MINOR_NUM(ddi_get_instance(ctrl_p->hc_dip),
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_device_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_condition = AP_COND_UNKNOWN;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* read Slot Capabilities Register */
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_capabilities = pciehpc_reg_get32(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCAP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* set slot-name/slot-number info */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_set_slot_name(ctrl_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* check if Attn Button present */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_has_attn = (slot_capabilities & PCIE_SLOTCAP_ATTN_BUTTON) ?
269473047d747f7815af570197e4ef7322d3632cEvan Yan B_TRUE : B_FALSE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* check if Manual Retention Latch sensor present */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_has_mrl = (slot_capabilities & PCIE_SLOTCAP_MRL_SENSOR) ?
269473047d747f7815af570197e4ef7322d3632cEvan Yan B_TRUE : B_FALSE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * PCI-E version 1.1 defines EMI Lock Present bit
269473047d747f7815af570197e4ef7322d3632cEvan Yan * in Slot Capabilities register. Check for it.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_has_emi_lock = (slot_capabilities &
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_SLOTCAP_EMI_LOCK_PRESENT) ? B_TRUE : B_FALSE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan link_capabilities = pciehpc_reg_get32(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_LINKCAP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_dll_active_rep = (link_capabilities &
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_LINKCAP_DLL_ACTIVE_REP_CAPABLE) ? B_TRUE : B_FALSE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ctrl_p->hc_dll_active_rep)
269473047d747f7815af570197e4ef7322d3632cEvan Yan cv_init(&slot_p->hs_dll_active_cv, NULL, CV_DRIVER, NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* setup thread for handling ATTN button events */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ctrl_p->hc_has_attn) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_slotinfo_init: setting up ATTN button event "
269473047d747f7815af570197e4ef7322d3632cEvan Yan "handler thread for slot %d\n", slot_p->hs_phy_slot_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan cv_init(&slot_p->hs_attn_btn_cv, NULL, CV_DRIVER, NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_attn_btn_pending = B_FALSE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_attn_btn_threadp = thread_create(NULL, 0,
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_attn_btn_handler,
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void *)ctrl_p, 0, &p0, TS_RUN, minclsyspri);
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_attn_btn_thread_exit = B_FALSE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get current slot state from the hw */
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_get_slot_state(slot_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_ENABLED)
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_condition = AP_COND_OK;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_exit(&ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*ARGSUSED*/
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (slot_p->hs_attn_btn_threadp != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_enter(&ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_attn_btn_thread_exit = B_TRUE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan cv_signal(&slot_p->hs_attn_btn_cv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_slotinfo_uninit: "
269473047d747f7815af570197e4ef7322d3632cEvan Yan "waiting for ATTN thread exit\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_slotinfo_uninit: ATTN thread exit\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan cv_destroy(&slot_p->hs_attn_btn_cv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_attn_btn_threadp = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_exit(&ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ctrl_p->hc_dll_active_rep)
269473047d747f7815af570197e4ef7322d3632cEvan Yan cv_destroy(&slot_p->hs_dll_active_cv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (slot_p->hs_info.cn_name)
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(slot_p->hs_info.cn_name,
269473047d747f7815af570197e4ef7322d3632cEvan Yan strlen(slot_p->hs_info.cn_name) + 1);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Enable hot plug interrupts.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Note: this is only for Native hot plug mode.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_enable_intr(pcie_hp_ctrl_t *ctrl_p)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint16_t reg;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* clear any interrupt status bits */
269473047d747f7815af570197e4ef7322d3632cEvan Yan reg = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_reg_put16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* read the Slot Control Register */
269473047d747f7815af570197e4ef7322d3632cEvan Yan reg = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * enable interrupts: power fault detection interrupt is enabled
269473047d747f7815af570197e4ef7322d3632cEvan Yan * only when the slot is powered ON
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_SLOTCTL, reg | PCIE_SLOTCTL_INTR_MASK);
269473047d747f7815af570197e4ef7322d3632cEvan Yan else
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_SLOTCTL, reg | (PCIE_SLOTCTL_INTR_MASK &
269473047d747f7815af570197e4ef7322d3632cEvan Yan ~PCIE_SLOTCTL_PWR_FAULT_EN));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Disable hot plug interrupts.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Note: this is only for Native hot plug mode.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_disable_intr(pcie_hp_ctrl_t *ctrl_p)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint16_t reg;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* read the Slot Control Register */
269473047d747f7815af570197e4ef7322d3632cEvan Yan reg = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* disable all interrupts */
269473047d747f7815af570197e4ef7322d3632cEvan Yan reg &= ~(PCIE_SLOTCTL_INTR_MASK);
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTCTL, reg);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* clear any interrupt status bits */
269473047d747f7815af570197e4ef7322d3632cEvan Yan reg = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_reg_put16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Allocate a new hotplug controller and slot structures for HPC
269473047d747f7815af570197e4ef7322d3632cEvan Yan * associated with this dip.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic pcie_hp_ctrl_t *
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_create_controller(dev_info_t *dip)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_ctrl_t *ctrl_p;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p = kmem_zalloc(sizeof (pcie_hp_ctrl_t), KM_SLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_dip = dip;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Allocate a new slot structure. */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_slots[0] = kmem_zalloc(sizeof (pcie_hp_slot_t), KM_SLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_slots[0]->hs_num = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_slots[0]->hs_ctrl = ctrl_p;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize the interrupt mutex */
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_init(&ctrl_p->hc_mutex, NULL, MUTEX_DRIVER,
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void *)PCIE_INTR_PRI);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize synchronization conditional variable */
269473047d747f7815af570197e4ef7322d3632cEvan Yan cv_init(&ctrl_p->hc_cmd_comp_cv, NULL, CV_DRIVER, NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_cmd_pending = B_FALSE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_hp_curr_mode = PCIE_NATIVE_HP_MODE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_SET_HP_CTRL(dip, ctrl_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ctrl_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Remove the HPC controller and slot structures
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_destroy_controller(dev_info_t *dip)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_ctrl_t *ctrl_p;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the soft state structure for this dip */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_SET_HP_CTRL(dip, NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_hp_curr_mode = PCIE_NONE_HP_MODE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_destroy(&ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan cv_destroy(&ctrl_p->hc_cmd_comp_cv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(ctrl_p->hc_slots[0], sizeof (pcie_hp_slot_t));
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(ctrl_p, sizeof (pcie_hp_ctrl_t));
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Register the PCI-E hot plug slot with DDI HP framework.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_register_slot(pcie_hp_ctrl_t *ctrl_p)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
269473047d747f7815af570197e4ef7322d3632cEvan Yan dev_info_t *dip = ctrl_p->hc_dip;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* register the slot with DDI HP framework */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ndi_hp_register(dip, &slot_p->hs_info) != NDI_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_register_slot() failed to register slot %d\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_phy_slot_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip),
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_minor), slot_p->hs_device_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_register_slot(): registered slot %d\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_phy_slot_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Unregister the PCI-E hot plug slot from DDI HP framework.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_unregister_slot(pcie_hp_ctrl_t *ctrl_p)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
269473047d747f7815af570197e4ef7322d3632cEvan Yan dev_info_t *dip = ctrl_p->hc_dip;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_delete_occupant_props(dip, makedevice(ddi_driver_major(dip),
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_minor));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* unregister the slot with DDI HP framework */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ndi_hp_unregister(dip, slot_p->hs_info.cn_name) != NDI_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_unregister_slot() "
269473047d747f7815af570197e4ef7322d3632cEvan Yan "failed to unregister slot %d\n", slot_p->hs_phy_slot_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_unregister_slot(): unregistered slot %d\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_phy_slot_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * pciehpc_slot_poweron()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Poweron/Enable the slot.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Note: This function is called by DDI HP framework at kernel context only
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*ARGSUSED*/
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint16_t status, control;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the current state of the slot */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_get_slot_state(slot_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* check if the slot is already in the 'enabled' state */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* slot is already in the 'enabled' state */
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_slot_poweron() slot %d already enabled\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_phy_slot_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan *result = slot_p->hs_info.cn_state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* read the Slot Status Register */
269473047d747f7815af570197e4ef7322d3632cEvan Yan status = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* make sure the MRL switch is closed if present */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((ctrl_p->hc_has_mrl) && (status & PCIE_SLOTSTS_MRL_SENSOR_OPEN)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* MRL switch is open */
269473047d747f7815af570197e4ef7322d3632cEvan Yan cmn_err(CE_WARN, "MRL switch is open on slot %d\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_phy_slot_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto cleanup;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* make sure the slot has a device present */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* slot is empty */
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("slot %d is empty\n", slot_p->hs_phy_slot_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto cleanup;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the current state of Slot Control Register */
269473047d747f7815af570197e4ef7322d3632cEvan Yan control = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Enable power to the slot involves:
269473047d747f7815af570197e4ef7322d3632cEvan Yan * 1. Set power LED to blink and ATTN led to OFF.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * 2. Set power control ON in Slot Control Reigster and
269473047d747f7815af570197e4ef7322d3632cEvan Yan * wait for Command Completed Interrupt or 1 sec timeout.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * 3. If Data Link Layer State Changed events are supported
269473047d747f7815af570197e4ef7322d3632cEvan Yan * then wait for the event to indicate Data Layer Link
269473047d747f7815af570197e4ef7322d3632cEvan Yan * is active. The time out value for this event is 1 second.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * This is specified in PCI-E version 1.1.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * 4. Set power LED to be ON.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* 1. set power LED to blink & ATTN led to OFF */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* 2. set power control to ON */
269473047d747f7815af570197e4ef7322d3632cEvan Yan control = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan control &= ~PCIE_SLOTCTL_PWR_CONTROL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_issue_hpc_command(ctrl_p, control);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* 3. wait for DLL State Change event, if it's supported */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ctrl_p->hc_dll_active_rep) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan status = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_LINKSTS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (!(status & PCIE_LINKSTS_DLL_LINK_ACTIVE)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* wait 1 sec for the DLL State Changed event */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) cv_timedwait(&slot_p->hs_dll_active_cv,
269473047d747f7815af570197e4ef7322d3632cEvan Yan &ctrl_p->hc_mutex,
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_get_lbolt() +
269473047d747f7815af570197e4ef7322d3632cEvan Yan SEC_TO_TICK(PCIE_HP_DLL_STATE_CHANGE_TIMEOUT));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* check Link status */
269473047d747f7815af570197e4ef7322d3632cEvan Yan status = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off +
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_LINKSTS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (!(status & PCIE_LINKSTS_DLL_LINK_ACTIVE))
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto cleanup2;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* wait 1 sec for link to come up */
269473047d747f7815af570197e4ef7322d3632cEvan Yan delay(drv_usectohz(1000000));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* check power is really turned ON */
269473047d747f7815af570197e4ef7322d3632cEvan Yan control = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (control & PCIE_SLOTCTL_PWR_CONTROL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("slot %d fails to turn on power on connect\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_phy_slot_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto cleanup1;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* clear power fault status */
269473047d747f7815af570197e4ef7322d3632cEvan Yan status = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan status |= PCIE_SLOTSTS_PWR_FAULT_DETECTED;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTSTS,
269473047d747f7815af570197e4ef7322d3632cEvan Yan status);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* enable power fault detection interrupt */
269473047d747f7815af570197e4ef7322d3632cEvan Yan control |= PCIE_SLOTCTL_PWR_FAULT_EN;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_issue_hpc_command(ctrl_p, control);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* 4. Set power LED to be ON */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_ON);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* if EMI is present, turn it ON */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ctrl_p->hc_has_emi_lock) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan status = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (!(status & PCIE_SLOTSTS_EMI_LOCK_SET)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan control = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_issue_hpc_command(ctrl_p, control);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* wait 1 sec after toggling the state of EMI lock */
269473047d747f7815af570197e4ef7322d3632cEvan Yan delay(drv_usectohz(1000000));
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan *result = slot_p->hs_info.cn_state =
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_CN_STATE_POWERED;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yancleanup2:
269473047d747f7815af570197e4ef7322d3632cEvan Yan control = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* if power is ON, set power control to OFF */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan control |= PCIE_SLOTCTL_PWR_CONTROL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_issue_hpc_command(ctrl_p, control);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yancleanup1:
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* set power led to OFF */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yancleanup:
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*ARGSUSED*/
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint16_t status, control;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the current state of the slot */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_get_slot_state(slot_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* check if the slot is not in the "enabled' state */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* slot is in the 'disabled' state */
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_slot_poweroff(): "
269473047d747f7815af570197e4ef7322d3632cEvan Yan "slot %d already disabled\n", slot_p->hs_phy_slot_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT(slot_p->hs_power_led_state == PCIE_HP_LED_OFF);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan *result = slot_p->hs_info.cn_state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* read the Slot Status Register */
269473047d747f7815af570197e4ef7322d3632cEvan Yan status = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* make sure the slot has a device present */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* slot is empty */
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_slot_poweroff(): slot %d is empty\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_phy_slot_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto cleanup;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Disable power to the slot involves:
269473047d747f7815af570197e4ef7322d3632cEvan Yan * 1. Set power LED to blink.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * 2. Set power control OFF in Slot Control Reigster and
269473047d747f7815af570197e4ef7322d3632cEvan Yan * wait for Command Completed Interrupt or 1 sec timeout.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * 3. Set POWER led and ATTN led to be OFF.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* 1. set power LED to blink */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* disable power fault detection interrupt */
269473047d747f7815af570197e4ef7322d3632cEvan Yan control = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan control &= ~PCIE_SLOTCTL_PWR_FAULT_EN;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_issue_hpc_command(ctrl_p, control);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* 2. set power control to OFF */
269473047d747f7815af570197e4ef7322d3632cEvan Yan control = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan control |= PCIE_SLOTCTL_PWR_CONTROL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_issue_hpc_command(ctrl_p, control);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan#ifdef DEBUG
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* check for power control bit to be OFF */
269473047d747f7815af570197e4ef7322d3632cEvan Yan control = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT(control & PCIE_SLOTCTL_PWR_CONTROL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan#endif
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* 3. Set power LED to be OFF */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* if EMI is present, turn it OFF */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ctrl_p->hc_has_emi_lock) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan status = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (status & PCIE_SLOTSTS_EMI_LOCK_SET) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan control = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_issue_hpc_command(ctrl_p, control);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* wait 1 sec after toggling the state of EMI lock */
269473047d747f7815af570197e4ef7322d3632cEvan Yan delay(drv_usectohz(1000000));
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the current state of the slot */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_get_slot_state(slot_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan *result = slot_p->hs_info.cn_state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yancleanup:
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * pciehpc_slot_probe()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Probe the slot.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Note: This function is called by DDI HP framework at kernel context only
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*ARGSUSED*/
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_slot_probe(pcie_hp_slot_t *slot_p)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int ret = DDI_SUCCESS;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_enter(&ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the current state of the slot */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_get_slot_state(slot_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Probe a given PCIe Hotplug Connection (CN).
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DISABLE_ERRORS(ctrl_p->hc_dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pcie_hp_probe(slot_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ret != DDI_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_slot_probe() failed\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* turn the ATTN led ON for configure failure */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_ON);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* if power to the slot is still on then set Power led to ON */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_HP_LED_ON);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_exit(&ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_ENABLE_ERRORS(ctrl_p->hc_dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the current state of the slot */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_get_slot_state(slot_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_exit(&ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * pciehpc_slot_unprobe()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Unprobe the slot.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Note: This function is called by DDI HP framework at kernel context only
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*ARGSUSED*/
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_slot_unprobe(pcie_hp_slot_t *slot_p)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int ret;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_enter(&ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the current state of the slot */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_get_slot_state(slot_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Unprobe a given PCIe Hotplug Connection (CN).
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DISABLE_ERRORS(ctrl_p->hc_dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = pcie_hp_unprobe(slot_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (ret != DDI_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_slot_unprobe() failed\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* if power to the slot is still on then set Power led to ON */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_HP_LED_ON);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_ENABLE_ERRORS(ctrl_p->hc_dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_exit(&ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the current state of the slot */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_get_slot_state(slot_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_exit(&ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_state_t target_state)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_state_t curr_state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv = DDI_SUCCESS;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (target_state > DDI_HP_CN_STATE_ENABLED) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_EINVAL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan curr_state = slot_p->hs_info.cn_state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan while ((curr_state < target_state) && (rv == DDI_SUCCESS)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan switch (curr_state) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HP_CN_STATE_EMPTY:
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * From EMPTY to PRESENT, just check the hardware
269473047d747f7815af570197e4ef7322d3632cEvan Yan * slot state.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_get_slot_state(slot_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan curr_state = slot_p->hs_info.cn_state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (curr_state < DDI_HP_CN_STATE_PRESENT)
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = DDI_FAILURE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HP_CN_STATE_PRESENT:
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = (slot_p->hs_ctrl->hc_ops.poweron_hpc_slot)(slot_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan &curr_state);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HP_CN_STATE_POWERED:
269473047d747f7815af570197e4ef7322d3632cEvan Yan curr_state = slot_p->hs_info.cn_state =
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_CN_STATE_ENABLED;
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan default:
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* should never reach here */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT("unknown devinfo state");
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_state_t target_state)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_state_t curr_state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv = DDI_SUCCESS;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan curr_state = slot_p->hs_info.cn_state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan while ((curr_state > target_state) && (rv == DDI_SUCCESS)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan switch (curr_state) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HP_CN_STATE_PRESENT:
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * From PRESENT to EMPTY, just check hardware slot
269473047d747f7815af570197e4ef7322d3632cEvan Yan * state.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_get_slot_state(slot_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan curr_state = slot_p->hs_info.cn_state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (curr_state >= DDI_HP_CN_STATE_PRESENT)
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = DDI_FAILURE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HP_CN_STATE_POWERED:
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = (slot_p->hs_ctrl->hc_ops.poweroff_hpc_slot)(
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p, &curr_state);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan case DDI_HP_CN_STATE_ENABLED:
269473047d747f7815af570197e4ef7322d3632cEvan Yan curr_state = slot_p->hs_info.cn_state =
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_CN_STATE_POWERED;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan default:
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* should never reach here */
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT("unknown devinfo state");
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/* Change slot state to a target state */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_change_slot_state(pcie_hp_slot_t *slot_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_state_t target_state)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_cn_state_t curr_state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int rv;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_get_slot_state(slot_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan curr_state = slot_p->hs_info.cn_state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (curr_state == target_state) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_SUCCESS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (curr_state < target_state) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = pciehpc_upgrade_slot_state(slot_p, target_state);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan rv = pciehpc_downgrade_slot_state(slot_p, target_state);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (rv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_slot_get_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_property_t *rval)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_property_t request, result;
269473047d747f7815af570197e4ef7322d3632cEvan Yan#ifdef _SYSCALL32_IMPL
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_property32_t request32, result32;
269473047d747f7815af570197e4ef7322d3632cEvan Yan#endif
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *prop_list;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *prop_rlist; /* nvlist for return values */
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvpair_t *prop_pair;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *name, *value;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int ret = DDI_SUCCESS;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int i, n;
269473047d747f7815af570197e4ef7322d3632cEvan Yan boolean_t get_all_prop = B_FALSE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (get_udatamodel() == DATAMODEL_NATIVE) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (copyin(arg, &request, sizeof (ddi_hp_property_t)) ||
269473047d747f7815af570197e4ef7322d3632cEvan Yan copyin(rval, &result, sizeof (ddi_hp_property_t)))
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan#ifdef _SYSCALL32_IMPL
269473047d747f7815af570197e4ef7322d3632cEvan Yan else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan bzero(&request, sizeof (request));
269473047d747f7815af570197e4ef7322d3632cEvan Yan bzero(&result, sizeof (result));
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)) ||
269473047d747f7815af570197e4ef7322d3632cEvan Yan copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
269473047d747f7815af570197e4ef7322d3632cEvan Yan request.buf_size = request32.buf_size;
269473047d747f7815af570197e4ef7322d3632cEvan Yan result.nvlist_buf = (char *)(uintptr_t)result32.nvlist_buf;
269473047d747f7815af570197e4ef7322d3632cEvan Yan result.buf_size = result32.buf_size;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan#endif
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
269473047d747f7815af570197e4ef7322d3632cEvan Yan &prop_list)) != DDI_SUCCESS)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_ENOMEM;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto get_prop_cleanup;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* check whether the requested property is "all" or "help" */
269473047d747f7815af570197e4ef7322d3632cEvan Yan prop_pair = nvlist_next_nvpair(prop_list, NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan name = nvpair_name(prop_pair);
269473047d747f7815af570197e4ef7322d3632cEvan Yan n = sizeof (pciehpc_props) / sizeof (pciehpc_prop_t);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (strcmp(name, PCIEHPC_PROP_ALL) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) nvlist_remove_all(prop_list, PCIEHPC_PROP_ALL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Add all properties into the request list, so that we
269473047d747f7815af570197e4ef7322d3632cEvan Yan * will get the values in the following for loop.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (i = 0; i < n; i++) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_add_string(prop_list,
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_props[i].prop_name, "") != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_FAILURE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto get_prop_cleanup1;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan get_all_prop = B_TRUE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else if (strcmp(name, PCIEHPC_PROP_HELP) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Empty the request list, and add help strings into the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * return list. We will pass the following for loop.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) nvlist_remove_all(prop_list, PCIEHPC_PROP_HELP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (i = 0; i < n; i++) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_add_string(prop_rlist,
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_props[i].prop_name,
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_props[i].prop_value) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_FAILURE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto get_prop_cleanup1;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_enter(&ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the current slot state */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_get_slot_state(slot_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* for each requested property, get the value and add it to nvlist */
269473047d747f7815af570197e4ef7322d3632cEvan Yan prop_pair = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan name = nvpair_name(prop_pair);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (strcmp(name, PCIEHPC_PROP_LED_FAULT) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan value = pcie_led_state_text(
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_fault_led_state);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else if (strcmp(name, PCIEHPC_PROP_LED_POWER) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan value = pcie_led_state_text(
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_power_led_state);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan value = pcie_led_state_text(
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_attn_led_state);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else if (strcmp(name, PCIEHPC_PROP_LED_ACTIVE) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan value = pcie_led_state_text(
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_active_led_state);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else if (strcmp(name, PCIEHPC_PROP_CARD_TYPE) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_acc_handle_t handle;
269473047d747f7815af570197e4ef7322d3632cEvan Yan dev_info_t *cdip;
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint8_t prog_class, base_class, sub_class;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int i;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_exit(&ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan cdip = pcie_hp_devi_find(
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_dip, slot_p->hs_device_num, 0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_enter(&ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((slot_p->hs_info.cn_state
269473047d747f7815af570197e4ef7322d3632cEvan Yan != DDI_HP_CN_STATE_ENABLED) || (cdip == NULL)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * When getting all properties, just ignore the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * one that's not available under certain state.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (get_all_prop)
269473047d747f7815af570197e4ef7322d3632cEvan Yan continue;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_ENOTSUP;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto get_prop_cleanup2;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (pci_config_setup(cdip, &handle) != DDI_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_FAILURE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto get_prop_cleanup2;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan prog_class = pci_config_get8(handle,
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCI_CONF_PROGCLASS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan base_class = pci_config_get8(handle, PCI_CONF_BASCLASS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan sub_class = pci_config_get8(handle, PCI_CONF_SUBCLASS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan pci_config_teardown(&handle);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (i = 0; i < class_pci_items; i++) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((base_class == class_pci[i].base_class) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan (sub_class == class_pci[i].sub_class) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan (prog_class == class_pci[i].prog_class)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan value = class_pci[i].short_desc;
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (i == class_pci_items)
269473047d747f7815af570197e4ef7322d3632cEvan Yan value = PCIEHPC_PROP_VALUE_UNKNOWN;
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else if (strcmp(name, PCIEHPC_PROP_BOARD_TYPE) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (slot_p->hs_info.cn_state <= DDI_HP_CN_STATE_EMPTY)
269473047d747f7815af570197e4ef7322d3632cEvan Yan value = PCIEHPC_PROP_VALUE_UNKNOWN;
269473047d747f7815af570197e4ef7322d3632cEvan Yan else
269473047d747f7815af570197e4ef7322d3632cEvan Yan value = PCIEHPC_PROP_VALUE_PCIHOTPLUG;
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else if (strcmp(name, PCIEHPC_PROP_SLOT_CONDITION) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan value = pcie_slot_condition_text(slot_p->hs_condition);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* unsupported property */
24fd5dc40967be3acf455139813c114a29e7c529Evan Yan PCIE_DBG("Unsupported property: %s\n", name);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_ENOTSUP;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto get_prop_cleanup2;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_add_string(prop_rlist, name, value) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_FAILURE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto get_prop_cleanup2;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* pack nvlist and copyout */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
269473047d747f7815af570197e4ef7322d3632cEvan Yan &result.buf_size)) != DDI_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto get_prop_cleanup2;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (get_udatamodel() == DATAMODEL_NATIVE) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (copyout(&result, rval, sizeof (ddi_hp_property_t)))
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_FAILURE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan#ifdef _SYSCALL32_IMPL
269473047d747f7815af570197e4ef7322d3632cEvan Yan else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (result.buf_size > UINT32_MAX) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_FAILURE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan result32.buf_size = (uint32_t)result.buf_size;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (copyout(&result32, rval,
269473047d747f7815af570197e4ef7322d3632cEvan Yan sizeof (ddi_hp_property32_t)))
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_FAILURE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan#endif
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanget_prop_cleanup2:
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_exit(&ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yanget_prop_cleanup1:
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(prop_rlist);
269473047d747f7815af570197e4ef7322d3632cEvan Yanget_prop_cleanup:
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(prop_list);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanint
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_slot_set_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_property_t *rval)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_property_t request, result;
269473047d747f7815af570197e4ef7322d3632cEvan Yan#ifdef _SYSCALL32_IMPL
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_hp_property32_t request32, result32;
269473047d747f7815af570197e4ef7322d3632cEvan Yan#endif
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *prop_list;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_t *prop_rlist;
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvpair_t *prop_pair;
269473047d747f7815af570197e4ef7322d3632cEvan Yan char *name, *value;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_led_state_t led_state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan int ret = DDI_SUCCESS;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (get_udatamodel() == DATAMODEL_NATIVE) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (copyin(arg, &request, sizeof (ddi_hp_property_t)))
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rval &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan copyin(rval, &result, sizeof (ddi_hp_property_t)))
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan#ifdef _SYSCALL32_IMPL
269473047d747f7815af570197e4ef7322d3632cEvan Yan else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan bzero(&request, sizeof (request));
269473047d747f7815af570197e4ef7322d3632cEvan Yan bzero(&result, sizeof (result));
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)))
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rval &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (DDI_FAILURE);
269473047d747f7815af570197e4ef7322d3632cEvan Yan request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
269473047d747f7815af570197e4ef7322d3632cEvan Yan request.buf_size = request32.buf_size;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rval) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan result.nvlist_buf =
269473047d747f7815af570197e4ef7322d3632cEvan Yan (char *)(uintptr_t)result32.nvlist_buf;
269473047d747f7815af570197e4ef7322d3632cEvan Yan result.buf_size = result32.buf_size;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan#endif
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
269473047d747f7815af570197e4ef7322d3632cEvan Yan &prop_list)) != DDI_SUCCESS)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* check whether the requested property is "help" */
269473047d747f7815af570197e4ef7322d3632cEvan Yan prop_pair = nvlist_next_nvpair(prop_list, NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan (strcmp(nvpair_name(prop_pair), PCIEHPC_PROP_HELP) == 0)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (!rval) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_ENOTSUP;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto set_prop_cleanup;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_ENOMEM;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto set_prop_cleanup;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_add_string(prop_rlist, PCIEHPC_PROP_LED_ATTN,
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIEHPC_PROP_VALUE_LED) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_FAILURE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto set_prop_cleanup1;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
269473047d747f7815af570197e4ef7322d3632cEvan Yan &result.buf_size)) != DDI_SUCCESS) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto set_prop_cleanup1;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (get_udatamodel() == DATAMODEL_NATIVE) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (copyout(&result, rval,
269473047d747f7815af570197e4ef7322d3632cEvan Yan sizeof (ddi_hp_property_t))) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_FAILURE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto set_prop_cleanup1;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan#ifdef _SYSCALL32_IMPL
269473047d747f7815af570197e4ef7322d3632cEvan Yan else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (result.buf_size > UINT32_MAX) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_FAILURE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto set_prop_cleanup1;
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan result32.buf_size = (uint32_t)result.buf_size;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (copyout(&result32, rval,
269473047d747f7815af570197e4ef7322d3632cEvan Yan sizeof (ddi_hp_property32_t))) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_FAILURE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto set_prop_cleanup1;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan#endif
269473047d747f7815af570197e4ef7322d3632cEvan Yanset_prop_cleanup1:
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(prop_rlist);
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(prop_list);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Validate the request */
269473047d747f7815af570197e4ef7322d3632cEvan Yan prop_pair = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan name = nvpair_name(prop_pair);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvpair_type(prop_pair) != DATA_TYPE_STRING) {
24fd5dc40967be3acf455139813c114a29e7c529Evan Yan PCIE_DBG("Unexpected data type of setting "
269473047d747f7815af570197e4ef7322d3632cEvan Yan "property %s.\n", name);
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_EINVAL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto set_prop_cleanup;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvpair_value_string(prop_pair, &value)) {
24fd5dc40967be3acf455139813c114a29e7c529Evan Yan PCIE_DBG("Get string value failed for property %s.\n",
24fd5dc40967be3acf455139813c114a29e7c529Evan Yan name);
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_FAILURE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto set_prop_cleanup;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((strcmp(value, PCIEHPC_PROP_VALUE_ON) != 0) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan (strcmp(value, PCIEHPC_PROP_VALUE_OFF) != 0) &&
269473047d747f7815af570197e4ef7322d3632cEvan Yan (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) != 0)) {
24fd5dc40967be3acf455139813c114a29e7c529Evan Yan PCIE_DBG("Unsupported value of setting "
269473047d747f7815af570197e4ef7322d3632cEvan Yan "property %s\n", name);
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_ENOTSUP;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto set_prop_cleanup;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
24fd5dc40967be3acf455139813c114a29e7c529Evan Yan PCIE_DBG("Unsupported property: %s\n", name);
269473047d747f7815af570197e4ef7322d3632cEvan Yan ret = DDI_ENOTSUP;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto set_prop_cleanup;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_enter(&ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the current slot state */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_get_slot_state(slot_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* set each property */
269473047d747f7815af570197e4ef7322d3632cEvan Yan prop_pair = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan name = nvpair_name(prop_pair);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (strcmp(value, PCIEHPC_PROP_VALUE_ON) == 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan led_state = PCIE_HP_LED_ON;
269473047d747f7815af570197e4ef7322d3632cEvan Yan else if (strcmp(value, PCIEHPC_PROP_VALUE_OFF) == 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan led_state = PCIE_HP_LED_OFF;
269473047d747f7815af570197e4ef7322d3632cEvan Yan else if (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) == 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan led_state = PCIE_HP_LED_BLINK;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED,
269473047d747f7815af570197e4ef7322d3632cEvan Yan led_state);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
24fd5dc40967be3acf455139813c114a29e7c529Evan Yan if (rval) {
24fd5dc40967be3acf455139813c114a29e7c529Evan Yan if (get_udatamodel() == DATAMODEL_NATIVE) {
24fd5dc40967be3acf455139813c114a29e7c529Evan Yan result.buf_size = 0;
24fd5dc40967be3acf455139813c114a29e7c529Evan Yan if (copyout(&result, rval, sizeof (ddi_hp_property_t)))
24fd5dc40967be3acf455139813c114a29e7c529Evan Yan ret = DDI_FAILURE;
24fd5dc40967be3acf455139813c114a29e7c529Evan Yan }
24fd5dc40967be3acf455139813c114a29e7c529Evan Yan#ifdef _SYSCALL32_IMPL
24fd5dc40967be3acf455139813c114a29e7c529Evan Yan else {
24fd5dc40967be3acf455139813c114a29e7c529Evan Yan result32.buf_size = 0;
24fd5dc40967be3acf455139813c114a29e7c529Evan Yan if (copyout(&result32, rval,
24fd5dc40967be3acf455139813c114a29e7c529Evan Yan sizeof (ddi_hp_property32_t)))
24fd5dc40967be3acf455139813c114a29e7c529Evan Yan ret = DDI_FAILURE;
24fd5dc40967be3acf455139813c114a29e7c529Evan Yan }
24fd5dc40967be3acf455139813c114a29e7c529Evan Yan#endif
24fd5dc40967be3acf455139813c114a29e7c529Evan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_exit(&ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yanset_prop_cleanup:
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvlist_free(prop_list);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ret);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Send a command to the PCI-E Hot Plug Controller.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * NOTES: The PCI-E spec defines the following semantics for issuing hot plug
269473047d747f7815af570197e4ef7322d3632cEvan Yan * commands.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * 1) If Command Complete events/interrupts are supported then software
269473047d747f7815af570197e4ef7322d3632cEvan Yan * waits for Command Complete event after issuing a command (i.e writing
269473047d747f7815af570197e4ef7322d3632cEvan Yan * to the Slot Control register). The command completion could take as
269473047d747f7815af570197e4ef7322d3632cEvan Yan * long as 1 second so software should be prepared to wait for 1 second
269473047d747f7815af570197e4ef7322d3632cEvan Yan * before issuing another command.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * 2) If Command Complete events/interrupts are not supported then
269473047d747f7815af570197e4ef7322d3632cEvan Yan * software could issue multiple Slot Control writes without any delay
269473047d747f7815af570197e4ef7322d3632cEvan Yan * between writes.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_issue_hpc_command(pcie_hp_ctrl_t *ctrl_p, uint16_t control)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint16_t status;
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint32_t slot_cap;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * PCI-E version 1.1 spec defines No Command Completed
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Support bit (bit#18) in Slot Capabilities register. If this
269473047d747f7815af570197e4ef7322d3632cEvan Yan * bit is set then slot doesn't support notification of command
269473047d747f7815af570197e4ef7322d3632cEvan Yan * completion events.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_cap = pciehpc_reg_get32(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCAP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If no Command Completion event is supported or it is ACPI
269473047d747f7815af570197e4ef7322d3632cEvan Yan * hot plug mode then just issue the command and return.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((slot_cap & PCIE_SLOTCAP_NO_CMD_COMP_SUPP) ||
269473047d747f7815af570197e4ef7322d3632cEvan Yan (bus_p->bus_hp_curr_mode == PCIE_ACPI_HP_MODE)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_reg_put16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * **************************************
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Command Complete events are supported.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * **************************************
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If HPC is not yet initialized then just poll for the Command
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Completion interrupt.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan int retry = PCIE_HP_CMD_WAIT_RETRY;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* write the command to the HPC */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_reg_put16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* poll for status completion */
269473047d747f7815af570197e4ef7322d3632cEvan Yan while (retry--) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* wait for 10 msec before checking the status */
269473047d747f7815af570197e4ef7322d3632cEvan Yan delay(drv_usectohz(PCIE_HP_CMD_WAIT_TIME));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan status = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* clear the status bits */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_reg_put16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan return;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* HPC is already initialized */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If previous command is still pending then wait for its
269473047d747f7815af570197e4ef7322d3632cEvan Yan * completion. i.e cv_wait()
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan while (ctrl_p->hc_cmd_pending == B_TRUE)
269473047d747f7815af570197e4ef7322d3632cEvan Yan cv_wait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Issue the command and wait for Command Completion or
269473047d747f7815af570197e4ef7322d3632cEvan Yan * the 1 sec timeout.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_reg_put16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_cmd_pending = B_TRUE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (cv_timedwait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex,
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_get_lbolt() + SEC_TO_TICK(1)) == -1) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* it is a timeout */
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_issue_hpc_command: Command Complete"
269473047d747f7815af570197e4ef7322d3632cEvan Yan " interrupt is not received for slot %d\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_phy_slot_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* clear the status info in case interrupts are disabled? */
269473047d747f7815af570197e4ef7322d3632cEvan Yan status = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* clear the status bits */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_reg_put16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_cmd_pending = B_FALSE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* wake up any one waiting for issuing another command to HPC */
269473047d747f7815af570197e4ef7322d3632cEvan Yan cv_signal(&ctrl_p->hc_cmd_comp_cv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * pciehcp_attn_btn_handler()
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * This handles ATTN button pressed event as per the PCI-E 1.1 spec.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_attn_btn_handler(pcie_hp_ctrl_t *ctrl_p)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_led_state_t power_led_state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan callb_cpr_t cprinfo;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_attn_btn_handler: thread started\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan CALLB_CPR_INIT(&cprinfo, &ctrl_p->hc_mutex, callb_generic_cpr,
269473047d747f7815af570197e4ef7322d3632cEvan Yan "pciehpc_attn_btn_handler");
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_enter(&ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* wait for ATTN button event */
269473047d747f7815af570197e4ef7322d3632cEvan Yan cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan while (slot_p->hs_attn_btn_thread_exit == B_FALSE) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (slot_p->hs_attn_btn_pending == B_TRUE) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the current state of power LED */
269473047d747f7815af570197e4ef7322d3632cEvan Yan power_led_state = pciehpc_get_led_state(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_HP_POWER_LED);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Blink the Power LED while we wait for 5 seconds */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_HP_LED_BLINK);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* wait for 5 seconds before taking any action */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (cv_timedwait(&slot_p->hs_attn_btn_cv,
269473047d747f7815af570197e4ef7322d3632cEvan Yan &ctrl_p->hc_mutex,
269473047d747f7815af570197e4ef7322d3632cEvan Yan ddi_get_lbolt() + SEC_TO_TICK(5)) == -1) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * It is a time out; make sure the ATTN pending
269473047d747f7815af570197e4ef7322d3632cEvan Yan * flag is still ON before sending the event to
269473047d747f7815af570197e4ef7322d3632cEvan Yan * DDI HP framework.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (slot_p->hs_attn_btn_pending == B_TRUE) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan int hint;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_attn_btn_pending = B_FALSE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_get_slot_state(slot_p);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (slot_p->hs_info.cn_state <=
269473047d747f7815af570197e4ef7322d3632cEvan Yan DDI_HP_CN_STATE_PRESENT) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Insertion.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan hint = SE_INCOMING_RES;
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Want to remove;
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan hint = SE_OUTGOING_RES;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * We can't call ddihp_cn_gen_sysevent
269473047d747f7815af570197e4ef7322d3632cEvan Yan * here since it's not a DDI interface.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_gen_sysevent_req(
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_info.cn_name,
269473047d747f7815af570197e4ef7322d3632cEvan Yan hint,
269473047d747f7815af570197e4ef7322d3632cEvan Yan ctrl_p->hc_dip,
269473047d747f7815af570197e4ef7322d3632cEvan Yan KM_SLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* restore the power LED state */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
269473047d747f7815af570197e4ef7322d3632cEvan Yan power_led_state);
269473047d747f7815af570197e4ef7322d3632cEvan Yan continue;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* wait for another ATTN button event */
269473047d747f7815af570197e4ef7322d3632cEvan Yan cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_attn_btn_handler: thread exit\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan cv_signal(&slot_p->hs_attn_btn_cv);
269473047d747f7815af570197e4ef7322d3632cEvan Yan CALLB_CPR_EXIT(&cprinfo);
269473047d747f7815af570197e4ef7322d3632cEvan Yan thread_exit();
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * convert LED state from PCIE HPC definition to pcie_hp_led_state_t
269473047d747f7815af570197e4ef7322d3632cEvan Yan * definition.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic pcie_hp_led_state_t
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_led_state_to_hpc(uint16_t state)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan switch (state) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan case PCIE_SLOTCTL_INDICATOR_STATE_ON:
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (PCIE_HP_LED_ON);
269473047d747f7815af570197e4ef7322d3632cEvan Yan case PCIE_SLOTCTL_INDICATOR_STATE_BLINK:
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (PCIE_HP_LED_BLINK);
269473047d747f7815af570197e4ef7322d3632cEvan Yan case PCIE_SLOTCTL_INDICATOR_STATE_OFF:
269473047d747f7815af570197e4ef7322d3632cEvan Yan default:
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (PCIE_HP_LED_OFF);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Get the state of an LED.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic pcie_hp_led_state_t
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_get_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint16_t control, state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the current state of Slot Control register */
269473047d747f7815af570197e4ef7322d3632cEvan Yan control = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan switch (led) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan case PCIE_HP_POWER_LED:
269473047d747f7815af570197e4ef7322d3632cEvan Yan state = pcie_slotctl_pwr_indicator_get(control);
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan case PCIE_HP_ATTN_LED:
269473047d747f7815af570197e4ef7322d3632cEvan Yan state = pcie_slotctl_attn_indicator_get(control);
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan default:
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_get_led_state() invalid LED %d\n", led);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (PCIE_HP_LED_OFF);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan switch (state) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan case PCIE_SLOTCTL_INDICATOR_STATE_ON:
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (PCIE_HP_LED_ON);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan case PCIE_SLOTCTL_INDICATOR_STATE_BLINK:
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (PCIE_HP_LED_BLINK);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan case PCIE_SLOTCTL_INDICATOR_STATE_OFF:
269473047d747f7815af570197e4ef7322d3632cEvan Yan default:
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (PCIE_HP_LED_OFF);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Set the state of an LED. It updates both hw and sw state.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led,
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_led_state_t state)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint16_t control;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the current state of Slot Control register */
269473047d747f7815af570197e4ef7322d3632cEvan Yan control = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan switch (led) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan case PCIE_HP_POWER_LED:
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* clear led mask */
269473047d747f7815af570197e4ef7322d3632cEvan Yan control &= ~PCIE_SLOTCTL_PWR_INDICATOR_MASK;
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_power_led_state = state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan case PCIE_HP_ATTN_LED:
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* clear led mask */
269473047d747f7815af570197e4ef7322d3632cEvan Yan control &= ~PCIE_SLOTCTL_ATTN_INDICATOR_MASK;
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_attn_led_state = state;
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan default:
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_set_led_state() invalid LED %d\n", led);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan switch (state) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan case PCIE_HP_LED_ON:
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (led == PCIE_HP_POWER_LED)
269473047d747f7815af570197e4ef7322d3632cEvan Yan control = pcie_slotctl_pwr_indicator_set(control,
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_SLOTCTL_INDICATOR_STATE_ON);
269473047d747f7815af570197e4ef7322d3632cEvan Yan else if (led == PCIE_HP_ATTN_LED)
269473047d747f7815af570197e4ef7322d3632cEvan Yan control = pcie_slotctl_attn_indicator_set(control,
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_SLOTCTL_INDICATOR_STATE_ON);
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan case PCIE_HP_LED_OFF:
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (led == PCIE_HP_POWER_LED)
269473047d747f7815af570197e4ef7322d3632cEvan Yan control = pcie_slotctl_pwr_indicator_set(control,
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_SLOTCTL_INDICATOR_STATE_OFF);
269473047d747f7815af570197e4ef7322d3632cEvan Yan else if (led == PCIE_HP_ATTN_LED)
269473047d747f7815af570197e4ef7322d3632cEvan Yan control = pcie_slotctl_attn_indicator_set(control,
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_SLOTCTL_INDICATOR_STATE_OFF);
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan case PCIE_HP_LED_BLINK:
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (led == PCIE_HP_POWER_LED)
269473047d747f7815af570197e4ef7322d3632cEvan Yan control = pcie_slotctl_pwr_indicator_set(control,
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_SLOTCTL_INDICATOR_STATE_BLINK);
269473047d747f7815af570197e4ef7322d3632cEvan Yan else if (led == PCIE_HP_ATTN_LED)
269473047d747f7815af570197e4ef7322d3632cEvan Yan control = pcie_slotctl_attn_indicator_set(control,
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_SLOTCTL_INDICATOR_STATE_BLINK);
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan default:
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_set_led_state() invalid LED state %d\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan state);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* update the Slot Control Register */
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_issue_hpc_command(ctrl_p, control);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan#ifdef DEBUG
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* get the current state of Slot Control register */
269473047d747f7815af570197e4ef7322d3632cEvan Yan control = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_set_led_state: slot %d power-led %s attn-led %s\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_phy_slot_num, pcie_led_state_text(
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control))),
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_led_state_text(pciehpc_led_state_to_hpc(
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_slotctl_attn_indicator_get(control))));
269473047d747f7815af570197e4ef7322d3632cEvan Yan#endif
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing Chinastatic void
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing Chinapciehpc_handle_power_fault(dev_info_t *dip)
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China{
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China /*
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China * Hold the parent's ref so that it won't disappear when the taskq is
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China * scheduled to run.
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China */
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China ndi_hold_devi(dip);
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China if (!taskq_dispatch(system_taskq, pciehpc_power_fault_handler, dip,
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China TQ_NOSLEEP)) {
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China ndi_rele_devi(dip);
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China PCIE_DBG("pciehpc_intr(): "
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China "Failed to dispatch power fault handler, dip %p\n", dip);
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China }
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China}
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing Chinastatic void
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing Chinapciehpc_power_fault_handler(void *arg)
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China{
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China dev_info_t *dip = (dev_info_t *)arg;
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China pcie_hp_ctrl_t *ctrl_p;
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China pcie_hp_slot_t *slot_p;
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China /* get the soft state structure for this dip */
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) {
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China ndi_rele_devi(dip);
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China return;
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China }
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China slot_p = ctrl_p->hc_slots[0];
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China /*
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China * Send the event to DDI Hotplug framework, power off
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China * the slot
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China */
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China (void) ndi_hp_state_change_req(dip,
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China slot_p->hs_info.cn_name,
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China DDI_HP_CN_STATE_EMPTY, DDI_HP_REQ_SYNC);
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China mutex_enter(&ctrl_p->hc_mutex);
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED,
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China PCIE_HP_LED_ON);
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China mutex_exit(&ctrl_p->hc_mutex);
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China ndi_rele_devi(dip);
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China}
80dc702d1ace8fb9dbee9d449a58b943b7308a8eColin Zou - Sun Microsystems - Beijing China
269473047d747f7815af570197e4ef7322d3632cEvan Yan#ifdef DEBUG
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Dump PCI-E Hot Plug registers.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void
269473047d747f7815af570197e4ef7322d3632cEvan Yanpciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint16_t control;
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint32_t capabilities;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (!pcie_debug_flags)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan capabilities = pciehpc_reg_get32(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCAP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan control = pciehpc_reg_get16(ctrl_p,
269473047d747f7815af570197e4ef7322d3632cEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("pciehpc_dump_hpregs: Found PCI-E hot plug slot %d\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan slot_p->hs_phy_slot_num);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("Attention Button Present = %s\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan capabilities & PCIE_SLOTCAP_ATTN_BUTTON ? "Yes":"No");
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("Power controller Present = %s\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan capabilities & PCIE_SLOTCAP_POWER_CONTROLLER ? "Yes":"No");
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("MRL Sensor Present = %s\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan capabilities & PCIE_SLOTCAP_MRL_SENSOR ? "Yes":"No");
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("Attn Indicator Present = %s\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan capabilities & PCIE_SLOTCAP_ATTN_INDICATOR ? "Yes":"No");
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("Power Indicator Present = %s\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan capabilities & PCIE_SLOTCAP_PWR_INDICATOR ? "Yes":"No");
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("HotPlug Surprise = %s\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan capabilities & PCIE_SLOTCAP_HP_SURPRISE ? "Yes":"No");
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("HotPlug Capable = %s\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan capabilities & PCIE_SLOTCAP_HP_CAPABLE ? "Yes":"No");
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("Physical Slot Number = %d\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_SLOTCAP_PHY_SLOT_NUM(capabilities));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("Attn Button interrupt Enabled = %s\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan control & PCIE_SLOTCTL_ATTN_BTN_EN ? "Yes":"No");
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("Power Fault interrupt Enabled = %s\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan control & PCIE_SLOTCTL_PWR_FAULT_EN ? "Yes":"No");
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("MRL Sensor INTR Enabled = %s\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan control & PCIE_SLOTCTL_MRL_SENSOR_EN ? "Yes":"No");
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("Presence interrupt Enabled = %s\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan control & PCIE_SLOTCTL_PRESENCE_CHANGE_EN ? "Yes":"No");
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("Cmd Complete interrupt Enabled = %s\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan control & PCIE_SLOTCTL_CMD_INTR_EN ? "Yes":"No");
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("HotPlug interrupt Enabled = %s\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan control & PCIE_SLOTCTL_HP_INTR_EN ? "Yes":"No");
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("Power Indicator LED = %s", pcie_led_state_text(
269473047d747f7815af570197e4ef7322d3632cEvan Yan pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control))));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan PCIE_DBG("Attn Indicator LED = %s\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_led_state_text(pciehpc_led_state_to_hpc(
269473047d747f7815af570197e4ef7322d3632cEvan Yan pcie_slotctl_attn_indicator_get(control))));
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan#endif /* DEBUG */