xref: /illumos-gate/usr/src/uts/common/io/pciex/hotplug/pcishpc.c (revision 89b2a9fbeabf42fa54594df0e5927bcc50a07cc9)
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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * This file contains PCI HotPlug functionality that is compatible with the
28  * PCI SHPC specification 1.x.
29  *
30  * NOTE: This file is compiled and delivered through misc/pcie module.
31  */
32 
33 #include <sys/note.h>
34 #include <sys/conf.h>
35 #include <sys/kmem.h>
36 #include <sys/kstat.h>
37 #include <sys/debug.h>
38 #include <sys/vtrace.h>
39 #include <sys/autoconf.h>
40 #include <sys/varargs.h>
41 #include <sys/hwconf.h>
42 #include <sys/ddi_impldefs.h>
43 #include <sys/callb.h>
44 #include <sys/ddi.h>
45 #include <sys/sunddi.h>
46 #include <sys/sunndi.h>
47 #include <sys/sysevent/dr.h>
48 #include <sys/ndi_impldefs.h>
49 #include <sys/pci_impl.h>
50 #include <sys/hotplug/pci/pcie_hp.h>
51 #include <sys/hotplug/pci/pcishpc.h>
52 
53 typedef struct pcishpc_prop {
54 	char	*prop_name;
55 	char	*prop_value;
56 } pcishpc_prop_t;
57 
58 static pcishpc_prop_t	pcishpc_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 /* reset delay to 1 sec. */
69 static int pcishpc_reset_delay = 1000000;
70 
71 /* Local function prototype */
72 static pcie_hp_ctrl_t *pcishpc_create_controller(dev_info_t *dip);
73 static int	pcishpc_setup_controller(pcie_hp_ctrl_t *ctrl_p);
74 static int	pcishpc_destroy_controller(dev_info_t *dip);
75 static pcie_hp_slot_t	*pcishpc_create_slot(pcie_hp_ctrl_t *ctrl_p);
76 static int	pcishpc_register_slot(pcie_hp_ctrl_t *ctrl_p, int slot);
77 static int	pcishpc_destroy_slots(pcie_hp_ctrl_t *ctrl_p);
78 static int	pcishpc_enable_irqs(pcie_hp_ctrl_t *ctrl_p);
79 static int	pcishpc_disable_irqs(pcie_hp_ctrl_t *ctrl_p);
80 static int	pcishpc_slot_get_property(pcie_hp_slot_t *slot_p,
81 		    ddi_hp_property_t *arg, ddi_hp_property_t *rval);
82 static int	pcishpc_slot_set_property(pcie_hp_slot_t *slot_p,
83 		    ddi_hp_property_t *arg, ddi_hp_property_t *rval);
84 static int	pcishpc_issue_command(pcie_hp_ctrl_t *ctrl_p,
85 		    uint32_t cmd_code);
86 static int	pcishpc_wait_busy(pcie_hp_ctrl_t *ctrl_p);
87 static void	pcishpc_attn_btn_handler(pcie_hp_slot_t *slot_p);
88 static void	pcishpc_get_slot_state(pcie_hp_slot_t *slot_p);
89 static int	pcishpc_set_slot_state(pcie_hp_slot_t *slot_p,
90 		    ddi_hp_cn_state_t new_slot_state);
91 static void	pcishpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p, int slot);
92 static int	pcishpc_set_bus_speed(pcie_hp_slot_t *slot_p);
93 static int	pcishpc_setled(pcie_hp_slot_t *slot_p, pcie_hp_led_t led,
94 		    pcie_hp_led_state_t state);
95 static int	pcishpc_led_shpc_to_hpc(int state);
96 static int	pcishpc_led_hpc_to_shpc(int state);
97 static int	pcishpc_slot_shpc_to_hpc(int shpc_state);
98 static int	pcishpc_slot_hpc_to_shpc(int state);
99 static char	*pcishpc_slot_textslotstate(ddi_hp_cn_state_t state);
100 static char	*pcishpc_slot_textledstate(pcie_hp_led_state_t state);
101 
102 static uint32_t	pcishpc_read_reg(pcie_hp_ctrl_t *ctrl_p, int reg);
103 static void	pcishpc_write_reg(pcie_hp_ctrl_t *ctrl_p, int reg,
104 		    uint32_t data);
105 
106 static int	pcishpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
107 		    ddi_hp_cn_state_t target_state);
108 static int	pcishpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
109 		    ddi_hp_cn_state_t target_state);
110 static int	pcishpc_change_slot_state(pcie_hp_slot_t *slot_p,
111 		    ddi_hp_cn_state_t target_state);
112 
113 static int	pcishpc_slot_poweron(pcie_hp_slot_t *slot_p,
114 		    ddi_hp_cn_state_t *result_state);
115 static int	pcishpc_slot_poweroff(pcie_hp_slot_t *slot_p,
116 		    ddi_hp_cn_state_t *result_state);
117 static int	pcishpc_slot_probe(pcie_hp_slot_t *slot_p);
118 static int	pcishpc_slot_unprobe(pcie_hp_slot_t *slot_p);
119 #ifdef	DEBUG
120 static void	pcishpc_dump_regs(pcie_hp_ctrl_t *ctrl_p);
121 #endif	/* DEBUG */
122 
123 
124 /*
125  * Global functions (called by other drivers/modules)
126  */
127 
128 /*
129  * pcishpc_init()
130  *
131  * Install and configure an SHPC controller and register the HotPlug slots
132  * with the Solaris HotPlug framework. This function is usually called by
133  * a PCI bridge Nexus driver that has a built in SHPC controller.
134  */
135 int
136 pcishpc_init(dev_info_t *dip)
137 {
138 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
139 	pcie_hp_ctrl_t	*ctrl_p;
140 	int		i;
141 
142 	PCIE_DBG("pcishpc_init() called from %s#%d\n",
143 	    ddi_driver_name(dip), ddi_get_instance(dip));
144 
145 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) != NULL) {
146 		PCIE_DBG("pcishpc_init() shpc instance already "
147 		    "initialized!\n");
148 		return (DDI_SUCCESS);
149 	}
150 
151 	/* Initialize soft state structure for the SHPC instance. */
152 	ctrl_p = pcishpc_create_controller(dip);
153 
154 	if (ctrl_p == NULL) {
155 		PCIE_DBG("pcishpc_init() failed to create shpc softstate\n");
156 		return (DDI_FAILURE);
157 	}
158 
159 	if (pcishpc_setup_controller(ctrl_p) != DDI_SUCCESS) {
160 		PCIE_DBG("pcishpc_init() failed to setup controller\n");
161 		goto cleanup;
162 	}
163 
164 	/*
165 	 * Setup resource maps for this bus node.
166 	 */
167 	(void) pci_resource_setup(dip);
168 
169 #ifdef	DEBUG
170 	PCIE_DBG("%s%d: P2P bridge register dump:\n",
171 	    ddi_driver_name(dip), ddi_get_instance(dip));
172 
173 	for (i = 0; i < 0x100; i += 4) {
174 		PCIE_DBG("SHPC Cfg reg 0x%02x: %08x\n", i,
175 		    pci_config_get32(bus_p->bus_cfg_hdl, i));
176 	}
177 #endif	/* DEBUG */
178 
179 	/* Setup each HotPlug slot on this SHPC controller. */
180 	for (i = 0; i < ctrl_p->hc_num_slots_impl; i++) {
181 		if (pcishpc_register_slot(ctrl_p, i) != DDI_SUCCESS) {
182 			PCIE_DBG("pcishpc_init() failed to register "
183 			    "slot %d\n", i);
184 			goto cleanup1;
185 		}
186 		if (pcie_create_minor_node(ctrl_p, i) != DDI_SUCCESS) {
187 			PCIE_DBG("pcishpc_init() failed to create "
188 			    "minor node for slot %d\n", i);
189 			goto cleanup1;
190 		}
191 	}
192 
193 	(void) pcishpc_enable_irqs(ctrl_p);
194 
195 #ifdef	DEBUG
196 	/* Dump out the SHPC registers. */
197 	pcishpc_dump_regs(ctrl_p);
198 #endif	/* DEBUG */
199 
200 	PCIE_DBG("pcishpc_init() success(dip=%p)\n", dip);
201 	return (DDI_SUCCESS);
202 
203 cleanup1:
204 	for (i = 0; i < ctrl_p->hc_num_slots_impl; i++) {
205 		if (ctrl_p->hc_slots[i] == NULL)
206 			continue;
207 
208 		pcie_remove_minor_node(ctrl_p, i);
209 	}
210 	(void) pci_resource_destroy(dip);
211 cleanup:
212 	(void) pcishpc_destroy_controller(dip);
213 	return (DDI_FAILURE);
214 }
215 
216 /*
217  * pcishpc_uninit()
218  * Unload the HogPlug controller driver and deallocate all resources.
219  */
220 int
221 pcishpc_uninit(dev_info_t *dip)
222 {
223 	pcie_hp_ctrl_t *ctrl_p;
224 	int i;
225 
226 	PCIE_DBG("pcishpc_uninit() called(dip=%p)\n", dip);
227 
228 	ctrl_p = PCIE_GET_HP_CTRL(dip);
229 
230 	if (!ctrl_p) {
231 		PCIE_DBG("pcishpc_uninit() Unable to find softstate\n");
232 		return (DDI_FAILURE);
233 	}
234 
235 	for (i = 0; i < PCIE_HP_MAX_SLOTS; i++) {
236 		if (ctrl_p->hc_slots[i] == NULL)
237 			continue;
238 
239 		pcie_remove_minor_node(ctrl_p, i);
240 	}
241 
242 	(void) pcishpc_disable_irqs(ctrl_p);
243 	ctrl_p->hc_flags = 0;
244 
245 	/*
246 	 * Destroy resource maps for this bus node.
247 	 */
248 	(void) pci_resource_destroy(dip);
249 
250 	(void) pcishpc_destroy_controller(dip);
251 
252 	PCIE_DBG("pcishpc_uninit() success(dip=%p)\n", dip);
253 
254 	return (DDI_SUCCESS);
255 }
256 
257 /*
258  * pcishpc_intr()
259  *
260  * This is the SHPC controller interrupt handler.
261  */
262 int
263 pcishpc_intr(dev_info_t *dip)
264 {
265 	pcie_hp_ctrl_t	*ctrl_p;
266 	uint32_t	irq_locator, irq_serr_locator, reg;
267 	int		slot;
268 
269 	PCIE_DBG("pcishpc_intr() called\n");
270 
271 	/* get the soft state structure for this dip */
272 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
273 		return (DDI_INTR_UNCLAIMED);
274 
275 	mutex_enter(&ctrl_p->hc_mutex);
276 
277 	if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
278 		PCIE_DBG("pcishpc_intr() unclaimed\n");
279 		mutex_exit(&ctrl_p->hc_mutex);
280 		return (DDI_INTR_UNCLAIMED);
281 	}
282 
283 	PCIE_DBG("pcishpc_intr() interrupt received\n");
284 
285 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG);
286 
287 	if (reg & PCI_HP_SERR_INT_CMD_COMPLETE_IRQ) {
288 		PCIE_DBG("pcishpc_intr() "
289 		    "PCI_HP_SERR_INT_CMD_COMPLETE_IRQ detected\n");
290 		ctrl_p->hc_cmd_pending = B_FALSE;
291 		cv_signal(&ctrl_p->hc_cmd_comp_cv);
292 	}
293 
294 	if (reg & PCI_HP_SERR_INT_ARBITER_IRQ) {
295 		PCIE_DBG("pcishpc_intr() PCI_HP_SERR_INT_ARBITER_IRQ "
296 		    "detected\n");
297 		ctrl_p->hc_arbiter_timeout = B_TRUE;
298 	}
299 
300 	/* Write back the SERR INT register to acknowledge the IRQs. */
301 	pcishpc_write_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG, reg);
302 
303 	irq_locator = pcishpc_read_reg(ctrl_p, PCI_HP_IRQ_LOCATOR_REG);
304 	irq_serr_locator = pcishpc_read_reg(ctrl_p, PCI_HP_SERR_LOCATOR_REG);
305 
306 	/* Check for slot events that might have occured. */
307 	for (slot = 0; slot < ctrl_p->hc_num_slots_impl; slot++) {
308 		if ((irq_locator & (PCI_HP_IRQ_SLOT_N_PENDING<<slot)) ||
309 		    (irq_serr_locator &
310 		    (PCI_HP_IRQ_SERR_SLOT_N_PENDING<<slot))) {
311 			PCIE_DBG("pcishpc_intr() slot %d and "
312 			    "pending IRQ\n", slot+1);
313 
314 			reg = pcishpc_read_reg(ctrl_p,
315 			    PCI_HP_LOGICAL_SLOT_REGS+slot);
316 
317 			if (reg & PCI_HP_SLOT_PRESENCE_DETECTED)
318 				PCIE_DBG("slot %d: "
319 				    "PCI_HP_SLOT_PRESENCE_DETECTED\n",
320 				    slot+1);
321 
322 			if (reg & PCI_HP_SLOT_ISO_PWR_DETECTED)
323 				PCIE_DBG("slot %d: "
324 				    "PCI_HP_SLOT_ISO_PWR_DETECTED\n",
325 				    slot+1);
326 
327 			if (reg & PCI_HP_SLOT_ATTN_DETECTED) {
328 				PCIE_DBG("slot %d: "
329 				    "PCI_HP_SLOT_ATTN_DETECTED\n", slot+1);
330 
331 				/*
332 				 * if ATTN button event is still pending
333 				 * then cancel it
334 				 */
335 				if (ctrl_p->hc_slots[slot]->
336 				    hs_attn_btn_pending == B_TRUE)
337 					ctrl_p->hc_slots[slot]->
338 					    hs_attn_btn_pending = B_FALSE;
339 
340 				/* wake up the ATTN event handler */
341 				cv_signal(&ctrl_p->hc_slots[slot]->
342 				    hs_attn_btn_cv);
343 			}
344 
345 			if (reg & PCI_HP_SLOT_MRL_DETECTED)
346 				PCIE_DBG("slot %d: "
347 				    "PCI_HP_SLOT_MRL_DETECTED\n", slot+1);
348 
349 			if (reg & PCI_HP_SLOT_POWER_DETECTED)
350 				PCIE_DBG("slot %d: "
351 				    "PCI_HP_SLOT_POWER_DETECTED\n", slot+1);
352 
353 			/* Acknoledge any slot interrupts */
354 			pcishpc_write_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot,
355 			    reg);
356 		}
357 	}
358 
359 	mutex_exit(&ctrl_p->hc_mutex);
360 
361 	PCIE_DBG("pcishpc_intr() claimed\n");
362 
363 	return (DDI_INTR_CLAIMED);
364 }
365 
366 int
367 pcishpc_slot_get_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
368     ddi_hp_property_t *rval)
369 {
370 	ddi_hp_property_t request, result;
371 #ifdef _SYSCALL32_IMPL
372 	ddi_hp_property32_t request32, result32;
373 #endif
374 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
375 	nvlist_t 	*prop_list;
376 	nvlist_t	*prop_rlist; /* nvlist for return values */
377 	nvpair_t 	*prop_pair;
378 	char 		*name, *value;
379 	int		ret = DDI_SUCCESS;
380 	int		i, n;
381 	boolean_t	get_all_prop = B_FALSE;
382 
383 	if (get_udatamodel() == DATAMODEL_NATIVE) {
384 		if (copyin(arg, &request, sizeof (ddi_hp_property_t)) ||
385 		    copyin(rval, &result, sizeof (ddi_hp_property_t)))
386 			return (DDI_FAILURE);
387 	}
388 #ifdef _SYSCALL32_IMPL
389 	else {
390 		bzero(&request, sizeof (request));
391 		bzero(&result, sizeof (result));
392 		if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)) ||
393 		    copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
394 			return (DDI_FAILURE);
395 		request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
396 		request.buf_size = request32.buf_size;
397 		result.nvlist_buf = (char *)(uintptr_t)result32.nvlist_buf;
398 		result.buf_size = result32.buf_size;
399 	}
400 #endif
401 
402 	if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
403 	    &prop_list)) != DDI_SUCCESS)
404 		return (ret);
405 
406 	if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
407 		ret = DDI_ENOMEM;
408 		goto get_prop_cleanup;
409 	}
410 
411 	/* check whether the requested property is "all" or "help" */
412 	prop_pair = nvlist_next_nvpair(prop_list, NULL);
413 	if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair)) {
414 		name = nvpair_name(prop_pair);
415 		n = sizeof (pcishpc_props) / sizeof (pcishpc_prop_t);
416 
417 		if (strcmp(name, PCIEHPC_PROP_ALL) == 0) {
418 			(void) nvlist_remove_all(prop_list, PCIEHPC_PROP_ALL);
419 
420 			/*
421 			 * Add all properties into the request list, so that we
422 			 * will get the values in the following for loop.
423 			 */
424 			for (i = 0; i < n; i++) {
425 				if (nvlist_add_string(prop_list,
426 				    pcishpc_props[i].prop_name, "") != 0) {
427 					ret = DDI_FAILURE;
428 					goto get_prop_cleanup1;
429 				}
430 			}
431 			get_all_prop = B_TRUE;
432 		} else if (strcmp(name, PCIEHPC_PROP_HELP) == 0) {
433 			/*
434 			 * Empty the request list, and add help strings into the
435 			 * return list. We will pass the following for loop.
436 			 */
437 			(void) nvlist_remove_all(prop_list, PCIEHPC_PROP_HELP);
438 
439 			for (i = 0; i < n; i++) {
440 				if (nvlist_add_string(prop_rlist,
441 				    pcishpc_props[i].prop_name,
442 				    pcishpc_props[i].prop_value) != 0) {
443 					ret = DDI_FAILURE;
444 					goto get_prop_cleanup1;
445 				}
446 			}
447 		}
448 	}
449 
450 	mutex_enter(&ctrl_p->hc_mutex);
451 
452 	/* get the current slot state */
453 	pcishpc_get_slot_state(slot_p);
454 
455 	/* for each requested property, get the value and add it to nvlist */
456 	prop_pair = NULL;
457 	while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
458 		name = nvpair_name(prop_pair);
459 
460 		if (strcmp(name, PCIEHPC_PROP_LED_FAULT) == 0) {
461 			value = pcie_led_state_text(
462 			    slot_p->hs_fault_led_state);
463 		} else if (strcmp(name, PCIEHPC_PROP_LED_POWER) == 0) {
464 			value = pcie_led_state_text(
465 			    slot_p->hs_power_led_state);
466 		} else if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
467 			value = pcie_led_state_text(
468 			    slot_p->hs_attn_led_state);
469 		} else if (strcmp(name, PCIEHPC_PROP_LED_ACTIVE) == 0) {
470 			value = pcie_led_state_text(
471 			    slot_p->hs_active_led_state);
472 		} else if (strcmp(name, PCIEHPC_PROP_CARD_TYPE) == 0) {
473 			ddi_acc_handle_t	handle;
474 			dev_info_t	*cdip;
475 			uint8_t		prog_class, base_class, sub_class;
476 			int		i;
477 
478 			mutex_exit(&ctrl_p->hc_mutex);
479 			cdip = pcie_hp_devi_find(
480 			    ctrl_p->hc_dip, slot_p->hs_device_num, 0);
481 			mutex_enter(&ctrl_p->hc_mutex);
482 
483 			if ((slot_p->hs_info.cn_state !=
484 			    DDI_HP_CN_STATE_ENABLED) || (cdip == NULL)) {
485 				/*
486 				 * When getting all properties, just ignore the
487 				 * one that's not available under certain state.
488 				 */
489 				if (get_all_prop)
490 					continue;
491 
492 				ret = DDI_ENOTSUP;
493 				goto get_prop_cleanup2;
494 			}
495 
496 			if (pci_config_setup(cdip, &handle) != DDI_SUCCESS) {
497 				ret = DDI_FAILURE;
498 				goto get_prop_cleanup2;
499 			}
500 
501 			prog_class = pci_config_get8(handle,
502 			    PCI_CONF_PROGCLASS);
503 			base_class = pci_config_get8(handle, PCI_CONF_BASCLASS);
504 			sub_class = pci_config_get8(handle, PCI_CONF_SUBCLASS);
505 			pci_config_teardown(&handle);
506 
507 			for (i = 0; i < class_pci_items; i++) {
508 				if ((base_class == class_pci[i].base_class) &&
509 				    (sub_class == class_pci[i].sub_class) &&
510 				    (prog_class == class_pci[i].prog_class)) {
511 					value = class_pci[i].short_desc;
512 					break;
513 				}
514 			}
515 			if (i == class_pci_items)
516 				value = PCIEHPC_PROP_VALUE_UNKNOWN;
517 		} else if (strcmp(name, PCIEHPC_PROP_BOARD_TYPE) == 0) {
518 			if (slot_p->hs_info.cn_state <= DDI_HP_CN_STATE_EMPTY)
519 				value = PCIEHPC_PROP_VALUE_UNKNOWN;
520 			else
521 				value = PCIEHPC_PROP_VALUE_PCIHOTPLUG;
522 		} else if (strcmp(name, PCIEHPC_PROP_SLOT_CONDITION) == 0) {
523 			value = pcie_slot_condition_text(slot_p->hs_condition);
524 		} else {
525 			/* unsupported property */
526 			PCIE_DBG("Unsupported property: %s\n", name);
527 
528 			ret = DDI_ENOTSUP;
529 			goto get_prop_cleanup2;
530 		}
531 		if (nvlist_add_string(prop_rlist, name, value) != 0) {
532 			ret = DDI_FAILURE;
533 			goto get_prop_cleanup2;
534 		}
535 	}
536 
537 	// pack nvlist and copyout
538 	if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
539 	    &result.buf_size)) != DDI_SUCCESS) {
540 		goto get_prop_cleanup2;
541 	}
542 	if (get_udatamodel() == DATAMODEL_NATIVE) {
543 		if (copyout(&result, rval, sizeof (ddi_hp_property_t))) {
544 			ret = DDI_FAILURE;
545 			goto get_prop_cleanup2;
546 		}
547 	}
548 #ifdef _SYSCALL32_IMPL
549 	else {
550 		if (result.buf_size > UINT32_MAX) {
551 			ret = DDI_FAILURE;
552 		} else {
553 			result32.buf_size = (uint32_t)result.buf_size;
554 			if (copyout(&result32, rval,
555 			    sizeof (ddi_hp_property32_t)))
556 				ret = DDI_FAILURE;
557 		}
558 	}
559 #endif
560 
561 get_prop_cleanup2:
562 	mutex_exit(&ctrl_p->hc_mutex);
563 get_prop_cleanup1:
564 	nvlist_free(prop_rlist);
565 get_prop_cleanup:
566 	nvlist_free(prop_list);
567 	return (ret);
568 }
569 
570 int
571 pcishpc_slot_set_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
572     ddi_hp_property_t *rval)
573 {
574 	ddi_hp_property_t request, result;
575 #ifdef _SYSCALL32_IMPL
576 	ddi_hp_property32_t request32, result32;
577 #endif
578 	pcie_hp_ctrl_t		*ctrl_p = slot_p->hs_ctrl;
579 	nvlist_t		*prop_list;
580 	nvlist_t		*prop_rlist;
581 	nvpair_t		*prop_pair;
582 	char			*name, *value;
583 	pcie_hp_led_state_t	led_state;
584 	int			ret = DDI_SUCCESS;
585 
586 	if (get_udatamodel() == DATAMODEL_NATIVE) {
587 		if (copyin(arg, &request, sizeof (ddi_hp_property_t)))
588 			return (DDI_FAILURE);
589 		if (rval &&
590 		    copyin(rval, &result, sizeof (ddi_hp_property_t)))
591 			return (DDI_FAILURE);
592 	}
593 #ifdef _SYSCALL32_IMPL
594 	else {
595 		bzero(&request, sizeof (request));
596 		bzero(&result, sizeof (result));
597 		if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)))
598 			return (DDI_FAILURE);
599 		if (rval &&
600 		    copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
601 			return (DDI_FAILURE);
602 		request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
603 		request.buf_size = request32.buf_size;
604 		if (rval) {
605 			result.nvlist_buf =
606 			    (char *)(uintptr_t)result32.nvlist_buf;
607 			result.buf_size = result32.buf_size;
608 		}
609 	}
610 #endif
611 
612 	if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
613 	    &prop_list)) != DDI_SUCCESS)
614 		return (ret);
615 
616 	/* check whether the requested property is "help" */
617 	prop_pair = nvlist_next_nvpair(prop_list, NULL);
618 	if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair) &&
619 	    (strcmp(nvpair_name(prop_pair), PCIEHPC_PROP_HELP) == 0)) {
620 		if (!rval) {
621 			ret = DDI_ENOTSUP;
622 			goto set_prop_cleanup;
623 		}
624 
625 		if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
626 			ret = DDI_ENOMEM;
627 			goto set_prop_cleanup;
628 		}
629 		if (nvlist_add_string(prop_rlist, PCIEHPC_PROP_LED_ATTN,
630 		    PCIEHPC_PROP_VALUE_LED) != 0) {
631 			ret = DDI_FAILURE;
632 			goto set_prop_cleanup1;
633 		}
634 
635 		if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
636 		    &result.buf_size)) != DDI_SUCCESS) {
637 			goto set_prop_cleanup1;
638 		}
639 		if (get_udatamodel() == DATAMODEL_NATIVE) {
640 			if (copyout(&result, rval,
641 			    sizeof (ddi_hp_property_t))) {
642 				ret =  DDI_FAILURE;
643 				goto set_prop_cleanup1;
644 			}
645 		}
646 #ifdef _SYSCALL32_IMPL
647 		else {
648 			if (result.buf_size > UINT32_MAX) {
649 				ret =  DDI_FAILURE;
650 				goto set_prop_cleanup1;
651 			} else {
652 				result32.buf_size = (uint32_t)result.buf_size;
653 				if (copyout(&result32, rval,
654 				    sizeof (ddi_hp_property32_t))) {
655 					ret =  DDI_FAILURE;
656 					goto set_prop_cleanup1;
657 				}
658 			}
659 		}
660 #endif
661 set_prop_cleanup1:
662 		nvlist_free(prop_rlist);
663 		nvlist_free(prop_list);
664 		return (ret);
665 	}
666 
667 	/* Validate the request */
668 	prop_pair = NULL;
669 	while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
670 		name = nvpair_name(prop_pair);
671 		if (nvpair_type(prop_pair) != DATA_TYPE_STRING) {
672 			PCIE_DBG("Unexpected data type of setting "
673 			    "property %s.\n", name);
674 			ret = DDI_EINVAL;
675 			goto set_prop_cleanup;
676 		}
677 		if (nvpair_value_string(prop_pair, &value)) {
678 			PCIE_DBG("Get string value failed for property %s.\n",
679 			    name);
680 			ret = DDI_FAILURE;
681 			goto set_prop_cleanup;
682 		}
683 
684 		if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
685 			if ((strcmp(value, PCIEHPC_PROP_VALUE_ON) != 0) &&
686 			    (strcmp(value, PCIEHPC_PROP_VALUE_OFF) != 0) &&
687 			    (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) != 0)) {
688 				PCIE_DBG("Unsupported value of setting "
689 				    "property %s\n", name);
690 				ret = DDI_ENOTSUP;
691 				goto set_prop_cleanup;
692 			}
693 		} else {
694 			PCIE_DBG("Unsupported property: %s\n", name);
695 			ret = DDI_ENOTSUP;
696 			goto set_prop_cleanup;
697 		}
698 	}
699 
700 	mutex_enter(&ctrl_p->hc_mutex);
701 
702 	/* get the current slot state */
703 	pcishpc_get_slot_state(slot_p);
704 
705 	// set each property
706 	prop_pair = NULL;
707 	while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
708 		name = nvpair_name(prop_pair);
709 
710 		if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
711 			if (strcmp(value, PCIEHPC_PROP_VALUE_ON) == 0)
712 				led_state = PCIE_HP_LED_ON;
713 			else if (strcmp(value, PCIEHPC_PROP_VALUE_OFF) == 0)
714 				led_state = PCIE_HP_LED_OFF;
715 			else if (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) == 0)
716 				led_state = PCIE_HP_LED_BLINK;
717 
718 			(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED,
719 			    led_state);
720 		}
721 	}
722 	if (rval) {
723 		if (get_udatamodel() == DATAMODEL_NATIVE) {
724 			result.buf_size = 0;
725 			if (copyout(&result, rval, sizeof (ddi_hp_property_t)))
726 				ret =  DDI_FAILURE;
727 		}
728 #ifdef _SYSCALL32_IMPL
729 		else {
730 			result32.buf_size = 0;
731 			if (copyout(&result32, rval,
732 			    sizeof (ddi_hp_property32_t)))
733 				ret =  DDI_FAILURE;
734 		}
735 #endif
736 	}
737 
738 	mutex_exit(&ctrl_p->hc_mutex);
739 set_prop_cleanup:
740 	nvlist_free(prop_list);
741 	return (ret);
742 }
743 
744 /*
745  * pcishpc_hp_ops()
746  *
747  * Handle hotplug commands
748  *
749  * Note: This function is called by DDI HP framework at kernel context only
750  */
751 /* ARGSUSED */
752 int
753 pcishpc_hp_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op,
754     void *arg, void *result)
755 {
756 	pcie_hp_slot_t	*slot_p = NULL;
757 	pcie_hp_ctrl_t	*ctrl_p;
758 	int		ret = DDI_SUCCESS, i;
759 
760 	PCIE_DBG("pcishpc_hp_ops: dip=%p cn_name=%s op=%x arg=%p\n",
761 	    dip, cn_name, op, arg);
762 
763 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
764 		return (DDI_FAILURE);
765 
766 	for (i = 0; i < PCIE_HP_MAX_SLOTS && ctrl_p->hc_slots[i]; i++) {
767 		if (strcmp(ctrl_p->hc_slots[i]->hs_info.cn_name, cn_name)
768 		    == 0) {
769 			/* Match with a physical slot, found */
770 			slot_p = ctrl_p->hc_slots[i];
771 			break;
772 		}
773 	}
774 	if (!slot_p) {
775 		PCIE_DBG("pcishpc_hp_ops: Failed to find the slot under"
776 		    "dip %p with name: %s; op=%x arg=%p\n",
777 		    dip, cn_name, op, arg);
778 		return (DDI_EINVAL);
779 	}
780 	switch (op) {
781 	case DDI_HPOP_CN_GET_STATE:
782 	{
783 		mutex_enter(&ctrl_p->hc_mutex);
784 
785 		/* get the current slot state */
786 		pcishpc_get_slot_state(slot_p);
787 
788 		*((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state;
789 
790 		mutex_exit(&ctrl_p->hc_mutex);
791 		break;
792 	}
793 	case DDI_HPOP_CN_CHANGE_STATE:
794 	{
795 		ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg;
796 
797 		mutex_enter(&slot_p->hs_ctrl->hc_mutex);
798 
799 		ret = pcishpc_change_slot_state(slot_p, target_state);
800 		*((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state;
801 
802 		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
803 		break;
804 	}
805 	case DDI_HPOP_CN_PROBE:
806 		ret = pcishpc_slot_probe(slot_p);
807 
808 		break;
809 	case DDI_HPOP_CN_UNPROBE:
810 		ret = pcishpc_slot_unprobe(slot_p);
811 
812 		break;
813 	case DDI_HPOP_CN_GET_PROPERTY:
814 		ret = pcishpc_slot_get_property(slot_p,
815 		    (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
816 		break;
817 	case DDI_HPOP_CN_SET_PROPERTY:
818 		ret = pcishpc_slot_set_property(slot_p,
819 		    (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
820 		break;
821 	default:
822 		ret = DDI_ENOTSUP;
823 		break;
824 	}
825 
826 	return (ret);
827 }
828 
829 /*
830  * Local functions (called within this file)
831  */
832 
833 /*
834  * pcishpc_create_controller()
835  *
836  * This function allocates and creates an SHPC controller state structure
837  * and adds it to the linked list of controllers.
838  */
839 static pcie_hp_ctrl_t *
840 pcishpc_create_controller(dev_info_t *dip)
841 {
842 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
843 	pcie_hp_ctrl_t	*ctrl_p;
844 
845 	PCIE_DBG("pcishpc: create controller for %s#%d\n",
846 	    ddi_driver_name(dip), ddi_get_instance(dip));
847 
848 	ctrl_p = kmem_zalloc(sizeof (pcie_hp_ctrl_t), KM_SLEEP);
849 	ctrl_p->hc_dip = dip;
850 
851 	cv_init(&ctrl_p->hc_cmd_comp_cv, NULL, CV_DRIVER, NULL);
852 
853 	/* Init the shpc controller's mutex. */
854 	mutex_init(&ctrl_p->hc_mutex, NULL, MUTEX_DRIVER, NULL);
855 
856 	/* HPC initialization is complete now */
857 	ctrl_p->hc_flags = PCIE_HP_INITIALIZED_FLAG;
858 	bus_p->bus_hp_curr_mode = PCIE_PCI_HP_MODE;
859 
860 	PCIE_SET_HP_CTRL(dip, ctrl_p);
861 
862 	PCIE_DBG("pcishpc_create_controller() success\n");
863 
864 	return (ctrl_p);
865 }
866 
867 
868 /*
869  * pcishpc_setup_controller()
870  *
871  * Get the number of HotPlug Slots, and the PCI device information
872  * for this HotPlug controller.
873  */
874 static int
875 pcishpc_setup_controller(pcie_hp_ctrl_t *ctrl_p)
876 {
877 	uint32_t config;
878 	dev_info_t *ppdip;
879 
880 	config = pcishpc_read_reg(ctrl_p, PCI_HP_SLOT_CONFIGURATION_REG);
881 
882 	/* Get the number of HotPlug slots implemented */
883 	ctrl_p->hc_num_slots_impl = ((config)&31);
884 
885 	/*
886 	 * Initilize the current bus speed and number of hotplug slots
887 	 * currently connected.
888 	 */
889 	ctrl_p->hc_curr_bus_speed = -1;
890 	ctrl_p->hc_num_slots_connected = 0;
891 
892 	/*
893 	 * Get the first PCI device Number used.
894 	 *
895 	 * PCI-X I/O boat workaround.
896 	 * The register doesn't set up the correct value.
897 	 */
898 	ppdip = ddi_get_parent(ddi_get_parent(ctrl_p->hc_dip));
899 	if ((ddi_prop_get_int(DDI_DEV_T_ANY, ppdip, DDI_PROP_DONTPASS,
900 	    "vendor-id", -1) == 0x108e) &&
901 	    (ddi_prop_get_int(DDI_DEV_T_ANY, ppdip, DDI_PROP_DONTPASS,
902 	    "device-id", -1) == 0x9010))
903 		ctrl_p->hc_device_start = 4;
904 	else
905 		ctrl_p->hc_device_start = ((config>>8)&31);
906 
907 	/* Get the first Physical device number. */
908 	ctrl_p->hc_phys_start = ((config>>16)&0x7ff);
909 
910 	/* Check if the device numbers increase or decrease. */
911 	ctrl_p->hc_device_increases = ((config>>29)&0x1);
912 
913 	ctrl_p->hc_has_attn =
914 	    (config & PCI_HP_SLOT_CONFIG_ATTN_BUTTON) ? B_TRUE : B_FALSE;
915 	ctrl_p->hc_has_mrl =
916 	    (config & PCI_HP_SLOT_CONFIG_MRL_SENSOR) ? B_TRUE : B_FALSE;
917 
918 	ctrl_p->hc_cmd_pending = B_FALSE;
919 	ctrl_p->hc_arbiter_timeout = B_FALSE;
920 
921 	if (ctrl_p->hc_num_slots_impl > PCIE_HP_MAX_SLOTS) {
922 		PCIE_DBG("pcishpc_setup_controller() too many SHPC "
923 		    "slots error\n");
924 		return (DDI_FAILURE);
925 	}
926 
927 	return (DDI_SUCCESS);
928 }
929 
930 
931 /*
932  * pcishpc_destroy_controller()
933  *
934  * This function deallocates all of the SHPC controller resources.
935  */
936 static int
937 pcishpc_destroy_controller(dev_info_t *dip)
938 {
939 	pcie_hp_ctrl_t	*ctrl_p;
940 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
941 
942 	PCIE_DBG("pcishpc_destroy_controller() called(dip=%p)\n", dip);
943 
944 	/* get the soft state structure for this dip */
945 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) {
946 		PCIE_DBG("pcishpc_destroy_controller() not found\n");
947 		return (DDI_FAILURE);
948 	}
949 
950 	/*
951 	 * Deallocate the slot state structures for this controller.
952 	 */
953 	(void) pcishpc_destroy_slots(ctrl_p);
954 	cv_destroy(&ctrl_p->hc_cmd_comp_cv);
955 	mutex_destroy(&ctrl_p->hc_mutex);
956 	kmem_free(ctrl_p, sizeof (pcie_hp_ctrl_t));
957 	bus_p->bus_hp_curr_mode = PCIE_NONE_HP_MODE;
958 
959 	PCIE_DBG("pcishpc_destroy_controller() success\n");
960 	return (DDI_SUCCESS);
961 }
962 
963 /*
964  * pcishpc_create_slot()
965  *
966  * Allocate and add a new HotPlug slot state structure to the linked list.
967  */
968 static pcie_hp_slot_t *
969 pcishpc_create_slot(pcie_hp_ctrl_t *ctrl_p)
970 {
971 	pcie_hp_slot_t *slot_p;
972 
973 	PCIE_DBG("pcishpc_create_slot() called(ctrl_p=%x)\n", ctrl_p);
974 
975 	/* Allocate a new slot structure. */
976 	slot_p = kmem_zalloc(sizeof (pcie_hp_slot_t), KM_SLEEP);
977 	slot_p->hs_ctrl = ctrl_p;
978 
979 	/* Assign an initial value */
980 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY;
981 
982 	PCIE_DBG("pcishpc_create_slot() success\n");
983 	return (slot_p);
984 }
985 
986 /*
987  * pcishpc_register_slot()
988  *
989  * Create and register a slot with the Solaris HotPlug framework.
990  */
991 static int
992 pcishpc_register_slot(pcie_hp_ctrl_t *ctrl_p, int slot)
993 {
994 	dev_info_t	*dip = ctrl_p->hc_dip;
995 	pcie_hp_slot_t	*slot_p;
996 
997 	slot_p = pcishpc_create_slot(ctrl_p);
998 	ctrl_p->hc_slots[slot] = slot_p;
999 	slot_p->hs_num = slot;
1000 
1001 	/* Setup the PCI device # for this SHPC slot. */
1002 	if (ctrl_p->hc_device_increases)
1003 		slot_p->hs_device_num = ctrl_p->hc_device_start +
1004 		    slot_p->hs_num;
1005 	else
1006 		slot_p->hs_device_num = ctrl_p->hc_device_start -
1007 		    slot_p->hs_num;
1008 
1009 	/* Setup the DDI HP framework slot information. */
1010 	slot_p->hs_info.cn_type = DDI_HP_CN_TYPE_PCI;
1011 	slot_p->hs_info.cn_type_str = PCIE_PCI_HP_TYPE;
1012 	slot_p->hs_info.cn_child = NULL;
1013 
1014 	slot_p->hs_minor = PCI_MINOR_NUM(
1015 	    ddi_get_instance(dip), slot_p->hs_device_num);
1016 	slot_p->hs_condition = AP_COND_UNKNOWN;
1017 
1018 	/* setup thread for handling ATTN button events */
1019 	if (ctrl_p->hc_has_attn) {
1020 		PCIE_DBG("pcishpc_register_slot: "
1021 		    "setting up ATTN button event "
1022 		    "handler thread for slot %d\n", slot);
1023 
1024 		cv_init(&slot_p->hs_attn_btn_cv, NULL, CV_DRIVER, NULL);
1025 		slot_p->hs_attn_btn_pending = B_FALSE;
1026 		slot_p->hs_attn_btn_threadp = thread_create(NULL, 0,
1027 		    pcishpc_attn_btn_handler,
1028 		    (void *)slot_p, 0, &p0, TS_RUN, minclsyspri);
1029 		slot_p->hs_attn_btn_thread_exit = B_FALSE;
1030 	}
1031 
1032 	/* setup the slot name (used for ap-id) */
1033 	pcishpc_set_slot_name(ctrl_p, slot);
1034 
1035 	pcishpc_get_slot_state(slot_p);
1036 	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_ENABLED)
1037 		slot_p->hs_condition = AP_COND_OK;
1038 
1039 	/* register the slot with DDI HP framework */
1040 	if (ndi_hp_register(dip, &slot_p->hs_info) != NDI_SUCCESS) {
1041 		PCIE_DBG("pciehpc_register_slot() failed to register slot %d\n",
1042 		    slot_p->hs_phy_slot_num);
1043 		return (DDI_FAILURE);
1044 	}
1045 
1046 	pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip),
1047 	    slot_p->hs_minor), slot_p->hs_device_num);
1048 
1049 	PCIE_DBG("pcishpc_register_slot() success for slot %d\n", slot);
1050 
1051 	return (DDI_SUCCESS);
1052 }
1053 
1054 /*
1055  * pcishpc_destroy_slots()
1056  *
1057  * Free up all of the slot resources for this controller.
1058  */
1059 static int
1060 pcishpc_destroy_slots(pcie_hp_ctrl_t *ctrl_p)
1061 {
1062 	dev_info_t	*dip = ctrl_p->hc_dip;
1063 	pcie_hp_slot_t	*slot_p;
1064 	int		i;
1065 
1066 	PCIE_DBG("pcishpc_destroy_slots() called(ctrl_p=%p)\n", ctrl_p);
1067 
1068 	for (i = 0; i < PCIE_HP_MAX_SLOTS; i++) {
1069 		if ((slot_p = ctrl_p->hc_slots[i]) == NULL)
1070 			continue;
1071 
1072 		if (slot_p->hs_attn_btn_threadp != NULL) {
1073 			mutex_enter(&ctrl_p->hc_mutex);
1074 			slot_p->hs_attn_btn_thread_exit = B_TRUE;
1075 			cv_signal(&slot_p->hs_attn_btn_cv);
1076 			PCIE_DBG("pcishpc_destroy_slots: "
1077 			    "waiting for ATTN thread exit\n");
1078 			cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
1079 			PCIE_DBG("pcishpc_destroy_slots: "
1080 			    "ATTN thread exit\n");
1081 			cv_destroy(&slot_p->hs_attn_btn_cv);
1082 			slot_p->hs_attn_btn_threadp = NULL;
1083 			mutex_exit(&ctrl_p->hc_mutex);
1084 		}
1085 
1086 		PCIE_DBG("pcishpc_destroy_slots() (shpc_p=%p)\n"
1087 		    "destroyed", slot_p);
1088 
1089 		pcie_hp_delete_occupant_props(dip,
1090 		    makedevice(ddi_driver_major(dip),
1091 		    slot_p->hs_minor));
1092 
1093 		/* unregister the slot with DDI HP framework */
1094 		if (ndi_hp_unregister(dip, slot_p->hs_info.cn_name) !=
1095 		    NDI_SUCCESS) {
1096 			PCIE_DBG("pcishpc_destroy_slots() "
1097 			    "failed to unregister slot %d\n",
1098 			    slot_p->hs_phy_slot_num);
1099 			return (DDI_FAILURE);
1100 		}
1101 		kmem_free(slot_p->hs_info.cn_name,
1102 		    strlen(slot_p->hs_info.cn_name) + 1);
1103 		kmem_free(slot_p, sizeof (pcie_hp_slot_t));
1104 	}
1105 
1106 	return (DDI_SUCCESS);
1107 }
1108 
1109 /*
1110  * pcishpc_enable_irqs()
1111  *
1112  * Enable/unmask the different IRQ's we support from the SHPC controller.
1113  */
1114 static int
1115 pcishpc_enable_irqs(pcie_hp_ctrl_t *ctrl_p)
1116 {
1117 	uint32_t reg;
1118 	int slot;
1119 
1120 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG);
1121 
1122 	/* Enable all interrupts. */
1123 	reg &= ~PCI_HP_SERR_INT_MASK_ALL;
1124 
1125 	pcishpc_write_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG, reg);
1126 
1127 	/* Unmask the interrupts for each slot. */
1128 	for (slot = 0; slot < ctrl_p->hc_num_slots_impl; slot++) {
1129 		reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot);
1130 		if ((reg & PCI_HP_SLOT_STATE_MASK) == PCI_HP_SLOT_ENABLED) {
1131 			reg &= ~(PCI_HP_SLOT_MASK_ALL |
1132 			    PCI_HP_SLOT_MRL_SERR_MASK);
1133 			ctrl_p->hc_num_slots_connected++;
1134 			if (ctrl_p->hc_curr_bus_speed == -1)
1135 				ctrl_p->hc_curr_bus_speed =
1136 				    pcishpc_read_reg(ctrl_p,
1137 				    PCI_HP_PROF_IF_SBCR_REG) &
1138 				    PCI_HP_SBCR_SPEED_MASK;
1139 		} else {
1140 			reg &= ~(PCI_HP_SLOT_MASK_ALL);
1141 		}
1142 
1143 		/* Enable/Unmask all slot interrupts. */
1144 		pcishpc_write_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot, reg);
1145 	}
1146 
1147 	PCIE_DBG("pcishpc_enable_irqs: ctrl_p 0x%p, "
1148 	    "current bus speed 0x%x, slots connected 0x%x\n", ctrl_p,
1149 	    ctrl_p->hc_curr_bus_speed, ctrl_p->hc_num_slots_connected);
1150 
1151 	return (DDI_SUCCESS);
1152 }
1153 
1154 
1155 /*
1156  * pcishpc_disable_irqs()
1157  *
1158  * Disable/Mask the different IRQ's we support from the SHPC controller.
1159  */
1160 static int
1161 pcishpc_disable_irqs(pcie_hp_ctrl_t *ctrl_p)
1162 {
1163 	uint32_t reg;
1164 	int slot;
1165 
1166 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG);
1167 
1168 	/* Mask all interrupts. */
1169 	reg |= PCI_HP_SERR_INT_MASK_ALL;
1170 
1171 	pcishpc_write_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG, reg);
1172 
1173 	/* Unmask the interrupts for each slot. */
1174 	for (slot = 0; slot < ctrl_p->hc_num_slots_impl; slot++) {
1175 		reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot);
1176 
1177 		/* Disable/Mask all slot interrupts. */
1178 		reg |= PCI_HP_SLOT_MASK_ALL;
1179 
1180 		pcishpc_write_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot, reg);
1181 	}
1182 
1183 	PCIE_DBG("pcishpc_disable_irqs: ctrl_p 0x%p, "
1184 	    "current bus speed 0x%x, slots connected 0x%x\n", ctrl_p,
1185 	    ctrl_p->hc_curr_bus_speed, ctrl_p->hc_num_slots_connected);
1186 
1187 	return (DDI_SUCCESS);
1188 }
1189 
1190 /*
1191  * pcishpc_slot_poweron()
1192  *
1193  * Poweron/Enable the slot.
1194  *
1195  * Note: This function is called by DDI HP framework at kernel context only
1196  */
1197 /*ARGSUSED*/
1198 static int
1199 pcishpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result_state)
1200 {
1201 	uint32_t	status;
1202 
1203 	PCIE_DBG("pcishpc_slot_poweron called()\n");
1204 
1205 	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
1206 
1207 	/* get the current slot state */
1208 	pcishpc_get_slot_state(slot_p);
1209 
1210 	/* check if the slot is already in the 'enabled' state */
1211 	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) {
1212 		/* slot is already in the 'enabled' state */
1213 		PCIE_DBG("pcishpc_slot_poweron() slot %d already enabled\n",
1214 		    slot_p->hs_phy_slot_num);
1215 
1216 		*result_state = slot_p->hs_info.cn_state;
1217 		return (DDI_SUCCESS);
1218 	}
1219 
1220 	if (slot_p->hs_info.cn_state == DDI_HP_CN_STATE_EMPTY) {
1221 		PCIE_DBG("pcishpc_slot_poweron() slot in empty state\n");
1222 		goto cleanup;
1223 	}
1224 
1225 	/* make sure the MRL sensor is closed */
1226 	status = pcishpc_read_reg(slot_p->hs_ctrl,
1227 	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
1228 
1229 	if (status & PCI_HP_SLOT_MRL_STATE_MASK) {
1230 		PCIE_DBG("pcishpc_slot_poweron() failed: MRL open\n");
1231 		goto cleanup;
1232 	}
1233 
1234 	/* Set the Power LED to blink */
1235 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
1236 
1237 	/* Turn all other LEDS off */
1238 	(void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF);
1239 	(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
1240 	(void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF);
1241 
1242 	/* Set the bus speed only if the bus segment is not running */
1243 	if (pcishpc_set_bus_speed(slot_p) != DDI_SUCCESS) {
1244 		PCIE_DBG("pcishpc_slot_poweron() setting speed failed\n");
1245 		goto cleanup;
1246 	}
1247 
1248 	slot_p->hs_ctrl->hc_num_slots_connected++;
1249 
1250 	PCIE_DBG("pcishpc_slot_poweron(): slot_p 0x%p, slot state 0x%x, "
1251 	    "current bus speed 0x%x, slots connected 0x%x\n", slot_p,
1252 	    slot_p->hs_info.cn_state, slot_p->hs_ctrl->hc_curr_bus_speed,
1253 	    slot_p->hs_ctrl->hc_num_slots_connected);
1254 
1255 	/* Mask or Unmask MRL Sensor SEER bit based on new slot state */
1256 	if (slot_p->hs_ctrl->hc_has_mrl == B_TRUE) {
1257 		uint32_t reg;
1258 
1259 		reg = pcishpc_read_reg(slot_p->hs_ctrl,
1260 		    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
1261 
1262 		pcishpc_write_reg(slot_p->hs_ctrl,
1263 		    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num,
1264 		    reg & ~PCI_HP_SLOT_MRL_SERR_MASK);
1265 	}
1266 
1267 	/* Update the hardware slot state. */
1268 	if (pcishpc_set_slot_state(slot_p,
1269 	    DDI_HP_CN_STATE_ENABLED) != DDI_SUCCESS) {
1270 		PCIE_DBG("pcishpc_slot_poweron() failed\n");
1271 
1272 		pcishpc_get_slot_state(slot_p);
1273 		goto cleanup;
1274 	}
1275 	/* Update the current state. It will be used in pcishpc_setled() */
1276 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_ENABLED;
1277 
1278 	/* Turn the Power LED ON for a enabled slot. */
1279 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_ON);
1280 
1281 	/* Turn all other LEDS off. */
1282 	(void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF);
1283 	(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
1284 	(void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF);
1285 
1286 	/* delay after powerON to let the device initialize itself */
1287 	delay(drv_usectohz(pcishpc_reset_delay));
1288 
1289 	PCIE_DBG("pcishpc_slot_poweron() success!\n");
1290 
1291 	/*
1292 	 * Want to show up as POWERED state for now. It will be updated to
1293 	 * ENABLED state when user explicitly enable the slot.
1294 	 */
1295 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_POWERED;
1296 
1297 	/* get the current slot state */
1298 	pcishpc_get_slot_state(slot_p);
1299 	/*
1300 	 * It should be poweron'ed now. Have a check here in case any
1301 	 * hardware problems.
1302 	 */
1303 	if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) {
1304 		PCIE_DBG("pcishpc_slot_poweron() failed after hardware"
1305 		    " registers all programmed.\n");
1306 
1307 		goto cleanup;
1308 	}
1309 
1310 	*result_state = slot_p->hs_info.cn_state;
1311 
1312 	return (DDI_SUCCESS);
1313 
1314 cleanup:
1315 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
1316 	return (DDI_FAILURE);
1317 }
1318 
1319 /*ARGSUSED*/
1320 static int
1321 pcishpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result_state)
1322 {
1323 	PCIE_DBG("pcishpc_slot_poweroff called()\n");
1324 
1325 	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
1326 
1327 	/* get the current slot state */
1328 	pcishpc_get_slot_state(slot_p);
1329 
1330 	/* check if the slot is not in the "enabled" or "powered" state */
1331 	if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) {
1332 		/* slot is in the 'disabled' state */
1333 		PCIE_DBG("pcishpc_slot_poweroff(): "
1334 		    "slot %d already disabled\n", slot_p->hs_phy_slot_num);
1335 
1336 		*result_state = slot_p->hs_info.cn_state;
1337 		return (DDI_SUCCESS);
1338 	}
1339 
1340 	/* Set the Power LED to blink */
1341 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
1342 
1343 	/* Turn all other LEDS off */
1344 	(void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF);
1345 	(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
1346 	(void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF);
1347 
1348 	if (--slot_p->hs_ctrl->hc_num_slots_connected == 0)
1349 		slot_p->hs_ctrl->hc_curr_bus_speed = -1;
1350 
1351 	PCIE_DBG("pcishpc_slot_poweroff(): slot_p 0x%p, slot state 0x%x, "
1352 	    "current bus speed 0x%x, slots connected 0x%x\n", slot_p,
1353 	    slot_p->hs_info.cn_state, slot_p->hs_ctrl->hc_curr_bus_speed,
1354 	    slot_p->hs_ctrl->hc_num_slots_connected);
1355 
1356 	/* Mask or Unmask MRL Sensor SEER bit based on new slot state */
1357 	if (slot_p->hs_ctrl->hc_has_mrl == B_TRUE) {
1358 		uint32_t reg;
1359 
1360 		reg = pcishpc_read_reg(slot_p->hs_ctrl,
1361 		    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
1362 
1363 		pcishpc_write_reg(slot_p->hs_ctrl,
1364 		    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num,
1365 		    reg | PCI_HP_SLOT_MRL_SERR_MASK);
1366 	}
1367 
1368 	/* Update the hardware slot state. */
1369 	if (pcishpc_set_slot_state(slot_p, DDI_HP_CN_STATE_PRESENT) !=
1370 	    DDI_SUCCESS) {
1371 		PCIE_DBG("pcishpc_slot_poweroff() failed\n");
1372 
1373 		pcishpc_get_slot_state(slot_p);
1374 		goto cleanup;
1375 	}
1376 
1377 	/* Update the current state. It will be used in pcishpc_setled() */
1378 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_PRESENT;
1379 
1380 	/* Turn the Power LED OFF for a disabled slot. */
1381 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
1382 
1383 	/* Turn all other LEDS off. */
1384 	(void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF);
1385 	(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
1386 	(void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF);
1387 
1388 	/* delay after powerON to let the device initialize itself */
1389 	delay(drv_usectohz(pcishpc_reset_delay));
1390 
1391 	pcishpc_get_slot_state(slot_p);
1392 	/*
1393 	 * It should be poweroff'ed now. Have a check here in case any
1394 	 * hardware problems.
1395 	 */
1396 	if (slot_p->hs_info.cn_state > DDI_HP_CN_STATE_PRESENT) {
1397 		PCIE_DBG("pcishpc_slot_poweroff() failed after hardware"
1398 		    " registers all programmed.\n");
1399 
1400 		goto cleanup;
1401 	}
1402 
1403 	PCIE_DBG("pcishpc_slot_poweroff() success!\n");
1404 
1405 	*result_state = slot_p->hs_info.cn_state;
1406 	return (DDI_SUCCESS);
1407 
1408 cleanup:
1409 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
1410 	return (DDI_FAILURE);
1411 }
1412 
1413 /*
1414  * pcishpc_slot_probe()
1415  *
1416  * Probe the slot.
1417  *
1418  * Note: This function is called by DDI HP framework at kernel context only
1419  */
1420 /*ARGSUSED*/
1421 static int
1422 pcishpc_slot_probe(pcie_hp_slot_t *slot_p)
1423 {
1424 	mutex_enter(&slot_p->hs_ctrl->hc_mutex);
1425 
1426 	PCIE_DBG("pcishpc_slot_probe called()\n");
1427 
1428 	/* get the current slot state */
1429 	pcishpc_get_slot_state(slot_p);
1430 
1431 	/*
1432 	 * Probe a given PCI Hotplug Connection (CN).
1433 	 */
1434 	if (pcie_hp_probe(slot_p) != DDI_SUCCESS) {
1435 		(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED,
1436 		    PCIE_HP_LED_BLINK);
1437 
1438 		PCIE_DBG("pcishpc_slot_probe() failed\n");
1439 
1440 		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
1441 		return (DDI_FAILURE);
1442 	}
1443 
1444 	PCIE_DBG("pcishpc_slot_probe() success!\n");
1445 
1446 	/* get the current slot state */
1447 	pcishpc_get_slot_state(slot_p);
1448 
1449 	mutex_exit(&slot_p->hs_ctrl->hc_mutex);
1450 	return (DDI_SUCCESS);
1451 }
1452 
1453 /*
1454  * pcishpc_slot_unprobe()
1455  *
1456  * Unprobe the slot.
1457  *
1458  * Note: This function is called by DDI HP framework at kernel context only
1459  */
1460 /*ARGSUSED*/
1461 static int
1462 pcishpc_slot_unprobe(pcie_hp_slot_t *slot_p)
1463 {
1464 	mutex_enter(&slot_p->hs_ctrl->hc_mutex);
1465 
1466 	PCIE_DBG("pcishpc_slot_unprobe called()\n");
1467 
1468 	/* get the current slot state */
1469 	pcishpc_get_slot_state(slot_p);
1470 
1471 	/*
1472 	 * Unprobe a given PCI Hotplug Connection (CN).
1473 	 */
1474 	if (pcie_hp_unprobe(slot_p) != DDI_SUCCESS) {
1475 		(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED,
1476 		    PCIE_HP_LED_BLINK);
1477 
1478 		PCIE_DBG("pcishpc_slot_unprobe() failed\n");
1479 
1480 		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
1481 		return (DDI_FAILURE);
1482 	}
1483 
1484 	PCIE_DBG("pcishpc_slot_unprobe() success!\n");
1485 
1486 	/* get the current slot state */
1487 	pcishpc_get_slot_state(slot_p);
1488 
1489 	mutex_exit(&slot_p->hs_ctrl->hc_mutex);
1490 	return (DDI_SUCCESS);
1491 }
1492 
1493 static int
1494 pcishpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
1495     ddi_hp_cn_state_t target_state)
1496 {
1497 	ddi_hp_cn_state_t curr_state;
1498 	int rv = DDI_SUCCESS;
1499 
1500 	if (target_state > DDI_HP_CN_STATE_ENABLED) {
1501 		return (DDI_EINVAL);
1502 	}
1503 
1504 	curr_state = slot_p->hs_info.cn_state;
1505 	while ((curr_state < target_state) && (rv == DDI_SUCCESS)) {
1506 
1507 		switch (curr_state) {
1508 		case DDI_HP_CN_STATE_EMPTY:
1509 			/*
1510 			 * From EMPTY to PRESENT, just check the hardware
1511 			 * slot state.
1512 			 */
1513 			pcishpc_get_slot_state(slot_p);
1514 			curr_state = slot_p->hs_info.cn_state;
1515 			if (curr_state < DDI_HP_CN_STATE_PRESENT)
1516 				rv = DDI_FAILURE;
1517 			break;
1518 		case DDI_HP_CN_STATE_PRESENT:
1519 			rv = pcishpc_slot_poweron(slot_p, &curr_state);
1520 			break;
1521 		case DDI_HP_CN_STATE_POWERED:
1522 			curr_state = slot_p->hs_info.cn_state =
1523 			    DDI_HP_CN_STATE_ENABLED;
1524 			break;
1525 		default:
1526 			/* should never reach here */
1527 			ASSERT("unknown devinfo state");
1528 		}
1529 	}
1530 
1531 	return (rv);
1532 }
1533 
1534 static int
1535 pcishpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
1536     ddi_hp_cn_state_t target_state)
1537 {
1538 	ddi_hp_cn_state_t curr_state;
1539 	int rv = DDI_SUCCESS;
1540 
1541 
1542 	curr_state = slot_p->hs_info.cn_state;
1543 	while ((curr_state > target_state) && (rv == DDI_SUCCESS)) {
1544 
1545 		switch (curr_state) {
1546 		case DDI_HP_CN_STATE_PRESENT:
1547 			/*
1548 			 * From PRESENT to EMPTY, just check hardware
1549 			 * slot state.
1550 			 */
1551 			pcishpc_get_slot_state(slot_p);
1552 			curr_state = slot_p->hs_info.cn_state;
1553 			if (curr_state >= DDI_HP_CN_STATE_PRESENT)
1554 				rv = DDI_FAILURE;
1555 			break;
1556 		case DDI_HP_CN_STATE_POWERED:
1557 			rv = pcishpc_slot_poweroff(slot_p, &curr_state);
1558 
1559 			break;
1560 		case DDI_HP_CN_STATE_ENABLED:
1561 			curr_state = slot_p->hs_info.cn_state =
1562 			    DDI_HP_CN_STATE_POWERED;
1563 
1564 			break;
1565 		default:
1566 			/* should never reach here */
1567 			ASSERT("unknown devinfo state");
1568 		}
1569 	}
1570 
1571 	return (rv);
1572 }
1573 
1574 /* Change slot state to a target state */
1575 static int
1576 pcishpc_change_slot_state(pcie_hp_slot_t *slot_p,
1577     ddi_hp_cn_state_t target_state)
1578 {
1579 	ddi_hp_cn_state_t curr_state;
1580 	int rv;
1581 
1582 	pcishpc_get_slot_state(slot_p);
1583 	curr_state = slot_p->hs_info.cn_state;
1584 
1585 	if (curr_state == target_state) {
1586 		return (DDI_SUCCESS);
1587 	}
1588 	if (curr_state < target_state) {
1589 
1590 		rv = pcishpc_upgrade_slot_state(slot_p, target_state);
1591 	} else {
1592 		rv = pcishpc_downgrade_slot_state(slot_p, target_state);
1593 	}
1594 
1595 	return (rv);
1596 }
1597 
1598 /*
1599  * pcishpc_issue_command()
1600  *
1601  * Sends a command to the SHPC controller.
1602  */
1603 static int
1604 pcishpc_issue_command(pcie_hp_ctrl_t *ctrl_p, uint32_t cmd_code)
1605 {
1606 	int	retCode;
1607 
1608 	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
1609 
1610 	PCIE_DBG("pcishpc_issue_command() cmd_code=%02x\n", cmd_code);
1611 
1612 	ctrl_p->hc_cmd_pending = B_TRUE;
1613 
1614 	/* Write the command to the SHPC controller. */
1615 	pcishpc_write_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG, cmd_code);
1616 
1617 	while (ctrl_p->hc_cmd_pending == B_TRUE)
1618 		cv_wait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex);
1619 
1620 	/* Wait until the SHPC controller processes the command. */
1621 	retCode = pcishpc_wait_busy(ctrl_p);
1622 
1623 	/* Make sure the command completed. */
1624 	if (retCode == DDI_SUCCESS) {
1625 		/* Did the command fail to generate the command complete IRQ? */
1626 		if (ctrl_p->hc_cmd_pending != B_FALSE) {
1627 			PCIE_DBG("pcishpc_issue_command() Failed on "
1628 			    "generate cmd complete IRQ\n");
1629 			retCode = DDI_FAILURE;
1630 		}
1631 	}
1632 
1633 	if (retCode == DDI_FAILURE)
1634 		PCIE_DBG("pcishpc_issue_command() Failed on cmd_code=%02x\n",
1635 		    cmd_code);
1636 	else
1637 		PCIE_DBG("pcishpc_issue_command() Success on "
1638 		    "cmd_code=%02x\n", cmd_code);
1639 
1640 	return (retCode);
1641 }
1642 
1643 /*
1644  * pcishpc_wait_busy()
1645  *
1646  * Wait until the SHPC controller is not busy.
1647  */
1648 static int
1649 pcishpc_wait_busy(pcie_hp_ctrl_t *ctrl_p)
1650 {
1651 	uint32_t	status;
1652 
1653 	/* Wait until SHPC controller is NOT busy */
1654 	for (;;) {
1655 		status = pcishpc_read_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG);
1656 
1657 		/* Is there an MRL Sensor error? */
1658 		if ((status & PCI_HP_COMM_STS_ERR_MASK) ==
1659 		    PCI_HP_COMM_STS_ERR_MRL_OPEN) {
1660 			PCIE_DBG("pcishpc_wait_busy() ERROR: "
1661 			    "MRL Sensor error\n");
1662 			break;
1663 		}
1664 
1665 		/* Is there an Invalid command error? */
1666 		if ((status & PCI_HP_COMM_STS_ERR_MASK) ==
1667 		    PCI_HP_COMM_STS_ERR_INVALID_COMMAND) {
1668 			PCIE_DBG("pcishpc_wait_busy() ERROR: Invalid "
1669 			    "command error\n");
1670 			break;
1671 		}
1672 
1673 		/* Is there an Invalid Speed/Mode error? */
1674 		if ((status & PCI_HP_COMM_STS_ERR_MASK) ==
1675 		    PCI_HP_COMM_STS_ERR_INVALID_SPEED) {
1676 			PCIE_DBG("pcishpc_wait_busy() ERROR: Invalid "
1677 			    "Speed/Mode error\n");
1678 			break;
1679 		}
1680 
1681 		/* Is the SHPC controller not BUSY? */
1682 		if (!(status & PCI_HP_COMM_STS_CTRL_BUSY)) {
1683 			/* Return Success. */
1684 			return (DDI_SUCCESS);
1685 		}
1686 
1687 		PCIE_DBG("pcishpc_wait_busy() SHPC controller busy. Waiting\n");
1688 
1689 		/* Wait before polling the status register again. */
1690 		delay(drv_usectohz(PCIE_HP_CMD_WAIT_TIME));
1691 	}
1692 
1693 	return (DDI_FAILURE);
1694 }
1695 
1696 static void
1697 pcishpc_attn_btn_handler(pcie_hp_slot_t *slot_p)
1698 {
1699 	pcie_hp_led_state_t hs_power_led_state;
1700 	callb_cpr_t cprinfo;
1701 
1702 	PCIE_DBG("pcishpc_attn_btn_handler: thread started\n");
1703 
1704 	CALLB_CPR_INIT(&cprinfo, &slot_p->hs_ctrl->hc_mutex,
1705 	    callb_generic_cpr, "pcishpc_attn_btn_handler");
1706 
1707 	mutex_enter(&slot_p->hs_ctrl->hc_mutex);
1708 
1709 	/* wait for ATTN button event */
1710 	cv_wait(&slot_p->hs_attn_btn_cv, &slot_p->hs_ctrl->hc_mutex);
1711 
1712 	while (slot_p->hs_attn_btn_thread_exit == B_FALSE) {
1713 		if (slot_p->hs_attn_btn_pending == B_TRUE) {
1714 			/* get the current state of power LED */
1715 			hs_power_led_state = slot_p->hs_power_led_state;
1716 
1717 			/* Blink the Power LED while we wait for 5 seconds */
1718 			(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED,
1719 			    PCIE_HP_LED_BLINK);
1720 
1721 			/* wait for 5 seconds before taking any action */
1722 			if (cv_reltimedwait(&slot_p->hs_attn_btn_cv,
1723 			    &slot_p->hs_ctrl->hc_mutex,
1724 			    SEC_TO_TICK(5), TR_CLOCK_TICK) == -1) {
1725 				/*
1726 				 * It is a time out;
1727 				 * make sure the ATTN pending flag is
1728 				 * still ON before sending the event
1729 				 * to DDI HP framework.
1730 				 */
1731 				if (slot_p->hs_attn_btn_pending == B_TRUE) {
1732 					int hint;
1733 
1734 					/* restore the power LED state */
1735 					(void) pcishpc_setled(slot_p,
1736 					    PCIE_HP_POWER_LED,
1737 					    hs_power_led_state);
1738 					/*
1739 					 * send the ATTN button event
1740 					 * to DDI HP framework
1741 					 */
1742 					slot_p->hs_attn_btn_pending = B_FALSE;
1743 
1744 					pcishpc_get_slot_state(slot_p);
1745 
1746 					if (slot_p->hs_info.cn_state <=
1747 					    DDI_HP_CN_STATE_PRESENT) {
1748 						/*
1749 						 * Insertion.
1750 						 */
1751 						hint = SE_INCOMING_RES;
1752 					} else {
1753 						/*
1754 						 * Want to remove;
1755 						 */
1756 						hint = SE_OUTGOING_RES;
1757 					}
1758 					pcie_hp_gen_sysevent_req(
1759 					    slot_p->hs_info.cn_name,
1760 					    hint,
1761 					    slot_p->hs_ctrl->hc_dip,
1762 					    KM_SLEEP);
1763 
1764 					continue;
1765 				}
1766 			}
1767 
1768 			/* restore the power LED state */
1769 			(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED,
1770 			    hs_power_led_state);
1771 			continue;
1772 		}
1773 
1774 		/* wait for another ATTN button event */
1775 		cv_wait(&slot_p->hs_attn_btn_cv, &slot_p->hs_ctrl->hc_mutex);
1776 	}
1777 
1778 	PCIE_DBG("pcishpc_attn_btn_handler: thread exit\n");
1779 	cv_signal(&slot_p->hs_attn_btn_cv);
1780 	CALLB_CPR_EXIT(&cprinfo);
1781 	thread_exit();
1782 }
1783 
1784 /*
1785  * pcishpc_get_slot_state()
1786  *
1787  * Get the state of the slot.
1788  * The slot state should have been initialized before this function gets called.
1789  */
1790 static void
1791 pcishpc_get_slot_state(pcie_hp_slot_t *slot_p)
1792 {
1793 	uint32_t reg;
1794 	ddi_hp_cn_state_t curr_state = slot_p->hs_info.cn_state;
1795 
1796 	/* Read the logical slot register for this Slot. */
1797 	reg = pcishpc_read_reg(slot_p->hs_ctrl,
1798 	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
1799 
1800 	/* Convert from the SHPC slot state to the HPC slot state. */
1801 	slot_p->hs_info.cn_state = pcishpc_slot_shpc_to_hpc(reg);
1802 	if (curr_state == DDI_HP_CN_STATE_POWERED &&
1803 	    slot_p->hs_info.cn_state > DDI_HP_CN_STATE_POWERED) {
1804 		/*
1805 		 * Keep POWERED state if it is currently POWERED state because
1806 		 * this driver does not really implement enable/disable
1807 		 * slot operations. That is, when poweron, it actually enables
1808 		 * the slot also.
1809 		 * So, from hardware view, POWERED == ENABLED.
1810 		 * But, when user explicitly change to POWERED state, it should
1811 		 * be kept until user explicitly change to other states later.
1812 		 */
1813 		slot_p->hs_info.cn_state = DDI_HP_CN_STATE_POWERED;
1814 	}
1815 
1816 	/* Convert from the SHPC Power LED state to the HPC Power LED state. */
1817 	slot_p->hs_power_led_state = pcishpc_led_shpc_to_hpc((reg>>2)&3);
1818 
1819 	/* Convert from the SHPC Attn LED state to the HPC Attn LED state. */
1820 	slot_p->hs_attn_led_state = pcishpc_led_shpc_to_hpc((reg>>4)&3);
1821 
1822 	/* We don't have a fault LED so just default it to OFF. */
1823 	slot_p->hs_fault_led_state = PCIE_HP_LED_OFF;
1824 
1825 	/* We don't have an active LED so just default it to OFF. */
1826 	slot_p->hs_active_led_state = PCIE_HP_LED_OFF;
1827 }
1828 
1829 /*
1830  * pcishpc_set_slot_state()
1831  *
1832  * Updates the slot's state and leds.
1833  */
1834 static int
1835 pcishpc_set_slot_state(pcie_hp_slot_t *slot_p,
1836     ddi_hp_cn_state_t new_slot_state)
1837 {
1838 	uint32_t		reg, cmd_code;
1839 	ddi_hp_cn_state_t	curr_state;
1840 
1841 	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
1842 
1843 	reg = pcishpc_read_reg(slot_p->hs_ctrl,
1844 	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
1845 
1846 	/* Default all states to unchanged. */
1847 	cmd_code = ((1 + slot_p->hs_num) << 8);
1848 
1849 	/* Has the slot state changed? */
1850 	curr_state = pcishpc_slot_shpc_to_hpc(reg);
1851 	if (curr_state != new_slot_state) {
1852 		PCIE_DBG("pcishpc_set_slot_state() Slot State changed");
1853 
1854 		/* Set the new slot state in the Slot operation command. */
1855 		cmd_code |= pcishpc_slot_hpc_to_shpc(new_slot_state);
1856 	}
1857 
1858 	/* Has the Power LED state changed? */
1859 	if (slot_p->hs_power_led_state != pcishpc_led_shpc_to_hpc((reg>>2)&3)) {
1860 		PCIE_DBG("pcishpc_set_slot_state() Power LED State changed\n");
1861 
1862 		/* Set the new power led state in the Slot operation command. */
1863 		cmd_code |=
1864 		    (pcishpc_led_hpc_to_shpc(slot_p->hs_power_led_state) << 2);
1865 	}
1866 
1867 	/* Has the Attn LED state changed? */
1868 	if (slot_p->hs_attn_led_state != pcishpc_led_shpc_to_hpc((reg>>4)&3)) {
1869 		PCIE_DBG("pcishpc_set_slot_state() Attn LED State changed\n");
1870 
1871 		/* Set the new attn led state in the Slot operation command. */
1872 		cmd_code |=
1873 		    (pcishpc_led_hpc_to_shpc(slot_p->hs_attn_led_state) << 4);
1874 	}
1875 
1876 	return (pcishpc_issue_command(slot_p->hs_ctrl, cmd_code));
1877 }
1878 
1879 /*
1880  * setup slot name/slot-number info.
1881  */
1882 static void
1883 pcishpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p, int slot)
1884 {
1885 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[slot];
1886 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1887 	uchar_t *slotname_data;
1888 	int *slotnum;
1889 	uint_t count;
1890 	int len;
1891 	uchar_t *s;
1892 	uint32_t bit_mask;
1893 	int pci_id_cnt, pci_id_bit;
1894 	int slots_before, found;
1895 	int invalid_slotnum = 0;
1896 
1897 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ctrl_p->hc_dip,
1898 	    DDI_PROP_DONTPASS, "physical-slot#", &slotnum, &count) ==
1899 	    DDI_PROP_SUCCESS) {
1900 		slot_p->hs_phy_slot_num = slotnum[0];
1901 		ddi_prop_free(slotnum);
1902 	} else {
1903 		if (ctrl_p->hc_device_increases)
1904 			slot_p->hs_phy_slot_num = ctrl_p->hc_phys_start + slot;
1905 		else
1906 			slot_p->hs_phy_slot_num = ctrl_p->hc_phys_start - slot;
1907 
1908 		if ((ndi_prop_update_int(DDI_DEV_T_NONE, ctrl_p->hc_dip,
1909 		    "physical-slot#", slot_p->hs_phy_slot_num)) != DDI_SUCCESS)
1910 			PCIE_DBG("pcishpc_set_slot_name(): failed to "
1911 			    "create phyical-slot#%d\n",
1912 			    slot_p->hs_phy_slot_num);
1913 	}
1914 
1915 	/* Platform may not have initialized it */
1916 	if (!slot_p->hs_phy_slot_num) {
1917 		slot_p->hs_phy_slot_num = pci_config_get8(bus_p->bus_cfg_hdl,
1918 		    PCI_BCNF_SECBUS);
1919 		invalid_slotnum = 1;
1920 	}
1921 	slot_p->hs_info.cn_num = slot_p->hs_phy_slot_num;
1922 	slot_p->hs_info.cn_num_dpd_on = DDI_HP_CN_NUM_NONE;
1923 
1924 	/*
1925 	 * construct the slot_name:
1926 	 * 	if "slot-names" property exists then use that name
1927 	 *	else if valid slot number exists then it is "pci<slot-num>".
1928 	 *	else it will be "pci<sec-bus-number>dev<dev-number>"
1929 	 */
1930 	if (ddi_getlongprop(DDI_DEV_T_ANY, ctrl_p->hc_dip, DDI_PROP_DONTPASS,
1931 	    "slot-names", (caddr_t)&slotname_data, &len) == DDI_PROP_SUCCESS) {
1932 		bit_mask = slotname_data[3] | (slotname_data[2] << 8) |
1933 		    (slotname_data[1] << 16) | (slotname_data[0] << 24);
1934 
1935 		pci_id_bit = 1;
1936 		pci_id_cnt = slots_before = found = 0;
1937 
1938 		/*
1939 		 * Walk the bit mask until we find the bit that corresponds
1940 		 * to our slots device number.  We count how many bits
1941 		 * we find before we find our slot's bit.
1942 		 */
1943 		while (!found && (pci_id_cnt < 32)) {
1944 			while (slot_p->hs_device_num != pci_id_cnt) {
1945 
1946 				/*
1947 				 * Find the next bit set.
1948 				 */
1949 				while (!(bit_mask & pci_id_bit) &&
1950 				    (pci_id_cnt < 32)) {
1951 					pci_id_bit = pci_id_bit << 1;
1952 					pci_id_cnt++;
1953 				}
1954 
1955 				if (slot_p->hs_device_num != pci_id_cnt)
1956 					slots_before++;
1957 				else
1958 					found = 1;
1959 			}
1960 		}
1961 
1962 		if (pci_id_cnt < 32) {
1963 
1964 			/*
1965 			 * Set ptr to first string.
1966 			 */
1967 			s = slotname_data + 4;
1968 
1969 			/*
1970 			 * Increment past all the strings for the slots
1971 			 * before ours.
1972 			 */
1973 			while (slots_before) {
1974 				while (*s != NULL)
1975 					s++;
1976 				s++;
1977 				slots_before--;
1978 			}
1979 
1980 			slot_p->hs_info.cn_name = i_ddi_strdup((char *)s,
1981 			    KM_SLEEP);
1982 			kmem_free(slotname_data, len);
1983 			return;
1984 		}
1985 
1986 		/* slot-names entry not found */
1987 		PCIE_DBG("pcishpc_set_slot_name(): "
1988 		    "No slot-names entry found for slot #%d\n",
1989 		    slot_p->hs_phy_slot_num);
1990 		kmem_free(slotname_data, len);
1991 	}
1992 
1993 	if (invalid_slotnum) {
1994 		char tmp_name[256];
1995 
1996 		(void) snprintf(tmp_name, sizeof (tmp_name), "pci%d",
1997 		    slot_p->hs_device_num);
1998 		slot_p->hs_info.cn_name = i_ddi_strdup(tmp_name, KM_SLEEP);
1999 	} else {
2000 		char tmp_name[256];
2001 
2002 		(void) snprintf(tmp_name, sizeof (tmp_name), "pci%d",
2003 		    slot_p->hs_phy_slot_num);
2004 		slot_p->hs_info.cn_name = i_ddi_strdup(tmp_name, KM_SLEEP);
2005 	}
2006 }
2007 
2008 /*
2009  * pcishpc_set_bus_speed()
2010  *
2011  * Set the bus speed and mode.
2012  */
2013 static int
2014 pcishpc_set_bus_speed(pcie_hp_slot_t *slot_p)
2015 {
2016 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
2017 	int		curr_speed = ctrl_p->hc_curr_bus_speed;
2018 	int		speed = -1;
2019 	int		avail_slots;
2020 	uint32_t	status, slots_avail1_reg, slots_avail2_reg;
2021 
2022 	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
2023 
2024 	/* Make sure that the slot is in a correct state */
2025 	status = pcishpc_read_reg(ctrl_p,
2026 	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
2027 
2028 	/* Return failure if the slot is empty */
2029 	if ((status & PCI_HP_SLOT_CARD_EMPTY_MASK) ==
2030 	    PCI_HP_SLOT_CARD_EMPTY_MASK) {
2031 		PCIE_DBG("pcishpc_set_bus_speed() failed: "
2032 		    "the slot is empty\n");
2033 		return (DDI_FAILURE);
2034 	}
2035 
2036 	/* Return failure if the slot is not in disabled state */
2037 	if ((status & PCI_HP_SLOT_STATE_MASK) != PCI_HP_SLOT_DISABLED) {
2038 		PCIE_DBG("pcishpc_set_bus_speed() failed: "
2039 		    "incorrect slot state\n");
2040 		return (DDI_FAILURE);
2041 	}
2042 
2043 	/* Set the "power-only" mode for the slot */
2044 	if (pcishpc_issue_command(ctrl_p, ((1+slot_p->hs_num)<<8) |
2045 	    PCI_HP_SLOT_POWER_ONLY) != DDI_SUCCESS) {
2046 		PCIE_DBG("pcishpc_set_bus_speed() failed to set "
2047 		    "the slot %d in the power-only mode\n", slot_p->hs_num);
2048 		return (DDI_FAILURE);
2049 	}
2050 
2051 	/* Wait for power good */
2052 	delay(drv_usectohz(PCIE_HP_POWER_GOOD_WAIT_TIME));
2053 
2054 	/* Make sure that the slot is in "power-only" state */
2055 	status = pcishpc_read_reg(ctrl_p,
2056 	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
2057 
2058 	if ((status & PCI_HP_SLOT_STATE_MASK) != PCI_HP_SLOT_POWER_ONLY) {
2059 		PCIE_DBG("pcishpc_set_bus_speed() "
2060 		    "power-only failed: incorrect slot state\n");
2061 		return (DDI_FAILURE);
2062 	}
2063 
2064 	slots_avail1_reg = pcishpc_read_reg(ctrl_p,
2065 	    PCI_HP_SLOTS_AVAIL_I_REG);
2066 	slots_avail2_reg = pcishpc_read_reg(ctrl_p,
2067 	    PCI_HP_SLOTS_AVAIL_II_REG);
2068 
2069 	/*
2070 	 * Check if SHPC has available slots and select the highest
2071 	 * available bus speed for the slot.
2072 	 *
2073 	 * The bus speed codes are:
2074 	 * 100 - 133Mhz; <--+
2075 	 * 011 - 100Mhz; <--+   PCI-X
2076 	 * 010 - 66Mhz;  <--+
2077 	 *
2078 	 * 001 - 66Mhz;  <--+
2079 	 * 000 - 33Mhz   <--+   Conv PCI
2080 	 */
2081 	switch (status & PCI_HP_SLOT_PCIX_CAPABLE_MASK) {
2082 	case PCI_HP_SLOT_133MHZ_PCIX_CAPABLE:
2083 		avail_slots = (slots_avail1_reg >>
2084 		    PCI_HP_AVAIL_133MHZ_PCIX_SPEED_SHIFT) &
2085 		    PCI_HP_AVAIL_SPEED_MASK;
2086 
2087 		if (((curr_speed == -1) && avail_slots) ||
2088 		    (curr_speed == PCI_HP_SBCR_133MHZ_PCIX_SPEED)) {
2089 			speed = PCI_HP_SBCR_133MHZ_PCIX_SPEED;
2090 			break;
2091 		}
2092 		/* FALLTHROUGH */
2093 	case PCI_HP_SLOT_100MHZ_PCIX_CAPABLE:
2094 		avail_slots = (slots_avail1_reg >>
2095 		    PCI_HP_AVAIL_100MHZ_PCIX_SPEED_SHIFT) &
2096 		    PCI_HP_AVAIL_SPEED_MASK;
2097 
2098 		if (((curr_speed == -1) && avail_slots) ||
2099 		    (curr_speed == PCI_HP_SBCR_100MHZ_PCIX_SPEED)) {
2100 			speed = PCI_HP_SBCR_100MHZ_PCIX_SPEED;
2101 			break;
2102 		}
2103 		/* FALLTHROUGH */
2104 	case PCI_HP_SLOT_66MHZ_PCIX_CAPABLE:
2105 		avail_slots = (slots_avail1_reg >>
2106 		    PCI_HP_AVAIL_66MHZ_PCIX_SPEED_SHIFT) &
2107 		    PCI_HP_AVAIL_SPEED_MASK;
2108 
2109 		if (((curr_speed == -1) && avail_slots) ||
2110 		    (curr_speed == PCI_HP_SBCR_66MHZ_PCIX_SPEED)) {
2111 			speed = PCI_HP_SBCR_66MHZ_PCIX_SPEED;
2112 			break;
2113 		}
2114 		/* FALLTHROUGH */
2115 	default:
2116 		avail_slots = (slots_avail2_reg >>
2117 		    PCI_HP_AVAIL_66MHZ_CONV_SPEED_SHIFT) &
2118 		    PCI_HP_AVAIL_SPEED_MASK;
2119 
2120 		if ((status & PCI_HP_SLOT_66MHZ_CONV_CAPABLE) &&
2121 		    (((curr_speed == -1) && avail_slots) ||
2122 		    (curr_speed == PCI_HP_SBCR_66MHZ_CONV_SPEED))) {
2123 			speed = PCI_HP_SBCR_66MHZ_CONV_SPEED;
2124 		} else {
2125 			avail_slots = (slots_avail1_reg >>
2126 			    PCI_HP_AVAIL_33MHZ_CONV_SPEED_SHIFT) &
2127 			    PCI_HP_AVAIL_SPEED_MASK;
2128 
2129 			if (((curr_speed == -1) && (avail_slots)) ||
2130 			    (curr_speed == PCI_HP_SBCR_33MHZ_CONV_SPEED)) {
2131 				speed = PCI_HP_SBCR_33MHZ_CONV_SPEED;
2132 			} else {
2133 				PCIE_DBG("pcishpc_set_bus_speed() "
2134 				    " failed to set the bus speed, slot# %d\n",
2135 				    slot_p->hs_num);
2136 				return (DDI_FAILURE);
2137 			}
2138 		}
2139 		break;
2140 	}
2141 
2142 	/*
2143 	 * If the bus segment is already running, check to see the card
2144 	 * in the slot can support the current bus speed.
2145 	 */
2146 	if (curr_speed == speed) {
2147 		/*
2148 		 * Check to see there is any slot available for the current
2149 		 * bus speed. Otherwise, we need fail the current slot connect
2150 		 * request.
2151 		 */
2152 		return ((avail_slots <= ctrl_p->hc_num_slots_connected) ?
2153 		    DDI_FAILURE : DDI_SUCCESS);
2154 	}
2155 
2156 	/* Set the bus speed */
2157 	if (pcishpc_issue_command(ctrl_p, PCI_HP_COMM_STS_SET_SPEED |
2158 	    speed) == DDI_FAILURE) {
2159 		PCIE_DBG("pcishpc_set_bus_speed() failed "
2160 		    "to set bus %d speed\n", slot_p->hs_num);
2161 		return (DDI_FAILURE);
2162 	}
2163 
2164 	/* Check the current bus speed */
2165 	status = pcishpc_read_reg(ctrl_p, PCI_HP_PROF_IF_SBCR_REG) &
2166 	    PCI_HP_SBCR_SPEED_MASK;
2167 	if ((status & PCI_HP_SBCR_SPEED_MASK) != speed) {
2168 		PCIE_DBG("pcishpc_set_bus_speed() an incorrect "
2169 		    "bus speed, slot = 0x%x, speed = 0x%x\n",
2170 		    slot_p->hs_num, status & PCI_HP_SBCR_SPEED_MASK);
2171 		return (DDI_FAILURE);
2172 	}
2173 
2174 
2175 	/* Save the current bus speed */
2176 	ctrl_p->hc_curr_bus_speed = speed;
2177 
2178 	return (DDI_SUCCESS);
2179 }
2180 
2181 /*
2182  * pcishpc_setled()
2183  *
2184  * Change the state of a slot's LED.
2185  */
2186 static int
2187 pcishpc_setled(pcie_hp_slot_t *slot_p, pcie_hp_led_t led,
2188     pcie_hp_led_state_t state)
2189 {
2190 	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
2191 
2192 	switch (led) {
2193 		case PCIE_HP_FAULT_LED:
2194 			PCIE_DBG("pcishpc_setled() - PCIE_HP_FAULT_LED "
2195 			    "(set %s)\n", pcishpc_slot_textledstate(state));
2196 			slot_p->hs_fault_led_state = state;
2197 			break;
2198 
2199 		case PCIE_HP_POWER_LED:
2200 			PCIE_DBG("pcishpc_setled() - PCIE_HP_POWER_LED "
2201 			    "(set %s)\n", pcishpc_slot_textledstate(state));
2202 			slot_p->hs_power_led_state = state;
2203 			break;
2204 
2205 		case PCIE_HP_ATTN_LED:
2206 			PCIE_DBG("pcishpc_setled() - PCIE_HP_ATTN_LED "
2207 			    "(set %s)\n", pcishpc_slot_textledstate(state));
2208 			slot_p->hs_attn_led_state = state;
2209 			break;
2210 
2211 		case PCIE_HP_ACTIVE_LED:
2212 			PCIE_DBG("pcishpc_setled() - PCIE_HP_ACTIVE_LED "
2213 			    "(set %s)\n", pcishpc_slot_textledstate(state));
2214 			slot_p->hs_active_led_state = state;
2215 			break;
2216 	}
2217 
2218 	return (pcishpc_set_slot_state(slot_p, slot_p->hs_info.cn_state));
2219 }
2220 
2221 /*
2222  * pcishpc_led_shpc_to_hpc()
2223  *
2224  * Convert from SHPC indicator status to HPC indicator status.
2225  */
2226 static int
2227 pcishpc_led_shpc_to_hpc(int state)
2228 {
2229 	switch (state) {
2230 		case 1:	/* SHPC On bits b01 */
2231 			return (PCIE_HP_LED_ON);
2232 		case 2:	/* SHPC Blink bits b10 */
2233 			return (PCIE_HP_LED_BLINK);
2234 		case 3:	/* SHPC Off bits b11 */
2235 			return (PCIE_HP_LED_OFF);
2236 	}
2237 
2238 	return (PCIE_HP_LED_OFF);
2239 }
2240 
2241 
2242 /*
2243  * pcishpc_led_hpc_to_shpc()
2244  *
2245  * Convert from HPC indicator status to SHPC indicator status.
2246  */
2247 static int
2248 pcishpc_led_hpc_to_shpc(int state)
2249 {
2250 	switch (state) {
2251 		case PCIE_HP_LED_ON:
2252 			return (1); /* SHPC On bits b01 */
2253 		case PCIE_HP_LED_BLINK:
2254 			return (2); /* SHPC Blink bits b10 */
2255 		case PCIE_HP_LED_OFF:
2256 			return (3); /* SHPC Off bits b11 */
2257 	}
2258 
2259 	return (3); /* SHPC Off bits b11 */
2260 }
2261 
2262 /*
2263  * pcishpc_slot_shpc_to_hpc()
2264  *
2265  * Convert from SHPC slot state to HPC slot state.
2266  * The argument shpc_state is expected to be read from the slot register.
2267  */
2268 static int
2269 pcishpc_slot_shpc_to_hpc(int shpc_state)
2270 {
2271 	if ((shpc_state & PCI_HP_SLOT_CARD_EMPTY_MASK) ==
2272 	    PCI_HP_SLOT_CARD_EMPTY_MASK)
2273 		return (DDI_HP_CN_STATE_EMPTY);
2274 
2275 	switch (shpc_state & PCI_HP_SLOT_STATE_MASK) {
2276 		case PCI_HP_SLOT_POWER_ONLY: /* SHPC Powered Only */
2277 			return (DDI_HP_CN_STATE_POWERED);
2278 
2279 		case PCI_HP_SLOT_ENABLED: /* SHPC Enabled */
2280 			return (DDI_HP_CN_STATE_ENABLED);
2281 
2282 		case PCI_HP_SLOT_DISABLED:	/* SHPC Disabled */
2283 		default :			/* SHPC Reserved */
2284 			return (DDI_HP_CN_STATE_PRESENT);
2285 	}
2286 }
2287 
2288 /*
2289  * pcishpc_slot_hpc_to_shpc()
2290  *
2291  * Convert from HPC slot state to SHPC slot state.
2292  */
2293 static int
2294 pcishpc_slot_hpc_to_shpc(int state)
2295 {
2296 	switch (state) {
2297 		case DDI_HP_CN_STATE_EMPTY:
2298 			return (0);
2299 
2300 		case DDI_HP_CN_STATE_POWERED:
2301 			return (PCI_HP_SLOT_POWER_ONLY);
2302 
2303 		case DDI_HP_CN_STATE_ENABLED:
2304 			return (PCI_HP_SLOT_ENABLED);
2305 
2306 		default:
2307 			return (PCI_HP_SLOT_DISABLED);
2308 	}
2309 }
2310 
2311 /*
2312  * pcishpc_slot_textslotstate()
2313  *
2314  * Convert the request into a text message.
2315  */
2316 static char *
2317 pcishpc_slot_textslotstate(ddi_hp_cn_state_t state)
2318 {
2319 	/* Convert an HPC slot state into a textual string. */
2320 	if (state == DDI_HP_CN_STATE_EMPTY)
2321 		return ("HPC_SLOT_EMPTY");
2322 	else if (state == DDI_HP_CN_STATE_ENABLED)
2323 		return ("HPC_SLOT_ENABLED");
2324 	else if (state == DDI_HP_CN_STATE_POWERED)
2325 		return ("HPC_SLOT_POWERED_ONLY");
2326 	else
2327 		return ("HPC_SLOT_DISABLED");
2328 }
2329 
2330 
2331 /*
2332  * pcishpc_slot_textledstate()
2333  *
2334  * Convert the led state into a text message.
2335  */
2336 static char *
2337 pcishpc_slot_textledstate(pcie_hp_led_state_t state)
2338 {
2339 	/* Convert an HPC led state into a textual string. */
2340 	switch (state) {
2341 		case PCIE_HP_LED_OFF:
2342 			return ("off");
2343 
2344 		case PCIE_HP_LED_ON:
2345 			return ("on");
2346 
2347 		case PCIE_HP_LED_BLINK:
2348 			return ("blink");
2349 	}
2350 	return ("unknown");
2351 }
2352 
2353 
2354 /*
2355  * pcishpc_read_reg()
2356  *
2357  * Read from a SHPC controller register.
2358  */
2359 static uint32_t
2360 pcishpc_read_reg(pcie_hp_ctrl_t *ctrl_p, int reg)
2361 {
2362 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
2363 
2364 	/* Setup the SHPC dword select register. */
2365 	pci_config_put8(bus_p->bus_cfg_hdl,
2366 	    bus_p->bus_pci_hp_off + PCI_HP_DWORD_SELECT_OFF, (uint8_t)reg);
2367 
2368 	/* Read back the SHPC dword select register and verify. */
2369 	if (pci_config_get8(bus_p->bus_cfg_hdl, bus_p->bus_pci_hp_off +
2370 	    PCI_HP_DWORD_SELECT_OFF) != (uint8_t)reg) {
2371 		PCIE_DBG("pcishpc_read_reg() - Failed writing DWORD "
2372 		    "select reg\n");
2373 		return (0xFFFFFFFF);
2374 	}
2375 
2376 	/* Read from the SHPC dword data register. */
2377 	return (pci_config_get32(bus_p->bus_cfg_hdl,
2378 	    bus_p->bus_pci_hp_off + PCI_HP_DWORD_DATA_OFF));
2379 }
2380 
2381 
2382 /*
2383  * pcishpc_write_reg()
2384  *
2385  * Write to a SHPC controller register.
2386  */
2387 static void
2388 pcishpc_write_reg(pcie_hp_ctrl_t *ctrl_p, int reg, uint32_t data)
2389 {
2390 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
2391 
2392 	/* Setup the SHPC dword select register. */
2393 	pci_config_put8(bus_p->bus_cfg_hdl,
2394 	    bus_p->bus_pci_hp_off + PCI_HP_DWORD_SELECT_OFF, (uint8_t)reg);
2395 
2396 	/* Read back the SHPC dword select register and verify. */
2397 	if (pci_config_get8(bus_p->bus_cfg_hdl, bus_p->bus_pci_hp_off +
2398 	    PCI_HP_DWORD_SELECT_OFF) != (uint8_t)reg) {
2399 		PCIE_DBG("pcishpc_write_reg() - Failed writing "
2400 		    "DWORD select reg\n");
2401 		return;
2402 	}
2403 
2404 	/* Write to the SHPC dword data register. */
2405 	pci_config_put32(bus_p->bus_cfg_hdl,
2406 	    bus_p->bus_pci_hp_off + PCI_HP_DWORD_DATA_OFF, data);
2407 
2408 	/*
2409 	 * Issue a read of the VendorID/DeviceID just to force the previous
2410 	 * write to complete. This is probably not necessary, but it does
2411 	 * help enforce ordering if there is an issue.
2412 	 */
2413 	(void) pci_config_get16(bus_p->bus_cfg_hdl, PCI_CONF_VENID);
2414 }
2415 
2416 
2417 #ifdef	DEBUG
2418 /*
2419  * pcishpc_dump_regs()
2420  *
2421  * Dumps all of the SHPC controller registers.
2422  */
2423 static void
2424 pcishpc_dump_regs(pcie_hp_ctrl_t *ctrl_p)
2425 {
2426 	int slot, numSlots;
2427 	uint32_t reg;
2428 	char *state;
2429 
2430 	if (!pcie_debug_flags)
2431 		return;
2432 
2433 	PCIE_DBG("pcishpc_dump_regs() called:\n");
2434 	PCIE_DBG("==========================================================");
2435 
2436 	PCIE_DBG("SHPC Base Offset				"
2437 	    ": 0x%08x\n", pcishpc_read_reg(ctrl_p, PCI_HP_BASE_OFFSET_REG));
2438 
2439 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOTS_AVAIL_I_REG);
2440 
2441 	PCIE_DBG("Number of PCIX slots avail (33 Mhz)		 : %d\n",
2442 	    (reg & 31));
2443 
2444 	PCIE_DBG("Number of PCIX slots avail (66 Mhz)		 : %d\n",
2445 	    ((reg>>8) & 31));
2446 
2447 	PCIE_DBG("Number of PCIX slots avail (100 Mhz)		: %d\n",
2448 	    ((reg>>16) & 31));
2449 
2450 	PCIE_DBG("Number of PCIX slots avail (133 Mhz)		: %d\n",
2451 	    ((reg>>24) & 31));
2452 
2453 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOTS_AVAIL_II_REG);
2454 
2455 	PCIE_DBG("Number of conventional PCI slots (66 Mhz) : %d\n",
2456 	    (reg & 31));
2457 
2458 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOT_CONFIGURATION_REG);
2459 
2460 	numSlots = (reg & 31);
2461 
2462 	PCIE_DBG("Number of Slots connected to this port	 : %d\n",
2463 	    numSlots);
2464 
2465 	PCIE_DBG("PCI Device # for First HotPlug Slot		 : %d\n",
2466 	    ((reg>>8) & 31));
2467 
2468 	PCIE_DBG("Physical Slot # for First PCI Device #	 : %d\n",
2469 	    ((reg>>16) & 0x7ff));
2470 
2471 	PCIE_DBG("Physical Slot Number Up/Down			 : %d\n",
2472 	    ((reg>>29) & 0x1));
2473 
2474 	PCIE_DBG("MRL Sensor Implemented			 : %s\n",
2475 	    (reg & PCI_HP_SLOT_CONFIG_MRL_SENSOR) ? "Yes" : "No");
2476 
2477 	PCIE_DBG("Attention Button Implemented			 : %s\n",
2478 	    (reg & PCI_HP_SLOT_CONFIG_ATTN_BUTTON) ? "Yes" : "No");
2479 
2480 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_PROF_IF_SBCR_REG);
2481 
2482 	switch (reg & 7) {
2483 		case 0:
2484 			state = "33Mhz Conventional PCI";
2485 			break;
2486 		case 1:
2487 			state = "66Mhz Conventional PCI";
2488 			break;
2489 		case 2:
2490 			state = "66Mhz PCI-X";
2491 			break;
2492 		case 3:
2493 			state = "100Mhz PCI-X";
2494 			break;
2495 		case 4:
2496 			state = "133Mhz PCI-X";
2497 			break;
2498 		default:
2499 			state = "Reserved (Error)";
2500 			break;
2501 	}
2502 
2503 	PCIE_DBG("Current Port Operation Mode		: %s\n", state);
2504 
2505 	PCIE_DBG("SHPC Interrupt Message Number		: %d\n",
2506 	    ((reg>>16) &31));
2507 
2508 	PCIE_DBG("SHPC Programming Interface		: %d\n",
2509 	    ((reg>>24) & 0xff));
2510 
2511 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG);
2512 
2513 	PCIE_DBG("SHPC Command Code			: %d\n",
2514 	    (reg & 0xff));
2515 
2516 	PCIE_DBG("SHPC Target Slot			: %d\n",
2517 	    ((reg>>8) & 31));
2518 
2519 	PCIE_DBG("SHPC Controller Busy			: %s\n",
2520 	    ((reg>>16) & 1) ? "Yes" : "No");
2521 
2522 	PCIE_DBG("SHPC Controller Err: MRL Sensor	: %s\n",
2523 	    ((reg>>17) & 1) ? "Yes" : "No");
2524 
2525 	PCIE_DBG("SHPC Controller Err: Invalid Command	: %s\n",
2526 	    ((reg>>18) & 1) ? "Yes" : "No");
2527 
2528 	PCIE_DBG("SHPC Controller Err: Invalid Speed/Mode : %s\n",
2529 	    ((reg>>19) & 1) ? "Yes" : "No");
2530 
2531 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_IRQ_LOCATOR_REG);
2532 
2533 	PCIE_DBG("Command Completion Interrupt Pending	: %s\n",
2534 	    (reg & PCI_HP_IRQ_CMD_COMPLETE) ? "Yes" : "No");
2535 
2536 	for (slot = 0; slot < numSlots; slot++) {
2537 		PCIE_DBG("Slot %d Interrupt Pending	: %s\n", slot+1,
2538 		    (reg & (PCI_HP_IRQ_SLOT_N_PENDING<<slot)) ? "Yes" : "No");
2539 	}
2540 
2541 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_SERR_LOCATOR_REG);
2542 
2543 	PCIE_DBG("Arbiter SERR Pending			: %s\n",
2544 	    (reg & PCI_HP_IRQ_SERR_ARBITER_PENDING) ? "Yes" : "No");
2545 
2546 	for (slot = 0; slot < numSlots; slot++) {
2547 		PCIE_DBG("Slot %d SERR Pending		: %s\n",
2548 		    slot+1, (reg &
2549 		    (PCI_HP_IRQ_SERR_SLOT_N_PENDING<<slot)) ? "Yes" : "No");
2550 	}
2551 
2552 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG);
2553 
2554 	PCIE_DBG("Global Interrupt Mask			: %s\n",
2555 	    (reg & PCI_HP_SERR_INT_GLOBAL_IRQ_MASK) ? "Yes" : "No");
2556 
2557 	PCIE_DBG("Global SERR Mask			: %s\n",
2558 	    (reg & PCI_HP_SERR_INT_GLOBAL_SERR_MASK) ? "Yes" : "No");
2559 
2560 	PCIE_DBG("Command Completion Interrupt Mask	: %s\n",
2561 	    (reg & PCI_HP_SERR_INT_CMD_COMPLETE_MASK) ? "Yes" : "No");
2562 
2563 	PCIE_DBG("Arbiter SERR Mask			: %s\n",
2564 	    (reg & PCI_HP_SERR_INT_ARBITER_SERR_MASK) ? "Yes" : "No");
2565 
2566 	PCIE_DBG("Command Completion Detected		: %s\n",
2567 	    (reg & PCI_HP_SERR_INT_CMD_COMPLETE_IRQ) ? "Yes" : "No");
2568 
2569 	PCIE_DBG("Arbiter Timeout Detected		: %s\n",
2570 	    (reg & PCI_HP_SERR_INT_ARBITER_IRQ) ? "Yes" : "No");
2571 
2572 	for (slot = 0; slot < numSlots; slot++) {
2573 		PCIE_DBG("Logical Slot %d Registers:\n", slot+1);
2574 		PCIE_DBG("------------------------------------\n");
2575 
2576 		reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot);
2577 
2578 		PCIE_DBG("Slot %d state			: %s\n", slot+1,
2579 		    pcishpc_slot_textslotstate(pcishpc_slot_shpc_to_hpc(reg)));
2580 
2581 		PCIE_DBG("Slot %d Power Indicator State	: %s\n", slot+1,
2582 		    pcishpc_slot_textledstate(pcishpc_led_shpc_to_hpc(
2583 		    (reg>>2) &3)));
2584 
2585 		PCIE_DBG("Slot %d Attention Indicator State : %s\n", slot+1,
2586 		    pcishpc_slot_textledstate(pcishpc_led_shpc_to_hpc(
2587 		    (reg>>4)&3)));
2588 
2589 		PCIE_DBG("Slot %d Power Fault		: %s\n", slot+1,
2590 		    ((reg>>6)&1) ? "Fault Detected" : "No Fault");
2591 		PCIE_DBG("Slot %d Attention Button	: %s\n", slot+1,
2592 		    ((reg>>7)&1) ? "Depressed" : "Not Depressed");
2593 		PCIE_DBG("Slot %d MRL Sensor		: %s\n", slot+1,
2594 		    ((reg>>8)&1) ? "Not Closed" : "Closed");
2595 		PCIE_DBG("Slot %d 66mhz Capable		: %s\n", slot+1,
2596 		    ((reg>>9)&1) ? "66mhz" : "33mgz");
2597 
2598 		switch ((reg>>10)&3) {
2599 			case 0:
2600 				state = "Card Present 7.5W";
2601 				break;
2602 			case 1:
2603 				state = "Card Present 15W";
2604 				break;
2605 			case 2:
2606 				state = "Card Present 25W";
2607 				break;
2608 			case 3:
2609 				state = "Slot Empty";
2610 				break;
2611 		}
2612 
2613 		PCIE_DBG("Slot %d PRSNT1#/PRSNT2#	: %s\n", slot+1,
2614 		    state);
2615 
2616 		switch ((reg>>12)&3) {
2617 			case 0:
2618 				state = "Non PCI-X";
2619 				break;
2620 			case 1:
2621 				state = "66mhz PCI-X";
2622 				break;
2623 			case 2:
2624 				state = "Reserved";
2625 				break;
2626 			case 3:
2627 				state = "133mhz PCI-X";
2628 				break;
2629 		}
2630 
2631 		PCIE_DBG("Slot %d Card Presence Change Detected	  : %s\n",
2632 		    slot+1, (reg & PCI_HP_SLOT_PRESENCE_DETECTED) ? "Yes" :
2633 		    "No");
2634 		PCIE_DBG("Slot %d Isolated Power Fault Detected	  : %s\n",
2635 		    slot+1, (reg & PCI_HP_SLOT_ISO_PWR_DETECTED) ? "Yes" :
2636 		    "No");
2637 		PCIE_DBG("Slot %d Attention Button Press Detected : %s\n",
2638 		    slot+1, (reg & PCI_HP_SLOT_ATTN_DETECTED) ? "Yes" : "No");
2639 		PCIE_DBG("Slot %d MRL Sensor Change Detected	  : %s\n",
2640 		    slot+1, (reg & PCI_HP_SLOT_MRL_DETECTED) ? "Yes" : "No");
2641 		PCIE_DBG("Slot %d Connected Power Fault Detected  : %s\n",
2642 		    slot+1, (reg & PCI_HP_SLOT_POWER_DETECTED) ? "Yes" : "No");
2643 
2644 		PCIE_DBG("Slot %d Card Presence IRQ Masked	  : %s\n",
2645 		    slot+1, (reg & PCI_HP_SLOT_PRESENCE_MASK) ? "Yes" : "No");
2646 		PCIE_DBG("Slot %d Isolated Power Fault IRQ Masked : %s\n",
2647 		    slot+1, (reg & PCI_HP_SLOT_ISO_PWR_MASK) ? "Yes" : "No");
2648 		PCIE_DBG("Slot %d Attention Button IRQ Masked	  : %s\n",
2649 		    slot+1, (reg & PCI_HP_SLOT_ATTN_MASK) ? "Yes" : "No");
2650 		PCIE_DBG("Slot %d MRL Sensor IRQ Masked		  : %s\n",
2651 		    slot+1, (reg & PCI_HP_SLOT_MRL_MASK) ? "Yes" : "No");
2652 		PCIE_DBG("Slot %d Connected Power Fault IRQ Masked : %s\n",
2653 		    slot+1, (reg & PCI_HP_SLOT_POWER_MASK) ? "Yes" : "No");
2654 		PCIE_DBG("Slot %d MRL Sensor SERR Masked          : %s\n",
2655 		    slot+1, (reg & PCI_HP_SLOT_MRL_SERR_MASK) ? "Yes" : "No");
2656 		PCIE_DBG("Slot %d Connected Power Fault SERR Masked : %s\n",
2657 		    slot+1, (reg & PCI_HP_SLOT_POWER_SERR_MASK) ? "Yes" : "No");
2658 	}
2659 }
2660 #endif	/* DEBUG */
2661