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