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 /*
23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2019 Joyent, Inc.
25 */
26
27 /*
28 * This file contains Standard PCI Express HotPlug functionality that is
29 * compatible with the PCI Express ver 1.1 specification.
30 *
31 * NOTE: This file is compiled and delivered through misc/pcie module.
32 */
33
34 #include <sys/types.h>
35 #include <sys/note.h>
36 #include <sys/conf.h>
37 #include <sys/kmem.h>
38 #include <sys/debug.h>
39 #include <sys/vtrace.h>
40 #include <sys/autoconf.h>
41 #include <sys/varargs.h>
42 #include <sys/ddi_impldefs.h>
43 #include <sys/time.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/pci_impl.h>
50 #include <sys/hotplug/pci/pcie_hp.h>
51 #include <sys/hotplug/pci/pciehpc.h>
52
53 typedef struct pciehpc_prop {
54 char *prop_name;
55 char *prop_value;
56 } pciehpc_prop_t;
57
58 static pciehpc_prop_t pciehpc_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 /* Local functions prototype */
69 static int pciehpc_hpc_init(pcie_hp_ctrl_t *ctrl_p);
70 static int pciehpc_hpc_uninit(pcie_hp_ctrl_t *ctrl_p);
71 static int pciehpc_slotinfo_init(pcie_hp_ctrl_t *ctrl_p);
72 static int pciehpc_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p);
73 static int pciehpc_enable_intr(pcie_hp_ctrl_t *ctrl_p);
74 static int pciehpc_disable_intr(pcie_hp_ctrl_t *ctrl_p);
75 static pcie_hp_ctrl_t *pciehpc_create_controller(dev_info_t *dip);
76 static void pciehpc_destroy_controller(dev_info_t *dip);
77 static int pciehpc_register_slot(pcie_hp_ctrl_t *ctrl_p);
78 static int pciehpc_unregister_slot(pcie_hp_ctrl_t *ctrl_p);
79 static int pciehpc_slot_get_property(pcie_hp_slot_t *slot_p,
80 ddi_hp_property_t *arg, ddi_hp_property_t *rval);
81 static int pciehpc_slot_set_property(pcie_hp_slot_t *slot_p,
82 ddi_hp_property_t *arg, ddi_hp_property_t *rval);
83 static void pciehpc_issue_hpc_command(pcie_hp_ctrl_t *ctrl_p, uint16_t control);
84 static void pciehpc_attn_btn_handler(pcie_hp_ctrl_t *ctrl_p);
85 static pcie_hp_led_state_t pciehpc_led_state_to_hpc(uint16_t state);
86 static pcie_hp_led_state_t pciehpc_get_led_state(pcie_hp_ctrl_t *ctrl_p,
87 pcie_hp_led_t led);
88 static void pciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led,
89 pcie_hp_led_state_t state);
90
91 static int pciehpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
92 ddi_hp_cn_state_t target_state);
93 static int pciehpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
94 ddi_hp_cn_state_t target_state);
95 static int pciehpc_change_slot_state(pcie_hp_slot_t *slot_p,
96 ddi_hp_cn_state_t target_state);
97 static int
98 pciehpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result);
99 static int
100 pciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result);
101 static int pciehpc_slot_probe(pcie_hp_slot_t *slot_p);
102 static int pciehpc_slot_unprobe(pcie_hp_slot_t *slot_p);
103 static void pciehpc_handle_power_fault(dev_info_t *dip);
104 static void pciehpc_power_fault_handler(void *arg);
105
106 #ifdef DEBUG
107 static void pciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p);
108 #endif /* DEBUG */
109
110 /*
111 * Global functions (called by other drivers/modules)
112 */
113
114 /*
115 * Initialize Hot Plug Controller if present. The arguments are:
116 * dip - Devinfo node pointer to the hot plug bus node
117 * regops - register ops to access HPC registers for non-standard
118 * HPC hw implementations (e.g: HPC in host PCI-E brdiges)
119 * This is NULL for standard HPC in PCIe bridges.
120 * Returns:
121 * DDI_SUCCESS for successful HPC initialization
122 * DDI_FAILURE for errors or if HPC hw not found
123 */
124 int
pciehpc_init(dev_info_t * dip,caddr_t arg)125 pciehpc_init(dev_info_t *dip, caddr_t arg)
126 {
127 pcie_hp_regops_t *regops = (pcie_hp_regops_t *)(void *)arg;
128 pcie_hp_ctrl_t *ctrl_p;
129
130 PCIE_DBG("pciehpc_init() called (dip=%p)\n", (void *)dip);
131
132 /* Make sure that it is not already initialized */
133 if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) != NULL) {
134 PCIE_DBG("%s%d: pciehpc instance already initialized!\n",
135 ddi_driver_name(dip), ddi_get_instance(dip));
136 return (DDI_SUCCESS);
137 }
138
139 /* Allocate a new hotplug controller and slot structures */
140 ctrl_p = pciehpc_create_controller(dip);
141
142 /* setup access handle for HPC regs */
143 if (regops != NULL) {
144 /* HPC access is non-standard; use the supplied reg ops */
145 ctrl_p->hc_regops = *regops;
146 }
147
148 /*
149 * Setup resource maps for this bus node.
150 */
151 (void) pci_resource_setup(dip);
152
153 PCIE_DISABLE_ERRORS(dip);
154
155 /*
156 * Set the platform specific hot plug mode.
157 */
158 ctrl_p->hc_ops.init_hpc_hw = pciehpc_hpc_init;
159 ctrl_p->hc_ops.uninit_hpc_hw = pciehpc_hpc_uninit;
160 ctrl_p->hc_ops.init_hpc_slotinfo = pciehpc_slotinfo_init;
161 ctrl_p->hc_ops.uninit_hpc_slotinfo = pciehpc_slotinfo_uninit;
162 ctrl_p->hc_ops.poweron_hpc_slot = pciehpc_slot_poweron;
163 ctrl_p->hc_ops.poweroff_hpc_slot = pciehpc_slot_poweroff;
164
165 ctrl_p->hc_ops.enable_hpc_intr = pciehpc_enable_intr;
166 ctrl_p->hc_ops.disable_hpc_intr = pciehpc_disable_intr;
167
168 #if defined(__x86)
169 pciehpc_update_ops(ctrl_p);
170 #endif
171
172 /* initialize hot plug controller hw */
173 if ((ctrl_p->hc_ops.init_hpc_hw)(ctrl_p) != DDI_SUCCESS)
174 goto cleanup1;
175
176 /* initialize slot information soft state structure */
177 if ((ctrl_p->hc_ops.init_hpc_slotinfo)(ctrl_p) != DDI_SUCCESS)
178 goto cleanup2;
179
180 /* register the hot plug slot with DDI HP framework */
181 if (pciehpc_register_slot(ctrl_p) != DDI_SUCCESS)
182 goto cleanup3;
183
184 /* create minor node for this slot */
185 if (pcie_create_minor_node(ctrl_p, 0) != DDI_SUCCESS)
186 goto cleanup4;
187
188 /* HPC initialization is complete now */
189 ctrl_p->hc_flags = PCIE_HP_INITIALIZED_FLAG;
190
191 #ifdef DEBUG
192 /* For debug, dump the HPC registers */
193 pciehpc_dump_hpregs(ctrl_p);
194 #endif /* DEBUG */
195
196 return (DDI_SUCCESS);
197 cleanup4:
198 (void) pciehpc_unregister_slot(ctrl_p);
199 cleanup3:
200 (void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p);
201
202 cleanup2:
203 (void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p);
204
205 cleanup1:
206 PCIE_ENABLE_ERRORS(dip);
207 (void) pci_resource_destroy(dip);
208
209 pciehpc_destroy_controller(dip);
210 return (DDI_FAILURE);
211 }
212
213 /*
214 * Uninitialize HPC soft state structure and free up any resources
215 * used for the HPC instance.
216 */
217 int
pciehpc_uninit(dev_info_t * dip)218 pciehpc_uninit(dev_info_t *dip)
219 {
220 pcie_hp_ctrl_t *ctrl_p;
221
222 PCIE_DBG("pciehpc_uninit() called (dip=%p)\n", (void *)dip);
223
224 /* get the soft state structure for this dip */
225 if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) {
226 return (DDI_FAILURE);
227 }
228
229 pcie_remove_minor_node(ctrl_p, 0);
230
231 /* unregister the slot */
232 (void) pciehpc_unregister_slot(ctrl_p);
233
234 /* uninit any slot info data structures */
235 (void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p);
236
237 /* uninitialize hpc, remove interrupt handler, etc. */
238 (void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p);
239
240 PCIE_ENABLE_ERRORS(dip);
241
242 /*
243 * Destroy resource maps for this bus node.
244 */
245 (void) pci_resource_destroy(dip);
246
247 /* destroy the soft state structure */
248 pciehpc_destroy_controller(dip);
249
250 return (DDI_SUCCESS);
251 }
252
253 /*
254 * pciehpc_intr()
255 *
256 * Interrupt handler for PCI-E Hot plug controller interrupts.
257 *
258 * Note: This is only for native mode hot plug. This is called
259 * by the nexus driver at interrupt context. Interrupt Service Routine
260 * registration is done by the nexus driver for both hot plug and
261 * non-hot plug interrupts. This function is called from the ISR
262 * of the nexus driver to handle hot-plug interrupts.
263 */
264 int
pciehpc_intr(dev_info_t * dip)265 pciehpc_intr(dev_info_t *dip)
266 {
267 pcie_hp_ctrl_t *ctrl_p;
268 pcie_hp_slot_t *slot_p;
269 pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
270 uint16_t status, control;
271
272 /* get the soft state structure for this dip */
273 if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
274 return (DDI_INTR_UNCLAIMED);
275
276 mutex_enter(&ctrl_p->hc_mutex);
277
278 /* make sure the controller soft state is initialized */
279 if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
280 mutex_exit(&ctrl_p->hc_mutex);
281 return (DDI_INTR_UNCLAIMED);
282 }
283
284 /* if it is not NATIVE hot plug mode then return */
285 if (bus_p->bus_hp_curr_mode != PCIE_NATIVE_HP_MODE) {
286 mutex_exit(&ctrl_p->hc_mutex);
287 return (DDI_INTR_UNCLAIMED);
288 }
289
290 slot_p = ctrl_p->hc_slots[0];
291
292 /* read the current slot status register */
293 status = pciehpc_reg_get16(ctrl_p,
294 bus_p->bus_pcie_off + PCIE_SLOTSTS);
295
296 /* check if there are any hot plug interrupts occurred */
297 if (!(status & PCIE_SLOTSTS_STATUS_EVENTS)) {
298 /* no hot plug events occurred */
299 mutex_exit(&ctrl_p->hc_mutex);
300 return (DDI_INTR_UNCLAIMED);
301 }
302
303 /* clear the interrupt status bits */
304 pciehpc_reg_put16(ctrl_p,
305 bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
306
307 /* check for CMD COMPLETE interrupt */
308 if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
309 PCIE_DBG("pciehpc_intr(): CMD COMPLETED interrupt received\n");
310 /* wake up any one waiting for Command Completion event */
311 cv_signal(&ctrl_p->hc_cmd_comp_cv);
312 }
313
314 /* check for ATTN button interrupt */
315 if (status & PCIE_SLOTSTS_ATTN_BTN_PRESSED) {
316 PCIE_DBG("pciehpc_intr(): ATTN BUTTON interrupt received\n");
317
318 /* if ATTN button event is still pending then cancel it */
319 if (slot_p->hs_attn_btn_pending == B_TRUE)
320 slot_p->hs_attn_btn_pending = B_FALSE;
321 else
322 slot_p->hs_attn_btn_pending = B_TRUE;
323
324 /* wake up the ATTN event handler */
325 cv_signal(&slot_p->hs_attn_btn_cv);
326 }
327
328 /* check for power fault interrupt */
329 if (status & PCIE_SLOTSTS_PWR_FAULT_DETECTED) {
330
331 PCIE_DBG("pciehpc_intr(): POWER FAULT interrupt received"
332 " on slot %d\n", slot_p->hs_phy_slot_num);
333 control = pciehpc_reg_get16(ctrl_p,
334 bus_p->bus_pcie_off + PCIE_SLOTCTL);
335
336 if (control & PCIE_SLOTCTL_PWR_FAULT_EN) {
337 slot_p->hs_condition = AP_COND_FAILED;
338
339 /* disable power fault detction interrupt */
340 pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
341 PCIE_SLOTCTL, control & ~PCIE_SLOTCTL_PWR_FAULT_EN);
342
343 pciehpc_handle_power_fault(dip);
344 }
345 }
346
347 /* check for MRL SENSOR CHANGED interrupt */
348 if (status & PCIE_SLOTSTS_MRL_SENSOR_CHANGED) {
349 /* For now (phase-I), no action is taken on this event */
350 PCIE_DBG("pciehpc_intr(): MRL SENSOR CHANGED interrupt received"
351 " on slot %d\n", slot_p->hs_phy_slot_num);
352 }
353
354 /* check for PRESENCE CHANGED interrupt */
355 if (status & PCIE_SLOTSTS_PRESENCE_CHANGED) {
356
357 PCIE_DBG("pciehpc_intr(): PRESENCE CHANGED interrupt received"
358 " on slot %d\n", slot_p->hs_phy_slot_num);
359
360 if (status & PCIE_SLOTSTS_PRESENCE_DETECTED) {
361 /*
362 * card is inserted into the slot, ask DDI Hotplug
363 * framework to change state to Present.
364 */
365 cmn_err(CE_NOTE, "pciehpc (%s%d): card is inserted"
366 " in the slot %s",
367 ddi_driver_name(dip),
368 ddi_get_instance(dip),
369 slot_p->hs_info.cn_name);
370
371 (void) ndi_hp_state_change_req(dip,
372 slot_p->hs_info.cn_name,
373 DDI_HP_CN_STATE_PRESENT,
374 DDI_HP_REQ_ASYNC);
375 } else { /* card is removed from the slot */
376 cmn_err(CE_NOTE, "pciehpc (%s%d): card is removed"
377 " from the slot %s",
378 ddi_driver_name(dip),
379 ddi_get_instance(dip),
380 slot_p->hs_info.cn_name);
381
382 if (slot_p->hs_info.cn_state ==
383 DDI_HP_CN_STATE_ENABLED) {
384 /* Card is removed when slot is enabled */
385 slot_p->hs_condition = AP_COND_FAILED;
386 } else {
387 slot_p->hs_condition = AP_COND_UNKNOWN;
388 }
389 /* make sure to disable power fault detction intr */
390 control = pciehpc_reg_get16(ctrl_p,
391 bus_p->bus_pcie_off + PCIE_SLOTCTL);
392
393 if (control & PCIE_SLOTCTL_PWR_FAULT_EN)
394 pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
395 PCIE_SLOTCTL,
396 control & ~PCIE_SLOTCTL_PWR_FAULT_EN);
397
398 /*
399 * If supported, notify the child device driver that the
400 * device is being removed.
401 */
402 dev_info_t *cdip = ddi_get_child(dip);
403 if (cdip != NULL) {
404 ddi_eventcookie_t rm_cookie;
405 if (ddi_get_eventcookie(cdip,
406 DDI_DEVI_REMOVE_EVENT,
407 &rm_cookie) == DDI_SUCCESS) {
408 ndi_post_event(dip, cdip, rm_cookie,
409 NULL);
410 }
411 }
412
413 /*
414 * Ask DDI Hotplug framework to change state to Empty
415 */
416 (void) ndi_hp_state_change_req(dip,
417 slot_p->hs_info.cn_name,
418 DDI_HP_CN_STATE_EMPTY,
419 DDI_HP_REQ_ASYNC);
420 }
421 }
422
423 /* check for DLL state changed interrupt */
424 if (ctrl_p->hc_dll_active_rep &&
425 (status & PCIE_SLOTSTS_DLL_STATE_CHANGED)) {
426 PCIE_DBG("pciehpc_intr(): DLL STATE CHANGED interrupt received"
427 " on slot %d\n", slot_p->hs_phy_slot_num);
428
429 cv_signal(&slot_p->hs_dll_active_cv);
430 }
431
432 mutex_exit(&ctrl_p->hc_mutex);
433
434 return (DDI_INTR_CLAIMED);
435 }
436
437 /*
438 * Handle hotplug commands
439 *
440 * Note: This function is called by DDI HP framework at kernel context only
441 */
442 /* ARGSUSED */
443 int
pciehpc_hp_ops(dev_info_t * dip,char * cn_name,ddi_hp_op_t op,void * arg,void * result)444 pciehpc_hp_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op,
445 void *arg, void *result)
446 {
447 pcie_hp_ctrl_t *ctrl_p;
448 pcie_hp_slot_t *slot_p;
449 int ret = DDI_SUCCESS;
450
451 PCIE_DBG("pciehpc_hp_ops: dip=%p cn_name=%s op=%x arg=%p\n",
452 dip, cn_name, op, arg);
453
454 if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
455 return (DDI_FAILURE);
456
457 slot_p = ctrl_p->hc_slots[0];
458
459 if (strcmp(cn_name, slot_p->hs_info.cn_name) != 0)
460 return (DDI_EINVAL);
461
462 switch (op) {
463 case DDI_HPOP_CN_GET_STATE:
464 {
465 mutex_enter(&slot_p->hs_ctrl->hc_mutex);
466
467 /* get the current slot state */
468 pciehpc_get_slot_state(slot_p);
469
470 *((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state;
471
472 mutex_exit(&slot_p->hs_ctrl->hc_mutex);
473 break;
474 }
475 case DDI_HPOP_CN_CHANGE_STATE:
476 {
477 ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg;
478
479 mutex_enter(&slot_p->hs_ctrl->hc_mutex);
480
481 ret = pciehpc_change_slot_state(slot_p, target_state);
482 *(ddi_hp_cn_state_t *)result = slot_p->hs_info.cn_state;
483
484 mutex_exit(&slot_p->hs_ctrl->hc_mutex);
485 break;
486 }
487 case DDI_HPOP_CN_PROBE:
488
489 ret = pciehpc_slot_probe(slot_p);
490
491 break;
492 case DDI_HPOP_CN_UNPROBE:
493 ret = pciehpc_slot_unprobe(slot_p);
494
495 break;
496 case DDI_HPOP_CN_GET_PROPERTY:
497 ret = pciehpc_slot_get_property(slot_p,
498 (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
499 break;
500 case DDI_HPOP_CN_SET_PROPERTY:
501 ret = pciehpc_slot_set_property(slot_p,
502 (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
503 break;
504 default:
505 ret = DDI_ENOTSUP;
506 break;
507 }
508
509 return (ret);
510 }
511
512 /*
513 * Get the current state of the slot from the hw.
514 *
515 * The slot state should have been initialized before this function gets called.
516 */
517 void
pciehpc_get_slot_state(pcie_hp_slot_t * slot_p)518 pciehpc_get_slot_state(pcie_hp_slot_t *slot_p)
519 {
520 pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
521 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
522 uint16_t control, status;
523 ddi_hp_cn_state_t curr_state = slot_p->hs_info.cn_state;
524
525 /* read the Slot Control Register */
526 control = pciehpc_reg_get16(ctrl_p,
527 bus_p->bus_pcie_off + PCIE_SLOTCTL);
528
529 slot_p->hs_fault_led_state = PCIE_HP_LED_OFF; /* no fault led */
530 slot_p->hs_active_led_state = PCIE_HP_LED_OFF; /* no active led */
531
532 /* read the current Slot Status Register */
533 status = pciehpc_reg_get16(ctrl_p,
534 bus_p->bus_pcie_off + PCIE_SLOTSTS);
535
536 /* get POWER led state */
537 slot_p->hs_power_led_state =
538 pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control));
539
540 /* get ATTN led state */
541 slot_p->hs_attn_led_state =
542 pciehpc_led_state_to_hpc(pcie_slotctl_attn_indicator_get(control));
543
544 if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
545 /* no device present; slot is empty */
546 slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY;
547
548 return;
549 }
550
551 /* device is present */
552 slot_p->hs_info.cn_state = DDI_HP_CN_STATE_PRESENT;
553
554 if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) {
555 /*
556 * Device is powered on. Set to "ENABLED" state (skip
557 * POWERED state) because there is not a explicit "enable"
558 * action exists for PCIe.
559 * If it is already in "POWERED" state, then keep it until
560 * user explicitly change it to other states.
561 */
562 if (curr_state == DDI_HP_CN_STATE_POWERED) {
563 slot_p->hs_info.cn_state = curr_state;
564 } else {
565 slot_p->hs_info.cn_state = DDI_HP_CN_STATE_ENABLED;
566 }
567 }
568 }
569
570 /*
571 * setup slot name/slot-number info.
572 */
573 void
pciehpc_set_slot_name(pcie_hp_ctrl_t * ctrl_p)574 pciehpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p)
575 {
576 pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
577 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
578 uchar_t *slotname_data;
579 int *slotnum;
580 uint_t count;
581 int len;
582 int invalid_slotnum = 0;
583 uint32_t slot_capabilities;
584
585 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ctrl_p->hc_dip,
586 DDI_PROP_DONTPASS, "physical-slot#", &slotnum, &count) ==
587 DDI_PROP_SUCCESS) {
588 slot_p->hs_phy_slot_num = slotnum[0];
589 ddi_prop_free(slotnum);
590 } else {
591 slot_capabilities = pciehpc_reg_get32(ctrl_p,
592 bus_p->bus_pcie_off + PCIE_SLOTCAP);
593 slot_p->hs_phy_slot_num =
594 PCIE_SLOTCAP_PHY_SLOT_NUM(slot_capabilities);
595 }
596
597 /* platform may not have initialized it */
598 if (!slot_p->hs_phy_slot_num) {
599 PCIE_DBG("%s#%d: Invalid slot number!\n",
600 ddi_driver_name(ctrl_p->hc_dip),
601 ddi_get_instance(ctrl_p->hc_dip));
602 slot_p->hs_phy_slot_num = pciehpc_reg_get8(ctrl_p,
603 PCI_BCNF_SECBUS);
604 invalid_slotnum = 1;
605 }
606 slot_p->hs_info.cn_num = slot_p->hs_phy_slot_num;
607 slot_p->hs_info.cn_num_dpd_on = DDI_HP_CN_NUM_NONE;
608
609 /*
610 * construct the slot_name:
611 * if "slot-names" property exists then use that name
612 * else if valid slot number exists then it is "pcie<slot-num>".
613 * else it will be "pcie<sec-bus-number>dev0"
614 */
615 if (ddi_getlongprop(DDI_DEV_T_ANY, ctrl_p->hc_dip, DDI_PROP_DONTPASS,
616 "slot-names", (caddr_t)&slotname_data, &len) == DDI_PROP_SUCCESS) {
617 char tmp_name[256];
618
619 /*
620 * Note: for PCI-E slots, the device number is always 0 so the
621 * first (and only) string is the slot name for this slot.
622 */
623 (void) snprintf(tmp_name, sizeof (tmp_name),
624 (char *)slotname_data + 4);
625 slot_p->hs_info.cn_name = ddi_strdup(tmp_name, KM_SLEEP);
626 kmem_free(slotname_data, len);
627 } else {
628 if (invalid_slotnum) {
629 /* use device number ie. 0 */
630 slot_p->hs_info.cn_name = ddi_strdup("pcie0",
631 KM_SLEEP);
632 } else {
633 char tmp_name[256];
634
635 (void) snprintf(tmp_name, sizeof (tmp_name), "pcie%d",
636 slot_p->hs_phy_slot_num);
637 slot_p->hs_info.cn_name = ddi_strdup(tmp_name,
638 KM_SLEEP);
639 }
640 }
641 }
642
643 /*
644 * Read/Write access to HPC registers. If platform nexus has non-standard
645 * HPC access mechanism then regops functions are used to do reads/writes.
646 */
647 uint8_t
pciehpc_reg_get8(pcie_hp_ctrl_t * ctrl_p,uint_t off)648 pciehpc_reg_get8(pcie_hp_ctrl_t *ctrl_p, uint_t off)
649 {
650 if (ctrl_p->hc_regops.get != NULL) {
651 return ((uint8_t)ctrl_p->hc_regops.get(
652 ctrl_p->hc_regops.cookie, (off_t)off));
653 } else {
654 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
655
656 return (pci_config_get8(bus_p->bus_cfg_hdl, off));
657 }
658 }
659
660 uint16_t
pciehpc_reg_get16(pcie_hp_ctrl_t * ctrl_p,uint_t off)661 pciehpc_reg_get16(pcie_hp_ctrl_t *ctrl_p, uint_t off)
662 {
663 if (ctrl_p->hc_regops.get != NULL) {
664 return ((uint16_t)ctrl_p->hc_regops.get(
665 ctrl_p->hc_regops.cookie, (off_t)off));
666 } else {
667 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
668
669 return (pci_config_get16(bus_p->bus_cfg_hdl, off));
670 }
671 }
672
673 uint32_t
pciehpc_reg_get32(pcie_hp_ctrl_t * ctrl_p,uint_t off)674 pciehpc_reg_get32(pcie_hp_ctrl_t *ctrl_p, uint_t off)
675 {
676 if (ctrl_p->hc_regops.get != NULL) {
677 return ((uint32_t)ctrl_p->hc_regops.get(
678 ctrl_p->hc_regops.cookie, (off_t)off));
679 } else {
680 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
681
682 return (pci_config_get32(bus_p->bus_cfg_hdl, off));
683 }
684 }
685
686 void
pciehpc_reg_put8(pcie_hp_ctrl_t * ctrl_p,uint_t off,uint8_t val)687 pciehpc_reg_put8(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint8_t val)
688 {
689 if (ctrl_p->hc_regops.put != NULL) {
690 ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
691 (off_t)off, (uint_t)val);
692 } else {
693 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
694
695 pci_config_put8(bus_p->bus_cfg_hdl, off, val);
696 }
697 }
698
699 void
pciehpc_reg_put16(pcie_hp_ctrl_t * ctrl_p,uint_t off,uint16_t val)700 pciehpc_reg_put16(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint16_t val)
701 {
702 if (ctrl_p->hc_regops.put != NULL) {
703 ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
704 (off_t)off, (uint_t)val);
705 } else {
706 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
707
708 pci_config_put16(bus_p->bus_cfg_hdl, off, val);
709 }
710 }
711
712 void
pciehpc_reg_put32(pcie_hp_ctrl_t * ctrl_p,uint_t off,uint32_t val)713 pciehpc_reg_put32(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint32_t val)
714 {
715 if (ctrl_p->hc_regops.put != NULL) {
716 ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
717 (off_t)off, (uint_t)val);
718 } else {
719 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
720
721 pci_config_put32(bus_p->bus_cfg_hdl, off, val);
722 }
723 }
724
725 /*
726 * ************************************************************************
727 * *** Local functions (called within this file)
728 * *** PCIe Native Hotplug mode specific functions
729 * ************************************************************************
730 */
731
732 /*
733 * Initialize HPC hardware, install interrupt handler, etc. It doesn't
734 * enable hot plug interrupts.
735 *
736 * (Note: It is called only from pciehpc_init().)
737 */
738 static int
pciehpc_hpc_init(pcie_hp_ctrl_t * ctrl_p)739 pciehpc_hpc_init(pcie_hp_ctrl_t *ctrl_p)
740 {
741 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
742 uint16_t reg;
743
744 /* read the Slot Control Register */
745 reg = pciehpc_reg_get16(ctrl_p,
746 bus_p->bus_pcie_off + PCIE_SLOTCTL);
747
748 /* disable all interrupts */
749 reg &= ~(PCIE_SLOTCTL_INTR_MASK);
750 pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
751 PCIE_SLOTCTL, reg);
752
753 /* clear any interrupt status bits */
754 reg = pciehpc_reg_get16(ctrl_p,
755 bus_p->bus_pcie_off + PCIE_SLOTSTS);
756 pciehpc_reg_put16(ctrl_p,
757 bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
758
759 return (DDI_SUCCESS);
760 }
761
762 /*
763 * Uninitialize HPC hardware, uninstall interrupt handler, etc.
764 *
765 * (Note: It is called only from pciehpc_uninit().)
766 */
767 static int
pciehpc_hpc_uninit(pcie_hp_ctrl_t * ctrl_p)768 pciehpc_hpc_uninit(pcie_hp_ctrl_t *ctrl_p)
769 {
770 /* disable interrupts */
771 (void) pciehpc_disable_intr(ctrl_p);
772
773 return (DDI_SUCCESS);
774 }
775
776 /*
777 * Setup slot information for use with DDI HP framework.
778 */
779 static int
pciehpc_slotinfo_init(pcie_hp_ctrl_t * ctrl_p)780 pciehpc_slotinfo_init(pcie_hp_ctrl_t *ctrl_p)
781 {
782 uint32_t slot_capabilities, link_capabilities;
783 pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
784 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
785
786 mutex_enter(&ctrl_p->hc_mutex);
787 /*
788 * setup DDI HP framework slot information structure
789 */
790 slot_p->hs_device_num = 0;
791
792 slot_p->hs_info.cn_type = DDI_HP_CN_TYPE_PCIE;
793 slot_p->hs_info.cn_type_str = (ctrl_p->hc_regops.get == NULL) ?
794 PCIE_NATIVE_HP_TYPE : PCIE_PROP_HP_TYPE;
795 slot_p->hs_info.cn_child = NULL;
796
797 slot_p->hs_minor =
798 PCI_MINOR_NUM(ddi_get_instance(ctrl_p->hc_dip),
799 slot_p->hs_device_num);
800 slot_p->hs_condition = AP_COND_UNKNOWN;
801
802 /* read Slot Capabilities Register */
803 slot_capabilities = pciehpc_reg_get32(ctrl_p,
804 bus_p->bus_pcie_off + PCIE_SLOTCAP);
805
806 /* set slot-name/slot-number info */
807 pciehpc_set_slot_name(ctrl_p);
808
809 /* check if Attn Button present */
810 ctrl_p->hc_has_attn = (slot_capabilities & PCIE_SLOTCAP_ATTN_BUTTON) ?
811 B_TRUE : B_FALSE;
812
813 /* check if Manual Retention Latch sensor present */
814 ctrl_p->hc_has_mrl = (slot_capabilities & PCIE_SLOTCAP_MRL_SENSOR) ?
815 B_TRUE : B_FALSE;
816
817 /*
818 * PCI-E version 1.1 defines EMI Lock Present bit
819 * in Slot Capabilities register. Check for it.
820 */
821 ctrl_p->hc_has_emi_lock = (slot_capabilities &
822 PCIE_SLOTCAP_EMI_LOCK_PRESENT) ? B_TRUE : B_FALSE;
823
824 link_capabilities = pciehpc_reg_get32(ctrl_p,
825 bus_p->bus_pcie_off + PCIE_LINKCAP);
826 ctrl_p->hc_dll_active_rep = (link_capabilities &
827 PCIE_LINKCAP_DLL_ACTIVE_REP_CAPABLE) ? B_TRUE : B_FALSE;
828 if (ctrl_p->hc_dll_active_rep)
829 cv_init(&slot_p->hs_dll_active_cv, NULL, CV_DRIVER, NULL);
830
831 /* setup thread for handling ATTN button events */
832 if (ctrl_p->hc_has_attn) {
833 PCIE_DBG("pciehpc_slotinfo_init: setting up ATTN button event "
834 "handler thread for slot %d\n", slot_p->hs_phy_slot_num);
835
836 cv_init(&slot_p->hs_attn_btn_cv, NULL, CV_DRIVER, NULL);
837 slot_p->hs_attn_btn_pending = B_FALSE;
838 slot_p->hs_attn_btn_threadp = thread_create(NULL, 0,
839 pciehpc_attn_btn_handler,
840 (void *)ctrl_p, 0, &p0, TS_RUN, minclsyspri);
841 slot_p->hs_attn_btn_thread_exit = B_FALSE;
842 }
843
844 /* get current slot state from the hw */
845 slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY;
846 pciehpc_get_slot_state(slot_p);
847 if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_ENABLED)
848 slot_p->hs_condition = AP_COND_OK;
849
850 mutex_exit(&ctrl_p->hc_mutex);
851
852 return (DDI_SUCCESS);
853 }
854
855 /*ARGSUSED*/
856 static int
pciehpc_slotinfo_uninit(pcie_hp_ctrl_t * ctrl_p)857 pciehpc_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p)
858 {
859 pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
860
861 if (slot_p->hs_attn_btn_threadp != NULL) {
862 mutex_enter(&ctrl_p->hc_mutex);
863 slot_p->hs_attn_btn_thread_exit = B_TRUE;
864 cv_signal(&slot_p->hs_attn_btn_cv);
865 PCIE_DBG("pciehpc_slotinfo_uninit: "
866 "waiting for ATTN thread exit\n");
867 cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
868 PCIE_DBG("pciehpc_slotinfo_uninit: ATTN thread exit\n");
869 cv_destroy(&slot_p->hs_attn_btn_cv);
870 slot_p->hs_attn_btn_threadp = NULL;
871 mutex_exit(&ctrl_p->hc_mutex);
872 }
873
874 if (ctrl_p->hc_dll_active_rep)
875 cv_destroy(&slot_p->hs_dll_active_cv);
876 if (slot_p->hs_info.cn_name)
877 kmem_free(slot_p->hs_info.cn_name,
878 strlen(slot_p->hs_info.cn_name) + 1);
879
880 return (DDI_SUCCESS);
881 }
882
883 /*
884 * Enable hot plug interrupts.
885 * Note: this is only for Native hot plug mode.
886 */
887 static int
pciehpc_enable_intr(pcie_hp_ctrl_t * ctrl_p)888 pciehpc_enable_intr(pcie_hp_ctrl_t *ctrl_p)
889 {
890 pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
891 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
892 uint16_t reg;
893
894 /* clear any interrupt status bits */
895 reg = pciehpc_reg_get16(ctrl_p,
896 bus_p->bus_pcie_off + PCIE_SLOTSTS);
897 pciehpc_reg_put16(ctrl_p,
898 bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
899
900 /* read the Slot Control Register */
901 reg = pciehpc_reg_get16(ctrl_p,
902 bus_p->bus_pcie_off + PCIE_SLOTCTL);
903
904 /*
905 * enable interrupts: power fault detection interrupt is enabled
906 * only when the slot is powered ON
907 */
908 if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
909 pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
910 PCIE_SLOTCTL, reg | PCIE_SLOTCTL_INTR_MASK);
911 else
912 pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
913 PCIE_SLOTCTL, reg | (PCIE_SLOTCTL_INTR_MASK &
914 ~PCIE_SLOTCTL_PWR_FAULT_EN));
915
916 return (DDI_SUCCESS);
917 }
918
919 /*
920 * Disable hot plug interrupts.
921 * Note: this is only for Native hot plug mode.
922 */
923 static int
pciehpc_disable_intr(pcie_hp_ctrl_t * ctrl_p)924 pciehpc_disable_intr(pcie_hp_ctrl_t *ctrl_p)
925 {
926 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
927 uint16_t reg;
928
929 /* read the Slot Control Register */
930 reg = pciehpc_reg_get16(ctrl_p,
931 bus_p->bus_pcie_off + PCIE_SLOTCTL);
932
933 /* disable all interrupts */
934 reg &= ~(PCIE_SLOTCTL_INTR_MASK);
935 pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTCTL, reg);
936
937 /* clear any interrupt status bits */
938 reg = pciehpc_reg_get16(ctrl_p,
939 bus_p->bus_pcie_off + PCIE_SLOTSTS);
940 pciehpc_reg_put16(ctrl_p,
941 bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
942
943 return (DDI_SUCCESS);
944 }
945
946 /*
947 * Allocate a new hotplug controller and slot structures for HPC
948 * associated with this dip.
949 */
950 static pcie_hp_ctrl_t *
pciehpc_create_controller(dev_info_t * dip)951 pciehpc_create_controller(dev_info_t *dip)
952 {
953 pcie_hp_ctrl_t *ctrl_p;
954 pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
955
956 ctrl_p = kmem_zalloc(sizeof (pcie_hp_ctrl_t), KM_SLEEP);
957 ctrl_p->hc_dip = dip;
958
959 /* Allocate a new slot structure. */
960 ctrl_p->hc_slots[0] = kmem_zalloc(sizeof (pcie_hp_slot_t), KM_SLEEP);
961 ctrl_p->hc_slots[0]->hs_num = 0;
962 ctrl_p->hc_slots[0]->hs_ctrl = ctrl_p;
963
964 /* Initialize the interrupt mutex */
965 mutex_init(&ctrl_p->hc_mutex, NULL, MUTEX_DRIVER,
966 (void *)PCIE_INTR_PRI);
967
968 /* Initialize synchronization conditional variable */
969 cv_init(&ctrl_p->hc_cmd_comp_cv, NULL, CV_DRIVER, NULL);
970 ctrl_p->hc_cmd_pending = B_FALSE;
971
972 bus_p->bus_hp_curr_mode = PCIE_NATIVE_HP_MODE;
973 PCIE_SET_HP_CTRL(dip, ctrl_p);
974
975 return (ctrl_p);
976 }
977
978 /*
979 * Remove the HPC controller and slot structures
980 */
981 static void
pciehpc_destroy_controller(dev_info_t * dip)982 pciehpc_destroy_controller(dev_info_t *dip)
983 {
984 pcie_hp_ctrl_t *ctrl_p;
985 pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
986
987 /* get the soft state structure for this dip */
988 if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
989 return;
990
991 PCIE_SET_HP_CTRL(dip, NULL);
992 bus_p->bus_hp_curr_mode = PCIE_NONE_HP_MODE;
993
994 mutex_destroy(&ctrl_p->hc_mutex);
995 cv_destroy(&ctrl_p->hc_cmd_comp_cv);
996 kmem_free(ctrl_p->hc_slots[0], sizeof (pcie_hp_slot_t));
997 kmem_free(ctrl_p, sizeof (pcie_hp_ctrl_t));
998 }
999
1000 /*
1001 * Register the PCI-E hot plug slot with DDI HP framework.
1002 */
1003 static int
pciehpc_register_slot(pcie_hp_ctrl_t * ctrl_p)1004 pciehpc_register_slot(pcie_hp_ctrl_t *ctrl_p)
1005 {
1006 pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
1007 dev_info_t *dip = ctrl_p->hc_dip;
1008
1009 /* register the slot with DDI HP framework */
1010 if (ndi_hp_register(dip, &slot_p->hs_info) != NDI_SUCCESS) {
1011 PCIE_DBG("pciehpc_register_slot() failed to register slot %d\n",
1012 slot_p->hs_phy_slot_num);
1013 return (DDI_FAILURE);
1014 }
1015
1016 pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip),
1017 slot_p->hs_minor), slot_p->hs_device_num);
1018
1019 PCIE_DBG("pciehpc_register_slot(): registered slot %d\n",
1020 slot_p->hs_phy_slot_num);
1021
1022 return (DDI_SUCCESS);
1023 }
1024
1025 /*
1026 * Unregister the PCI-E hot plug slot from DDI HP framework.
1027 */
1028 static int
pciehpc_unregister_slot(pcie_hp_ctrl_t * ctrl_p)1029 pciehpc_unregister_slot(pcie_hp_ctrl_t *ctrl_p)
1030 {
1031 pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
1032 dev_info_t *dip = ctrl_p->hc_dip;
1033
1034 pcie_hp_delete_occupant_props(dip, makedevice(ddi_driver_major(dip),
1035 slot_p->hs_minor));
1036
1037 /* unregister the slot with DDI HP framework */
1038 if (ndi_hp_unregister(dip, slot_p->hs_info.cn_name) != NDI_SUCCESS) {
1039 PCIE_DBG("pciehpc_unregister_slot() "
1040 "failed to unregister slot %d\n", slot_p->hs_phy_slot_num);
1041 return (DDI_FAILURE);
1042 }
1043
1044 PCIE_DBG("pciehpc_unregister_slot(): unregistered slot %d\n",
1045 slot_p->hs_phy_slot_num);
1046
1047 return (DDI_SUCCESS);
1048 }
1049
1050 /*
1051 * pciehpc_slot_poweron()
1052 *
1053 * Poweron/Enable the slot.
1054 *
1055 * Note: This function is called by DDI HP framework at kernel context only
1056 */
1057 /*ARGSUSED*/
1058 static int
pciehpc_slot_poweron(pcie_hp_slot_t * slot_p,ddi_hp_cn_state_t * result)1059 pciehpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result)
1060 {
1061 pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
1062 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1063 uint16_t status, control;
1064
1065 ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
1066
1067 /* get the current state of the slot */
1068 pciehpc_get_slot_state(slot_p);
1069
1070 /* check if the slot is already in the 'enabled' state */
1071 if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) {
1072 /* slot is already in the 'enabled' state */
1073 PCIE_DBG("pciehpc_slot_poweron() slot %d already enabled\n",
1074 slot_p->hs_phy_slot_num);
1075
1076 *result = slot_p->hs_info.cn_state;
1077 return (DDI_SUCCESS);
1078 }
1079
1080 /* read the Slot Status Register */
1081 status = pciehpc_reg_get16(ctrl_p,
1082 bus_p->bus_pcie_off + PCIE_SLOTSTS);
1083
1084 /* make sure the MRL switch is closed if present */
1085 if ((ctrl_p->hc_has_mrl) && (status & PCIE_SLOTSTS_MRL_SENSOR_OPEN)) {
1086 /* MRL switch is open */
1087 cmn_err(CE_WARN, "MRL switch is open on slot %d\n",
1088 slot_p->hs_phy_slot_num);
1089 goto cleanup;
1090 }
1091
1092 /* make sure the slot has a device present */
1093 if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
1094 /* slot is empty */
1095 PCIE_DBG("slot %d is empty\n", slot_p->hs_phy_slot_num);
1096 goto cleanup;
1097 }
1098
1099 /* get the current state of Slot Control Register */
1100 control = pciehpc_reg_get16(ctrl_p,
1101 bus_p->bus_pcie_off + PCIE_SLOTCTL);
1102
1103 /*
1104 * Enable power to the slot involves:
1105 * 1. Set power LED to blink and ATTN led to OFF.
1106 * 2. Set power control ON in Slot Control Reigster and
1107 * wait for Command Completed Interrupt or 1 sec timeout.
1108 * 3. If Data Link Layer State Changed events are supported
1109 * then wait for the event to indicate Data Layer Link
1110 * is active. The time out value for this event is 1 second.
1111 * This is specified in PCI-E version 1.1.
1112 * 4. Set power LED to be ON.
1113 */
1114
1115 /* 1. set power LED to blink & ATTN led to OFF */
1116 pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
1117 pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
1118
1119 /* 2. set power control to ON */
1120 control = pciehpc_reg_get16(ctrl_p,
1121 bus_p->bus_pcie_off + PCIE_SLOTCTL);
1122 control &= ~PCIE_SLOTCTL_PWR_CONTROL;
1123 pciehpc_issue_hpc_command(ctrl_p, control);
1124
1125 /* 3. wait for DLL State Change event, if it's supported */
1126 if (ctrl_p->hc_dll_active_rep) {
1127 status = pciehpc_reg_get16(ctrl_p,
1128 bus_p->bus_pcie_off + PCIE_LINKSTS);
1129
1130 if (!(status & PCIE_LINKSTS_DLL_LINK_ACTIVE)) {
1131 /* wait 1 sec for the DLL State Changed event */
1132 (void) cv_timedwait(&slot_p->hs_dll_active_cv,
1133 &ctrl_p->hc_mutex,
1134 ddi_get_lbolt() +
1135 SEC_TO_TICK(PCIE_HP_DLL_STATE_CHANGE_TIMEOUT));
1136
1137 /* check Link status */
1138 status = pciehpc_reg_get16(ctrl_p,
1139 bus_p->bus_pcie_off +
1140 PCIE_LINKSTS);
1141 if (!(status & PCIE_LINKSTS_DLL_LINK_ACTIVE))
1142 goto cleanup2;
1143 }
1144 }
1145
1146 /* wait 1 sec for link to come up */
1147 delay(drv_usectohz(1000000));
1148
1149 /* check power is really turned ON */
1150 control = pciehpc_reg_get16(ctrl_p,
1151 bus_p->bus_pcie_off + PCIE_SLOTCTL);
1152
1153 if (control & PCIE_SLOTCTL_PWR_CONTROL) {
1154 PCIE_DBG("slot %d fails to turn on power on connect\n",
1155 slot_p->hs_phy_slot_num);
1156
1157 goto cleanup1;
1158 }
1159
1160 /* clear power fault status */
1161 status = pciehpc_reg_get16(ctrl_p,
1162 bus_p->bus_pcie_off + PCIE_SLOTSTS);
1163 status |= PCIE_SLOTSTS_PWR_FAULT_DETECTED;
1164 pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTSTS,
1165 status);
1166
1167 /* enable power fault detection interrupt */
1168 control |= PCIE_SLOTCTL_PWR_FAULT_EN;
1169 pciehpc_issue_hpc_command(ctrl_p, control);
1170
1171 /* 4. Set power LED to be ON */
1172 pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_ON);
1173
1174 /* if EMI is present, turn it ON */
1175 if (ctrl_p->hc_has_emi_lock) {
1176 status = pciehpc_reg_get16(ctrl_p,
1177 bus_p->bus_pcie_off + PCIE_SLOTSTS);
1178
1179 if (!(status & PCIE_SLOTSTS_EMI_LOCK_SET)) {
1180 control = pciehpc_reg_get16(ctrl_p,
1181 bus_p->bus_pcie_off + PCIE_SLOTCTL);
1182 control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL;
1183 pciehpc_issue_hpc_command(ctrl_p, control);
1184
1185 /* wait 1 sec after toggling the state of EMI lock */
1186 delay(drv_usectohz(1000000));
1187 }
1188 }
1189
1190 *result = slot_p->hs_info.cn_state =
1191 DDI_HP_CN_STATE_POWERED;
1192
1193 return (DDI_SUCCESS);
1194
1195 cleanup2:
1196 control = pciehpc_reg_get16(ctrl_p,
1197 bus_p->bus_pcie_off + PCIE_SLOTCTL);
1198
1199 /* if power is ON, set power control to OFF */
1200 if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) {
1201 control |= PCIE_SLOTCTL_PWR_CONTROL;
1202 pciehpc_issue_hpc_command(ctrl_p, control);
1203 }
1204
1205 cleanup1:
1206 /* set power led to OFF */
1207 pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
1208
1209 cleanup:
1210 return (DDI_FAILURE);
1211 }
1212
1213 /*ARGSUSED*/
1214 static int
pciehpc_slot_poweroff(pcie_hp_slot_t * slot_p,ddi_hp_cn_state_t * result)1215 pciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result)
1216 {
1217 pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
1218 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1219 uint16_t status, control;
1220
1221 ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
1222
1223 /* get the current state of the slot */
1224 pciehpc_get_slot_state(slot_p);
1225
1226 /* check if the slot is not in the "enabled' state */
1227 if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) {
1228 /* slot is in the 'disabled' state */
1229 PCIE_DBG("pciehpc_slot_poweroff(): "
1230 "slot %d already disabled\n", slot_p->hs_phy_slot_num);
1231 ASSERT(slot_p->hs_power_led_state == PCIE_HP_LED_OFF);
1232
1233 *result = slot_p->hs_info.cn_state;
1234 return (DDI_SUCCESS);
1235 }
1236
1237 /* read the Slot Status Register */
1238 status = pciehpc_reg_get16(ctrl_p,
1239 bus_p->bus_pcie_off + PCIE_SLOTSTS);
1240
1241 /* make sure the slot has a device present */
1242 if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
1243 /* slot is empty */
1244 PCIE_DBG("pciehpc_slot_poweroff(): slot %d is empty\n",
1245 slot_p->hs_phy_slot_num);
1246 goto cleanup;
1247 }
1248
1249 /*
1250 * Disable power to the slot involves:
1251 * 1. Set power LED to blink.
1252 * 2. Set power control OFF in Slot Control Reigster and
1253 * wait for Command Completed Interrupt or 1 sec timeout.
1254 * 3. Set POWER led and ATTN led to be OFF.
1255 */
1256
1257 /* 1. set power LED to blink */
1258 pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
1259
1260 /* disable power fault detection interrupt */
1261 control = pciehpc_reg_get16(ctrl_p,
1262 bus_p->bus_pcie_off + PCIE_SLOTCTL);
1263 control &= ~PCIE_SLOTCTL_PWR_FAULT_EN;
1264 pciehpc_issue_hpc_command(ctrl_p, control);
1265
1266 /* 2. set power control to OFF */
1267 control = pciehpc_reg_get16(ctrl_p,
1268 bus_p->bus_pcie_off + PCIE_SLOTCTL);
1269 control |= PCIE_SLOTCTL_PWR_CONTROL;
1270 pciehpc_issue_hpc_command(ctrl_p, control);
1271
1272 #ifdef DEBUG
1273 /* check for power control bit to be OFF */
1274 control = pciehpc_reg_get16(ctrl_p,
1275 bus_p->bus_pcie_off + PCIE_SLOTCTL);
1276 ASSERT(control & PCIE_SLOTCTL_PWR_CONTROL);
1277 #endif
1278
1279 /* 3. Set power LED to be OFF */
1280 pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
1281 pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
1282
1283 /* if EMI is present, turn it OFF */
1284 if (ctrl_p->hc_has_emi_lock) {
1285 status = pciehpc_reg_get16(ctrl_p,
1286 bus_p->bus_pcie_off + PCIE_SLOTSTS);
1287
1288 if (status & PCIE_SLOTSTS_EMI_LOCK_SET) {
1289 control = pciehpc_reg_get16(ctrl_p,
1290 bus_p->bus_pcie_off + PCIE_SLOTCTL);
1291 control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL;
1292 pciehpc_issue_hpc_command(ctrl_p, control);
1293
1294 /* wait 1 sec after toggling the state of EMI lock */
1295 delay(drv_usectohz(1000000));
1296 }
1297 }
1298
1299 /* get the current state of the slot */
1300 pciehpc_get_slot_state(slot_p);
1301
1302 *result = slot_p->hs_info.cn_state;
1303
1304 return (DDI_SUCCESS);
1305
1306 cleanup:
1307 return (DDI_FAILURE);
1308 }
1309
1310 /*
1311 * pciehpc_slot_probe()
1312 *
1313 * Probe the slot.
1314 *
1315 * Note: This function is called by DDI HP framework at kernel context only
1316 */
1317 /*ARGSUSED*/
1318 static int
pciehpc_slot_probe(pcie_hp_slot_t * slot_p)1319 pciehpc_slot_probe(pcie_hp_slot_t *slot_p)
1320 {
1321 pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
1322 int ret = DDI_SUCCESS;
1323
1324 mutex_enter(&ctrl_p->hc_mutex);
1325
1326 /* get the current state of the slot */
1327 pciehpc_get_slot_state(slot_p);
1328
1329 /*
1330 * Probe a given PCIe Hotplug Connection (CN).
1331 */
1332 PCIE_DISABLE_ERRORS(ctrl_p->hc_dip);
1333 ret = pcie_hp_probe(slot_p);
1334
1335 if (ret != DDI_SUCCESS) {
1336 PCIE_DBG("pciehpc_slot_probe() failed\n");
1337
1338 /* turn the ATTN led ON for configure failure */
1339 pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_ON);
1340
1341 /* if power to the slot is still on then set Power led to ON */
1342 if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
1343 pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
1344 PCIE_HP_LED_ON);
1345
1346 mutex_exit(&ctrl_p->hc_mutex);
1347 return (DDI_FAILURE);
1348 }
1349
1350 PCIE_ENABLE_ERRORS(ctrl_p->hc_dip);
1351
1352 /* get the current state of the slot */
1353 pciehpc_get_slot_state(slot_p);
1354
1355 mutex_exit(&ctrl_p->hc_mutex);
1356 return (DDI_SUCCESS);
1357 }
1358
1359 /*
1360 * pciehpc_slot_unprobe()
1361 *
1362 * Unprobe the slot.
1363 *
1364 * Note: This function is called by DDI HP framework at kernel context only
1365 */
1366 /*ARGSUSED*/
1367 static int
pciehpc_slot_unprobe(pcie_hp_slot_t * slot_p)1368 pciehpc_slot_unprobe(pcie_hp_slot_t *slot_p)
1369 {
1370 pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
1371 int ret;
1372
1373 mutex_enter(&ctrl_p->hc_mutex);
1374
1375 /* get the current state of the slot */
1376 pciehpc_get_slot_state(slot_p);
1377
1378 /*
1379 * Unprobe a given PCIe Hotplug Connection (CN).
1380 */
1381 PCIE_DISABLE_ERRORS(ctrl_p->hc_dip);
1382 ret = pcie_hp_unprobe(slot_p);
1383
1384 if (ret != DDI_SUCCESS) {
1385 PCIE_DBG("pciehpc_slot_unprobe() failed\n");
1386
1387 /* if power to the slot is still on then set Power led to ON */
1388 if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
1389 pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
1390 PCIE_HP_LED_ON);
1391
1392 PCIE_ENABLE_ERRORS(ctrl_p->hc_dip);
1393
1394 mutex_exit(&ctrl_p->hc_mutex);
1395 return (DDI_FAILURE);
1396 }
1397
1398 /* get the current state of the slot */
1399 pciehpc_get_slot_state(slot_p);
1400
1401 mutex_exit(&ctrl_p->hc_mutex);
1402 return (DDI_SUCCESS);
1403 }
1404
1405 static int
pciehpc_upgrade_slot_state(pcie_hp_slot_t * slot_p,ddi_hp_cn_state_t target_state)1406 pciehpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
1407 ddi_hp_cn_state_t target_state)
1408 {
1409 ddi_hp_cn_state_t curr_state;
1410 int rv = DDI_SUCCESS;
1411
1412 if (target_state > DDI_HP_CN_STATE_ENABLED) {
1413 return (DDI_EINVAL);
1414 }
1415
1416 curr_state = slot_p->hs_info.cn_state;
1417 while ((curr_state < target_state) && (rv == DDI_SUCCESS)) {
1418
1419 switch (curr_state) {
1420 case DDI_HP_CN_STATE_EMPTY:
1421 /*
1422 * From EMPTY to PRESENT, just check the hardware
1423 * slot state.
1424 */
1425 pciehpc_get_slot_state(slot_p);
1426 curr_state = slot_p->hs_info.cn_state;
1427 if (curr_state < DDI_HP_CN_STATE_PRESENT)
1428 rv = DDI_FAILURE;
1429 break;
1430 case DDI_HP_CN_STATE_PRESENT:
1431 rv = (slot_p->hs_ctrl->hc_ops.poweron_hpc_slot)(slot_p,
1432 &curr_state);
1433
1434 break;
1435 case DDI_HP_CN_STATE_POWERED:
1436 curr_state = slot_p->hs_info.cn_state =
1437 DDI_HP_CN_STATE_ENABLED;
1438 break;
1439 default:
1440 /* should never reach here */
1441 ASSERT("unknown devinfo state");
1442 }
1443 }
1444
1445 return (rv);
1446 }
1447
1448 static int
pciehpc_downgrade_slot_state(pcie_hp_slot_t * slot_p,ddi_hp_cn_state_t target_state)1449 pciehpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
1450 ddi_hp_cn_state_t target_state)
1451 {
1452 ddi_hp_cn_state_t curr_state;
1453 int rv = DDI_SUCCESS;
1454
1455
1456 curr_state = slot_p->hs_info.cn_state;
1457 while ((curr_state > target_state) && (rv == DDI_SUCCESS)) {
1458
1459 switch (curr_state) {
1460 case DDI_HP_CN_STATE_PRESENT:
1461 /*
1462 * From PRESENT to EMPTY, just check hardware slot
1463 * state.
1464 */
1465 pciehpc_get_slot_state(slot_p);
1466 curr_state = slot_p->hs_info.cn_state;
1467 if (curr_state >= DDI_HP_CN_STATE_PRESENT)
1468 rv = DDI_FAILURE;
1469 break;
1470 case DDI_HP_CN_STATE_POWERED:
1471 rv = (slot_p->hs_ctrl->hc_ops.poweroff_hpc_slot)(
1472 slot_p, &curr_state);
1473
1474 break;
1475 case DDI_HP_CN_STATE_ENABLED:
1476 curr_state = slot_p->hs_info.cn_state =
1477 DDI_HP_CN_STATE_POWERED;
1478
1479 break;
1480 default:
1481 /* should never reach here */
1482 ASSERT("unknown devinfo state");
1483 }
1484 }
1485
1486 return (rv);
1487 }
1488
1489 /* Change slot state to a target state */
1490 static int
pciehpc_change_slot_state(pcie_hp_slot_t * slot_p,ddi_hp_cn_state_t target_state)1491 pciehpc_change_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;
1496
1497 pciehpc_get_slot_state(slot_p);
1498 curr_state = slot_p->hs_info.cn_state;
1499
1500 if (curr_state == target_state) {
1501 return (DDI_SUCCESS);
1502 }
1503 if (curr_state < target_state) {
1504
1505 rv = pciehpc_upgrade_slot_state(slot_p, target_state);
1506 } else {
1507 rv = pciehpc_downgrade_slot_state(slot_p, target_state);
1508 }
1509
1510 return (rv);
1511 }
1512
1513 int
pciehpc_slot_get_property(pcie_hp_slot_t * slot_p,ddi_hp_property_t * arg,ddi_hp_property_t * rval)1514 pciehpc_slot_get_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
1515 ddi_hp_property_t *rval)
1516 {
1517 ddi_hp_property_t request, result;
1518 #ifdef _SYSCALL32_IMPL
1519 ddi_hp_property32_t request32, result32;
1520 #endif
1521 pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
1522 nvlist_t *prop_list;
1523 nvlist_t *prop_rlist; /* nvlist for return values */
1524 nvpair_t *prop_pair;
1525 char *name, *value;
1526 int ret = DDI_SUCCESS;
1527 int i, n;
1528 boolean_t get_all_prop = B_FALSE;
1529
1530 if (get_udatamodel() == DATAMODEL_NATIVE) {
1531 if (copyin(arg, &request, sizeof (ddi_hp_property_t)) ||
1532 copyin(rval, &result, sizeof (ddi_hp_property_t)))
1533 return (DDI_FAILURE);
1534 }
1535 #ifdef _SYSCALL32_IMPL
1536 else {
1537 bzero(&request, sizeof (request));
1538 bzero(&result, sizeof (result));
1539 if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)) ||
1540 copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
1541 return (DDI_FAILURE);
1542 request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
1543 request.buf_size = request32.buf_size;
1544 result.nvlist_buf = (char *)(uintptr_t)result32.nvlist_buf;
1545 result.buf_size = result32.buf_size;
1546 }
1547 #endif
1548
1549 if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
1550 &prop_list)) != DDI_SUCCESS)
1551 return (ret);
1552
1553 if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
1554 ret = DDI_ENOMEM;
1555 goto get_prop_cleanup;
1556 }
1557
1558 /* check whether the requested property is "all" or "help" */
1559 prop_pair = nvlist_next_nvpair(prop_list, NULL);
1560 if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair)) {
1561 name = nvpair_name(prop_pair);
1562 n = sizeof (pciehpc_props) / sizeof (pciehpc_prop_t);
1563
1564 if (strcmp(name, PCIEHPC_PROP_ALL) == 0) {
1565 (void) nvlist_remove_all(prop_list, PCIEHPC_PROP_ALL);
1566
1567 /*
1568 * Add all properties into the request list, so that we
1569 * will get the values in the following for loop.
1570 */
1571 for (i = 0; i < n; i++) {
1572 if (nvlist_add_string(prop_list,
1573 pciehpc_props[i].prop_name, "") != 0) {
1574 ret = DDI_FAILURE;
1575 goto get_prop_cleanup1;
1576 }
1577 }
1578 get_all_prop = B_TRUE;
1579 } else if (strcmp(name, PCIEHPC_PROP_HELP) == 0) {
1580 /*
1581 * Empty the request list, and add help strings into the
1582 * return list. We will pass the following for loop.
1583 */
1584 (void) nvlist_remove_all(prop_list, PCIEHPC_PROP_HELP);
1585
1586 for (i = 0; i < n; i++) {
1587 if (nvlist_add_string(prop_rlist,
1588 pciehpc_props[i].prop_name,
1589 pciehpc_props[i].prop_value) != 0) {
1590 ret = DDI_FAILURE;
1591 goto get_prop_cleanup1;
1592 }
1593 }
1594 }
1595 }
1596
1597 mutex_enter(&ctrl_p->hc_mutex);
1598
1599 /* get the current slot state */
1600 pciehpc_get_slot_state(slot_p);
1601
1602 /* for each requested property, get the value and add it to nvlist */
1603 prop_pair = NULL;
1604 while ((prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) != NULL) {
1605 name = nvpair_name(prop_pair);
1606 value = NULL;
1607
1608 if (strcmp(name, PCIEHPC_PROP_LED_FAULT) == 0) {
1609 value = pcie_led_state_text(
1610 slot_p->hs_fault_led_state);
1611 } else if (strcmp(name, PCIEHPC_PROP_LED_POWER) == 0) {
1612 value = pcie_led_state_text(
1613 slot_p->hs_power_led_state);
1614 } else if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
1615 value = pcie_led_state_text(
1616 slot_p->hs_attn_led_state);
1617 } else if (strcmp(name, PCIEHPC_PROP_LED_ACTIVE) == 0) {
1618 value = pcie_led_state_text(
1619 slot_p->hs_active_led_state);
1620 } else if (strcmp(name, PCIEHPC_PROP_CARD_TYPE) == 0) {
1621 ddi_acc_handle_t handle;
1622 dev_info_t *cdip;
1623 uint8_t prog_class, base_class, sub_class;
1624 int i;
1625
1626 mutex_exit(&ctrl_p->hc_mutex);
1627 cdip = pcie_hp_devi_find(
1628 ctrl_p->hc_dip, slot_p->hs_device_num, 0);
1629 mutex_enter(&ctrl_p->hc_mutex);
1630
1631 if ((slot_p->hs_info.cn_state
1632 != DDI_HP_CN_STATE_ENABLED) || (cdip == NULL)) {
1633 /*
1634 * When getting all properties, just ignore the
1635 * one that's not available under certain state.
1636 */
1637 if (get_all_prop)
1638 continue;
1639
1640 ret = DDI_ENOTSUP;
1641 goto get_prop_cleanup2;
1642 }
1643
1644 if (pci_config_setup(cdip, &handle) != DDI_SUCCESS) {
1645 ret = DDI_FAILURE;
1646 goto get_prop_cleanup2;
1647 }
1648
1649 prog_class = pci_config_get8(handle,
1650 PCI_CONF_PROGCLASS);
1651 base_class = pci_config_get8(handle, PCI_CONF_BASCLASS);
1652 sub_class = pci_config_get8(handle, PCI_CONF_SUBCLASS);
1653 pci_config_teardown(&handle);
1654
1655 for (i = 0; i < class_pci_items; i++) {
1656 if ((base_class == class_pci[i].base_class) &&
1657 (sub_class == class_pci[i].sub_class) &&
1658 (prog_class == class_pci[i].prog_class)) {
1659 value = class_pci[i].short_desc;
1660 break;
1661 }
1662 }
1663 if (i == class_pci_items)
1664 value = PCIEHPC_PROP_VALUE_UNKNOWN;
1665 } else if (strcmp(name, PCIEHPC_PROP_BOARD_TYPE) == 0) {
1666 if (slot_p->hs_info.cn_state <= DDI_HP_CN_STATE_EMPTY)
1667 value = PCIEHPC_PROP_VALUE_UNKNOWN;
1668 else
1669 value = PCIEHPC_PROP_VALUE_PCIHOTPLUG;
1670 } else if (strcmp(name, PCIEHPC_PROP_SLOT_CONDITION) == 0) {
1671 value = pcie_slot_condition_text(slot_p->hs_condition);
1672 } else {
1673 /* unsupported property */
1674 PCIE_DBG("Unsupported property: %s\n", name);
1675
1676 ret = DDI_ENOTSUP;
1677 goto get_prop_cleanup2;
1678 }
1679 if (nvlist_add_string(prop_rlist, name, value) != 0) {
1680 ret = DDI_FAILURE;
1681 goto get_prop_cleanup2;
1682 }
1683 }
1684
1685 /* pack nvlist and copyout */
1686 if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
1687 &result.buf_size)) != DDI_SUCCESS) {
1688 goto get_prop_cleanup2;
1689 }
1690 if (get_udatamodel() == DATAMODEL_NATIVE) {
1691 if (copyout(&result, rval, sizeof (ddi_hp_property_t)))
1692 ret = DDI_FAILURE;
1693 }
1694 #ifdef _SYSCALL32_IMPL
1695 else {
1696 if (result.buf_size > UINT32_MAX) {
1697 ret = DDI_FAILURE;
1698 } else {
1699 result32.buf_size = (uint32_t)result.buf_size;
1700 if (copyout(&result32, rval,
1701 sizeof (ddi_hp_property32_t)))
1702 ret = DDI_FAILURE;
1703 }
1704 }
1705 #endif
1706
1707 get_prop_cleanup2:
1708 mutex_exit(&ctrl_p->hc_mutex);
1709 get_prop_cleanup1:
1710 nvlist_free(prop_rlist);
1711 get_prop_cleanup:
1712 nvlist_free(prop_list);
1713 return (ret);
1714 }
1715
1716 int
pciehpc_slot_set_property(pcie_hp_slot_t * slot_p,ddi_hp_property_t * arg,ddi_hp_property_t * rval)1717 pciehpc_slot_set_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
1718 ddi_hp_property_t *rval)
1719 {
1720 ddi_hp_property_t request, result;
1721 #ifdef _SYSCALL32_IMPL
1722 ddi_hp_property32_t request32, result32;
1723 #endif
1724 pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
1725 nvlist_t *prop_list;
1726 nvlist_t *prop_rlist;
1727 nvpair_t *prop_pair;
1728 char *name, *value;
1729 pcie_hp_led_state_t led_state;
1730 int ret = DDI_SUCCESS;
1731
1732 if (get_udatamodel() == DATAMODEL_NATIVE) {
1733 if (copyin(arg, &request, sizeof (ddi_hp_property_t)))
1734 return (DDI_FAILURE);
1735 if (rval &&
1736 copyin(rval, &result, sizeof (ddi_hp_property_t)))
1737 return (DDI_FAILURE);
1738 }
1739 #ifdef _SYSCALL32_IMPL
1740 else {
1741 bzero(&request, sizeof (request));
1742 bzero(&result, sizeof (result));
1743 if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)))
1744 return (DDI_FAILURE);
1745 if (rval &&
1746 copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
1747 return (DDI_FAILURE);
1748 request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
1749 request.buf_size = request32.buf_size;
1750 if (rval) {
1751 result.nvlist_buf =
1752 (char *)(uintptr_t)result32.nvlist_buf;
1753 result.buf_size = result32.buf_size;
1754 }
1755 }
1756 #endif
1757
1758 if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
1759 &prop_list)) != DDI_SUCCESS)
1760 return (ret);
1761
1762 /* check whether the requested property is "help" */
1763 prop_pair = nvlist_next_nvpair(prop_list, NULL);
1764 if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair) &&
1765 (strcmp(nvpair_name(prop_pair), PCIEHPC_PROP_HELP) == 0)) {
1766 if (!rval) {
1767 ret = DDI_ENOTSUP;
1768 goto set_prop_cleanup;
1769 }
1770
1771 if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
1772 ret = DDI_ENOMEM;
1773 goto set_prop_cleanup;
1774 }
1775 if (nvlist_add_string(prop_rlist, PCIEHPC_PROP_LED_ATTN,
1776 PCIEHPC_PROP_VALUE_LED) != 0) {
1777 ret = DDI_FAILURE;
1778 goto set_prop_cleanup1;
1779 }
1780
1781 if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
1782 &result.buf_size)) != DDI_SUCCESS) {
1783 goto set_prop_cleanup1;
1784 }
1785 if (get_udatamodel() == DATAMODEL_NATIVE) {
1786 if (copyout(&result, rval,
1787 sizeof (ddi_hp_property_t))) {
1788 ret = DDI_FAILURE;
1789 goto set_prop_cleanup1;
1790 }
1791 }
1792 #ifdef _SYSCALL32_IMPL
1793 else {
1794 if (result.buf_size > UINT32_MAX) {
1795 ret = DDI_FAILURE;
1796 goto set_prop_cleanup1;
1797 } else {
1798 result32.buf_size = (uint32_t)result.buf_size;
1799 if (copyout(&result32, rval,
1800 sizeof (ddi_hp_property32_t))) {
1801 ret = DDI_FAILURE;
1802 goto set_prop_cleanup1;
1803 }
1804 }
1805 }
1806 #endif
1807 set_prop_cleanup1:
1808 nvlist_free(prop_rlist);
1809 nvlist_free(prop_list);
1810 return (ret);
1811 }
1812
1813 /* Validate the request */
1814 prop_pair = NULL;
1815 while ((prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) != NULL) {
1816 name = nvpair_name(prop_pair);
1817 if (nvpair_type(prop_pair) != DATA_TYPE_STRING) {
1818 PCIE_DBG("Unexpected data type of setting "
1819 "property %s.\n", name);
1820 ret = DDI_EINVAL;
1821 goto set_prop_cleanup;
1822 }
1823 if (nvpair_value_string(prop_pair, &value)) {
1824 PCIE_DBG("Get string value failed for property %s.\n",
1825 name);
1826 ret = DDI_FAILURE;
1827 goto set_prop_cleanup;
1828 }
1829
1830 if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
1831 if ((strcmp(value, PCIEHPC_PROP_VALUE_ON) != 0) &&
1832 (strcmp(value, PCIEHPC_PROP_VALUE_OFF) != 0) &&
1833 (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) != 0)) {
1834 PCIE_DBG("Unsupported value of setting "
1835 "property %s\n", name);
1836 ret = DDI_ENOTSUP;
1837 goto set_prop_cleanup;
1838 }
1839 } else {
1840 PCIE_DBG("Unsupported property: %s\n", name);
1841 ret = DDI_ENOTSUP;
1842 goto set_prop_cleanup;
1843 }
1844 }
1845 mutex_enter(&ctrl_p->hc_mutex);
1846
1847 /* get the current slot state */
1848 pciehpc_get_slot_state(slot_p);
1849
1850 /* set each property */
1851 prop_pair = NULL;
1852 while ((prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) != NULL) {
1853 name = nvpair_name(prop_pair);
1854
1855 /*
1856 * The validity of the property was checked above.
1857 */
1858 if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
1859 if (strcmp(value, PCIEHPC_PROP_VALUE_ON) == 0)
1860 led_state = PCIE_HP_LED_ON;
1861 else if (strcmp(value, PCIEHPC_PROP_VALUE_OFF) == 0)
1862 led_state = PCIE_HP_LED_OFF;
1863 else if (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) == 0)
1864 led_state = PCIE_HP_LED_BLINK;
1865 else
1866 continue;
1867
1868 pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED,
1869 led_state);
1870 }
1871 }
1872 if (rval) {
1873 if (get_udatamodel() == DATAMODEL_NATIVE) {
1874 result.buf_size = 0;
1875 if (copyout(&result, rval, sizeof (ddi_hp_property_t)))
1876 ret = DDI_FAILURE;
1877 }
1878 #ifdef _SYSCALL32_IMPL
1879 else {
1880 result32.buf_size = 0;
1881 if (copyout(&result32, rval,
1882 sizeof (ddi_hp_property32_t)))
1883 ret = DDI_FAILURE;
1884 }
1885 #endif
1886 }
1887
1888 mutex_exit(&ctrl_p->hc_mutex);
1889 set_prop_cleanup:
1890 nvlist_free(prop_list);
1891 return (ret);
1892 }
1893
1894 /*
1895 * Send a command to the PCI-E Hot Plug Controller.
1896 *
1897 * NOTES: The PCI-E spec defines the following semantics for issuing hot plug
1898 * commands.
1899 * 1) If Command Complete events/interrupts are supported then software
1900 * waits for Command Complete event after issuing a command (i.e writing
1901 * to the Slot Control register). The command completion could take as
1902 * long as 1 second so software should be prepared to wait for 1 second
1903 * before issuing another command.
1904 *
1905 * 2) If Command Complete events/interrupts are not supported then
1906 * software could issue multiple Slot Control writes without any delay
1907 * between writes.
1908 */
1909 static void
pciehpc_issue_hpc_command(pcie_hp_ctrl_t * ctrl_p,uint16_t control)1910 pciehpc_issue_hpc_command(pcie_hp_ctrl_t *ctrl_p, uint16_t control)
1911 {
1912 pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
1913 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1914 uint16_t status;
1915 uint32_t slot_cap;
1916
1917 /*
1918 * PCI-E version 1.1 spec defines No Command Completed
1919 * Support bit (bit#18) in Slot Capabilities register. If this
1920 * bit is set then slot doesn't support notification of command
1921 * completion events.
1922 */
1923 slot_cap = pciehpc_reg_get32(ctrl_p,
1924 bus_p->bus_pcie_off + PCIE_SLOTCAP);
1925
1926 /*
1927 * If no Command Completion event is supported or it is ACPI
1928 * hot plug mode then just issue the command and return.
1929 */
1930 if ((slot_cap & PCIE_SLOTCAP_NO_CMD_COMP_SUPP) ||
1931 (bus_p->bus_hp_curr_mode == PCIE_ACPI_HP_MODE)) {
1932 pciehpc_reg_put16(ctrl_p,
1933 bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
1934 return;
1935 }
1936
1937 /*
1938 * **************************************
1939 * Command Complete events are supported.
1940 * **************************************
1941 */
1942
1943 /*
1944 * If HPC is not yet initialized then just poll for the Command
1945 * Completion interrupt.
1946 */
1947 if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
1948 int retry = PCIE_HP_CMD_WAIT_RETRY;
1949
1950 /* write the command to the HPC */
1951 pciehpc_reg_put16(ctrl_p,
1952 bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
1953
1954 /* poll for status completion */
1955 while (retry--) {
1956 /* wait for 10 msec before checking the status */
1957 delay(drv_usectohz(PCIE_HP_CMD_WAIT_TIME));
1958
1959 status = pciehpc_reg_get16(ctrl_p,
1960 bus_p->bus_pcie_off + PCIE_SLOTSTS);
1961
1962 if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
1963 /* clear the status bits */
1964 pciehpc_reg_put16(ctrl_p,
1965 bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
1966 break;
1967 }
1968 }
1969 return;
1970 }
1971
1972 /* HPC is already initialized */
1973
1974 ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
1975
1976 /*
1977 * If previous command is still pending then wait for its
1978 * completion. i.e cv_wait()
1979 */
1980
1981 while (ctrl_p->hc_cmd_pending == B_TRUE)
1982 cv_wait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex);
1983
1984 /*
1985 * Issue the command and wait for Command Completion or
1986 * the 1 sec timeout.
1987 */
1988 pciehpc_reg_put16(ctrl_p,
1989 bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
1990
1991 ctrl_p->hc_cmd_pending = B_TRUE;
1992
1993 if (cv_timedwait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex,
1994 ddi_get_lbolt() + SEC_TO_TICK(1)) == -1) {
1995
1996 /* it is a timeout */
1997 PCIE_DBG("pciehpc_issue_hpc_command: Command Complete"
1998 " interrupt is not received for slot %d\n",
1999 slot_p->hs_phy_slot_num);
2000
2001 /* clear the status info in case interrupts are disabled? */
2002 status = pciehpc_reg_get16(ctrl_p,
2003 bus_p->bus_pcie_off + PCIE_SLOTSTS);
2004
2005 if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
2006 /* clear the status bits */
2007 pciehpc_reg_put16(ctrl_p,
2008 bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
2009 }
2010 }
2011
2012 ctrl_p->hc_cmd_pending = B_FALSE;
2013
2014 /* wake up any one waiting for issuing another command to HPC */
2015 cv_signal(&ctrl_p->hc_cmd_comp_cv);
2016 }
2017
2018 /*
2019 * pciehcp_attn_btn_handler()
2020 *
2021 * This handles ATTN button pressed event as per the PCI-E 1.1 spec.
2022 */
2023 static void
pciehpc_attn_btn_handler(pcie_hp_ctrl_t * ctrl_p)2024 pciehpc_attn_btn_handler(pcie_hp_ctrl_t *ctrl_p)
2025 {
2026 pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
2027 pcie_hp_led_state_t power_led_state;
2028 callb_cpr_t cprinfo;
2029
2030 PCIE_DBG("pciehpc_attn_btn_handler: thread started\n");
2031
2032 CALLB_CPR_INIT(&cprinfo, &ctrl_p->hc_mutex, callb_generic_cpr,
2033 "pciehpc_attn_btn_handler");
2034
2035 mutex_enter(&ctrl_p->hc_mutex);
2036
2037 /* wait for ATTN button event */
2038 cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
2039
2040 while (slot_p->hs_attn_btn_thread_exit == B_FALSE) {
2041 if (slot_p->hs_attn_btn_pending == B_TRUE) {
2042 /* get the current state of power LED */
2043 power_led_state = pciehpc_get_led_state(ctrl_p,
2044 PCIE_HP_POWER_LED);
2045
2046 /* Blink the Power LED while we wait for 5 seconds */
2047 pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
2048 PCIE_HP_LED_BLINK);
2049
2050 /* wait for 5 seconds before taking any action */
2051 if (cv_timedwait(&slot_p->hs_attn_btn_cv,
2052 &ctrl_p->hc_mutex,
2053 ddi_get_lbolt() + SEC_TO_TICK(5)) == -1) {
2054 /*
2055 * It is a time out; make sure the ATTN pending
2056 * flag is still ON before sending the event to
2057 * DDI HP framework.
2058 */
2059 if (slot_p->hs_attn_btn_pending == B_TRUE) {
2060 int hint;
2061
2062 slot_p->hs_attn_btn_pending = B_FALSE;
2063 pciehpc_get_slot_state(slot_p);
2064
2065 if (slot_p->hs_info.cn_state <=
2066 DDI_HP_CN_STATE_PRESENT) {
2067 /*
2068 * Insertion.
2069 */
2070 hint = SE_INCOMING_RES;
2071 } else {
2072 /*
2073 * Want to remove;
2074 */
2075 hint = SE_OUTGOING_RES;
2076 }
2077
2078 /*
2079 * We can't call ddihp_cn_gen_sysevent
2080 * here since it's not a DDI interface.
2081 */
2082 pcie_hp_gen_sysevent_req(
2083 slot_p->hs_info.cn_name,
2084 hint,
2085 ctrl_p->hc_dip,
2086 KM_SLEEP);
2087 }
2088 }
2089
2090 /* restore the power LED state */
2091 pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
2092 power_led_state);
2093 continue;
2094 }
2095
2096 /* wait for another ATTN button event */
2097 cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
2098 }
2099
2100 PCIE_DBG("pciehpc_attn_btn_handler: thread exit\n");
2101 cv_signal(&slot_p->hs_attn_btn_cv);
2102 CALLB_CPR_EXIT(&cprinfo);
2103 thread_exit();
2104 }
2105
2106 /*
2107 * convert LED state from PCIE HPC definition to pcie_hp_led_state_t
2108 * definition.
2109 */
2110 static pcie_hp_led_state_t
pciehpc_led_state_to_hpc(uint16_t state)2111 pciehpc_led_state_to_hpc(uint16_t state)
2112 {
2113 switch (state) {
2114 case PCIE_SLOTCTL_INDICATOR_STATE_ON:
2115 return (PCIE_HP_LED_ON);
2116 case PCIE_SLOTCTL_INDICATOR_STATE_BLINK:
2117 return (PCIE_HP_LED_BLINK);
2118 case PCIE_SLOTCTL_INDICATOR_STATE_OFF:
2119 default:
2120 return (PCIE_HP_LED_OFF);
2121 }
2122 }
2123
2124 /*
2125 * Get the state of an LED.
2126 */
2127 static pcie_hp_led_state_t
pciehpc_get_led_state(pcie_hp_ctrl_t * ctrl_p,pcie_hp_led_t led)2128 pciehpc_get_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led)
2129 {
2130 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
2131 uint16_t control, state;
2132
2133 /* get the current state of Slot Control register */
2134 control = pciehpc_reg_get16(ctrl_p,
2135 bus_p->bus_pcie_off + PCIE_SLOTCTL);
2136
2137 switch (led) {
2138 case PCIE_HP_POWER_LED:
2139 state = pcie_slotctl_pwr_indicator_get(control);
2140 break;
2141 case PCIE_HP_ATTN_LED:
2142 state = pcie_slotctl_attn_indicator_get(control);
2143 break;
2144 default:
2145 PCIE_DBG("pciehpc_get_led_state() invalid LED %d\n", led);
2146 return (PCIE_HP_LED_OFF);
2147 }
2148
2149 switch (state) {
2150 case PCIE_SLOTCTL_INDICATOR_STATE_ON:
2151 return (PCIE_HP_LED_ON);
2152
2153 case PCIE_SLOTCTL_INDICATOR_STATE_BLINK:
2154 return (PCIE_HP_LED_BLINK);
2155
2156 case PCIE_SLOTCTL_INDICATOR_STATE_OFF:
2157 default:
2158 return (PCIE_HP_LED_OFF);
2159 }
2160 }
2161
2162 /*
2163 * Set the state of an LED. It updates both hw and sw state.
2164 */
2165 static void
pciehpc_set_led_state(pcie_hp_ctrl_t * ctrl_p,pcie_hp_led_t led,pcie_hp_led_state_t state)2166 pciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led,
2167 pcie_hp_led_state_t state)
2168 {
2169 pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
2170 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
2171 uint16_t control;
2172
2173 /* get the current state of Slot Control register */
2174 control = pciehpc_reg_get16(ctrl_p,
2175 bus_p->bus_pcie_off + PCIE_SLOTCTL);
2176
2177 switch (led) {
2178 case PCIE_HP_POWER_LED:
2179 /* clear led mask */
2180 control &= ~PCIE_SLOTCTL_PWR_INDICATOR_MASK;
2181 slot_p->hs_power_led_state = state;
2182 break;
2183 case PCIE_HP_ATTN_LED:
2184 /* clear led mask */
2185 control &= ~PCIE_SLOTCTL_ATTN_INDICATOR_MASK;
2186 slot_p->hs_attn_led_state = state;
2187 break;
2188 default:
2189 PCIE_DBG("pciehpc_set_led_state() invalid LED %d\n", led);
2190 return;
2191 }
2192
2193 switch (state) {
2194 case PCIE_HP_LED_ON:
2195 if (led == PCIE_HP_POWER_LED)
2196 control = pcie_slotctl_pwr_indicator_set(control,
2197 PCIE_SLOTCTL_INDICATOR_STATE_ON);
2198 else if (led == PCIE_HP_ATTN_LED)
2199 control = pcie_slotctl_attn_indicator_set(control,
2200 PCIE_SLOTCTL_INDICATOR_STATE_ON);
2201 break;
2202 case PCIE_HP_LED_OFF:
2203 if (led == PCIE_HP_POWER_LED)
2204 control = pcie_slotctl_pwr_indicator_set(control,
2205 PCIE_SLOTCTL_INDICATOR_STATE_OFF);
2206 else if (led == PCIE_HP_ATTN_LED)
2207 control = pcie_slotctl_attn_indicator_set(control,
2208 PCIE_SLOTCTL_INDICATOR_STATE_OFF);
2209 break;
2210 case PCIE_HP_LED_BLINK:
2211 if (led == PCIE_HP_POWER_LED)
2212 control = pcie_slotctl_pwr_indicator_set(control,
2213 PCIE_SLOTCTL_INDICATOR_STATE_BLINK);
2214 else if (led == PCIE_HP_ATTN_LED)
2215 control = pcie_slotctl_attn_indicator_set(control,
2216 PCIE_SLOTCTL_INDICATOR_STATE_BLINK);
2217 break;
2218
2219 default:
2220 PCIE_DBG("pciehpc_set_led_state() invalid LED state %d\n",
2221 state);
2222 return;
2223 }
2224
2225 /* update the Slot Control Register */
2226 pciehpc_issue_hpc_command(ctrl_p, control);
2227
2228 #ifdef DEBUG
2229 /* get the current state of Slot Control register */
2230 control = pciehpc_reg_get16(ctrl_p,
2231 bus_p->bus_pcie_off + PCIE_SLOTCTL);
2232
2233 PCIE_DBG("pciehpc_set_led_state: slot %d power-led %s attn-led %s\n",
2234 slot_p->hs_phy_slot_num, pcie_led_state_text(
2235 pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control))),
2236 pcie_led_state_text(pciehpc_led_state_to_hpc(
2237 pcie_slotctl_attn_indicator_get(control))));
2238 #endif
2239 }
2240
2241 static void
pciehpc_handle_power_fault(dev_info_t * dip)2242 pciehpc_handle_power_fault(dev_info_t *dip)
2243 {
2244 /*
2245 * Hold the parent's ref so that it won't disappear when the taskq is
2246 * scheduled to run.
2247 */
2248 ndi_hold_devi(dip);
2249
2250 if (taskq_dispatch(system_taskq, pciehpc_power_fault_handler, dip,
2251 TQ_NOSLEEP) == TASKQID_INVALID) {
2252 ndi_rele_devi(dip);
2253 PCIE_DBG("pciehpc_intr(): "
2254 "Failed to dispatch power fault handler, dip %p\n", dip);
2255 }
2256 }
2257
2258 static void
pciehpc_power_fault_handler(void * arg)2259 pciehpc_power_fault_handler(void *arg)
2260 {
2261 dev_info_t *dip = (dev_info_t *)arg;
2262 pcie_hp_ctrl_t *ctrl_p;
2263 pcie_hp_slot_t *slot_p;
2264
2265 /* get the soft state structure for this dip */
2266 if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) {
2267 ndi_rele_devi(dip);
2268 return;
2269 }
2270 slot_p = ctrl_p->hc_slots[0];
2271
2272 /*
2273 * Send the event to DDI Hotplug framework, power off
2274 * the slot
2275 */
2276 (void) ndi_hp_state_change_req(dip,
2277 slot_p->hs_info.cn_name,
2278 DDI_HP_CN_STATE_EMPTY, DDI_HP_REQ_SYNC);
2279
2280 mutex_enter(&ctrl_p->hc_mutex);
2281 pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED,
2282 PCIE_HP_LED_ON);
2283 mutex_exit(&ctrl_p->hc_mutex);
2284 ndi_rele_devi(dip);
2285 }
2286
2287 #ifdef DEBUG
2288 /*
2289 * Dump PCI-E Hot Plug registers.
2290 */
2291 static void
pciehpc_dump_hpregs(pcie_hp_ctrl_t * ctrl_p)2292 pciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p)
2293 {
2294 pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
2295 pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
2296 uint16_t control;
2297 uint32_t capabilities;
2298
2299 if (!pcie_debug_flags)
2300 return;
2301
2302 capabilities = pciehpc_reg_get32(ctrl_p,
2303 bus_p->bus_pcie_off + PCIE_SLOTCAP);
2304
2305 control = pciehpc_reg_get16(ctrl_p,
2306 bus_p->bus_pcie_off + PCIE_SLOTCTL);
2307
2308 PCIE_DBG("pciehpc_dump_hpregs: Found PCI-E hot plug slot %d\n",
2309 slot_p->hs_phy_slot_num);
2310
2311 PCIE_DBG("Attention Button Present = %s\n",
2312 capabilities & PCIE_SLOTCAP_ATTN_BUTTON ? "Yes":"No");
2313
2314 PCIE_DBG("Power controller Present = %s\n",
2315 capabilities & PCIE_SLOTCAP_POWER_CONTROLLER ? "Yes":"No");
2316
2317 PCIE_DBG("MRL Sensor Present = %s\n",
2318 capabilities & PCIE_SLOTCAP_MRL_SENSOR ? "Yes":"No");
2319
2320 PCIE_DBG("Attn Indicator Present = %s\n",
2321 capabilities & PCIE_SLOTCAP_ATTN_INDICATOR ? "Yes":"No");
2322
2323 PCIE_DBG("Power Indicator Present = %s\n",
2324 capabilities & PCIE_SLOTCAP_PWR_INDICATOR ? "Yes":"No");
2325
2326 PCIE_DBG("HotPlug Surprise = %s\n",
2327 capabilities & PCIE_SLOTCAP_HP_SURPRISE ? "Yes":"No");
2328
2329 PCIE_DBG("HotPlug Capable = %s\n",
2330 capabilities & PCIE_SLOTCAP_HP_CAPABLE ? "Yes":"No");
2331
2332 PCIE_DBG("Physical Slot Number = %d\n",
2333 PCIE_SLOTCAP_PHY_SLOT_NUM(capabilities));
2334
2335 PCIE_DBG("Attn Button interrupt Enabled = %s\n",
2336 control & PCIE_SLOTCTL_ATTN_BTN_EN ? "Yes":"No");
2337
2338 PCIE_DBG("Power Fault interrupt Enabled = %s\n",
2339 control & PCIE_SLOTCTL_PWR_FAULT_EN ? "Yes":"No");
2340
2341 PCIE_DBG("MRL Sensor INTR Enabled = %s\n",
2342 control & PCIE_SLOTCTL_MRL_SENSOR_EN ? "Yes":"No");
2343
2344 PCIE_DBG("Presence interrupt Enabled = %s\n",
2345 control & PCIE_SLOTCTL_PRESENCE_CHANGE_EN ? "Yes":"No");
2346
2347 PCIE_DBG("Cmd Complete interrupt Enabled = %s\n",
2348 control & PCIE_SLOTCTL_CMD_INTR_EN ? "Yes":"No");
2349
2350 PCIE_DBG("HotPlug interrupt Enabled = %s\n",
2351 control & PCIE_SLOTCTL_HP_INTR_EN ? "Yes":"No");
2352
2353 PCIE_DBG("Power Indicator LED = %s", pcie_led_state_text(
2354 pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control))));
2355
2356 PCIE_DBG("Attn Indicator LED = %s\n",
2357 pcie_led_state_text(pciehpc_led_state_to_hpc(
2358 pcie_slotctl_attn_indicator_get(control))));
2359 }
2360 #endif /* DEBUG */
2361