126947304SEvan Yan /*
226947304SEvan Yan  * CDDL HEADER START
326947304SEvan Yan  *
426947304SEvan Yan  * The contents of this file are subject to the terms of the
526947304SEvan Yan  * Common Development and Distribution License (the "License").
626947304SEvan Yan  * You may not use this file except in compliance with the License.
726947304SEvan Yan  *
826947304SEvan Yan  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
926947304SEvan Yan  * or http://www.opensolaris.org/os/licensing.
1026947304SEvan Yan  * See the License for the specific language governing permissions
1126947304SEvan Yan  * and limitations under the License.
1226947304SEvan Yan  *
1326947304SEvan Yan  * When distributing Covered Code, include this CDDL HEADER in each
1426947304SEvan Yan  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1526947304SEvan Yan  * If applicable, add the following below this CDDL HEADER, with the
1626947304SEvan Yan  * fields enclosed by brackets "[]" replaced with your own identifying
1726947304SEvan Yan  * information: Portions Copyright [yyyy] [name of copyright owner]
1826947304SEvan Yan  *
1926947304SEvan Yan  * CDDL HEADER END
2026947304SEvan Yan  */
2126947304SEvan Yan /*
2270f83219SEvan Yan  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2326947304SEvan Yan  * Use is subject to license terms.
24*b3d69c05SRobert Mustacchi  * Copyright 2019 Joyent, Inc.
2526947304SEvan Yan  */
2626947304SEvan Yan 
2726947304SEvan Yan /*
2826947304SEvan Yan  * This file contains PCI HotPlug functionality that is compatible with the
2926947304SEvan Yan  * PCI SHPC specification 1.x.
3026947304SEvan Yan  *
3126947304SEvan Yan  * NOTE: This file is compiled and delivered through misc/pcie module.
3226947304SEvan Yan  */
3326947304SEvan Yan 
3426947304SEvan Yan #include <sys/note.h>
3526947304SEvan Yan #include <sys/conf.h>
3626947304SEvan Yan #include <sys/kmem.h>
3726947304SEvan Yan #include <sys/kstat.h>
3826947304SEvan Yan #include <sys/debug.h>
3926947304SEvan Yan #include <sys/vtrace.h>
4026947304SEvan Yan #include <sys/autoconf.h>
4126947304SEvan Yan #include <sys/varargs.h>
4226947304SEvan Yan #include <sys/hwconf.h>
4326947304SEvan Yan #include <sys/ddi_impldefs.h>
4426947304SEvan Yan #include <sys/callb.h>
4526947304SEvan Yan #include <sys/ddi.h>
4626947304SEvan Yan #include <sys/sunddi.h>
4726947304SEvan Yan #include <sys/sunndi.h>
4826947304SEvan Yan #include <sys/sysevent/dr.h>
4926947304SEvan Yan #include <sys/ndi_impldefs.h>
5026947304SEvan Yan #include <sys/pci_impl.h>
5126947304SEvan Yan #include <sys/hotplug/pci/pcie_hp.h>
5226947304SEvan Yan #include <sys/hotplug/pci/pcishpc.h>
5326947304SEvan Yan 
5426947304SEvan Yan typedef struct pcishpc_prop {
5526947304SEvan Yan 	char	*prop_name;
5626947304SEvan Yan 	char	*prop_value;
5726947304SEvan Yan } pcishpc_prop_t;
5826947304SEvan Yan 
5926947304SEvan Yan static pcishpc_prop_t	pcishpc_props[] = {
6026947304SEvan Yan 	{ PCIEHPC_PROP_LED_FAULT,	PCIEHPC_PROP_VALUE_LED },
6126947304SEvan Yan 	{ PCIEHPC_PROP_LED_POWER,	PCIEHPC_PROP_VALUE_LED },
6226947304SEvan Yan 	{ PCIEHPC_PROP_LED_ATTN,	PCIEHPC_PROP_VALUE_LED },
6326947304SEvan Yan 	{ PCIEHPC_PROP_LED_ACTIVE,	PCIEHPC_PROP_VALUE_LED },
6426947304SEvan Yan 	{ PCIEHPC_PROP_CARD_TYPE,	PCIEHPC_PROP_VALUE_TYPE },
6526947304SEvan Yan 	{ PCIEHPC_PROP_BOARD_TYPE,	PCIEHPC_PROP_VALUE_TYPE },
6626947304SEvan Yan 	{ PCIEHPC_PROP_SLOT_CONDITION,	PCIEHPC_PROP_VALUE_TYPE }
6726947304SEvan Yan };
6826947304SEvan Yan 
6926947304SEvan Yan /* reset delay to 1 sec. */
7026947304SEvan Yan static int pcishpc_reset_delay = 1000000;
7126947304SEvan Yan 
7226947304SEvan Yan /* Local function prototype */
7326947304SEvan Yan static pcie_hp_ctrl_t *pcishpc_create_controller(dev_info_t *dip);
7426947304SEvan Yan static int	pcishpc_setup_controller(pcie_hp_ctrl_t *ctrl_p);
7526947304SEvan Yan static int	pcishpc_destroy_controller(dev_info_t *dip);
7626947304SEvan Yan static pcie_hp_slot_t	*pcishpc_create_slot(pcie_hp_ctrl_t *ctrl_p);
7726947304SEvan Yan static int	pcishpc_register_slot(pcie_hp_ctrl_t *ctrl_p, int slot);
7826947304SEvan Yan static int	pcishpc_destroy_slots(pcie_hp_ctrl_t *ctrl_p);
7926947304SEvan Yan static int	pcishpc_slot_get_property(pcie_hp_slot_t *slot_p,
8026947304SEvan Yan 		    ddi_hp_property_t *arg, ddi_hp_property_t *rval);
8126947304SEvan Yan static int	pcishpc_slot_set_property(pcie_hp_slot_t *slot_p,
8226947304SEvan Yan 		    ddi_hp_property_t *arg, ddi_hp_property_t *rval);
8326947304SEvan Yan static int	pcishpc_issue_command(pcie_hp_ctrl_t *ctrl_p,
8426947304SEvan Yan 		    uint32_t cmd_code);
8526947304SEvan Yan static int	pcishpc_wait_busy(pcie_hp_ctrl_t *ctrl_p);
8626947304SEvan Yan static void	pcishpc_attn_btn_handler(pcie_hp_slot_t *slot_p);
8726947304SEvan Yan static void	pcishpc_get_slot_state(pcie_hp_slot_t *slot_p);
8826947304SEvan Yan static int	pcishpc_set_slot_state(pcie_hp_slot_t *slot_p,
8926947304SEvan Yan 		    ddi_hp_cn_state_t new_slot_state);
9026947304SEvan Yan static void	pcishpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p, int slot);
9126947304SEvan Yan static int	pcishpc_set_bus_speed(pcie_hp_slot_t *slot_p);
9226947304SEvan Yan static int	pcishpc_setled(pcie_hp_slot_t *slot_p, pcie_hp_led_t led,
9326947304SEvan Yan 		    pcie_hp_led_state_t state);
9426947304SEvan Yan static int	pcishpc_led_shpc_to_hpc(int state);
9526947304SEvan Yan static int	pcishpc_led_hpc_to_shpc(int state);
9626947304SEvan Yan static int	pcishpc_slot_shpc_to_hpc(int shpc_state);
9726947304SEvan Yan static int	pcishpc_slot_hpc_to_shpc(int state);
9826947304SEvan Yan static char	*pcishpc_slot_textslotstate(ddi_hp_cn_state_t state);
9926947304SEvan Yan static char	*pcishpc_slot_textledstate(pcie_hp_led_state_t state);
10026947304SEvan Yan 
10126947304SEvan Yan static uint32_t	pcishpc_read_reg(pcie_hp_ctrl_t *ctrl_p, int reg);
10226947304SEvan Yan static void	pcishpc_write_reg(pcie_hp_ctrl_t *ctrl_p, int reg,
10326947304SEvan Yan 		    uint32_t data);
10426947304SEvan Yan 
10526947304SEvan Yan static int	pcishpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
10626947304SEvan Yan 		    ddi_hp_cn_state_t target_state);
10726947304SEvan Yan static int	pcishpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
10826947304SEvan Yan 		    ddi_hp_cn_state_t target_state);
10926947304SEvan Yan static int	pcishpc_change_slot_state(pcie_hp_slot_t *slot_p,
11026947304SEvan Yan 		    ddi_hp_cn_state_t target_state);
11126947304SEvan Yan 
11226947304SEvan Yan static int	pcishpc_slot_poweron(pcie_hp_slot_t *slot_p,
11326947304SEvan Yan 		    ddi_hp_cn_state_t *result_state);
11426947304SEvan Yan static int	pcishpc_slot_poweroff(pcie_hp_slot_t *slot_p,
11526947304SEvan Yan 		    ddi_hp_cn_state_t *result_state);
11626947304SEvan Yan static int	pcishpc_slot_probe(pcie_hp_slot_t *slot_p);
11726947304SEvan Yan static int	pcishpc_slot_unprobe(pcie_hp_slot_t *slot_p);
11826947304SEvan Yan #ifdef	DEBUG
11926947304SEvan Yan static void	pcishpc_dump_regs(pcie_hp_ctrl_t *ctrl_p);
12026947304SEvan Yan #endif	/* DEBUG */
12126947304SEvan Yan 
12226947304SEvan Yan 
12326947304SEvan Yan /*
12426947304SEvan Yan  * Global functions (called by other drivers/modules)
12526947304SEvan Yan  */
12626947304SEvan Yan 
12726947304SEvan Yan /*
12826947304SEvan Yan  * pcishpc_init()
12926947304SEvan Yan  *
13026947304SEvan Yan  * Install and configure an SHPC controller and register the HotPlug slots
13126947304SEvan Yan  * with the Solaris HotPlug framework. This function is usually called by
13226947304SEvan Yan  * a PCI bridge Nexus driver that has a built in SHPC controller.
13326947304SEvan Yan  */
13426947304SEvan Yan int
13526947304SEvan Yan pcishpc_init(dev_info_t *dip)
13626947304SEvan Yan {
13726947304SEvan Yan 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
13826947304SEvan Yan 	pcie_hp_ctrl_t	*ctrl_p;
13926947304SEvan Yan 	int		i;
14026947304SEvan Yan 
14126947304SEvan Yan 	PCIE_DBG("pcishpc_init() called from %s#%d\n",
14226947304SEvan Yan 	    ddi_driver_name(dip), ddi_get_instance(dip));
14326947304SEvan Yan 
14426947304SEvan Yan 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) != NULL) {
14526947304SEvan Yan 		PCIE_DBG("pcishpc_init() shpc instance already "
14626947304SEvan Yan 		    "initialized!\n");
14726947304SEvan Yan 		return (DDI_SUCCESS);
14826947304SEvan Yan 	}
14926947304SEvan Yan 
15026947304SEvan Yan 	/* Initialize soft state structure for the SHPC instance. */
15126947304SEvan Yan 	ctrl_p = pcishpc_create_controller(dip);
15226947304SEvan Yan 
15326947304SEvan Yan 	if (ctrl_p == NULL) {
15426947304SEvan Yan 		PCIE_DBG("pcishpc_init() failed to create shpc softstate\n");
15526947304SEvan Yan 		return (DDI_FAILURE);
15626947304SEvan Yan 	}
15726947304SEvan Yan 
15826947304SEvan Yan 	if (pcishpc_setup_controller(ctrl_p) != DDI_SUCCESS) {
15926947304SEvan Yan 		PCIE_DBG("pcishpc_init() failed to setup controller\n");
16026947304SEvan Yan 		goto cleanup;
16126947304SEvan Yan 	}
16226947304SEvan Yan 
16326947304SEvan Yan 	/*
16426947304SEvan Yan 	 * Setup resource maps for this bus node.
16526947304SEvan Yan 	 */
16626947304SEvan Yan 	(void) pci_resource_setup(dip);
16726947304SEvan Yan 
16826947304SEvan Yan #ifdef	DEBUG
16926947304SEvan Yan 	PCIE_DBG("%s%d: P2P bridge register dump:\n",
17026947304SEvan Yan 	    ddi_driver_name(dip), ddi_get_instance(dip));
17126947304SEvan Yan 
17226947304SEvan Yan 	for (i = 0; i < 0x100; i += 4) {
17326947304SEvan Yan 		PCIE_DBG("SHPC Cfg reg 0x%02x: %08x\n", i,
17426947304SEvan Yan 		    pci_config_get32(bus_p->bus_cfg_hdl, i));
17526947304SEvan Yan 	}
17626947304SEvan Yan #endif	/* DEBUG */
17726947304SEvan Yan 
17826947304SEvan Yan 	/* Setup each HotPlug slot on this SHPC controller. */
17926947304SEvan Yan 	for (i = 0; i < ctrl_p->hc_num_slots_impl; i++) {
18026947304SEvan Yan 		if (pcishpc_register_slot(ctrl_p, i) != DDI_SUCCESS) {
18126947304SEvan Yan 			PCIE_DBG("pcishpc_init() failed to register "
18226947304SEvan Yan 			    "slot %d\n", i);
18326947304SEvan Yan 			goto cleanup1;
18426947304SEvan Yan 		}
18526947304SEvan Yan 		if (pcie_create_minor_node(ctrl_p, i) != DDI_SUCCESS) {
18626947304SEvan Yan 			PCIE_DBG("pcishpc_init() failed to create "
18726947304SEvan Yan 			    "minor node for slot %d\n", i);
18826947304SEvan Yan 			goto cleanup1;
18926947304SEvan Yan 		}
19026947304SEvan Yan 	}
19126947304SEvan Yan 
19226947304SEvan Yan #ifdef	DEBUG
19326947304SEvan Yan 	/* Dump out the SHPC registers. */
19426947304SEvan Yan 	pcishpc_dump_regs(ctrl_p);
19526947304SEvan Yan #endif	/* DEBUG */
19626947304SEvan Yan 
19726947304SEvan Yan 	PCIE_DBG("pcishpc_init() success(dip=%p)\n", dip);
19826947304SEvan Yan 	return (DDI_SUCCESS);
19926947304SEvan Yan 
20026947304SEvan Yan cleanup1:
20126947304SEvan Yan 	for (i = 0; i < ctrl_p->hc_num_slots_impl; i++) {
20226947304SEvan Yan 		if (ctrl_p->hc_slots[i] == NULL)
20326947304SEvan Yan 			continue;
20426947304SEvan Yan 
20526947304SEvan Yan 		pcie_remove_minor_node(ctrl_p, i);
20626947304SEvan Yan 	}
20726947304SEvan Yan 	(void) pci_resource_destroy(dip);
20826947304SEvan Yan cleanup:
20926947304SEvan Yan 	(void) pcishpc_destroy_controller(dip);
21026947304SEvan Yan 	return (DDI_FAILURE);
21126947304SEvan Yan }
21226947304SEvan Yan 
21326947304SEvan Yan /*
21426947304SEvan Yan  * pcishpc_uninit()
21526947304SEvan Yan  * Unload the HogPlug controller driver and deallocate all resources.
21626947304SEvan Yan  */
21726947304SEvan Yan int
21826947304SEvan Yan pcishpc_uninit(dev_info_t *dip)
21926947304SEvan Yan {
22026947304SEvan Yan 	pcie_hp_ctrl_t *ctrl_p;
22126947304SEvan Yan 	int i;
22226947304SEvan Yan 
22326947304SEvan Yan 	PCIE_DBG("pcishpc_uninit() called(dip=%p)\n", dip);
22426947304SEvan Yan 
22526947304SEvan Yan 	ctrl_p = PCIE_GET_HP_CTRL(dip);
22626947304SEvan Yan 
22726947304SEvan Yan 	if (!ctrl_p) {
22826947304SEvan Yan 		PCIE_DBG("pcishpc_uninit() Unable to find softstate\n");
22926947304SEvan Yan 		return (DDI_FAILURE);
23026947304SEvan Yan 	}
23126947304SEvan Yan 
23226947304SEvan Yan 	for (i = 0; i < PCIE_HP_MAX_SLOTS; i++) {
23326947304SEvan Yan 		if (ctrl_p->hc_slots[i] == NULL)
23426947304SEvan Yan 			continue;
23526947304SEvan Yan 
23626947304SEvan Yan 		pcie_remove_minor_node(ctrl_p, i);
23726947304SEvan Yan 	}
23826947304SEvan Yan 
23926947304SEvan Yan 	ctrl_p->hc_flags = 0;
24026947304SEvan Yan 
24126947304SEvan Yan 	/*
24226947304SEvan Yan 	 * Destroy resource maps for this bus node.
24326947304SEvan Yan 	 */
24426947304SEvan Yan 	(void) pci_resource_destroy(dip);
24526947304SEvan Yan 
24626947304SEvan Yan 	(void) pcishpc_destroy_controller(dip);
24726947304SEvan Yan 
24826947304SEvan Yan 	PCIE_DBG("pcishpc_uninit() success(dip=%p)\n", dip);
24926947304SEvan Yan 
25026947304SEvan Yan 	return (DDI_SUCCESS);
25126947304SEvan Yan }
25226947304SEvan Yan 
25326947304SEvan Yan /*
25426947304SEvan Yan  * pcishpc_intr()
25526947304SEvan Yan  *
25626947304SEvan Yan  * This is the SHPC controller interrupt handler.
25726947304SEvan Yan  */
25826947304SEvan Yan int
25926947304SEvan Yan pcishpc_intr(dev_info_t *dip)
26026947304SEvan Yan {
26126947304SEvan Yan 	pcie_hp_ctrl_t	*ctrl_p;
26226947304SEvan Yan 	uint32_t	irq_locator, irq_serr_locator, reg;
26326947304SEvan Yan 	int		slot;
26426947304SEvan Yan 
26526947304SEvan Yan 	PCIE_DBG("pcishpc_intr() called\n");
26626947304SEvan Yan 
26726947304SEvan Yan 	/* get the soft state structure for this dip */
26826947304SEvan Yan 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
26926947304SEvan Yan 		return (DDI_INTR_UNCLAIMED);
27026947304SEvan Yan 
27126947304SEvan Yan 	mutex_enter(&ctrl_p->hc_mutex);
27226947304SEvan Yan 
27326947304SEvan Yan 	if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
27426947304SEvan Yan 		PCIE_DBG("pcishpc_intr() unclaimed\n");
27526947304SEvan Yan 		mutex_exit(&ctrl_p->hc_mutex);
27626947304SEvan Yan 		return (DDI_INTR_UNCLAIMED);
27726947304SEvan Yan 	}
27826947304SEvan Yan 
27926947304SEvan Yan 	PCIE_DBG("pcishpc_intr() interrupt received\n");
28026947304SEvan Yan 
28126947304SEvan Yan 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG);
28226947304SEvan Yan 
28326947304SEvan Yan 	if (reg & PCI_HP_SERR_INT_CMD_COMPLETE_IRQ) {
28426947304SEvan Yan 		PCIE_DBG("pcishpc_intr() "
28526947304SEvan Yan 		    "PCI_HP_SERR_INT_CMD_COMPLETE_IRQ detected\n");
28626947304SEvan Yan 		ctrl_p->hc_cmd_pending = B_FALSE;
28726947304SEvan Yan 		cv_signal(&ctrl_p->hc_cmd_comp_cv);
28826947304SEvan Yan 	}
28926947304SEvan Yan 
29026947304SEvan Yan 	if (reg & PCI_HP_SERR_INT_ARBITER_IRQ) {
29126947304SEvan Yan 		PCIE_DBG("pcishpc_intr() PCI_HP_SERR_INT_ARBITER_IRQ "
29226947304SEvan Yan 		    "detected\n");
29326947304SEvan Yan 		ctrl_p->hc_arbiter_timeout = B_TRUE;
29426947304SEvan Yan 	}
29526947304SEvan Yan 
29626947304SEvan Yan 	/* Write back the SERR INT register to acknowledge the IRQs. */
29726947304SEvan Yan 	pcishpc_write_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG, reg);
29826947304SEvan Yan 
29926947304SEvan Yan 	irq_locator = pcishpc_read_reg(ctrl_p, PCI_HP_IRQ_LOCATOR_REG);
30026947304SEvan Yan 	irq_serr_locator = pcishpc_read_reg(ctrl_p, PCI_HP_SERR_LOCATOR_REG);
30126947304SEvan Yan 
30226947304SEvan Yan 	/* Check for slot events that might have occured. */
30326947304SEvan Yan 	for (slot = 0; slot < ctrl_p->hc_num_slots_impl; slot++) {
30426947304SEvan Yan 		if ((irq_locator & (PCI_HP_IRQ_SLOT_N_PENDING<<slot)) ||
30526947304SEvan Yan 		    (irq_serr_locator &
30626947304SEvan Yan 		    (PCI_HP_IRQ_SERR_SLOT_N_PENDING<<slot))) {
30726947304SEvan Yan 			PCIE_DBG("pcishpc_intr() slot %d and "
30826947304SEvan Yan 			    "pending IRQ\n", slot+1);
30926947304SEvan Yan 
31026947304SEvan Yan 			reg = pcishpc_read_reg(ctrl_p,
31126947304SEvan Yan 			    PCI_HP_LOGICAL_SLOT_REGS+slot);
31226947304SEvan Yan 
31326947304SEvan Yan 			if (reg & PCI_HP_SLOT_PRESENCE_DETECTED)
31426947304SEvan Yan 				PCIE_DBG("slot %d: "
31526947304SEvan Yan 				    "PCI_HP_SLOT_PRESENCE_DETECTED\n",
31626947304SEvan Yan 				    slot+1);
31726947304SEvan Yan 
31826947304SEvan Yan 			if (reg & PCI_HP_SLOT_ISO_PWR_DETECTED)
31926947304SEvan Yan 				PCIE_DBG("slot %d: "
32026947304SEvan Yan 				    "PCI_HP_SLOT_ISO_PWR_DETECTED\n",
32126947304SEvan Yan 				    slot+1);
32226947304SEvan Yan 
32326947304SEvan Yan 			if (reg & PCI_HP_SLOT_ATTN_DETECTED) {
32426947304SEvan Yan 				PCIE_DBG("slot %d: "
32526947304SEvan Yan 				    "PCI_HP_SLOT_ATTN_DETECTED\n", slot+1);
32626947304SEvan Yan 
32726947304SEvan Yan 				/*
32826947304SEvan Yan 				 * if ATTN button event is still pending
32926947304SEvan Yan 				 * then cancel it
33026947304SEvan Yan 				 */
33126947304SEvan Yan 				if (ctrl_p->hc_slots[slot]->
33226947304SEvan Yan 				    hs_attn_btn_pending == B_TRUE)
33326947304SEvan Yan 					ctrl_p->hc_slots[slot]->
33426947304SEvan Yan 					    hs_attn_btn_pending = B_FALSE;
33526947304SEvan Yan 
33626947304SEvan Yan 				/* wake up the ATTN event handler */
33726947304SEvan Yan 				cv_signal(&ctrl_p->hc_slots[slot]->
33826947304SEvan Yan 				    hs_attn_btn_cv);
33926947304SEvan Yan 			}
34026947304SEvan Yan 
34126947304SEvan Yan 			if (reg & PCI_HP_SLOT_MRL_DETECTED)
34226947304SEvan Yan 				PCIE_DBG("slot %d: "
34326947304SEvan Yan 				    "PCI_HP_SLOT_MRL_DETECTED\n", slot+1);
34426947304SEvan Yan 
34526947304SEvan Yan 			if (reg & PCI_HP_SLOT_POWER_DETECTED)
34626947304SEvan Yan 				PCIE_DBG("slot %d: "
34726947304SEvan Yan 				    "PCI_HP_SLOT_POWER_DETECTED\n", slot+1);
34826947304SEvan Yan 
34926947304SEvan Yan 			/* Acknoledge any slot interrupts */
35026947304SEvan Yan 			pcishpc_write_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot,
35126947304SEvan Yan 			    reg);
35226947304SEvan Yan 		}
35326947304SEvan Yan 	}
35426947304SEvan Yan 
35526947304SEvan Yan 	mutex_exit(&ctrl_p->hc_mutex);
35626947304SEvan Yan 
35726947304SEvan Yan 	PCIE_DBG("pcishpc_intr() claimed\n");
35826947304SEvan Yan 
35926947304SEvan Yan 	return (DDI_INTR_CLAIMED);
36026947304SEvan Yan }
36126947304SEvan Yan 
36226947304SEvan Yan int
36326947304SEvan Yan pcishpc_slot_get_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
36426947304SEvan Yan     ddi_hp_property_t *rval)
36526947304SEvan Yan {
36626947304SEvan Yan 	ddi_hp_property_t request, result;
36726947304SEvan Yan #ifdef _SYSCALL32_IMPL
36826947304SEvan Yan 	ddi_hp_property32_t request32, result32;
36926947304SEvan Yan #endif
37026947304SEvan Yan 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
371296f12dcSToomas Soome 	nvlist_t	*prop_list;
37226947304SEvan Yan 	nvlist_t	*prop_rlist; /* nvlist for return values */
373296f12dcSToomas Soome 	nvpair_t	*prop_pair;
374296f12dcSToomas Soome 	char		*name, *value;
37526947304SEvan Yan 	int		ret = DDI_SUCCESS;
37626947304SEvan Yan 	int		i, n;
37726947304SEvan Yan 	boolean_t	get_all_prop = B_FALSE;
37826947304SEvan Yan 
37926947304SEvan Yan 	if (get_udatamodel() == DATAMODEL_NATIVE) {
38026947304SEvan Yan 		if (copyin(arg, &request, sizeof (ddi_hp_property_t)) ||
38126947304SEvan Yan 		    copyin(rval, &result, sizeof (ddi_hp_property_t)))
38226947304SEvan Yan 			return (DDI_FAILURE);
38326947304SEvan Yan 	}
38426947304SEvan Yan #ifdef _SYSCALL32_IMPL
38526947304SEvan Yan 	else {
38626947304SEvan Yan 		bzero(&request, sizeof (request));
38726947304SEvan Yan 		bzero(&result, sizeof (result));
38826947304SEvan Yan 		if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)) ||
38926947304SEvan Yan 		    copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
39026947304SEvan Yan 			return (DDI_FAILURE);
39126947304SEvan Yan 		request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
39226947304SEvan Yan 		request.buf_size = request32.buf_size;
39326947304SEvan Yan 		result.nvlist_buf = (char *)(uintptr_t)result32.nvlist_buf;
39426947304SEvan Yan 		result.buf_size = result32.buf_size;
39526947304SEvan Yan 	}
39626947304SEvan Yan #endif
39726947304SEvan Yan 
39826947304SEvan Yan 	if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
39926947304SEvan Yan 	    &prop_list)) != DDI_SUCCESS)
40026947304SEvan Yan 		return (ret);
40126947304SEvan Yan 
40226947304SEvan Yan 	if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
40326947304SEvan Yan 		ret = DDI_ENOMEM;
40426947304SEvan Yan 		goto get_prop_cleanup;
40526947304SEvan Yan 	}
40626947304SEvan Yan 
40726947304SEvan Yan 	/* check whether the requested property is "all" or "help" */
40826947304SEvan Yan 	prop_pair = nvlist_next_nvpair(prop_list, NULL);
40926947304SEvan Yan 	if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair)) {
41026947304SEvan Yan 		name = nvpair_name(prop_pair);
41126947304SEvan Yan 		n = sizeof (pcishpc_props) / sizeof (pcishpc_prop_t);
41226947304SEvan Yan 
41326947304SEvan Yan 		if (strcmp(name, PCIEHPC_PROP_ALL) == 0) {
41426947304SEvan Yan 			(void) nvlist_remove_all(prop_list, PCIEHPC_PROP_ALL);
41526947304SEvan Yan 
41626947304SEvan Yan 			/*
41726947304SEvan Yan 			 * Add all properties into the request list, so that we
41826947304SEvan Yan 			 * will get the values in the following for loop.
41926947304SEvan Yan 			 */
42026947304SEvan Yan 			for (i = 0; i < n; i++) {
42126947304SEvan Yan 				if (nvlist_add_string(prop_list,
42226947304SEvan Yan 				    pcishpc_props[i].prop_name, "") != 0) {
42326947304SEvan Yan 					ret = DDI_FAILURE;
42426947304SEvan Yan 					goto get_prop_cleanup1;
42526947304SEvan Yan 				}
42626947304SEvan Yan 			}
42726947304SEvan Yan 			get_all_prop = B_TRUE;
42826947304SEvan Yan 		} else if (strcmp(name, PCIEHPC_PROP_HELP) == 0) {
42926947304SEvan Yan 			/*
43026947304SEvan Yan 			 * Empty the request list, and add help strings into the
43126947304SEvan Yan 			 * return list. We will pass the following for loop.
43226947304SEvan Yan 			 */
43326947304SEvan Yan 			(void) nvlist_remove_all(prop_list, PCIEHPC_PROP_HELP);
43426947304SEvan Yan 
43526947304SEvan Yan 			for (i = 0; i < n; i++) {
43626947304SEvan Yan 				if (nvlist_add_string(prop_rlist,
43726947304SEvan Yan 				    pcishpc_props[i].prop_name,
43826947304SEvan Yan 				    pcishpc_props[i].prop_value) != 0) {
43926947304SEvan Yan 					ret = DDI_FAILURE;
44026947304SEvan Yan 					goto get_prop_cleanup1;
44126947304SEvan Yan 				}
44226947304SEvan Yan 			}
44326947304SEvan Yan 		}
44426947304SEvan Yan 	}
44526947304SEvan Yan 
44626947304SEvan Yan 	mutex_enter(&ctrl_p->hc_mutex);
44726947304SEvan Yan 
44826947304SEvan Yan 	/* get the current slot state */
44926947304SEvan Yan 	pcishpc_get_slot_state(slot_p);
45026947304SEvan Yan 
45126947304SEvan Yan 	/* for each requested property, get the value and add it to nvlist */
45226947304SEvan Yan 	prop_pair = NULL;
453*b3d69c05SRobert Mustacchi 	while ((prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) != NULL) {
45426947304SEvan Yan 		name = nvpair_name(prop_pair);
455*b3d69c05SRobert Mustacchi 		value = NULL;
45626947304SEvan Yan 
45726947304SEvan Yan 		if (strcmp(name, PCIEHPC_PROP_LED_FAULT) == 0) {
45826947304SEvan Yan 			value = pcie_led_state_text(
45926947304SEvan Yan 			    slot_p->hs_fault_led_state);
46026947304SEvan Yan 		} else if (strcmp(name, PCIEHPC_PROP_LED_POWER) == 0) {
46126947304SEvan Yan 			value = pcie_led_state_text(
46226947304SEvan Yan 			    slot_p->hs_power_led_state);
46326947304SEvan Yan 		} else if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
46426947304SEvan Yan 			value = pcie_led_state_text(
46526947304SEvan Yan 			    slot_p->hs_attn_led_state);
46626947304SEvan Yan 		} else if (strcmp(name, PCIEHPC_PROP_LED_ACTIVE) == 0) {
46726947304SEvan Yan 			value = pcie_led_state_text(
46826947304SEvan Yan 			    slot_p->hs_active_led_state);
46926947304SEvan Yan 		} else if (strcmp(name, PCIEHPC_PROP_CARD_TYPE) == 0) {
47026947304SEvan Yan 			ddi_acc_handle_t	handle;
47126947304SEvan Yan 			dev_info_t	*cdip;
47226947304SEvan Yan 			uint8_t		prog_class, base_class, sub_class;
47326947304SEvan Yan 			int		i;
47426947304SEvan Yan 
47526947304SEvan Yan 			mutex_exit(&ctrl_p->hc_mutex);
47626947304SEvan Yan 			cdip = pcie_hp_devi_find(
47726947304SEvan Yan 			    ctrl_p->hc_dip, slot_p->hs_device_num, 0);
47826947304SEvan Yan 			mutex_enter(&ctrl_p->hc_mutex);
47926947304SEvan Yan 
48026947304SEvan Yan 			if ((slot_p->hs_info.cn_state !=
48126947304SEvan Yan 			    DDI_HP_CN_STATE_ENABLED) || (cdip == NULL)) {
48226947304SEvan Yan 				/*
48326947304SEvan Yan 				 * When getting all properties, just ignore the
48426947304SEvan Yan 				 * one that's not available under certain state.
48526947304SEvan Yan 				 */
48626947304SEvan Yan 				if (get_all_prop)
48726947304SEvan Yan 					continue;
48826947304SEvan Yan 
48926947304SEvan Yan 				ret = DDI_ENOTSUP;
49026947304SEvan Yan 				goto get_prop_cleanup2;
49126947304SEvan Yan 			}
49226947304SEvan Yan 
49326947304SEvan Yan 			if (pci_config_setup(cdip, &handle) != DDI_SUCCESS) {
49426947304SEvan Yan 				ret = DDI_FAILURE;
49526947304SEvan Yan 				goto get_prop_cleanup2;
49626947304SEvan Yan 			}
49726947304SEvan Yan 
49826947304SEvan Yan 			prog_class = pci_config_get8(handle,
49926947304SEvan Yan 			    PCI_CONF_PROGCLASS);
50026947304SEvan Yan 			base_class = pci_config_get8(handle, PCI_CONF_BASCLASS);
50126947304SEvan Yan 			sub_class = pci_config_get8(handle, PCI_CONF_SUBCLASS);
50226947304SEvan Yan 			pci_config_teardown(&handle);
50326947304SEvan Yan 
50426947304SEvan Yan 			for (i = 0; i < class_pci_items; i++) {
50526947304SEvan Yan 				if ((base_class == class_pci[i].base_class) &&
50626947304SEvan Yan 				    (sub_class == class_pci[i].sub_class) &&
50726947304SEvan Yan 				    (prog_class == class_pci[i].prog_class)) {
50826947304SEvan Yan 					value = class_pci[i].short_desc;
50926947304SEvan Yan 					break;
51026947304SEvan Yan 				}
51126947304SEvan Yan 			}
51226947304SEvan Yan 			if (i == class_pci_items)
51326947304SEvan Yan 				value = PCIEHPC_PROP_VALUE_UNKNOWN;
51426947304SEvan Yan 		} else if (strcmp(name, PCIEHPC_PROP_BOARD_TYPE) == 0) {
51526947304SEvan Yan 			if (slot_p->hs_info.cn_state <= DDI_HP_CN_STATE_EMPTY)
51626947304SEvan Yan 				value = PCIEHPC_PROP_VALUE_UNKNOWN;
51726947304SEvan Yan 			else
51826947304SEvan Yan 				value = PCIEHPC_PROP_VALUE_PCIHOTPLUG;
51926947304SEvan Yan 		} else if (strcmp(name, PCIEHPC_PROP_SLOT_CONDITION) == 0) {
52026947304SEvan Yan 			value = pcie_slot_condition_text(slot_p->hs_condition);
52126947304SEvan Yan 		} else {
52226947304SEvan Yan 			/* unsupported property */
52324fd5dc4SEvan Yan 			PCIE_DBG("Unsupported property: %s\n", name);
52426947304SEvan Yan 
52526947304SEvan Yan 			ret = DDI_ENOTSUP;
52626947304SEvan Yan 			goto get_prop_cleanup2;
52726947304SEvan Yan 		}
52826947304SEvan Yan 		if (nvlist_add_string(prop_rlist, name, value) != 0) {
52926947304SEvan Yan 			ret = DDI_FAILURE;
53026947304SEvan Yan 			goto get_prop_cleanup2;
53126947304SEvan Yan 		}
53226947304SEvan Yan 	}
53326947304SEvan Yan 
53426947304SEvan Yan 	// pack nvlist and copyout
53526947304SEvan Yan 	if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
53626947304SEvan Yan 	    &result.buf_size)) != DDI_SUCCESS) {
53726947304SEvan Yan 		goto get_prop_cleanup2;
53826947304SEvan Yan 	}
53926947304SEvan Yan 	if (get_udatamodel() == DATAMODEL_NATIVE) {
54026947304SEvan Yan 		if (copyout(&result, rval, sizeof (ddi_hp_property_t))) {
54126947304SEvan Yan 			ret = DDI_FAILURE;
54226947304SEvan Yan 			goto get_prop_cleanup2;
54326947304SEvan Yan 		}
54426947304SEvan Yan 	}
54526947304SEvan Yan #ifdef _SYSCALL32_IMPL
54626947304SEvan Yan 	else {
54726947304SEvan Yan 		if (result.buf_size > UINT32_MAX) {
54826947304SEvan Yan 			ret = DDI_FAILURE;
54926947304SEvan Yan 		} else {
55026947304SEvan Yan 			result32.buf_size = (uint32_t)result.buf_size;
55126947304SEvan Yan 			if (copyout(&result32, rval,
55226947304SEvan Yan 			    sizeof (ddi_hp_property32_t)))
55326947304SEvan Yan 				ret = DDI_FAILURE;
55426947304SEvan Yan 		}
55526947304SEvan Yan 	}
55626947304SEvan Yan #endif
55726947304SEvan Yan 
55826947304SEvan Yan get_prop_cleanup2:
55926947304SEvan Yan 	mutex_exit(&ctrl_p->hc_mutex);
56026947304SEvan Yan get_prop_cleanup1:
56126947304SEvan Yan 	nvlist_free(prop_rlist);
56226947304SEvan Yan get_prop_cleanup:
56326947304SEvan Yan 	nvlist_free(prop_list);
56426947304SEvan Yan 	return (ret);
56526947304SEvan Yan }
56626947304SEvan Yan 
56726947304SEvan Yan int
56826947304SEvan Yan pcishpc_slot_set_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
56926947304SEvan Yan     ddi_hp_property_t *rval)
57026947304SEvan Yan {
57126947304SEvan Yan 	ddi_hp_property_t request, result;
57226947304SEvan Yan #ifdef _SYSCALL32_IMPL
57326947304SEvan Yan 	ddi_hp_property32_t request32, result32;
57426947304SEvan Yan #endif
57526947304SEvan Yan 	pcie_hp_ctrl_t		*ctrl_p = slot_p->hs_ctrl;
57626947304SEvan Yan 	nvlist_t		*prop_list;
57726947304SEvan Yan 	nvlist_t		*prop_rlist;
57826947304SEvan Yan 	nvpair_t		*prop_pair;
57926947304SEvan Yan 	char			*name, *value;
58026947304SEvan Yan 	pcie_hp_led_state_t	led_state;
58126947304SEvan Yan 	int			ret = DDI_SUCCESS;
58226947304SEvan Yan 
58326947304SEvan Yan 	if (get_udatamodel() == DATAMODEL_NATIVE) {
58426947304SEvan Yan 		if (copyin(arg, &request, sizeof (ddi_hp_property_t)))
58526947304SEvan Yan 			return (DDI_FAILURE);
58626947304SEvan Yan 		if (rval &&
58726947304SEvan Yan 		    copyin(rval, &result, sizeof (ddi_hp_property_t)))
58826947304SEvan Yan 			return (DDI_FAILURE);
58926947304SEvan Yan 	}
59026947304SEvan Yan #ifdef _SYSCALL32_IMPL
59126947304SEvan Yan 	else {
59226947304SEvan Yan 		bzero(&request, sizeof (request));
59326947304SEvan Yan 		bzero(&result, sizeof (result));
59426947304SEvan Yan 		if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)))
59526947304SEvan Yan 			return (DDI_FAILURE);
59626947304SEvan Yan 		if (rval &&
59726947304SEvan Yan 		    copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
59826947304SEvan Yan 			return (DDI_FAILURE);
59926947304SEvan Yan 		request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
60026947304SEvan Yan 		request.buf_size = request32.buf_size;
60126947304SEvan Yan 		if (rval) {
60226947304SEvan Yan 			result.nvlist_buf =
60326947304SEvan Yan 			    (char *)(uintptr_t)result32.nvlist_buf;
60426947304SEvan Yan 			result.buf_size = result32.buf_size;
60526947304SEvan Yan 		}
60626947304SEvan Yan 	}
60726947304SEvan Yan #endif
60826947304SEvan Yan 
60926947304SEvan Yan 	if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
61026947304SEvan Yan 	    &prop_list)) != DDI_SUCCESS)
61126947304SEvan Yan 		return (ret);
61226947304SEvan Yan 
61326947304SEvan Yan 	/* check whether the requested property is "help" */
61426947304SEvan Yan 	prop_pair = nvlist_next_nvpair(prop_list, NULL);
61526947304SEvan Yan 	if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair) &&
61626947304SEvan Yan 	    (strcmp(nvpair_name(prop_pair), PCIEHPC_PROP_HELP) == 0)) {
61726947304SEvan Yan 		if (!rval) {
61826947304SEvan Yan 			ret = DDI_ENOTSUP;
61926947304SEvan Yan 			goto set_prop_cleanup;
62026947304SEvan Yan 		}
62126947304SEvan Yan 
62226947304SEvan Yan 		if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
62326947304SEvan Yan 			ret = DDI_ENOMEM;
62426947304SEvan Yan 			goto set_prop_cleanup;
62526947304SEvan Yan 		}
62626947304SEvan Yan 		if (nvlist_add_string(prop_rlist, PCIEHPC_PROP_LED_ATTN,
62726947304SEvan Yan 		    PCIEHPC_PROP_VALUE_LED) != 0) {
62826947304SEvan Yan 			ret = DDI_FAILURE;
62926947304SEvan Yan 			goto set_prop_cleanup1;
63026947304SEvan Yan 		}
63126947304SEvan Yan 
63226947304SEvan Yan 		if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
63326947304SEvan Yan 		    &result.buf_size)) != DDI_SUCCESS) {
63426947304SEvan Yan 			goto set_prop_cleanup1;
63526947304SEvan Yan 		}
63626947304SEvan Yan 		if (get_udatamodel() == DATAMODEL_NATIVE) {
63726947304SEvan Yan 			if (copyout(&result, rval,
63826947304SEvan Yan 			    sizeof (ddi_hp_property_t))) {
63926947304SEvan Yan 				ret =  DDI_FAILURE;
64026947304SEvan Yan 				goto set_prop_cleanup1;
64126947304SEvan Yan 			}
64226947304SEvan Yan 		}
64326947304SEvan Yan #ifdef _SYSCALL32_IMPL
64426947304SEvan Yan 		else {
64526947304SEvan Yan 			if (result.buf_size > UINT32_MAX) {
64626947304SEvan Yan 				ret =  DDI_FAILURE;
64726947304SEvan Yan 				goto set_prop_cleanup1;
64826947304SEvan Yan 			} else {
64926947304SEvan Yan 				result32.buf_size = (uint32_t)result.buf_size;
65026947304SEvan Yan 				if (copyout(&result32, rval,
65126947304SEvan Yan 				    sizeof (ddi_hp_property32_t))) {
65226947304SEvan Yan 					ret =  DDI_FAILURE;
65326947304SEvan Yan 					goto set_prop_cleanup1;
65426947304SEvan Yan 				}
65526947304SEvan Yan 			}
65626947304SEvan Yan 		}
65726947304SEvan Yan #endif
65826947304SEvan Yan set_prop_cleanup1:
65926947304SEvan Yan 		nvlist_free(prop_rlist);
66026947304SEvan Yan 		nvlist_free(prop_list);
66126947304SEvan Yan 		return (ret);
66226947304SEvan Yan 	}
66326947304SEvan Yan 
66426947304SEvan Yan 	/* Validate the request */
66526947304SEvan Yan 	prop_pair = NULL;
666*b3d69c05SRobert Mustacchi 	while ((prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) != NULL) {
66726947304SEvan Yan 		name = nvpair_name(prop_pair);
66826947304SEvan Yan 		if (nvpair_type(prop_pair) != DATA_TYPE_STRING) {
66924fd5dc4SEvan Yan 			PCIE_DBG("Unexpected data type of setting "
67026947304SEvan Yan 			    "property %s.\n", name);
67126947304SEvan Yan 			ret = DDI_EINVAL;
67226947304SEvan Yan 			goto set_prop_cleanup;
67326947304SEvan Yan 		}
67426947304SEvan Yan 		if (nvpair_value_string(prop_pair, &value)) {
67524fd5dc4SEvan Yan 			PCIE_DBG("Get string value failed for property %s.\n",
67624fd5dc4SEvan Yan 			    name);
67726947304SEvan Yan 			ret = DDI_FAILURE;
67826947304SEvan Yan 			goto set_prop_cleanup;
67926947304SEvan Yan 		}
68026947304SEvan Yan 
68126947304SEvan Yan 		if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
68226947304SEvan Yan 			if ((strcmp(value, PCIEHPC_PROP_VALUE_ON) != 0) &&
68326947304SEvan Yan 			    (strcmp(value, PCIEHPC_PROP_VALUE_OFF) != 0) &&
68426947304SEvan Yan 			    (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) != 0)) {
68524fd5dc4SEvan Yan 				PCIE_DBG("Unsupported value of setting "
68626947304SEvan Yan 				    "property %s\n", name);
68726947304SEvan Yan 				ret = DDI_ENOTSUP;
68826947304SEvan Yan 				goto set_prop_cleanup;
68926947304SEvan Yan 			}
69026947304SEvan Yan 		} else {
69124fd5dc4SEvan Yan 			PCIE_DBG("Unsupported property: %s\n", name);
69226947304SEvan Yan 			ret = DDI_ENOTSUP;
69326947304SEvan Yan 			goto set_prop_cleanup;
69426947304SEvan Yan 		}
69526947304SEvan Yan 	}
69626947304SEvan Yan 
69726947304SEvan Yan 	mutex_enter(&ctrl_p->hc_mutex);
69826947304SEvan Yan 
69926947304SEvan Yan 	/* get the current slot state */
70026947304SEvan Yan 	pcishpc_get_slot_state(slot_p);
70126947304SEvan Yan 
70226947304SEvan Yan 	// set each property
70326947304SEvan Yan 	prop_pair = NULL;
704*b3d69c05SRobert Mustacchi 	while ((prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) != NULL) {
70526947304SEvan Yan 		name = nvpair_name(prop_pair);
70626947304SEvan Yan 
70726947304SEvan Yan 		if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
70826947304SEvan Yan 			if (strcmp(value, PCIEHPC_PROP_VALUE_ON) == 0)
70926947304SEvan Yan 				led_state = PCIE_HP_LED_ON;
71026947304SEvan Yan 			else if (strcmp(value, PCIEHPC_PROP_VALUE_OFF) == 0)
71126947304SEvan Yan 				led_state = PCIE_HP_LED_OFF;
71226947304SEvan Yan 			else if (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) == 0)
71326947304SEvan Yan 				led_state = PCIE_HP_LED_BLINK;
714*b3d69c05SRobert Mustacchi 			else
715*b3d69c05SRobert Mustacchi 				continue;
71626947304SEvan Yan 
71726947304SEvan Yan 			(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED,
71826947304SEvan Yan 			    led_state);
71926947304SEvan Yan 		}
72026947304SEvan Yan 	}
72124fd5dc4SEvan Yan 	if (rval) {
72224fd5dc4SEvan Yan 		if (get_udatamodel() == DATAMODEL_NATIVE) {
72324fd5dc4SEvan Yan 			result.buf_size = 0;
72424fd5dc4SEvan Yan 			if (copyout(&result, rval, sizeof (ddi_hp_property_t)))
72524fd5dc4SEvan Yan 				ret =  DDI_FAILURE;
72624fd5dc4SEvan Yan 		}
72724fd5dc4SEvan Yan #ifdef _SYSCALL32_IMPL
72824fd5dc4SEvan Yan 		else {
72924fd5dc4SEvan Yan 			result32.buf_size = 0;
73024fd5dc4SEvan Yan 			if (copyout(&result32, rval,
73124fd5dc4SEvan Yan 			    sizeof (ddi_hp_property32_t)))
73224fd5dc4SEvan Yan 				ret =  DDI_FAILURE;
73324fd5dc4SEvan Yan 		}
73424fd5dc4SEvan Yan #endif
73524fd5dc4SEvan Yan 	}
73626947304SEvan Yan 
73726947304SEvan Yan 	mutex_exit(&ctrl_p->hc_mutex);
73826947304SEvan Yan set_prop_cleanup:
73926947304SEvan Yan 	nvlist_free(prop_list);
74026947304SEvan Yan 	return (ret);
74126947304SEvan Yan }
74226947304SEvan Yan 
74326947304SEvan Yan /*
74426947304SEvan Yan  * pcishpc_hp_ops()
74526947304SEvan Yan  *
74626947304SEvan Yan  * Handle hotplug commands
74726947304SEvan Yan  *
74826947304SEvan Yan  * Note: This function is called by DDI HP framework at kernel context only
74926947304SEvan Yan  */
75026947304SEvan Yan /* ARGSUSED */
75126947304SEvan Yan int
75226947304SEvan Yan pcishpc_hp_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op,
75326947304SEvan Yan     void *arg, void *result)
75426947304SEvan Yan {
75526947304SEvan Yan 	pcie_hp_slot_t	*slot_p = NULL;
75626947304SEvan Yan 	pcie_hp_ctrl_t	*ctrl_p;
75726947304SEvan Yan 	int		ret = DDI_SUCCESS, i;
75826947304SEvan Yan 
75926947304SEvan Yan 	PCIE_DBG("pcishpc_hp_ops: dip=%p cn_name=%s op=%x arg=%p\n",
76026947304SEvan Yan 	    dip, cn_name, op, arg);
76126947304SEvan Yan 
76226947304SEvan Yan 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
76326947304SEvan Yan 		return (DDI_FAILURE);
76426947304SEvan Yan 
76526947304SEvan Yan 	for (i = 0; i < PCIE_HP_MAX_SLOTS && ctrl_p->hc_slots[i]; i++) {
76626947304SEvan Yan 		if (strcmp(ctrl_p->hc_slots[i]->hs_info.cn_name, cn_name)
76726947304SEvan Yan 		    == 0) {
76826947304SEvan Yan 			/* Match with a physical slot, found */
76926947304SEvan Yan 			slot_p = ctrl_p->hc_slots[i];
77026947304SEvan Yan 			break;
77126947304SEvan Yan 		}
77226947304SEvan Yan 	}
77326947304SEvan Yan 	if (!slot_p) {
77426947304SEvan Yan 		PCIE_DBG("pcishpc_hp_ops: Failed to find the slot under"
77526947304SEvan Yan 		    "dip %p with name: %s; op=%x arg=%p\n",
77626947304SEvan Yan 		    dip, cn_name, op, arg);
77726947304SEvan Yan 		return (DDI_EINVAL);
77826947304SEvan Yan 	}
77926947304SEvan Yan 	switch (op) {
78026947304SEvan Yan 	case DDI_HPOP_CN_GET_STATE:
78126947304SEvan Yan 	{
78226947304SEvan Yan 		mutex_enter(&ctrl_p->hc_mutex);
78326947304SEvan Yan 
78426947304SEvan Yan 		/* get the current slot state */
78526947304SEvan Yan 		pcishpc_get_slot_state(slot_p);
78626947304SEvan Yan 
78726947304SEvan Yan 		*((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state;
78826947304SEvan Yan 
78926947304SEvan Yan 		mutex_exit(&ctrl_p->hc_mutex);
79026947304SEvan Yan 		break;
79126947304SEvan Yan 	}
79226947304SEvan Yan 	case DDI_HPOP_CN_CHANGE_STATE:
79326947304SEvan Yan 	{
79426947304SEvan Yan 		ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg;
79526947304SEvan Yan 
79626947304SEvan Yan 		mutex_enter(&slot_p->hs_ctrl->hc_mutex);
79726947304SEvan Yan 
79826947304SEvan Yan 		ret = pcishpc_change_slot_state(slot_p, target_state);
79926947304SEvan Yan 		*((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state;
80026947304SEvan Yan 
80126947304SEvan Yan 		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
80226947304SEvan Yan 		break;
80326947304SEvan Yan 	}
80426947304SEvan Yan 	case DDI_HPOP_CN_PROBE:
80526947304SEvan Yan 		ret = pcishpc_slot_probe(slot_p);
80626947304SEvan Yan 
80726947304SEvan Yan 		break;
80826947304SEvan Yan 	case DDI_HPOP_CN_UNPROBE:
80926947304SEvan Yan 		ret = pcishpc_slot_unprobe(slot_p);
81026947304SEvan Yan 
81126947304SEvan Yan 		break;
81226947304SEvan Yan 	case DDI_HPOP_CN_GET_PROPERTY:
81326947304SEvan Yan 		ret = pcishpc_slot_get_property(slot_p,
81426947304SEvan Yan 		    (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
81526947304SEvan Yan 		break;
81626947304SEvan Yan 	case DDI_HPOP_CN_SET_PROPERTY:
81726947304SEvan Yan 		ret = pcishpc_slot_set_property(slot_p,
81826947304SEvan Yan 		    (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
81926947304SEvan Yan 		break;
82026947304SEvan Yan 	default:
82126947304SEvan Yan 		ret = DDI_ENOTSUP;
82226947304SEvan Yan 		break;
82326947304SEvan Yan 	}
82426947304SEvan Yan 
82526947304SEvan Yan 	return (ret);
82626947304SEvan Yan }
82726947304SEvan Yan 
82826947304SEvan Yan /*
82926947304SEvan Yan  * Local functions (called within this file)
83026947304SEvan Yan  */
83126947304SEvan Yan 
83226947304SEvan Yan /*
83326947304SEvan Yan  * pcishpc_create_controller()
83426947304SEvan Yan  *
83526947304SEvan Yan  * This function allocates and creates an SHPC controller state structure
83626947304SEvan Yan  * and adds it to the linked list of controllers.
83726947304SEvan Yan  */
83826947304SEvan Yan static pcie_hp_ctrl_t *
83926947304SEvan Yan pcishpc_create_controller(dev_info_t *dip)
84026947304SEvan Yan {
84126947304SEvan Yan 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
84226947304SEvan Yan 	pcie_hp_ctrl_t	*ctrl_p;
84326947304SEvan Yan 
84426947304SEvan Yan 	PCIE_DBG("pcishpc: create controller for %s#%d\n",
84526947304SEvan Yan 	    ddi_driver_name(dip), ddi_get_instance(dip));
84626947304SEvan Yan 
84726947304SEvan Yan 	ctrl_p = kmem_zalloc(sizeof (pcie_hp_ctrl_t), KM_SLEEP);
84826947304SEvan Yan 	ctrl_p->hc_dip = dip;
84926947304SEvan Yan 
85026947304SEvan Yan 	cv_init(&ctrl_p->hc_cmd_comp_cv, NULL, CV_DRIVER, NULL);
85126947304SEvan Yan 
85226947304SEvan Yan 	/* Init the shpc controller's mutex. */
85326947304SEvan Yan 	mutex_init(&ctrl_p->hc_mutex, NULL, MUTEX_DRIVER, NULL);
85426947304SEvan Yan 
85526947304SEvan Yan 	/* HPC initialization is complete now */
85626947304SEvan Yan 	ctrl_p->hc_flags = PCIE_HP_INITIALIZED_FLAG;
85726947304SEvan Yan 	bus_p->bus_hp_curr_mode = PCIE_PCI_HP_MODE;
85826947304SEvan Yan 
85926947304SEvan Yan 	PCIE_SET_HP_CTRL(dip, ctrl_p);
86026947304SEvan Yan 
86126947304SEvan Yan 	PCIE_DBG("pcishpc_create_controller() success\n");
86226947304SEvan Yan 
86326947304SEvan Yan 	return (ctrl_p);
86426947304SEvan Yan }
86526947304SEvan Yan 
86626947304SEvan Yan 
86726947304SEvan Yan /*
86826947304SEvan Yan  * pcishpc_setup_controller()
86926947304SEvan Yan  *
87026947304SEvan Yan  * Get the number of HotPlug Slots, and the PCI device information
87126947304SEvan Yan  * for this HotPlug controller.
87226947304SEvan Yan  */
87326947304SEvan Yan static int
87426947304SEvan Yan pcishpc_setup_controller(pcie_hp_ctrl_t *ctrl_p)
87526947304SEvan Yan {
87626947304SEvan Yan 	uint32_t config;
87726947304SEvan Yan 	dev_info_t *ppdip;
87826947304SEvan Yan 
87926947304SEvan Yan 	config = pcishpc_read_reg(ctrl_p, PCI_HP_SLOT_CONFIGURATION_REG);
88026947304SEvan Yan 
88126947304SEvan Yan 	/* Get the number of HotPlug slots implemented */
88226947304SEvan Yan 	ctrl_p->hc_num_slots_impl = ((config)&31);
88326947304SEvan Yan 
88426947304SEvan Yan 	/*
88526947304SEvan Yan 	 * Initilize the current bus speed and number of hotplug slots
88626947304SEvan Yan 	 * currently connected.
88726947304SEvan Yan 	 */
88826947304SEvan Yan 	ctrl_p->hc_curr_bus_speed = -1;
88926947304SEvan Yan 	ctrl_p->hc_num_slots_connected = 0;
89026947304SEvan Yan 
89126947304SEvan Yan 	/*
89226947304SEvan Yan 	 * Get the first PCI device Number used.
89326947304SEvan Yan 	 *
89426947304SEvan Yan 	 * PCI-X I/O boat workaround.
89526947304SEvan Yan 	 * The register doesn't set up the correct value.
89626947304SEvan Yan 	 */
89726947304SEvan Yan 	ppdip = ddi_get_parent(ddi_get_parent(ctrl_p->hc_dip));
89826947304SEvan Yan 	if ((ddi_prop_get_int(DDI_DEV_T_ANY, ppdip, DDI_PROP_DONTPASS,
89926947304SEvan Yan 	    "vendor-id", -1) == 0x108e) &&
90026947304SEvan Yan 	    (ddi_prop_get_int(DDI_DEV_T_ANY, ppdip, DDI_PROP_DONTPASS,
90126947304SEvan Yan 	    "device-id", -1) == 0x9010))
90226947304SEvan Yan 		ctrl_p->hc_device_start = 4;
90326947304SEvan Yan 	else
90426947304SEvan Yan 		ctrl_p->hc_device_start = ((config>>8)&31);
90526947304SEvan Yan 
90626947304SEvan Yan 	/* Get the first Physical device number. */
90726947304SEvan Yan 	ctrl_p->hc_phys_start = ((config>>16)&0x7ff);
90826947304SEvan Yan 
90926947304SEvan Yan 	/* Check if the device numbers increase or decrease. */
91026947304SEvan Yan 	ctrl_p->hc_device_increases = ((config>>29)&0x1);
91126947304SEvan Yan 
91226947304SEvan Yan 	ctrl_p->hc_has_attn =
91326947304SEvan Yan 	    (config & PCI_HP_SLOT_CONFIG_ATTN_BUTTON) ? B_TRUE : B_FALSE;
91426947304SEvan Yan 	ctrl_p->hc_has_mrl =
91526947304SEvan Yan 	    (config & PCI_HP_SLOT_CONFIG_MRL_SENSOR) ? B_TRUE : B_FALSE;
91626947304SEvan Yan 
91726947304SEvan Yan 	ctrl_p->hc_cmd_pending = B_FALSE;
91826947304SEvan Yan 	ctrl_p->hc_arbiter_timeout = B_FALSE;
91926947304SEvan Yan 
92026947304SEvan Yan 	if (ctrl_p->hc_num_slots_impl > PCIE_HP_MAX_SLOTS) {
92126947304SEvan Yan 		PCIE_DBG("pcishpc_setup_controller() too many SHPC "
92226947304SEvan Yan 		    "slots error\n");
92326947304SEvan Yan 		return (DDI_FAILURE);
92426947304SEvan Yan 	}
92526947304SEvan Yan 
92626947304SEvan Yan 	return (DDI_SUCCESS);
92726947304SEvan Yan }
92826947304SEvan Yan 
92926947304SEvan Yan 
93026947304SEvan Yan /*
93126947304SEvan Yan  * pcishpc_destroy_controller()
93226947304SEvan Yan  *
93326947304SEvan Yan  * This function deallocates all of the SHPC controller resources.
93426947304SEvan Yan  */
93526947304SEvan Yan static int
93626947304SEvan Yan pcishpc_destroy_controller(dev_info_t *dip)
93726947304SEvan Yan {
93826947304SEvan Yan 	pcie_hp_ctrl_t	*ctrl_p;
93926947304SEvan Yan 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
94026947304SEvan Yan 
94126947304SEvan Yan 	PCIE_DBG("pcishpc_destroy_controller() called(dip=%p)\n", dip);
94226947304SEvan Yan 
94326947304SEvan Yan 	/* get the soft state structure for this dip */
94426947304SEvan Yan 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) {
94526947304SEvan Yan 		PCIE_DBG("pcishpc_destroy_controller() not found\n");
94626947304SEvan Yan 		return (DDI_FAILURE);
94726947304SEvan Yan 	}
94826947304SEvan Yan 
94926947304SEvan Yan 	/*
95026947304SEvan Yan 	 * Deallocate the slot state structures for this controller.
95126947304SEvan Yan 	 */
952c0da6274SZhi-Jun Robin Fu 	PCIE_SET_HP_CTRL(dip, NULL);
953c0da6274SZhi-Jun Robin Fu 	bus_p->bus_hp_curr_mode = PCIE_NONE_HP_MODE;
954c0da6274SZhi-Jun Robin Fu 
95526947304SEvan Yan 	(void) pcishpc_destroy_slots(ctrl_p);
95626947304SEvan Yan 	cv_destroy(&ctrl_p->hc_cmd_comp_cv);
95726947304SEvan Yan 	mutex_destroy(&ctrl_p->hc_mutex);
95826947304SEvan Yan 	kmem_free(ctrl_p, sizeof (pcie_hp_ctrl_t));
95926947304SEvan Yan 
96026947304SEvan Yan 	PCIE_DBG("pcishpc_destroy_controller() success\n");
96126947304SEvan Yan 	return (DDI_SUCCESS);
96226947304SEvan Yan }
96326947304SEvan Yan 
96426947304SEvan Yan /*
96526947304SEvan Yan  * pcishpc_create_slot()
96626947304SEvan Yan  *
96726947304SEvan Yan  * Allocate and add a new HotPlug slot state structure to the linked list.
96826947304SEvan Yan  */
96926947304SEvan Yan static pcie_hp_slot_t *
97026947304SEvan Yan pcishpc_create_slot(pcie_hp_ctrl_t *ctrl_p)
97126947304SEvan Yan {
97226947304SEvan Yan 	pcie_hp_slot_t *slot_p;
97326947304SEvan Yan 
97426947304SEvan Yan 	PCIE_DBG("pcishpc_create_slot() called(ctrl_p=%x)\n", ctrl_p);
97526947304SEvan Yan 
97626947304SEvan Yan 	/* Allocate a new slot structure. */
97726947304SEvan Yan 	slot_p = kmem_zalloc(sizeof (pcie_hp_slot_t), KM_SLEEP);
97826947304SEvan Yan 	slot_p->hs_ctrl = ctrl_p;
97926947304SEvan Yan 
98026947304SEvan Yan 	/* Assign an initial value */
98126947304SEvan Yan 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY;
98226947304SEvan Yan 
98326947304SEvan Yan 	PCIE_DBG("pcishpc_create_slot() success\n");
98426947304SEvan Yan 	return (slot_p);
98526947304SEvan Yan }
98626947304SEvan Yan 
98726947304SEvan Yan /*
98826947304SEvan Yan  * pcishpc_register_slot()
98926947304SEvan Yan  *
99026947304SEvan Yan  * Create and register a slot with the Solaris HotPlug framework.
99126947304SEvan Yan  */
99226947304SEvan Yan static int
99326947304SEvan Yan pcishpc_register_slot(pcie_hp_ctrl_t *ctrl_p, int slot)
99426947304SEvan Yan {
99526947304SEvan Yan 	dev_info_t	*dip = ctrl_p->hc_dip;
99626947304SEvan Yan 	pcie_hp_slot_t	*slot_p;
99726947304SEvan Yan 
99826947304SEvan Yan 	slot_p = pcishpc_create_slot(ctrl_p);
99926947304SEvan Yan 	ctrl_p->hc_slots[slot] = slot_p;
100026947304SEvan Yan 	slot_p->hs_num = slot;
100126947304SEvan Yan 
100226947304SEvan Yan 	/* Setup the PCI device # for this SHPC slot. */
100326947304SEvan Yan 	if (ctrl_p->hc_device_increases)
100426947304SEvan Yan 		slot_p->hs_device_num = ctrl_p->hc_device_start +
100526947304SEvan Yan 		    slot_p->hs_num;
100626947304SEvan Yan 	else
100726947304SEvan Yan 		slot_p->hs_device_num = ctrl_p->hc_device_start -
100826947304SEvan Yan 		    slot_p->hs_num;
100926947304SEvan Yan 
101026947304SEvan Yan 	/* Setup the DDI HP framework slot information. */
101126947304SEvan Yan 	slot_p->hs_info.cn_type = DDI_HP_CN_TYPE_PCI;
101226947304SEvan Yan 	slot_p->hs_info.cn_type_str = PCIE_PCI_HP_TYPE;
101326947304SEvan Yan 	slot_p->hs_info.cn_child = NULL;
101426947304SEvan Yan 
101526947304SEvan Yan 	slot_p->hs_minor = PCI_MINOR_NUM(
101626947304SEvan Yan 	    ddi_get_instance(dip), slot_p->hs_device_num);
101726947304SEvan Yan 	slot_p->hs_condition = AP_COND_UNKNOWN;
101826947304SEvan Yan 
101926947304SEvan Yan 	/* setup thread for handling ATTN button events */
102026947304SEvan Yan 	if (ctrl_p->hc_has_attn) {
102126947304SEvan Yan 		PCIE_DBG("pcishpc_register_slot: "
102226947304SEvan Yan 		    "setting up ATTN button event "
102326947304SEvan Yan 		    "handler thread for slot %d\n", slot);
102426947304SEvan Yan 
102526947304SEvan Yan 		cv_init(&slot_p->hs_attn_btn_cv, NULL, CV_DRIVER, NULL);
102626947304SEvan Yan 		slot_p->hs_attn_btn_pending = B_FALSE;
102726947304SEvan Yan 		slot_p->hs_attn_btn_threadp = thread_create(NULL, 0,
102826947304SEvan Yan 		    pcishpc_attn_btn_handler,
102926947304SEvan Yan 		    (void *)slot_p, 0, &p0, TS_RUN, minclsyspri);
103026947304SEvan Yan 		slot_p->hs_attn_btn_thread_exit = B_FALSE;
103126947304SEvan Yan 	}
103226947304SEvan Yan 
103326947304SEvan Yan 	/* setup the slot name (used for ap-id) */
103426947304SEvan Yan 	pcishpc_set_slot_name(ctrl_p, slot);
103526947304SEvan Yan 
103626947304SEvan Yan 	pcishpc_get_slot_state(slot_p);
103726947304SEvan Yan 	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_ENABLED)
103826947304SEvan Yan 		slot_p->hs_condition = AP_COND_OK;
103926947304SEvan Yan 
104026947304SEvan Yan 	/* register the slot with DDI HP framework */
104126947304SEvan Yan 	if (ndi_hp_register(dip, &slot_p->hs_info) != NDI_SUCCESS) {
104226947304SEvan Yan 		PCIE_DBG("pciehpc_register_slot() failed to register slot %d\n",
104326947304SEvan Yan 		    slot_p->hs_phy_slot_num);
104426947304SEvan Yan 		return (DDI_FAILURE);
104526947304SEvan Yan 	}
104626947304SEvan Yan 
104726947304SEvan Yan 	pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip),
104826947304SEvan Yan 	    slot_p->hs_minor), slot_p->hs_device_num);
104926947304SEvan Yan 
105026947304SEvan Yan 	PCIE_DBG("pcishpc_register_slot() success for slot %d\n", slot);
105126947304SEvan Yan 
105226947304SEvan Yan 	return (DDI_SUCCESS);
105326947304SEvan Yan }
105426947304SEvan Yan 
105526947304SEvan Yan /*
105626947304SEvan Yan  * pcishpc_destroy_slots()
105726947304SEvan Yan  *
105826947304SEvan Yan  * Free up all of the slot resources for this controller.
105926947304SEvan Yan  */
106026947304SEvan Yan static int
106126947304SEvan Yan pcishpc_destroy_slots(pcie_hp_ctrl_t *ctrl_p)
106226947304SEvan Yan {
106326947304SEvan Yan 	dev_info_t	*dip = ctrl_p->hc_dip;
106426947304SEvan Yan 	pcie_hp_slot_t	*slot_p;
106526947304SEvan Yan 	int		i;
106626947304SEvan Yan 
106726947304SEvan Yan 	PCIE_DBG("pcishpc_destroy_slots() called(ctrl_p=%p)\n", ctrl_p);
106826947304SEvan Yan 
106926947304SEvan Yan 	for (i = 0; i < PCIE_HP_MAX_SLOTS; i++) {
107026947304SEvan Yan 		if ((slot_p = ctrl_p->hc_slots[i]) == NULL)
107126947304SEvan Yan 			continue;
107226947304SEvan Yan 
107326947304SEvan Yan 		if (slot_p->hs_attn_btn_threadp != NULL) {
107426947304SEvan Yan 			mutex_enter(&ctrl_p->hc_mutex);
107526947304SEvan Yan 			slot_p->hs_attn_btn_thread_exit = B_TRUE;
107626947304SEvan Yan 			cv_signal(&slot_p->hs_attn_btn_cv);
107726947304SEvan Yan 			PCIE_DBG("pcishpc_destroy_slots: "
107826947304SEvan Yan 			    "waiting for ATTN thread exit\n");
107926947304SEvan Yan 			cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
108026947304SEvan Yan 			PCIE_DBG("pcishpc_destroy_slots: "
108126947304SEvan Yan 			    "ATTN thread exit\n");
108226947304SEvan Yan 			cv_destroy(&slot_p->hs_attn_btn_cv);
108326947304SEvan Yan 			slot_p->hs_attn_btn_threadp = NULL;
108426947304SEvan Yan 			mutex_exit(&ctrl_p->hc_mutex);
108526947304SEvan Yan 		}
108626947304SEvan Yan 
108726947304SEvan Yan 		PCIE_DBG("pcishpc_destroy_slots() (shpc_p=%p)\n"
108826947304SEvan Yan 		    "destroyed", slot_p);
108926947304SEvan Yan 
109026947304SEvan Yan 		pcie_hp_delete_occupant_props(dip,
109126947304SEvan Yan 		    makedevice(ddi_driver_major(dip),
109226947304SEvan Yan 		    slot_p->hs_minor));
109326947304SEvan Yan 
109426947304SEvan Yan 		/* unregister the slot with DDI HP framework */
109526947304SEvan Yan 		if (ndi_hp_unregister(dip, slot_p->hs_info.cn_name) !=
109626947304SEvan Yan 		    NDI_SUCCESS) {
109726947304SEvan Yan 			PCIE_DBG("pcishpc_destroy_slots() "
109826947304SEvan Yan 			    "failed to unregister slot %d\n",
109926947304SEvan Yan 			    slot_p->hs_phy_slot_num);
110026947304SEvan Yan 			return (DDI_FAILURE);
110126947304SEvan Yan 		}
110226947304SEvan Yan 		kmem_free(slot_p->hs_info.cn_name,
110326947304SEvan Yan 		    strlen(slot_p->hs_info.cn_name) + 1);
110426947304SEvan Yan 		kmem_free(slot_p, sizeof (pcie_hp_slot_t));
110526947304SEvan Yan 	}
110626947304SEvan Yan 
110726947304SEvan Yan 	return (DDI_SUCCESS);
110826947304SEvan Yan }
110926947304SEvan Yan 
111026947304SEvan Yan /*
111126947304SEvan Yan  * pcishpc_enable_irqs()
111226947304SEvan Yan  *
111326947304SEvan Yan  * Enable/unmask the different IRQ's we support from the SHPC controller.
111426947304SEvan Yan  */
111570f83219SEvan Yan int
111626947304SEvan Yan pcishpc_enable_irqs(pcie_hp_ctrl_t *ctrl_p)
111726947304SEvan Yan {
111826947304SEvan Yan 	uint32_t reg;
111926947304SEvan Yan 	int slot;
112026947304SEvan Yan 
112126947304SEvan Yan 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG);
112226947304SEvan Yan 
112326947304SEvan Yan 	/* Enable all interrupts. */
112426947304SEvan Yan 	reg &= ~PCI_HP_SERR_INT_MASK_ALL;
112526947304SEvan Yan 
112626947304SEvan Yan 	pcishpc_write_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG, reg);
112726947304SEvan Yan 
112826947304SEvan Yan 	/* Unmask the interrupts for each slot. */
112926947304SEvan Yan 	for (slot = 0; slot < ctrl_p->hc_num_slots_impl; slot++) {
113026947304SEvan Yan 		reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot);
113126947304SEvan Yan 		if ((reg & PCI_HP_SLOT_STATE_MASK) == PCI_HP_SLOT_ENABLED) {
113226947304SEvan Yan 			reg &= ~(PCI_HP_SLOT_MASK_ALL |
113326947304SEvan Yan 			    PCI_HP_SLOT_MRL_SERR_MASK);
113426947304SEvan Yan 			ctrl_p->hc_num_slots_connected++;
113526947304SEvan Yan 			if (ctrl_p->hc_curr_bus_speed == -1)
113626947304SEvan Yan 				ctrl_p->hc_curr_bus_speed =
113726947304SEvan Yan 				    pcishpc_read_reg(ctrl_p,
113826947304SEvan Yan 				    PCI_HP_PROF_IF_SBCR_REG) &
113926947304SEvan Yan 				    PCI_HP_SBCR_SPEED_MASK;
114026947304SEvan Yan 		} else {
114126947304SEvan Yan 			reg &= ~(PCI_HP_SLOT_MASK_ALL);
114226947304SEvan Yan 		}
114326947304SEvan Yan 
114426947304SEvan Yan 		/* Enable/Unmask all slot interrupts. */
114526947304SEvan Yan 		pcishpc_write_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot, reg);
114626947304SEvan Yan 	}
114726947304SEvan Yan 
114826947304SEvan Yan 	PCIE_DBG("pcishpc_enable_irqs: ctrl_p 0x%p, "
114926947304SEvan Yan 	    "current bus speed 0x%x, slots connected 0x%x\n", ctrl_p,
115026947304SEvan Yan 	    ctrl_p->hc_curr_bus_speed, ctrl_p->hc_num_slots_connected);
115126947304SEvan Yan 
115226947304SEvan Yan 	return (DDI_SUCCESS);
115326947304SEvan Yan }
115426947304SEvan Yan 
115526947304SEvan Yan 
115626947304SEvan Yan /*
115726947304SEvan Yan  * pcishpc_disable_irqs()
115826947304SEvan Yan  *
115926947304SEvan Yan  * Disable/Mask the different IRQ's we support from the SHPC controller.
116026947304SEvan Yan  */
116170f83219SEvan Yan int
116226947304SEvan Yan pcishpc_disable_irqs(pcie_hp_ctrl_t *ctrl_p)
116326947304SEvan Yan {
116426947304SEvan Yan 	uint32_t reg;
116526947304SEvan Yan 	int slot;
116626947304SEvan Yan 
116726947304SEvan Yan 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG);
116826947304SEvan Yan 
116926947304SEvan Yan 	/* Mask all interrupts. */
117026947304SEvan Yan 	reg |= PCI_HP_SERR_INT_MASK_ALL;
117126947304SEvan Yan 
117226947304SEvan Yan 	pcishpc_write_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG, reg);
117326947304SEvan Yan 
117426947304SEvan Yan 	/* Unmask the interrupts for each slot. */
117526947304SEvan Yan 	for (slot = 0; slot < ctrl_p->hc_num_slots_impl; slot++) {
117626947304SEvan Yan 		reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot);
117726947304SEvan Yan 
117826947304SEvan Yan 		/* Disable/Mask all slot interrupts. */
117926947304SEvan Yan 		reg |= PCI_HP_SLOT_MASK_ALL;
118026947304SEvan Yan 
118126947304SEvan Yan 		pcishpc_write_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot, reg);
118226947304SEvan Yan 	}
118326947304SEvan Yan 
118426947304SEvan Yan 	PCIE_DBG("pcishpc_disable_irqs: ctrl_p 0x%p, "
118526947304SEvan Yan 	    "current bus speed 0x%x, slots connected 0x%x\n", ctrl_p,
118626947304SEvan Yan 	    ctrl_p->hc_curr_bus_speed, ctrl_p->hc_num_slots_connected);
118726947304SEvan Yan 
118826947304SEvan Yan 	return (DDI_SUCCESS);
118926947304SEvan Yan }
119026947304SEvan Yan 
119126947304SEvan Yan /*
119226947304SEvan Yan  * pcishpc_slot_poweron()
119326947304SEvan Yan  *
119426947304SEvan Yan  * Poweron/Enable the slot.
119526947304SEvan Yan  *
119626947304SEvan Yan  * Note: This function is called by DDI HP framework at kernel context only
119726947304SEvan Yan  */
119826947304SEvan Yan /*ARGSUSED*/
119926947304SEvan Yan static int
120026947304SEvan Yan pcishpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result_state)
120126947304SEvan Yan {
120226947304SEvan Yan 	uint32_t	status;
120326947304SEvan Yan 
120426947304SEvan Yan 	PCIE_DBG("pcishpc_slot_poweron called()\n");
120526947304SEvan Yan 
120626947304SEvan Yan 	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
120726947304SEvan Yan 
120826947304SEvan Yan 	/* get the current slot state */
120926947304SEvan Yan 	pcishpc_get_slot_state(slot_p);
121026947304SEvan Yan 
121126947304SEvan Yan 	/* check if the slot is already in the 'enabled' state */
121226947304SEvan Yan 	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) {
121326947304SEvan Yan 		/* slot is already in the 'enabled' state */
121426947304SEvan Yan 		PCIE_DBG("pcishpc_slot_poweron() slot %d already enabled\n",
121526947304SEvan Yan 		    slot_p->hs_phy_slot_num);
121626947304SEvan Yan 
121726947304SEvan Yan 		*result_state = slot_p->hs_info.cn_state;
121826947304SEvan Yan 		return (DDI_SUCCESS);
121926947304SEvan Yan 	}
122026947304SEvan Yan 
122126947304SEvan Yan 	if (slot_p->hs_info.cn_state == DDI_HP_CN_STATE_EMPTY) {
122226947304SEvan Yan 		PCIE_DBG("pcishpc_slot_poweron() slot in empty state\n");
122326947304SEvan Yan 		goto cleanup;
122426947304SEvan Yan 	}
122526947304SEvan Yan 
122626947304SEvan Yan 	/* make sure the MRL sensor is closed */
122726947304SEvan Yan 	status = pcishpc_read_reg(slot_p->hs_ctrl,
122826947304SEvan Yan 	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
122926947304SEvan Yan 
123026947304SEvan Yan 	if (status & PCI_HP_SLOT_MRL_STATE_MASK) {
123126947304SEvan Yan 		PCIE_DBG("pcishpc_slot_poweron() failed: MRL open\n");
123226947304SEvan Yan 		goto cleanup;
123326947304SEvan Yan 	}
123426947304SEvan Yan 
123526947304SEvan Yan 	/* Set the Power LED to blink */
123626947304SEvan Yan 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
123726947304SEvan Yan 
123826947304SEvan Yan 	/* Turn all other LEDS off */
123926947304SEvan Yan 	(void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF);
124026947304SEvan Yan 	(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
124126947304SEvan Yan 	(void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF);
124226947304SEvan Yan 
124326947304SEvan Yan 	/* Set the bus speed only if the bus segment is not running */
124426947304SEvan Yan 	if (pcishpc_set_bus_speed(slot_p) != DDI_SUCCESS) {
124526947304SEvan Yan 		PCIE_DBG("pcishpc_slot_poweron() setting speed failed\n");
124626947304SEvan Yan 		goto cleanup;
124726947304SEvan Yan 	}
124826947304SEvan Yan 
124926947304SEvan Yan 	slot_p->hs_ctrl->hc_num_slots_connected++;
125026947304SEvan Yan 
125126947304SEvan Yan 	PCIE_DBG("pcishpc_slot_poweron(): slot_p 0x%p, slot state 0x%x, "
125226947304SEvan Yan 	    "current bus speed 0x%x, slots connected 0x%x\n", slot_p,
125326947304SEvan Yan 	    slot_p->hs_info.cn_state, slot_p->hs_ctrl->hc_curr_bus_speed,
125426947304SEvan Yan 	    slot_p->hs_ctrl->hc_num_slots_connected);
125526947304SEvan Yan 
125626947304SEvan Yan 	/* Mask or Unmask MRL Sensor SEER bit based on new slot state */
125726947304SEvan Yan 	if (slot_p->hs_ctrl->hc_has_mrl == B_TRUE) {
125826947304SEvan Yan 		uint32_t reg;
125926947304SEvan Yan 
126026947304SEvan Yan 		reg = pcishpc_read_reg(slot_p->hs_ctrl,
126126947304SEvan Yan 		    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
126226947304SEvan Yan 
126326947304SEvan Yan 		pcishpc_write_reg(slot_p->hs_ctrl,
126426947304SEvan Yan 		    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num,
126526947304SEvan Yan 		    reg & ~PCI_HP_SLOT_MRL_SERR_MASK);
126626947304SEvan Yan 	}
126726947304SEvan Yan 
126826947304SEvan Yan 	/* Update the hardware slot state. */
126926947304SEvan Yan 	if (pcishpc_set_slot_state(slot_p,
127026947304SEvan Yan 	    DDI_HP_CN_STATE_ENABLED) != DDI_SUCCESS) {
127126947304SEvan Yan 		PCIE_DBG("pcishpc_slot_poweron() failed\n");
127226947304SEvan Yan 
127326947304SEvan Yan 		pcishpc_get_slot_state(slot_p);
127426947304SEvan Yan 		goto cleanup;
127526947304SEvan Yan 	}
127626947304SEvan Yan 	/* Update the current state. It will be used in pcishpc_setled() */
127726947304SEvan Yan 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_ENABLED;
127826947304SEvan Yan 
127926947304SEvan Yan 	/* Turn the Power LED ON for a enabled slot. */
128026947304SEvan Yan 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_ON);
128126947304SEvan Yan 
128226947304SEvan Yan 	/* Turn all other LEDS off. */
128326947304SEvan Yan 	(void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF);
128426947304SEvan Yan 	(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
128526947304SEvan Yan 	(void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF);
128626947304SEvan Yan 
128726947304SEvan Yan 	/* delay after powerON to let the device initialize itself */
128826947304SEvan Yan 	delay(drv_usectohz(pcishpc_reset_delay));
128926947304SEvan Yan 
129026947304SEvan Yan 	PCIE_DBG("pcishpc_slot_poweron() success!\n");
129126947304SEvan Yan 
129226947304SEvan Yan 	/*
129326947304SEvan Yan 	 * Want to show up as POWERED state for now. It will be updated to
129426947304SEvan Yan 	 * ENABLED state when user explicitly enable the slot.
129526947304SEvan Yan 	 */
129626947304SEvan Yan 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_POWERED;
129726947304SEvan Yan 
129826947304SEvan Yan 	/* get the current slot state */
129926947304SEvan Yan 	pcishpc_get_slot_state(slot_p);
130026947304SEvan Yan 	/*
130126947304SEvan Yan 	 * It should be poweron'ed now. Have a check here in case any
130226947304SEvan Yan 	 * hardware problems.
130326947304SEvan Yan 	 */
130426947304SEvan Yan 	if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) {
130526947304SEvan Yan 		PCIE_DBG("pcishpc_slot_poweron() failed after hardware"
130626947304SEvan Yan 		    " registers all programmed.\n");
130726947304SEvan Yan 
130826947304SEvan Yan 		goto cleanup;
130926947304SEvan Yan 	}
131026947304SEvan Yan 
131126947304SEvan Yan 	*result_state = slot_p->hs_info.cn_state;
131226947304SEvan Yan 
131326947304SEvan Yan 	return (DDI_SUCCESS);
131426947304SEvan Yan 
131526947304SEvan Yan cleanup:
131626947304SEvan Yan 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
131726947304SEvan Yan 	return (DDI_FAILURE);
131826947304SEvan Yan }
131926947304SEvan Yan 
132026947304SEvan Yan /*ARGSUSED*/
132126947304SEvan Yan static int
132226947304SEvan Yan pcishpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result_state)
132326947304SEvan Yan {
132426947304SEvan Yan 	PCIE_DBG("pcishpc_slot_poweroff called()\n");
132526947304SEvan Yan 
132626947304SEvan Yan 	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
132726947304SEvan Yan 
132826947304SEvan Yan 	/* get the current slot state */
132926947304SEvan Yan 	pcishpc_get_slot_state(slot_p);
133026947304SEvan Yan 
133126947304SEvan Yan 	/* check if the slot is not in the "enabled" or "powered" state */
133226947304SEvan Yan 	if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) {
133326947304SEvan Yan 		/* slot is in the 'disabled' state */
133426947304SEvan Yan 		PCIE_DBG("pcishpc_slot_poweroff(): "
133526947304SEvan Yan 		    "slot %d already disabled\n", slot_p->hs_phy_slot_num);
133626947304SEvan Yan 
133726947304SEvan Yan 		*result_state = slot_p->hs_info.cn_state;
133826947304SEvan Yan 		return (DDI_SUCCESS);
133926947304SEvan Yan 	}
134026947304SEvan Yan 
134126947304SEvan Yan 	/* Set the Power LED to blink */
134226947304SEvan Yan 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
134326947304SEvan Yan 
134426947304SEvan Yan 	/* Turn all other LEDS off */
134526947304SEvan Yan 	(void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF);
134626947304SEvan Yan 	(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
134726947304SEvan Yan 	(void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF);
134826947304SEvan Yan 
134926947304SEvan Yan 	if (--slot_p->hs_ctrl->hc_num_slots_connected == 0)
135026947304SEvan Yan 		slot_p->hs_ctrl->hc_curr_bus_speed = -1;
135126947304SEvan Yan 
135226947304SEvan Yan 	PCIE_DBG("pcishpc_slot_poweroff(): slot_p 0x%p, slot state 0x%x, "
135326947304SEvan Yan 	    "current bus speed 0x%x, slots connected 0x%x\n", slot_p,
135426947304SEvan Yan 	    slot_p->hs_info.cn_state, slot_p->hs_ctrl->hc_curr_bus_speed,
135526947304SEvan Yan 	    slot_p->hs_ctrl->hc_num_slots_connected);
135626947304SEvan Yan 
135726947304SEvan Yan 	/* Mask or Unmask MRL Sensor SEER bit based on new slot state */
135826947304SEvan Yan 	if (slot_p->hs_ctrl->hc_has_mrl == B_TRUE) {
135926947304SEvan Yan 		uint32_t reg;
136026947304SEvan Yan 
136126947304SEvan Yan 		reg = pcishpc_read_reg(slot_p->hs_ctrl,
136226947304SEvan Yan 		    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
136326947304SEvan Yan 
136426947304SEvan Yan 		pcishpc_write_reg(slot_p->hs_ctrl,
136526947304SEvan Yan 		    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num,
136626947304SEvan Yan 		    reg | PCI_HP_SLOT_MRL_SERR_MASK);
136726947304SEvan Yan 	}
136826947304SEvan Yan 
136926947304SEvan Yan 	/* Update the hardware slot state. */
137026947304SEvan Yan 	if (pcishpc_set_slot_state(slot_p, DDI_HP_CN_STATE_PRESENT) !=
137126947304SEvan Yan 	    DDI_SUCCESS) {
137226947304SEvan Yan 		PCIE_DBG("pcishpc_slot_poweroff() failed\n");
137326947304SEvan Yan 
137426947304SEvan Yan 		pcishpc_get_slot_state(slot_p);
137526947304SEvan Yan 		goto cleanup;
137626947304SEvan Yan 	}
137726947304SEvan Yan 
137826947304SEvan Yan 	/* Update the current state. It will be used in pcishpc_setled() */
137926947304SEvan Yan 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_PRESENT;
138026947304SEvan Yan 
138126947304SEvan Yan 	/* Turn the Power LED OFF for a disabled slot. */
138226947304SEvan Yan 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
138326947304SEvan Yan 
138426947304SEvan Yan 	/* Turn all other LEDS off. */
138526947304SEvan Yan 	(void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF);
138626947304SEvan Yan 	(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
138726947304SEvan Yan 	(void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF);
138826947304SEvan Yan 
138926947304SEvan Yan 	/* delay after powerON to let the device initialize itself */
139026947304SEvan Yan 	delay(drv_usectohz(pcishpc_reset_delay));
139126947304SEvan Yan 
139226947304SEvan Yan 	pcishpc_get_slot_state(slot_p);
139326947304SEvan Yan 	/*
139426947304SEvan Yan 	 * It should be poweroff'ed now. Have a check here in case any
139526947304SEvan Yan 	 * hardware problems.
139626947304SEvan Yan 	 */
139726947304SEvan Yan 	if (slot_p->hs_info.cn_state > DDI_HP_CN_STATE_PRESENT) {
139826947304SEvan Yan 		PCIE_DBG("pcishpc_slot_poweroff() failed after hardware"
139926947304SEvan Yan 		    " registers all programmed.\n");
140026947304SEvan Yan 
140126947304SEvan Yan 		goto cleanup;
140226947304SEvan Yan 	}
140326947304SEvan Yan 
140426947304SEvan Yan 	PCIE_DBG("pcishpc_slot_poweroff() success!\n");
140526947304SEvan Yan 
140626947304SEvan Yan 	*result_state = slot_p->hs_info.cn_state;
140726947304SEvan Yan 	return (DDI_SUCCESS);
140826947304SEvan Yan 
140926947304SEvan Yan cleanup:
141026947304SEvan Yan 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
141126947304SEvan Yan 	return (DDI_FAILURE);
141226947304SEvan Yan }
141326947304SEvan Yan 
141426947304SEvan Yan /*
141526947304SEvan Yan  * pcishpc_slot_probe()
141626947304SEvan Yan  *
141726947304SEvan Yan  * Probe the slot.
141826947304SEvan Yan  *
141926947304SEvan Yan  * Note: This function is called by DDI HP framework at kernel context only
142026947304SEvan Yan  */
142126947304SEvan Yan /*ARGSUSED*/
142226947304SEvan Yan static int
142326947304SEvan Yan pcishpc_slot_probe(pcie_hp_slot_t *slot_p)
142426947304SEvan Yan {
142526947304SEvan Yan 	mutex_enter(&slot_p->hs_ctrl->hc_mutex);
142626947304SEvan Yan 
142726947304SEvan Yan 	PCIE_DBG("pcishpc_slot_probe called()\n");
142826947304SEvan Yan 
142926947304SEvan Yan 	/* get the current slot state */
143026947304SEvan Yan 	pcishpc_get_slot_state(slot_p);
143126947304SEvan Yan 
143226947304SEvan Yan 	/*
143326947304SEvan Yan 	 * Probe a given PCI Hotplug Connection (CN).
143426947304SEvan Yan 	 */
143526947304SEvan Yan 	if (pcie_hp_probe(slot_p) != DDI_SUCCESS) {
143626947304SEvan Yan 		(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED,
143726947304SEvan Yan 		    PCIE_HP_LED_BLINK);
143826947304SEvan Yan 
143926947304SEvan Yan 		PCIE_DBG("pcishpc_slot_probe() failed\n");
144026947304SEvan Yan 
144126947304SEvan Yan 		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
144226947304SEvan Yan 		return (DDI_FAILURE);
144326947304SEvan Yan 	}
144426947304SEvan Yan 
144526947304SEvan Yan 	PCIE_DBG("pcishpc_slot_probe() success!\n");
144626947304SEvan Yan 
144726947304SEvan Yan 	/* get the current slot state */
144826947304SEvan Yan 	pcishpc_get_slot_state(slot_p);
144926947304SEvan Yan 
145026947304SEvan Yan 	mutex_exit(&slot_p->hs_ctrl->hc_mutex);
145126947304SEvan Yan 	return (DDI_SUCCESS);
145226947304SEvan Yan }
145326947304SEvan Yan 
145426947304SEvan Yan /*
145526947304SEvan Yan  * pcishpc_slot_unprobe()
145626947304SEvan Yan  *
145726947304SEvan Yan  * Unprobe the slot.
145826947304SEvan Yan  *
145926947304SEvan Yan  * Note: This function is called by DDI HP framework at kernel context only
146026947304SEvan Yan  */
146126947304SEvan Yan /*ARGSUSED*/
146226947304SEvan Yan static int
146326947304SEvan Yan pcishpc_slot_unprobe(pcie_hp_slot_t *slot_p)
146426947304SEvan Yan {
146526947304SEvan Yan 	mutex_enter(&slot_p->hs_ctrl->hc_mutex);
146626947304SEvan Yan 
146726947304SEvan Yan 	PCIE_DBG("pcishpc_slot_unprobe called()\n");
146826947304SEvan Yan 
146926947304SEvan Yan 	/* get the current slot state */
147026947304SEvan Yan 	pcishpc_get_slot_state(slot_p);
147126947304SEvan Yan 
147226947304SEvan Yan 	/*
147326947304SEvan Yan 	 * Unprobe a given PCI Hotplug Connection (CN).
147426947304SEvan Yan 	 */
147526947304SEvan Yan 	if (pcie_hp_unprobe(slot_p) != DDI_SUCCESS) {
147626947304SEvan Yan 		(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED,
147726947304SEvan Yan 		    PCIE_HP_LED_BLINK);
147826947304SEvan Yan 
147926947304SEvan Yan 		PCIE_DBG("pcishpc_slot_unprobe() failed\n");
148026947304SEvan Yan 
148126947304SEvan Yan 		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
148226947304SEvan Yan 		return (DDI_FAILURE);
148326947304SEvan Yan 	}
148426947304SEvan Yan 
148526947304SEvan Yan 	PCIE_DBG("pcishpc_slot_unprobe() success!\n");
148626947304SEvan Yan 
148726947304SEvan Yan 	/* get the current slot state */
148826947304SEvan Yan 	pcishpc_get_slot_state(slot_p);
148926947304SEvan Yan 
149026947304SEvan Yan 	mutex_exit(&slot_p->hs_ctrl->hc_mutex);
149126947304SEvan Yan 	return (DDI_SUCCESS);
149226947304SEvan Yan }
149326947304SEvan Yan 
149426947304SEvan Yan static int
149526947304SEvan Yan pcishpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
149626947304SEvan Yan     ddi_hp_cn_state_t target_state)
149726947304SEvan Yan {
149826947304SEvan Yan 	ddi_hp_cn_state_t curr_state;
149926947304SEvan Yan 	int rv = DDI_SUCCESS;
150026947304SEvan Yan 
150126947304SEvan Yan 	if (target_state > DDI_HP_CN_STATE_ENABLED) {
150226947304SEvan Yan 		return (DDI_EINVAL);
150326947304SEvan Yan 	}
150426947304SEvan Yan 
150526947304SEvan Yan 	curr_state = slot_p->hs_info.cn_state;
150626947304SEvan Yan 	while ((curr_state < target_state) && (rv == DDI_SUCCESS)) {
150726947304SEvan Yan 
150826947304SEvan Yan 		switch (curr_state) {
150926947304SEvan Yan 		case DDI_HP_CN_STATE_EMPTY:
151026947304SEvan Yan 			/*
151126947304SEvan Yan 			 * From EMPTY to PRESENT, just check the hardware
151226947304SEvan Yan 			 * slot state.
151326947304SEvan Yan 			 */
151426947304SEvan Yan 			pcishpc_get_slot_state(slot_p);
151526947304SEvan Yan 			curr_state = slot_p->hs_info.cn_state;
151626947304SEvan Yan 			if (curr_state < DDI_HP_CN_STATE_PRESENT)
151726947304SEvan Yan 				rv = DDI_FAILURE;
151826947304SEvan Yan 			break;
151926947304SEvan Yan 		case DDI_HP_CN_STATE_PRESENT:
152026947304SEvan Yan 			rv = pcishpc_slot_poweron(slot_p, &curr_state);
152126947304SEvan Yan 			break;
152226947304SEvan Yan 		case DDI_HP_CN_STATE_POWERED:
152326947304SEvan Yan 			curr_state = slot_p->hs_info.cn_state =
152426947304SEvan Yan 			    DDI_HP_CN_STATE_ENABLED;
152526947304SEvan Yan 			break;
152626947304SEvan Yan 		default:
152726947304SEvan Yan 			/* should never reach here */
152826947304SEvan Yan 			ASSERT("unknown devinfo state");
152926947304SEvan Yan 		}
153026947304SEvan Yan 	}
153126947304SEvan Yan 
153226947304SEvan Yan 	return (rv);
153326947304SEvan Yan }
153426947304SEvan Yan 
153526947304SEvan Yan static int
153626947304SEvan Yan pcishpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
153726947304SEvan Yan     ddi_hp_cn_state_t target_state)
153826947304SEvan Yan {
153926947304SEvan Yan 	ddi_hp_cn_state_t curr_state;
154026947304SEvan Yan 	int rv = DDI_SUCCESS;
154126947304SEvan Yan 
154226947304SEvan Yan 
154326947304SEvan Yan 	curr_state = slot_p->hs_info.cn_state;
154426947304SEvan Yan 	while ((curr_state > target_state) && (rv == DDI_SUCCESS)) {
154526947304SEvan Yan 
154626947304SEvan Yan 		switch (curr_state) {
154726947304SEvan Yan 		case DDI_HP_CN_STATE_PRESENT:
154826947304SEvan Yan 			/*
154926947304SEvan Yan 			 * From PRESENT to EMPTY, just check hardware
155026947304SEvan Yan 			 * slot state.
155126947304SEvan Yan 			 */
155226947304SEvan Yan 			pcishpc_get_slot_state(slot_p);
155326947304SEvan Yan 			curr_state = slot_p->hs_info.cn_state;
155426947304SEvan Yan 			if (curr_state >= DDI_HP_CN_STATE_PRESENT)
155526947304SEvan Yan 				rv = DDI_FAILURE;
155626947304SEvan Yan 			break;
155726947304SEvan Yan 		case DDI_HP_CN_STATE_POWERED:
155826947304SEvan Yan 			rv = pcishpc_slot_poweroff(slot_p, &curr_state);
155926947304SEvan Yan 
156026947304SEvan Yan 			break;
156126947304SEvan Yan 		case DDI_HP_CN_STATE_ENABLED:
156226947304SEvan Yan 			curr_state = slot_p->hs_info.cn_state =
156326947304SEvan Yan 			    DDI_HP_CN_STATE_POWERED;
156426947304SEvan Yan 
156526947304SEvan Yan 			break;
156626947304SEvan Yan 		default:
156726947304SEvan Yan 			/* should never reach here */
156826947304SEvan Yan 			ASSERT("unknown devinfo state");
156926947304SEvan Yan 		}
157026947304SEvan Yan 	}
157126947304SEvan Yan 
157226947304SEvan Yan 	return (rv);
157326947304SEvan Yan }
157426947304SEvan Yan 
157526947304SEvan Yan /* Change slot state to a target state */
157626947304SEvan Yan static int
157726947304SEvan Yan pcishpc_change_slot_state(pcie_hp_slot_t *slot_p,
157826947304SEvan Yan     ddi_hp_cn_state_t target_state)
157926947304SEvan Yan {
158026947304SEvan Yan 	ddi_hp_cn_state_t curr_state;
158126947304SEvan Yan 	int rv;
158226947304SEvan Yan 
158326947304SEvan Yan 	pcishpc_get_slot_state(slot_p);
158426947304SEvan Yan 	curr_state = slot_p->hs_info.cn_state;
158526947304SEvan Yan 
158626947304SEvan Yan 	if (curr_state == target_state) {
158726947304SEvan Yan 		return (DDI_SUCCESS);
158826947304SEvan Yan 	}
158926947304SEvan Yan 	if (curr_state < target_state) {
159026947304SEvan Yan 
159126947304SEvan Yan 		rv = pcishpc_upgrade_slot_state(slot_p, target_state);
159226947304SEvan Yan 	} else {
159326947304SEvan Yan 		rv = pcishpc_downgrade_slot_state(slot_p, target_state);
159426947304SEvan Yan 	}
159526947304SEvan Yan 
159626947304SEvan Yan 	return (rv);
159726947304SEvan Yan }
159826947304SEvan Yan 
159926947304SEvan Yan /*
160026947304SEvan Yan  * pcishpc_issue_command()
160126947304SEvan Yan  *
160226947304SEvan Yan  * Sends a command to the SHPC controller.
160326947304SEvan Yan  */
160426947304SEvan Yan static int
160526947304SEvan Yan pcishpc_issue_command(pcie_hp_ctrl_t *ctrl_p, uint32_t cmd_code)
160626947304SEvan Yan {
160726947304SEvan Yan 	int	retCode;
160826947304SEvan Yan 
160926947304SEvan Yan 	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
161026947304SEvan Yan 
161126947304SEvan Yan 	PCIE_DBG("pcishpc_issue_command() cmd_code=%02x\n", cmd_code);
161226947304SEvan Yan 
161326947304SEvan Yan 	ctrl_p->hc_cmd_pending = B_TRUE;
161426947304SEvan Yan 
161526947304SEvan Yan 	/* Write the command to the SHPC controller. */
161626947304SEvan Yan 	pcishpc_write_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG, cmd_code);
161726947304SEvan Yan 
161826947304SEvan Yan 	while (ctrl_p->hc_cmd_pending == B_TRUE)
161926947304SEvan Yan 		cv_wait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex);
162026947304SEvan Yan 
162126947304SEvan Yan 	/* Wait until the SHPC controller processes the command. */
162226947304SEvan Yan 	retCode = pcishpc_wait_busy(ctrl_p);
162326947304SEvan Yan 
162426947304SEvan Yan 	/* Make sure the command completed. */
162526947304SEvan Yan 	if (retCode == DDI_SUCCESS) {
162626947304SEvan Yan 		/* Did the command fail to generate the command complete IRQ? */
162726947304SEvan Yan 		if (ctrl_p->hc_cmd_pending != B_FALSE) {
162826947304SEvan Yan 			PCIE_DBG("pcishpc_issue_command() Failed on "
162926947304SEvan Yan 			    "generate cmd complete IRQ\n");
163026947304SEvan Yan 			retCode = DDI_FAILURE;
163126947304SEvan Yan 		}
163226947304SEvan Yan 	}
163326947304SEvan Yan 
163426947304SEvan Yan 	if (retCode == DDI_FAILURE)
163526947304SEvan Yan 		PCIE_DBG("pcishpc_issue_command() Failed on cmd_code=%02x\n",
163626947304SEvan Yan 		    cmd_code);
163726947304SEvan Yan 	else
163826947304SEvan Yan 		PCIE_DBG("pcishpc_issue_command() Success on "
163926947304SEvan Yan 		    "cmd_code=%02x\n", cmd_code);
164026947304SEvan Yan 
164126947304SEvan Yan 	return (retCode);
164226947304SEvan Yan }
164326947304SEvan Yan 
164426947304SEvan Yan /*
164526947304SEvan Yan  * pcishpc_wait_busy()
164626947304SEvan Yan  *
164726947304SEvan Yan  * Wait until the SHPC controller is not busy.
164826947304SEvan Yan  */
164926947304SEvan Yan static int
165026947304SEvan Yan pcishpc_wait_busy(pcie_hp_ctrl_t *ctrl_p)
165126947304SEvan Yan {
165226947304SEvan Yan 	uint32_t	status;
165326947304SEvan Yan 
165426947304SEvan Yan 	/* Wait until SHPC controller is NOT busy */
165526947304SEvan Yan 	for (;;) {
165626947304SEvan Yan 		status = pcishpc_read_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG);
165726947304SEvan Yan 
165826947304SEvan Yan 		/* Is there an MRL Sensor error? */
165926947304SEvan Yan 		if ((status & PCI_HP_COMM_STS_ERR_MASK) ==
166026947304SEvan Yan 		    PCI_HP_COMM_STS_ERR_MRL_OPEN) {
166126947304SEvan Yan 			PCIE_DBG("pcishpc_wait_busy() ERROR: "
166226947304SEvan Yan 			    "MRL Sensor error\n");
166326947304SEvan Yan 			break;
166426947304SEvan Yan 		}
166526947304SEvan Yan 
166626947304SEvan Yan 		/* Is there an Invalid command error? */
166726947304SEvan Yan 		if ((status & PCI_HP_COMM_STS_ERR_MASK) ==
166826947304SEvan Yan 		    PCI_HP_COMM_STS_ERR_INVALID_COMMAND) {
166926947304SEvan Yan 			PCIE_DBG("pcishpc_wait_busy() ERROR: Invalid "
167026947304SEvan Yan 			    "command error\n");
167126947304SEvan Yan 			break;
167226947304SEvan Yan 		}
167326947304SEvan Yan 
167426947304SEvan Yan 		/* Is there an Invalid Speed/Mode error? */
167526947304SEvan Yan 		if ((status & PCI_HP_COMM_STS_ERR_MASK) ==
167626947304SEvan Yan 		    PCI_HP_COMM_STS_ERR_INVALID_SPEED) {
167726947304SEvan Yan 			PCIE_DBG("pcishpc_wait_busy() ERROR: Invalid "
167826947304SEvan Yan 			    "Speed/Mode error\n");
167926947304SEvan Yan 			break;
168026947304SEvan Yan 		}
168126947304SEvan Yan 
168226947304SEvan Yan 		/* Is the SHPC controller not BUSY? */
168326947304SEvan Yan 		if (!(status & PCI_HP_COMM_STS_CTRL_BUSY)) {
168426947304SEvan Yan 			/* Return Success. */
168526947304SEvan Yan 			return (DDI_SUCCESS);
168626947304SEvan Yan 		}
168726947304SEvan Yan 
168826947304SEvan Yan 		PCIE_DBG("pcishpc_wait_busy() SHPC controller busy. Waiting\n");
168926947304SEvan Yan 
169026947304SEvan Yan 		/* Wait before polling the status register again. */
169126947304SEvan Yan 		delay(drv_usectohz(PCIE_HP_CMD_WAIT_TIME));
169226947304SEvan Yan 	}
169326947304SEvan Yan 
169426947304SEvan Yan 	return (DDI_FAILURE);
169526947304SEvan Yan }
169626947304SEvan Yan 
169726947304SEvan Yan static void
169826947304SEvan Yan pcishpc_attn_btn_handler(pcie_hp_slot_t *slot_p)
169926947304SEvan Yan {
170026947304SEvan Yan 	pcie_hp_led_state_t hs_power_led_state;
170126947304SEvan Yan 	callb_cpr_t cprinfo;
170226947304SEvan Yan 
170326947304SEvan Yan 	PCIE_DBG("pcishpc_attn_btn_handler: thread started\n");
170426947304SEvan Yan 
170526947304SEvan Yan 	CALLB_CPR_INIT(&cprinfo, &slot_p->hs_ctrl->hc_mutex,
170626947304SEvan Yan 	    callb_generic_cpr, "pcishpc_attn_btn_handler");
170726947304SEvan Yan 
170826947304SEvan Yan 	mutex_enter(&slot_p->hs_ctrl->hc_mutex);
170926947304SEvan Yan 
171026947304SEvan Yan 	/* wait for ATTN button event */
171126947304SEvan Yan 	cv_wait(&slot_p->hs_attn_btn_cv, &slot_p->hs_ctrl->hc_mutex);
171226947304SEvan Yan 
171326947304SEvan Yan 	while (slot_p->hs_attn_btn_thread_exit == B_FALSE) {
171426947304SEvan Yan 		if (slot_p->hs_attn_btn_pending == B_TRUE) {
171526947304SEvan Yan 			/* get the current state of power LED */
171626947304SEvan Yan 			hs_power_led_state = slot_p->hs_power_led_state;
171726947304SEvan Yan 
171826947304SEvan Yan 			/* Blink the Power LED while we wait for 5 seconds */
171926947304SEvan Yan 			(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED,
172026947304SEvan Yan 			    PCIE_HP_LED_BLINK);
172126947304SEvan Yan 
172226947304SEvan Yan 			/* wait for 5 seconds before taking any action */
1723d3d50737SRafael Vanoni 			if (cv_reltimedwait(&slot_p->hs_attn_btn_cv,
172426947304SEvan Yan 			    &slot_p->hs_ctrl->hc_mutex,
1725d3d50737SRafael Vanoni 			    SEC_TO_TICK(5), TR_CLOCK_TICK) == -1) {
172626947304SEvan Yan 				/*
172726947304SEvan Yan 				 * It is a time out;
172826947304SEvan Yan 				 * make sure the ATTN pending flag is
172926947304SEvan Yan 				 * still ON before sending the event
173026947304SEvan Yan 				 * to DDI HP framework.
173126947304SEvan Yan 				 */
173226947304SEvan Yan 				if (slot_p->hs_attn_btn_pending == B_TRUE) {
173326947304SEvan Yan 					int hint;
173426947304SEvan Yan 
173526947304SEvan Yan 					/* restore the power LED state */
173626947304SEvan Yan 					(void) pcishpc_setled(slot_p,
173726947304SEvan Yan 					    PCIE_HP_POWER_LED,
173826947304SEvan Yan 					    hs_power_led_state);
173926947304SEvan Yan 					/*
174026947304SEvan Yan 					 * send the ATTN button event
174126947304SEvan Yan 					 * to DDI HP framework
174226947304SEvan Yan 					 */
174326947304SEvan Yan 					slot_p->hs_attn_btn_pending = B_FALSE;
174426947304SEvan Yan 
174526947304SEvan Yan 					pcishpc_get_slot_state(slot_p);
174626947304SEvan Yan 
174726947304SEvan Yan 					if (slot_p->hs_info.cn_state <=
174826947304SEvan Yan 					    DDI_HP_CN_STATE_PRESENT) {
174926947304SEvan Yan 						/*
175026947304SEvan Yan 						 * Insertion.
175126947304SEvan Yan 						 */
175226947304SEvan Yan 						hint = SE_INCOMING_RES;
175326947304SEvan Yan 					} else {
175426947304SEvan Yan 						/*
175526947304SEvan Yan 						 * Want to remove;
175626947304SEvan Yan 						 */
175726947304SEvan Yan 						hint = SE_OUTGOING_RES;
175826947304SEvan Yan 					}
175926947304SEvan Yan 					pcie_hp_gen_sysevent_req(
176026947304SEvan Yan 					    slot_p->hs_info.cn_name,
176126947304SEvan Yan 					    hint,
176226947304SEvan Yan 					    slot_p->hs_ctrl->hc_dip,
176326947304SEvan Yan 					    KM_SLEEP);
176426947304SEvan Yan 
176526947304SEvan Yan 					continue;
176626947304SEvan Yan 				}
176726947304SEvan Yan 			}
176826947304SEvan Yan 
176926947304SEvan Yan 			/* restore the power LED state */
177026947304SEvan Yan 			(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED,
177126947304SEvan Yan 			    hs_power_led_state);
177226947304SEvan Yan 			continue;
177326947304SEvan Yan 		}
177426947304SEvan Yan 
177526947304SEvan Yan 		/* wait for another ATTN button event */
177626947304SEvan Yan 		cv_wait(&slot_p->hs_attn_btn_cv, &slot_p->hs_ctrl->hc_mutex);
177726947304SEvan Yan 	}
177826947304SEvan Yan 
177926947304SEvan Yan 	PCIE_DBG("pcishpc_attn_btn_handler: thread exit\n");
178026947304SEvan Yan 	cv_signal(&slot_p->hs_attn_btn_cv);
178126947304SEvan Yan 	CALLB_CPR_EXIT(&cprinfo);
178226947304SEvan Yan 	thread_exit();
178326947304SEvan Yan }
178426947304SEvan Yan 
178526947304SEvan Yan /*
178626947304SEvan Yan  * pcishpc_get_slot_state()
178726947304SEvan Yan  *
178826947304SEvan Yan  * Get the state of the slot.
178926947304SEvan Yan  * The slot state should have been initialized before this function gets called.
179026947304SEvan Yan  */
179126947304SEvan Yan static void
179226947304SEvan Yan pcishpc_get_slot_state(pcie_hp_slot_t *slot_p)
179326947304SEvan Yan {
179426947304SEvan Yan 	uint32_t reg;
179526947304SEvan Yan 	ddi_hp_cn_state_t curr_state = slot_p->hs_info.cn_state;
179626947304SEvan Yan 
179726947304SEvan Yan 	/* Read the logical slot register for this Slot. */
179826947304SEvan Yan 	reg = pcishpc_read_reg(slot_p->hs_ctrl,
179926947304SEvan Yan 	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
180026947304SEvan Yan 
180126947304SEvan Yan 	/* Convert from the SHPC slot state to the HPC slot state. */
180226947304SEvan Yan 	slot_p->hs_info.cn_state = pcishpc_slot_shpc_to_hpc(reg);
180326947304SEvan Yan 	if (curr_state == DDI_HP_CN_STATE_POWERED &&
180426947304SEvan Yan 	    slot_p->hs_info.cn_state > DDI_HP_CN_STATE_POWERED) {
180526947304SEvan Yan 		/*
180626947304SEvan Yan 		 * Keep POWERED state if it is currently POWERED state because
180726947304SEvan Yan 		 * this driver does not really implement enable/disable
180826947304SEvan Yan 		 * slot operations. That is, when poweron, it actually enables
180926947304SEvan Yan 		 * the slot also.
181026947304SEvan Yan 		 * So, from hardware view, POWERED == ENABLED.
181126947304SEvan Yan 		 * But, when user explicitly change to POWERED state, it should
181226947304SEvan Yan 		 * be kept until user explicitly change to other states later.
181326947304SEvan Yan 		 */
181426947304SEvan Yan 		slot_p->hs_info.cn_state = DDI_HP_CN_STATE_POWERED;
181526947304SEvan Yan 	}
181626947304SEvan Yan 
181726947304SEvan Yan 	/* Convert from the SHPC Power LED state to the HPC Power LED state. */
181826947304SEvan Yan 	slot_p->hs_power_led_state = pcishpc_led_shpc_to_hpc((reg>>2)&3);
181926947304SEvan Yan 
182026947304SEvan Yan 	/* Convert from the SHPC Attn LED state to the HPC Attn LED state. */
182126947304SEvan Yan 	slot_p->hs_attn_led_state = pcishpc_led_shpc_to_hpc((reg>>4)&3);
182226947304SEvan Yan 
182326947304SEvan Yan 	/* We don't have a fault LED so just default it to OFF. */
182426947304SEvan Yan 	slot_p->hs_fault_led_state = PCIE_HP_LED_OFF;
182526947304SEvan Yan 
182626947304SEvan Yan 	/* We don't have an active LED so just default it to OFF. */
182726947304SEvan Yan 	slot_p->hs_active_led_state = PCIE_HP_LED_OFF;
182826947304SEvan Yan }
182926947304SEvan Yan 
183026947304SEvan Yan /*
183126947304SEvan Yan  * pcishpc_set_slot_state()
183226947304SEvan Yan  *
183326947304SEvan Yan  * Updates the slot's state and leds.
183426947304SEvan Yan  */
183526947304SEvan Yan static int
183626947304SEvan Yan pcishpc_set_slot_state(pcie_hp_slot_t *slot_p,
183726947304SEvan Yan     ddi_hp_cn_state_t new_slot_state)
183826947304SEvan Yan {
183926947304SEvan Yan 	uint32_t		reg, cmd_code;
184026947304SEvan Yan 	ddi_hp_cn_state_t	curr_state;
184126947304SEvan Yan 
184226947304SEvan Yan 	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
184326947304SEvan Yan 
184426947304SEvan Yan 	reg = pcishpc_read_reg(slot_p->hs_ctrl,
184526947304SEvan Yan 	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
184626947304SEvan Yan 
184726947304SEvan Yan 	/* Default all states to unchanged. */
184826947304SEvan Yan 	cmd_code = ((1 + slot_p->hs_num) << 8);
184926947304SEvan Yan 
185026947304SEvan Yan 	/* Has the slot state changed? */
185126947304SEvan Yan 	curr_state = pcishpc_slot_shpc_to_hpc(reg);
185226947304SEvan Yan 	if (curr_state != new_slot_state) {
185326947304SEvan Yan 		PCIE_DBG("pcishpc_set_slot_state() Slot State changed");
185426947304SEvan Yan 
185526947304SEvan Yan 		/* Set the new slot state in the Slot operation command. */
185626947304SEvan Yan 		cmd_code |= pcishpc_slot_hpc_to_shpc(new_slot_state);
185726947304SEvan Yan 	}
185826947304SEvan Yan 
185926947304SEvan Yan 	/* Has the Power LED state changed? */
186026947304SEvan Yan 	if (slot_p->hs_power_led_state != pcishpc_led_shpc_to_hpc((reg>>2)&3)) {
186126947304SEvan Yan 		PCIE_DBG("pcishpc_set_slot_state() Power LED State changed\n");
186226947304SEvan Yan 
186326947304SEvan Yan 		/* Set the new power led state in the Slot operation command. */
186426947304SEvan Yan 		cmd_code |=
186526947304SEvan Yan 		    (pcishpc_led_hpc_to_shpc(slot_p->hs_power_led_state) << 2);
186626947304SEvan Yan 	}
186726947304SEvan Yan 
186826947304SEvan Yan 	/* Has the Attn LED state changed? */
186926947304SEvan Yan 	if (slot_p->hs_attn_led_state != pcishpc_led_shpc_to_hpc((reg>>4)&3)) {
187026947304SEvan Yan 		PCIE_DBG("pcishpc_set_slot_state() Attn LED State changed\n");
187126947304SEvan Yan 
187226947304SEvan Yan 		/* Set the new attn led state in the Slot operation command. */
187326947304SEvan Yan 		cmd_code |=
187426947304SEvan Yan 		    (pcishpc_led_hpc_to_shpc(slot_p->hs_attn_led_state) << 4);
187526947304SEvan Yan 	}
187626947304SEvan Yan 
187726947304SEvan Yan 	return (pcishpc_issue_command(slot_p->hs_ctrl, cmd_code));
187826947304SEvan Yan }
187926947304SEvan Yan 
188026947304SEvan Yan /*
188126947304SEvan Yan  * setup slot name/slot-number info.
188226947304SEvan Yan  */
188326947304SEvan Yan static void
188426947304SEvan Yan pcishpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p, int slot)
188526947304SEvan Yan {
188626947304SEvan Yan 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[slot];
188726947304SEvan Yan 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
188826947304SEvan Yan 	uchar_t *slotname_data;
188926947304SEvan Yan 	int *slotnum;
189026947304SEvan Yan 	uint_t count;
189126947304SEvan Yan 	int len;
189226947304SEvan Yan 	uchar_t *s;
189326947304SEvan Yan 	uint32_t bit_mask;
189426947304SEvan Yan 	int pci_id_cnt, pci_id_bit;
189526947304SEvan Yan 	int slots_before, found;
189626947304SEvan Yan 	int invalid_slotnum = 0;
189726947304SEvan Yan 
189826947304SEvan Yan 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ctrl_p->hc_dip,
189926947304SEvan Yan 	    DDI_PROP_DONTPASS, "physical-slot#", &slotnum, &count) ==
190026947304SEvan Yan 	    DDI_PROP_SUCCESS) {
190126947304SEvan Yan 		slot_p->hs_phy_slot_num = slotnum[0];
190226947304SEvan Yan 		ddi_prop_free(slotnum);
190326947304SEvan Yan 	} else {
190426947304SEvan Yan 		if (ctrl_p->hc_device_increases)
190526947304SEvan Yan 			slot_p->hs_phy_slot_num = ctrl_p->hc_phys_start + slot;
190626947304SEvan Yan 		else
190726947304SEvan Yan 			slot_p->hs_phy_slot_num = ctrl_p->hc_phys_start - slot;
190826947304SEvan Yan 
190926947304SEvan Yan 		if ((ndi_prop_update_int(DDI_DEV_T_NONE, ctrl_p->hc_dip,
191026947304SEvan Yan 		    "physical-slot#", slot_p->hs_phy_slot_num)) != DDI_SUCCESS)
191126947304SEvan Yan 			PCIE_DBG("pcishpc_set_slot_name(): failed to "
191226947304SEvan Yan 			    "create phyical-slot#%d\n",
191326947304SEvan Yan 			    slot_p->hs_phy_slot_num);
191426947304SEvan Yan 	}
191526947304SEvan Yan 
191626947304SEvan Yan 	/* Platform may not have initialized it */
191726947304SEvan Yan 	if (!slot_p->hs_phy_slot_num) {
191826947304SEvan Yan 		slot_p->hs_phy_slot_num = pci_config_get8(bus_p->bus_cfg_hdl,
191926947304SEvan Yan 		    PCI_BCNF_SECBUS);
192026947304SEvan Yan 		invalid_slotnum = 1;
192126947304SEvan Yan 	}
192226947304SEvan Yan 	slot_p->hs_info.cn_num = slot_p->hs_phy_slot_num;
192326947304SEvan Yan 	slot_p->hs_info.cn_num_dpd_on = DDI_HP_CN_NUM_NONE;
192426947304SEvan Yan 
192526947304SEvan Yan 	/*
192626947304SEvan Yan 	 * construct the slot_name:
1927296f12dcSToomas Soome 	 *	if "slot-names" property exists then use that name
192826947304SEvan Yan 	 *	else if valid slot number exists then it is "pci<slot-num>".
192926947304SEvan Yan 	 *	else it will be "pci<sec-bus-number>dev<dev-number>"
193026947304SEvan Yan 	 */
193126947304SEvan Yan 	if (ddi_getlongprop(DDI_DEV_T_ANY, ctrl_p->hc_dip, DDI_PROP_DONTPASS,
193226947304SEvan Yan 	    "slot-names", (caddr_t)&slotname_data, &len) == DDI_PROP_SUCCESS) {
193326947304SEvan Yan 		bit_mask = slotname_data[3] | (slotname_data[2] << 8) |
193426947304SEvan Yan 		    (slotname_data[1] << 16) | (slotname_data[0] << 24);
193526947304SEvan Yan 
193626947304SEvan Yan 		pci_id_bit = 1;
193726947304SEvan Yan 		pci_id_cnt = slots_before = found = 0;
193826947304SEvan Yan 
193926947304SEvan Yan 		/*
194026947304SEvan Yan 		 * Walk the bit mask until we find the bit that corresponds
194126947304SEvan Yan 		 * to our slots device number.  We count how many bits
194226947304SEvan Yan 		 * we find before we find our slot's bit.
194326947304SEvan Yan 		 */
194426947304SEvan Yan 		while (!found && (pci_id_cnt < 32)) {
194526947304SEvan Yan 			while (slot_p->hs_device_num != pci_id_cnt) {
194626947304SEvan Yan 
194726947304SEvan Yan 				/*
194826947304SEvan Yan 				 * Find the next bit set.
194926947304SEvan Yan 				 */
195026947304SEvan Yan 				while (!(bit_mask & pci_id_bit) &&
195126947304SEvan Yan 				    (pci_id_cnt < 32)) {
195226947304SEvan Yan 					pci_id_bit = pci_id_bit << 1;
195326947304SEvan Yan 					pci_id_cnt++;
195426947304SEvan Yan 				}
195526947304SEvan Yan 
195626947304SEvan Yan 				if (slot_p->hs_device_num != pci_id_cnt)
195726947304SEvan Yan 					slots_before++;
195826947304SEvan Yan 				else
195926947304SEvan Yan 					found = 1;
196026947304SEvan Yan 			}
196126947304SEvan Yan 		}
196226947304SEvan Yan 
196326947304SEvan Yan 		if (pci_id_cnt < 32) {
196426947304SEvan Yan 
196526947304SEvan Yan 			/*
196626947304SEvan Yan 			 * Set ptr to first string.
196726947304SEvan Yan 			 */
196826947304SEvan Yan 			s = slotname_data + 4;
196926947304SEvan Yan 
197026947304SEvan Yan 			/*
197126947304SEvan Yan 			 * Increment past all the strings for the slots
197226947304SEvan Yan 			 * before ours.
197326947304SEvan Yan 			 */
197426947304SEvan Yan 			while (slots_before) {
1975296f12dcSToomas Soome 				while (*s != '\0')
197626947304SEvan Yan 					s++;
197726947304SEvan Yan 				s++;
197826947304SEvan Yan 				slots_before--;
197926947304SEvan Yan 			}
198026947304SEvan Yan 
198126947304SEvan Yan 			slot_p->hs_info.cn_name = i_ddi_strdup((char *)s,
198226947304SEvan Yan 			    KM_SLEEP);
198326947304SEvan Yan 			kmem_free(slotname_data, len);
198426947304SEvan Yan 			return;
198526947304SEvan Yan 		}
198626947304SEvan Yan 
198726947304SEvan Yan 		/* slot-names entry not found */
198826947304SEvan Yan 		PCIE_DBG("pcishpc_set_slot_name(): "
198926947304SEvan Yan 		    "No slot-names entry found for slot #%d\n",
199026947304SEvan Yan 		    slot_p->hs_phy_slot_num);
199126947304SEvan Yan 		kmem_free(slotname_data, len);
199226947304SEvan Yan 	}
199326947304SEvan Yan 
199426947304SEvan Yan 	if (invalid_slotnum) {
199526947304SEvan Yan 		char tmp_name[256];
199626947304SEvan Yan 
199726947304SEvan Yan 		(void) snprintf(tmp_name, sizeof (tmp_name), "pci%d",
199826947304SEvan Yan 		    slot_p->hs_device_num);
199926947304SEvan Yan 		slot_p->hs_info.cn_name = i_ddi_strdup(tmp_name, KM_SLEEP);
200026947304SEvan Yan 	} else {
200126947304SEvan Yan 		char tmp_name[256];
200226947304SEvan Yan 
200326947304SEvan Yan 		(void) snprintf(tmp_name, sizeof (tmp_name), "pci%d",
200426947304SEvan Yan 		    slot_p->hs_phy_slot_num);
200526947304SEvan Yan 		slot_p->hs_info.cn_name = i_ddi_strdup(tmp_name, KM_SLEEP);
200626947304SEvan Yan 	}
200726947304SEvan Yan }
200826947304SEvan Yan 
200926947304SEvan Yan /*
201026947304SEvan Yan  * pcishpc_set_bus_speed()
201126947304SEvan Yan  *
201226947304SEvan Yan  * Set the bus speed and mode.
201326947304SEvan Yan  */
201426947304SEvan Yan static int
201526947304SEvan Yan pcishpc_set_bus_speed(pcie_hp_slot_t *slot_p)
201626947304SEvan Yan {
201726947304SEvan Yan 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
201826947304SEvan Yan 	int		curr_speed = ctrl_p->hc_curr_bus_speed;
201926947304SEvan Yan 	int		speed = -1;
202026947304SEvan Yan 	int		avail_slots;
202126947304SEvan Yan 	uint32_t	status, slots_avail1_reg, slots_avail2_reg;
202226947304SEvan Yan 
202326947304SEvan Yan 	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
202426947304SEvan Yan 
202526947304SEvan Yan 	/* Make sure that the slot is in a correct state */
202626947304SEvan Yan 	status = pcishpc_read_reg(ctrl_p,
202726947304SEvan Yan 	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
202826947304SEvan Yan 
202926947304SEvan Yan 	/* Return failure if the slot is empty */
203026947304SEvan Yan 	if ((status & PCI_HP_SLOT_CARD_EMPTY_MASK) ==
203126947304SEvan Yan 	    PCI_HP_SLOT_CARD_EMPTY_MASK) {
203226947304SEvan Yan 		PCIE_DBG("pcishpc_set_bus_speed() failed: "
203326947304SEvan Yan 		    "the slot is empty\n");
203426947304SEvan Yan 		return (DDI_FAILURE);
203526947304SEvan Yan 	}
203626947304SEvan Yan 
203726947304SEvan Yan 	/* Return failure if the slot is not in disabled state */
203826947304SEvan Yan 	if ((status & PCI_HP_SLOT_STATE_MASK) != PCI_HP_SLOT_DISABLED) {
203926947304SEvan Yan 		PCIE_DBG("pcishpc_set_bus_speed() failed: "
204026947304SEvan Yan 		    "incorrect slot state\n");
204126947304SEvan Yan 		return (DDI_FAILURE);
204226947304SEvan Yan 	}
204326947304SEvan Yan 
204426947304SEvan Yan 	/* Set the "power-only" mode for the slot */
204526947304SEvan Yan 	if (pcishpc_issue_command(ctrl_p, ((1+slot_p->hs_num)<<8) |
204626947304SEvan Yan 	    PCI_HP_SLOT_POWER_ONLY) != DDI_SUCCESS) {
204726947304SEvan Yan 		PCIE_DBG("pcishpc_set_bus_speed() failed to set "
204826947304SEvan Yan 		    "the slot %d in the power-only mode\n", slot_p->hs_num);
204926947304SEvan Yan 		return (DDI_FAILURE);
205026947304SEvan Yan 	}
205126947304SEvan Yan 
205226947304SEvan Yan 	/* Wait for power good */
205326947304SEvan Yan 	delay(drv_usectohz(PCIE_HP_POWER_GOOD_WAIT_TIME));
205426947304SEvan Yan 
205526947304SEvan Yan 	/* Make sure that the slot is in "power-only" state */
205626947304SEvan Yan 	status = pcishpc_read_reg(ctrl_p,
205726947304SEvan Yan 	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
205826947304SEvan Yan 
205926947304SEvan Yan 	if ((status & PCI_HP_SLOT_STATE_MASK) != PCI_HP_SLOT_POWER_ONLY) {
206026947304SEvan Yan 		PCIE_DBG("pcishpc_set_bus_speed() "
206126947304SEvan Yan 		    "power-only failed: incorrect slot state\n");
206226947304SEvan Yan 		return (DDI_FAILURE);
206326947304SEvan Yan 	}
206426947304SEvan Yan 
206526947304SEvan Yan 	slots_avail1_reg = pcishpc_read_reg(ctrl_p,
206626947304SEvan Yan 	    PCI_HP_SLOTS_AVAIL_I_REG);
206726947304SEvan Yan 	slots_avail2_reg = pcishpc_read_reg(ctrl_p,
206826947304SEvan Yan 	    PCI_HP_SLOTS_AVAIL_II_REG);
206926947304SEvan Yan 
207026947304SEvan Yan 	/*
207126947304SEvan Yan 	 * Check if SHPC has available slots and select the highest
207226947304SEvan Yan 	 * available bus speed for the slot.
207326947304SEvan Yan 	 *
207426947304SEvan Yan 	 * The bus speed codes are:
207526947304SEvan Yan 	 * 100 - 133Mhz; <--+
207626947304SEvan Yan 	 * 011 - 100Mhz; <--+   PCI-X
207726947304SEvan Yan 	 * 010 - 66Mhz;  <--+
207826947304SEvan Yan 	 *
207926947304SEvan Yan 	 * 001 - 66Mhz;  <--+
208026947304SEvan Yan 	 * 000 - 33Mhz   <--+   Conv PCI
208126947304SEvan Yan 	 */
208226947304SEvan Yan 	switch (status & PCI_HP_SLOT_PCIX_CAPABLE_MASK) {
208326947304SEvan Yan 	case PCI_HP_SLOT_133MHZ_PCIX_CAPABLE:
208426947304SEvan Yan 		avail_slots = (slots_avail1_reg >>
208526947304SEvan Yan 		    PCI_HP_AVAIL_133MHZ_PCIX_SPEED_SHIFT) &
208626947304SEvan Yan 		    PCI_HP_AVAIL_SPEED_MASK;
208726947304SEvan Yan 
208826947304SEvan Yan 		if (((curr_speed == -1) && avail_slots) ||
208926947304SEvan Yan 		    (curr_speed == PCI_HP_SBCR_133MHZ_PCIX_SPEED)) {
209026947304SEvan Yan 			speed = PCI_HP_SBCR_133MHZ_PCIX_SPEED;
209126947304SEvan Yan 			break;
209226947304SEvan Yan 		}
209326947304SEvan Yan 		/* FALLTHROUGH */
209426947304SEvan Yan 	case PCI_HP_SLOT_100MHZ_PCIX_CAPABLE:
209526947304SEvan Yan 		avail_slots = (slots_avail1_reg >>
209626947304SEvan Yan 		    PCI_HP_AVAIL_100MHZ_PCIX_SPEED_SHIFT) &
209726947304SEvan Yan 		    PCI_HP_AVAIL_SPEED_MASK;
209826947304SEvan Yan 
209926947304SEvan Yan 		if (((curr_speed == -1) && avail_slots) ||
210026947304SEvan Yan 		    (curr_speed == PCI_HP_SBCR_100MHZ_PCIX_SPEED)) {
210126947304SEvan Yan 			speed = PCI_HP_SBCR_100MHZ_PCIX_SPEED;
210226947304SEvan Yan 			break;
210326947304SEvan Yan 		}
210426947304SEvan Yan 		/* FALLTHROUGH */
210526947304SEvan Yan 	case PCI_HP_SLOT_66MHZ_PCIX_CAPABLE:
210626947304SEvan Yan 		avail_slots = (slots_avail1_reg >>
210726947304SEvan Yan 		    PCI_HP_AVAIL_66MHZ_PCIX_SPEED_SHIFT) &
210826947304SEvan Yan 		    PCI_HP_AVAIL_SPEED_MASK;
210926947304SEvan Yan 
211026947304SEvan Yan 		if (((curr_speed == -1) && avail_slots) ||
211126947304SEvan Yan 		    (curr_speed == PCI_HP_SBCR_66MHZ_PCIX_SPEED)) {
211226947304SEvan Yan 			speed = PCI_HP_SBCR_66MHZ_PCIX_SPEED;
211326947304SEvan Yan 			break;
211426947304SEvan Yan 		}
211526947304SEvan Yan 		/* FALLTHROUGH */
211626947304SEvan Yan 	default:
211726947304SEvan Yan 		avail_slots = (slots_avail2_reg >>
211826947304SEvan Yan 		    PCI_HP_AVAIL_66MHZ_CONV_SPEED_SHIFT) &
211926947304SEvan Yan 		    PCI_HP_AVAIL_SPEED_MASK;
212026947304SEvan Yan 
212126947304SEvan Yan 		if ((status & PCI_HP_SLOT_66MHZ_CONV_CAPABLE) &&
212226947304SEvan Yan 		    (((curr_speed == -1) && avail_slots) ||
212326947304SEvan Yan 		    (curr_speed == PCI_HP_SBCR_66MHZ_CONV_SPEED))) {
212426947304SEvan Yan 			speed = PCI_HP_SBCR_66MHZ_CONV_SPEED;
212526947304SEvan Yan 		} else {
212626947304SEvan Yan 			avail_slots = (slots_avail1_reg >>
212726947304SEvan Yan 			    PCI_HP_AVAIL_33MHZ_CONV_SPEED_SHIFT) &
212826947304SEvan Yan 			    PCI_HP_AVAIL_SPEED_MASK;
212926947304SEvan Yan 
213026947304SEvan Yan 			if (((curr_speed == -1) && (avail_slots)) ||
213126947304SEvan Yan 			    (curr_speed == PCI_HP_SBCR_33MHZ_CONV_SPEED)) {
213226947304SEvan Yan 				speed = PCI_HP_SBCR_33MHZ_CONV_SPEED;
213326947304SEvan Yan 			} else {
213426947304SEvan Yan 				PCIE_DBG("pcishpc_set_bus_speed() "
213526947304SEvan Yan 				    " failed to set the bus speed, slot# %d\n",
213626947304SEvan Yan 				    slot_p->hs_num);
213726947304SEvan Yan 				return (DDI_FAILURE);
213826947304SEvan Yan 			}
213926947304SEvan Yan 		}
214026947304SEvan Yan 		break;
214126947304SEvan Yan 	}
214226947304SEvan Yan 
214326947304SEvan Yan 	/*
214426947304SEvan Yan 	 * If the bus segment is already running, check to see the card
214526947304SEvan Yan 	 * in the slot can support the current bus speed.
214626947304SEvan Yan 	 */
214726947304SEvan Yan 	if (curr_speed == speed) {
214826947304SEvan Yan 		/*
214926947304SEvan Yan 		 * Check to see there is any slot available for the current
215026947304SEvan Yan 		 * bus speed. Otherwise, we need fail the current slot connect
215126947304SEvan Yan 		 * request.
215226947304SEvan Yan 		 */
215326947304SEvan Yan 		return ((avail_slots <= ctrl_p->hc_num_slots_connected) ?
215426947304SEvan Yan 		    DDI_FAILURE : DDI_SUCCESS);
215526947304SEvan Yan 	}
215626947304SEvan Yan 
215726947304SEvan Yan 	/* Set the bus speed */
215826947304SEvan Yan 	if (pcishpc_issue_command(ctrl_p, PCI_HP_COMM_STS_SET_SPEED |
215926947304SEvan Yan 	    speed) == DDI_FAILURE) {
216026947304SEvan Yan 		PCIE_DBG("pcishpc_set_bus_speed() failed "
216126947304SEvan Yan 		    "to set bus %d speed\n", slot_p->hs_num);
216226947304SEvan Yan 		return (DDI_FAILURE);
216326947304SEvan Yan 	}
216426947304SEvan Yan 
216526947304SEvan Yan 	/* Check the current bus speed */
216626947304SEvan Yan 	status = pcishpc_read_reg(ctrl_p, PCI_HP_PROF_IF_SBCR_REG) &
216726947304SEvan Yan 	    PCI_HP_SBCR_SPEED_MASK;
216826947304SEvan Yan 	if ((status & PCI_HP_SBCR_SPEED_MASK) != speed) {
216926947304SEvan Yan 		PCIE_DBG("pcishpc_set_bus_speed() an incorrect "
217026947304SEvan Yan 		    "bus speed, slot = 0x%x, speed = 0x%x\n",
217126947304SEvan Yan 		    slot_p->hs_num, status & PCI_HP_SBCR_SPEED_MASK);
217226947304SEvan Yan 		return (DDI_FAILURE);
217326947304SEvan Yan 	}
217426947304SEvan Yan 
217526947304SEvan Yan 
217626947304SEvan Yan 	/* Save the current bus speed */
217726947304SEvan Yan 	ctrl_p->hc_curr_bus_speed = speed;
217826947304SEvan Yan 
217926947304SEvan Yan 	return (DDI_SUCCESS);
218026947304SEvan Yan }
218126947304SEvan Yan 
218226947304SEvan Yan /*
218326947304SEvan Yan  * pcishpc_setled()
218426947304SEvan Yan  *
218526947304SEvan Yan  * Change the state of a slot's LED.
218626947304SEvan Yan  */
218726947304SEvan Yan static int
218826947304SEvan Yan pcishpc_setled(pcie_hp_slot_t *slot_p, pcie_hp_led_t led,
218926947304SEvan Yan     pcie_hp_led_state_t state)
219026947304SEvan Yan {
219126947304SEvan Yan 	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
219226947304SEvan Yan 
219326947304SEvan Yan 	switch (led) {
219426947304SEvan Yan 		case PCIE_HP_FAULT_LED:
219526947304SEvan Yan 			PCIE_DBG("pcishpc_setled() - PCIE_HP_FAULT_LED "
219626947304SEvan Yan 			    "(set %s)\n", pcishpc_slot_textledstate(state));
219726947304SEvan Yan 			slot_p->hs_fault_led_state = state;
219826947304SEvan Yan 			break;
219926947304SEvan Yan 
220026947304SEvan Yan 		case PCIE_HP_POWER_LED:
220126947304SEvan Yan 			PCIE_DBG("pcishpc_setled() - PCIE_HP_POWER_LED "
220226947304SEvan Yan 			    "(set %s)\n", pcishpc_slot_textledstate(state));
220326947304SEvan Yan 			slot_p->hs_power_led_state = state;
220426947304SEvan Yan 			break;
220526947304SEvan Yan 
220626947304SEvan Yan 		case PCIE_HP_ATTN_LED:
220726947304SEvan Yan 			PCIE_DBG("pcishpc_setled() - PCIE_HP_ATTN_LED "
220826947304SEvan Yan 			    "(set %s)\n", pcishpc_slot_textledstate(state));
220926947304SEvan Yan 			slot_p->hs_attn_led_state = state;
221026947304SEvan Yan 			break;
221126947304SEvan Yan 
221226947304SEvan Yan 		case PCIE_HP_ACTIVE_LED:
221326947304SEvan Yan 			PCIE_DBG("pcishpc_setled() - PCIE_HP_ACTIVE_LED "
221426947304SEvan Yan 			    "(set %s)\n", pcishpc_slot_textledstate(state));
221526947304SEvan Yan 			slot_p->hs_active_led_state = state;
221626947304SEvan Yan 			break;
221726947304SEvan Yan 	}
221826947304SEvan Yan 
221926947304SEvan Yan 	return (pcishpc_set_slot_state(slot_p, slot_p->hs_info.cn_state));
222026947304SEvan Yan }
222126947304SEvan Yan 
222226947304SEvan Yan /*
222326947304SEvan Yan  * pcishpc_led_shpc_to_hpc()
222426947304SEvan Yan  *
222526947304SEvan Yan  * Convert from SHPC indicator status to HPC indicator status.
222626947304SEvan Yan  */
222726947304SEvan Yan static int
222826947304SEvan Yan pcishpc_led_shpc_to_hpc(int state)
222926947304SEvan Yan {
223026947304SEvan Yan 	switch (state) {
223126947304SEvan Yan 		case 1:	/* SHPC On bits b01 */
223226947304SEvan Yan 			return (PCIE_HP_LED_ON);
223326947304SEvan Yan 		case 2:	/* SHPC Blink bits b10 */
223426947304SEvan Yan 			return (PCIE_HP_LED_BLINK);
223526947304SEvan Yan 		case 3:	/* SHPC Off bits b11 */
223626947304SEvan Yan 			return (PCIE_HP_LED_OFF);
223726947304SEvan Yan 	}
223826947304SEvan Yan 
223926947304SEvan Yan 	return (PCIE_HP_LED_OFF);
224026947304SEvan Yan }
224126947304SEvan Yan 
224226947304SEvan Yan 
224326947304SEvan Yan /*
224426947304SEvan Yan  * pcishpc_led_hpc_to_shpc()
224526947304SEvan Yan  *
224626947304SEvan Yan  * Convert from HPC indicator status to SHPC indicator status.
224726947304SEvan Yan  */
224826947304SEvan Yan static int
224926947304SEvan Yan pcishpc_led_hpc_to_shpc(int state)
225026947304SEvan Yan {
225126947304SEvan Yan 	switch (state) {
225226947304SEvan Yan 		case PCIE_HP_LED_ON:
225326947304SEvan Yan 			return (1); /* SHPC On bits b01 */
225426947304SEvan Yan 		case PCIE_HP_LED_BLINK:
225526947304SEvan Yan 			return (2); /* SHPC Blink bits b10 */
225626947304SEvan Yan 		case PCIE_HP_LED_OFF:
225726947304SEvan Yan 			return (3); /* SHPC Off bits b11 */
225826947304SEvan Yan 	}
225926947304SEvan Yan 
226026947304SEvan Yan 	return (3); /* SHPC Off bits b11 */
226126947304SEvan Yan }
226226947304SEvan Yan 
226326947304SEvan Yan /*
226426947304SEvan Yan  * pcishpc_slot_shpc_to_hpc()
226526947304SEvan Yan  *
226626947304SEvan Yan  * Convert from SHPC slot state to HPC slot state.
226726947304SEvan Yan  * The argument shpc_state is expected to be read from the slot register.
226826947304SEvan Yan  */
226926947304SEvan Yan static int
227026947304SEvan Yan pcishpc_slot_shpc_to_hpc(int shpc_state)
227126947304SEvan Yan {
227226947304SEvan Yan 	if ((shpc_state & PCI_HP_SLOT_CARD_EMPTY_MASK) ==
227326947304SEvan Yan 	    PCI_HP_SLOT_CARD_EMPTY_MASK)
227426947304SEvan Yan 		return (DDI_HP_CN_STATE_EMPTY);
227526947304SEvan Yan 
227626947304SEvan Yan 	switch (shpc_state & PCI_HP_SLOT_STATE_MASK) {
227726947304SEvan Yan 		case PCI_HP_SLOT_POWER_ONLY: /* SHPC Powered Only */
227826947304SEvan Yan 			return (DDI_HP_CN_STATE_POWERED);
227926947304SEvan Yan 
228026947304SEvan Yan 		case PCI_HP_SLOT_ENABLED: /* SHPC Enabled */
228126947304SEvan Yan 			return (DDI_HP_CN_STATE_ENABLED);
228226947304SEvan Yan 
228326947304SEvan Yan 		case PCI_HP_SLOT_DISABLED:	/* SHPC Disabled */
228426947304SEvan Yan 		default :			/* SHPC Reserved */
228526947304SEvan Yan 			return (DDI_HP_CN_STATE_PRESENT);
228626947304SEvan Yan 	}
228726947304SEvan Yan }
228826947304SEvan Yan 
228926947304SEvan Yan /*
229026947304SEvan Yan  * pcishpc_slot_hpc_to_shpc()
229126947304SEvan Yan  *
229226947304SEvan Yan  * Convert from HPC slot state to SHPC slot state.
229326947304SEvan Yan  */
229426947304SEvan Yan static int
229526947304SEvan Yan pcishpc_slot_hpc_to_shpc(int state)
229626947304SEvan Yan {
229726947304SEvan Yan 	switch (state) {
229826947304SEvan Yan 		case DDI_HP_CN_STATE_EMPTY:
229926947304SEvan Yan 			return (0);
230026947304SEvan Yan 
230126947304SEvan Yan 		case DDI_HP_CN_STATE_POWERED:
230226947304SEvan Yan 			return (PCI_HP_SLOT_POWER_ONLY);
230326947304SEvan Yan 
230426947304SEvan Yan 		case DDI_HP_CN_STATE_ENABLED:
230526947304SEvan Yan 			return (PCI_HP_SLOT_ENABLED);
230626947304SEvan Yan 
230726947304SEvan Yan 		default:
230826947304SEvan Yan 			return (PCI_HP_SLOT_DISABLED);
230926947304SEvan Yan 	}
231026947304SEvan Yan }
231126947304SEvan Yan 
231226947304SEvan Yan /*
231326947304SEvan Yan  * pcishpc_slot_textslotstate()
231426947304SEvan Yan  *
231526947304SEvan Yan  * Convert the request into a text message.
231626947304SEvan Yan  */
231726947304SEvan Yan static char *
231826947304SEvan Yan pcishpc_slot_textslotstate(ddi_hp_cn_state_t state)
231926947304SEvan Yan {
232026947304SEvan Yan 	/* Convert an HPC slot state into a textual string. */
232126947304SEvan Yan 	if (state == DDI_HP_CN_STATE_EMPTY)
232226947304SEvan Yan 		return ("HPC_SLOT_EMPTY");
232326947304SEvan Yan 	else if (state == DDI_HP_CN_STATE_ENABLED)
232426947304SEvan Yan 		return ("HPC_SLOT_ENABLED");
232526947304SEvan Yan 	else if (state == DDI_HP_CN_STATE_POWERED)
232626947304SEvan Yan 		return ("HPC_SLOT_POWERED_ONLY");
232726947304SEvan Yan 	else
232826947304SEvan Yan 		return ("HPC_SLOT_DISABLED");
232926947304SEvan Yan }
233026947304SEvan Yan 
233126947304SEvan Yan 
233226947304SEvan Yan /*
233326947304SEvan Yan  * pcishpc_slot_textledstate()
233426947304SEvan Yan  *
233526947304SEvan Yan  * Convert the led state into a text message.
233626947304SEvan Yan  */
233726947304SEvan Yan static char *
233826947304SEvan Yan pcishpc_slot_textledstate(pcie_hp_led_state_t state)
233926947304SEvan Yan {
234026947304SEvan Yan 	/* Convert an HPC led state into a textual string. */
234126947304SEvan Yan 	switch (state) {
234226947304SEvan Yan 		case PCIE_HP_LED_OFF:
234326947304SEvan Yan 			return ("off");
234426947304SEvan Yan 
234526947304SEvan Yan 		case PCIE_HP_LED_ON:
234626947304SEvan Yan 			return ("on");
234726947304SEvan Yan 
234826947304SEvan Yan 		case PCIE_HP_LED_BLINK:
234926947304SEvan Yan 			return ("blink");
235026947304SEvan Yan 	}
235126947304SEvan Yan 	return ("unknown");
235226947304SEvan Yan }
235326947304SEvan Yan 
235426947304SEvan Yan 
235526947304SEvan Yan /*
235626947304SEvan Yan  * pcishpc_read_reg()
235726947304SEvan Yan  *
235826947304SEvan Yan  * Read from a SHPC controller register.
235926947304SEvan Yan  */
236026947304SEvan Yan static uint32_t
236126947304SEvan Yan pcishpc_read_reg(pcie_hp_ctrl_t *ctrl_p, int reg)
236226947304SEvan Yan {
236326947304SEvan Yan 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
236426947304SEvan Yan 
236526947304SEvan Yan 	/* Setup the SHPC dword select register. */
236626947304SEvan Yan 	pci_config_put8(bus_p->bus_cfg_hdl,
236726947304SEvan Yan 	    bus_p->bus_pci_hp_off + PCI_HP_DWORD_SELECT_OFF, (uint8_t)reg);
236826947304SEvan Yan 
236926947304SEvan Yan 	/* Read back the SHPC dword select register and verify. */
237026947304SEvan Yan 	if (pci_config_get8(bus_p->bus_cfg_hdl, bus_p->bus_pci_hp_off +
237126947304SEvan Yan 	    PCI_HP_DWORD_SELECT_OFF) != (uint8_t)reg) {
237226947304SEvan Yan 		PCIE_DBG("pcishpc_read_reg() - Failed writing DWORD "
237326947304SEvan Yan 		    "select reg\n");
237426947304SEvan Yan 		return (0xFFFFFFFF);
237526947304SEvan Yan 	}
237626947304SEvan Yan 
237726947304SEvan Yan 	/* Read from the SHPC dword data register. */
237826947304SEvan Yan 	return (pci_config_get32(bus_p->bus_cfg_hdl,
237926947304SEvan Yan 	    bus_p->bus_pci_hp_off + PCI_HP_DWORD_DATA_OFF));
238026947304SEvan Yan }
238126947304SEvan Yan 
238226947304SEvan Yan 
238326947304SEvan Yan /*
238426947304SEvan Yan  * pcishpc_write_reg()
238526947304SEvan Yan  *
238626947304SEvan Yan  * Write to a SHPC controller register.
238726947304SEvan Yan  */
238826947304SEvan Yan static void
238926947304SEvan Yan pcishpc_write_reg(pcie_hp_ctrl_t *ctrl_p, int reg, uint32_t data)
239026947304SEvan Yan {
239126947304SEvan Yan 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
239226947304SEvan Yan 
239326947304SEvan Yan 	/* Setup the SHPC dword select register. */
239426947304SEvan Yan 	pci_config_put8(bus_p->bus_cfg_hdl,
239526947304SEvan Yan 	    bus_p->bus_pci_hp_off + PCI_HP_DWORD_SELECT_OFF, (uint8_t)reg);
239626947304SEvan Yan 
239726947304SEvan Yan 	/* Read back the SHPC dword select register and verify. */
239826947304SEvan Yan 	if (pci_config_get8(bus_p->bus_cfg_hdl, bus_p->bus_pci_hp_off +
239926947304SEvan Yan 	    PCI_HP_DWORD_SELECT_OFF) != (uint8_t)reg) {
240026947304SEvan Yan 		PCIE_DBG("pcishpc_write_reg() - Failed writing "
240126947304SEvan Yan 		    "DWORD select reg\n");
240226947304SEvan Yan 		return;
240326947304SEvan Yan 	}
240426947304SEvan Yan 
240526947304SEvan Yan 	/* Write to the SHPC dword data register. */
240626947304SEvan Yan 	pci_config_put32(bus_p->bus_cfg_hdl,
240726947304SEvan Yan 	    bus_p->bus_pci_hp_off + PCI_HP_DWORD_DATA_OFF, data);
240826947304SEvan Yan 
240926947304SEvan Yan 	/*
241026947304SEvan Yan 	 * Issue a read of the VendorID/DeviceID just to force the previous
241126947304SEvan Yan 	 * write to complete. This is probably not necessary, but it does
241226947304SEvan Yan 	 * help enforce ordering if there is an issue.
241326947304SEvan Yan 	 */
241426947304SEvan Yan 	(void) pci_config_get16(bus_p->bus_cfg_hdl, PCI_CONF_VENID);
241526947304SEvan Yan }
241626947304SEvan Yan 
241726947304SEvan Yan 
241826947304SEvan Yan #ifdef	DEBUG
241926947304SEvan Yan /*
242026947304SEvan Yan  * pcishpc_dump_regs()
242126947304SEvan Yan  *
242226947304SEvan Yan  * Dumps all of the SHPC controller registers.
242326947304SEvan Yan  */
242426947304SEvan Yan static void
242526947304SEvan Yan pcishpc_dump_regs(pcie_hp_ctrl_t *ctrl_p)
242626947304SEvan Yan {
242726947304SEvan Yan 	int slot, numSlots;
242826947304SEvan Yan 	uint32_t reg;
242926947304SEvan Yan 	char *state;
243026947304SEvan Yan 
243126947304SEvan Yan 	if (!pcie_debug_flags)
243226947304SEvan Yan 		return;
243326947304SEvan Yan 
243426947304SEvan Yan 	PCIE_DBG("pcishpc_dump_regs() called:\n");
243526947304SEvan Yan 	PCIE_DBG("==========================================================");
243626947304SEvan Yan 
243726947304SEvan Yan 	PCIE_DBG("SHPC Base Offset				"
243826947304SEvan Yan 	    ": 0x%08x\n", pcishpc_read_reg(ctrl_p, PCI_HP_BASE_OFFSET_REG));
243926947304SEvan Yan 
244026947304SEvan Yan 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOTS_AVAIL_I_REG);
244126947304SEvan Yan 
244226947304SEvan Yan 	PCIE_DBG("Number of PCIX slots avail (33 Mhz)		 : %d\n",
244326947304SEvan Yan 	    (reg & 31));
244426947304SEvan Yan 
244526947304SEvan Yan 	PCIE_DBG("Number of PCIX slots avail (66 Mhz)		 : %d\n",
244626947304SEvan Yan 	    ((reg>>8) & 31));
244726947304SEvan Yan 
244826947304SEvan Yan 	PCIE_DBG("Number of PCIX slots avail (100 Mhz)		: %d\n",
244926947304SEvan Yan 	    ((reg>>16) & 31));
245026947304SEvan Yan 
245126947304SEvan Yan 	PCIE_DBG("Number of PCIX slots avail (133 Mhz)		: %d\n",
245226947304SEvan Yan 	    ((reg>>24) & 31));
245326947304SEvan Yan 
245426947304SEvan Yan 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOTS_AVAIL_II_REG);
245526947304SEvan Yan 
245626947304SEvan Yan 	PCIE_DBG("Number of conventional PCI slots (66 Mhz) : %d\n",
245726947304SEvan Yan 	    (reg & 31));
245826947304SEvan Yan 
245926947304SEvan Yan 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOT_CONFIGURATION_REG);
246026947304SEvan Yan 
246126947304SEvan Yan 	numSlots = (reg & 31);
246226947304SEvan Yan 
246326947304SEvan Yan 	PCIE_DBG("Number of Slots connected to this port	 : %d\n",
246426947304SEvan Yan 	    numSlots);
246526947304SEvan Yan 
246626947304SEvan Yan 	PCIE_DBG("PCI Device # for First HotPlug Slot		 : %d\n",
246726947304SEvan Yan 	    ((reg>>8) & 31));
246826947304SEvan Yan 
246926947304SEvan Yan 	PCIE_DBG("Physical Slot # for First PCI Device #	 : %d\n",
247026947304SEvan Yan 	    ((reg>>16) & 0x7ff));
247126947304SEvan Yan 
247226947304SEvan Yan 	PCIE_DBG("Physical Slot Number Up/Down			 : %d\n",
247326947304SEvan Yan 	    ((reg>>29) & 0x1));
247426947304SEvan Yan 
247526947304SEvan Yan 	PCIE_DBG("MRL Sensor Implemented			 : %s\n",
247626947304SEvan Yan 	    (reg & PCI_HP_SLOT_CONFIG_MRL_SENSOR) ? "Yes" : "No");
247726947304SEvan Yan 
247826947304SEvan Yan 	PCIE_DBG("Attention Button Implemented			 : %s\n",
247926947304SEvan Yan 	    (reg & PCI_HP_SLOT_CONFIG_ATTN_BUTTON) ? "Yes" : "No");
248026947304SEvan Yan 
248126947304SEvan Yan 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_PROF_IF_SBCR_REG);
248226947304SEvan Yan 
248326947304SEvan Yan 	switch (reg & 7) {
248426947304SEvan Yan 		case 0:
248526947304SEvan Yan 			state = "33Mhz Conventional PCI";
248626947304SEvan Yan 			break;
248726947304SEvan Yan 		case 1:
248826947304SEvan Yan 			state = "66Mhz Conventional PCI";
248926947304SEvan Yan 			break;
249026947304SEvan Yan 		case 2:
249126947304SEvan Yan 			state = "66Mhz PCI-X";
249226947304SEvan Yan 			break;
249326947304SEvan Yan 		case 3:
249426947304SEvan Yan 			state = "100Mhz PCI-X";
249526947304SEvan Yan 			break;
249626947304SEvan Yan 		case 4:
249726947304SEvan Yan 			state = "133Mhz PCI-X";
249826947304SEvan Yan 			break;
249926947304SEvan Yan 		default:
250026947304SEvan Yan 			state = "Reserved (Error)";
250126947304SEvan Yan 			break;
250226947304SEvan Yan 	}
250326947304SEvan Yan 
250426947304SEvan Yan 	PCIE_DBG("Current Port Operation Mode		: %s\n", state);
250526947304SEvan Yan 
250626947304SEvan Yan 	PCIE_DBG("SHPC Interrupt Message Number		: %d\n",
250726947304SEvan Yan 	    ((reg>>16) &31));
250826947304SEvan Yan 
250926947304SEvan Yan 	PCIE_DBG("SHPC Programming Interface		: %d\n",
251026947304SEvan Yan 	    ((reg>>24) & 0xff));
251126947304SEvan Yan 
251226947304SEvan Yan 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG);
251326947304SEvan Yan 
251426947304SEvan Yan 	PCIE_DBG("SHPC Command Code			: %d\n",
251526947304SEvan Yan 	    (reg & 0xff));
251626947304SEvan Yan 
251726947304SEvan Yan 	PCIE_DBG("SHPC Target Slot			: %d\n",
251826947304SEvan Yan 	    ((reg>>8) & 31));
251926947304SEvan Yan 
252026947304SEvan Yan 	PCIE_DBG("SHPC Controller Busy			: %s\n",
252126947304SEvan Yan 	    ((reg>>16) & 1) ? "Yes" : "No");
252226947304SEvan Yan 
252326947304SEvan Yan 	PCIE_DBG("SHPC Controller Err: MRL Sensor	: %s\n",
252426947304SEvan Yan 	    ((reg>>17) & 1) ? "Yes" : "No");
252526947304SEvan Yan 
252626947304SEvan Yan 	PCIE_DBG("SHPC Controller Err: Invalid Command	: %s\n",
252726947304SEvan Yan 	    ((reg>>18) & 1) ? "Yes" : "No");
252826947304SEvan Yan 
252926947304SEvan Yan 	PCIE_DBG("SHPC Controller Err: Invalid Speed/Mode : %s\n",
253026947304SEvan Yan 	    ((reg>>19) & 1) ? "Yes" : "No");
253126947304SEvan Yan 
253226947304SEvan Yan 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_IRQ_LOCATOR_REG);
253326947304SEvan Yan 
253426947304SEvan Yan 	PCIE_DBG("Command Completion Interrupt Pending	: %s\n",
253526947304SEvan Yan 	    (reg & PCI_HP_IRQ_CMD_COMPLETE) ? "Yes" : "No");
253626947304SEvan Yan 
253726947304SEvan Yan 	for (slot = 0; slot < numSlots; slot++) {
253826947304SEvan Yan 		PCIE_DBG("Slot %d Interrupt Pending	: %s\n", slot+1,
253926947304SEvan Yan 		    (reg & (PCI_HP_IRQ_SLOT_N_PENDING<<slot)) ? "Yes" : "No");
254026947304SEvan Yan 	}
254126947304SEvan Yan 
254226947304SEvan Yan 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_SERR_LOCATOR_REG);
254326947304SEvan Yan 
254426947304SEvan Yan 	PCIE_DBG("Arbiter SERR Pending			: %s\n",
254526947304SEvan Yan 	    (reg & PCI_HP_IRQ_SERR_ARBITER_PENDING) ? "Yes" : "No");
254626947304SEvan Yan 
254726947304SEvan Yan 	for (slot = 0; slot < numSlots; slot++) {
254826947304SEvan Yan 		PCIE_DBG("Slot %d SERR Pending		: %s\n",
254926947304SEvan Yan 		    slot+1, (reg &
255026947304SEvan Yan 		    (PCI_HP_IRQ_SERR_SLOT_N_PENDING<<slot)) ? "Yes" : "No");
255126947304SEvan Yan 	}
255226947304SEvan Yan 
255326947304SEvan Yan 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG);
255426947304SEvan Yan 
255526947304SEvan Yan 	PCIE_DBG("Global Interrupt Mask			: %s\n",
255626947304SEvan Yan 	    (reg & PCI_HP_SERR_INT_GLOBAL_IRQ_MASK) ? "Yes" : "No");
255726947304SEvan Yan 
255826947304SEvan Yan 	PCIE_DBG("Global SERR Mask			: %s\n",
255926947304SEvan Yan 	    (reg & PCI_HP_SERR_INT_GLOBAL_SERR_MASK) ? "Yes" : "No");
256026947304SEvan Yan 
256126947304SEvan Yan 	PCIE_DBG("Command Completion Interrupt Mask	: %s\n",
256226947304SEvan Yan 	    (reg & PCI_HP_SERR_INT_CMD_COMPLETE_MASK) ? "Yes" : "No");
256326947304SEvan Yan 
256426947304SEvan Yan 	PCIE_DBG("Arbiter SERR Mask			: %s\n",
256526947304SEvan Yan 	    (reg & PCI_HP_SERR_INT_ARBITER_SERR_MASK) ? "Yes" : "No");
256626947304SEvan Yan 
256726947304SEvan Yan 	PCIE_DBG("Command Completion Detected		: %s\n",
256826947304SEvan Yan 	    (reg & PCI_HP_SERR_INT_CMD_COMPLETE_IRQ) ? "Yes" : "No");
256926947304SEvan Yan 
257026947304SEvan Yan 	PCIE_DBG("Arbiter Timeout Detected		: %s\n",
257126947304SEvan Yan 	    (reg & PCI_HP_SERR_INT_ARBITER_IRQ) ? "Yes" : "No");
257226947304SEvan Yan 
257326947304SEvan Yan 	for (slot = 0; slot < numSlots; slot++) {
257426947304SEvan Yan 		PCIE_DBG("Logical Slot %d Registers:\n", slot+1);
257526947304SEvan Yan 		PCIE_DBG("------------------------------------\n");
257626947304SEvan Yan 
257726947304SEvan Yan 		reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot);
257826947304SEvan Yan 
257926947304SEvan Yan 		PCIE_DBG("Slot %d state			: %s\n", slot+1,
258026947304SEvan Yan 		    pcishpc_slot_textslotstate(pcishpc_slot_shpc_to_hpc(reg)));
258126947304SEvan Yan 
258226947304SEvan Yan 		PCIE_DBG("Slot %d Power Indicator State	: %s\n", slot+1,
258326947304SEvan Yan 		    pcishpc_slot_textledstate(pcishpc_led_shpc_to_hpc(
258426947304SEvan Yan 		    (reg>>2) &3)));
258526947304SEvan Yan 
258626947304SEvan Yan 		PCIE_DBG("Slot %d Attention Indicator State : %s\n", slot+1,
258726947304SEvan Yan 		    pcishpc_slot_textledstate(pcishpc_led_shpc_to_hpc(
258826947304SEvan Yan 		    (reg>>4)&3)));
258926947304SEvan Yan 
259026947304SEvan Yan 		PCIE_DBG("Slot %d Power Fault		: %s\n", slot+1,
259126947304SEvan Yan 		    ((reg>>6)&1) ? "Fault Detected" : "No Fault");
259226947304SEvan Yan 		PCIE_DBG("Slot %d Attention Button	: %s\n", slot+1,
259326947304SEvan Yan 		    ((reg>>7)&1) ? "Depressed" : "Not Depressed");
259426947304SEvan Yan 		PCIE_DBG("Slot %d MRL Sensor		: %s\n", slot+1,
259526947304SEvan Yan 		    ((reg>>8)&1) ? "Not Closed" : "Closed");
259626947304SEvan Yan 		PCIE_DBG("Slot %d 66mhz Capable		: %s\n", slot+1,
259726947304SEvan Yan 		    ((reg>>9)&1) ? "66mhz" : "33mgz");
259826947304SEvan Yan 
259926947304SEvan Yan 		switch ((reg>>10)&3) {
260026947304SEvan Yan 			case 0:
260126947304SEvan Yan 				state = "Card Present 7.5W";
260226947304SEvan Yan 				break;
260326947304SEvan Yan 			case 1:
260426947304SEvan Yan 				state = "Card Present 15W";
260526947304SEvan Yan 				break;
260626947304SEvan Yan 			case 2:
260726947304SEvan Yan 				state = "Card Present 25W";
260826947304SEvan Yan 				break;
260926947304SEvan Yan 			case 3:
261026947304SEvan Yan 				state = "Slot Empty";
261126947304SEvan Yan 				break;
261226947304SEvan Yan 		}
261326947304SEvan Yan 
261426947304SEvan Yan 		PCIE_DBG("Slot %d PRSNT1#/PRSNT2#	: %s\n", slot+1,
261526947304SEvan Yan 		    state);
261626947304SEvan Yan 
261726947304SEvan Yan 		switch ((reg>>12)&3) {
261826947304SEvan Yan 			case 0:
261926947304SEvan Yan 				state = "Non PCI-X";
262026947304SEvan Yan 				break;
262126947304SEvan Yan 			case 1:
262226947304SEvan Yan 				state = "66mhz PCI-X";
262326947304SEvan Yan 				break;
262426947304SEvan Yan 			case 2:
262526947304SEvan Yan 				state = "Reserved";
262626947304SEvan Yan 				break;
262726947304SEvan Yan 			case 3:
262826947304SEvan Yan 				state = "133mhz PCI-X";
262926947304SEvan Yan 				break;
263026947304SEvan Yan 		}
263126947304SEvan Yan 
263226947304SEvan Yan 		PCIE_DBG("Slot %d Card Presence Change Detected	  : %s\n",
263326947304SEvan Yan 		    slot+1, (reg & PCI_HP_SLOT_PRESENCE_DETECTED) ? "Yes" :
263426947304SEvan Yan 		    "No");
263526947304SEvan Yan 		PCIE_DBG("Slot %d Isolated Power Fault Detected	  : %s\n",
263626947304SEvan Yan 		    slot+1, (reg & PCI_HP_SLOT_ISO_PWR_DETECTED) ? "Yes" :
263726947304SEvan Yan 		    "No");
263826947304SEvan Yan 		PCIE_DBG("Slot %d Attention Button Press Detected : %s\n",
263926947304SEvan Yan 		    slot+1, (reg & PCI_HP_SLOT_ATTN_DETECTED) ? "Yes" : "No");
264026947304SEvan Yan 		PCIE_DBG("Slot %d MRL Sensor Change Detected	  : %s\n",
264126947304SEvan Yan 		    slot+1, (reg & PCI_HP_SLOT_MRL_DETECTED) ? "Yes" : "No");
264226947304SEvan Yan 		PCIE_DBG("Slot %d Connected Power Fault Detected  : %s\n",
264326947304SEvan Yan 		    slot+1, (reg & PCI_HP_SLOT_POWER_DETECTED) ? "Yes" : "No");
264426947304SEvan Yan 
264526947304SEvan Yan 		PCIE_DBG("Slot %d Card Presence IRQ Masked	  : %s\n",
264626947304SEvan Yan 		    slot+1, (reg & PCI_HP_SLOT_PRESENCE_MASK) ? "Yes" : "No");
264726947304SEvan Yan 		PCIE_DBG("Slot %d Isolated Power Fault IRQ Masked : %s\n",
264826947304SEvan Yan 		    slot+1, (reg & PCI_HP_SLOT_ISO_PWR_MASK) ? "Yes" : "No");
264926947304SEvan Yan 		PCIE_DBG("Slot %d Attention Button IRQ Masked	  : %s\n",
265026947304SEvan Yan 		    slot+1, (reg & PCI_HP_SLOT_ATTN_MASK) ? "Yes" : "No");
265126947304SEvan Yan 		PCIE_DBG("Slot %d MRL Sensor IRQ Masked		  : %s\n",
265226947304SEvan Yan 		    slot+1, (reg & PCI_HP_SLOT_MRL_MASK) ? "Yes" : "No");
265326947304SEvan Yan 		PCIE_DBG("Slot %d Connected Power Fault IRQ Masked : %s\n",
265426947304SEvan Yan 		    slot+1, (reg & PCI_HP_SLOT_POWER_MASK) ? "Yes" : "No");
265526947304SEvan Yan 		PCIE_DBG("Slot %d MRL Sensor SERR Masked          : %s\n",
265626947304SEvan Yan 		    slot+1, (reg & PCI_HP_SLOT_MRL_SERR_MASK) ? "Yes" : "No");
265726947304SEvan Yan 		PCIE_DBG("Slot %d Connected Power Fault SERR Masked : %s\n",
265826947304SEvan Yan 		    slot+1, (reg & PCI_HP_SLOT_POWER_SERR_MASK) ? "Yes" : "No");
265926947304SEvan Yan 	}
266026947304SEvan Yan }
266126947304SEvan Yan #endif	/* DEBUG */
2662