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