126947304SEvan Yan /*
226947304SEvan Yan  * CDDL HEADER START
326947304SEvan Yan  *
426947304SEvan Yan  * The contents of this file are subject to the terms of the
526947304SEvan Yan  * Common Development and Distribution License (the "License").
626947304SEvan Yan  * You may not use this file except in compliance with the License.
726947304SEvan Yan  *
826947304SEvan Yan  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
926947304SEvan Yan  * or http://www.opensolaris.org/os/licensing.
1026947304SEvan Yan  * See the License for the specific language governing permissions
1126947304SEvan Yan  * and limitations under the License.
1226947304SEvan Yan  *
1326947304SEvan Yan  * When distributing Covered Code, include this CDDL HEADER in each
1426947304SEvan Yan  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1526947304SEvan Yan  * If applicable, add the following below this CDDL HEADER, with the
1626947304SEvan Yan  * fields enclosed by brackets "[]" replaced with your own identifying
1726947304SEvan Yan  * information: Portions Copyright [yyyy] [name of copyright owner]
1826947304SEvan Yan  *
1926947304SEvan Yan  * CDDL HEADER END
2026947304SEvan Yan  */
2126947304SEvan Yan 
2226947304SEvan Yan /*
2380dc702dSColin Zou - Sun Microsystems - Beijing China  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24b3d69c05SRobert Mustacchi  * Copyright 2019 Joyent, Inc.
2526947304SEvan Yan  */
2626947304SEvan Yan 
2726947304SEvan Yan /*
2826947304SEvan Yan  * This file contains Standard PCI Express HotPlug functionality that is
2926947304SEvan Yan  * compatible with the PCI Express ver 1.1 specification.
3026947304SEvan Yan  *
3126947304SEvan Yan  * NOTE: This file is compiled and delivered through misc/pcie module.
3226947304SEvan Yan  */
3326947304SEvan Yan 
3426947304SEvan Yan #include <sys/types.h>
3526947304SEvan Yan #include <sys/note.h>
3626947304SEvan Yan #include <sys/conf.h>
3726947304SEvan Yan #include <sys/kmem.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/ddi_impldefs.h>
4326947304SEvan Yan #include <sys/time.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/pci_impl.h>
5026947304SEvan Yan #include <sys/hotplug/pci/pcie_hp.h>
5126947304SEvan Yan #include <sys/hotplug/pci/pciehpc.h>
5226947304SEvan Yan 
5326947304SEvan Yan typedef struct pciehpc_prop {
5426947304SEvan Yan 	char	*prop_name;
5526947304SEvan Yan 	char	*prop_value;
5626947304SEvan Yan } pciehpc_prop_t;
5726947304SEvan Yan 
5826947304SEvan Yan static pciehpc_prop_t	pciehpc_props[] = {
6626947304SEvan Yan };
6726947304SEvan Yan 
6826947304SEvan Yan /* Local functions prototype */
6926947304SEvan Yan static int pciehpc_hpc_init(pcie_hp_ctrl_t *ctrl_p);
7026947304SEvan Yan static int pciehpc_hpc_uninit(pcie_hp_ctrl_t *ctrl_p);
7126947304SEvan Yan static int pciehpc_slotinfo_init(pcie_hp_ctrl_t *ctrl_p);
7226947304SEvan Yan static int pciehpc_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p);
7326947304SEvan Yan static int pciehpc_enable_intr(pcie_hp_ctrl_t *ctrl_p);
7426947304SEvan Yan static int pciehpc_disable_intr(pcie_hp_ctrl_t *ctrl_p);
7526947304SEvan Yan static pcie_hp_ctrl_t *pciehpc_create_controller(dev_info_t *dip);
7626947304SEvan Yan static void pciehpc_destroy_controller(dev_info_t *dip);
7726947304SEvan Yan static int pciehpc_register_slot(pcie_hp_ctrl_t *ctrl_p);
7826947304SEvan Yan static int pciehpc_unregister_slot(pcie_hp_ctrl_t *ctrl_p);
7926947304SEvan Yan static int pciehpc_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 pciehpc_slot_set_property(pcie_hp_slot_t *slot_p,
8226947304SEvan Yan     ddi_hp_property_t *arg, ddi_hp_property_t *rval);
8326947304SEvan Yan static void pciehpc_issue_hpc_command(pcie_hp_ctrl_t *ctrl_p, uint16_t control);
8426947304SEvan Yan static void pciehpc_attn_btn_handler(pcie_hp_ctrl_t *ctrl_p);
8526947304SEvan Yan static pcie_hp_led_state_t pciehpc_led_state_to_hpc(uint16_t state);
8626947304SEvan Yan static pcie_hp_led_state_t pciehpc_get_led_state(pcie_hp_ctrl_t *ctrl_p,
8726947304SEvan Yan     pcie_hp_led_t led);
8826947304SEvan Yan static void pciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led,
8926947304SEvan Yan     pcie_hp_led_state_t state);
9026947304SEvan Yan 
9126947304SEvan Yan static int pciehpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
9226947304SEvan Yan     ddi_hp_cn_state_t target_state);
9326947304SEvan Yan static int pciehpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
9426947304SEvan Yan     ddi_hp_cn_state_t target_state);
9526947304SEvan Yan static int pciehpc_change_slot_state(pcie_hp_slot_t *slot_p,
9626947304SEvan Yan     ddi_hp_cn_state_t target_state);
9726947304SEvan Yan static int
9826947304SEvan Yan     pciehpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result);
9926947304SEvan Yan static int
10026947304SEvan Yan     pciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result);
10126947304SEvan Yan static int pciehpc_slot_probe(pcie_hp_slot_t *slot_p);
10226947304SEvan Yan static int pciehpc_slot_unprobe(pcie_hp_slot_t *slot_p);
10380dc702dSColin Zou - Sun Microsystems - Beijing China static void pciehpc_handle_power_fault(dev_info_t *dip);
10480dc702dSColin Zou - Sun Microsystems - Beijing China static void pciehpc_power_fault_handler(void *arg);
10526947304SEvan Yan 
10626947304SEvan Yan #ifdef	DEBUG
10726947304SEvan Yan static void pciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p);
10826947304SEvan Yan #endif	/* DEBUG */
10926947304SEvan Yan 
11026947304SEvan Yan /*
11126947304SEvan Yan  * Global functions (called by other drivers/modules)
11226947304SEvan Yan  */
11326947304SEvan Yan 
11426947304SEvan Yan /*
11526947304SEvan Yan  * Initialize Hot Plug Controller if present. The arguments are:
11626947304SEvan Yan  *	dip	- Devinfo node pointer to the hot plug bus node
11726947304SEvan Yan  *	regops	- register ops to access HPC registers for non-standard
11826947304SEvan Yan  *		  HPC hw implementations (e.g: HPC in host PCI-E brdiges)
11926947304SEvan Yan  *		  This is NULL for standard HPC in PCIe bridges.
12026947304SEvan Yan  * Returns:
12126947304SEvan Yan  *	DDI_SUCCESS for successful HPC initialization
12226947304SEvan Yan  *	DDI_FAILURE for errors or if HPC hw not found
12326947304SEvan Yan  */
12426947304SEvan Yan int
pciehpc_init(dev_info_t * dip,caddr_t arg)12526947304SEvan Yan pciehpc_init(dev_info_t *dip, caddr_t arg)
12626947304SEvan Yan {
12726947304SEvan Yan 	pcie_hp_regops_t	*regops = (pcie_hp_regops_t *)(void *)arg;
12826947304SEvan Yan 	pcie_hp_ctrl_t		*ctrl_p;
12926947304SEvan Yan 
13026947304SEvan Yan 	PCIE_DBG("pciehpc_init() called (dip=%p)\n", (void *)dip);
13126947304SEvan Yan 
13226947304SEvan Yan 	/* Make sure that it is not already initialized */
13326947304SEvan Yan 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) != NULL) {
13426947304SEvan Yan 		PCIE_DBG("%s%d: pciehpc instance already initialized!\n",
13526947304SEvan Yan 		    ddi_driver_name(dip), ddi_get_instance(dip));
13626947304SEvan Yan 		return (DDI_SUCCESS);
13726947304SEvan Yan 	}
13826947304SEvan Yan 
13926947304SEvan Yan 	/* Allocate a new hotplug controller and slot structures */
14026947304SEvan Yan 	ctrl_p = pciehpc_create_controller(dip);
14126947304SEvan Yan 
14226947304SEvan Yan 	/* setup access handle for HPC regs */
14326947304SEvan Yan 	if (regops != NULL) {
14426947304SEvan Yan 		/* HPC access is non-standard; use the supplied reg ops */
14526947304SEvan Yan 		ctrl_p->hc_regops = *regops;
14626947304SEvan Yan 	}
14726947304SEvan Yan 
14826947304SEvan Yan 	/*
14926947304SEvan Yan 	 * Setup resource maps for this bus node.
15026947304SEvan Yan 	 */
15126947304SEvan Yan 	(void) pci_resource_setup(dip);
15226947304SEvan Yan 
15326947304SEvan Yan 	PCIE_DISABLE_ERRORS(dip);
15426947304SEvan Yan 
15526947304SEvan Yan 	/*
15626947304SEvan Yan 	 * Set the platform specific hot plug mode.
15726947304SEvan Yan 	 */
15826947304SEvan Yan 	ctrl_p->hc_ops.init_hpc_hw = pciehpc_hpc_init;
15926947304SEvan Yan 	ctrl_p->hc_ops.uninit_hpc_hw = pciehpc_hpc_uninit;
16026947304SEvan Yan 	ctrl_p->hc_ops.init_hpc_slotinfo = pciehpc_slotinfo_init;
16126947304SEvan Yan 	ctrl_p->hc_ops.uninit_hpc_slotinfo = pciehpc_slotinfo_uninit;
16226947304SEvan Yan 	ctrl_p->hc_ops.poweron_hpc_slot = pciehpc_slot_poweron;
16326947304SEvan Yan 	ctrl_p->hc_ops.poweroff_hpc_slot = pciehpc_slot_poweroff;
16426947304SEvan Yan 
16526947304SEvan Yan 	ctrl_p->hc_ops.enable_hpc_intr = pciehpc_enable_intr;
16626947304SEvan Yan 	ctrl_p->hc_ops.disable_hpc_intr = pciehpc_disable_intr;
16726947304SEvan Yan 
168*86ef0a63SRichard Lowe #if	defined(__x86)
16926947304SEvan Yan 	pciehpc_update_ops(ctrl_p);
17026947304SEvan Yan #endif
17126947304SEvan Yan 
17226947304SEvan Yan 	/* initialize hot plug controller hw */
17326947304SEvan Yan 	if ((ctrl_p->hc_ops.init_hpc_hw)(ctrl_p) != DDI_SUCCESS)
17426947304SEvan Yan 		goto cleanup1;
17526947304SEvan Yan 
17626947304SEvan Yan 	/* initialize slot information soft state structure */
17726947304SEvan Yan 	if ((ctrl_p->hc_ops.init_hpc_slotinfo)(ctrl_p) != DDI_SUCCESS)
17826947304SEvan Yan 		goto cleanup2;
17926947304SEvan Yan 
18026947304SEvan Yan 	/* register the hot plug slot with DDI HP framework */
18126947304SEvan Yan 	if (pciehpc_register_slot(ctrl_p) != DDI_SUCCESS)
18226947304SEvan Yan 		goto cleanup3;
18326947304SEvan Yan 
18426947304SEvan Yan 	/* create minor node for this slot */
18526947304SEvan Yan 	if (pcie_create_minor_node(ctrl_p, 0) != DDI_SUCCESS)
18626947304SEvan Yan 		goto cleanup4;
18726947304SEvan Yan 
18826947304SEvan Yan 	/* HPC initialization is complete now */
18926947304SEvan Yan 	ctrl_p->hc_flags = PCIE_HP_INITIALIZED_FLAG;
19026947304SEvan Yan 
19126947304SEvan Yan #ifdef	DEBUG
19226947304SEvan Yan 	/* For debug, dump the HPC registers */
19326947304SEvan Yan 	pciehpc_dump_hpregs(ctrl_p);
19426947304SEvan Yan #endif	/* DEBUG */
19526947304SEvan Yan 
19626947304SEvan Yan 	return (DDI_SUCCESS);
19726947304SEvan Yan cleanup4:
19826947304SEvan Yan 	(void) pciehpc_unregister_slot(ctrl_p);
19926947304SEvan Yan cleanup3:
20026947304SEvan Yan 	(void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p);
20126947304SEvan Yan 
20226947304SEvan Yan cleanup2:
20326947304SEvan Yan 	(void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p);
20426947304SEvan Yan 
20526947304SEvan Yan cleanup1:
20626947304SEvan Yan 	PCIE_ENABLE_ERRORS(dip);
20726947304SEvan Yan 	(void) pci_resource_destroy(dip);
20826947304SEvan Yan 
20926947304SEvan Yan 	pciehpc_destroy_controller(dip);
21026947304SEvan Yan 	return (DDI_FAILURE);
21126947304SEvan Yan }
21226947304SEvan Yan 
21326947304SEvan Yan /*
21426947304SEvan Yan  * Uninitialize HPC soft state structure and free up any resources
21526947304SEvan Yan  * used for the HPC instance.
21626947304SEvan Yan  */
21726947304SEvan Yan int
pciehpc_uninit(dev_info_t * dip)21826947304SEvan Yan pciehpc_uninit(dev_info_t *dip)
21926947304SEvan Yan {
22026947304SEvan Yan 	pcie_hp_ctrl_t *ctrl_p;
22126947304SEvan Yan 
22226947304SEvan Yan 	PCIE_DBG("pciehpc_uninit() called (dip=%p)\n", (void *)dip);
22326947304SEvan Yan 
22426947304SEvan Yan 	/* get the soft state structure for this dip */
22526947304SEvan Yan 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) {
22626947304SEvan Yan 		return (DDI_FAILURE);
22726947304SEvan Yan 	}
22826947304SEvan Yan 
22926947304SEvan Yan 	pcie_remove_minor_node(ctrl_p, 0);
23026947304SEvan Yan 
23126947304SEvan Yan 	/* unregister the slot */
23226947304SEvan Yan 	(void) pciehpc_unregister_slot(ctrl_p);
23326947304SEvan Yan 
23426947304SEvan Yan 	/* uninit any slot info data structures */
23526947304SEvan Yan 	(void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p);
23626947304SEvan Yan 
23726947304SEvan Yan 	/* uninitialize hpc, remove interrupt handler, etc. */
23826947304SEvan Yan 	(void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p);
23926947304SEvan Yan 
24026947304SEvan Yan 	PCIE_ENABLE_ERRORS(dip);
24126947304SEvan Yan 
24226947304SEvan Yan 	/*
24326947304SEvan Yan 	 * Destroy resource maps for this bus node.
24426947304SEvan Yan 	 */
24526947304SEvan Yan 	(void) pci_resource_destroy(dip);
24626947304SEvan Yan 
24726947304SEvan Yan 	/* destroy the soft state structure */
24826947304SEvan Yan 	pciehpc_destroy_controller(dip);
24926947304SEvan Yan 
25026947304SEvan Yan 	return (DDI_SUCCESS);
25126947304SEvan Yan }
25226947304SEvan Yan 
25326947304SEvan Yan /*
25426947304SEvan Yan  * pciehpc_intr()
25526947304SEvan Yan  *
25626947304SEvan Yan  * Interrupt handler for PCI-E Hot plug controller interrupts.
25726947304SEvan Yan  *
25826947304SEvan Yan  * Note: This is only for native mode hot plug. This is called
25926947304SEvan Yan  * by the nexus driver at interrupt context. Interrupt Service Routine
26026947304SEvan Yan  * registration is done by the nexus driver for both hot plug and
26126947304SEvan Yan  * non-hot plug interrupts. This function is called from the ISR
26226947304SEvan Yan  * of the nexus driver to handle hot-plug interrupts.
26326947304SEvan Yan  */
26426947304SEvan Yan int
pciehpc_intr(dev_info_t * dip)26526947304SEvan Yan pciehpc_intr(dev_info_t *dip)
26626947304SEvan Yan {
26726947304SEvan Yan 	pcie_hp_ctrl_t	*ctrl_p;
26826947304SEvan Yan 	pcie_hp_slot_t	*slot_p;
26926947304SEvan Yan 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
27026947304SEvan Yan 	uint16_t	status, control;
27126947304SEvan Yan 
27226947304SEvan Yan 	/* get the soft state structure for this dip */
27326947304SEvan Yan 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
27426947304SEvan Yan 		return (DDI_INTR_UNCLAIMED);
27526947304SEvan Yan 
27626947304SEvan Yan 	mutex_enter(&ctrl_p->hc_mutex);
27726947304SEvan Yan 
27826947304SEvan Yan 	/* make sure the controller soft state is initialized */
27926947304SEvan Yan 	if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
28026947304SEvan Yan 		mutex_exit(&ctrl_p->hc_mutex);
28126947304SEvan Yan 		return (DDI_INTR_UNCLAIMED);
28226947304SEvan Yan 	}
28326947304SEvan Yan 
28426947304SEvan Yan 	/* if it is not NATIVE hot plug mode then return */
28526947304SEvan Yan 	if (bus_p->bus_hp_curr_mode != PCIE_NATIVE_HP_MODE) {
28626947304SEvan Yan 		mutex_exit(&ctrl_p->hc_mutex);
28726947304SEvan Yan 		return (DDI_INTR_UNCLAIMED);
28826947304SEvan Yan 	}
28926947304SEvan Yan 
29026947304SEvan Yan 	slot_p = ctrl_p->hc_slots[0];
29126947304SEvan Yan 
29226947304SEvan Yan 	/* read the current slot status register */
29326947304SEvan Yan 	status = pciehpc_reg_get16(ctrl_p,
29426947304SEvan Yan 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
29526947304SEvan Yan 
29626947304SEvan Yan 	/* check if there are any hot plug interrupts occurred */
29726947304SEvan Yan 	if (!(status & PCIE_SLOTSTS_STATUS_EVENTS)) {
29826947304SEvan Yan 		/* no hot plug events occurred */
29926947304SEvan Yan 		mutex_exit(&ctrl_p->hc_mutex);
30026947304SEvan Yan 		return (DDI_INTR_UNCLAIMED);
30126947304SEvan Yan 	}
30226947304SEvan Yan 
30326947304SEvan Yan 	/* clear the interrupt status bits */
30426947304SEvan Yan 	pciehpc_reg_put16(ctrl_p,
30526947304SEvan Yan 	    bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
30626947304SEvan Yan 
30726947304SEvan Yan 	/* check for CMD COMPLETE interrupt */
30826947304SEvan Yan 	if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
30926947304SEvan Yan 		PCIE_DBG("pciehpc_intr(): CMD COMPLETED interrupt received\n");
31026947304SEvan Yan 		/* wake up any one waiting for Command Completion event */
31126947304SEvan Yan 		cv_signal(&ctrl_p->hc_cmd_comp_cv);
31226947304SEvan Yan 	}
31326947304SEvan Yan 
31426947304SEvan Yan 	/* check for ATTN button interrupt */
31526947304SEvan Yan 	if (status & PCIE_SLOTSTS_ATTN_BTN_PRESSED) {
31626947304SEvan Yan 		PCIE_DBG("pciehpc_intr(): ATTN BUTTON interrupt received\n");
31726947304SEvan Yan 
31826947304SEvan Yan 		/* if ATTN button event is still pending then cancel it */
31926947304SEvan Yan 		if (slot_p->hs_attn_btn_pending == B_TRUE)
32026947304SEvan Yan 			slot_p->hs_attn_btn_pending = B_FALSE;
32126947304SEvan Yan 		else
32226947304SEvan Yan 			slot_p->hs_attn_btn_pending = B_TRUE;
32326947304SEvan Yan 
32426947304SEvan Yan 		/* wake up the ATTN event handler */
32526947304SEvan Yan 		cv_signal(&slot_p->hs_attn_btn_cv);
32626947304SEvan Yan 	}
32726947304SEvan Yan 
32826947304SEvan Yan 	/* check for power fault interrupt */
32926947304SEvan Yan 	if (status & PCIE_SLOTSTS_PWR_FAULT_DETECTED) {
33026947304SEvan Yan 
33126947304SEvan Yan 		PCIE_DBG("pciehpc_intr(): POWER FAULT interrupt received"
33226947304SEvan Yan 		    " on slot %d\n", slot_p->hs_phy_slot_num);
33326947304SEvan Yan 		control =  pciehpc_reg_get16(ctrl_p,
33426947304SEvan Yan 		    bus_p->bus_pcie_off + PCIE_SLOTCTL);
33526947304SEvan Yan 
33626947304SEvan Yan 		if (control & PCIE_SLOTCTL_PWR_FAULT_EN) {
33726947304SEvan Yan 			slot_p->hs_condition = AP_COND_FAILED;
33826947304SEvan Yan 
33926947304SEvan Yan 			/* disable power fault detction interrupt */
34026947304SEvan Yan 			pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
34126947304SEvan Yan 			    PCIE_SLOTCTL, control & ~PCIE_SLOTCTL_PWR_FAULT_EN);
34226947304SEvan Yan 
34380dc702dSColin Zou - Sun Microsystems - Beijing China 			pciehpc_handle_power_fault(dip);
34426947304SEvan Yan 		}
34526947304SEvan Yan 	}
34626947304SEvan Yan 
34726947304SEvan Yan 	/* check for MRL SENSOR CHANGED interrupt */
34826947304SEvan Yan 	if (status & PCIE_SLOTSTS_MRL_SENSOR_CHANGED) {
34926947304SEvan Yan 		/* For now (phase-I), no action is taken on this event */
35026947304SEvan Yan 		PCIE_DBG("pciehpc_intr(): MRL SENSOR CHANGED interrupt received"
35126947304SEvan Yan 		    " on slot %d\n", slot_p->hs_phy_slot_num);
35226947304SEvan Yan 	}
35326947304SEvan Yan 
35426947304SEvan Yan 	/* check for PRESENCE CHANGED interrupt */
35526947304SEvan Yan 	if (status & PCIE_SLOTSTS_PRESENCE_CHANGED) {
35626947304SEvan Yan 
35726947304SEvan Yan 		PCIE_DBG("pciehpc_intr(): PRESENCE CHANGED interrupt received"
35826947304SEvan Yan 		    " on slot %d\n", slot_p->hs_phy_slot_num);
35926947304SEvan Yan 
36026947304SEvan Yan 		if (status & PCIE_SLOTSTS_PRESENCE_DETECTED) {
36126947304SEvan Yan 			/*
36226947304SEvan Yan 			 * card is inserted into the slot, ask DDI Hotplug
36326947304SEvan Yan 			 * framework to change state to Present.
36426947304SEvan Yan 			 */
36570f83219SEvan Yan 			cmn_err(CE_NOTE, "pciehpc (%s%d): card is inserted"
36670f83219SEvan Yan 			    " in the slot %s",
36770f83219SEvan Yan 			    ddi_driver_name(dip),
36870f83219SEvan Yan 			    ddi_get_instance(dip),
36970f83219SEvan Yan 			    slot_p->hs_info.cn_name);
37070f83219SEvan Yan 
37126947304SEvan Yan 			(void) ndi_hp_state_change_req(dip,
37226947304SEvan Yan 			    slot_p->hs_info.cn_name,
37326947304SEvan Yan 			    DDI_HP_CN_STATE_PRESENT,
37426947304SEvan Yan 			    DDI_HP_REQ_ASYNC);
37526947304SEvan Yan 		} else { /* card is removed from the slot */
37626947304SEvan Yan 			cmn_err(CE_NOTE, "pciehpc (%s%d): card is removed"
37726947304SEvan Yan 			    " from the slot %s",
37826947304SEvan Yan 			    ddi_driver_name(dip),
37926947304SEvan Yan 			    ddi_get_instance(dip),
38026947304SEvan Yan 			    slot_p->hs_info.cn_name);
38126947304SEvan Yan 
38226947304SEvan Yan 			if (slot_p->hs_info.cn_state ==
38326947304SEvan Yan 			    DDI_HP_CN_STATE_ENABLED) {
38426947304SEvan Yan 				/* Card is removed when slot is enabled */
38526947304SEvan Yan 				slot_p->hs_condition = AP_COND_FAILED;
38626947304SEvan Yan 			} else {
38726947304SEvan Yan 				slot_p->hs_condition = AP_COND_UNKNOWN;
38826947304SEvan Yan 			}
38926947304SEvan Yan 			/* make sure to disable power fault detction intr */
39026947304SEvan Yan 			control =  pciehpc_reg_get16(ctrl_p,
39126947304SEvan Yan 			    bus_p->bus_pcie_off + PCIE_SLOTCTL);
39226947304SEvan Yan 
39326947304SEvan Yan 			if (control & PCIE_SLOTCTL_PWR_FAULT_EN)
39426947304SEvan Yan 				pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
39526947304SEvan Yan 				    PCIE_SLOTCTL,
39626947304SEvan Yan 				    control & ~PCIE_SLOTCTL_PWR_FAULT_EN);
39726947304SEvan Yan 
398ffb64830SJordan Paige Hendricks 			/*
399ffb64830SJordan Paige Hendricks 			 * If supported, notify the child device driver that the
400ffb64830SJordan Paige Hendricks 			 * device is being removed.
401ffb64830SJordan Paige Hendricks 			 */
402ffb64830SJordan Paige Hendricks 			dev_info_t *cdip = ddi_get_child(dip);
403ffb64830SJordan Paige Hendricks 			if (cdip != NULL) {
404ffb64830SJordan Paige Hendricks 				ddi_eventcookie_t rm_cookie;
405ffb64830SJordan Paige Hendricks 				if (ddi_get_eventcookie(cdip,
406ffb64830SJordan Paige Hendricks 				    DDI_DEVI_REMOVE_EVENT,
407ffb64830SJordan Paige Hendricks 				    &rm_cookie) == DDI_SUCCESS) {
408ffb64830SJordan Paige Hendricks 					ndi_post_event(dip, cdip, rm_cookie,
409ffb64830SJordan Paige Hendricks 					    NULL);
410ffb64830SJordan Paige Hendricks 				}
411ffb64830SJordan Paige Hendricks 			}
412ffb64830SJordan Paige Hendricks 
41326947304SEvan Yan 			/*
41426947304SEvan Yan 			 * Ask DDI Hotplug framework to change state to Empty
41526947304SEvan Yan 			 */
41626947304SEvan Yan 			(void) ndi_hp_state_change_req(dip,
41726947304SEvan Yan 			    slot_p->hs_info.cn_name,
41826947304SEvan Yan 			    DDI_HP_CN_STATE_EMPTY,
41926947304SEvan Yan 			    DDI_HP_REQ_ASYNC);
42026947304SEvan Yan 		}
42126947304SEvan Yan 	}
42226947304SEvan Yan 
42326947304SEvan Yan 	/* check for DLL state changed interrupt */
42426947304SEvan Yan 	if (ctrl_p->hc_dll_active_rep &&
42526947304SEvan Yan 	    (status & PCIE_SLOTSTS_DLL_STATE_CHANGED)) {
42626947304SEvan Yan 		PCIE_DBG("pciehpc_intr(): DLL STATE CHANGED interrupt received"
42726947304SEvan Yan 		    " on slot %d\n", slot_p->hs_phy_slot_num);
42826947304SEvan Yan 
42926947304SEvan Yan 		cv_signal(&slot_p->hs_dll_active_cv);
43026947304SEvan Yan 	}
43126947304SEvan Yan 
43226947304SEvan Yan 	mutex_exit(&ctrl_p->hc_mutex);
43326947304SEvan Yan 
43426947304SEvan Yan 	return (DDI_INTR_CLAIMED);
43526947304SEvan Yan }
43626947304SEvan Yan 
43726947304SEvan Yan /*
43826947304SEvan Yan  * Handle hotplug commands
43926947304SEvan Yan  *
44026947304SEvan Yan  * Note: This function is called by DDI HP framework at kernel context only
44126947304SEvan Yan  */
44226947304SEvan Yan /* ARGSUSED */
44326947304SEvan Yan int
pciehpc_hp_ops(dev_info_t * dip,char * cn_name,ddi_hp_op_t op,void * arg,void * result)44426947304SEvan Yan pciehpc_hp_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op,
44526947304SEvan Yan     void *arg, void *result)