diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/uts/sun4/io/px/pcie_pwr.c | 16 | ||||
-rw-r--r-- | usr/src/uts/sun4/io/px/px_intr.c | 8 | ||||
-rw-r--r-- | usr/src/uts/sun4/io/px/px_pci.c | 41 | ||||
-rw-r--r-- | usr/src/uts/sun4/io/px/px_space.h | 3 | ||||
-rw-r--r-- | usr/src/uts/sun4/io/px/px_var.h | 12 | ||||
-rw-r--r-- | usr/src/uts/sun4u/io/px/px_err.c | 42 | ||||
-rw-r--r-- | usr/src/uts/sun4u/io/px/px_err_impl.h | 2 | ||||
-rw-r--r-- | usr/src/uts/sun4u/io/px/px_lib4u.c | 71 | ||||
-rw-r--r-- | usr/src/uts/sun4v/io/px/px_lib4v.c | 6 |
9 files changed, 138 insertions, 63 deletions
diff --git a/usr/src/uts/sun4/io/px/pcie_pwr.c b/usr/src/uts/sun4/io/px/pcie_pwr.c index a55c73c21b..855d9aa0c4 100644 --- a/usr/src/uts/sun4/io/px/pcie_pwr.c +++ b/usr/src/uts/sun4/io/px/pcie_pwr.c @@ -449,27 +449,11 @@ pcie_add_comps(dev_info_t *dip, dev_info_t *cdip, pcie_pwr_t *pwr_p) int comps = PM_NUMCMPTS(cdip); pcie_pm_t *pcie_pm_p; pcie_pwr_child_t *cpwr_p; - int i, total = 0; ASSERT(MUTEX_HELD(&pwr_p->pwr_lock)); if (!comps) return; - /* - * Remove the hold done at the time of our attach. - * This is done when we add the first child. If the - * sum of our counters is zero, that means we are - * adding the first child. - */ - for (i = 0; i < PCIE_MAX_PWR_LEVELS; i++) { - total += (pwr_p->pwr_counters)[i]; - } - if (total == 0 && pwr_p->pwr_hold > 0) { - DBG(DBG_PWR, dip, "pm_add_comps: decrementing hold \n"); - pwr_p->pwr_hold--; - ASSERT(pwr_p->pwr_flags & PCIE_PM_BUSY); - } - DBG(DBG_PWR, dip, "pcie_add_comps: unknown level counter incremented " "from %d by %d because of %s@%d\n", (pwr_p->pwr_counters)[PCIE_UNKNOWN_INDEX], comps, diff --git a/usr/src/uts/sun4/io/px/px_intr.c b/usr/src/uts/sun4/io/px/px_intr.c index 3d68b18c90..de5082362e 100644 --- a/usr/src/uts/sun4/io/px/px_intr.c +++ b/usr/src/uts/sun4/io/px/px_intr.c @@ -252,10 +252,10 @@ px_msiq_intr(caddr_t arg) px_lib_get_msiq_rec(dip, msiq_p, msiq_rec_p); /* - * Process current MSIQ record as long as request id + * Process current MSIQ record as long as record type * field is non-zero. */ - while (msiq_rec_p->msiq_rec_rid) { + while (msiq_rec_p->msiq_rec_type) { DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: MSIQ RECORD, " "msiq_rec_type 0x%llx msiq_rec_rid 0x%llx\n", msiq_rec_p->msiq_rec_type, msiq_rec_p->msiq_rec_rid); @@ -355,8 +355,8 @@ px_msiq_intr(caddr_t arg) next_rec: new_msiq_rec_cnt++; - /* Zero out msiq_rec_rid field */ - msiq_rec_p->msiq_rec_rid = 0; + /* Zero out msiq_rec_type field */ + msiq_rec_p->msiq_rec_type = 0; /* Read next MSIQ record */ px_lib_get_msiq_rec(dip, msiq_p, msiq_rec_p); diff --git a/usr/src/uts/sun4/io/px/px_pci.c b/usr/src/uts/sun4/io/px/px_pci.c index b6dc3d8169..c319d95cbc 100644 --- a/usr/src/uts/sun4/io/px/px_pci.c +++ b/usr/src/uts/sun4/io/px/px_pci.c @@ -304,6 +304,10 @@ pxb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) pxb->pxb_config_handle = config_handle; pxb->pxb_init_flags |= PXB_INIT_CONFIG_HANDLE; + /* Save the vnedor id and device id */ + pxb->pxb_vendor_id = pci_config_get16(config_handle, PCI_CONF_VENID); + pxb->pxb_device_id = pci_config_get16(config_handle, PCI_CONF_DEVID); + /* * Power management setup. This also makes sure that switch/bridge * is at D0 during attach. @@ -331,9 +335,6 @@ pxb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) goto fail; } - /* Save the vnedor id and device id */ - pxb->pxb_vendor_id = pci_config_get16(config_handle, PCI_CONF_VENID); - pxb->pxb_device_id = pci_config_get16(config_handle, PCI_CONF_DEVID); /* * Make sure the "device_type" property exists. @@ -825,7 +826,7 @@ pxb_initchild(dev_info_t *child) if ((!pxb_tlp_count) || (pxb->pxb_vendor_id != PXB_VENDOR_PLX) || ((pxb->pxb_device_id != PXB_DEVICE_PLX_8532) && - (pxb->pxb_device_id != PXB_DEVICE_PLX_8532))) { + (pxb->pxb_device_id != PXB_DEVICE_PLX_8516))) { /* Workaround not needed return success */ result = DDI_SUCCESS; goto cleanup; @@ -1364,16 +1365,33 @@ static int pxb_pwr_setup(dev_info_t *dip) { char *comp_array[5]; - int i; + int i, instance; ddi_acc_handle_t conf_hdl; uint8_t cap_ptr, cap_id; uint16_t pmcap; pcie_pwr_t *pwr_p; + pxb_devstate_t *pxb; ASSERT(PCIE_PMINFO(dip)); pwr_p = PCIE_NEXUS_PMINFO(dip); ASSERT(pwr_p); + instance = ddi_get_instance(dip); + pxb = (pxb_devstate_t *)ddi_get_soft_state(pxb_state, instance); + /* + * Disable PM for PLX 8532 switch. Transitioning one port on + * this switch to low power causes links on other ports on the + * same station to die. + */ + if ((pxb->pxb_vendor_id == PXB_VENDOR_PLX) && + ((pxb->pxb_device_id == PXB_DEVICE_PLX_8516) || + (pxb->pxb_device_id == PXB_DEVICE_PLX_8532))) { + DBG(DBG_PWR, dip, "pxb_pwr_setup: PLX8532/PLX8516 found " + "disabling PM\n"); + pwr_p->pwr_func_lvl = PM_LEVEL_D0; + return (DDI_SUCCESS); + } + /* Code taken from pci_pci driver */ if (pci_config_setup(dip, &pwr_p->pwr_conf_hdl) != DDI_SUCCESS) { DBG(DBG_PWR, dip, "pxb_pwr_setup: pci_config_setup failed\n"); @@ -1424,7 +1442,7 @@ pxb_pwr_setup(dev_info_t *dip) comp_array[i++] = "3=Full Power D0"; /* - * Create pm-components property. If it does not already exist. + * Create pm-components property, if it does not exist already. */ if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip, "pm-components", comp_array, i) != DDI_PROP_SUCCESS) { @@ -1472,17 +1490,6 @@ pxb_pwr_init_and_raise(dev_info_t *dip, pcie_pwr_t *pwr_p) default: break; } - /* - * Workaround to be revisted. - * Transitioning the un-connected ports on a switch to low - * power causes links on other ports to die. As a result a panic - * might happen. To avoid any panics, increment pwr_hold and mark - * ourselves busy so that PM framework will not call our power entry. - */ - DBG(DBG_PWR, dip, "pxb_attach: incrementing hold and marking busy\n"); - pwr_p->pwr_hold++; - pwr_p->pwr_flags |= PCIE_PM_BUSY; - (void) pm_busy_component(dip, 0); /* Raise the power to D0. */ if (pwr_p->pwr_func_lvl != PM_LEVEL_D0 && diff --git a/usr/src/uts/sun4/io/px/px_space.h b/usr/src/uts/sun4/io/px/px_space.h index d1a8ad03a6..a51f574220 100644 --- a/usr/src/uts/sun4/io/px/px_space.h +++ b/usr/src/uts/sun4/io/px/px_space.h @@ -150,9 +150,10 @@ extern uint64_t px_lpug_intr_mask; extern uint64_t px_lpug_log_mask; extern uint64_t px_lpug_count_mask; -/* timeout length in nano second */ +/* timeout length in micro seconds */ #define PX_PME_TO_ACK_TIMEOUT 1000000 #define PX_LINKUP_TIMEOUT 100000 + #define PX_PWR_PIL 1 #define PX_MAX_L1_TRIES 5 diff --git a/usr/src/uts/sun4/io/px/px_var.h b/usr/src/uts/sun4/io/px/px_var.h index a5ae5a71e6..efde9b22ef 100644 --- a/usr/src/uts/sun4/io/px/px_var.h +++ b/usr/src/uts/sun4/io/px/px_var.h @@ -157,11 +157,13 @@ struct px { #define PX_SOFT_STATE_CLOSED 0x04 #define PX_BYPASS_DMA_ALLOWED 0x10 -/* px_pm_flags definitions */ -#define PX_PMETOACK_RECVD 0x1 -#define PX_PME_TURNOFF_PENDING 0x2 -#define PX_LINKUP_RECVD 0x4 -#define PX_LINKUP_PENDING 0x8 +/* px_pm_flags definitions used with interrupts and FMA code */ +#define PX_PMETOACK_RECVD 0x01 /* With PME_To_ACK interrupt */ +#define PX_PME_TURNOFF_PENDING 0x02 /* With PME_To_ACK interrupt */ +#define PX_LINKUP_RECVD 0x04 /* With link up soft interrupt */ +#define PX_LINKUP_PENDING 0x08 /* With link up soft interrupt */ +#define PX_LUP_EXPECTED 0x10 /* With FMA code */ +#define PX_LDN_EXPECTED 0x20 /* With FMA code */ #define DIP_TO_INST(dip) ddi_get_instance(dip) #define INST_TO_STATE(inst) ddi_get_soft_state(px_state_p, inst) diff --git a/usr/src/uts/sun4u/io/px/px_err.c b/usr/src/uts/sun4u/io/px/px_err.c index 63b1de184e..2a24aa4fb0 100644 --- a/usr/src/uts/sun4u/io/px/px_err.c +++ b/usr/src/uts/sun4u/io/px/px_err.c @@ -254,8 +254,8 @@ px_err_bit_desc_t px_err_tlu_oe_tbl[] = { { TLU_OE_BIT_DESC(EHP, fatal_gos, pciex_oe) }, { TLU_OE_BIT_DESC(LIN, non_fatal, pciex_oe) }, { TLU_OE_BIT_DESC(LRS, non_fatal, pciex_oe) }, - { TLU_OE_BIT_DESC(LDN, non_fatal, pciex_oe) }, - { TLU_OE_BIT_DESC(LUP, tlu_lup, pciex_oe) }, + { TLU_OE_BIT_DESC(LDN, non_fatal, pciex_ldn) }, + { TLU_OE_BIT_DESC(LUP, tlu_lup, pciex_lup) }, { TLU_OE_BIT_DESC(ERU, fatal_gos, pciex_oe) }, { TLU_OE_BIT_DESC(ERO, fatal_gos, pciex_oe) }, { TLU_OE_BIT_DESC(EMP, fatal_gos, pciex_oe) }, @@ -1670,7 +1670,7 @@ PX_ERPT_SEND_DEC(pciex_rx_tx_oe) /* TLU Other Event - see io erpt doc, section 3.9 */ PX_ERPT_SEND_DEC(pciex_oe) { - char buf[FM_MAX_CLASS]; + char buf[FM_MAX_CLASS]; (void) snprintf(buf, FM_MAX_CLASS, "%s", class_name); ddi_fm_ereport_post(rpdip, buf, derr->fme_ena, @@ -1688,3 +1688,39 @@ PX_ERPT_SEND_DEC(pciex_oe) return (PX_OK); } + +/* TLU Other Event - Link Down see io erpt doc, section 3.9 */ +PX_ERPT_SEND_DEC(pciex_ldn) +{ + px_t *px_p = DIP_TO_STATE(rpdip); + + /* + * Don't post ereport, if ldn event is due to + * power management. + */ + if (px_p->px_pm_flags & PX_LDN_EXPECTED) { + px_p->px_pm_flags &= ~PX_LDN_EXPECTED; + return (PX_OK); + } + return (PX_ERPT_SEND(pciex_oe)(rpdip, csr_base, ss_reg, derr, + class_name)); + +} + +/* TLU Other Event - Link Up see io erpt doc, section 3.9 */ +PX_ERPT_SEND_DEC(pciex_lup) +{ + px_t *px_p = DIP_TO_STATE(rpdip); + + /* + * Don't post ereport, if lup event is due to + * power management. + */ + if (px_p->px_pm_flags & PX_LUP_EXPECTED) { + px_p->px_pm_flags &= ~PX_LUP_EXPECTED; + return (PX_OK); + } + + return (PX_ERPT_SEND(pciex_oe)(rpdip, csr_base, ss_reg, derr, + class_name)); +} diff --git a/usr/src/uts/sun4u/io/px/px_err_impl.h b/usr/src/uts/sun4u/io/px/px_err_impl.h index 60bc2316e3..f1ff1f9635 100644 --- a/usr/src/uts/sun4u/io/px/px_err_impl.h +++ b/usr/src/uts/sun4u/io/px/px_err_impl.h @@ -223,6 +223,8 @@ PX_ERPT_SEND_DEC(pciex_ce); PX_ERPT_SEND_DEC(pciex_rx_oe); PX_ERPT_SEND_DEC(pciex_rx_tx_oe); PX_ERPT_SEND_DEC(pciex_oe); +PX_ERPT_SEND_DEC(pciex_lup); +PX_ERPT_SEND_DEC(pciex_ldn); #ifdef __cplusplus } diff --git a/usr/src/uts/sun4u/io/px/px_lib4u.c b/usr/src/uts/sun4u/io/px/px_lib4u.c index 2c72267627..faa8a22a77 100644 --- a/usr/src/uts/sun4u/io/px/px_lib4u.c +++ b/usr/src/uts/sun4u/io/px/px_lib4u.c @@ -892,9 +892,9 @@ px_lib_get_msiq_rec(dev_info_t *dip, px_msiq_t *msiq_p, msiq_rec_t *msiq_rec_p) DBG(DBG_LIB_MSIQ, dip, "px_lib_get_msiq_rec: dip 0x%p eq_rec_p 0x%p\n", dip, eq_rec_p); - if (!eq_rec_p->eq_rec_rid) { - /* Set msiq_rec_rid to zero */ - msiq_rec_p->msiq_rec_rid = 0; + if (!eq_rec_p->eq_rec_fmt_type) { + /* Set msiq_rec_type to zero */ + msiq_rec_p->msiq_rec_type = 0; return; } @@ -945,8 +945,8 @@ px_lib_get_msiq_rec(dev_info_t *dip, px_msiq_t *msiq_p, msiq_rec_t *msiq_rec_p) msiq_rec_p->msiq_rec_msi_addr = ((eq_rec_p->eq_rec_addr1 << 16) | (eq_rec_p->eq_rec_addr0 << 2)); - /* Zero out eq_rec_rid field */ - eq_rec_p->eq_rec_rid = 0; + /* Zero out eq_rec_fmt_type field */ + eq_rec_p->eq_rec_fmt_type = 0; } /* @@ -1627,6 +1627,8 @@ px_lib_pmctl(int cmd, px_t *px_p) } } +#define MSEC_TO_USEC 1000 + /* * sends PME_Turn_Off message to put the link in L2/L3 ready state. * called by px_ioctl. @@ -1656,6 +1658,17 @@ px_goto_l23ready(px_t *px_p) mutex_enter(&px_p->px_l23ready_lock); /* Clear the PME_To_ACK receieved flag */ px_p->px_pm_flags &= ~PX_PMETOACK_RECVD; + /* + * When P25 is the downstream device, after receiving + * PME_To_ACK, fire will go to Detect state, which causes + * the link down event. Inform FMA that this is expected. + * In case of all other cards complaint with the pci express + * spec, this will happen when the power is re-applied. FMA + * code will clear this flag after one instance of LDN. Since + * there will not be a LDN event for the spec compliant cards, + * we need to clear the flag after receiving PME_To_ACK. + */ + px_p->px_pm_flags |= PX_LDN_EXPECTED; if (px_send_pme_turnoff(csr_base) != DDI_SUCCESS) { ret = DDI_FAILURE; goto l23ready_done; @@ -1688,7 +1701,7 @@ px_goto_l23ready(px_t *px_p) * consequetive requests. */ mutex_exit(&px_p->px_l23ready_lock); - delay(5); + delay(drv_usectohz(50 * MSEC_TO_USEC)); mutex_held = 0; if (!(px_p->px_pm_flags & PX_PMETOACK_RECVD)) { ret = DDI_FAILURE; @@ -1696,7 +1709,8 @@ px_goto_l23ready(px_t *px_p) " for PME_TO_ACK\n"); } } - px_p->px_pm_flags &= ~(PX_PME_TURNOFF_PENDING | PX_PMETOACK_RECVD); + px_p->px_pm_flags &= + ~(PX_PME_TURNOFF_PENDING | PX_PMETOACK_RECVD | PX_LDN_EXPECTED); l23ready_done: if (mutex_held) @@ -1708,10 +1722,20 @@ l23ready_done: if (ret == DDI_SUCCESS) { if (px_link_wait4l1idle(csr_base) != DDI_SUCCESS) { DBG(DBG_PWR, px_p->px_dip, " Link is not at L1" - "even though we received PME_To_ACK.\n"); - ret = DDI_FAILURE; - } else - pwr_p->pwr_link_lvl = PM_LEVEL_L3; + " even though we received PME_To_ACK.\n"); + /* + * Workaround for hardware bug with P25. + * Due to a hardware bug with P25, link state + * will be Detect state rather than L1 after + * link is transitioned to L23Ready state. Since + * we don't know whether link is L23ready state + * without Fire's state being L1_idle, we delay + * here just to make sure that we wait till link + * is transitioned to L23Ready state. + */ + delay(drv_usectohz(100 * MSEC_TO_USEC)); + } + pwr_p->pwr_link_lvl = PM_LEVEL_L3; } mutex_exit(&pwr_p->pwr_lock); @@ -1728,6 +1752,7 @@ px_pmeq_intr(caddr_t arg) { px_t *px_p = (px_t *)arg; + DBG(DBG_PWR, px_p->px_dip, " PME_To_ACK received \n"); mutex_enter(&px_p->px_l23ready_lock); cv_broadcast(&px_p->px_l23ready_cv); if (px_p->px_pm_flags & PX_PME_TURNOFF_PENDING) { @@ -1753,6 +1778,11 @@ px_pre_pwron_check(px_t *px_p) !(pwr_p = PCIE_NEXUS_PMINFO(px_p->px_dip))) return (DDI_FAILURE); + /* + * For the spec compliant downstream cards link down + * is expected when the device is powered on. + */ + px_p->px_pm_flags |= PX_LDN_EXPECTED; return (pwr_p->pwr_link_lvl == PM_LEVEL_L3 ? DDI_SUCCESS : DDI_FAILURE); } @@ -1775,6 +1805,16 @@ px_goto_l0(px_t *px_p) mutex_enter(&px_p->px_lupsoft_lock); /* Clear the LINKUP_RECVD receieved flag */ px_p->px_pm_flags &= ~PX_LINKUP_RECVD; + /* + * Set flags LUP_EXPECTED to inform FMA code that LUP is + * expected as part of link training and no ereports should + * be posted for this event. FMA code will clear this flag + * after one instance of this event. In case of P25, there + * will not be a LDN event. So clear the flag set at PRE_PWRON + * time. + */ + px_p->px_pm_flags |= PX_LUP_EXPECTED; + px_p->px_pm_flags &= ~PX_LDN_EXPECTED; if (px_link_retrain(csr_base) != DDI_SUCCESS) { ret = DDI_FAILURE; goto l0_done; @@ -1808,20 +1848,22 @@ px_goto_l0(px_t *px_p) */ mutex_exit(&px_p->px_lupsoft_lock); mutex_held = 0; - delay(5); + delay(drv_usectohz(50 * MSEC_TO_USEC)); if (!(px_p->px_pm_flags & PX_LINKUP_RECVD)) { ret = DDI_FAILURE; DBG(DBG_PWR, px_p->px_dip, " Timed out while waiting" " for link up\n"); } } - px_p->px_pm_flags &= ~(PX_LINKUP_PENDING | PX_LINKUP_RECVD); + px_p->px_pm_flags &= + ~(PX_LINKUP_PENDING | PX_LINKUP_RECVD | PX_LUP_EXPECTED); l0_done: if (mutex_held) mutex_exit(&px_p->px_lupsoft_lock); + px_enable_detect_quiet(csr_base); if (ret == DDI_SUCCESS) - px_enable_detect_quiet(csr_base); + pwr_p->pwr_link_lvl = PM_LEVEL_L0; mutex_exit(&pwr_p->pwr_lock); return (ret); } @@ -1831,6 +1873,7 @@ px_lup_softintr(caddr_t arg) { px_t *px_p = (px_t *)arg; + DBG(DBG_PWR, px_p->px_dip, " Link up soft interrupt received \n"); mutex_enter(&px_p->px_lup_lock); if (!(px_p->px_lupsoft_pending > 0)) { /* Spurious */ diff --git a/usr/src/uts/sun4v/io/px/px_lib4v.c b/usr/src/uts/sun4v/io/px/px_lib4v.c index 4d44d831cb..5fcce7892c 100644 --- a/usr/src/uts/sun4v/io/px/px_lib4v.c +++ b/usr/src/uts/sun4v/io/px/px_lib4v.c @@ -710,13 +710,13 @@ px_lib_get_msiq_rec(dev_info_t *dip, px_msiq_t *msiq_p, msiq_rec_t *msiq_rec_p) DBG(DBG_LIB_MSIQ, dip, "px_lib_get_msiq_rec: dip 0x%p\n", dip); - if (!curr_msiq_rec_p->msiq_rec_rid) + if (!curr_msiq_rec_p->msiq_rec_type) return; *msiq_rec_p = *curr_msiq_rec_p; - /* Zero out msiq_rec_rid field */ - curr_msiq_rec_p->msiq_rec_rid = 0; + /* Zero out msiq_rec_type field */ + curr_msiq_rec_p->msiq_rec_type = 0; } /* |