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