xref: /onnv-gate/usr/src/uts/common/io/pciex/hotplug/pcishpc.c (revision 11445:03736011d310)
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 /*
22*11445SEvan.Yan@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2310923SEvan.Yan@Sun.COM  * Use is subject to license terms.
2410923SEvan.Yan@Sun.COM  */
2510923SEvan.Yan@Sun.COM 
2610923SEvan.Yan@Sun.COM /*
2710923SEvan.Yan@Sun.COM  * This file contains PCI HotPlug functionality that is compatible with the
2810923SEvan.Yan@Sun.COM  * PCI SHPC specification 1.x.
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/note.h>
3410923SEvan.Yan@Sun.COM #include <sys/conf.h>
3510923SEvan.Yan@Sun.COM #include <sys/kmem.h>
3610923SEvan.Yan@Sun.COM #include <sys/kstat.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/hwconf.h>
4210923SEvan.Yan@Sun.COM #include <sys/ddi_impldefs.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/ndi_impldefs.h>
4910923SEvan.Yan@Sun.COM #include <sys/pci_impl.h>
5010923SEvan.Yan@Sun.COM #include <sys/hotplug/pci/pcie_hp.h>
5110923SEvan.Yan@Sun.COM #include <sys/hotplug/pci/pcishpc.h>
5210923SEvan.Yan@Sun.COM 
5310923SEvan.Yan@Sun.COM typedef struct pcishpc_prop {
5410923SEvan.Yan@Sun.COM 	char	*prop_name;
5510923SEvan.Yan@Sun.COM 	char	*prop_value;
5610923SEvan.Yan@Sun.COM } pcishpc_prop_t;
5710923SEvan.Yan@Sun.COM 
5810923SEvan.Yan@Sun.COM static pcishpc_prop_t	pcishpc_props[] = {
5910923SEvan.Yan@Sun.COM 	{ PCIEHPC_PROP_LED_FAULT,	PCIEHPC_PROP_VALUE_LED },
6010923SEvan.Yan@Sun.COM 	{ PCIEHPC_PROP_LED_POWER,	PCIEHPC_PROP_VALUE_LED },
6110923SEvan.Yan@Sun.COM 	{ PCIEHPC_PROP_LED_ATTN,	PCIEHPC_PROP_VALUE_LED },
6210923SEvan.Yan@Sun.COM 	{ PCIEHPC_PROP_LED_ACTIVE,	PCIEHPC_PROP_VALUE_LED },
6310923SEvan.Yan@Sun.COM 	{ PCIEHPC_PROP_CARD_TYPE,	PCIEHPC_PROP_VALUE_TYPE },
6410923SEvan.Yan@Sun.COM 	{ PCIEHPC_PROP_BOARD_TYPE,	PCIEHPC_PROP_VALUE_TYPE },
6510923SEvan.Yan@Sun.COM 	{ PCIEHPC_PROP_SLOT_CONDITION,	PCIEHPC_PROP_VALUE_TYPE }
6610923SEvan.Yan@Sun.COM };
6710923SEvan.Yan@Sun.COM 
6810923SEvan.Yan@Sun.COM /* reset delay to 1 sec. */
6910923SEvan.Yan@Sun.COM static int pcishpc_reset_delay = 1000000;
7010923SEvan.Yan@Sun.COM 
7110923SEvan.Yan@Sun.COM /* Local function prototype */
7210923SEvan.Yan@Sun.COM static pcie_hp_ctrl_t *pcishpc_create_controller(dev_info_t *dip);
7310923SEvan.Yan@Sun.COM static int	pcishpc_setup_controller(pcie_hp_ctrl_t *ctrl_p);
7410923SEvan.Yan@Sun.COM static int	pcishpc_destroy_controller(dev_info_t *dip);
7510923SEvan.Yan@Sun.COM static pcie_hp_slot_t	*pcishpc_create_slot(pcie_hp_ctrl_t *ctrl_p);
7610923SEvan.Yan@Sun.COM static int	pcishpc_register_slot(pcie_hp_ctrl_t *ctrl_p, int slot);
7710923SEvan.Yan@Sun.COM static int	pcishpc_destroy_slots(pcie_hp_ctrl_t *ctrl_p);
7810923SEvan.Yan@Sun.COM static int	pcishpc_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	pcishpc_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 int	pcishpc_issue_command(pcie_hp_ctrl_t *ctrl_p,
8310923SEvan.Yan@Sun.COM 		    uint32_t cmd_code);
8410923SEvan.Yan@Sun.COM static int	pcishpc_wait_busy(pcie_hp_ctrl_t *ctrl_p);
8510923SEvan.Yan@Sun.COM static void	pcishpc_attn_btn_handler(pcie_hp_slot_t *slot_p);
8610923SEvan.Yan@Sun.COM static void	pcishpc_get_slot_state(pcie_hp_slot_t *slot_p);
8710923SEvan.Yan@Sun.COM static int	pcishpc_set_slot_state(pcie_hp_slot_t *slot_p,
8810923SEvan.Yan@Sun.COM 		    ddi_hp_cn_state_t new_slot_state);
8910923SEvan.Yan@Sun.COM static void	pcishpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p, int slot);
9010923SEvan.Yan@Sun.COM static int	pcishpc_set_bus_speed(pcie_hp_slot_t *slot_p);
9110923SEvan.Yan@Sun.COM static int	pcishpc_setled(pcie_hp_slot_t *slot_p, pcie_hp_led_t led,
9210923SEvan.Yan@Sun.COM 		    pcie_hp_led_state_t state);
9310923SEvan.Yan@Sun.COM static int	pcishpc_led_shpc_to_hpc(int state);
9410923SEvan.Yan@Sun.COM static int	pcishpc_led_hpc_to_shpc(int state);
9510923SEvan.Yan@Sun.COM static int	pcishpc_slot_shpc_to_hpc(int shpc_state);
9610923SEvan.Yan@Sun.COM static int	pcishpc_slot_hpc_to_shpc(int state);
9710923SEvan.Yan@Sun.COM static char	*pcishpc_slot_textslotstate(ddi_hp_cn_state_t state);
9810923SEvan.Yan@Sun.COM static char	*pcishpc_slot_textledstate(pcie_hp_led_state_t state);
9910923SEvan.Yan@Sun.COM 
10010923SEvan.Yan@Sun.COM static uint32_t	pcishpc_read_reg(pcie_hp_ctrl_t *ctrl_p, int reg);
10110923SEvan.Yan@Sun.COM static void	pcishpc_write_reg(pcie_hp_ctrl_t *ctrl_p, int reg,
10210923SEvan.Yan@Sun.COM 		    uint32_t data);
10310923SEvan.Yan@Sun.COM 
10410923SEvan.Yan@Sun.COM static int	pcishpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
10510923SEvan.Yan@Sun.COM 		    ddi_hp_cn_state_t target_state);
10610923SEvan.Yan@Sun.COM static int	pcishpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
10710923SEvan.Yan@Sun.COM 		    ddi_hp_cn_state_t target_state);
10810923SEvan.Yan@Sun.COM static int	pcishpc_change_slot_state(pcie_hp_slot_t *slot_p,
10910923SEvan.Yan@Sun.COM 		    ddi_hp_cn_state_t target_state);
11010923SEvan.Yan@Sun.COM 
11110923SEvan.Yan@Sun.COM static int	pcishpc_slot_poweron(pcie_hp_slot_t *slot_p,
11210923SEvan.Yan@Sun.COM 		    ddi_hp_cn_state_t *result_state);
11310923SEvan.Yan@Sun.COM static int	pcishpc_slot_poweroff(pcie_hp_slot_t *slot_p,
11410923SEvan.Yan@Sun.COM 		    ddi_hp_cn_state_t *result_state);
11510923SEvan.Yan@Sun.COM static int	pcishpc_slot_probe(pcie_hp_slot_t *slot_p);
11610923SEvan.Yan@Sun.COM static int	pcishpc_slot_unprobe(pcie_hp_slot_t *slot_p);
11710923SEvan.Yan@Sun.COM #ifdef	DEBUG
11810923SEvan.Yan@Sun.COM static void	pcishpc_dump_regs(pcie_hp_ctrl_t *ctrl_p);
11910923SEvan.Yan@Sun.COM #endif	/* DEBUG */
12010923SEvan.Yan@Sun.COM 
12110923SEvan.Yan@Sun.COM 
12210923SEvan.Yan@Sun.COM /*
12310923SEvan.Yan@Sun.COM  * Global functions (called by other drivers/modules)
12410923SEvan.Yan@Sun.COM  */
12510923SEvan.Yan@Sun.COM 
12610923SEvan.Yan@Sun.COM /*
12710923SEvan.Yan@Sun.COM  * pcishpc_init()
12810923SEvan.Yan@Sun.COM  *
12910923SEvan.Yan@Sun.COM  * Install and configure an SHPC controller and register the HotPlug slots
13010923SEvan.Yan@Sun.COM  * with the Solaris HotPlug framework. This function is usually called by
13110923SEvan.Yan@Sun.COM  * a PCI bridge Nexus driver that has a built in SHPC controller.
13210923SEvan.Yan@Sun.COM  */
13310923SEvan.Yan@Sun.COM int
pcishpc_init(dev_info_t * dip)13410923SEvan.Yan@Sun.COM pcishpc_init(dev_info_t *dip)
13510923SEvan.Yan@Sun.COM {
13610923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
13710923SEvan.Yan@Sun.COM 	pcie_hp_ctrl_t	*ctrl_p;
13810923SEvan.Yan@Sun.COM 	int		i;
13910923SEvan.Yan@Sun.COM 
14010923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_init() called from %s#%d\n",
14110923SEvan.Yan@Sun.COM 	    ddi_driver_name(dip), ddi_get_instance(dip));
14210923SEvan.Yan@Sun.COM 
14310923SEvan.Yan@Sun.COM 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) != NULL) {
14410923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_init() shpc instance already "
14510923SEvan.Yan@Sun.COM 		    "initialized!\n");
14610923SEvan.Yan@Sun.COM 		return (DDI_SUCCESS);
14710923SEvan.Yan@Sun.COM 	}
14810923SEvan.Yan@Sun.COM 
14910923SEvan.Yan@Sun.COM 	/* Initialize soft state structure for the SHPC instance. */
15010923SEvan.Yan@Sun.COM 	ctrl_p = pcishpc_create_controller(dip);
15110923SEvan.Yan@Sun.COM 
15210923SEvan.Yan@Sun.COM 	if (ctrl_p == NULL) {
15310923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_init() failed to create shpc softstate\n");
15410923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
15510923SEvan.Yan@Sun.COM 	}
15610923SEvan.Yan@Sun.COM 
15710923SEvan.Yan@Sun.COM 	if (pcishpc_setup_controller(ctrl_p) != DDI_SUCCESS) {
15810923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_init() failed to setup controller\n");
15910923SEvan.Yan@Sun.COM 		goto cleanup;
16010923SEvan.Yan@Sun.COM 	}
16110923SEvan.Yan@Sun.COM 
16210923SEvan.Yan@Sun.COM 	/*
16310923SEvan.Yan@Sun.COM 	 * Setup resource maps for this bus node.
16410923SEvan.Yan@Sun.COM 	 */
16510923SEvan.Yan@Sun.COM 	(void) pci_resource_setup(dip);
16610923SEvan.Yan@Sun.COM 
16710923SEvan.Yan@Sun.COM #ifdef	DEBUG
16810923SEvan.Yan@Sun.COM 	PCIE_DBG("%s%d: P2P bridge register dump:\n",
16910923SEvan.Yan@Sun.COM 	    ddi_driver_name(dip), ddi_get_instance(dip));
17010923SEvan.Yan@Sun.COM 
17110923SEvan.Yan@Sun.COM 	for (i = 0; i < 0x100; i += 4) {
17210923SEvan.Yan@Sun.COM 		PCIE_DBG("SHPC Cfg reg 0x%02x: %08x\n", i,
17310923SEvan.Yan@Sun.COM 		    pci_config_get32(bus_p->bus_cfg_hdl, i));
17410923SEvan.Yan@Sun.COM 	}
17510923SEvan.Yan@Sun.COM #endif	/* DEBUG */
17610923SEvan.Yan@Sun.COM 
17710923SEvan.Yan@Sun.COM 	/* Setup each HotPlug slot on this SHPC controller. */
17810923SEvan.Yan@Sun.COM 	for (i = 0; i < ctrl_p->hc_num_slots_impl; i++) {
17910923SEvan.Yan@Sun.COM 		if (pcishpc_register_slot(ctrl_p, i) != DDI_SUCCESS) {
18010923SEvan.Yan@Sun.COM 			PCIE_DBG("pcishpc_init() failed to register "
18110923SEvan.Yan@Sun.COM 			    "slot %d\n", i);
18210923SEvan.Yan@Sun.COM 			goto cleanup1;
18310923SEvan.Yan@Sun.COM 		}
18410923SEvan.Yan@Sun.COM 		if (pcie_create_minor_node(ctrl_p, i) != DDI_SUCCESS) {
18510923SEvan.Yan@Sun.COM 			PCIE_DBG("pcishpc_init() failed to create "
18610923SEvan.Yan@Sun.COM 			    "minor node for slot %d\n", i);
18710923SEvan.Yan@Sun.COM 			goto cleanup1;
18810923SEvan.Yan@Sun.COM 		}
18910923SEvan.Yan@Sun.COM 	}
19010923SEvan.Yan@Sun.COM 
19110923SEvan.Yan@Sun.COM #ifdef	DEBUG
19210923SEvan.Yan@Sun.COM 	/* Dump out the SHPC registers. */
19310923SEvan.Yan@Sun.COM 	pcishpc_dump_regs(ctrl_p);
19410923SEvan.Yan@Sun.COM #endif	/* DEBUG */
19510923SEvan.Yan@Sun.COM 
19610923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_init() success(dip=%p)\n", dip);
19710923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
19810923SEvan.Yan@Sun.COM 
19910923SEvan.Yan@Sun.COM cleanup1:
20010923SEvan.Yan@Sun.COM 	for (i = 0; i < ctrl_p->hc_num_slots_impl; i++) {
20110923SEvan.Yan@Sun.COM 		if (ctrl_p->hc_slots[i] == NULL)
20210923SEvan.Yan@Sun.COM 			continue;
20310923SEvan.Yan@Sun.COM 
20410923SEvan.Yan@Sun.COM 		pcie_remove_minor_node(ctrl_p, i);
20510923SEvan.Yan@Sun.COM 	}
20610923SEvan.Yan@Sun.COM 	(void) pci_resource_destroy(dip);
20710923SEvan.Yan@Sun.COM cleanup:
20810923SEvan.Yan@Sun.COM 	(void) pcishpc_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  * pcishpc_uninit()
21410923SEvan.Yan@Sun.COM  * Unload the HogPlug controller driver and deallocate all resources.
21510923SEvan.Yan@Sun.COM  */
21610923SEvan.Yan@Sun.COM int
pcishpc_uninit(dev_info_t * dip)21710923SEvan.Yan@Sun.COM pcishpc_uninit(dev_info_t *dip)
21810923SEvan.Yan@Sun.COM {
21910923SEvan.Yan@Sun.COM 	pcie_hp_ctrl_t *ctrl_p;
22010923SEvan.Yan@Sun.COM 	int i;
22110923SEvan.Yan@Sun.COM 
22210923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_uninit() called(dip=%p)\n", dip);
22310923SEvan.Yan@Sun.COM 
22410923SEvan.Yan@Sun.COM 	ctrl_p = PCIE_GET_HP_CTRL(dip);
22510923SEvan.Yan@Sun.COM 
22610923SEvan.Yan@Sun.COM 	if (!ctrl_p) {
22710923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_uninit() Unable to find softstate\n");
22810923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
22910923SEvan.Yan@Sun.COM 	}
23010923SEvan.Yan@Sun.COM 
23110923SEvan.Yan@Sun.COM 	for (i = 0; i < PCIE_HP_MAX_SLOTS; i++) {
23210923SEvan.Yan@Sun.COM 		if (ctrl_p->hc_slots[i] == NULL)
23310923SEvan.Yan@Sun.COM 			continue;
23410923SEvan.Yan@Sun.COM 
23510923SEvan.Yan@Sun.COM 		pcie_remove_minor_node(ctrl_p, i);
23610923SEvan.Yan@Sun.COM 	}
23710923SEvan.Yan@Sun.COM 
23810923SEvan.Yan@Sun.COM 	ctrl_p->hc_flags = 0;
23910923SEvan.Yan@Sun.COM 
24010923SEvan.Yan@Sun.COM 	/*
24110923SEvan.Yan@Sun.COM 	 * Destroy resource maps for this bus node.
24210923SEvan.Yan@Sun.COM 	 */
24310923SEvan.Yan@Sun.COM 	(void) pci_resource_destroy(dip);
24410923SEvan.Yan@Sun.COM 
24510923SEvan.Yan@Sun.COM 	(void) pcishpc_destroy_controller(dip);
24610923SEvan.Yan@Sun.COM 
24710923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_uninit() success(dip=%p)\n", 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  * pcishpc_intr()
25410923SEvan.Yan@Sun.COM  *
25510923SEvan.Yan@Sun.COM  * This is the SHPC controller interrupt handler.
25610923SEvan.Yan@Sun.COM  */
25710923SEvan.Yan@Sun.COM int
pcishpc_intr(dev_info_t * dip)25810923SEvan.Yan@Sun.COM pcishpc_intr(dev_info_t *dip)
25910923SEvan.Yan@Sun.COM {
26010923SEvan.Yan@Sun.COM 	pcie_hp_ctrl_t	*ctrl_p;
26110923SEvan.Yan@Sun.COM 	uint32_t	irq_locator, irq_serr_locator, reg;
26210923SEvan.Yan@Sun.COM 	int		slot;
26310923SEvan.Yan@Sun.COM 
26410923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_intr() called\n");
26510923SEvan.Yan@Sun.COM 
26610923SEvan.Yan@Sun.COM 	/* get the soft state structure for this dip */
26710923SEvan.Yan@Sun.COM 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
26810923SEvan.Yan@Sun.COM 		return (DDI_INTR_UNCLAIMED);
26910923SEvan.Yan@Sun.COM 
27010923SEvan.Yan@Sun.COM 	mutex_enter(&ctrl_p->hc_mutex);
27110923SEvan.Yan@Sun.COM 
27210923SEvan.Yan@Sun.COM 	if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
27310923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_intr() unclaimed\n");
27410923SEvan.Yan@Sun.COM 		mutex_exit(&ctrl_p->hc_mutex);
27510923SEvan.Yan@Sun.COM 		return (DDI_INTR_UNCLAIMED);
27610923SEvan.Yan@Sun.COM 	}
27710923SEvan.Yan@Sun.COM 
27810923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_intr() interrupt received\n");
27910923SEvan.Yan@Sun.COM 
28010923SEvan.Yan@Sun.COM 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG);
28110923SEvan.Yan@Sun.COM 
28210923SEvan.Yan@Sun.COM 	if (reg & PCI_HP_SERR_INT_CMD_COMPLETE_IRQ) {
28310923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_intr() "
28410923SEvan.Yan@Sun.COM 		    "PCI_HP_SERR_INT_CMD_COMPLETE_IRQ detected\n");
28510923SEvan.Yan@Sun.COM 		ctrl_p->hc_cmd_pending = B_FALSE;
28610923SEvan.Yan@Sun.COM 		cv_signal(&ctrl_p->hc_cmd_comp_cv);
28710923SEvan.Yan@Sun.COM 	}
28810923SEvan.Yan@Sun.COM 
28910923SEvan.Yan@Sun.COM 	if (reg & PCI_HP_SERR_INT_ARBITER_IRQ) {
29010923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_intr() PCI_HP_SERR_INT_ARBITER_IRQ "
29110923SEvan.Yan@Sun.COM 		    "detected\n");
29210923SEvan.Yan@Sun.COM 		ctrl_p->hc_arbiter_timeout = B_TRUE;
29310923SEvan.Yan@Sun.COM 	}
29410923SEvan.Yan@Sun.COM 
29510923SEvan.Yan@Sun.COM 	/* Write back the SERR INT register to acknowledge the IRQs. */
29610923SEvan.Yan@Sun.COM 	pcishpc_write_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG, reg);
29710923SEvan.Yan@Sun.COM 
29810923SEvan.Yan@Sun.COM 	irq_locator = pcishpc_read_reg(ctrl_p, PCI_HP_IRQ_LOCATOR_REG);
29910923SEvan.Yan@Sun.COM 	irq_serr_locator = pcishpc_read_reg(ctrl_p, PCI_HP_SERR_LOCATOR_REG);
30010923SEvan.Yan@Sun.COM 
30110923SEvan.Yan@Sun.COM 	/* Check for slot events that might have occured. */
30210923SEvan.Yan@Sun.COM 	for (slot = 0; slot < ctrl_p->hc_num_slots_impl; slot++) {
30310923SEvan.Yan@Sun.COM 		if ((irq_locator & (PCI_HP_IRQ_SLOT_N_PENDING<<slot)) ||
30410923SEvan.Yan@Sun.COM 		    (irq_serr_locator &
30510923SEvan.Yan@Sun.COM 		    (PCI_HP_IRQ_SERR_SLOT_N_PENDING<<slot))) {
30610923SEvan.Yan@Sun.COM 			PCIE_DBG("pcishpc_intr() slot %d and "
30710923SEvan.Yan@Sun.COM 			    "pending IRQ\n", slot+1);
30810923SEvan.Yan@Sun.COM 
30910923SEvan.Yan@Sun.COM 			reg = pcishpc_read_reg(ctrl_p,
31010923SEvan.Yan@Sun.COM 			    PCI_HP_LOGICAL_SLOT_REGS+slot);
31110923SEvan.Yan@Sun.COM 
31210923SEvan.Yan@Sun.COM 			if (reg & PCI_HP_SLOT_PRESENCE_DETECTED)
31310923SEvan.Yan@Sun.COM 				PCIE_DBG("slot %d: "
31410923SEvan.Yan@Sun.COM 				    "PCI_HP_SLOT_PRESENCE_DETECTED\n",
31510923SEvan.Yan@Sun.COM 				    slot+1);
31610923SEvan.Yan@Sun.COM 
31710923SEvan.Yan@Sun.COM 			if (reg & PCI_HP_SLOT_ISO_PWR_DETECTED)
31810923SEvan.Yan@Sun.COM 				PCIE_DBG("slot %d: "
31910923SEvan.Yan@Sun.COM 				    "PCI_HP_SLOT_ISO_PWR_DETECTED\n",
32010923SEvan.Yan@Sun.COM 				    slot+1);
32110923SEvan.Yan@Sun.COM 
32210923SEvan.Yan@Sun.COM 			if (reg & PCI_HP_SLOT_ATTN_DETECTED) {
32310923SEvan.Yan@Sun.COM 				PCIE_DBG("slot %d: "
32410923SEvan.Yan@Sun.COM 				    "PCI_HP_SLOT_ATTN_DETECTED\n", slot+1);
32510923SEvan.Yan@Sun.COM 
32610923SEvan.Yan@Sun.COM 				/*
32710923SEvan.Yan@Sun.COM 				 * if ATTN button event is still pending
32810923SEvan.Yan@Sun.COM 				 * then cancel it
32910923SEvan.Yan@Sun.COM 				 */
33010923SEvan.Yan@Sun.COM 				if (ctrl_p->hc_slots[slot]->
33110923SEvan.Yan@Sun.COM 				    hs_attn_btn_pending == B_TRUE)
33210923SEvan.Yan@Sun.COM 					ctrl_p->hc_slots[slot]->
33310923SEvan.Yan@Sun.COM 					    hs_attn_btn_pending = B_FALSE;
33410923SEvan.Yan@Sun.COM 
33510923SEvan.Yan@Sun.COM 				/* wake up the ATTN event handler */
33610923SEvan.Yan@Sun.COM 				cv_signal(&ctrl_p->hc_slots[slot]->
33710923SEvan.Yan@Sun.COM 				    hs_attn_btn_cv);
33810923SEvan.Yan@Sun.COM 			}
33910923SEvan.Yan@Sun.COM 
34010923SEvan.Yan@Sun.COM 			if (reg & PCI_HP_SLOT_MRL_DETECTED)
34110923SEvan.Yan@Sun.COM 				PCIE_DBG("slot %d: "
34210923SEvan.Yan@Sun.COM 				    "PCI_HP_SLOT_MRL_DETECTED\n", slot+1);
34310923SEvan.Yan@Sun.COM 
34410923SEvan.Yan@Sun.COM 			if (reg & PCI_HP_SLOT_POWER_DETECTED)
34510923SEvan.Yan@Sun.COM 				PCIE_DBG("slot %d: "
34610923SEvan.Yan@Sun.COM 				    "PCI_HP_SLOT_POWER_DETECTED\n", slot+1);
34710923SEvan.Yan@Sun.COM 
34810923SEvan.Yan@Sun.COM 			/* Acknoledge any slot interrupts */
34910923SEvan.Yan@Sun.COM 			pcishpc_write_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot,
35010923SEvan.Yan@Sun.COM 			    reg);
35110923SEvan.Yan@Sun.COM 		}
35210923SEvan.Yan@Sun.COM 	}
35310923SEvan.Yan@Sun.COM 
35410923SEvan.Yan@Sun.COM 	mutex_exit(&ctrl_p->hc_mutex);
35510923SEvan.Yan@Sun.COM 
35610923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_intr() claimed\n");
35710923SEvan.Yan@Sun.COM 
35810923SEvan.Yan@Sun.COM 	return (DDI_INTR_CLAIMED);
35910923SEvan.Yan@Sun.COM }
36010923SEvan.Yan@Sun.COM 
36110923SEvan.Yan@Sun.COM int
pcishpc_slot_get_property(pcie_hp_slot_t * slot_p,ddi_hp_property_t * arg,ddi_hp_property_t * rval)36210923SEvan.Yan@Sun.COM pcishpc_slot_get_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
36310923SEvan.Yan@Sun.COM     ddi_hp_property_t *rval)
36410923SEvan.Yan@Sun.COM {
36510923SEvan.Yan@Sun.COM 	ddi_hp_property_t request, result;
36610923SEvan.Yan@Sun.COM #ifdef _SYSCALL32_IMPL
36710923SEvan.Yan@Sun.COM 	ddi_hp_property32_t request32, result32;
36810923SEvan.Yan@Sun.COM #endif
36910923SEvan.Yan@Sun.COM 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
37010923SEvan.Yan@Sun.COM 	nvlist_t 	*prop_list;
37110923SEvan.Yan@Sun.COM 	nvlist_t	*prop_rlist; /* nvlist for return values */
37210923SEvan.Yan@Sun.COM 	nvpair_t 	*prop_pair;
37310923SEvan.Yan@Sun.COM 	char 		*name, *value;
37410923SEvan.Yan@Sun.COM 	int		ret = DDI_SUCCESS;
37510923SEvan.Yan@Sun.COM 	int		i, n;
37610923SEvan.Yan@Sun.COM 	boolean_t	get_all_prop = B_FALSE;
37710923SEvan.Yan@Sun.COM 
37810923SEvan.Yan@Sun.COM 	if (get_udatamodel() == DATAMODEL_NATIVE) {
37910923SEvan.Yan@Sun.COM 		if (copyin(arg, &request, sizeof (ddi_hp_property_t)) ||
38010923SEvan.Yan@Sun.COM 		    copyin(rval, &result, sizeof (ddi_hp_property_t)))
38110923SEvan.Yan@Sun.COM 			return (DDI_FAILURE);
38210923SEvan.Yan@Sun.COM 	}
38310923SEvan.Yan@Sun.COM #ifdef _SYSCALL32_IMPL
38410923SEvan.Yan@Sun.COM 	else {
38510923SEvan.Yan@Sun.COM 		bzero(&request, sizeof (request));
38610923SEvan.Yan@Sun.COM 		bzero(&result, sizeof (result));
38710923SEvan.Yan@Sun.COM 		if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)) ||
38810923SEvan.Yan@Sun.COM 		    copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
38910923SEvan.Yan@Sun.COM 			return (DDI_FAILURE);
39010923SEvan.Yan@Sun.COM 		request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
39110923SEvan.Yan@Sun.COM 		request.buf_size = request32.buf_size;
39210923SEvan.Yan@Sun.COM 		result.nvlist_buf = (char *)(uintptr_t)result32.nvlist_buf;
39310923SEvan.Yan@Sun.COM 		result.buf_size = result32.buf_size;
39410923SEvan.Yan@Sun.COM 	}
39510923SEvan.Yan@Sun.COM #endif
39610923SEvan.Yan@Sun.COM 
39710923SEvan.Yan@Sun.COM 	if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
39810923SEvan.Yan@Sun.COM 	    &prop_list)) != DDI_SUCCESS)
39910923SEvan.Yan@Sun.COM 		return (ret);
40010923SEvan.Yan@Sun.COM 
40110923SEvan.Yan@Sun.COM 	if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
40210923SEvan.Yan@Sun.COM 		ret = DDI_ENOMEM;
40310923SEvan.Yan@Sun.COM 		goto get_prop_cleanup;
40410923SEvan.Yan@Sun.COM 	}
40510923SEvan.Yan@Sun.COM 
40610923SEvan.Yan@Sun.COM 	/* check whether the requested property is "all" or "help" */
40710923SEvan.Yan@Sun.COM 	prop_pair = nvlist_next_nvpair(prop_list, NULL);
40810923SEvan.Yan@Sun.COM 	if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair)) {
40910923SEvan.Yan@Sun.COM 		name = nvpair_name(prop_pair);
41010923SEvan.Yan@Sun.COM 		n = sizeof (pcishpc_props) / sizeof (pcishpc_prop_t);
41110923SEvan.Yan@Sun.COM 
41210923SEvan.Yan@Sun.COM 		if (strcmp(name, PCIEHPC_PROP_ALL) == 0) {
41310923SEvan.Yan@Sun.COM 			(void) nvlist_remove_all(prop_list, PCIEHPC_PROP_ALL);
41410923SEvan.Yan@Sun.COM 
41510923SEvan.Yan@Sun.COM 			/*
41610923SEvan.Yan@Sun.COM 			 * Add all properties into the request list, so that we
41710923SEvan.Yan@Sun.COM 			 * will get the values in the following for loop.
41810923SEvan.Yan@Sun.COM 			 */
41910923SEvan.Yan@Sun.COM 			for (i = 0; i < n; i++) {
42010923SEvan.Yan@Sun.COM 				if (nvlist_add_string(prop_list,
42110923SEvan.Yan@Sun.COM 				    pcishpc_props[i].prop_name, "") != 0) {
42210923SEvan.Yan@Sun.COM 					ret = DDI_FAILURE;
42310923SEvan.Yan@Sun.COM 					goto get_prop_cleanup1;
42410923SEvan.Yan@Sun.COM 				}
42510923SEvan.Yan@Sun.COM 			}
42610923SEvan.Yan@Sun.COM 			get_all_prop = B_TRUE;
42710923SEvan.Yan@Sun.COM 		} else if (strcmp(name, PCIEHPC_PROP_HELP) == 0) {
42810923SEvan.Yan@Sun.COM 			/*
42910923SEvan.Yan@Sun.COM 			 * Empty the request list, and add help strings into the
43010923SEvan.Yan@Sun.COM 			 * return list. We will pass the following for loop.
43110923SEvan.Yan@Sun.COM 			 */
43210923SEvan.Yan@Sun.COM 			(void) nvlist_remove_all(prop_list, PCIEHPC_PROP_HELP);
43310923SEvan.Yan@Sun.COM 
43410923SEvan.Yan@Sun.COM 			for (i = 0; i < n; i++) {
43510923SEvan.Yan@Sun.COM 				if (nvlist_add_string(prop_rlist,
43610923SEvan.Yan@Sun.COM 				    pcishpc_props[i].prop_name,
43710923SEvan.Yan@Sun.COM 				    pcishpc_props[i].prop_value) != 0) {
43810923SEvan.Yan@Sun.COM 					ret = DDI_FAILURE;
43910923SEvan.Yan@Sun.COM 					goto get_prop_cleanup1;
44010923SEvan.Yan@Sun.COM 				}
44110923SEvan.Yan@Sun.COM 			}
44210923SEvan.Yan@Sun.COM 		}
44310923SEvan.Yan@Sun.COM 	}
44410923SEvan.Yan@Sun.COM 
44510923SEvan.Yan@Sun.COM 	mutex_enter(&ctrl_p->hc_mutex);
44610923SEvan.Yan@Sun.COM 
44710923SEvan.Yan@Sun.COM 	/* get the current slot state */
44810923SEvan.Yan@Sun.COM 	pcishpc_get_slot_state(slot_p);
44910923SEvan.Yan@Sun.COM 
45010923SEvan.Yan@Sun.COM 	/* for each requested property, get the value and add it to nvlist */
45110923SEvan.Yan@Sun.COM 	prop_pair = NULL;
45210923SEvan.Yan@Sun.COM 	while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
45310923SEvan.Yan@Sun.COM 		name = nvpair_name(prop_pair);
45410923SEvan.Yan@Sun.COM 
45510923SEvan.Yan@Sun.COM 		if (strcmp(name, PCIEHPC_PROP_LED_FAULT) == 0) {
45610923SEvan.Yan@Sun.COM 			value = pcie_led_state_text(
45710923SEvan.Yan@Sun.COM 			    slot_p->hs_fault_led_state);
45810923SEvan.Yan@Sun.COM 		} else if (strcmp(name, PCIEHPC_PROP_LED_POWER) == 0) {
45910923SEvan.Yan@Sun.COM 			value = pcie_led_state_text(
46010923SEvan.Yan@Sun.COM 			    slot_p->hs_power_led_state);
46110923SEvan.Yan@Sun.COM 		} else if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
46210923SEvan.Yan@Sun.COM 			value = pcie_led_state_text(
46310923SEvan.Yan@Sun.COM 			    slot_p->hs_attn_led_state);
46410923SEvan.Yan@Sun.COM 		} else if (strcmp(name, PCIEHPC_PROP_LED_ACTIVE) == 0) {
46510923SEvan.Yan@Sun.COM 			value = pcie_led_state_text(
46610923SEvan.Yan@Sun.COM 			    slot_p->hs_active_led_state);
46710923SEvan.Yan@Sun.COM 		} else if (strcmp(name, PCIEHPC_PROP_CARD_TYPE) == 0) {
46810923SEvan.Yan@Sun.COM 			ddi_acc_handle_t	handle;
46910923SEvan.Yan@Sun.COM 			dev_info_t	*cdip;
47010923SEvan.Yan@Sun.COM 			uint8_t		prog_class, base_class, sub_class;
47110923SEvan.Yan@Sun.COM 			int		i;
47210923SEvan.Yan@Sun.COM 
47310923SEvan.Yan@Sun.COM 			mutex_exit(&ctrl_p->hc_mutex);
47410923SEvan.Yan@Sun.COM 			cdip = pcie_hp_devi_find(
47510923SEvan.Yan@Sun.COM 			    ctrl_p->hc_dip, slot_p->hs_device_num, 0);
47610923SEvan.Yan@Sun.COM 			mutex_enter(&ctrl_p->hc_mutex);
47710923SEvan.Yan@Sun.COM 
47810923SEvan.Yan@Sun.COM 			if ((slot_p->hs_info.cn_state !=
47910923SEvan.Yan@Sun.COM 			    DDI_HP_CN_STATE_ENABLED) || (cdip == NULL)) {
48010923SEvan.Yan@Sun.COM 				/*
48110923SEvan.Yan@Sun.COM 				 * When getting all properties, just ignore the
48210923SEvan.Yan@Sun.COM 				 * one that's not available under certain state.
48310923SEvan.Yan@Sun.COM 				 */
48410923SEvan.Yan@Sun.COM 				if (get_all_prop)
48510923SEvan.Yan@Sun.COM 					continue;
48610923SEvan.Yan@Sun.COM 
48710923SEvan.Yan@Sun.COM 				ret = DDI_ENOTSUP;
48810923SEvan.Yan@Sun.COM 				goto get_prop_cleanup2;
48910923SEvan.Yan@Sun.COM 			}
49010923SEvan.Yan@Sun.COM 
49110923SEvan.Yan@Sun.COM 			if (pci_config_setup(cdip, &handle) != DDI_SUCCESS) {
49210923SEvan.Yan@Sun.COM 				ret = DDI_FAILURE;
49310923SEvan.Yan@Sun.COM 				goto get_prop_cleanup2;
49410923SEvan.Yan@Sun.COM 			}
49510923SEvan.Yan@Sun.COM 
49610923SEvan.Yan@Sun.COM 			prog_class = pci_config_get8(handle,
49710923SEvan.Yan@Sun.COM 			    PCI_CONF_PROGCLASS);
49810923SEvan.Yan@Sun.COM 			base_class = pci_config_get8(handle, PCI_CONF_BASCLASS);
49910923SEvan.Yan@Sun.COM 			sub_class = pci_config_get8(handle, PCI_CONF_SUBCLASS);
50010923SEvan.Yan@Sun.COM 			pci_config_teardown(&handle);
50110923SEvan.Yan@Sun.COM 
50210923SEvan.Yan@Sun.COM 			for (i = 0; i < class_pci_items; i++) {
50310923SEvan.Yan@Sun.COM 				if ((base_class == class_pci[i].base_class) &&
50410923SEvan.Yan@Sun.COM 				    (sub_class == class_pci[i].sub_class) &&
50510923SEvan.Yan@Sun.COM 				    (prog_class == class_pci[i].prog_class)) {
50610923SEvan.Yan@Sun.COM 					value = class_pci[i].short_desc;
50710923SEvan.Yan@Sun.COM 					break;
50810923SEvan.Yan@Sun.COM 				}
50910923SEvan.Yan@Sun.COM 			}
51010923SEvan.Yan@Sun.COM 			if (i == class_pci_items)
51110923SEvan.Yan@Sun.COM 				value = PCIEHPC_PROP_VALUE_UNKNOWN;
51210923SEvan.Yan@Sun.COM 		} else if (strcmp(name, PCIEHPC_PROP_BOARD_TYPE) == 0) {
51310923SEvan.Yan@Sun.COM 			if (slot_p->hs_info.cn_state <= DDI_HP_CN_STATE_EMPTY)
51410923SEvan.Yan@Sun.COM 				value = PCIEHPC_PROP_VALUE_UNKNOWN;
51510923SEvan.Yan@Sun.COM 			else
51610923SEvan.Yan@Sun.COM 				value = PCIEHPC_PROP_VALUE_PCIHOTPLUG;
51710923SEvan.Yan@Sun.COM 		} else if (strcmp(name, PCIEHPC_PROP_SLOT_CONDITION) == 0) {
51810923SEvan.Yan@Sun.COM 			value = pcie_slot_condition_text(slot_p->hs_condition);
51910923SEvan.Yan@Sun.COM 		} else {
52010923SEvan.Yan@Sun.COM 			/* unsupported property */
52110996SEvan.Yan@Sun.COM 			PCIE_DBG("Unsupported property: %s\n", name);
52210923SEvan.Yan@Sun.COM 
52310923SEvan.Yan@Sun.COM 			ret = DDI_ENOTSUP;
52410923SEvan.Yan@Sun.COM 			goto get_prop_cleanup2;
52510923SEvan.Yan@Sun.COM 		}
52610923SEvan.Yan@Sun.COM 		if (nvlist_add_string(prop_rlist, name, value) != 0) {
52710923SEvan.Yan@Sun.COM 			ret = DDI_FAILURE;
52810923SEvan.Yan@Sun.COM 			goto get_prop_cleanup2;
52910923SEvan.Yan@Sun.COM 		}
53010923SEvan.Yan@Sun.COM 	}
53110923SEvan.Yan@Sun.COM 
53210923SEvan.Yan@Sun.COM 	// pack nvlist and copyout
53310923SEvan.Yan@Sun.COM 	if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
53410923SEvan.Yan@Sun.COM 	    &result.buf_size)) != DDI_SUCCESS) {
53510923SEvan.Yan@Sun.COM 		goto get_prop_cleanup2;
53610923SEvan.Yan@Sun.COM 	}
53710923SEvan.Yan@Sun.COM 	if (get_udatamodel() == DATAMODEL_NATIVE) {
53810923SEvan.Yan@Sun.COM 		if (copyout(&result, rval, sizeof (ddi_hp_property_t))) {
53910923SEvan.Yan@Sun.COM 			ret = DDI_FAILURE;
54010923SEvan.Yan@Sun.COM 			goto get_prop_cleanup2;
54110923SEvan.Yan@Sun.COM 		}
54210923SEvan.Yan@Sun.COM 	}
54310923SEvan.Yan@Sun.COM #ifdef _SYSCALL32_IMPL
54410923SEvan.Yan@Sun.COM 	else {
54510923SEvan.Yan@Sun.COM 		if (result.buf_size > UINT32_MAX) {
54610923SEvan.Yan@Sun.COM 			ret = DDI_FAILURE;
54710923SEvan.Yan@Sun.COM 		} else {
54810923SEvan.Yan@Sun.COM 			result32.buf_size = (uint32_t)result.buf_size;
54910923SEvan.Yan@Sun.COM 			if (copyout(&result32, rval,
55010923SEvan.Yan@Sun.COM 			    sizeof (ddi_hp_property32_t)))
55110923SEvan.Yan@Sun.COM 				ret = DDI_FAILURE;
55210923SEvan.Yan@Sun.COM 		}
55310923SEvan.Yan@Sun.COM 	}
55410923SEvan.Yan@Sun.COM #endif
55510923SEvan.Yan@Sun.COM 
55610923SEvan.Yan@Sun.COM get_prop_cleanup2:
55710923SEvan.Yan@Sun.COM 	mutex_exit(&ctrl_p->hc_mutex);
55810923SEvan.Yan@Sun.COM get_prop_cleanup1:
55910923SEvan.Yan@Sun.COM 	nvlist_free(prop_rlist);
56010923SEvan.Yan@Sun.COM get_prop_cleanup:
56110923SEvan.Yan@Sun.COM 	nvlist_free(prop_list);
56210923SEvan.Yan@Sun.COM 	return (ret);
56310923SEvan.Yan@Sun.COM }
56410923SEvan.Yan@Sun.COM 
56510923SEvan.Yan@Sun.COM int
pcishpc_slot_set_property(pcie_hp_slot_t * slot_p,ddi_hp_property_t * arg,ddi_hp_property_t * rval)56610923SEvan.Yan@Sun.COM pcishpc_slot_set_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
56710923SEvan.Yan@Sun.COM     ddi_hp_property_t *rval)
56810923SEvan.Yan@Sun.COM {
56910923SEvan.Yan@Sun.COM 	ddi_hp_property_t request, result;
57010923SEvan.Yan@Sun.COM #ifdef _SYSCALL32_IMPL
57110923SEvan.Yan@Sun.COM 	ddi_hp_property32_t request32, result32;
57210923SEvan.Yan@Sun.COM #endif
57310923SEvan.Yan@Sun.COM 	pcie_hp_ctrl_t		*ctrl_p = slot_p->hs_ctrl;
57410923SEvan.Yan@Sun.COM 	nvlist_t		*prop_list;
57510923SEvan.Yan@Sun.COM 	nvlist_t		*prop_rlist;
57610923SEvan.Yan@Sun.COM 	nvpair_t		*prop_pair;
57710923SEvan.Yan@Sun.COM 	char			*name, *value;
57810923SEvan.Yan@Sun.COM 	pcie_hp_led_state_t	led_state;
57910923SEvan.Yan@Sun.COM 	int			ret = DDI_SUCCESS;
58010923SEvan.Yan@Sun.COM 
58110923SEvan.Yan@Sun.COM 	if (get_udatamodel() == DATAMODEL_NATIVE) {
58210923SEvan.Yan@Sun.COM 		if (copyin(arg, &request, sizeof (ddi_hp_property_t)))
58310923SEvan.Yan@Sun.COM 			return (DDI_FAILURE);
58410923SEvan.Yan@Sun.COM 		if (rval &&
58510923SEvan.Yan@Sun.COM 		    copyin(rval, &result, sizeof (ddi_hp_property_t)))
58610923SEvan.Yan@Sun.COM 			return (DDI_FAILURE);
58710923SEvan.Yan@Sun.COM 	}
58810923SEvan.Yan@Sun.COM #ifdef _SYSCALL32_IMPL
58910923SEvan.Yan@Sun.COM 	else {
59010923SEvan.Yan@Sun.COM 		bzero(&request, sizeof (request));
59110923SEvan.Yan@Sun.COM 		bzero(&result, sizeof (result));
59210923SEvan.Yan@Sun.COM 		if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)))
59310923SEvan.Yan@Sun.COM 			return (DDI_FAILURE);
59410923SEvan.Yan@Sun.COM 		if (rval &&
59510923SEvan.Yan@Sun.COM 		    copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
59610923SEvan.Yan@Sun.COM 			return (DDI_FAILURE);
59710923SEvan.Yan@Sun.COM 		request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
59810923SEvan.Yan@Sun.COM 		request.buf_size = request32.buf_size;
59910923SEvan.Yan@Sun.COM 		if (rval) {
60010923SEvan.Yan@Sun.COM 			result.nvlist_buf =
60110923SEvan.Yan@Sun.COM 			    (char *)(uintptr_t)result32.nvlist_buf;
60210923SEvan.Yan@Sun.COM 			result.buf_size = result32.buf_size;
60310923SEvan.Yan@Sun.COM 		}
60410923SEvan.Yan@Sun.COM 	}
60510923SEvan.Yan@Sun.COM #endif
60610923SEvan.Yan@Sun.COM 
60710923SEvan.Yan@Sun.COM 	if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
60810923SEvan.Yan@Sun.COM 	    &prop_list)) != DDI_SUCCESS)
60910923SEvan.Yan@Sun.COM 		return (ret);
61010923SEvan.Yan@Sun.COM 
61110923SEvan.Yan@Sun.COM 	/* check whether the requested property is "help" */
61210923SEvan.Yan@Sun.COM 	prop_pair = nvlist_next_nvpair(prop_list, NULL);
61310923SEvan.Yan@Sun.COM 	if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair) &&
61410923SEvan.Yan@Sun.COM 	    (strcmp(nvpair_name(prop_pair), PCIEHPC_PROP_HELP) == 0)) {
61510923SEvan.Yan@Sun.COM 		if (!rval) {
61610923SEvan.Yan@Sun.COM 			ret = DDI_ENOTSUP;
61710923SEvan.Yan@Sun.COM 			goto set_prop_cleanup;
61810923SEvan.Yan@Sun.COM 		}
61910923SEvan.Yan@Sun.COM 
62010923SEvan.Yan@Sun.COM 		if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
62110923SEvan.Yan@Sun.COM 			ret = DDI_ENOMEM;
62210923SEvan.Yan@Sun.COM 			goto set_prop_cleanup;
62310923SEvan.Yan@Sun.COM 		}
62410923SEvan.Yan@Sun.COM 		if (nvlist_add_string(prop_rlist, PCIEHPC_PROP_LED_ATTN,
62510923SEvan.Yan@Sun.COM 		    PCIEHPC_PROP_VALUE_LED) != 0) {
62610923SEvan.Yan@Sun.COM 			ret = DDI_FAILURE;
62710923SEvan.Yan@Sun.COM 			goto set_prop_cleanup1;
62810923SEvan.Yan@Sun.COM 		}
62910923SEvan.Yan@Sun.COM 
63010923SEvan.Yan@Sun.COM 		if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
63110923SEvan.Yan@Sun.COM 		    &result.buf_size)) != DDI_SUCCESS) {
63210923SEvan.Yan@Sun.COM 			goto set_prop_cleanup1;
63310923SEvan.Yan@Sun.COM 		}
63410923SEvan.Yan@Sun.COM 		if (get_udatamodel() == DATAMODEL_NATIVE) {
63510923SEvan.Yan@Sun.COM 			if (copyout(&result, rval,
63610923SEvan.Yan@Sun.COM 			    sizeof (ddi_hp_property_t))) {
63710923SEvan.Yan@Sun.COM 				ret =  DDI_FAILURE;
63810923SEvan.Yan@Sun.COM 				goto set_prop_cleanup1;
63910923SEvan.Yan@Sun.COM 			}
64010923SEvan.Yan@Sun.COM 		}
64110923SEvan.Yan@Sun.COM #ifdef _SYSCALL32_IMPL
64210923SEvan.Yan@Sun.COM 		else {
64310923SEvan.Yan@Sun.COM 			if (result.buf_size > UINT32_MAX) {
64410923SEvan.Yan@Sun.COM 				ret =  DDI_FAILURE;
64510923SEvan.Yan@Sun.COM 				goto set_prop_cleanup1;
64610923SEvan.Yan@Sun.COM 			} else {
64710923SEvan.Yan@Sun.COM 				result32.buf_size = (uint32_t)result.buf_size;
64810923SEvan.Yan@Sun.COM 				if (copyout(&result32, rval,
64910923SEvan.Yan@Sun.COM 				    sizeof (ddi_hp_property32_t))) {
65010923SEvan.Yan@Sun.COM 					ret =  DDI_FAILURE;
65110923SEvan.Yan@Sun.COM 					goto set_prop_cleanup1;
65210923SEvan.Yan@Sun.COM 				}
65310923SEvan.Yan@Sun.COM 			}
65410923SEvan.Yan@Sun.COM 		}
65510923SEvan.Yan@Sun.COM #endif
65610923SEvan.Yan@Sun.COM set_prop_cleanup1:
65710923SEvan.Yan@Sun.COM 		nvlist_free(prop_rlist);
65810923SEvan.Yan@Sun.COM 		nvlist_free(prop_list);
65910923SEvan.Yan@Sun.COM 		return (ret);
66010923SEvan.Yan@Sun.COM 	}
66110923SEvan.Yan@Sun.COM 
66210923SEvan.Yan@Sun.COM 	/* Validate the request */
66310923SEvan.Yan@Sun.COM 	prop_pair = NULL;
66410923SEvan.Yan@Sun.COM 	while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
66510923SEvan.Yan@Sun.COM 		name = nvpair_name(prop_pair);
66610923SEvan.Yan@Sun.COM 		if (nvpair_type(prop_pair) != DATA_TYPE_STRING) {
66710996SEvan.Yan@Sun.COM 			PCIE_DBG("Unexpected data type of setting "
66810923SEvan.Yan@Sun.COM 			    "property %s.\n", name);
66910923SEvan.Yan@Sun.COM 			ret = DDI_EINVAL;
67010923SEvan.Yan@Sun.COM 			goto set_prop_cleanup;
67110923SEvan.Yan@Sun.COM 		}
67210923SEvan.Yan@Sun.COM 		if (nvpair_value_string(prop_pair, &value)) {
67310996SEvan.Yan@Sun.COM 			PCIE_DBG("Get string value failed for property %s.\n",
67410996SEvan.Yan@Sun.COM 			    name);
67510923SEvan.Yan@Sun.COM 			ret = DDI_FAILURE;
67610923SEvan.Yan@Sun.COM 			goto set_prop_cleanup;
67710923SEvan.Yan@Sun.COM 		}
67810923SEvan.Yan@Sun.COM 
67910923SEvan.Yan@Sun.COM 		if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
68010923SEvan.Yan@Sun.COM 			if ((strcmp(value, PCIEHPC_PROP_VALUE_ON) != 0) &&
68110923SEvan.Yan@Sun.COM 			    (strcmp(value, PCIEHPC_PROP_VALUE_OFF) != 0) &&
68210923SEvan.Yan@Sun.COM 			    (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) != 0)) {
68310996SEvan.Yan@Sun.COM 				PCIE_DBG("Unsupported value of setting "
68410923SEvan.Yan@Sun.COM 				    "property %s\n", name);
68510923SEvan.Yan@Sun.COM 				ret = DDI_ENOTSUP;
68610923SEvan.Yan@Sun.COM 				goto set_prop_cleanup;
68710923SEvan.Yan@Sun.COM 			}
68810923SEvan.Yan@Sun.COM 		} else {
68910996SEvan.Yan@Sun.COM 			PCIE_DBG("Unsupported property: %s\n", name);
69010923SEvan.Yan@Sun.COM 			ret = DDI_ENOTSUP;
69110923SEvan.Yan@Sun.COM 			goto set_prop_cleanup;
69210923SEvan.Yan@Sun.COM 		}
69310923SEvan.Yan@Sun.COM 	}
69410923SEvan.Yan@Sun.COM 
69510923SEvan.Yan@Sun.COM 	mutex_enter(&ctrl_p->hc_mutex);
69610923SEvan.Yan@Sun.COM 
69710923SEvan.Yan@Sun.COM 	/* get the current slot state */
69810923SEvan.Yan@Sun.COM 	pcishpc_get_slot_state(slot_p);
69910923SEvan.Yan@Sun.COM 
70010923SEvan.Yan@Sun.COM 	// set each property
70110923SEvan.Yan@Sun.COM 	prop_pair = NULL;
70210923SEvan.Yan@Sun.COM 	while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
70310923SEvan.Yan@Sun.COM 		name = nvpair_name(prop_pair);
70410923SEvan.Yan@Sun.COM 
70510923SEvan.Yan@Sun.COM 		if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
70610923SEvan.Yan@Sun.COM 			if (strcmp(value, PCIEHPC_PROP_VALUE_ON) == 0)
70710923SEvan.Yan@Sun.COM 				led_state = PCIE_HP_LED_ON;
70810923SEvan.Yan@Sun.COM 			else if (strcmp(value, PCIEHPC_PROP_VALUE_OFF) == 0)
70910923SEvan.Yan@Sun.COM 				led_state = PCIE_HP_LED_OFF;
71010923SEvan.Yan@Sun.COM 			else if (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) == 0)
71110923SEvan.Yan@Sun.COM 				led_state = PCIE_HP_LED_BLINK;
71210923SEvan.Yan@Sun.COM 
71310923SEvan.Yan@Sun.COM 			(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED,
71410923SEvan.Yan@Sun.COM 			    led_state);
71510923SEvan.Yan@Sun.COM 		}
71610923SEvan.Yan@Sun.COM 	}
71710996SEvan.Yan@Sun.COM 	if (rval) {
71810996SEvan.Yan@Sun.COM 		if (get_udatamodel() == DATAMODEL_NATIVE) {
71910996SEvan.Yan@Sun.COM 			result.buf_size = 0;
72010996SEvan.Yan@Sun.COM 			if (copyout(&result, rval, sizeof (ddi_hp_property_t)))
72110996SEvan.Yan@Sun.COM 				ret =  DDI_FAILURE;
72210996SEvan.Yan@Sun.COM 		}
72310996SEvan.Yan@Sun.COM #ifdef _SYSCALL32_IMPL
72410996SEvan.Yan@Sun.COM 		else {
72510996SEvan.Yan@Sun.COM 			result32.buf_size = 0;
72610996SEvan.Yan@Sun.COM 			if (copyout(&result32, rval,
72710996SEvan.Yan@Sun.COM 			    sizeof (ddi_hp_property32_t)))
72810996SEvan.Yan@Sun.COM 				ret =  DDI_FAILURE;
72910996SEvan.Yan@Sun.COM 		}
73010996SEvan.Yan@Sun.COM #endif
73110996SEvan.Yan@Sun.COM 	}
73210923SEvan.Yan@Sun.COM 
73310923SEvan.Yan@Sun.COM 	mutex_exit(&ctrl_p->hc_mutex);
73410923SEvan.Yan@Sun.COM set_prop_cleanup:
73510923SEvan.Yan@Sun.COM 	nvlist_free(prop_list);
73610923SEvan.Yan@Sun.COM 	return (ret);
73710923SEvan.Yan@Sun.COM }
73810923SEvan.Yan@Sun.COM 
73910923SEvan.Yan@Sun.COM /*
74010923SEvan.Yan@Sun.COM  * pcishpc_hp_ops()
74110923SEvan.Yan@Sun.COM  *
74210923SEvan.Yan@Sun.COM  * Handle hotplug commands
74310923SEvan.Yan@Sun.COM  *
74410923SEvan.Yan@Sun.COM  * Note: This function is called by DDI HP framework at kernel context only
74510923SEvan.Yan@Sun.COM  */
74610923SEvan.Yan@Sun.COM /* ARGSUSED */
74710923SEvan.Yan@Sun.COM int
pcishpc_hp_ops(dev_info_t * dip,char * cn_name,ddi_hp_op_t op,void * arg,void * result)74810923SEvan.Yan@Sun.COM pcishpc_hp_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op,
74910923SEvan.Yan@Sun.COM     void *arg, void *result)
75010923SEvan.Yan@Sun.COM {
75110923SEvan.Yan@Sun.COM 	pcie_hp_slot_t	*slot_p = NULL;
75210923SEvan.Yan@Sun.COM 	pcie_hp_ctrl_t	*ctrl_p;
75310923SEvan.Yan@Sun.COM 	int		ret = DDI_SUCCESS, i;
75410923SEvan.Yan@Sun.COM 
75510923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_hp_ops: dip=%p cn_name=%s op=%x arg=%p\n",
75610923SEvan.Yan@Sun.COM 	    dip, cn_name, op, arg);
75710923SEvan.Yan@Sun.COM 
75810923SEvan.Yan@Sun.COM 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
75910923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
76010923SEvan.Yan@Sun.COM 
76110923SEvan.Yan@Sun.COM 	for (i = 0; i < PCIE_HP_MAX_SLOTS && ctrl_p->hc_slots[i]; i++) {
76210923SEvan.Yan@Sun.COM 		if (strcmp(ctrl_p->hc_slots[i]->hs_info.cn_name, cn_name)
76310923SEvan.Yan@Sun.COM 		    == 0) {
76410923SEvan.Yan@Sun.COM 			/* Match with a physical slot, found */
76510923SEvan.Yan@Sun.COM 			slot_p = ctrl_p->hc_slots[i];
76610923SEvan.Yan@Sun.COM 			break;
76710923SEvan.Yan@Sun.COM 		}
76810923SEvan.Yan@Sun.COM 	}
76910923SEvan.Yan@Sun.COM 	if (!slot_p) {
77010923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_hp_ops: Failed to find the slot under"
77110923SEvan.Yan@Sun.COM 		    "dip %p with name: %s; op=%x arg=%p\n",
77210923SEvan.Yan@Sun.COM 		    dip, cn_name, op, arg);
77310923SEvan.Yan@Sun.COM 		return (DDI_EINVAL);
77410923SEvan.Yan@Sun.COM 	}
77510923SEvan.Yan@Sun.COM 	switch (op) {
77610923SEvan.Yan@Sun.COM 	case DDI_HPOP_CN_GET_STATE:
77710923SEvan.Yan@Sun.COM 	{
77810923SEvan.Yan@Sun.COM 		mutex_enter(&ctrl_p->hc_mutex);
77910923SEvan.Yan@Sun.COM 
78010923SEvan.Yan@Sun.COM 		/* get the current slot state */
78110923SEvan.Yan@Sun.COM 		pcishpc_get_slot_state(slot_p);
78210923SEvan.Yan@Sun.COM 
78310923SEvan.Yan@Sun.COM 		*((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state;
78410923SEvan.Yan@Sun.COM 
78510923SEvan.Yan@Sun.COM 		mutex_exit(&ctrl_p->hc_mutex);
78610923SEvan.Yan@Sun.COM 		break;
78710923SEvan.Yan@Sun.COM 	}
78810923SEvan.Yan@Sun.COM 	case DDI_HPOP_CN_CHANGE_STATE:
78910923SEvan.Yan@Sun.COM 	{
79010923SEvan.Yan@Sun.COM 		ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg;
79110923SEvan.Yan@Sun.COM 
79210923SEvan.Yan@Sun.COM 		mutex_enter(&slot_p->hs_ctrl->hc_mutex);
79310923SEvan.Yan@Sun.COM 
79410923SEvan.Yan@Sun.COM 		ret = pcishpc_change_slot_state(slot_p, target_state);
79510923SEvan.Yan@Sun.COM 		*((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state;
79610923SEvan.Yan@Sun.COM 
79710923SEvan.Yan@Sun.COM 		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
79810923SEvan.Yan@Sun.COM 		break;
79910923SEvan.Yan@Sun.COM 	}
80010923SEvan.Yan@Sun.COM 	case DDI_HPOP_CN_PROBE:
80110923SEvan.Yan@Sun.COM 		ret = pcishpc_slot_probe(slot_p);
80210923SEvan.Yan@Sun.COM 
80310923SEvan.Yan@Sun.COM 		break;
80410923SEvan.Yan@Sun.COM 	case DDI_HPOP_CN_UNPROBE:
80510923SEvan.Yan@Sun.COM 		ret = pcishpc_slot_unprobe(slot_p);
80610923SEvan.Yan@Sun.COM 
80710923SEvan.Yan@Sun.COM 		break;
80810923SEvan.Yan@Sun.COM 	case DDI_HPOP_CN_GET_PROPERTY:
80910923SEvan.Yan@Sun.COM 		ret = pcishpc_slot_get_property(slot_p,
81010923SEvan.Yan@Sun.COM 		    (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
81110923SEvan.Yan@Sun.COM 		break;
81210923SEvan.Yan@Sun.COM 	case DDI_HPOP_CN_SET_PROPERTY:
81310923SEvan.Yan@Sun.COM 		ret = pcishpc_slot_set_property(slot_p,
81410923SEvan.Yan@Sun.COM 		    (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
81510923SEvan.Yan@Sun.COM 		break;
81610923SEvan.Yan@Sun.COM 	default:
81710923SEvan.Yan@Sun.COM 		ret = DDI_ENOTSUP;
81810923SEvan.Yan@Sun.COM 		break;
81910923SEvan.Yan@Sun.COM 	}
82010923SEvan.Yan@Sun.COM 
82110923SEvan.Yan@Sun.COM 	return (ret);
82210923SEvan.Yan@Sun.COM }
82310923SEvan.Yan@Sun.COM 
82410923SEvan.Yan@Sun.COM /*
82510923SEvan.Yan@Sun.COM  * Local functions (called within this file)
82610923SEvan.Yan@Sun.COM  */
82710923SEvan.Yan@Sun.COM 
82810923SEvan.Yan@Sun.COM /*
82910923SEvan.Yan@Sun.COM  * pcishpc_create_controller()
83010923SEvan.Yan@Sun.COM  *
83110923SEvan.Yan@Sun.COM  * This function allocates and creates an SHPC controller state structure
83210923SEvan.Yan@Sun.COM  * and adds it to the linked list of controllers.
83310923SEvan.Yan@Sun.COM  */
83410923SEvan.Yan@Sun.COM static pcie_hp_ctrl_t *
pcishpc_create_controller(dev_info_t * dip)83510923SEvan.Yan@Sun.COM pcishpc_create_controller(dev_info_t *dip)
83610923SEvan.Yan@Sun.COM {
83710923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
83810923SEvan.Yan@Sun.COM 	pcie_hp_ctrl_t	*ctrl_p;
83910923SEvan.Yan@Sun.COM 
84010923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc: create controller for %s#%d\n",
84110923SEvan.Yan@Sun.COM 	    ddi_driver_name(dip), ddi_get_instance(dip));
84210923SEvan.Yan@Sun.COM 
84310923SEvan.Yan@Sun.COM 	ctrl_p = kmem_zalloc(sizeof (pcie_hp_ctrl_t), KM_SLEEP);
84410923SEvan.Yan@Sun.COM 	ctrl_p->hc_dip = dip;
84510923SEvan.Yan@Sun.COM 
84610923SEvan.Yan@Sun.COM 	cv_init(&ctrl_p->hc_cmd_comp_cv, NULL, CV_DRIVER, NULL);
84710923SEvan.Yan@Sun.COM 
84810923SEvan.Yan@Sun.COM 	/* Init the shpc controller's mutex. */
84910923SEvan.Yan@Sun.COM 	mutex_init(&ctrl_p->hc_mutex, NULL, MUTEX_DRIVER, NULL);
85010923SEvan.Yan@Sun.COM 
85110923SEvan.Yan@Sun.COM 	/* HPC initialization is complete now */
85210923SEvan.Yan@Sun.COM 	ctrl_p->hc_flags = PCIE_HP_INITIALIZED_FLAG;
85310923SEvan.Yan@Sun.COM 	bus_p->bus_hp_curr_mode = PCIE_PCI_HP_MODE;
85410923SEvan.Yan@Sun.COM 
85510923SEvan.Yan@Sun.COM 	PCIE_SET_HP_CTRL(dip, ctrl_p);
85610923SEvan.Yan@Sun.COM 
85710923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_create_controller() success\n");
85810923SEvan.Yan@Sun.COM 
85910923SEvan.Yan@Sun.COM 	return (ctrl_p);
86010923SEvan.Yan@Sun.COM }
86110923SEvan.Yan@Sun.COM 
86210923SEvan.Yan@Sun.COM 
86310923SEvan.Yan@Sun.COM /*
86410923SEvan.Yan@Sun.COM  * pcishpc_setup_controller()
86510923SEvan.Yan@Sun.COM  *
86610923SEvan.Yan@Sun.COM  * Get the number of HotPlug Slots, and the PCI device information
86710923SEvan.Yan@Sun.COM  * for this HotPlug controller.
86810923SEvan.Yan@Sun.COM  */
86910923SEvan.Yan@Sun.COM static int
pcishpc_setup_controller(pcie_hp_ctrl_t * ctrl_p)87010923SEvan.Yan@Sun.COM pcishpc_setup_controller(pcie_hp_ctrl_t *ctrl_p)
87110923SEvan.Yan@Sun.COM {
87210923SEvan.Yan@Sun.COM 	uint32_t config;
87310923SEvan.Yan@Sun.COM 	dev_info_t *ppdip;
87410923SEvan.Yan@Sun.COM 
87510923SEvan.Yan@Sun.COM 	config = pcishpc_read_reg(ctrl_p, PCI_HP_SLOT_CONFIGURATION_REG);
87610923SEvan.Yan@Sun.COM 
87710923SEvan.Yan@Sun.COM 	/* Get the number of HotPlug slots implemented */
87810923SEvan.Yan@Sun.COM 	ctrl_p->hc_num_slots_impl = ((config)&31);
87910923SEvan.Yan@Sun.COM 
88010923SEvan.Yan@Sun.COM 	/*
88110923SEvan.Yan@Sun.COM 	 * Initilize the current bus speed and number of hotplug slots
88210923SEvan.Yan@Sun.COM 	 * currently connected.
88310923SEvan.Yan@Sun.COM 	 */
88410923SEvan.Yan@Sun.COM 	ctrl_p->hc_curr_bus_speed = -1;
88510923SEvan.Yan@Sun.COM 	ctrl_p->hc_num_slots_connected = 0;
88610923SEvan.Yan@Sun.COM 
88710923SEvan.Yan@Sun.COM 	/*
88810923SEvan.Yan@Sun.COM 	 * Get the first PCI device Number used.
88910923SEvan.Yan@Sun.COM 	 *
89010923SEvan.Yan@Sun.COM 	 * PCI-X I/O boat workaround.
89110923SEvan.Yan@Sun.COM 	 * The register doesn't set up the correct value.
89210923SEvan.Yan@Sun.COM 	 */
89310923SEvan.Yan@Sun.COM 	ppdip = ddi_get_parent(ddi_get_parent(ctrl_p->hc_dip));
89410923SEvan.Yan@Sun.COM 	if ((ddi_prop_get_int(DDI_DEV_T_ANY, ppdip, DDI_PROP_DONTPASS,
89510923SEvan.Yan@Sun.COM 	    "vendor-id", -1) == 0x108e) &&
89610923SEvan.Yan@Sun.COM 	    (ddi_prop_get_int(DDI_DEV_T_ANY, ppdip, DDI_PROP_DONTPASS,
89710923SEvan.Yan@Sun.COM 	    "device-id", -1) == 0x9010))
89810923SEvan.Yan@Sun.COM 		ctrl_p->hc_device_start = 4;
89910923SEvan.Yan@Sun.COM 	else
90010923SEvan.Yan@Sun.COM 		ctrl_p->hc_device_start = ((config>>8)&31);
90110923SEvan.Yan@Sun.COM 
90210923SEvan.Yan@Sun.COM 	/* Get the first Physical device number. */
90310923SEvan.Yan@Sun.COM 	ctrl_p->hc_phys_start = ((config>>16)&0x7ff);
90410923SEvan.Yan@Sun.COM 
90510923SEvan.Yan@Sun.COM 	/* Check if the device numbers increase or decrease. */
90610923SEvan.Yan@Sun.COM 	ctrl_p->hc_device_increases = ((config>>29)&0x1);
90710923SEvan.Yan@Sun.COM 
90810923SEvan.Yan@Sun.COM 	ctrl_p->hc_has_attn =
90910923SEvan.Yan@Sun.COM 	    (config & PCI_HP_SLOT_CONFIG_ATTN_BUTTON) ? B_TRUE : B_FALSE;
91010923SEvan.Yan@Sun.COM 	ctrl_p->hc_has_mrl =
91110923SEvan.Yan@Sun.COM 	    (config & PCI_HP_SLOT_CONFIG_MRL_SENSOR) ? B_TRUE : B_FALSE;
91210923SEvan.Yan@Sun.COM 
91310923SEvan.Yan@Sun.COM 	ctrl_p->hc_cmd_pending = B_FALSE;
91410923SEvan.Yan@Sun.COM 	ctrl_p->hc_arbiter_timeout = B_FALSE;
91510923SEvan.Yan@Sun.COM 
91610923SEvan.Yan@Sun.COM 	if (ctrl_p->hc_num_slots_impl > PCIE_HP_MAX_SLOTS) {
91710923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_setup_controller() too many SHPC "
91810923SEvan.Yan@Sun.COM 		    "slots error\n");
91910923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
92010923SEvan.Yan@Sun.COM 	}
92110923SEvan.Yan@Sun.COM 
92210923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
92310923SEvan.Yan@Sun.COM }
92410923SEvan.Yan@Sun.COM 
92510923SEvan.Yan@Sun.COM 
92610923SEvan.Yan@Sun.COM /*
92710923SEvan.Yan@Sun.COM  * pcishpc_destroy_controller()
92810923SEvan.Yan@Sun.COM  *
92910923SEvan.Yan@Sun.COM  * This function deallocates all of the SHPC controller resources.
93010923SEvan.Yan@Sun.COM  */
93110923SEvan.Yan@Sun.COM static int
pcishpc_destroy_controller(dev_info_t * dip)93210923SEvan.Yan@Sun.COM pcishpc_destroy_controller(dev_info_t *dip)
93310923SEvan.Yan@Sun.COM {
93410923SEvan.Yan@Sun.COM 	pcie_hp_ctrl_t	*ctrl_p;
93510923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
93610923SEvan.Yan@Sun.COM 
93710923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_destroy_controller() called(dip=%p)\n", dip);
93810923SEvan.Yan@Sun.COM 
93910923SEvan.Yan@Sun.COM 	/* get the soft state structure for this dip */
94010923SEvan.Yan@Sun.COM 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) {
94110923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_destroy_controller() not found\n");
94210923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
94310923SEvan.Yan@Sun.COM 	}
94410923SEvan.Yan@Sun.COM 
94510923SEvan.Yan@Sun.COM 	/*
94610923SEvan.Yan@Sun.COM 	 * Deallocate the slot state structures for this controller.
94710923SEvan.Yan@Sun.COM 	 */
94811245SZhijun.Fu@Sun.COM 	PCIE_SET_HP_CTRL(dip, NULL);
94911245SZhijun.Fu@Sun.COM 	bus_p->bus_hp_curr_mode = PCIE_NONE_HP_MODE;
95011245SZhijun.Fu@Sun.COM 
95110923SEvan.Yan@Sun.COM 	(void) pcishpc_destroy_slots(ctrl_p);
95210923SEvan.Yan@Sun.COM 	cv_destroy(&ctrl_p->hc_cmd_comp_cv);
95310923SEvan.Yan@Sun.COM 	mutex_destroy(&ctrl_p->hc_mutex);
95410923SEvan.Yan@Sun.COM 	kmem_free(ctrl_p, sizeof (pcie_hp_ctrl_t));
95510923SEvan.Yan@Sun.COM 
95610923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_destroy_controller() success\n");
95710923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
95810923SEvan.Yan@Sun.COM }
95910923SEvan.Yan@Sun.COM 
96010923SEvan.Yan@Sun.COM /*
96110923SEvan.Yan@Sun.COM  * pcishpc_create_slot()
96210923SEvan.Yan@Sun.COM  *
96310923SEvan.Yan@Sun.COM  * Allocate and add a new HotPlug slot state structure to the linked list.
96410923SEvan.Yan@Sun.COM  */
96510923SEvan.Yan@Sun.COM static pcie_hp_slot_t *
pcishpc_create_slot(pcie_hp_ctrl_t * ctrl_p)96610923SEvan.Yan@Sun.COM pcishpc_create_slot(pcie_hp_ctrl_t *ctrl_p)
96710923SEvan.Yan@Sun.COM {
96810923SEvan.Yan@Sun.COM 	pcie_hp_slot_t *slot_p;
96910923SEvan.Yan@Sun.COM 
97010923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_create_slot() called(ctrl_p=%x)\n", ctrl_p);
97110923SEvan.Yan@Sun.COM 
97210923SEvan.Yan@Sun.COM 	/* Allocate a new slot structure. */
97310923SEvan.Yan@Sun.COM 	slot_p = kmem_zalloc(sizeof (pcie_hp_slot_t), KM_SLEEP);
97410923SEvan.Yan@Sun.COM 	slot_p->hs_ctrl = ctrl_p;
97510923SEvan.Yan@Sun.COM 
97610923SEvan.Yan@Sun.COM 	/* Assign an initial value */
97710923SEvan.Yan@Sun.COM 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY;
97810923SEvan.Yan@Sun.COM 
97910923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_create_slot() success\n");
98010923SEvan.Yan@Sun.COM 	return (slot_p);
98110923SEvan.Yan@Sun.COM }
98210923SEvan.Yan@Sun.COM 
98310923SEvan.Yan@Sun.COM /*
98410923SEvan.Yan@Sun.COM  * pcishpc_register_slot()
98510923SEvan.Yan@Sun.COM  *
98610923SEvan.Yan@Sun.COM  * Create and register a slot with the Solaris HotPlug framework.
98710923SEvan.Yan@Sun.COM  */
98810923SEvan.Yan@Sun.COM static int
pcishpc_register_slot(pcie_hp_ctrl_t * ctrl_p,int slot)98910923SEvan.Yan@Sun.COM pcishpc_register_slot(pcie_hp_ctrl_t *ctrl_p, int slot)
99010923SEvan.Yan@Sun.COM {
99110923SEvan.Yan@Sun.COM 	dev_info_t	*dip = ctrl_p->hc_dip;
99210923SEvan.Yan@Sun.COM 	pcie_hp_slot_t	*slot_p;
99310923SEvan.Yan@Sun.COM 
99410923SEvan.Yan@Sun.COM 	slot_p = pcishpc_create_slot(ctrl_p);
99510923SEvan.Yan@Sun.COM 	ctrl_p->hc_slots[slot] = slot_p;
99610923SEvan.Yan@Sun.COM 	slot_p->hs_num = slot;
99710923SEvan.Yan@Sun.COM 
99810923SEvan.Yan@Sun.COM 	/* Setup the PCI device # for this SHPC slot. */
99910923SEvan.Yan@Sun.COM 	if (ctrl_p->hc_device_increases)
100010923SEvan.Yan@Sun.COM 		slot_p->hs_device_num = ctrl_p->hc_device_start +
100110923SEvan.Yan@Sun.COM 		    slot_p->hs_num;
100210923SEvan.Yan@Sun.COM 	else
100310923SEvan.Yan@Sun.COM 		slot_p->hs_device_num = ctrl_p->hc_device_start -
100410923SEvan.Yan@Sun.COM 		    slot_p->hs_num;
100510923SEvan.Yan@Sun.COM 
100610923SEvan.Yan@Sun.COM 	/* Setup the DDI HP framework slot information. */
100710923SEvan.Yan@Sun.COM 	slot_p->hs_info.cn_type = DDI_HP_CN_TYPE_PCI;
100810923SEvan.Yan@Sun.COM 	slot_p->hs_info.cn_type_str = PCIE_PCI_HP_TYPE;
100910923SEvan.Yan@Sun.COM 	slot_p->hs_info.cn_child = NULL;
101010923SEvan.Yan@Sun.COM 
101110923SEvan.Yan@Sun.COM 	slot_p->hs_minor = PCI_MINOR_NUM(
101210923SEvan.Yan@Sun.COM 	    ddi_get_instance(dip), slot_p->hs_device_num);
101310923SEvan.Yan@Sun.COM 	slot_p->hs_condition = AP_COND_UNKNOWN;
101410923SEvan.Yan@Sun.COM 
101510923SEvan.Yan@Sun.COM 	/* setup thread for handling ATTN button events */
101610923SEvan.Yan@Sun.COM 	if (ctrl_p->hc_has_attn) {
101710923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_register_slot: "
101810923SEvan.Yan@Sun.COM 		    "setting up ATTN button event "
101910923SEvan.Yan@Sun.COM 		    "handler thread for slot %d\n", slot);
102010923SEvan.Yan@Sun.COM 
102110923SEvan.Yan@Sun.COM 		cv_init(&slot_p->hs_attn_btn_cv, NULL, CV_DRIVER, NULL);
102210923SEvan.Yan@Sun.COM 		slot_p->hs_attn_btn_pending = B_FALSE;
102310923SEvan.Yan@Sun.COM 		slot_p->hs_attn_btn_threadp = thread_create(NULL, 0,
102410923SEvan.Yan@Sun.COM 		    pcishpc_attn_btn_handler,
102510923SEvan.Yan@Sun.COM 		    (void *)slot_p, 0, &p0, TS_RUN, minclsyspri);
102610923SEvan.Yan@Sun.COM 		slot_p->hs_attn_btn_thread_exit = B_FALSE;
102710923SEvan.Yan@Sun.COM 	}
102810923SEvan.Yan@Sun.COM 
102910923SEvan.Yan@Sun.COM 	/* setup the slot name (used for ap-id) */
103010923SEvan.Yan@Sun.COM 	pcishpc_set_slot_name(ctrl_p, slot);
103110923SEvan.Yan@Sun.COM 
103210923SEvan.Yan@Sun.COM 	pcishpc_get_slot_state(slot_p);
103310923SEvan.Yan@Sun.COM 	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_ENABLED)
103410923SEvan.Yan@Sun.COM 		slot_p->hs_condition = AP_COND_OK;
103510923SEvan.Yan@Sun.COM 
103610923SEvan.Yan@Sun.COM 	/* register the slot with DDI HP framework */
103710923SEvan.Yan@Sun.COM 	if (ndi_hp_register(dip, &slot_p->hs_info) != NDI_SUCCESS) {
103810923SEvan.Yan@Sun.COM 		PCIE_DBG("pciehpc_register_slot() failed to register slot %d\n",
103910923SEvan.Yan@Sun.COM 		    slot_p->hs_phy_slot_num);
104010923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
104110923SEvan.Yan@Sun.COM 	}
104210923SEvan.Yan@Sun.COM 
104310923SEvan.Yan@Sun.COM 	pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip),
104410923SEvan.Yan@Sun.COM 	    slot_p->hs_minor), slot_p->hs_device_num);
104510923SEvan.Yan@Sun.COM 
104610923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_register_slot() success for slot %d\n", slot);
104710923SEvan.Yan@Sun.COM 
104810923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
104910923SEvan.Yan@Sun.COM }
105010923SEvan.Yan@Sun.COM 
105110923SEvan.Yan@Sun.COM /*
105210923SEvan.Yan@Sun.COM  * pcishpc_destroy_slots()
105310923SEvan.Yan@Sun.COM  *
105410923SEvan.Yan@Sun.COM  * Free up all of the slot resources for this controller.
105510923SEvan.Yan@Sun.COM  */
105610923SEvan.Yan@Sun.COM static int
pcishpc_destroy_slots(pcie_hp_ctrl_t * ctrl_p)105710923SEvan.Yan@Sun.COM pcishpc_destroy_slots(pcie_hp_ctrl_t *ctrl_p)
105810923SEvan.Yan@Sun.COM {
105910923SEvan.Yan@Sun.COM 	dev_info_t	*dip = ctrl_p->hc_dip;
106010923SEvan.Yan@Sun.COM 	pcie_hp_slot_t	*slot_p;
106110923SEvan.Yan@Sun.COM 	int		i;
106210923SEvan.Yan@Sun.COM 
106310923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_destroy_slots() called(ctrl_p=%p)\n", ctrl_p);
106410923SEvan.Yan@Sun.COM 
106510923SEvan.Yan@Sun.COM 	for (i = 0; i < PCIE_HP_MAX_SLOTS; i++) {
106610923SEvan.Yan@Sun.COM 		if ((slot_p = ctrl_p->hc_slots[i]) == NULL)
106710923SEvan.Yan@Sun.COM 			continue;
106810923SEvan.Yan@Sun.COM 
106910923SEvan.Yan@Sun.COM 		if (slot_p->hs_attn_btn_threadp != NULL) {
107010923SEvan.Yan@Sun.COM 			mutex_enter(&ctrl_p->hc_mutex);
107110923SEvan.Yan@Sun.COM 			slot_p->hs_attn_btn_thread_exit = B_TRUE;
107210923SEvan.Yan@Sun.COM 			cv_signal(&slot_p->hs_attn_btn_cv);
107310923SEvan.Yan@Sun.COM 			PCIE_DBG("pcishpc_destroy_slots: "
107410923SEvan.Yan@Sun.COM 			    "waiting for ATTN thread exit\n");
107510923SEvan.Yan@Sun.COM 			cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
107610923SEvan.Yan@Sun.COM 			PCIE_DBG("pcishpc_destroy_slots: "
107710923SEvan.Yan@Sun.COM 			    "ATTN thread exit\n");
107810923SEvan.Yan@Sun.COM 			cv_destroy(&slot_p->hs_attn_btn_cv);
107910923SEvan.Yan@Sun.COM 			slot_p->hs_attn_btn_threadp = NULL;
108010923SEvan.Yan@Sun.COM 			mutex_exit(&ctrl_p->hc_mutex);
108110923SEvan.Yan@Sun.COM 		}
108210923SEvan.Yan@Sun.COM 
108310923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_destroy_slots() (shpc_p=%p)\n"
108410923SEvan.Yan@Sun.COM 		    "destroyed", slot_p);
108510923SEvan.Yan@Sun.COM 
108610923SEvan.Yan@Sun.COM 		pcie_hp_delete_occupant_props(dip,
108710923SEvan.Yan@Sun.COM 		    makedevice(ddi_driver_major(dip),
108810923SEvan.Yan@Sun.COM 		    slot_p->hs_minor));
108910923SEvan.Yan@Sun.COM 
109010923SEvan.Yan@Sun.COM 		/* unregister the slot with DDI HP framework */
109110923SEvan.Yan@Sun.COM 		if (ndi_hp_unregister(dip, slot_p->hs_info.cn_name) !=
109210923SEvan.Yan@Sun.COM 		    NDI_SUCCESS) {
109310923SEvan.Yan@Sun.COM 			PCIE_DBG("pcishpc_destroy_slots() "
109410923SEvan.Yan@Sun.COM 			    "failed to unregister slot %d\n",
109510923SEvan.Yan@Sun.COM 			    slot_p->hs_phy_slot_num);
109610923SEvan.Yan@Sun.COM 			return (DDI_FAILURE);
109710923SEvan.Yan@Sun.COM 		}
109810923SEvan.Yan@Sun.COM 		kmem_free(slot_p->hs_info.cn_name,
109910923SEvan.Yan@Sun.COM 		    strlen(slot_p->hs_info.cn_name) + 1);
110010923SEvan.Yan@Sun.COM 		kmem_free(slot_p, sizeof (pcie_hp_slot_t));
110110923SEvan.Yan@Sun.COM 	}
110210923SEvan.Yan@Sun.COM 
110310923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
110410923SEvan.Yan@Sun.COM }
110510923SEvan.Yan@Sun.COM 
110610923SEvan.Yan@Sun.COM /*
110710923SEvan.Yan@Sun.COM  * pcishpc_enable_irqs()
110810923SEvan.Yan@Sun.COM  *
110910923SEvan.Yan@Sun.COM  * Enable/unmask the different IRQ's we support from the SHPC controller.
111010923SEvan.Yan@Sun.COM  */
1111*11445SEvan.Yan@Sun.COM int
pcishpc_enable_irqs(pcie_hp_ctrl_t * ctrl_p)111210923SEvan.Yan@Sun.COM pcishpc_enable_irqs(pcie_hp_ctrl_t *ctrl_p)
111310923SEvan.Yan@Sun.COM {
111410923SEvan.Yan@Sun.COM 	uint32_t reg;
111510923SEvan.Yan@Sun.COM 	int slot;
111610923SEvan.Yan@Sun.COM 
111710923SEvan.Yan@Sun.COM 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG);
111810923SEvan.Yan@Sun.COM 
111910923SEvan.Yan@Sun.COM 	/* Enable all interrupts. */
112010923SEvan.Yan@Sun.COM 	reg &= ~PCI_HP_SERR_INT_MASK_ALL;
112110923SEvan.Yan@Sun.COM 
112210923SEvan.Yan@Sun.COM 	pcishpc_write_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG, reg);
112310923SEvan.Yan@Sun.COM 
112410923SEvan.Yan@Sun.COM 	/* Unmask the interrupts for each slot. */
112510923SEvan.Yan@Sun.COM 	for (slot = 0; slot < ctrl_p->hc_num_slots_impl; slot++) {
112610923SEvan.Yan@Sun.COM 		reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot);
112710923SEvan.Yan@Sun.COM 		if ((reg & PCI_HP_SLOT_STATE_MASK) == PCI_HP_SLOT_ENABLED) {
112810923SEvan.Yan@Sun.COM 			reg &= ~(PCI_HP_SLOT_MASK_ALL |
112910923SEvan.Yan@Sun.COM 			    PCI_HP_SLOT_MRL_SERR_MASK);
113010923SEvan.Yan@Sun.COM 			ctrl_p->hc_num_slots_connected++;
113110923SEvan.Yan@Sun.COM 			if (ctrl_p->hc_curr_bus_speed == -1)
113210923SEvan.Yan@Sun.COM 				ctrl_p->hc_curr_bus_speed =
113310923SEvan.Yan@Sun.COM 				    pcishpc_read_reg(ctrl_p,
113410923SEvan.Yan@Sun.COM 				    PCI_HP_PROF_IF_SBCR_REG) &
113510923SEvan.Yan@Sun.COM 				    PCI_HP_SBCR_SPEED_MASK;
113610923SEvan.Yan@Sun.COM 		} else {
113710923SEvan.Yan@Sun.COM 			reg &= ~(PCI_HP_SLOT_MASK_ALL);
113810923SEvan.Yan@Sun.COM 		}
113910923SEvan.Yan@Sun.COM 
114010923SEvan.Yan@Sun.COM 		/* Enable/Unmask all slot interrupts. */
114110923SEvan.Yan@Sun.COM 		pcishpc_write_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot, reg);
114210923SEvan.Yan@Sun.COM 	}
114310923SEvan.Yan@Sun.COM 
114410923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_enable_irqs: ctrl_p 0x%p, "
114510923SEvan.Yan@Sun.COM 	    "current bus speed 0x%x, slots connected 0x%x\n", ctrl_p,
114610923SEvan.Yan@Sun.COM 	    ctrl_p->hc_curr_bus_speed, ctrl_p->hc_num_slots_connected);
114710923SEvan.Yan@Sun.COM 
114810923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
114910923SEvan.Yan@Sun.COM }
115010923SEvan.Yan@Sun.COM 
115110923SEvan.Yan@Sun.COM 
115210923SEvan.Yan@Sun.COM /*
115310923SEvan.Yan@Sun.COM  * pcishpc_disable_irqs()
115410923SEvan.Yan@Sun.COM  *
115510923SEvan.Yan@Sun.COM  * Disable/Mask the different IRQ's we support from the SHPC controller.
115610923SEvan.Yan@Sun.COM  */
1157*11445SEvan.Yan@Sun.COM int
pcishpc_disable_irqs(pcie_hp_ctrl_t * ctrl_p)115810923SEvan.Yan@Sun.COM pcishpc_disable_irqs(pcie_hp_ctrl_t *ctrl_p)
115910923SEvan.Yan@Sun.COM {
116010923SEvan.Yan@Sun.COM 	uint32_t reg;
116110923SEvan.Yan@Sun.COM 	int slot;
116210923SEvan.Yan@Sun.COM 
116310923SEvan.Yan@Sun.COM 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG);
116410923SEvan.Yan@Sun.COM 
116510923SEvan.Yan@Sun.COM 	/* Mask all interrupts. */
116610923SEvan.Yan@Sun.COM 	reg |= PCI_HP_SERR_INT_MASK_ALL;
116710923SEvan.Yan@Sun.COM 
116810923SEvan.Yan@Sun.COM 	pcishpc_write_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG, reg);
116910923SEvan.Yan@Sun.COM 
117010923SEvan.Yan@Sun.COM 	/* Unmask the interrupts for each slot. */
117110923SEvan.Yan@Sun.COM 	for (slot = 0; slot < ctrl_p->hc_num_slots_impl; slot++) {
117210923SEvan.Yan@Sun.COM 		reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot);
117310923SEvan.Yan@Sun.COM 
117410923SEvan.Yan@Sun.COM 		/* Disable/Mask all slot interrupts. */
117510923SEvan.Yan@Sun.COM 		reg |= PCI_HP_SLOT_MASK_ALL;
117610923SEvan.Yan@Sun.COM 
117710923SEvan.Yan@Sun.COM 		pcishpc_write_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot, reg);
117810923SEvan.Yan@Sun.COM 	}
117910923SEvan.Yan@Sun.COM 
118010923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_disable_irqs: ctrl_p 0x%p, "
118110923SEvan.Yan@Sun.COM 	    "current bus speed 0x%x, slots connected 0x%x\n", ctrl_p,
118210923SEvan.Yan@Sun.COM 	    ctrl_p->hc_curr_bus_speed, ctrl_p->hc_num_slots_connected);
118310923SEvan.Yan@Sun.COM 
118410923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
118510923SEvan.Yan@Sun.COM }
118610923SEvan.Yan@Sun.COM 
118710923SEvan.Yan@Sun.COM /*
118810923SEvan.Yan@Sun.COM  * pcishpc_slot_poweron()
118910923SEvan.Yan@Sun.COM  *
119010923SEvan.Yan@Sun.COM  * Poweron/Enable the slot.
119110923SEvan.Yan@Sun.COM  *
119210923SEvan.Yan@Sun.COM  * Note: This function is called by DDI HP framework at kernel context only
119310923SEvan.Yan@Sun.COM  */
119410923SEvan.Yan@Sun.COM /*ARGSUSED*/
119510923SEvan.Yan@Sun.COM static int
pcishpc_slot_poweron(pcie_hp_slot_t * slot_p,ddi_hp_cn_state_t * result_state)119610923SEvan.Yan@Sun.COM pcishpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result_state)
119710923SEvan.Yan@Sun.COM {
119810923SEvan.Yan@Sun.COM 	uint32_t	status;
119910923SEvan.Yan@Sun.COM 
120010923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_slot_poweron called()\n");
120110923SEvan.Yan@Sun.COM 
120210923SEvan.Yan@Sun.COM 	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
120310923SEvan.Yan@Sun.COM 
120410923SEvan.Yan@Sun.COM 	/* get the current slot state */
120510923SEvan.Yan@Sun.COM 	pcishpc_get_slot_state(slot_p);
120610923SEvan.Yan@Sun.COM 
120710923SEvan.Yan@Sun.COM 	/* check if the slot is already in the 'enabled' state */
120810923SEvan.Yan@Sun.COM 	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) {
120910923SEvan.Yan@Sun.COM 		/* slot is already in the 'enabled' state */
121010923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_slot_poweron() slot %d already enabled\n",
121110923SEvan.Yan@Sun.COM 		    slot_p->hs_phy_slot_num);
121210923SEvan.Yan@Sun.COM 
121310923SEvan.Yan@Sun.COM 		*result_state = slot_p->hs_info.cn_state;
121410923SEvan.Yan@Sun.COM 		return (DDI_SUCCESS);
121510923SEvan.Yan@Sun.COM 	}
121610923SEvan.Yan@Sun.COM 
121710923SEvan.Yan@Sun.COM 	if (slot_p->hs_info.cn_state == DDI_HP_CN_STATE_EMPTY) {
121810923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_slot_poweron() slot in empty state\n");
121910923SEvan.Yan@Sun.COM 		goto cleanup;
122010923SEvan.Yan@Sun.COM 	}
122110923SEvan.Yan@Sun.COM 
122210923SEvan.Yan@Sun.COM 	/* make sure the MRL sensor is closed */
122310923SEvan.Yan@Sun.COM 	status = pcishpc_read_reg(slot_p->hs_ctrl,
122410923SEvan.Yan@Sun.COM 	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
122510923SEvan.Yan@Sun.COM 
122610923SEvan.Yan@Sun.COM 	if (status & PCI_HP_SLOT_MRL_STATE_MASK) {
122710923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_slot_poweron() failed: MRL open\n");
122810923SEvan.Yan@Sun.COM 		goto cleanup;
122910923SEvan.Yan@Sun.COM 	}
123010923SEvan.Yan@Sun.COM 
123110923SEvan.Yan@Sun.COM 	/* Set the Power LED to blink */
123210923SEvan.Yan@Sun.COM 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
123310923SEvan.Yan@Sun.COM 
123410923SEvan.Yan@Sun.COM 	/* Turn all other LEDS off */
123510923SEvan.Yan@Sun.COM 	(void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF);
123610923SEvan.Yan@Sun.COM 	(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
123710923SEvan.Yan@Sun.COM 	(void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF);
123810923SEvan.Yan@Sun.COM 
123910923SEvan.Yan@Sun.COM 	/* Set the bus speed only if the bus segment is not running */
124010923SEvan.Yan@Sun.COM 	if (pcishpc_set_bus_speed(slot_p) != DDI_SUCCESS) {
124110923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_slot_poweron() setting speed failed\n");
124210923SEvan.Yan@Sun.COM 		goto cleanup;
124310923SEvan.Yan@Sun.COM 	}
124410923SEvan.Yan@Sun.COM 
124510923SEvan.Yan@Sun.COM 	slot_p->hs_ctrl->hc_num_slots_connected++;
124610923SEvan.Yan@Sun.COM 
124710923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_slot_poweron(): slot_p 0x%p, slot state 0x%x, "
124810923SEvan.Yan@Sun.COM 	    "current bus speed 0x%x, slots connected 0x%x\n", slot_p,
124910923SEvan.Yan@Sun.COM 	    slot_p->hs_info.cn_state, slot_p->hs_ctrl->hc_curr_bus_speed,
125010923SEvan.Yan@Sun.COM 	    slot_p->hs_ctrl->hc_num_slots_connected);
125110923SEvan.Yan@Sun.COM 
125210923SEvan.Yan@Sun.COM 	/* Mask or Unmask MRL Sensor SEER bit based on new slot state */
125310923SEvan.Yan@Sun.COM 	if (slot_p->hs_ctrl->hc_has_mrl == B_TRUE) {
125410923SEvan.Yan@Sun.COM 		uint32_t reg;
125510923SEvan.Yan@Sun.COM 
125610923SEvan.Yan@Sun.COM 		reg = pcishpc_read_reg(slot_p->hs_ctrl,
125710923SEvan.Yan@Sun.COM 		    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
125810923SEvan.Yan@Sun.COM 
125910923SEvan.Yan@Sun.COM 		pcishpc_write_reg(slot_p->hs_ctrl,
126010923SEvan.Yan@Sun.COM 		    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num,
126110923SEvan.Yan@Sun.COM 		    reg & ~PCI_HP_SLOT_MRL_SERR_MASK);
126210923SEvan.Yan@Sun.COM 	}
126310923SEvan.Yan@Sun.COM 
126410923SEvan.Yan@Sun.COM 	/* Update the hardware slot state. */
126510923SEvan.Yan@Sun.COM 	if (pcishpc_set_slot_state(slot_p,
126610923SEvan.Yan@Sun.COM 	    DDI_HP_CN_STATE_ENABLED) != DDI_SUCCESS) {
126710923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_slot_poweron() failed\n");
126810923SEvan.Yan@Sun.COM 
126910923SEvan.Yan@Sun.COM 		pcishpc_get_slot_state(slot_p);
127010923SEvan.Yan@Sun.COM 		goto cleanup;
127110923SEvan.Yan@Sun.COM 	}
127210923SEvan.Yan@Sun.COM 	/* Update the current state. It will be used in pcishpc_setled() */
127310923SEvan.Yan@Sun.COM 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_ENABLED;
127410923SEvan.Yan@Sun.COM 
127510923SEvan.Yan@Sun.COM 	/* Turn the Power LED ON for a enabled slot. */
127610923SEvan.Yan@Sun.COM 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_ON);
127710923SEvan.Yan@Sun.COM 
127810923SEvan.Yan@Sun.COM 	/* Turn all other LEDS off. */
127910923SEvan.Yan@Sun.COM 	(void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF);
128010923SEvan.Yan@Sun.COM 	(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
128110923SEvan.Yan@Sun.COM 	(void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF);
128210923SEvan.Yan@Sun.COM 
128310923SEvan.Yan@Sun.COM 	/* delay after powerON to let the device initialize itself */
128410923SEvan.Yan@Sun.COM 	delay(drv_usectohz(pcishpc_reset_delay));
128510923SEvan.Yan@Sun.COM 
128610923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_slot_poweron() success!\n");
128710923SEvan.Yan@Sun.COM 
128810923SEvan.Yan@Sun.COM 	/*
128910923SEvan.Yan@Sun.COM 	 * Want to show up as POWERED state for now. It will be updated to
129010923SEvan.Yan@Sun.COM 	 * ENABLED state when user explicitly enable the slot.
129110923SEvan.Yan@Sun.COM 	 */
129210923SEvan.Yan@Sun.COM 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_POWERED;
129310923SEvan.Yan@Sun.COM 
129410923SEvan.Yan@Sun.COM 	/* get the current slot state */
129510923SEvan.Yan@Sun.COM 	pcishpc_get_slot_state(slot_p);
129610923SEvan.Yan@Sun.COM 	/*
129710923SEvan.Yan@Sun.COM 	 * It should be poweron'ed now. Have a check here in case any
129810923SEvan.Yan@Sun.COM 	 * hardware problems.
129910923SEvan.Yan@Sun.COM 	 */
130010923SEvan.Yan@Sun.COM 	if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) {
130110923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_slot_poweron() failed after hardware"
130210923SEvan.Yan@Sun.COM 		    " registers all programmed.\n");
130310923SEvan.Yan@Sun.COM 
130410923SEvan.Yan@Sun.COM 		goto cleanup;
130510923SEvan.Yan@Sun.COM 	}
130610923SEvan.Yan@Sun.COM 
130710923SEvan.Yan@Sun.COM 	*result_state = slot_p->hs_info.cn_state;
130810923SEvan.Yan@Sun.COM 
130910923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
131010923SEvan.Yan@Sun.COM 
131110923SEvan.Yan@Sun.COM cleanup:
131210923SEvan.Yan@Sun.COM 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
131310923SEvan.Yan@Sun.COM 	return (DDI_FAILURE);
131410923SEvan.Yan@Sun.COM }
131510923SEvan.Yan@Sun.COM 
131610923SEvan.Yan@Sun.COM /*ARGSUSED*/
131710923SEvan.Yan@Sun.COM static int
pcishpc_slot_poweroff(pcie_hp_slot_t * slot_p,ddi_hp_cn_state_t * result_state)131810923SEvan.Yan@Sun.COM pcishpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result_state)
131910923SEvan.Yan@Sun.COM {
132010923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_slot_poweroff called()\n");
132110923SEvan.Yan@Sun.COM 
132210923SEvan.Yan@Sun.COM 	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
132310923SEvan.Yan@Sun.COM 
132410923SEvan.Yan@Sun.COM 	/* get the current slot state */
132510923SEvan.Yan@Sun.COM 	pcishpc_get_slot_state(slot_p);
132610923SEvan.Yan@Sun.COM 
132710923SEvan.Yan@Sun.COM 	/* check if the slot is not in the "enabled" or "powered" state */
132810923SEvan.Yan@Sun.COM 	if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) {
132910923SEvan.Yan@Sun.COM 		/* slot is in the 'disabled' state */
133010923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_slot_poweroff(): "
133110923SEvan.Yan@Sun.COM 		    "slot %d already disabled\n", slot_p->hs_phy_slot_num);
133210923SEvan.Yan@Sun.COM 
133310923SEvan.Yan@Sun.COM 		*result_state = slot_p->hs_info.cn_state;
133410923SEvan.Yan@Sun.COM 		return (DDI_SUCCESS);
133510923SEvan.Yan@Sun.COM 	}
133610923SEvan.Yan@Sun.COM 
133710923SEvan.Yan@Sun.COM 	/* Set the Power LED to blink */
133810923SEvan.Yan@Sun.COM 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
133910923SEvan.Yan@Sun.COM 
134010923SEvan.Yan@Sun.COM 	/* Turn all other LEDS off */
134110923SEvan.Yan@Sun.COM 	(void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF);
134210923SEvan.Yan@Sun.COM 	(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
134310923SEvan.Yan@Sun.COM 	(void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF);
134410923SEvan.Yan@Sun.COM 
134510923SEvan.Yan@Sun.COM 	if (--slot_p->hs_ctrl->hc_num_slots_connected == 0)
134610923SEvan.Yan@Sun.COM 		slot_p->hs_ctrl->hc_curr_bus_speed = -1;
134710923SEvan.Yan@Sun.COM 
134810923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_slot_poweroff(): slot_p 0x%p, slot state 0x%x, "
134910923SEvan.Yan@Sun.COM 	    "current bus speed 0x%x, slots connected 0x%x\n", slot_p,
135010923SEvan.Yan@Sun.COM 	    slot_p->hs_info.cn_state, slot_p->hs_ctrl->hc_curr_bus_speed,
135110923SEvan.Yan@Sun.COM 	    slot_p->hs_ctrl->hc_num_slots_connected);
135210923SEvan.Yan@Sun.COM 
135310923SEvan.Yan@Sun.COM 	/* Mask or Unmask MRL Sensor SEER bit based on new slot state */
135410923SEvan.Yan@Sun.COM 	if (slot_p->hs_ctrl->hc_has_mrl == B_TRUE) {
135510923SEvan.Yan@Sun.COM 		uint32_t reg;
135610923SEvan.Yan@Sun.COM 
135710923SEvan.Yan@Sun.COM 		reg = pcishpc_read_reg(slot_p->hs_ctrl,
135810923SEvan.Yan@Sun.COM 		    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
135910923SEvan.Yan@Sun.COM 
136010923SEvan.Yan@Sun.COM 		pcishpc_write_reg(slot_p->hs_ctrl,
136110923SEvan.Yan@Sun.COM 		    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num,
136210923SEvan.Yan@Sun.COM 		    reg | PCI_HP_SLOT_MRL_SERR_MASK);
136310923SEvan.Yan@Sun.COM 	}
136410923SEvan.Yan@Sun.COM 
136510923SEvan.Yan@Sun.COM 	/* Update the hardware slot state. */
136610923SEvan.Yan@Sun.COM 	if (pcishpc_set_slot_state(slot_p, DDI_HP_CN_STATE_PRESENT) !=
136710923SEvan.Yan@Sun.COM 	    DDI_SUCCESS) {
136810923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_slot_poweroff() failed\n");
136910923SEvan.Yan@Sun.COM 
137010923SEvan.Yan@Sun.COM 		pcishpc_get_slot_state(slot_p);
137110923SEvan.Yan@Sun.COM 		goto cleanup;
137210923SEvan.Yan@Sun.COM 	}
137310923SEvan.Yan@Sun.COM 
137410923SEvan.Yan@Sun.COM 	/* Update the current state. It will be used in pcishpc_setled() */
137510923SEvan.Yan@Sun.COM 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_PRESENT;
137610923SEvan.Yan@Sun.COM 
137710923SEvan.Yan@Sun.COM 	/* Turn the Power LED OFF for a disabled slot. */
137810923SEvan.Yan@Sun.COM 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
137910923SEvan.Yan@Sun.COM 
138010923SEvan.Yan@Sun.COM 	/* Turn all other LEDS off. */
138110923SEvan.Yan@Sun.COM 	(void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF);
138210923SEvan.Yan@Sun.COM 	(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
138310923SEvan.Yan@Sun.COM 	(void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF);
138410923SEvan.Yan@Sun.COM 
138510923SEvan.Yan@Sun.COM 	/* delay after powerON to let the device initialize itself */
138610923SEvan.Yan@Sun.COM 	delay(drv_usectohz(pcishpc_reset_delay));
138710923SEvan.Yan@Sun.COM 
138810923SEvan.Yan@Sun.COM 	pcishpc_get_slot_state(slot_p);
138910923SEvan.Yan@Sun.COM 	/*
139010923SEvan.Yan@Sun.COM 	 * It should be poweroff'ed now. Have a check here in case any
139110923SEvan.Yan@Sun.COM 	 * hardware problems.
139210923SEvan.Yan@Sun.COM 	 */
139310923SEvan.Yan@Sun.COM 	if (slot_p->hs_info.cn_state > DDI_HP_CN_STATE_PRESENT) {
139410923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_slot_poweroff() failed after hardware"
139510923SEvan.Yan@Sun.COM 		    " registers all programmed.\n");
139610923SEvan.Yan@Sun.COM 
139710923SEvan.Yan@Sun.COM 		goto cleanup;
139810923SEvan.Yan@Sun.COM 	}
139910923SEvan.Yan@Sun.COM 
140010923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_slot_poweroff() success!\n");
140110923SEvan.Yan@Sun.COM 
140210923SEvan.Yan@Sun.COM 	*result_state = slot_p->hs_info.cn_state;
140310923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
140410923SEvan.Yan@Sun.COM 
140510923SEvan.Yan@Sun.COM cleanup:
140610923SEvan.Yan@Sun.COM 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
140710923SEvan.Yan@Sun.COM 	return (DDI_FAILURE);
140810923SEvan.Yan@Sun.COM }
140910923SEvan.Yan@Sun.COM 
141010923SEvan.Yan@Sun.COM /*
141110923SEvan.Yan@Sun.COM  * pcishpc_slot_probe()
141210923SEvan.Yan@Sun.COM  *
141310923SEvan.Yan@Sun.COM  * Probe the slot.
141410923SEvan.Yan@Sun.COM  *
141510923SEvan.Yan@Sun.COM  * Note: This function is called by DDI HP framework at kernel context only
141610923SEvan.Yan@Sun.COM  */
141710923SEvan.Yan@Sun.COM /*ARGSUSED*/
141810923SEvan.Yan@Sun.COM static int
pcishpc_slot_probe(pcie_hp_slot_t * slot_p)141910923SEvan.Yan@Sun.COM pcishpc_slot_probe(pcie_hp_slot_t *slot_p)
142010923SEvan.Yan@Sun.COM {
142110923SEvan.Yan@Sun.COM 	mutex_enter(&slot_p->hs_ctrl->hc_mutex);
142210923SEvan.Yan@Sun.COM 
142310923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_slot_probe called()\n");
142410923SEvan.Yan@Sun.COM 
142510923SEvan.Yan@Sun.COM 	/* get the current slot state */
142610923SEvan.Yan@Sun.COM 	pcishpc_get_slot_state(slot_p);
142710923SEvan.Yan@Sun.COM 
142810923SEvan.Yan@Sun.COM 	/*
142910923SEvan.Yan@Sun.COM 	 * Probe a given PCI Hotplug Connection (CN).
143010923SEvan.Yan@Sun.COM 	 */
143110923SEvan.Yan@Sun.COM 	if (pcie_hp_probe(slot_p) != DDI_SUCCESS) {
143210923SEvan.Yan@Sun.COM 		(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED,
143310923SEvan.Yan@Sun.COM 		    PCIE_HP_LED_BLINK);
143410923SEvan.Yan@Sun.COM 
143510923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_slot_probe() failed\n");
143610923SEvan.Yan@Sun.COM 
143710923SEvan.Yan@Sun.COM 		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
143810923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
143910923SEvan.Yan@Sun.COM 	}
144010923SEvan.Yan@Sun.COM 
144110923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_slot_probe() success!\n");
144210923SEvan.Yan@Sun.COM 
144310923SEvan.Yan@Sun.COM 	/* get the current slot state */
144410923SEvan.Yan@Sun.COM 	pcishpc_get_slot_state(slot_p);
144510923SEvan.Yan@Sun.COM 
144610923SEvan.Yan@Sun.COM 	mutex_exit(&slot_p->hs_ctrl->hc_mutex);
144710923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
144810923SEvan.Yan@Sun.COM }
144910923SEvan.Yan@Sun.COM 
145010923SEvan.Yan@Sun.COM /*
145110923SEvan.Yan@Sun.COM  * pcishpc_slot_unprobe()
145210923SEvan.Yan@Sun.COM  *
145310923SEvan.Yan@Sun.COM  * Unprobe the slot.
145410923SEvan.Yan@Sun.COM  *
145510923SEvan.Yan@Sun.COM  * Note: This function is called by DDI HP framework at kernel context only
145610923SEvan.Yan@Sun.COM  */
145710923SEvan.Yan@Sun.COM /*ARGSUSED*/
145810923SEvan.Yan@Sun.COM static int
pcishpc_slot_unprobe(pcie_hp_slot_t * slot_p)145910923SEvan.Yan@Sun.COM pcishpc_slot_unprobe(pcie_hp_slot_t *slot_p)
146010923SEvan.Yan@Sun.COM {
146110923SEvan.Yan@Sun.COM 	mutex_enter(&slot_p->hs_ctrl->hc_mutex);
146210923SEvan.Yan@Sun.COM 
146310923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_slot_unprobe called()\n");
146410923SEvan.Yan@Sun.COM 
146510923SEvan.Yan@Sun.COM 	/* get the current slot state */
146610923SEvan.Yan@Sun.COM 	pcishpc_get_slot_state(slot_p);
146710923SEvan.Yan@Sun.COM 
146810923SEvan.Yan@Sun.COM 	/*
146910923SEvan.Yan@Sun.COM 	 * Unprobe a given PCI Hotplug Connection (CN).
147010923SEvan.Yan@Sun.COM 	 */
147110923SEvan.Yan@Sun.COM 	if (pcie_hp_unprobe(slot_p) != DDI_SUCCESS) {
147210923SEvan.Yan@Sun.COM 		(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED,
147310923SEvan.Yan@Sun.COM 		    PCIE_HP_LED_BLINK);
147410923SEvan.Yan@Sun.COM 
147510923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_slot_unprobe() failed\n");
147610923SEvan.Yan@Sun.COM 
147710923SEvan.Yan@Sun.COM 		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
147810923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
147910923SEvan.Yan@Sun.COM 	}
148010923SEvan.Yan@Sun.COM 
148110923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_slot_unprobe() success!\n");
148210923SEvan.Yan@Sun.COM 
148310923SEvan.Yan@Sun.COM 	/* get the current slot state */
148410923SEvan.Yan@Sun.COM 	pcishpc_get_slot_state(slot_p);
148510923SEvan.Yan@Sun.COM 
148610923SEvan.Yan@Sun.COM 	mutex_exit(&slot_p->hs_ctrl->hc_mutex);
148710923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
148810923SEvan.Yan@Sun.COM }
148910923SEvan.Yan@Sun.COM 
149010923SEvan.Yan@Sun.COM static int
pcishpc_upgrade_slot_state(pcie_hp_slot_t * slot_p,ddi_hp_cn_state_t target_state)149110923SEvan.Yan@Sun.COM pcishpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
149210923SEvan.Yan@Sun.COM     ddi_hp_cn_state_t target_state)
149310923SEvan.Yan@Sun.COM {
149410923SEvan.Yan@Sun.COM 	ddi_hp_cn_state_t curr_state;
149510923SEvan.Yan@Sun.COM 	int rv = DDI_SUCCESS;
149610923SEvan.Yan@Sun.COM 
149710923SEvan.Yan@Sun.COM 	if (target_state > DDI_HP_CN_STATE_ENABLED) {
149810923SEvan.Yan@Sun.COM 		return (DDI_EINVAL);
149910923SEvan.Yan@Sun.COM 	}
150010923SEvan.Yan@Sun.COM 
150110923SEvan.Yan@Sun.COM 	curr_state = slot_p->hs_info.cn_state;
150210923SEvan.Yan@Sun.COM 	while ((curr_state < target_state) && (rv == DDI_SUCCESS)) {
150310923SEvan.Yan@Sun.COM 
150410923SEvan.Yan@Sun.COM 		switch (curr_state) {
150510923SEvan.Yan@Sun.COM 		case DDI_HP_CN_STATE_EMPTY:
150610923SEvan.Yan@Sun.COM 			/*
150710923SEvan.Yan@Sun.COM 			 * From EMPTY to PRESENT, just check the hardware
150810923SEvan.Yan@Sun.COM 			 * slot state.
150910923SEvan.Yan@Sun.COM 			 */
151010923SEvan.Yan@Sun.COM 			pcishpc_get_slot_state(slot_p);
151110923SEvan.Yan@Sun.COM 			curr_state = slot_p->hs_info.cn_state;
151210923SEvan.Yan@Sun.COM 			if (curr_state < DDI_HP_CN_STATE_PRESENT)
151310923SEvan.Yan@Sun.COM 				rv = DDI_FAILURE;
151410923SEvan.Yan@Sun.COM 			break;
151510923SEvan.Yan@Sun.COM 		case DDI_HP_CN_STATE_PRESENT:
151610923SEvan.Yan@Sun.COM 			rv = pcishpc_slot_poweron(slot_p, &curr_state);
151710923SEvan.Yan@Sun.COM 			break;
151810923SEvan.Yan@Sun.COM 		case DDI_HP_CN_STATE_POWERED:
151910923SEvan.Yan@Sun.COM 			curr_state = slot_p->hs_info.cn_state =
152010923SEvan.Yan@Sun.COM 			    DDI_HP_CN_STATE_ENABLED;
152110923SEvan.Yan@Sun.COM 			break;
152210923SEvan.Yan@Sun.COM 		default:
152310923SEvan.Yan@Sun.COM 			/* should never reach here */
152410923SEvan.Yan@Sun.COM 			ASSERT("unknown devinfo state");
152510923SEvan.Yan@Sun.COM 		}
152610923SEvan.Yan@Sun.COM 	}
152710923SEvan.Yan@Sun.COM 
152810923SEvan.Yan@Sun.COM 	return (rv);
152910923SEvan.Yan@Sun.COM }
153010923SEvan.Yan@Sun.COM 
153110923SEvan.Yan@Sun.COM static int
pcishpc_downgrade_slot_state(pcie_hp_slot_t * slot_p,ddi_hp_cn_state_t target_state)153210923SEvan.Yan@Sun.COM pcishpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
153310923SEvan.Yan@Sun.COM     ddi_hp_cn_state_t target_state)
153410923SEvan.Yan@Sun.COM {
153510923SEvan.Yan@Sun.COM 	ddi_hp_cn_state_t curr_state;
153610923SEvan.Yan@Sun.COM 	int rv = DDI_SUCCESS;
153710923SEvan.Yan@Sun.COM 
153810923SEvan.Yan@Sun.COM 
153910923SEvan.Yan@Sun.COM 	curr_state = slot_p->hs_info.cn_state;
154010923SEvan.Yan@Sun.COM 	while ((curr_state > target_state) && (rv == DDI_SUCCESS)) {
154110923SEvan.Yan@Sun.COM 
154210923SEvan.Yan@Sun.COM 		switch (curr_state) {
154310923SEvan.Yan@Sun.COM 		case DDI_HP_CN_STATE_PRESENT:
154410923SEvan.Yan@Sun.COM 			/*
154510923SEvan.Yan@Sun.COM 			 * From PRESENT to EMPTY, just check hardware
154610923SEvan.Yan@Sun.COM 			 * slot state.
154710923SEvan.Yan@Sun.COM 			 */
154810923SEvan.Yan@Sun.COM 			pcishpc_get_slot_state(slot_p);
154910923SEvan.Yan@Sun.COM 			curr_state = slot_p->hs_info.cn_state;
155010923SEvan.Yan@Sun.COM 			if (curr_state >= DDI_HP_CN_STATE_PRESENT)
155110923SEvan.Yan@Sun.COM 				rv = DDI_FAILURE;
155210923SEvan.Yan@Sun.COM 			break;
155310923SEvan.Yan@Sun.COM 		case DDI_HP_CN_STATE_POWERED:
155410923SEvan.Yan@Sun.COM 			rv = pcishpc_slot_poweroff(slot_p, &curr_state);
155510923SEvan.Yan@Sun.COM 
155610923SEvan.Yan@Sun.COM 			break;
155710923SEvan.Yan@Sun.COM 		case DDI_HP_CN_STATE_ENABLED:
155810923SEvan.Yan@Sun.COM 			curr_state = slot_p->hs_info.cn_state =
155910923SEvan.Yan@Sun.COM 			    DDI_HP_CN_STATE_POWERED;
156010923SEvan.Yan@Sun.COM 
156110923SEvan.Yan@Sun.COM 			break;
156210923SEvan.Yan@Sun.COM 		default:
156310923SEvan.Yan@Sun.COM 			/* should never reach here */
156410923SEvan.Yan@Sun.COM 			ASSERT("unknown devinfo state");
156510923SEvan.Yan@Sun.COM 		}
156610923SEvan.Yan@Sun.COM 	}
156710923SEvan.Yan@Sun.COM 
156810923SEvan.Yan@Sun.COM 	return (rv);
156910923SEvan.Yan@Sun.COM }
157010923SEvan.Yan@Sun.COM 
157110923SEvan.Yan@Sun.COM /* Change slot state to a target state */
157210923SEvan.Yan@Sun.COM static int
pcishpc_change_slot_state(pcie_hp_slot_t * slot_p,ddi_hp_cn_state_t target_state)157310923SEvan.Yan@Sun.COM pcishpc_change_slot_state(pcie_hp_slot_t *slot_p,
157410923SEvan.Yan@Sun.COM     ddi_hp_cn_state_t target_state)
157510923SEvan.Yan@Sun.COM {
157610923SEvan.Yan@Sun.COM 	ddi_hp_cn_state_t curr_state;
157710923SEvan.Yan@Sun.COM 	int rv;
157810923SEvan.Yan@Sun.COM 
157910923SEvan.Yan@Sun.COM 	pcishpc_get_slot_state(slot_p);
158010923SEvan.Yan@Sun.COM 	curr_state = slot_p->hs_info.cn_state;
158110923SEvan.Yan@Sun.COM 
158210923SEvan.Yan@Sun.COM 	if (curr_state == target_state) {
158310923SEvan.Yan@Sun.COM 		return (DDI_SUCCESS);
158410923SEvan.Yan@Sun.COM 	}
158510923SEvan.Yan@Sun.COM 	if (curr_state < target_state) {
158610923SEvan.Yan@Sun.COM 
158710923SEvan.Yan@Sun.COM 		rv = pcishpc_upgrade_slot_state(slot_p, target_state);
158810923SEvan.Yan@Sun.COM 	} else {
158910923SEvan.Yan@Sun.COM 		rv = pcishpc_downgrade_slot_state(slot_p, target_state);
159010923SEvan.Yan@Sun.COM 	}
159110923SEvan.Yan@Sun.COM 
159210923SEvan.Yan@Sun.COM 	return (rv);
159310923SEvan.Yan@Sun.COM }
159410923SEvan.Yan@Sun.COM 
159510923SEvan.Yan@Sun.COM /*
159610923SEvan.Yan@Sun.COM  * pcishpc_issue_command()
159710923SEvan.Yan@Sun.COM  *
159810923SEvan.Yan@Sun.COM  * Sends a command to the SHPC controller.
159910923SEvan.Yan@Sun.COM  */
160010923SEvan.Yan@Sun.COM static int
pcishpc_issue_command(pcie_hp_ctrl_t * ctrl_p,uint32_t cmd_code)160110923SEvan.Yan@Sun.COM pcishpc_issue_command(pcie_hp_ctrl_t *ctrl_p, uint32_t cmd_code)
160210923SEvan.Yan@Sun.COM {
160310923SEvan.Yan@Sun.COM 	int	retCode;
160410923SEvan.Yan@Sun.COM 
160510923SEvan.Yan@Sun.COM 	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
160610923SEvan.Yan@Sun.COM 
160710923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_issue_command() cmd_code=%02x\n", cmd_code);
160810923SEvan.Yan@Sun.COM 
160910923SEvan.Yan@Sun.COM 	ctrl_p->hc_cmd_pending = B_TRUE;
161010923SEvan.Yan@Sun.COM 
161110923SEvan.Yan@Sun.COM 	/* Write the command to the SHPC controller. */
161210923SEvan.Yan@Sun.COM 	pcishpc_write_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG, cmd_code);
161310923SEvan.Yan@Sun.COM 
161410923SEvan.Yan@Sun.COM 	while (ctrl_p->hc_cmd_pending == B_TRUE)
161510923SEvan.Yan@Sun.COM 		cv_wait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex);
161610923SEvan.Yan@Sun.COM 
161710923SEvan.Yan@Sun.COM 	/* Wait until the SHPC controller processes the command. */
161810923SEvan.Yan@Sun.COM 	retCode = pcishpc_wait_busy(ctrl_p);
161910923SEvan.Yan@Sun.COM 
162010923SEvan.Yan@Sun.COM 	/* Make sure the command completed. */
162110923SEvan.Yan@Sun.COM 	if (retCode == DDI_SUCCESS) {
162210923SEvan.Yan@Sun.COM 		/* Did the command fail to generate the command complete IRQ? */
162310923SEvan.Yan@Sun.COM 		if (ctrl_p->hc_cmd_pending != B_FALSE) {
162410923SEvan.Yan@Sun.COM 			PCIE_DBG("pcishpc_issue_command() Failed on "
162510923SEvan.Yan@Sun.COM 			    "generate cmd complete IRQ\n");
162610923SEvan.Yan@Sun.COM 			retCode = DDI_FAILURE;
162710923SEvan.Yan@Sun.COM 		}
162810923SEvan.Yan@Sun.COM 	}
162910923SEvan.Yan@Sun.COM 
163010923SEvan.Yan@Sun.COM 	if (retCode == DDI_FAILURE)
163110923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_issue_command() Failed on cmd_code=%02x\n",
163210923SEvan.Yan@Sun.COM 		    cmd_code);
163310923SEvan.Yan@Sun.COM 	else
163410923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_issue_command() Success on "
163510923SEvan.Yan@Sun.COM 		    "cmd_code=%02x\n", cmd_code);
163610923SEvan.Yan@Sun.COM 
163710923SEvan.Yan@Sun.COM 	return (retCode);
163810923SEvan.Yan@Sun.COM }
163910923SEvan.Yan@Sun.COM 
164010923SEvan.Yan@Sun.COM /*
164110923SEvan.Yan@Sun.COM  * pcishpc_wait_busy()
164210923SEvan.Yan@Sun.COM  *
164310923SEvan.Yan@Sun.COM  * Wait until the SHPC controller is not busy.
164410923SEvan.Yan@Sun.COM  */
164510923SEvan.Yan@Sun.COM static int
pcishpc_wait_busy(pcie_hp_ctrl_t * ctrl_p)164610923SEvan.Yan@Sun.COM pcishpc_wait_busy(pcie_hp_ctrl_t *ctrl_p)
164710923SEvan.Yan@Sun.COM {
164810923SEvan.Yan@Sun.COM 	uint32_t	status;
164910923SEvan.Yan@Sun.COM 
165010923SEvan.Yan@Sun.COM 	/* Wait until SHPC controller is NOT busy */
165110923SEvan.Yan@Sun.COM 	for (;;) {
165210923SEvan.Yan@Sun.COM 		status = pcishpc_read_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG);
165310923SEvan.Yan@Sun.COM 
165410923SEvan.Yan@Sun.COM 		/* Is there an MRL Sensor error? */
165510923SEvan.Yan@Sun.COM 		if ((status & PCI_HP_COMM_STS_ERR_MASK) ==
165610923SEvan.Yan@Sun.COM 		    PCI_HP_COMM_STS_ERR_MRL_OPEN) {
165710923SEvan.Yan@Sun.COM 			PCIE_DBG("pcishpc_wait_busy() ERROR: "
165810923SEvan.Yan@Sun.COM 			    "MRL Sensor error\n");
165910923SEvan.Yan@Sun.COM 			break;
166010923SEvan.Yan@Sun.COM 		}
166110923SEvan.Yan@Sun.COM 
166210923SEvan.Yan@Sun.COM 		/* Is there an Invalid command error? */
166310923SEvan.Yan@Sun.COM 		if ((status & PCI_HP_COMM_STS_ERR_MASK) ==
166410923SEvan.Yan@Sun.COM 		    PCI_HP_COMM_STS_ERR_INVALID_COMMAND) {
166510923SEvan.Yan@Sun.COM 			PCIE_DBG("pcishpc_wait_busy() ERROR: Invalid "
166610923SEvan.Yan@Sun.COM 			    "command error\n");
166710923SEvan.Yan@Sun.COM 			break;
166810923SEvan.Yan@Sun.COM 		}
166910923SEvan.Yan@Sun.COM 
167010923SEvan.Yan@Sun.COM 		/* Is there an Invalid Speed/Mode error? */
167110923SEvan.Yan@Sun.COM 		if ((status & PCI_HP_COMM_STS_ERR_MASK) ==
167210923SEvan.Yan@Sun.COM 		    PCI_HP_COMM_STS_ERR_INVALID_SPEED) {
167310923SEvan.Yan@Sun.COM 			PCIE_DBG("pcishpc_wait_busy() ERROR: Invalid "
167410923SEvan.Yan@Sun.COM 			    "Speed/Mode error\n");
167510923SEvan.Yan@Sun.COM 			break;
167610923SEvan.Yan@Sun.COM 		}
167710923SEvan.Yan@Sun.COM 
167810923SEvan.Yan@Sun.COM 		/* Is the SHPC controller not BUSY? */
167910923SEvan.Yan@Sun.COM 		if (!(status & PCI_HP_COMM_STS_CTRL_BUSY)) {
168010923SEvan.Yan@Sun.COM 			/* Return Success. */
168110923SEvan.Yan@Sun.COM 			return (DDI_SUCCESS);
168210923SEvan.Yan@Sun.COM 		}
168310923SEvan.Yan@Sun.COM 
168410923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_wait_busy() SHPC controller busy. Waiting\n");
168510923SEvan.Yan@Sun.COM 
168610923SEvan.Yan@Sun.COM 		/* Wait before polling the status register again. */
168710923SEvan.Yan@Sun.COM 		delay(drv_usectohz(PCIE_HP_CMD_WAIT_TIME));
168810923SEvan.Yan@Sun.COM 	}
168910923SEvan.Yan@Sun.COM 
169010923SEvan.Yan@Sun.COM 	return (DDI_FAILURE);
169110923SEvan.Yan@Sun.COM }
169210923SEvan.Yan@Sun.COM 
169310923SEvan.Yan@Sun.COM static void
pcishpc_attn_btn_handler(pcie_hp_slot_t * slot_p)169410923SEvan.Yan@Sun.COM pcishpc_attn_btn_handler(pcie_hp_slot_t *slot_p)
169510923SEvan.Yan@Sun.COM {
169610923SEvan.Yan@Sun.COM 	pcie_hp_led_state_t hs_power_led_state;
169710923SEvan.Yan@Sun.COM 	callb_cpr_t cprinfo;
169810923SEvan.Yan@Sun.COM 
169910923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_attn_btn_handler: thread started\n");
170010923SEvan.Yan@Sun.COM 
170110923SEvan.Yan@Sun.COM 	CALLB_CPR_INIT(&cprinfo, &slot_p->hs_ctrl->hc_mutex,
170210923SEvan.Yan@Sun.COM 	    callb_generic_cpr, "pcishpc_attn_btn_handler");
170310923SEvan.Yan@Sun.COM 
170410923SEvan.Yan@Sun.COM 	mutex_enter(&slot_p->hs_ctrl->hc_mutex);
170510923SEvan.Yan@Sun.COM 
170610923SEvan.Yan@Sun.COM 	/* wait for ATTN button event */
170710923SEvan.Yan@Sun.COM 	cv_wait(&slot_p->hs_attn_btn_cv, &slot_p->hs_ctrl->hc_mutex);
170810923SEvan.Yan@Sun.COM 
170910923SEvan.Yan@Sun.COM 	while (slot_p->hs_attn_btn_thread_exit == B_FALSE) {
171010923SEvan.Yan@Sun.COM 		if (slot_p->hs_attn_btn_pending == B_TRUE) {
171110923SEvan.Yan@Sun.COM 			/* get the current state of power LED */
171210923SEvan.Yan@Sun.COM 			hs_power_led_state = slot_p->hs_power_led_state;
171310923SEvan.Yan@Sun.COM 
171410923SEvan.Yan@Sun.COM 			/* Blink the Power LED while we wait for 5 seconds */
171510923SEvan.Yan@Sun.COM 			(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED,
171610923SEvan.Yan@Sun.COM 			    PCIE_HP_LED_BLINK);
171710923SEvan.Yan@Sun.COM 
171810923SEvan.Yan@Sun.COM 			/* wait for 5 seconds before taking any action */
171911066Srafael.vanoni@sun.com 			if (cv_reltimedwait(&slot_p->hs_attn_btn_cv,
172010923SEvan.Yan@Sun.COM 			    &slot_p->hs_ctrl->hc_mutex,
172111066Srafael.vanoni@sun.com 			    SEC_TO_TICK(5), TR_CLOCK_TICK) == -1) {
172210923SEvan.Yan@Sun.COM 				/*
172310923SEvan.Yan@Sun.COM 				 * It is a time out;
172410923SEvan.Yan@Sun.COM 				 * make sure the ATTN pending flag is
172510923SEvan.Yan@Sun.COM 				 * still ON before sending the event
172610923SEvan.Yan@Sun.COM 				 * to DDI HP framework.
172710923SEvan.Yan@Sun.COM 				 */
172810923SEvan.Yan@Sun.COM 				if (slot_p->hs_attn_btn_pending == B_TRUE) {
172910923SEvan.Yan@Sun.COM 					int hint;
173010923SEvan.Yan@Sun.COM 
173110923SEvan.Yan@Sun.COM 					/* restore the power LED state */
173210923SEvan.Yan@Sun.COM 					(void) pcishpc_setled(slot_p,
173310923SEvan.Yan@Sun.COM 					    PCIE_HP_POWER_LED,
173410923SEvan.Yan@Sun.COM 					    hs_power_led_state);
173510923SEvan.Yan@Sun.COM 					/*
173610923SEvan.Yan@Sun.COM 					 * send the ATTN button event
173710923SEvan.Yan@Sun.COM 					 * to DDI HP framework
173810923SEvan.Yan@Sun.COM 					 */
173910923SEvan.Yan@Sun.COM 					slot_p->hs_attn_btn_pending = B_FALSE;
174010923SEvan.Yan@Sun.COM 
174110923SEvan.Yan@Sun.COM 					pcishpc_get_slot_state(slot_p);
174210923SEvan.Yan@Sun.COM 
174310923SEvan.Yan@Sun.COM 					if (slot_p->hs_info.cn_state <=
174410923SEvan.Yan@Sun.COM 					    DDI_HP_CN_STATE_PRESENT) {
174510923SEvan.Yan@Sun.COM 						/*
174610923SEvan.Yan@Sun.COM 						 * Insertion.
174710923SEvan.Yan@Sun.COM 						 */
174810923SEvan.Yan@Sun.COM 						hint = SE_INCOMING_RES;
174910923SEvan.Yan@Sun.COM 					} else {
175010923SEvan.Yan@Sun.COM 						/*
175110923SEvan.Yan@Sun.COM 						 * Want to remove;
175210923SEvan.Yan@Sun.COM 						 */
175310923SEvan.Yan@Sun.COM 						hint = SE_OUTGOING_RES;
175410923SEvan.Yan@Sun.COM 					}
175510923SEvan.Yan@Sun.COM 					pcie_hp_gen_sysevent_req(
175610923SEvan.Yan@Sun.COM 					    slot_p->hs_info.cn_name,
175710923SEvan.Yan@Sun.COM 					    hint,
175810923SEvan.Yan@Sun.COM 					    slot_p->hs_ctrl->hc_dip,
175910923SEvan.Yan@Sun.COM 					    KM_SLEEP);
176010923SEvan.Yan@Sun.COM 
176110923SEvan.Yan@Sun.COM 					continue;
176210923SEvan.Yan@Sun.COM 				}
176310923SEvan.Yan@Sun.COM 			}
176410923SEvan.Yan@Sun.COM 
176510923SEvan.Yan@Sun.COM 			/* restore the power LED state */
176610923SEvan.Yan@Sun.COM 			(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED,
176710923SEvan.Yan@Sun.COM 			    hs_power_led_state);
176810923SEvan.Yan@Sun.COM 			continue;
176910923SEvan.Yan@Sun.COM 		}
177010923SEvan.Yan@Sun.COM 
177110923SEvan.Yan@Sun.COM 		/* wait for another ATTN button event */
177210923SEvan.Yan@Sun.COM 		cv_wait(&slot_p->hs_attn_btn_cv, &slot_p->hs_ctrl->hc_mutex);
177310923SEvan.Yan@Sun.COM 	}
177410923SEvan.Yan@Sun.COM 
177510923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_attn_btn_handler: thread exit\n");
177610923SEvan.Yan@Sun.COM 	cv_signal(&slot_p->hs_attn_btn_cv);
177710923SEvan.Yan@Sun.COM 	CALLB_CPR_EXIT(&cprinfo);
177810923SEvan.Yan@Sun.COM 	thread_exit();
177910923SEvan.Yan@Sun.COM }
178010923SEvan.Yan@Sun.COM 
178110923SEvan.Yan@Sun.COM /*
178210923SEvan.Yan@Sun.COM  * pcishpc_get_slot_state()
178310923SEvan.Yan@Sun.COM  *
178410923SEvan.Yan@Sun.COM  * Get the state of the slot.
178510923SEvan.Yan@Sun.COM  * The slot state should have been initialized before this function gets called.
178610923SEvan.Yan@Sun.COM  */
178710923SEvan.Yan@Sun.COM static void
pcishpc_get_slot_state(pcie_hp_slot_t * slot_p)178810923SEvan.Yan@Sun.COM pcishpc_get_slot_state(pcie_hp_slot_t *slot_p)
178910923SEvan.Yan@Sun.COM {
179010923SEvan.Yan@Sun.COM 	uint32_t reg;
179110923SEvan.Yan@Sun.COM 	ddi_hp_cn_state_t curr_state = slot_p->hs_info.cn_state;
179210923SEvan.Yan@Sun.COM 
179310923SEvan.Yan@Sun.COM 	/* Read the logical slot register for this Slot. */
179410923SEvan.Yan@Sun.COM 	reg = pcishpc_read_reg(slot_p->hs_ctrl,
179510923SEvan.Yan@Sun.COM 	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
179610923SEvan.Yan@Sun.COM 
179710923SEvan.Yan@Sun.COM 	/* Convert from the SHPC slot state to the HPC slot state. */
179810923SEvan.Yan@Sun.COM 	slot_p->hs_info.cn_state = pcishpc_slot_shpc_to_hpc(reg);
179910923SEvan.Yan@Sun.COM 	if (curr_state == DDI_HP_CN_STATE_POWERED &&
180010923SEvan.Yan@Sun.COM 	    slot_p->hs_info.cn_state > DDI_HP_CN_STATE_POWERED) {
180110923SEvan.Yan@Sun.COM 		/*
180210923SEvan.Yan@Sun.COM 		 * Keep POWERED state if it is currently POWERED state because
180310923SEvan.Yan@Sun.COM 		 * this driver does not really implement enable/disable
180410923SEvan.Yan@Sun.COM 		 * slot operations. That is, when poweron, it actually enables
180510923SEvan.Yan@Sun.COM 		 * the slot also.
180610923SEvan.Yan@Sun.COM 		 * So, from hardware view, POWERED == ENABLED.
180710923SEvan.Yan@Sun.COM 		 * But, when user explicitly change to POWERED state, it should
180810923SEvan.Yan@Sun.COM 		 * be kept until user explicitly change to other states later.
180910923SEvan.Yan@Sun.COM 		 */
181010923SEvan.Yan@Sun.COM 		slot_p->hs_info.cn_state = DDI_HP_CN_STATE_POWERED;
181110923SEvan.Yan@Sun.COM 	}
181210923SEvan.Yan@Sun.COM 
181310923SEvan.Yan@Sun.COM 	/* Convert from the SHPC Power LED state to the HPC Power LED state. */
181410923SEvan.Yan@Sun.COM 	slot_p->hs_power_led_state = pcishpc_led_shpc_to_hpc((reg>>2)&3);
181510923SEvan.Yan@Sun.COM 
181610923SEvan.Yan@Sun.COM 	/* Convert from the SHPC Attn LED state to the HPC Attn LED state. */
181710923SEvan.Yan@Sun.COM 	slot_p->hs_attn_led_state = pcishpc_led_shpc_to_hpc((reg>>4)&3);
181810923SEvan.Yan@Sun.COM 
181910923SEvan.Yan@Sun.COM 	/* We don't have a fault LED so just default it to OFF. */
182010923SEvan.Yan@Sun.COM 	slot_p->hs_fault_led_state = PCIE_HP_LED_OFF;
182110923SEvan.Yan@Sun.COM 
182210923SEvan.Yan@Sun.COM 	/* We don't have an active LED so just default it to OFF. */
182310923SEvan.Yan@Sun.COM 	slot_p->hs_active_led_state = PCIE_HP_LED_OFF;
182410923SEvan.Yan@Sun.COM }
182510923SEvan.Yan@Sun.COM 
182610923SEvan.Yan@Sun.COM /*
182710923SEvan.Yan@Sun.COM  * pcishpc_set_slot_state()
182810923SEvan.Yan@Sun.COM  *
182910923SEvan.Yan@Sun.COM  * Updates the slot's state and leds.
183010923SEvan.Yan@Sun.COM  */
183110923SEvan.Yan@Sun.COM static int
pcishpc_set_slot_state(pcie_hp_slot_t * slot_p,ddi_hp_cn_state_t new_slot_state)183210923SEvan.Yan@Sun.COM pcishpc_set_slot_state(pcie_hp_slot_t *slot_p,
183310923SEvan.Yan@Sun.COM     ddi_hp_cn_state_t new_slot_state)
183410923SEvan.Yan@Sun.COM {
183510923SEvan.Yan@Sun.COM 	uint32_t		reg, cmd_code;
183610923SEvan.Yan@Sun.COM 	ddi_hp_cn_state_t	curr_state;
183710923SEvan.Yan@Sun.COM 
183810923SEvan.Yan@Sun.COM 	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
183910923SEvan.Yan@Sun.COM 
184010923SEvan.Yan@Sun.COM 	reg = pcishpc_read_reg(slot_p->hs_ctrl,
184110923SEvan.Yan@Sun.COM 	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
184210923SEvan.Yan@Sun.COM 
184310923SEvan.Yan@Sun.COM 	/* Default all states to unchanged. */
184410923SEvan.Yan@Sun.COM 	cmd_code = ((1 + slot_p->hs_num) << 8);
184510923SEvan.Yan@Sun.COM 
184610923SEvan.Yan@Sun.COM 	/* Has the slot state changed? */
184710923SEvan.Yan@Sun.COM 	curr_state = pcishpc_slot_shpc_to_hpc(reg);
184810923SEvan.Yan@Sun.COM 	if (curr_state != new_slot_state) {
184910923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_set_slot_state() Slot State changed");
185010923SEvan.Yan@Sun.COM 
185110923SEvan.Yan@Sun.COM 		/* Set the new slot state in the Slot operation command. */
185210923SEvan.Yan@Sun.COM 		cmd_code |= pcishpc_slot_hpc_to_shpc(new_slot_state);
185310923SEvan.Yan@Sun.COM 	}
185410923SEvan.Yan@Sun.COM 
185510923SEvan.Yan@Sun.COM 	/* Has the Power LED state changed? */
185610923SEvan.Yan@Sun.COM 	if (slot_p->hs_power_led_state != pcishpc_led_shpc_to_hpc((reg>>2)&3)) {
185710923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_set_slot_state() Power LED State changed\n");
185810923SEvan.Yan@Sun.COM 
185910923SEvan.Yan@Sun.COM 		/* Set the new power led state in the Slot operation command. */
186010923SEvan.Yan@Sun.COM 		cmd_code |=
186110923SEvan.Yan@Sun.COM 		    (pcishpc_led_hpc_to_shpc(slot_p->hs_power_led_state) << 2);
186210923SEvan.Yan@Sun.COM 	}
186310923SEvan.Yan@Sun.COM 
186410923SEvan.Yan@Sun.COM 	/* Has the Attn LED state changed? */
186510923SEvan.Yan@Sun.COM 	if (slot_p->hs_attn_led_state != pcishpc_led_shpc_to_hpc((reg>>4)&3)) {
186610923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_set_slot_state() Attn LED State changed\n");
186710923SEvan.Yan@Sun.COM 
186810923SEvan.Yan@Sun.COM 		/* Set the new attn led state in the Slot operation command. */
186910923SEvan.Yan@Sun.COM 		cmd_code |=
187010923SEvan.Yan@Sun.COM 		    (pcishpc_led_hpc_to_shpc(slot_p->hs_attn_led_state) << 4);
187110923SEvan.Yan@Sun.COM 	}
187210923SEvan.Yan@Sun.COM 
187310923SEvan.Yan@Sun.COM 	return (pcishpc_issue_command(slot_p->hs_ctrl, cmd_code));
187410923SEvan.Yan@Sun.COM }
187510923SEvan.Yan@Sun.COM 
187610923SEvan.Yan@Sun.COM /*
187710923SEvan.Yan@Sun.COM  * setup slot name/slot-number info.
187810923SEvan.Yan@Sun.COM  */
187910923SEvan.Yan@Sun.COM static void
pcishpc_set_slot_name(pcie_hp_ctrl_t * ctrl_p,int slot)188010923SEvan.Yan@Sun.COM pcishpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p, int slot)
188110923SEvan.Yan@Sun.COM {
188210923SEvan.Yan@Sun.COM 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[slot];
188310923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
188410923SEvan.Yan@Sun.COM 	uchar_t *slotname_data;
188510923SEvan.Yan@Sun.COM 	int *slotnum;
188610923SEvan.Yan@Sun.COM 	uint_t count;
188710923SEvan.Yan@Sun.COM 	int len;
188810923SEvan.Yan@Sun.COM 	uchar_t *s;
188910923SEvan.Yan@Sun.COM 	uint32_t bit_mask;
189010923SEvan.Yan@Sun.COM 	int pci_id_cnt, pci_id_bit;
189110923SEvan.Yan@Sun.COM 	int slots_before, found;
189210923SEvan.Yan@Sun.COM 	int invalid_slotnum = 0;
189310923SEvan.Yan@Sun.COM 
189410923SEvan.Yan@Sun.COM 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ctrl_p->hc_dip,
189510923SEvan.Yan@Sun.COM 	    DDI_PROP_DONTPASS, "physical-slot#", &slotnum, &count) ==
189610923SEvan.Yan@Sun.COM 	    DDI_PROP_SUCCESS) {
189710923SEvan.Yan@Sun.COM 		slot_p->hs_phy_slot_num = slotnum[0];
189810923SEvan.Yan@Sun.COM 		ddi_prop_free(slotnum);
189910923SEvan.Yan@Sun.COM 	} else {
190010923SEvan.Yan@Sun.COM 		if (ctrl_p->hc_device_increases)
190110923SEvan.Yan@Sun.COM 			slot_p->hs_phy_slot_num = ctrl_p->hc_phys_start + slot;
190210923SEvan.Yan@Sun.COM 		else
190310923SEvan.Yan@Sun.COM 			slot_p->hs_phy_slot_num = ctrl_p->hc_phys_start - slot;
190410923SEvan.Yan@Sun.COM 
190510923SEvan.Yan@Sun.COM 		if ((ndi_prop_update_int(DDI_DEV_T_NONE, ctrl_p->hc_dip,
190610923SEvan.Yan@Sun.COM 		    "physical-slot#", slot_p->hs_phy_slot_num)) != DDI_SUCCESS)
190710923SEvan.Yan@Sun.COM 			PCIE_DBG("pcishpc_set_slot_name(): failed to "
190810923SEvan.Yan@Sun.COM 			    "create phyical-slot#%d\n",
190910923SEvan.Yan@Sun.COM 			    slot_p->hs_phy_slot_num);
191010923SEvan.Yan@Sun.COM 	}
191110923SEvan.Yan@Sun.COM 
191210923SEvan.Yan@Sun.COM 	/* Platform may not have initialized it */
191310923SEvan.Yan@Sun.COM 	if (!slot_p->hs_phy_slot_num) {
191410923SEvan.Yan@Sun.COM 		slot_p->hs_phy_slot_num = pci_config_get8(bus_p->bus_cfg_hdl,
191510923SEvan.Yan@Sun.COM 		    PCI_BCNF_SECBUS);
191610923SEvan.Yan@Sun.COM 		invalid_slotnum = 1;
191710923SEvan.Yan@Sun.COM 	}
191810923SEvan.Yan@Sun.COM 	slot_p->hs_info.cn_num = slot_p->hs_phy_slot_num;
191910923SEvan.Yan@Sun.COM 	slot_p->hs_info.cn_num_dpd_on = DDI_HP_CN_NUM_NONE;
192010923SEvan.Yan@Sun.COM 
192110923SEvan.Yan@Sun.COM 	/*
192210923SEvan.Yan@Sun.COM 	 * construct the slot_name:
192310923SEvan.Yan@Sun.COM 	 * 	if "slot-names" property exists then use that name
192410923SEvan.Yan@Sun.COM 	 *	else if valid slot number exists then it is "pci<slot-num>".
192510923SEvan.Yan@Sun.COM 	 *	else it will be "pci<sec-bus-number>dev<dev-number>"
192610923SEvan.Yan@Sun.COM 	 */
192710923SEvan.Yan@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, ctrl_p->hc_dip, DDI_PROP_DONTPASS,
192810923SEvan.Yan@Sun.COM 	    "slot-names", (caddr_t)&slotname_data, &len) == DDI_PROP_SUCCESS) {
192910923SEvan.Yan@Sun.COM 		bit_mask = slotname_data[3] | (slotname_data[2] << 8) |
193010923SEvan.Yan@Sun.COM 		    (slotname_data[1] << 16) | (slotname_data[0] << 24);
193110923SEvan.Yan@Sun.COM 
193210923SEvan.Yan@Sun.COM 		pci_id_bit = 1;
193310923SEvan.Yan@Sun.COM 		pci_id_cnt = slots_before = found = 0;
193410923SEvan.Yan@Sun.COM 
193510923SEvan.Yan@Sun.COM 		/*
193610923SEvan.Yan@Sun.COM 		 * Walk the bit mask until we find the bit that corresponds
193710923SEvan.Yan@Sun.COM 		 * to our slots device number.  We count how many bits
193810923SEvan.Yan@Sun.COM 		 * we find before we find our slot's bit.
193910923SEvan.Yan@Sun.COM 		 */
194010923SEvan.Yan@Sun.COM 		while (!found && (pci_id_cnt < 32)) {
194110923SEvan.Yan@Sun.COM 			while (slot_p->hs_device_num != pci_id_cnt) {
194210923SEvan.Yan@Sun.COM 
194310923SEvan.Yan@Sun.COM 				/*
194410923SEvan.Yan@Sun.COM 				 * Find the next bit set.
194510923SEvan.Yan@Sun.COM 				 */
194610923SEvan.Yan@Sun.COM 				while (!(bit_mask & pci_id_bit) &&
194710923SEvan.Yan@Sun.COM 				    (pci_id_cnt < 32)) {
194810923SEvan.Yan@Sun.COM 					pci_id_bit = pci_id_bit << 1;
194910923SEvan.Yan@Sun.COM 					pci_id_cnt++;
195010923SEvan.Yan@Sun.COM 				}
195110923SEvan.Yan@Sun.COM 
195210923SEvan.Yan@Sun.COM 				if (slot_p->hs_device_num != pci_id_cnt)
195310923SEvan.Yan@Sun.COM 					slots_before++;
195410923SEvan.Yan@Sun.COM 				else
195510923SEvan.Yan@Sun.COM 					found = 1;
195610923SEvan.Yan@Sun.COM 			}
195710923SEvan.Yan@Sun.COM 		}
195810923SEvan.Yan@Sun.COM 
195910923SEvan.Yan@Sun.COM 		if (pci_id_cnt < 32) {
196010923SEvan.Yan@Sun.COM 
196110923SEvan.Yan@Sun.COM 			/*
196210923SEvan.Yan@Sun.COM 			 * Set ptr to first string.
196310923SEvan.Yan@Sun.COM 			 */
196410923SEvan.Yan@Sun.COM 			s = slotname_data + 4;
196510923SEvan.Yan@Sun.COM 
196610923SEvan.Yan@Sun.COM 			/*
196710923SEvan.Yan@Sun.COM 			 * Increment past all the strings for the slots
196810923SEvan.Yan@Sun.COM 			 * before ours.
196910923SEvan.Yan@Sun.COM 			 */
197010923SEvan.Yan@Sun.COM 			while (slots_before) {
197110923SEvan.Yan@Sun.COM 				while (*s != NULL)
197210923SEvan.Yan@Sun.COM 					s++;
197310923SEvan.Yan@Sun.COM 				s++;
197410923SEvan.Yan@Sun.COM 				slots_before--;
197510923SEvan.Yan@Sun.COM 			}
197610923SEvan.Yan@Sun.COM 
197710923SEvan.Yan@Sun.COM 			slot_p->hs_info.cn_name = i_ddi_strdup((char *)s,
197810923SEvan.Yan@Sun.COM 			    KM_SLEEP);
197910923SEvan.Yan@Sun.COM 			kmem_free(slotname_data, len);
198010923SEvan.Yan@Sun.COM 			return;
198110923SEvan.Yan@Sun.COM 		}
198210923SEvan.Yan@Sun.COM 
198310923SEvan.Yan@Sun.COM 		/* slot-names entry not found */
198410923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_set_slot_name(): "
198510923SEvan.Yan@Sun.COM 		    "No slot-names entry found for slot #%d\n",
198610923SEvan.Yan@Sun.COM 		    slot_p->hs_phy_slot_num);
198710923SEvan.Yan@Sun.COM 		kmem_free(slotname_data, len);
198810923SEvan.Yan@Sun.COM 	}
198910923SEvan.Yan@Sun.COM 
199010923SEvan.Yan@Sun.COM 	if (invalid_slotnum) {
199110923SEvan.Yan@Sun.COM 		char tmp_name[256];
199210923SEvan.Yan@Sun.COM 
199310923SEvan.Yan@Sun.COM 		(void) snprintf(tmp_name, sizeof (tmp_name), "pci%d",
199410923SEvan.Yan@Sun.COM 		    slot_p->hs_device_num);
199510923SEvan.Yan@Sun.COM 		slot_p->hs_info.cn_name = i_ddi_strdup(tmp_name, KM_SLEEP);
199610923SEvan.Yan@Sun.COM 	} else {
199710923SEvan.Yan@Sun.COM 		char tmp_name[256];
199810923SEvan.Yan@Sun.COM 
199910923SEvan.Yan@Sun.COM 		(void) snprintf(tmp_name, sizeof (tmp_name), "pci%d",
200010923SEvan.Yan@Sun.COM 		    slot_p->hs_phy_slot_num);
200110923SEvan.Yan@Sun.COM 		slot_p->hs_info.cn_name = i_ddi_strdup(tmp_name, KM_SLEEP);
200210923SEvan.Yan@Sun.COM 	}
200310923SEvan.Yan@Sun.COM }
200410923SEvan.Yan@Sun.COM 
200510923SEvan.Yan@Sun.COM /*
200610923SEvan.Yan@Sun.COM  * pcishpc_set_bus_speed()
200710923SEvan.Yan@Sun.COM  *
200810923SEvan.Yan@Sun.COM  * Set the bus speed and mode.
200910923SEvan.Yan@Sun.COM  */
201010923SEvan.Yan@Sun.COM static int
pcishpc_set_bus_speed(pcie_hp_slot_t * slot_p)201110923SEvan.Yan@Sun.COM pcishpc_set_bus_speed(pcie_hp_slot_t *slot_p)
201210923SEvan.Yan@Sun.COM {
201310923SEvan.Yan@Sun.COM 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
201410923SEvan.Yan@Sun.COM 	int		curr_speed = ctrl_p->hc_curr_bus_speed;
201510923SEvan.Yan@Sun.COM 	int		speed = -1;
201610923SEvan.Yan@Sun.COM 	int		avail_slots;
201710923SEvan.Yan@Sun.COM 	uint32_t	status, slots_avail1_reg, slots_avail2_reg;
201810923SEvan.Yan@Sun.COM 
201910923SEvan.Yan@Sun.COM 	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
202010923SEvan.Yan@Sun.COM 
202110923SEvan.Yan@Sun.COM 	/* Make sure that the slot is in a correct state */
202210923SEvan.Yan@Sun.COM 	status = pcishpc_read_reg(ctrl_p,
202310923SEvan.Yan@Sun.COM 	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
202410923SEvan.Yan@Sun.COM 
202510923SEvan.Yan@Sun.COM 	/* Return failure if the slot is empty */
202610923SEvan.Yan@Sun.COM 	if ((status & PCI_HP_SLOT_CARD_EMPTY_MASK) ==
202710923SEvan.Yan@Sun.COM 	    PCI_HP_SLOT_CARD_EMPTY_MASK) {
202810923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_set_bus_speed() failed: "
202910923SEvan.Yan@Sun.COM 		    "the slot is empty\n");
203010923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
203110923SEvan.Yan@Sun.COM 	}
203210923SEvan.Yan@Sun.COM 
203310923SEvan.Yan@Sun.COM 	/* Return failure if the slot is not in disabled state */
203410923SEvan.Yan@Sun.COM 	if ((status & PCI_HP_SLOT_STATE_MASK) != PCI_HP_SLOT_DISABLED) {
203510923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_set_bus_speed() failed: "
203610923SEvan.Yan@Sun.COM 		    "incorrect slot state\n");
203710923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
203810923SEvan.Yan@Sun.COM 	}
203910923SEvan.Yan@Sun.COM 
204010923SEvan.Yan@Sun.COM 	/* Set the "power-only" mode for the slot */
204110923SEvan.Yan@Sun.COM 	if (pcishpc_issue_command(ctrl_p, ((1+slot_p->hs_num)<<8) |
204210923SEvan.Yan@Sun.COM 	    PCI_HP_SLOT_POWER_ONLY) != DDI_SUCCESS) {
204310923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_set_bus_speed() failed to set "
204410923SEvan.Yan@Sun.COM 		    "the slot %d in the power-only mode\n", slot_p->hs_num);
204510923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
204610923SEvan.Yan@Sun.COM 	}
204710923SEvan.Yan@Sun.COM 
204810923SEvan.Yan@Sun.COM 	/* Wait for power good */
204910923SEvan.Yan@Sun.COM 	delay(drv_usectohz(PCIE_HP_POWER_GOOD_WAIT_TIME));
205010923SEvan.Yan@Sun.COM 
205110923SEvan.Yan@Sun.COM 	/* Make sure that the slot is in "power-only" state */
205210923SEvan.Yan@Sun.COM 	status = pcishpc_read_reg(ctrl_p,
205310923SEvan.Yan@Sun.COM 	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
205410923SEvan.Yan@Sun.COM 
205510923SEvan.Yan@Sun.COM 	if ((status & PCI_HP_SLOT_STATE_MASK) != PCI_HP_SLOT_POWER_ONLY) {
205610923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_set_bus_speed() "
205710923SEvan.Yan@Sun.COM 		    "power-only failed: incorrect slot state\n");
205810923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
205910923SEvan.Yan@Sun.COM 	}
206010923SEvan.Yan@Sun.COM 
206110923SEvan.Yan@Sun.COM 	slots_avail1_reg = pcishpc_read_reg(ctrl_p,
206210923SEvan.Yan@Sun.COM 	    PCI_HP_SLOTS_AVAIL_I_REG);
206310923SEvan.Yan@Sun.COM 	slots_avail2_reg = pcishpc_read_reg(ctrl_p,
206410923SEvan.Yan@Sun.COM 	    PCI_HP_SLOTS_AVAIL_II_REG);
206510923SEvan.Yan@Sun.COM 
206610923SEvan.Yan@Sun.COM 	/*
206710923SEvan.Yan@Sun.COM 	 * Check if SHPC has available slots and select the highest
206810923SEvan.Yan@Sun.COM 	 * available bus speed for the slot.
206910923SEvan.Yan@Sun.COM 	 *
207010923SEvan.Yan@Sun.COM 	 * The bus speed codes are:
207110923SEvan.Yan@Sun.COM 	 * 100 - 133Mhz; <--+
207210923SEvan.Yan@Sun.COM 	 * 011 - 100Mhz; <--+   PCI-X
207310923SEvan.Yan@Sun.COM 	 * 010 - 66Mhz;  <--+
207410923SEvan.Yan@Sun.COM 	 *
207510923SEvan.Yan@Sun.COM 	 * 001 - 66Mhz;  <--+
207610923SEvan.Yan@Sun.COM 	 * 000 - 33Mhz   <--+   Conv PCI
207710923SEvan.Yan@Sun.COM 	 */
207810923SEvan.Yan@Sun.COM 	switch (status & PCI_HP_SLOT_PCIX_CAPABLE_MASK) {
207910923SEvan.Yan@Sun.COM 	case PCI_HP_SLOT_133MHZ_PCIX_CAPABLE:
208010923SEvan.Yan@Sun.COM 		avail_slots = (slots_avail1_reg >>
208110923SEvan.Yan@Sun.COM 		    PCI_HP_AVAIL_133MHZ_PCIX_SPEED_SHIFT) &
208210923SEvan.Yan@Sun.COM 		    PCI_HP_AVAIL_SPEED_MASK;
208310923SEvan.Yan@Sun.COM 
208410923SEvan.Yan@Sun.COM 		if (((curr_speed == -1) && avail_slots) ||
208510923SEvan.Yan@Sun.COM 		    (curr_speed == PCI_HP_SBCR_133MHZ_PCIX_SPEED)) {
208610923SEvan.Yan@Sun.COM 			speed = PCI_HP_SBCR_133MHZ_PCIX_SPEED;
208710923SEvan.Yan@Sun.COM 			break;
208810923SEvan.Yan@Sun.COM 		}
208910923SEvan.Yan@Sun.COM 		/* FALLTHROUGH */
209010923SEvan.Yan@Sun.COM 	case PCI_HP_SLOT_100MHZ_PCIX_CAPABLE:
209110923SEvan.Yan@Sun.COM 		avail_slots = (slots_avail1_reg >>
209210923SEvan.Yan@Sun.COM 		    PCI_HP_AVAIL_100MHZ_PCIX_SPEED_SHIFT) &
209310923SEvan.Yan@Sun.COM 		    PCI_HP_AVAIL_SPEED_MASK;
209410923SEvan.Yan@Sun.COM 
209510923SEvan.Yan@Sun.COM 		if (((curr_speed == -1) && avail_slots) ||
209610923SEvan.Yan@Sun.COM 		    (curr_speed == PCI_HP_SBCR_100MHZ_PCIX_SPEED)) {
209710923SEvan.Yan@Sun.COM 			speed = PCI_HP_SBCR_100MHZ_PCIX_SPEED;
209810923SEvan.Yan@Sun.COM 			break;
209910923SEvan.Yan@Sun.COM 		}
210010923SEvan.Yan@Sun.COM 		/* FALLTHROUGH */
210110923SEvan.Yan@Sun.COM 	case PCI_HP_SLOT_66MHZ_PCIX_CAPABLE:
210210923SEvan.Yan@Sun.COM 		avail_slots = (slots_avail1_reg >>
210310923SEvan.Yan@Sun.COM 		    PCI_HP_AVAIL_66MHZ_PCIX_SPEED_SHIFT) &
210410923SEvan.Yan@Sun.COM 		    PCI_HP_AVAIL_SPEED_MASK;
210510923SEvan.Yan@Sun.COM 
210610923SEvan.Yan@Sun.COM 		if (((curr_speed == -1) && avail_slots) ||
210710923SEvan.Yan@Sun.COM 		    (curr_speed == PCI_HP_SBCR_66MHZ_PCIX_SPEED)) {
210810923SEvan.Yan@Sun.COM 			speed = PCI_HP_SBCR_66MHZ_PCIX_SPEED;
210910923SEvan.Yan@Sun.COM 			break;
211010923SEvan.Yan@Sun.COM 		}
211110923SEvan.Yan@Sun.COM 		/* FALLTHROUGH */
211210923SEvan.Yan@Sun.COM 	default:
211310923SEvan.Yan@Sun.COM 		avail_slots = (slots_avail2_reg >>
211410923SEvan.Yan@Sun.COM 		    PCI_HP_AVAIL_66MHZ_CONV_SPEED_SHIFT) &
211510923SEvan.Yan@Sun.COM 		    PCI_HP_AVAIL_SPEED_MASK;
211610923SEvan.Yan@Sun.COM 
211710923SEvan.Yan@Sun.COM 		if ((status & PCI_HP_SLOT_66MHZ_CONV_CAPABLE) &&
211810923SEvan.Yan@Sun.COM 		    (((curr_speed == -1) && avail_slots) ||
211910923SEvan.Yan@Sun.COM 		    (curr_speed == PCI_HP_SBCR_66MHZ_CONV_SPEED))) {
212010923SEvan.Yan@Sun.COM 			speed = PCI_HP_SBCR_66MHZ_CONV_SPEED;
212110923SEvan.Yan@Sun.COM 		} else {
212210923SEvan.Yan@Sun.COM 			avail_slots = (slots_avail1_reg >>
212310923SEvan.Yan@Sun.COM 			    PCI_HP_AVAIL_33MHZ_CONV_SPEED_SHIFT) &
212410923SEvan.Yan@Sun.COM 			    PCI_HP_AVAIL_SPEED_MASK;
212510923SEvan.Yan@Sun.COM 
212610923SEvan.Yan@Sun.COM 			if (((curr_speed == -1) && (avail_slots)) ||
212710923SEvan.Yan@Sun.COM 			    (curr_speed == PCI_HP_SBCR_33MHZ_CONV_SPEED)) {
212810923SEvan.Yan@Sun.COM 				speed = PCI_HP_SBCR_33MHZ_CONV_SPEED;
212910923SEvan.Yan@Sun.COM 			} else {
213010923SEvan.Yan@Sun.COM 				PCIE_DBG("pcishpc_set_bus_speed() "
213110923SEvan.Yan@Sun.COM 				    " failed to set the bus speed, slot# %d\n",
213210923SEvan.Yan@Sun.COM 				    slot_p->hs_num);
213310923SEvan.Yan@Sun.COM 				return (DDI_FAILURE);
213410923SEvan.Yan@Sun.COM 			}
213510923SEvan.Yan@Sun.COM 		}
213610923SEvan.Yan@Sun.COM 		break;
213710923SEvan.Yan@Sun.COM 	}
213810923SEvan.Yan@Sun.COM 
213910923SEvan.Yan@Sun.COM 	/*
214010923SEvan.Yan@Sun.COM 	 * If the bus segment is already running, check to see the card
214110923SEvan.Yan@Sun.COM 	 * in the slot can support the current bus speed.
214210923SEvan.Yan@Sun.COM 	 */
214310923SEvan.Yan@Sun.COM 	if (curr_speed == speed) {
214410923SEvan.Yan@Sun.COM 		/*
214510923SEvan.Yan@Sun.COM 		 * Check to see there is any slot available for the current
214610923SEvan.Yan@Sun.COM 		 * bus speed. Otherwise, we need fail the current slot connect
214710923SEvan.Yan@Sun.COM 		 * request.
214810923SEvan.Yan@Sun.COM 		 */
214910923SEvan.Yan@Sun.COM 		return ((avail_slots <= ctrl_p->hc_num_slots_connected) ?
215010923SEvan.Yan@Sun.COM 		    DDI_FAILURE : DDI_SUCCESS);
215110923SEvan.Yan@Sun.COM 	}
215210923SEvan.Yan@Sun.COM 
215310923SEvan.Yan@Sun.COM 	/* Set the bus speed */
215410923SEvan.Yan@Sun.COM 	if (pcishpc_issue_command(ctrl_p, PCI_HP_COMM_STS_SET_SPEED |
215510923SEvan.Yan@Sun.COM 	    speed) == DDI_FAILURE) {
215610923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_set_bus_speed() failed "
215710923SEvan.Yan@Sun.COM 		    "to set bus %d speed\n", slot_p->hs_num);
215810923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
215910923SEvan.Yan@Sun.COM 	}
216010923SEvan.Yan@Sun.COM 
216110923SEvan.Yan@Sun.COM 	/* Check the current bus speed */
216210923SEvan.Yan@Sun.COM 	status = pcishpc_read_reg(ctrl_p, PCI_HP_PROF_IF_SBCR_REG) &
216310923SEvan.Yan@Sun.COM 	    PCI_HP_SBCR_SPEED_MASK;
216410923SEvan.Yan@Sun.COM 	if ((status & PCI_HP_SBCR_SPEED_MASK) != speed) {
216510923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_set_bus_speed() an incorrect "
216610923SEvan.Yan@Sun.COM 		    "bus speed, slot = 0x%x, speed = 0x%x\n",
216710923SEvan.Yan@Sun.COM 		    slot_p->hs_num, status & PCI_HP_SBCR_SPEED_MASK);
216810923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
216910923SEvan.Yan@Sun.COM 	}
217010923SEvan.Yan@Sun.COM 
217110923SEvan.Yan@Sun.COM 
217210923SEvan.Yan@Sun.COM 	/* Save the current bus speed */
217310923SEvan.Yan@Sun.COM 	ctrl_p->hc_curr_bus_speed = speed;
217410923SEvan.Yan@Sun.COM 
217510923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
217610923SEvan.Yan@Sun.COM }
217710923SEvan.Yan@Sun.COM 
217810923SEvan.Yan@Sun.COM /*
217910923SEvan.Yan@Sun.COM  * pcishpc_setled()
218010923SEvan.Yan@Sun.COM  *
218110923SEvan.Yan@Sun.COM  * Change the state of a slot's LED.
218210923SEvan.Yan@Sun.COM  */
218310923SEvan.Yan@Sun.COM static int
pcishpc_setled(pcie_hp_slot_t * slot_p,pcie_hp_led_t led,pcie_hp_led_state_t state)218410923SEvan.Yan@Sun.COM pcishpc_setled(pcie_hp_slot_t *slot_p, pcie_hp_led_t led,
218510923SEvan.Yan@Sun.COM     pcie_hp_led_state_t state)
218610923SEvan.Yan@Sun.COM {
218710923SEvan.Yan@Sun.COM 	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
218810923SEvan.Yan@Sun.COM 
218910923SEvan.Yan@Sun.COM 	switch (led) {
219010923SEvan.Yan@Sun.COM 		case PCIE_HP_FAULT_LED:
219110923SEvan.Yan@Sun.COM 			PCIE_DBG("pcishpc_setled() - PCIE_HP_FAULT_LED "
219210923SEvan.Yan@Sun.COM 			    "(set %s)\n", pcishpc_slot_textledstate(state));
219310923SEvan.Yan@Sun.COM 			slot_p->hs_fault_led_state = state;
219410923SEvan.Yan@Sun.COM 			break;
219510923SEvan.Yan@Sun.COM 
219610923SEvan.Yan@Sun.COM 		case PCIE_HP_POWER_LED:
219710923SEvan.Yan@Sun.COM 			PCIE_DBG("pcishpc_setled() - PCIE_HP_POWER_LED "
219810923SEvan.Yan@Sun.COM 			    "(set %s)\n", pcishpc_slot_textledstate(state));
219910923SEvan.Yan@Sun.COM 			slot_p->hs_power_led_state = state;
220010923SEvan.Yan@Sun.COM 			break;
220110923SEvan.Yan@Sun.COM 
220210923SEvan.Yan@Sun.COM 		case PCIE_HP_ATTN_LED:
220310923SEvan.Yan@Sun.COM 			PCIE_DBG("pcishpc_setled() - PCIE_HP_ATTN_LED "
220410923SEvan.Yan@Sun.COM 			    "(set %s)\n", pcishpc_slot_textledstate(state));
220510923SEvan.Yan@Sun.COM 			slot_p->hs_attn_led_state = state;
220610923SEvan.Yan@Sun.COM 			break;
220710923SEvan.Yan@Sun.COM 
220810923SEvan.Yan@Sun.COM 		case PCIE_HP_ACTIVE_LED:
220910923SEvan.Yan@Sun.COM 			PCIE_DBG("pcishpc_setled() - PCIE_HP_ACTIVE_LED "
221010923SEvan.Yan@Sun.COM 			    "(set %s)\n", pcishpc_slot_textledstate(state));
221110923SEvan.Yan@Sun.COM 			slot_p->hs_active_led_state = state;
221210923SEvan.Yan@Sun.COM 			break;
221310923SEvan.Yan@Sun.COM 	}
221410923SEvan.Yan@Sun.COM 
221510923SEvan.Yan@Sun.COM 	return (pcishpc_set_slot_state(slot_p, slot_p->hs_info.cn_state));
221610923SEvan.Yan@Sun.COM }
221710923SEvan.Yan@Sun.COM 
221810923SEvan.Yan@Sun.COM /*
221910923SEvan.Yan@Sun.COM  * pcishpc_led_shpc_to_hpc()
222010923SEvan.Yan@Sun.COM  *
222110923SEvan.Yan@Sun.COM  * Convert from SHPC indicator status to HPC indicator status.
222210923SEvan.Yan@Sun.COM  */
222310923SEvan.Yan@Sun.COM static int
pcishpc_led_shpc_to_hpc(int state)222410923SEvan.Yan@Sun.COM pcishpc_led_shpc_to_hpc(int state)
222510923SEvan.Yan@Sun.COM {
222610923SEvan.Yan@Sun.COM 	switch (state) {
222710923SEvan.Yan@Sun.COM 		case 1:	/* SHPC On bits b01 */
222810923SEvan.Yan@Sun.COM 			return (PCIE_HP_LED_ON);
222910923SEvan.Yan@Sun.COM 		case 2:	/* SHPC Blink bits b10 */
223010923SEvan.Yan@Sun.COM 			return (PCIE_HP_LED_BLINK);
223110923SEvan.Yan@Sun.COM 		case 3:	/* SHPC Off bits b11 */
223210923SEvan.Yan@Sun.COM 			return (PCIE_HP_LED_OFF);
223310923SEvan.Yan@Sun.COM 	}
223410923SEvan.Yan@Sun.COM 
223510923SEvan.Yan@Sun.COM 	return (PCIE_HP_LED_OFF);
223610923SEvan.Yan@Sun.COM }
223710923SEvan.Yan@Sun.COM 
223810923SEvan.Yan@Sun.COM 
223910923SEvan.Yan@Sun.COM /*
224010923SEvan.Yan@Sun.COM  * pcishpc_led_hpc_to_shpc()
224110923SEvan.Yan@Sun.COM  *
224210923SEvan.Yan@Sun.COM  * Convert from HPC indicator status to SHPC indicator status.
224310923SEvan.Yan@Sun.COM  */
224410923SEvan.Yan@Sun.COM static int
pcishpc_led_hpc_to_shpc(int state)224510923SEvan.Yan@Sun.COM pcishpc_led_hpc_to_shpc(int state)
224610923SEvan.Yan@Sun.COM {
224710923SEvan.Yan@Sun.COM 	switch (state) {
224810923SEvan.Yan@Sun.COM 		case PCIE_HP_LED_ON:
224910923SEvan.Yan@Sun.COM 			return (1); /* SHPC On bits b01 */
225010923SEvan.Yan@Sun.COM 		case PCIE_HP_LED_BLINK:
225110923SEvan.Yan@Sun.COM 			return (2); /* SHPC Blink bits b10 */
225210923SEvan.Yan@Sun.COM 		case PCIE_HP_LED_OFF:
225310923SEvan.Yan@Sun.COM 			return (3); /* SHPC Off bits b11 */
225410923SEvan.Yan@Sun.COM 	}
225510923SEvan.Yan@Sun.COM 
225610923SEvan.Yan@Sun.COM 	return (3); /* SHPC Off bits b11 */
225710923SEvan.Yan@Sun.COM }
225810923SEvan.Yan@Sun.COM 
225910923SEvan.Yan@Sun.COM /*
226010923SEvan.Yan@Sun.COM  * pcishpc_slot_shpc_to_hpc()
226110923SEvan.Yan@Sun.COM  *
226210923SEvan.Yan@Sun.COM  * Convert from SHPC slot state to HPC slot state.
226310923SEvan.Yan@Sun.COM  * The argument shpc_state is expected to be read from the slot register.
226410923SEvan.Yan@Sun.COM  */
226510923SEvan.Yan@Sun.COM static int
pcishpc_slot_shpc_to_hpc(int shpc_state)226610923SEvan.Yan@Sun.COM pcishpc_slot_shpc_to_hpc(int shpc_state)
226710923SEvan.Yan@Sun.COM {
226810923SEvan.Yan@Sun.COM 	if ((shpc_state & PCI_HP_SLOT_CARD_EMPTY_MASK) ==
226910923SEvan.Yan@Sun.COM 	    PCI_HP_SLOT_CARD_EMPTY_MASK)
227010923SEvan.Yan@Sun.COM 		return (DDI_HP_CN_STATE_EMPTY);
227110923SEvan.Yan@Sun.COM 
227210923SEvan.Yan@Sun.COM 	switch (shpc_state & PCI_HP_SLOT_STATE_MASK) {
227310923SEvan.Yan@Sun.COM 		case PCI_HP_SLOT_POWER_ONLY: /* SHPC Powered Only */
227410923SEvan.Yan@Sun.COM 			return (DDI_HP_CN_STATE_POWERED);
227510923SEvan.Yan@Sun.COM 
227610923SEvan.Yan@Sun.COM 		case PCI_HP_SLOT_ENABLED: /* SHPC Enabled */
227710923SEvan.Yan@Sun.COM 			return (DDI_HP_CN_STATE_ENABLED);
227810923SEvan.Yan@Sun.COM 
227910923SEvan.Yan@Sun.COM 		case PCI_HP_SLOT_DISABLED:	/* SHPC Disabled */
228010923SEvan.Yan@Sun.COM 		default :			/* SHPC Reserved */
228110923SEvan.Yan@Sun.COM 			return (DDI_HP_CN_STATE_PRESENT);
228210923SEvan.Yan@Sun.COM 	}
228310923SEvan.Yan@Sun.COM }
228410923SEvan.Yan@Sun.COM 
228510923SEvan.Yan@Sun.COM /*
228610923SEvan.Yan@Sun.COM  * pcishpc_slot_hpc_to_shpc()
228710923SEvan.Yan@Sun.COM  *
228810923SEvan.Yan@Sun.COM  * Convert from HPC slot state to SHPC slot state.
228910923SEvan.Yan@Sun.COM  */
229010923SEvan.Yan@Sun.COM static int
pcishpc_slot_hpc_to_shpc(int state)229110923SEvan.Yan@Sun.COM pcishpc_slot_hpc_to_shpc(int state)
229210923SEvan.Yan@Sun.COM {
229310923SEvan.Yan@Sun.COM 	switch (state) {
229410923SEvan.Yan@Sun.COM 		case DDI_HP_CN_STATE_EMPTY:
229510923SEvan.Yan@Sun.COM 			return (0);
229610923SEvan.Yan@Sun.COM 
229710923SEvan.Yan@Sun.COM 		case DDI_HP_CN_STATE_POWERED:
229810923SEvan.Yan@Sun.COM 			return (PCI_HP_SLOT_POWER_ONLY);
229910923SEvan.Yan@Sun.COM 
230010923SEvan.Yan@Sun.COM 		case DDI_HP_CN_STATE_ENABLED:
230110923SEvan.Yan@Sun.COM 			return (PCI_HP_SLOT_ENABLED);
230210923SEvan.Yan@Sun.COM 
230310923SEvan.Yan@Sun.COM 		default:
230410923SEvan.Yan@Sun.COM 			return (PCI_HP_SLOT_DISABLED);
230510923SEvan.Yan@Sun.COM 	}
230610923SEvan.Yan@Sun.COM }
230710923SEvan.Yan@Sun.COM 
230810923SEvan.Yan@Sun.COM /*
230910923SEvan.Yan@Sun.COM  * pcishpc_slot_textslotstate()
231010923SEvan.Yan@Sun.COM  *
231110923SEvan.Yan@Sun.COM  * Convert the request into a text message.
231210923SEvan.Yan@Sun.COM  */
231310923SEvan.Yan@Sun.COM static char *
pcishpc_slot_textslotstate(ddi_hp_cn_state_t state)231410923SEvan.Yan@Sun.COM pcishpc_slot_textslotstate(ddi_hp_cn_state_t state)
231510923SEvan.Yan@Sun.COM {
231610923SEvan.Yan@Sun.COM 	/* Convert an HPC slot state into a textual string. */
231710923SEvan.Yan@Sun.COM 	if (state == DDI_HP_CN_STATE_EMPTY)
231810923SEvan.Yan@Sun.COM 		return ("HPC_SLOT_EMPTY");
231910923SEvan.Yan@Sun.COM 	else if (state == DDI_HP_CN_STATE_ENABLED)
232010923SEvan.Yan@Sun.COM 		return ("HPC_SLOT_ENABLED");
232110923SEvan.Yan@Sun.COM 	else if (state == DDI_HP_CN_STATE_POWERED)
232210923SEvan.Yan@Sun.COM 		return ("HPC_SLOT_POWERED_ONLY");
232310923SEvan.Yan@Sun.COM 	else
232410923SEvan.Yan@Sun.COM 		return ("HPC_SLOT_DISABLED");
232510923SEvan.Yan@Sun.COM }
232610923SEvan.Yan@Sun.COM 
232710923SEvan.Yan@Sun.COM 
232810923SEvan.Yan@Sun.COM /*
232910923SEvan.Yan@Sun.COM  * pcishpc_slot_textledstate()
233010923SEvan.Yan@Sun.COM  *
233110923SEvan.Yan@Sun.COM  * Convert the led state into a text message.
233210923SEvan.Yan@Sun.COM  */
233310923SEvan.Yan@Sun.COM static char *
pcishpc_slot_textledstate(pcie_hp_led_state_t state)233410923SEvan.Yan@Sun.COM pcishpc_slot_textledstate(pcie_hp_led_state_t state)
233510923SEvan.Yan@Sun.COM {
233610923SEvan.Yan@Sun.COM 	/* Convert an HPC led state into a textual string. */
233710923SEvan.Yan@Sun.COM 	switch (state) {
233810923SEvan.Yan@Sun.COM 		case PCIE_HP_LED_OFF:
233910923SEvan.Yan@Sun.COM 			return ("off");
234010923SEvan.Yan@Sun.COM 
234110923SEvan.Yan@Sun.COM 		case PCIE_HP_LED_ON:
234210923SEvan.Yan@Sun.COM 			return ("on");
234310923SEvan.Yan@Sun.COM 
234410923SEvan.Yan@Sun.COM 		case PCIE_HP_LED_BLINK:
234510923SEvan.Yan@Sun.COM 			return ("blink");
234610923SEvan.Yan@Sun.COM 	}
234710923SEvan.Yan@Sun.COM 	return ("unknown");
234810923SEvan.Yan@Sun.COM }
234910923SEvan.Yan@Sun.COM 
235010923SEvan.Yan@Sun.COM 
235110923SEvan.Yan@Sun.COM /*
235210923SEvan.Yan@Sun.COM  * pcishpc_read_reg()
235310923SEvan.Yan@Sun.COM  *
235410923SEvan.Yan@Sun.COM  * Read from a SHPC controller register.
235510923SEvan.Yan@Sun.COM  */
235610923SEvan.Yan@Sun.COM static uint32_t
pcishpc_read_reg(pcie_hp_ctrl_t * ctrl_p,int reg)235710923SEvan.Yan@Sun.COM pcishpc_read_reg(pcie_hp_ctrl_t *ctrl_p, int reg)
235810923SEvan.Yan@Sun.COM {
235910923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
236010923SEvan.Yan@Sun.COM 
236110923SEvan.Yan@Sun.COM 	/* Setup the SHPC dword select register. */
236210923SEvan.Yan@Sun.COM 	pci_config_put8(bus_p->bus_cfg_hdl,
236310923SEvan.Yan@Sun.COM 	    bus_p->bus_pci_hp_off + PCI_HP_DWORD_SELECT_OFF, (uint8_t)reg);
236410923SEvan.Yan@Sun.COM 
236510923SEvan.Yan@Sun.COM 	/* Read back the SHPC dword select register and verify. */
236610923SEvan.Yan@Sun.COM 	if (pci_config_get8(bus_p->bus_cfg_hdl, bus_p->bus_pci_hp_off +
236710923SEvan.Yan@Sun.COM 	    PCI_HP_DWORD_SELECT_OFF) != (uint8_t)reg) {
236810923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_read_reg() - Failed writing DWORD "
236910923SEvan.Yan@Sun.COM 		    "select reg\n");
237010923SEvan.Yan@Sun.COM 		return (0xFFFFFFFF);
237110923SEvan.Yan@Sun.COM 	}
237210923SEvan.Yan@Sun.COM 
237310923SEvan.Yan@Sun.COM 	/* Read from the SHPC dword data register. */
237410923SEvan.Yan@Sun.COM 	return (pci_config_get32(bus_p->bus_cfg_hdl,
237510923SEvan.Yan@Sun.COM 	    bus_p->bus_pci_hp_off + PCI_HP_DWORD_DATA_OFF));
237610923SEvan.Yan@Sun.COM }
237710923SEvan.Yan@Sun.COM 
237810923SEvan.Yan@Sun.COM 
237910923SEvan.Yan@Sun.COM /*
238010923SEvan.Yan@Sun.COM  * pcishpc_write_reg()
238110923SEvan.Yan@Sun.COM  *
238210923SEvan.Yan@Sun.COM  * Write to a SHPC controller register.
238310923SEvan.Yan@Sun.COM  */
238410923SEvan.Yan@Sun.COM static void
pcishpc_write_reg(pcie_hp_ctrl_t * ctrl_p,int reg,uint32_t data)238510923SEvan.Yan@Sun.COM pcishpc_write_reg(pcie_hp_ctrl_t *ctrl_p, int reg, uint32_t data)
238610923SEvan.Yan@Sun.COM {
238710923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
238810923SEvan.Yan@Sun.COM 
238910923SEvan.Yan@Sun.COM 	/* Setup the SHPC dword select register. */
239010923SEvan.Yan@Sun.COM 	pci_config_put8(bus_p->bus_cfg_hdl,
239110923SEvan.Yan@Sun.COM 	    bus_p->bus_pci_hp_off + PCI_HP_DWORD_SELECT_OFF, (uint8_t)reg);
239210923SEvan.Yan@Sun.COM 
239310923SEvan.Yan@Sun.COM 	/* Read back the SHPC dword select register and verify. */
239410923SEvan.Yan@Sun.COM 	if (pci_config_get8(bus_p->bus_cfg_hdl, bus_p->bus_pci_hp_off +
239510923SEvan.Yan@Sun.COM 	    PCI_HP_DWORD_SELECT_OFF) != (uint8_t)reg) {
239610923SEvan.Yan@Sun.COM 		PCIE_DBG("pcishpc_write_reg() - Failed writing "
239710923SEvan.Yan@Sun.COM 		    "DWORD select reg\n");
239810923SEvan.Yan@Sun.COM 		return;
239910923SEvan.Yan@Sun.COM 	}
240010923SEvan.Yan@Sun.COM 
240110923SEvan.Yan@Sun.COM 	/* Write to the SHPC dword data register. */
240210923SEvan.Yan@Sun.COM 	pci_config_put32(bus_p->bus_cfg_hdl,
240310923SEvan.Yan@Sun.COM 	    bus_p->bus_pci_hp_off + PCI_HP_DWORD_DATA_OFF, data);
240410923SEvan.Yan@Sun.COM 
240510923SEvan.Yan@Sun.COM 	/*
240610923SEvan.Yan@Sun.COM 	 * Issue a read of the VendorID/DeviceID just to force the previous
240710923SEvan.Yan@Sun.COM 	 * write to complete. This is probably not necessary, but it does
240810923SEvan.Yan@Sun.COM 	 * help enforce ordering if there is an issue.
240910923SEvan.Yan@Sun.COM 	 */
241010923SEvan.Yan@Sun.COM 	(void) pci_config_get16(bus_p->bus_cfg_hdl, PCI_CONF_VENID);
241110923SEvan.Yan@Sun.COM }
241210923SEvan.Yan@Sun.COM 
241310923SEvan.Yan@Sun.COM 
241410923SEvan.Yan@Sun.COM #ifdef	DEBUG
241510923SEvan.Yan@Sun.COM /*
241610923SEvan.Yan@Sun.COM  * pcishpc_dump_regs()
241710923SEvan.Yan@Sun.COM  *
241810923SEvan.Yan@Sun.COM  * Dumps all of the SHPC controller registers.
241910923SEvan.Yan@Sun.COM  */
242010923SEvan.Yan@Sun.COM static void
pcishpc_dump_regs(pcie_hp_ctrl_t * ctrl_p)242110923SEvan.Yan@Sun.COM pcishpc_dump_regs(pcie_hp_ctrl_t *ctrl_p)
242210923SEvan.Yan@Sun.COM {
242310923SEvan.Yan@Sun.COM 	int slot, numSlots;
242410923SEvan.Yan@Sun.COM 	uint32_t reg;
242510923SEvan.Yan@Sun.COM 	char *state;
242610923SEvan.Yan@Sun.COM 
242710923SEvan.Yan@Sun.COM 	if (!pcie_debug_flags)
242810923SEvan.Yan@Sun.COM 		return;
242910923SEvan.Yan@Sun.COM 
243010923SEvan.Yan@Sun.COM 	PCIE_DBG("pcishpc_dump_regs() called:\n");
243110923SEvan.Yan@Sun.COM 	PCIE_DBG("==========================================================");
243210923SEvan.Yan@Sun.COM 
243310923SEvan.Yan@Sun.COM 	PCIE_DBG("SHPC Base Offset				"
243410923SEvan.Yan@Sun.COM 	    ": 0x%08x\n", pcishpc_read_reg(ctrl_p, PCI_HP_BASE_OFFSET_REG));
243510923SEvan.Yan@Sun.COM 
243610923SEvan.Yan@Sun.COM 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOTS_AVAIL_I_REG);
243710923SEvan.Yan@Sun.COM 
243810923SEvan.Yan@Sun.COM 	PCIE_DBG("Number of PCIX slots avail (33 Mhz)		 : %d\n",
243910923SEvan.Yan@Sun.COM 	    (reg & 31));
244010923SEvan.Yan@Sun.COM 
244110923SEvan.Yan@Sun.COM 	PCIE_DBG("Number of PCIX slots avail (66 Mhz)		 : %d\n",
244210923SEvan.Yan@Sun.COM 	    ((reg>>8) & 31));
244310923SEvan.Yan@Sun.COM 
244410923SEvan.Yan@Sun.COM 	PCIE_DBG("Number of PCIX slots avail (100 Mhz)		: %d\n",
244510923SEvan.Yan@Sun.COM 	    ((reg>>16) & 31));
244610923SEvan.Yan@Sun.COM 
244710923SEvan.Yan@Sun.COM 	PCIE_DBG("Number of PCIX slots avail (133 Mhz)		: %d\n",
244810923SEvan.Yan@Sun.COM 	    ((reg>>24) & 31));
244910923SEvan.Yan@Sun.COM 
245010923SEvan.Yan@Sun.COM 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOTS_AVAIL_II_REG);
245110923SEvan.Yan@Sun.COM 
245210923SEvan.Yan@Sun.COM 	PCIE_DBG("Number of conventional PCI slots (66 Mhz) : %d\n",
245310923SEvan.Yan@Sun.COM 	    (reg & 31));
245410923SEvan.Yan@Sun.COM 
245510923SEvan.Yan@Sun.COM 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOT_CONFIGURATION_REG);
245610923SEvan.Yan@Sun.COM 
245710923SEvan.Yan@Sun.COM 	numSlots = (reg & 31);
245810923SEvan.Yan@Sun.COM 
245910923SEvan.Yan@Sun.COM 	PCIE_DBG("Number of Slots connected to this port	 : %d\n",
246010923SEvan.Yan@Sun.COM 	    numSlots);
246110923SEvan.Yan@Sun.COM 
246210923SEvan.Yan@Sun.COM 	PCIE_DBG("PCI Device # for First HotPlug Slot		 : %d\n",
246310923SEvan.Yan@Sun.COM 	    ((reg>>8) & 31));
246410923SEvan.Yan@Sun.COM 
246510923SEvan.Yan@Sun.COM 	PCIE_DBG("Physical Slot # for First PCI Device #	 : %d\n",
246610923SEvan.Yan@Sun.COM 	    ((reg>>16) & 0x7ff));
246710923SEvan.Yan@Sun.COM 
246810923SEvan.Yan@Sun.COM 	PCIE_DBG("Physical Slot Number Up/Down			 : %d\n",
246910923SEvan.Yan@Sun.COM 	    ((reg>>29) & 0x1));
247010923SEvan.Yan@Sun.COM 
247110923SEvan.Yan@Sun.COM 	PCIE_DBG("MRL Sensor Implemented			 : %s\n",
247210923SEvan.Yan@Sun.COM 	    (reg & PCI_HP_SLOT_CONFIG_MRL_SENSOR) ? "Yes" : "No");
247310923SEvan.Yan@Sun.COM 
247410923SEvan.Yan@Sun.COM 	PCIE_DBG("Attention Button Implemented			 : %s\n",
247510923SEvan.Yan@Sun.COM 	    (reg & PCI_HP_SLOT_CONFIG_ATTN_BUTTON) ? "Yes" : "No");
247610923SEvan.Yan@Sun.COM 
247710923SEvan.Yan@Sun.COM 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_PROF_IF_SBCR_REG);
247810923SEvan.Yan@Sun.COM 
247910923SEvan.Yan@Sun.COM 	switch (reg & 7) {
248010923SEvan.Yan@Sun.COM 		case 0:
248110923SEvan.Yan@Sun.COM 			state = "33Mhz Conventional PCI";
248210923SEvan.Yan@Sun.COM 			break;
248310923SEvan.Yan@Sun.COM 		case 1:
248410923SEvan.Yan@Sun.COM 			state = "66Mhz Conventional PCI";
248510923SEvan.Yan@Sun.COM 			break;
248610923SEvan.Yan@Sun.COM 		case 2:
248710923SEvan.Yan@Sun.COM 			state = "66Mhz PCI-X";
248810923SEvan.Yan@Sun.COM 			break;
248910923SEvan.Yan@Sun.COM 		case 3:
249010923SEvan.Yan@Sun.COM 			state = "100Mhz PCI-X";
249110923SEvan.Yan@Sun.COM 			break;
249210923SEvan.Yan@Sun.COM 		case 4:
249310923SEvan.Yan@Sun.COM 			state = "133Mhz PCI-X";
249410923SEvan.Yan@Sun.COM 			break;
249510923SEvan.Yan@Sun.COM 		default:
249610923SEvan.Yan@Sun.COM 			state = "Reserved (Error)";
249710923SEvan.Yan@Sun.COM 			break;
249810923SEvan.Yan@Sun.COM 	}
249910923SEvan.Yan@Sun.COM 
250010923SEvan.Yan@Sun.COM 	PCIE_DBG("Current Port Operation Mode		: %s\n", state);
250110923SEvan.Yan@Sun.COM 
250210923SEvan.Yan@Sun.COM 	PCIE_DBG("SHPC Interrupt Message Number		: %d\n",
250310923SEvan.Yan@Sun.COM 	    ((reg>>16) &31));
250410923SEvan.Yan@Sun.COM 
250510923SEvan.Yan@Sun.COM 	PCIE_DBG("SHPC Programming Interface		: %d\n",
250610923SEvan.Yan@Sun.COM 	    ((reg>>24) & 0xff));
250710923SEvan.Yan@Sun.COM 
250810923SEvan.Yan@Sun.COM 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG);
250910923SEvan.Yan@Sun.COM 
251010923SEvan.Yan@Sun.COM 	PCIE_DBG("SHPC Command Code			: %d\n",
251110923SEvan.Yan@Sun.COM 	    (reg & 0xff));
251210923SEvan.Yan@Sun.COM 
251310923SEvan.Yan@Sun.COM 	PCIE_DBG("SHPC Target Slot			: %d\n",
251410923SEvan.Yan@Sun.COM 	    ((reg>>8) & 31));
251510923SEvan.Yan@Sun.COM 
251610923SEvan.Yan@Sun.COM 	PCIE_DBG("SHPC Controller Busy			: %s\n",
251710923SEvan.Yan@Sun.COM 	    ((reg>>16) & 1) ? "Yes" : "No");
251810923SEvan.Yan@Sun.COM 
251910923SEvan.Yan@Sun.COM 	PCIE_DBG("SHPC Controller Err: MRL Sensor	: %s\n",
252010923SEvan.Yan@Sun.COM 	    ((reg>>17) & 1) ? "Yes" : "No");
252110923SEvan.Yan@Sun.COM 
252210923SEvan.Yan@Sun.COM 	PCIE_DBG("SHPC Controller Err: Invalid Command	: %s\n",
252310923SEvan.Yan@Sun.COM 	    ((reg>>18) & 1) ? "Yes" : "No");
252410923SEvan.Yan@Sun.COM 
252510923SEvan.Yan@Sun.COM 	PCIE_DBG("SHPC Controller Err: Invalid Speed/Mode : %s\n",
252610923SEvan.Yan@Sun.COM 	    ((reg>>19) & 1) ? "Yes" : "No");
252710923SEvan.Yan@Sun.COM 
252810923SEvan.Yan@Sun.COM 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_IRQ_LOCATOR_REG);
252910923SEvan.Yan@Sun.COM 
253010923SEvan.Yan@Sun.COM 	PCIE_DBG("Command Completion Interrupt Pending	: %s\n",
253110923SEvan.Yan@Sun.COM 	    (reg & PCI_HP_IRQ_CMD_COMPLETE) ? "Yes" : "No");
253210923SEvan.Yan@Sun.COM 
253310923SEvan.Yan@Sun.COM 	for (slot = 0; slot < numSlots; slot++) {
253410923SEvan.Yan@Sun.COM 		PCIE_DBG("Slot %d Interrupt Pending	: %s\n", slot+1,
253510923SEvan.Yan@Sun.COM 		    (reg & (PCI_HP_IRQ_SLOT_N_PENDING<<slot)) ? "Yes" : "No");
253610923SEvan.Yan@Sun.COM 	}
253710923SEvan.Yan@Sun.COM 
253810923SEvan.Yan@Sun.COM 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_SERR_LOCATOR_REG);
253910923SEvan.Yan@Sun.COM 
254010923SEvan.Yan@Sun.COM 	PCIE_DBG("Arbiter SERR Pending			: %s\n",
254110923SEvan.Yan@Sun.COM 	    (reg & PCI_HP_IRQ_SERR_ARBITER_PENDING) ? "Yes" : "No");
254210923SEvan.Yan@Sun.COM 
254310923SEvan.Yan@Sun.COM 	for (slot = 0; slot < numSlots; slot++) {
254410923SEvan.Yan@Sun.COM 		PCIE_DBG("Slot %d SERR Pending		: %s\n",
254510923SEvan.Yan@Sun.COM 		    slot+1, (reg &
254610923SEvan.Yan@Sun.COM 		    (PCI_HP_IRQ_SERR_SLOT_N_PENDING<<slot)) ? "Yes" : "No");
254710923SEvan.Yan@Sun.COM 	}
254810923SEvan.Yan@Sun.COM 
254910923SEvan.Yan@Sun.COM 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG);
255010923SEvan.Yan@Sun.COM 
255110923SEvan.Yan@Sun.COM 	PCIE_DBG("Global Interrupt Mask			: %s\n",
255210923SEvan.Yan@Sun.COM 	    (reg & PCI_HP_SERR_INT_GLOBAL_IRQ_MASK) ? "Yes" : "No");
255310923SEvan.Yan@Sun.COM 
255410923SEvan.Yan@Sun.COM 	PCIE_DBG("Global SERR Mask			: %s\n",
255510923SEvan.Yan@Sun.COM 	    (reg & PCI_HP_SERR_INT_GLOBAL_SERR_MASK) ? "Yes" : "No");
255610923SEvan.Yan@Sun.COM 
255710923SEvan.Yan@Sun.COM 	PCIE_DBG("Command Completion Interrupt Mask	: %s\n",
255810923SEvan.Yan@Sun.COM 	    (reg & PCI_HP_SERR_INT_CMD_COMPLETE_MASK) ? "Yes" : "No");
255910923SEvan.Yan@Sun.COM 
256010923SEvan.Yan@Sun.COM 	PCIE_DBG("Arbiter SERR Mask			: %s\n",
256110923SEvan.Yan@Sun.COM 	    (reg & PCI_HP_SERR_INT_ARBITER_SERR_MASK) ? "Yes" : "No");
256210923SEvan.Yan@Sun.COM 
256310923SEvan.Yan@Sun.COM 	PCIE_DBG("Command Completion Detected		: %s\n",
256410923SEvan.Yan@Sun.COM 	    (reg & PCI_HP_SERR_INT_CMD_COMPLETE_IRQ) ? "Yes" : "No");
256510923SEvan.Yan@Sun.COM 
256610923SEvan.Yan@Sun.COM 	PCIE_DBG("Arbiter Timeout Detected		: %s\n",
256710923SEvan.Yan@Sun.COM 	    (reg & PCI_HP_SERR_INT_ARBITER_IRQ) ? "Yes" : "No");
256810923SEvan.Yan@Sun.COM 
256910923SEvan.Yan@Sun.COM 	for (slot = 0; slot < numSlots; slot++) {
257010923SEvan.Yan@Sun.COM 		PCIE_DBG("Logical Slot %d Registers:\n", slot+1);
257110923SEvan.Yan@Sun.COM 		PCIE_DBG("------------------------------------\n");
257210923SEvan.Yan@Sun.COM 
257310923SEvan.Yan@Sun.COM 		reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot);
257410923SEvan.Yan@Sun.COM 
257510923SEvan.Yan@Sun.COM 		PCIE_DBG("Slot %d state			: %s\n", slot+1,
257610923SEvan.Yan@Sun.COM 		    pcishpc_slot_textslotstate(pcishpc_slot_shpc_to_hpc(reg)));
257710923SEvan.Yan@Sun.COM 
257810923SEvan.Yan@Sun.COM 		PCIE_DBG("Slot %d Power Indicator State	: %s\n", slot+1,
257910923SEvan.Yan@Sun.COM 		    pcishpc_slot_textledstate(pcishpc_led_shpc_to_hpc(
258010923SEvan.Yan@Sun.COM 		    (reg>>2) &3)));
258110923SEvan.Yan@Sun.COM 
258210923SEvan.Yan@Sun.COM 		PCIE_DBG("Slot %d Attention Indicator State : %s\n", slot+1,
258310923SEvan.Yan@Sun.COM 		    pcishpc_slot_textledstate(pcishpc_led_shpc_to_hpc(
258410923SEvan.Yan@Sun.COM 		    (reg>>4)&3)));
258510923SEvan.Yan@Sun.COM 
258610923SEvan.Yan@Sun.COM 		PCIE_DBG("Slot %d Power Fault		: %s\n", slot+1,
258710923SEvan.Yan@Sun.COM 		    ((reg>>6)&1) ? "Fault Detected" : "No Fault");
258810923SEvan.Yan@Sun.COM 		PCIE_DBG("Slot %d Attention Button	: %s\n", slot+1,
258910923SEvan.Yan@Sun.COM 		    ((reg>>7)&1) ? "Depressed" : "Not Depressed");
259010923SEvan.Yan@Sun.COM 		PCIE_DBG("Slot %d MRL Sensor		: %s\n", slot+1,
259110923SEvan.Yan@Sun.COM 		    ((reg>>8)&1) ? "Not Closed" : "Closed");
259210923SEvan.Yan@Sun.COM 		PCIE_DBG("Slot %d 66mhz Capable		: %s\n", slot+1,
259310923SEvan.Yan@Sun.COM 		    ((reg>>9)&1) ? "66mhz" : "33mgz");
259410923SEvan.Yan@Sun.COM 
259510923SEvan.Yan@Sun.COM 		switch ((reg>>10)&3) {
259610923SEvan.Yan@Sun.COM 			case 0:
259710923SEvan.Yan@Sun.COM 				state = "Card Present 7.5W";
259810923SEvan.Yan@Sun.COM 				break;
259910923SEvan.Yan@Sun.COM 			case 1:
260010923SEvan.Yan@Sun.COM 				state = "Card Present 15W";
260110923SEvan.Yan@Sun.COM 				break;
260210923SEvan.Yan@Sun.COM 			case 2:
260310923SEvan.Yan@Sun.COM 				state = "Card Present 25W";
260410923SEvan.Yan@Sun.COM 				break;
260510923SEvan.Yan@Sun.COM 			case 3:
260610923SEvan.Yan@Sun.COM 				state = "Slot Empty";
260710923SEvan.Yan@Sun.COM 				break;
260810923SEvan.Yan@Sun.COM 		}
260910923SEvan.Yan@Sun.COM 
261010923SEvan.Yan@Sun.COM 		PCIE_DBG("Slot %d PRSNT1#/PRSNT2#	: %s\n", slot+1,
261110923SEvan.Yan@Sun.COM 		    state);
261210923SEvan.Yan@Sun.COM 
261310923SEvan.Yan@Sun.COM 		switch ((reg>>12)&3) {
261410923SEvan.Yan@Sun.COM 			case 0:
261510923SEvan.Yan@Sun.COM 				state = "Non PCI-X";
261610923SEvan.Yan@Sun.COM 				break;
261710923SEvan.Yan@Sun.COM 			case 1:
261810923SEvan.Yan@Sun.COM 				state = "66mhz PCI-X";
261910923SEvan.Yan@Sun.COM 				break;
262010923SEvan.Yan@Sun.COM 			case 2:
262110923SEvan.Yan@Sun.COM 				state = "Reserved";
262210923SEvan.Yan@Sun.COM 				break;
262310923SEvan.Yan@Sun.COM 			case 3:
262410923SEvan.Yan@Sun.COM 				state = "133mhz PCI-X";
262510923SEvan.Yan@Sun.COM 				break;
262610923SEvan.Yan@Sun.COM 		}
262710923SEvan.Yan@Sun.COM 
262810923SEvan.Yan@Sun.COM 		PCIE_DBG("Slot %d Card Presence Change Detected	  : %s\n",
262910923SEvan.Yan@Sun.COM 		    slot+1, (reg & PCI_HP_SLOT_PRESENCE_DETECTED) ? "Yes" :
263010923SEvan.Yan@Sun.COM 		    "No");
263110923SEvan.Yan@Sun.COM 		PCIE_DBG("Slot %d Isolated Power Fault Detected	  : %s\n",
263210923SEvan.Yan@Sun.COM 		    slot+1, (reg & PCI_HP_SLOT_ISO_PWR_DETECTED) ? "Yes" :
263310923SEvan.Yan@Sun.COM 		    "No");
263410923SEvan.Yan@Sun.COM 		PCIE_DBG("Slot %d Attention Button Press Detected : %s\n",
263510923SEvan.Yan@Sun.COM 		    slot+1, (reg & PCI_HP_SLOT_ATTN_DETECTED) ? "Yes" : "No");
263610923SEvan.Yan@Sun.COM 		PCIE_DBG("Slot %d MRL Sensor Change Detected	  : %s\n",
263710923SEvan.Yan@Sun.COM 		    slot+1, (reg & PCI_HP_SLOT_MRL_DETECTED) ? "Yes" : "No");
263810923SEvan.Yan@Sun.COM 		PCIE_DBG("Slot %d Connected Power Fault Detected  : %s\n",
263910923SEvan.Yan@Sun.COM 		    slot+1, (reg & PCI_HP_SLOT_POWER_DETECTED) ? "Yes" : "No");
264010923SEvan.Yan@Sun.COM 
264110923SEvan.Yan@Sun.COM 		PCIE_DBG("Slot %d Card Presence IRQ Masked	  : %s\n",
264210923SEvan.Yan@Sun.COM 		    slot+1, (reg & PCI_HP_SLOT_PRESENCE_MASK) ? "Yes" : "No");
264310923SEvan.Yan@Sun.COM 		PCIE_DBG("Slot %d Isolated Power Fault IRQ Masked : %s\n",
264410923SEvan.Yan@Sun.COM 		    slot+1, (reg & PCI_HP_SLOT_ISO_PWR_MASK) ? "Yes" : "No");
264510923SEvan.Yan@Sun.COM 		PCIE_DBG("Slot %d Attention Button IRQ Masked	  : %s\n",
264610923SEvan.Yan@Sun.COM 		    slot+1, (reg & PCI_HP_SLOT_ATTN_MASK) ? "Yes" : "No");
264710923SEvan.Yan@Sun.COM 		PCIE_DBG("Slot %d MRL Sensor IRQ Masked		  : %s\n",
264810923SEvan.Yan@Sun.COM 		    slot+1, (reg & PCI_HP_SLOT_MRL_MASK) ? "Yes" : "No");
264910923SEvan.Yan@Sun.COM 		PCIE_DBG("Slot %d Connected Power Fault IRQ Masked : %s\n",
265010923SEvan.Yan@Sun.COM 		    slot+1, (reg & PCI_HP_SLOT_POWER_MASK) ? "Yes" : "No");
265110923SEvan.Yan@Sun.COM 		PCIE_DBG("Slot %d MRL Sensor SERR Masked          : %s\n",
265210923SEvan.Yan@Sun.COM 		    slot+1, (reg & PCI_HP_SLOT_MRL_SERR_MASK) ? "Yes" : "No");
265310923SEvan.Yan@Sun.COM 		PCIE_DBG("Slot %d Connected Power Fault SERR Masked : %s\n",
265410923SEvan.Yan@Sun.COM 		    slot+1, (reg & PCI_HP_SLOT_POWER_SERR_MASK) ? "Yes" : "No");
265510923SEvan.Yan@Sun.COM 	}
265610923SEvan.Yan@Sun.COM }
265710923SEvan.Yan@Sun.COM #endif	/* DEBUG */
2658