xref: /titanic_51/usr/src/uts/common/io/pciex/hotplug/pcishpc.c (revision 269473047d747f7815af570197e4ef7322d3632c)
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 			cmn_err(CE_WARN, "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 			cmn_err(CE_WARN, "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 			cmn_err(CE_WARN, "Get string value failed for property "
679 			    "%s.\n", 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 				cmn_err(CE_WARN, "Unsupported value of setting "
689 				    "property %s\n", name);
690 				ret = DDI_ENOTSUP;
691 				goto set_prop_cleanup;
692 			}
693 		} else {
694 			cmn_err(CE_WARN, "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 
723 	mutex_exit(&ctrl_p->hc_mutex);
724 set_prop_cleanup:
725 	nvlist_free(prop_list);
726 	return (ret);
727 }
728 
729 /*
730  * pcishpc_hp_ops()
731  *
732  * Handle hotplug commands
733  *
734  * Note: This function is called by DDI HP framework at kernel context only
735  */
736 /* ARGSUSED */
737 int
738 pcishpc_hp_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op,
739     void *arg, void *result)
740 {
741 	pcie_hp_slot_t	*slot_p = NULL;
742 	pcie_hp_ctrl_t	*ctrl_p;
743 	int		ret = DDI_SUCCESS, i;
744 
745 	PCIE_DBG("pcishpc_hp_ops: dip=%p cn_name=%s op=%x arg=%p\n",
746 	    dip, cn_name, op, arg);
747 
748 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
749 		return (DDI_FAILURE);
750 
751 	for (i = 0; i < PCIE_HP_MAX_SLOTS && ctrl_p->hc_slots[i]; i++) {
752 		if (strcmp(ctrl_p->hc_slots[i]->hs_info.cn_name, cn_name)
753 		    == 0) {
754 			/* Match with a physical slot, found */
755 			slot_p = ctrl_p->hc_slots[i];
756 			break;
757 		}
758 	}
759 	if (!slot_p) {
760 		PCIE_DBG("pcishpc_hp_ops: Failed to find the slot under"
761 		    "dip %p with name: %s; op=%x arg=%p\n",
762 		    dip, cn_name, op, arg);
763 		return (DDI_EINVAL);
764 	}
765 	switch (op) {
766 	case DDI_HPOP_CN_GET_STATE:
767 	{
768 		mutex_enter(&ctrl_p->hc_mutex);
769 
770 		/* get the current slot state */
771 		pcishpc_get_slot_state(slot_p);
772 
773 		*((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state;
774 
775 		mutex_exit(&ctrl_p->hc_mutex);
776 		break;
777 	}
778 	case DDI_HPOP_CN_CHANGE_STATE:
779 	{
780 		ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg;
781 
782 		mutex_enter(&slot_p->hs_ctrl->hc_mutex);
783 
784 		ret = pcishpc_change_slot_state(slot_p, target_state);
785 		*((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state;
786 
787 		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
788 		break;
789 	}
790 	case DDI_HPOP_CN_PROBE:
791 		ret = pcishpc_slot_probe(slot_p);
792 
793 		break;
794 	case DDI_HPOP_CN_UNPROBE:
795 		ret = pcishpc_slot_unprobe(slot_p);
796 
797 		break;
798 	case DDI_HPOP_CN_GET_PROPERTY:
799 		ret = pcishpc_slot_get_property(slot_p,
800 		    (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
801 		break;
802 	case DDI_HPOP_CN_SET_PROPERTY:
803 		ret = pcishpc_slot_set_property(slot_p,
804 		    (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
805 		break;
806 	default:
807 		ret = DDI_ENOTSUP;
808 		break;
809 	}
810 
811 	return (ret);
812 }
813 
814 /*
815  * Local functions (called within this file)
816  */
817 
818 /*
819  * pcishpc_create_controller()
820  *
821  * This function allocates and creates an SHPC controller state structure
822  * and adds it to the linked list of controllers.
823  */
824 static pcie_hp_ctrl_t *
825 pcishpc_create_controller(dev_info_t *dip)
826 {
827 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
828 	pcie_hp_ctrl_t	*ctrl_p;
829 
830 	PCIE_DBG("pcishpc: create controller for %s#%d\n",
831 	    ddi_driver_name(dip), ddi_get_instance(dip));
832 
833 	ctrl_p = kmem_zalloc(sizeof (pcie_hp_ctrl_t), KM_SLEEP);
834 	ctrl_p->hc_dip = dip;
835 
836 	cv_init(&ctrl_p->hc_cmd_comp_cv, NULL, CV_DRIVER, NULL);
837 
838 	/* Init the shpc controller's mutex. */
839 	mutex_init(&ctrl_p->hc_mutex, NULL, MUTEX_DRIVER, NULL);
840 
841 	/* HPC initialization is complete now */
842 	ctrl_p->hc_flags = PCIE_HP_INITIALIZED_FLAG;
843 	bus_p->bus_hp_curr_mode = PCIE_PCI_HP_MODE;
844 
845 	PCIE_SET_HP_CTRL(dip, ctrl_p);
846 
847 	PCIE_DBG("pcishpc_create_controller() success\n");
848 
849 	return (ctrl_p);
850 }
851 
852 
853 /*
854  * pcishpc_setup_controller()
855  *
856  * Get the number of HotPlug Slots, and the PCI device information
857  * for this HotPlug controller.
858  */
859 static int
860 pcishpc_setup_controller(pcie_hp_ctrl_t *ctrl_p)
861 {
862 	uint32_t config;
863 	dev_info_t *ppdip;
864 
865 	config = pcishpc_read_reg(ctrl_p, PCI_HP_SLOT_CONFIGURATION_REG);
866 
867 	/* Get the number of HotPlug slots implemented */
868 	ctrl_p->hc_num_slots_impl = ((config)&31);
869 
870 	/*
871 	 * Initilize the current bus speed and number of hotplug slots
872 	 * currently connected.
873 	 */
874 	ctrl_p->hc_curr_bus_speed = -1;
875 	ctrl_p->hc_num_slots_connected = 0;
876 
877 	/*
878 	 * Get the first PCI device Number used.
879 	 *
880 	 * PCI-X I/O boat workaround.
881 	 * The register doesn't set up the correct value.
882 	 */
883 	ppdip = ddi_get_parent(ddi_get_parent(ctrl_p->hc_dip));
884 	if ((ddi_prop_get_int(DDI_DEV_T_ANY, ppdip, DDI_PROP_DONTPASS,
885 	    "vendor-id", -1) == 0x108e) &&
886 	    (ddi_prop_get_int(DDI_DEV_T_ANY, ppdip, DDI_PROP_DONTPASS,
887 	    "device-id", -1) == 0x9010))
888 		ctrl_p->hc_device_start = 4;
889 	else
890 		ctrl_p->hc_device_start = ((config>>8)&31);
891 
892 	/* Get the first Physical device number. */
893 	ctrl_p->hc_phys_start = ((config>>16)&0x7ff);
894 
895 	/* Check if the device numbers increase or decrease. */
896 	ctrl_p->hc_device_increases = ((config>>29)&0x1);
897 
898 	ctrl_p->hc_has_attn =
899 	    (config & PCI_HP_SLOT_CONFIG_ATTN_BUTTON) ? B_TRUE : B_FALSE;
900 	ctrl_p->hc_has_mrl =
901 	    (config & PCI_HP_SLOT_CONFIG_MRL_SENSOR) ? B_TRUE : B_FALSE;
902 
903 	ctrl_p->hc_cmd_pending = B_FALSE;
904 	ctrl_p->hc_arbiter_timeout = B_FALSE;
905 
906 	if (ctrl_p->hc_num_slots_impl > PCIE_HP_MAX_SLOTS) {
907 		PCIE_DBG("pcishpc_setup_controller() too many SHPC "
908 		    "slots error\n");
909 		return (DDI_FAILURE);
910 	}
911 
912 	return (DDI_SUCCESS);
913 }
914 
915 
916 /*
917  * pcishpc_destroy_controller()
918  *
919  * This function deallocates all of the SHPC controller resources.
920  */
921 static int
922 pcishpc_destroy_controller(dev_info_t *dip)
923 {
924 	pcie_hp_ctrl_t	*ctrl_p;
925 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
926 
927 	PCIE_DBG("pcishpc_destroy_controller() called(dip=%p)\n", dip);
928 
929 	/* get the soft state structure for this dip */
930 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) {
931 		PCIE_DBG("pcishpc_destroy_controller() not found\n");
932 		return (DDI_FAILURE);
933 	}
934 
935 	/*
936 	 * Deallocate the slot state structures for this controller.
937 	 */
938 	(void) pcishpc_destroy_slots(ctrl_p);
939 	cv_destroy(&ctrl_p->hc_cmd_comp_cv);
940 	mutex_destroy(&ctrl_p->hc_mutex);
941 	kmem_free(ctrl_p, sizeof (pcie_hp_ctrl_t));
942 	bus_p->bus_hp_curr_mode = PCIE_NONE_HP_MODE;
943 
944 	PCIE_DBG("pcishpc_destroy_controller() success\n");
945 	return (DDI_SUCCESS);
946 }
947 
948 /*
949  * pcishpc_create_slot()
950  *
951  * Allocate and add a new HotPlug slot state structure to the linked list.
952  */
953 static pcie_hp_slot_t *
954 pcishpc_create_slot(pcie_hp_ctrl_t *ctrl_p)
955 {
956 	pcie_hp_slot_t *slot_p;
957 
958 	PCIE_DBG("pcishpc_create_slot() called(ctrl_p=%x)\n", ctrl_p);
959 
960 	/* Allocate a new slot structure. */
961 	slot_p = kmem_zalloc(sizeof (pcie_hp_slot_t), KM_SLEEP);
962 	slot_p->hs_ctrl = ctrl_p;
963 
964 	/* Assign an initial value */
965 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY;
966 
967 	PCIE_DBG("pcishpc_create_slot() success\n");
968 	return (slot_p);
969 }
970 
971 /*
972  * pcishpc_register_slot()
973  *
974  * Create and register a slot with the Solaris HotPlug framework.
975  */
976 static int
977 pcishpc_register_slot(pcie_hp_ctrl_t *ctrl_p, int slot)
978 {
979 	dev_info_t	*dip = ctrl_p->hc_dip;
980 	pcie_hp_slot_t	*slot_p;
981 
982 	slot_p = pcishpc_create_slot(ctrl_p);
983 	ctrl_p->hc_slots[slot] = slot_p;
984 	slot_p->hs_num = slot;
985 
986 	/* Setup the PCI device # for this SHPC slot. */
987 	if (ctrl_p->hc_device_increases)
988 		slot_p->hs_device_num = ctrl_p->hc_device_start +
989 		    slot_p->hs_num;
990 	else
991 		slot_p->hs_device_num = ctrl_p->hc_device_start -
992 		    slot_p->hs_num;
993 
994 	/* Setup the DDI HP framework slot information. */
995 	slot_p->hs_info.cn_type = DDI_HP_CN_TYPE_PCI;
996 	slot_p->hs_info.cn_type_str = PCIE_PCI_HP_TYPE;
997 	slot_p->hs_info.cn_child = NULL;
998 
999 	slot_p->hs_minor = PCI_MINOR_NUM(
1000 	    ddi_get_instance(dip), slot_p->hs_device_num);
1001 	slot_p->hs_condition = AP_COND_UNKNOWN;
1002 
1003 	/* setup thread for handling ATTN button events */
1004 	if (ctrl_p->hc_has_attn) {
1005 		PCIE_DBG("pcishpc_register_slot: "
1006 		    "setting up ATTN button event "
1007 		    "handler thread for slot %d\n", slot);
1008 
1009 		cv_init(&slot_p->hs_attn_btn_cv, NULL, CV_DRIVER, NULL);
1010 		slot_p->hs_attn_btn_pending = B_FALSE;
1011 		slot_p->hs_attn_btn_threadp = thread_create(NULL, 0,
1012 		    pcishpc_attn_btn_handler,
1013 		    (void *)slot_p, 0, &p0, TS_RUN, minclsyspri);
1014 		slot_p->hs_attn_btn_thread_exit = B_FALSE;
1015 	}
1016 
1017 	/* setup the slot name (used for ap-id) */
1018 	pcishpc_set_slot_name(ctrl_p, slot);
1019 
1020 	pcishpc_get_slot_state(slot_p);
1021 	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_ENABLED)
1022 		slot_p->hs_condition = AP_COND_OK;
1023 
1024 	/* register the slot with DDI HP framework */
1025 	if (ndi_hp_register(dip, &slot_p->hs_info) != NDI_SUCCESS) {
1026 		PCIE_DBG("pciehpc_register_slot() failed to register slot %d\n",
1027 		    slot_p->hs_phy_slot_num);
1028 		return (DDI_FAILURE);
1029 	}
1030 
1031 	pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip),
1032 	    slot_p->hs_minor), slot_p->hs_device_num);
1033 
1034 	PCIE_DBG("pcishpc_register_slot() success for slot %d\n", slot);
1035 
1036 	return (DDI_SUCCESS);
1037 }
1038 
1039 /*
1040  * pcishpc_destroy_slots()
1041  *
1042  * Free up all of the slot resources for this controller.
1043  */
1044 static int
1045 pcishpc_destroy_slots(pcie_hp_ctrl_t *ctrl_p)
1046 {
1047 	dev_info_t	*dip = ctrl_p->hc_dip;
1048 	pcie_hp_slot_t	*slot_p;
1049 	int		i;
1050 
1051 	PCIE_DBG("pcishpc_destroy_slots() called(ctrl_p=%p)\n", ctrl_p);
1052 
1053 	for (i = 0; i < PCIE_HP_MAX_SLOTS; i++) {
1054 		if ((slot_p = ctrl_p->hc_slots[i]) == NULL)
1055 			continue;
1056 
1057 		if (slot_p->hs_attn_btn_threadp != NULL) {
1058 			mutex_enter(&ctrl_p->hc_mutex);
1059 			slot_p->hs_attn_btn_thread_exit = B_TRUE;
1060 			cv_signal(&slot_p->hs_attn_btn_cv);
1061 			PCIE_DBG("pcishpc_destroy_slots: "
1062 			    "waiting for ATTN thread exit\n");
1063 			cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
1064 			PCIE_DBG("pcishpc_destroy_slots: "
1065 			    "ATTN thread exit\n");
1066 			cv_destroy(&slot_p->hs_attn_btn_cv);
1067 			slot_p->hs_attn_btn_threadp = NULL;
1068 			mutex_exit(&ctrl_p->hc_mutex);
1069 		}
1070 
1071 		PCIE_DBG("pcishpc_destroy_slots() (shpc_p=%p)\n"
1072 		    "destroyed", slot_p);
1073 
1074 		pcie_hp_delete_occupant_props(dip,
1075 		    makedevice(ddi_driver_major(dip),
1076 		    slot_p->hs_minor));
1077 
1078 		/* unregister the slot with DDI HP framework */
1079 		if (ndi_hp_unregister(dip, slot_p->hs_info.cn_name) !=
1080 		    NDI_SUCCESS) {
1081 			PCIE_DBG("pcishpc_destroy_slots() "
1082 			    "failed to unregister slot %d\n",
1083 			    slot_p->hs_phy_slot_num);
1084 			return (DDI_FAILURE);
1085 		}
1086 		kmem_free(slot_p->hs_info.cn_name,
1087 		    strlen(slot_p->hs_info.cn_name) + 1);
1088 		kmem_free(slot_p, sizeof (pcie_hp_slot_t));
1089 	}
1090 
1091 	return (DDI_SUCCESS);
1092 }
1093 
1094 /*
1095  * pcishpc_enable_irqs()
1096  *
1097  * Enable/unmask the different IRQ's we support from the SHPC controller.
1098  */
1099 static int
1100 pcishpc_enable_irqs(pcie_hp_ctrl_t *ctrl_p)
1101 {
1102 	uint32_t reg;
1103 	int slot;
1104 
1105 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG);
1106 
1107 	/* Enable all interrupts. */
1108 	reg &= ~PCI_HP_SERR_INT_MASK_ALL;
1109 
1110 	pcishpc_write_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG, reg);
1111 
1112 	/* Unmask the interrupts for each slot. */
1113 	for (slot = 0; slot < ctrl_p->hc_num_slots_impl; slot++) {
1114 		reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot);
1115 		if ((reg & PCI_HP_SLOT_STATE_MASK) == PCI_HP_SLOT_ENABLED) {
1116 			reg &= ~(PCI_HP_SLOT_MASK_ALL |
1117 			    PCI_HP_SLOT_MRL_SERR_MASK);
1118 			ctrl_p->hc_num_slots_connected++;
1119 			if (ctrl_p->hc_curr_bus_speed == -1)
1120 				ctrl_p->hc_curr_bus_speed =
1121 				    pcishpc_read_reg(ctrl_p,
1122 				    PCI_HP_PROF_IF_SBCR_REG) &
1123 				    PCI_HP_SBCR_SPEED_MASK;
1124 		} else {
1125 			reg &= ~(PCI_HP_SLOT_MASK_ALL);
1126 		}
1127 
1128 		/* Enable/Unmask all slot interrupts. */
1129 		pcishpc_write_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot, reg);
1130 	}
1131 
1132 	PCIE_DBG("pcishpc_enable_irqs: ctrl_p 0x%p, "
1133 	    "current bus speed 0x%x, slots connected 0x%x\n", ctrl_p,
1134 	    ctrl_p->hc_curr_bus_speed, ctrl_p->hc_num_slots_connected);
1135 
1136 	return (DDI_SUCCESS);
1137 }
1138 
1139 
1140 /*
1141  * pcishpc_disable_irqs()
1142  *
1143  * Disable/Mask the different IRQ's we support from the SHPC controller.
1144  */
1145 static int
1146 pcishpc_disable_irqs(pcie_hp_ctrl_t *ctrl_p)
1147 {
1148 	uint32_t reg;
1149 	int slot;
1150 
1151 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG);
1152 
1153 	/* Mask all interrupts. */
1154 	reg |= PCI_HP_SERR_INT_MASK_ALL;
1155 
1156 	pcishpc_write_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG, reg);
1157 
1158 	/* Unmask the interrupts for each slot. */
1159 	for (slot = 0; slot < ctrl_p->hc_num_slots_impl; slot++) {
1160 		reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot);
1161 
1162 		/* Disable/Mask all slot interrupts. */
1163 		reg |= PCI_HP_SLOT_MASK_ALL;
1164 
1165 		pcishpc_write_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot, reg);
1166 	}
1167 
1168 	PCIE_DBG("pcishpc_disable_irqs: ctrl_p 0x%p, "
1169 	    "current bus speed 0x%x, slots connected 0x%x\n", ctrl_p,
1170 	    ctrl_p->hc_curr_bus_speed, ctrl_p->hc_num_slots_connected);
1171 
1172 	return (DDI_SUCCESS);
1173 }
1174 
1175 /*
1176  * pcishpc_slot_poweron()
1177  *
1178  * Poweron/Enable the slot.
1179  *
1180  * Note: This function is called by DDI HP framework at kernel context only
1181  */
1182 /*ARGSUSED*/
1183 static int
1184 pcishpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result_state)
1185 {
1186 	uint32_t	status;
1187 
1188 	PCIE_DBG("pcishpc_slot_poweron called()\n");
1189 
1190 	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
1191 
1192 	/* get the current slot state */
1193 	pcishpc_get_slot_state(slot_p);
1194 
1195 	/* check if the slot is already in the 'enabled' state */
1196 	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) {
1197 		/* slot is already in the 'enabled' state */
1198 		PCIE_DBG("pcishpc_slot_poweron() slot %d already enabled\n",
1199 		    slot_p->hs_phy_slot_num);
1200 
1201 		*result_state = slot_p->hs_info.cn_state;
1202 		return (DDI_SUCCESS);
1203 	}
1204 
1205 	if (slot_p->hs_info.cn_state == DDI_HP_CN_STATE_EMPTY) {
1206 		PCIE_DBG("pcishpc_slot_poweron() slot in empty state\n");
1207 		goto cleanup;
1208 	}
1209 
1210 	/* make sure the MRL sensor is closed */
1211 	status = pcishpc_read_reg(slot_p->hs_ctrl,
1212 	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
1213 
1214 	if (status & PCI_HP_SLOT_MRL_STATE_MASK) {
1215 		PCIE_DBG("pcishpc_slot_poweron() failed: MRL open\n");
1216 		goto cleanup;
1217 	}
1218 
1219 	/* Set the Power LED to blink */
1220 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
1221 
1222 	/* Turn all other LEDS off */
1223 	(void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF);
1224 	(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
1225 	(void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF);
1226 
1227 	/* Set the bus speed only if the bus segment is not running */
1228 	if (pcishpc_set_bus_speed(slot_p) != DDI_SUCCESS) {
1229 		PCIE_DBG("pcishpc_slot_poweron() setting speed failed\n");
1230 		goto cleanup;
1231 	}
1232 
1233 	slot_p->hs_ctrl->hc_num_slots_connected++;
1234 
1235 	PCIE_DBG("pcishpc_slot_poweron(): slot_p 0x%p, slot state 0x%x, "
1236 	    "current bus speed 0x%x, slots connected 0x%x\n", slot_p,
1237 	    slot_p->hs_info.cn_state, slot_p->hs_ctrl->hc_curr_bus_speed,
1238 	    slot_p->hs_ctrl->hc_num_slots_connected);
1239 
1240 	/* Mask or Unmask MRL Sensor SEER bit based on new slot state */
1241 	if (slot_p->hs_ctrl->hc_has_mrl == B_TRUE) {
1242 		uint32_t reg;
1243 
1244 		reg = pcishpc_read_reg(slot_p->hs_ctrl,
1245 		    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
1246 
1247 		pcishpc_write_reg(slot_p->hs_ctrl,
1248 		    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num,
1249 		    reg & ~PCI_HP_SLOT_MRL_SERR_MASK);
1250 	}
1251 
1252 	/* Update the hardware slot state. */
1253 	if (pcishpc_set_slot_state(slot_p,
1254 	    DDI_HP_CN_STATE_ENABLED) != DDI_SUCCESS) {
1255 		PCIE_DBG("pcishpc_slot_poweron() failed\n");
1256 
1257 		pcishpc_get_slot_state(slot_p);
1258 		goto cleanup;
1259 	}
1260 	/* Update the current state. It will be used in pcishpc_setled() */
1261 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_ENABLED;
1262 
1263 	/* Turn the Power LED ON for a enabled slot. */
1264 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_ON);
1265 
1266 	/* Turn all other LEDS off. */
1267 	(void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF);
1268 	(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
1269 	(void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF);
1270 
1271 	/* delay after powerON to let the device initialize itself */
1272 	delay(drv_usectohz(pcishpc_reset_delay));
1273 
1274 	PCIE_DBG("pcishpc_slot_poweron() success!\n");
1275 
1276 	/*
1277 	 * Want to show up as POWERED state for now. It will be updated to
1278 	 * ENABLED state when user explicitly enable the slot.
1279 	 */
1280 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_POWERED;
1281 
1282 	/* get the current slot state */
1283 	pcishpc_get_slot_state(slot_p);
1284 	/*
1285 	 * It should be poweron'ed now. Have a check here in case any
1286 	 * hardware problems.
1287 	 */
1288 	if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) {
1289 		PCIE_DBG("pcishpc_slot_poweron() failed after hardware"
1290 		    " registers all programmed.\n");
1291 
1292 		goto cleanup;
1293 	}
1294 
1295 	*result_state = slot_p->hs_info.cn_state;
1296 
1297 	return (DDI_SUCCESS);
1298 
1299 cleanup:
1300 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
1301 	return (DDI_FAILURE);
1302 }
1303 
1304 /*ARGSUSED*/
1305 static int
1306 pcishpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result_state)
1307 {
1308 	PCIE_DBG("pcishpc_slot_poweroff called()\n");
1309 
1310 	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
1311 
1312 	/* get the current slot state */
1313 	pcishpc_get_slot_state(slot_p);
1314 
1315 	/* check if the slot is not in the "enabled" or "powered" state */
1316 	if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) {
1317 		/* slot is in the 'disabled' state */
1318 		PCIE_DBG("pcishpc_slot_poweroff(): "
1319 		    "slot %d already disabled\n", slot_p->hs_phy_slot_num);
1320 
1321 		*result_state = slot_p->hs_info.cn_state;
1322 		return (DDI_SUCCESS);
1323 	}
1324 
1325 	/* Set the Power LED to blink */
1326 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
1327 
1328 	/* Turn all other LEDS off */
1329 	(void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF);
1330 	(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
1331 	(void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF);
1332 
1333 	if (--slot_p->hs_ctrl->hc_num_slots_connected == 0)
1334 		slot_p->hs_ctrl->hc_curr_bus_speed = -1;
1335 
1336 	PCIE_DBG("pcishpc_slot_poweroff(): slot_p 0x%p, slot state 0x%x, "
1337 	    "current bus speed 0x%x, slots connected 0x%x\n", slot_p,
1338 	    slot_p->hs_info.cn_state, slot_p->hs_ctrl->hc_curr_bus_speed,
1339 	    slot_p->hs_ctrl->hc_num_slots_connected);
1340 
1341 	/* Mask or Unmask MRL Sensor SEER bit based on new slot state */
1342 	if (slot_p->hs_ctrl->hc_has_mrl == B_TRUE) {
1343 		uint32_t reg;
1344 
1345 		reg = pcishpc_read_reg(slot_p->hs_ctrl,
1346 		    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
1347 
1348 		pcishpc_write_reg(slot_p->hs_ctrl,
1349 		    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num,
1350 		    reg | PCI_HP_SLOT_MRL_SERR_MASK);
1351 	}
1352 
1353 	/* Update the hardware slot state. */
1354 	if (pcishpc_set_slot_state(slot_p, DDI_HP_CN_STATE_PRESENT) !=
1355 	    DDI_SUCCESS) {
1356 		PCIE_DBG("pcishpc_slot_poweroff() failed\n");
1357 
1358 		pcishpc_get_slot_state(slot_p);
1359 		goto cleanup;
1360 	}
1361 
1362 	/* Update the current state. It will be used in pcishpc_setled() */
1363 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_PRESENT;
1364 
1365 	/* Turn the Power LED OFF for a disabled slot. */
1366 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
1367 
1368 	/* Turn all other LEDS off. */
1369 	(void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF);
1370 	(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
1371 	(void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF);
1372 
1373 	/* delay after powerON to let the device initialize itself */
1374 	delay(drv_usectohz(pcishpc_reset_delay));
1375 
1376 	pcishpc_get_slot_state(slot_p);
1377 	/*
1378 	 * It should be poweroff'ed now. Have a check here in case any
1379 	 * hardware problems.
1380 	 */
1381 	if (slot_p->hs_info.cn_state > DDI_HP_CN_STATE_PRESENT) {
1382 		PCIE_DBG("pcishpc_slot_poweroff() failed after hardware"
1383 		    " registers all programmed.\n");
1384 
1385 		goto cleanup;
1386 	}
1387 
1388 	PCIE_DBG("pcishpc_slot_poweroff() success!\n");
1389 
1390 	*result_state = slot_p->hs_info.cn_state;
1391 	return (DDI_SUCCESS);
1392 
1393 cleanup:
1394 	(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
1395 	return (DDI_FAILURE);
1396 }
1397 
1398 /*
1399  * pcishpc_slot_probe()
1400  *
1401  * Probe the slot.
1402  *
1403  * Note: This function is called by DDI HP framework at kernel context only
1404  */
1405 /*ARGSUSED*/
1406 static int
1407 pcishpc_slot_probe(pcie_hp_slot_t *slot_p)
1408 {
1409 	mutex_enter(&slot_p->hs_ctrl->hc_mutex);
1410 
1411 	PCIE_DBG("pcishpc_slot_probe called()\n");
1412 
1413 	/* get the current slot state */
1414 	pcishpc_get_slot_state(slot_p);
1415 
1416 	/*
1417 	 * Probe a given PCI Hotplug Connection (CN).
1418 	 */
1419 	if (pcie_hp_probe(slot_p) != DDI_SUCCESS) {
1420 		(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED,
1421 		    PCIE_HP_LED_BLINK);
1422 
1423 		PCIE_DBG("pcishpc_slot_probe() failed\n");
1424 
1425 		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
1426 		return (DDI_FAILURE);
1427 	}
1428 
1429 	PCIE_DBG("pcishpc_slot_probe() success!\n");
1430 
1431 	/* get the current slot state */
1432 	pcishpc_get_slot_state(slot_p);
1433 
1434 	mutex_exit(&slot_p->hs_ctrl->hc_mutex);
1435 	return (DDI_SUCCESS);
1436 }
1437 
1438 /*
1439  * pcishpc_slot_unprobe()
1440  *
1441  * Unprobe the slot.
1442  *
1443  * Note: This function is called by DDI HP framework at kernel context only
1444  */
1445 /*ARGSUSED*/
1446 static int
1447 pcishpc_slot_unprobe(pcie_hp_slot_t *slot_p)
1448 {
1449 	mutex_enter(&slot_p->hs_ctrl->hc_mutex);
1450 
1451 	PCIE_DBG("pcishpc_slot_unprobe called()\n");
1452 
1453 	/* get the current slot state */
1454 	pcishpc_get_slot_state(slot_p);
1455 
1456 	/*
1457 	 * Unprobe a given PCI Hotplug Connection (CN).
1458 	 */
1459 	if (pcie_hp_unprobe(slot_p) != DDI_SUCCESS) {
1460 		(void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED,
1461 		    PCIE_HP_LED_BLINK);
1462 
1463 		PCIE_DBG("pcishpc_slot_unprobe() failed\n");
1464 
1465 		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
1466 		return (DDI_FAILURE);
1467 	}
1468 
1469 	PCIE_DBG("pcishpc_slot_unprobe() success!\n");
1470 
1471 	/* get the current slot state */
1472 	pcishpc_get_slot_state(slot_p);
1473 
1474 	mutex_exit(&slot_p->hs_ctrl->hc_mutex);
1475 	return (DDI_SUCCESS);
1476 }
1477 
1478 static int
1479 pcishpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
1480     ddi_hp_cn_state_t target_state)
1481 {
1482 	ddi_hp_cn_state_t curr_state;
1483 	int rv = DDI_SUCCESS;
1484 
1485 	if (target_state > DDI_HP_CN_STATE_ENABLED) {
1486 		return (DDI_EINVAL);
1487 	}
1488 
1489 	curr_state = slot_p->hs_info.cn_state;
1490 	while ((curr_state < target_state) && (rv == DDI_SUCCESS)) {
1491 
1492 		switch (curr_state) {
1493 		case DDI_HP_CN_STATE_EMPTY:
1494 			/*
1495 			 * From EMPTY to PRESENT, just check the hardware
1496 			 * slot state.
1497 			 */
1498 			pcishpc_get_slot_state(slot_p);
1499 			curr_state = slot_p->hs_info.cn_state;
1500 			if (curr_state < DDI_HP_CN_STATE_PRESENT)
1501 				rv = DDI_FAILURE;
1502 			break;
1503 		case DDI_HP_CN_STATE_PRESENT:
1504 			rv = pcishpc_slot_poweron(slot_p, &curr_state);
1505 			break;
1506 		case DDI_HP_CN_STATE_POWERED:
1507 			curr_state = slot_p->hs_info.cn_state =
1508 			    DDI_HP_CN_STATE_ENABLED;
1509 			break;
1510 		default:
1511 			/* should never reach here */
1512 			ASSERT("unknown devinfo state");
1513 		}
1514 	}
1515 
1516 	return (rv);
1517 }
1518 
1519 static int
1520 pcishpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
1521     ddi_hp_cn_state_t target_state)
1522 {
1523 	ddi_hp_cn_state_t curr_state;
1524 	int rv = DDI_SUCCESS;
1525 
1526 
1527 	curr_state = slot_p->hs_info.cn_state;
1528 	while ((curr_state > target_state) && (rv == DDI_SUCCESS)) {
1529 
1530 		switch (curr_state) {
1531 		case DDI_HP_CN_STATE_PRESENT:
1532 			/*
1533 			 * From PRESENT to EMPTY, just check hardware
1534 			 * slot state.
1535 			 */
1536 			pcishpc_get_slot_state(slot_p);
1537 			curr_state = slot_p->hs_info.cn_state;
1538 			if (curr_state >= DDI_HP_CN_STATE_PRESENT)
1539 				rv = DDI_FAILURE;
1540 			break;
1541 		case DDI_HP_CN_STATE_POWERED:
1542 			rv = pcishpc_slot_poweroff(slot_p, &curr_state);
1543 
1544 			break;
1545 		case DDI_HP_CN_STATE_ENABLED:
1546 			curr_state = slot_p->hs_info.cn_state =
1547 			    DDI_HP_CN_STATE_POWERED;
1548 
1549 			break;
1550 		default:
1551 			/* should never reach here */
1552 			ASSERT("unknown devinfo state");
1553 		}
1554 	}
1555 
1556 	return (rv);
1557 }
1558 
1559 /* Change slot state to a target state */
1560 static int
1561 pcishpc_change_slot_state(pcie_hp_slot_t *slot_p,
1562     ddi_hp_cn_state_t target_state)
1563 {
1564 	ddi_hp_cn_state_t curr_state;
1565 	int rv;
1566 
1567 	pcishpc_get_slot_state(slot_p);
1568 	curr_state = slot_p->hs_info.cn_state;
1569 
1570 	if (curr_state == target_state) {
1571 		return (DDI_SUCCESS);
1572 	}
1573 	if (curr_state < target_state) {
1574 
1575 		rv = pcishpc_upgrade_slot_state(slot_p, target_state);
1576 	} else {
1577 		rv = pcishpc_downgrade_slot_state(slot_p, target_state);
1578 	}
1579 
1580 	return (rv);
1581 }
1582 
1583 /*
1584  * pcishpc_issue_command()
1585  *
1586  * Sends a command to the SHPC controller.
1587  */
1588 static int
1589 pcishpc_issue_command(pcie_hp_ctrl_t *ctrl_p, uint32_t cmd_code)
1590 {
1591 	int	retCode;
1592 
1593 	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
1594 
1595 	PCIE_DBG("pcishpc_issue_command() cmd_code=%02x\n", cmd_code);
1596 
1597 	ctrl_p->hc_cmd_pending = B_TRUE;
1598 
1599 	/* Write the command to the SHPC controller. */
1600 	pcishpc_write_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG, cmd_code);
1601 
1602 	while (ctrl_p->hc_cmd_pending == B_TRUE)
1603 		cv_wait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex);
1604 
1605 	/* Wait until the SHPC controller processes the command. */
1606 	retCode = pcishpc_wait_busy(ctrl_p);
1607 
1608 	/* Make sure the command completed. */
1609 	if (retCode == DDI_SUCCESS) {
1610 		/* Did the command fail to generate the command complete IRQ? */
1611 		if (ctrl_p->hc_cmd_pending != B_FALSE) {
1612 			PCIE_DBG("pcishpc_issue_command() Failed on "
1613 			    "generate cmd complete IRQ\n");
1614 			retCode = DDI_FAILURE;
1615 		}
1616 	}
1617 
1618 	if (retCode == DDI_FAILURE)
1619 		PCIE_DBG("pcishpc_issue_command() Failed on cmd_code=%02x\n",
1620 		    cmd_code);
1621 	else
1622 		PCIE_DBG("pcishpc_issue_command() Success on "
1623 		    "cmd_code=%02x\n", cmd_code);
1624 
1625 	return (retCode);
1626 }
1627 
1628 /*
1629  * pcishpc_wait_busy()
1630  *
1631  * Wait until the SHPC controller is not busy.
1632  */
1633 static int
1634 pcishpc_wait_busy(pcie_hp_ctrl_t *ctrl_p)
1635 {
1636 	uint32_t	status;
1637 
1638 	/* Wait until SHPC controller is NOT busy */
1639 	for (;;) {
1640 		status = pcishpc_read_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG);
1641 
1642 		/* Is there an MRL Sensor error? */
1643 		if ((status & PCI_HP_COMM_STS_ERR_MASK) ==
1644 		    PCI_HP_COMM_STS_ERR_MRL_OPEN) {
1645 			PCIE_DBG("pcishpc_wait_busy() ERROR: "
1646 			    "MRL Sensor error\n");
1647 			break;
1648 		}
1649 
1650 		/* Is there an Invalid command error? */
1651 		if ((status & PCI_HP_COMM_STS_ERR_MASK) ==
1652 		    PCI_HP_COMM_STS_ERR_INVALID_COMMAND) {
1653 			PCIE_DBG("pcishpc_wait_busy() ERROR: Invalid "
1654 			    "command error\n");
1655 			break;
1656 		}
1657 
1658 		/* Is there an Invalid Speed/Mode error? */
1659 		if ((status & PCI_HP_COMM_STS_ERR_MASK) ==
1660 		    PCI_HP_COMM_STS_ERR_INVALID_SPEED) {
1661 			PCIE_DBG("pcishpc_wait_busy() ERROR: Invalid "
1662 			    "Speed/Mode error\n");
1663 			break;
1664 		}
1665 
1666 		/* Is the SHPC controller not BUSY? */
1667 		if (!(status & PCI_HP_COMM_STS_CTRL_BUSY)) {
1668 			/* Return Success. */
1669 			return (DDI_SUCCESS);
1670 		}
1671 
1672 		PCIE_DBG("pcishpc_wait_busy() SHPC controller busy. Waiting\n");
1673 
1674 		/* Wait before polling the status register again. */
1675 		delay(drv_usectohz(PCIE_HP_CMD_WAIT_TIME));
1676 	}
1677 
1678 	return (DDI_FAILURE);
1679 }
1680 
1681 static void
1682 pcishpc_attn_btn_handler(pcie_hp_slot_t *slot_p)
1683 {
1684 	pcie_hp_led_state_t hs_power_led_state;
1685 	callb_cpr_t cprinfo;
1686 
1687 	PCIE_DBG("pcishpc_attn_btn_handler: thread started\n");
1688 
1689 	CALLB_CPR_INIT(&cprinfo, &slot_p->hs_ctrl->hc_mutex,
1690 	    callb_generic_cpr, "pcishpc_attn_btn_handler");
1691 
1692 	mutex_enter(&slot_p->hs_ctrl->hc_mutex);
1693 
1694 	/* wait for ATTN button event */
1695 	cv_wait(&slot_p->hs_attn_btn_cv, &slot_p->hs_ctrl->hc_mutex);
1696 
1697 	while (slot_p->hs_attn_btn_thread_exit == B_FALSE) {
1698 		if (slot_p->hs_attn_btn_pending == B_TRUE) {
1699 			/* get the current state of power LED */
1700 			hs_power_led_state = slot_p->hs_power_led_state;
1701 
1702 			/* Blink the Power LED while we wait for 5 seconds */
1703 			(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED,
1704 			    PCIE_HP_LED_BLINK);
1705 
1706 			/* wait for 5 seconds before taking any action */
1707 			if (cv_timedwait(&slot_p->hs_attn_btn_cv,
1708 			    &slot_p->hs_ctrl->hc_mutex,
1709 			    ddi_get_lbolt() + SEC_TO_TICK(5)) == -1) {
1710 				/*
1711 				 * It is a time out;
1712 				 * make sure the ATTN pending flag is
1713 				 * still ON before sending the event
1714 				 * to DDI HP framework.
1715 				 */
1716 				if (slot_p->hs_attn_btn_pending == B_TRUE) {
1717 					int hint;
1718 
1719 					/* restore the power LED state */
1720 					(void) pcishpc_setled(slot_p,
1721 					    PCIE_HP_POWER_LED,
1722 					    hs_power_led_state);
1723 					/*
1724 					 * send the ATTN button event
1725 					 * to DDI HP framework
1726 					 */
1727 					slot_p->hs_attn_btn_pending = B_FALSE;
1728 
1729 					pcishpc_get_slot_state(slot_p);
1730 
1731 					if (slot_p->hs_info.cn_state <=
1732 					    DDI_HP_CN_STATE_PRESENT) {
1733 						/*
1734 						 * Insertion.
1735 						 */
1736 						hint = SE_INCOMING_RES;
1737 					} else {
1738 						/*
1739 						 * Want to remove;
1740 						 */
1741 						hint = SE_OUTGOING_RES;
1742 					}
1743 					pcie_hp_gen_sysevent_req(
1744 					    slot_p->hs_info.cn_name,
1745 					    hint,
1746 					    slot_p->hs_ctrl->hc_dip,
1747 					    KM_SLEEP);
1748 
1749 					continue;
1750 				}
1751 			}
1752 
1753 			/* restore the power LED state */
1754 			(void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED,
1755 			    hs_power_led_state);
1756 			continue;
1757 		}
1758 
1759 		/* wait for another ATTN button event */
1760 		cv_wait(&slot_p->hs_attn_btn_cv, &slot_p->hs_ctrl->hc_mutex);
1761 	}
1762 
1763 	PCIE_DBG("pcishpc_attn_btn_handler: thread exit\n");
1764 	cv_signal(&slot_p->hs_attn_btn_cv);
1765 	CALLB_CPR_EXIT(&cprinfo);
1766 	thread_exit();
1767 }
1768 
1769 /*
1770  * pcishpc_get_slot_state()
1771  *
1772  * Get the state of the slot.
1773  * The slot state should have been initialized before this function gets called.
1774  */
1775 static void
1776 pcishpc_get_slot_state(pcie_hp_slot_t *slot_p)
1777 {
1778 	uint32_t reg;
1779 	ddi_hp_cn_state_t curr_state = slot_p->hs_info.cn_state;
1780 
1781 	/* Read the logical slot register for this Slot. */
1782 	reg = pcishpc_read_reg(slot_p->hs_ctrl,
1783 	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
1784 
1785 	/* Convert from the SHPC slot state to the HPC slot state. */
1786 	slot_p->hs_info.cn_state = pcishpc_slot_shpc_to_hpc(reg);
1787 	if (curr_state == DDI_HP_CN_STATE_POWERED &&
1788 	    slot_p->hs_info.cn_state > DDI_HP_CN_STATE_POWERED) {
1789 		/*
1790 		 * Keep POWERED state if it is currently POWERED state because
1791 		 * this driver does not really implement enable/disable
1792 		 * slot operations. That is, when poweron, it actually enables
1793 		 * the slot also.
1794 		 * So, from hardware view, POWERED == ENABLED.
1795 		 * But, when user explicitly change to POWERED state, it should
1796 		 * be kept until user explicitly change to other states later.
1797 		 */
1798 		slot_p->hs_info.cn_state = DDI_HP_CN_STATE_POWERED;
1799 	}
1800 
1801 	/* Convert from the SHPC Power LED state to the HPC Power LED state. */
1802 	slot_p->hs_power_led_state = pcishpc_led_shpc_to_hpc((reg>>2)&3);
1803 
1804 	/* Convert from the SHPC Attn LED state to the HPC Attn LED state. */
1805 	slot_p->hs_attn_led_state = pcishpc_led_shpc_to_hpc((reg>>4)&3);
1806 
1807 	/* We don't have a fault LED so just default it to OFF. */
1808 	slot_p->hs_fault_led_state = PCIE_HP_LED_OFF;
1809 
1810 	/* We don't have an active LED so just default it to OFF. */
1811 	slot_p->hs_active_led_state = PCIE_HP_LED_OFF;
1812 }
1813 
1814 /*
1815  * pcishpc_set_slot_state()
1816  *
1817  * Updates the slot's state and leds.
1818  */
1819 static int
1820 pcishpc_set_slot_state(pcie_hp_slot_t *slot_p,
1821     ddi_hp_cn_state_t new_slot_state)
1822 {
1823 	uint32_t		reg, cmd_code;
1824 	ddi_hp_cn_state_t	curr_state;
1825 
1826 	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
1827 
1828 	reg = pcishpc_read_reg(slot_p->hs_ctrl,
1829 	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
1830 
1831 	/* Default all states to unchanged. */
1832 	cmd_code = ((1 + slot_p->hs_num) << 8);
1833 
1834 	/* Has the slot state changed? */
1835 	curr_state = pcishpc_slot_shpc_to_hpc(reg);
1836 	if (curr_state != new_slot_state) {
1837 		PCIE_DBG("pcishpc_set_slot_state() Slot State changed");
1838 
1839 		/* Set the new slot state in the Slot operation command. */
1840 		cmd_code |= pcishpc_slot_hpc_to_shpc(new_slot_state);
1841 	}
1842 
1843 	/* Has the Power LED state changed? */
1844 	if (slot_p->hs_power_led_state != pcishpc_led_shpc_to_hpc((reg>>2)&3)) {
1845 		PCIE_DBG("pcishpc_set_slot_state() Power LED State changed\n");
1846 
1847 		/* Set the new power led state in the Slot operation command. */
1848 		cmd_code |=
1849 		    (pcishpc_led_hpc_to_shpc(slot_p->hs_power_led_state) << 2);
1850 	}
1851 
1852 	/* Has the Attn LED state changed? */
1853 	if (slot_p->hs_attn_led_state != pcishpc_led_shpc_to_hpc((reg>>4)&3)) {
1854 		PCIE_DBG("pcishpc_set_slot_state() Attn LED State changed\n");
1855 
1856 		/* Set the new attn led state in the Slot operation command. */
1857 		cmd_code |=
1858 		    (pcishpc_led_hpc_to_shpc(slot_p->hs_attn_led_state) << 4);
1859 	}
1860 
1861 	return (pcishpc_issue_command(slot_p->hs_ctrl, cmd_code));
1862 }
1863 
1864 /*
1865  * setup slot name/slot-number info.
1866  */
1867 static void
1868 pcishpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p, int slot)
1869 {
1870 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[slot];
1871 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1872 	uchar_t *slotname_data;
1873 	int *slotnum;
1874 	uint_t count;
1875 	int len;
1876 	uchar_t *s;
1877 	uint32_t bit_mask;
1878 	int pci_id_cnt, pci_id_bit;
1879 	int slots_before, found;
1880 	int invalid_slotnum = 0;
1881 
1882 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ctrl_p->hc_dip,
1883 	    DDI_PROP_DONTPASS, "physical-slot#", &slotnum, &count) ==
1884 	    DDI_PROP_SUCCESS) {
1885 		slot_p->hs_phy_slot_num = slotnum[0];
1886 		ddi_prop_free(slotnum);
1887 	} else {
1888 		if (ctrl_p->hc_device_increases)
1889 			slot_p->hs_phy_slot_num = ctrl_p->hc_phys_start + slot;
1890 		else
1891 			slot_p->hs_phy_slot_num = ctrl_p->hc_phys_start - slot;
1892 
1893 		if ((ndi_prop_update_int(DDI_DEV_T_NONE, ctrl_p->hc_dip,
1894 		    "physical-slot#", slot_p->hs_phy_slot_num)) != DDI_SUCCESS)
1895 			PCIE_DBG("pcishpc_set_slot_name(): failed to "
1896 			    "create phyical-slot#%d\n",
1897 			    slot_p->hs_phy_slot_num);
1898 	}
1899 
1900 	/* Platform may not have initialized it */
1901 	if (!slot_p->hs_phy_slot_num) {
1902 		slot_p->hs_phy_slot_num = pci_config_get8(bus_p->bus_cfg_hdl,
1903 		    PCI_BCNF_SECBUS);
1904 		invalid_slotnum = 1;
1905 	}
1906 	slot_p->hs_info.cn_num = slot_p->hs_phy_slot_num;
1907 	slot_p->hs_info.cn_num_dpd_on = DDI_HP_CN_NUM_NONE;
1908 
1909 	/*
1910 	 * construct the slot_name:
1911 	 * 	if "slot-names" property exists then use that name
1912 	 *	else if valid slot number exists then it is "pci<slot-num>".
1913 	 *	else it will be "pci<sec-bus-number>dev<dev-number>"
1914 	 */
1915 	if (ddi_getlongprop(DDI_DEV_T_ANY, ctrl_p->hc_dip, DDI_PROP_DONTPASS,
1916 	    "slot-names", (caddr_t)&slotname_data, &len) == DDI_PROP_SUCCESS) {
1917 		bit_mask = slotname_data[3] | (slotname_data[2] << 8) |
1918 		    (slotname_data[1] << 16) | (slotname_data[0] << 24);
1919 
1920 		pci_id_bit = 1;
1921 		pci_id_cnt = slots_before = found = 0;
1922 
1923 		/*
1924 		 * Walk the bit mask until we find the bit that corresponds
1925 		 * to our slots device number.  We count how many bits
1926 		 * we find before we find our slot's bit.
1927 		 */
1928 		while (!found && (pci_id_cnt < 32)) {
1929 			while (slot_p->hs_device_num != pci_id_cnt) {
1930 
1931 				/*
1932 				 * Find the next bit set.
1933 				 */
1934 				while (!(bit_mask & pci_id_bit) &&
1935 				    (pci_id_cnt < 32)) {
1936 					pci_id_bit = pci_id_bit << 1;
1937 					pci_id_cnt++;
1938 				}
1939 
1940 				if (slot_p->hs_device_num != pci_id_cnt)
1941 					slots_before++;
1942 				else
1943 					found = 1;
1944 			}
1945 		}
1946 
1947 		if (pci_id_cnt < 32) {
1948 
1949 			/*
1950 			 * Set ptr to first string.
1951 			 */
1952 			s = slotname_data + 4;
1953 
1954 			/*
1955 			 * Increment past all the strings for the slots
1956 			 * before ours.
1957 			 */
1958 			while (slots_before) {
1959 				while (*s != NULL)
1960 					s++;
1961 				s++;
1962 				slots_before--;
1963 			}
1964 
1965 			slot_p->hs_info.cn_name = i_ddi_strdup((char *)s,
1966 			    KM_SLEEP);
1967 			kmem_free(slotname_data, len);
1968 			return;
1969 		}
1970 
1971 		/* slot-names entry not found */
1972 		PCIE_DBG("pcishpc_set_slot_name(): "
1973 		    "No slot-names entry found for slot #%d\n",
1974 		    slot_p->hs_phy_slot_num);
1975 		kmem_free(slotname_data, len);
1976 	}
1977 
1978 	if (invalid_slotnum) {
1979 		char tmp_name[256];
1980 
1981 		(void) snprintf(tmp_name, sizeof (tmp_name), "pci%d",
1982 		    slot_p->hs_device_num);
1983 		slot_p->hs_info.cn_name = i_ddi_strdup(tmp_name, KM_SLEEP);
1984 	} else {
1985 		char tmp_name[256];
1986 
1987 		(void) snprintf(tmp_name, sizeof (tmp_name), "pci%d",
1988 		    slot_p->hs_phy_slot_num);
1989 		slot_p->hs_info.cn_name = i_ddi_strdup(tmp_name, KM_SLEEP);
1990 	}
1991 }
1992 
1993 /*
1994  * pcishpc_set_bus_speed()
1995  *
1996  * Set the bus speed and mode.
1997  */
1998 static int
1999 pcishpc_set_bus_speed(pcie_hp_slot_t *slot_p)
2000 {
2001 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
2002 	int		curr_speed = ctrl_p->hc_curr_bus_speed;
2003 	int		speed = -1;
2004 	int		avail_slots;
2005 	uint32_t	status, slots_avail1_reg, slots_avail2_reg;
2006 
2007 	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
2008 
2009 	/* Make sure that the slot is in a correct state */
2010 	status = pcishpc_read_reg(ctrl_p,
2011 	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
2012 
2013 	/* Return failure if the slot is empty */
2014 	if ((status & PCI_HP_SLOT_CARD_EMPTY_MASK) ==
2015 	    PCI_HP_SLOT_CARD_EMPTY_MASK) {
2016 		PCIE_DBG("pcishpc_set_bus_speed() failed: "
2017 		    "the slot is empty\n");
2018 		return (DDI_FAILURE);
2019 	}
2020 
2021 	/* Return failure if the slot is not in disabled state */
2022 	if ((status & PCI_HP_SLOT_STATE_MASK) != PCI_HP_SLOT_DISABLED) {
2023 		PCIE_DBG("pcishpc_set_bus_speed() failed: "
2024 		    "incorrect slot state\n");
2025 		return (DDI_FAILURE);
2026 	}
2027 
2028 	/* Set the "power-only" mode for the slot */
2029 	if (pcishpc_issue_command(ctrl_p, ((1+slot_p->hs_num)<<8) |
2030 	    PCI_HP_SLOT_POWER_ONLY) != DDI_SUCCESS) {
2031 		PCIE_DBG("pcishpc_set_bus_speed() failed to set "
2032 		    "the slot %d in the power-only mode\n", slot_p->hs_num);
2033 		return (DDI_FAILURE);
2034 	}
2035 
2036 	/* Wait for power good */
2037 	delay(drv_usectohz(PCIE_HP_POWER_GOOD_WAIT_TIME));
2038 
2039 	/* Make sure that the slot is in "power-only" state */
2040 	status = pcishpc_read_reg(ctrl_p,
2041 	    PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num);
2042 
2043 	if ((status & PCI_HP_SLOT_STATE_MASK) != PCI_HP_SLOT_POWER_ONLY) {
2044 		PCIE_DBG("pcishpc_set_bus_speed() "
2045 		    "power-only failed: incorrect slot state\n");
2046 		return (DDI_FAILURE);
2047 	}
2048 
2049 	slots_avail1_reg = pcishpc_read_reg(ctrl_p,
2050 	    PCI_HP_SLOTS_AVAIL_I_REG);
2051 	slots_avail2_reg = pcishpc_read_reg(ctrl_p,
2052 	    PCI_HP_SLOTS_AVAIL_II_REG);
2053 
2054 	/*
2055 	 * Check if SHPC has available slots and select the highest
2056 	 * available bus speed for the slot.
2057 	 *
2058 	 * The bus speed codes are:
2059 	 * 100 - 133Mhz; <--+
2060 	 * 011 - 100Mhz; <--+   PCI-X
2061 	 * 010 - 66Mhz;  <--+
2062 	 *
2063 	 * 001 - 66Mhz;  <--+
2064 	 * 000 - 33Mhz   <--+   Conv PCI
2065 	 */
2066 	switch (status & PCI_HP_SLOT_PCIX_CAPABLE_MASK) {
2067 	case PCI_HP_SLOT_133MHZ_PCIX_CAPABLE:
2068 		avail_slots = (slots_avail1_reg >>
2069 		    PCI_HP_AVAIL_133MHZ_PCIX_SPEED_SHIFT) &
2070 		    PCI_HP_AVAIL_SPEED_MASK;
2071 
2072 		if (((curr_speed == -1) && avail_slots) ||
2073 		    (curr_speed == PCI_HP_SBCR_133MHZ_PCIX_SPEED)) {
2074 			speed = PCI_HP_SBCR_133MHZ_PCIX_SPEED;
2075 			break;
2076 		}
2077 		/* FALLTHROUGH */
2078 	case PCI_HP_SLOT_100MHZ_PCIX_CAPABLE:
2079 		avail_slots = (slots_avail1_reg >>
2080 		    PCI_HP_AVAIL_100MHZ_PCIX_SPEED_SHIFT) &
2081 		    PCI_HP_AVAIL_SPEED_MASK;
2082 
2083 		if (((curr_speed == -1) && avail_slots) ||
2084 		    (curr_speed == PCI_HP_SBCR_100MHZ_PCIX_SPEED)) {
2085 			speed = PCI_HP_SBCR_100MHZ_PCIX_SPEED;
2086 			break;
2087 		}
2088 		/* FALLTHROUGH */
2089 	case PCI_HP_SLOT_66MHZ_PCIX_CAPABLE:
2090 		avail_slots = (slots_avail1_reg >>
2091 		    PCI_HP_AVAIL_66MHZ_PCIX_SPEED_SHIFT) &
2092 		    PCI_HP_AVAIL_SPEED_MASK;
2093 
2094 		if (((curr_speed == -1) && avail_slots) ||
2095 		    (curr_speed == PCI_HP_SBCR_66MHZ_PCIX_SPEED)) {
2096 			speed = PCI_HP_SBCR_66MHZ_PCIX_SPEED;
2097 			break;
2098 		}
2099 		/* FALLTHROUGH */
2100 	default:
2101 		avail_slots = (slots_avail2_reg >>
2102 		    PCI_HP_AVAIL_66MHZ_CONV_SPEED_SHIFT) &
2103 		    PCI_HP_AVAIL_SPEED_MASK;
2104 
2105 		if ((status & PCI_HP_SLOT_66MHZ_CONV_CAPABLE) &&
2106 		    (((curr_speed == -1) && avail_slots) ||
2107 		    (curr_speed == PCI_HP_SBCR_66MHZ_CONV_SPEED))) {
2108 			speed = PCI_HP_SBCR_66MHZ_CONV_SPEED;
2109 		} else {
2110 			avail_slots = (slots_avail1_reg >>
2111 			    PCI_HP_AVAIL_33MHZ_CONV_SPEED_SHIFT) &
2112 			    PCI_HP_AVAIL_SPEED_MASK;
2113 
2114 			if (((curr_speed == -1) && (avail_slots)) ||
2115 			    (curr_speed == PCI_HP_SBCR_33MHZ_CONV_SPEED)) {
2116 				speed = PCI_HP_SBCR_33MHZ_CONV_SPEED;
2117 			} else {
2118 				PCIE_DBG("pcishpc_set_bus_speed() "
2119 				    " failed to set the bus speed, slot# %d\n",
2120 				    slot_p->hs_num);
2121 				return (DDI_FAILURE);
2122 			}
2123 		}
2124 		break;
2125 	}
2126 
2127 	/*
2128 	 * If the bus segment is already running, check to see the card
2129 	 * in the slot can support the current bus speed.
2130 	 */
2131 	if (curr_speed == speed) {
2132 		/*
2133 		 * Check to see there is any slot available for the current
2134 		 * bus speed. Otherwise, we need fail the current slot connect
2135 		 * request.
2136 		 */
2137 		return ((avail_slots <= ctrl_p->hc_num_slots_connected) ?
2138 		    DDI_FAILURE : DDI_SUCCESS);
2139 	}
2140 
2141 	/* Set the bus speed */
2142 	if (pcishpc_issue_command(ctrl_p, PCI_HP_COMM_STS_SET_SPEED |
2143 	    speed) == DDI_FAILURE) {
2144 		PCIE_DBG("pcishpc_set_bus_speed() failed "
2145 		    "to set bus %d speed\n", slot_p->hs_num);
2146 		return (DDI_FAILURE);
2147 	}
2148 
2149 	/* Check the current bus speed */
2150 	status = pcishpc_read_reg(ctrl_p, PCI_HP_PROF_IF_SBCR_REG) &
2151 	    PCI_HP_SBCR_SPEED_MASK;
2152 	if ((status & PCI_HP_SBCR_SPEED_MASK) != speed) {
2153 		PCIE_DBG("pcishpc_set_bus_speed() an incorrect "
2154 		    "bus speed, slot = 0x%x, speed = 0x%x\n",
2155 		    slot_p->hs_num, status & PCI_HP_SBCR_SPEED_MASK);
2156 		return (DDI_FAILURE);
2157 	}
2158 
2159 
2160 	/* Save the current bus speed */
2161 	ctrl_p->hc_curr_bus_speed = speed;
2162 
2163 	return (DDI_SUCCESS);
2164 }
2165 
2166 /*
2167  * pcishpc_setled()
2168  *
2169  * Change the state of a slot's LED.
2170  */
2171 static int
2172 pcishpc_setled(pcie_hp_slot_t *slot_p, pcie_hp_led_t led,
2173     pcie_hp_led_state_t state)
2174 {
2175 	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
2176 
2177 	switch (led) {
2178 		case PCIE_HP_FAULT_LED:
2179 			PCIE_DBG("pcishpc_setled() - PCIE_HP_FAULT_LED "
2180 			    "(set %s)\n", pcishpc_slot_textledstate(state));
2181 			slot_p->hs_fault_led_state = state;
2182 			break;
2183 
2184 		case PCIE_HP_POWER_LED:
2185 			PCIE_DBG("pcishpc_setled() - PCIE_HP_POWER_LED "
2186 			    "(set %s)\n", pcishpc_slot_textledstate(state));
2187 			slot_p->hs_power_led_state = state;
2188 			break;
2189 
2190 		case PCIE_HP_ATTN_LED:
2191 			PCIE_DBG("pcishpc_setled() - PCIE_HP_ATTN_LED "
2192 			    "(set %s)\n", pcishpc_slot_textledstate(state));
2193 			slot_p->hs_attn_led_state = state;
2194 			break;
2195 
2196 		case PCIE_HP_ACTIVE_LED:
2197 			PCIE_DBG("pcishpc_setled() - PCIE_HP_ACTIVE_LED "
2198 			    "(set %s)\n", pcishpc_slot_textledstate(state));
2199 			slot_p->hs_active_led_state = state;
2200 			break;
2201 	}
2202 
2203 	return (pcishpc_set_slot_state(slot_p, slot_p->hs_info.cn_state));
2204 }
2205 
2206 /*
2207  * pcishpc_led_shpc_to_hpc()
2208  *
2209  * Convert from SHPC indicator status to HPC indicator status.
2210  */
2211 static int
2212 pcishpc_led_shpc_to_hpc(int state)
2213 {
2214 	switch (state) {
2215 		case 1:	/* SHPC On bits b01 */
2216 			return (PCIE_HP_LED_ON);
2217 		case 2:	/* SHPC Blink bits b10 */
2218 			return (PCIE_HP_LED_BLINK);
2219 		case 3:	/* SHPC Off bits b11 */
2220 			return (PCIE_HP_LED_OFF);
2221 	}
2222 
2223 	return (PCIE_HP_LED_OFF);
2224 }
2225 
2226 
2227 /*
2228  * pcishpc_led_hpc_to_shpc()
2229  *
2230  * Convert from HPC indicator status to SHPC indicator status.
2231  */
2232 static int
2233 pcishpc_led_hpc_to_shpc(int state)
2234 {
2235 	switch (state) {
2236 		case PCIE_HP_LED_ON:
2237 			return (1); /* SHPC On bits b01 */
2238 		case PCIE_HP_LED_BLINK:
2239 			return (2); /* SHPC Blink bits b10 */
2240 		case PCIE_HP_LED_OFF:
2241 			return (3); /* SHPC Off bits b11 */
2242 	}
2243 
2244 	return (3); /* SHPC Off bits b11 */
2245 }
2246 
2247 /*
2248  * pcishpc_slot_shpc_to_hpc()
2249  *
2250  * Convert from SHPC slot state to HPC slot state.
2251  * The argument shpc_state is expected to be read from the slot register.
2252  */
2253 static int
2254 pcishpc_slot_shpc_to_hpc(int shpc_state)
2255 {
2256 	if ((shpc_state & PCI_HP_SLOT_CARD_EMPTY_MASK) ==
2257 	    PCI_HP_SLOT_CARD_EMPTY_MASK)
2258 		return (DDI_HP_CN_STATE_EMPTY);
2259 
2260 	switch (shpc_state & PCI_HP_SLOT_STATE_MASK) {
2261 		case PCI_HP_SLOT_POWER_ONLY: /* SHPC Powered Only */
2262 			return (DDI_HP_CN_STATE_POWERED);
2263 
2264 		case PCI_HP_SLOT_ENABLED: /* SHPC Enabled */
2265 			return (DDI_HP_CN_STATE_ENABLED);
2266 
2267 		case PCI_HP_SLOT_DISABLED:	/* SHPC Disabled */
2268 		default :			/* SHPC Reserved */
2269 			return (DDI_HP_CN_STATE_PRESENT);
2270 	}
2271 }
2272 
2273 /*
2274  * pcishpc_slot_hpc_to_shpc()
2275  *
2276  * Convert from HPC slot state to SHPC slot state.
2277  */
2278 static int
2279 pcishpc_slot_hpc_to_shpc(int state)
2280 {
2281 	switch (state) {
2282 		case DDI_HP_CN_STATE_EMPTY:
2283 			return (0);
2284 
2285 		case DDI_HP_CN_STATE_POWERED:
2286 			return (PCI_HP_SLOT_POWER_ONLY);
2287 
2288 		case DDI_HP_CN_STATE_ENABLED:
2289 			return (PCI_HP_SLOT_ENABLED);
2290 
2291 		default:
2292 			return (PCI_HP_SLOT_DISABLED);
2293 	}
2294 }
2295 
2296 /*
2297  * pcishpc_slot_textslotstate()
2298  *
2299  * Convert the request into a text message.
2300  */
2301 static char *
2302 pcishpc_slot_textslotstate(ddi_hp_cn_state_t state)
2303 {
2304 	/* Convert an HPC slot state into a textual string. */
2305 	if (state == DDI_HP_CN_STATE_EMPTY)
2306 		return ("HPC_SLOT_EMPTY");
2307 	else if (state == DDI_HP_CN_STATE_ENABLED)
2308 		return ("HPC_SLOT_ENABLED");
2309 	else if (state == DDI_HP_CN_STATE_POWERED)
2310 		return ("HPC_SLOT_POWERED_ONLY");
2311 	else
2312 		return ("HPC_SLOT_DISABLED");
2313 }
2314 
2315 
2316 /*
2317  * pcishpc_slot_textledstate()
2318  *
2319  * Convert the led state into a text message.
2320  */
2321 static char *
2322 pcishpc_slot_textledstate(pcie_hp_led_state_t state)
2323 {
2324 	/* Convert an HPC led state into a textual string. */
2325 	switch (state) {
2326 		case PCIE_HP_LED_OFF:
2327 			return ("off");
2328 
2329 		case PCIE_HP_LED_ON:
2330 			return ("on");
2331 
2332 		case PCIE_HP_LED_BLINK:
2333 			return ("blink");
2334 	}
2335 	return ("unknown");
2336 }
2337 
2338 
2339 /*
2340  * pcishpc_read_reg()
2341  *
2342  * Read from a SHPC controller register.
2343  */
2344 static uint32_t
2345 pcishpc_read_reg(pcie_hp_ctrl_t *ctrl_p, int reg)
2346 {
2347 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
2348 
2349 	/* Setup the SHPC dword select register. */
2350 	pci_config_put8(bus_p->bus_cfg_hdl,
2351 	    bus_p->bus_pci_hp_off + PCI_HP_DWORD_SELECT_OFF, (uint8_t)reg);
2352 
2353 	/* Read back the SHPC dword select register and verify. */
2354 	if (pci_config_get8(bus_p->bus_cfg_hdl, bus_p->bus_pci_hp_off +
2355 	    PCI_HP_DWORD_SELECT_OFF) != (uint8_t)reg) {
2356 		PCIE_DBG("pcishpc_read_reg() - Failed writing DWORD "
2357 		    "select reg\n");
2358 		return (0xFFFFFFFF);
2359 	}
2360 
2361 	/* Read from the SHPC dword data register. */
2362 	return (pci_config_get32(bus_p->bus_cfg_hdl,
2363 	    bus_p->bus_pci_hp_off + PCI_HP_DWORD_DATA_OFF));
2364 }
2365 
2366 
2367 /*
2368  * pcishpc_write_reg()
2369  *
2370  * Write to a SHPC controller register.
2371  */
2372 static void
2373 pcishpc_write_reg(pcie_hp_ctrl_t *ctrl_p, int reg, uint32_t data)
2374 {
2375 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
2376 
2377 	/* Setup the SHPC dword select register. */
2378 	pci_config_put8(bus_p->bus_cfg_hdl,
2379 	    bus_p->bus_pci_hp_off + PCI_HP_DWORD_SELECT_OFF, (uint8_t)reg);
2380 
2381 	/* Read back the SHPC dword select register and verify. */
2382 	if (pci_config_get8(bus_p->bus_cfg_hdl, bus_p->bus_pci_hp_off +
2383 	    PCI_HP_DWORD_SELECT_OFF) != (uint8_t)reg) {
2384 		PCIE_DBG("pcishpc_write_reg() - Failed writing "
2385 		    "DWORD select reg\n");
2386 		return;
2387 	}
2388 
2389 	/* Write to the SHPC dword data register. */
2390 	pci_config_put32(bus_p->bus_cfg_hdl,
2391 	    bus_p->bus_pci_hp_off + PCI_HP_DWORD_DATA_OFF, data);
2392 
2393 	/*
2394 	 * Issue a read of the VendorID/DeviceID just to force the previous
2395 	 * write to complete. This is probably not necessary, but it does
2396 	 * help enforce ordering if there is an issue.
2397 	 */
2398 	(void) pci_config_get16(bus_p->bus_cfg_hdl, PCI_CONF_VENID);
2399 }
2400 
2401 
2402 #ifdef	DEBUG
2403 /*
2404  * pcishpc_dump_regs()
2405  *
2406  * Dumps all of the SHPC controller registers.
2407  */
2408 static void
2409 pcishpc_dump_regs(pcie_hp_ctrl_t *ctrl_p)
2410 {
2411 	int slot, numSlots;
2412 	uint32_t reg;
2413 	char *state;
2414 
2415 	if (!pcie_debug_flags)
2416 		return;
2417 
2418 	PCIE_DBG("pcishpc_dump_regs() called:\n");
2419 	PCIE_DBG("==========================================================");
2420 
2421 	PCIE_DBG("SHPC Base Offset				"
2422 	    ": 0x%08x\n", pcishpc_read_reg(ctrl_p, PCI_HP_BASE_OFFSET_REG));
2423 
2424 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOTS_AVAIL_I_REG);
2425 
2426 	PCIE_DBG("Number of PCIX slots avail (33 Mhz)		 : %d\n",
2427 	    (reg & 31));
2428 
2429 	PCIE_DBG("Number of PCIX slots avail (66 Mhz)		 : %d\n",
2430 	    ((reg>>8) & 31));
2431 
2432 	PCIE_DBG("Number of PCIX slots avail (100 Mhz)		: %d\n",
2433 	    ((reg>>16) & 31));
2434 
2435 	PCIE_DBG("Number of PCIX slots avail (133 Mhz)		: %d\n",
2436 	    ((reg>>24) & 31));
2437 
2438 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOTS_AVAIL_II_REG);
2439 
2440 	PCIE_DBG("Number of conventional PCI slots (66 Mhz) : %d\n",
2441 	    (reg & 31));
2442 
2443 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOT_CONFIGURATION_REG);
2444 
2445 	numSlots = (reg & 31);
2446 
2447 	PCIE_DBG("Number of Slots connected to this port	 : %d\n",
2448 	    numSlots);
2449 
2450 	PCIE_DBG("PCI Device # for First HotPlug Slot		 : %d\n",
2451 	    ((reg>>8) & 31));
2452 
2453 	PCIE_DBG("Physical Slot # for First PCI Device #	 : %d\n",
2454 	    ((reg>>16) & 0x7ff));
2455 
2456 	PCIE_DBG("Physical Slot Number Up/Down			 : %d\n",
2457 	    ((reg>>29) & 0x1));
2458 
2459 	PCIE_DBG("MRL Sensor Implemented			 : %s\n",
2460 	    (reg & PCI_HP_SLOT_CONFIG_MRL_SENSOR) ? "Yes" : "No");
2461 
2462 	PCIE_DBG("Attention Button Implemented			 : %s\n",
2463 	    (reg & PCI_HP_SLOT_CONFIG_ATTN_BUTTON) ? "Yes" : "No");
2464 
2465 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_PROF_IF_SBCR_REG);
2466 
2467 	switch (reg & 7) {
2468 		case 0:
2469 			state = "33Mhz Conventional PCI";
2470 			break;
2471 		case 1:
2472 			state = "66Mhz Conventional PCI";
2473 			break;
2474 		case 2:
2475 			state = "66Mhz PCI-X";
2476 			break;
2477 		case 3:
2478 			state = "100Mhz PCI-X";
2479 			break;
2480 		case 4:
2481 			state = "133Mhz PCI-X";
2482 			break;
2483 		default:
2484 			state = "Reserved (Error)";
2485 			break;
2486 	}
2487 
2488 	PCIE_DBG("Current Port Operation Mode		: %s\n", state);
2489 
2490 	PCIE_DBG("SHPC Interrupt Message Number		: %d\n",
2491 	    ((reg>>16) &31));
2492 
2493 	PCIE_DBG("SHPC Programming Interface		: %d\n",
2494 	    ((reg>>24) & 0xff));
2495 
2496 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG);
2497 
2498 	PCIE_DBG("SHPC Command Code			: %d\n",
2499 	    (reg & 0xff));
2500 
2501 	PCIE_DBG("SHPC Target Slot			: %d\n",
2502 	    ((reg>>8) & 31));
2503 
2504 	PCIE_DBG("SHPC Controller Busy			: %s\n",
2505 	    ((reg>>16) & 1) ? "Yes" : "No");
2506 
2507 	PCIE_DBG("SHPC Controller Err: MRL Sensor	: %s\n",
2508 	    ((reg>>17) & 1) ? "Yes" : "No");
2509 
2510 	PCIE_DBG("SHPC Controller Err: Invalid Command	: %s\n",
2511 	    ((reg>>18) & 1) ? "Yes" : "No");
2512 
2513 	PCIE_DBG("SHPC Controller Err: Invalid Speed/Mode : %s\n",
2514 	    ((reg>>19) & 1) ? "Yes" : "No");
2515 
2516 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_IRQ_LOCATOR_REG);
2517 
2518 	PCIE_DBG("Command Completion Interrupt Pending	: %s\n",
2519 	    (reg & PCI_HP_IRQ_CMD_COMPLETE) ? "Yes" : "No");
2520 
2521 	for (slot = 0; slot < numSlots; slot++) {
2522 		PCIE_DBG("Slot %d Interrupt Pending	: %s\n", slot+1,
2523 		    (reg & (PCI_HP_IRQ_SLOT_N_PENDING<<slot)) ? "Yes" : "No");
2524 	}
2525 
2526 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_SERR_LOCATOR_REG);
2527 
2528 	PCIE_DBG("Arbiter SERR Pending			: %s\n",
2529 	    (reg & PCI_HP_IRQ_SERR_ARBITER_PENDING) ? "Yes" : "No");
2530 
2531 	for (slot = 0; slot < numSlots; slot++) {
2532 		PCIE_DBG("Slot %d SERR Pending		: %s\n",
2533 		    slot+1, (reg &
2534 		    (PCI_HP_IRQ_SERR_SLOT_N_PENDING<<slot)) ? "Yes" : "No");
2535 	}
2536 
2537 	reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG);
2538 
2539 	PCIE_DBG("Global Interrupt Mask			: %s\n",
2540 	    (reg & PCI_HP_SERR_INT_GLOBAL_IRQ_MASK) ? "Yes" : "No");
2541 
2542 	PCIE_DBG("Global SERR Mask			: %s\n",
2543 	    (reg & PCI_HP_SERR_INT_GLOBAL_SERR_MASK) ? "Yes" : "No");
2544 
2545 	PCIE_DBG("Command Completion Interrupt Mask	: %s\n",
2546 	    (reg & PCI_HP_SERR_INT_CMD_COMPLETE_MASK) ? "Yes" : "No");
2547 
2548 	PCIE_DBG("Arbiter SERR Mask			: %s\n",
2549 	    (reg & PCI_HP_SERR_INT_ARBITER_SERR_MASK) ? "Yes" : "No");
2550 
2551 	PCIE_DBG("Command Completion Detected		: %s\n",
2552 	    (reg & PCI_HP_SERR_INT_CMD_COMPLETE_IRQ) ? "Yes" : "No");
2553 
2554 	PCIE_DBG("Arbiter Timeout Detected		: %s\n",
2555 	    (reg & PCI_HP_SERR_INT_ARBITER_IRQ) ? "Yes" : "No");
2556 
2557 	for (slot = 0; slot < numSlots; slot++) {
2558 		PCIE_DBG("Logical Slot %d Registers:\n", slot+1);
2559 		PCIE_DBG("------------------------------------\n");
2560 
2561 		reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot);
2562 
2563 		PCIE_DBG("Slot %d state			: %s\n", slot+1,
2564 		    pcishpc_slot_textslotstate(pcishpc_slot_shpc_to_hpc(reg)));
2565 
2566 		PCIE_DBG("Slot %d Power Indicator State	: %s\n", slot+1,
2567 		    pcishpc_slot_textledstate(pcishpc_led_shpc_to_hpc(
2568 		    (reg>>2) &3)));
2569 
2570 		PCIE_DBG("Slot %d Attention Indicator State : %s\n", slot+1,
2571 		    pcishpc_slot_textledstate(pcishpc_led_shpc_to_hpc(
2572 		    (reg>>4)&3)));
2573 
2574 		PCIE_DBG("Slot %d Power Fault		: %s\n", slot+1,
2575 		    ((reg>>6)&1) ? "Fault Detected" : "No Fault");
2576 		PCIE_DBG("Slot %d Attention Button	: %s\n", slot+1,
2577 		    ((reg>>7)&1) ? "Depressed" : "Not Depressed");
2578 		PCIE_DBG("Slot %d MRL Sensor		: %s\n", slot+1,
2579 		    ((reg>>8)&1) ? "Not Closed" : "Closed");
2580 		PCIE_DBG("Slot %d 66mhz Capable		: %s\n", slot+1,
2581 		    ((reg>>9)&1) ? "66mhz" : "33mgz");
2582 
2583 		switch ((reg>>10)&3) {
2584 			case 0:
2585 				state = "Card Present 7.5W";
2586 				break;
2587 			case 1:
2588 				state = "Card Present 15W";
2589 				break;
2590 			case 2:
2591 				state = "Card Present 25W";
2592 				break;
2593 			case 3:
2594 				state = "Slot Empty";
2595 				break;
2596 		}
2597 
2598 		PCIE_DBG("Slot %d PRSNT1#/PRSNT2#	: %s\n", slot+1,
2599 		    state);
2600 
2601 		switch ((reg>>12)&3) {
2602 			case 0:
2603 				state = "Non PCI-X";
2604 				break;
2605 			case 1:
2606 				state = "66mhz PCI-X";
2607 				break;
2608 			case 2:
2609 				state = "Reserved";
2610 				break;
2611 			case 3:
2612 				state = "133mhz PCI-X";
2613 				break;
2614 		}
2615 
2616 		PCIE_DBG("Slot %d Card Presence Change Detected	  : %s\n",
2617 		    slot+1, (reg & PCI_HP_SLOT_PRESENCE_DETECTED) ? "Yes" :
2618 		    "No");
2619 		PCIE_DBG("Slot %d Isolated Power Fault Detected	  : %s\n",
2620 		    slot+1, (reg & PCI_HP_SLOT_ISO_PWR_DETECTED) ? "Yes" :
2621 		    "No");
2622 		PCIE_DBG("Slot %d Attention Button Press Detected : %s\n",
2623 		    slot+1, (reg & PCI_HP_SLOT_ATTN_DETECTED) ? "Yes" : "No");
2624 		PCIE_DBG("Slot %d MRL Sensor Change Detected	  : %s\n",
2625 		    slot+1, (reg & PCI_HP_SLOT_MRL_DETECTED) ? "Yes" : "No");
2626 		PCIE_DBG("Slot %d Connected Power Fault Detected  : %s\n",
2627 		    slot+1, (reg & PCI_HP_SLOT_POWER_DETECTED) ? "Yes" : "No");
2628 
2629 		PCIE_DBG("Slot %d Card Presence IRQ Masked	  : %s\n",
2630 		    slot+1, (reg & PCI_HP_SLOT_PRESENCE_MASK) ? "Yes" : "No");
2631 		PCIE_DBG("Slot %d Isolated Power Fault IRQ Masked : %s\n",
2632 		    slot+1, (reg & PCI_HP_SLOT_ISO_PWR_MASK) ? "Yes" : "No");
2633 		PCIE_DBG("Slot %d Attention Button IRQ Masked	  : %s\n",
2634 		    slot+1, (reg & PCI_HP_SLOT_ATTN_MASK) ? "Yes" : "No");
2635 		PCIE_DBG("Slot %d MRL Sensor IRQ Masked		  : %s\n",
2636 		    slot+1, (reg & PCI_HP_SLOT_MRL_MASK) ? "Yes" : "No");
2637 		PCIE_DBG("Slot %d Connected Power Fault IRQ Masked : %s\n",
2638 		    slot+1, (reg & PCI_HP_SLOT_POWER_MASK) ? "Yes" : "No");
2639 		PCIE_DBG("Slot %d MRL Sensor SERR Masked          : %s\n",
2640 		    slot+1, (reg & PCI_HP_SLOT_MRL_SERR_MASK) ? "Yes" : "No");
2641 		PCIE_DBG("Slot %d Connected Power Fault SERR Masked : %s\n",
2642 		    slot+1, (reg & PCI_HP_SLOT_POWER_SERR_MASK) ? "Yes" : "No");
2643 	}
2644 }
2645 #endif	/* DEBUG */
2646