xref: /onnv-gate/usr/src/uts/common/io/pciex/hotplug/pciehpc.c (revision 12221:c3b88f2d6f3f)
110923SEvan.Yan@Sun.COM /*
210923SEvan.Yan@Sun.COM  * CDDL HEADER START
310923SEvan.Yan@Sun.COM  *
410923SEvan.Yan@Sun.COM  * The contents of this file are subject to the terms of the
510923SEvan.Yan@Sun.COM  * Common Development and Distribution License (the "License").
610923SEvan.Yan@Sun.COM  * You may not use this file except in compliance with the License.
710923SEvan.Yan@Sun.COM  *
810923SEvan.Yan@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910923SEvan.Yan@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1010923SEvan.Yan@Sun.COM  * See the License for the specific language governing permissions
1110923SEvan.Yan@Sun.COM  * and limitations under the License.
1210923SEvan.Yan@Sun.COM  *
1310923SEvan.Yan@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1410923SEvan.Yan@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510923SEvan.Yan@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1610923SEvan.Yan@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1710923SEvan.Yan@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1810923SEvan.Yan@Sun.COM  *
1910923SEvan.Yan@Sun.COM  * CDDL HEADER END
2010923SEvan.Yan@Sun.COM  */
2110923SEvan.Yan@Sun.COM 
2210923SEvan.Yan@Sun.COM /*
23*12221SColin.Zou@Sun.COM  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
2410923SEvan.Yan@Sun.COM  */
2510923SEvan.Yan@Sun.COM 
2610923SEvan.Yan@Sun.COM /*
2710923SEvan.Yan@Sun.COM  * This file contains Standard PCI Express HotPlug functionality that is
2810923SEvan.Yan@Sun.COM  * compatible with the PCI Express ver 1.1 specification.
2910923SEvan.Yan@Sun.COM  *
3010923SEvan.Yan@Sun.COM  * NOTE: This file is compiled and delivered through misc/pcie module.
3110923SEvan.Yan@Sun.COM  */
3210923SEvan.Yan@Sun.COM 
3310923SEvan.Yan@Sun.COM #include <sys/types.h>
3410923SEvan.Yan@Sun.COM #include <sys/note.h>
3510923SEvan.Yan@Sun.COM #include <sys/conf.h>
3610923SEvan.Yan@Sun.COM #include <sys/kmem.h>
3710923SEvan.Yan@Sun.COM #include <sys/debug.h>
3810923SEvan.Yan@Sun.COM #include <sys/vtrace.h>
3910923SEvan.Yan@Sun.COM #include <sys/autoconf.h>
4010923SEvan.Yan@Sun.COM #include <sys/varargs.h>
4110923SEvan.Yan@Sun.COM #include <sys/ddi_impldefs.h>
4210923SEvan.Yan@Sun.COM #include <sys/time.h>
4310923SEvan.Yan@Sun.COM #include <sys/callb.h>
4410923SEvan.Yan@Sun.COM #include <sys/ddi.h>
4510923SEvan.Yan@Sun.COM #include <sys/sunddi.h>
4610923SEvan.Yan@Sun.COM #include <sys/sunndi.h>
4710923SEvan.Yan@Sun.COM #include <sys/sysevent/dr.h>
4810923SEvan.Yan@Sun.COM #include <sys/pci_impl.h>
4910923SEvan.Yan@Sun.COM #include <sys/hotplug/pci/pcie_hp.h>
5010923SEvan.Yan@Sun.COM #include <sys/hotplug/pci/pciehpc.h>
5110923SEvan.Yan@Sun.COM 
5210923SEvan.Yan@Sun.COM typedef struct pciehpc_prop {
5310923SEvan.Yan@Sun.COM 	char	*prop_name;
5410923SEvan.Yan@Sun.COM 	char	*prop_value;
5510923SEvan.Yan@Sun.COM } pciehpc_prop_t;
5610923SEvan.Yan@Sun.COM 
5710923SEvan.Yan@Sun.COM static pciehpc_prop_t	pciehpc_props[] = {
5810923SEvan.Yan@Sun.COM 	{ PCIEHPC_PROP_LED_FAULT,	PCIEHPC_PROP_VALUE_LED },
5910923SEvan.Yan@Sun.COM 	{ PCIEHPC_PROP_LED_POWER,	PCIEHPC_PROP_VALUE_LED },
6010923SEvan.Yan@Sun.COM 	{ PCIEHPC_PROP_LED_ATTN,	PCIEHPC_PROP_VALUE_LED },
6110923SEvan.Yan@Sun.COM 	{ PCIEHPC_PROP_LED_ACTIVE,	PCIEHPC_PROP_VALUE_LED },
6210923SEvan.Yan@Sun.COM 	{ PCIEHPC_PROP_CARD_TYPE,	PCIEHPC_PROP_VALUE_TYPE },
6310923SEvan.Yan@Sun.COM 	{ PCIEHPC_PROP_BOARD_TYPE,	PCIEHPC_PROP_VALUE_TYPE },
6410923SEvan.Yan@Sun.COM 	{ PCIEHPC_PROP_SLOT_CONDITION,	PCIEHPC_PROP_VALUE_TYPE }
6510923SEvan.Yan@Sun.COM };
6610923SEvan.Yan@Sun.COM 
6710923SEvan.Yan@Sun.COM /* Local functions prototype */
6810923SEvan.Yan@Sun.COM static int pciehpc_hpc_init(pcie_hp_ctrl_t *ctrl_p);
6910923SEvan.Yan@Sun.COM static int pciehpc_hpc_uninit(pcie_hp_ctrl_t *ctrl_p);
7010923SEvan.Yan@Sun.COM static int pciehpc_slotinfo_init(pcie_hp_ctrl_t *ctrl_p);
7110923SEvan.Yan@Sun.COM static int pciehpc_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p);
7210923SEvan.Yan@Sun.COM static int pciehpc_enable_intr(pcie_hp_ctrl_t *ctrl_p);
7310923SEvan.Yan@Sun.COM static int pciehpc_disable_intr(pcie_hp_ctrl_t *ctrl_p);
7410923SEvan.Yan@Sun.COM static pcie_hp_ctrl_t *pciehpc_create_controller(dev_info_t *dip);
7510923SEvan.Yan@Sun.COM static void pciehpc_destroy_controller(dev_info_t *dip);
7610923SEvan.Yan@Sun.COM static int pciehpc_register_slot(pcie_hp_ctrl_t *ctrl_p);
7710923SEvan.Yan@Sun.COM static int pciehpc_unregister_slot(pcie_hp_ctrl_t *ctrl_p);
7810923SEvan.Yan@Sun.COM static int pciehpc_slot_get_property(pcie_hp_slot_t *slot_p,
7910923SEvan.Yan@Sun.COM     ddi_hp_property_t *arg, ddi_hp_property_t *rval);
8010923SEvan.Yan@Sun.COM static int pciehpc_slot_set_property(pcie_hp_slot_t *slot_p,
8110923SEvan.Yan@Sun.COM     ddi_hp_property_t *arg, ddi_hp_property_t *rval);
8210923SEvan.Yan@Sun.COM static void pciehpc_issue_hpc_command(pcie_hp_ctrl_t *ctrl_p, uint16_t control);
8310923SEvan.Yan@Sun.COM static void pciehpc_attn_btn_handler(pcie_hp_ctrl_t *ctrl_p);
8410923SEvan.Yan@Sun.COM static pcie_hp_led_state_t pciehpc_led_state_to_hpc(uint16_t state);
8510923SEvan.Yan@Sun.COM static pcie_hp_led_state_t pciehpc_get_led_state(pcie_hp_ctrl_t *ctrl_p,
8610923SEvan.Yan@Sun.COM     pcie_hp_led_t led);
8710923SEvan.Yan@Sun.COM static void pciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led,
8810923SEvan.Yan@Sun.COM     pcie_hp_led_state_t state);
8910923SEvan.Yan@Sun.COM 
9010923SEvan.Yan@Sun.COM static int pciehpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
9110923SEvan.Yan@Sun.COM     ddi_hp_cn_state_t target_state);
9210923SEvan.Yan@Sun.COM static int pciehpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
9310923SEvan.Yan@Sun.COM     ddi_hp_cn_state_t target_state);
9410923SEvan.Yan@Sun.COM static int pciehpc_change_slot_state(pcie_hp_slot_t *slot_p,
9510923SEvan.Yan@Sun.COM     ddi_hp_cn_state_t target_state);
9610923SEvan.Yan@Sun.COM static int
9710923SEvan.Yan@Sun.COM     pciehpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result);
9810923SEvan.Yan@Sun.COM static int
9910923SEvan.Yan@Sun.COM     pciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result);
10010923SEvan.Yan@Sun.COM static int pciehpc_slot_probe(pcie_hp_slot_t *slot_p);
10110923SEvan.Yan@Sun.COM static int pciehpc_slot_unprobe(pcie_hp_slot_t *slot_p);
102*12221SColin.Zou@Sun.COM static void pciehpc_handle_power_fault(dev_info_t *dip);
103*12221SColin.Zou@Sun.COM static void pciehpc_power_fault_handler(void *arg);
10410923SEvan.Yan@Sun.COM 
10510923SEvan.Yan@Sun.COM #ifdef	DEBUG
10610923SEvan.Yan@Sun.COM static void pciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p);
10710923SEvan.Yan@Sun.COM #endif	/* DEBUG */
10810923SEvan.Yan@Sun.COM 
10910923SEvan.Yan@Sun.COM /*
11010923SEvan.Yan@Sun.COM  * Global functions (called by other drivers/modules)
11110923SEvan.Yan@Sun.COM  */
11210923SEvan.Yan@Sun.COM 
11310923SEvan.Yan@Sun.COM /*
11410923SEvan.Yan@Sun.COM  * Initialize Hot Plug Controller if present. The arguments are:
11510923SEvan.Yan@Sun.COM  *	dip	- Devinfo node pointer to the hot plug bus node
11610923SEvan.Yan@Sun.COM  *	regops	- register ops to access HPC registers for non-standard
11710923SEvan.Yan@Sun.COM  *		  HPC hw implementations (e.g: HPC in host PCI-E brdiges)
11810923SEvan.Yan@Sun.COM  *		  This is NULL for standard HPC in PCIe bridges.
11910923SEvan.Yan@Sun.COM  * Returns:
12010923SEvan.Yan@Sun.COM  *	DDI_SUCCESS for successful HPC initialization
12110923SEvan.Yan@Sun.COM  *	DDI_FAILURE for errors or if HPC hw not found
12210923SEvan.Yan@Sun.COM  */
12310923SEvan.Yan@Sun.COM int
pciehpc_init(dev_info_t * dip,caddr_t arg)12410923SEvan.Yan@Sun.COM pciehpc_init(dev_info_t *dip, caddr_t arg)
12510923SEvan.Yan@Sun.COM {
12610923SEvan.Yan@Sun.COM 	pcie_hp_regops_t	*regops = (pcie_hp_regops_t *)(void *)arg;
12710923SEvan.Yan@Sun.COM 	pcie_hp_ctrl_t		*ctrl_p;
12810923SEvan.Yan@Sun.COM 
12910923SEvan.Yan@Sun.COM 	PCIE_DBG("pciehpc_init() called (dip=%p)\n", (void *)dip);
13010923SEvan.Yan@Sun.COM 
13110923SEvan.Yan@Sun.COM 	/* Make sure that it is not already initialized */
13210923SEvan.Yan@Sun.COM 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) != NULL) {
13310923SEvan.Yan@Sun.COM 		PCIE_DBG("%s%d: pciehpc instance already initialized!\n",
13410923SEvan.Yan@Sun.COM 		    ddi_driver_name(dip), ddi_get_instance(dip));
13510923SEvan.Yan@Sun.COM 		return (DDI_SUCCESS);
13610923SEvan.Yan@Sun.COM 	}
13710923SEvan.Yan@Sun.COM 
13810923SEvan.Yan@Sun.COM 	/* Allocate a new hotplug controller and slot structures */
13910923SEvan.Yan@Sun.COM 	ctrl_p = pciehpc_create_controller(dip);
14010923SEvan.Yan@Sun.COM 
14110923SEvan.Yan@Sun.COM 	/* setup access handle for HPC regs */
14210923SEvan.Yan@Sun.COM 	if (regops != NULL) {
14310923SEvan.Yan@Sun.COM 		/* HPC access is non-standard; use the supplied reg ops */
14410923SEvan.Yan@Sun.COM 		ctrl_p->hc_regops = *regops;
14510923SEvan.Yan@Sun.COM 	}
14610923SEvan.Yan@Sun.COM 
14710923SEvan.Yan@Sun.COM 	/*
14810923SEvan.Yan@Sun.COM 	 * Setup resource maps for this bus node.
14910923SEvan.Yan@Sun.COM 	 */
15010923SEvan.Yan@Sun.COM 	(void) pci_resource_setup(dip);
15110923SEvan.Yan@Sun.COM 
15210923SEvan.Yan@Sun.COM 	PCIE_DISABLE_ERRORS(dip);
15310923SEvan.Yan@Sun.COM 
15410923SEvan.Yan@Sun.COM 	/*
15510923SEvan.Yan@Sun.COM 	 * Set the platform specific hot plug mode.
15610923SEvan.Yan@Sun.COM 	 */
15710923SEvan.Yan@Sun.COM 	ctrl_p->hc_ops.init_hpc_hw = pciehpc_hpc_init;
15810923SEvan.Yan@Sun.COM 	ctrl_p->hc_ops.uninit_hpc_hw = pciehpc_hpc_uninit;
15910923SEvan.Yan@Sun.COM 	ctrl_p->hc_ops.init_hpc_slotinfo = pciehpc_slotinfo_init;
16010923SEvan.Yan@Sun.COM 	ctrl_p->hc_ops.uninit_hpc_slotinfo = pciehpc_slotinfo_uninit;
16110923SEvan.Yan@Sun.COM 	ctrl_p->hc_ops.poweron_hpc_slot = pciehpc_slot_poweron;
16210923SEvan.Yan@Sun.COM 	ctrl_p->hc_ops.poweroff_hpc_slot = pciehpc_slot_poweroff;
16310923SEvan.Yan@Sun.COM 
16410923SEvan.Yan@Sun.COM 	ctrl_p->hc_ops.enable_hpc_intr = pciehpc_enable_intr;
16510923SEvan.Yan@Sun.COM 	ctrl_p->hc_ops.disable_hpc_intr = pciehpc_disable_intr;
16610923SEvan.Yan@Sun.COM 
16710923SEvan.Yan@Sun.COM #if	defined(__i386) || defined(__amd64)
16810923SEvan.Yan@Sun.COM 	pciehpc_update_ops(ctrl_p);
16910923SEvan.Yan@Sun.COM #endif
17010923SEvan.Yan@Sun.COM 
17110923SEvan.Yan@Sun.COM 	/* initialize hot plug controller hw */
17210923SEvan.Yan@Sun.COM 	if ((ctrl_p->hc_ops.init_hpc_hw)(ctrl_p) != DDI_SUCCESS)
17310923SEvan.Yan@Sun.COM 		goto cleanup1;
17410923SEvan.Yan@Sun.COM 
17510923SEvan.Yan@Sun.COM 	/* initialize slot information soft state structure */
17610923SEvan.Yan@Sun.COM 	if ((ctrl_p->hc_ops.init_hpc_slotinfo)(ctrl_p) != DDI_SUCCESS)
17710923SEvan.Yan@Sun.COM 		goto cleanup2;
17810923SEvan.Yan@Sun.COM 
17910923SEvan.Yan@Sun.COM 	/* register the hot plug slot with DDI HP framework */
18010923SEvan.Yan@Sun.COM 	if (pciehpc_register_slot(ctrl_p) != DDI_SUCCESS)
18110923SEvan.Yan@Sun.COM 		goto cleanup3;
18210923SEvan.Yan@Sun.COM 
18310923SEvan.Yan@Sun.COM 	/* create minor node for this slot */
18410923SEvan.Yan@Sun.COM 	if (pcie_create_minor_node(ctrl_p, 0) != DDI_SUCCESS)
18510923SEvan.Yan@Sun.COM 		goto cleanup4;
18610923SEvan.Yan@Sun.COM 
18710923SEvan.Yan@Sun.COM 	/* HPC initialization is complete now */
18810923SEvan.Yan@Sun.COM 	ctrl_p->hc_flags = PCIE_HP_INITIALIZED_FLAG;
18910923SEvan.Yan@Sun.COM 
19010923SEvan.Yan@Sun.COM #ifdef	DEBUG
19110923SEvan.Yan@Sun.COM 	/* For debug, dump the HPC registers */
19210923SEvan.Yan@Sun.COM 	pciehpc_dump_hpregs(ctrl_p);
19310923SEvan.Yan@Sun.COM #endif	/* DEBUG */
19410923SEvan.Yan@Sun.COM 
19510923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
19610923SEvan.Yan@Sun.COM cleanup4:
19710923SEvan.Yan@Sun.COM 	(void) pciehpc_unregister_slot(ctrl_p);
19810923SEvan.Yan@Sun.COM cleanup3:
19910923SEvan.Yan@Sun.COM 	(void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p);
20010923SEvan.Yan@Sun.COM 
20110923SEvan.Yan@Sun.COM cleanup2:
20210923SEvan.Yan@Sun.COM 	(void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p);
20310923SEvan.Yan@Sun.COM 
20410923SEvan.Yan@Sun.COM cleanup1:
20510923SEvan.Yan@Sun.COM 	PCIE_ENABLE_ERRORS(dip);
20610923SEvan.Yan@Sun.COM 	(void) pci_resource_destroy(dip);
20710923SEvan.Yan@Sun.COM 
20810923SEvan.Yan@Sun.COM 	pciehpc_destroy_controller(dip);
20910923SEvan.Yan@Sun.COM 	return (DDI_FAILURE);
21010923SEvan.Yan@Sun.COM }
21110923SEvan.Yan@Sun.COM 
21210923SEvan.Yan@Sun.COM /*
21310923SEvan.Yan@Sun.COM  * Uninitialize HPC soft state structure and free up any resources
21410923SEvan.Yan@Sun.COM  * used for the HPC instance.
21510923SEvan.Yan@Sun.COM  */
21610923SEvan.Yan@Sun.COM int
pciehpc_uninit(dev_info_t * dip)21710923SEvan.Yan@Sun.COM pciehpc_uninit(dev_info_t *dip)
21810923SEvan.Yan@Sun.COM {
21910923SEvan.Yan@Sun.COM 	pcie_hp_ctrl_t *ctrl_p;
22010923SEvan.Yan@Sun.COM 
22110923SEvan.Yan@Sun.COM 	PCIE_DBG("pciehpc_uninit() called (dip=%p)\n", (void *)dip);
22210923SEvan.Yan@Sun.COM 
22310923SEvan.Yan@Sun.COM 	/* get the soft state structure for this dip */
22410923SEvan.Yan@Sun.COM 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) {
22510923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
22610923SEvan.Yan@Sun.COM 	}
22710923SEvan.Yan@Sun.COM 
22810923SEvan.Yan@Sun.COM 	pcie_remove_minor_node(ctrl_p, 0);
22910923SEvan.Yan@Sun.COM 
23010923SEvan.Yan@Sun.COM 	/* unregister the slot */
23110923SEvan.Yan@Sun.COM 	(void) pciehpc_unregister_slot(ctrl_p);
23210923SEvan.Yan@Sun.COM 
23310923SEvan.Yan@Sun.COM 	/* uninit any slot info data structures */
23410923SEvan.Yan@Sun.COM 	(void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p);
23510923SEvan.Yan@Sun.COM 
23610923SEvan.Yan@Sun.COM 	/* uninitialize hpc, remove interrupt handler, etc. */
23710923SEvan.Yan@Sun.COM 	(void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p);
23810923SEvan.Yan@Sun.COM 
23910923SEvan.Yan@Sun.COM 	PCIE_ENABLE_ERRORS(dip);
24010923SEvan.Yan@Sun.COM 
24110923SEvan.Yan@Sun.COM 	/*
24210923SEvan.Yan@Sun.COM 	 * Destroy resource maps for this bus node.
24310923SEvan.Yan@Sun.COM 	 */
24410923SEvan.Yan@Sun.COM 	(void) pci_resource_destroy(dip);
24510923SEvan.Yan@Sun.COM 
24610923SEvan.Yan@Sun.COM 	/* destroy the soft state structure */
24710923SEvan.Yan@Sun.COM 	pciehpc_destroy_controller(dip);
24810923SEvan.Yan@Sun.COM 
24910923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
25010923SEvan.Yan@Sun.COM }
25110923SEvan.Yan@Sun.COM 
25210923SEvan.Yan@Sun.COM /*
25310923SEvan.Yan@Sun.COM  * pciehpc_intr()
25410923SEvan.Yan@Sun.COM  *
25510923SEvan.Yan@Sun.COM  * Interrupt handler for PCI-E Hot plug controller interrupts.
25610923SEvan.Yan@Sun.COM  *
25710923SEvan.Yan@Sun.COM  * Note: This is only for native mode hot plug. This is called
25810923SEvan.Yan@Sun.COM  * by the nexus driver at interrupt context. Interrupt Service Routine
25910923SEvan.Yan@Sun.COM  * registration is done by the nexus driver for both hot plug and
26010923SEvan.Yan@Sun.COM  * non-hot plug interrupts. This function is called from the ISR
26110923SEvan.Yan@Sun.COM  * of the nexus driver to handle hot-plug interrupts.
26210923SEvan.Yan@Sun.COM  */
26310923SEvan.Yan@Sun.COM int
pciehpc_intr(dev_info_t * dip)26410923SEvan.Yan@Sun.COM pciehpc_intr(dev_info_t *dip)
26510923SEvan.Yan@Sun.COM {
26610923SEvan.Yan@Sun.COM 	pcie_hp_ctrl_t	*ctrl_p;
26710923SEvan.Yan@Sun.COM 	pcie_hp_slot_t	*slot_p;
26810923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
26910923SEvan.Yan@Sun.COM 	uint16_t	status, control;
27010923SEvan.Yan@Sun.COM 
27110923SEvan.Yan@Sun.COM 	/* get the soft state structure for this dip */
27210923SEvan.Yan@Sun.COM 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
27310923SEvan.Yan@Sun.COM 		return (DDI_INTR_UNCLAIMED);
27410923SEvan.Yan@Sun.COM 
27510923SEvan.Yan@Sun.COM 	mutex_enter(&ctrl_p->hc_mutex);
27610923SEvan.Yan@Sun.COM 
27710923SEvan.Yan@Sun.COM 	/* make sure the controller soft state is initialized */
27810923SEvan.Yan@Sun.COM 	if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
27910923SEvan.Yan@Sun.COM 		mutex_exit(&ctrl_p->hc_mutex);
28010923SEvan.Yan@Sun.COM 		return (DDI_INTR_UNCLAIMED);
28110923SEvan.Yan@Sun.COM 	}
28210923SEvan.Yan@Sun.COM 
28310923SEvan.Yan@Sun.COM 	/* if it is not NATIVE hot plug mode then return */
28410923SEvan.Yan@Sun.COM 	if (bus_p->bus_hp_curr_mode != PCIE_NATIVE_HP_MODE) {
28510923SEvan.Yan@Sun.COM 		mutex_exit(&ctrl_p->hc_mutex);
28610923SEvan.Yan@Sun.COM 		return (DDI_INTR_UNCLAIMED);
28710923SEvan.Yan@Sun.COM 	}
28810923SEvan.Yan@Sun.COM 
28910923SEvan.Yan@Sun.COM 	slot_p = ctrl_p->hc_slots[0];
29010923SEvan.Yan@Sun.COM 
29110923SEvan.Yan@Sun.COM 	/* read the current slot status register */
29210923SEvan.Yan@Sun.COM 	status = pciehpc_reg_get16(ctrl_p,
29310923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
29410923SEvan.Yan@Sun.COM 
29510923SEvan.Yan@Sun.COM 	/* check if there are any hot plug interrupts occurred */
29610923SEvan.Yan@Sun.COM 	if (!(status & PCIE_SLOTSTS_STATUS_EVENTS)) {
29710923SEvan.Yan@Sun.COM 		/* no hot plug events occurred */
29810923SEvan.Yan@Sun.COM 		mutex_exit(&ctrl_p->hc_mutex);
29910923SEvan.Yan@Sun.COM 		return (DDI_INTR_UNCLAIMED);
30010923SEvan.Yan@Sun.COM 	}
30110923SEvan.Yan@Sun.COM 
30210923SEvan.Yan@Sun.COM 	/* clear the interrupt status bits */
30310923SEvan.Yan@Sun.COM 	pciehpc_reg_put16(ctrl_p,
30410923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
30510923SEvan.Yan@Sun.COM 
30610923SEvan.Yan@Sun.COM 	/* check for CMD COMPLETE interrupt */
30710923SEvan.Yan@Sun.COM 	if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
30810923SEvan.Yan@Sun.COM 		PCIE_DBG("pciehpc_intr(): CMD COMPLETED interrupt received\n");
30910923SEvan.Yan@Sun.COM 		/* wake up any one waiting for Command Completion event */
31010923SEvan.Yan@Sun.COM 		cv_signal(&ctrl_p->hc_cmd_comp_cv);
31110923SEvan.Yan@Sun.COM 	}
31210923SEvan.Yan@Sun.COM 
31310923SEvan.Yan@Sun.COM 	/* check for ATTN button interrupt */
31410923SEvan.Yan@Sun.COM 	if (status & PCIE_SLOTSTS_ATTN_BTN_PRESSED) {
31510923SEvan.Yan@Sun.COM 		PCIE_DBG("pciehpc_intr(): ATTN BUTTON interrupt received\n");
31610923SEvan.Yan@Sun.COM 
31710923SEvan.Yan@Sun.COM 		/* if ATTN button event is still pending then cancel it */
31810923SEvan.Yan@Sun.COM 		if (slot_p->hs_attn_btn_pending == B_TRUE)
31910923SEvan.Yan@Sun.COM 			slot_p->hs_attn_btn_pending = B_FALSE;
32010923SEvan.Yan@Sun.COM 		else
32110923SEvan.Yan@Sun.COM 			slot_p->hs_attn_btn_pending = B_TRUE;
32210923SEvan.Yan@Sun.COM 
32310923SEvan.Yan@Sun.COM 		/* wake up the ATTN event handler */
32410923SEvan.Yan@Sun.COM 		cv_signal(&slot_p->hs_attn_btn_cv);
32510923SEvan.Yan@Sun.COM 	}
32610923SEvan.Yan@Sun.COM 
32710923SEvan.Yan@Sun.COM 	/* check for power fault interrupt */
32810923SEvan.Yan@Sun.COM 	if (status & PCIE_SLOTSTS_PWR_FAULT_DETECTED) {
32910923SEvan.Yan@Sun.COM 
33010923SEvan.Yan@Sun.COM 		PCIE_DBG("pciehpc_intr(): POWER FAULT interrupt received"
33110923SEvan.Yan@Sun.COM 		    " on slot %d\n", slot_p->hs_phy_slot_num);
33210923SEvan.Yan@Sun.COM 		control =  pciehpc_reg_get16(ctrl_p,
33310923SEvan.Yan@Sun.COM 		    bus_p->bus_pcie_off + PCIE_SLOTCTL);
33410923SEvan.Yan@Sun.COM 
33510923SEvan.Yan@Sun.COM 		if (control & PCIE_SLOTCTL_PWR_FAULT_EN) {
33610923SEvan.Yan@Sun.COM 			slot_p->hs_condition = AP_COND_FAILED;
33710923SEvan.Yan@Sun.COM 
33810923SEvan.Yan@Sun.COM 			/* disable power fault detction interrupt */
33910923SEvan.Yan@Sun.COM 			pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
34010923SEvan.Yan@Sun.COM 			    PCIE_SLOTCTL, control & ~PCIE_SLOTCTL_PWR_FAULT_EN);
34110923SEvan.Yan@Sun.COM 
342*12221SColin.Zou@Sun.COM 			pciehpc_handle_power_fault(dip);
34310923SEvan.Yan@Sun.COM 		}
34410923SEvan.Yan@Sun.COM 	}
34510923SEvan.Yan@Sun.COM 
34610923SEvan.Yan@Sun.COM 	/* check for MRL SENSOR CHANGED interrupt */
34710923SEvan.Yan@Sun.COM 	if (status & PCIE_SLOTSTS_MRL_SENSOR_CHANGED) {
34810923SEvan.Yan@Sun.COM 		/* For now (phase-I), no action is taken on this event */
34910923SEvan.Yan@Sun.COM 		PCIE_DBG("pciehpc_intr(): MRL SENSOR CHANGED interrupt received"
35010923SEvan.Yan@Sun.COM 		    " on slot %d\n", slot_p->hs_phy_slot_num);
35110923SEvan.Yan@Sun.COM 	}
35210923SEvan.Yan@Sun.COM 
35310923SEvan.Yan@Sun.COM 	/* check for PRESENCE CHANGED interrupt */
35410923SEvan.Yan@Sun.COM 	if (status & PCIE_SLOTSTS_PRESENCE_CHANGED) {
35510923SEvan.Yan@Sun.COM 
35610923SEvan.Yan@Sun.COM 		PCIE_DBG("pciehpc_intr(): PRESENCE CHANGED interrupt received"
35710923SEvan.Yan@Sun.COM 		    " on slot %d\n", slot_p->hs_phy_slot_num);
35810923SEvan.Yan@Sun.COM 
35910923SEvan.Yan@Sun.COM 		if (status & PCIE_SLOTSTS_PRESENCE_DETECTED) {
36010923SEvan.Yan@Sun.COM 			/*
36110923SEvan.Yan@Sun.COM 			 * card is inserted into the slot, ask DDI Hotplug
36210923SEvan.Yan@Sun.COM 			 * framework to change state to Present.
36310923SEvan.Yan@Sun.COM 			 */
36411445SEvan.Yan@Sun.COM 			cmn_err(CE_NOTE, "pciehpc (%s%d): card is inserted"
36511445SEvan.Yan@Sun.COM 			    " in the slot %s",
36611445SEvan.Yan@Sun.COM 			    ddi_driver_name(dip),
36711445SEvan.Yan@Sun.COM 			    ddi_get_instance(dip),
36811445SEvan.Yan@Sun.COM 			    slot_p->hs_info.cn_name);
36911445SEvan.Yan@Sun.COM 
37010923SEvan.Yan@Sun.COM 			(void) ndi_hp_state_change_req(dip,
37110923SEvan.Yan@Sun.COM 			    slot_p->hs_info.cn_name,
37210923SEvan.Yan@Sun.COM 			    DDI_HP_CN_STATE_PRESENT,
37310923SEvan.Yan@Sun.COM 			    DDI_HP_REQ_ASYNC);
37410923SEvan.Yan@Sun.COM 		} else { /* card is removed from the slot */
37510923SEvan.Yan@Sun.COM 			cmn_err(CE_NOTE, "pciehpc (%s%d): card is removed"
37610923SEvan.Yan@Sun.COM 			    " from the slot %s",
37710923SEvan.Yan@Sun.COM 			    ddi_driver_name(dip),
37810923SEvan.Yan@Sun.COM 			    ddi_get_instance(dip),
37910923SEvan.Yan@Sun.COM 			    slot_p->hs_info.cn_name);
38010923SEvan.Yan@Sun.COM 
38110923SEvan.Yan@Sun.COM 			if (slot_p->hs_info.cn_state ==
38210923SEvan.Yan@Sun.COM 			    DDI_HP_CN_STATE_ENABLED) {
38310923SEvan.Yan@Sun.COM 				/* Card is removed when slot is enabled */
38410923SEvan.Yan@Sun.COM 				slot_p->hs_condition = AP_COND_FAILED;
38510923SEvan.Yan@Sun.COM 			} else {
38610923SEvan.Yan@Sun.COM 				slot_p->hs_condition = AP_COND_UNKNOWN;
38710923SEvan.Yan@Sun.COM 			}
38810923SEvan.Yan@Sun.COM 			/* make sure to disable power fault detction intr */
38910923SEvan.Yan@Sun.COM 			control =  pciehpc_reg_get16(ctrl_p,
39010923SEvan.Yan@Sun.COM 			    bus_p->bus_pcie_off + PCIE_SLOTCTL);
39110923SEvan.Yan@Sun.COM 
39210923SEvan.Yan@Sun.COM 			if (control & PCIE_SLOTCTL_PWR_FAULT_EN)
39310923SEvan.Yan@Sun.COM 				pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
39410923SEvan.Yan@Sun.COM 				    PCIE_SLOTCTL,
39510923SEvan.Yan@Sun.COM 				    control & ~PCIE_SLOTCTL_PWR_FAULT_EN);
39610923SEvan.Yan@Sun.COM 
39710923SEvan.Yan@Sun.COM 			/*
39810923SEvan.Yan@Sun.COM 			 * Ask DDI Hotplug framework to change state to Empty
39910923SEvan.Yan@Sun.COM 			 */
40010923SEvan.Yan@Sun.COM 			(void) ndi_hp_state_change_req(dip,
40110923SEvan.Yan@Sun.COM 			    slot_p->hs_info.cn_name,
40210923SEvan.Yan@Sun.COM 			    DDI_HP_CN_STATE_EMPTY,
40310923SEvan.Yan@Sun.COM 			    DDI_HP_REQ_ASYNC);
40410923SEvan.Yan@Sun.COM 		}
40510923SEvan.Yan@Sun.COM 	}
40610923SEvan.Yan@Sun.COM 
40710923SEvan.Yan@Sun.COM 	/* check for DLL state changed interrupt */
40810923SEvan.Yan@Sun.COM 	if (ctrl_p->hc_dll_active_rep &&
40910923SEvan.Yan@Sun.COM 	    (status & PCIE_SLOTSTS_DLL_STATE_CHANGED)) {
41010923SEvan.Yan@Sun.COM 		PCIE_DBG("pciehpc_intr(): DLL STATE CHANGED interrupt received"
41110923SEvan.Yan@Sun.COM 		    " on slot %d\n", slot_p->hs_phy_slot_num);
41210923SEvan.Yan@Sun.COM 
41310923SEvan.Yan@Sun.COM 		cv_signal(&slot_p->hs_dll_active_cv);
41410923SEvan.Yan@Sun.COM 	}
41510923SEvan.Yan@Sun.COM 
41610923SEvan.Yan@Sun.COM 	mutex_exit(&ctrl_p->hc_mutex);
41710923SEvan.Yan@Sun.COM 
41810923SEvan.Yan@Sun.COM 	return (DDI_INTR_CLAIMED);
41910923SEvan.Yan@Sun.COM }
42010923SEvan.Yan@Sun.COM 
42110923SEvan.Yan@Sun.COM /*
42210923SEvan.Yan@Sun.COM  * Handle hotplug commands
42310923SEvan.Yan@Sun.COM  *
42410923SEvan.Yan@Sun.COM  * Note: This function is called by DDI HP framework at kernel context only
42510923SEvan.Yan@Sun.COM  */
42610923SEvan.Yan@Sun.COM /* ARGSUSED */
42710923SEvan.Yan@Sun.COM int
pciehpc_hp_ops(dev_info_t * dip,char * cn_name,ddi_hp_op_t op,void * arg,void * result)42810923SEvan.Yan@Sun.COM pciehpc_hp_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op,
42910923SEvan.Yan@Sun.COM     void *arg, void *result)
43010923SEvan.Yan@Sun.COM {
43110923SEvan.Yan@Sun.COM 	pcie_hp_ctrl_t	*ctrl_p;
43210923SEvan.Yan@Sun.COM 	pcie_hp_slot_t	*slot_p;
43310923SEvan.Yan@Sun.COM 	int		ret = DDI_SUCCESS;
43410923SEvan.Yan@Sun.COM 
43510923SEvan.Yan@Sun.COM 	PCIE_DBG("pciehpc_hp_ops: dip=%p cn_name=%s op=%x arg=%p\n",
43610923SEvan.Yan@Sun.COM 	    dip, cn_name, op, arg);
43710923SEvan.Yan@Sun.COM 
43810923SEvan.Yan@Sun.COM 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
43910923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
44010923SEvan.Yan@Sun.COM 
44110923SEvan.Yan@Sun.COM 	slot_p = ctrl_p->hc_slots[0];
44210923SEvan.Yan@Sun.COM 
44310923SEvan.Yan@Sun.COM 	if (strcmp(cn_name, slot_p->hs_info.cn_name) != 0)
44410923SEvan.Yan@Sun.COM 		return (DDI_EINVAL);
44510923SEvan.Yan@Sun.COM 
44610923SEvan.Yan@Sun.COM 	switch (op) {
44710923SEvan.Yan@Sun.COM 	case DDI_HPOP_CN_GET_STATE:
44810923SEvan.Yan@Sun.COM 	{
44910923SEvan.Yan@Sun.COM 		mutex_enter(&slot_p->hs_ctrl->hc_mutex);
45010923SEvan.Yan@Sun.COM 
45110923SEvan.Yan@Sun.COM 		/* get the current slot state */
45210923SEvan.Yan@Sun.COM 		pciehpc_get_slot_state(slot_p);
45310923SEvan.Yan@Sun.COM 
45410923SEvan.Yan@Sun.COM 		*((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state;
45510923SEvan.Yan@Sun.COM 
45610923SEvan.Yan@Sun.COM 		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
45710923SEvan.Yan@Sun.COM 		break;
45810923SEvan.Yan@Sun.COM 	}
45910923SEvan.Yan@Sun.COM 	case DDI_HPOP_CN_CHANGE_STATE:
46010923SEvan.Yan@Sun.COM 	{
46110923SEvan.Yan@Sun.COM 		ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg;
46210923SEvan.Yan@Sun.COM 
46310923SEvan.Yan@Sun.COM 		mutex_enter(&slot_p->hs_ctrl->hc_mutex);
46410923SEvan.Yan@Sun.COM 
46510923SEvan.Yan@Sun.COM 		ret = pciehpc_change_slot_state(slot_p, target_state);
46610923SEvan.Yan@Sun.COM 		*(ddi_hp_cn_state_t *)result = slot_p->hs_info.cn_state;
46710923SEvan.Yan@Sun.COM 
46810923SEvan.Yan@Sun.COM 		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
46910923SEvan.Yan@Sun.COM 		break;
47010923SEvan.Yan@Sun.COM 	}
47110923SEvan.Yan@Sun.COM 	case DDI_HPOP_CN_PROBE:
47210923SEvan.Yan@Sun.COM 
47310923SEvan.Yan@Sun.COM 		ret = pciehpc_slot_probe(slot_p);
47410923SEvan.Yan@Sun.COM 
47510923SEvan.Yan@Sun.COM 		break;
47610923SEvan.Yan@Sun.COM 	case DDI_HPOP_CN_UNPROBE:
47710923SEvan.Yan@Sun.COM 		ret = pciehpc_slot_unprobe(slot_p);
47810923SEvan.Yan@Sun.COM 
47910923SEvan.Yan@Sun.COM 		break;
48010923SEvan.Yan@Sun.COM 	case DDI_HPOP_CN_GET_PROPERTY:
48110923SEvan.Yan@Sun.COM 		ret = pciehpc_slot_get_property(slot_p,
48210923SEvan.Yan@Sun.COM 		    (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
48310923SEvan.Yan@Sun.COM 		break;
48410923SEvan.Yan@Sun.COM 	case DDI_HPOP_CN_SET_PROPERTY:
48510923SEvan.Yan@Sun.COM 		ret = pciehpc_slot_set_property(slot_p,
48610923SEvan.Yan@Sun.COM 		    (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
48710923SEvan.Yan@Sun.COM 		break;
48810923SEvan.Yan@Sun.COM 	default:
48910923SEvan.Yan@Sun.COM 		ret = DDI_ENOTSUP;
49010923SEvan.Yan@Sun.COM 		break;
49110923SEvan.Yan@Sun.COM 	}
49210923SEvan.Yan@Sun.COM 
49310923SEvan.Yan@Sun.COM 	return (ret);
49410923SEvan.Yan@Sun.COM }
49510923SEvan.Yan@Sun.COM 
49610923SEvan.Yan@Sun.COM /*
49710923SEvan.Yan@Sun.COM  * Get the current state of the slot from the hw.
49810923SEvan.Yan@Sun.COM  *
49910923SEvan.Yan@Sun.COM  * The slot state should have been initialized before this function gets called.
50010923SEvan.Yan@Sun.COM  */
50110923SEvan.Yan@Sun.COM void
pciehpc_get_slot_state(pcie_hp_slot_t * slot_p)50210923SEvan.Yan@Sun.COM pciehpc_get_slot_state(pcie_hp_slot_t *slot_p)
50310923SEvan.Yan@Sun.COM {
50410923SEvan.Yan@Sun.COM 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
50510923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
50610923SEvan.Yan@Sun.COM 	uint16_t	control, status;
50710923SEvan.Yan@Sun.COM 	ddi_hp_cn_state_t curr_state = slot_p->hs_info.cn_state;
50810923SEvan.Yan@Sun.COM 
50910923SEvan.Yan@Sun.COM 	/* read the Slot Control Register */
51010923SEvan.Yan@Sun.COM 	control = pciehpc_reg_get16(ctrl_p,
51110923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
51210923SEvan.Yan@Sun.COM 
51310923SEvan.Yan@Sun.COM 	slot_p->hs_fault_led_state = PCIE_HP_LED_OFF; /* no fault led */
51410923SEvan.Yan@Sun.COM 	slot_p->hs_active_led_state = PCIE_HP_LED_OFF; /* no active led */
51510923SEvan.Yan@Sun.COM 
51610923SEvan.Yan@Sun.COM 	/* read the current Slot Status Register */
51710923SEvan.Yan@Sun.COM 	status = pciehpc_reg_get16(ctrl_p,
51810923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
51910923SEvan.Yan@Sun.COM 
52010923SEvan.Yan@Sun.COM 	/* get POWER led state */
52110923SEvan.Yan@Sun.COM 	slot_p->hs_power_led_state =
52210923SEvan.Yan@Sun.COM 	    pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control));
52310923SEvan.Yan@Sun.COM 
52410923SEvan.Yan@Sun.COM 	/* get ATTN led state */
52510923SEvan.Yan@Sun.COM 	slot_p->hs_attn_led_state =
52610923SEvan.Yan@Sun.COM 	    pciehpc_led_state_to_hpc(pcie_slotctl_attn_indicator_get(control));
52710923SEvan.Yan@Sun.COM 
52810923SEvan.Yan@Sun.COM 	if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
52910923SEvan.Yan@Sun.COM 		/* no device present; slot is empty */
53010923SEvan.Yan@Sun.COM 		slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY;
53110923SEvan.Yan@Sun.COM 
53210923SEvan.Yan@Sun.COM 		return;
53310923SEvan.Yan@Sun.COM 	}
53410923SEvan.Yan@Sun.COM 
53510923SEvan.Yan@Sun.COM 	/* device is present */
53610923SEvan.Yan@Sun.COM 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_PRESENT;
53710923SEvan.Yan@Sun.COM 
53810923SEvan.Yan@Sun.COM 	if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) {
53910923SEvan.Yan@Sun.COM 		/*
54010923SEvan.Yan@Sun.COM 		 * Device is powered on. Set to "ENABLED" state (skip
54110923SEvan.Yan@Sun.COM 		 * POWERED state) because there is not a explicit "enable"
54210923SEvan.Yan@Sun.COM 		 * action exists for PCIe.
54310923SEvan.Yan@Sun.COM 		 * If it is already in "POWERED" state, then keep it until
54410923SEvan.Yan@Sun.COM 		 * user explicitly change it to other states.
54510923SEvan.Yan@Sun.COM 		 */
54610923SEvan.Yan@Sun.COM 		if (curr_state == DDI_HP_CN_STATE_POWERED) {
54710923SEvan.Yan@Sun.COM 			slot_p->hs_info.cn_state = curr_state;
54810923SEvan.Yan@Sun.COM 		} else {
54910923SEvan.Yan@Sun.COM 			slot_p->hs_info.cn_state = DDI_HP_CN_STATE_ENABLED;
55010923SEvan.Yan@Sun.COM 		}
55110923SEvan.Yan@Sun.COM 	}
55210923SEvan.Yan@Sun.COM }
55310923SEvan.Yan@Sun.COM 
55410923SEvan.Yan@Sun.COM /*
55510923SEvan.Yan@Sun.COM  * setup slot name/slot-number info.
55610923SEvan.Yan@Sun.COM  */
55710923SEvan.Yan@Sun.COM void
pciehpc_set_slot_name(pcie_hp_ctrl_t * ctrl_p)55810923SEvan.Yan@Sun.COM pciehpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p)
55910923SEvan.Yan@Sun.COM {
56010923SEvan.Yan@Sun.COM 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
56110923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
56210923SEvan.Yan@Sun.COM 	uchar_t		*slotname_data;
56310923SEvan.Yan@Sun.COM 	int		*slotnum;
56410923SEvan.Yan@Sun.COM 	uint_t		count;
56510923SEvan.Yan@Sun.COM 	int		len;
56610923SEvan.Yan@Sun.COM 	int		invalid_slotnum = 0;
56710923SEvan.Yan@Sun.COM 	uint32_t	slot_capabilities;
56810923SEvan.Yan@Sun.COM 
56910923SEvan.Yan@Sun.COM 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ctrl_p->hc_dip,
57010923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "physical-slot#", &slotnum, &count) ==
57110923SEvan.Yan@Sun.COM 	    DDI_PROP_SUCCESS) {
57210923SEvan.Yan@Sun.COM 		slot_p->hs_phy_slot_num = slotnum[0];
57310923SEvan.Yan@Sun.COM 		ddi_prop_free(slotnum);
57410923SEvan.Yan@Sun.COM 	} else {
57510923SEvan.Yan@Sun.COM 		slot_capabilities = pciehpc_reg_get32(ctrl_p,
57610923SEvan.Yan@Sun.COM 		    bus_p->bus_pcie_off + PCIE_SLOTCAP);
57710923SEvan.Yan@Sun.COM 		slot_p->hs_phy_slot_num =
57810923SEvan.Yan@Sun.COM 		    PCIE_SLOTCAP_PHY_SLOT_NUM(slot_capabilities);
57910923SEvan.Yan@Sun.COM 	}
58010923SEvan.Yan@Sun.COM 
58110923SEvan.Yan@Sun.COM 	/* platform may not have initialized it */
58210923SEvan.Yan@Sun.COM 	if (!slot_p->hs_phy_slot_num) {
58310923SEvan.Yan@Sun.COM 		PCIE_DBG("%s#%d: Invalid slot number!\n",
58410923SEvan.Yan@Sun.COM 		    ddi_driver_name(ctrl_p->hc_dip),
58510923SEvan.Yan@Sun.COM 		    ddi_get_instance(ctrl_p->hc_dip));
58610923SEvan.Yan@Sun.COM 		slot_p->hs_phy_slot_num = pciehpc_reg_get8(ctrl_p,
58710923SEvan.Yan@Sun.COM 		    PCI_BCNF_SECBUS);
58810923SEvan.Yan@Sun.COM 		invalid_slotnum = 1;
58910923SEvan.Yan@Sun.COM 	}
59010923SEvan.Yan@Sun.COM 	slot_p->hs_info.cn_num = slot_p->hs_phy_slot_num;
59110923SEvan.Yan@Sun.COM 	slot_p->hs_info.cn_num_dpd_on = DDI_HP_CN_NUM_NONE;
59210923SEvan.Yan@Sun.COM 
59310923SEvan.Yan@Sun.COM 	/*
59410923SEvan.Yan@Sun.COM 	 * construct the slot_name:
59510923SEvan.Yan@Sun.COM 	 *	if "slot-names" property exists then use that name
59610923SEvan.Yan@Sun.COM 	 *	else if valid slot number exists then it is "pcie<slot-num>".
59710923SEvan.Yan@Sun.COM 	 *	else it will be "pcie<sec-bus-number>dev0"
59810923SEvan.Yan@Sun.COM 	 */
59910923SEvan.Yan@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, ctrl_p->hc_dip, DDI_PROP_DONTPASS,
60010923SEvan.Yan@Sun.COM 	    "slot-names", (caddr_t)&slotname_data, &len) == DDI_PROP_SUCCESS) {
60110923SEvan.Yan@Sun.COM 		char tmp_name[256];
60210923SEvan.Yan@Sun.COM 
60310923SEvan.Yan@Sun.COM 		/*
60410923SEvan.Yan@Sun.COM 		 * Note: for PCI-E slots, the device number is always 0 so the
60510923SEvan.Yan@Sun.COM 		 * first (and only) string is the slot name for this slot.
60610923SEvan.Yan@Sun.COM 		 */
60710923SEvan.Yan@Sun.COM 		(void) snprintf(tmp_name, sizeof (tmp_name),
60810923SEvan.Yan@Sun.COM 		    (char *)slotname_data + 4);
60910923SEvan.Yan@Sun.COM 		slot_p->hs_info.cn_name = ddi_strdup(tmp_name, KM_SLEEP);
61010923SEvan.Yan@Sun.COM 		kmem_free(slotname_data, len);
61110923SEvan.Yan@Sun.COM 	} else {
61210923SEvan.Yan@Sun.COM 		if (invalid_slotnum) {
61310923SEvan.Yan@Sun.COM 			/* use device number ie. 0 */
61410923SEvan.Yan@Sun.COM 			slot_p->hs_info.cn_name = ddi_strdup("pcie0",
61510923SEvan.Yan@Sun.COM 			    KM_SLEEP);
61610923SEvan.Yan@Sun.COM 		} else {
61710923SEvan.Yan@Sun.COM 			char tmp_name[256];
61810923SEvan.Yan@Sun.COM 
61910923SEvan.Yan@Sun.COM 			(void) snprintf(tmp_name, sizeof (tmp_name), "pcie%d",
62010923SEvan.Yan@Sun.COM 			    slot_p->hs_phy_slot_num);
62110923SEvan.Yan@Sun.COM 			slot_p->hs_info.cn_name = ddi_strdup(tmp_name,
62210923SEvan.Yan@Sun.COM 			    KM_SLEEP);
62310923SEvan.Yan@Sun.COM 		}
62410923SEvan.Yan@Sun.COM 	}
62510923SEvan.Yan@Sun.COM }
62610923SEvan.Yan@Sun.COM 
62710923SEvan.Yan@Sun.COM /*
62810923SEvan.Yan@Sun.COM  * Read/Write access to HPC registers. If platform nexus has non-standard
62910923SEvan.Yan@Sun.COM  * HPC access mechanism then regops functions are used to do reads/writes.
63010923SEvan.Yan@Sun.COM  */
63110923SEvan.Yan@Sun.COM uint8_t
pciehpc_reg_get8(pcie_hp_ctrl_t * ctrl_p,uint_t off)63210923SEvan.Yan@Sun.COM pciehpc_reg_get8(pcie_hp_ctrl_t *ctrl_p, uint_t off)
63310923SEvan.Yan@Sun.COM {
63410923SEvan.Yan@Sun.COM 	if (ctrl_p->hc_regops.get != NULL) {
63510923SEvan.Yan@Sun.COM 		return ((uint8_t)ctrl_p->hc_regops.get(
63610923SEvan.Yan@Sun.COM 		    ctrl_p->hc_regops.cookie, (off_t)off));
63710923SEvan.Yan@Sun.COM 	} else {
63810923SEvan.Yan@Sun.COM 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
63910923SEvan.Yan@Sun.COM 
64010923SEvan.Yan@Sun.COM 		return (pci_config_get8(bus_p->bus_cfg_hdl, off));
64110923SEvan.Yan@Sun.COM 	}
64210923SEvan.Yan@Sun.COM }
64310923SEvan.Yan@Sun.COM 
64410923SEvan.Yan@Sun.COM uint16_t
pciehpc_reg_get16(pcie_hp_ctrl_t * ctrl_p,uint_t off)64510923SEvan.Yan@Sun.COM pciehpc_reg_get16(pcie_hp_ctrl_t *ctrl_p, uint_t off)
64610923SEvan.Yan@Sun.COM {
64710923SEvan.Yan@Sun.COM 	if (ctrl_p->hc_regops.get != NULL) {
64810923SEvan.Yan@Sun.COM 		return ((uint16_t)ctrl_p->hc_regops.get(
64910923SEvan.Yan@Sun.COM 		    ctrl_p->hc_regops.cookie, (off_t)off));
65010923SEvan.Yan@Sun.COM 	} else {
65110923SEvan.Yan@Sun.COM 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
65210923SEvan.Yan@Sun.COM 
65310923SEvan.Yan@Sun.COM 		return (pci_config_get16(bus_p->bus_cfg_hdl, off));
65410923SEvan.Yan@Sun.COM 	}
65510923SEvan.Yan@Sun.COM }
65610923SEvan.Yan@Sun.COM 
65710923SEvan.Yan@Sun.COM uint32_t
pciehpc_reg_get32(pcie_hp_ctrl_t * ctrl_p,uint_t off)65810923SEvan.Yan@Sun.COM pciehpc_reg_get32(pcie_hp_ctrl_t *ctrl_p, uint_t off)
65910923SEvan.Yan@Sun.COM {
66010923SEvan.Yan@Sun.COM 	if (ctrl_p->hc_regops.get != NULL) {
66110923SEvan.Yan@Sun.COM 		return ((uint32_t)ctrl_p->hc_regops.get(
66210923SEvan.Yan@Sun.COM 		    ctrl_p->hc_regops.cookie, (off_t)off));
66310923SEvan.Yan@Sun.COM 	} else {
66410923SEvan.Yan@Sun.COM 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
66510923SEvan.Yan@Sun.COM 
66610923SEvan.Yan@Sun.COM 		return (pci_config_get32(bus_p->bus_cfg_hdl, off));
66710923SEvan.Yan@Sun.COM 	}
66810923SEvan.Yan@Sun.COM }
66910923SEvan.Yan@Sun.COM 
67010923SEvan.Yan@Sun.COM void
pciehpc_reg_put8(pcie_hp_ctrl_t * ctrl_p,uint_t off,uint8_t val)67110923SEvan.Yan@Sun.COM pciehpc_reg_put8(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint8_t val)
67210923SEvan.Yan@Sun.COM {
67310923SEvan.Yan@Sun.COM 	if (ctrl_p->hc_regops.put != NULL) {
67410923SEvan.Yan@Sun.COM 		ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
67510923SEvan.Yan@Sun.COM 		    (off_t)off, (uint_t)val);
67610923SEvan.Yan@Sun.COM 	} else {
67710923SEvan.Yan@Sun.COM 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
67810923SEvan.Yan@Sun.COM 
67910923SEvan.Yan@Sun.COM 		pci_config_put8(bus_p->bus_cfg_hdl, off, val);
68010923SEvan.Yan@Sun.COM 	}
68110923SEvan.Yan@Sun.COM }
68210923SEvan.Yan@Sun.COM 
68310923SEvan.Yan@Sun.COM void
pciehpc_reg_put16(pcie_hp_ctrl_t * ctrl_p,uint_t off,uint16_t val)68410923SEvan.Yan@Sun.COM pciehpc_reg_put16(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint16_t val)
68510923SEvan.Yan@Sun.COM {
68610923SEvan.Yan@Sun.COM 	if (ctrl_p->hc_regops.put != NULL) {
68710923SEvan.Yan@Sun.COM 		ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
68810923SEvan.Yan@Sun.COM 		    (off_t)off, (uint_t)val);
68910923SEvan.Yan@Sun.COM 	} else {
69010923SEvan.Yan@Sun.COM 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
69110923SEvan.Yan@Sun.COM 
69210923SEvan.Yan@Sun.COM 		pci_config_put16(bus_p->bus_cfg_hdl, off, val);
69310923SEvan.Yan@Sun.COM 	}
69410923SEvan.Yan@Sun.COM }
69510923SEvan.Yan@Sun.COM 
69610923SEvan.Yan@Sun.COM void
pciehpc_reg_put32(pcie_hp_ctrl_t * ctrl_p,uint_t off,uint32_t val)69710923SEvan.Yan@Sun.COM pciehpc_reg_put32(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint32_t val)
69810923SEvan.Yan@Sun.COM {
69910923SEvan.Yan@Sun.COM 	if (ctrl_p->hc_regops.put != NULL) {
70010923SEvan.Yan@Sun.COM 		ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
70110923SEvan.Yan@Sun.COM 		    (off_t)off, (uint_t)val);
70210923SEvan.Yan@Sun.COM 	} else {
70310923SEvan.Yan@Sun.COM 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
70410923SEvan.Yan@Sun.COM 
70510923SEvan.Yan@Sun.COM 		pci_config_put32(bus_p->bus_cfg_hdl, off, val);
70610923SEvan.Yan@Sun.COM 	}
70710923SEvan.Yan@Sun.COM }
70810923SEvan.Yan@Sun.COM 
70910923SEvan.Yan@Sun.COM /*
71010923SEvan.Yan@Sun.COM  * ************************************************************************
71110923SEvan.Yan@Sun.COM  * ***	Local functions (called within this file)
71210923SEvan.Yan@Sun.COM  * ***	PCIe Native Hotplug mode specific functions
71310923SEvan.Yan@Sun.COM  * ************************************************************************
71410923SEvan.Yan@Sun.COM  */
71510923SEvan.Yan@Sun.COM 
71610923SEvan.Yan@Sun.COM /*
71710923SEvan.Yan@Sun.COM  * Initialize HPC hardware, install interrupt handler, etc. It doesn't
71810923SEvan.Yan@Sun.COM  * enable hot plug interrupts.
71910923SEvan.Yan@Sun.COM  *
72010923SEvan.Yan@Sun.COM  * (Note: It is called only from pciehpc_init().)
72110923SEvan.Yan@Sun.COM  */
72210923SEvan.Yan@Sun.COM static int
pciehpc_hpc_init(pcie_hp_ctrl_t * ctrl_p)72310923SEvan.Yan@Sun.COM pciehpc_hpc_init(pcie_hp_ctrl_t *ctrl_p)
72410923SEvan.Yan@Sun.COM {
72510923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
72610923SEvan.Yan@Sun.COM 	uint16_t	reg;
72710923SEvan.Yan@Sun.COM 
72810923SEvan.Yan@Sun.COM 	/* read the Slot Control Register */
72910923SEvan.Yan@Sun.COM 	reg = pciehpc_reg_get16(ctrl_p,
73010923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
73110923SEvan.Yan@Sun.COM 
73210923SEvan.Yan@Sun.COM 	/* disable all interrupts */
73310923SEvan.Yan@Sun.COM 	reg &= ~(PCIE_SLOTCTL_INTR_MASK);
73410923SEvan.Yan@Sun.COM 	pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
73510923SEvan.Yan@Sun.COM 	    PCIE_SLOTCTL, reg);
73610923SEvan.Yan@Sun.COM 
73710923SEvan.Yan@Sun.COM 	/* clear any interrupt status bits */
73810923SEvan.Yan@Sun.COM 	reg = pciehpc_reg_get16(ctrl_p,
73910923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
74010923SEvan.Yan@Sun.COM 	pciehpc_reg_put16(ctrl_p,
74110923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
74210923SEvan.Yan@Sun.COM 
74310923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
74410923SEvan.Yan@Sun.COM }
74510923SEvan.Yan@Sun.COM 
74610923SEvan.Yan@Sun.COM /*
74710923SEvan.Yan@Sun.COM  * Uninitialize HPC hardware, uninstall interrupt handler, etc.
74810923SEvan.Yan@Sun.COM  *
74910923SEvan.Yan@Sun.COM  * (Note: It is called only from pciehpc_uninit().)
75010923SEvan.Yan@Sun.COM  */
75110923SEvan.Yan@Sun.COM static int
pciehpc_hpc_uninit(pcie_hp_ctrl_t * ctrl_p)75210923SEvan.Yan@Sun.COM pciehpc_hpc_uninit(pcie_hp_ctrl_t *ctrl_p)
75310923SEvan.Yan@Sun.COM {
75410923SEvan.Yan@Sun.COM 	/* disable interrupts */
75510923SEvan.Yan@Sun.COM 	(void) pciehpc_disable_intr(ctrl_p);
75610923SEvan.Yan@Sun.COM 
75710923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
75810923SEvan.Yan@Sun.COM }
75910923SEvan.Yan@Sun.COM 
76010923SEvan.Yan@Sun.COM /*
76110923SEvan.Yan@Sun.COM  * Setup slot information for use with DDI HP framework.
76210923SEvan.Yan@Sun.COM  */
76310923SEvan.Yan@Sun.COM static int
pciehpc_slotinfo_init(pcie_hp_ctrl_t * ctrl_p)76410923SEvan.Yan@Sun.COM pciehpc_slotinfo_init(pcie_hp_ctrl_t *ctrl_p)
76510923SEvan.Yan@Sun.COM {
76610923SEvan.Yan@Sun.COM 	uint32_t	slot_capabilities, link_capabilities;
76710923SEvan.Yan@Sun.COM 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
76810923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
76910923SEvan.Yan@Sun.COM 
77010923SEvan.Yan@Sun.COM 	mutex_enter(&ctrl_p->hc_mutex);
77110923SEvan.Yan@Sun.COM 	/*
77210923SEvan.Yan@Sun.COM 	 * setup DDI HP framework slot information structure
77310923SEvan.Yan@Sun.COM 	 */
77410923SEvan.Yan@Sun.COM 	slot_p->hs_device_num = 0;
77510923SEvan.Yan@Sun.COM 
77610923SEvan.Yan@Sun.COM 	slot_p->hs_info.cn_type = DDI_HP_CN_TYPE_PCIE;
77710923SEvan.Yan@Sun.COM 	slot_p->hs_info.cn_type_str = (ctrl_p->hc_regops.get == NULL) ?
77810923SEvan.Yan@Sun.COM 	    PCIE_NATIVE_HP_TYPE : PCIE_PROP_HP_TYPE;
77910923SEvan.Yan@Sun.COM 	slot_p->hs_info.cn_child = NULL;
78010923SEvan.Yan@Sun.COM 
78110923SEvan.Yan@Sun.COM 	slot_p->hs_minor =
78210923SEvan.Yan@Sun.COM 	    PCI_MINOR_NUM(ddi_get_instance(ctrl_p->hc_dip),
78310923SEvan.Yan@Sun.COM 	    slot_p->hs_device_num);
78410923SEvan.Yan@Sun.COM 	slot_p->hs_condition = AP_COND_UNKNOWN;
78510923SEvan.Yan@Sun.COM 
78610923SEvan.Yan@Sun.COM 	/* read Slot Capabilities Register */
78710923SEvan.Yan@Sun.COM 	slot_capabilities = pciehpc_reg_get32(ctrl_p,
78810923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTCAP);
78910923SEvan.Yan@Sun.COM 
79010923SEvan.Yan@Sun.COM 	/* set slot-name/slot-number info */
79110923SEvan.Yan@Sun.COM 	pciehpc_set_slot_name(ctrl_p);
79210923SEvan.Yan@Sun.COM 
79310923SEvan.Yan@Sun.COM 	/* check if Attn Button present */
79410923SEvan.Yan@Sun.COM 	ctrl_p->hc_has_attn = (slot_capabilities & PCIE_SLOTCAP_ATTN_BUTTON) ?
79510923SEvan.Yan@Sun.COM 	    B_TRUE : B_FALSE;
79610923SEvan.Yan@Sun.COM 
79710923SEvan.Yan@Sun.COM 	/* check if Manual Retention Latch sensor present */
79810923SEvan.Yan@Sun.COM 	ctrl_p->hc_has_mrl = (slot_capabilities & PCIE_SLOTCAP_MRL_SENSOR) ?
79910923SEvan.Yan@Sun.COM 	    B_TRUE : B_FALSE;
80010923SEvan.Yan@Sun.COM 
80110923SEvan.Yan@Sun.COM 	/*
80210923SEvan.Yan@Sun.COM 	 * PCI-E version 1.1 defines EMI Lock Present bit
80310923SEvan.Yan@Sun.COM 	 * in Slot Capabilities register. Check for it.
80410923SEvan.Yan@Sun.COM 	 */
80510923SEvan.Yan@Sun.COM 	ctrl_p->hc_has_emi_lock = (slot_capabilities &
80610923SEvan.Yan@Sun.COM 	    PCIE_SLOTCAP_EMI_LOCK_PRESENT) ? B_TRUE : B_FALSE;
80710923SEvan.Yan@Sun.COM 
80810923SEvan.Yan@Sun.COM 	link_capabilities = pciehpc_reg_get32(ctrl_p,
80910923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_LINKCAP);
81010923SEvan.Yan@Sun.COM 	ctrl_p->hc_dll_active_rep = (link_capabilities &
81110923SEvan.Yan@Sun.COM 	    PCIE_LINKCAP_DLL_ACTIVE_REP_CAPABLE) ? B_TRUE : B_FALSE;
81210923SEvan.Yan@Sun.COM 	if (ctrl_p->hc_dll_active_rep)
81310923SEvan.Yan@Sun.COM 		cv_init(&slot_p->hs_dll_active_cv, NULL, CV_DRIVER, NULL);
81410923SEvan.Yan@Sun.COM 
81510923SEvan.Yan@Sun.COM 	/* setup thread for handling ATTN button events */
81610923SEvan.Yan@Sun.COM 	if (ctrl_p->hc_has_attn) {
81710923SEvan.Yan@Sun.COM 		PCIE_DBG("pciehpc_slotinfo_init: setting up ATTN button event "
81810923SEvan.Yan@Sun.COM 		    "handler thread for slot %d\n", slot_p->hs_phy_slot_num);
81910923SEvan.Yan@Sun.COM 
82010923SEvan.Yan@Sun.COM 		cv_init(&slot_p->hs_attn_btn_cv, NULL, CV_DRIVER, NULL);
82110923SEvan.Yan@Sun.COM 		slot_p->hs_attn_btn_pending = B_FALSE;
82210923SEvan.Yan@Sun.COM 		slot_p->hs_attn_btn_threadp = thread_create(NULL, 0,
82310923SEvan.Yan@Sun.COM 		    pciehpc_attn_btn_handler,
82410923SEvan.Yan@Sun.COM 		    (void *)ctrl_p, 0, &p0, TS_RUN, minclsyspri);
82510923SEvan.Yan@Sun.COM 		slot_p->hs_attn_btn_thread_exit = B_FALSE;
82610923SEvan.Yan@Sun.COM 	}
82710923SEvan.Yan@Sun.COM 
82810923SEvan.Yan@Sun.COM 	/* get current slot state from the hw */
82910923SEvan.Yan@Sun.COM 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY;
83010923SEvan.Yan@Sun.COM 	pciehpc_get_slot_state(slot_p);
83110923SEvan.Yan@Sun.COM 	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_ENABLED)
83210923SEvan.Yan@Sun.COM 		slot_p->hs_condition = AP_COND_OK;
83310923SEvan.Yan@Sun.COM 
83410923SEvan.Yan@Sun.COM 	mutex_exit(&ctrl_p->hc_mutex);
83510923SEvan.Yan@Sun.COM 
83610923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
83710923SEvan.Yan@Sun.COM }
83810923SEvan.Yan@Sun.COM 
83910923SEvan.Yan@Sun.COM /*ARGSUSED*/
84010923SEvan.Yan@Sun.COM static int
pciehpc_slotinfo_uninit(pcie_hp_ctrl_t * ctrl_p)84110923SEvan.Yan@Sun.COM pciehpc_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p)
84210923SEvan.Yan@Sun.COM {
84310923SEvan.Yan@Sun.COM 	pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
84410923SEvan.Yan@Sun.COM 
84510923SEvan.Yan@Sun.COM 	if (slot_p->hs_attn_btn_threadp != NULL) {
84610923SEvan.Yan@Sun.COM 		mutex_enter(&ctrl_p->hc_mutex);
84710923SEvan.Yan@Sun.COM 		slot_p->hs_attn_btn_thread_exit = B_TRUE;
84810923SEvan.Yan@Sun.COM 		cv_signal(&slot_p->hs_attn_btn_cv);
84910923SEvan.Yan@Sun.COM 		PCIE_DBG("pciehpc_slotinfo_uninit: "
85010923SEvan.Yan@Sun.COM 		    "waiting for ATTN thread exit\n");
85110923SEvan.Yan@Sun.COM 		cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
85210923SEvan.Yan@Sun.COM 		PCIE_DBG("pciehpc_slotinfo_uninit: ATTN thread exit\n");
85310923SEvan.Yan@Sun.COM 		cv_destroy(&slot_p->hs_attn_btn_cv);
85410923SEvan.Yan@Sun.COM 		slot_p->hs_attn_btn_threadp = NULL;
85510923SEvan.Yan@Sun.COM 		mutex_exit(&ctrl_p->hc_mutex);
85610923SEvan.Yan@Sun.COM 	}
85710923SEvan.Yan@Sun.COM 
85810923SEvan.Yan@Sun.COM 	if (ctrl_p->hc_dll_active_rep)
85910923SEvan.Yan@Sun.COM 		cv_destroy(&slot_p->hs_dll_active_cv);
86010923SEvan.Yan@Sun.COM 	if (slot_p->hs_info.cn_name)
86110923SEvan.Yan@Sun.COM 		kmem_free(slot_p->hs_info.cn_name,
86210923SEvan.Yan@Sun.COM 		    strlen(slot_p->hs_info.cn_name) + 1);
86310923SEvan.Yan@Sun.COM 
86410923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
86510923SEvan.Yan@Sun.COM }
86610923SEvan.Yan@Sun.COM 
86710923SEvan.Yan@Sun.COM /*
86810923SEvan.Yan@Sun.COM  * Enable hot plug interrupts.
86910923SEvan.Yan@Sun.COM  * Note: this is only for Native hot plug mode.
87010923SEvan.Yan@Sun.COM  */
87110923SEvan.Yan@Sun.COM static int
pciehpc_enable_intr(pcie_hp_ctrl_t * ctrl_p)87210923SEvan.Yan@Sun.COM pciehpc_enable_intr(pcie_hp_ctrl_t *ctrl_p)
87310923SEvan.Yan@Sun.COM {
87410923SEvan.Yan@Sun.COM 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
87510923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
87610923SEvan.Yan@Sun.COM 	uint16_t	reg;
87710923SEvan.Yan@Sun.COM 
87810923SEvan.Yan@Sun.COM 	/* clear any interrupt status bits */
87910923SEvan.Yan@Sun.COM 	reg = pciehpc_reg_get16(ctrl_p,
88010923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
88110923SEvan.Yan@Sun.COM 	pciehpc_reg_put16(ctrl_p,
88210923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
88310923SEvan.Yan@Sun.COM 
88410923SEvan.Yan@Sun.COM 	/* read the Slot Control Register */
88510923SEvan.Yan@Sun.COM 	reg = pciehpc_reg_get16(ctrl_p,
88610923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
88710923SEvan.Yan@Sun.COM 
88810923SEvan.Yan@Sun.COM 	/*
88910923SEvan.Yan@Sun.COM 	 * enable interrupts: power fault detection interrupt is enabled
89010923SEvan.Yan@Sun.COM 	 * only when the slot is powered ON
89110923SEvan.Yan@Sun.COM 	 */
89210923SEvan.Yan@Sun.COM 	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
89310923SEvan.Yan@Sun.COM 		pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
89410923SEvan.Yan@Sun.COM 		    PCIE_SLOTCTL, reg | PCIE_SLOTCTL_INTR_MASK);
89510923SEvan.Yan@Sun.COM 	else
89610923SEvan.Yan@Sun.COM 		pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
89710923SEvan.Yan@Sun.COM 		    PCIE_SLOTCTL, reg | (PCIE_SLOTCTL_INTR_MASK &
89810923SEvan.Yan@Sun.COM 		    ~PCIE_SLOTCTL_PWR_FAULT_EN));
89910923SEvan.Yan@Sun.COM 
90010923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
90110923SEvan.Yan@Sun.COM }
90210923SEvan.Yan@Sun.COM 
90310923SEvan.Yan@Sun.COM /*
90410923SEvan.Yan@Sun.COM  * Disable hot plug interrupts.
90510923SEvan.Yan@Sun.COM  * Note: this is only for Native hot plug mode.
90610923SEvan.Yan@Sun.COM  */
90710923SEvan.Yan@Sun.COM static int
pciehpc_disable_intr(pcie_hp_ctrl_t * ctrl_p)90810923SEvan.Yan@Sun.COM pciehpc_disable_intr(pcie_hp_ctrl_t *ctrl_p)
90910923SEvan.Yan@Sun.COM {
91010923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
91110923SEvan.Yan@Sun.COM 	uint16_t	reg;
91210923SEvan.Yan@Sun.COM 
91310923SEvan.Yan@Sun.COM 	/* read the Slot Control Register */
91410923SEvan.Yan@Sun.COM 	reg = pciehpc_reg_get16(ctrl_p,
91510923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
91610923SEvan.Yan@Sun.COM 
91710923SEvan.Yan@Sun.COM 	/* disable all interrupts */
91810923SEvan.Yan@Sun.COM 	reg &= ~(PCIE_SLOTCTL_INTR_MASK);
91910923SEvan.Yan@Sun.COM 	pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTCTL, reg);
92010923SEvan.Yan@Sun.COM 
92110923SEvan.Yan@Sun.COM 	/* clear any interrupt status bits */
92210923SEvan.Yan@Sun.COM 	reg = pciehpc_reg_get16(ctrl_p,
92310923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
92410923SEvan.Yan@Sun.COM 	pciehpc_reg_put16(ctrl_p,
92510923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
92610923SEvan.Yan@Sun.COM 
92710923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
92810923SEvan.Yan@Sun.COM }
92910923SEvan.Yan@Sun.COM 
93010923SEvan.Yan@Sun.COM /*
93110923SEvan.Yan@Sun.COM  * Allocate a new hotplug controller and slot structures for HPC
93210923SEvan.Yan@Sun.COM  * associated with this dip.
93310923SEvan.Yan@Sun.COM  */
93410923SEvan.Yan@Sun.COM static pcie_hp_ctrl_t *
pciehpc_create_controller(dev_info_t * dip)93510923SEvan.Yan@Sun.COM pciehpc_create_controller(dev_info_t *dip)
93610923SEvan.Yan@Sun.COM {
93710923SEvan.Yan@Sun.COM 	pcie_hp_ctrl_t	*ctrl_p;
93810923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
93910923SEvan.Yan@Sun.COM 
94010923SEvan.Yan@Sun.COM 	ctrl_p = kmem_zalloc(sizeof (pcie_hp_ctrl_t), KM_SLEEP);
94110923SEvan.Yan@Sun.COM 	ctrl_p->hc_dip = dip;
94210923SEvan.Yan@Sun.COM 
94310923SEvan.Yan@Sun.COM 	/* Allocate a new slot structure. */
94410923SEvan.Yan@Sun.COM 	ctrl_p->hc_slots[0] = kmem_zalloc(sizeof (pcie_hp_slot_t), KM_SLEEP);
94510923SEvan.Yan@Sun.COM 	ctrl_p->hc_slots[0]->hs_num = 0;
94610923SEvan.Yan@Sun.COM 	ctrl_p->hc_slots[0]->hs_ctrl = ctrl_p;
94710923SEvan.Yan@Sun.COM 
94810923SEvan.Yan@Sun.COM 	/* Initialize the interrupt mutex */
94910923SEvan.Yan@Sun.COM 	mutex_init(&ctrl_p->hc_mutex, NULL, MUTEX_DRIVER,
95010923SEvan.Yan@Sun.COM 	    (void *)PCIE_INTR_PRI);
95110923SEvan.Yan@Sun.COM 
95210923SEvan.Yan@Sun.COM 	/* Initialize synchronization conditional variable */
95310923SEvan.Yan@Sun.COM 	cv_init(&ctrl_p->hc_cmd_comp_cv, NULL, CV_DRIVER, NULL);
95410923SEvan.Yan@Sun.COM 	ctrl_p->hc_cmd_pending = B_FALSE;
95510923SEvan.Yan@Sun.COM 
95610923SEvan.Yan@Sun.COM 	bus_p->bus_hp_curr_mode = PCIE_NATIVE_HP_MODE;
95710923SEvan.Yan@Sun.COM 	PCIE_SET_HP_CTRL(dip, ctrl_p);
95810923SEvan.Yan@Sun.COM 
95910923SEvan.Yan@Sun.COM 	return (ctrl_p);
96010923SEvan.Yan@Sun.COM }
96110923SEvan.Yan@Sun.COM 
96210923SEvan.Yan@Sun.COM /*
96310923SEvan.Yan@Sun.COM  * Remove the HPC controller and slot structures
96410923SEvan.Yan@Sun.COM  */
96510923SEvan.Yan@Sun.COM static void
pciehpc_destroy_controller(dev_info_t * dip)96610923SEvan.Yan@Sun.COM pciehpc_destroy_controller(dev_info_t *dip)
96710923SEvan.Yan@Sun.COM {
96810923SEvan.Yan@Sun.COM 	pcie_hp_ctrl_t	*ctrl_p;
96910923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
97010923SEvan.Yan@Sun.COM 
97110923SEvan.Yan@Sun.COM 	/* get the soft state structure for this dip */
97210923SEvan.Yan@Sun.COM 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
97310923SEvan.Yan@Sun.COM 		return;
97410923SEvan.Yan@Sun.COM 
97510923SEvan.Yan@Sun.COM 	PCIE_SET_HP_CTRL(dip, NULL);
97610923SEvan.Yan@Sun.COM 	bus_p->bus_hp_curr_mode = PCIE_NONE_HP_MODE;
97710923SEvan.Yan@Sun.COM 
97810923SEvan.Yan@Sun.COM 	mutex_destroy(&ctrl_p->hc_mutex);
97910923SEvan.Yan@Sun.COM 	cv_destroy(&ctrl_p->hc_cmd_comp_cv);
98010923SEvan.Yan@Sun.COM 	kmem_free(ctrl_p->hc_slots[0], sizeof (pcie_hp_slot_t));
98110923SEvan.Yan@Sun.COM 	kmem_free(ctrl_p, sizeof (pcie_hp_ctrl_t));
98210923SEvan.Yan@Sun.COM }
98310923SEvan.Yan@Sun.COM 
98410923SEvan.Yan@Sun.COM /*
98510923SEvan.Yan@Sun.COM  * Register the PCI-E hot plug slot with DDI HP framework.
98610923SEvan.Yan@Sun.COM  */
98710923SEvan.Yan@Sun.COM static int
pciehpc_register_slot(pcie_hp_ctrl_t * ctrl_p)98810923SEvan.Yan@Sun.COM pciehpc_register_slot(pcie_hp_ctrl_t *ctrl_p)
98910923SEvan.Yan@Sun.COM {
99010923SEvan.Yan@Sun.COM 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
99110923SEvan.Yan@Sun.COM 	dev_info_t	*dip = ctrl_p->hc_dip;
99210923SEvan.Yan@Sun.COM 
99310923SEvan.Yan@Sun.COM 	/* register the slot with DDI HP framework */
99410923SEvan.Yan@Sun.COM 	if (ndi_hp_register(dip, &slot_p->hs_info) != NDI_SUCCESS) {
99510923SEvan.Yan@Sun.COM 		PCIE_DBG("pciehpc_register_slot() failed to register slot %d\n",
99610923SEvan.Yan@Sun.COM 		    slot_p->hs_phy_slot_num);
99710923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
99810923SEvan.Yan@Sun.COM 	}
99910923SEvan.Yan@Sun.COM 
100010923SEvan.Yan@Sun.COM 	pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip),
100110923SEvan.Yan@Sun.COM 	    slot_p->hs_minor), slot_p->hs_device_num);
100210923SEvan.Yan@Sun.COM 
100310923SEvan.Yan@Sun.COM 	PCIE_DBG("pciehpc_register_slot(): registered slot %d\n",
100410923SEvan.Yan@Sun.COM 	    slot_p->hs_phy_slot_num);
100510923SEvan.Yan@Sun.COM 
100610923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
100710923SEvan.Yan@Sun.COM }
100810923SEvan.Yan@Sun.COM 
100910923SEvan.Yan@Sun.COM /*
101010923SEvan.Yan@Sun.COM  * Unregister the PCI-E hot plug slot from DDI HP framework.
101110923SEvan.Yan@Sun.COM  */
101210923SEvan.Yan@Sun.COM static int
pciehpc_unregister_slot(pcie_hp_ctrl_t * ctrl_p)101310923SEvan.Yan@Sun.COM pciehpc_unregister_slot(pcie_hp_ctrl_t *ctrl_p)
101410923SEvan.Yan@Sun.COM {
101510923SEvan.Yan@Sun.COM 	pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
101610923SEvan.Yan@Sun.COM 	dev_info_t	*dip = ctrl_p->hc_dip;
101710923SEvan.Yan@Sun.COM 
101810923SEvan.Yan@Sun.COM 	pcie_hp_delete_occupant_props(dip, makedevice(ddi_driver_major(dip),
101910923SEvan.Yan@Sun.COM 	    slot_p->hs_minor));
102010923SEvan.Yan@Sun.COM 
102110923SEvan.Yan@Sun.COM 	/* unregister the slot with DDI HP framework */
102210923SEvan.Yan@Sun.COM 	if (ndi_hp_unregister(dip, slot_p->hs_info.cn_name) != NDI_SUCCESS) {
102310923SEvan.Yan@Sun.COM 		PCIE_DBG("pciehpc_unregister_slot() "
102410923SEvan.Yan@Sun.COM 		    "failed to unregister slot %d\n", slot_p->hs_phy_slot_num);
102510923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
102610923SEvan.Yan@Sun.COM 	}
102710923SEvan.Yan@Sun.COM 
102810923SEvan.Yan@Sun.COM 	PCIE_DBG("pciehpc_unregister_slot(): unregistered slot %d\n",
102910923SEvan.Yan@Sun.COM 	    slot_p->hs_phy_slot_num);
103010923SEvan.Yan@Sun.COM 
103110923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
103210923SEvan.Yan@Sun.COM }
103310923SEvan.Yan@Sun.COM 
103410923SEvan.Yan@Sun.COM /*
103510923SEvan.Yan@Sun.COM  * pciehpc_slot_poweron()
103610923SEvan.Yan@Sun.COM  *
103710923SEvan.Yan@Sun.COM  * Poweron/Enable the slot.
103810923SEvan.Yan@Sun.COM  *
103910923SEvan.Yan@Sun.COM  * Note: This function is called by DDI HP framework at kernel context only
104010923SEvan.Yan@Sun.COM  */
104110923SEvan.Yan@Sun.COM /*ARGSUSED*/
104210923SEvan.Yan@Sun.COM static int
pciehpc_slot_poweron(pcie_hp_slot_t * slot_p,ddi_hp_cn_state_t * result)104310923SEvan.Yan@Sun.COM pciehpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result)
104410923SEvan.Yan@Sun.COM {
104510923SEvan.Yan@Sun.COM 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
104610923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
104710923SEvan.Yan@Sun.COM 	uint16_t	status, control;
104810923SEvan.Yan@Sun.COM 
104910923SEvan.Yan@Sun.COM 	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
105010923SEvan.Yan@Sun.COM 
105110923SEvan.Yan@Sun.COM 	/* get the current state of the slot */
105210923SEvan.Yan@Sun.COM 	pciehpc_get_slot_state(slot_p);
105310923SEvan.Yan@Sun.COM 
105410923SEvan.Yan@Sun.COM 	/* check if the slot is already in the 'enabled' state */
105510923SEvan.Yan@Sun.COM 	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) {
105610923SEvan.Yan@Sun.COM 		/* slot is already in the 'enabled' state */
105710923SEvan.Yan@Sun.COM 		PCIE_DBG("pciehpc_slot_poweron() slot %d already enabled\n",
105810923SEvan.Yan@Sun.COM 		    slot_p->hs_phy_slot_num);
105910923SEvan.Yan@Sun.COM 
106010923SEvan.Yan@Sun.COM 		*result = slot_p->hs_info.cn_state;
106110923SEvan.Yan@Sun.COM 		return (DDI_SUCCESS);
106210923SEvan.Yan@Sun.COM 	}
106310923SEvan.Yan@Sun.COM 
106410923SEvan.Yan@Sun.COM 	/* read the Slot Status Register */
106510923SEvan.Yan@Sun.COM 	status =  pciehpc_reg_get16(ctrl_p,
106610923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
106710923SEvan.Yan@Sun.COM 
106810923SEvan.Yan@Sun.COM 	/* make sure the MRL switch is closed if present */
106910923SEvan.Yan@Sun.COM 	if ((ctrl_p->hc_has_mrl) && (status & PCIE_SLOTSTS_MRL_SENSOR_OPEN)) {
107010923SEvan.Yan@Sun.COM 		/* MRL switch is open */
107110923SEvan.Yan@Sun.COM 		cmn_err(CE_WARN, "MRL switch is open on slot %d\n",
107210923SEvan.Yan@Sun.COM 		    slot_p->hs_phy_slot_num);
107310923SEvan.Yan@Sun.COM 		goto cleanup;
107410923SEvan.Yan@Sun.COM 	}
107510923SEvan.Yan@Sun.COM 
107610923SEvan.Yan@Sun.COM 	/* make sure the slot has a device present */
107710923SEvan.Yan@Sun.COM 	if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
107810923SEvan.Yan@Sun.COM 		/* slot is empty */
107910923SEvan.Yan@Sun.COM 		PCIE_DBG("slot %d is empty\n", slot_p->hs_phy_slot_num);
108010923SEvan.Yan@Sun.COM 		goto cleanup;
108110923SEvan.Yan@Sun.COM 	}
108210923SEvan.Yan@Sun.COM 
108310923SEvan.Yan@Sun.COM 	/* get the current state of Slot Control Register */
108410923SEvan.Yan@Sun.COM 	control =  pciehpc_reg_get16(ctrl_p,
108510923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
108610923SEvan.Yan@Sun.COM 
108710923SEvan.Yan@Sun.COM 	/*
108810923SEvan.Yan@Sun.COM 	 * Enable power to the slot involves:
108910923SEvan.Yan@Sun.COM 	 *	1. Set power LED to blink and ATTN led to OFF.
109010923SEvan.Yan@Sun.COM 	 *	2. Set power control ON in Slot Control Reigster and
109110923SEvan.Yan@Sun.COM 	 *	   wait for Command Completed Interrupt or 1 sec timeout.
109210923SEvan.Yan@Sun.COM 	 *	3. If Data Link Layer State Changed events are supported
109310923SEvan.Yan@Sun.COM 	 *	   then wait for the event to indicate Data Layer Link
109410923SEvan.Yan@Sun.COM 	 *	   is active. The time out value for this event is 1 second.
109510923SEvan.Yan@Sun.COM 	 *	   This is specified in PCI-E version 1.1.
109610923SEvan.Yan@Sun.COM 	 *	4. Set power LED to be ON.
109710923SEvan.Yan@Sun.COM 	 */
109810923SEvan.Yan@Sun.COM 
109910923SEvan.Yan@Sun.COM 	/* 1. set power LED to blink & ATTN led to OFF */
110010923SEvan.Yan@Sun.COM 	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
110110923SEvan.Yan@Sun.COM 	pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
110210923SEvan.Yan@Sun.COM 
110310923SEvan.Yan@Sun.COM 	/* 2. set power control to ON */
110410923SEvan.Yan@Sun.COM 	control =  pciehpc_reg_get16(ctrl_p,
110510923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
110610923SEvan.Yan@Sun.COM 	control &= ~PCIE_SLOTCTL_PWR_CONTROL;
110710923SEvan.Yan@Sun.COM 	pciehpc_issue_hpc_command(ctrl_p, control);
110810923SEvan.Yan@Sun.COM 
110910923SEvan.Yan@Sun.COM 	/* 3. wait for DLL State Change event, if it's supported */
111010923SEvan.Yan@Sun.COM 	if (ctrl_p->hc_dll_active_rep) {
111110923SEvan.Yan@Sun.COM 		status =  pciehpc_reg_get16(ctrl_p,
111210923SEvan.Yan@Sun.COM 		    bus_p->bus_pcie_off + PCIE_LINKSTS);
111310923SEvan.Yan@Sun.COM 
111410923SEvan.Yan@Sun.COM 		if (!(status & PCIE_LINKSTS_DLL_LINK_ACTIVE)) {
111510923SEvan.Yan@Sun.COM 			/* wait 1 sec for the DLL State Changed event */
111610923SEvan.Yan@Sun.COM 			(void) cv_timedwait(&slot_p->hs_dll_active_cv,
111710923SEvan.Yan@Sun.COM 			    &ctrl_p->hc_mutex,
111810923SEvan.Yan@Sun.COM 			    ddi_get_lbolt() +
111910923SEvan.Yan@Sun.COM 			    SEC_TO_TICK(PCIE_HP_DLL_STATE_CHANGE_TIMEOUT));
112010923SEvan.Yan@Sun.COM 
112110923SEvan.Yan@Sun.COM 			/* check Link status */
112210923SEvan.Yan@Sun.COM 			status =  pciehpc_reg_get16(ctrl_p,
112310923SEvan.Yan@Sun.COM 			    bus_p->bus_pcie_off +
112410923SEvan.Yan@Sun.COM 			    PCIE_LINKSTS);
112510923SEvan.Yan@Sun.COM 			if (!(status & PCIE_LINKSTS_DLL_LINK_ACTIVE))
112610923SEvan.Yan@Sun.COM 				goto cleanup2;
112710923SEvan.Yan@Sun.COM 		}
112810923SEvan.Yan@Sun.COM 	}
112910923SEvan.Yan@Sun.COM 
113010923SEvan.Yan@Sun.COM 	/* wait 1 sec for link to come up */
113110923SEvan.Yan@Sun.COM 	delay(drv_usectohz(1000000));
113210923SEvan.Yan@Sun.COM 
113310923SEvan.Yan@Sun.COM 	/* check power is really turned ON */
113410923SEvan.Yan@Sun.COM 	control =  pciehpc_reg_get16(ctrl_p,
113510923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
113610923SEvan.Yan@Sun.COM 
113710923SEvan.Yan@Sun.COM 	if (control & PCIE_SLOTCTL_PWR_CONTROL) {
113810923SEvan.Yan@Sun.COM 		PCIE_DBG("slot %d fails to turn on power on connect\n",
113910923SEvan.Yan@Sun.COM 		    slot_p->hs_phy_slot_num);
114010923SEvan.Yan@Sun.COM 
114110923SEvan.Yan@Sun.COM 		goto cleanup1;
114210923SEvan.Yan@Sun.COM 	}
114310923SEvan.Yan@Sun.COM 
114410923SEvan.Yan@Sun.COM 	/* clear power fault status */
114510923SEvan.Yan@Sun.COM 	status =  pciehpc_reg_get16(ctrl_p,
114610923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
114710923SEvan.Yan@Sun.COM 	status |= PCIE_SLOTSTS_PWR_FAULT_DETECTED;
114810923SEvan.Yan@Sun.COM 	pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTSTS,
114910923SEvan.Yan@Sun.COM 	    status);
115010923SEvan.Yan@Sun.COM 
115110923SEvan.Yan@Sun.COM 	/* enable power fault detection interrupt */
115210923SEvan.Yan@Sun.COM 	control |= PCIE_SLOTCTL_PWR_FAULT_EN;
115310923SEvan.Yan@Sun.COM 	pciehpc_issue_hpc_command(ctrl_p, control);
115410923SEvan.Yan@Sun.COM 
115510923SEvan.Yan@Sun.COM 	/* 4. Set power LED to be ON */
115610923SEvan.Yan@Sun.COM 	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_ON);
115710923SEvan.Yan@Sun.COM 
115810923SEvan.Yan@Sun.COM 	/* if EMI is present, turn it ON */
115910923SEvan.Yan@Sun.COM 	if (ctrl_p->hc_has_emi_lock) {
116010923SEvan.Yan@Sun.COM 		status =  pciehpc_reg_get16(ctrl_p,
116110923SEvan.Yan@Sun.COM 		    bus_p->bus_pcie_off + PCIE_SLOTSTS);
116210923SEvan.Yan@Sun.COM 
116310923SEvan.Yan@Sun.COM 		if (!(status & PCIE_SLOTSTS_EMI_LOCK_SET)) {
116410923SEvan.Yan@Sun.COM 			control =  pciehpc_reg_get16(ctrl_p,
116510923SEvan.Yan@Sun.COM 			    bus_p->bus_pcie_off + PCIE_SLOTCTL);
116610923SEvan.Yan@Sun.COM 			control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL;
116710923SEvan.Yan@Sun.COM 			pciehpc_issue_hpc_command(ctrl_p, control);
116810923SEvan.Yan@Sun.COM 
116910923SEvan.Yan@Sun.COM 			/* wait 1 sec after toggling the state of EMI lock */
117010923SEvan.Yan@Sun.COM 			delay(drv_usectohz(1000000));
117110923SEvan.Yan@Sun.COM 		}
117210923SEvan.Yan@Sun.COM 	}
117310923SEvan.Yan@Sun.COM 
117410923SEvan.Yan@Sun.COM 	*result = slot_p->hs_info.cn_state =
117510923SEvan.Yan@Sun.COM 	    DDI_HP_CN_STATE_POWERED;
117610923SEvan.Yan@Sun.COM 
117710923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
117810923SEvan.Yan@Sun.COM 
117910923SEvan.Yan@Sun.COM cleanup2:
118010923SEvan.Yan@Sun.COM 	control =  pciehpc_reg_get16(ctrl_p,
118110923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
118210923SEvan.Yan@Sun.COM 
118310923SEvan.Yan@Sun.COM 	/* if power is ON, set power control to OFF */
118410923SEvan.Yan@Sun.COM 	if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) {
118510923SEvan.Yan@Sun.COM 		control |= PCIE_SLOTCTL_PWR_CONTROL;
118610923SEvan.Yan@Sun.COM 		pciehpc_issue_hpc_command(ctrl_p, control);
118710923SEvan.Yan@Sun.COM 	}
118810923SEvan.Yan@Sun.COM 
118910923SEvan.Yan@Sun.COM cleanup1:
119010923SEvan.Yan@Sun.COM 	/* set power led to OFF */
119110923SEvan.Yan@Sun.COM 	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
119210923SEvan.Yan@Sun.COM 
119310923SEvan.Yan@Sun.COM cleanup:
119410923SEvan.Yan@Sun.COM 	return (DDI_FAILURE);
119510923SEvan.Yan@Sun.COM }
119610923SEvan.Yan@Sun.COM 
119710923SEvan.Yan@Sun.COM /*ARGSUSED*/
119810923SEvan.Yan@Sun.COM static int
pciehpc_slot_poweroff(pcie_hp_slot_t * slot_p,ddi_hp_cn_state_t * result)119910923SEvan.Yan@Sun.COM pciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result)
120010923SEvan.Yan@Sun.COM {
120110923SEvan.Yan@Sun.COM 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
120210923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
120310923SEvan.Yan@Sun.COM 	uint16_t	status, control;
120410923SEvan.Yan@Sun.COM 
120510923SEvan.Yan@Sun.COM 	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
120610923SEvan.Yan@Sun.COM 
120710923SEvan.Yan@Sun.COM 	/* get the current state of the slot */
120810923SEvan.Yan@Sun.COM 	pciehpc_get_slot_state(slot_p);
120910923SEvan.Yan@Sun.COM 
121010923SEvan.Yan@Sun.COM 	/* check if the slot is not in the "enabled' state */
121110923SEvan.Yan@Sun.COM 	if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) {
121210923SEvan.Yan@Sun.COM 		/* slot is in the 'disabled' state */
121310923SEvan.Yan@Sun.COM 		PCIE_DBG("pciehpc_slot_poweroff(): "
121410923SEvan.Yan@Sun.COM 		    "slot %d already disabled\n", slot_p->hs_phy_slot_num);
121510923SEvan.Yan@Sun.COM 		ASSERT(slot_p->hs_power_led_state == PCIE_HP_LED_OFF);
121610923SEvan.Yan@Sun.COM 
121710923SEvan.Yan@Sun.COM 		*result = slot_p->hs_info.cn_state;
121810923SEvan.Yan@Sun.COM 		return (DDI_SUCCESS);
121910923SEvan.Yan@Sun.COM 	}
122010923SEvan.Yan@Sun.COM 
122110923SEvan.Yan@Sun.COM 	/* read the Slot Status Register */
122210923SEvan.Yan@Sun.COM 	status =  pciehpc_reg_get16(ctrl_p,
122310923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
122410923SEvan.Yan@Sun.COM 
122510923SEvan.Yan@Sun.COM 	/* make sure the slot has a device present */
122610923SEvan.Yan@Sun.COM 	if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
122710923SEvan.Yan@Sun.COM 		/* slot is empty */
122810923SEvan.Yan@Sun.COM 		PCIE_DBG("pciehpc_slot_poweroff(): slot %d is empty\n",
122910923SEvan.Yan@Sun.COM 		    slot_p->hs_phy_slot_num);
123010923SEvan.Yan@Sun.COM 		goto cleanup;
123110923SEvan.Yan@Sun.COM 	}
123210923SEvan.Yan@Sun.COM 
123310923SEvan.Yan@Sun.COM 	/*
123410923SEvan.Yan@Sun.COM 	 * Disable power to the slot involves:
123510923SEvan.Yan@Sun.COM 	 *	1. Set power LED to blink.
123610923SEvan.Yan@Sun.COM 	 *	2. Set power control OFF in Slot Control Reigster and
123710923SEvan.Yan@Sun.COM 	 *	   wait for Command Completed Interrupt or 1 sec timeout.
123810923SEvan.Yan@Sun.COM 	 *	3. Set POWER led and ATTN led to be OFF.
123910923SEvan.Yan@Sun.COM 	 */
124010923SEvan.Yan@Sun.COM 
124110923SEvan.Yan@Sun.COM 	/* 1. set power LED to blink */
124210923SEvan.Yan@Sun.COM 	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
124310923SEvan.Yan@Sun.COM 
124410923SEvan.Yan@Sun.COM 	/* disable power fault detection interrupt */
124510923SEvan.Yan@Sun.COM 	control = pciehpc_reg_get16(ctrl_p,
124610923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
124710923SEvan.Yan@Sun.COM 	control &= ~PCIE_SLOTCTL_PWR_FAULT_EN;
124810923SEvan.Yan@Sun.COM 	pciehpc_issue_hpc_command(ctrl_p, control);
124910923SEvan.Yan@Sun.COM 
125010923SEvan.Yan@Sun.COM 	/* 2. set power control to OFF */
125110923SEvan.Yan@Sun.COM 	control =  pciehpc_reg_get16(ctrl_p,
125210923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
125310923SEvan.Yan@Sun.COM 	control |= PCIE_SLOTCTL_PWR_CONTROL;
125410923SEvan.Yan@Sun.COM 	pciehpc_issue_hpc_command(ctrl_p, control);
125510923SEvan.Yan@Sun.COM 
125610923SEvan.Yan@Sun.COM #ifdef DEBUG
125710923SEvan.Yan@Sun.COM 	/* check for power control bit to be OFF */
125810923SEvan.Yan@Sun.COM 	control =  pciehpc_reg_get16(ctrl_p,
125910923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
126010923SEvan.Yan@Sun.COM 	ASSERT(control & PCIE_SLOTCTL_PWR_CONTROL);
126110923SEvan.Yan@Sun.COM #endif
126210923SEvan.Yan@Sun.COM 
126310923SEvan.Yan@Sun.COM 	/* 3. Set power LED to be OFF */
126410923SEvan.Yan@Sun.COM 	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
126510923SEvan.Yan@Sun.COM 	pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
126610923SEvan.Yan@Sun.COM 
126710923SEvan.Yan@Sun.COM 	/* if EMI is present, turn it OFF */
126810923SEvan.Yan@Sun.COM 	if (ctrl_p->hc_has_emi_lock) {
126910923SEvan.Yan@Sun.COM 		status =  pciehpc_reg_get16(ctrl_p,
127010923SEvan.Yan@Sun.COM 		    bus_p->bus_pcie_off + PCIE_SLOTSTS);
127110923SEvan.Yan@Sun.COM 
127210923SEvan.Yan@Sun.COM 		if (status & PCIE_SLOTSTS_EMI_LOCK_SET) {
127310923SEvan.Yan@Sun.COM 			control =  pciehpc_reg_get16(ctrl_p,
127410923SEvan.Yan@Sun.COM 			    bus_p->bus_pcie_off + PCIE_SLOTCTL);
127510923SEvan.Yan@Sun.COM 			control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL;
127610923SEvan.Yan@Sun.COM 			pciehpc_issue_hpc_command(ctrl_p, control);
127710923SEvan.Yan@Sun.COM 
127810923SEvan.Yan@Sun.COM 			/* wait 1 sec after toggling the state of EMI lock */
127910923SEvan.Yan@Sun.COM 			delay(drv_usectohz(1000000));
128010923SEvan.Yan@Sun.COM 		}
128110923SEvan.Yan@Sun.COM 	}
128210923SEvan.Yan@Sun.COM 
128310923SEvan.Yan@Sun.COM 	/* get the current state of the slot */
128410923SEvan.Yan@Sun.COM 	pciehpc_get_slot_state(slot_p);
128510923SEvan.Yan@Sun.COM 
128610923SEvan.Yan@Sun.COM 	*result = slot_p->hs_info.cn_state;
128710923SEvan.Yan@Sun.COM 
128810923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
128910923SEvan.Yan@Sun.COM 
129010923SEvan.Yan@Sun.COM cleanup:
129110923SEvan.Yan@Sun.COM 	return (DDI_FAILURE);
129210923SEvan.Yan@Sun.COM }
129310923SEvan.Yan@Sun.COM 
129410923SEvan.Yan@Sun.COM /*
129510923SEvan.Yan@Sun.COM  * pciehpc_slot_probe()
129610923SEvan.Yan@Sun.COM  *
129710923SEvan.Yan@Sun.COM  * Probe the slot.
129810923SEvan.Yan@Sun.COM  *
129910923SEvan.Yan@Sun.COM  * Note: This function is called by DDI HP framework at kernel context only
130010923SEvan.Yan@Sun.COM  */
130110923SEvan.Yan@Sun.COM /*ARGSUSED*/
130210923SEvan.Yan@Sun.COM static int
pciehpc_slot_probe(pcie_hp_slot_t * slot_p)130310923SEvan.Yan@Sun.COM pciehpc_slot_probe(pcie_hp_slot_t *slot_p)
130410923SEvan.Yan@Sun.COM {
130510923SEvan.Yan@Sun.COM 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
130610923SEvan.Yan@Sun.COM 	int		ret = DDI_SUCCESS;
130710923SEvan.Yan@Sun.COM 
130810923SEvan.Yan@Sun.COM 	mutex_enter(&ctrl_p->hc_mutex);
130910923SEvan.Yan@Sun.COM 
131010923SEvan.Yan@Sun.COM 	/* get the current state of the slot */
131110923SEvan.Yan@Sun.COM 	pciehpc_get_slot_state(slot_p);
131210923SEvan.Yan@Sun.COM 
131310923SEvan.Yan@Sun.COM 	/*
131410923SEvan.Yan@Sun.COM 	 * Probe a given PCIe Hotplug Connection (CN).
131510923SEvan.Yan@Sun.COM 	 */
131610923SEvan.Yan@Sun.COM 	PCIE_DISABLE_ERRORS(ctrl_p->hc_dip);
131710923SEvan.Yan@Sun.COM 	ret = pcie_hp_probe(slot_p);
131810923SEvan.Yan@Sun.COM 
131910923SEvan.Yan@Sun.COM 	if (ret != DDI_SUCCESS) {
132010923SEvan.Yan@Sun.COM 		PCIE_DBG("pciehpc_slot_probe() failed\n");
132110923SEvan.Yan@Sun.COM 
132210923SEvan.Yan@Sun.COM 		/* turn the ATTN led ON for configure failure */
132310923SEvan.Yan@Sun.COM 		pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_ON);
132410923SEvan.Yan@Sun.COM 
132510923SEvan.Yan@Sun.COM 		/* if power to the slot is still on then set Power led to ON */
132610923SEvan.Yan@Sun.COM 		if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
132710923SEvan.Yan@Sun.COM 			pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
132810923SEvan.Yan@Sun.COM 			    PCIE_HP_LED_ON);
132910923SEvan.Yan@Sun.COM 
133010923SEvan.Yan@Sun.COM 		mutex_exit(&ctrl_p->hc_mutex);
133110923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
133210923SEvan.Yan@Sun.COM 	}
133310923SEvan.Yan@Sun.COM 
133410923SEvan.Yan@Sun.COM 	PCIE_ENABLE_ERRORS(ctrl_p->hc_dip);
133510923SEvan.Yan@Sun.COM 
133610923SEvan.Yan@Sun.COM 	/* get the current state of the slot */
133710923SEvan.Yan@Sun.COM 	pciehpc_get_slot_state(slot_p);
133810923SEvan.Yan@Sun.COM 
133910923SEvan.Yan@Sun.COM 	mutex_exit(&ctrl_p->hc_mutex);
134010923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
134110923SEvan.Yan@Sun.COM }
134210923SEvan.Yan@Sun.COM 
134310923SEvan.Yan@Sun.COM /*
134410923SEvan.Yan@Sun.COM  * pciehpc_slot_unprobe()
134510923SEvan.Yan@Sun.COM  *
134610923SEvan.Yan@Sun.COM  * Unprobe the slot.
134710923SEvan.Yan@Sun.COM  *
134810923SEvan.Yan@Sun.COM  * Note: This function is called by DDI HP framework at kernel context only
134910923SEvan.Yan@Sun.COM  */
135010923SEvan.Yan@Sun.COM /*ARGSUSED*/
135110923SEvan.Yan@Sun.COM static int
pciehpc_slot_unprobe(pcie_hp_slot_t * slot_p)135210923SEvan.Yan@Sun.COM pciehpc_slot_unprobe(pcie_hp_slot_t *slot_p)
135310923SEvan.Yan@Sun.COM {
135410923SEvan.Yan@Sun.COM 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
135510923SEvan.Yan@Sun.COM 	int		ret;
135610923SEvan.Yan@Sun.COM 
135710923SEvan.Yan@Sun.COM 	mutex_enter(&ctrl_p->hc_mutex);
135810923SEvan.Yan@Sun.COM 
135910923SEvan.Yan@Sun.COM 	/* get the current state of the slot */
136010923SEvan.Yan@Sun.COM 	pciehpc_get_slot_state(slot_p);
136110923SEvan.Yan@Sun.COM 
136210923SEvan.Yan@Sun.COM 	/*
136310923SEvan.Yan@Sun.COM 	 * Unprobe a given PCIe Hotplug Connection (CN).
136410923SEvan.Yan@Sun.COM 	 */
136510923SEvan.Yan@Sun.COM 	PCIE_DISABLE_ERRORS(ctrl_p->hc_dip);
136610923SEvan.Yan@Sun.COM 	ret = pcie_hp_unprobe(slot_p);
136710923SEvan.Yan@Sun.COM 
136810923SEvan.Yan@Sun.COM 	if (ret != DDI_SUCCESS) {
136910923SEvan.Yan@Sun.COM 		PCIE_DBG("pciehpc_slot_unprobe() failed\n");
137010923SEvan.Yan@Sun.COM 
137110923SEvan.Yan@Sun.COM 		/* if power to the slot is still on then set Power led to ON */
137210923SEvan.Yan@Sun.COM 		if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
137310923SEvan.Yan@Sun.COM 			pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
137410923SEvan.Yan@Sun.COM 			    PCIE_HP_LED_ON);
137510923SEvan.Yan@Sun.COM 
137610923SEvan.Yan@Sun.COM 		PCIE_ENABLE_ERRORS(ctrl_p->hc_dip);
137710923SEvan.Yan@Sun.COM 
137810923SEvan.Yan@Sun.COM 		mutex_exit(&ctrl_p->hc_mutex);
137910923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
138010923SEvan.Yan@Sun.COM 	}
138110923SEvan.Yan@Sun.COM 
138210923SEvan.Yan@Sun.COM 	/* get the current state of the slot */
138310923SEvan.Yan@Sun.COM 	pciehpc_get_slot_state(slot_p);
138410923SEvan.Yan@Sun.COM 
138510923SEvan.Yan@Sun.COM 	mutex_exit(&ctrl_p->hc_mutex);
138610923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
138710923SEvan.Yan@Sun.COM }
138810923SEvan.Yan@Sun.COM 
138910923SEvan.Yan@Sun.COM static int
pciehpc_upgrade_slot_state(pcie_hp_slot_t * slot_p,ddi_hp_cn_state_t target_state)139010923SEvan.Yan@Sun.COM pciehpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
139110923SEvan.Yan@Sun.COM     ddi_hp_cn_state_t target_state)
139210923SEvan.Yan@Sun.COM {
139310923SEvan.Yan@Sun.COM 	ddi_hp_cn_state_t curr_state;
139410923SEvan.Yan@Sun.COM 	int rv = DDI_SUCCESS;
139510923SEvan.Yan@Sun.COM 
139610923SEvan.Yan@Sun.COM 	if (target_state > DDI_HP_CN_STATE_ENABLED) {
139710923SEvan.Yan@Sun.COM 		return (DDI_EINVAL);
139810923SEvan.Yan@Sun.COM 	}
139910923SEvan.Yan@Sun.COM 
140010923SEvan.Yan@Sun.COM 	curr_state = slot_p->hs_info.cn_state;
140110923SEvan.Yan@Sun.COM 	while ((curr_state < target_state) && (rv == DDI_SUCCESS)) {
140210923SEvan.Yan@Sun.COM 
140310923SEvan.Yan@Sun.COM 		switch (curr_state) {
140410923SEvan.Yan@Sun.COM 		case DDI_HP_CN_STATE_EMPTY:
140510923SEvan.Yan@Sun.COM 			/*
140610923SEvan.Yan@Sun.COM 			 * From EMPTY to PRESENT, just check the hardware
140710923SEvan.Yan@Sun.COM 			 * slot state.
140810923SEvan.Yan@Sun.COM 			 */
140910923SEvan.Yan@Sun.COM 			pciehpc_get_slot_state(slot_p);
141010923SEvan.Yan@Sun.COM 			curr_state = slot_p->hs_info.cn_state;
141110923SEvan.Yan@Sun.COM 			if (curr_state < DDI_HP_CN_STATE_PRESENT)
141210923SEvan.Yan@Sun.COM 				rv = DDI_FAILURE;
141310923SEvan.Yan@Sun.COM 			break;
141410923SEvan.Yan@Sun.COM 		case DDI_HP_CN_STATE_PRESENT:
141510923SEvan.Yan@Sun.COM 			rv = (slot_p->hs_ctrl->hc_ops.poweron_hpc_slot)(slot_p,
141610923SEvan.Yan@Sun.COM 			    &curr_state);
141710923SEvan.Yan@Sun.COM 
141810923SEvan.Yan@Sun.COM 			break;
141910923SEvan.Yan@Sun.COM 		case DDI_HP_CN_STATE_POWERED:
142010923SEvan.Yan@Sun.COM 			curr_state = slot_p->hs_info.cn_state =
142110923SEvan.Yan@Sun.COM 			    DDI_HP_CN_STATE_ENABLED;
142210923SEvan.Yan@Sun.COM 			break;
142310923SEvan.Yan@Sun.COM 		default:
142410923SEvan.Yan@Sun.COM 			/* should never reach here */
142510923SEvan.Yan@Sun.COM 			ASSERT("unknown devinfo state");
142610923SEvan.Yan@Sun.COM 		}
142710923SEvan.Yan@Sun.COM 	}
142810923SEvan.Yan@Sun.COM 
142910923SEvan.Yan@Sun.COM 	return (rv);
143010923SEvan.Yan@Sun.COM }
143110923SEvan.Yan@Sun.COM 
143210923SEvan.Yan@Sun.COM static int
pciehpc_downgrade_slot_state(pcie_hp_slot_t * slot_p,ddi_hp_cn_state_t target_state)143310923SEvan.Yan@Sun.COM pciehpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
143410923SEvan.Yan@Sun.COM     ddi_hp_cn_state_t target_state)
143510923SEvan.Yan@Sun.COM {
143610923SEvan.Yan@Sun.COM 	ddi_hp_cn_state_t curr_state;
143710923SEvan.Yan@Sun.COM 	int rv = DDI_SUCCESS;
143810923SEvan.Yan@Sun.COM 
143910923SEvan.Yan@Sun.COM 
144010923SEvan.Yan@Sun.COM 	curr_state = slot_p->hs_info.cn_state;
144110923SEvan.Yan@Sun.COM 	while ((curr_state > target_state) && (rv == DDI_SUCCESS)) {
144210923SEvan.Yan@Sun.COM 
144310923SEvan.Yan@Sun.COM 		switch (curr_state) {
144410923SEvan.Yan@Sun.COM 		case DDI_HP_CN_STATE_PRESENT:
144510923SEvan.Yan@Sun.COM 			/*
144610923SEvan.Yan@Sun.COM 			 * From PRESENT to EMPTY, just check hardware slot
144710923SEvan.Yan@Sun.COM 			 * state.
144810923SEvan.Yan@Sun.COM 			 */
144910923SEvan.Yan@Sun.COM 			pciehpc_get_slot_state(slot_p);
145010923SEvan.Yan@Sun.COM 			curr_state = slot_p->hs_info.cn_state;
145110923SEvan.Yan@Sun.COM 			if (curr_state >= DDI_HP_CN_STATE_PRESENT)
145210923SEvan.Yan@Sun.COM 				rv = DDI_FAILURE;
145310923SEvan.Yan@Sun.COM 			break;
145410923SEvan.Yan@Sun.COM 		case DDI_HP_CN_STATE_POWERED:
145510923SEvan.Yan@Sun.COM 			rv = (slot_p->hs_ctrl->hc_ops.poweroff_hpc_slot)(
145610923SEvan.Yan@Sun.COM 			    slot_p, &curr_state);
145710923SEvan.Yan@Sun.COM 
145810923SEvan.Yan@Sun.COM 			break;
145910923SEvan.Yan@Sun.COM 		case DDI_HP_CN_STATE_ENABLED:
146010923SEvan.Yan@Sun.COM 			curr_state = slot_p->hs_info.cn_state =
146110923SEvan.Yan@Sun.COM 			    DDI_HP_CN_STATE_POWERED;
146210923SEvan.Yan@Sun.COM 
146310923SEvan.Yan@Sun.COM 			break;
146410923SEvan.Yan@Sun.COM 		default:
146510923SEvan.Yan@Sun.COM 			/* should never reach here */
146610923SEvan.Yan@Sun.COM 			ASSERT("unknown devinfo state");
146710923SEvan.Yan@Sun.COM 		}
146810923SEvan.Yan@Sun.COM 	}
146910923SEvan.Yan@Sun.COM 
147010923SEvan.Yan@Sun.COM 	return (rv);
147110923SEvan.Yan@Sun.COM }
147210923SEvan.Yan@Sun.COM 
147310923SEvan.Yan@Sun.COM /* Change slot state to a target state */
147410923SEvan.Yan@Sun.COM static int
pciehpc_change_slot_state(pcie_hp_slot_t * slot_p,ddi_hp_cn_state_t target_state)147510923SEvan.Yan@Sun.COM pciehpc_change_slot_state(pcie_hp_slot_t *slot_p,
147610923SEvan.Yan@Sun.COM     ddi_hp_cn_state_t target_state)
147710923SEvan.Yan@Sun.COM {
147810923SEvan.Yan@Sun.COM 	ddi_hp_cn_state_t curr_state;
147910923SEvan.Yan@Sun.COM 	int rv;
148010923SEvan.Yan@Sun.COM 
148110923SEvan.Yan@Sun.COM 	pciehpc_get_slot_state(slot_p);
148210923SEvan.Yan@Sun.COM 	curr_state = slot_p->hs_info.cn_state;
148310923SEvan.Yan@Sun.COM 
148410923SEvan.Yan@Sun.COM 	if (curr_state == target_state) {
148510923SEvan.Yan@Sun.COM 		return (DDI_SUCCESS);
148610923SEvan.Yan@Sun.COM 	}
148710923SEvan.Yan@Sun.COM 	if (curr_state < target_state) {
148810923SEvan.Yan@Sun.COM 
148910923SEvan.Yan@Sun.COM 		rv = pciehpc_upgrade_slot_state(slot_p, target_state);
149010923SEvan.Yan@Sun.COM 	} else {
149110923SEvan.Yan@Sun.COM 		rv = pciehpc_downgrade_slot_state(slot_p, target_state);
149210923SEvan.Yan@Sun.COM 	}
149310923SEvan.Yan@Sun.COM 
149410923SEvan.Yan@Sun.COM 	return (rv);
149510923SEvan.Yan@Sun.COM }
149610923SEvan.Yan@Sun.COM 
149710923SEvan.Yan@Sun.COM int
pciehpc_slot_get_property(pcie_hp_slot_t * slot_p,ddi_hp_property_t * arg,ddi_hp_property_t * rval)149810923SEvan.Yan@Sun.COM pciehpc_slot_get_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
149910923SEvan.Yan@Sun.COM     ddi_hp_property_t *rval)
150010923SEvan.Yan@Sun.COM {
150110923SEvan.Yan@Sun.COM 	ddi_hp_property_t request, result;
150210923SEvan.Yan@Sun.COM #ifdef _SYSCALL32_IMPL
150310923SEvan.Yan@Sun.COM 	ddi_hp_property32_t request32, result32;
150410923SEvan.Yan@Sun.COM #endif
150510923SEvan.Yan@Sun.COM 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
150610923SEvan.Yan@Sun.COM 	nvlist_t	*prop_list;
150710923SEvan.Yan@Sun.COM 	nvlist_t	*prop_rlist; /* nvlist for return values */
150810923SEvan.Yan@Sun.COM 	nvpair_t	*prop_pair;
150910923SEvan.Yan@Sun.COM 	char		*name, *value;
151010923SEvan.Yan@Sun.COM 	int		ret = DDI_SUCCESS;
151110923SEvan.Yan@Sun.COM 	int		i, n;
151210923SEvan.Yan@Sun.COM 	boolean_t	get_all_prop = B_FALSE;
151310923SEvan.Yan@Sun.COM 
151410923SEvan.Yan@Sun.COM 	if (get_udatamodel() == DATAMODEL_NATIVE) {
151510923SEvan.Yan@Sun.COM 		if (copyin(arg, &request, sizeof (ddi_hp_property_t)) ||
151610923SEvan.Yan@Sun.COM 		    copyin(rval, &result, sizeof (ddi_hp_property_t)))
151710923SEvan.Yan@Sun.COM 			return (DDI_FAILURE);
151810923SEvan.Yan@Sun.COM 	}
151910923SEvan.Yan@Sun.COM #ifdef _SYSCALL32_IMPL
152010923SEvan.Yan@Sun.COM 	else {
152110923SEvan.Yan@Sun.COM 		bzero(&request, sizeof (request));
152210923SEvan.Yan@Sun.COM 		bzero(&result, sizeof (result));
152310923SEvan.Yan@Sun.COM 		if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)) ||
152410923SEvan.Yan@Sun.COM 		    copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
152510923SEvan.Yan@Sun.COM 			return (DDI_FAILURE);
152610923SEvan.Yan@Sun.COM 		request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
152710923SEvan.Yan@Sun.COM 		request.buf_size = request32.buf_size;
152810923SEvan.Yan@Sun.COM 		result.nvlist_buf = (char *)(uintptr_t)result32.nvlist_buf;
152910923SEvan.Yan@Sun.COM 		result.buf_size = result32.buf_size;
153010923SEvan.Yan@Sun.COM 	}
153110923SEvan.Yan@Sun.COM #endif
153210923SEvan.Yan@Sun.COM 
153310923SEvan.Yan@Sun.COM 	if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
153410923SEvan.Yan@Sun.COM 	    &prop_list)) != DDI_SUCCESS)
153510923SEvan.Yan@Sun.COM 		return (ret);
153610923SEvan.Yan@Sun.COM 
153710923SEvan.Yan@Sun.COM 	if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
153810923SEvan.Yan@Sun.COM 		ret = DDI_ENOMEM;
153910923SEvan.Yan@Sun.COM 		goto get_prop_cleanup;
154010923SEvan.Yan@Sun.COM 	}
154110923SEvan.Yan@Sun.COM 
154210923SEvan.Yan@Sun.COM 	/* check whether the requested property is "all" or "help" */
154310923SEvan.Yan@Sun.COM 	prop_pair = nvlist_next_nvpair(prop_list, NULL);
154410923SEvan.Yan@Sun.COM 	if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair)) {
154510923SEvan.Yan@Sun.COM 		name = nvpair_name(prop_pair);
154610923SEvan.Yan@Sun.COM 		n = sizeof (pciehpc_props) / sizeof (pciehpc_prop_t);
154710923SEvan.Yan@Sun.COM 
154810923SEvan.Yan@Sun.COM 		if (strcmp(name, PCIEHPC_PROP_ALL) == 0) {
154910923SEvan.Yan@Sun.COM 			(void) nvlist_remove_all(prop_list, PCIEHPC_PROP_ALL);
155010923SEvan.Yan@Sun.COM 
155110923SEvan.Yan@Sun.COM 			/*
155210923SEvan.Yan@Sun.COM 			 * Add all properties into the request list, so that we
155310923SEvan.Yan@Sun.COM 			 * will get the values in the following for loop.
155410923SEvan.Yan@Sun.COM 			 */
155510923SEvan.Yan@Sun.COM 			for (i = 0; i < n; i++) {
155610923SEvan.Yan@Sun.COM 				if (nvlist_add_string(prop_list,
155710923SEvan.Yan@Sun.COM 				    pciehpc_props[i].prop_name, "") != 0) {
155810923SEvan.Yan@Sun.COM 					ret = DDI_FAILURE;
155910923SEvan.Yan@Sun.COM 					goto get_prop_cleanup1;
156010923SEvan.Yan@Sun.COM 				}
156110923SEvan.Yan@Sun.COM 			}
156210923SEvan.Yan@Sun.COM 			get_all_prop = B_TRUE;
156310923SEvan.Yan@Sun.COM 		} else if (strcmp(name, PCIEHPC_PROP_HELP) == 0) {
156410923SEvan.Yan@Sun.COM 			/*
156510923SEvan.Yan@Sun.COM 			 * Empty the request list, and add help strings into the
156610923SEvan.Yan@Sun.COM 			 * return list. We will pass the following for loop.
156710923SEvan.Yan@Sun.COM 			 */
156810923SEvan.Yan@Sun.COM 			(void) nvlist_remove_all(prop_list, PCIEHPC_PROP_HELP);
156910923SEvan.Yan@Sun.COM 
157010923SEvan.Yan@Sun.COM 			for (i = 0; i < n; i++) {
157110923SEvan.Yan@Sun.COM 				if (nvlist_add_string(prop_rlist,
157210923SEvan.Yan@Sun.COM 				    pciehpc_props[i].prop_name,
157310923SEvan.Yan@Sun.COM 				    pciehpc_props[i].prop_value) != 0) {
157410923SEvan.Yan@Sun.COM 					ret = DDI_FAILURE;
157510923SEvan.Yan@Sun.COM 					goto get_prop_cleanup1;
157610923SEvan.Yan@Sun.COM 				}
157710923SEvan.Yan@Sun.COM 			}
157810923SEvan.Yan@Sun.COM 		}
157910923SEvan.Yan@Sun.COM 	}
158010923SEvan.Yan@Sun.COM 
158110923SEvan.Yan@Sun.COM 	mutex_enter(&ctrl_p->hc_mutex);
158210923SEvan.Yan@Sun.COM 
158310923SEvan.Yan@Sun.COM 	/* get the current slot state */
158410923SEvan.Yan@Sun.COM 	pciehpc_get_slot_state(slot_p);
158510923SEvan.Yan@Sun.COM 
158610923SEvan.Yan@Sun.COM 	/* for each requested property, get the value and add it to nvlist */
158710923SEvan.Yan@Sun.COM 	prop_pair = NULL;
158810923SEvan.Yan@Sun.COM 	while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
158910923SEvan.Yan@Sun.COM 		name = nvpair_name(prop_pair);
159010923SEvan.Yan@Sun.COM 
159110923SEvan.Yan@Sun.COM 		if (strcmp(name, PCIEHPC_PROP_LED_FAULT) == 0) {
159210923SEvan.Yan@Sun.COM 			value = pcie_led_state_text(
159310923SEvan.Yan@Sun.COM 			    slot_p->hs_fault_led_state);
159410923SEvan.Yan@Sun.COM 		} else if (strcmp(name, PCIEHPC_PROP_LED_POWER) == 0) {
159510923SEvan.Yan@Sun.COM 			value = pcie_led_state_text(
159610923SEvan.Yan@Sun.COM 			    slot_p->hs_power_led_state);
159710923SEvan.Yan@Sun.COM 		} else if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
159810923SEvan.Yan@Sun.COM 			value = pcie_led_state_text(
159910923SEvan.Yan@Sun.COM 			    slot_p->hs_attn_led_state);
160010923SEvan.Yan@Sun.COM 		} else if (strcmp(name, PCIEHPC_PROP_LED_ACTIVE) == 0) {
160110923SEvan.Yan@Sun.COM 			value = pcie_led_state_text(
160210923SEvan.Yan@Sun.COM 			    slot_p->hs_active_led_state);
160310923SEvan.Yan@Sun.COM 		} else if (strcmp(name, PCIEHPC_PROP_CARD_TYPE) == 0) {
160410923SEvan.Yan@Sun.COM 			ddi_acc_handle_t handle;
160510923SEvan.Yan@Sun.COM 			dev_info_t	*cdip;
160610923SEvan.Yan@Sun.COM 			uint8_t		prog_class, base_class, sub_class;
160710923SEvan.Yan@Sun.COM 			int		i;
160810923SEvan.Yan@Sun.COM 
160910923SEvan.Yan@Sun.COM 			mutex_exit(&ctrl_p->hc_mutex);
161010923SEvan.Yan@Sun.COM 			cdip = pcie_hp_devi_find(
161110923SEvan.Yan@Sun.COM 			    ctrl_p->hc_dip, slot_p->hs_device_num, 0);
161210923SEvan.Yan@Sun.COM 			mutex_enter(&ctrl_p->hc_mutex);
161310923SEvan.Yan@Sun.COM 
161410923SEvan.Yan@Sun.COM 			if ((slot_p->hs_info.cn_state
161510923SEvan.Yan@Sun.COM 			    != DDI_HP_CN_STATE_ENABLED) || (cdip == NULL)) {
161610923SEvan.Yan@Sun.COM 				/*
161710923SEvan.Yan@Sun.COM 				 * When getting all properties, just ignore the
161810923SEvan.Yan@Sun.COM 				 * one that's not available under certain state.
161910923SEvan.Yan@Sun.COM 				 */
162010923SEvan.Yan@Sun.COM 				if (get_all_prop)
162110923SEvan.Yan@Sun.COM 					continue;
162210923SEvan.Yan@Sun.COM 
162310923SEvan.Yan@Sun.COM 				ret = DDI_ENOTSUP;
162410923SEvan.Yan@Sun.COM 				goto get_prop_cleanup2;
162510923SEvan.Yan@Sun.COM 			}
162610923SEvan.Yan@Sun.COM 
162710923SEvan.Yan@Sun.COM 			if (pci_config_setup(cdip, &handle) != DDI_SUCCESS) {
162810923SEvan.Yan@Sun.COM 				ret = DDI_FAILURE;
162910923SEvan.Yan@Sun.COM 				goto get_prop_cleanup2;
163010923SEvan.Yan@Sun.COM 			}
163110923SEvan.Yan@Sun.COM 
163210923SEvan.Yan@Sun.COM 			prog_class = pci_config_get8(handle,
163310923SEvan.Yan@Sun.COM 			    PCI_CONF_PROGCLASS);
163410923SEvan.Yan@Sun.COM 			base_class = pci_config_get8(handle, PCI_CONF_BASCLASS);
163510923SEvan.Yan@Sun.COM 			sub_class = pci_config_get8(handle, PCI_CONF_SUBCLASS);
163610923SEvan.Yan@Sun.COM 			pci_config_teardown(&handle);
163710923SEvan.Yan@Sun.COM 
163810923SEvan.Yan@Sun.COM 			for (i = 0; i < class_pci_items; i++) {
163910923SEvan.Yan@Sun.COM 				if ((base_class == class_pci[i].base_class) &&
164010923SEvan.Yan@Sun.COM 				    (sub_class == class_pci[i].sub_class) &&
164110923SEvan.Yan@Sun.COM 				    (prog_class == class_pci[i].prog_class)) {
164210923SEvan.Yan@Sun.COM 					value = class_pci[i].short_desc;
164310923SEvan.Yan@Sun.COM 					break;
164410923SEvan.Yan@Sun.COM 				}
164510923SEvan.Yan@Sun.COM 			}
164610923SEvan.Yan@Sun.COM 			if (i == class_pci_items)
164710923SEvan.Yan@Sun.COM 				value = PCIEHPC_PROP_VALUE_UNKNOWN;
164810923SEvan.Yan@Sun.COM 		} else if (strcmp(name, PCIEHPC_PROP_BOARD_TYPE) == 0) {
164910923SEvan.Yan@Sun.COM 			if (slot_p->hs_info.cn_state <= DDI_HP_CN_STATE_EMPTY)
165010923SEvan.Yan@Sun.COM 				value = PCIEHPC_PROP_VALUE_UNKNOWN;
165110923SEvan.Yan@Sun.COM 			else
165210923SEvan.Yan@Sun.COM 				value = PCIEHPC_PROP_VALUE_PCIHOTPLUG;
165310923SEvan.Yan@Sun.COM 		} else if (strcmp(name, PCIEHPC_PROP_SLOT_CONDITION) == 0) {
165410923SEvan.Yan@Sun.COM 			value = pcie_slot_condition_text(slot_p->hs_condition);
165510923SEvan.Yan@Sun.COM 		} else {
165610923SEvan.Yan@Sun.COM 			/* unsupported property */
165710996SEvan.Yan@Sun.COM 			PCIE_DBG("Unsupported property: %s\n", name);
165810923SEvan.Yan@Sun.COM 
165910923SEvan.Yan@Sun.COM 			ret = DDI_ENOTSUP;
166010923SEvan.Yan@Sun.COM 			goto get_prop_cleanup2;
166110923SEvan.Yan@Sun.COM 		}
166210923SEvan.Yan@Sun.COM 		if (nvlist_add_string(prop_rlist, name, value) != 0) {
166310923SEvan.Yan@Sun.COM 			ret = DDI_FAILURE;
166410923SEvan.Yan@Sun.COM 			goto get_prop_cleanup2;
166510923SEvan.Yan@Sun.COM 		}
166610923SEvan.Yan@Sun.COM 	}
166710923SEvan.Yan@Sun.COM 
166810923SEvan.Yan@Sun.COM 	/* pack nvlist and copyout */
166910923SEvan.Yan@Sun.COM 	if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
167010923SEvan.Yan@Sun.COM 	    &result.buf_size)) != DDI_SUCCESS) {
167110923SEvan.Yan@Sun.COM 		goto get_prop_cleanup2;
167210923SEvan.Yan@Sun.COM 	}
167310923SEvan.Yan@Sun.COM 	if (get_udatamodel() == DATAMODEL_NATIVE) {
167410923SEvan.Yan@Sun.COM 		if (copyout(&result, rval, sizeof (ddi_hp_property_t)))
167510923SEvan.Yan@Sun.COM 			ret = DDI_FAILURE;
167610923SEvan.Yan@Sun.COM 	}
167710923SEvan.Yan@Sun.COM #ifdef _SYSCALL32_IMPL
167810923SEvan.Yan@Sun.COM 	else {
167910923SEvan.Yan@Sun.COM 		if (result.buf_size > UINT32_MAX) {
168010923SEvan.Yan@Sun.COM 			ret = DDI_FAILURE;
168110923SEvan.Yan@Sun.COM 		} else {
168210923SEvan.Yan@Sun.COM 			result32.buf_size = (uint32_t)result.buf_size;
168310923SEvan.Yan@Sun.COM 			if (copyout(&result32, rval,
168410923SEvan.Yan@Sun.COM 			    sizeof (ddi_hp_property32_t)))
168510923SEvan.Yan@Sun.COM 				ret = DDI_FAILURE;
168610923SEvan.Yan@Sun.COM 		}
168710923SEvan.Yan@Sun.COM 	}
168810923SEvan.Yan@Sun.COM #endif
168910923SEvan.Yan@Sun.COM 
169010923SEvan.Yan@Sun.COM get_prop_cleanup2:
169110923SEvan.Yan@Sun.COM 	mutex_exit(&ctrl_p->hc_mutex);
169210923SEvan.Yan@Sun.COM get_prop_cleanup1:
169310923SEvan.Yan@Sun.COM 	nvlist_free(prop_rlist);
169410923SEvan.Yan@Sun.COM get_prop_cleanup:
169510923SEvan.Yan@Sun.COM 	nvlist_free(prop_list);
169610923SEvan.Yan@Sun.COM 	return (ret);
169710923SEvan.Yan@Sun.COM }
169810923SEvan.Yan@Sun.COM 
169910923SEvan.Yan@Sun.COM int
pciehpc_slot_set_property(pcie_hp_slot_t * slot_p,ddi_hp_property_t * arg,ddi_hp_property_t * rval)170010923SEvan.Yan@Sun.COM pciehpc_slot_set_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
170110923SEvan.Yan@Sun.COM     ddi_hp_property_t *rval)
170210923SEvan.Yan@Sun.COM {
170310923SEvan.Yan@Sun.COM 	ddi_hp_property_t	request, result;
170410923SEvan.Yan@Sun.COM #ifdef _SYSCALL32_IMPL
170510923SEvan.Yan@Sun.COM 	ddi_hp_property32_t	request32, result32;
170610923SEvan.Yan@Sun.COM #endif
170710923SEvan.Yan@Sun.COM 	pcie_hp_ctrl_t		*ctrl_p = slot_p->hs_ctrl;
170810923SEvan.Yan@Sun.COM 	nvlist_t		*prop_list;
170910923SEvan.Yan@Sun.COM 	nvlist_t		*prop_rlist;
171010923SEvan.Yan@Sun.COM 	nvpair_t		*prop_pair;
171110923SEvan.Yan@Sun.COM 	char			*name, *value;
171210923SEvan.Yan@Sun.COM 	pcie_hp_led_state_t	led_state;
171310923SEvan.Yan@Sun.COM 	int			ret = DDI_SUCCESS;
171410923SEvan.Yan@Sun.COM 
171510923SEvan.Yan@Sun.COM 	if (get_udatamodel() == DATAMODEL_NATIVE) {
171610923SEvan.Yan@Sun.COM 		if (copyin(arg, &request, sizeof (ddi_hp_property_t)))
171710923SEvan.Yan@Sun.COM 			return (DDI_FAILURE);
171810923SEvan.Yan@Sun.COM 		if (rval &&
171910923SEvan.Yan@Sun.COM 		    copyin(rval, &result, sizeof (ddi_hp_property_t)))
172010923SEvan.Yan@Sun.COM 			return (DDI_FAILURE);
172110923SEvan.Yan@Sun.COM 	}
172210923SEvan.Yan@Sun.COM #ifdef _SYSCALL32_IMPL
172310923SEvan.Yan@Sun.COM 	else {
172410923SEvan.Yan@Sun.COM 		bzero(&request, sizeof (request));
172510923SEvan.Yan@Sun.COM 		bzero(&result, sizeof (result));
172610923SEvan.Yan@Sun.COM 		if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)))
172710923SEvan.Yan@Sun.COM 			return (DDI_FAILURE);
172810923SEvan.Yan@Sun.COM 		if (rval &&
172910923SEvan.Yan@Sun.COM 		    copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
173010923SEvan.Yan@Sun.COM 			return (DDI_FAILURE);
173110923SEvan.Yan@Sun.COM 		request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
173210923SEvan.Yan@Sun.COM 		request.buf_size = request32.buf_size;
173310923SEvan.Yan@Sun.COM 		if (rval) {
173410923SEvan.Yan@Sun.COM 			result.nvlist_buf =
173510923SEvan.Yan@Sun.COM 			    (char *)(uintptr_t)result32.nvlist_buf;
173610923SEvan.Yan@Sun.COM 			result.buf_size = result32.buf_size;
173710923SEvan.Yan@Sun.COM 		}
173810923SEvan.Yan@Sun.COM 	}
173910923SEvan.Yan@Sun.COM #endif
174010923SEvan.Yan@Sun.COM 
174110923SEvan.Yan@Sun.COM 	if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
174210923SEvan.Yan@Sun.COM 	    &prop_list)) != DDI_SUCCESS)
174310923SEvan.Yan@Sun.COM 		return (ret);
174410923SEvan.Yan@Sun.COM 
174510923SEvan.Yan@Sun.COM 	/* check whether the requested property is "help" */
174610923SEvan.Yan@Sun.COM 	prop_pair = nvlist_next_nvpair(prop_list, NULL);
174710923SEvan.Yan@Sun.COM 	if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair) &&
174810923SEvan.Yan@Sun.COM 	    (strcmp(nvpair_name(prop_pair), PCIEHPC_PROP_HELP) == 0)) {
174910923SEvan.Yan@Sun.COM 		if (!rval) {
175010923SEvan.Yan@Sun.COM 			ret = DDI_ENOTSUP;
175110923SEvan.Yan@Sun.COM 			goto set_prop_cleanup;
175210923SEvan.Yan@Sun.COM 		}
175310923SEvan.Yan@Sun.COM 
175410923SEvan.Yan@Sun.COM 		if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
175510923SEvan.Yan@Sun.COM 			ret = DDI_ENOMEM;
175610923SEvan.Yan@Sun.COM 			goto set_prop_cleanup;
175710923SEvan.Yan@Sun.COM 		}
175810923SEvan.Yan@Sun.COM 		if (nvlist_add_string(prop_rlist, PCIEHPC_PROP_LED_ATTN,
175910923SEvan.Yan@Sun.COM 		    PCIEHPC_PROP_VALUE_LED) != 0) {
176010923SEvan.Yan@Sun.COM 			ret = DDI_FAILURE;
176110923SEvan.Yan@Sun.COM 			goto set_prop_cleanup1;
176210923SEvan.Yan@Sun.COM 		}
176310923SEvan.Yan@Sun.COM 
176410923SEvan.Yan@Sun.COM 		if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
176510923SEvan.Yan@Sun.COM 		    &result.buf_size)) != DDI_SUCCESS) {
176610923SEvan.Yan@Sun.COM 			goto set_prop_cleanup1;
176710923SEvan.Yan@Sun.COM 		}
176810923SEvan.Yan@Sun.COM 		if (get_udatamodel() == DATAMODEL_NATIVE) {
176910923SEvan.Yan@Sun.COM 			if (copyout(&result, rval,
177010923SEvan.Yan@Sun.COM 			    sizeof (ddi_hp_property_t))) {
177110923SEvan.Yan@Sun.COM 				ret =  DDI_FAILURE;
177210923SEvan.Yan@Sun.COM 				goto set_prop_cleanup1;
177310923SEvan.Yan@Sun.COM 			}
177410923SEvan.Yan@Sun.COM 		}
177510923SEvan.Yan@Sun.COM #ifdef _SYSCALL32_IMPL
177610923SEvan.Yan@Sun.COM 		else {
177710923SEvan.Yan@Sun.COM 			if (result.buf_size > UINT32_MAX) {
177810923SEvan.Yan@Sun.COM 				ret =  DDI_FAILURE;
177910923SEvan.Yan@Sun.COM 				goto set_prop_cleanup1;
178010923SEvan.Yan@Sun.COM 			} else {
178110923SEvan.Yan@Sun.COM 				result32.buf_size = (uint32_t)result.buf_size;
178210923SEvan.Yan@Sun.COM 				if (copyout(&result32, rval,
178310923SEvan.Yan@Sun.COM 				    sizeof (ddi_hp_property32_t))) {
178410923SEvan.Yan@Sun.COM 					ret =  DDI_FAILURE;
178510923SEvan.Yan@Sun.COM 					goto set_prop_cleanup1;
178610923SEvan.Yan@Sun.COM 				}
178710923SEvan.Yan@Sun.COM 			}
178810923SEvan.Yan@Sun.COM 		}
178910923SEvan.Yan@Sun.COM #endif
179010923SEvan.Yan@Sun.COM set_prop_cleanup1:
179110923SEvan.Yan@Sun.COM 		nvlist_free(prop_rlist);
179210923SEvan.Yan@Sun.COM 		nvlist_free(prop_list);
179310923SEvan.Yan@Sun.COM 		return (ret);
179410923SEvan.Yan@Sun.COM 	}
179510923SEvan.Yan@Sun.COM 
179610923SEvan.Yan@Sun.COM 	/* Validate the request */
179710923SEvan.Yan@Sun.COM 	prop_pair = NULL;
179810923SEvan.Yan@Sun.COM 	while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
179910923SEvan.Yan@Sun.COM 		name = nvpair_name(prop_pair);
180010923SEvan.Yan@Sun.COM 		if (nvpair_type(prop_pair) != DATA_TYPE_STRING) {
180110996SEvan.Yan@Sun.COM 			PCIE_DBG("Unexpected data type of setting "
180210923SEvan.Yan@Sun.COM 			    "property %s.\n", name);
180310923SEvan.Yan@Sun.COM 			ret = DDI_EINVAL;
180410923SEvan.Yan@Sun.COM 			goto set_prop_cleanup;
180510923SEvan.Yan@Sun.COM 		}
180610923SEvan.Yan@Sun.COM 		if (nvpair_value_string(prop_pair, &value)) {
180710996SEvan.Yan@Sun.COM 			PCIE_DBG("Get string value failed for property %s.\n",
180810996SEvan.Yan@Sun.COM 			    name);
180910923SEvan.Yan@Sun.COM 			ret = DDI_FAILURE;
181010923SEvan.Yan@Sun.COM 			goto set_prop_cleanup;
181110923SEvan.Yan@Sun.COM 		}
181210923SEvan.Yan@Sun.COM 
181310923SEvan.Yan@Sun.COM 		if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
181410923SEvan.Yan@Sun.COM 			if ((strcmp(value, PCIEHPC_PROP_VALUE_ON) != 0) &&
181510923SEvan.Yan@Sun.COM 			    (strcmp(value, PCIEHPC_PROP_VALUE_OFF) != 0) &&
181610923SEvan.Yan@Sun.COM 			    (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) != 0)) {
181710996SEvan.Yan@Sun.COM 				PCIE_DBG("Unsupported value of setting "
181810923SEvan.Yan@Sun.COM 				    "property %s\n", name);
181910923SEvan.Yan@Sun.COM 				ret = DDI_ENOTSUP;
182010923SEvan.Yan@Sun.COM 				goto set_prop_cleanup;
182110923SEvan.Yan@Sun.COM 			}
182210923SEvan.Yan@Sun.COM 		} else {
182310996SEvan.Yan@Sun.COM 			PCIE_DBG("Unsupported property: %s\n", name);
182410923SEvan.Yan@Sun.COM 			ret = DDI_ENOTSUP;
182510923SEvan.Yan@Sun.COM 			goto set_prop_cleanup;
182610923SEvan.Yan@Sun.COM 		}
182710923SEvan.Yan@Sun.COM 	}
182810923SEvan.Yan@Sun.COM 	mutex_enter(&ctrl_p->hc_mutex);
182910923SEvan.Yan@Sun.COM 
183010923SEvan.Yan@Sun.COM 	/* get the current slot state */
183110923SEvan.Yan@Sun.COM 	pciehpc_get_slot_state(slot_p);
183210923SEvan.Yan@Sun.COM 
183310923SEvan.Yan@Sun.COM 	/* set each property */
183410923SEvan.Yan@Sun.COM 	prop_pair = NULL;
183510923SEvan.Yan@Sun.COM 	while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
183610923SEvan.Yan@Sun.COM 		name = nvpair_name(prop_pair);
183710923SEvan.Yan@Sun.COM 
183810923SEvan.Yan@Sun.COM 		if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
183910923SEvan.Yan@Sun.COM 			if (strcmp(value, PCIEHPC_PROP_VALUE_ON) == 0)
184010923SEvan.Yan@Sun.COM 				led_state = PCIE_HP_LED_ON;
184110923SEvan.Yan@Sun.COM 			else if (strcmp(value, PCIEHPC_PROP_VALUE_OFF) == 0)
184210923SEvan.Yan@Sun.COM 				led_state = PCIE_HP_LED_OFF;
184310923SEvan.Yan@Sun.COM 			else if (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) == 0)
184410923SEvan.Yan@Sun.COM 				led_state = PCIE_HP_LED_BLINK;
184510923SEvan.Yan@Sun.COM 
184610923SEvan.Yan@Sun.COM 			pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED,
184710923SEvan.Yan@Sun.COM 			    led_state);
184810923SEvan.Yan@Sun.COM 		}
184910923SEvan.Yan@Sun.COM 	}
185010996SEvan.Yan@Sun.COM 	if (rval) {
185110996SEvan.Yan@Sun.COM 		if (get_udatamodel() == DATAMODEL_NATIVE) {
185210996SEvan.Yan@Sun.COM 			result.buf_size = 0;
185310996SEvan.Yan@Sun.COM 			if (copyout(&result, rval, sizeof (ddi_hp_property_t)))
185410996SEvan.Yan@Sun.COM 				ret =  DDI_FAILURE;
185510996SEvan.Yan@Sun.COM 		}
185610996SEvan.Yan@Sun.COM #ifdef _SYSCALL32_IMPL
185710996SEvan.Yan@Sun.COM 		else {
185810996SEvan.Yan@Sun.COM 			result32.buf_size = 0;
185910996SEvan.Yan@Sun.COM 			if (copyout(&result32, rval,
186010996SEvan.Yan@Sun.COM 			    sizeof (ddi_hp_property32_t)))
186110996SEvan.Yan@Sun.COM 				ret =  DDI_FAILURE;
186210996SEvan.Yan@Sun.COM 		}
186310996SEvan.Yan@Sun.COM #endif
186410996SEvan.Yan@Sun.COM 	}
186510923SEvan.Yan@Sun.COM 
186610923SEvan.Yan@Sun.COM 	mutex_exit(&ctrl_p->hc_mutex);
186710923SEvan.Yan@Sun.COM set_prop_cleanup:
186810923SEvan.Yan@Sun.COM 	nvlist_free(prop_list);
186910923SEvan.Yan@Sun.COM 	return (ret);
187010923SEvan.Yan@Sun.COM }
187110923SEvan.Yan@Sun.COM 
187210923SEvan.Yan@Sun.COM /*
187310923SEvan.Yan@Sun.COM  * Send a command to the PCI-E Hot Plug Controller.
187410923SEvan.Yan@Sun.COM  *
187510923SEvan.Yan@Sun.COM  * NOTES: The PCI-E spec defines the following semantics for issuing hot plug
187610923SEvan.Yan@Sun.COM  * commands.
187710923SEvan.Yan@Sun.COM  * 1) If Command Complete events/interrupts are supported then software
187810923SEvan.Yan@Sun.COM  *    waits for Command Complete event after issuing a command (i.e writing
187910923SEvan.Yan@Sun.COM  *    to the Slot Control register). The command completion could take as
188010923SEvan.Yan@Sun.COM  *    long as 1 second so software should be prepared to wait for 1 second
188110923SEvan.Yan@Sun.COM  *    before issuing another command.
188210923SEvan.Yan@Sun.COM  *
188310923SEvan.Yan@Sun.COM  * 2) If Command Complete events/interrupts are not supported then
188410923SEvan.Yan@Sun.COM  *    software could issue multiple Slot Control writes without any delay
188510923SEvan.Yan@Sun.COM  *    between writes.
188610923SEvan.Yan@Sun.COM  */
188710923SEvan.Yan@Sun.COM static void
pciehpc_issue_hpc_command(pcie_hp_ctrl_t * ctrl_p,uint16_t control)188810923SEvan.Yan@Sun.COM pciehpc_issue_hpc_command(pcie_hp_ctrl_t *ctrl_p, uint16_t control)
188910923SEvan.Yan@Sun.COM {
189010923SEvan.Yan@Sun.COM 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
189110923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
189210923SEvan.Yan@Sun.COM 	uint16_t	status;
189310923SEvan.Yan@Sun.COM 	uint32_t	slot_cap;
189410923SEvan.Yan@Sun.COM 
189510923SEvan.Yan@Sun.COM 	/*
189610923SEvan.Yan@Sun.COM 	 * PCI-E version 1.1 spec defines No Command Completed
189710923SEvan.Yan@Sun.COM 	 * Support bit (bit#18) in Slot Capabilities register. If this
189810923SEvan.Yan@Sun.COM 	 * bit is set then slot doesn't support notification of command
189910923SEvan.Yan@Sun.COM 	 * completion events.
190010923SEvan.Yan@Sun.COM 	 */
190110923SEvan.Yan@Sun.COM 	slot_cap =  pciehpc_reg_get32(ctrl_p,
190210923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTCAP);
190310923SEvan.Yan@Sun.COM 
190410923SEvan.Yan@Sun.COM 	/*
190510923SEvan.Yan@Sun.COM 	 * If no Command Completion event is supported or it is ACPI
190610923SEvan.Yan@Sun.COM 	 * hot plug mode then just issue the command and return.
190710923SEvan.Yan@Sun.COM 	 */
190810923SEvan.Yan@Sun.COM 	if ((slot_cap & PCIE_SLOTCAP_NO_CMD_COMP_SUPP) ||
190910923SEvan.Yan@Sun.COM 	    (bus_p->bus_hp_curr_mode == PCIE_ACPI_HP_MODE)) {
191010923SEvan.Yan@Sun.COM 		pciehpc_reg_put16(ctrl_p,
191110923SEvan.Yan@Sun.COM 		    bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
191210923SEvan.Yan@Sun.COM 		return;
191310923SEvan.Yan@Sun.COM 	}
191410923SEvan.Yan@Sun.COM 
191510923SEvan.Yan@Sun.COM 	/*
191610923SEvan.Yan@Sun.COM 	 * **************************************
191710923SEvan.Yan@Sun.COM 	 * Command Complete events are supported.
191810923SEvan.Yan@Sun.COM 	 * **************************************
191910923SEvan.Yan@Sun.COM 	 */
192010923SEvan.Yan@Sun.COM 
192110923SEvan.Yan@Sun.COM 	/*
192210923SEvan.Yan@Sun.COM 	 * If HPC is not yet initialized then just poll for the Command
192310923SEvan.Yan@Sun.COM 	 * Completion interrupt.
192410923SEvan.Yan@Sun.COM 	 */
192510923SEvan.Yan@Sun.COM 	if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
192610923SEvan.Yan@Sun.COM 		int retry = PCIE_HP_CMD_WAIT_RETRY;
192710923SEvan.Yan@Sun.COM 
192810923SEvan.Yan@Sun.COM 		/* write the command to the HPC */
192910923SEvan.Yan@Sun.COM 		pciehpc_reg_put16(ctrl_p,
193010923SEvan.Yan@Sun.COM 		    bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
193110923SEvan.Yan@Sun.COM 
193210923SEvan.Yan@Sun.COM 		/* poll for status completion */
193310923SEvan.Yan@Sun.COM 		while (retry--) {
193410923SEvan.Yan@Sun.COM 			/* wait for 10 msec before checking the status */
193510923SEvan.Yan@Sun.COM 			delay(drv_usectohz(PCIE_HP_CMD_WAIT_TIME));
193610923SEvan.Yan@Sun.COM 
193710923SEvan.Yan@Sun.COM 			status = pciehpc_reg_get16(ctrl_p,
193810923SEvan.Yan@Sun.COM 			    bus_p->bus_pcie_off + PCIE_SLOTSTS);
193910923SEvan.Yan@Sun.COM 
194010923SEvan.Yan@Sun.COM 			if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
194110923SEvan.Yan@Sun.COM 				/* clear the status bits */
194210923SEvan.Yan@Sun.COM 				pciehpc_reg_put16(ctrl_p,
194310923SEvan.Yan@Sun.COM 				    bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
194410923SEvan.Yan@Sun.COM 				break;
194510923SEvan.Yan@Sun.COM 			}
194610923SEvan.Yan@Sun.COM 		}
194710923SEvan.Yan@Sun.COM 		return;
194810923SEvan.Yan@Sun.COM 	}
194910923SEvan.Yan@Sun.COM 
195010923SEvan.Yan@Sun.COM 	/* HPC is already initialized */
195110923SEvan.Yan@Sun.COM 
195210923SEvan.Yan@Sun.COM 	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
195310923SEvan.Yan@Sun.COM 
195410923SEvan.Yan@Sun.COM 	/*
195510923SEvan.Yan@Sun.COM 	 * If previous command is still pending then wait for its
195610923SEvan.Yan@Sun.COM 	 * completion. i.e cv_wait()
195710923SEvan.Yan@Sun.COM 	 */
195810923SEvan.Yan@Sun.COM 
195910923SEvan.Yan@Sun.COM 	while (ctrl_p->hc_cmd_pending == B_TRUE)
196010923SEvan.Yan@Sun.COM 		cv_wait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex);
196110923SEvan.Yan@Sun.COM 
196210923SEvan.Yan@Sun.COM 	/*
196310923SEvan.Yan@Sun.COM 	 * Issue the command and wait for Command Completion or
196410923SEvan.Yan@Sun.COM 	 * the 1 sec timeout.
196510923SEvan.Yan@Sun.COM 	 */
196610923SEvan.Yan@Sun.COM 	pciehpc_reg_put16(ctrl_p,
196710923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
196810923SEvan.Yan@Sun.COM 
196910923SEvan.Yan@Sun.COM 	ctrl_p->hc_cmd_pending = B_TRUE;
197010923SEvan.Yan@Sun.COM 
197110923SEvan.Yan@Sun.COM 	if (cv_timedwait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex,
197210923SEvan.Yan@Sun.COM 	    ddi_get_lbolt() + SEC_TO_TICK(1)) == -1) {
197310923SEvan.Yan@Sun.COM 
197410923SEvan.Yan@Sun.COM 		/* it is a timeout */
197510923SEvan.Yan@Sun.COM 		PCIE_DBG("pciehpc_issue_hpc_command: Command Complete"
197610923SEvan.Yan@Sun.COM 		    " interrupt is not received for slot %d\n",
197710923SEvan.Yan@Sun.COM 		    slot_p->hs_phy_slot_num);
197810923SEvan.Yan@Sun.COM 
197910923SEvan.Yan@Sun.COM 		/* clear the status info in case interrupts are disabled? */
198010923SEvan.Yan@Sun.COM 		status = pciehpc_reg_get16(ctrl_p,
198110923SEvan.Yan@Sun.COM 		    bus_p->bus_pcie_off + PCIE_SLOTSTS);
198210923SEvan.Yan@Sun.COM 
198310923SEvan.Yan@Sun.COM 		if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
198410923SEvan.Yan@Sun.COM 			/* clear the status bits */
198510923SEvan.Yan@Sun.COM 			pciehpc_reg_put16(ctrl_p,
198610923SEvan.Yan@Sun.COM 			    bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
198710923SEvan.Yan@Sun.COM 		}
198810923SEvan.Yan@Sun.COM 	}
198910923SEvan.Yan@Sun.COM 
199010923SEvan.Yan@Sun.COM 	ctrl_p->hc_cmd_pending = B_FALSE;
199110923SEvan.Yan@Sun.COM 
199210923SEvan.Yan@Sun.COM 	/* wake up any one waiting for issuing another command to HPC */
199310923SEvan.Yan@Sun.COM 	cv_signal(&ctrl_p->hc_cmd_comp_cv);
199410923SEvan.Yan@Sun.COM }
199510923SEvan.Yan@Sun.COM 
199610923SEvan.Yan@Sun.COM /*
199710923SEvan.Yan@Sun.COM  * pciehcp_attn_btn_handler()
199810923SEvan.Yan@Sun.COM  *
199910923SEvan.Yan@Sun.COM  * This handles ATTN button pressed event as per the PCI-E 1.1 spec.
200010923SEvan.Yan@Sun.COM  */
200110923SEvan.Yan@Sun.COM static void
pciehpc_attn_btn_handler(pcie_hp_ctrl_t * ctrl_p)200210923SEvan.Yan@Sun.COM pciehpc_attn_btn_handler(pcie_hp_ctrl_t *ctrl_p)
200310923SEvan.Yan@Sun.COM {
200410923SEvan.Yan@Sun.COM 	pcie_hp_slot_t		*slot_p = ctrl_p->hc_slots[0];
200510923SEvan.Yan@Sun.COM 	pcie_hp_led_state_t	power_led_state;
200610923SEvan.Yan@Sun.COM 	callb_cpr_t		cprinfo;
200710923SEvan.Yan@Sun.COM 
200810923SEvan.Yan@Sun.COM 	PCIE_DBG("pciehpc_attn_btn_handler: thread started\n");
200910923SEvan.Yan@Sun.COM 
201010923SEvan.Yan@Sun.COM 	CALLB_CPR_INIT(&cprinfo, &ctrl_p->hc_mutex, callb_generic_cpr,
201110923SEvan.Yan@Sun.COM 	    "pciehpc_attn_btn_handler");
201210923SEvan.Yan@Sun.COM 
201310923SEvan.Yan@Sun.COM 	mutex_enter(&ctrl_p->hc_mutex);
201410923SEvan.Yan@Sun.COM 
201510923SEvan.Yan@Sun.COM 	/* wait for ATTN button event */
201610923SEvan.Yan@Sun.COM 	cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
201710923SEvan.Yan@Sun.COM 
201810923SEvan.Yan@Sun.COM 	while (slot_p->hs_attn_btn_thread_exit == B_FALSE) {
201910923SEvan.Yan@Sun.COM 		if (slot_p->hs_attn_btn_pending == B_TRUE) {
202010923SEvan.Yan@Sun.COM 			/* get the current state of power LED */
202110923SEvan.Yan@Sun.COM 			power_led_state = pciehpc_get_led_state(ctrl_p,
202210923SEvan.Yan@Sun.COM 			    PCIE_HP_POWER_LED);
202310923SEvan.Yan@Sun.COM 
202410923SEvan.Yan@Sun.COM 			/* Blink the Power LED while we wait for 5 seconds */
202510923SEvan.Yan@Sun.COM 			pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
202610923SEvan.Yan@Sun.COM 			    PCIE_HP_LED_BLINK);
202710923SEvan.Yan@Sun.COM 
202810923SEvan.Yan@Sun.COM 			/* wait for 5 seconds before taking any action */
202910923SEvan.Yan@Sun.COM 			if (cv_timedwait(&slot_p->hs_attn_btn_cv,
203010923SEvan.Yan@Sun.COM 			    &ctrl_p->hc_mutex,
203110923SEvan.Yan@Sun.COM 			    ddi_get_lbolt() + SEC_TO_TICK(5)) == -1) {
203210923SEvan.Yan@Sun.COM 				/*
203310923SEvan.Yan@Sun.COM 				 * It is a time out; make sure the ATTN pending
203410923SEvan.Yan@Sun.COM 				 * flag is still ON before sending the event to
203510923SEvan.Yan@Sun.COM 				 * DDI HP framework.
203610923SEvan.Yan@Sun.COM 				 */
203710923SEvan.Yan@Sun.COM 				if (slot_p->hs_attn_btn_pending == B_TRUE) {
203810923SEvan.Yan@Sun.COM 					int hint;
203910923SEvan.Yan@Sun.COM 
204010923SEvan.Yan@Sun.COM 					slot_p->hs_attn_btn_pending = B_FALSE;
204110923SEvan.Yan@Sun.COM 					pciehpc_get_slot_state(slot_p);
204210923SEvan.Yan@Sun.COM 
204310923SEvan.Yan@Sun.COM 					if (slot_p->hs_info.cn_state <=
204410923SEvan.Yan@Sun.COM 					    DDI_HP_CN_STATE_PRESENT) {
204510923SEvan.Yan@Sun.COM 						/*
204610923SEvan.Yan@Sun.COM 						 * Insertion.
204710923SEvan.Yan@Sun.COM 						 */
204810923SEvan.Yan@Sun.COM 						hint = SE_INCOMING_RES;
204910923SEvan.Yan@Sun.COM 					} else {
205010923SEvan.Yan@Sun.COM 						/*
205110923SEvan.Yan@Sun.COM 						 * Want to remove;
205210923SEvan.Yan@Sun.COM 						 */
205310923SEvan.Yan@Sun.COM 						hint = SE_OUTGOING_RES;
205410923SEvan.Yan@Sun.COM 					}
205510923SEvan.Yan@Sun.COM 
205610923SEvan.Yan@Sun.COM 					/*
205710923SEvan.Yan@Sun.COM 					 * We can't call ddihp_cn_gen_sysevent
205810923SEvan.Yan@Sun.COM 					 * here since it's not a DDI interface.
205910923SEvan.Yan@Sun.COM 					 */
206010923SEvan.Yan@Sun.COM 					pcie_hp_gen_sysevent_req(
206110923SEvan.Yan@Sun.COM 					    slot_p->hs_info.cn_name,
206210923SEvan.Yan@Sun.COM 					    hint,
206310923SEvan.Yan@Sun.COM 					    ctrl_p->hc_dip,
206410923SEvan.Yan@Sun.COM 					    KM_SLEEP);
206510923SEvan.Yan@Sun.COM 				}
206610923SEvan.Yan@Sun.COM 			}
206710923SEvan.Yan@Sun.COM 
206810923SEvan.Yan@Sun.COM 			/* restore the power LED state */
206910923SEvan.Yan@Sun.COM 			pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
207010923SEvan.Yan@Sun.COM 			    power_led_state);
207110923SEvan.Yan@Sun.COM 			continue;
207210923SEvan.Yan@Sun.COM 		}
207310923SEvan.Yan@Sun.COM 
207410923SEvan.Yan@Sun.COM 		/* wait for another ATTN button event */
207510923SEvan.Yan@Sun.COM 		cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
207610923SEvan.Yan@Sun.COM 	}
207710923SEvan.Yan@Sun.COM 
207810923SEvan.Yan@Sun.COM 	PCIE_DBG("pciehpc_attn_btn_handler: thread exit\n");
207910923SEvan.Yan@Sun.COM 	cv_signal(&slot_p->hs_attn_btn_cv);
208010923SEvan.Yan@Sun.COM 	CALLB_CPR_EXIT(&cprinfo);
208110923SEvan.Yan@Sun.COM 	thread_exit();
208210923SEvan.Yan@Sun.COM }
208310923SEvan.Yan@Sun.COM 
208410923SEvan.Yan@Sun.COM /*
208510923SEvan.Yan@Sun.COM  * convert LED state from PCIE HPC definition to pcie_hp_led_state_t
208610923SEvan.Yan@Sun.COM  * definition.
208710923SEvan.Yan@Sun.COM  */
208810923SEvan.Yan@Sun.COM static pcie_hp_led_state_t
pciehpc_led_state_to_hpc(uint16_t state)208910923SEvan.Yan@Sun.COM pciehpc_led_state_to_hpc(uint16_t state)
209010923SEvan.Yan@Sun.COM {
209110923SEvan.Yan@Sun.COM 	switch (state) {
209210923SEvan.Yan@Sun.COM 	case PCIE_SLOTCTL_INDICATOR_STATE_ON:
209310923SEvan.Yan@Sun.COM 		return (PCIE_HP_LED_ON);
209410923SEvan.Yan@Sun.COM 	case PCIE_SLOTCTL_INDICATOR_STATE_BLINK:
209510923SEvan.Yan@Sun.COM 		return (PCIE_HP_LED_BLINK);
209610923SEvan.Yan@Sun.COM 	case PCIE_SLOTCTL_INDICATOR_STATE_OFF:
209710923SEvan.Yan@Sun.COM 	default:
209810923SEvan.Yan@Sun.COM 		return (PCIE_HP_LED_OFF);
209910923SEvan.Yan@Sun.COM 	}
210010923SEvan.Yan@Sun.COM }
210110923SEvan.Yan@Sun.COM 
210210923SEvan.Yan@Sun.COM /*
210310923SEvan.Yan@Sun.COM  * Get the state of an LED.
210410923SEvan.Yan@Sun.COM  */
210510923SEvan.Yan@Sun.COM static pcie_hp_led_state_t
pciehpc_get_led_state(pcie_hp_ctrl_t * ctrl_p,pcie_hp_led_t led)210610923SEvan.Yan@Sun.COM pciehpc_get_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led)
210710923SEvan.Yan@Sun.COM {
210810923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
210910923SEvan.Yan@Sun.COM 	uint16_t	control, state;
211010923SEvan.Yan@Sun.COM 
211110923SEvan.Yan@Sun.COM 	/* get the current state of Slot Control register */
211210923SEvan.Yan@Sun.COM 	control =  pciehpc_reg_get16(ctrl_p,
211310923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
211410923SEvan.Yan@Sun.COM 
211510923SEvan.Yan@Sun.COM 	switch (led) {
211610923SEvan.Yan@Sun.COM 	case PCIE_HP_POWER_LED:
211710923SEvan.Yan@Sun.COM 		state = pcie_slotctl_pwr_indicator_get(control);
211810923SEvan.Yan@Sun.COM 		break;
211910923SEvan.Yan@Sun.COM 	case PCIE_HP_ATTN_LED:
212010923SEvan.Yan@Sun.COM 		state = pcie_slotctl_attn_indicator_get(control);
212110923SEvan.Yan@Sun.COM 		break;
212210923SEvan.Yan@Sun.COM 	default:
212310923SEvan.Yan@Sun.COM 		PCIE_DBG("pciehpc_get_led_state() invalid LED %d\n", led);
212410923SEvan.Yan@Sun.COM 		return (PCIE_HP_LED_OFF);
212510923SEvan.Yan@Sun.COM 	}
212610923SEvan.Yan@Sun.COM 
212710923SEvan.Yan@Sun.COM 	switch (state) {
212810923SEvan.Yan@Sun.COM 	case PCIE_SLOTCTL_INDICATOR_STATE_ON:
212910923SEvan.Yan@Sun.COM 		return (PCIE_HP_LED_ON);
213010923SEvan.Yan@Sun.COM 
213110923SEvan.Yan@Sun.COM 	case PCIE_SLOTCTL_INDICATOR_STATE_BLINK:
213210923SEvan.Yan@Sun.COM 		return (PCIE_HP_LED_BLINK);
213310923SEvan.Yan@Sun.COM 
213410923SEvan.Yan@Sun.COM 	case PCIE_SLOTCTL_INDICATOR_STATE_OFF:
213510923SEvan.Yan@Sun.COM 	default:
213610923SEvan.Yan@Sun.COM 		return (PCIE_HP_LED_OFF);
213710923SEvan.Yan@Sun.COM 	}
213810923SEvan.Yan@Sun.COM }
213910923SEvan.Yan@Sun.COM 
214010923SEvan.Yan@Sun.COM /*
214110923SEvan.Yan@Sun.COM  * Set the state of an LED. It updates both hw and sw state.
214210923SEvan.Yan@Sun.COM  */
214310923SEvan.Yan@Sun.COM static void
pciehpc_set_led_state(pcie_hp_ctrl_t * ctrl_p,pcie_hp_led_t led,pcie_hp_led_state_t state)214410923SEvan.Yan@Sun.COM pciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led,
214510923SEvan.Yan@Sun.COM     pcie_hp_led_state_t state)
214610923SEvan.Yan@Sun.COM {
214710923SEvan.Yan@Sun.COM 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
214810923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
214910923SEvan.Yan@Sun.COM 	uint16_t	control;
215010923SEvan.Yan@Sun.COM 
215110923SEvan.Yan@Sun.COM 	/* get the current state of Slot Control register */
215210923SEvan.Yan@Sun.COM 	control =  pciehpc_reg_get16(ctrl_p,
215310923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
215410923SEvan.Yan@Sun.COM 
215510923SEvan.Yan@Sun.COM 	switch (led) {
215610923SEvan.Yan@Sun.COM 	case PCIE_HP_POWER_LED:
215710923SEvan.Yan@Sun.COM 		/* clear led mask */
215810923SEvan.Yan@Sun.COM 		control &= ~PCIE_SLOTCTL_PWR_INDICATOR_MASK;
215910923SEvan.Yan@Sun.COM 		slot_p->hs_power_led_state = state;
216010923SEvan.Yan@Sun.COM 		break;
216110923SEvan.Yan@Sun.COM 	case PCIE_HP_ATTN_LED:
216210923SEvan.Yan@Sun.COM 		/* clear led mask */
216310923SEvan.Yan@Sun.COM 		control &= ~PCIE_SLOTCTL_ATTN_INDICATOR_MASK;
216410923SEvan.Yan@Sun.COM 		slot_p->hs_attn_led_state = state;
216510923SEvan.Yan@Sun.COM 		break;
216610923SEvan.Yan@Sun.COM 	default:
216710923SEvan.Yan@Sun.COM 		PCIE_DBG("pciehpc_set_led_state() invalid LED %d\n", led);
216810923SEvan.Yan@Sun.COM 		return;
216910923SEvan.Yan@Sun.COM 	}
217010923SEvan.Yan@Sun.COM 
217110923SEvan.Yan@Sun.COM 	switch (state) {
217210923SEvan.Yan@Sun.COM 	case PCIE_HP_LED_ON:
217310923SEvan.Yan@Sun.COM 		if (led == PCIE_HP_POWER_LED)
217410923SEvan.Yan@Sun.COM 			control = pcie_slotctl_pwr_indicator_set(control,
217510923SEvan.Yan@Sun.COM 			    PCIE_SLOTCTL_INDICATOR_STATE_ON);
217610923SEvan.Yan@Sun.COM 		else if (led == PCIE_HP_ATTN_LED)
217710923SEvan.Yan@Sun.COM 			control = pcie_slotctl_attn_indicator_set(control,
217810923SEvan.Yan@Sun.COM 			    PCIE_SLOTCTL_INDICATOR_STATE_ON);
217910923SEvan.Yan@Sun.COM 		break;
218010923SEvan.Yan@Sun.COM 	case PCIE_HP_LED_OFF:
218110923SEvan.Yan@Sun.COM 		if (led == PCIE_HP_POWER_LED)
218210923SEvan.Yan@Sun.COM 			control = pcie_slotctl_pwr_indicator_set(control,
218310923SEvan.Yan@Sun.COM 			    PCIE_SLOTCTL_INDICATOR_STATE_OFF);
218410923SEvan.Yan@Sun.COM 		else if (led == PCIE_HP_ATTN_LED)
218510923SEvan.Yan@Sun.COM 			control = pcie_slotctl_attn_indicator_set(control,
218610923SEvan.Yan@Sun.COM 			    PCIE_SLOTCTL_INDICATOR_STATE_OFF);
218710923SEvan.Yan@Sun.COM 		break;
218810923SEvan.Yan@Sun.COM 	case PCIE_HP_LED_BLINK:
218910923SEvan.Yan@Sun.COM 		if (led == PCIE_HP_POWER_LED)
219010923SEvan.Yan@Sun.COM 			control = pcie_slotctl_pwr_indicator_set(control,
219110923SEvan.Yan@Sun.COM 			    PCIE_SLOTCTL_INDICATOR_STATE_BLINK);
219210923SEvan.Yan@Sun.COM 		else if (led == PCIE_HP_ATTN_LED)
219310923SEvan.Yan@Sun.COM 			control = pcie_slotctl_attn_indicator_set(control,
219410923SEvan.Yan@Sun.COM 			    PCIE_SLOTCTL_INDICATOR_STATE_BLINK);
219510923SEvan.Yan@Sun.COM 		break;
219610923SEvan.Yan@Sun.COM 
219710923SEvan.Yan@Sun.COM 	default:
219810923SEvan.Yan@Sun.COM 		PCIE_DBG("pciehpc_set_led_state() invalid LED state %d\n",
219910923SEvan.Yan@Sun.COM 		    state);
220010923SEvan.Yan@Sun.COM 		return;
220110923SEvan.Yan@Sun.COM 	}
220210923SEvan.Yan@Sun.COM 
220310923SEvan.Yan@Sun.COM 	/* update the Slot Control Register */
220410923SEvan.Yan@Sun.COM 	pciehpc_issue_hpc_command(ctrl_p, control);
220510923SEvan.Yan@Sun.COM 
220610923SEvan.Yan@Sun.COM #ifdef DEBUG
220710923SEvan.Yan@Sun.COM 	/* get the current state of Slot Control register */
220810923SEvan.Yan@Sun.COM 	control =  pciehpc_reg_get16(ctrl_p,
220910923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
221010923SEvan.Yan@Sun.COM 
221110923SEvan.Yan@Sun.COM 	PCIE_DBG("pciehpc_set_led_state: slot %d power-led %s attn-led %s\n",
221210923SEvan.Yan@Sun.COM 	    slot_p->hs_phy_slot_num, pcie_led_state_text(
221310923SEvan.Yan@Sun.COM 	    pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control))),
221410923SEvan.Yan@Sun.COM 	    pcie_led_state_text(pciehpc_led_state_to_hpc(
221510923SEvan.Yan@Sun.COM 	    pcie_slotctl_attn_indicator_get(control))));
221610923SEvan.Yan@Sun.COM #endif
221710923SEvan.Yan@Sun.COM }
221810923SEvan.Yan@Sun.COM 
2219*12221SColin.Zou@Sun.COM static void
pciehpc_handle_power_fault(dev_info_t * dip)2220*12221SColin.Zou@Sun.COM pciehpc_handle_power_fault(dev_info_t *dip)
2221*12221SColin.Zou@Sun.COM {
2222*12221SColin.Zou@Sun.COM 	/*
2223*12221SColin.Zou@Sun.COM 	 * Hold the parent's ref so that it won't disappear when the taskq is
2224*12221SColin.Zou@Sun.COM 	 * scheduled to run.
2225*12221SColin.Zou@Sun.COM 	 */
2226*12221SColin.Zou@Sun.COM 	ndi_hold_devi(dip);
2227*12221SColin.Zou@Sun.COM 
2228*12221SColin.Zou@Sun.COM 	if (!taskq_dispatch(system_taskq, pciehpc_power_fault_handler, dip,
2229*12221SColin.Zou@Sun.COM 	    TQ_NOSLEEP)) {
2230*12221SColin.Zou@Sun.COM 		ndi_rele_devi(dip);
2231*12221SColin.Zou@Sun.COM 		PCIE_DBG("pciehpc_intr(): "
2232*12221SColin.Zou@Sun.COM 		    "Failed to dispatch power fault handler, dip %p\n", dip);
2233*12221SColin.Zou@Sun.COM 	}
2234*12221SColin.Zou@Sun.COM }
2235*12221SColin.Zou@Sun.COM 
2236*12221SColin.Zou@Sun.COM static void
pciehpc_power_fault_handler(void * arg)2237*12221SColin.Zou@Sun.COM pciehpc_power_fault_handler(void *arg)
2238*12221SColin.Zou@Sun.COM {
2239*12221SColin.Zou@Sun.COM 	dev_info_t *dip = (dev_info_t *)arg;
2240*12221SColin.Zou@Sun.COM 	pcie_hp_ctrl_t  *ctrl_p;
2241*12221SColin.Zou@Sun.COM 	pcie_hp_slot_t  *slot_p;
2242*12221SColin.Zou@Sun.COM 
2243*12221SColin.Zou@Sun.COM 	/* get the soft state structure for this dip */
2244*12221SColin.Zou@Sun.COM 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) {
2245*12221SColin.Zou@Sun.COM 		ndi_rele_devi(dip);
2246*12221SColin.Zou@Sun.COM 		return;
2247*12221SColin.Zou@Sun.COM 	}
2248*12221SColin.Zou@Sun.COM 	slot_p = ctrl_p->hc_slots[0];
2249*12221SColin.Zou@Sun.COM 
2250*12221SColin.Zou@Sun.COM 	/*
2251*12221SColin.Zou@Sun.COM 	 * Send the event to DDI Hotplug framework, power off
2252*12221SColin.Zou@Sun.COM 	 * the slot
2253*12221SColin.Zou@Sun.COM 	 */
2254*12221SColin.Zou@Sun.COM 	(void) ndi_hp_state_change_req(dip,
2255*12221SColin.Zou@Sun.COM 	    slot_p->hs_info.cn_name,
2256*12221SColin.Zou@Sun.COM 	    DDI_HP_CN_STATE_EMPTY, DDI_HP_REQ_SYNC);
2257*12221SColin.Zou@Sun.COM 
2258*12221SColin.Zou@Sun.COM 	mutex_enter(&ctrl_p->hc_mutex);
2259*12221SColin.Zou@Sun.COM 	pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED,
2260*12221SColin.Zou@Sun.COM 	    PCIE_HP_LED_ON);
2261*12221SColin.Zou@Sun.COM 	mutex_exit(&ctrl_p->hc_mutex);
2262*12221SColin.Zou@Sun.COM 	ndi_rele_devi(dip);
2263*12221SColin.Zou@Sun.COM }
2264*12221SColin.Zou@Sun.COM 
226510923SEvan.Yan@Sun.COM #ifdef DEBUG
226610923SEvan.Yan@Sun.COM /*
226710923SEvan.Yan@Sun.COM  * Dump PCI-E Hot Plug registers.
226810923SEvan.Yan@Sun.COM  */
226910923SEvan.Yan@Sun.COM static void
pciehpc_dump_hpregs(pcie_hp_ctrl_t * ctrl_p)227010923SEvan.Yan@Sun.COM pciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p)
227110923SEvan.Yan@Sun.COM {
227210923SEvan.Yan@Sun.COM 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
227310923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
227410923SEvan.Yan@Sun.COM 	uint16_t	control;
227510923SEvan.Yan@Sun.COM 	uint32_t	capabilities;
227610923SEvan.Yan@Sun.COM 
227710923SEvan.Yan@Sun.COM 	if (!pcie_debug_flags)
227810923SEvan.Yan@Sun.COM 		return;
227910923SEvan.Yan@Sun.COM 
228010923SEvan.Yan@Sun.COM 	capabilities = pciehpc_reg_get32(ctrl_p,
228110923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTCAP);
228210923SEvan.Yan@Sun.COM 
228310923SEvan.Yan@Sun.COM 	control =  pciehpc_reg_get16(ctrl_p,
228410923SEvan.Yan@Sun.COM 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
228510923SEvan.Yan@Sun.COM 
228610923SEvan.Yan@Sun.COM 	PCIE_DBG("pciehpc_dump_hpregs: Found PCI-E hot plug slot %d\n",
228710923SEvan.Yan@Sun.COM 	    slot_p->hs_phy_slot_num);
228810923SEvan.Yan@Sun.COM 
228910923SEvan.Yan@Sun.COM 	PCIE_DBG("Attention Button Present = %s\n",
229010923SEvan.Yan@Sun.COM 	    capabilities & PCIE_SLOTCAP_ATTN_BUTTON ? "Yes":"No");
229110923SEvan.Yan@Sun.COM 
229210923SEvan.Yan@Sun.COM 	PCIE_DBG("Power controller Present = %s\n",
229310923SEvan.Yan@Sun.COM 	    capabilities & PCIE_SLOTCAP_POWER_CONTROLLER ? "Yes":"No");
229410923SEvan.Yan@Sun.COM 
229510923SEvan.Yan@Sun.COM 	PCIE_DBG("MRL Sensor Present	   = %s\n",
229610923SEvan.Yan@Sun.COM 	    capabilities & PCIE_SLOTCAP_MRL_SENSOR ? "Yes":"No");
229710923SEvan.Yan@Sun.COM 
229810923SEvan.Yan@Sun.COM 	PCIE_DBG("Attn Indicator Present   = %s\n",
229910923SEvan.Yan@Sun.COM 	    capabilities & PCIE_SLOTCAP_ATTN_INDICATOR ? "Yes":"No");
230010923SEvan.Yan@Sun.COM 
230110923SEvan.Yan@Sun.COM 	PCIE_DBG("Power Indicator Present  = %s\n",
230210923SEvan.Yan@Sun.COM 	    capabilities & PCIE_SLOTCAP_PWR_INDICATOR ? "Yes":"No");
230310923SEvan.Yan@Sun.COM 
230410923SEvan.Yan@Sun.COM 	PCIE_DBG("HotPlug Surprise	   = %s\n",
230510923SEvan.Yan@Sun.COM 	    capabilities & PCIE_SLOTCAP_HP_SURPRISE ? "Yes":"No");
230610923SEvan.Yan@Sun.COM 
230710923SEvan.Yan@Sun.COM 	PCIE_DBG("HotPlug Capable	   = %s\n",
230810923SEvan.Yan@Sun.COM 	    capabilities & PCIE_SLOTCAP_HP_CAPABLE ? "Yes":"No");
230910923SEvan.Yan@Sun.COM 
231010923SEvan.Yan@Sun.COM 	PCIE_DBG("Physical Slot Number	   = %d\n",
231110923SEvan.Yan@Sun.COM 	    PCIE_SLOTCAP_PHY_SLOT_NUM(capabilities));
231210923SEvan.Yan@Sun.COM 
231310923SEvan.Yan@Sun.COM 	PCIE_DBG("Attn Button interrupt Enabled  = %s\n",
231410923SEvan.Yan@Sun.COM 	    control & PCIE_SLOTCTL_ATTN_BTN_EN ? "Yes":"No");
231510923SEvan.Yan@Sun.COM 
231610923SEvan.Yan@Sun.COM 	PCIE_DBG("Power Fault interrupt Enabled  = %s\n",
231710923SEvan.Yan@Sun.COM 	    control & PCIE_SLOTCTL_PWR_FAULT_EN ? "Yes":"No");
231810923SEvan.Yan@Sun.COM 
231910923SEvan.Yan@Sun.COM 	PCIE_DBG("MRL Sensor INTR Enabled   = %s\n",
232010923SEvan.Yan@Sun.COM 	    control & PCIE_SLOTCTL_MRL_SENSOR_EN ? "Yes":"No");
232110923SEvan.Yan@Sun.COM 
232210923SEvan.Yan@Sun.COM 	PCIE_DBG("Presence interrupt Enabled	 = %s\n",
232310923SEvan.Yan@Sun.COM 	    control & PCIE_SLOTCTL_PRESENCE_CHANGE_EN ? "Yes":"No");
232410923SEvan.Yan@Sun.COM 
232510923SEvan.Yan@Sun.COM 	PCIE_DBG("Cmd Complete interrupt Enabled = %s\n",
232610923SEvan.Yan@Sun.COM 	    control & PCIE_SLOTCTL_CMD_INTR_EN ? "Yes":"No");
232710923SEvan.Yan@Sun.COM 
232810923SEvan.Yan@Sun.COM 	PCIE_DBG("HotPlug interrupt Enabled	 = %s\n",
232910923SEvan.Yan@Sun.COM 	    control & PCIE_SLOTCTL_HP_INTR_EN ? "Yes":"No");
233010923SEvan.Yan@Sun.COM 
233110923SEvan.Yan@Sun.COM 	PCIE_DBG("Power Indicator LED = %s", pcie_led_state_text(
233210923SEvan.Yan@Sun.COM 	    pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control))));
233310923SEvan.Yan@Sun.COM 
233410923SEvan.Yan@Sun.COM 	PCIE_DBG("Attn Indicator LED = %s\n",
233510923SEvan.Yan@Sun.COM 	    pcie_led_state_text(pciehpc_led_state_to_hpc(
233610923SEvan.Yan@Sun.COM 	    pcie_slotctl_attn_indicator_get(control))));
233710923SEvan.Yan@Sun.COM }
233810923SEvan.Yan@Sun.COM #endif	/* DEBUG */
2339