|
@@ -8344,6 +8344,52 @@ static int read_lcb_via_8051(struct hfi1_devdata *dd, u32 addr, u64 *data)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Provide a cache for some of the LCB registers in case the LCB is
|
|
|
+ * unavailable.
|
|
|
+ * (The LCB is unavailable in certain link states, for example.)
|
|
|
+ */
|
|
|
+struct lcb_datum {
|
|
|
+ u32 off;
|
|
|
+ u64 val;
|
|
|
+};
|
|
|
+
|
|
|
+static struct lcb_datum lcb_cache[] = {
|
|
|
+ { DC_LCB_ERR_INFO_RX_REPLAY_CNT, 0},
|
|
|
+ { DC_LCB_ERR_INFO_SEQ_CRC_CNT, 0 },
|
|
|
+ { DC_LCB_ERR_INFO_REINIT_FROM_PEER_CNT, 0 },
|
|
|
+};
|
|
|
+
|
|
|
+static void update_lcb_cache(struct hfi1_devdata *dd)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ int ret;
|
|
|
+ u64 val;
|
|
|
+
|
|
|
+ for (i = 0; i < ARRAY_SIZE(lcb_cache); i++) {
|
|
|
+ ret = read_lcb_csr(dd, lcb_cache[i].off, &val);
|
|
|
+
|
|
|
+ /* Update if we get good data */
|
|
|
+ if (likely(ret != -EBUSY))
|
|
|
+ lcb_cache[i].val = val;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int read_lcb_cache(u32 off, u64 *val)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < ARRAY_SIZE(lcb_cache); i++) {
|
|
|
+ if (lcb_cache[i].off == off) {
|
|
|
+ *val = lcb_cache[i].val;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pr_warn("%s bad offset 0x%x\n", __func__, off);
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Read an LCB CSR. Access may not be in host control, so check.
|
|
|
* Return 0 on success, -EBUSY on failure.
|
|
@@ -8355,9 +8401,13 @@ int read_lcb_csr(struct hfi1_devdata *dd, u32 addr, u64 *data)
|
|
|
/* if up, go through the 8051 for the value */
|
|
|
if (ppd->host_link_state & HLS_UP)
|
|
|
return read_lcb_via_8051(dd, addr, data);
|
|
|
- /* if going up or down, no access */
|
|
|
- if (ppd->host_link_state & (HLS_GOING_UP | HLS_GOING_OFFLINE))
|
|
|
- return -EBUSY;
|
|
|
+ /* if going up or down, check the cache, otherwise, no access */
|
|
|
+ if (ppd->host_link_state & (HLS_GOING_UP | HLS_GOING_OFFLINE)) {
|
|
|
+ if (read_lcb_cache(addr, data))
|
|
|
+ return -EBUSY;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
/* otherwise, host has access */
|
|
|
*data = read_csr(dd, addr);
|
|
|
return 0;
|
|
@@ -10145,6 +10195,8 @@ static int goto_offline(struct hfi1_pportdata *ppd, u8 rem_reason)
|
|
|
int do_transition;
|
|
|
int do_wait;
|
|
|
|
|
|
+ update_lcb_cache(dd);
|
|
|
+
|
|
|
previous_state = ppd->host_link_state;
|
|
|
ppd->host_link_state = HLS_GOING_OFFLINE;
|
|
|
pstate = read_physical_state(dd);
|