summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/io/pciex/hotplug/pciehpc.c62
1 files changed, 50 insertions, 12 deletions
diff --git a/usr/src/uts/common/io/pciex/hotplug/pciehpc.c b/usr/src/uts/common/io/pciex/hotplug/pciehpc.c
index bded8b8c13..2100646260 100644
--- a/usr/src/uts/common/io/pciex/hotplug/pciehpc.c
+++ b/usr/src/uts/common/io/pciex/hotplug/pciehpc.c
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -100,6 +99,8 @@ static int
pciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result);
static int pciehpc_slot_probe(pcie_hp_slot_t *slot_p);
static int pciehpc_slot_unprobe(pcie_hp_slot_t *slot_p);
+static void pciehpc_handle_power_fault(dev_info_t *dip);
+static void pciehpc_power_fault_handler(void *arg);
#ifdef DEBUG
static void pciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p);
@@ -338,16 +339,7 @@ pciehpc_intr(dev_info_t *dip)
pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
PCIE_SLOTCTL, control & ~PCIE_SLOTCTL_PWR_FAULT_EN);
- /*
- * Send the event to DDI Hotplug framework, power off
- * the slot
- */
- (void) ndi_hp_state_change_req(dip,
- slot_p->hs_info.cn_name,
- DDI_HP_CN_STATE_EMPTY, DDI_HP_REQ_ASYNC);
-
- pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED,
- PCIE_HP_LED_ON);
+ pciehpc_handle_power_fault(dip);
}
}
@@ -2224,6 +2216,52 @@ pciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led,
#endif
}
+static void
+pciehpc_handle_power_fault(dev_info_t *dip)
+{
+ /*
+ * Hold the parent's ref so that it won't disappear when the taskq is
+ * scheduled to run.
+ */
+ ndi_hold_devi(dip);
+
+ if (!taskq_dispatch(system_taskq, pciehpc_power_fault_handler, dip,
+ TQ_NOSLEEP)) {
+ ndi_rele_devi(dip);
+ PCIE_DBG("pciehpc_intr(): "
+ "Failed to dispatch power fault handler, dip %p\n", dip);
+ }
+}
+
+static void
+pciehpc_power_fault_handler(void *arg)
+{
+ dev_info_t *dip = (dev_info_t *)arg;
+ pcie_hp_ctrl_t *ctrl_p;
+ pcie_hp_slot_t *slot_p;
+
+ /* get the soft state structure for this dip */
+ if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) {
+ ndi_rele_devi(dip);
+ return;
+ }
+ slot_p = ctrl_p->hc_slots[0];
+
+ /*
+ * Send the event to DDI Hotplug framework, power off
+ * the slot
+ */
+ (void) ndi_hp_state_change_req(dip,
+ slot_p->hs_info.cn_name,
+ DDI_HP_CN_STATE_EMPTY, DDI_HP_REQ_SYNC);
+
+ mutex_enter(&ctrl_p->hc_mutex);
+ pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED,
+ PCIE_HP_LED_ON);
+ mutex_exit(&ctrl_p->hc_mutex);
+ ndi_rele_devi(dip);
+}
+
#ifdef DEBUG
/*
* Dump PCI-E Hot Plug registers.