summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/sun4/io/px/pcie_pwr.c16
-rw-r--r--usr/src/uts/sun4/io/px/px_intr.c8
-rw-r--r--usr/src/uts/sun4/io/px/px_pci.c41
-rw-r--r--usr/src/uts/sun4/io/px/px_space.h3
-rw-r--r--usr/src/uts/sun4/io/px/px_var.h12
-rw-r--r--usr/src/uts/sun4u/io/px/px_err.c42
-rw-r--r--usr/src/uts/sun4u/io/px/px_err_impl.h2
-rw-r--r--usr/src/uts/sun4u/io/px/px_lib4u.c71
-rw-r--r--usr/src/uts/sun4v/io/px/px_lib4v.c6
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;
}
/*