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 /* 22*70f83219SEvan Yan * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 2326947304SEvan Yan * Use is subject to license terms. 2426947304SEvan Yan */ 2526947304SEvan Yan 2626947304SEvan Yan /* 2726947304SEvan Yan * This file contains PCI HotPlug functionality that is compatible with the 2826947304SEvan Yan * PCI SHPC specification 1.x. 2926947304SEvan Yan * 3026947304SEvan Yan * NOTE: This file is compiled and delivered through misc/pcie module. 3126947304SEvan Yan */ 3226947304SEvan Yan 3326947304SEvan Yan #include <sys/note.h> 3426947304SEvan Yan #include <sys/conf.h> 3526947304SEvan Yan #include <sys/kmem.h> 3626947304SEvan Yan #include <sys/kstat.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/hwconf.h> 4226947304SEvan Yan #include <sys/ddi_impldefs.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/ndi_impldefs.h> 4926947304SEvan Yan #include <sys/pci_impl.h> 5026947304SEvan Yan #include <sys/hotplug/pci/pcie_hp.h> 5126947304SEvan Yan #include <sys/hotplug/pci/pcishpc.h> 5226947304SEvan Yan 5326947304SEvan Yan typedef struct pcishpc_prop { 5426947304SEvan Yan char *prop_name; 5526947304SEvan Yan char *prop_value; 5626947304SEvan Yan } pcishpc_prop_t; 5726947304SEvan Yan 5826947304SEvan Yan static pcishpc_prop_t pcishpc_props[] = { 5926947304SEvan Yan { PCIEHPC_PROP_LED_FAULT, PCIEHPC_PROP_VALUE_LED }, 6026947304SEvan Yan { PCIEHPC_PROP_LED_POWER, PCIEHPC_PROP_VALUE_LED }, 6126947304SEvan Yan { PCIEHPC_PROP_LED_ATTN, PCIEHPC_PROP_VALUE_LED }, 6226947304SEvan Yan { PCIEHPC_PROP_LED_ACTIVE, PCIEHPC_PROP_VALUE_LED }, 6326947304SEvan Yan { PCIEHPC_PROP_CARD_TYPE, PCIEHPC_PROP_VALUE_TYPE }, 6426947304SEvan Yan { PCIEHPC_PROP_BOARD_TYPE, PCIEHPC_PROP_VALUE_TYPE }, 6526947304SEvan Yan { PCIEHPC_PROP_SLOT_CONDITION, PCIEHPC_PROP_VALUE_TYPE } 6626947304SEvan Yan }; 6726947304SEvan Yan 6826947304SEvan Yan /* reset delay to 1 sec. */ 6926947304SEvan Yan static int pcishpc_reset_delay = 1000000; 7026947304SEvan Yan 7126947304SEvan Yan /* Local function prototype */ 7226947304SEvan Yan static pcie_hp_ctrl_t *pcishpc_create_controller(dev_info_t *dip); 7326947304SEvan Yan static int pcishpc_setup_controller(pcie_hp_ctrl_t *ctrl_p); 7426947304SEvan Yan static int pcishpc_destroy_controller(dev_info_t *dip); 7526947304SEvan Yan static pcie_hp_slot_t *pcishpc_create_slot(pcie_hp_ctrl_t *ctrl_p); 7626947304SEvan Yan static int pcishpc_register_slot(pcie_hp_ctrl_t *ctrl_p, int slot); 7726947304SEvan Yan static int pcishpc_destroy_slots(pcie_hp_ctrl_t *ctrl_p); 7826947304SEvan Yan static int pcishpc_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 pcishpc_slot_set_property(pcie_hp_slot_t *slot_p, 8126947304SEvan Yan ddi_hp_property_t *arg, ddi_hp_property_t *rval); 8226947304SEvan Yan static int pcishpc_issue_command(pcie_hp_ctrl_t *ctrl_p, 8326947304SEvan Yan uint32_t cmd_code); 8426947304SEvan Yan static int pcishpc_wait_busy(pcie_hp_ctrl_t *ctrl_p); 8526947304SEvan Yan static void pcishpc_attn_btn_handler(pcie_hp_slot_t *slot_p); 8626947304SEvan Yan static void pcishpc_get_slot_state(pcie_hp_slot_t *slot_p); 8726947304SEvan Yan static int pcishpc_set_slot_state(pcie_hp_slot_t *slot_p, 8826947304SEvan Yan ddi_hp_cn_state_t new_slot_state); 8926947304SEvan Yan static void pcishpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p, int slot); 9026947304SEvan Yan static int pcishpc_set_bus_speed(pcie_hp_slot_t *slot_p); 9126947304SEvan Yan static int pcishpc_setled(pcie_hp_slot_t *slot_p, pcie_hp_led_t led, 9226947304SEvan Yan pcie_hp_led_state_t state); 9326947304SEvan Yan static int pcishpc_led_shpc_to_hpc(int state); 9426947304SEvan Yan static int pcishpc_led_hpc_to_shpc(int state); 9526947304SEvan Yan static int pcishpc_slot_shpc_to_hpc(int shpc_state); 9626947304SEvan Yan static int pcishpc_slot_hpc_to_shpc(int state); 9726947304SEvan Yan static char *pcishpc_slot_textslotstate(ddi_hp_cn_state_t state); 9826947304SEvan Yan static char *pcishpc_slot_textledstate(pcie_hp_led_state_t state); 9926947304SEvan Yan 10026947304SEvan Yan static uint32_t pcishpc_read_reg(pcie_hp_ctrl_t *ctrl_p, int reg); 10126947304SEvan Yan static void pcishpc_write_reg(pcie_hp_ctrl_t *ctrl_p, int reg, 10226947304SEvan Yan uint32_t data); 10326947304SEvan Yan 10426947304SEvan Yan static int pcishpc_upgrade_slot_state(pcie_hp_slot_t *slot_p, 10526947304SEvan Yan ddi_hp_cn_state_t target_state); 10626947304SEvan Yan static int pcishpc_downgrade_slot_state(pcie_hp_slot_t *slot_p, 10726947304SEvan Yan ddi_hp_cn_state_t target_state); 10826947304SEvan Yan static int pcishpc_change_slot_state(pcie_hp_slot_t *slot_p, 10926947304SEvan Yan ddi_hp_cn_state_t target_state); 11026947304SEvan Yan 11126947304SEvan Yan static int pcishpc_slot_poweron(pcie_hp_slot_t *slot_p, 11226947304SEvan Yan ddi_hp_cn_state_t *result_state); 11326947304SEvan Yan static int pcishpc_slot_poweroff(pcie_hp_slot_t *slot_p, 11426947304SEvan Yan ddi_hp_cn_state_t *result_state); 11526947304SEvan Yan static int pcishpc_slot_probe(pcie_hp_slot_t *slot_p); 11626947304SEvan Yan static int pcishpc_slot_unprobe(pcie_hp_slot_t *slot_p); 11726947304SEvan Yan #ifdef DEBUG 11826947304SEvan Yan static void pcishpc_dump_regs(pcie_hp_ctrl_t *ctrl_p); 11926947304SEvan Yan #endif /* DEBUG */ 12026947304SEvan Yan 12126947304SEvan Yan 12226947304SEvan Yan /* 12326947304SEvan Yan * Global functions (called by other drivers/modules) 12426947304SEvan Yan */ 12526947304SEvan Yan 12626947304SEvan Yan /* 12726947304SEvan Yan * pcishpc_init() 12826947304SEvan Yan * 12926947304SEvan Yan * Install and configure an SHPC controller and register the HotPlug slots 13026947304SEvan Yan * with the Solaris HotPlug framework. This function is usually called by 13126947304SEvan Yan * a PCI bridge Nexus driver that has a built in SHPC controller. 13226947304SEvan Yan */ 13326947304SEvan Yan int 13426947304SEvan Yan pcishpc_init(dev_info_t *dip) 13526947304SEvan Yan { 13626947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 13726947304SEvan Yan pcie_hp_ctrl_t *ctrl_p; 13826947304SEvan Yan int i; 13926947304SEvan Yan 14026947304SEvan Yan PCIE_DBG("pcishpc_init() called from %s#%d\n", 14126947304SEvan Yan ddi_driver_name(dip), ddi_get_instance(dip)); 14226947304SEvan Yan 14326947304SEvan Yan if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) != NULL) { 14426947304SEvan Yan PCIE_DBG("pcishpc_init() shpc instance already " 14526947304SEvan Yan "initialized!\n"); 14626947304SEvan Yan return (DDI_SUCCESS); 14726947304SEvan Yan } 14826947304SEvan Yan 14926947304SEvan Yan /* Initialize soft state structure for the SHPC instance. */ 15026947304SEvan Yan ctrl_p = pcishpc_create_controller(dip); 15126947304SEvan Yan 15226947304SEvan Yan if (ctrl_p == NULL) { 15326947304SEvan Yan PCIE_DBG("pcishpc_init() failed to create shpc softstate\n"); 15426947304SEvan Yan return (DDI_FAILURE); 15526947304SEvan Yan } 15626947304SEvan Yan 15726947304SEvan Yan if (pcishpc_setup_controller(ctrl_p) != DDI_SUCCESS) { 15826947304SEvan Yan PCIE_DBG("pcishpc_init() failed to setup controller\n"); 15926947304SEvan Yan goto cleanup; 16026947304SEvan Yan } 16126947304SEvan Yan 16226947304SEvan Yan /* 16326947304SEvan Yan * Setup resource maps for this bus node. 16426947304SEvan Yan */ 16526947304SEvan Yan (void) pci_resource_setup(dip); 16626947304SEvan Yan 16726947304SEvan Yan #ifdef DEBUG 16826947304SEvan Yan PCIE_DBG("%s%d: P2P bridge register dump:\n", 16926947304SEvan Yan ddi_driver_name(dip), ddi_get_instance(dip)); 17026947304SEvan Yan 17126947304SEvan Yan for (i = 0; i < 0x100; i += 4) { 17226947304SEvan Yan PCIE_DBG("SHPC Cfg reg 0x%02x: %08x\n", i, 17326947304SEvan Yan pci_config_get32(bus_p->bus_cfg_hdl, i)); 17426947304SEvan Yan } 17526947304SEvan Yan #endif /* DEBUG */ 17626947304SEvan Yan 17726947304SEvan Yan /* Setup each HotPlug slot on this SHPC controller. */ 17826947304SEvan Yan for (i = 0; i < ctrl_p->hc_num_slots_impl; i++) { 17926947304SEvan Yan if (pcishpc_register_slot(ctrl_p, i) != DDI_SUCCESS) { 18026947304SEvan Yan PCIE_DBG("pcishpc_init() failed to register " 18126947304SEvan Yan "slot %d\n", i); 18226947304SEvan Yan goto cleanup1; 18326947304SEvan Yan } 18426947304SEvan Yan if (pcie_create_minor_node(ctrl_p, i) != DDI_SUCCESS) { 18526947304SEvan Yan PCIE_DBG("pcishpc_init() failed to create " 18626947304SEvan Yan "minor node for slot %d\n", i); 18726947304SEvan Yan goto cleanup1; 18826947304SEvan Yan } 18926947304SEvan Yan } 19026947304SEvan Yan 19126947304SEvan Yan #ifdef DEBUG 19226947304SEvan Yan /* Dump out the SHPC registers. */ 19326947304SEvan Yan pcishpc_dump_regs(ctrl_p); 19426947304SEvan Yan #endif /* DEBUG */ 19526947304SEvan Yan 19626947304SEvan Yan PCIE_DBG("pcishpc_init() success(dip=%p)\n", dip); 19726947304SEvan Yan return (DDI_SUCCESS); 19826947304SEvan Yan 19926947304SEvan Yan cleanup1: 20026947304SEvan Yan for (i = 0; i < ctrl_p->hc_num_slots_impl; i++) { 20126947304SEvan Yan if (ctrl_p->hc_slots[i] == NULL) 20226947304SEvan Yan continue; 20326947304SEvan Yan 20426947304SEvan Yan pcie_remove_minor_node(ctrl_p, i); 20526947304SEvan Yan } 20626947304SEvan Yan (void) pci_resource_destroy(dip); 20726947304SEvan Yan cleanup: 20826947304SEvan Yan (void) pcishpc_destroy_controller(dip); 20926947304SEvan Yan return (DDI_FAILURE); 21026947304SEvan Yan } 21126947304SEvan Yan 21226947304SEvan Yan /* 21326947304SEvan Yan * pcishpc_uninit() 21426947304SEvan Yan * Unload the HogPlug controller driver and deallocate all resources. 21526947304SEvan Yan */ 21626947304SEvan Yan int 21726947304SEvan Yan pcishpc_uninit(dev_info_t *dip) 21826947304SEvan Yan { 21926947304SEvan Yan pcie_hp_ctrl_t *ctrl_p; 22026947304SEvan Yan int i; 22126947304SEvan Yan 22226947304SEvan Yan PCIE_DBG("pcishpc_uninit() called(dip=%p)\n", dip); 22326947304SEvan Yan 22426947304SEvan Yan ctrl_p = PCIE_GET_HP_CTRL(dip); 22526947304SEvan Yan 22626947304SEvan Yan if (!ctrl_p) { 22726947304SEvan Yan PCIE_DBG("pcishpc_uninit() Unable to find softstate\n"); 22826947304SEvan Yan return (DDI_FAILURE); 22926947304SEvan Yan } 23026947304SEvan Yan 23126947304SEvan Yan for (i = 0; i < PCIE_HP_MAX_SLOTS; i++) { 23226947304SEvan Yan if (ctrl_p->hc_slots[i] == NULL) 23326947304SEvan Yan continue; 23426947304SEvan Yan 23526947304SEvan Yan pcie_remove_minor_node(ctrl_p, i); 23626947304SEvan Yan } 23726947304SEvan Yan 23826947304SEvan Yan ctrl_p->hc_flags = 0; 23926947304SEvan Yan 24026947304SEvan Yan /* 24126947304SEvan Yan * Destroy resource maps for this bus node. 24226947304SEvan Yan */ 24326947304SEvan Yan (void) pci_resource_destroy(dip); 24426947304SEvan Yan 24526947304SEvan Yan (void) pcishpc_destroy_controller(dip); 24626947304SEvan Yan 24726947304SEvan Yan PCIE_DBG("pcishpc_uninit() success(dip=%p)\n", dip); 24826947304SEvan Yan 24926947304SEvan Yan return (DDI_SUCCESS); 25026947304SEvan Yan } 25126947304SEvan Yan 25226947304SEvan Yan /* 25326947304SEvan Yan * pcishpc_intr() 25426947304SEvan Yan * 25526947304SEvan Yan * This is the SHPC controller interrupt handler. 25626947304SEvan Yan */ 25726947304SEvan Yan int 25826947304SEvan Yan pcishpc_intr(dev_info_t *dip) 25926947304SEvan Yan { 26026947304SEvan Yan pcie_hp_ctrl_t *ctrl_p; 26126947304SEvan Yan uint32_t irq_locator, irq_serr_locator, reg; 26226947304SEvan Yan int slot; 26326947304SEvan Yan 26426947304SEvan Yan PCIE_DBG("pcishpc_intr() called\n"); 26526947304SEvan Yan 26626947304SEvan Yan /* get the soft state structure for this dip */ 26726947304SEvan Yan if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) 26826947304SEvan Yan return (DDI_INTR_UNCLAIMED); 26926947304SEvan Yan 27026947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex); 27126947304SEvan Yan 27226947304SEvan Yan if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) { 27326947304SEvan Yan PCIE_DBG("pcishpc_intr() unclaimed\n"); 27426947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex); 27526947304SEvan Yan return (DDI_INTR_UNCLAIMED); 27626947304SEvan Yan } 27726947304SEvan Yan 27826947304SEvan Yan PCIE_DBG("pcishpc_intr() interrupt received\n"); 27926947304SEvan Yan 28026947304SEvan Yan reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG); 28126947304SEvan Yan 28226947304SEvan Yan if (reg & PCI_HP_SERR_INT_CMD_COMPLETE_IRQ) { 28326947304SEvan Yan PCIE_DBG("pcishpc_intr() " 28426947304SEvan Yan "PCI_HP_SERR_INT_CMD_COMPLETE_IRQ detected\n"); 28526947304SEvan Yan ctrl_p->hc_cmd_pending = B_FALSE; 28626947304SEvan Yan cv_signal(&ctrl_p->hc_cmd_comp_cv); 28726947304SEvan Yan } 28826947304SEvan Yan 28926947304SEvan Yan if (reg & PCI_HP_SERR_INT_ARBITER_IRQ) { 29026947304SEvan Yan PCIE_DBG("pcishpc_intr() PCI_HP_SERR_INT_ARBITER_IRQ " 29126947304SEvan Yan "detected\n"); 29226947304SEvan Yan ctrl_p->hc_arbiter_timeout = B_TRUE; 29326947304SEvan Yan } 29426947304SEvan Yan 29526947304SEvan Yan /* Write back the SERR INT register to acknowledge the IRQs. */ 29626947304SEvan Yan pcishpc_write_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG, reg); 29726947304SEvan Yan 29826947304SEvan Yan irq_locator = pcishpc_read_reg(ctrl_p, PCI_HP_IRQ_LOCATOR_REG); 29926947304SEvan Yan irq_serr_locator = pcishpc_read_reg(ctrl_p, PCI_HP_SERR_LOCATOR_REG); 30026947304SEvan Yan 30126947304SEvan Yan /* Check for slot events that might have occured. */ 30226947304SEvan Yan for (slot = 0; slot < ctrl_p->hc_num_slots_impl; slot++) { 30326947304SEvan Yan if ((irq_locator & (PCI_HP_IRQ_SLOT_N_PENDING<<slot)) || 30426947304SEvan Yan (irq_serr_locator & 30526947304SEvan Yan (PCI_HP_IRQ_SERR_SLOT_N_PENDING<<slot))) { 30626947304SEvan Yan PCIE_DBG("pcishpc_intr() slot %d and " 30726947304SEvan Yan "pending IRQ\n", slot+1); 30826947304SEvan Yan 30926947304SEvan Yan reg = pcishpc_read_reg(ctrl_p, 31026947304SEvan Yan PCI_HP_LOGICAL_SLOT_REGS+slot); 31126947304SEvan Yan 31226947304SEvan Yan if (reg & PCI_HP_SLOT_PRESENCE_DETECTED) 31326947304SEvan Yan PCIE_DBG("slot %d: " 31426947304SEvan Yan "PCI_HP_SLOT_PRESENCE_DETECTED\n", 31526947304SEvan Yan slot+1); 31626947304SEvan Yan 31726947304SEvan Yan if (reg & PCI_HP_SLOT_ISO_PWR_DETECTED) 31826947304SEvan Yan PCIE_DBG("slot %d: " 31926947304SEvan Yan "PCI_HP_SLOT_ISO_PWR_DETECTED\n", 32026947304SEvan Yan slot+1); 32126947304SEvan Yan 32226947304SEvan Yan if (reg & PCI_HP_SLOT_ATTN_DETECTED) { 32326947304SEvan Yan PCIE_DBG("slot %d: " 32426947304SEvan Yan "PCI_HP_SLOT_ATTN_DETECTED\n", slot+1); 32526947304SEvan Yan 32626947304SEvan Yan /* 32726947304SEvan Yan * if ATTN button event is still pending 32826947304SEvan Yan * then cancel it 32926947304SEvan Yan */ 33026947304SEvan Yan if (ctrl_p->hc_slots[slot]-> 33126947304SEvan Yan hs_attn_btn_pending == B_TRUE) 33226947304SEvan Yan ctrl_p->hc_slots[slot]-> 33326947304SEvan Yan hs_attn_btn_pending = B_FALSE; 33426947304SEvan Yan 33526947304SEvan Yan /* wake up the ATTN event handler */ 33626947304SEvan Yan cv_signal(&ctrl_p->hc_slots[slot]-> 33726947304SEvan Yan hs_attn_btn_cv); 33826947304SEvan Yan } 33926947304SEvan Yan 34026947304SEvan Yan if (reg & PCI_HP_SLOT_MRL_DETECTED) 34126947304SEvan Yan PCIE_DBG("slot %d: " 34226947304SEvan Yan "PCI_HP_SLOT_MRL_DETECTED\n", slot+1); 34326947304SEvan Yan 34426947304SEvan Yan if (reg & PCI_HP_SLOT_POWER_DETECTED) 34526947304SEvan Yan PCIE_DBG("slot %d: " 34626947304SEvan Yan "PCI_HP_SLOT_POWER_DETECTED\n", slot+1); 34726947304SEvan Yan 34826947304SEvan Yan /* Acknoledge any slot interrupts */ 34926947304SEvan Yan pcishpc_write_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot, 35026947304SEvan Yan reg); 35126947304SEvan Yan } 35226947304SEvan Yan } 35326947304SEvan Yan 35426947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex); 35526947304SEvan Yan 35626947304SEvan Yan PCIE_DBG("pcishpc_intr() claimed\n"); 35726947304SEvan Yan 35826947304SEvan Yan return (DDI_INTR_CLAIMED); 35926947304SEvan Yan } 36026947304SEvan Yan 36126947304SEvan Yan int 36226947304SEvan Yan pcishpc_slot_get_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg, 36326947304SEvan Yan ddi_hp_property_t *rval) 36426947304SEvan Yan { 36526947304SEvan Yan ddi_hp_property_t request, result; 36626947304SEvan Yan #ifdef _SYSCALL32_IMPL 36726947304SEvan Yan ddi_hp_property32_t request32, result32; 36826947304SEvan Yan #endif 36926947304SEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; 37026947304SEvan Yan nvlist_t *prop_list; 37126947304SEvan Yan nvlist_t *prop_rlist; /* nvlist for return values */ 37226947304SEvan Yan nvpair_t *prop_pair; 37326947304SEvan Yan char *name, *value; 37426947304SEvan Yan int ret = DDI_SUCCESS; 37526947304SEvan Yan int i, n; 37626947304SEvan Yan boolean_t get_all_prop = B_FALSE; 37726947304SEvan Yan 37826947304SEvan Yan if (get_udatamodel() == DATAMODEL_NATIVE) { 37926947304SEvan Yan if (copyin(arg, &request, sizeof (ddi_hp_property_t)) || 38026947304SEvan Yan copyin(rval, &result, sizeof (ddi_hp_property_t))) 38126947304SEvan Yan return (DDI_FAILURE); 38226947304SEvan Yan } 38326947304SEvan Yan #ifdef _SYSCALL32_IMPL 38426947304SEvan Yan else { 38526947304SEvan Yan bzero(&request, sizeof (request)); 38626947304SEvan Yan bzero(&result, sizeof (result)); 38726947304SEvan Yan if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)) || 38826947304SEvan Yan copyin(rval, &result32, sizeof (ddi_hp_property32_t))) 38926947304SEvan Yan return (DDI_FAILURE); 39026947304SEvan Yan request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf; 39126947304SEvan Yan request.buf_size = request32.buf_size; 39226947304SEvan Yan result.nvlist_buf = (char *)(uintptr_t)result32.nvlist_buf; 39326947304SEvan Yan result.buf_size = result32.buf_size; 39426947304SEvan Yan } 39526947304SEvan Yan #endif 39626947304SEvan Yan 39726947304SEvan Yan if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size, 39826947304SEvan Yan &prop_list)) != DDI_SUCCESS) 39926947304SEvan Yan return (ret); 40026947304SEvan Yan 40126947304SEvan Yan if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) { 40226947304SEvan Yan ret = DDI_ENOMEM; 40326947304SEvan Yan goto get_prop_cleanup; 40426947304SEvan Yan } 40526947304SEvan Yan 40626947304SEvan Yan /* check whether the requested property is "all" or "help" */ 40726947304SEvan Yan prop_pair = nvlist_next_nvpair(prop_list, NULL); 40826947304SEvan Yan if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair)) { 40926947304SEvan Yan name = nvpair_name(prop_pair); 41026947304SEvan Yan n = sizeof (pcishpc_props) / sizeof (pcishpc_prop_t); 41126947304SEvan Yan 41226947304SEvan Yan if (strcmp(name, PCIEHPC_PROP_ALL) == 0) { 41326947304SEvan Yan (void) nvlist_remove_all(prop_list, PCIEHPC_PROP_ALL); 41426947304SEvan Yan 41526947304SEvan Yan /* 41626947304SEvan Yan * Add all properties into the request list, so that we 41726947304SEvan Yan * will get the values in the following for loop. 41826947304SEvan Yan */ 41926947304SEvan Yan for (i = 0; i < n; i++) { 42026947304SEvan Yan if (nvlist_add_string(prop_list, 42126947304SEvan Yan pcishpc_props[i].prop_name, "") != 0) { 42226947304SEvan Yan ret = DDI_FAILURE; 42326947304SEvan Yan goto get_prop_cleanup1; 42426947304SEvan Yan } 42526947304SEvan Yan } 42626947304SEvan Yan get_all_prop = B_TRUE; 42726947304SEvan Yan } else if (strcmp(name, PCIEHPC_PROP_HELP) == 0) { 42826947304SEvan Yan /* 42926947304SEvan Yan * Empty the request list, and add help strings into the 43026947304SEvan Yan * return list. We will pass the following for loop. 43126947304SEvan Yan */ 43226947304SEvan Yan (void) nvlist_remove_all(prop_list, PCIEHPC_PROP_HELP); 43326947304SEvan Yan 43426947304SEvan Yan for (i = 0; i < n; i++) { 43526947304SEvan Yan if (nvlist_add_string(prop_rlist, 43626947304SEvan Yan pcishpc_props[i].prop_name, 43726947304SEvan Yan pcishpc_props[i].prop_value) != 0) { 43826947304SEvan Yan ret = DDI_FAILURE; 43926947304SEvan Yan goto get_prop_cleanup1; 44026947304SEvan Yan } 44126947304SEvan Yan } 44226947304SEvan Yan } 44326947304SEvan Yan } 44426947304SEvan Yan 44526947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex); 44626947304SEvan Yan 44726947304SEvan Yan /* get the current slot state */ 44826947304SEvan Yan pcishpc_get_slot_state(slot_p); 44926947304SEvan Yan 45026947304SEvan Yan /* for each requested property, get the value and add it to nvlist */ 45126947304SEvan Yan prop_pair = NULL; 45226947304SEvan Yan while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) { 45326947304SEvan Yan name = nvpair_name(prop_pair); 45426947304SEvan Yan 45526947304SEvan Yan if (strcmp(name, PCIEHPC_PROP_LED_FAULT) == 0) { 45626947304SEvan Yan value = pcie_led_state_text( 45726947304SEvan Yan slot_p->hs_fault_led_state); 45826947304SEvan Yan } else if (strcmp(name, PCIEHPC_PROP_LED_POWER) == 0) { 45926947304SEvan Yan value = pcie_led_state_text( 46026947304SEvan Yan slot_p->hs_power_led_state); 46126947304SEvan Yan } else if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) { 46226947304SEvan Yan value = pcie_led_state_text( 46326947304SEvan Yan slot_p->hs_attn_led_state); 46426947304SEvan Yan } else if (strcmp(name, PCIEHPC_PROP_LED_ACTIVE) == 0) { 46526947304SEvan Yan value = pcie_led_state_text( 46626947304SEvan Yan slot_p->hs_active_led_state); 46726947304SEvan Yan } else if (strcmp(name, PCIEHPC_PROP_CARD_TYPE) == 0) { 46826947304SEvan Yan ddi_acc_handle_t handle; 46926947304SEvan Yan dev_info_t *cdip; 47026947304SEvan Yan uint8_t prog_class, base_class, sub_class; 47126947304SEvan Yan int i; 47226947304SEvan Yan 47326947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex); 47426947304SEvan Yan cdip = pcie_hp_devi_find( 47526947304SEvan Yan ctrl_p->hc_dip, slot_p->hs_device_num, 0); 47626947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex); 47726947304SEvan Yan 47826947304SEvan Yan if ((slot_p->hs_info.cn_state != 47926947304SEvan Yan DDI_HP_CN_STATE_ENABLED) || (cdip == NULL)) { 48026947304SEvan Yan /* 48126947304SEvan Yan * When getting all properties, just ignore the 48226947304SEvan Yan * one that's not available under certain state. 48326947304SEvan Yan */ 48426947304SEvan Yan if (get_all_prop) 48526947304SEvan Yan continue; 48626947304SEvan Yan 48726947304SEvan Yan ret = DDI_ENOTSUP; 48826947304SEvan Yan goto get_prop_cleanup2; 48926947304SEvan Yan } 49026947304SEvan Yan 49126947304SEvan Yan if (pci_config_setup(cdip, &handle) != DDI_SUCCESS) { 49226947304SEvan Yan ret = DDI_FAILURE; 49326947304SEvan Yan goto get_prop_cleanup2; 49426947304SEvan Yan } 49526947304SEvan Yan 49626947304SEvan Yan prog_class = pci_config_get8(handle, 49726947304SEvan Yan PCI_CONF_PROGCLASS); 49826947304SEvan Yan base_class = pci_config_get8(handle, PCI_CONF_BASCLASS); 49926947304SEvan Yan sub_class = pci_config_get8(handle, PCI_CONF_SUBCLASS); 50026947304SEvan Yan pci_config_teardown(&handle); 50126947304SEvan Yan 50226947304SEvan Yan for (i = 0; i < class_pci_items; i++) { 50326947304SEvan Yan if ((base_class == class_pci[i].base_class) && 50426947304SEvan Yan (sub_class == class_pci[i].sub_class) && 50526947304SEvan Yan (prog_class == class_pci[i].prog_class)) { 50626947304SEvan Yan value = class_pci[i].short_desc; 50726947304SEvan Yan break; 50826947304SEvan Yan } 50926947304SEvan Yan } 51026947304SEvan Yan if (i == class_pci_items) 51126947304SEvan Yan value = PCIEHPC_PROP_VALUE_UNKNOWN; 51226947304SEvan Yan } else if (strcmp(name, PCIEHPC_PROP_BOARD_TYPE) == 0) { 51326947304SEvan Yan if (slot_p->hs_info.cn_state <= DDI_HP_CN_STATE_EMPTY) 51426947304SEvan Yan value = PCIEHPC_PROP_VALUE_UNKNOWN; 51526947304SEvan Yan else 51626947304SEvan Yan value = PCIEHPC_PROP_VALUE_PCIHOTPLUG; 51726947304SEvan Yan } else if (strcmp(name, PCIEHPC_PROP_SLOT_CONDITION) == 0) { 51826947304SEvan Yan value = pcie_slot_condition_text(slot_p->hs_condition); 51926947304SEvan Yan } else { 52026947304SEvan Yan /* unsupported property */ 52124fd5dc4SEvan Yan PCIE_DBG("Unsupported property: %s\n", name); 52226947304SEvan Yan 52326947304SEvan Yan ret = DDI_ENOTSUP; 52426947304SEvan Yan goto get_prop_cleanup2; 52526947304SEvan Yan } 52626947304SEvan Yan if (nvlist_add_string(prop_rlist, name, value) != 0) { 52726947304SEvan Yan ret = DDI_FAILURE; 52826947304SEvan Yan goto get_prop_cleanup2; 52926947304SEvan Yan } 53026947304SEvan Yan } 53126947304SEvan Yan 53226947304SEvan Yan // pack nvlist and copyout 53326947304SEvan Yan if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf, 53426947304SEvan Yan &result.buf_size)) != DDI_SUCCESS) { 53526947304SEvan Yan goto get_prop_cleanup2; 53626947304SEvan Yan } 53726947304SEvan Yan if (get_udatamodel() == DATAMODEL_NATIVE) { 53826947304SEvan Yan if (copyout(&result, rval, sizeof (ddi_hp_property_t))) { 53926947304SEvan Yan ret = DDI_FAILURE; 54026947304SEvan Yan goto get_prop_cleanup2; 54126947304SEvan Yan } 54226947304SEvan Yan } 54326947304SEvan Yan #ifdef _SYSCALL32_IMPL 54426947304SEvan Yan else { 54526947304SEvan Yan if (result.buf_size > UINT32_MAX) { 54626947304SEvan Yan ret = DDI_FAILURE; 54726947304SEvan Yan } else { 54826947304SEvan Yan result32.buf_size = (uint32_t)result.buf_size; 54926947304SEvan Yan if (copyout(&result32, rval, 55026947304SEvan Yan sizeof (ddi_hp_property32_t))) 55126947304SEvan Yan ret = DDI_FAILURE; 55226947304SEvan Yan } 55326947304SEvan Yan } 55426947304SEvan Yan #endif 55526947304SEvan Yan 55626947304SEvan Yan get_prop_cleanup2: 55726947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex); 55826947304SEvan Yan get_prop_cleanup1: 55926947304SEvan Yan nvlist_free(prop_rlist); 56026947304SEvan Yan get_prop_cleanup: 56126947304SEvan Yan nvlist_free(prop_list); 56226947304SEvan Yan return (ret); 56326947304SEvan Yan } 56426947304SEvan Yan 56526947304SEvan Yan int 56626947304SEvan Yan pcishpc_slot_set_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg, 56726947304SEvan Yan ddi_hp_property_t *rval) 56826947304SEvan Yan { 56926947304SEvan Yan ddi_hp_property_t request, result; 57026947304SEvan Yan #ifdef _SYSCALL32_IMPL 57126947304SEvan Yan ddi_hp_property32_t request32, result32; 57226947304SEvan Yan #endif 57326947304SEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; 57426947304SEvan Yan nvlist_t *prop_list; 57526947304SEvan Yan nvlist_t *prop_rlist; 57626947304SEvan Yan nvpair_t *prop_pair; 57726947304SEvan Yan char *name, *value; 57826947304SEvan Yan pcie_hp_led_state_t led_state; 57926947304SEvan Yan int ret = DDI_SUCCESS; 58026947304SEvan Yan 58126947304SEvan Yan if (get_udatamodel() == DATAMODEL_NATIVE) { 58226947304SEvan Yan if (copyin(arg, &request, sizeof (ddi_hp_property_t))) 58326947304SEvan Yan return (DDI_FAILURE); 58426947304SEvan Yan if (rval && 58526947304SEvan Yan copyin(rval, &result, sizeof (ddi_hp_property_t))) 58626947304SEvan Yan return (DDI_FAILURE); 58726947304SEvan Yan } 58826947304SEvan Yan #ifdef _SYSCALL32_IMPL 58926947304SEvan Yan else { 59026947304SEvan Yan bzero(&request, sizeof (request)); 59126947304SEvan Yan bzero(&result, sizeof (result)); 59226947304SEvan Yan if (copyin(arg, &request32, sizeof (ddi_hp_property32_t))) 59326947304SEvan Yan return (DDI_FAILURE); 59426947304SEvan Yan if (rval && 59526947304SEvan Yan copyin(rval, &result32, sizeof (ddi_hp_property32_t))) 59626947304SEvan Yan return (DDI_FAILURE); 59726947304SEvan Yan request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf; 59826947304SEvan Yan request.buf_size = request32.buf_size; 59926947304SEvan Yan if (rval) { 60026947304SEvan Yan result.nvlist_buf = 60126947304SEvan Yan (char *)(uintptr_t)result32.nvlist_buf; 60226947304SEvan Yan result.buf_size = result32.buf_size; 60326947304SEvan Yan } 60426947304SEvan Yan } 60526947304SEvan Yan #endif 60626947304SEvan Yan 60726947304SEvan Yan if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size, 60826947304SEvan Yan &prop_list)) != DDI_SUCCESS) 60926947304SEvan Yan return (ret); 61026947304SEvan Yan 61126947304SEvan Yan /* check whether the requested property is "help" */ 61226947304SEvan Yan prop_pair = nvlist_next_nvpair(prop_list, NULL); 61326947304SEvan Yan if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair) && 61426947304SEvan Yan (strcmp(nvpair_name(prop_pair), PCIEHPC_PROP_HELP) == 0)) { 61526947304SEvan Yan if (!rval) { 61626947304SEvan Yan ret = DDI_ENOTSUP; 61726947304SEvan Yan goto set_prop_cleanup; 61826947304SEvan Yan } 61926947304SEvan Yan 62026947304SEvan Yan if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) { 62126947304SEvan Yan ret = DDI_ENOMEM; 62226947304SEvan Yan goto set_prop_cleanup; 62326947304SEvan Yan } 62426947304SEvan Yan if (nvlist_add_string(prop_rlist, PCIEHPC_PROP_LED_ATTN, 62526947304SEvan Yan PCIEHPC_PROP_VALUE_LED) != 0) { 62626947304SEvan Yan ret = DDI_FAILURE; 62726947304SEvan Yan goto set_prop_cleanup1; 62826947304SEvan Yan } 62926947304SEvan Yan 63026947304SEvan Yan if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf, 63126947304SEvan Yan &result.buf_size)) != DDI_SUCCESS) { 63226947304SEvan Yan goto set_prop_cleanup1; 63326947304SEvan Yan } 63426947304SEvan Yan if (get_udatamodel() == DATAMODEL_NATIVE) { 63526947304SEvan Yan if (copyout(&result, rval, 63626947304SEvan Yan sizeof (ddi_hp_property_t))) { 63726947304SEvan Yan ret = DDI_FAILURE; 63826947304SEvan Yan goto set_prop_cleanup1; 63926947304SEvan Yan } 64026947304SEvan Yan } 64126947304SEvan Yan #ifdef _SYSCALL32_IMPL 64226947304SEvan Yan else { 64326947304SEvan Yan if (result.buf_size > UINT32_MAX) { 64426947304SEvan Yan ret = DDI_FAILURE; 64526947304SEvan Yan goto set_prop_cleanup1; 64626947304SEvan Yan } else { 64726947304SEvan Yan result32.buf_size = (uint32_t)result.buf_size; 64826947304SEvan Yan if (copyout(&result32, rval, 64926947304SEvan Yan sizeof (ddi_hp_property32_t))) { 65026947304SEvan Yan ret = DDI_FAILURE; 65126947304SEvan Yan goto set_prop_cleanup1; 65226947304SEvan Yan } 65326947304SEvan Yan } 65426947304SEvan Yan } 65526947304SEvan Yan #endif 65626947304SEvan Yan set_prop_cleanup1: 65726947304SEvan Yan nvlist_free(prop_rlist); 65826947304SEvan Yan nvlist_free(prop_list); 65926947304SEvan Yan return (ret); 66026947304SEvan Yan } 66126947304SEvan Yan 66226947304SEvan Yan /* Validate the request */ 66326947304SEvan Yan prop_pair = NULL; 66426947304SEvan Yan while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) { 66526947304SEvan Yan name = nvpair_name(prop_pair); 66626947304SEvan Yan if (nvpair_type(prop_pair) != DATA_TYPE_STRING) { 66724fd5dc4SEvan Yan PCIE_DBG("Unexpected data type of setting " 66826947304SEvan Yan "property %s.\n", name); 66926947304SEvan Yan ret = DDI_EINVAL; 67026947304SEvan Yan goto set_prop_cleanup; 67126947304SEvan Yan } 67226947304SEvan Yan if (nvpair_value_string(prop_pair, &value)) { 67324fd5dc4SEvan Yan PCIE_DBG("Get string value failed for property %s.\n", 67424fd5dc4SEvan Yan name); 67526947304SEvan Yan ret = DDI_FAILURE; 67626947304SEvan Yan goto set_prop_cleanup; 67726947304SEvan Yan } 67826947304SEvan Yan 67926947304SEvan Yan if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) { 68026947304SEvan Yan if ((strcmp(value, PCIEHPC_PROP_VALUE_ON) != 0) && 68126947304SEvan Yan (strcmp(value, PCIEHPC_PROP_VALUE_OFF) != 0) && 68226947304SEvan Yan (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) != 0)) { 68324fd5dc4SEvan Yan PCIE_DBG("Unsupported value of setting " 68426947304SEvan Yan "property %s\n", name); 68526947304SEvan Yan ret = DDI_ENOTSUP; 68626947304SEvan Yan goto set_prop_cleanup; 68726947304SEvan Yan } 68826947304SEvan Yan } else { 68924fd5dc4SEvan Yan PCIE_DBG("Unsupported property: %s\n", name); 69026947304SEvan Yan ret = DDI_ENOTSUP; 69126947304SEvan Yan goto set_prop_cleanup; 69226947304SEvan Yan } 69326947304SEvan Yan } 69426947304SEvan Yan 69526947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex); 69626947304SEvan Yan 69726947304SEvan Yan /* get the current slot state */ 69826947304SEvan Yan pcishpc_get_slot_state(slot_p); 69926947304SEvan Yan 70026947304SEvan Yan // set each property 70126947304SEvan Yan prop_pair = NULL; 70226947304SEvan Yan while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) { 70326947304SEvan Yan name = nvpair_name(prop_pair); 70426947304SEvan Yan 70526947304SEvan Yan if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) { 70626947304SEvan Yan if (strcmp(value, PCIEHPC_PROP_VALUE_ON) == 0) 70726947304SEvan Yan led_state = PCIE_HP_LED_ON; 70826947304SEvan Yan else if (strcmp(value, PCIEHPC_PROP_VALUE_OFF) == 0) 70926947304SEvan Yan led_state = PCIE_HP_LED_OFF; 71026947304SEvan Yan else if (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) == 0) 71126947304SEvan Yan led_state = PCIE_HP_LED_BLINK; 71226947304SEvan Yan 71326947304SEvan Yan (void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, 71426947304SEvan Yan led_state); 71526947304SEvan Yan } 71626947304SEvan Yan } 71724fd5dc4SEvan Yan if (rval) { 71824fd5dc4SEvan Yan if (get_udatamodel() == DATAMODEL_NATIVE) { 71924fd5dc4SEvan Yan result.buf_size = 0; 72024fd5dc4SEvan Yan if (copyout(&result, rval, sizeof (ddi_hp_property_t))) 72124fd5dc4SEvan Yan ret = DDI_FAILURE; 72224fd5dc4SEvan Yan } 72324fd5dc4SEvan Yan #ifdef _SYSCALL32_IMPL 72424fd5dc4SEvan Yan else { 72524fd5dc4SEvan Yan result32.buf_size = 0; 72624fd5dc4SEvan Yan if (copyout(&result32, rval, 72724fd5dc4SEvan Yan sizeof (ddi_hp_property32_t))) 72824fd5dc4SEvan Yan ret = DDI_FAILURE; 72924fd5dc4SEvan Yan } 73024fd5dc4SEvan Yan #endif 73124fd5dc4SEvan Yan } 73226947304SEvan Yan 73326947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex); 73426947304SEvan Yan set_prop_cleanup: 73526947304SEvan Yan nvlist_free(prop_list); 73626947304SEvan Yan return (ret); 73726947304SEvan Yan } 73826947304SEvan Yan 73926947304SEvan Yan /* 74026947304SEvan Yan * pcishpc_hp_ops() 74126947304SEvan Yan * 74226947304SEvan Yan * Handle hotplug commands 74326947304SEvan Yan * 74426947304SEvan Yan * Note: This function is called by DDI HP framework at kernel context only 74526947304SEvan Yan */ 74626947304SEvan Yan /* ARGSUSED */ 74726947304SEvan Yan int 74826947304SEvan Yan pcishpc_hp_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op, 74926947304SEvan Yan void *arg, void *result) 75026947304SEvan Yan { 75126947304SEvan Yan pcie_hp_slot_t *slot_p = NULL; 75226947304SEvan Yan pcie_hp_ctrl_t *ctrl_p; 75326947304SEvan Yan int ret = DDI_SUCCESS, i; 75426947304SEvan Yan 75526947304SEvan Yan PCIE_DBG("pcishpc_hp_ops: dip=%p cn_name=%s op=%x arg=%p\n", 75626947304SEvan Yan dip, cn_name, op, arg); 75726947304SEvan Yan 75826947304SEvan Yan if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) 75926947304SEvan Yan return (DDI_FAILURE); 76026947304SEvan Yan 76126947304SEvan Yan for (i = 0; i < PCIE_HP_MAX_SLOTS && ctrl_p->hc_slots[i]; i++) { 76226947304SEvan Yan if (strcmp(ctrl_p->hc_slots[i]->hs_info.cn_name, cn_name) 76326947304SEvan Yan == 0) { 76426947304SEvan Yan /* Match with a physical slot, found */ 76526947304SEvan Yan slot_p = ctrl_p->hc_slots[i]; 76626947304SEvan Yan break; 76726947304SEvan Yan } 76826947304SEvan Yan } 76926947304SEvan Yan if (!slot_p) { 77026947304SEvan Yan PCIE_DBG("pcishpc_hp_ops: Failed to find the slot under" 77126947304SEvan Yan "dip %p with name: %s; op=%x arg=%p\n", 77226947304SEvan Yan dip, cn_name, op, arg); 77326947304SEvan Yan return (DDI_EINVAL); 77426947304SEvan Yan } 77526947304SEvan Yan switch (op) { 77626947304SEvan Yan case DDI_HPOP_CN_GET_STATE: 77726947304SEvan Yan { 77826947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex); 77926947304SEvan Yan 78026947304SEvan Yan /* get the current slot state */ 78126947304SEvan Yan pcishpc_get_slot_state(slot_p); 78226947304SEvan Yan 78326947304SEvan Yan *((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state; 78426947304SEvan Yan 78526947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex); 78626947304SEvan Yan break; 78726947304SEvan Yan } 78826947304SEvan Yan case DDI_HPOP_CN_CHANGE_STATE: 78926947304SEvan Yan { 79026947304SEvan Yan ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg; 79126947304SEvan Yan 79226947304SEvan Yan mutex_enter(&slot_p->hs_ctrl->hc_mutex); 79326947304SEvan Yan 79426947304SEvan Yan ret = pcishpc_change_slot_state(slot_p, target_state); 79526947304SEvan Yan *((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state; 79626947304SEvan Yan 79726947304SEvan Yan mutex_exit(&slot_p->hs_ctrl->hc_mutex); 79826947304SEvan Yan break; 79926947304SEvan Yan } 80026947304SEvan Yan case DDI_HPOP_CN_PROBE: 80126947304SEvan Yan ret = pcishpc_slot_probe(slot_p); 80226947304SEvan Yan 80326947304SEvan Yan break; 80426947304SEvan Yan case DDI_HPOP_CN_UNPROBE: 80526947304SEvan Yan ret = pcishpc_slot_unprobe(slot_p); 80626947304SEvan Yan 80726947304SEvan Yan break; 80826947304SEvan Yan case DDI_HPOP_CN_GET_PROPERTY: 80926947304SEvan Yan ret = pcishpc_slot_get_property(slot_p, 81026947304SEvan Yan (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result); 81126947304SEvan Yan break; 81226947304SEvan Yan case DDI_HPOP_CN_SET_PROPERTY: 81326947304SEvan Yan ret = pcishpc_slot_set_property(slot_p, 81426947304SEvan Yan (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result); 81526947304SEvan Yan break; 81626947304SEvan Yan default: 81726947304SEvan Yan ret = DDI_ENOTSUP; 81826947304SEvan Yan break; 81926947304SEvan Yan } 82026947304SEvan Yan 82126947304SEvan Yan return (ret); 82226947304SEvan Yan } 82326947304SEvan Yan 82426947304SEvan Yan /* 82526947304SEvan Yan * Local functions (called within this file) 82626947304SEvan Yan */ 82726947304SEvan Yan 82826947304SEvan Yan /* 82926947304SEvan Yan * pcishpc_create_controller() 83026947304SEvan Yan * 83126947304SEvan Yan * This function allocates and creates an SHPC controller state structure 83226947304SEvan Yan * and adds it to the linked list of controllers. 83326947304SEvan Yan */ 83426947304SEvan Yan static pcie_hp_ctrl_t * 83526947304SEvan Yan pcishpc_create_controller(dev_info_t *dip) 83626947304SEvan Yan { 83726947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 83826947304SEvan Yan pcie_hp_ctrl_t *ctrl_p; 83926947304SEvan Yan 84026947304SEvan Yan PCIE_DBG("pcishpc: create controller for %s#%d\n", 84126947304SEvan Yan ddi_driver_name(dip), ddi_get_instance(dip)); 84226947304SEvan Yan 84326947304SEvan Yan ctrl_p = kmem_zalloc(sizeof (pcie_hp_ctrl_t), KM_SLEEP); 84426947304SEvan Yan ctrl_p->hc_dip = dip; 84526947304SEvan Yan 84626947304SEvan Yan cv_init(&ctrl_p->hc_cmd_comp_cv, NULL, CV_DRIVER, NULL); 84726947304SEvan Yan 84826947304SEvan Yan /* Init the shpc controller's mutex. */ 84926947304SEvan Yan mutex_init(&ctrl_p->hc_mutex, NULL, MUTEX_DRIVER, NULL); 85026947304SEvan Yan 85126947304SEvan Yan /* HPC initialization is complete now */ 85226947304SEvan Yan ctrl_p->hc_flags = PCIE_HP_INITIALIZED_FLAG; 85326947304SEvan Yan bus_p->bus_hp_curr_mode = PCIE_PCI_HP_MODE; 85426947304SEvan Yan 85526947304SEvan Yan PCIE_SET_HP_CTRL(dip, ctrl_p); 85626947304SEvan Yan 85726947304SEvan Yan PCIE_DBG("pcishpc_create_controller() success\n"); 85826947304SEvan Yan 85926947304SEvan Yan return (ctrl_p); 86026947304SEvan Yan } 86126947304SEvan Yan 86226947304SEvan Yan 86326947304SEvan Yan /* 86426947304SEvan Yan * pcishpc_setup_controller() 86526947304SEvan Yan * 86626947304SEvan Yan * Get the number of HotPlug Slots, and the PCI device information 86726947304SEvan Yan * for this HotPlug controller. 86826947304SEvan Yan */ 86926947304SEvan Yan static int 87026947304SEvan Yan pcishpc_setup_controller(pcie_hp_ctrl_t *ctrl_p) 87126947304SEvan Yan { 87226947304SEvan Yan uint32_t config; 87326947304SEvan Yan dev_info_t *ppdip; 87426947304SEvan Yan 87526947304SEvan Yan config = pcishpc_read_reg(ctrl_p, PCI_HP_SLOT_CONFIGURATION_REG); 87626947304SEvan Yan 87726947304SEvan Yan /* Get the number of HotPlug slots implemented */ 87826947304SEvan Yan ctrl_p->hc_num_slots_impl = ((config)&31); 87926947304SEvan Yan 88026947304SEvan Yan /* 88126947304SEvan Yan * Initilize the current bus speed and number of hotplug slots 88226947304SEvan Yan * currently connected. 88326947304SEvan Yan */ 88426947304SEvan Yan ctrl_p->hc_curr_bus_speed = -1; 88526947304SEvan Yan ctrl_p->hc_num_slots_connected = 0; 88626947304SEvan Yan 88726947304SEvan Yan /* 88826947304SEvan Yan * Get the first PCI device Number used. 88926947304SEvan Yan * 89026947304SEvan Yan * PCI-X I/O boat workaround. 89126947304SEvan Yan * The register doesn't set up the correct value. 89226947304SEvan Yan */ 89326947304SEvan Yan ppdip = ddi_get_parent(ddi_get_parent(ctrl_p->hc_dip)); 89426947304SEvan Yan if ((ddi_prop_get_int(DDI_DEV_T_ANY, ppdip, DDI_PROP_DONTPASS, 89526947304SEvan Yan "vendor-id", -1) == 0x108e) && 89626947304SEvan Yan (ddi_prop_get_int(DDI_DEV_T_ANY, ppdip, DDI_PROP_DONTPASS, 89726947304SEvan Yan "device-id", -1) == 0x9010)) 89826947304SEvan Yan ctrl_p->hc_device_start = 4; 89926947304SEvan Yan else 90026947304SEvan Yan ctrl_p->hc_device_start = ((config>>8)&31); 90126947304SEvan Yan 90226947304SEvan Yan /* Get the first Physical device number. */ 90326947304SEvan Yan ctrl_p->hc_phys_start = ((config>>16)&0x7ff); 90426947304SEvan Yan 90526947304SEvan Yan /* Check if the device numbers increase or decrease. */ 90626947304SEvan Yan ctrl_p->hc_device_increases = ((config>>29)&0x1); 90726947304SEvan Yan 90826947304SEvan Yan ctrl_p->hc_has_attn = 90926947304SEvan Yan (config & PCI_HP_SLOT_CONFIG_ATTN_BUTTON) ? B_TRUE : B_FALSE; 91026947304SEvan Yan ctrl_p->hc_has_mrl = 91126947304SEvan Yan (config & PCI_HP_SLOT_CONFIG_MRL_SENSOR) ? B_TRUE : B_FALSE; 91226947304SEvan Yan 91326947304SEvan Yan ctrl_p->hc_cmd_pending = B_FALSE; 91426947304SEvan Yan ctrl_p->hc_arbiter_timeout = B_FALSE; 91526947304SEvan Yan 91626947304SEvan Yan if (ctrl_p->hc_num_slots_impl > PCIE_HP_MAX_SLOTS) { 91726947304SEvan Yan PCIE_DBG("pcishpc_setup_controller() too many SHPC " 91826947304SEvan Yan "slots error\n"); 91926947304SEvan Yan return (DDI_FAILURE); 92026947304SEvan Yan } 92126947304SEvan Yan 92226947304SEvan Yan return (DDI_SUCCESS); 92326947304SEvan Yan } 92426947304SEvan Yan 92526947304SEvan Yan 92626947304SEvan Yan /* 92726947304SEvan Yan * pcishpc_destroy_controller() 92826947304SEvan Yan * 92926947304SEvan Yan * This function deallocates all of the SHPC controller resources. 93026947304SEvan Yan */ 93126947304SEvan Yan static int 93226947304SEvan Yan pcishpc_destroy_controller(dev_info_t *dip) 93326947304SEvan Yan { 93426947304SEvan Yan pcie_hp_ctrl_t *ctrl_p; 93526947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 93626947304SEvan Yan 93726947304SEvan Yan PCIE_DBG("pcishpc_destroy_controller() called(dip=%p)\n", dip); 93826947304SEvan Yan 93926947304SEvan Yan /* get the soft state structure for this dip */ 94026947304SEvan Yan if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) { 94126947304SEvan Yan PCIE_DBG("pcishpc_destroy_controller() not found\n"); 94226947304SEvan Yan return (DDI_FAILURE); 94326947304SEvan Yan } 94426947304SEvan Yan 94526947304SEvan Yan /* 94626947304SEvan Yan * Deallocate the slot state structures for this controller. 94726947304SEvan Yan */ 948c0da6274SZhi-Jun Robin Fu PCIE_SET_HP_CTRL(dip, NULL); 949c0da6274SZhi-Jun Robin Fu bus_p->bus_hp_curr_mode = PCIE_NONE_HP_MODE; 950c0da6274SZhi-Jun Robin Fu 95126947304SEvan Yan (void) pcishpc_destroy_slots(ctrl_p); 95226947304SEvan Yan cv_destroy(&ctrl_p->hc_cmd_comp_cv); 95326947304SEvan Yan mutex_destroy(&ctrl_p->hc_mutex); 95426947304SEvan Yan kmem_free(ctrl_p, sizeof (pcie_hp_ctrl_t)); 95526947304SEvan Yan 95626947304SEvan Yan PCIE_DBG("pcishpc_destroy_controller() success\n"); 95726947304SEvan Yan return (DDI_SUCCESS); 95826947304SEvan Yan } 95926947304SEvan Yan 96026947304SEvan Yan /* 96126947304SEvan Yan * pcishpc_create_slot() 96226947304SEvan Yan * 96326947304SEvan Yan * Allocate and add a new HotPlug slot state structure to the linked list. 96426947304SEvan Yan */ 96526947304SEvan Yan static pcie_hp_slot_t * 96626947304SEvan Yan pcishpc_create_slot(pcie_hp_ctrl_t *ctrl_p) 96726947304SEvan Yan { 96826947304SEvan Yan pcie_hp_slot_t *slot_p; 96926947304SEvan Yan 97026947304SEvan Yan PCIE_DBG("pcishpc_create_slot() called(ctrl_p=%x)\n", ctrl_p); 97126947304SEvan Yan 97226947304SEvan Yan /* Allocate a new slot structure. */ 97326947304SEvan Yan slot_p = kmem_zalloc(sizeof (pcie_hp_slot_t), KM_SLEEP); 97426947304SEvan Yan slot_p->hs_ctrl = ctrl_p; 97526947304SEvan Yan 97626947304SEvan Yan /* Assign an initial value */ 97726947304SEvan Yan slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY; 97826947304SEvan Yan 97926947304SEvan Yan PCIE_DBG("pcishpc_create_slot() success\n"); 98026947304SEvan Yan return (slot_p); 98126947304SEvan Yan } 98226947304SEvan Yan 98326947304SEvan Yan /* 98426947304SEvan Yan * pcishpc_register_slot() 98526947304SEvan Yan * 98626947304SEvan Yan * Create and register a slot with the Solaris HotPlug framework. 98726947304SEvan Yan */ 98826947304SEvan Yan static int 98926947304SEvan Yan pcishpc_register_slot(pcie_hp_ctrl_t *ctrl_p, int slot) 99026947304SEvan Yan { 99126947304SEvan Yan dev_info_t *dip = ctrl_p->hc_dip; 99226947304SEvan Yan pcie_hp_slot_t *slot_p; 99326947304SEvan Yan 99426947304SEvan Yan slot_p = pcishpc_create_slot(ctrl_p); 99526947304SEvan Yan ctrl_p->hc_slots[slot] = slot_p; 99626947304SEvan Yan slot_p->hs_num = slot; 99726947304SEvan Yan 99826947304SEvan Yan /* Setup the PCI device # for this SHPC slot. */ 99926947304SEvan Yan if (ctrl_p->hc_device_increases) 100026947304SEvan Yan slot_p->hs_device_num = ctrl_p->hc_device_start + 100126947304SEvan Yan slot_p->hs_num; 100226947304SEvan Yan else 100326947304SEvan Yan slot_p->hs_device_num = ctrl_p->hc_device_start - 100426947304SEvan Yan slot_p->hs_num; 100526947304SEvan Yan 100626947304SEvan Yan /* Setup the DDI HP framework slot information. */ 100726947304SEvan Yan slot_p->hs_info.cn_type = DDI_HP_CN_TYPE_PCI; 100826947304SEvan Yan slot_p->hs_info.cn_type_str = PCIE_PCI_HP_TYPE; 100926947304SEvan Yan slot_p->hs_info.cn_child = NULL; 101026947304SEvan Yan 101126947304SEvan Yan slot_p->hs_minor = PCI_MINOR_NUM( 101226947304SEvan Yan ddi_get_instance(dip), slot_p->hs_device_num); 101326947304SEvan Yan slot_p->hs_condition = AP_COND_UNKNOWN; 101426947304SEvan Yan 101526947304SEvan Yan /* setup thread for handling ATTN button events */ 101626947304SEvan Yan if (ctrl_p->hc_has_attn) { 101726947304SEvan Yan PCIE_DBG("pcishpc_register_slot: " 101826947304SEvan Yan "setting up ATTN button event " 101926947304SEvan Yan "handler thread for slot %d\n", slot); 102026947304SEvan Yan 102126947304SEvan Yan cv_init(&slot_p->hs_attn_btn_cv, NULL, CV_DRIVER, NULL); 102226947304SEvan Yan slot_p->hs_attn_btn_pending = B_FALSE; 102326947304SEvan Yan slot_p->hs_attn_btn_threadp = thread_create(NULL, 0, 102426947304SEvan Yan pcishpc_attn_btn_handler, 102526947304SEvan Yan (void *)slot_p, 0, &p0, TS_RUN, minclsyspri); 102626947304SEvan Yan slot_p->hs_attn_btn_thread_exit = B_FALSE; 102726947304SEvan Yan } 102826947304SEvan Yan 102926947304SEvan Yan /* setup the slot name (used for ap-id) */ 103026947304SEvan Yan pcishpc_set_slot_name(ctrl_p, slot); 103126947304SEvan Yan 103226947304SEvan Yan pcishpc_get_slot_state(slot_p); 103326947304SEvan Yan if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_ENABLED) 103426947304SEvan Yan slot_p->hs_condition = AP_COND_OK; 103526947304SEvan Yan 103626947304SEvan Yan /* register the slot with DDI HP framework */ 103726947304SEvan Yan if (ndi_hp_register(dip, &slot_p->hs_info) != NDI_SUCCESS) { 103826947304SEvan Yan PCIE_DBG("pciehpc_register_slot() failed to register slot %d\n", 103926947304SEvan Yan slot_p->hs_phy_slot_num); 104026947304SEvan Yan return (DDI_FAILURE); 104126947304SEvan Yan } 104226947304SEvan Yan 104326947304SEvan Yan pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip), 104426947304SEvan Yan slot_p->hs_minor), slot_p->hs_device_num); 104526947304SEvan Yan 104626947304SEvan Yan PCIE_DBG("pcishpc_register_slot() success for slot %d\n", slot); 104726947304SEvan Yan 104826947304SEvan Yan return (DDI_SUCCESS); 104926947304SEvan Yan } 105026947304SEvan Yan 105126947304SEvan Yan /* 105226947304SEvan Yan * pcishpc_destroy_slots() 105326947304SEvan Yan * 105426947304SEvan Yan * Free up all of the slot resources for this controller. 105526947304SEvan Yan */ 105626947304SEvan Yan static int 105726947304SEvan Yan pcishpc_destroy_slots(pcie_hp_ctrl_t *ctrl_p) 105826947304SEvan Yan { 105926947304SEvan Yan dev_info_t *dip = ctrl_p->hc_dip; 106026947304SEvan Yan pcie_hp_slot_t *slot_p; 106126947304SEvan Yan int i; 106226947304SEvan Yan 106326947304SEvan Yan PCIE_DBG("pcishpc_destroy_slots() called(ctrl_p=%p)\n", ctrl_p); 106426947304SEvan Yan 106526947304SEvan Yan for (i = 0; i < PCIE_HP_MAX_SLOTS; i++) { 106626947304SEvan Yan if ((slot_p = ctrl_p->hc_slots[i]) == NULL) 106726947304SEvan Yan continue; 106826947304SEvan Yan 106926947304SEvan Yan if (slot_p->hs_attn_btn_threadp != NULL) { 107026947304SEvan Yan mutex_enter(&ctrl_p->hc_mutex); 107126947304SEvan Yan slot_p->hs_attn_btn_thread_exit = B_TRUE; 107226947304SEvan Yan cv_signal(&slot_p->hs_attn_btn_cv); 107326947304SEvan Yan PCIE_DBG("pcishpc_destroy_slots: " 107426947304SEvan Yan "waiting for ATTN thread exit\n"); 107526947304SEvan Yan cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex); 107626947304SEvan Yan PCIE_DBG("pcishpc_destroy_slots: " 107726947304SEvan Yan "ATTN thread exit\n"); 107826947304SEvan Yan cv_destroy(&slot_p->hs_attn_btn_cv); 107926947304SEvan Yan slot_p->hs_attn_btn_threadp = NULL; 108026947304SEvan Yan mutex_exit(&ctrl_p->hc_mutex); 108126947304SEvan Yan } 108226947304SEvan Yan 108326947304SEvan Yan PCIE_DBG("pcishpc_destroy_slots() (shpc_p=%p)\n" 108426947304SEvan Yan "destroyed", slot_p); 108526947304SEvan Yan 108626947304SEvan Yan pcie_hp_delete_occupant_props(dip, 108726947304SEvan Yan makedevice(ddi_driver_major(dip), 108826947304SEvan Yan slot_p->hs_minor)); 108926947304SEvan Yan 109026947304SEvan Yan /* unregister the slot with DDI HP framework */ 109126947304SEvan Yan if (ndi_hp_unregister(dip, slot_p->hs_info.cn_name) != 109226947304SEvan Yan NDI_SUCCESS) { 109326947304SEvan Yan PCIE_DBG("pcishpc_destroy_slots() " 109426947304SEvan Yan "failed to unregister slot %d\n", 109526947304SEvan Yan slot_p->hs_phy_slot_num); 109626947304SEvan Yan return (DDI_FAILURE); 109726947304SEvan Yan } 109826947304SEvan Yan kmem_free(slot_p->hs_info.cn_name, 109926947304SEvan Yan strlen(slot_p->hs_info.cn_name) + 1); 110026947304SEvan Yan kmem_free(slot_p, sizeof (pcie_hp_slot_t)); 110126947304SEvan Yan } 110226947304SEvan Yan 110326947304SEvan Yan return (DDI_SUCCESS); 110426947304SEvan Yan } 110526947304SEvan Yan 110626947304SEvan Yan /* 110726947304SEvan Yan * pcishpc_enable_irqs() 110826947304SEvan Yan * 110926947304SEvan Yan * Enable/unmask the different IRQ's we support from the SHPC controller. 111026947304SEvan Yan */ 1111*70f83219SEvan Yan int 111226947304SEvan Yan pcishpc_enable_irqs(pcie_hp_ctrl_t *ctrl_p) 111326947304SEvan Yan { 111426947304SEvan Yan uint32_t reg; 111526947304SEvan Yan int slot; 111626947304SEvan Yan 111726947304SEvan Yan reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG); 111826947304SEvan Yan 111926947304SEvan Yan /* Enable all interrupts. */ 112026947304SEvan Yan reg &= ~PCI_HP_SERR_INT_MASK_ALL; 112126947304SEvan Yan 112226947304SEvan Yan pcishpc_write_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG, reg); 112326947304SEvan Yan 112426947304SEvan Yan /* Unmask the interrupts for each slot. */ 112526947304SEvan Yan for (slot = 0; slot < ctrl_p->hc_num_slots_impl; slot++) { 112626947304SEvan Yan reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot); 112726947304SEvan Yan if ((reg & PCI_HP_SLOT_STATE_MASK) == PCI_HP_SLOT_ENABLED) { 112826947304SEvan Yan reg &= ~(PCI_HP_SLOT_MASK_ALL | 112926947304SEvan Yan PCI_HP_SLOT_MRL_SERR_MASK); 113026947304SEvan Yan ctrl_p->hc_num_slots_connected++; 113126947304SEvan Yan if (ctrl_p->hc_curr_bus_speed == -1) 113226947304SEvan Yan ctrl_p->hc_curr_bus_speed = 113326947304SEvan Yan pcishpc_read_reg(ctrl_p, 113426947304SEvan Yan PCI_HP_PROF_IF_SBCR_REG) & 113526947304SEvan Yan PCI_HP_SBCR_SPEED_MASK; 113626947304SEvan Yan } else { 113726947304SEvan Yan reg &= ~(PCI_HP_SLOT_MASK_ALL); 113826947304SEvan Yan } 113926947304SEvan Yan 114026947304SEvan Yan /* Enable/Unmask all slot interrupts. */ 114126947304SEvan Yan pcishpc_write_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot, reg); 114226947304SEvan Yan } 114326947304SEvan Yan 114426947304SEvan Yan PCIE_DBG("pcishpc_enable_irqs: ctrl_p 0x%p, " 114526947304SEvan Yan "current bus speed 0x%x, slots connected 0x%x\n", ctrl_p, 114626947304SEvan Yan ctrl_p->hc_curr_bus_speed, ctrl_p->hc_num_slots_connected); 114726947304SEvan Yan 114826947304SEvan Yan return (DDI_SUCCESS); 114926947304SEvan Yan } 115026947304SEvan Yan 115126947304SEvan Yan 115226947304SEvan Yan /* 115326947304SEvan Yan * pcishpc_disable_irqs() 115426947304SEvan Yan * 115526947304SEvan Yan * Disable/Mask the different IRQ's we support from the SHPC controller. 115626947304SEvan Yan */ 1157*70f83219SEvan Yan int 115826947304SEvan Yan pcishpc_disable_irqs(pcie_hp_ctrl_t *ctrl_p) 115926947304SEvan Yan { 116026947304SEvan Yan uint32_t reg; 116126947304SEvan Yan int slot; 116226947304SEvan Yan 116326947304SEvan Yan reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG); 116426947304SEvan Yan 116526947304SEvan Yan /* Mask all interrupts. */ 116626947304SEvan Yan reg |= PCI_HP_SERR_INT_MASK_ALL; 116726947304SEvan Yan 116826947304SEvan Yan pcishpc_write_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG, reg); 116926947304SEvan Yan 117026947304SEvan Yan /* Unmask the interrupts for each slot. */ 117126947304SEvan Yan for (slot = 0; slot < ctrl_p->hc_num_slots_impl; slot++) { 117226947304SEvan Yan reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot); 117326947304SEvan Yan 117426947304SEvan Yan /* Disable/Mask all slot interrupts. */ 117526947304SEvan Yan reg |= PCI_HP_SLOT_MASK_ALL; 117626947304SEvan Yan 117726947304SEvan Yan pcishpc_write_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot, reg); 117826947304SEvan Yan } 117926947304SEvan Yan 118026947304SEvan Yan PCIE_DBG("pcishpc_disable_irqs: ctrl_p 0x%p, " 118126947304SEvan Yan "current bus speed 0x%x, slots connected 0x%x\n", ctrl_p, 118226947304SEvan Yan ctrl_p->hc_curr_bus_speed, ctrl_p->hc_num_slots_connected); 118326947304SEvan Yan 118426947304SEvan Yan return (DDI_SUCCESS); 118526947304SEvan Yan } 118626947304SEvan Yan 118726947304SEvan Yan /* 118826947304SEvan Yan * pcishpc_slot_poweron() 118926947304SEvan Yan * 119026947304SEvan Yan * Poweron/Enable the slot. 119126947304SEvan Yan * 119226947304SEvan Yan * Note: This function is called by DDI HP framework at kernel context only 119326947304SEvan Yan */ 119426947304SEvan Yan /*ARGSUSED*/ 119526947304SEvan Yan static int 119626947304SEvan Yan pcishpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result_state) 119726947304SEvan Yan { 119826947304SEvan Yan uint32_t status; 119926947304SEvan Yan 120026947304SEvan Yan PCIE_DBG("pcishpc_slot_poweron called()\n"); 120126947304SEvan Yan 120226947304SEvan Yan ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex)); 120326947304SEvan Yan 120426947304SEvan Yan /* get the current slot state */ 120526947304SEvan Yan pcishpc_get_slot_state(slot_p); 120626947304SEvan Yan 120726947304SEvan Yan /* check if the slot is already in the 'enabled' state */ 120826947304SEvan Yan if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) { 120926947304SEvan Yan /* slot is already in the 'enabled' state */ 121026947304SEvan Yan PCIE_DBG("pcishpc_slot_poweron() slot %d already enabled\n", 121126947304SEvan Yan slot_p->hs_phy_slot_num); 121226947304SEvan Yan 121326947304SEvan Yan *result_state = slot_p->hs_info.cn_state; 121426947304SEvan Yan return (DDI_SUCCESS); 121526947304SEvan Yan } 121626947304SEvan Yan 121726947304SEvan Yan if (slot_p->hs_info.cn_state == DDI_HP_CN_STATE_EMPTY) { 121826947304SEvan Yan PCIE_DBG("pcishpc_slot_poweron() slot in empty state\n"); 121926947304SEvan Yan goto cleanup; 122026947304SEvan Yan } 122126947304SEvan Yan 122226947304SEvan Yan /* make sure the MRL sensor is closed */ 122326947304SEvan Yan status = pcishpc_read_reg(slot_p->hs_ctrl, 122426947304SEvan Yan PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num); 122526947304SEvan Yan 122626947304SEvan Yan if (status & PCI_HP_SLOT_MRL_STATE_MASK) { 122726947304SEvan Yan PCIE_DBG("pcishpc_slot_poweron() failed: MRL open\n"); 122826947304SEvan Yan goto cleanup; 122926947304SEvan Yan } 123026947304SEvan Yan 123126947304SEvan Yan /* Set the Power LED to blink */ 123226947304SEvan Yan (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK); 123326947304SEvan Yan 123426947304SEvan Yan /* Turn all other LEDS off */ 123526947304SEvan Yan (void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF); 123626947304SEvan Yan (void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF); 123726947304SEvan Yan (void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF); 123826947304SEvan Yan 123926947304SEvan Yan /* Set the bus speed only if the bus segment is not running */ 124026947304SEvan Yan if (pcishpc_set_bus_speed(slot_p) != DDI_SUCCESS) { 124126947304SEvan Yan PCIE_DBG("pcishpc_slot_poweron() setting speed failed\n"); 124226947304SEvan Yan goto cleanup; 124326947304SEvan Yan } 124426947304SEvan Yan 124526947304SEvan Yan slot_p->hs_ctrl->hc_num_slots_connected++; 124626947304SEvan Yan 124726947304SEvan Yan PCIE_DBG("pcishpc_slot_poweron(): slot_p 0x%p, slot state 0x%x, " 124826947304SEvan Yan "current bus speed 0x%x, slots connected 0x%x\n", slot_p, 124926947304SEvan Yan slot_p->hs_info.cn_state, slot_p->hs_ctrl->hc_curr_bus_speed, 125026947304SEvan Yan slot_p->hs_ctrl->hc_num_slots_connected); 125126947304SEvan Yan 125226947304SEvan Yan /* Mask or Unmask MRL Sensor SEER bit based on new slot state */ 125326947304SEvan Yan if (slot_p->hs_ctrl->hc_has_mrl == B_TRUE) { 125426947304SEvan Yan uint32_t reg; 125526947304SEvan Yan 125626947304SEvan Yan reg = pcishpc_read_reg(slot_p->hs_ctrl, 125726947304SEvan Yan PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num); 125826947304SEvan Yan 125926947304SEvan Yan pcishpc_write_reg(slot_p->hs_ctrl, 126026947304SEvan Yan PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num, 126126947304SEvan Yan reg & ~PCI_HP_SLOT_MRL_SERR_MASK); 126226947304SEvan Yan } 126326947304SEvan Yan 126426947304SEvan Yan /* Update the hardware slot state. */ 126526947304SEvan Yan if (pcishpc_set_slot_state(slot_p, 126626947304SEvan Yan DDI_HP_CN_STATE_ENABLED) != DDI_SUCCESS) { 126726947304SEvan Yan PCIE_DBG("pcishpc_slot_poweron() failed\n"); 126826947304SEvan Yan 126926947304SEvan Yan pcishpc_get_slot_state(slot_p); 127026947304SEvan Yan goto cleanup; 127126947304SEvan Yan } 127226947304SEvan Yan /* Update the current state. It will be used in pcishpc_setled() */ 127326947304SEvan Yan slot_p->hs_info.cn_state = DDI_HP_CN_STATE_ENABLED; 127426947304SEvan Yan 127526947304SEvan Yan /* Turn the Power LED ON for a enabled slot. */ 127626947304SEvan Yan (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_ON); 127726947304SEvan Yan 127826947304SEvan Yan /* Turn all other LEDS off. */ 127926947304SEvan Yan (void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF); 128026947304SEvan Yan (void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF); 128126947304SEvan Yan (void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF); 128226947304SEvan Yan 128326947304SEvan Yan /* delay after powerON to let the device initialize itself */ 128426947304SEvan Yan delay(drv_usectohz(pcishpc_reset_delay)); 128526947304SEvan Yan 128626947304SEvan Yan PCIE_DBG("pcishpc_slot_poweron() success!\n"); 128726947304SEvan Yan 128826947304SEvan Yan /* 128926947304SEvan Yan * Want to show up as POWERED state for now. It will be updated to 129026947304SEvan Yan * ENABLED state when user explicitly enable the slot. 129126947304SEvan Yan */ 129226947304SEvan Yan slot_p->hs_info.cn_state = DDI_HP_CN_STATE_POWERED; 129326947304SEvan Yan 129426947304SEvan Yan /* get the current slot state */ 129526947304SEvan Yan pcishpc_get_slot_state(slot_p); 129626947304SEvan Yan /* 129726947304SEvan Yan * It should be poweron'ed now. Have a check here in case any 129826947304SEvan Yan * hardware problems. 129926947304SEvan Yan */ 130026947304SEvan Yan if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) { 130126947304SEvan Yan PCIE_DBG("pcishpc_slot_poweron() failed after hardware" 130226947304SEvan Yan " registers all programmed.\n"); 130326947304SEvan Yan 130426947304SEvan Yan goto cleanup; 130526947304SEvan Yan } 130626947304SEvan Yan 130726947304SEvan Yan *result_state = slot_p->hs_info.cn_state; 130826947304SEvan Yan 130926947304SEvan Yan return (DDI_SUCCESS); 131026947304SEvan Yan 131126947304SEvan Yan cleanup: 131226947304SEvan Yan (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF); 131326947304SEvan Yan return (DDI_FAILURE); 131426947304SEvan Yan } 131526947304SEvan Yan 131626947304SEvan Yan /*ARGSUSED*/ 131726947304SEvan Yan static int 131826947304SEvan Yan pcishpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result_state) 131926947304SEvan Yan { 132026947304SEvan Yan PCIE_DBG("pcishpc_slot_poweroff called()\n"); 132126947304SEvan Yan 132226947304SEvan Yan ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex)); 132326947304SEvan Yan 132426947304SEvan Yan /* get the current slot state */ 132526947304SEvan Yan pcishpc_get_slot_state(slot_p); 132626947304SEvan Yan 132726947304SEvan Yan /* check if the slot is not in the "enabled" or "powered" state */ 132826947304SEvan Yan if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) { 132926947304SEvan Yan /* slot is in the 'disabled' state */ 133026947304SEvan Yan PCIE_DBG("pcishpc_slot_poweroff(): " 133126947304SEvan Yan "slot %d already disabled\n", slot_p->hs_phy_slot_num); 133226947304SEvan Yan 133326947304SEvan Yan *result_state = slot_p->hs_info.cn_state; 133426947304SEvan Yan return (DDI_SUCCESS); 133526947304SEvan Yan } 133626947304SEvan Yan 133726947304SEvan Yan /* Set the Power LED to blink */ 133826947304SEvan Yan (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK); 133926947304SEvan Yan 134026947304SEvan Yan /* Turn all other LEDS off */ 134126947304SEvan Yan (void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF); 134226947304SEvan Yan (void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF); 134326947304SEvan Yan (void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF); 134426947304SEvan Yan 134526947304SEvan Yan if (--slot_p->hs_ctrl->hc_num_slots_connected == 0) 134626947304SEvan Yan slot_p->hs_ctrl->hc_curr_bus_speed = -1; 134726947304SEvan Yan 134826947304SEvan Yan PCIE_DBG("pcishpc_slot_poweroff(): slot_p 0x%p, slot state 0x%x, " 134926947304SEvan Yan "current bus speed 0x%x, slots connected 0x%x\n", slot_p, 135026947304SEvan Yan slot_p->hs_info.cn_state, slot_p->hs_ctrl->hc_curr_bus_speed, 135126947304SEvan Yan slot_p->hs_ctrl->hc_num_slots_connected); 135226947304SEvan Yan 135326947304SEvan Yan /* Mask or Unmask MRL Sensor SEER bit based on new slot state */ 135426947304SEvan Yan if (slot_p->hs_ctrl->hc_has_mrl == B_TRUE) { 135526947304SEvan Yan uint32_t reg; 135626947304SEvan Yan 135726947304SEvan Yan reg = pcishpc_read_reg(slot_p->hs_ctrl, 135826947304SEvan Yan PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num); 135926947304SEvan Yan 136026947304SEvan Yan pcishpc_write_reg(slot_p->hs_ctrl, 136126947304SEvan Yan PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num, 136226947304SEvan Yan reg | PCI_HP_SLOT_MRL_SERR_MASK); 136326947304SEvan Yan } 136426947304SEvan Yan 136526947304SEvan Yan /* Update the hardware slot state. */ 136626947304SEvan Yan if (pcishpc_set_slot_state(slot_p, DDI_HP_CN_STATE_PRESENT) != 136726947304SEvan Yan DDI_SUCCESS) { 136826947304SEvan Yan PCIE_DBG("pcishpc_slot_poweroff() failed\n"); 136926947304SEvan Yan 137026947304SEvan Yan pcishpc_get_slot_state(slot_p); 137126947304SEvan Yan goto cleanup; 137226947304SEvan Yan } 137326947304SEvan Yan 137426947304SEvan Yan /* Update the current state. It will be used in pcishpc_setled() */ 137526947304SEvan Yan slot_p->hs_info.cn_state = DDI_HP_CN_STATE_PRESENT; 137626947304SEvan Yan 137726947304SEvan Yan /* Turn the Power LED OFF for a disabled slot. */ 137826947304SEvan Yan (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF); 137926947304SEvan Yan 138026947304SEvan Yan /* Turn all other LEDS off. */ 138126947304SEvan Yan (void) pcishpc_setled(slot_p, PCIE_HP_FAULT_LED, PCIE_HP_LED_OFF); 138226947304SEvan Yan (void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF); 138326947304SEvan Yan (void) pcishpc_setled(slot_p, PCIE_HP_ACTIVE_LED, PCIE_HP_LED_OFF); 138426947304SEvan Yan 138526947304SEvan Yan /* delay after powerON to let the device initialize itself */ 138626947304SEvan Yan delay(drv_usectohz(pcishpc_reset_delay)); 138726947304SEvan Yan 138826947304SEvan Yan pcishpc_get_slot_state(slot_p); 138926947304SEvan Yan /* 139026947304SEvan Yan * It should be poweroff'ed now. Have a check here in case any 139126947304SEvan Yan * hardware problems. 139226947304SEvan Yan */ 139326947304SEvan Yan if (slot_p->hs_info.cn_state > DDI_HP_CN_STATE_PRESENT) { 139426947304SEvan Yan PCIE_DBG("pcishpc_slot_poweroff() failed after hardware" 139526947304SEvan Yan " registers all programmed.\n"); 139626947304SEvan Yan 139726947304SEvan Yan goto cleanup; 139826947304SEvan Yan } 139926947304SEvan Yan 140026947304SEvan Yan PCIE_DBG("pcishpc_slot_poweroff() success!\n"); 140126947304SEvan Yan 140226947304SEvan Yan *result_state = slot_p->hs_info.cn_state; 140326947304SEvan Yan return (DDI_SUCCESS); 140426947304SEvan Yan 140526947304SEvan Yan cleanup: 140626947304SEvan Yan (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF); 140726947304SEvan Yan return (DDI_FAILURE); 140826947304SEvan Yan } 140926947304SEvan Yan 141026947304SEvan Yan /* 141126947304SEvan Yan * pcishpc_slot_probe() 141226947304SEvan Yan * 141326947304SEvan Yan * Probe the slot. 141426947304SEvan Yan * 141526947304SEvan Yan * Note: This function is called by DDI HP framework at kernel context only 141626947304SEvan Yan */ 141726947304SEvan Yan /*ARGSUSED*/ 141826947304SEvan Yan static int 141926947304SEvan Yan pcishpc_slot_probe(pcie_hp_slot_t *slot_p) 142026947304SEvan Yan { 142126947304SEvan Yan mutex_enter(&slot_p->hs_ctrl->hc_mutex); 142226947304SEvan Yan 142326947304SEvan Yan PCIE_DBG("pcishpc_slot_probe called()\n"); 142426947304SEvan Yan 142526947304SEvan Yan /* get the current slot state */ 142626947304SEvan Yan pcishpc_get_slot_state(slot_p); 142726947304SEvan Yan 142826947304SEvan Yan /* 142926947304SEvan Yan * Probe a given PCI Hotplug Connection (CN). 143026947304SEvan Yan */ 143126947304SEvan Yan if (pcie_hp_probe(slot_p) != DDI_SUCCESS) { 143226947304SEvan Yan (void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, 143326947304SEvan Yan PCIE_HP_LED_BLINK); 143426947304SEvan Yan 143526947304SEvan Yan PCIE_DBG("pcishpc_slot_probe() failed\n"); 143626947304SEvan Yan 143726947304SEvan Yan mutex_exit(&slot_p->hs_ctrl->hc_mutex); 143826947304SEvan Yan return (DDI_FAILURE); 143926947304SEvan Yan } 144026947304SEvan Yan 144126947304SEvan Yan PCIE_DBG("pcishpc_slot_probe() success!\n"); 144226947304SEvan Yan 144326947304SEvan Yan /* get the current slot state */ 144426947304SEvan Yan pcishpc_get_slot_state(slot_p); 144526947304SEvan Yan 144626947304SEvan Yan mutex_exit(&slot_p->hs_ctrl->hc_mutex); 144726947304SEvan Yan return (DDI_SUCCESS); 144826947304SEvan Yan } 144926947304SEvan Yan 145026947304SEvan Yan /* 145126947304SEvan Yan * pcishpc_slot_unprobe() 145226947304SEvan Yan * 145326947304SEvan Yan * Unprobe the slot. 145426947304SEvan Yan * 145526947304SEvan Yan * Note: This function is called by DDI HP framework at kernel context only 145626947304SEvan Yan */ 145726947304SEvan Yan /*ARGSUSED*/ 145826947304SEvan Yan static int 145926947304SEvan Yan pcishpc_slot_unprobe(pcie_hp_slot_t *slot_p) 146026947304SEvan Yan { 146126947304SEvan Yan mutex_enter(&slot_p->hs_ctrl->hc_mutex); 146226947304SEvan Yan 146326947304SEvan Yan PCIE_DBG("pcishpc_slot_unprobe called()\n"); 146426947304SEvan Yan 146526947304SEvan Yan /* get the current slot state */ 146626947304SEvan Yan pcishpc_get_slot_state(slot_p); 146726947304SEvan Yan 146826947304SEvan Yan /* 146926947304SEvan Yan * Unprobe a given PCI Hotplug Connection (CN). 147026947304SEvan Yan */ 147126947304SEvan Yan if (pcie_hp_unprobe(slot_p) != DDI_SUCCESS) { 147226947304SEvan Yan (void) pcishpc_setled(slot_p, PCIE_HP_ATTN_LED, 147326947304SEvan Yan PCIE_HP_LED_BLINK); 147426947304SEvan Yan 147526947304SEvan Yan PCIE_DBG("pcishpc_slot_unprobe() failed\n"); 147626947304SEvan Yan 147726947304SEvan Yan mutex_exit(&slot_p->hs_ctrl->hc_mutex); 147826947304SEvan Yan return (DDI_FAILURE); 147926947304SEvan Yan } 148026947304SEvan Yan 148126947304SEvan Yan PCIE_DBG("pcishpc_slot_unprobe() success!\n"); 148226947304SEvan Yan 148326947304SEvan Yan /* get the current slot state */ 148426947304SEvan Yan pcishpc_get_slot_state(slot_p); 148526947304SEvan Yan 148626947304SEvan Yan mutex_exit(&slot_p->hs_ctrl->hc_mutex); 148726947304SEvan Yan return (DDI_SUCCESS); 148826947304SEvan Yan } 148926947304SEvan Yan 149026947304SEvan Yan static int 149126947304SEvan Yan pcishpc_upgrade_slot_state(pcie_hp_slot_t *slot_p, 149226947304SEvan Yan ddi_hp_cn_state_t target_state) 149326947304SEvan Yan { 149426947304SEvan Yan ddi_hp_cn_state_t curr_state; 149526947304SEvan Yan int rv = DDI_SUCCESS; 149626947304SEvan Yan 149726947304SEvan Yan if (target_state > DDI_HP_CN_STATE_ENABLED) { 149826947304SEvan Yan return (DDI_EINVAL); 149926947304SEvan Yan } 150026947304SEvan Yan 150126947304SEvan Yan curr_state = slot_p->hs_info.cn_state; 150226947304SEvan Yan while ((curr_state < target_state) && (rv == DDI_SUCCESS)) { 150326947304SEvan Yan 150426947304SEvan Yan switch (curr_state) { 150526947304SEvan Yan case DDI_HP_CN_STATE_EMPTY: 150626947304SEvan Yan /* 150726947304SEvan Yan * From EMPTY to PRESENT, just check the hardware 150826947304SEvan Yan * slot state. 150926947304SEvan Yan */ 151026947304SEvan Yan pcishpc_get_slot_state(slot_p); 151126947304SEvan Yan curr_state = slot_p->hs_info.cn_state; 151226947304SEvan Yan if (curr_state < DDI_HP_CN_STATE_PRESENT) 151326947304SEvan Yan rv = DDI_FAILURE; 151426947304SEvan Yan break; 151526947304SEvan Yan case DDI_HP_CN_STATE_PRESENT: 151626947304SEvan Yan rv = pcishpc_slot_poweron(slot_p, &curr_state); 151726947304SEvan Yan break; 151826947304SEvan Yan case DDI_HP_CN_STATE_POWERED: 151926947304SEvan Yan curr_state = slot_p->hs_info.cn_state = 152026947304SEvan Yan DDI_HP_CN_STATE_ENABLED; 152126947304SEvan Yan break; 152226947304SEvan Yan default: 152326947304SEvan Yan /* should never reach here */ 152426947304SEvan Yan ASSERT("unknown devinfo state"); 152526947304SEvan Yan } 152626947304SEvan Yan } 152726947304SEvan Yan 152826947304SEvan Yan return (rv); 152926947304SEvan Yan } 153026947304SEvan Yan 153126947304SEvan Yan static int 153226947304SEvan Yan pcishpc_downgrade_slot_state(pcie_hp_slot_t *slot_p, 153326947304SEvan Yan ddi_hp_cn_state_t target_state) 153426947304SEvan Yan { 153526947304SEvan Yan ddi_hp_cn_state_t curr_state; 153626947304SEvan Yan int rv = DDI_SUCCESS; 153726947304SEvan Yan 153826947304SEvan Yan 153926947304SEvan Yan curr_state = slot_p->hs_info.cn_state; 154026947304SEvan Yan while ((curr_state > target_state) && (rv == DDI_SUCCESS)) { 154126947304SEvan Yan 154226947304SEvan Yan switch (curr_state) { 154326947304SEvan Yan case DDI_HP_CN_STATE_PRESENT: 154426947304SEvan Yan /* 154526947304SEvan Yan * From PRESENT to EMPTY, just check hardware 154626947304SEvan Yan * slot state. 154726947304SEvan Yan */ 154826947304SEvan Yan pcishpc_get_slot_state(slot_p); 154926947304SEvan Yan curr_state = slot_p->hs_info.cn_state; 155026947304SEvan Yan if (curr_state >= DDI_HP_CN_STATE_PRESENT) 155126947304SEvan Yan rv = DDI_FAILURE; 155226947304SEvan Yan break; 155326947304SEvan Yan case DDI_HP_CN_STATE_POWERED: 155426947304SEvan Yan rv = pcishpc_slot_poweroff(slot_p, &curr_state); 155526947304SEvan Yan 155626947304SEvan Yan break; 155726947304SEvan Yan case DDI_HP_CN_STATE_ENABLED: 155826947304SEvan Yan curr_state = slot_p->hs_info.cn_state = 155926947304SEvan Yan DDI_HP_CN_STATE_POWERED; 156026947304SEvan Yan 156126947304SEvan Yan break; 156226947304SEvan Yan default: 156326947304SEvan Yan /* should never reach here */ 156426947304SEvan Yan ASSERT("unknown devinfo state"); 156526947304SEvan Yan } 156626947304SEvan Yan } 156726947304SEvan Yan 156826947304SEvan Yan return (rv); 156926947304SEvan Yan } 157026947304SEvan Yan 157126947304SEvan Yan /* Change slot state to a target state */ 157226947304SEvan Yan static int 157326947304SEvan Yan pcishpc_change_slot_state(pcie_hp_slot_t *slot_p, 157426947304SEvan Yan ddi_hp_cn_state_t target_state) 157526947304SEvan Yan { 157626947304SEvan Yan ddi_hp_cn_state_t curr_state; 157726947304SEvan Yan int rv; 157826947304SEvan Yan 157926947304SEvan Yan pcishpc_get_slot_state(slot_p); 158026947304SEvan Yan curr_state = slot_p->hs_info.cn_state; 158126947304SEvan Yan 158226947304SEvan Yan if (curr_state == target_state) { 158326947304SEvan Yan return (DDI_SUCCESS); 158426947304SEvan Yan } 158526947304SEvan Yan if (curr_state < target_state) { 158626947304SEvan Yan 158726947304SEvan Yan rv = pcishpc_upgrade_slot_state(slot_p, target_state); 158826947304SEvan Yan } else { 158926947304SEvan Yan rv = pcishpc_downgrade_slot_state(slot_p, target_state); 159026947304SEvan Yan } 159126947304SEvan Yan 159226947304SEvan Yan return (rv); 159326947304SEvan Yan } 159426947304SEvan Yan 159526947304SEvan Yan /* 159626947304SEvan Yan * pcishpc_issue_command() 159726947304SEvan Yan * 159826947304SEvan Yan * Sends a command to the SHPC controller. 159926947304SEvan Yan */ 160026947304SEvan Yan static int 160126947304SEvan Yan pcishpc_issue_command(pcie_hp_ctrl_t *ctrl_p, uint32_t cmd_code) 160226947304SEvan Yan { 160326947304SEvan Yan int retCode; 160426947304SEvan Yan 160526947304SEvan Yan ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex)); 160626947304SEvan Yan 160726947304SEvan Yan PCIE_DBG("pcishpc_issue_command() cmd_code=%02x\n", cmd_code); 160826947304SEvan Yan 160926947304SEvan Yan ctrl_p->hc_cmd_pending = B_TRUE; 161026947304SEvan Yan 161126947304SEvan Yan /* Write the command to the SHPC controller. */ 161226947304SEvan Yan pcishpc_write_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG, cmd_code); 161326947304SEvan Yan 161426947304SEvan Yan while (ctrl_p->hc_cmd_pending == B_TRUE) 161526947304SEvan Yan cv_wait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex); 161626947304SEvan Yan 161726947304SEvan Yan /* Wait until the SHPC controller processes the command. */ 161826947304SEvan Yan retCode = pcishpc_wait_busy(ctrl_p); 161926947304SEvan Yan 162026947304SEvan Yan /* Make sure the command completed. */ 162126947304SEvan Yan if (retCode == DDI_SUCCESS) { 162226947304SEvan Yan /* Did the command fail to generate the command complete IRQ? */ 162326947304SEvan Yan if (ctrl_p->hc_cmd_pending != B_FALSE) { 162426947304SEvan Yan PCIE_DBG("pcishpc_issue_command() Failed on " 162526947304SEvan Yan "generate cmd complete IRQ\n"); 162626947304SEvan Yan retCode = DDI_FAILURE; 162726947304SEvan Yan } 162826947304SEvan Yan } 162926947304SEvan Yan 163026947304SEvan Yan if (retCode == DDI_FAILURE) 163126947304SEvan Yan PCIE_DBG("pcishpc_issue_command() Failed on cmd_code=%02x\n", 163226947304SEvan Yan cmd_code); 163326947304SEvan Yan else 163426947304SEvan Yan PCIE_DBG("pcishpc_issue_command() Success on " 163526947304SEvan Yan "cmd_code=%02x\n", cmd_code); 163626947304SEvan Yan 163726947304SEvan Yan return (retCode); 163826947304SEvan Yan } 163926947304SEvan Yan 164026947304SEvan Yan /* 164126947304SEvan Yan * pcishpc_wait_busy() 164226947304SEvan Yan * 164326947304SEvan Yan * Wait until the SHPC controller is not busy. 164426947304SEvan Yan */ 164526947304SEvan Yan static int 164626947304SEvan Yan pcishpc_wait_busy(pcie_hp_ctrl_t *ctrl_p) 164726947304SEvan Yan { 164826947304SEvan Yan uint32_t status; 164926947304SEvan Yan 165026947304SEvan Yan /* Wait until SHPC controller is NOT busy */ 165126947304SEvan Yan for (;;) { 165226947304SEvan Yan status = pcishpc_read_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG); 165326947304SEvan Yan 165426947304SEvan Yan /* Is there an MRL Sensor error? */ 165526947304SEvan Yan if ((status & PCI_HP_COMM_STS_ERR_MASK) == 165626947304SEvan Yan PCI_HP_COMM_STS_ERR_MRL_OPEN) { 165726947304SEvan Yan PCIE_DBG("pcishpc_wait_busy() ERROR: " 165826947304SEvan Yan "MRL Sensor error\n"); 165926947304SEvan Yan break; 166026947304SEvan Yan } 166126947304SEvan Yan 166226947304SEvan Yan /* Is there an Invalid command error? */ 166326947304SEvan Yan if ((status & PCI_HP_COMM_STS_ERR_MASK) == 166426947304SEvan Yan PCI_HP_COMM_STS_ERR_INVALID_COMMAND) { 166526947304SEvan Yan PCIE_DBG("pcishpc_wait_busy() ERROR: Invalid " 166626947304SEvan Yan "command error\n"); 166726947304SEvan Yan break; 166826947304SEvan Yan } 166926947304SEvan Yan 167026947304SEvan Yan /* Is there an Invalid Speed/Mode error? */ 167126947304SEvan Yan if ((status & PCI_HP_COMM_STS_ERR_MASK) == 167226947304SEvan Yan PCI_HP_COMM_STS_ERR_INVALID_SPEED) { 167326947304SEvan Yan PCIE_DBG("pcishpc_wait_busy() ERROR: Invalid " 167426947304SEvan Yan "Speed/Mode error\n"); 167526947304SEvan Yan break; 167626947304SEvan Yan } 167726947304SEvan Yan 167826947304SEvan Yan /* Is the SHPC controller not BUSY? */ 167926947304SEvan Yan if (!(status & PCI_HP_COMM_STS_CTRL_BUSY)) { 168026947304SEvan Yan /* Return Success. */ 168126947304SEvan Yan return (DDI_SUCCESS); 168226947304SEvan Yan } 168326947304SEvan Yan 168426947304SEvan Yan PCIE_DBG("pcishpc_wait_busy() SHPC controller busy. Waiting\n"); 168526947304SEvan Yan 168626947304SEvan Yan /* Wait before polling the status register again. */ 168726947304SEvan Yan delay(drv_usectohz(PCIE_HP_CMD_WAIT_TIME)); 168826947304SEvan Yan } 168926947304SEvan Yan 169026947304SEvan Yan return (DDI_FAILURE); 169126947304SEvan Yan } 169226947304SEvan Yan 169326947304SEvan Yan static void 169426947304SEvan Yan pcishpc_attn_btn_handler(pcie_hp_slot_t *slot_p) 169526947304SEvan Yan { 169626947304SEvan Yan pcie_hp_led_state_t hs_power_led_state; 169726947304SEvan Yan callb_cpr_t cprinfo; 169826947304SEvan Yan 169926947304SEvan Yan PCIE_DBG("pcishpc_attn_btn_handler: thread started\n"); 170026947304SEvan Yan 170126947304SEvan Yan CALLB_CPR_INIT(&cprinfo, &slot_p->hs_ctrl->hc_mutex, 170226947304SEvan Yan callb_generic_cpr, "pcishpc_attn_btn_handler"); 170326947304SEvan Yan 170426947304SEvan Yan mutex_enter(&slot_p->hs_ctrl->hc_mutex); 170526947304SEvan Yan 170626947304SEvan Yan /* wait for ATTN button event */ 170726947304SEvan Yan cv_wait(&slot_p->hs_attn_btn_cv, &slot_p->hs_ctrl->hc_mutex); 170826947304SEvan Yan 170926947304SEvan Yan while (slot_p->hs_attn_btn_thread_exit == B_FALSE) { 171026947304SEvan Yan if (slot_p->hs_attn_btn_pending == B_TRUE) { 171126947304SEvan Yan /* get the current state of power LED */ 171226947304SEvan Yan hs_power_led_state = slot_p->hs_power_led_state; 171326947304SEvan Yan 171426947304SEvan Yan /* Blink the Power LED while we wait for 5 seconds */ 171526947304SEvan Yan (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, 171626947304SEvan Yan PCIE_HP_LED_BLINK); 171726947304SEvan Yan 171826947304SEvan Yan /* wait for 5 seconds before taking any action */ 1719d3d50737SRafael Vanoni if (cv_reltimedwait(&slot_p->hs_attn_btn_cv, 172026947304SEvan Yan &slot_p->hs_ctrl->hc_mutex, 1721d3d50737SRafael Vanoni SEC_TO_TICK(5), TR_CLOCK_TICK) == -1) { 172226947304SEvan Yan /* 172326947304SEvan Yan * It is a time out; 172426947304SEvan Yan * make sure the ATTN pending flag is 172526947304SEvan Yan * still ON before sending the event 172626947304SEvan Yan * to DDI HP framework. 172726947304SEvan Yan */ 172826947304SEvan Yan if (slot_p->hs_attn_btn_pending == B_TRUE) { 172926947304SEvan Yan int hint; 173026947304SEvan Yan 173126947304SEvan Yan /* restore the power LED state */ 173226947304SEvan Yan (void) pcishpc_setled(slot_p, 173326947304SEvan Yan PCIE_HP_POWER_LED, 173426947304SEvan Yan hs_power_led_state); 173526947304SEvan Yan /* 173626947304SEvan Yan * send the ATTN button event 173726947304SEvan Yan * to DDI HP framework 173826947304SEvan Yan */ 173926947304SEvan Yan slot_p->hs_attn_btn_pending = B_FALSE; 174026947304SEvan Yan 174126947304SEvan Yan pcishpc_get_slot_state(slot_p); 174226947304SEvan Yan 174326947304SEvan Yan if (slot_p->hs_info.cn_state <= 174426947304SEvan Yan DDI_HP_CN_STATE_PRESENT) { 174526947304SEvan Yan /* 174626947304SEvan Yan * Insertion. 174726947304SEvan Yan */ 174826947304SEvan Yan hint = SE_INCOMING_RES; 174926947304SEvan Yan } else { 175026947304SEvan Yan /* 175126947304SEvan Yan * Want to remove; 175226947304SEvan Yan */ 175326947304SEvan Yan hint = SE_OUTGOING_RES; 175426947304SEvan Yan } 175526947304SEvan Yan pcie_hp_gen_sysevent_req( 175626947304SEvan Yan slot_p->hs_info.cn_name, 175726947304SEvan Yan hint, 175826947304SEvan Yan slot_p->hs_ctrl->hc_dip, 175926947304SEvan Yan KM_SLEEP); 176026947304SEvan Yan 176126947304SEvan Yan continue; 176226947304SEvan Yan } 176326947304SEvan Yan } 176426947304SEvan Yan 176526947304SEvan Yan /* restore the power LED state */ 176626947304SEvan Yan (void) pcishpc_setled(slot_p, PCIE_HP_POWER_LED, 176726947304SEvan Yan hs_power_led_state); 176826947304SEvan Yan continue; 176926947304SEvan Yan } 177026947304SEvan Yan 177126947304SEvan Yan /* wait for another ATTN button event */ 177226947304SEvan Yan cv_wait(&slot_p->hs_attn_btn_cv, &slot_p->hs_ctrl->hc_mutex); 177326947304SEvan Yan } 177426947304SEvan Yan 177526947304SEvan Yan PCIE_DBG("pcishpc_attn_btn_handler: thread exit\n"); 177626947304SEvan Yan cv_signal(&slot_p->hs_attn_btn_cv); 177726947304SEvan Yan CALLB_CPR_EXIT(&cprinfo); 177826947304SEvan Yan thread_exit(); 177926947304SEvan Yan } 178026947304SEvan Yan 178126947304SEvan Yan /* 178226947304SEvan Yan * pcishpc_get_slot_state() 178326947304SEvan Yan * 178426947304SEvan Yan * Get the state of the slot. 178526947304SEvan Yan * The slot state should have been initialized before this function gets called. 178626947304SEvan Yan */ 178726947304SEvan Yan static void 178826947304SEvan Yan pcishpc_get_slot_state(pcie_hp_slot_t *slot_p) 178926947304SEvan Yan { 179026947304SEvan Yan uint32_t reg; 179126947304SEvan Yan ddi_hp_cn_state_t curr_state = slot_p->hs_info.cn_state; 179226947304SEvan Yan 179326947304SEvan Yan /* Read the logical slot register for this Slot. */ 179426947304SEvan Yan reg = pcishpc_read_reg(slot_p->hs_ctrl, 179526947304SEvan Yan PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num); 179626947304SEvan Yan 179726947304SEvan Yan /* Convert from the SHPC slot state to the HPC slot state. */ 179826947304SEvan Yan slot_p->hs_info.cn_state = pcishpc_slot_shpc_to_hpc(reg); 179926947304SEvan Yan if (curr_state == DDI_HP_CN_STATE_POWERED && 180026947304SEvan Yan slot_p->hs_info.cn_state > DDI_HP_CN_STATE_POWERED) { 180126947304SEvan Yan /* 180226947304SEvan Yan * Keep POWERED state if it is currently POWERED state because 180326947304SEvan Yan * this driver does not really implement enable/disable 180426947304SEvan Yan * slot operations. That is, when poweron, it actually enables 180526947304SEvan Yan * the slot also. 180626947304SEvan Yan * So, from hardware view, POWERED == ENABLED. 180726947304SEvan Yan * But, when user explicitly change to POWERED state, it should 180826947304SEvan Yan * be kept until user explicitly change to other states later. 180926947304SEvan Yan */ 181026947304SEvan Yan slot_p->hs_info.cn_state = DDI_HP_CN_STATE_POWERED; 181126947304SEvan Yan } 181226947304SEvan Yan 181326947304SEvan Yan /* Convert from the SHPC Power LED state to the HPC Power LED state. */ 181426947304SEvan Yan slot_p->hs_power_led_state = pcishpc_led_shpc_to_hpc((reg>>2)&3); 181526947304SEvan Yan 181626947304SEvan Yan /* Convert from the SHPC Attn LED state to the HPC Attn LED state. */ 181726947304SEvan Yan slot_p->hs_attn_led_state = pcishpc_led_shpc_to_hpc((reg>>4)&3); 181826947304SEvan Yan 181926947304SEvan Yan /* We don't have a fault LED so just default it to OFF. */ 182026947304SEvan Yan slot_p->hs_fault_led_state = PCIE_HP_LED_OFF; 182126947304SEvan Yan 182226947304SEvan Yan /* We don't have an active LED so just default it to OFF. */ 182326947304SEvan Yan slot_p->hs_active_led_state = PCIE_HP_LED_OFF; 182426947304SEvan Yan } 182526947304SEvan Yan 182626947304SEvan Yan /* 182726947304SEvan Yan * pcishpc_set_slot_state() 182826947304SEvan Yan * 182926947304SEvan Yan * Updates the slot's state and leds. 183026947304SEvan Yan */ 183126947304SEvan Yan static int 183226947304SEvan Yan pcishpc_set_slot_state(pcie_hp_slot_t *slot_p, 183326947304SEvan Yan ddi_hp_cn_state_t new_slot_state) 183426947304SEvan Yan { 183526947304SEvan Yan uint32_t reg, cmd_code; 183626947304SEvan Yan ddi_hp_cn_state_t curr_state; 183726947304SEvan Yan 183826947304SEvan Yan ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex)); 183926947304SEvan Yan 184026947304SEvan Yan reg = pcishpc_read_reg(slot_p->hs_ctrl, 184126947304SEvan Yan PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num); 184226947304SEvan Yan 184326947304SEvan Yan /* Default all states to unchanged. */ 184426947304SEvan Yan cmd_code = ((1 + slot_p->hs_num) << 8); 184526947304SEvan Yan 184626947304SEvan Yan /* Has the slot state changed? */ 184726947304SEvan Yan curr_state = pcishpc_slot_shpc_to_hpc(reg); 184826947304SEvan Yan if (curr_state != new_slot_state) { 184926947304SEvan Yan PCIE_DBG("pcishpc_set_slot_state() Slot State changed"); 185026947304SEvan Yan 185126947304SEvan Yan /* Set the new slot state in the Slot operation command. */ 185226947304SEvan Yan cmd_code |= pcishpc_slot_hpc_to_shpc(new_slot_state); 185326947304SEvan Yan } 185426947304SEvan Yan 185526947304SEvan Yan /* Has the Power LED state changed? */ 185626947304SEvan Yan if (slot_p->hs_power_led_state != pcishpc_led_shpc_to_hpc((reg>>2)&3)) { 185726947304SEvan Yan PCIE_DBG("pcishpc_set_slot_state() Power LED State changed\n"); 185826947304SEvan Yan 185926947304SEvan Yan /* Set the new power led state in the Slot operation command. */ 186026947304SEvan Yan cmd_code |= 186126947304SEvan Yan (pcishpc_led_hpc_to_shpc(slot_p->hs_power_led_state) << 2); 186226947304SEvan Yan } 186326947304SEvan Yan 186426947304SEvan Yan /* Has the Attn LED state changed? */ 186526947304SEvan Yan if (slot_p->hs_attn_led_state != pcishpc_led_shpc_to_hpc((reg>>4)&3)) { 186626947304SEvan Yan PCIE_DBG("pcishpc_set_slot_state() Attn LED State changed\n"); 186726947304SEvan Yan 186826947304SEvan Yan /* Set the new attn led state in the Slot operation command. */ 186926947304SEvan Yan cmd_code |= 187026947304SEvan Yan (pcishpc_led_hpc_to_shpc(slot_p->hs_attn_led_state) << 4); 187126947304SEvan Yan } 187226947304SEvan Yan 187326947304SEvan Yan return (pcishpc_issue_command(slot_p->hs_ctrl, cmd_code)); 187426947304SEvan Yan } 187526947304SEvan Yan 187626947304SEvan Yan /* 187726947304SEvan Yan * setup slot name/slot-number info. 187826947304SEvan Yan */ 187926947304SEvan Yan static void 188026947304SEvan Yan pcishpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p, int slot) 188126947304SEvan Yan { 188226947304SEvan Yan pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[slot]; 188326947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 188426947304SEvan Yan uchar_t *slotname_data; 188526947304SEvan Yan int *slotnum; 188626947304SEvan Yan uint_t count; 188726947304SEvan Yan int len; 188826947304SEvan Yan uchar_t *s; 188926947304SEvan Yan uint32_t bit_mask; 189026947304SEvan Yan int pci_id_cnt, pci_id_bit; 189126947304SEvan Yan int slots_before, found; 189226947304SEvan Yan int invalid_slotnum = 0; 189326947304SEvan Yan 189426947304SEvan Yan if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ctrl_p->hc_dip, 189526947304SEvan Yan DDI_PROP_DONTPASS, "physical-slot#", &slotnum, &count) == 189626947304SEvan Yan DDI_PROP_SUCCESS) { 189726947304SEvan Yan slot_p->hs_phy_slot_num = slotnum[0]; 189826947304SEvan Yan ddi_prop_free(slotnum); 189926947304SEvan Yan } else { 190026947304SEvan Yan if (ctrl_p->hc_device_increases) 190126947304SEvan Yan slot_p->hs_phy_slot_num = ctrl_p->hc_phys_start + slot; 190226947304SEvan Yan else 190326947304SEvan Yan slot_p->hs_phy_slot_num = ctrl_p->hc_phys_start - slot; 190426947304SEvan Yan 190526947304SEvan Yan if ((ndi_prop_update_int(DDI_DEV_T_NONE, ctrl_p->hc_dip, 190626947304SEvan Yan "physical-slot#", slot_p->hs_phy_slot_num)) != DDI_SUCCESS) 190726947304SEvan Yan PCIE_DBG("pcishpc_set_slot_name(): failed to " 190826947304SEvan Yan "create phyical-slot#%d\n", 190926947304SEvan Yan slot_p->hs_phy_slot_num); 191026947304SEvan Yan } 191126947304SEvan Yan 191226947304SEvan Yan /* Platform may not have initialized it */ 191326947304SEvan Yan if (!slot_p->hs_phy_slot_num) { 191426947304SEvan Yan slot_p->hs_phy_slot_num = pci_config_get8(bus_p->bus_cfg_hdl, 191526947304SEvan Yan PCI_BCNF_SECBUS); 191626947304SEvan Yan invalid_slotnum = 1; 191726947304SEvan Yan } 191826947304SEvan Yan slot_p->hs_info.cn_num = slot_p->hs_phy_slot_num; 191926947304SEvan Yan slot_p->hs_info.cn_num_dpd_on = DDI_HP_CN_NUM_NONE; 192026947304SEvan Yan 192126947304SEvan Yan /* 192226947304SEvan Yan * construct the slot_name: 192326947304SEvan Yan * if "slot-names" property exists then use that name 192426947304SEvan Yan * else if valid slot number exists then it is "pci<slot-num>". 192526947304SEvan Yan * else it will be "pci<sec-bus-number>dev<dev-number>" 192626947304SEvan Yan */ 192726947304SEvan Yan if (ddi_getlongprop(DDI_DEV_T_ANY, ctrl_p->hc_dip, DDI_PROP_DONTPASS, 192826947304SEvan Yan "slot-names", (caddr_t)&slotname_data, &len) == DDI_PROP_SUCCESS) { 192926947304SEvan Yan bit_mask = slotname_data[3] | (slotname_data[2] << 8) | 193026947304SEvan Yan (slotname_data[1] << 16) | (slotname_data[0] << 24); 193126947304SEvan Yan 193226947304SEvan Yan pci_id_bit = 1; 193326947304SEvan Yan pci_id_cnt = slots_before = found = 0; 193426947304SEvan Yan 193526947304SEvan Yan /* 193626947304SEvan Yan * Walk the bit mask until we find the bit that corresponds 193726947304SEvan Yan * to our slots device number. We count how many bits 193826947304SEvan Yan * we find before we find our slot's bit. 193926947304SEvan Yan */ 194026947304SEvan Yan while (!found && (pci_id_cnt < 32)) { 194126947304SEvan Yan while (slot_p->hs_device_num != pci_id_cnt) { 194226947304SEvan Yan 194326947304SEvan Yan /* 194426947304SEvan Yan * Find the next bit set. 194526947304SEvan Yan */ 194626947304SEvan Yan while (!(bit_mask & pci_id_bit) && 194726947304SEvan Yan (pci_id_cnt < 32)) { 194826947304SEvan Yan pci_id_bit = pci_id_bit << 1; 194926947304SEvan Yan pci_id_cnt++; 195026947304SEvan Yan } 195126947304SEvan Yan 195226947304SEvan Yan if (slot_p->hs_device_num != pci_id_cnt) 195326947304SEvan Yan slots_before++; 195426947304SEvan Yan else 195526947304SEvan Yan found = 1; 195626947304SEvan Yan } 195726947304SEvan Yan } 195826947304SEvan Yan 195926947304SEvan Yan if (pci_id_cnt < 32) { 196026947304SEvan Yan 196126947304SEvan Yan /* 196226947304SEvan Yan * Set ptr to first string. 196326947304SEvan Yan */ 196426947304SEvan Yan s = slotname_data + 4; 196526947304SEvan Yan 196626947304SEvan Yan /* 196726947304SEvan Yan * Increment past all the strings for the slots 196826947304SEvan Yan * before ours. 196926947304SEvan Yan */ 197026947304SEvan Yan while (slots_before) { 197126947304SEvan Yan while (*s != NULL) 197226947304SEvan Yan s++; 197326947304SEvan Yan s++; 197426947304SEvan Yan slots_before--; 197526947304SEvan Yan } 197626947304SEvan Yan 197726947304SEvan Yan slot_p->hs_info.cn_name = i_ddi_strdup((char *)s, 197826947304SEvan Yan KM_SLEEP); 197926947304SEvan Yan kmem_free(slotname_data, len); 198026947304SEvan Yan return; 198126947304SEvan Yan } 198226947304SEvan Yan 198326947304SEvan Yan /* slot-names entry not found */ 198426947304SEvan Yan PCIE_DBG("pcishpc_set_slot_name(): " 198526947304SEvan Yan "No slot-names entry found for slot #%d\n", 198626947304SEvan Yan slot_p->hs_phy_slot_num); 198726947304SEvan Yan kmem_free(slotname_data, len); 198826947304SEvan Yan } 198926947304SEvan Yan 199026947304SEvan Yan if (invalid_slotnum) { 199126947304SEvan Yan char tmp_name[256]; 199226947304SEvan Yan 199326947304SEvan Yan (void) snprintf(tmp_name, sizeof (tmp_name), "pci%d", 199426947304SEvan Yan slot_p->hs_device_num); 199526947304SEvan Yan slot_p->hs_info.cn_name = i_ddi_strdup(tmp_name, KM_SLEEP); 199626947304SEvan Yan } else { 199726947304SEvan Yan char tmp_name[256]; 199826947304SEvan Yan 199926947304SEvan Yan (void) snprintf(tmp_name, sizeof (tmp_name), "pci%d", 200026947304SEvan Yan slot_p->hs_phy_slot_num); 200126947304SEvan Yan slot_p->hs_info.cn_name = i_ddi_strdup(tmp_name, KM_SLEEP); 200226947304SEvan Yan } 200326947304SEvan Yan } 200426947304SEvan Yan 200526947304SEvan Yan /* 200626947304SEvan Yan * pcishpc_set_bus_speed() 200726947304SEvan Yan * 200826947304SEvan Yan * Set the bus speed and mode. 200926947304SEvan Yan */ 201026947304SEvan Yan static int 201126947304SEvan Yan pcishpc_set_bus_speed(pcie_hp_slot_t *slot_p) 201226947304SEvan Yan { 201326947304SEvan Yan pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl; 201426947304SEvan Yan int curr_speed = ctrl_p->hc_curr_bus_speed; 201526947304SEvan Yan int speed = -1; 201626947304SEvan Yan int avail_slots; 201726947304SEvan Yan uint32_t status, slots_avail1_reg, slots_avail2_reg; 201826947304SEvan Yan 201926947304SEvan Yan ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex)); 202026947304SEvan Yan 202126947304SEvan Yan /* Make sure that the slot is in a correct state */ 202226947304SEvan Yan status = pcishpc_read_reg(ctrl_p, 202326947304SEvan Yan PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num); 202426947304SEvan Yan 202526947304SEvan Yan /* Return failure if the slot is empty */ 202626947304SEvan Yan if ((status & PCI_HP_SLOT_CARD_EMPTY_MASK) == 202726947304SEvan Yan PCI_HP_SLOT_CARD_EMPTY_MASK) { 202826947304SEvan Yan PCIE_DBG("pcishpc_set_bus_speed() failed: " 202926947304SEvan Yan "the slot is empty\n"); 203026947304SEvan Yan return (DDI_FAILURE); 203126947304SEvan Yan } 203226947304SEvan Yan 203326947304SEvan Yan /* Return failure if the slot is not in disabled state */ 203426947304SEvan Yan if ((status & PCI_HP_SLOT_STATE_MASK) != PCI_HP_SLOT_DISABLED) { 203526947304SEvan Yan PCIE_DBG("pcishpc_set_bus_speed() failed: " 203626947304SEvan Yan "incorrect slot state\n"); 203726947304SEvan Yan return (DDI_FAILURE); 203826947304SEvan Yan } 203926947304SEvan Yan 204026947304SEvan Yan /* Set the "power-only" mode for the slot */ 204126947304SEvan Yan if (pcishpc_issue_command(ctrl_p, ((1+slot_p->hs_num)<<8) | 204226947304SEvan Yan PCI_HP_SLOT_POWER_ONLY) != DDI_SUCCESS) { 204326947304SEvan Yan PCIE_DBG("pcishpc_set_bus_speed() failed to set " 204426947304SEvan Yan "the slot %d in the power-only mode\n", slot_p->hs_num); 204526947304SEvan Yan return (DDI_FAILURE); 204626947304SEvan Yan } 204726947304SEvan Yan 204826947304SEvan Yan /* Wait for power good */ 204926947304SEvan Yan delay(drv_usectohz(PCIE_HP_POWER_GOOD_WAIT_TIME)); 205026947304SEvan Yan 205126947304SEvan Yan /* Make sure that the slot is in "power-only" state */ 205226947304SEvan Yan status = pcishpc_read_reg(ctrl_p, 205326947304SEvan Yan PCI_HP_LOGICAL_SLOT_REGS+slot_p->hs_num); 205426947304SEvan Yan 205526947304SEvan Yan if ((status & PCI_HP_SLOT_STATE_MASK) != PCI_HP_SLOT_POWER_ONLY) { 205626947304SEvan Yan PCIE_DBG("pcishpc_set_bus_speed() " 205726947304SEvan Yan "power-only failed: incorrect slot state\n"); 205826947304SEvan Yan return (DDI_FAILURE); 205926947304SEvan Yan } 206026947304SEvan Yan 206126947304SEvan Yan slots_avail1_reg = pcishpc_read_reg(ctrl_p, 206226947304SEvan Yan PCI_HP_SLOTS_AVAIL_I_REG); 206326947304SEvan Yan slots_avail2_reg = pcishpc_read_reg(ctrl_p, 206426947304SEvan Yan PCI_HP_SLOTS_AVAIL_II_REG); 206526947304SEvan Yan 206626947304SEvan Yan /* 206726947304SEvan Yan * Check if SHPC has available slots and select the highest 206826947304SEvan Yan * available bus speed for the slot. 206926947304SEvan Yan * 207026947304SEvan Yan * The bus speed codes are: 207126947304SEvan Yan * 100 - 133Mhz; <--+ 207226947304SEvan Yan * 011 - 100Mhz; <--+ PCI-X 207326947304SEvan Yan * 010 - 66Mhz; <--+ 207426947304SEvan Yan * 207526947304SEvan Yan * 001 - 66Mhz; <--+ 207626947304SEvan Yan * 000 - 33Mhz <--+ Conv PCI 207726947304SEvan Yan */ 207826947304SEvan Yan switch (status & PCI_HP_SLOT_PCIX_CAPABLE_MASK) { 207926947304SEvan Yan case PCI_HP_SLOT_133MHZ_PCIX_CAPABLE: 208026947304SEvan Yan avail_slots = (slots_avail1_reg >> 208126947304SEvan Yan PCI_HP_AVAIL_133MHZ_PCIX_SPEED_SHIFT) & 208226947304SEvan Yan PCI_HP_AVAIL_SPEED_MASK; 208326947304SEvan Yan 208426947304SEvan Yan if (((curr_speed == -1) && avail_slots) || 208526947304SEvan Yan (curr_speed == PCI_HP_SBCR_133MHZ_PCIX_SPEED)) { 208626947304SEvan Yan speed = PCI_HP_SBCR_133MHZ_PCIX_SPEED; 208726947304SEvan Yan break; 208826947304SEvan Yan } 208926947304SEvan Yan /* FALLTHROUGH */ 209026947304SEvan Yan case PCI_HP_SLOT_100MHZ_PCIX_CAPABLE: 209126947304SEvan Yan avail_slots = (slots_avail1_reg >> 209226947304SEvan Yan PCI_HP_AVAIL_100MHZ_PCIX_SPEED_SHIFT) & 209326947304SEvan Yan PCI_HP_AVAIL_SPEED_MASK; 209426947304SEvan Yan 209526947304SEvan Yan if (((curr_speed == -1) && avail_slots) || 209626947304SEvan Yan (curr_speed == PCI_HP_SBCR_100MHZ_PCIX_SPEED)) { 209726947304SEvan Yan speed = PCI_HP_SBCR_100MHZ_PCIX_SPEED; 209826947304SEvan Yan break; 209926947304SEvan Yan } 210026947304SEvan Yan /* FALLTHROUGH */ 210126947304SEvan Yan case PCI_HP_SLOT_66MHZ_PCIX_CAPABLE: 210226947304SEvan Yan avail_slots = (slots_avail1_reg >> 210326947304SEvan Yan PCI_HP_AVAIL_66MHZ_PCIX_SPEED_SHIFT) & 210426947304SEvan Yan PCI_HP_AVAIL_SPEED_MASK; 210526947304SEvan Yan 210626947304SEvan Yan if (((curr_speed == -1) && avail_slots) || 210726947304SEvan Yan (curr_speed == PCI_HP_SBCR_66MHZ_PCIX_SPEED)) { 210826947304SEvan Yan speed = PCI_HP_SBCR_66MHZ_PCIX_SPEED; 210926947304SEvan Yan break; 211026947304SEvan Yan } 211126947304SEvan Yan /* FALLTHROUGH */ 211226947304SEvan Yan default: 211326947304SEvan Yan avail_slots = (slots_avail2_reg >> 211426947304SEvan Yan PCI_HP_AVAIL_66MHZ_CONV_SPEED_SHIFT) & 211526947304SEvan Yan PCI_HP_AVAIL_SPEED_MASK; 211626947304SEvan Yan 211726947304SEvan Yan if ((status & PCI_HP_SLOT_66MHZ_CONV_CAPABLE) && 211826947304SEvan Yan (((curr_speed == -1) && avail_slots) || 211926947304SEvan Yan (curr_speed == PCI_HP_SBCR_66MHZ_CONV_SPEED))) { 212026947304SEvan Yan speed = PCI_HP_SBCR_66MHZ_CONV_SPEED; 212126947304SEvan Yan } else { 212226947304SEvan Yan avail_slots = (slots_avail1_reg >> 212326947304SEvan Yan PCI_HP_AVAIL_33MHZ_CONV_SPEED_SHIFT) & 212426947304SEvan Yan PCI_HP_AVAIL_SPEED_MASK; 212526947304SEvan Yan 212626947304SEvan Yan if (((curr_speed == -1) && (avail_slots)) || 212726947304SEvan Yan (curr_speed == PCI_HP_SBCR_33MHZ_CONV_SPEED)) { 212826947304SEvan Yan speed = PCI_HP_SBCR_33MHZ_CONV_SPEED; 212926947304SEvan Yan } else { 213026947304SEvan Yan PCIE_DBG("pcishpc_set_bus_speed() " 213126947304SEvan Yan " failed to set the bus speed, slot# %d\n", 213226947304SEvan Yan slot_p->hs_num); 213326947304SEvan Yan return (DDI_FAILURE); 213426947304SEvan Yan } 213526947304SEvan Yan } 213626947304SEvan Yan break; 213726947304SEvan Yan } 213826947304SEvan Yan 213926947304SEvan Yan /* 214026947304SEvan Yan * If the bus segment is already running, check to see the card 214126947304SEvan Yan * in the slot can support the current bus speed. 214226947304SEvan Yan */ 214326947304SEvan Yan if (curr_speed == speed) { 214426947304SEvan Yan /* 214526947304SEvan Yan * Check to see there is any slot available for the current 214626947304SEvan Yan * bus speed. Otherwise, we need fail the current slot connect 214726947304SEvan Yan * request. 214826947304SEvan Yan */ 214926947304SEvan Yan return ((avail_slots <= ctrl_p->hc_num_slots_connected) ? 215026947304SEvan Yan DDI_FAILURE : DDI_SUCCESS); 215126947304SEvan Yan } 215226947304SEvan Yan 215326947304SEvan Yan /* Set the bus speed */ 215426947304SEvan Yan if (pcishpc_issue_command(ctrl_p, PCI_HP_COMM_STS_SET_SPEED | 215526947304SEvan Yan speed) == DDI_FAILURE) { 215626947304SEvan Yan PCIE_DBG("pcishpc_set_bus_speed() failed " 215726947304SEvan Yan "to set bus %d speed\n", slot_p->hs_num); 215826947304SEvan Yan return (DDI_FAILURE); 215926947304SEvan Yan } 216026947304SEvan Yan 216126947304SEvan Yan /* Check the current bus speed */ 216226947304SEvan Yan status = pcishpc_read_reg(ctrl_p, PCI_HP_PROF_IF_SBCR_REG) & 216326947304SEvan Yan PCI_HP_SBCR_SPEED_MASK; 216426947304SEvan Yan if ((status & PCI_HP_SBCR_SPEED_MASK) != speed) { 216526947304SEvan Yan PCIE_DBG("pcishpc_set_bus_speed() an incorrect " 216626947304SEvan Yan "bus speed, slot = 0x%x, speed = 0x%x\n", 216726947304SEvan Yan slot_p->hs_num, status & PCI_HP_SBCR_SPEED_MASK); 216826947304SEvan Yan return (DDI_FAILURE); 216926947304SEvan Yan } 217026947304SEvan Yan 217126947304SEvan Yan 217226947304SEvan Yan /* Save the current bus speed */ 217326947304SEvan Yan ctrl_p->hc_curr_bus_speed = speed; 217426947304SEvan Yan 217526947304SEvan Yan return (DDI_SUCCESS); 217626947304SEvan Yan } 217726947304SEvan Yan 217826947304SEvan Yan /* 217926947304SEvan Yan * pcishpc_setled() 218026947304SEvan Yan * 218126947304SEvan Yan * Change the state of a slot's LED. 218226947304SEvan Yan */ 218326947304SEvan Yan static int 218426947304SEvan Yan pcishpc_setled(pcie_hp_slot_t *slot_p, pcie_hp_led_t led, 218526947304SEvan Yan pcie_hp_led_state_t state) 218626947304SEvan Yan { 218726947304SEvan Yan ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex)); 218826947304SEvan Yan 218926947304SEvan Yan switch (led) { 219026947304SEvan Yan case PCIE_HP_FAULT_LED: 219126947304SEvan Yan PCIE_DBG("pcishpc_setled() - PCIE_HP_FAULT_LED " 219226947304SEvan Yan "(set %s)\n", pcishpc_slot_textledstate(state)); 219326947304SEvan Yan slot_p->hs_fault_led_state = state; 219426947304SEvan Yan break; 219526947304SEvan Yan 219626947304SEvan Yan case PCIE_HP_POWER_LED: 219726947304SEvan Yan PCIE_DBG("pcishpc_setled() - PCIE_HP_POWER_LED " 219826947304SEvan Yan "(set %s)\n", pcishpc_slot_textledstate(state)); 219926947304SEvan Yan slot_p->hs_power_led_state = state; 220026947304SEvan Yan break; 220126947304SEvan Yan 220226947304SEvan Yan case PCIE_HP_ATTN_LED: 220326947304SEvan Yan PCIE_DBG("pcishpc_setled() - PCIE_HP_ATTN_LED " 220426947304SEvan Yan "(set %s)\n", pcishpc_slot_textledstate(state)); 220526947304SEvan Yan slot_p->hs_attn_led_state = state; 220626947304SEvan Yan break; 220726947304SEvan Yan 220826947304SEvan Yan case PCIE_HP_ACTIVE_LED: 220926947304SEvan Yan PCIE_DBG("pcishpc_setled() - PCIE_HP_ACTIVE_LED " 221026947304SEvan Yan "(set %s)\n", pcishpc_slot_textledstate(state)); 221126947304SEvan Yan slot_p->hs_active_led_state = state; 221226947304SEvan Yan break; 221326947304SEvan Yan } 221426947304SEvan Yan 221526947304SEvan Yan return (pcishpc_set_slot_state(slot_p, slot_p->hs_info.cn_state)); 221626947304SEvan Yan } 221726947304SEvan Yan 221826947304SEvan Yan /* 221926947304SEvan Yan * pcishpc_led_shpc_to_hpc() 222026947304SEvan Yan * 222126947304SEvan Yan * Convert from SHPC indicator status to HPC indicator status. 222226947304SEvan Yan */ 222326947304SEvan Yan static int 222426947304SEvan Yan pcishpc_led_shpc_to_hpc(int state) 222526947304SEvan Yan { 222626947304SEvan Yan switch (state) { 222726947304SEvan Yan case 1: /* SHPC On bits b01 */ 222826947304SEvan Yan return (PCIE_HP_LED_ON); 222926947304SEvan Yan case 2: /* SHPC Blink bits b10 */ 223026947304SEvan Yan return (PCIE_HP_LED_BLINK); 223126947304SEvan Yan case 3: /* SHPC Off bits b11 */ 223226947304SEvan Yan return (PCIE_HP_LED_OFF); 223326947304SEvan Yan } 223426947304SEvan Yan 223526947304SEvan Yan return (PCIE_HP_LED_OFF); 223626947304SEvan Yan } 223726947304SEvan Yan 223826947304SEvan Yan 223926947304SEvan Yan /* 224026947304SEvan Yan * pcishpc_led_hpc_to_shpc() 224126947304SEvan Yan * 224226947304SEvan Yan * Convert from HPC indicator status to SHPC indicator status. 224326947304SEvan Yan */ 224426947304SEvan Yan static int 224526947304SEvan Yan pcishpc_led_hpc_to_shpc(int state) 224626947304SEvan Yan { 224726947304SEvan Yan switch (state) { 224826947304SEvan Yan case PCIE_HP_LED_ON: 224926947304SEvan Yan return (1); /* SHPC On bits b01 */ 225026947304SEvan Yan case PCIE_HP_LED_BLINK: 225126947304SEvan Yan return (2); /* SHPC Blink bits b10 */ 225226947304SEvan Yan case PCIE_HP_LED_OFF: 225326947304SEvan Yan return (3); /* SHPC Off bits b11 */ 225426947304SEvan Yan } 225526947304SEvan Yan 225626947304SEvan Yan return (3); /* SHPC Off bits b11 */ 225726947304SEvan Yan } 225826947304SEvan Yan 225926947304SEvan Yan /* 226026947304SEvan Yan * pcishpc_slot_shpc_to_hpc() 226126947304SEvan Yan * 226226947304SEvan Yan * Convert from SHPC slot state to HPC slot state. 226326947304SEvan Yan * The argument shpc_state is expected to be read from the slot register. 226426947304SEvan Yan */ 226526947304SEvan Yan static int 226626947304SEvan Yan pcishpc_slot_shpc_to_hpc(int shpc_state) 226726947304SEvan Yan { 226826947304SEvan Yan if ((shpc_state & PCI_HP_SLOT_CARD_EMPTY_MASK) == 226926947304SEvan Yan PCI_HP_SLOT_CARD_EMPTY_MASK) 227026947304SEvan Yan return (DDI_HP_CN_STATE_EMPTY); 227126947304SEvan Yan 227226947304SEvan Yan switch (shpc_state & PCI_HP_SLOT_STATE_MASK) { 227326947304SEvan Yan case PCI_HP_SLOT_POWER_ONLY: /* SHPC Powered Only */ 227426947304SEvan Yan return (DDI_HP_CN_STATE_POWERED); 227526947304SEvan Yan 227626947304SEvan Yan case PCI_HP_SLOT_ENABLED: /* SHPC Enabled */ 227726947304SEvan Yan return (DDI_HP_CN_STATE_ENABLED); 227826947304SEvan Yan 227926947304SEvan Yan case PCI_HP_SLOT_DISABLED: /* SHPC Disabled */ 228026947304SEvan Yan default : /* SHPC Reserved */ 228126947304SEvan Yan return (DDI_HP_CN_STATE_PRESENT); 228226947304SEvan Yan } 228326947304SEvan Yan } 228426947304SEvan Yan 228526947304SEvan Yan /* 228626947304SEvan Yan * pcishpc_slot_hpc_to_shpc() 228726947304SEvan Yan * 228826947304SEvan Yan * Convert from HPC slot state to SHPC slot state. 228926947304SEvan Yan */ 229026947304SEvan Yan static int 229126947304SEvan Yan pcishpc_slot_hpc_to_shpc(int state) 229226947304SEvan Yan { 229326947304SEvan Yan switch (state) { 229426947304SEvan Yan case DDI_HP_CN_STATE_EMPTY: 229526947304SEvan Yan return (0); 229626947304SEvan Yan 229726947304SEvan Yan case DDI_HP_CN_STATE_POWERED: 229826947304SEvan Yan return (PCI_HP_SLOT_POWER_ONLY); 229926947304SEvan Yan 230026947304SEvan Yan case DDI_HP_CN_STATE_ENABLED: 230126947304SEvan Yan return (PCI_HP_SLOT_ENABLED); 230226947304SEvan Yan 230326947304SEvan Yan default: 230426947304SEvan Yan return (PCI_HP_SLOT_DISABLED); 230526947304SEvan Yan } 230626947304SEvan Yan } 230726947304SEvan Yan 230826947304SEvan Yan /* 230926947304SEvan Yan * pcishpc_slot_textslotstate() 231026947304SEvan Yan * 231126947304SEvan Yan * Convert the request into a text message. 231226947304SEvan Yan */ 231326947304SEvan Yan static char * 231426947304SEvan Yan pcishpc_slot_textslotstate(ddi_hp_cn_state_t state) 231526947304SEvan Yan { 231626947304SEvan Yan /* Convert an HPC slot state into a textual string. */ 231726947304SEvan Yan if (state == DDI_HP_CN_STATE_EMPTY) 231826947304SEvan Yan return ("HPC_SLOT_EMPTY"); 231926947304SEvan Yan else if (state == DDI_HP_CN_STATE_ENABLED) 232026947304SEvan Yan return ("HPC_SLOT_ENABLED"); 232126947304SEvan Yan else if (state == DDI_HP_CN_STATE_POWERED) 232226947304SEvan Yan return ("HPC_SLOT_POWERED_ONLY"); 232326947304SEvan Yan else 232426947304SEvan Yan return ("HPC_SLOT_DISABLED"); 232526947304SEvan Yan } 232626947304SEvan Yan 232726947304SEvan Yan 232826947304SEvan Yan /* 232926947304SEvan Yan * pcishpc_slot_textledstate() 233026947304SEvan Yan * 233126947304SEvan Yan * Convert the led state into a text message. 233226947304SEvan Yan */ 233326947304SEvan Yan static char * 233426947304SEvan Yan pcishpc_slot_textledstate(pcie_hp_led_state_t state) 233526947304SEvan Yan { 233626947304SEvan Yan /* Convert an HPC led state into a textual string. */ 233726947304SEvan Yan switch (state) { 233826947304SEvan Yan case PCIE_HP_LED_OFF: 233926947304SEvan Yan return ("off"); 234026947304SEvan Yan 234126947304SEvan Yan case PCIE_HP_LED_ON: 234226947304SEvan Yan return ("on"); 234326947304SEvan Yan 234426947304SEvan Yan case PCIE_HP_LED_BLINK: 234526947304SEvan Yan return ("blink"); 234626947304SEvan Yan } 234726947304SEvan Yan return ("unknown"); 234826947304SEvan Yan } 234926947304SEvan Yan 235026947304SEvan Yan 235126947304SEvan Yan /* 235226947304SEvan Yan * pcishpc_read_reg() 235326947304SEvan Yan * 235426947304SEvan Yan * Read from a SHPC controller register. 235526947304SEvan Yan */ 235626947304SEvan Yan static uint32_t 235726947304SEvan Yan pcishpc_read_reg(pcie_hp_ctrl_t *ctrl_p, int reg) 235826947304SEvan Yan { 235926947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 236026947304SEvan Yan 236126947304SEvan Yan /* Setup the SHPC dword select register. */ 236226947304SEvan Yan pci_config_put8(bus_p->bus_cfg_hdl, 236326947304SEvan Yan bus_p->bus_pci_hp_off + PCI_HP_DWORD_SELECT_OFF, (uint8_t)reg); 236426947304SEvan Yan 236526947304SEvan Yan /* Read back the SHPC dword select register and verify. */ 236626947304SEvan Yan if (pci_config_get8(bus_p->bus_cfg_hdl, bus_p->bus_pci_hp_off + 236726947304SEvan Yan PCI_HP_DWORD_SELECT_OFF) != (uint8_t)reg) { 236826947304SEvan Yan PCIE_DBG("pcishpc_read_reg() - Failed writing DWORD " 236926947304SEvan Yan "select reg\n"); 237026947304SEvan Yan return (0xFFFFFFFF); 237126947304SEvan Yan } 237226947304SEvan Yan 237326947304SEvan Yan /* Read from the SHPC dword data register. */ 237426947304SEvan Yan return (pci_config_get32(bus_p->bus_cfg_hdl, 237526947304SEvan Yan bus_p->bus_pci_hp_off + PCI_HP_DWORD_DATA_OFF)); 237626947304SEvan Yan } 237726947304SEvan Yan 237826947304SEvan Yan 237926947304SEvan Yan /* 238026947304SEvan Yan * pcishpc_write_reg() 238126947304SEvan Yan * 238226947304SEvan Yan * Write to a SHPC controller register. 238326947304SEvan Yan */ 238426947304SEvan Yan static void 238526947304SEvan Yan pcishpc_write_reg(pcie_hp_ctrl_t *ctrl_p, int reg, uint32_t data) 238626947304SEvan Yan { 238726947304SEvan Yan pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip); 238826947304SEvan Yan 238926947304SEvan Yan /* Setup the SHPC dword select register. */ 239026947304SEvan Yan pci_config_put8(bus_p->bus_cfg_hdl, 239126947304SEvan Yan bus_p->bus_pci_hp_off + PCI_HP_DWORD_SELECT_OFF, (uint8_t)reg); 239226947304SEvan Yan 239326947304SEvan Yan /* Read back the SHPC dword select register and verify. */ 239426947304SEvan Yan if (pci_config_get8(bus_p->bus_cfg_hdl, bus_p->bus_pci_hp_off + 239526947304SEvan Yan PCI_HP_DWORD_SELECT_OFF) != (uint8_t)reg) { 239626947304SEvan Yan PCIE_DBG("pcishpc_write_reg() - Failed writing " 239726947304SEvan Yan "DWORD select reg\n"); 239826947304SEvan Yan return; 239926947304SEvan Yan } 240026947304SEvan Yan 240126947304SEvan Yan /* Write to the SHPC dword data register. */ 240226947304SEvan Yan pci_config_put32(bus_p->bus_cfg_hdl, 240326947304SEvan Yan bus_p->bus_pci_hp_off + PCI_HP_DWORD_DATA_OFF, data); 240426947304SEvan Yan 240526947304SEvan Yan /* 240626947304SEvan Yan * Issue a read of the VendorID/DeviceID just to force the previous 240726947304SEvan Yan * write to complete. This is probably not necessary, but it does 240826947304SEvan Yan * help enforce ordering if there is an issue. 240926947304SEvan Yan */ 241026947304SEvan Yan (void) pci_config_get16(bus_p->bus_cfg_hdl, PCI_CONF_VENID); 241126947304SEvan Yan } 241226947304SEvan Yan 241326947304SEvan Yan 241426947304SEvan Yan #ifdef DEBUG 241526947304SEvan Yan /* 241626947304SEvan Yan * pcishpc_dump_regs() 241726947304SEvan Yan * 241826947304SEvan Yan * Dumps all of the SHPC controller registers. 241926947304SEvan Yan */ 242026947304SEvan Yan static void 242126947304SEvan Yan pcishpc_dump_regs(pcie_hp_ctrl_t *ctrl_p) 242226947304SEvan Yan { 242326947304SEvan Yan int slot, numSlots; 242426947304SEvan Yan uint32_t reg; 242526947304SEvan Yan char *state; 242626947304SEvan Yan 242726947304SEvan Yan if (!pcie_debug_flags) 242826947304SEvan Yan return; 242926947304SEvan Yan 243026947304SEvan Yan PCIE_DBG("pcishpc_dump_regs() called:\n"); 243126947304SEvan Yan PCIE_DBG("=========================================================="); 243226947304SEvan Yan 243326947304SEvan Yan PCIE_DBG("SHPC Base Offset " 243426947304SEvan Yan ": 0x%08x\n", pcishpc_read_reg(ctrl_p, PCI_HP_BASE_OFFSET_REG)); 243526947304SEvan Yan 243626947304SEvan Yan reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOTS_AVAIL_I_REG); 243726947304SEvan Yan 243826947304SEvan Yan PCIE_DBG("Number of PCIX slots avail (33 Mhz) : %d\n", 243926947304SEvan Yan (reg & 31)); 244026947304SEvan Yan 244126947304SEvan Yan PCIE_DBG("Number of PCIX slots avail (66 Mhz) : %d\n", 244226947304SEvan Yan ((reg>>8) & 31)); 244326947304SEvan Yan 244426947304SEvan Yan PCIE_DBG("Number of PCIX slots avail (100 Mhz) : %d\n", 244526947304SEvan Yan ((reg>>16) & 31)); 244626947304SEvan Yan 244726947304SEvan Yan PCIE_DBG("Number of PCIX slots avail (133 Mhz) : %d\n", 244826947304SEvan Yan ((reg>>24) & 31)); 244926947304SEvan Yan 245026947304SEvan Yan reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOTS_AVAIL_II_REG); 245126947304SEvan Yan 245226947304SEvan Yan PCIE_DBG("Number of conventional PCI slots (66 Mhz) : %d\n", 245326947304SEvan Yan (reg & 31)); 245426947304SEvan Yan 245526947304SEvan Yan reg = pcishpc_read_reg(ctrl_p, PCI_HP_SLOT_CONFIGURATION_REG); 245626947304SEvan Yan 245726947304SEvan Yan numSlots = (reg & 31); 245826947304SEvan Yan 245926947304SEvan Yan PCIE_DBG("Number of Slots connected to this port : %d\n", 246026947304SEvan Yan numSlots); 246126947304SEvan Yan 246226947304SEvan Yan PCIE_DBG("PCI Device # for First HotPlug Slot : %d\n", 246326947304SEvan Yan ((reg>>8) & 31)); 246426947304SEvan Yan 246526947304SEvan Yan PCIE_DBG("Physical Slot # for First PCI Device # : %d\n", 246626947304SEvan Yan ((reg>>16) & 0x7ff)); 246726947304SEvan Yan 246826947304SEvan Yan PCIE_DBG("Physical Slot Number Up/Down : %d\n", 246926947304SEvan Yan ((reg>>29) & 0x1)); 247026947304SEvan Yan 247126947304SEvan Yan PCIE_DBG("MRL Sensor Implemented : %s\n", 247226947304SEvan Yan (reg & PCI_HP_SLOT_CONFIG_MRL_SENSOR) ? "Yes" : "No"); 247326947304SEvan Yan 247426947304SEvan Yan PCIE_DBG("Attention Button Implemented : %s\n", 247526947304SEvan Yan (reg & PCI_HP_SLOT_CONFIG_ATTN_BUTTON) ? "Yes" : "No"); 247626947304SEvan Yan 247726947304SEvan Yan reg = pcishpc_read_reg(ctrl_p, PCI_HP_PROF_IF_SBCR_REG); 247826947304SEvan Yan 247926947304SEvan Yan switch (reg & 7) { 248026947304SEvan Yan case 0: 248126947304SEvan Yan state = "33Mhz Conventional PCI"; 248226947304SEvan Yan break; 248326947304SEvan Yan case 1: 248426947304SEvan Yan state = "66Mhz Conventional PCI"; 248526947304SEvan Yan break; 248626947304SEvan Yan case 2: 248726947304SEvan Yan state = "66Mhz PCI-X"; 248826947304SEvan Yan break; 248926947304SEvan Yan case 3: 249026947304SEvan Yan state = "100Mhz PCI-X"; 249126947304SEvan Yan break; 249226947304SEvan Yan case 4: 249326947304SEvan Yan state = "133Mhz PCI-X"; 249426947304SEvan Yan break; 249526947304SEvan Yan default: 249626947304SEvan Yan state = "Reserved (Error)"; 249726947304SEvan Yan break; 249826947304SEvan Yan } 249926947304SEvan Yan 250026947304SEvan Yan PCIE_DBG("Current Port Operation Mode : %s\n", state); 250126947304SEvan Yan 250226947304SEvan Yan PCIE_DBG("SHPC Interrupt Message Number : %d\n", 250326947304SEvan Yan ((reg>>16) &31)); 250426947304SEvan Yan 250526947304SEvan Yan PCIE_DBG("SHPC Programming Interface : %d\n", 250626947304SEvan Yan ((reg>>24) & 0xff)); 250726947304SEvan Yan 250826947304SEvan Yan reg = pcishpc_read_reg(ctrl_p, PCI_HP_COMMAND_STATUS_REG); 250926947304SEvan Yan 251026947304SEvan Yan PCIE_DBG("SHPC Command Code : %d\n", 251126947304SEvan Yan (reg & 0xff)); 251226947304SEvan Yan 251326947304SEvan Yan PCIE_DBG("SHPC Target Slot : %d\n", 251426947304SEvan Yan ((reg>>8) & 31)); 251526947304SEvan Yan 251626947304SEvan Yan PCIE_DBG("SHPC Controller Busy : %s\n", 251726947304SEvan Yan ((reg>>16) & 1) ? "Yes" : "No"); 251826947304SEvan Yan 251926947304SEvan Yan PCIE_DBG("SHPC Controller Err: MRL Sensor : %s\n", 252026947304SEvan Yan ((reg>>17) & 1) ? "Yes" : "No"); 252126947304SEvan Yan 252226947304SEvan Yan PCIE_DBG("SHPC Controller Err: Invalid Command : %s\n", 252326947304SEvan Yan ((reg>>18) & 1) ? "Yes" : "No"); 252426947304SEvan Yan 252526947304SEvan Yan PCIE_DBG("SHPC Controller Err: Invalid Speed/Mode : %s\n", 252626947304SEvan Yan ((reg>>19) & 1) ? "Yes" : "No"); 252726947304SEvan Yan 252826947304SEvan Yan reg = pcishpc_read_reg(ctrl_p, PCI_HP_IRQ_LOCATOR_REG); 252926947304SEvan Yan 253026947304SEvan Yan PCIE_DBG("Command Completion Interrupt Pending : %s\n", 253126947304SEvan Yan (reg & PCI_HP_IRQ_CMD_COMPLETE) ? "Yes" : "No"); 253226947304SEvan Yan 253326947304SEvan Yan for (slot = 0; slot < numSlots; slot++) { 253426947304SEvan Yan PCIE_DBG("Slot %d Interrupt Pending : %s\n", slot+1, 253526947304SEvan Yan (reg & (PCI_HP_IRQ_SLOT_N_PENDING<<slot)) ? "Yes" : "No"); 253626947304SEvan Yan } 253726947304SEvan Yan 253826947304SEvan Yan reg = pcishpc_read_reg(ctrl_p, PCI_HP_SERR_LOCATOR_REG); 253926947304SEvan Yan 254026947304SEvan Yan PCIE_DBG("Arbiter SERR Pending : %s\n", 254126947304SEvan Yan (reg & PCI_HP_IRQ_SERR_ARBITER_PENDING) ? "Yes" : "No"); 254226947304SEvan Yan 254326947304SEvan Yan for (slot = 0; slot < numSlots; slot++) { 254426947304SEvan Yan PCIE_DBG("Slot %d SERR Pending : %s\n", 254526947304SEvan Yan slot+1, (reg & 254626947304SEvan Yan (PCI_HP_IRQ_SERR_SLOT_N_PENDING<<slot)) ? "Yes" : "No"); 254726947304SEvan Yan } 254826947304SEvan Yan 254926947304SEvan Yan reg = pcishpc_read_reg(ctrl_p, PCI_HP_CTRL_SERR_INT_REG); 255026947304SEvan Yan 255126947304SEvan Yan PCIE_DBG("Global Interrupt Mask : %s\n", 255226947304SEvan Yan (reg & PCI_HP_SERR_INT_GLOBAL_IRQ_MASK) ? "Yes" : "No"); 255326947304SEvan Yan 255426947304SEvan Yan PCIE_DBG("Global SERR Mask : %s\n", 255526947304SEvan Yan (reg & PCI_HP_SERR_INT_GLOBAL_SERR_MASK) ? "Yes" : "No"); 255626947304SEvan Yan 255726947304SEvan Yan PCIE_DBG("Command Completion Interrupt Mask : %s\n", 255826947304SEvan Yan (reg & PCI_HP_SERR_INT_CMD_COMPLETE_MASK) ? "Yes" : "No"); 255926947304SEvan Yan 256026947304SEvan Yan PCIE_DBG("Arbiter SERR Mask : %s\n", 256126947304SEvan Yan (reg & PCI_HP_SERR_INT_ARBITER_SERR_MASK) ? "Yes" : "No"); 256226947304SEvan Yan 256326947304SEvan Yan PCIE_DBG("Command Completion Detected : %s\n", 256426947304SEvan Yan (reg & PCI_HP_SERR_INT_CMD_COMPLETE_IRQ) ? "Yes" : "No"); 256526947304SEvan Yan 256626947304SEvan Yan PCIE_DBG("Arbiter Timeout Detected : %s\n", 256726947304SEvan Yan (reg & PCI_HP_SERR_INT_ARBITER_IRQ) ? "Yes" : "No"); 256826947304SEvan Yan 256926947304SEvan Yan for (slot = 0; slot < numSlots; slot++) { 257026947304SEvan Yan PCIE_DBG("Logical Slot %d Registers:\n", slot+1); 257126947304SEvan Yan PCIE_DBG("------------------------------------\n"); 257226947304SEvan Yan 257326947304SEvan Yan reg = pcishpc_read_reg(ctrl_p, PCI_HP_LOGICAL_SLOT_REGS+slot); 257426947304SEvan Yan 257526947304SEvan Yan PCIE_DBG("Slot %d state : %s\n", slot+1, 257626947304SEvan Yan pcishpc_slot_textslotstate(pcishpc_slot_shpc_to_hpc(reg))); 257726947304SEvan Yan 257826947304SEvan Yan PCIE_DBG("Slot %d Power Indicator State : %s\n", slot+1, 257926947304SEvan Yan pcishpc_slot_textledstate(pcishpc_led_shpc_to_hpc( 258026947304SEvan Yan (reg>>2) &3))); 258126947304SEvan Yan 258226947304SEvan Yan PCIE_DBG("Slot %d Attention Indicator State : %s\n", slot+1, 258326947304SEvan Yan pcishpc_slot_textledstate(pcishpc_led_shpc_to_hpc( 258426947304SEvan Yan (reg>>4)&3))); 258526947304SEvan Yan 258626947304SEvan Yan PCIE_DBG("Slot %d Power Fault : %s\n", slot+1, 258726947304SEvan Yan ((reg>>6)&1) ? "Fault Detected" : "No Fault"); 258826947304SEvan Yan PCIE_DBG("Slot %d Attention Button : %s\n", slot+1, 258926947304SEvan Yan ((reg>>7)&1) ? "Depressed" : "Not Depressed"); 259026947304SEvan Yan PCIE_DBG("Slot %d MRL Sensor : %s\n", slot+1, 259126947304SEvan Yan ((reg>>8)&1) ? "Not Closed" : "Closed"); 259226947304SEvan Yan PCIE_DBG("Slot %d 66mhz Capable : %s\n", slot+1, 259326947304SEvan Yan ((reg>>9)&1) ? "66mhz" : "33mgz"); 259426947304SEvan Yan 259526947304SEvan Yan switch ((reg>>10)&3) { 259626947304SEvan Yan case 0: 259726947304SEvan Yan state = "Card Present 7.5W"; 259826947304SEvan Yan break; 259926947304SEvan Yan case 1: 260026947304SEvan Yan state = "Card Present 15W"; 260126947304SEvan Yan break; 260226947304SEvan Yan case 2: 260326947304SEvan Yan state = "Card Present 25W"; 260426947304SEvan Yan break; 260526947304SEvan Yan case 3: 260626947304SEvan Yan state = "Slot Empty"; 260726947304SEvan Yan break; 260826947304SEvan Yan } 260926947304SEvan Yan 261026947304SEvan Yan PCIE_DBG("Slot %d PRSNT1#/PRSNT2# : %s\n", slot+1, 261126947304SEvan Yan state); 261226947304SEvan Yan 261326947304SEvan Yan switch ((reg>>12)&3) { 261426947304SEvan Yan case 0: 261526947304SEvan Yan state = "Non PCI-X"; 261626947304SEvan Yan break; 261726947304SEvan Yan case 1: 261826947304SEvan Yan state = "66mhz PCI-X"; 261926947304SEvan Yan break; 262026947304SEvan Yan case 2: 262126947304SEvan Yan state = "Reserved"; 262226947304SEvan Yan break; 262326947304SEvan Yan case 3: 262426947304SEvan Yan state = "133mhz PCI-X"; 262526947304SEvan Yan break; 262626947304SEvan Yan } 262726947304SEvan Yan 262826947304SEvan Yan PCIE_DBG("Slot %d Card Presence Change Detected : %s\n", 262926947304SEvan Yan slot+1, (reg & PCI_HP_SLOT_PRESENCE_DETECTED) ? "Yes" : 263026947304SEvan Yan "No"); 263126947304SEvan Yan PCIE_DBG("Slot %d Isolated Power Fault Detected : %s\n", 263226947304SEvan Yan slot+1, (reg & PCI_HP_SLOT_ISO_PWR_DETECTED) ? "Yes" : 263326947304SEvan Yan "No"); 263426947304SEvan Yan PCIE_DBG("Slot %d Attention Button Press Detected : %s\n", 263526947304SEvan Yan slot+1, (reg & PCI_HP_SLOT_ATTN_DETECTED) ? "Yes" : "No"); 263626947304SEvan Yan PCIE_DBG("Slot %d MRL Sensor Change Detected : %s\n", 263726947304SEvan Yan slot+1, (reg & PCI_HP_SLOT_MRL_DETECTED) ? "Yes" : "No"); 263826947304SEvan Yan PCIE_DBG("Slot %d Connected Power Fault Detected : %s\n", 263926947304SEvan Yan slot+1, (reg & PCI_HP_SLOT_POWER_DETECTED) ? "Yes" : "No"); 264026947304SEvan Yan 264126947304SEvan Yan PCIE_DBG("Slot %d Card Presence IRQ Masked : %s\n", 264226947304SEvan Yan slot+1, (reg & PCI_HP_SLOT_PRESENCE_MASK) ? "Yes" : "No"); 264326947304SEvan Yan PCIE_DBG("Slot %d Isolated Power Fault IRQ Masked : %s\n", 264426947304SEvan Yan slot+1, (reg & PCI_HP_SLOT_ISO_PWR_MASK) ? "Yes" : "No"); 264526947304SEvan Yan PCIE_DBG("Slot %d Attention Button IRQ Masked : %s\n", 264626947304SEvan Yan slot+1, (reg & PCI_HP_SLOT_ATTN_MASK) ? "Yes" : "No"); 264726947304SEvan Yan PCIE_DBG("Slot %d MRL Sensor IRQ Masked : %s\n", 264826947304SEvan Yan slot+1, (reg & PCI_HP_SLOT_MRL_MASK) ? "Yes" : "No"); 264926947304SEvan Yan PCIE_DBG("Slot %d Connected Power Fault IRQ Masked : %s\n", 265026947304SEvan Yan slot+1, (reg & PCI_HP_SLOT_POWER_MASK) ? "Yes" : "No"); 265126947304SEvan Yan PCIE_DBG("Slot %d MRL Sensor SERR Masked : %s\n", 265226947304SEvan Yan slot+1, (reg & PCI_HP_SLOT_MRL_SERR_MASK) ? "Yes" : "No"); 265326947304SEvan Yan PCIE_DBG("Slot %d Connected Power Fault SERR Masked : %s\n", 265426947304SEvan Yan slot+1, (reg & PCI_HP_SLOT_POWER_SERR_MASK) ? "Yes" : "No"); 265526947304SEvan Yan } 265626947304SEvan Yan } 265726947304SEvan Yan #endif /* DEBUG */ 2658