pciehpc.c revision 80dc702d1ace8fb9dbee9d449a58b943b7308a8e
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/*
* This file contains Standard PCI Express HotPlug functionality that is
* compatible with the PCI Express ver 1.1 specification.
*
*/
#include <sys/autoconf.h>
#include <sys/ddi_impldefs.h>
#include <sys/pci_impl.h>
typedef struct pciehpc_prop {
char *prop_name;
char *prop_value;
static pciehpc_prop_t pciehpc_props[] = {
};
/* Local functions prototype */
static int
static int
static void pciehpc_power_fault_handler(void *arg);
#ifdef DEBUG
#endif /* DEBUG */
/*
*/
/*
* Initialize Hot Plug Controller if present. The arguments are:
* dip - Devinfo node pointer to the hot plug bus node
* regops - register ops to access HPC registers for non-standard
* HPC hw implementations (e.g: HPC in host PCI-E brdiges)
* This is NULL for standard HPC in PCIe bridges.
* Returns:
* DDI_SUCCESS for successful HPC initialization
* DDI_FAILURE for errors or if HPC hw not found
*/
int
{
/* Make sure that it is not already initialized */
PCIE_DBG("%s%d: pciehpc instance already initialized!\n",
return (DDI_SUCCESS);
}
/* Allocate a new hotplug controller and slot structures */
/* setup access handle for HPC regs */
/* HPC access is non-standard; use the supplied reg ops */
}
/*
* Setup resource maps for this bus node.
*/
(void) pci_resource_setup(dip);
/*
* Set the platform specific hot plug mode.
*/
#endif
/* initialize hot plug controller hw */
goto cleanup1;
/* initialize slot information soft state structure */
goto cleanup2;
/* register the hot plug slot with DDI HP framework */
goto cleanup3;
/* create minor node for this slot */
goto cleanup4;
/* HPC initialization is complete now */
#ifdef DEBUG
/* For debug, dump the HPC registers */
#endif /* DEBUG */
return (DDI_SUCCESS);
(void) pciehpc_unregister_slot(ctrl_p);
(void) pci_resource_destroy(dip);
return (DDI_FAILURE);
}
/*
* Uninitialize HPC soft state structure and free up any resources
* used for the HPC instance.
*/
int
{
/* get the soft state structure for this dip */
return (DDI_FAILURE);
}
/* unregister the slot */
(void) pciehpc_unregister_slot(ctrl_p);
/* uninit any slot info data structures */
/* uninitialize hpc, remove interrupt handler, etc. */
/*
* Destroy resource maps for this bus node.
*/
(void) pci_resource_destroy(dip);
/* destroy the soft state structure */
return (DDI_SUCCESS);
}
/*
* pciehpc_intr()
*
* Interrupt handler for PCI-E Hot plug controller interrupts.
*
* Note: This is only for native mode hot plug. This is called
* by the nexus driver at interrupt context. Interrupt Service Routine
* registration is done by the nexus driver for both hot plug and
* non-hot plug interrupts. This function is called from the ISR
* of the nexus driver to handle hot-plug interrupts.
*/
int
{
/* get the soft state structure for this dip */
return (DDI_INTR_UNCLAIMED);
/* make sure the controller soft state is initialized */
return (DDI_INTR_UNCLAIMED);
}
/* if it is not NATIVE hot plug mode then return */
return (DDI_INTR_UNCLAIMED);
}
/* read the current slot status register */
/* check if there are any hot plug interrupts occurred */
if (!(status & PCIE_SLOTSTS_STATUS_EVENTS)) {
/* no hot plug events occurred */
return (DDI_INTR_UNCLAIMED);
}
/* clear the interrupt status bits */
/* check for CMD COMPLETE interrupt */
if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
PCIE_DBG("pciehpc_intr(): CMD COMPLETED interrupt received\n");
/* wake up any one waiting for Command Completion event */
}
/* check for ATTN button interrupt */
if (status & PCIE_SLOTSTS_ATTN_BTN_PRESSED) {
PCIE_DBG("pciehpc_intr(): ATTN BUTTON interrupt received\n");
/* if ATTN button event is still pending then cancel it */
else
/* wake up the ATTN event handler */
}
/* check for power fault interrupt */
if (status & PCIE_SLOTSTS_PWR_FAULT_DETECTED) {
PCIE_DBG("pciehpc_intr(): POWER FAULT interrupt received"
if (control & PCIE_SLOTCTL_PWR_FAULT_EN) {
/* disable power fault detction interrupt */
}
}
/* check for MRL SENSOR CHANGED interrupt */
if (status & PCIE_SLOTSTS_MRL_SENSOR_CHANGED) {
/* For now (phase-I), no action is taken on this event */
PCIE_DBG("pciehpc_intr(): MRL SENSOR CHANGED interrupt received"
}
/* check for PRESENCE CHANGED interrupt */
if (status & PCIE_SLOTSTS_PRESENCE_CHANGED) {
PCIE_DBG("pciehpc_intr(): PRESENCE CHANGED interrupt received"
if (status & PCIE_SLOTSTS_PRESENCE_DETECTED) {
/*
* card is inserted into the slot, ask DDI Hotplug
* framework to change state to Present.
*/
" in the slot %s",
(void) ndi_hp_state_change_req(dip,
} else { /* card is removed from the slot */
" from the slot %s",
/* Card is removed when slot is enabled */
} else {
}
/* make sure to disable power fault detction intr */
if (control & PCIE_SLOTCTL_PWR_FAULT_EN)
/*
* Ask DDI Hotplug framework to change state to Empty
*/
(void) ndi_hp_state_change_req(dip,
}
}
/* check for DLL state changed interrupt */
if (ctrl_p->hc_dll_active_rep &&
PCIE_DBG("pciehpc_intr(): DLL STATE CHANGED interrupt received"
}
return (DDI_INTR_CLAIMED);
}
/*
* Handle hotplug commands
*
* Note: This function is called by DDI HP framework at kernel context only
*/
/* ARGSUSED */
int
{
int ret = DDI_SUCCESS;
PCIE_DBG("pciehpc_hp_ops: dip=%p cn_name=%s op=%x arg=%p\n",
return (DDI_FAILURE);
return (DDI_EINVAL);
switch (op) {
case DDI_HPOP_CN_GET_STATE:
{
/* get the current slot state */
break;
}
case DDI_HPOP_CN_CHANGE_STATE:
{
break;
}
case DDI_HPOP_CN_PROBE:
break;
case DDI_HPOP_CN_UNPROBE:
break;
case DDI_HPOP_CN_GET_PROPERTY:
break;
case DDI_HPOP_CN_SET_PROPERTY:
break;
default:
ret = DDI_ENOTSUP;
break;
}
return (ret);
}
/*
* Get the current state of the slot from the hw.
*
* The slot state should have been initialized before this function gets called.
*/
void
{
/* read the Slot Control Register */
/* read the current Slot Status Register */
/* get POWER led state */
/* get ATTN led state */
if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
/* no device present; slot is empty */
return;
}
/* device is present */
if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) {
/*
* Device is powered on. Set to "ENABLED" state (skip
* POWERED state) because there is not a explicit "enable"
* action exists for PCIe.
* If it is already in "POWERED" state, then keep it until
* user explicitly change it to other states.
*/
if (curr_state == DDI_HP_CN_STATE_POWERED) {
} else {
}
}
}
/*
* setup slot name/slot-number info.
*/
void
{
int *slotnum;
int len;
int invalid_slotnum = 0;
} else {
}
/* platform may not have initialized it */
if (!slot_p->hs_phy_slot_num) {
PCIE_DBG("%s#%d: Invalid slot number!\n",
invalid_slotnum = 1;
}
/*
* construct the slot_name:
* if "slot-names" property exists then use that name
* else if valid slot number exists then it is "pcie<slot-num>".
* else it will be "pcie<sec-bus-number>dev0"
*/
char tmp_name[256];
/*
* Note: for PCI-E slots, the device number is always 0 so the
* first (and only) string is the slot name for this slot.
*/
(char *)slotname_data + 4);
} else {
if (invalid_slotnum) {
/* use device number ie. 0 */
KM_SLEEP);
} else {
char tmp_name[256];
KM_SLEEP);
}
}
}
/*
*/
{
} else {
}
}
{
} else {
}
}
{
} else {
}
}
void
{
} else {
}
}
void
{
} else {
}
}
void
{
} else {
}
}
/*
* ************************************************************************
* *** Local functions (called within this file)
* *** PCIe Native Hotplug mode specific functions
* ************************************************************************
*/
/*
* Initialize HPC hardware, install interrupt handler, etc. It doesn't
* enable hot plug interrupts.
*
* (Note: It is called only from pciehpc_init().)
*/
static int
{
/* read the Slot Control Register */
/* disable all interrupts */
reg &= ~(PCIE_SLOTCTL_INTR_MASK);
PCIE_SLOTCTL, reg);
/* clear any interrupt status bits */
return (DDI_SUCCESS);
}
/*
* Uninitialize HPC hardware, uninstall interrupt handler, etc.
*
* (Note: It is called only from pciehpc_uninit().)
*/
static int
{
/* disable interrupts */
(void) pciehpc_disable_intr(ctrl_p);
return (DDI_SUCCESS);
}
/*
* Setup slot information for use with DDI HP framework.
*/
static int
{
/*
* setup DDI HP framework slot information structure
*/
slot_p->hs_device_num = 0;
/* read Slot Capabilities Register */
/* set slot-name/slot-number info */
/* check if Attn Button present */
/* check if Manual Retention Latch sensor present */
/*
* PCI-E version 1.1 defines EMI Lock Present bit
* in Slot Capabilities register. Check for it.
*/
if (ctrl_p->hc_dll_active_rep)
/* setup thread for handling ATTN button events */
if (ctrl_p->hc_has_attn) {
PCIE_DBG("pciehpc_slotinfo_init: setting up ATTN button event "
}
/* get current slot state from the hw */
return (DDI_SUCCESS);
}
/*ARGSUSED*/
static int
{
PCIE_DBG("pciehpc_slotinfo_uninit: "
"waiting for ATTN thread exit\n");
PCIE_DBG("pciehpc_slotinfo_uninit: ATTN thread exit\n");
}
if (ctrl_p->hc_dll_active_rep)
return (DDI_SUCCESS);
}
/*
* Enable hot plug interrupts.
* Note: this is only for Native hot plug mode.
*/
static int
{
/* clear any interrupt status bits */
/* read the Slot Control Register */
/*
* enable interrupts: power fault detection interrupt is enabled
* only when the slot is powered ON
*/
else
return (DDI_SUCCESS);
}
/*
* Disable hot plug interrupts.
* Note: this is only for Native hot plug mode.
*/
static int
{
/* read the Slot Control Register */
/* disable all interrupts */
reg &= ~(PCIE_SLOTCTL_INTR_MASK);
/* clear any interrupt status bits */
return (DDI_SUCCESS);
}
/*
* Allocate a new hotplug controller and slot structures for HPC
* associated with this dip.
*/
static pcie_hp_ctrl_t *
{
/* Allocate a new slot structure. */
/* Initialize the interrupt mutex */
(void *)PCIE_INTR_PRI);
/* Initialize synchronization conditional variable */
return (ctrl_p);
}
/*
* Remove the HPC controller and slot structures
*/
static void
{
/* get the soft state structure for this dip */
return;
}
/*
* Register the PCI-E hot plug slot with DDI HP framework.
*/
static int
{
/* register the slot with DDI HP framework */
PCIE_DBG("pciehpc_register_slot() failed to register slot %d\n",
return (DDI_FAILURE);
}
PCIE_DBG("pciehpc_register_slot(): registered slot %d\n",
return (DDI_SUCCESS);
}
/*
* Unregister the PCI-E hot plug slot from DDI HP framework.
*/
static int
{
/* unregister the slot with DDI HP framework */
PCIE_DBG("pciehpc_unregister_slot() "
return (DDI_FAILURE);
}
PCIE_DBG("pciehpc_unregister_slot(): unregistered slot %d\n",
return (DDI_SUCCESS);
}
/*
* pciehpc_slot_poweron()
*
*
* Note: This function is called by DDI HP framework at kernel context only
*/
/*ARGSUSED*/
static int
{
/* get the current state of the slot */
/* check if the slot is already in the 'enabled' state */
/* slot is already in the 'enabled' state */
PCIE_DBG("pciehpc_slot_poweron() slot %d already enabled\n",
return (DDI_SUCCESS);
}
/* read the Slot Status Register */
/* make sure the MRL switch is closed if present */
/* MRL switch is open */
goto cleanup;
}
/* make sure the slot has a device present */
if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
/* slot is empty */
goto cleanup;
}
/* get the current state of Slot Control Register */
/*
* Enable power to the slot involves:
* 1. Set power LED to blink and ATTN led to OFF.
* 2. Set power control ON in Slot Control Reigster and
* wait for Command Completed Interrupt or 1 sec timeout.
* 3. If Data Link Layer State Changed events are supported
* then wait for the event to indicate Data Layer Link
* is active. The time out value for this event is 1 second.
* This is specified in PCI-E version 1.1.
* 4. Set power LED to be ON.
*/
/* 1. set power LED to blink & ATTN led to OFF */
/* 2. set power control to ON */
/* 3. wait for DLL State Change event, if it's supported */
if (ctrl_p->hc_dll_active_rep) {
if (!(status & PCIE_LINKSTS_DLL_LINK_ACTIVE)) {
/* wait 1 sec for the DLL State Changed event */
ddi_get_lbolt() +
/* check Link status */
if (!(status & PCIE_LINKSTS_DLL_LINK_ACTIVE))
goto cleanup2;
}
}
/* wait 1 sec for link to come up */
/* check power is really turned ON */
if (control & PCIE_SLOTCTL_PWR_CONTROL) {
PCIE_DBG("slot %d fails to turn on power on connect\n",
goto cleanup1;
}
/* clear power fault status */
status);
/* enable power fault detection interrupt */
/* 4. Set power LED to be ON */
/* if EMI is present, turn it ON */
if (ctrl_p->hc_has_emi_lock) {
if (!(status & PCIE_SLOTSTS_EMI_LOCK_SET)) {
/* wait 1 sec after toggling the state of EMI lock */
}
}
return (DDI_SUCCESS);
/* if power is ON, set power control to OFF */
if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) {
}
/* set power led to OFF */
return (DDI_FAILURE);
}
/*ARGSUSED*/
static int
{
/* get the current state of the slot */
/* check if the slot is not in the "enabled' state */
/* slot is in the 'disabled' state */
PCIE_DBG("pciehpc_slot_poweroff(): "
return (DDI_SUCCESS);
}
/* read the Slot Status Register */
/* make sure the slot has a device present */
if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
/* slot is empty */
PCIE_DBG("pciehpc_slot_poweroff(): slot %d is empty\n",
goto cleanup;
}
/*
* Disable power to the slot involves:
* 1. Set power LED to blink.
* 2. Set power control OFF in Slot Control Reigster and
* wait for Command Completed Interrupt or 1 sec timeout.
* 3. Set POWER led and ATTN led to be OFF.
*/
/* 1. set power LED to blink */
/* disable power fault detection interrupt */
/* 2. set power control to OFF */
#ifdef DEBUG
/* check for power control bit to be OFF */
#endif
/* 3. Set power LED to be OFF */
/* if EMI is present, turn it OFF */
if (ctrl_p->hc_has_emi_lock) {
if (status & PCIE_SLOTSTS_EMI_LOCK_SET) {
/* wait 1 sec after toggling the state of EMI lock */
}
}
/* get the current state of the slot */
return (DDI_SUCCESS);
return (DDI_FAILURE);
}
/*
* pciehpc_slot_probe()
*
* Probe the slot.
*
* Note: This function is called by DDI HP framework at kernel context only
*/
/*ARGSUSED*/
static int
{
int ret = DDI_SUCCESS;
/* get the current state of the slot */
/*
* Probe a given PCIe Hotplug Connection (CN).
*/
if (ret != DDI_SUCCESS) {
PCIE_DBG("pciehpc_slot_probe() failed\n");
/* turn the ATTN led ON for configure failure */
/* if power to the slot is still on then set Power led to ON */
return (DDI_FAILURE);
}
/* get the current state of the slot */
return (DDI_SUCCESS);
}
/*
* pciehpc_slot_unprobe()
*
* Unprobe the slot.
*
* Note: This function is called by DDI HP framework at kernel context only
*/
/*ARGSUSED*/
static int
{
int ret;
/* get the current state of the slot */
/*
* Unprobe a given PCIe Hotplug Connection (CN).
*/
if (ret != DDI_SUCCESS) {
PCIE_DBG("pciehpc_slot_unprobe() failed\n");
/* if power to the slot is still on then set Power led to ON */
return (DDI_FAILURE);
}
/* get the current state of the slot */
return (DDI_SUCCESS);
}
static int
{
int rv = DDI_SUCCESS;
if (target_state > DDI_HP_CN_STATE_ENABLED) {
return (DDI_EINVAL);
}
switch (curr_state) {
case DDI_HP_CN_STATE_EMPTY:
/*
* From EMPTY to PRESENT, just check the hardware
* slot state.
*/
rv = DDI_FAILURE;
break;
case DDI_HP_CN_STATE_PRESENT:
&curr_state);
break;
case DDI_HP_CN_STATE_POWERED:
break;
default:
/* should never reach here */
ASSERT("unknown devinfo state");
}
}
return (rv);
}
static int
{
int rv = DDI_SUCCESS;
switch (curr_state) {
case DDI_HP_CN_STATE_PRESENT:
/*
* From PRESENT to EMPTY, just check hardware slot
* state.
*/
if (curr_state >= DDI_HP_CN_STATE_PRESENT)
rv = DDI_FAILURE;
break;
case DDI_HP_CN_STATE_POWERED:
slot_p, &curr_state);
break;
case DDI_HP_CN_STATE_ENABLED:
break;
default:
/* should never reach here */
ASSERT("unknown devinfo state");
}
}
return (rv);
}
/* Change slot state to a target state */
static int
{
int rv;
if (curr_state == target_state) {
return (DDI_SUCCESS);
}
if (curr_state < target_state) {
} else {
}
return (rv);
}
int
{
#ifdef _SYSCALL32_IMPL
#endif
int ret = DDI_SUCCESS;
int i, n;
if (get_udatamodel() == DATAMODEL_NATIVE) {
return (DDI_FAILURE);
}
#ifdef _SYSCALL32_IMPL
else {
return (DDI_FAILURE);
}
#endif
&prop_list)) != DDI_SUCCESS)
return (ret);
ret = DDI_ENOMEM;
goto get_prop_cleanup;
}
/* check whether the requested property is "all" or "help" */
n = sizeof (pciehpc_props) / sizeof (pciehpc_prop_t);
/*
* Add all properties into the request list, so that we
* will get the values in the following for loop.
*/
for (i = 0; i < n; i++) {
ret = DDI_FAILURE;
goto get_prop_cleanup1;
}
}
/*
* Empty the request list, and add help strings into the
* return list. We will pass the following for loop.
*/
for (i = 0; i < n; i++) {
pciehpc_props[i].prop_value) != 0) {
ret = DDI_FAILURE;
goto get_prop_cleanup1;
}
}
}
}
/* get the current slot state */
/* for each requested property, get the value and add it to nvlist */
int i;
/*
* When getting all properties, just ignore the
* one that's not available under certain state.
*/
if (get_all_prop)
continue;
ret = DDI_ENOTSUP;
goto get_prop_cleanup2;
}
ret = DDI_FAILURE;
goto get_prop_cleanup2;
}
for (i = 0; i < class_pci_items; i++) {
break;
}
}
if (i == class_pci_items)
else
} else {
/* unsupported property */
ret = DDI_ENOTSUP;
goto get_prop_cleanup2;
}
ret = DDI_FAILURE;
goto get_prop_cleanup2;
}
}
/* pack nvlist and copyout */
goto get_prop_cleanup2;
}
if (get_udatamodel() == DATAMODEL_NATIVE) {
ret = DDI_FAILURE;
}
#ifdef _SYSCALL32_IMPL
else {
ret = DDI_FAILURE;
} else {
sizeof (ddi_hp_property32_t)))
ret = DDI_FAILURE;
}
}
#endif
return (ret);
}
int
{
#ifdef _SYSCALL32_IMPL
#endif
int ret = DDI_SUCCESS;
if (get_udatamodel() == DATAMODEL_NATIVE) {
return (DDI_FAILURE);
if (rval &&
return (DDI_FAILURE);
}
#ifdef _SYSCALL32_IMPL
else {
return (DDI_FAILURE);
if (rval &&
return (DDI_FAILURE);
if (rval) {
}
}
#endif
&prop_list)) != DDI_SUCCESS)
return (ret);
/* check whether the requested property is "help" */
if (!rval) {
ret = DDI_ENOTSUP;
goto set_prop_cleanup;
}
ret = DDI_ENOMEM;
goto set_prop_cleanup;
}
PCIEHPC_PROP_VALUE_LED) != 0) {
ret = DDI_FAILURE;
goto set_prop_cleanup1;
}
goto set_prop_cleanup1;
}
if (get_udatamodel() == DATAMODEL_NATIVE) {
sizeof (ddi_hp_property_t))) {
ret = DDI_FAILURE;
goto set_prop_cleanup1;
}
}
#ifdef _SYSCALL32_IMPL
else {
ret = DDI_FAILURE;
goto set_prop_cleanup1;
} else {
sizeof (ddi_hp_property32_t))) {
ret = DDI_FAILURE;
goto set_prop_cleanup1;
}
}
}
#endif
return (ret);
}
/* Validate the request */
PCIE_DBG("Unexpected data type of setting "
"property %s.\n", name);
ret = DDI_EINVAL;
goto set_prop_cleanup;
}
PCIE_DBG("Get string value failed for property %s.\n",
name);
ret = DDI_FAILURE;
goto set_prop_cleanup;
}
PCIE_DBG("Unsupported value of setting "
"property %s\n", name);
ret = DDI_ENOTSUP;
goto set_prop_cleanup;
}
} else {
ret = DDI_ENOTSUP;
goto set_prop_cleanup;
}
}
/* get the current slot state */
/* set each property */
}
}
if (rval) {
if (get_udatamodel() == DATAMODEL_NATIVE) {
ret = DDI_FAILURE;
}
#ifdef _SYSCALL32_IMPL
else {
sizeof (ddi_hp_property32_t)))
ret = DDI_FAILURE;
}
#endif
}
return (ret);
}
/*
* Send a command to the PCI-E Hot Plug Controller.
*
* NOTES: The PCI-E spec defines the following semantics for issuing hot plug
* commands.
* 1) If Command Complete events/interrupts are supported then software
* waits for Command Complete event after issuing a command (i.e writing
* to the Slot Control register). The command completion could take as
* long as 1 second so software should be prepared to wait for 1 second
* before issuing another command.
*
* 2) If Command Complete events/interrupts are not supported then
* software could issue multiple Slot Control writes without any delay
* between writes.
*/
static void
{
/*
* PCI-E version 1.1 spec defines No Command Completed
* Support bit (bit#18) in Slot Capabilities register. If this
* bit is set then slot doesn't support notification of command
* completion events.
*/
/*
* If no Command Completion event is supported or it is ACPI
* hot plug mode then just issue the command and return.
*/
if ((slot_cap & PCIE_SLOTCAP_NO_CMD_COMP_SUPP) ||
return;
}
/*
* **************************************
* Command Complete events are supported.
* **************************************
*/
/*
* If HPC is not yet initialized then just poll for the Command
* Completion interrupt.
*/
int retry = PCIE_HP_CMD_WAIT_RETRY;
/* write the command to the HPC */
/* poll for status completion */
while (retry--) {
/* wait for 10 msec before checking the status */
if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
/* clear the status bits */
break;
}
}
return;
}
/* HPC is already initialized */
/*
* If previous command is still pending then wait for its
* completion. i.e cv_wait()
*/
/*
* Issue the command and wait for Command Completion or
* the 1 sec timeout.
*/
/* it is a timeout */
PCIE_DBG("pciehpc_issue_hpc_command: Command Complete"
" interrupt is not received for slot %d\n",
/* clear the status info in case interrupts are disabled? */
if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
/* clear the status bits */
}
}
/* wake up any one waiting for issuing another command to HPC */
}
/*
* pciehcp_attn_btn_handler()
*
* This handles ATTN button pressed event as per the PCI-E 1.1 spec.
*/
static void
{
PCIE_DBG("pciehpc_attn_btn_handler: thread started\n");
"pciehpc_attn_btn_handler");
/* wait for ATTN button event */
/* get the current state of power LED */
/* Blink the Power LED while we wait for 5 seconds */
/* wait for 5 seconds before taking any action */
/*
* It is a time out; make sure the ATTN pending
* flag is still ON before sending the event to
* DDI HP framework.
*/
int hint;
/*
* Insertion.
*/
} else {
/*
* Want to remove;
*/
}
/*
* We can't call ddihp_cn_gen_sysevent
* here since it's not a DDI interface.
*/
hint,
KM_SLEEP);
}
}
/* restore the power LED state */
continue;
}
/* wait for another ATTN button event */
}
PCIE_DBG("pciehpc_attn_btn_handler: thread exit\n");
thread_exit();
}
/*
* convert LED state from PCIE HPC definition to pcie_hp_led_state_t
* definition.
*/
static pcie_hp_led_state_t
{
switch (state) {
return (PCIE_HP_LED_ON);
return (PCIE_HP_LED_BLINK);
default:
return (PCIE_HP_LED_OFF);
}
}
/*
* Get the state of an LED.
*/
static pcie_hp_led_state_t
{
/* get the current state of Slot Control register */
switch (led) {
case PCIE_HP_POWER_LED:
break;
case PCIE_HP_ATTN_LED:
break;
default:
return (PCIE_HP_LED_OFF);
}
switch (state) {
return (PCIE_HP_LED_ON);
return (PCIE_HP_LED_BLINK);
default:
return (PCIE_HP_LED_OFF);
}
}
/*
* Set the state of an LED. It updates both hw and sw state.
*/
static void
{
/* get the current state of Slot Control register */
switch (led) {
case PCIE_HP_POWER_LED:
/* clear led mask */
break;
case PCIE_HP_ATTN_LED:
/* clear led mask */
break;
default:
return;
}
switch (state) {
case PCIE_HP_LED_ON:
if (led == PCIE_HP_POWER_LED)
else if (led == PCIE_HP_ATTN_LED)
break;
case PCIE_HP_LED_OFF:
if (led == PCIE_HP_POWER_LED)
else if (led == PCIE_HP_ATTN_LED)
break;
case PCIE_HP_LED_BLINK:
if (led == PCIE_HP_POWER_LED)
else if (led == PCIE_HP_ATTN_LED)
break;
default:
PCIE_DBG("pciehpc_set_led_state() invalid LED state %d\n",
state);
return;
}
/* update the Slot Control Register */
#ifdef DEBUG
/* get the current state of Slot Control register */
PCIE_DBG("pciehpc_set_led_state: slot %d power-led %s attn-led %s\n",
#endif
}
static void
{
/*
* Hold the parent's ref so that it won't disappear when the taskq is
* scheduled to run.
*/
TQ_NOSLEEP)) {
PCIE_DBG("pciehpc_intr(): "
"Failed to dispatch power fault handler, dip %p\n", dip);
}
}
static void
pciehpc_power_fault_handler(void *arg)
{
/* get the soft state structure for this dip */
return;
}
/*
* Send the event to DDI Hotplug framework, power off
* the slot
*/
(void) ndi_hp_state_change_req(dip,
}
#ifdef DEBUG
/*
* Dump PCI-E Hot Plug registers.
*/
static void
{
if (!pcie_debug_flags)
return;
PCIE_DBG("pciehpc_dump_hpregs: Found PCI-E hot plug slot %d\n",
PCIE_DBG("Attention Button Present = %s\n",
PCIE_DBG("Power controller Present = %s\n",
PCIE_DBG("MRL Sensor Present = %s\n",
PCIE_DBG("Attn Indicator Present = %s\n",
PCIE_DBG("Power Indicator Present = %s\n",
PCIE_DBG("HotPlug Surprise = %s\n",
PCIE_DBG("HotPlug Capable = %s\n",
PCIE_DBG("Physical Slot Number = %d\n",
PCIE_DBG("Attn Button interrupt Enabled = %s\n",
PCIE_DBG("Power Fault interrupt Enabled = %s\n",
PCIE_DBG("MRL Sensor INTR Enabled = %s\n",
PCIE_DBG("Presence interrupt Enabled = %s\n",
PCIE_DBG("Cmd Complete interrupt Enabled = %s\n",
PCIE_DBG("HotPlug interrupt Enabled = %s\n",
PCIE_DBG("Attn Indicator LED = %s\n",
}
#endif /* DEBUG */