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