xref: /illumos-gate/usr/src/uts/common/io/pciex/hotplug/pciehpc.c (revision 3665ce8aeee26b1a84fb98951ef011e0779e1ae2)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright 2019 Joyent, Inc.
25  */
26 
27 /*
28  * This file contains Standard PCI Express HotPlug functionality that is
29  * compatible with the PCI Express ver 1.1 specification.
30  *
31  * NOTE: This file is compiled and delivered through misc/pcie module.
32  */
33 
34 #include <sys/types.h>
35 #include <sys/note.h>
36 #include <sys/conf.h>
37 #include <sys/kmem.h>
38 #include <sys/debug.h>
39 #include <sys/vtrace.h>
40 #include <sys/autoconf.h>
41 #include <sys/varargs.h>
42 #include <sys/ddi_impldefs.h>
43 #include <sys/time.h>
44 #include <sys/callb.h>
45 #include <sys/ddi.h>
46 #include <sys/sunddi.h>
47 #include <sys/sunndi.h>
48 #include <sys/sysevent/dr.h>
49 #include <sys/pci_impl.h>
50 #include <sys/hotplug/pci/pcie_hp.h>
51 #include <sys/hotplug/pci/pciehpc.h>
52 
53 typedef struct pciehpc_prop {
54 	char	*prop_name;
55 	char	*prop_value;
56 } pciehpc_prop_t;
57 
58 static pciehpc_prop_t	pciehpc_props[] = {
59 	{ PCIEHPC_PROP_LED_FAULT,	PCIEHPC_PROP_VALUE_LED },
60 	{ PCIEHPC_PROP_LED_POWER,	PCIEHPC_PROP_VALUE_LED },
61 	{ PCIEHPC_PROP_LED_ATTN,	PCIEHPC_PROP_VALUE_LED },
62 	{ PCIEHPC_PROP_LED_ACTIVE,	PCIEHPC_PROP_VALUE_LED },
63 	{ PCIEHPC_PROP_CARD_TYPE,	PCIEHPC_PROP_VALUE_TYPE },
64 	{ PCIEHPC_PROP_BOARD_TYPE,	PCIEHPC_PROP_VALUE_TYPE },
65 	{ PCIEHPC_PROP_SLOT_CONDITION,	PCIEHPC_PROP_VALUE_TYPE }
66 };
67 
68 /* Local functions prototype */
69 static int pciehpc_hpc_init(pcie_hp_ctrl_t *ctrl_p);
70 static int pciehpc_hpc_uninit(pcie_hp_ctrl_t *ctrl_p);
71 static int pciehpc_slotinfo_init(pcie_hp_ctrl_t *ctrl_p);
72 static int pciehpc_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p);
73 static int pciehpc_enable_intr(pcie_hp_ctrl_t *ctrl_p);
74 static int pciehpc_disable_intr(pcie_hp_ctrl_t *ctrl_p);
75 static pcie_hp_ctrl_t *pciehpc_create_controller(dev_info_t *dip);
76 static void pciehpc_destroy_controller(dev_info_t *dip);
77 static int pciehpc_register_slot(pcie_hp_ctrl_t *ctrl_p);
78 static int pciehpc_unregister_slot(pcie_hp_ctrl_t *ctrl_p);
79 static int pciehpc_slot_get_property(pcie_hp_slot_t *slot_p,
80     ddi_hp_property_t *arg, ddi_hp_property_t *rval);
81 static int pciehpc_slot_set_property(pcie_hp_slot_t *slot_p,
82     ddi_hp_property_t *arg, ddi_hp_property_t *rval);
83 static void pciehpc_issue_hpc_command(pcie_hp_ctrl_t *ctrl_p, uint16_t control);
84 static void pciehpc_attn_btn_handler(pcie_hp_ctrl_t *ctrl_p);
85 static pcie_hp_led_state_t pciehpc_led_state_to_hpc(uint16_t state);
86 static pcie_hp_led_state_t pciehpc_get_led_state(pcie_hp_ctrl_t *ctrl_p,
87     pcie_hp_led_t led);
88 static void pciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led,
89     pcie_hp_led_state_t state);
90 
91 static int pciehpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
92     ddi_hp_cn_state_t target_state);
93 static int pciehpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
94     ddi_hp_cn_state_t target_state);
95 static int pciehpc_change_slot_state(pcie_hp_slot_t *slot_p,
96     ddi_hp_cn_state_t target_state);
97 static int
98     pciehpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result);
99 static int
100     pciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result);
101 static int pciehpc_slot_probe(pcie_hp_slot_t *slot_p);
102 static int pciehpc_slot_unprobe(pcie_hp_slot_t *slot_p);
103 static void pciehpc_handle_power_fault(dev_info_t *dip);
104 static void pciehpc_power_fault_handler(void *arg);
105 
106 #ifdef	DEBUG
107 static void pciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p);
108 #endif	/* DEBUG */
109 
110 /*
111  * Global functions (called by other drivers/modules)
112  */
113 
114 /*
115  * Initialize Hot Plug Controller if present. The arguments are:
116  *	dip	- Devinfo node pointer to the hot plug bus node
117  *	regops	- register ops to access HPC registers for non-standard
118  *		  HPC hw implementations (e.g: HPC in host PCI-E brdiges)
119  *		  This is NULL for standard HPC in PCIe bridges.
120  * Returns:
121  *	DDI_SUCCESS for successful HPC initialization
122  *	DDI_FAILURE for errors or if HPC hw not found
123  */
124 int
125 pciehpc_init(dev_info_t *dip, caddr_t arg)
126 {
127 	pcie_hp_regops_t	*regops = (pcie_hp_regops_t *)(void *)arg;
128 	pcie_hp_ctrl_t		*ctrl_p;
129 
130 	PCIE_DBG("pciehpc_init() called (dip=%p)\n", (void *)dip);
131 
132 	/* Make sure that it is not already initialized */
133 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) != NULL) {
134 		PCIE_DBG("%s%d: pciehpc instance already initialized!\n",
135 		    ddi_driver_name(dip), ddi_get_instance(dip));
136 		return (DDI_SUCCESS);
137 	}
138 
139 	/* Allocate a new hotplug controller and slot structures */
140 	ctrl_p = pciehpc_create_controller(dip);
141 
142 	/* setup access handle for HPC regs */
143 	if (regops != NULL) {
144 		/* HPC access is non-standard; use the supplied reg ops */
145 		ctrl_p->hc_regops = *regops;
146 	}
147 
148 	/*
149 	 * Setup resource maps for this bus node.
150 	 */
151 	(void) pci_resource_setup(dip);
152 
153 	PCIE_DISABLE_ERRORS(dip);
154 
155 	/*
156 	 * Set the platform specific hot plug mode.
157 	 */
158 	ctrl_p->hc_ops.init_hpc_hw = pciehpc_hpc_init;
159 	ctrl_p->hc_ops.uninit_hpc_hw = pciehpc_hpc_uninit;
160 	ctrl_p->hc_ops.init_hpc_slotinfo = pciehpc_slotinfo_init;
161 	ctrl_p->hc_ops.uninit_hpc_slotinfo = pciehpc_slotinfo_uninit;
162 	ctrl_p->hc_ops.poweron_hpc_slot = pciehpc_slot_poweron;
163 	ctrl_p->hc_ops.poweroff_hpc_slot = pciehpc_slot_poweroff;
164 
165 	ctrl_p->hc_ops.enable_hpc_intr = pciehpc_enable_intr;
166 	ctrl_p->hc_ops.disable_hpc_intr = pciehpc_disable_intr;
167 
168 #if	defined(__i386) || defined(__amd64)
169 	pciehpc_update_ops(ctrl_p);
170 #endif
171 
172 	/* initialize hot plug controller hw */
173 	if ((ctrl_p->hc_ops.init_hpc_hw)(ctrl_p) != DDI_SUCCESS)
174 		goto cleanup1;
175 
176 	/* initialize slot information soft state structure */
177 	if ((ctrl_p->hc_ops.init_hpc_slotinfo)(ctrl_p) != DDI_SUCCESS)
178 		goto cleanup2;
179 
180 	/* register the hot plug slot with DDI HP framework */
181 	if (pciehpc_register_slot(ctrl_p) != DDI_SUCCESS)
182 		goto cleanup3;
183 
184 	/* create minor node for this slot */
185 	if (pcie_create_minor_node(ctrl_p, 0) != DDI_SUCCESS)
186 		goto cleanup4;
187 
188 	/* HPC initialization is complete now */
189 	ctrl_p->hc_flags = PCIE_HP_INITIALIZED_FLAG;
190 
191 #ifdef	DEBUG
192 	/* For debug, dump the HPC registers */
193 	pciehpc_dump_hpregs(ctrl_p);
194 #endif	/* DEBUG */
195 
196 	return (DDI_SUCCESS);
197 cleanup4:
198 	(void) pciehpc_unregister_slot(ctrl_p);
199 cleanup3:
200 	(void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p);
201 
202 cleanup2:
203 	(void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p);
204 
205 cleanup1:
206 	PCIE_ENABLE_ERRORS(dip);
207 	(void) pci_resource_destroy(dip);
208 
209 	pciehpc_destroy_controller(dip);
210 	return (DDI_FAILURE);
211 }
212 
213 /*
214  * Uninitialize HPC soft state structure and free up any resources
215  * used for the HPC instance.
216  */
217 int
218 pciehpc_uninit(dev_info_t *dip)
219 {
220 	pcie_hp_ctrl_t *ctrl_p;
221 
222 	PCIE_DBG("pciehpc_uninit() called (dip=%p)\n", (void *)dip);
223 
224 	/* get the soft state structure for this dip */
225 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) {
226 		return (DDI_FAILURE);
227 	}
228 
229 	pcie_remove_minor_node(ctrl_p, 0);
230 
231 	/* unregister the slot */
232 	(void) pciehpc_unregister_slot(ctrl_p);
233 
234 	/* uninit any slot info data structures */
235 	(void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p);
236 
237 	/* uninitialize hpc, remove interrupt handler, etc. */
238 	(void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p);
239 
240 	PCIE_ENABLE_ERRORS(dip);
241 
242 	/*
243 	 * Destroy resource maps for this bus node.
244 	 */
245 	(void) pci_resource_destroy(dip);
246 
247 	/* destroy the soft state structure */
248 	pciehpc_destroy_controller(dip);
249 
250 	return (DDI_SUCCESS);
251 }
252 
253 /*
254  * pciehpc_intr()
255  *
256  * Interrupt handler for PCI-E Hot plug controller interrupts.
257  *
258  * Note: This is only for native mode hot plug. This is called
259  * by the nexus driver at interrupt context. Interrupt Service Routine
260  * registration is done by the nexus driver for both hot plug and
261  * non-hot plug interrupts. This function is called from the ISR
262  * of the nexus driver to handle hot-plug interrupts.
263  */
264 int
265 pciehpc_intr(dev_info_t *dip)
266 {
267 	pcie_hp_ctrl_t	*ctrl_p;
268 	pcie_hp_slot_t	*slot_p;
269 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
270 	uint16_t	status, control;
271 
272 	/* get the soft state structure for this dip */
273 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
274 		return (DDI_INTR_UNCLAIMED);
275 
276 	mutex_enter(&ctrl_p->hc_mutex);
277 
278 	/* make sure the controller soft state is initialized */
279 	if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
280 		mutex_exit(&ctrl_p->hc_mutex);
281 		return (DDI_INTR_UNCLAIMED);
282 	}
283 
284 	/* if it is not NATIVE hot plug mode then return */
285 	if (bus_p->bus_hp_curr_mode != PCIE_NATIVE_HP_MODE) {
286 		mutex_exit(&ctrl_p->hc_mutex);
287 		return (DDI_INTR_UNCLAIMED);
288 	}
289 
290 	slot_p = ctrl_p->hc_slots[0];
291 
292 	/* read the current slot status register */
293 	status = pciehpc_reg_get16(ctrl_p,
294 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
295 
296 	/* check if there are any hot plug interrupts occurred */
297 	if (!(status & PCIE_SLOTSTS_STATUS_EVENTS)) {
298 		/* no hot plug events occurred */
299 		mutex_exit(&ctrl_p->hc_mutex);
300 		return (DDI_INTR_UNCLAIMED);
301 	}
302 
303 	/* clear the interrupt status bits */
304 	pciehpc_reg_put16(ctrl_p,
305 	    bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
306 
307 	/* check for CMD COMPLETE interrupt */
308 	if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
309 		PCIE_DBG("pciehpc_intr(): CMD COMPLETED interrupt received\n");
310 		/* wake up any one waiting for Command Completion event */
311 		cv_signal(&ctrl_p->hc_cmd_comp_cv);
312 	}
313 
314 	/* check for ATTN button interrupt */
315 	if (status & PCIE_SLOTSTS_ATTN_BTN_PRESSED) {
316 		PCIE_DBG("pciehpc_intr(): ATTN BUTTON interrupt received\n");
317 
318 		/* if ATTN button event is still pending then cancel it */
319 		if (slot_p->hs_attn_btn_pending == B_TRUE)
320 			slot_p->hs_attn_btn_pending = B_FALSE;
321 		else
322 			slot_p->hs_attn_btn_pending = B_TRUE;
323 
324 		/* wake up the ATTN event handler */
325 		cv_signal(&slot_p->hs_attn_btn_cv);
326 	}
327 
328 	/* check for power fault interrupt */
329 	if (status & PCIE_SLOTSTS_PWR_FAULT_DETECTED) {
330 
331 		PCIE_DBG("pciehpc_intr(): POWER FAULT interrupt received"
332 		    " on slot %d\n", slot_p->hs_phy_slot_num);
333 		control =  pciehpc_reg_get16(ctrl_p,
334 		    bus_p->bus_pcie_off + PCIE_SLOTCTL);
335 
336 		if (control & PCIE_SLOTCTL_PWR_FAULT_EN) {
337 			slot_p->hs_condition = AP_COND_FAILED;
338 
339 			/* disable power fault detction interrupt */
340 			pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
341 			    PCIE_SLOTCTL, control & ~PCIE_SLOTCTL_PWR_FAULT_EN);
342 
343 			pciehpc_handle_power_fault(dip);
344 		}
345 	}
346 
347 	/* check for MRL SENSOR CHANGED interrupt */
348 	if (status & PCIE_SLOTSTS_MRL_SENSOR_CHANGED) {
349 		/* For now (phase-I), no action is taken on this event */
350 		PCIE_DBG("pciehpc_intr(): MRL SENSOR CHANGED interrupt received"
351 		    " on slot %d\n", slot_p->hs_phy_slot_num);
352 	}
353 
354 	/* check for PRESENCE CHANGED interrupt */
355 	if (status & PCIE_SLOTSTS_PRESENCE_CHANGED) {
356 
357 		PCIE_DBG("pciehpc_intr(): PRESENCE CHANGED interrupt received"
358 		    " on slot %d\n", slot_p->hs_phy_slot_num);
359 
360 		if (status & PCIE_SLOTSTS_PRESENCE_DETECTED) {
361 			/*
362 			 * card is inserted into the slot, ask DDI Hotplug
363 			 * framework to change state to Present.
364 			 */
365 			cmn_err(CE_NOTE, "pciehpc (%s%d): card is inserted"
366 			    " in the slot %s",
367 			    ddi_driver_name(dip),
368 			    ddi_get_instance(dip),
369 			    slot_p->hs_info.cn_name);
370 
371 			(void) ndi_hp_state_change_req(dip,
372 			    slot_p->hs_info.cn_name,
373 			    DDI_HP_CN_STATE_PRESENT,
374 			    DDI_HP_REQ_ASYNC);
375 		} else { /* card is removed from the slot */
376 			cmn_err(CE_NOTE, "pciehpc (%s%d): card is removed"
377 			    " from the slot %s",
378 			    ddi_driver_name(dip),
379 			    ddi_get_instance(dip),
380 			    slot_p->hs_info.cn_name);
381 
382 			if (slot_p->hs_info.cn_state ==
383 			    DDI_HP_CN_STATE_ENABLED) {
384 				/* Card is removed when slot is enabled */
385 				slot_p->hs_condition = AP_COND_FAILED;
386 			} else {
387 				slot_p->hs_condition = AP_COND_UNKNOWN;
388 			}
389 			/* make sure to disable power fault detction intr */
390 			control =  pciehpc_reg_get16(ctrl_p,
391 			    bus_p->bus_pcie_off + PCIE_SLOTCTL);
392 
393 			if (control & PCIE_SLOTCTL_PWR_FAULT_EN)
394 				pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
395 				    PCIE_SLOTCTL,
396 				    control & ~PCIE_SLOTCTL_PWR_FAULT_EN);
397 
398 			/*
399 			 * Ask DDI Hotplug framework to change state to Empty
400 			 */
401 			(void) ndi_hp_state_change_req(dip,
402 			    slot_p->hs_info.cn_name,
403 			    DDI_HP_CN_STATE_EMPTY,
404 			    DDI_HP_REQ_ASYNC);
405 		}
406 	}
407 
408 	/* check for DLL state changed interrupt */
409 	if (ctrl_p->hc_dll_active_rep &&
410 	    (status & PCIE_SLOTSTS_DLL_STATE_CHANGED)) {
411 		PCIE_DBG("pciehpc_intr(): DLL STATE CHANGED interrupt received"
412 		    " on slot %d\n", slot_p->hs_phy_slot_num);
413 
414 		cv_signal(&slot_p->hs_dll_active_cv);
415 	}
416 
417 	mutex_exit(&ctrl_p->hc_mutex);
418 
419 	return (DDI_INTR_CLAIMED);
420 }
421 
422 /*
423  * Handle hotplug commands
424  *
425  * Note: This function is called by DDI HP framework at kernel context only
426  */
427 /* ARGSUSED */
428 int
429 pciehpc_hp_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op,
430     void *arg, void *result)
431 {
432 	pcie_hp_ctrl_t	*ctrl_p;
433 	pcie_hp_slot_t	*slot_p;
434 	int		ret = DDI_SUCCESS;
435 
436 	PCIE_DBG("pciehpc_hp_ops: dip=%p cn_name=%s op=%x arg=%p\n",
437 	    dip, cn_name, op, arg);
438 
439 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
440 		return (DDI_FAILURE);
441 
442 	slot_p = ctrl_p->hc_slots[0];
443 
444 	if (strcmp(cn_name, slot_p->hs_info.cn_name) != 0)
445 		return (DDI_EINVAL);
446 
447 	switch (op) {
448 	case DDI_HPOP_CN_GET_STATE:
449 	{
450 		mutex_enter(&slot_p->hs_ctrl->hc_mutex);
451 
452 		/* get the current slot state */
453 		pciehpc_get_slot_state(slot_p);
454 
455 		*((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state;
456 
457 		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
458 		break;
459 	}
460 	case DDI_HPOP_CN_CHANGE_STATE:
461 	{
462 		ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg;
463 
464 		mutex_enter(&slot_p->hs_ctrl->hc_mutex);
465 
466 		ret = pciehpc_change_slot_state(slot_p, target_state);
467 		*(ddi_hp_cn_state_t *)result = slot_p->hs_info.cn_state;
468 
469 		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
470 		break;
471 	}
472 	case DDI_HPOP_CN_PROBE:
473 
474 		ret = pciehpc_slot_probe(slot_p);
475 
476 		break;
477 	case DDI_HPOP_CN_UNPROBE:
478 		ret = pciehpc_slot_unprobe(slot_p);
479 
480 		break;
481 	case DDI_HPOP_CN_GET_PROPERTY:
482 		ret = pciehpc_slot_get_property(slot_p,
483 		    (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
484 		break;
485 	case DDI_HPOP_CN_SET_PROPERTY:
486 		ret = pciehpc_slot_set_property(slot_p,
487 		    (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
488 		break;
489 	default:
490 		ret = DDI_ENOTSUP;
491 		break;
492 	}
493 
494 	return (ret);
495 }
496 
497 /*
498  * Get the current state of the slot from the hw.
499  *
500  * The slot state should have been initialized before this function gets called.
501  */
502 void
503 pciehpc_get_slot_state(pcie_hp_slot_t *slot_p)
504 {
505 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
506 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
507 	uint16_t	control, status;
508 	ddi_hp_cn_state_t curr_state = slot_p->hs_info.cn_state;
509 
510 	/* read the Slot Control Register */
511 	control = pciehpc_reg_get16(ctrl_p,
512 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
513 
514 	slot_p->hs_fault_led_state = PCIE_HP_LED_OFF; /* no fault led */
515 	slot_p->hs_active_led_state = PCIE_HP_LED_OFF; /* no active led */
516 
517 	/* read the current Slot Status Register */
518 	status = pciehpc_reg_get16(ctrl_p,
519 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
520 
521 	/* get POWER led state */
522 	slot_p->hs_power_led_state =
523 	    pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control));
524 
525 	/* get ATTN led state */
526 	slot_p->hs_attn_led_state =
527 	    pciehpc_led_state_to_hpc(pcie_slotctl_attn_indicator_get(control));
528 
529 	if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
530 		/* no device present; slot is empty */
531 		slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY;
532 
533 		return;
534 	}
535 
536 	/* device is present */
537 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_PRESENT;
538 
539 	if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) {
540 		/*
541 		 * Device is powered on. Set to "ENABLED" state (skip
542 		 * POWERED state) because there is not a explicit "enable"
543 		 * action exists for PCIe.
544 		 * If it is already in "POWERED" state, then keep it until
545 		 * user explicitly change it to other states.
546 		 */
547 		if (curr_state == DDI_HP_CN_STATE_POWERED) {
548 			slot_p->hs_info.cn_state = curr_state;
549 		} else {
550 			slot_p->hs_info.cn_state = DDI_HP_CN_STATE_ENABLED;
551 		}
552 	}
553 }
554 
555 /*
556  * setup slot name/slot-number info.
557  */
558 void
559 pciehpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p)
560 {
561 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
562 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
563 	uchar_t		*slotname_data;
564 	int		*slotnum;
565 	uint_t		count;
566 	int		len;
567 	int		invalid_slotnum = 0;
568 	uint32_t	slot_capabilities;
569 
570 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ctrl_p->hc_dip,
571 	    DDI_PROP_DONTPASS, "physical-slot#", &slotnum, &count) ==
572 	    DDI_PROP_SUCCESS) {
573 		slot_p->hs_phy_slot_num = slotnum[0];
574 		ddi_prop_free(slotnum);
575 	} else {
576 		slot_capabilities = pciehpc_reg_get32(ctrl_p,
577 		    bus_p->bus_pcie_off + PCIE_SLOTCAP);
578 		slot_p->hs_phy_slot_num =
579 		    PCIE_SLOTCAP_PHY_SLOT_NUM(slot_capabilities);
580 	}
581 
582 	/* platform may not have initialized it */
583 	if (!slot_p->hs_phy_slot_num) {
584 		PCIE_DBG("%s#%d: Invalid slot number!\n",
585 		    ddi_driver_name(ctrl_p->hc_dip),
586 		    ddi_get_instance(ctrl_p->hc_dip));
587 		slot_p->hs_phy_slot_num = pciehpc_reg_get8(ctrl_p,
588 		    PCI_BCNF_SECBUS);
589 		invalid_slotnum = 1;
590 	}
591 	slot_p->hs_info.cn_num = slot_p->hs_phy_slot_num;
592 	slot_p->hs_info.cn_num_dpd_on = DDI_HP_CN_NUM_NONE;
593 
594 	/*
595 	 * construct the slot_name:
596 	 *	if "slot-names" property exists then use that name
597 	 *	else if valid slot number exists then it is "pcie<slot-num>".
598 	 *	else it will be "pcie<sec-bus-number>dev0"
599 	 */
600 	if (ddi_getlongprop(DDI_DEV_T_ANY, ctrl_p->hc_dip, DDI_PROP_DONTPASS,
601 	    "slot-names", (caddr_t)&slotname_data, &len) == DDI_PROP_SUCCESS) {
602 		char tmp_name[256];
603 
604 		/*
605 		 * Note: for PCI-E slots, the device number is always 0 so the
606 		 * first (and only) string is the slot name for this slot.
607 		 */
608 		(void) snprintf(tmp_name, sizeof (tmp_name),
609 		    (char *)slotname_data + 4);
610 		slot_p->hs_info.cn_name = ddi_strdup(tmp_name, KM_SLEEP);
611 		kmem_free(slotname_data, len);
612 	} else {
613 		if (invalid_slotnum) {
614 			/* use device number ie. 0 */
615 			slot_p->hs_info.cn_name = ddi_strdup("pcie0",
616 			    KM_SLEEP);
617 		} else {
618 			char tmp_name[256];
619 
620 			(void) snprintf(tmp_name, sizeof (tmp_name), "pcie%d",
621 			    slot_p->hs_phy_slot_num);
622 			slot_p->hs_info.cn_name = ddi_strdup(tmp_name,
623 			    KM_SLEEP);
624 		}
625 	}
626 }
627 
628 /*
629  * Read/Write access to HPC registers. If platform nexus has non-standard
630  * HPC access mechanism then regops functions are used to do reads/writes.
631  */
632 uint8_t
633 pciehpc_reg_get8(pcie_hp_ctrl_t *ctrl_p, uint_t off)
634 {
635 	if (ctrl_p->hc_regops.get != NULL) {
636 		return ((uint8_t)ctrl_p->hc_regops.get(
637 		    ctrl_p->hc_regops.cookie, (off_t)off));
638 	} else {
639 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
640 
641 		return (pci_config_get8(bus_p->bus_cfg_hdl, off));
642 	}
643 }
644 
645 uint16_t
646 pciehpc_reg_get16(pcie_hp_ctrl_t *ctrl_p, uint_t off)
647 {
648 	if (ctrl_p->hc_regops.get != NULL) {
649 		return ((uint16_t)ctrl_p->hc_regops.get(
650 		    ctrl_p->hc_regops.cookie, (off_t)off));
651 	} else {
652 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
653 
654 		return (pci_config_get16(bus_p->bus_cfg_hdl, off));
655 	}
656 }
657 
658 uint32_t
659 pciehpc_reg_get32(pcie_hp_ctrl_t *ctrl_p, uint_t off)
660 {
661 	if (ctrl_p->hc_regops.get != NULL) {
662 		return ((uint32_t)ctrl_p->hc_regops.get(
663 		    ctrl_p->hc_regops.cookie, (off_t)off));
664 	} else {
665 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
666 
667 		return (pci_config_get32(bus_p->bus_cfg_hdl, off));
668 	}
669 }
670 
671 void
672 pciehpc_reg_put8(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint8_t val)
673 {
674 	if (ctrl_p->hc_regops.put != NULL) {
675 		ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
676 		    (off_t)off, (uint_t)val);
677 	} else {
678 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
679 
680 		pci_config_put8(bus_p->bus_cfg_hdl, off, val);
681 	}
682 }
683 
684 void
685 pciehpc_reg_put16(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint16_t val)
686 {
687 	if (ctrl_p->hc_regops.put != NULL) {
688 		ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
689 		    (off_t)off, (uint_t)val);
690 	} else {
691 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
692 
693 		pci_config_put16(bus_p->bus_cfg_hdl, off, val);
694 	}
695 }
696 
697 void
698 pciehpc_reg_put32(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint32_t val)
699 {
700 	if (ctrl_p->hc_regops.put != NULL) {
701 		ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
702 		    (off_t)off, (uint_t)val);
703 	} else {
704 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
705 
706 		pci_config_put32(bus_p->bus_cfg_hdl, off, val);
707 	}
708 }
709 
710 /*
711  * ************************************************************************
712  * ***	Local functions (called within this file)
713  * ***	PCIe Native Hotplug mode specific functions
714  * ************************************************************************
715  */
716 
717 /*
718  * Initialize HPC hardware, install interrupt handler, etc. It doesn't
719  * enable hot plug interrupts.
720  *
721  * (Note: It is called only from pciehpc_init().)
722  */
723 static int
724 pciehpc_hpc_init(pcie_hp_ctrl_t *ctrl_p)
725 {
726 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
727 	uint16_t	reg;
728 
729 	/* read the Slot Control Register */
730 	reg = pciehpc_reg_get16(ctrl_p,
731 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
732 
733 	/* disable all interrupts */
734 	reg &= ~(PCIE_SLOTCTL_INTR_MASK);
735 	pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
736 	    PCIE_SLOTCTL, reg);
737 
738 	/* clear any interrupt status bits */
739 	reg = pciehpc_reg_get16(ctrl_p,
740 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
741 	pciehpc_reg_put16(ctrl_p,
742 	    bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
743 
744 	return (DDI_SUCCESS);
745 }
746 
747 /*
748  * Uninitialize HPC hardware, uninstall interrupt handler, etc.
749  *
750  * (Note: It is called only from pciehpc_uninit().)
751  */
752 static int
753 pciehpc_hpc_uninit(pcie_hp_ctrl_t *ctrl_p)
754 {
755 	/* disable interrupts */
756 	(void) pciehpc_disable_intr(ctrl_p);
757 
758 	return (DDI_SUCCESS);
759 }
760 
761 /*
762  * Setup slot information for use with DDI HP framework.
763  */
764 static int
765 pciehpc_slotinfo_init(pcie_hp_ctrl_t *ctrl_p)
766 {
767 	uint32_t	slot_capabilities, link_capabilities;
768 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
769 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
770 
771 	mutex_enter(&ctrl_p->hc_mutex);
772 	/*
773 	 * setup DDI HP framework slot information structure
774 	 */
775 	slot_p->hs_device_num = 0;
776 
777 	slot_p->hs_info.cn_type = DDI_HP_CN_TYPE_PCIE;
778 	slot_p->hs_info.cn_type_str = (ctrl_p->hc_regops.get == NULL) ?
779 	    PCIE_NATIVE_HP_TYPE : PCIE_PROP_HP_TYPE;
780 	slot_p->hs_info.cn_child = NULL;
781 
782 	slot_p->hs_minor =
783 	    PCI_MINOR_NUM(ddi_get_instance(ctrl_p->hc_dip),
784 	    slot_p->hs_device_num);
785 	slot_p->hs_condition = AP_COND_UNKNOWN;
786 
787 	/* read Slot Capabilities Register */
788 	slot_capabilities = pciehpc_reg_get32(ctrl_p,
789 	    bus_p->bus_pcie_off + PCIE_SLOTCAP);
790 
791 	/* set slot-name/slot-number info */
792 	pciehpc_set_slot_name(ctrl_p);
793 
794 	/* check if Attn Button present */
795 	ctrl_p->hc_has_attn = (slot_capabilities & PCIE_SLOTCAP_ATTN_BUTTON) ?
796 	    B_TRUE : B_FALSE;
797 
798 	/* check if Manual Retention Latch sensor present */
799 	ctrl_p->hc_has_mrl = (slot_capabilities & PCIE_SLOTCAP_MRL_SENSOR) ?
800 	    B_TRUE : B_FALSE;
801 
802 	/*
803 	 * PCI-E version 1.1 defines EMI Lock Present bit
804 	 * in Slot Capabilities register. Check for it.
805 	 */
806 	ctrl_p->hc_has_emi_lock = (slot_capabilities &
807 	    PCIE_SLOTCAP_EMI_LOCK_PRESENT) ? B_TRUE : B_FALSE;
808 
809 	link_capabilities = pciehpc_reg_get32(ctrl_p,
810 	    bus_p->bus_pcie_off + PCIE_LINKCAP);
811 	ctrl_p->hc_dll_active_rep = (link_capabilities &
812 	    PCIE_LINKCAP_DLL_ACTIVE_REP_CAPABLE) ? B_TRUE : B_FALSE;
813 	if (ctrl_p->hc_dll_active_rep)
814 		cv_init(&slot_p->hs_dll_active_cv, NULL, CV_DRIVER, NULL);
815 
816 	/* setup thread for handling ATTN button events */
817 	if (ctrl_p->hc_has_attn) {
818 		PCIE_DBG("pciehpc_slotinfo_init: setting up ATTN button event "
819 		    "handler thread for slot %d\n", slot_p->hs_phy_slot_num);
820 
821 		cv_init(&slot_p->hs_attn_btn_cv, NULL, CV_DRIVER, NULL);
822 		slot_p->hs_attn_btn_pending = B_FALSE;
823 		slot_p->hs_attn_btn_threadp = thread_create(NULL, 0,
824 		    pciehpc_attn_btn_handler,
825 		    (void *)ctrl_p, 0, &p0, TS_RUN, minclsyspri);
826 		slot_p->hs_attn_btn_thread_exit = B_FALSE;
827 	}
828 
829 	/* get current slot state from the hw */
830 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY;
831 	pciehpc_get_slot_state(slot_p);
832 	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_ENABLED)
833 		slot_p->hs_condition = AP_COND_OK;
834 
835 	mutex_exit(&ctrl_p->hc_mutex);
836 
837 	return (DDI_SUCCESS);
838 }
839 
840 /*ARGSUSED*/
841 static int
842 pciehpc_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p)
843 {
844 	pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
845 
846 	if (slot_p->hs_attn_btn_threadp != NULL) {
847 		mutex_enter(&ctrl_p->hc_mutex);
848 		slot_p->hs_attn_btn_thread_exit = B_TRUE;
849 		cv_signal(&slot_p->hs_attn_btn_cv);
850 		PCIE_DBG("pciehpc_slotinfo_uninit: "
851 		    "waiting for ATTN thread exit\n");
852 		cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
853 		PCIE_DBG("pciehpc_slotinfo_uninit: ATTN thread exit\n");
854 		cv_destroy(&slot_p->hs_attn_btn_cv);
855 		slot_p->hs_attn_btn_threadp = NULL;
856 		mutex_exit(&ctrl_p->hc_mutex);
857 	}
858 
859 	if (ctrl_p->hc_dll_active_rep)
860 		cv_destroy(&slot_p->hs_dll_active_cv);
861 	if (slot_p->hs_info.cn_name)
862 		kmem_free(slot_p->hs_info.cn_name,
863 		    strlen(slot_p->hs_info.cn_name) + 1);
864 
865 	return (DDI_SUCCESS);
866 }
867 
868 /*
869  * Enable hot plug interrupts.
870  * Note: this is only for Native hot plug mode.
871  */
872 static int
873 pciehpc_enable_intr(pcie_hp_ctrl_t *ctrl_p)
874 {
875 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
876 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
877 	uint16_t	reg;
878 
879 	/* clear any interrupt status bits */
880 	reg = pciehpc_reg_get16(ctrl_p,
881 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
882 	pciehpc_reg_put16(ctrl_p,
883 	    bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
884 
885 	/* read the Slot Control Register */
886 	reg = pciehpc_reg_get16(ctrl_p,
887 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
888 
889 	/*
890 	 * enable interrupts: power fault detection interrupt is enabled
891 	 * only when the slot is powered ON
892 	 */
893 	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
894 		pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
895 		    PCIE_SLOTCTL, reg | PCIE_SLOTCTL_INTR_MASK);
896 	else
897 		pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
898 		    PCIE_SLOTCTL, reg | (PCIE_SLOTCTL_INTR_MASK &
899 		    ~PCIE_SLOTCTL_PWR_FAULT_EN));
900 
901 	return (DDI_SUCCESS);
902 }
903 
904 /*
905  * Disable hot plug interrupts.
906  * Note: this is only for Native hot plug mode.
907  */
908 static int
909 pciehpc_disable_intr(pcie_hp_ctrl_t *ctrl_p)
910 {
911 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
912 	uint16_t	reg;
913 
914 	/* read the Slot Control Register */
915 	reg = pciehpc_reg_get16(ctrl_p,
916 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
917 
918 	/* disable all interrupts */
919 	reg &= ~(PCIE_SLOTCTL_INTR_MASK);
920 	pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTCTL, reg);
921 
922 	/* clear any interrupt status bits */
923 	reg = pciehpc_reg_get16(ctrl_p,
924 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
925 	pciehpc_reg_put16(ctrl_p,
926 	    bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
927 
928 	return (DDI_SUCCESS);
929 }
930 
931 /*
932  * Allocate a new hotplug controller and slot structures for HPC
933  * associated with this dip.
934  */
935 static pcie_hp_ctrl_t *
936 pciehpc_create_controller(dev_info_t *dip)
937 {
938 	pcie_hp_ctrl_t	*ctrl_p;
939 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
940 
941 	ctrl_p = kmem_zalloc(sizeof (pcie_hp_ctrl_t), KM_SLEEP);
942 	ctrl_p->hc_dip = dip;
943 
944 	/* Allocate a new slot structure. */
945 	ctrl_p->hc_slots[0] = kmem_zalloc(sizeof (pcie_hp_slot_t), KM_SLEEP);
946 	ctrl_p->hc_slots[0]->hs_num = 0;
947 	ctrl_p->hc_slots[0]->hs_ctrl = ctrl_p;
948 
949 	/* Initialize the interrupt mutex */
950 	mutex_init(&ctrl_p->hc_mutex, NULL, MUTEX_DRIVER,
951 	    (void *)PCIE_INTR_PRI);
952 
953 	/* Initialize synchronization conditional variable */
954 	cv_init(&ctrl_p->hc_cmd_comp_cv, NULL, CV_DRIVER, NULL);
955 	ctrl_p->hc_cmd_pending = B_FALSE;
956 
957 	bus_p->bus_hp_curr_mode = PCIE_NATIVE_HP_MODE;
958 	PCIE_SET_HP_CTRL(dip, ctrl_p);
959 
960 	return (ctrl_p);
961 }
962 
963 /*
964  * Remove the HPC controller and slot structures
965  */
966 static void
967 pciehpc_destroy_controller(dev_info_t *dip)
968 {
969 	pcie_hp_ctrl_t	*ctrl_p;
970 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
971 
972 	/* get the soft state structure for this dip */
973 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
974 		return;
975 
976 	PCIE_SET_HP_CTRL(dip, NULL);
977 	bus_p->bus_hp_curr_mode = PCIE_NONE_HP_MODE;
978 
979 	mutex_destroy(&ctrl_p->hc_mutex);
980 	cv_destroy(&ctrl_p->hc_cmd_comp_cv);
981 	kmem_free(ctrl_p->hc_slots[0], sizeof (pcie_hp_slot_t));
982 	kmem_free(ctrl_p, sizeof (pcie_hp_ctrl_t));
983 }
984 
985 /*
986  * Register the PCI-E hot plug slot with DDI HP framework.
987  */
988 static int
989 pciehpc_register_slot(pcie_hp_ctrl_t *ctrl_p)
990 {
991 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
992 	dev_info_t	*dip = ctrl_p->hc_dip;
993 
994 	/* register the slot with DDI HP framework */
995 	if (ndi_hp_register(dip, &slot_p->hs_info) != NDI_SUCCESS) {
996 		PCIE_DBG("pciehpc_register_slot() failed to register slot %d\n",
997 		    slot_p->hs_phy_slot_num);
998 		return (DDI_FAILURE);
999 	}
1000 
1001 	pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip),
1002 	    slot_p->hs_minor), slot_p->hs_device_num);
1003 
1004 	PCIE_DBG("pciehpc_register_slot(): registered slot %d\n",
1005 	    slot_p->hs_phy_slot_num);
1006 
1007 	return (DDI_SUCCESS);
1008 }
1009 
1010 /*
1011  * Unregister the PCI-E hot plug slot from DDI HP framework.
1012  */
1013 static int
1014 pciehpc_unregister_slot(pcie_hp_ctrl_t *ctrl_p)
1015 {
1016 	pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
1017 	dev_info_t	*dip = ctrl_p->hc_dip;
1018 
1019 	pcie_hp_delete_occupant_props(dip, makedevice(ddi_driver_major(dip),
1020 	    slot_p->hs_minor));
1021 
1022 	/* unregister the slot with DDI HP framework */
1023 	if (ndi_hp_unregister(dip, slot_p->hs_info.cn_name) != NDI_SUCCESS) {
1024 		PCIE_DBG("pciehpc_unregister_slot() "
1025 		    "failed to unregister slot %d\n", slot_p->hs_phy_slot_num);
1026 		return (DDI_FAILURE);
1027 	}
1028 
1029 	PCIE_DBG("pciehpc_unregister_slot(): unregistered slot %d\n",
1030 	    slot_p->hs_phy_slot_num);
1031 
1032 	return (DDI_SUCCESS);
1033 }
1034 
1035 /*
1036  * pciehpc_slot_poweron()
1037  *
1038  * Poweron/Enable the slot.
1039  *
1040  * Note: This function is called by DDI HP framework at kernel context only
1041  */
1042 /*ARGSUSED*/
1043 static int
1044 pciehpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result)
1045 {
1046 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
1047 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1048 	uint16_t	status, control;
1049 
1050 	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
1051 
1052 	/* get the current state of the slot */
1053 	pciehpc_get_slot_state(slot_p);
1054 
1055 	/* check if the slot is already in the 'enabled' state */
1056 	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) {
1057 		/* slot is already in the 'enabled' state */
1058 		PCIE_DBG("pciehpc_slot_poweron() slot %d already enabled\n",
1059 		    slot_p->hs_phy_slot_num);
1060 
1061 		*result = slot_p->hs_info.cn_state;
1062 		return (DDI_SUCCESS);
1063 	}
1064 
1065 	/* read the Slot Status Register */
1066 	status =  pciehpc_reg_get16(ctrl_p,
1067 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
1068 
1069 	/* make sure the MRL switch is closed if present */
1070 	if ((ctrl_p->hc_has_mrl) && (status & PCIE_SLOTSTS_MRL_SENSOR_OPEN)) {
1071 		/* MRL switch is open */
1072 		cmn_err(CE_WARN, "MRL switch is open on slot %d\n",
1073 		    slot_p->hs_phy_slot_num);
1074 		goto cleanup;
1075 	}
1076 
1077 	/* make sure the slot has a device present */
1078 	if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
1079 		/* slot is empty */
1080 		PCIE_DBG("slot %d is empty\n", slot_p->hs_phy_slot_num);
1081 		goto cleanup;
1082 	}
1083 
1084 	/* get the current state of Slot Control Register */
1085 	control =  pciehpc_reg_get16(ctrl_p,
1086 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1087 
1088 	/*
1089 	 * Enable power to the slot involves:
1090 	 *	1. Set power LED to blink and ATTN led to OFF.
1091 	 *	2. Set power control ON in Slot Control Reigster and
1092 	 *	   wait for Command Completed Interrupt or 1 sec timeout.
1093 	 *	3. If Data Link Layer State Changed events are supported
1094 	 *	   then wait for the event to indicate Data Layer Link
1095 	 *	   is active. The time out value for this event is 1 second.
1096 	 *	   This is specified in PCI-E version 1.1.
1097 	 *	4. Set power LED to be ON.
1098 	 */
1099 
1100 	/* 1. set power LED to blink & ATTN led to OFF */
1101 	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
1102 	pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
1103 
1104 	/* 2. set power control to ON */
1105 	control =  pciehpc_reg_get16(ctrl_p,
1106 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1107 	control &= ~PCIE_SLOTCTL_PWR_CONTROL;
1108 	pciehpc_issue_hpc_command(ctrl_p, control);
1109 
1110 	/* 3. wait for DLL State Change event, if it's supported */
1111 	if (ctrl_p->hc_dll_active_rep) {
1112 		status =  pciehpc_reg_get16(ctrl_p,
1113 		    bus_p->bus_pcie_off + PCIE_LINKSTS);
1114 
1115 		if (!(status & PCIE_LINKSTS_DLL_LINK_ACTIVE)) {
1116 			/* wait 1 sec for the DLL State Changed event */
1117 			(void) cv_timedwait(&slot_p->hs_dll_active_cv,
1118 			    &ctrl_p->hc_mutex,
1119 			    ddi_get_lbolt() +
1120 			    SEC_TO_TICK(PCIE_HP_DLL_STATE_CHANGE_TIMEOUT));
1121 
1122 			/* check Link status */
1123 			status =  pciehpc_reg_get16(ctrl_p,
1124 			    bus_p->bus_pcie_off +
1125 			    PCIE_LINKSTS);
1126 			if (!(status & PCIE_LINKSTS_DLL_LINK_ACTIVE))
1127 				goto cleanup2;
1128 		}
1129 	}
1130 
1131 	/* wait 1 sec for link to come up */
1132 	delay(drv_usectohz(1000000));
1133 
1134 	/* check power is really turned ON */
1135 	control =  pciehpc_reg_get16(ctrl_p,
1136 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1137 
1138 	if (control & PCIE_SLOTCTL_PWR_CONTROL) {
1139 		PCIE_DBG("slot %d fails to turn on power on connect\n",
1140 		    slot_p->hs_phy_slot_num);
1141 
1142 		goto cleanup1;
1143 	}
1144 
1145 	/* clear power fault status */
1146 	status =  pciehpc_reg_get16(ctrl_p,
1147 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
1148 	status |= PCIE_SLOTSTS_PWR_FAULT_DETECTED;
1149 	pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTSTS,
1150 	    status);
1151 
1152 	/* enable power fault detection interrupt */
1153 	control |= PCIE_SLOTCTL_PWR_FAULT_EN;
1154 	pciehpc_issue_hpc_command(ctrl_p, control);
1155 
1156 	/* 4. Set power LED to be ON */
1157 	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_ON);
1158 
1159 	/* if EMI is present, turn it ON */
1160 	if (ctrl_p->hc_has_emi_lock) {
1161 		status =  pciehpc_reg_get16(ctrl_p,
1162 		    bus_p->bus_pcie_off + PCIE_SLOTSTS);
1163 
1164 		if (!(status & PCIE_SLOTSTS_EMI_LOCK_SET)) {
1165 			control =  pciehpc_reg_get16(ctrl_p,
1166 			    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1167 			control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL;
1168 			pciehpc_issue_hpc_command(ctrl_p, control);
1169 
1170 			/* wait 1 sec after toggling the state of EMI lock */
1171 			delay(drv_usectohz(1000000));
1172 		}
1173 	}
1174 
1175 	*result = slot_p->hs_info.cn_state =
1176 	    DDI_HP_CN_STATE_POWERED;
1177 
1178 	return (DDI_SUCCESS);
1179 
1180 cleanup2:
1181 	control =  pciehpc_reg_get16(ctrl_p,
1182 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1183 
1184 	/* if power is ON, set power control to OFF */
1185 	if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) {
1186 		control |= PCIE_SLOTCTL_PWR_CONTROL;
1187 		pciehpc_issue_hpc_command(ctrl_p, control);
1188 	}
1189 
1190 cleanup1:
1191 	/* set power led to OFF */
1192 	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
1193 
1194 cleanup:
1195 	return (DDI_FAILURE);
1196 }
1197 
1198 /*ARGSUSED*/
1199 static int
1200 pciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result)
1201 {
1202 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
1203 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1204 	uint16_t	status, control;
1205 
1206 	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
1207 
1208 	/* get the current state of the slot */
1209 	pciehpc_get_slot_state(slot_p);
1210 
1211 	/* check if the slot is not in the "enabled' state */
1212 	if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) {
1213 		/* slot is in the 'disabled' state */
1214 		PCIE_DBG("pciehpc_slot_poweroff(): "
1215 		    "slot %d already disabled\n", slot_p->hs_phy_slot_num);
1216 		ASSERT(slot_p->hs_power_led_state == PCIE_HP_LED_OFF);
1217 
1218 		*result = slot_p->hs_info.cn_state;
1219 		return (DDI_SUCCESS);
1220 	}
1221 
1222 	/* read the Slot Status Register */
1223 	status =  pciehpc_reg_get16(ctrl_p,
1224 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
1225 
1226 	/* make sure the slot has a device present */
1227 	if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
1228 		/* slot is empty */
1229 		PCIE_DBG("pciehpc_slot_poweroff(): slot %d is empty\n",
1230 		    slot_p->hs_phy_slot_num);
1231 		goto cleanup;
1232 	}
1233 
1234 	/*
1235 	 * Disable power to the slot involves:
1236 	 *	1. Set power LED to blink.
1237 	 *	2. Set power control OFF in Slot Control Reigster and
1238 	 *	   wait for Command Completed Interrupt or 1 sec timeout.
1239 	 *	3. Set POWER led and ATTN led to be OFF.
1240 	 */
1241 
1242 	/* 1. set power LED to blink */
1243 	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
1244 
1245 	/* disable power fault detection interrupt */
1246 	control = pciehpc_reg_get16(ctrl_p,
1247 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1248 	control &= ~PCIE_SLOTCTL_PWR_FAULT_EN;
1249 	pciehpc_issue_hpc_command(ctrl_p, control);
1250 
1251 	/* 2. set power control to OFF */
1252 	control =  pciehpc_reg_get16(ctrl_p,
1253 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1254 	control |= PCIE_SLOTCTL_PWR_CONTROL;
1255 	pciehpc_issue_hpc_command(ctrl_p, control);
1256 
1257 #ifdef DEBUG
1258 	/* check for power control bit to be OFF */
1259 	control =  pciehpc_reg_get16(ctrl_p,
1260 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1261 	ASSERT(control & PCIE_SLOTCTL_PWR_CONTROL);
1262 #endif
1263 
1264 	/* 3. Set power LED to be OFF */
1265 	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
1266 	pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
1267 
1268 	/* if EMI is present, turn it OFF */
1269 	if (ctrl_p->hc_has_emi_lock) {
1270 		status =  pciehpc_reg_get16(ctrl_p,
1271 		    bus_p->bus_pcie_off + PCIE_SLOTSTS);
1272 
1273 		if (status & PCIE_SLOTSTS_EMI_LOCK_SET) {
1274 			control =  pciehpc_reg_get16(ctrl_p,
1275 			    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1276 			control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL;
1277 			pciehpc_issue_hpc_command(ctrl_p, control);
1278 
1279 			/* wait 1 sec after toggling the state of EMI lock */
1280 			delay(drv_usectohz(1000000));
1281 		}
1282 	}
1283 
1284 	/* get the current state of the slot */
1285 	pciehpc_get_slot_state(slot_p);
1286 
1287 	*result = slot_p->hs_info.cn_state;
1288 
1289 	return (DDI_SUCCESS);
1290 
1291 cleanup:
1292 	return (DDI_FAILURE);
1293 }
1294 
1295 /*
1296  * pciehpc_slot_probe()
1297  *
1298  * Probe the slot.
1299  *
1300  * Note: This function is called by DDI HP framework at kernel context only
1301  */
1302 /*ARGSUSED*/
1303 static int
1304 pciehpc_slot_probe(pcie_hp_slot_t *slot_p)
1305 {
1306 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
1307 	int		ret = DDI_SUCCESS;
1308 
1309 	mutex_enter(&ctrl_p->hc_mutex);
1310 
1311 	/* get the current state of the slot */
1312 	pciehpc_get_slot_state(slot_p);
1313 
1314 	/*
1315 	 * Probe a given PCIe Hotplug Connection (CN).
1316 	 */
1317 	PCIE_DISABLE_ERRORS(ctrl_p->hc_dip);
1318 	ret = pcie_hp_probe(slot_p);
1319 
1320 	if (ret != DDI_SUCCESS) {
1321 		PCIE_DBG("pciehpc_slot_probe() failed\n");
1322 
1323 		/* turn the ATTN led ON for configure failure */
1324 		pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_ON);
1325 
1326 		/* if power to the slot is still on then set Power led to ON */
1327 		if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
1328 			pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
1329 			    PCIE_HP_LED_ON);
1330 
1331 		mutex_exit(&ctrl_p->hc_mutex);
1332 		return (DDI_FAILURE);
1333 	}
1334 
1335 	PCIE_ENABLE_ERRORS(ctrl_p->hc_dip);
1336 
1337 	/* get the current state of the slot */
1338 	pciehpc_get_slot_state(slot_p);
1339 
1340 	mutex_exit(&ctrl_p->hc_mutex);
1341 	return (DDI_SUCCESS);
1342 }
1343 
1344 /*
1345  * pciehpc_slot_unprobe()
1346  *
1347  * Unprobe the slot.
1348  *
1349  * Note: This function is called by DDI HP framework at kernel context only
1350  */
1351 /*ARGSUSED*/
1352 static int
1353 pciehpc_slot_unprobe(pcie_hp_slot_t *slot_p)
1354 {
1355 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
1356 	int		ret;
1357 
1358 	mutex_enter(&ctrl_p->hc_mutex);
1359 
1360 	/* get the current state of the slot */
1361 	pciehpc_get_slot_state(slot_p);
1362 
1363 	/*
1364 	 * Unprobe a given PCIe Hotplug Connection (CN).
1365 	 */
1366 	PCIE_DISABLE_ERRORS(ctrl_p->hc_dip);
1367 	ret = pcie_hp_unprobe(slot_p);
1368 
1369 	if (ret != DDI_SUCCESS) {
1370 		PCIE_DBG("pciehpc_slot_unprobe() failed\n");
1371 
1372 		/* if power to the slot is still on then set Power led to ON */
1373 		if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
1374 			pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
1375 			    PCIE_HP_LED_ON);
1376 
1377 		PCIE_ENABLE_ERRORS(ctrl_p->hc_dip);
1378 
1379 		mutex_exit(&ctrl_p->hc_mutex);
1380 		return (DDI_FAILURE);
1381 	}
1382 
1383 	/* get the current state of the slot */
1384 	pciehpc_get_slot_state(slot_p);
1385 
1386 	mutex_exit(&ctrl_p->hc_mutex);
1387 	return (DDI_SUCCESS);
1388 }
1389 
1390 static int
1391 pciehpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
1392     ddi_hp_cn_state_t target_state)
1393 {
1394 	ddi_hp_cn_state_t curr_state;
1395 	int rv = DDI_SUCCESS;
1396 
1397 	if (target_state > DDI_HP_CN_STATE_ENABLED) {
1398 		return (DDI_EINVAL);
1399 	}
1400 
1401 	curr_state = slot_p->hs_info.cn_state;
1402 	while ((curr_state < target_state) && (rv == DDI_SUCCESS)) {
1403 
1404 		switch (curr_state) {
1405 		case DDI_HP_CN_STATE_EMPTY:
1406 			/*
1407 			 * From EMPTY to PRESENT, just check the hardware
1408 			 * slot state.
1409 			 */
1410 			pciehpc_get_slot_state(slot_p);
1411 			curr_state = slot_p->hs_info.cn_state;
1412 			if (curr_state < DDI_HP_CN_STATE_PRESENT)
1413 				rv = DDI_FAILURE;
1414 			break;
1415 		case DDI_HP_CN_STATE_PRESENT:
1416 			rv = (slot_p->hs_ctrl->hc_ops.poweron_hpc_slot)(slot_p,
1417 			    &curr_state);
1418 
1419 			break;
1420 		case DDI_HP_CN_STATE_POWERED:
1421 			curr_state = slot_p->hs_info.cn_state =
1422 			    DDI_HP_CN_STATE_ENABLED;
1423 			break;
1424 		default:
1425 			/* should never reach here */
1426 			ASSERT("unknown devinfo state");
1427 		}
1428 	}
1429 
1430 	return (rv);
1431 }
1432 
1433 static int
1434 pciehpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
1435     ddi_hp_cn_state_t target_state)
1436 {
1437 	ddi_hp_cn_state_t curr_state;
1438 	int rv = DDI_SUCCESS;
1439 
1440 
1441 	curr_state = slot_p->hs_info.cn_state;
1442 	while ((curr_state > target_state) && (rv == DDI_SUCCESS)) {
1443 
1444 		switch (curr_state) {
1445 		case DDI_HP_CN_STATE_PRESENT:
1446 			/*
1447 			 * From PRESENT to EMPTY, just check hardware slot
1448 			 * state.
1449 			 */
1450 			pciehpc_get_slot_state(slot_p);
1451 			curr_state = slot_p->hs_info.cn_state;
1452 			if (curr_state >= DDI_HP_CN_STATE_PRESENT)
1453 				rv = DDI_FAILURE;
1454 			break;
1455 		case DDI_HP_CN_STATE_POWERED:
1456 			rv = (slot_p->hs_ctrl->hc_ops.poweroff_hpc_slot)(
1457 			    slot_p, &curr_state);
1458 
1459 			break;
1460 		case DDI_HP_CN_STATE_ENABLED:
1461 			curr_state = slot_p->hs_info.cn_state =
1462 			    DDI_HP_CN_STATE_POWERED;
1463 
1464 			break;
1465 		default:
1466 			/* should never reach here */
1467 			ASSERT("unknown devinfo state");
1468 		}
1469 	}
1470 
1471 	return (rv);
1472 }
1473 
1474 /* Change slot state to a target state */
1475 static int
1476 pciehpc_change_slot_state(pcie_hp_slot_t *slot_p,
1477     ddi_hp_cn_state_t target_state)
1478 {
1479 	ddi_hp_cn_state_t curr_state;
1480 	int rv;
1481 
1482 	pciehpc_get_slot_state(slot_p);
1483 	curr_state = slot_p->hs_info.cn_state;
1484 
1485 	if (curr_state == target_state) {
1486 		return (DDI_SUCCESS);
1487 	}
1488 	if (curr_state < target_state) {
1489 
1490 		rv = pciehpc_upgrade_slot_state(slot_p, target_state);
1491 	} else {
1492 		rv = pciehpc_downgrade_slot_state(slot_p, target_state);
1493 	}
1494 
1495 	return (rv);
1496 }
1497 
1498 int
1499 pciehpc_slot_get_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
1500     ddi_hp_property_t *rval)
1501 {
1502 	ddi_hp_property_t request, result;
1503 #ifdef _SYSCALL32_IMPL
1504 	ddi_hp_property32_t request32, result32;
1505 #endif
1506 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
1507 	nvlist_t	*prop_list;
1508 	nvlist_t	*prop_rlist; /* nvlist for return values */
1509 	nvpair_t	*prop_pair;
1510 	char		*name, *value;
1511 	int		ret = DDI_SUCCESS;
1512 	int		i, n;
1513 	boolean_t	get_all_prop = B_FALSE;
1514 
1515 	if (get_udatamodel() == DATAMODEL_NATIVE) {
1516 		if (copyin(arg, &request, sizeof (ddi_hp_property_t)) ||
1517 		    copyin(rval, &result, sizeof (ddi_hp_property_t)))
1518 			return (DDI_FAILURE);
1519 	}
1520 #ifdef _SYSCALL32_IMPL
1521 	else {
1522 		bzero(&request, sizeof (request));
1523 		bzero(&result, sizeof (result));
1524 		if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)) ||
1525 		    copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
1526 			return (DDI_FAILURE);
1527 		request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
1528 		request.buf_size = request32.buf_size;
1529 		result.nvlist_buf = (char *)(uintptr_t)result32.nvlist_buf;
1530 		result.buf_size = result32.buf_size;
1531 	}
1532 #endif
1533 
1534 	if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
1535 	    &prop_list)) != DDI_SUCCESS)
1536 		return (ret);
1537 
1538 	if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
1539 		ret = DDI_ENOMEM;
1540 		goto get_prop_cleanup;
1541 	}
1542 
1543 	/* check whether the requested property is "all" or "help" */
1544 	prop_pair = nvlist_next_nvpair(prop_list, NULL);
1545 	if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair)) {
1546 		name = nvpair_name(prop_pair);
1547 		n = sizeof (pciehpc_props) / sizeof (pciehpc_prop_t);
1548 
1549 		if (strcmp(name, PCIEHPC_PROP_ALL) == 0) {
1550 			(void) nvlist_remove_all(prop_list, PCIEHPC_PROP_ALL);
1551 
1552 			/*
1553 			 * Add all properties into the request list, so that we
1554 			 * will get the values in the following for loop.
1555 			 */
1556 			for (i = 0; i < n; i++) {
1557 				if (nvlist_add_string(prop_list,
1558 				    pciehpc_props[i].prop_name, "") != 0) {
1559 					ret = DDI_FAILURE;
1560 					goto get_prop_cleanup1;
1561 				}
1562 			}
1563 			get_all_prop = B_TRUE;
1564 		} else if (strcmp(name, PCIEHPC_PROP_HELP) == 0) {
1565 			/*
1566 			 * Empty the request list, and add help strings into the
1567 			 * return list. We will pass the following for loop.
1568 			 */
1569 			(void) nvlist_remove_all(prop_list, PCIEHPC_PROP_HELP);
1570 
1571 			for (i = 0; i < n; i++) {
1572 				if (nvlist_add_string(prop_rlist,
1573 				    pciehpc_props[i].prop_name,
1574 				    pciehpc_props[i].prop_value) != 0) {
1575 					ret = DDI_FAILURE;
1576 					goto get_prop_cleanup1;
1577 				}
1578 			}
1579 		}
1580 	}
1581 
1582 	mutex_enter(&ctrl_p->hc_mutex);
1583 
1584 	/* get the current slot state */
1585 	pciehpc_get_slot_state(slot_p);
1586 
1587 	/* for each requested property, get the value and add it to nvlist */
1588 	prop_pair = NULL;
1589 	while ((prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) != NULL) {
1590 		name = nvpair_name(prop_pair);
1591 		value = NULL;
1592 
1593 		if (strcmp(name, PCIEHPC_PROP_LED_FAULT) == 0) {
1594 			value = pcie_led_state_text(
1595 			    slot_p->hs_fault_led_state);
1596 		} else if (strcmp(name, PCIEHPC_PROP_LED_POWER) == 0) {
1597 			value = pcie_led_state_text(
1598 			    slot_p->hs_power_led_state);
1599 		} else if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
1600 			value = pcie_led_state_text(
1601 			    slot_p->hs_attn_led_state);
1602 		} else if (strcmp(name, PCIEHPC_PROP_LED_ACTIVE) == 0) {
1603 			value = pcie_led_state_text(
1604 			    slot_p->hs_active_led_state);
1605 		} else if (strcmp(name, PCIEHPC_PROP_CARD_TYPE) == 0) {
1606 			ddi_acc_handle_t handle;
1607 			dev_info_t	*cdip;
1608 			uint8_t		prog_class, base_class, sub_class;
1609 			int		i;
1610 
1611 			mutex_exit(&ctrl_p->hc_mutex);
1612 			cdip = pcie_hp_devi_find(
1613 			    ctrl_p->hc_dip, slot_p->hs_device_num, 0);
1614 			mutex_enter(&ctrl_p->hc_mutex);
1615 
1616 			if ((slot_p->hs_info.cn_state
1617 			    != DDI_HP_CN_STATE_ENABLED) || (cdip == NULL)) {
1618 				/*
1619 				 * When getting all properties, just ignore the
1620 				 * one that's not available under certain state.
1621 				 */
1622 				if (get_all_prop)
1623 					continue;
1624 
1625 				ret = DDI_ENOTSUP;
1626 				goto get_prop_cleanup2;
1627 			}
1628 
1629 			if (pci_config_setup(cdip, &handle) != DDI_SUCCESS) {
1630 				ret = DDI_FAILURE;
1631 				goto get_prop_cleanup2;
1632 			}
1633 
1634 			prog_class = pci_config_get8(handle,
1635 			    PCI_CONF_PROGCLASS);
1636 			base_class = pci_config_get8(handle, PCI_CONF_BASCLASS);
1637 			sub_class = pci_config_get8(handle, PCI_CONF_SUBCLASS);
1638 			pci_config_teardown(&handle);
1639 
1640 			for (i = 0; i < class_pci_items; i++) {
1641 				if ((base_class == class_pci[i].base_class) &&
1642 				    (sub_class == class_pci[i].sub_class) &&
1643 				    (prog_class == class_pci[i].prog_class)) {
1644 					value = class_pci[i].short_desc;
1645 					break;
1646 				}
1647 			}
1648 			if (i == class_pci_items)
1649 				value = PCIEHPC_PROP_VALUE_UNKNOWN;
1650 		} else if (strcmp(name, PCIEHPC_PROP_BOARD_TYPE) == 0) {
1651 			if (slot_p->hs_info.cn_state <= DDI_HP_CN_STATE_EMPTY)
1652 				value = PCIEHPC_PROP_VALUE_UNKNOWN;
1653 			else
1654 				value = PCIEHPC_PROP_VALUE_PCIHOTPLUG;
1655 		} else if (strcmp(name, PCIEHPC_PROP_SLOT_CONDITION) == 0) {
1656 			value = pcie_slot_condition_text(slot_p->hs_condition);
1657 		} else {
1658 			/* unsupported property */
1659 			PCIE_DBG("Unsupported property: %s\n", name);
1660 
1661 			ret = DDI_ENOTSUP;
1662 			goto get_prop_cleanup2;
1663 		}
1664 		if (nvlist_add_string(prop_rlist, name, value) != 0) {
1665 			ret = DDI_FAILURE;
1666 			goto get_prop_cleanup2;
1667 		}
1668 	}
1669 
1670 	/* pack nvlist and copyout */
1671 	if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
1672 	    &result.buf_size)) != DDI_SUCCESS) {
1673 		goto get_prop_cleanup2;
1674 	}
1675 	if (get_udatamodel() == DATAMODEL_NATIVE) {
1676 		if (copyout(&result, rval, sizeof (ddi_hp_property_t)))
1677 			ret = DDI_FAILURE;
1678 	}
1679 #ifdef _SYSCALL32_IMPL
1680 	else {
1681 		if (result.buf_size > UINT32_MAX) {
1682 			ret = DDI_FAILURE;
1683 		} else {
1684 			result32.buf_size = (uint32_t)result.buf_size;
1685 			if (copyout(&result32, rval,
1686 			    sizeof (ddi_hp_property32_t)))
1687 				ret = DDI_FAILURE;
1688 		}
1689 	}
1690 #endif
1691 
1692 get_prop_cleanup2:
1693 	mutex_exit(&ctrl_p->hc_mutex);
1694 get_prop_cleanup1:
1695 	nvlist_free(prop_rlist);
1696 get_prop_cleanup:
1697 	nvlist_free(prop_list);
1698 	return (ret);
1699 }
1700 
1701 int
1702 pciehpc_slot_set_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
1703     ddi_hp_property_t *rval)
1704 {
1705 	ddi_hp_property_t	request, result;
1706 #ifdef _SYSCALL32_IMPL
1707 	ddi_hp_property32_t	request32, result32;
1708 #endif
1709 	pcie_hp_ctrl_t		*ctrl_p = slot_p->hs_ctrl;
1710 	nvlist_t		*prop_list;
1711 	nvlist_t		*prop_rlist;
1712 	nvpair_t		*prop_pair;
1713 	char			*name, *value;
1714 	pcie_hp_led_state_t	led_state;
1715 	int			ret = DDI_SUCCESS;
1716 
1717 	if (get_udatamodel() == DATAMODEL_NATIVE) {
1718 		if (copyin(arg, &request, sizeof (ddi_hp_property_t)))
1719 			return (DDI_FAILURE);
1720 		if (rval &&
1721 		    copyin(rval, &result, sizeof (ddi_hp_property_t)))
1722 			return (DDI_FAILURE);
1723 	}
1724 #ifdef _SYSCALL32_IMPL
1725 	else {
1726 		bzero(&request, sizeof (request));
1727 		bzero(&result, sizeof (result));
1728 		if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)))
1729 			return (DDI_FAILURE);
1730 		if (rval &&
1731 		    copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
1732 			return (DDI_FAILURE);
1733 		request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
1734 		request.buf_size = request32.buf_size;
1735 		if (rval) {
1736 			result.nvlist_buf =
1737 			    (char *)(uintptr_t)result32.nvlist_buf;
1738 			result.buf_size = result32.buf_size;
1739 		}
1740 	}
1741 #endif
1742 
1743 	if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
1744 	    &prop_list)) != DDI_SUCCESS)
1745 		return (ret);
1746 
1747 	/* check whether the requested property is "help" */
1748 	prop_pair = nvlist_next_nvpair(prop_list, NULL);
1749 	if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair) &&
1750 	    (strcmp(nvpair_name(prop_pair), PCIEHPC_PROP_HELP) == 0)) {
1751 		if (!rval) {
1752 			ret = DDI_ENOTSUP;
1753 			goto set_prop_cleanup;
1754 		}
1755 
1756 		if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
1757 			ret = DDI_ENOMEM;
1758 			goto set_prop_cleanup;
1759 		}
1760 		if (nvlist_add_string(prop_rlist, PCIEHPC_PROP_LED_ATTN,
1761 		    PCIEHPC_PROP_VALUE_LED) != 0) {
1762 			ret = DDI_FAILURE;
1763 			goto set_prop_cleanup1;
1764 		}
1765 
1766 		if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
1767 		    &result.buf_size)) != DDI_SUCCESS) {
1768 			goto set_prop_cleanup1;
1769 		}
1770 		if (get_udatamodel() == DATAMODEL_NATIVE) {
1771 			if (copyout(&result, rval,
1772 			    sizeof (ddi_hp_property_t))) {
1773 				ret =  DDI_FAILURE;
1774 				goto set_prop_cleanup1;
1775 			}
1776 		}
1777 #ifdef _SYSCALL32_IMPL
1778 		else {
1779 			if (result.buf_size > UINT32_MAX) {
1780 				ret =  DDI_FAILURE;
1781 				goto set_prop_cleanup1;
1782 			} else {
1783 				result32.buf_size = (uint32_t)result.buf_size;
1784 				if (copyout(&result32, rval,
1785 				    sizeof (ddi_hp_property32_t))) {
1786 					ret =  DDI_FAILURE;
1787 					goto set_prop_cleanup1;
1788 				}
1789 			}
1790 		}
1791 #endif
1792 set_prop_cleanup1:
1793 		nvlist_free(prop_rlist);
1794 		nvlist_free(prop_list);
1795 		return (ret);
1796 	}
1797 
1798 	/* Validate the request */
1799 	prop_pair = NULL;
1800 	while ((prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) != NULL) {
1801 		name = nvpair_name(prop_pair);
1802 		if (nvpair_type(prop_pair) != DATA_TYPE_STRING) {
1803 			PCIE_DBG("Unexpected data type of setting "
1804 			    "property %s.\n", name);
1805 			ret = DDI_EINVAL;
1806 			goto set_prop_cleanup;
1807 		}
1808 		if (nvpair_value_string(prop_pair, &value)) {
1809 			PCIE_DBG("Get string value failed for property %s.\n",
1810 			    name);
1811 			ret = DDI_FAILURE;
1812 			goto set_prop_cleanup;
1813 		}
1814 
1815 		if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
1816 			if ((strcmp(value, PCIEHPC_PROP_VALUE_ON) != 0) &&
1817 			    (strcmp(value, PCIEHPC_PROP_VALUE_OFF) != 0) &&
1818 			    (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) != 0)) {
1819 				PCIE_DBG("Unsupported value of setting "
1820 				    "property %s\n", name);
1821 				ret = DDI_ENOTSUP;
1822 				goto set_prop_cleanup;
1823 			}
1824 		} else {
1825 			PCIE_DBG("Unsupported property: %s\n", name);
1826 			ret = DDI_ENOTSUP;
1827 			goto set_prop_cleanup;
1828 		}
1829 	}
1830 	mutex_enter(&ctrl_p->hc_mutex);
1831 
1832 	/* get the current slot state */
1833 	pciehpc_get_slot_state(slot_p);
1834 
1835 	/* set each property */
1836 	prop_pair = NULL;
1837 	while ((prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) != NULL) {
1838 		name = nvpair_name(prop_pair);
1839 
1840 		/*
1841 		 * The validity of the property was checked above.
1842 		 */
1843 		if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
1844 			if (strcmp(value, PCIEHPC_PROP_VALUE_ON) == 0)
1845 				led_state = PCIE_HP_LED_ON;
1846 			else if (strcmp(value, PCIEHPC_PROP_VALUE_OFF) == 0)
1847 				led_state = PCIE_HP_LED_OFF;
1848 			else if (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) == 0)
1849 				led_state = PCIE_HP_LED_BLINK;
1850 			else
1851 				continue;
1852 
1853 			pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED,
1854 			    led_state);
1855 		}
1856 	}
1857 	if (rval) {
1858 		if (get_udatamodel() == DATAMODEL_NATIVE) {
1859 			result.buf_size = 0;
1860 			if (copyout(&result, rval, sizeof (ddi_hp_property_t)))
1861 				ret =  DDI_FAILURE;
1862 		}
1863 #ifdef _SYSCALL32_IMPL
1864 		else {
1865 			result32.buf_size = 0;
1866 			if (copyout(&result32, rval,
1867 			    sizeof (ddi_hp_property32_t)))
1868 				ret =  DDI_FAILURE;
1869 		}
1870 #endif
1871 	}
1872 
1873 	mutex_exit(&ctrl_p->hc_mutex);
1874 set_prop_cleanup:
1875 	nvlist_free(prop_list);
1876 	return (ret);
1877 }
1878 
1879 /*
1880  * Send a command to the PCI-E Hot Plug Controller.
1881  *
1882  * NOTES: The PCI-E spec defines the following semantics for issuing hot plug
1883  * commands.
1884  * 1) If Command Complete events/interrupts are supported then software
1885  *    waits for Command Complete event after issuing a command (i.e writing
1886  *    to the Slot Control register). The command completion could take as
1887  *    long as 1 second so software should be prepared to wait for 1 second
1888  *    before issuing another command.
1889  *
1890  * 2) If Command Complete events/interrupts are not supported then
1891  *    software could issue multiple Slot Control writes without any delay
1892  *    between writes.
1893  */
1894 static void
1895 pciehpc_issue_hpc_command(pcie_hp_ctrl_t *ctrl_p, uint16_t control)
1896 {
1897 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
1898 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1899 	uint16_t	status;
1900 	uint32_t	slot_cap;
1901 
1902 	/*
1903 	 * PCI-E version 1.1 spec defines No Command Completed
1904 	 * Support bit (bit#18) in Slot Capabilities register. If this
1905 	 * bit is set then slot doesn't support notification of command
1906 	 * completion events.
1907 	 */
1908 	slot_cap =  pciehpc_reg_get32(ctrl_p,
1909 	    bus_p->bus_pcie_off + PCIE_SLOTCAP);
1910 
1911 	/*
1912 	 * If no Command Completion event is supported or it is ACPI
1913 	 * hot plug mode then just issue the command and return.
1914 	 */
1915 	if ((slot_cap & PCIE_SLOTCAP_NO_CMD_COMP_SUPP) ||
1916 	    (bus_p->bus_hp_curr_mode == PCIE_ACPI_HP_MODE)) {
1917 		pciehpc_reg_put16(ctrl_p,
1918 		    bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
1919 		return;
1920 	}
1921 
1922 	/*
1923 	 * **************************************
1924 	 * Command Complete events are supported.
1925 	 * **************************************
1926 	 */
1927 
1928 	/*
1929 	 * If HPC is not yet initialized then just poll for the Command
1930 	 * Completion interrupt.
1931 	 */
1932 	if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
1933 		int retry = PCIE_HP_CMD_WAIT_RETRY;
1934 
1935 		/* write the command to the HPC */
1936 		pciehpc_reg_put16(ctrl_p,
1937 		    bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
1938 
1939 		/* poll for status completion */
1940 		while (retry--) {
1941 			/* wait for 10 msec before checking the status */
1942 			delay(drv_usectohz(PCIE_HP_CMD_WAIT_TIME));
1943 
1944 			status = pciehpc_reg_get16(ctrl_p,
1945 			    bus_p->bus_pcie_off + PCIE_SLOTSTS);
1946 
1947 			if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
1948 				/* clear the status bits */
1949 				pciehpc_reg_put16(ctrl_p,
1950 				    bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
1951 				break;
1952 			}
1953 		}
1954 		return;
1955 	}
1956 
1957 	/* HPC is already initialized */
1958 
1959 	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
1960 
1961 	/*
1962 	 * If previous command is still pending then wait for its
1963 	 * completion. i.e cv_wait()
1964 	 */
1965 
1966 	while (ctrl_p->hc_cmd_pending == B_TRUE)
1967 		cv_wait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex);
1968 
1969 	/*
1970 	 * Issue the command and wait for Command Completion or
1971 	 * the 1 sec timeout.
1972 	 */
1973 	pciehpc_reg_put16(ctrl_p,
1974 	    bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
1975 
1976 	ctrl_p->hc_cmd_pending = B_TRUE;
1977 
1978 	if (cv_timedwait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex,
1979 	    ddi_get_lbolt() + SEC_TO_TICK(1)) == -1) {
1980 
1981 		/* it is a timeout */
1982 		PCIE_DBG("pciehpc_issue_hpc_command: Command Complete"
1983 		    " interrupt is not received for slot %d\n",
1984 		    slot_p->hs_phy_slot_num);
1985 
1986 		/* clear the status info in case interrupts are disabled? */
1987 		status = pciehpc_reg_get16(ctrl_p,
1988 		    bus_p->bus_pcie_off + PCIE_SLOTSTS);
1989 
1990 		if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
1991 			/* clear the status bits */
1992 			pciehpc_reg_put16(ctrl_p,
1993 			    bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
1994 		}
1995 	}
1996 
1997 	ctrl_p->hc_cmd_pending = B_FALSE;
1998 
1999 	/* wake up any one waiting for issuing another command to HPC */
2000 	cv_signal(&ctrl_p->hc_cmd_comp_cv);
2001 }
2002 
2003 /*
2004  * pciehcp_attn_btn_handler()
2005  *
2006  * This handles ATTN button pressed event as per the PCI-E 1.1 spec.
2007  */
2008 static void
2009 pciehpc_attn_btn_handler(pcie_hp_ctrl_t *ctrl_p)
2010 {
2011 	pcie_hp_slot_t		*slot_p = ctrl_p->hc_slots[0];
2012 	pcie_hp_led_state_t	power_led_state;
2013 	callb_cpr_t		cprinfo;
2014 
2015 	PCIE_DBG("pciehpc_attn_btn_handler: thread started\n");
2016 
2017 	CALLB_CPR_INIT(&cprinfo, &ctrl_p->hc_mutex, callb_generic_cpr,
2018 	    "pciehpc_attn_btn_handler");
2019 
2020 	mutex_enter(&ctrl_p->hc_mutex);
2021 
2022 	/* wait for ATTN button event */
2023 	cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
2024 
2025 	while (slot_p->hs_attn_btn_thread_exit == B_FALSE) {
2026 		if (slot_p->hs_attn_btn_pending == B_TRUE) {
2027 			/* get the current state of power LED */
2028 			power_led_state = pciehpc_get_led_state(ctrl_p,
2029 			    PCIE_HP_POWER_LED);
2030 
2031 			/* Blink the Power LED while we wait for 5 seconds */
2032 			pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
2033 			    PCIE_HP_LED_BLINK);
2034 
2035 			/* wait for 5 seconds before taking any action */
2036 			if (cv_timedwait(&slot_p->hs_attn_btn_cv,
2037 			    &ctrl_p->hc_mutex,
2038 			    ddi_get_lbolt() + SEC_TO_TICK(5)) == -1) {
2039 				/*
2040 				 * It is a time out; make sure the ATTN pending
2041 				 * flag is still ON before sending the event to
2042 				 * DDI HP framework.
2043 				 */
2044 				if (slot_p->hs_attn_btn_pending == B_TRUE) {
2045 					int hint;
2046 
2047 					slot_p->hs_attn_btn_pending = B_FALSE;
2048 					pciehpc_get_slot_state(slot_p);
2049 
2050 					if (slot_p->hs_info.cn_state <=
2051 					    DDI_HP_CN_STATE_PRESENT) {
2052 						/*
2053 						 * Insertion.
2054 						 */
2055 						hint = SE_INCOMING_RES;
2056 					} else {
2057 						/*
2058 						 * Want to remove;
2059 						 */
2060 						hint = SE_OUTGOING_RES;
2061 					}
2062 
2063 					/*
2064 					 * We can't call ddihp_cn_gen_sysevent
2065 					 * here since it's not a DDI interface.
2066 					 */
2067 					pcie_hp_gen_sysevent_req(
2068 					    slot_p->hs_info.cn_name,
2069 					    hint,
2070 					    ctrl_p->hc_dip,
2071 					    KM_SLEEP);
2072 				}
2073 			}
2074 
2075 			/* restore the power LED state */
2076 			pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
2077 			    power_led_state);
2078 			continue;
2079 		}
2080 
2081 		/* wait for another ATTN button event */
2082 		cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
2083 	}
2084 
2085 	PCIE_DBG("pciehpc_attn_btn_handler: thread exit\n");
2086 	cv_signal(&slot_p->hs_attn_btn_cv);
2087 	CALLB_CPR_EXIT(&cprinfo);
2088 	thread_exit();
2089 }
2090 
2091 /*
2092  * convert LED state from PCIE HPC definition to pcie_hp_led_state_t
2093  * definition.
2094  */
2095 static pcie_hp_led_state_t
2096 pciehpc_led_state_to_hpc(uint16_t state)
2097 {
2098 	switch (state) {
2099 	case PCIE_SLOTCTL_INDICATOR_STATE_ON:
2100 		return (PCIE_HP_LED_ON);
2101 	case PCIE_SLOTCTL_INDICATOR_STATE_BLINK:
2102 		return (PCIE_HP_LED_BLINK);
2103 	case PCIE_SLOTCTL_INDICATOR_STATE_OFF:
2104 	default:
2105 		return (PCIE_HP_LED_OFF);
2106 	}
2107 }
2108 
2109 /*
2110  * Get the state of an LED.
2111  */
2112 static pcie_hp_led_state_t
2113 pciehpc_get_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led)
2114 {
2115 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
2116 	uint16_t	control, state;
2117 
2118 	/* get the current state of Slot Control register */
2119 	control =  pciehpc_reg_get16(ctrl_p,
2120 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
2121 
2122 	switch (led) {
2123 	case PCIE_HP_POWER_LED:
2124 		state = pcie_slotctl_pwr_indicator_get(control);
2125 		break;
2126 	case PCIE_HP_ATTN_LED:
2127 		state = pcie_slotctl_attn_indicator_get(control);
2128 		break;
2129 	default:
2130 		PCIE_DBG("pciehpc_get_led_state() invalid LED %d\n", led);
2131 		return (PCIE_HP_LED_OFF);
2132 	}
2133 
2134 	switch (state) {
2135 	case PCIE_SLOTCTL_INDICATOR_STATE_ON:
2136 		return (PCIE_HP_LED_ON);
2137 
2138 	case PCIE_SLOTCTL_INDICATOR_STATE_BLINK:
2139 		return (PCIE_HP_LED_BLINK);
2140 
2141 	case PCIE_SLOTCTL_INDICATOR_STATE_OFF:
2142 	default:
2143 		return (PCIE_HP_LED_OFF);
2144 	}
2145 }
2146 
2147 /*
2148  * Set the state of an LED. It updates both hw and sw state.
2149  */
2150 static void
2151 pciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led,
2152     pcie_hp_led_state_t state)
2153 {
2154 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
2155 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
2156 	uint16_t	control;
2157 
2158 	/* get the current state of Slot Control register */
2159 	control =  pciehpc_reg_get16(ctrl_p,
2160 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
2161 
2162 	switch (led) {
2163 	case PCIE_HP_POWER_LED:
2164 		/* clear led mask */
2165 		control &= ~PCIE_SLOTCTL_PWR_INDICATOR_MASK;
2166 		slot_p->hs_power_led_state = state;
2167 		break;
2168 	case PCIE_HP_ATTN_LED:
2169 		/* clear led mask */
2170 		control &= ~PCIE_SLOTCTL_ATTN_INDICATOR_MASK;
2171 		slot_p->hs_attn_led_state = state;
2172 		break;
2173 	default:
2174 		PCIE_DBG("pciehpc_set_led_state() invalid LED %d\n", led);
2175 		return;
2176 	}
2177 
2178 	switch (state) {
2179 	case PCIE_HP_LED_ON:
2180 		if (led == PCIE_HP_POWER_LED)
2181 			control = pcie_slotctl_pwr_indicator_set(control,
2182 			    PCIE_SLOTCTL_INDICATOR_STATE_ON);
2183 		else if (led == PCIE_HP_ATTN_LED)
2184 			control = pcie_slotctl_attn_indicator_set(control,
2185 			    PCIE_SLOTCTL_INDICATOR_STATE_ON);
2186 		break;
2187 	case PCIE_HP_LED_OFF:
2188 		if (led == PCIE_HP_POWER_LED)
2189 			control = pcie_slotctl_pwr_indicator_set(control,
2190 			    PCIE_SLOTCTL_INDICATOR_STATE_OFF);
2191 		else if (led == PCIE_HP_ATTN_LED)
2192 			control = pcie_slotctl_attn_indicator_set(control,
2193 			    PCIE_SLOTCTL_INDICATOR_STATE_OFF);
2194 		break;
2195 	case PCIE_HP_LED_BLINK:
2196 		if (led == PCIE_HP_POWER_LED)
2197 			control = pcie_slotctl_pwr_indicator_set(control,
2198 			    PCIE_SLOTCTL_INDICATOR_STATE_BLINK);
2199 		else if (led == PCIE_HP_ATTN_LED)
2200 			control = pcie_slotctl_attn_indicator_set(control,
2201 			    PCIE_SLOTCTL_INDICATOR_STATE_BLINK);
2202 		break;
2203 
2204 	default:
2205 		PCIE_DBG("pciehpc_set_led_state() invalid LED state %d\n",
2206 		    state);
2207 		return;
2208 	}
2209 
2210 	/* update the Slot Control Register */
2211 	pciehpc_issue_hpc_command(ctrl_p, control);
2212 
2213 #ifdef DEBUG
2214 	/* get the current state of Slot Control register */
2215 	control =  pciehpc_reg_get16(ctrl_p,
2216 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
2217 
2218 	PCIE_DBG("pciehpc_set_led_state: slot %d power-led %s attn-led %s\n",
2219 	    slot_p->hs_phy_slot_num, pcie_led_state_text(
2220 	    pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control))),
2221 	    pcie_led_state_text(pciehpc_led_state_to_hpc(
2222 	    pcie_slotctl_attn_indicator_get(control))));
2223 #endif
2224 }
2225 
2226 static void
2227 pciehpc_handle_power_fault(dev_info_t *dip)
2228 {
2229 	/*
2230 	 * Hold the parent's ref so that it won't disappear when the taskq is
2231 	 * scheduled to run.
2232 	 */
2233 	ndi_hold_devi(dip);
2234 
2235 	if (taskq_dispatch(system_taskq, pciehpc_power_fault_handler, dip,
2236 	    TQ_NOSLEEP) == TASKQID_INVALID) {
2237 		ndi_rele_devi(dip);
2238 		PCIE_DBG("pciehpc_intr(): "
2239 		    "Failed to dispatch power fault handler, dip %p\n", dip);
2240 	}
2241 }
2242 
2243 static void
2244 pciehpc_power_fault_handler(void *arg)
2245 {
2246 	dev_info_t *dip = (dev_info_t *)arg;
2247 	pcie_hp_ctrl_t  *ctrl_p;
2248 	pcie_hp_slot_t  *slot_p;
2249 
2250 	/* get the soft state structure for this dip */
2251 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) {
2252 		ndi_rele_devi(dip);
2253 		return;
2254 	}
2255 	slot_p = ctrl_p->hc_slots[0];
2256 
2257 	/*
2258 	 * Send the event to DDI Hotplug framework, power off
2259 	 * the slot
2260 	 */
2261 	(void) ndi_hp_state_change_req(dip,
2262 	    slot_p->hs_info.cn_name,
2263 	    DDI_HP_CN_STATE_EMPTY, DDI_HP_REQ_SYNC);
2264 
2265 	mutex_enter(&ctrl_p->hc_mutex);
2266 	pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED,
2267 	    PCIE_HP_LED_ON);
2268 	mutex_exit(&ctrl_p->hc_mutex);
2269 	ndi_rele_devi(dip);
2270 }
2271 
2272 #ifdef DEBUG
2273 /*
2274  * Dump PCI-E Hot Plug registers.
2275  */
2276 static void
2277 pciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p)
2278 {
2279 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
2280 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
2281 	uint16_t	control;
2282 	uint32_t	capabilities;
2283 
2284 	if (!pcie_debug_flags)
2285 		return;
2286 
2287 	capabilities = pciehpc_reg_get32(ctrl_p,
2288 	    bus_p->bus_pcie_off + PCIE_SLOTCAP);
2289 
2290 	control =  pciehpc_reg_get16(ctrl_p,
2291 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
2292 
2293 	PCIE_DBG("pciehpc_dump_hpregs: Found PCI-E hot plug slot %d\n",
2294 	    slot_p->hs_phy_slot_num);
2295 
2296 	PCIE_DBG("Attention Button Present = %s\n",
2297 	    capabilities & PCIE_SLOTCAP_ATTN_BUTTON ? "Yes":"No");
2298 
2299 	PCIE_DBG("Power controller Present = %s\n",
2300 	    capabilities & PCIE_SLOTCAP_POWER_CONTROLLER ? "Yes":"No");
2301 
2302 	PCIE_DBG("MRL Sensor Present	   = %s\n",
2303 	    capabilities & PCIE_SLOTCAP_MRL_SENSOR ? "Yes":"No");
2304 
2305 	PCIE_DBG("Attn Indicator Present   = %s\n",
2306 	    capabilities & PCIE_SLOTCAP_ATTN_INDICATOR ? "Yes":"No");
2307 
2308 	PCIE_DBG("Power Indicator Present  = %s\n",
2309 	    capabilities & PCIE_SLOTCAP_PWR_INDICATOR ? "Yes":"No");
2310 
2311 	PCIE_DBG("HotPlug Surprise	   = %s\n",
2312 	    capabilities & PCIE_SLOTCAP_HP_SURPRISE ? "Yes":"No");
2313 
2314 	PCIE_DBG("HotPlug Capable	   = %s\n",
2315 	    capabilities & PCIE_SLOTCAP_HP_CAPABLE ? "Yes":"No");
2316 
2317 	PCIE_DBG("Physical Slot Number	   = %d\n",
2318 	    PCIE_SLOTCAP_PHY_SLOT_NUM(capabilities));
2319 
2320 	PCIE_DBG("Attn Button interrupt Enabled  = %s\n",
2321 	    control & PCIE_SLOTCTL_ATTN_BTN_EN ? "Yes":"No");
2322 
2323 	PCIE_DBG("Power Fault interrupt Enabled  = %s\n",
2324 	    control & PCIE_SLOTCTL_PWR_FAULT_EN ? "Yes":"No");
2325 
2326 	PCIE_DBG("MRL Sensor INTR Enabled   = %s\n",
2327 	    control & PCIE_SLOTCTL_MRL_SENSOR_EN ? "Yes":"No");
2328 
2329 	PCIE_DBG("Presence interrupt Enabled	 = %s\n",
2330 	    control & PCIE_SLOTCTL_PRESENCE_CHANGE_EN ? "Yes":"No");
2331 
2332 	PCIE_DBG("Cmd Complete interrupt Enabled = %s\n",
2333 	    control & PCIE_SLOTCTL_CMD_INTR_EN ? "Yes":"No");
2334 
2335 	PCIE_DBG("HotPlug interrupt Enabled	 = %s\n",
2336 	    control & PCIE_SLOTCTL_HP_INTR_EN ? "Yes":"No");
2337 
2338 	PCIE_DBG("Power Indicator LED = %s", pcie_led_state_text(
2339 	    pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control))));
2340 
2341 	PCIE_DBG("Attn Indicator LED = %s\n",
2342 	    pcie_led_state_text(pciehpc_led_state_to_hpc(
2343 	    pcie_slotctl_attn_indicator_get(control))));
2344 }
2345 #endif	/* DEBUG */
2346