126947304SEvan Yan /*
226947304SEvan Yan * CDDL HEADER START
326947304SEvan Yan *
426947304SEvan Yan * The contents of this file are subject to the terms of the
526947304SEvan Yan * Common Development and Distribution License (the "License").
626947304SEvan Yan * You may not use this file except in compliance with the License.
726947304SEvan Yan *
826947304SEvan Yan * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
926947304SEvan Yan * or http://www.opensolaris.org/os/licensing.
1026947304SEvan Yan * See the License for the specific language governing permissions
1126947304SEvan Yan * and limitations under the License.
1226947304SEvan Yan *
1326947304SEvan Yan * When distributing Covered Code, include this CDDL HEADER in each
1426947304SEvan Yan * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1526947304SEvan Yan * If applicable, add the following below this CDDL HEADER, with the
1626947304SEvan Yan * fields enclosed by brackets "[]" replaced with your own identifying
1726947304SEvan Yan * information: Portions Copyright [yyyy] [name of copyright owner]
1826947304SEvan Yan *
1926947304SEvan Yan * CDDL HEADER END
2026947304SEvan Yan */
2126947304SEvan Yan
2226947304SEvan Yan /*
23*80dc702dSColin Zou - Sun Microsystems - Beijing China * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
2426947304SEvan Yan */
2526947304SEvan Yan
2626947304SEvan Yan /*
2726947304SEvan Yan * This file contains Standard PCI Express HotPlug functionality that is
2826947304SEvan Yan * compatible with the PCI Express ver 1.1 specification.
2926947304SEvan Yan *
3026947304SEvan Yan * NOTE: This file is compiled and delivered through misc/pcie module.
3126947304SEvan Yan */
3226947304SEvan Yan
3326947304SEvan Yan #include <sys/types.h>
3426947304SEvan Yan #include <sys/note.h>
3526947304SEvan Yan #include <sys/conf.h>
3626947304SEvan Yan #include <sys/kmem.h>
3726947304SEvan Yan #include <sys/debug.h>
3826947304SEvan Yan #include <sys/vtrace.h>
3926947304SEvan Yan #include <sys/autoconf.h>
4026947304SEvan Yan #include <sys/varargs.h>
4126947304SEvan Yan #include <sys/ddi_impldefs.h>
4226947304SEvan Yan #include <sys/time.h>
4326947304SEvan Yan #include <sys/callb.h>
4426947304SEvan Yan #include <sys/ddi.h>
4526947304SEvan Yan #include <sys/sunddi.h>
4626947304SEvan Yan #include <sys/sunndi.h>
4726947304SEvan Yan #include <sys/sysevent/dr.h>
4826947304SEvan Yan #include <sys/pci_impl.h>
4926947304SEvan Yan #include <sys/hotplug/pci/pcie_hp.h>
5026947304SEvan Yan #include <sys/hotplug/pci/pciehpc.h>
5126947304SEvan Yan
5226947304SEvan Yan typedef struct pciehpc_prop {
5326947304SEvan Yan char *prop_name;
5426947304SEvan Yan char *prop_value;
5526947304SEvan Yan } pciehpc_prop_t;
5626947304SEvan Yan
5726947304SEvan Yan static pciehpc_prop_t pciehpc_props[] = {
5826947304SEvan Yan { PCIEHPC_PROP_LED_FAULT, PCIEHPC_PROP_VALUE_LED },
5926947304SEvan Yan { PCIEHPC_PROP_LED_POWER, PCIEHPC_PROP_VALUE_LED },
6026947304SEvan Yan { PCIEHPC_PROP_LED_ATTN, PCIEHPC_PROP_VALUE_LED },
6126947304SEvan Yan { PCIEHPC_PROP_LED_ACTIVE, PCIEHPC_PROP_VALUE_LED },
6226947304SEvan Yan { PCIEHPC_PROP_CARD_TYPE, PCIEHPC_PROP_VALUE_TYPE },
6326947304SEvan Yan { PCIEHPC_PROP_BOARD_TYPE, PCIEHPC_PROP_VALUE_TYPE },
6426947304SEvan Yan { PCIEHPC_PROP_SLOT_CONDITION, PCIEHPC_PROP_VALUE_TYPE }
6526947304SEvan Yan };
6626947304SEvan Yan
6726947304SEvan Yan /* Local functions prototype */
6826947304SEvan Yan static int pciehpc_hpc_init(pcie_hp_ctrl_t *ctrl_p);
6926947304SEvan Yan static int pciehpc_hpc_uninit(pcie_hp_ctrl_t *ctrl_p);
7026947304SEvan Yan static int pciehpc_slotinfo_init(pcie_hp_ctrl_t *ctrl_p);
7126947304SEvan Yan static int pciehpc_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p);
7226947304SEvan Yan static int pciehpc_enable_intr(pcie_hp_ctrl_t *ctrl_p);
7326947304SEvan Yan static int pciehpc_disable_intr(pcie_hp_ctrl_t *ctrl_p);
7426947304SEvan Yan static pcie_hp_ctrl_t *pciehpc_create_controller(dev_info_t *dip);
7526947304SEvan Yan static void pciehpc_destroy_controller(dev_info_t *dip);
7626947304SEvan Yan static int pciehpc_register_slot(pcie_hp_ctrl_t *ctrl_p);
7726947304SEvan Yan static int pciehpc_unregister_slot(pcie_hp_ctrl_t *ctrl_p);
7826947304SEvan Yan static int pciehpc_slot_get_property(pcie_hp_slot_t *slot_p,
7926947304SEvan Yan ddi_hp_property_t *arg, ddi_hp_property_t *rval);
8026947304SEvan Yan static int pciehpc_slot_set_property(pcie_hp_slot_t *slot_p,
8126947304SEvan Yan ddi_hp_property_t *arg, ddi_hp_property_t *rval);
8226947304SEvan Yan static void pciehpc_issue_hpc_command(pcie_hp_ctrl_t *ctrl_p, uint16_t control);
8326947304SEvan Yan static void pciehpc_attn_btn_handler(pcie_hp_ctrl_t *ctrl_p);
8426947304SEvan Yan static pcie_hp_led_state_t pciehpc_led_state_to_hpc(uint16_t state);
8526947304SEvan Yan static pcie_hp_led_state_t pciehpc_get_led_state(pcie_hp_ctrl_t *ctrl_p,
8626947304SEvan Yan pcie_hp_led_t led);
8726947304SEvan Yan static void pciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led,
8826947304SEvan Yan pcie_hp_led_state_t state);
8926947304SEvan Yan
9026947304SEvan Yan static int pciehpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
9126947304SEvan Yan ddi_hp_cn_state_t target_state);
9226947304SEvan Yan static int pciehpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
9326947304SEvan Yan ddi_hp_cn_state_t target_state);
9426947304SEvan Yan static int pciehpc_change_slot_state(pcie_hp_slot_t *slot_p,
9526947304SEvan Yan ddi_hp_cn_state_t target_state);
9626947304SEvan Yan static int
9726947304SEvan Yan pciehpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result);
9826947304SEvan Yan static int
9926947304SEvan Yan pciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result);
10026947304SEvan Yan static int pciehpc_slot_probe(pcie_hp_slot_t *slot_p);
10126947304SEvan Yan static int pciehpc_slot_unprobe(pcie_hp_slot_t *slot_p);
102*80dc702dSColin Zou - Sun Microsystems - Beijing China static void pciehpc_handle_power_fault(dev_info_t *dip);
103*80dc702dSColin Zou - Sun Microsystems - Beijing China static void pciehpc_power_fault_handler(void *arg);
10426947304SEvan Yan
10526947304SEvan Yan #ifdef DEBUG
10626947304SEvan Yan static void pciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p);
10726947304SEvan Yan #endif /* DEBUG */
10826947304SEvan Yan
10926947304SEvan Yan /*
11026947304SEvan Yan * Global functions (called by other drivers/modules)
11126947304SEvan Yan */
11226947304SEvan Yan
11326947304SEvan Yan /*
11426947304SEvan Yan * Initialize Hot Plug Controller if present. The arguments are:
11526947304SEvan Yan * dip - Devinfo node pointer to the hot plug bus node
11626947304SEvan Yan * regops - register ops to access HPC registers for non-standard
11726947304SEvan Yan * HPC hw implementations (e.g: HPC in host PCI-E brdiges)
11826947304SEvan Yan * This is NULL for standard HPC in PCIe bridges.
11926947304SEvan Yan * Returns:
12026947304SEvan Yan * DDI_SUCCESS for successful HPC initialization
12126947304SEvan Yan * DDI_FAILURE for errors or if HPC hw not found
12226947304SEvan Yan */
12326947304SEvan Yan int
pciehpc_init(dev_info_t * dip,caddr_t arg)12426947304SEvan Yan pciehpc_init(dev_info_t *dip, caddr_t arg)
12526947304SEvan Yan {
12626947304SEvan Yan pcie_hp_regops_t *regops = (pcie_hp_regops_t *)(void *)arg;
12726947304SEvan Yan pcie_hp_ctrl_t *ctrl_p;
12826947304SEvan Yan
12926947304SEvan Yan PCIE_DBG("pciehpc_init() called (dip=%p)\n", (void *)dip);
13026947304SEvan Yan
13126947304SEvan Yan /* Make sure that it is not already initialized */
13226947304SEvan Yan if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) != NULL) {
13326947304SEvan Yan PCIE_DBG("%s%d: pciehpc instance already initialized!\n",
13426947304SEvan Yan ddi_driver_name(dip), ddi_get_instance(dip));
13526947304SEvan Yan return (DDI_SUCCESS);
13626947304SEvan Yan }
13726947304SEvan Yan
13826947304SEvan Yan /* Allocate a new hotplug controller and slot structures */
13926947304SEvan Yan ctrl_p = pciehpc_create_controller(dip);
14026947304SEvan Yan
14126947304SEvan Yan /* setup access handle for HPC regs */
14226947304SEvan Yan if (regops != NULL) {
14326947304SEvan Yan /* HPC access is non-standard; use the supplied reg ops */
14426947304SEvan Yan ctrl_p->hc_regops = *regops;
14526947304SEvan Yan }
14626947304SEvan Yan
14726947304SEvan Yan /*
14826947304SEvan Yan * Setup resource maps for this bus node.
14926947304SEvan Yan */
15026947304SEvan Yan (void) pci_resource_setup(dip);
15126947304SEvan Yan
15226947304SEvan Yan PCIE_DISABLE_ERRORS(dip);
15326947304SEvan Yan
15426947304SEvan Yan /*
15526947304SEvan Yan * Set the platform specific hot plug mode.
15626947304SEvan Yan */
15726947304SEvan Yan ctrl_p->hc_ops.init_hpc_hw = pciehpc_hpc_init;
15826947304SEvan Yan ctrl_p->hc_ops.uninit_hpc_hw = pciehpc_hpc_uninit;
15926947304SEvan Yan ctrl_p->hc_ops.init_hpc_slotinfo = pciehpc_slotinfo_init;
16026947304SEvan Yan ctrl_p->hc_ops.uninit_hpc_slotinfo = pciehpc_slotinfo_uninit;
16126947304SEvan Yan ctrl_p->hc_ops.poweron_hpc_slot = pciehpc_slot_poweron;
16226947304SEvan Yan ctrl_p->hc_ops.poweroff_hpc_slot = pciehpc_slot_poweroff;
16326947304SEvan Yan
16426947304SEvan Yan ctrl_p->hc_ops.enable_hpc_intr = pciehpc_enable_intr;
16526947304SEvan Yan ctrl_p->hc_ops.disable_hpc_intr = pciehpc_disable_intr;
16626947304SEvan Yan
16726947304SEvan Yan #if defined(__i386) || defined(__amd64)
16826947304SEvan Yan pciehpc_update_ops(ctrl_p);
16926947304SEvan Yan #endif
17026947304SEvan Yan
17126947304SEvan Yan /* initialize hot plug controller hw */
17226947304SEvan Yan if ((ctrl_p->hc_ops.init_hpc_hw)(ctrl_p) != DDI_SUCCESS)
17326947304SEvan Yan goto cleanup1;
17426947304SEvan Yan
17526947304SEvan Yan /* initialize slot information soft state structure */
17626947304SEvan Yan if ((ctrl_p->hc_ops.init_hpc_slotinfo)(ctrl_p) != DDI_SUCCESS)
17726947304SEvan Yan goto cleanup2;
17826947304SEvan Yan
17926947304SEvan Yan /* register the hot plug slot with DDI HP framework */
18026947304SEvan Yan if (pciehpc_register_slot(ctrl_p) != DDI_SUCCESS)
18126947304SEvan Yan goto cleanup3;
18226947304SEvan Yan
18326947304SEvan Yan /* create minor node for this slot */
18426947304SEvan Yan if (pcie_create_minor_node(ctrl_p, 0) != DDI_SUCCESS)
18526947304SEvan Yan goto cleanup4;
18626947304SEvan Yan
18726947304SEvan Yan /* HPC initialization is complete now */
18826947304SEvan Yan ctrl_p->hc_flags = PCIE_HP_INITIALIZED_FLAG;
18926947304SEvan Yan
19026947304SEvan Yan #ifdef DEBUG
19126947304SEvan Yan /* For debug, dump the HPC registers */
19226947304SEvan Yan pciehpc_dump_hpregs(ctrl_p);
19326947304SEvan Yan #endif /* DEBUG */
19426947304SEvan Yan
19526947304SEvan Yan return (DDI_SUCCESS);
19626947304SEvan Yan cleanup4:
19726947304SEvan Yan (void) pciehpc_unregister_slot(ctrl_p);
19826947304SEvan Yan cleanup3:
19926947304SEvan Yan (void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p);
20026947304SEvan Yan
20126947304SEvan Yan cleanup2:
20226947304SEvan Yan (void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p);
20326947304SEvan Yan
20426947304SEvan Yan cleanup1:
20526947304SEvan Yan PCIE_ENABLE_ERRORS(dip);
20626947304SEvan Yan (void) pci_resource_destroy(dip);
20726947304SEvan Yan
20826947304SEvan Yan pciehpc_destroy_controller(dip);
20926947304SEvan Yan return (DDI_FAILURE);
21026947304SEvan Yan }
21126947304SEvan Yan
21226947304SEvan Yan /*
21326947304SEvan Yan * Uninitialize HPC soft state structure and free up any resources
21426947304SEvan Yan * used for the HPC instance.
21526947304SEvan Yan */
21626947304SEvan Yan int
pciehpc_uninit(dev_info_t * dip)21726947304SEvan Yan pciehpc_uninit(dev_info_t *dip)
21826947304SEvan Yan {
21926947304SEvan Yan pcie_hp_ctrl_t *ctrl_p;
22026947304SEvan Yan
22126947304SEvan Yan PCIE_DBG("pciehpc_uninit() called (dip=%p)\n", (void *)dip);
22226947304SEvan Yan
22326947304SEvan Yan /* get the soft state structure for this dip */
22426947304SEvan Yan if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) {
22526947304SEvan Yan return (DDI_FAILURE);
22626947304SEvan Yan }
22726947304SEvan Yan
22826947304SEvan Yan pcie_remove_minor_node(ctrl_p, 0);
22926947304SEvan Yan
23026947304SEvan Yan /* unregister the slot */
23126947304SEvan Yan (void) pciehpc_unregister_slot(ctrl_p);
23226947304SEvan Yan
23326947304SEvan Yan /* uninit any slot info data structures */
23426947304SEvan Yan (void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p);
23526947304SEvan Yan
23626947304SEvan Yan /* uninitialize hpc, remove interrupt handler, etc. */
23726947304SEvan Yan (void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p);
23826947304SEvan Yan
23926947304SEvan Yan PCIE_ENABLE_ERRORS(dip);
24026947304SEvan Yan
24126947304SEvan Yan /*
24226947304SEvan Yan * Destroy resource maps for this bus node.
24326947304SEvan Yan */
24426947304SEvan Yan (void) pci_resource_destroy(dip);
24526947304SEvan Yan
24626947304SEvan Yan /* destroy the soft state structure */
24726947304SEvan Yan pciehpc_destroy_controller(dip);
24826947304SEvan Yan
24926947304SEvan Yan return (DDI_SUCCESS);
25026947304SEvan Yan }
25126947304SEvan Yan
25226947304SEvan Yan /*
25326947304SEvan Yan * pciehpc_intr()
25426947304SEvan Yan *
25526947304SEvan Yan * Interrupt handler for PCI-E Hot plug controller interrupts.
25626947304SEvan Yan *
25726947304SEvan Yan * Note: This is only for native mode hot plug. This is called
25826947304SEvan Yan * by the nexus driver at interrupt context. Interrupt Service Routine
25926947304SEvan Yan * registration is done by the nexus driver for both hot plug and
26026947304SEvan Yan * non-hot plug interrupts. This function is called from the ISR
26126947304SEvan Yan * of the nexus driver to handle hot-plug interrupts.
26226947304SEvan Yan */
26326947304SEvan Yan int
pciehpc_intr(dev_info_t * dip)26426947304SEvan Yan pciehpc_intr(dev_info_t *dip)
26526947304SEvan Yan {
26626947304SEvan Yan pcie_hp_ctrl_t *ctrl_p;
26726947304SEvan Yan pcie_hp_slot_t *slot_p;
26826947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
26926947304SEvan Yan uint16_t status, control;
27026947304SEvan Yan
27126947304SEvan Yan /* get the soft state structure for this dip */
27226947304SEvan Yan if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
27326947304SEvan Yan return (DDI_INTR_UNCLAIMED);
27426947304SEvan Yan
27526947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex);
27626947304SEvan Yan
27726947304SEvan Yan /* make sure the controller soft state is initialized */
27826947304SEvan Yan if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
27926947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex);
28026947304SEvan Yan return (DDI_INTR_UNCLAIMED);
28126947304SEvan Yan }
28226947304SEvan Yan
28326947304SEvan Yan /* if it is not NATIVE hot plug mode then return */
28426947304SEvan Yan if (bus_p->bus_hp_curr_mode != PCIE_NATIVE_HP_MODE) {
28526947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex);
28626947304SEvan Yan return (DDI_INTR_UNCLAIMED);
28726947304SEvan Yan }
28826947304SEvan Yan
28926947304SEvan Yan slot_p = ctrl_p->hc_slots[0];
29026947304SEvan Yan
29126947304SEvan Yan /* read the current slot status register */
29226947304SEvan Yan status = pciehpc_reg_get16(ctrl_p,
29326947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
29426947304SEvan Yan
29526947304SEvan Yan /* check if there are any hot plug interrupts occurred */
29626947304SEvan Yan if (!(status & PCIE_SLOTSTS_STATUS_EVENTS)) {
29726947304SEvan Yan /* no hot plug events occurred */
29826947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex);
29926947304SEvan Yan return (DDI_INTR_UNCLAIMED);
30026947304SEvan Yan }
30126947304SEvan Yan
30226947304SEvan Yan /* clear the interrupt status bits */
30326947304SEvan Yan pciehpc_reg_put16(ctrl_p,
30426947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
30526947304SEvan Yan
30626947304SEvan Yan /* check for CMD COMPLETE interrupt */
30726947304SEvan Yan if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
30826947304SEvan Yan PCIE_DBG("pciehpc_intr(): CMD COMPLETED interrupt received\n");
30926947304SEvan Yan /* wake up any one waiting for Command Completion event */
31026947304SEvan Yan cv_signal(&ctrl_p->hc_cmd_comp_cv);
31126947304SEvan Yan }
31226947304SEvan Yan
31326947304SEvan Yan /* check for ATTN button interrupt */
31426947304SEvan Yan if (status & PCIE_SLOTSTS_ATTN_BTN_PRESSED) {
31526947304SEvan Yan PCIE_DBG("pciehpc_intr(): ATTN BUTTON interrupt received\n");
31626947304SEvan Yan
31726947304SEvan Yan /* if ATTN button event is still pending then cancel it */
31826947304SEvan Yan if (slot_p->hs_attn_btn_pending == B_TRUE)
31926947304SEvan Yan slot_p->hs_attn_btn_pending = B_FALSE;
32026947304SEvan Yan else
32126947304SEvan Yan slot_p->hs_attn_btn_pending = B_TRUE;
32226947304SEvan Yan
32326947304SEvan Yan /* wake up the ATTN event handler */
32426947304SEvan Yan cv_signal(&slot_p->hs_attn_btn_cv);
32526947304SEvan Yan }
32626947304SEvan Yan
32726947304SEvan Yan /* check for power fault interrupt */
32826947304SEvan Yan if (status & PCIE_SLOTSTS_PWR_FAULT_DETECTED) {
32926947304SEvan Yan
33026947304SEvan Yan PCIE_DBG("pciehpc_intr(): POWER FAULT interrupt received"
33126947304SEvan Yan " on slot %d\n", slot_p->hs_phy_slot_num);
33226947304SEvan Yan control = pciehpc_reg_get16(ctrl_p,
33326947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
33426947304SEvan Yan
33526947304SEvan Yan if (control & PCIE_SLOTCTL_PWR_FAULT_EN) {
33626947304SEvan Yan slot_p->hs_condition = AP_COND_FAILED;
33726947304SEvan Yan
33826947304SEvan Yan /* disable power fault detction interrupt */
33926947304SEvan Yan pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
34026947304SEvan Yan PCIE_SLOTCTL, control & ~PCIE_SLOTCTL_PWR_FAULT_EN);
34126947304SEvan Yan
342*80dc702dSColin Zou - Sun Microsystems - Beijing China pciehpc_handle_power_fault(dip);
34326947304SEvan Yan }
34426947304SEvan Yan }
34526947304SEvan Yan
34626947304SEvan Yan /* check for MRL SENSOR CHANGED interrupt */
34726947304SEvan Yan if (status & PCIE_SLOTSTS_MRL_SENSOR_CHANGED) {
34826947304SEvan Yan /* For now (phase-I), no action is taken on this event */
34926947304SEvan Yan PCIE_DBG("pciehpc_intr(): MRL SENSOR CHANGED interrupt received"
35026947304SEvan Yan " on slot %d\n", slot_p->hs_phy_slot_num);
35126947304SEvan Yan }
35226947304SEvan Yan
35326947304SEvan Yan /* check for PRESENCE CHANGED interrupt */
35426947304SEvan Yan if (status & PCIE_SLOTSTS_PRESENCE_CHANGED) {
35526947304SEvan Yan
35626947304SEvan Yan PCIE_DBG("pciehpc_intr(): PRESENCE CHANGED interrupt received"
35726947304SEvan Yan " on slot %d\n", slot_p->hs_phy_slot_num);
35826947304SEvan Yan
35926947304SEvan Yan if (status & PCIE_SLOTSTS_PRESENCE_DETECTED) {
36026947304SEvan Yan /*
36126947304SEvan Yan * card is inserted into the slot, ask DDI Hotplug
36226947304SEvan Yan * framework to change state to Present.
36326947304SEvan Yan */
36470f83219SEvan Yan cmn_err(CE_NOTE, "pciehpc (%s%d): card is inserted"
36570f83219SEvan Yan " in the slot %s",
36670f83219SEvan Yan ddi_driver_name(dip),
36770f83219SEvan Yan ddi_get_instance(dip),
36870f83219SEvan Yan slot_p->hs_info.cn_name);
36970f83219SEvan Yan
37026947304SEvan Yan (void) ndi_hp_state_change_req(dip,
37126947304SEvan Yan slot_p->hs_info.cn_name,
37226947304SEvan Yan DDI_HP_CN_STATE_PRESENT,
37326947304SEvan Yan DDI_HP_REQ_ASYNC);
37426947304SEvan Yan } else { /* card is removed from the slot */
37526947304SEvan Yan cmn_err(CE_NOTE, "pciehpc (%s%d): card is removed"
37626947304SEvan Yan " from the slot %s",
37726947304SEvan Yan ddi_driver_name(dip),
37826947304SEvan Yan ddi_get_instance(dip),
37926947304SEvan Yan slot_p->hs_info.cn_name);
38026947304SEvan Yan
38126947304SEvan Yan if (slot_p->hs_info.cn_state ==
38226947304SEvan Yan DDI_HP_CN_STATE_ENABLED) {
38326947304SEvan Yan /* Card is removed when slot is enabled */
38426947304SEvan Yan slot_p->hs_condition = AP_COND_FAILED;
38526947304SEvan Yan } else {
38626947304SEvan Yan slot_p->hs_condition = AP_COND_UNKNOWN;
38726947304SEvan Yan }
38826947304SEvan Yan /* make sure to disable power fault detction intr */
38926947304SEvan Yan control = pciehpc_reg_get16(ctrl_p,
39026947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
39126947304SEvan Yan
39226947304SEvan Yan if (control & PCIE_SLOTCTL_PWR_FAULT_EN)
39326947304SEvan Yan pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
39426947304SEvan Yan PCIE_SLOTCTL,
39526947304SEvan Yan control & ~PCIE_SLOTCTL_PWR_FAULT_EN);
39626947304SEvan Yan
39726947304SEvan Yan /*
39826947304SEvan Yan * Ask DDI Hotplug framework to change state to Empty
39926947304SEvan Yan */
40026947304SEvan Yan (void) ndi_hp_state_change_req(dip,
40126947304SEvan Yan slot_p->hs_info.cn_name,
40226947304SEvan Yan DDI_HP_CN_STATE_EMPTY,
40326947304SEvan Yan DDI_HP_REQ_ASYNC);
40426947304SEvan Yan }
40526947304SEvan Yan }
40626947304SEvan Yan
40726947304SEvan Yan /* check for DLL state changed interrupt */
40826947304SEvan Yan if (ctrl_p->hc_dll_active_rep &&
40926947304SEvan Yan (status & PCIE_SLOTSTS_DLL_STATE_CHANGED)) {
41026947304SEvan Yan PCIE_DBG("pciehpc_intr(): DLL STATE CHANGED interrupt received"
41126947304SEvan Yan " on slot %d\n", slot_p->hs_phy_slot_num);
41226947304SEvan Yan
41326947304SEvan Yan cv_signal(&slot_p->hs_dll_active_cv);
41426947304SEvan Yan }
41526947304SEvan Yan
41626947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex);
41726947304SEvan Yan
41826947304SEvan Yan return (DDI_INTR_CLAIMED);
41926947304SEvan Yan }
42026947304SEvan Yan
42126947304SEvan Yan /*
42226947304SEvan Yan * Handle hotplug commands
42326947304SEvan Yan *
42426947304SEvan Yan * Note: This function is called by DDI HP framework at kernel context only
42526947304SEvan Yan */
42626947304SEvan Yan /* ARGSUSED */
42726947304SEvan Yan int
pciehpc_hp_ops(dev_info_t * dip,char * cn_name,ddi_hp_op_t op,void * arg,void * result)42826947304SEvan Yan pciehpc_hp_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op,
42926947304SEvan Yan void *arg, void *result)
43026947304SEvan Yan {
43126947304SEvan Yan pcie_hp_ctrl_t *ctrl_p;
43226947304SEvan Yan pcie_hp_slot_t *slot_p;
43326947304SEvan Yan int ret = DDI_SUCCESS;
43426947304SEvan Yan
43526947304SEvan Yan PCIE_DBG("pciehpc_hp_ops: dip=%p cn_name=%s op=%x arg=%p\n",
43626947304SEvan Yan dip, cn_name, op, arg);
43726947304SEvan Yan
43826947304SEvan Yan if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
43926947304SEvan Yan return (DDI_FAILURE);
44026947304SEvan Yan
44126947304SEvan Yan slot_p = ctrl_p->hc_slots[0];
44226947304SEvan Yan
44326947304SEvan Yan if (strcmp(cn_name, slot_p->hs_info.cn_name) != 0)
44426947304SEvan Yan return (DDI_EINVAL);
44526947304SEvan Yan
44626947304SEvan Yan switch (op) {
44726947304SEvan Yan case DDI_HPOP_CN_GET_STATE:
44826947304SEvan Yan {
44926947304SEvan Yan mutex_enter(&slot_p->hs_ctrl->hc_mutex);
45026947304SEvan Yan
45126947304SEvan Yan /* get the current slot state */
45226947304SEvan Yan pciehpc_get_slot_state(slot_p);
45326947304SEvan Yan
45426947304SEvan Yan *((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state;
45526947304SEvan Yan
45626947304SEvan Yan mutex_exit(&slot_p->hs_ctrl->hc_mutex);
45726947304SEvan Yan break;
45826947304SEvan Yan }
45926947304SEvan Yan case DDI_HPOP_CN_CHANGE_STATE:
46026947304SEvan Yan {
46126947304SEvan Yan ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg;
46226947304SEvan Yan
46326947304SEvan Yan mutex_enter(&slot_p->hs_ctrl->hc_mutex);
46426947304SEvan Yan
46526947304SEvan Yan ret = pciehpc_change_slot_state(slot_p, target_state);
46626947304SEvan Yan *(ddi_hp_cn_state_t *)result = slot_p->hs_info.cn_state;
46726947304SEvan Yan
46826947304SEvan Yan mutex_exit(&slot_p->hs_ctrl->hc_mutex);
46926947304SEvan Yan break;
47026947304SEvan Yan }
47126947304SEvan Yan case DDI_HPOP_CN_PROBE:
47226947304SEvan Yan
47326947304SEvan Yan ret = pciehpc_slot_probe(slot_p);
47426947304SEvan Yan
47526947304SEvan Yan break;
47626947304SEvan Yan case DDI_HPOP_CN_UNPROBE:
47726947304SEvan Yan ret = pciehpc_slot_unprobe(slot_p);
47826947304SEvan Yan
47926947304SEvan Yan break;
48026947304SEvan Yan case DDI_HPOP_CN_GET_PROPERTY:
48126947304SEvan Yan ret = pciehpc_slot_get_property(slot_p,
48226947304SEvan Yan (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
48326947304SEvan Yan break;
48426947304SEvan Yan case DDI_HPOP_CN_SET_PROPERTY:
48526947304SEvan Yan ret = pciehpc_slot_set_property(slot_p,
48626947304SEvan Yan (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
48726947304SEvan Yan break;
48826947304SEvan Yan default:
48926947304SEvan Yan ret = DDI_ENOTSUP;
49026947304SEvan Yan break;
49126947304SEvan Yan }
49226947304SEvan Yan
49326947304SEvan Yan return (ret);
49426947304SEvan Yan }
49526947304SEvan Yan
49626947304SEvan Yan /*
49726947304SEvan Yan * Get the current state of the slot from the hw.
49826947304SEvan Yan *
49926947304SEvan Yan * The slot state should have been initialized before this function gets called.
50026947304SEvan Yan */
50126947304SEvan Yan void
pciehpc_get_slot_state(pcie_hp_slot_t * slot_p)50226947304SEvan Yan pciehpc_get_slot_state(pcie_hp_slot_t *slot_p)
50326947304SEvan Yan {
50426947304SEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
50526947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
50626947304SEvan Yan uint16_t control, status;
50726947304SEvan Yan ddi_hp_cn_state_t curr_state = slot_p->hs_info.cn_state;
50826947304SEvan Yan
50926947304SEvan Yan /* read the Slot Control Register */
51026947304SEvan Yan control = pciehpc_reg_get16(ctrl_p,
51126947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
51226947304SEvan Yan
51326947304SEvan Yan slot_p->hs_fault_led_state = PCIE_HP_LED_OFF; /* no fault led */
51426947304SEvan Yan slot_p->hs_active_led_state = PCIE_HP_LED_OFF; /* no active led */
51526947304SEvan Yan
51626947304SEvan Yan /* read the current Slot Status Register */
51726947304SEvan Yan status = pciehpc_reg_get16(ctrl_p,
51826947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
51926947304SEvan Yan
52026947304SEvan Yan /* get POWER led state */
52126947304SEvan Yan slot_p->hs_power_led_state =
52226947304SEvan Yan pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control));
52326947304SEvan Yan
52426947304SEvan Yan /* get ATTN led state */
52526947304SEvan Yan slot_p->hs_attn_led_state =
52626947304SEvan Yan pciehpc_led_state_to_hpc(pcie_slotctl_attn_indicator_get(control));
52726947304SEvan Yan
52826947304SEvan Yan if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
52926947304SEvan Yan /* no device present; slot is empty */
53026947304SEvan Yan slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY;
53126947304SEvan Yan
53226947304SEvan Yan return;
53326947304SEvan Yan }
53426947304SEvan Yan
53526947304SEvan Yan /* device is present */
53626947304SEvan Yan slot_p->hs_info.cn_state = DDI_HP_CN_STATE_PRESENT;
53726947304SEvan Yan
53826947304SEvan Yan if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) {
53926947304SEvan Yan /*
54026947304SEvan Yan * Device is powered on. Set to "ENABLED" state (skip
54126947304SEvan Yan * POWERED state) because there is not a explicit "enable"
54226947304SEvan Yan * action exists for PCIe.
54326947304SEvan Yan * If it is already in "POWERED" state, then keep it until
54426947304SEvan Yan * user explicitly change it to other states.
54526947304SEvan Yan */
54626947304SEvan Yan if (curr_state == DDI_HP_CN_STATE_POWERED) {
54726947304SEvan Yan slot_p->hs_info.cn_state = curr_state;
54826947304SEvan Yan } else {
54926947304SEvan Yan slot_p->hs_info.cn_state = DDI_HP_CN_STATE_ENABLED;
55026947304SEvan Yan }
55126947304SEvan Yan }
55226947304SEvan Yan }
55326947304SEvan Yan
55426947304SEvan Yan /*
55526947304SEvan Yan * setup slot name/slot-number info.
55626947304SEvan Yan */
55726947304SEvan Yan void
pciehpc_set_slot_name(pcie_hp_ctrl_t * ctrl_p)55826947304SEvan Yan pciehpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p)
55926947304SEvan Yan {
56026947304SEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
56126947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
56226947304SEvan Yan uchar_t *slotname_data;
56326947304SEvan Yan int *slotnum;
56426947304SEvan Yan uint_t count;
56526947304SEvan Yan int len;
56626947304SEvan Yan int invalid_slotnum = 0;
56726947304SEvan Yan uint32_t slot_capabilities;
56826947304SEvan Yan
56926947304SEvan Yan if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ctrl_p->hc_dip,
57026947304SEvan Yan DDI_PROP_DONTPASS, "physical-slot#", &slotnum, &count) ==
57126947304SEvan Yan DDI_PROP_SUCCESS) {
57226947304SEvan Yan slot_p->hs_phy_slot_num = slotnum[0];
57326947304SEvan Yan ddi_prop_free(slotnum);
57426947304SEvan Yan } else {
57526947304SEvan Yan slot_capabilities = pciehpc_reg_get32(ctrl_p,
57626947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCAP);
57726947304SEvan Yan slot_p->hs_phy_slot_num =
57826947304SEvan Yan PCIE_SLOTCAP_PHY_SLOT_NUM(slot_capabilities);
57926947304SEvan Yan }
58026947304SEvan Yan
58126947304SEvan Yan /* platform may not have initialized it */
58226947304SEvan Yan if (!slot_p->hs_phy_slot_num) {
58326947304SEvan Yan PCIE_DBG("%s#%d: Invalid slot number!\n",
58426947304SEvan Yan ddi_driver_name(ctrl_p->hc_dip),
58526947304SEvan Yan ddi_get_instance(ctrl_p->hc_dip));
58626947304SEvan Yan slot_p->hs_phy_slot_num = pciehpc_reg_get8(ctrl_p,
58726947304SEvan Yan PCI_BCNF_SECBUS);
58826947304SEvan Yan invalid_slotnum = 1;
58926947304SEvan Yan }
59026947304SEvan Yan slot_p->hs_info.cn_num = slot_p->hs_phy_slot_num;
59126947304SEvan Yan slot_p->hs_info.cn_num_dpd_on = DDI_HP_CN_NUM_NONE;
59226947304SEvan Yan
59326947304SEvan Yan /*
59426947304SEvan Yan * construct the slot_name:
59526947304SEvan Yan * if "slot-names" property exists then use that name
59626947304SEvan Yan * else if valid slot number exists then it is "pcie<slot-num>".
59726947304SEvan Yan * else it will be "pcie<sec-bus-number>dev0"
59826947304SEvan Yan */
59926947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, ctrl_p->hc_dip, DDI_PROP_DONTPASS,
60026947304SEvan Yan "slot-names", (caddr_t)&slotname_data, &len) == DDI_PROP_SUCCESS) {
60126947304SEvan Yan char tmp_name[256];
60226947304SEvan Yan
60326947304SEvan Yan /*
60426947304SEvan Yan * Note: for PCI-E slots, the device number is always 0 so the
60526947304SEvan Yan * first (and only) string is the slot name for this slot.
60626947304SEvan Yan */
60726947304SEvan Yan (void) snprintf(tmp_name, sizeof (tmp_name),
60826947304SEvan Yan (char *)slotname_data + 4);
60926947304SEvan Yan slot_p->hs_info.cn_name = ddi_strdup(tmp_name, KM_SLEEP);
61026947304SEvan Yan kmem_free(slotname_data, len);
61126947304SEvan Yan } else {
61226947304SEvan Yan if (invalid_slotnum) {
61326947304SEvan Yan /* use device number ie. 0 */
61426947304SEvan Yan slot_p->hs_info.cn_name = ddi_strdup("pcie0",
61526947304SEvan Yan KM_SLEEP);
61626947304SEvan Yan } else {
61726947304SEvan Yan char tmp_name[256];
61826947304SEvan Yan
61926947304SEvan Yan (void) snprintf(tmp_name, sizeof (tmp_name), "pcie%d",
62026947304SEvan Yan slot_p->hs_phy_slot_num);
62126947304SEvan Yan slot_p->hs_info.cn_name = ddi_strdup(tmp_name,
62226947304SEvan Yan KM_SLEEP);
62326947304SEvan Yan }
62426947304SEvan Yan }
62526947304SEvan Yan }
62626947304SEvan Yan
62726947304SEvan Yan /*
62826947304SEvan Yan * Read/Write access to HPC registers. If platform nexus has non-standard
62926947304SEvan Yan * HPC access mechanism then regops functions are used to do reads/writes.
63026947304SEvan Yan */
63126947304SEvan Yan uint8_t
pciehpc_reg_get8(pcie_hp_ctrl_t * ctrl_p,uint_t off)63226947304SEvan Yan pciehpc_reg_get8(pcie_hp_ctrl_t *ctrl_p, uint_t off)
63326947304SEvan Yan {
63426947304SEvan Yan if (ctrl_p->hc_regops.get != NULL) {
63526947304SEvan Yan return ((uint8_t)ctrl_p->hc_regops.get(
63626947304SEvan Yan ctrl_p->hc_regops.cookie, (off_t)off));
63726947304SEvan Yan } else {
63826947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
63926947304SEvan Yan
64026947304SEvan Yan return (pci_config_get8(bus_p->bus_cfg_hdl, off));
64126947304SEvan Yan }
64226947304SEvan Yan }
64326947304SEvan Yan
64426947304SEvan Yan uint16_t
pciehpc_reg_get16(pcie_hp_ctrl_t * ctrl_p,uint_t off)64526947304SEvan Yan pciehpc_reg_get16(pcie_hp_ctrl_t *ctrl_p, uint_t off)
64626947304SEvan Yan {
64726947304SEvan Yan if (ctrl_p->hc_regops.get != NULL) {
64826947304SEvan Yan return ((uint16_t)ctrl_p->hc_regops.get(
64926947304SEvan Yan ctrl_p->hc_regops.cookie, (off_t)off));
65026947304SEvan Yan } else {
65126947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
65226947304SEvan Yan
65326947304SEvan Yan return (pci_config_get16(bus_p->bus_cfg_hdl, off));
65426947304SEvan Yan }
65526947304SEvan Yan }
65626947304SEvan Yan
65726947304SEvan Yan uint32_t
pciehpc_reg_get32(pcie_hp_ctrl_t * ctrl_p,uint_t off)65826947304SEvan Yan pciehpc_reg_get32(pcie_hp_ctrl_t *ctrl_p, uint_t off)
65926947304SEvan Yan {
66026947304SEvan Yan if (ctrl_p->hc_regops.get != NULL) {
66126947304SEvan Yan return ((uint32_t)ctrl_p->hc_regops.get(
66226947304SEvan Yan ctrl_p->hc_regops.cookie, (off_t)off));
66326947304SEvan Yan } else {
66426947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
66526947304SEvan Yan
66626947304SEvan Yan return (pci_config_get32(bus_p->bus_cfg_hdl, off));
66726947304SEvan Yan }
66826947304SEvan Yan }
66926947304SEvan Yan
67026947304SEvan Yan void
pciehpc_reg_put8(pcie_hp_ctrl_t * ctrl_p,uint_t off,uint8_t val)67126947304SEvan Yan pciehpc_reg_put8(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint8_t val)
67226947304SEvan Yan {
67326947304SEvan Yan if (ctrl_p->hc_regops.put != NULL) {
67426947304SEvan Yan ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
67526947304SEvan Yan (off_t)off, (uint_t)val);
67626947304SEvan Yan } else {
67726947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
67826947304SEvan Yan
67926947304SEvan Yan pci_config_put8(bus_p->bus_cfg_hdl, off, val);
68026947304SEvan Yan }
68126947304SEvan Yan }
68226947304SEvan Yan
68326947304SEvan Yan void
pciehpc_reg_put16(pcie_hp_ctrl_t * ctrl_p,uint_t off,uint16_t val)68426947304SEvan Yan pciehpc_reg_put16(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint16_t val)
68526947304SEvan Yan {
68626947304SEvan Yan if (ctrl_p->hc_regops.put != NULL) {
68726947304SEvan Yan ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
68826947304SEvan Yan (off_t)off, (uint_t)val);
68926947304SEvan Yan } else {
69026947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
69126947304SEvan Yan
69226947304SEvan Yan pci_config_put16(bus_p->bus_cfg_hdl, off, val);
69326947304SEvan Yan }
69426947304SEvan Yan }
69526947304SEvan Yan
69626947304SEvan Yan void
pciehpc_reg_put32(pcie_hp_ctrl_t * ctrl_p,uint_t off,uint32_t val)69726947304SEvan Yan pciehpc_reg_put32(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint32_t val)
69826947304SEvan Yan {
69926947304SEvan Yan if (ctrl_p->hc_regops.put != NULL) {
70026947304SEvan Yan ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
70126947304SEvan Yan (off_t)off, (uint_t)val);
70226947304SEvan Yan } else {
70326947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
70426947304SEvan Yan
70526947304SEvan Yan pci_config_put32(bus_p->bus_cfg_hdl, off, val);
70626947304SEvan Yan }
70726947304SEvan Yan }
70826947304SEvan Yan
70926947304SEvan Yan /*
71026947304SEvan Yan * ************************************************************************
71126947304SEvan Yan * *** Local functions (called within this file)
71226947304SEvan Yan * *** PCIe Native Hotplug mode specific functions
71326947304SEvan Yan * ************************************************************************
71426947304SEvan Yan */
71526947304SEvan Yan
71626947304SEvan Yan /*
71726947304SEvan Yan * Initialize HPC hardware, install interrupt handler, etc. It doesn't
71826947304SEvan Yan * enable hot plug interrupts.
71926947304SEvan Yan *
72026947304SEvan Yan * (Note: It is called only from pciehpc_init().)
72126947304SEvan Yan */
72226947304SEvan Yan static int
pciehpc_hpc_init(pcie_hp_ctrl_t * ctrl_p)72326947304SEvan Yan pciehpc_hpc_init(pcie_hp_ctrl_t *ctrl_p)
72426947304SEvan Yan {
72526947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
72626947304SEvan Yan uint16_t reg;
72726947304SEvan Yan
72826947304SEvan Yan /* read the Slot Control Register */
72926947304SEvan Yan reg = pciehpc_reg_get16(ctrl_p,
73026947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
73126947304SEvan Yan
73226947304SEvan Yan /* disable all interrupts */
73326947304SEvan Yan reg &= ~(PCIE_SLOTCTL_INTR_MASK);
73426947304SEvan Yan pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
73526947304SEvan Yan PCIE_SLOTCTL, reg);
73626947304SEvan Yan
73726947304SEvan Yan /* clear any interrupt status bits */
73826947304SEvan Yan reg = pciehpc_reg_get16(ctrl_p,
73926947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
74026947304SEvan Yan pciehpc_reg_put16(ctrl_p,
74126947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
74226947304SEvan Yan
74326947304SEvan Yan return (DDI_SUCCESS);
74426947304SEvan Yan }
74526947304SEvan Yan
74626947304SEvan Yan /*
74726947304SEvan Yan * Uninitialize HPC hardware, uninstall interrupt handler, etc.
74826947304SEvan Yan *
74926947304SEvan Yan * (Note: It is called only from pciehpc_uninit().)
75026947304SEvan Yan */
75126947304SEvan Yan static int
pciehpc_hpc_uninit(pcie_hp_ctrl_t * ctrl_p)75226947304SEvan Yan pciehpc_hpc_uninit(pcie_hp_ctrl_t *ctrl_p)
75326947304SEvan Yan {
75426947304SEvan Yan /* disable interrupts */
75526947304SEvan Yan (void) pciehpc_disable_intr(ctrl_p);
75626947304SEvan Yan
75726947304SEvan Yan return (DDI_SUCCESS);
75826947304SEvan Yan }
75926947304SEvan Yan
76026947304SEvan Yan /*
76126947304SEvan Yan * Setup slot information for use with DDI HP framework.
76226947304SEvan Yan */
76326947304SEvan Yan static int
pciehpc_slotinfo_init(pcie_hp_ctrl_t * ctrl_p)76426947304SEvan Yan pciehpc_slotinfo_init(pcie_hp_ctrl_t *ctrl_p)
76526947304SEvan Yan {
76626947304SEvan Yan uint32_t slot_capabilities, link_capabilities;
76726947304SEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
76826947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
76926947304SEvan Yan
77026947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex);
77126947304SEvan Yan /*
77226947304SEvan Yan * setup DDI HP framework slot information structure
77326947304SEvan Yan */
77426947304SEvan Yan slot_p->hs_device_num = 0;
77526947304SEvan Yan
77626947304SEvan Yan slot_p->hs_info.cn_type = DDI_HP_CN_TYPE_PCIE;
77726947304SEvan Yan slot_p->hs_info.cn_type_str = (ctrl_p->hc_regops.get == NULL) ?
77826947304SEvan Yan PCIE_NATIVE_HP_TYPE : PCIE_PROP_HP_TYPE;
77926947304SEvan Yan slot_p->hs_info.cn_child = NULL;
78026947304SEvan Yan
78126947304SEvan Yan slot_p->hs_minor =
78226947304SEvan Yan PCI_MINOR_NUM(ddi_get_instance(ctrl_p->hc_dip),
78326947304SEvan Yan slot_p->hs_device_num);
78426947304SEvan Yan slot_p->hs_condition = AP_COND_UNKNOWN;
78526947304SEvan Yan
78626947304SEvan Yan /* read Slot Capabilities Register */
78726947304SEvan Yan slot_capabilities = pciehpc_reg_get32(ctrl_p,
78826947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCAP);
78926947304SEvan Yan
79026947304SEvan Yan /* set slot-name/slot-number info */
79126947304SEvan Yan pciehpc_set_slot_name(ctrl_p);
79226947304SEvan Yan
79326947304SEvan Yan /* check if Attn Button present */
79426947304SEvan Yan ctrl_p->hc_has_attn = (slot_capabilities & PCIE_SLOTCAP_ATTN_BUTTON) ?
79526947304SEvan Yan B_TRUE : B_FALSE;
79626947304SEvan Yan
79726947304SEvan Yan /* check if Manual Retention Latch sensor present */
79826947304SEvan Yan ctrl_p->hc_has_mrl = (slot_capabilities & PCIE_SLOTCAP_MRL_SENSOR) ?
79926947304SEvan Yan B_TRUE : B_FALSE;
80026947304SEvan Yan
80126947304SEvan Yan /*
80226947304SEvan Yan * PCI-E version 1.1 defines EMI Lock Present bit
80326947304SEvan Yan * in Slot Capabilities register. Check for it.
80426947304SEvan Yan */
80526947304SEvan Yan ctrl_p->hc_has_emi_lock = (slot_capabilities &
80626947304SEvan Yan PCIE_SLOTCAP_EMI_LOCK_PRESENT) ? B_TRUE : B_FALSE;
80726947304SEvan Yan
80826947304SEvan Yan link_capabilities = pciehpc_reg_get32(ctrl_p,
80926947304SEvan Yan bus_p->bus_pcie_off + PCIE_LINKCAP);
81026947304SEvan Yan ctrl_p->hc_dll_active_rep = (link_capabilities &
81126947304SEvan Yan PCIE_LINKCAP_DLL_ACTIVE_REP_CAPABLE) ? B_TRUE : B_FALSE;
81226947304SEvan Yan if (ctrl_p->hc_dll_active_rep)
81326947304SEvan Yan cv_init(&slot_p->hs_dll_active_cv, NULL, CV_DRIVER, NULL);
81426947304SEvan Yan
81526947304SEvan Yan /* setup thread for handling ATTN button events */
81626947304SEvan Yan if (ctrl_p->hc_has_attn) {
81726947304SEvan Yan PCIE_DBG("pciehpc_slotinfo_init: setting up ATTN button event "
81826947304SEvan Yan "handler thread for slot %d\n", slot_p->hs_phy_slot_num);
81926947304SEvan Yan
82026947304SEvan Yan cv_init(&slot_p->hs_attn_btn_cv, NULL, CV_DRIVER, NULL);
82126947304SEvan Yan slot_p->hs_attn_btn_pending = B_FALSE;
82226947304SEvan Yan slot_p->hs_attn_btn_threadp = thread_create(NULL, 0,
82326947304SEvan Yan pciehpc_attn_btn_handler,
82426947304SEvan Yan (void *)ctrl_p, 0, &p0, TS_RUN, minclsyspri);
82526947304SEvan Yan slot_p->hs_attn_btn_thread_exit = B_FALSE;
82626947304SEvan Yan }
82726947304SEvan Yan
82826947304SEvan Yan /* get current slot state from the hw */
82926947304SEvan Yan slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY;
83026947304SEvan Yan pciehpc_get_slot_state(slot_p);
83126947304SEvan Yan if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_ENABLED)
83226947304SEvan Yan slot_p->hs_condition = AP_COND_OK;
83326947304SEvan Yan
83426947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex);
83526947304SEvan Yan
83626947304SEvan Yan return (DDI_SUCCESS);
83726947304SEvan Yan }
83826947304SEvan Yan
83926947304SEvan Yan /*ARGSUSED*/
84026947304SEvan Yan static int
pciehpc_slotinfo_uninit(pcie_hp_ctrl_t * ctrl_p)84126947304SEvan Yan pciehpc_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p)
84226947304SEvan Yan {
84326947304SEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
84426947304SEvan Yan
84526947304SEvan Yan if (slot_p->hs_attn_btn_threadp != NULL) {
84626947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex);
84726947304SEvan Yan slot_p->hs_attn_btn_thread_exit = B_TRUE;
84826947304SEvan Yan cv_signal(&slot_p->hs_attn_btn_cv);
84926947304SEvan Yan PCIE_DBG("pciehpc_slotinfo_uninit: "
85026947304SEvan Yan "waiting for ATTN thread exit\n");
85126947304SEvan Yan cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
85226947304SEvan Yan PCIE_DBG("pciehpc_slotinfo_uninit: ATTN thread exit\n");
85326947304SEvan Yan cv_destroy(&slot_p->hs_attn_btn_cv);
85426947304SEvan Yan slot_p->hs_attn_btn_threadp = NULL;
85526947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex);
85626947304SEvan Yan }
85726947304SEvan Yan
85826947304SEvan Yan if (ctrl_p->hc_dll_active_rep)
85926947304SEvan Yan cv_destroy(&slot_p->hs_dll_active_cv);
86026947304SEvan Yan if (slot_p->hs_info.cn_name)
86126947304SEvan Yan kmem_free(slot_p->hs_info.cn_name,
86226947304SEvan Yan strlen(slot_p->hs_info.cn_name) + 1);
86326947304SEvan Yan
86426947304SEvan Yan return (DDI_SUCCESS);
86526947304SEvan Yan }
86626947304SEvan Yan
86726947304SEvan Yan /*
86826947304SEvan Yan * Enable hot plug interrupts.
86926947304SEvan Yan * Note: this is only for Native hot plug mode.
87026947304SEvan Yan */
87126947304SEvan Yan static int
pciehpc_enable_intr(pcie_hp_ctrl_t * ctrl_p)87226947304SEvan Yan pciehpc_enable_intr(pcie_hp_ctrl_t *ctrl_p)
87326947304SEvan Yan {
87426947304SEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
87526947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
87626947304SEvan Yan uint16_t reg;
87726947304SEvan Yan
87826947304SEvan Yan /* clear any interrupt status bits */
87926947304SEvan Yan reg = pciehpc_reg_get16(ctrl_p,
88026947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
88126947304SEvan Yan pciehpc_reg_put16(ctrl_p,
88226947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
88326947304SEvan Yan
88426947304SEvan Yan /* read the Slot Control Register */
88526947304SEvan Yan reg = pciehpc_reg_get16(ctrl_p,
88626947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
88726947304SEvan Yan
88826947304SEvan Yan /*
88926947304SEvan Yan * enable interrupts: power fault detection interrupt is enabled
89026947304SEvan Yan * only when the slot is powered ON
89126947304SEvan Yan */
89226947304SEvan Yan if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
89326947304SEvan Yan pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
89426947304SEvan Yan PCIE_SLOTCTL, reg | PCIE_SLOTCTL_INTR_MASK);
89526947304SEvan Yan else
89626947304SEvan Yan pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
89726947304SEvan Yan PCIE_SLOTCTL, reg | (PCIE_SLOTCTL_INTR_MASK &
89826947304SEvan Yan ~PCIE_SLOTCTL_PWR_FAULT_EN));
89926947304SEvan Yan
90026947304SEvan Yan return (DDI_SUCCESS);
90126947304SEvan Yan }
90226947304SEvan Yan
90326947304SEvan Yan /*
90426947304SEvan Yan * Disable hot plug interrupts.
90526947304SEvan Yan * Note: this is only for Native hot plug mode.
90626947304SEvan Yan */
90726947304SEvan Yan static int
pciehpc_disable_intr(pcie_hp_ctrl_t * ctrl_p)90826947304SEvan Yan pciehpc_disable_intr(pcie_hp_ctrl_t *ctrl_p)
90926947304SEvan Yan {
91026947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
91126947304SEvan Yan uint16_t reg;
91226947304SEvan Yan
91326947304SEvan Yan /* read the Slot Control Register */
91426947304SEvan Yan reg = pciehpc_reg_get16(ctrl_p,
91526947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
91626947304SEvan Yan
91726947304SEvan Yan /* disable all interrupts */
91826947304SEvan Yan reg &= ~(PCIE_SLOTCTL_INTR_MASK);
91926947304SEvan Yan pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTCTL, reg);
92026947304SEvan Yan
92126947304SEvan Yan /* clear any interrupt status bits */
92226947304SEvan Yan reg = pciehpc_reg_get16(ctrl_p,
92326947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
92426947304SEvan Yan pciehpc_reg_put16(ctrl_p,
92526947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
92626947304SEvan Yan
92726947304SEvan Yan return (DDI_SUCCESS);
92826947304SEvan Yan }
92926947304SEvan Yan
93026947304SEvan Yan /*
93126947304SEvan Yan * Allocate a new hotplug controller and slot structures for HPC
93226947304SEvan Yan * associated with this dip.
93326947304SEvan Yan */
93426947304SEvan Yan static pcie_hp_ctrl_t *
pciehpc_create_controller(dev_info_t * dip)93526947304SEvan Yan pciehpc_create_controller(dev_info_t *dip)
93626947304SEvan Yan {
93726947304SEvan Yan pcie_hp_ctrl_t *ctrl_p;
93826947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
93926947304SEvan Yan
94026947304SEvan Yan ctrl_p = kmem_zalloc(sizeof (pcie_hp_ctrl_t), KM_SLEEP);
94126947304SEvan Yan ctrl_p->hc_dip = dip;
94226947304SEvan Yan
94326947304SEvan Yan /* Allocate a new slot structure. */
94426947304SEvan Yan ctrl_p->hc_slots[0] = kmem_zalloc(sizeof (pcie_hp_slot_t), KM_SLEEP);
94526947304SEvan Yan ctrl_p->hc_slots[0]->hs_num = 0;
94626947304SEvan Yan ctrl_p->hc_slots[0]->hs_ctrl = ctrl_p;
94726947304SEvan Yan
94826947304SEvan Yan /* Initialize the interrupt mutex */
94926947304SEvan Yan mutex_init(&ctrl_p->hc_mutex, NULL, MUTEX_DRIVER,
95026947304SEvan Yan (void *)PCIE_INTR_PRI);
95126947304SEvan Yan
95226947304SEvan Yan /* Initialize synchronization conditional variable */
95326947304SEvan Yan cv_init(&ctrl_p->hc_cmd_comp_cv, NULL, CV_DRIVER, NULL);
95426947304SEvan Yan ctrl_p->hc_cmd_pending = B_FALSE;
95526947304SEvan Yan
95626947304SEvan Yan bus_p->bus_hp_curr_mode = PCIE_NATIVE_HP_MODE;
95726947304SEvan Yan PCIE_SET_HP_CTRL(dip, ctrl_p);
95826947304SEvan Yan
95926947304SEvan Yan return (ctrl_p);
96026947304SEvan Yan }
96126947304SEvan Yan
96226947304SEvan Yan /*
96326947304SEvan Yan * Remove the HPC controller and slot structures
96426947304SEvan Yan */
96526947304SEvan Yan static void
pciehpc_destroy_controller(dev_info_t * dip)96626947304SEvan Yan pciehpc_destroy_controller(dev_info_t *dip)
96726947304SEvan Yan {
96826947304SEvan Yan pcie_hp_ctrl_t *ctrl_p;
96926947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
97026947304SEvan Yan
97126947304SEvan Yan /* get the soft state structure for this dip */
97226947304SEvan Yan if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
97326947304SEvan Yan return;
97426947304SEvan Yan
97526947304SEvan Yan PCIE_SET_HP_CTRL(dip, NULL);
97626947304SEvan Yan bus_p->bus_hp_curr_mode = PCIE_NONE_HP_MODE;
97726947304SEvan Yan
97826947304SEvan Yan mutex_destroy(&ctrl_p->hc_mutex);
97926947304SEvan Yan cv_destroy(&ctrl_p->hc_cmd_comp_cv);
98026947304SEvan Yan kmem_free(ctrl_p->hc_slots[0], sizeof (pcie_hp_slot_t));
98126947304SEvan Yan kmem_free(ctrl_p, sizeof (pcie_hp_ctrl_t));
98226947304SEvan Yan }
98326947304SEvan Yan
98426947304SEvan Yan /*
98526947304SEvan Yan * Register the PCI-E hot plug slot with DDI HP framework.
98626947304SEvan Yan */
98726947304SEvan Yan static int
pciehpc_register_slot(pcie_hp_ctrl_t * ctrl_p)98826947304SEvan Yan pciehpc_register_slot(pcie_hp_ctrl_t *ctrl_p)
98926947304SEvan Yan {
99026947304SEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
99126947304SEvan Yan dev_info_t *dip = ctrl_p->hc_dip;
99226947304SEvan Yan
99326947304SEvan Yan /* register the slot with DDI HP framework */
99426947304SEvan Yan if (ndi_hp_register(dip, &slot_p->hs_info) != NDI_SUCCESS) {
99526947304SEvan Yan PCIE_DBG("pciehpc_register_slot() failed to register slot %d\n",
99626947304SEvan Yan slot_p->hs_phy_slot_num);
99726947304SEvan Yan return (DDI_FAILURE);
99826947304SEvan Yan }
99926947304SEvan Yan
100026947304SEvan Yan pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip),
100126947304SEvan Yan slot_p->hs_minor), slot_p->hs_device_num);
100226947304SEvan Yan
100326947304SEvan Yan PCIE_DBG("pciehpc_register_slot(): registered slot %d\n",
100426947304SEvan Yan slot_p->hs_phy_slot_num);
100526947304SEvan Yan
100626947304SEvan Yan return (DDI_SUCCESS);
100726947304SEvan Yan }
100826947304SEvan Yan
100926947304SEvan Yan /*
101026947304SEvan Yan * Unregister the PCI-E hot plug slot from DDI HP framework.
101126947304SEvan Yan */
101226947304SEvan Yan static int
pciehpc_unregister_slot(pcie_hp_ctrl_t * ctrl_p)101326947304SEvan Yan pciehpc_unregister_slot(pcie_hp_ctrl_t *ctrl_p)
101426947304SEvan Yan {
101526947304SEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
101626947304SEvan Yan dev_info_t *dip = ctrl_p->hc_dip;
101726947304SEvan Yan
101826947304SEvan Yan pcie_hp_delete_occupant_props(dip, makedevice(ddi_driver_major(dip),
101926947304SEvan Yan slot_p->hs_minor));
102026947304SEvan Yan
102126947304SEvan Yan /* unregister the slot with DDI HP framework */
102226947304SEvan Yan if (ndi_hp_unregister(dip, slot_p->hs_info.cn_name) != NDI_SUCCESS) {
102326947304SEvan Yan PCIE_DBG("pciehpc_unregister_slot() "
102426947304SEvan Yan "failed to unregister slot %d\n", slot_p->hs_phy_slot_num);
102526947304SEvan Yan return (DDI_FAILURE);
102626947304SEvan Yan }
102726947304SEvan Yan
102826947304SEvan Yan PCIE_DBG("pciehpc_unregister_slot(): unregistered slot %d\n",
102926947304SEvan Yan slot_p->hs_phy_slot_num);
103026947304SEvan Yan
103126947304SEvan Yan return (DDI_SUCCESS);
103226947304SEvan Yan }
103326947304SEvan Yan
103426947304SEvan Yan /*
103526947304SEvan Yan * pciehpc_slot_poweron()
103626947304SEvan Yan *
103726947304SEvan Yan * Poweron/Enable the slot.
103826947304SEvan Yan *
103926947304SEvan Yan * Note: This function is called by DDI HP framework at kernel context only
104026947304SEvan Yan */
104126947304SEvan Yan /*ARGSUSED*/
104226947304SEvan Yan static int
pciehpc_slot_poweron(pcie_hp_slot_t * slot_p,ddi_hp_cn_state_t * result)104326947304SEvan Yan pciehpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result)
104426947304SEvan Yan {
104526947304SEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
104626947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
104726947304SEvan Yan uint16_t status, control;
104826947304SEvan Yan
104926947304SEvan Yan ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
105026947304SEvan Yan
105126947304SEvan Yan /* get the current state of the slot */
105226947304SEvan Yan pciehpc_get_slot_state(slot_p);
105326947304SEvan Yan
105426947304SEvan Yan /* check if the slot is already in the 'enabled' state */
105526947304SEvan Yan if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) {
105626947304SEvan Yan /* slot is already in the 'enabled' state */
105726947304SEvan Yan PCIE_DBG("pciehpc_slot_poweron() slot %d already enabled\n",
105826947304SEvan Yan slot_p->hs_phy_slot_num);
105926947304SEvan Yan
106026947304SEvan Yan *result = slot_p->hs_info.cn_state;
106126947304SEvan Yan return (DDI_SUCCESS);
106226947304SEvan Yan }
106326947304SEvan Yan
106426947304SEvan Yan /* read the Slot Status Register */
106526947304SEvan Yan status = pciehpc_reg_get16(ctrl_p,
106626947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
106726947304SEvan Yan
106826947304SEvan Yan /* make sure the MRL switch is closed if present */
106926947304SEvan Yan if ((ctrl_p->hc_has_mrl) && (status & PCIE_SLOTSTS_MRL_SENSOR_OPEN)) {
107026947304SEvan Yan /* MRL switch is open */
107126947304SEvan Yan cmn_err(CE_WARN, "MRL switch is open on slot %d\n",
107226947304SEvan Yan slot_p->hs_phy_slot_num);
107326947304SEvan Yan goto cleanup;
107426947304SEvan Yan }
107526947304SEvan Yan
107626947304SEvan Yan /* make sure the slot has a device present */
107726947304SEvan Yan if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
107826947304SEvan Yan /* slot is empty */
107926947304SEvan Yan PCIE_DBG("slot %d is empty\n", slot_p->hs_phy_slot_num);
108026947304SEvan Yan goto cleanup;
108126947304SEvan Yan }
108226947304SEvan Yan
108326947304SEvan Yan /* get the current state of Slot Control Register */
108426947304SEvan Yan control = pciehpc_reg_get16(ctrl_p,
108526947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
108626947304SEvan Yan
108726947304SEvan Yan /*
108826947304SEvan Yan * Enable power to the slot involves:
108926947304SEvan Yan * 1. Set power LED to blink and ATTN led to OFF.
109026947304SEvan Yan * 2. Set power control ON in Slot Control Reigster and
109126947304SEvan Yan * wait for Command Completed Interrupt or 1 sec timeout.
109226947304SEvan Yan * 3. If Data Link Layer State Changed events are supported
109326947304SEvan Yan * then wait for the event to indicate Data Layer Link
109426947304SEvan Yan * is active. The time out value for this event is 1 second.
109526947304SEvan Yan * This is specified in PCI-E version 1.1.
109626947304SEvan Yan * 4. Set power LED to be ON.
109726947304SEvan Yan */
109826947304SEvan Yan
109926947304SEvan Yan /* 1. set power LED to blink & ATTN led to OFF */
110026947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
110126947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
110226947304SEvan Yan
110326947304SEvan Yan /* 2. set power control to ON */
110426947304SEvan Yan control = pciehpc_reg_get16(ctrl_p,
110526947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
110626947304SEvan Yan control &= ~PCIE_SLOTCTL_PWR_CONTROL;
110726947304SEvan Yan pciehpc_issue_hpc_command(ctrl_p, control);
110826947304SEvan Yan
110926947304SEvan Yan /* 3. wait for DLL State Change event, if it's supported */
111026947304SEvan Yan if (ctrl_p->hc_dll_active_rep) {
111126947304SEvan Yan status = pciehpc_reg_get16(ctrl_p,
111226947304SEvan Yan bus_p->bus_pcie_off + PCIE_LINKSTS);
111326947304SEvan Yan
111426947304SEvan Yan if (!(status & PCIE_LINKSTS_DLL_LINK_ACTIVE)) {
111526947304SEvan Yan /* wait 1 sec for the DLL State Changed event */
111626947304SEvan Yan (void) cv_timedwait(&slot_p->hs_dll_active_cv,
111726947304SEvan Yan &ctrl_p->hc_mutex,
111826947304SEvan Yan ddi_get_lbolt() +
111926947304SEvan Yan SEC_TO_TICK(PCIE_HP_DLL_STATE_CHANGE_TIMEOUT));
112026947304SEvan Yan
112126947304SEvan Yan /* check Link status */
112226947304SEvan Yan status = pciehpc_reg_get16(ctrl_p,
112326947304SEvan Yan bus_p->bus_pcie_off +
112426947304SEvan Yan PCIE_LINKSTS);
112526947304SEvan Yan if (!(status & PCIE_LINKSTS_DLL_LINK_ACTIVE))
112626947304SEvan Yan goto cleanup2;
112726947304SEvan Yan }
112826947304SEvan Yan }
112926947304SEvan Yan
113026947304SEvan Yan /* wait 1 sec for link to come up */
113126947304SEvan Yan delay(drv_usectohz(1000000));
113226947304SEvan Yan
113326947304SEvan Yan /* check power is really turned ON */
113426947304SEvan Yan control = pciehpc_reg_get16(ctrl_p,
113526947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
113626947304SEvan Yan
113726947304SEvan Yan if (control & PCIE_SLOTCTL_PWR_CONTROL) {
113826947304SEvan Yan PCIE_DBG("slot %d fails to turn on power on connect\n",
113926947304SEvan Yan slot_p->hs_phy_slot_num);
114026947304SEvan Yan
114126947304SEvan Yan goto cleanup1;
114226947304SEvan Yan }
114326947304SEvan Yan
114426947304SEvan Yan /* clear power fault status */
114526947304SEvan Yan status = pciehpc_reg_get16(ctrl_p,
114626947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
114726947304SEvan Yan status |= PCIE_SLOTSTS_PWR_FAULT_DETECTED;
114826947304SEvan Yan pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTSTS,
114926947304SEvan Yan status);
115026947304SEvan Yan
115126947304SEvan Yan /* enable power fault detection interrupt */
115226947304SEvan Yan control |= PCIE_SLOTCTL_PWR_FAULT_EN;
115326947304SEvan Yan pciehpc_issue_hpc_command(ctrl_p, control);
115426947304SEvan Yan
115526947304SEvan Yan /* 4. Set power LED to be ON */
115626947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_ON);
115726947304SEvan Yan
115826947304SEvan Yan /* if EMI is present, turn it ON */
115926947304SEvan Yan if (ctrl_p->hc_has_emi_lock) {
116026947304SEvan Yan status = pciehpc_reg_get16(ctrl_p,
116126947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
116226947304SEvan Yan
116326947304SEvan Yan if (!(status & PCIE_SLOTSTS_EMI_LOCK_SET)) {
116426947304SEvan Yan control = pciehpc_reg_get16(ctrl_p,
116526947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
116626947304SEvan Yan control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL;
116726947304SEvan Yan pciehpc_issue_hpc_command(ctrl_p, control);
116826947304SEvan Yan
116926947304SEvan Yan /* wait 1 sec after toggling the state of EMI lock */
117026947304SEvan Yan delay(drv_usectohz(1000000));
117126947304SEvan Yan }
117226947304SEvan Yan }
117326947304SEvan Yan
117426947304SEvan Yan *result = slot_p->hs_info.cn_state =
117526947304SEvan Yan DDI_HP_CN_STATE_POWERED;
117626947304SEvan Yan
117726947304SEvan Yan return (DDI_SUCCESS);
117826947304SEvan Yan
117926947304SEvan Yan cleanup2:
118026947304SEvan Yan control = pciehpc_reg_get16(ctrl_p,
118126947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
118226947304SEvan Yan
118326947304SEvan Yan /* if power is ON, set power control to OFF */
118426947304SEvan Yan if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) {
118526947304SEvan Yan control |= PCIE_SLOTCTL_PWR_CONTROL;
118626947304SEvan Yan pciehpc_issue_hpc_command(ctrl_p, control);
118726947304SEvan Yan }
118826947304SEvan Yan
118926947304SEvan Yan cleanup1:
119026947304SEvan Yan /* set power led to OFF */
119126947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
119226947304SEvan Yan
119326947304SEvan Yan cleanup:
119426947304SEvan Yan return (DDI_FAILURE);
119526947304SEvan Yan }
119626947304SEvan Yan
119726947304SEvan Yan /*ARGSUSED*/
119826947304SEvan Yan static int
pciehpc_slot_poweroff(pcie_hp_slot_t * slot_p,ddi_hp_cn_state_t * result)119926947304SEvan Yan pciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result)
120026947304SEvan Yan {
120126947304SEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
120226947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
120326947304SEvan Yan uint16_t status, control;
120426947304SEvan Yan
120526947304SEvan Yan ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
120626947304SEvan Yan
120726947304SEvan Yan /* get the current state of the slot */
120826947304SEvan Yan pciehpc_get_slot_state(slot_p);
120926947304SEvan Yan
121026947304SEvan Yan /* check if the slot is not in the "enabled' state */
121126947304SEvan Yan if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) {
121226947304SEvan Yan /* slot is in the 'disabled' state */
121326947304SEvan Yan PCIE_DBG("pciehpc_slot_poweroff(): "
121426947304SEvan Yan "slot %d already disabled\n", slot_p->hs_phy_slot_num);
121526947304SEvan Yan ASSERT(slot_p->hs_power_led_state == PCIE_HP_LED_OFF);
121626947304SEvan Yan
121726947304SEvan Yan *result = slot_p->hs_info.cn_state;
121826947304SEvan Yan return (DDI_SUCCESS);
121926947304SEvan Yan }
122026947304SEvan Yan
122126947304SEvan Yan /* read the Slot Status Register */
122226947304SEvan Yan status = pciehpc_reg_get16(ctrl_p,
122326947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
122426947304SEvan Yan
122526947304SEvan Yan /* make sure the slot has a device present */
122626947304SEvan Yan if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
122726947304SEvan Yan /* slot is empty */
122826947304SEvan Yan PCIE_DBG("pciehpc_slot_poweroff(): slot %d is empty\n",
122926947304SEvan Yan slot_p->hs_phy_slot_num);
123026947304SEvan Yan goto cleanup;
123126947304SEvan Yan }
123226947304SEvan Yan
123326947304SEvan Yan /*
123426947304SEvan Yan * Disable power to the slot involves:
123526947304SEvan Yan * 1. Set power LED to blink.
123626947304SEvan Yan * 2. Set power control OFF in Slot Control Reigster and
123726947304SEvan Yan * wait for Command Completed Interrupt or 1 sec timeout.
123826947304SEvan Yan * 3. Set POWER led and ATTN led to be OFF.
123926947304SEvan Yan */
124026947304SEvan Yan
124126947304SEvan Yan /* 1. set power LED to blink */
124226947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
124326947304SEvan Yan
124426947304SEvan Yan /* disable power fault detection interrupt */
124526947304SEvan Yan control = pciehpc_reg_get16(ctrl_p,
124626947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
124726947304SEvan Yan control &= ~PCIE_SLOTCTL_PWR_FAULT_EN;
124826947304SEvan Yan pciehpc_issue_hpc_command(ctrl_p, control);
124926947304SEvan Yan
125026947304SEvan Yan /* 2. set power control to OFF */
125126947304SEvan Yan control = pciehpc_reg_get16(ctrl_p,
125226947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
125326947304SEvan Yan control |= PCIE_SLOTCTL_PWR_CONTROL;
125426947304SEvan Yan pciehpc_issue_hpc_command(ctrl_p, control);
125526947304SEvan Yan
125626947304SEvan Yan #ifdef DEBUG
125726947304SEvan Yan /* check for power control bit to be OFF */
125826947304SEvan Yan control = pciehpc_reg_get16(ctrl_p,
125926947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
126026947304SEvan Yan ASSERT(control & PCIE_SLOTCTL_PWR_CONTROL);
126126947304SEvan Yan #endif
126226947304SEvan Yan
126326947304SEvan Yan /* 3. Set power LED to be OFF */
126426947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
126526947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
126626947304SEvan Yan
126726947304SEvan Yan /* if EMI is present, turn it OFF */
126826947304SEvan Yan if (ctrl_p->hc_has_emi_lock) {
126926947304SEvan Yan status = pciehpc_reg_get16(ctrl_p,
127026947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
127126947304SEvan Yan
127226947304SEvan Yan if (status & PCIE_SLOTSTS_EMI_LOCK_SET) {
127326947304SEvan Yan control = pciehpc_reg_get16(ctrl_p,
127426947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
127526947304SEvan Yan control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL;
127626947304SEvan Yan pciehpc_issue_hpc_command(ctrl_p, control);
127726947304SEvan Yan
127826947304SEvan Yan /* wait 1 sec after toggling the state of EMI lock */
127926947304SEvan Yan delay(drv_usectohz(1000000));
128026947304SEvan Yan }
128126947304SEvan Yan }
128226947304SEvan Yan
128326947304SEvan Yan /* get the current state of the slot */
128426947304SEvan Yan pciehpc_get_slot_state(slot_p);
128526947304SEvan Yan
128626947304SEvan Yan *result = slot_p->hs_info.cn_state;
128726947304SEvan Yan
128826947304SEvan Yan return (DDI_SUCCESS);
128926947304SEvan Yan
129026947304SEvan Yan cleanup:
129126947304SEvan Yan return (DDI_FAILURE);
129226947304SEvan Yan }
129326947304SEvan Yan
129426947304SEvan Yan /*
129526947304SEvan Yan * pciehpc_slot_probe()
129626947304SEvan Yan *
129726947304SEvan Yan * Probe the slot.
129826947304SEvan Yan *
129926947304SEvan Yan * Note: This function is called by DDI HP framework at kernel context only
130026947304SEvan Yan */
130126947304SEvan Yan /*ARGSUSED*/
130226947304SEvan Yan static int
pciehpc_slot_probe(pcie_hp_slot_t * slot_p)130326947304SEvan Yan pciehpc_slot_probe(pcie_hp_slot_t *slot_p)
130426947304SEvan Yan {
130526947304SEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
130626947304SEvan Yan int ret = DDI_SUCCESS;
130726947304SEvan Yan
130826947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex);
130926947304SEvan Yan
131026947304SEvan Yan /* get the current state of the slot */
131126947304SEvan Yan pciehpc_get_slot_state(slot_p);
131226947304SEvan Yan
131326947304SEvan Yan /*
131426947304SEvan Yan * Probe a given PCIe Hotplug Connection (CN).
131526947304SEvan Yan */
131626947304SEvan Yan PCIE_DISABLE_ERRORS(ctrl_p->hc_dip);
131726947304SEvan Yan ret = pcie_hp_probe(slot_p);
131826947304SEvan Yan
131926947304SEvan Yan if (ret != DDI_SUCCESS) {
132026947304SEvan Yan PCIE_DBG("pciehpc_slot_probe() failed\n");
132126947304SEvan Yan
132226947304SEvan Yan /* turn the ATTN led ON for configure failure */
132326947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_ON);
132426947304SEvan Yan
132526947304SEvan Yan /* if power to the slot is still on then set Power led to ON */
132626947304SEvan Yan if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
132726947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
132826947304SEvan Yan PCIE_HP_LED_ON);
132926947304SEvan Yan
133026947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex);
133126947304SEvan Yan return (DDI_FAILURE);
133226947304SEvan Yan }
133326947304SEvan Yan
133426947304SEvan Yan PCIE_ENABLE_ERRORS(ctrl_p->hc_dip);
133526947304SEvan Yan
133626947304SEvan Yan /* get the current state of the slot */
133726947304SEvan Yan pciehpc_get_slot_state(slot_p);
133826947304SEvan Yan
133926947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex);
134026947304SEvan Yan return (DDI_SUCCESS);
134126947304SEvan Yan }
134226947304SEvan Yan
134326947304SEvan Yan /*
134426947304SEvan Yan * pciehpc_slot_unprobe()
134526947304SEvan Yan *
134626947304SEvan Yan * Unprobe the slot.
134726947304SEvan Yan *
134826947304SEvan Yan * Note: This function is called by DDI HP framework at kernel context only
134926947304SEvan Yan */
135026947304SEvan Yan /*ARGSUSED*/
135126947304SEvan Yan static int
pciehpc_slot_unprobe(pcie_hp_slot_t * slot_p)135226947304SEvan Yan pciehpc_slot_unprobe(pcie_hp_slot_t *slot_p)
135326947304SEvan Yan {
135426947304SEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
135526947304SEvan Yan int ret;
135626947304SEvan Yan
135726947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex);
135826947304SEvan Yan
135926947304SEvan Yan /* get the current state of the slot */
136026947304SEvan Yan pciehpc_get_slot_state(slot_p);
136126947304SEvan Yan
136226947304SEvan Yan /*
136326947304SEvan Yan * Unprobe a given PCIe Hotplug Connection (CN).
136426947304SEvan Yan */
136526947304SEvan Yan PCIE_DISABLE_ERRORS(ctrl_p->hc_dip);
136626947304SEvan Yan ret = pcie_hp_unprobe(slot_p);
136726947304SEvan Yan
136826947304SEvan Yan if (ret != DDI_SUCCESS) {
136926947304SEvan Yan PCIE_DBG("pciehpc_slot_unprobe() failed\n");
137026947304SEvan Yan
137126947304SEvan Yan /* if power to the slot is still on then set Power led to ON */
137226947304SEvan Yan if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
137326947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
137426947304SEvan Yan PCIE_HP_LED_ON);
137526947304SEvan Yan
137626947304SEvan Yan PCIE_ENABLE_ERRORS(ctrl_p->hc_dip);
137726947304SEvan Yan
137826947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex);
137926947304SEvan Yan return (DDI_FAILURE);
138026947304SEvan Yan }
138126947304SEvan Yan
138226947304SEvan Yan /* get the current state of the slot */
138326947304SEvan Yan pciehpc_get_slot_state(slot_p);
138426947304SEvan Yan
138526947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex);
138626947304SEvan Yan return (DDI_SUCCESS);
138726947304SEvan Yan }
138826947304SEvan Yan
138926947304SEvan Yan static int
pciehpc_upgrade_slot_state(pcie_hp_slot_t * slot_p,ddi_hp_cn_state_t target_state)139026947304SEvan Yan pciehpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
139126947304SEvan Yan ddi_hp_cn_state_t target_state)
139226947304SEvan Yan {
139326947304SEvan Yan ddi_hp_cn_state_t curr_state;
139426947304SEvan Yan int rv = DDI_SUCCESS;
139526947304SEvan Yan
139626947304SEvan Yan if (target_state > DDI_HP_CN_STATE_ENABLED) {
139726947304SEvan Yan return (DDI_EINVAL);
139826947304SEvan Yan }
139926947304SEvan Yan
140026947304SEvan Yan curr_state = slot_p->hs_info.cn_state;
140126947304SEvan Yan while ((curr_state < target_state) && (rv == DDI_SUCCESS)) {
140226947304SEvan Yan
140326947304SEvan Yan switch (curr_state) {
140426947304SEvan Yan case DDI_HP_CN_STATE_EMPTY:
140526947304SEvan Yan /*
140626947304SEvan Yan * From EMPTY to PRESENT, just check the hardware
140726947304SEvan Yan * slot state.
140826947304SEvan Yan */
140926947304SEvan Yan pciehpc_get_slot_state(slot_p);
141026947304SEvan Yan curr_state = slot_p->hs_info.cn_state;
141126947304SEvan Yan if (curr_state < DDI_HP_CN_STATE_PRESENT)
141226947304SEvan Yan rv = DDI_FAILURE;
141326947304SEvan Yan break;
141426947304SEvan Yan case DDI_HP_CN_STATE_PRESENT:
141526947304SEvan Yan rv = (slot_p->hs_ctrl->hc_ops.poweron_hpc_slot)(slot_p,
141626947304SEvan Yan &curr_state);
141726947304SEvan Yan
141826947304SEvan Yan break;
141926947304SEvan Yan case DDI_HP_CN_STATE_POWERED:
142026947304SEvan Yan curr_state = slot_p->hs_info.cn_state =
142126947304SEvan Yan DDI_HP_CN_STATE_ENABLED;
142226947304SEvan Yan break;
142326947304SEvan Yan default:
142426947304SEvan Yan /* should never reach here */
142526947304SEvan Yan ASSERT("unknown devinfo state");
142626947304SEvan Yan }
142726947304SEvan Yan }
142826947304SEvan Yan
142926947304SEvan Yan return (rv);
143026947304SEvan Yan }
143126947304SEvan Yan
143226947304SEvan Yan static int
pciehpc_downgrade_slot_state(pcie_hp_slot_t * slot_p,ddi_hp_cn_state_t target_state)143326947304SEvan Yan pciehpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
143426947304SEvan Yan ddi_hp_cn_state_t target_state)
143526947304SEvan Yan {
143626947304SEvan Yan ddi_hp_cn_state_t curr_state;
143726947304SEvan Yan int rv = DDI_SUCCESS;
143826947304SEvan Yan
143926947304SEvan Yan
144026947304SEvan Yan curr_state = slot_p->hs_info.cn_state;
144126947304SEvan Yan while ((curr_state > target_state) && (rv == DDI_SUCCESS)) {
144226947304SEvan Yan
144326947304SEvan Yan switch (curr_state) {
144426947304SEvan Yan case DDI_HP_CN_STATE_PRESENT:
144526947304SEvan Yan /*
144626947304SEvan Yan * From PRESENT to EMPTY, just check hardware slot
144726947304SEvan Yan * state.
144826947304SEvan Yan */
144926947304SEvan Yan pciehpc_get_slot_state(slot_p);
145026947304SEvan Yan curr_state = slot_p->hs_info.cn_state;
145126947304SEvan Yan if (curr_state >= DDI_HP_CN_STATE_PRESENT)
145226947304SEvan Yan rv = DDI_FAILURE;
145326947304SEvan Yan break;
145426947304SEvan Yan case DDI_HP_CN_STATE_POWERED:
145526947304SEvan Yan rv = (slot_p->hs_ctrl->hc_ops.poweroff_hpc_slot)(
145626947304SEvan Yan slot_p, &curr_state);
145726947304SEvan Yan
145826947304SEvan Yan break;
145926947304SEvan Yan case DDI_HP_CN_STATE_ENABLED:
146026947304SEvan Yan curr_state = slot_p->hs_info.cn_state =
146126947304SEvan Yan DDI_HP_CN_STATE_POWERED;
146226947304SEvan Yan
146326947304SEvan Yan break;
146426947304SEvan Yan default:
146526947304SEvan Yan /* should never reach here */
146626947304SEvan Yan ASSERT("unknown devinfo state");
146726947304SEvan Yan }
146826947304SEvan Yan }
146926947304SEvan Yan
147026947304SEvan Yan return (rv);
147126947304SEvan Yan }
147226947304SEvan Yan
147326947304SEvan Yan /* Change slot state to a target state */
147426947304SEvan Yan static int
pciehpc_change_slot_state(pcie_hp_slot_t * slot_p,ddi_hp_cn_state_t target_state)147526947304SEvan Yan pciehpc_change_slot_state(pcie_hp_slot_t *slot_p,
147626947304SEvan Yan ddi_hp_cn_state_t target_state)
147726947304SEvan Yan {
147826947304SEvan Yan ddi_hp_cn_state_t curr_state;
147926947304SEvan Yan int rv;
148026947304SEvan Yan
148126947304SEvan Yan pciehpc_get_slot_state(slot_p);
148226947304SEvan Yan curr_state = slot_p->hs_info.cn_state;
148326947304SEvan Yan
148426947304SEvan Yan if (curr_state == target_state) {
148526947304SEvan Yan return (DDI_SUCCESS);
148626947304SEvan Yan }
148726947304SEvan Yan if (curr_state < target_state) {
148826947304SEvan Yan
148926947304SEvan Yan rv = pciehpc_upgrade_slot_state(slot_p, target_state);
149026947304SEvan Yan } else {
149126947304SEvan Yan rv = pciehpc_downgrade_slot_state(slot_p, target_state);
149226947304SEvan Yan }
149326947304SEvan Yan
149426947304SEvan Yan return (rv);
149526947304SEvan Yan }
149626947304SEvan Yan
149726947304SEvan Yan int
pciehpc_slot_get_property(pcie_hp_slot_t * slot_p,ddi_hp_property_t * arg,ddi_hp_property_t * rval)149826947304SEvan Yan pciehpc_slot_get_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
149926947304SEvan Yan ddi_hp_property_t *rval)
150026947304SEvan Yan {
150126947304SEvan Yan ddi_hp_property_t request, result;
150226947304SEvan Yan #ifdef _SYSCALL32_IMPL
150326947304SEvan Yan ddi_hp_property32_t request32, result32;
150426947304SEvan Yan #endif
150526947304SEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
150626947304SEvan Yan nvlist_t *prop_list;
150726947304SEvan Yan nvlist_t *prop_rlist; /* nvlist for return values */
150826947304SEvan Yan nvpair_t *prop_pair;
150926947304SEvan Yan char *name, *value;
151026947304SEvan Yan int ret = DDI_SUCCESS;
151126947304SEvan Yan int i, n;
151226947304SEvan Yan boolean_t get_all_prop = B_FALSE;
151326947304SEvan Yan
151426947304SEvan Yan if (get_udatamodel() == DATAMODEL_NATIVE) {
151526947304SEvan Yan if (copyin(arg, &request, sizeof (ddi_hp_property_t)) ||
151626947304SEvan Yan copyin(rval, &result, sizeof (ddi_hp_property_t)))
151726947304SEvan Yan return (DDI_FAILURE);
151826947304SEvan Yan }
151926947304SEvan Yan #ifdef _SYSCALL32_IMPL
152026947304SEvan Yan else {
152126947304SEvan Yan bzero(&request, sizeof (request));
152226947304SEvan Yan bzero(&result, sizeof (result));
152326947304SEvan Yan if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)) ||
152426947304SEvan Yan copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
152526947304SEvan Yan return (DDI_FAILURE);
152626947304SEvan Yan request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
152726947304SEvan Yan request.buf_size = request32.buf_size;
152826947304SEvan Yan result.nvlist_buf = (char *)(uintptr_t)result32.nvlist_buf;
152926947304SEvan Yan result.buf_size = result32.buf_size;
153026947304SEvan Yan }
153126947304SEvan Yan #endif
153226947304SEvan Yan
153326947304SEvan Yan if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
153426947304SEvan Yan &prop_list)) != DDI_SUCCESS)
153526947304SEvan Yan return (ret);
153626947304SEvan Yan
153726947304SEvan Yan if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
153826947304SEvan Yan ret = DDI_ENOMEM;
153926947304SEvan Yan goto get_prop_cleanup;
154026947304SEvan Yan }
154126947304SEvan Yan
154226947304SEvan Yan /* check whether the requested property is "all" or "help" */
154326947304SEvan Yan prop_pair = nvlist_next_nvpair(prop_list, NULL);
154426947304SEvan Yan if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair)) {
154526947304SEvan Yan name = nvpair_name(prop_pair);
154626947304SEvan Yan n = sizeof (pciehpc_props) / sizeof (pciehpc_prop_t);
154726947304SEvan Yan
154826947304SEvan Yan if (strcmp(name, PCIEHPC_PROP_ALL) == 0) {
154926947304SEvan Yan (void) nvlist_remove_all(prop_list, PCIEHPC_PROP_ALL);
155026947304SEvan Yan
155126947304SEvan Yan /*
155226947304SEvan Yan * Add all properties into the request list, so that we
155326947304SEvan Yan * will get the values in the following for loop.
155426947304SEvan Yan */
155526947304SEvan Yan for (i = 0; i < n; i++) {
155626947304SEvan Yan if (nvlist_add_string(prop_list,
155726947304SEvan Yan pciehpc_props[i].prop_name, "") != 0) {
155826947304SEvan Yan ret = DDI_FAILURE;
155926947304SEvan Yan goto get_prop_cleanup1;
156026947304SEvan Yan }
156126947304SEvan Yan }
156226947304SEvan Yan get_all_prop = B_TRUE;
156326947304SEvan Yan } else if (strcmp(name, PCIEHPC_PROP_HELP) == 0) {
156426947304SEvan Yan /*
156526947304SEvan Yan * Empty the request list, and add help strings into the
156626947304SEvan Yan * return list. We will pass the following for loop.
156726947304SEvan Yan */
156826947304SEvan Yan (void) nvlist_remove_all(prop_list, PCIEHPC_PROP_HELP);
156926947304SEvan Yan
157026947304SEvan Yan for (i = 0; i < n; i++) {
157126947304SEvan Yan if (nvlist_add_string(prop_rlist,
157226947304SEvan Yan pciehpc_props[i].prop_name,
157326947304SEvan Yan pciehpc_props[i].prop_value) != 0) {
157426947304SEvan Yan ret = DDI_FAILURE;
157526947304SEvan Yan goto get_prop_cleanup1;
157626947304SEvan Yan }
157726947304SEvan Yan }
157826947304SEvan Yan }
157926947304SEvan Yan }
158026947304SEvan Yan
158126947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex);
158226947304SEvan Yan
158326947304SEvan Yan /* get the current slot state */
158426947304SEvan Yan pciehpc_get_slot_state(slot_p);
158526947304SEvan Yan
158626947304SEvan Yan /* for each requested property, get the value and add it to nvlist */
158726947304SEvan Yan prop_pair = NULL;
158826947304SEvan Yan while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
158926947304SEvan Yan name = nvpair_name(prop_pair);
159026947304SEvan Yan
159126947304SEvan Yan if (strcmp(name, PCIEHPC_PROP_LED_FAULT) == 0) {
159226947304SEvan Yan value = pcie_led_state_text(
159326947304SEvan Yan slot_p->hs_fault_led_state);
159426947304SEvan Yan } else if (strcmp(name, PCIEHPC_PROP_LED_POWER) == 0) {
159526947304SEvan Yan value = pcie_led_state_text(
159626947304SEvan Yan slot_p->hs_power_led_state);
159726947304SEvan Yan } else if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
159826947304SEvan Yan value = pcie_led_state_text(
159926947304SEvan Yan slot_p->hs_attn_led_state);
160026947304SEvan Yan } else if (strcmp(name, PCIEHPC_PROP_LED_ACTIVE) == 0) {
160126947304SEvan Yan value = pcie_led_state_text(
160226947304SEvan Yan slot_p->hs_active_led_state);
160326947304SEvan Yan } else if (strcmp(name, PCIEHPC_PROP_CARD_TYPE) == 0) {
160426947304SEvan Yan ddi_acc_handle_t handle;
160526947304SEvan Yan dev_info_t *cdip;
160626947304SEvan Yan uint8_t prog_class, base_class, sub_class;
160726947304SEvan Yan int i;
160826947304SEvan Yan
160926947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex);
161026947304SEvan Yan cdip = pcie_hp_devi_find(
161126947304SEvan Yan ctrl_p->hc_dip, slot_p->hs_device_num, 0);
161226947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex);
161326947304SEvan Yan
161426947304SEvan Yan if ((slot_p->hs_info.cn_state
161526947304SEvan Yan != DDI_HP_CN_STATE_ENABLED) || (cdip == NULL)) {
161626947304SEvan Yan /*
161726947304SEvan Yan * When getting all properties, just ignore the
161826947304SEvan Yan * one that's not available under certain state.
161926947304SEvan Yan */
162026947304SEvan Yan if (get_all_prop)
162126947304SEvan Yan continue;
162226947304SEvan Yan
162326947304SEvan Yan ret = DDI_ENOTSUP;
162426947304SEvan Yan goto get_prop_cleanup2;
162526947304SEvan Yan }
162626947304SEvan Yan
162726947304SEvan Yan if (pci_config_setup(cdip, &handle) != DDI_SUCCESS) {
162826947304SEvan Yan ret = DDI_FAILURE;
162926947304SEvan Yan goto get_prop_cleanup2;
163026947304SEvan Yan }
163126947304SEvan Yan
163226947304SEvan Yan prog_class = pci_config_get8(handle,
163326947304SEvan Yan PCI_CONF_PROGCLASS);
163426947304SEvan Yan base_class = pci_config_get8(handle, PCI_CONF_BASCLASS);
163526947304SEvan Yan sub_class = pci_config_get8(handle, PCI_CONF_SUBCLASS);
163626947304SEvan Yan pci_config_teardown(&handle);
163726947304SEvan Yan
163826947304SEvan Yan for (i = 0; i < class_pci_items; i++) {
163926947304SEvan Yan if ((base_class == class_pci[i].base_class) &&
164026947304SEvan Yan (sub_class == class_pci[i].sub_class) &&
164126947304SEvan Yan (prog_class == class_pci[i].prog_class)) {
164226947304SEvan Yan value = class_pci[i].short_desc;
164326947304SEvan Yan break;
164426947304SEvan Yan }
164526947304SEvan Yan }
164626947304SEvan Yan if (i == class_pci_items)
164726947304SEvan Yan value = PCIEHPC_PROP_VALUE_UNKNOWN;
164826947304SEvan Yan } else if (strcmp(name, PCIEHPC_PROP_BOARD_TYPE) == 0) {
164926947304SEvan Yan if (slot_p->hs_info.cn_state <= DDI_HP_CN_STATE_EMPTY)
165026947304SEvan Yan value = PCIEHPC_PROP_VALUE_UNKNOWN;
165126947304SEvan Yan else
165226947304SEvan Yan value = PCIEHPC_PROP_VALUE_PCIHOTPLUG;
165326947304SEvan Yan } else if (strcmp(name, PCIEHPC_PROP_SLOT_CONDITION) == 0) {
165426947304SEvan Yan value = pcie_slot_condition_text(slot_p->hs_condition);
165526947304SEvan Yan } else {
165626947304SEvan Yan /* unsupported property */
165724fd5dc4SEvan Yan PCIE_DBG("Unsupported property: %s\n", name);
165826947304SEvan Yan
165926947304SEvan Yan ret = DDI_ENOTSUP;
166026947304SEvan Yan goto get_prop_cleanup2;
166126947304SEvan Yan }
166226947304SEvan Yan if (nvlist_add_string(prop_rlist, name, value) != 0) {
166326947304SEvan Yan ret = DDI_FAILURE;
166426947304SEvan Yan goto get_prop_cleanup2;
166526947304SEvan Yan }
166626947304SEvan Yan }
166726947304SEvan Yan
166826947304SEvan Yan /* pack nvlist and copyout */
166926947304SEvan Yan if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
167026947304SEvan Yan &result.buf_size)) != DDI_SUCCESS) {
167126947304SEvan Yan goto get_prop_cleanup2;
167226947304SEvan Yan }
167326947304SEvan Yan if (get_udatamodel() == DATAMODEL_NATIVE) {
167426947304SEvan Yan if (copyout(&result, rval, sizeof (ddi_hp_property_t)))
167526947304SEvan Yan ret = DDI_FAILURE;
167626947304SEvan Yan }
167726947304SEvan Yan #ifdef _SYSCALL32_IMPL
167826947304SEvan Yan else {
167926947304SEvan Yan if (result.buf_size > UINT32_MAX) {
168026947304SEvan Yan ret = DDI_FAILURE;
168126947304SEvan Yan } else {
168226947304SEvan Yan result32.buf_size = (uint32_t)result.buf_size;
168326947304SEvan Yan if (copyout(&result32, rval,
168426947304SEvan Yan sizeof (ddi_hp_property32_t)))
168526947304SEvan Yan ret = DDI_FAILURE;
168626947304SEvan Yan }
168726947304SEvan Yan }
168826947304SEvan Yan #endif
168926947304SEvan Yan
169026947304SEvan Yan get_prop_cleanup2:
169126947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex);
169226947304SEvan Yan get_prop_cleanup1:
169326947304SEvan Yan nvlist_free(prop_rlist);
169426947304SEvan Yan get_prop_cleanup:
169526947304SEvan Yan nvlist_free(prop_list);
169626947304SEvan Yan return (ret);
169726947304SEvan Yan }
169826947304SEvan Yan
169926947304SEvan Yan int
pciehpc_slot_set_property(pcie_hp_slot_t * slot_p,ddi_hp_property_t * arg,ddi_hp_property_t * rval)170026947304SEvan Yan pciehpc_slot_set_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
170126947304SEvan Yan ddi_hp_property_t *rval)
170226947304SEvan Yan {
170326947304SEvan Yan ddi_hp_property_t request, result;
170426947304SEvan Yan #ifdef _SYSCALL32_IMPL
170526947304SEvan Yan ddi_hp_property32_t request32, result32;
170626947304SEvan Yan #endif
170726947304SEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
170826947304SEvan Yan nvlist_t *prop_list;
170926947304SEvan Yan nvlist_t *prop_rlist;
171026947304SEvan Yan nvpair_t *prop_pair;
171126947304SEvan Yan char *name, *value;
171226947304SEvan Yan pcie_hp_led_state_t led_state;
171326947304SEvan Yan int ret = DDI_SUCCESS;
171426947304SEvan Yan
171526947304SEvan Yan if (get_udatamodel() == DATAMODEL_NATIVE) {
171626947304SEvan Yan if (copyin(arg, &request, sizeof (ddi_hp_property_t)))
171726947304SEvan Yan return (DDI_FAILURE);
171826947304SEvan Yan if (rval &&
171926947304SEvan Yan copyin(rval, &result, sizeof (ddi_hp_property_t)))
172026947304SEvan Yan return (DDI_FAILURE);
172126947304SEvan Yan }
172226947304SEvan Yan #ifdef _SYSCALL32_IMPL
172326947304SEvan Yan else {
172426947304SEvan Yan bzero(&request, sizeof (request));
172526947304SEvan Yan bzero(&result, sizeof (result));
172626947304SEvan Yan if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)))
172726947304SEvan Yan return (DDI_FAILURE);
172826947304SEvan Yan if (rval &&
172926947304SEvan Yan copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
173026947304SEvan Yan return (DDI_FAILURE);
173126947304SEvan Yan request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
173226947304SEvan Yan request.buf_size = request32.buf_size;
173326947304SEvan Yan if (rval) {
173426947304SEvan Yan result.nvlist_buf =
173526947304SEvan Yan (char *)(uintptr_t)result32.nvlist_buf;
173626947304SEvan Yan result.buf_size = result32.buf_size;
173726947304SEvan Yan }
173826947304SEvan Yan }
173926947304SEvan Yan #endif
174026947304SEvan Yan
174126947304SEvan Yan if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
174226947304SEvan Yan &prop_list)) != DDI_SUCCESS)
174326947304SEvan Yan return (ret);
174426947304SEvan Yan
174526947304SEvan Yan /* check whether the requested property is "help" */
174626947304SEvan Yan prop_pair = nvlist_next_nvpair(prop_list, NULL);
174726947304SEvan Yan if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair) &&
174826947304SEvan Yan (strcmp(nvpair_name(prop_pair), PCIEHPC_PROP_HELP) == 0)) {
174926947304SEvan Yan if (!rval) {
175026947304SEvan Yan ret = DDI_ENOTSUP;
175126947304SEvan Yan goto set_prop_cleanup;
175226947304SEvan Yan }
175326947304SEvan Yan
175426947304SEvan Yan if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
175526947304SEvan Yan ret = DDI_ENOMEM;
175626947304SEvan Yan goto set_prop_cleanup;
175726947304SEvan Yan }
175826947304SEvan Yan if (nvlist_add_string(prop_rlist, PCIEHPC_PROP_LED_ATTN,
175926947304SEvan Yan PCIEHPC_PROP_VALUE_LED) != 0) {
176026947304SEvan Yan ret = DDI_FAILURE;
176126947304SEvan Yan goto set_prop_cleanup1;
176226947304SEvan Yan }
176326947304SEvan Yan
176426947304SEvan Yan if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
176526947304SEvan Yan &result.buf_size)) != DDI_SUCCESS) {
176626947304SEvan Yan goto set_prop_cleanup1;
176726947304SEvan Yan }
176826947304SEvan Yan if (get_udatamodel() == DATAMODEL_NATIVE) {
176926947304SEvan Yan if (copyout(&result, rval,
177026947304SEvan Yan sizeof (ddi_hp_property_t))) {
177126947304SEvan Yan ret = DDI_FAILURE;
177226947304SEvan Yan goto set_prop_cleanup1;
177326947304SEvan Yan }
177426947304SEvan Yan }
177526947304SEvan Yan #ifdef _SYSCALL32_IMPL
177626947304SEvan Yan else {
177726947304SEvan Yan if (result.buf_size > UINT32_MAX) {
177826947304SEvan Yan ret = DDI_FAILURE;
177926947304SEvan Yan goto set_prop_cleanup1;
178026947304SEvan Yan } else {
178126947304SEvan Yan result32.buf_size = (uint32_t)result.buf_size;
178226947304SEvan Yan if (copyout(&result32, rval,
178326947304SEvan Yan sizeof (ddi_hp_property32_t))) {
178426947304SEvan Yan ret = DDI_FAILURE;
178526947304SEvan Yan goto set_prop_cleanup1;
178626947304SEvan Yan }
178726947304SEvan Yan }
178826947304SEvan Yan }
178926947304SEvan Yan #endif
179026947304SEvan Yan set_prop_cleanup1:
179126947304SEvan Yan nvlist_free(prop_rlist);
179226947304SEvan Yan nvlist_free(prop_list);
179326947304SEvan Yan return (ret);
179426947304SEvan Yan }
179526947304SEvan Yan
179626947304SEvan Yan /* Validate the request */
179726947304SEvan Yan prop_pair = NULL;
179826947304SEvan Yan while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
179926947304SEvan Yan name = nvpair_name(prop_pair);
180026947304SEvan Yan if (nvpair_type(prop_pair) != DATA_TYPE_STRING) {
180124fd5dc4SEvan Yan PCIE_DBG("Unexpected data type of setting "
180226947304SEvan Yan "property %s.\n", name);
180326947304SEvan Yan ret = DDI_EINVAL;
180426947304SEvan Yan goto set_prop_cleanup;
180526947304SEvan Yan }
180626947304SEvan Yan if (nvpair_value_string(prop_pair, &value)) {
180724fd5dc4SEvan Yan PCIE_DBG("Get string value failed for property %s.\n",
180824fd5dc4SEvan Yan name);
180926947304SEvan Yan ret = DDI_FAILURE;
181026947304SEvan Yan goto set_prop_cleanup;
181126947304SEvan Yan }
181226947304SEvan Yan
181326947304SEvan Yan if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
181426947304SEvan Yan if ((strcmp(value, PCIEHPC_PROP_VALUE_ON) != 0) &&
181526947304SEvan Yan (strcmp(value, PCIEHPC_PROP_VALUE_OFF) != 0) &&
181626947304SEvan Yan (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) != 0)) {
181724fd5dc4SEvan Yan PCIE_DBG("Unsupported value of setting "
181826947304SEvan Yan "property %s\n", name);
181926947304SEvan Yan ret = DDI_ENOTSUP;
182026947304SEvan Yan goto set_prop_cleanup;
182126947304SEvan Yan }
182226947304SEvan Yan } else {
182324fd5dc4SEvan Yan PCIE_DBG("Unsupported property: %s\n", name);
182426947304SEvan Yan ret = DDI_ENOTSUP;
182526947304SEvan Yan goto set_prop_cleanup;
182626947304SEvan Yan }
182726947304SEvan Yan }
182826947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex);
182926947304SEvan Yan
183026947304SEvan Yan /* get the current slot state */
183126947304SEvan Yan pciehpc_get_slot_state(slot_p);
183226947304SEvan Yan
183326947304SEvan Yan /* set each property */
183426947304SEvan Yan prop_pair = NULL;
183526947304SEvan Yan while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
183626947304SEvan Yan name = nvpair_name(prop_pair);
183726947304SEvan Yan
183826947304SEvan Yan if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
183926947304SEvan Yan if (strcmp(value, PCIEHPC_PROP_VALUE_ON) == 0)
184026947304SEvan Yan led_state = PCIE_HP_LED_ON;
184126947304SEvan Yan else if (strcmp(value, PCIEHPC_PROP_VALUE_OFF) == 0)
184226947304SEvan Yan led_state = PCIE_HP_LED_OFF;
184326947304SEvan Yan else if (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) == 0)
184426947304SEvan Yan led_state = PCIE_HP_LED_BLINK;
184526947304SEvan Yan
184626947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED,
184726947304SEvan Yan led_state);
184826947304SEvan Yan }
184926947304SEvan Yan }
185024fd5dc4SEvan Yan if (rval) {
185124fd5dc4SEvan Yan if (get_udatamodel() == DATAMODEL_NATIVE) {
185224fd5dc4SEvan Yan result.buf_size = 0;
185324fd5dc4SEvan Yan if (copyout(&result, rval, sizeof (ddi_hp_property_t)))
185424fd5dc4SEvan Yan ret = DDI_FAILURE;
185524fd5dc4SEvan Yan }
185624fd5dc4SEvan Yan #ifdef _SYSCALL32_IMPL
185724fd5dc4SEvan Yan else {
185824fd5dc4SEvan Yan result32.buf_size = 0;
185924fd5dc4SEvan Yan if (copyout(&result32, rval,
186024fd5dc4SEvan Yan sizeof (ddi_hp_property32_t)))
186124fd5dc4SEvan Yan ret = DDI_FAILURE;
186224fd5dc4SEvan Yan }
186324fd5dc4SEvan Yan #endif
186424fd5dc4SEvan Yan }
186526947304SEvan Yan
186626947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex);
186726947304SEvan Yan set_prop_cleanup:
186826947304SEvan Yan nvlist_free(prop_list);
186926947304SEvan Yan return (ret);
187026947304SEvan Yan }
187126947304SEvan Yan
187226947304SEvan Yan /*
187326947304SEvan Yan * Send a command to the PCI-E Hot Plug Controller.
187426947304SEvan Yan *
187526947304SEvan Yan * NOTES: The PCI-E spec defines the following semantics for issuing hot plug
187626947304SEvan Yan * commands.
187726947304SEvan Yan * 1) If Command Complete events/interrupts are supported then software
187826947304SEvan Yan * waits for Command Complete event after issuing a command (i.e writing
187926947304SEvan Yan * to the Slot Control register). The command completion could take as
188026947304SEvan Yan * long as 1 second so software should be prepared to wait for 1 second
188126947304SEvan Yan * before issuing another command.
188226947304SEvan Yan *
188326947304SEvan Yan * 2) If Command Complete events/interrupts are not supported then
188426947304SEvan Yan * software could issue multiple Slot Control writes without any delay
188526947304SEvan Yan * between writes.
188626947304SEvan Yan */
188726947304SEvan Yan static void
pciehpc_issue_hpc_command(pcie_hp_ctrl_t * ctrl_p,uint16_t control)188826947304SEvan Yan pciehpc_issue_hpc_command(pcie_hp_ctrl_t *ctrl_p, uint16_t control)
188926947304SEvan Yan {
189026947304SEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
189126947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
189226947304SEvan Yan uint16_t status;
189326947304SEvan Yan uint32_t slot_cap;
189426947304SEvan Yan
189526947304SEvan Yan /*
189626947304SEvan Yan * PCI-E version 1.1 spec defines No Command Completed
189726947304SEvan Yan * Support bit (bit#18) in Slot Capabilities register. If this
189826947304SEvan Yan * bit is set then slot doesn't support notification of command
189926947304SEvan Yan * completion events.
190026947304SEvan Yan */
190126947304SEvan Yan slot_cap = pciehpc_reg_get32(ctrl_p,
190226947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCAP);
190326947304SEvan Yan
190426947304SEvan Yan /*
190526947304SEvan Yan * If no Command Completion event is supported or it is ACPI
190626947304SEvan Yan * hot plug mode then just issue the command and return.
190726947304SEvan Yan */
190826947304SEvan Yan if ((slot_cap & PCIE_SLOTCAP_NO_CMD_COMP_SUPP) ||
190926947304SEvan Yan (bus_p->bus_hp_curr_mode == PCIE_ACPI_HP_MODE)) {
191026947304SEvan Yan pciehpc_reg_put16(ctrl_p,
191126947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
191226947304SEvan Yan return;
191326947304SEvan Yan }
191426947304SEvan Yan
191526947304SEvan Yan /*
191626947304SEvan Yan * **************************************
191726947304SEvan Yan * Command Complete events are supported.
191826947304SEvan Yan * **************************************
191926947304SEvan Yan */
192026947304SEvan Yan
192126947304SEvan Yan /*
192226947304SEvan Yan * If HPC is not yet initialized then just poll for the Command
192326947304SEvan Yan * Completion interrupt.
192426947304SEvan Yan */
192526947304SEvan Yan if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
192626947304SEvan Yan int retry = PCIE_HP_CMD_WAIT_RETRY;
192726947304SEvan Yan
192826947304SEvan Yan /* write the command to the HPC */
192926947304SEvan Yan pciehpc_reg_put16(ctrl_p,
193026947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
193126947304SEvan Yan
193226947304SEvan Yan /* poll for status completion */
193326947304SEvan Yan while (retry--) {
193426947304SEvan Yan /* wait for 10 msec before checking the status */
193526947304SEvan Yan delay(drv_usectohz(PCIE_HP_CMD_WAIT_TIME));
193626947304SEvan Yan
193726947304SEvan Yan status = pciehpc_reg_get16(ctrl_p,
193826947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
193926947304SEvan Yan
194026947304SEvan Yan if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
194126947304SEvan Yan /* clear the status bits */
194226947304SEvan Yan pciehpc_reg_put16(ctrl_p,
194326947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
194426947304SEvan Yan break;
194526947304SEvan Yan }
194626947304SEvan Yan }
194726947304SEvan Yan return;
194826947304SEvan Yan }
194926947304SEvan Yan
195026947304SEvan Yan /* HPC is already initialized */
195126947304SEvan Yan
195226947304SEvan Yan ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
195326947304SEvan Yan
195426947304SEvan Yan /*
195526947304SEvan Yan * If previous command is still pending then wait for its
195626947304SEvan Yan * completion. i.e cv_wait()
195726947304SEvan Yan */
195826947304SEvan Yan
195926947304SEvan Yan while (ctrl_p->hc_cmd_pending == B_TRUE)
196026947304SEvan Yan cv_wait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex);
196126947304SEvan Yan
196226947304SEvan Yan /*
196326947304SEvan Yan * Issue the command and wait for Command Completion or
196426947304SEvan Yan * the 1 sec timeout.
196526947304SEvan Yan */
196626947304SEvan Yan pciehpc_reg_put16(ctrl_p,
196726947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
196826947304SEvan Yan
196926947304SEvan Yan ctrl_p->hc_cmd_pending = B_TRUE;
197026947304SEvan Yan
197126947304SEvan Yan if (cv_timedwait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex,
197226947304SEvan Yan ddi_get_lbolt() + SEC_TO_TICK(1)) == -1) {
197326947304SEvan Yan
197426947304SEvan Yan /* it is a timeout */
197526947304SEvan Yan PCIE_DBG("pciehpc_issue_hpc_command: Command Complete"
197626947304SEvan Yan " interrupt is not received for slot %d\n",
197726947304SEvan Yan slot_p->hs_phy_slot_num);
197826947304SEvan Yan
197926947304SEvan Yan /* clear the status info in case interrupts are disabled? */
198026947304SEvan Yan status = pciehpc_reg_get16(ctrl_p,
198126947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS);
198226947304SEvan Yan
198326947304SEvan Yan if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
198426947304SEvan Yan /* clear the status bits */
198526947304SEvan Yan pciehpc_reg_put16(ctrl_p,
198626947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
198726947304SEvan Yan }
198826947304SEvan Yan }
198926947304SEvan Yan
199026947304SEvan Yan ctrl_p->hc_cmd_pending = B_FALSE;
199126947304SEvan Yan
199226947304SEvan Yan /* wake up any one waiting for issuing another command to HPC */
199326947304SEvan Yan cv_signal(&ctrl_p->hc_cmd_comp_cv);
199426947304SEvan Yan }
199526947304SEvan Yan
199626947304SEvan Yan /*
199726947304SEvan Yan * pciehcp_attn_btn_handler()
199826947304SEvan Yan *
199926947304SEvan Yan * This handles ATTN button pressed event as per the PCI-E 1.1 spec.
200026947304SEvan Yan */
200126947304SEvan Yan static void
pciehpc_attn_btn_handler(pcie_hp_ctrl_t * ctrl_p)200226947304SEvan Yan pciehpc_attn_btn_handler(pcie_hp_ctrl_t *ctrl_p)
200326947304SEvan Yan {
200426947304SEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
200526947304SEvan Yan pcie_hp_led_state_t power_led_state;
200626947304SEvan Yan callb_cpr_t cprinfo;
200726947304SEvan Yan
200826947304SEvan Yan PCIE_DBG("pciehpc_attn_btn_handler: thread started\n");
200926947304SEvan Yan
201026947304SEvan Yan CALLB_CPR_INIT(&cprinfo, &ctrl_p->hc_mutex, callb_generic_cpr,
201126947304SEvan Yan "pciehpc_attn_btn_handler");
201226947304SEvan Yan
201326947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex);
201426947304SEvan Yan
201526947304SEvan Yan /* wait for ATTN button event */
201626947304SEvan Yan cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
201726947304SEvan Yan
201826947304SEvan Yan while (slot_p->hs_attn_btn_thread_exit == B_FALSE) {
201926947304SEvan Yan if (slot_p->hs_attn_btn_pending == B_TRUE) {
202026947304SEvan Yan /* get the current state of power LED */
202126947304SEvan Yan power_led_state = pciehpc_get_led_state(ctrl_p,
202226947304SEvan Yan PCIE_HP_POWER_LED);
202326947304SEvan Yan
202426947304SEvan Yan /* Blink the Power LED while we wait for 5 seconds */
202526947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
202626947304SEvan Yan PCIE_HP_LED_BLINK);
202726947304SEvan Yan
202826947304SEvan Yan /* wait for 5 seconds before taking any action */
202926947304SEvan Yan if (cv_timedwait(&slot_p->hs_attn_btn_cv,
203026947304SEvan Yan &ctrl_p->hc_mutex,
203126947304SEvan Yan ddi_get_lbolt() + SEC_TO_TICK(5)) == -1) {
203226947304SEvan Yan /*
203326947304SEvan Yan * It is a time out; make sure the ATTN pending
203426947304SEvan Yan * flag is still ON before sending the event to
203526947304SEvan Yan * DDI HP framework.
203626947304SEvan Yan */
203726947304SEvan Yan if (slot_p->hs_attn_btn_pending == B_TRUE) {
203826947304SEvan Yan int hint;
203926947304SEvan Yan
204026947304SEvan Yan slot_p->hs_attn_btn_pending = B_FALSE;
204126947304SEvan Yan pciehpc_get_slot_state(slot_p);
204226947304SEvan Yan
204326947304SEvan Yan if (slot_p->hs_info.cn_state <=
204426947304SEvan Yan DDI_HP_CN_STATE_PRESENT) {
204526947304SEvan Yan /*
204626947304SEvan Yan * Insertion.
204726947304SEvan Yan */
204826947304SEvan Yan hint = SE_INCOMING_RES;
204926947304SEvan Yan } else {
205026947304SEvan Yan /*
205126947304SEvan Yan * Want to remove;
205226947304SEvan Yan */
205326947304SEvan Yan hint = SE_OUTGOING_RES;
205426947304SEvan Yan }
205526947304SEvan Yan
205626947304SEvan Yan /*
205726947304SEvan Yan * We can't call ddihp_cn_gen_sysevent
205826947304SEvan Yan * here since it's not a DDI interface.
205926947304SEvan Yan */
206026947304SEvan Yan pcie_hp_gen_sysevent_req(
206126947304SEvan Yan slot_p->hs_info.cn_name,
206226947304SEvan Yan hint,
206326947304SEvan Yan ctrl_p->hc_dip,
206426947304SEvan Yan KM_SLEEP);
206526947304SEvan Yan }
206626947304SEvan Yan }
206726947304SEvan Yan
206826947304SEvan Yan /* restore the power LED state */
206926947304SEvan Yan pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
207026947304SEvan Yan power_led_state);
207126947304SEvan Yan continue;
207226947304SEvan Yan }
207326947304SEvan Yan
207426947304SEvan Yan /* wait for another ATTN button event */
207526947304SEvan Yan cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
207626947304SEvan Yan }
207726947304SEvan Yan
207826947304SEvan Yan PCIE_DBG("pciehpc_attn_btn_handler: thread exit\n");
207926947304SEvan Yan cv_signal(&slot_p->hs_attn_btn_cv);
208026947304SEvan Yan CALLB_CPR_EXIT(&cprinfo);
208126947304SEvan Yan thread_exit();
208226947304SEvan Yan }
208326947304SEvan Yan
208426947304SEvan Yan /*
208526947304SEvan Yan * convert LED state from PCIE HPC definition to pcie_hp_led_state_t
208626947304SEvan Yan * definition.
208726947304SEvan Yan */
208826947304SEvan Yan static pcie_hp_led_state_t
pciehpc_led_state_to_hpc(uint16_t state)208926947304SEvan Yan pciehpc_led_state_to_hpc(uint16_t state)
209026947304SEvan Yan {
209126947304SEvan Yan switch (state) {
209226947304SEvan Yan case PCIE_SLOTCTL_INDICATOR_STATE_ON:
209326947304SEvan Yan return (PCIE_HP_LED_ON);
209426947304SEvan Yan case PCIE_SLOTCTL_INDICATOR_STATE_BLINK:
209526947304SEvan Yan return (PCIE_HP_LED_BLINK);
209626947304SEvan Yan case PCIE_SLOTCTL_INDICATOR_STATE_OFF:
209726947304SEvan Yan default:
209826947304SEvan Yan return (PCIE_HP_LED_OFF);
209926947304SEvan Yan }
210026947304SEvan Yan }
210126947304SEvan Yan
210226947304SEvan Yan /*
210326947304SEvan Yan * Get the state of an LED.
210426947304SEvan Yan */
210526947304SEvan Yan static pcie_hp_led_state_t
pciehpc_get_led_state(pcie_hp_ctrl_t * ctrl_p,pcie_hp_led_t led)210626947304SEvan Yan pciehpc_get_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led)
210726947304SEvan Yan {
210826947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
210926947304SEvan Yan uint16_t control, state;
211026947304SEvan Yan
211126947304SEvan Yan /* get the current state of Slot Control register */
211226947304SEvan Yan control = pciehpc_reg_get16(ctrl_p,
211326947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
211426947304SEvan Yan
211526947304SEvan Yan switch (led) {
211626947304SEvan Yan case PCIE_HP_POWER_LED:
211726947304SEvan Yan state = pcie_slotctl_pwr_indicator_get(control);
211826947304SEvan Yan break;
211926947304SEvan Yan case PCIE_HP_ATTN_LED:
212026947304SEvan Yan state = pcie_slotctl_attn_indicator_get(control);
212126947304SEvan Yan break;
212226947304SEvan Yan default:
212326947304SEvan Yan PCIE_DBG("pciehpc_get_led_state() invalid LED %d\n", led);
212426947304SEvan Yan return (PCIE_HP_LED_OFF);
212526947304SEvan Yan }
212626947304SEvan Yan
212726947304SEvan Yan switch (state) {
212826947304SEvan Yan case PCIE_SLOTCTL_INDICATOR_STATE_ON:
212926947304SEvan Yan return (PCIE_HP_LED_ON);
213026947304SEvan Yan
213126947304SEvan Yan case PCIE_SLOTCTL_INDICATOR_STATE_BLINK:
213226947304SEvan Yan return (PCIE_HP_LED_BLINK);
213326947304SEvan Yan
213426947304SEvan Yan case PCIE_SLOTCTL_INDICATOR_STATE_OFF:
213526947304SEvan Yan default:
213626947304SEvan Yan return (PCIE_HP_LED_OFF);
213726947304SEvan Yan }
213826947304SEvan Yan }
213926947304SEvan Yan
214026947304SEvan Yan /*
214126947304SEvan Yan * Set the state of an LED. It updates both hw and sw state.
214226947304SEvan Yan */
214326947304SEvan Yan static void
pciehpc_set_led_state(pcie_hp_ctrl_t * ctrl_p,pcie_hp_led_t led,pcie_hp_led_state_t state)214426947304SEvan Yan pciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led,
214526947304SEvan Yan pcie_hp_led_state_t state)
214626947304SEvan Yan {
214726947304SEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
214826947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
214926947304SEvan Yan uint16_t control;
215026947304SEvan Yan
215126947304SEvan Yan /* get the current state of Slot Control register */
215226947304SEvan Yan control = pciehpc_reg_get16(ctrl_p,
215326947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
215426947304SEvan Yan
215526947304SEvan Yan switch (led) {
215626947304SEvan Yan case PCIE_HP_POWER_LED:
215726947304SEvan Yan /* clear led mask */
215826947304SEvan Yan control &= ~PCIE_SLOTCTL_PWR_INDICATOR_MASK;
215926947304SEvan Yan slot_p->hs_power_led_state = state;
216026947304SEvan Yan break;
216126947304SEvan Yan case PCIE_HP_ATTN_LED:
216226947304SEvan Yan /* clear led mask */
216326947304SEvan Yan control &= ~PCIE_SLOTCTL_ATTN_INDICATOR_MASK;
216426947304SEvan Yan slot_p->hs_attn_led_state = state;
216526947304SEvan Yan break;
216626947304SEvan Yan default:
216726947304SEvan Yan PCIE_DBG("pciehpc_set_led_state() invalid LED %d\n", led);
216826947304SEvan Yan return;
216926947304SEvan Yan }
217026947304SEvan Yan
217126947304SEvan Yan switch (state) {
217226947304SEvan Yan case PCIE_HP_LED_ON:
217326947304SEvan Yan if (led == PCIE_HP_POWER_LED)
217426947304SEvan Yan control = pcie_slotctl_pwr_indicator_set(control,
217526947304SEvan Yan PCIE_SLOTCTL_INDICATOR_STATE_ON);
217626947304SEvan Yan else if (led == PCIE_HP_ATTN_LED)
217726947304SEvan Yan control = pcie_slotctl_attn_indicator_set(control,
217826947304SEvan Yan PCIE_SLOTCTL_INDICATOR_STATE_ON);
217926947304SEvan Yan break;
218026947304SEvan Yan case PCIE_HP_LED_OFF:
218126947304SEvan Yan if (led == PCIE_HP_POWER_LED)
218226947304SEvan Yan control = pcie_slotctl_pwr_indicator_set(control,
218326947304SEvan Yan PCIE_SLOTCTL_INDICATOR_STATE_OFF);
218426947304SEvan Yan else if (led == PCIE_HP_ATTN_LED)
218526947304SEvan Yan control = pcie_slotctl_attn_indicator_set(control,
218626947304SEvan Yan PCIE_SLOTCTL_INDICATOR_STATE_OFF);
218726947304SEvan Yan break;
218826947304SEvan Yan case PCIE_HP_LED_BLINK:
218926947304SEvan Yan if (led == PCIE_HP_POWER_LED)
219026947304SEvan Yan control = pcie_slotctl_pwr_indicator_set(control,
219126947304SEvan Yan PCIE_SLOTCTL_INDICATOR_STATE_BLINK);
219226947304SEvan Yan else if (led == PCIE_HP_ATTN_LED)
219326947304SEvan Yan control = pcie_slotctl_attn_indicator_set(control,
219426947304SEvan Yan PCIE_SLOTCTL_INDICATOR_STATE_BLINK);
219526947304SEvan Yan break;
219626947304SEvan Yan
219726947304SEvan Yan default:
219826947304SEvan Yan PCIE_DBG("pciehpc_set_led_state() invalid LED state %d\n",
219926947304SEvan Yan state);
220026947304SEvan Yan return;
220126947304SEvan Yan }
220226947304SEvan Yan
220326947304SEvan Yan /* update the Slot Control Register */
220426947304SEvan Yan pciehpc_issue_hpc_command(ctrl_p, control);
220526947304SEvan Yan
220626947304SEvan Yan #ifdef DEBUG
220726947304SEvan Yan /* get the current state of Slot Control register */
220826947304SEvan Yan control = pciehpc_reg_get16(ctrl_p,
220926947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
221026947304SEvan Yan
221126947304SEvan Yan PCIE_DBG("pciehpc_set_led_state: slot %d power-led %s attn-led %s\n",
221226947304SEvan Yan slot_p->hs_phy_slot_num, pcie_led_state_text(
221326947304SEvan Yan pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control))),
221426947304SEvan Yan pcie_led_state_text(pciehpc_led_state_to_hpc(
221526947304SEvan Yan pcie_slotctl_attn_indicator_get(control))));
221626947304SEvan Yan #endif
221726947304SEvan Yan }
221826947304SEvan Yan
2219*80dc702dSColin Zou - Sun Microsystems - Beijing China static void
pciehpc_handle_power_fault(dev_info_t * dip)2220*80dc702dSColin Zou - Sun Microsystems - Beijing China pciehpc_handle_power_fault(dev_info_t *dip)
2221*80dc702dSColin Zou - Sun Microsystems - Beijing China {
2222*80dc702dSColin Zou - Sun Microsystems - Beijing China /*
2223*80dc702dSColin Zou - Sun Microsystems - Beijing China * Hold the parent's ref so that it won't disappear when the taskq is
2224*80dc702dSColin Zou - Sun Microsystems - Beijing China * scheduled to run.
2225*80dc702dSColin Zou - Sun Microsystems - Beijing China */
2226*80dc702dSColin Zou - Sun Microsystems - Beijing China ndi_hold_devi(dip);
2227*80dc702dSColin Zou - Sun Microsystems - Beijing China
2228*80dc702dSColin Zou - Sun Microsystems - Beijing China if (!taskq_dispatch(system_taskq, pciehpc_power_fault_handler, dip,
2229*80dc702dSColin Zou - Sun Microsystems - Beijing China TQ_NOSLEEP)) {
2230*80dc702dSColin Zou - Sun Microsystems - Beijing China ndi_rele_devi(dip);
2231*80dc702dSColin Zou - Sun Microsystems - Beijing China PCIE_DBG("pciehpc_intr(): "
2232*80dc702dSColin Zou - Sun Microsystems - Beijing China "Failed to dispatch power fault handler, dip %p\n", dip);
2233*80dc702dSColin Zou - Sun Microsystems - Beijing China }
2234*80dc702dSColin Zou - Sun Microsystems - Beijing China }
2235*80dc702dSColin Zou - Sun Microsystems - Beijing China
2236*80dc702dSColin Zou - Sun Microsystems - Beijing China static void
pciehpc_power_fault_handler(void * arg)2237*80dc702dSColin Zou - Sun Microsystems - Beijing China pciehpc_power_fault_handler(void *arg)
2238*80dc702dSColin Zou - Sun Microsystems - Beijing China {
2239*80dc702dSColin Zou - Sun Microsystems - Beijing China dev_info_t *dip = (dev_info_t *)arg;
2240*80dc702dSColin Zou - Sun Microsystems - Beijing China pcie_hp_ctrl_t *ctrl_p;
2241*80dc702dSColin Zou - Sun Microsystems - Beijing China pcie_hp_slot_t *slot_p;
2242*80dc702dSColin Zou - Sun Microsystems - Beijing China
2243*80dc702dSColin Zou - Sun Microsystems - Beijing China /* get the soft state structure for this dip */
2244*80dc702dSColin Zou - Sun Microsystems - Beijing China if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) {
2245*80dc702dSColin Zou - Sun Microsystems - Beijing China ndi_rele_devi(dip);
2246*80dc702dSColin Zou - Sun Microsystems - Beijing China return;
2247*80dc702dSColin Zou - Sun Microsystems - Beijing China }
2248*80dc702dSColin Zou - Sun Microsystems - Beijing China slot_p = ctrl_p->hc_slots[0];
2249*80dc702dSColin Zou - Sun Microsystems - Beijing China
2250*80dc702dSColin Zou - Sun Microsystems - Beijing China /*
2251*80dc702dSColin Zou - Sun Microsystems - Beijing China * Send the event to DDI Hotplug framework, power off
2252*80dc702dSColin Zou - Sun Microsystems - Beijing China * the slot
2253*80dc702dSColin Zou - Sun Microsystems - Beijing China */
2254*80dc702dSColin Zou - Sun Microsystems - Beijing China (void) ndi_hp_state_change_req(dip,
2255*80dc702dSColin Zou - Sun Microsystems - Beijing China slot_p->hs_info.cn_name,
2256*80dc702dSColin Zou - Sun Microsystems - Beijing China DDI_HP_CN_STATE_EMPTY, DDI_HP_REQ_SYNC);
2257*80dc702dSColin Zou - Sun Microsystems - Beijing China
2258*80dc702dSColin Zou - Sun Microsystems - Beijing China mutex_enter(&ctrl_p->hc_mutex);
2259*80dc702dSColin Zou - Sun Microsystems - Beijing China pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED,
2260*80dc702dSColin Zou - Sun Microsystems - Beijing China PCIE_HP_LED_ON);
2261*80dc702dSColin Zou - Sun Microsystems - Beijing China mutex_exit(&ctrl_p->hc_mutex);
2262*80dc702dSColin Zou - Sun Microsystems - Beijing China ndi_rele_devi(dip);
2263*80dc702dSColin Zou - Sun Microsystems - Beijing China }
2264*80dc702dSColin Zou - Sun Microsystems - Beijing China
226526947304SEvan Yan #ifdef DEBUG
226626947304SEvan Yan /*
226726947304SEvan Yan * Dump PCI-E Hot Plug registers.
226826947304SEvan Yan */
226926947304SEvan Yan static void
pciehpc_dump_hpregs(pcie_hp_ctrl_t * ctrl_p)227026947304SEvan Yan pciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p)
227126947304SEvan Yan {
227226947304SEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
227326947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
227426947304SEvan Yan uint16_t control;
227526947304SEvan Yan uint32_t capabilities;
227626947304SEvan Yan
227726947304SEvan Yan if (!pcie_debug_flags)
227826947304SEvan Yan return;
227926947304SEvan Yan
228026947304SEvan Yan capabilities = pciehpc_reg_get32(ctrl_p,
228126947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCAP);
228226947304SEvan Yan
228326947304SEvan Yan control = pciehpc_reg_get16(ctrl_p,
228426947304SEvan Yan bus_p->bus_pcie_off + PCIE_SLOTCTL);
228526947304SEvan Yan
228626947304SEvan Yan PCIE_DBG("pciehpc_dump_hpregs: Found PCI-E hot plug slot %d\n",
228726947304SEvan Yan slot_p->hs_phy_slot_num);
228826947304SEvan Yan
228926947304SEvan Yan PCIE_DBG("Attention Button Present = %s\n",
229026947304SEvan Yan capabilities & PCIE_SLOTCAP_ATTN_BUTTON ? "Yes":"No");
229126947304SEvan Yan
229226947304SEvan Yan PCIE_DBG("Power controller Present = %s\n",
229326947304SEvan Yan capabilities & PCIE_SLOTCAP_POWER_CONTROLLER ? "Yes":"No");
229426947304SEvan Yan
229526947304SEvan Yan PCIE_DBG("MRL Sensor Present = %s\n",
229626947304SEvan Yan capabilities & PCIE_SLOTCAP_MRL_SENSOR ? "Yes":"No");
229726947304SEvan Yan
229826947304SEvan Yan PCIE_DBG("Attn Indicator Present = %s\n",
229926947304SEvan Yan capabilities & PCIE_SLOTCAP_ATTN_INDICATOR ? "Yes":"No");
230026947304SEvan Yan
230126947304SEvan Yan PCIE_DBG("Power Indicator Present = %s\n",
230226947304SEvan Yan capabilities & PCIE_SLOTCAP_PWR_INDICATOR ? "Yes":"No");
230326947304SEvan Yan
230426947304SEvan Yan PCIE_DBG("HotPlug Surprise = %s\n",
230526947304SEvan Yan capabilities & PCIE_SLOTCAP_HP_SURPRISE ? "Yes":"No");
230626947304SEvan Yan
230726947304SEvan Yan PCIE_DBG("HotPlug Capable = %s\n",
230826947304SEvan Yan capabilities & PCIE_SLOTCAP_HP_CAPABLE ? "Yes":"No");
230926947304SEvan Yan
231026947304SEvan Yan PCIE_DBG("Physical Slot Number = %d\n",
231126947304SEvan Yan PCIE_SLOTCAP_PHY_SLOT_NUM(capabilities));
231226947304SEvan Yan
231326947304SEvan Yan PCIE_DBG("Attn Button interrupt Enabled = %s\n",
231426947304SEvan Yan control & PCIE_SLOTCTL_ATTN_BTN_EN ? "Yes":"No");
231526947304SEvan Yan
231626947304SEvan Yan PCIE_DBG("Power Fault interrupt Enabled = %s\n",
231726947304SEvan Yan control & PCIE_SLOTCTL_PWR_FAULT_EN ? "Yes":"No");
231826947304SEvan Yan
231926947304SEvan Yan PCIE_DBG("MRL Sensor INTR Enabled = %s\n",
232026947304SEvan Yan control & PCIE_SLOTCTL_MRL_SENSOR_EN ? "Yes":"No");
232126947304SEvan Yan
232226947304SEvan Yan PCIE_DBG("Presence interrupt Enabled = %s\n",
232326947304SEvan Yan control & PCIE_SLOTCTL_PRESENCE_CHANGE_EN ? "Yes":"No");
232426947304SEvan Yan
232526947304SEvan Yan PCIE_DBG("Cmd Complete interrupt Enabled = %s\n",
232626947304SEvan Yan control & PCIE_SLOTCTL_CMD_INTR_EN ? "Yes":"No");
232726947304SEvan Yan
232826947304SEvan Yan PCIE_DBG("HotPlug interrupt Enabled = %s\n",
232926947304SEvan Yan control & PCIE_SLOTCTL_HP_INTR_EN ? "Yes":"No");
233026947304SEvan Yan
233126947304SEvan Yan PCIE_DBG("Power Indicator LED = %s", pcie_led_state_text(
233226947304SEvan Yan pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control))));
233326947304SEvan Yan
233426947304SEvan Yan PCIE_DBG("Attn Indicator LED = %s\n",
233526947304SEvan Yan pcie_led_state_text(pciehpc_led_state_to_hpc(
233626947304SEvan Yan pcie_slotctl_attn_indicator_get(control))));
233726947304SEvan Yan }
233826947304SEvan Yan #endif /* DEBUG */
2339