summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornp <np@FreeBSD.org>2016-03-08 06:27:47 +0000
committernp <np@FreeBSD.org>2016-03-08 06:27:47 +0000
commit475b5a6654dcd3f42eff929b1a113d1fcf7bb686 (patch)
tree8f0c6422e357290a51e5e79ebd6503b69e12df48
parent2b06c278d4f6d67a8f0b85d62569311bf5a93bc1 (diff)
downloadFreeBSD-src-475b5a6654dcd3f42eff929b1a113d1fcf7bb686.zip
FreeBSD-src-475b5a6654dcd3f42eff929b1a113d1fcf7bb686.tar.gz
cxgbe(4): Updates to mailbox routines in the shared code.
Obtained from: Chelsio Communications
-rw-r--r--sys/dev/cxgbe/common/common.h10
-rw-r--r--sys/dev/cxgbe/common/t4_hw.c130
2 files changed, 112 insertions, 28 deletions
diff --git a/sys/dev/cxgbe/common/common.h b/sys/dev/cxgbe/common/common.h
index ad19fc96..a2ec22f 100644
--- a/sys/dev/cxgbe/common/common.h
+++ b/sys/dev/cxgbe/common/common.h
@@ -448,9 +448,19 @@ static inline unsigned int dack_ticks_to_usec(const struct adapter *adap,
void t4_set_reg_field(struct adapter *adap, unsigned int addr, u32 mask, u32 val);
+int t4_wr_mbox_meat_timeout(struct adapter *adap, int mbox, const void *cmd,
+ int size, void *rpl, bool sleep_ok, int timeout);
int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
void *rpl, bool sleep_ok);
+static inline int t4_wr_mbox_timeout(struct adapter *adap, int mbox,
+ const void *cmd, int size, void *rpl,
+ int timeout)
+{
+ return t4_wr_mbox_meat_timeout(adap, mbox, cmd, size, rpl, true,
+ timeout);
+}
+
static inline int t4_wr_mbox(struct adapter *adap, int mbox, const void *cmd,
int size, void *rpl)
{
diff --git a/sys/dev/cxgbe/common/t4_hw.c b/sys/dev/cxgbe/common/t4_hw.c
index 47e9939..e8293c7 100644
--- a/sys/dev/cxgbe/common/t4_hw.c
+++ b/sys/dev/cxgbe/common/t4_hw.c
@@ -211,7 +211,7 @@ static void t4_report_fw_error(struct adapter *adap)
pcie_fw = t4_read_reg(adap, A_PCIE_FW);
if (pcie_fw & F_PCIE_FW_ERR)
CH_ERR(adap, "Firmware reports adapter error: %s\n",
- reason[G_PCIE_FW_EVAL(pcie_fw)]);
+ reason[G_PCIE_FW_EVAL(pcie_fw)]);
}
/*
@@ -227,25 +227,27 @@ static void get_mbox_rpl(struct adapter *adap, __be64 *rpl, int nflit,
/*
* Handle a FW assertion reported in a mailbox.
*/
-static void fw_asrt(struct adapter *adap, u32 mbox_addr)
+static void fw_asrt(struct adapter *adap, struct fw_debug_cmd *asrt)
{
- struct fw_debug_cmd asrt;
-
- get_mbox_rpl(adap, (__be64 *)&asrt, sizeof(asrt) / 8, mbox_addr);
- CH_ALERT(adap, "FW assertion at %.16s:%u, val0 %#x, val1 %#x\n",
- asrt.u.assert.filename_0_7, ntohl(asrt.u.assert.line),
- ntohl(asrt.u.assert.x), ntohl(asrt.u.assert.y));
+ CH_ALERT(adap,
+ "FW assertion at %.16s:%u, val0 %#x, val1 %#x\n",
+ asrt->u.assert.filename_0_7,
+ be32_to_cpu(asrt->u.assert.line),
+ be32_to_cpu(asrt->u.assert.x),
+ be32_to_cpu(asrt->u.assert.y));
}
#define X_CIM_PF_NOACCESS 0xeeeeeeee
/**
- * t4_wr_mbox_meat - send a command to FW through the given mailbox
+ * t4_wr_mbox_meat_timeout - send a command to FW through the given mailbox
* @adap: the adapter
* @mbox: index of the mailbox to use
* @cmd: the command to write
* @size: command length in bytes
* @rpl: where to optionally store the reply
* @sleep_ok: if true we may sleep while awaiting command completion
+ * @timeout: time to wait for command to finish before timing out
+ * (negative implies @sleep_ok=false)
*
* Sends the given command to FW through the selected mailbox and waits
* for the FW to execute the command. If @rpl is not %NULL it is used to
@@ -254,14 +256,17 @@ static void fw_asrt(struct adapter *adap, u32 mbox_addr)
* INITIALIZE can take a considerable amount of time to execute.
* @sleep_ok determines whether we may sleep while awaiting the response.
* If sleeping is allowed we use progressive backoff otherwise we spin.
+ * Note that passing in a negative @timeout is an alternate mechanism
+ * for specifying @sleep_ok=false. This is useful when a higher level
+ * interface allows for specification of @timeout but not @sleep_ok ...
*
* The return value is 0 on success or a negative errno on failure. A
* failure can happen either because we are not able to execute the
* command or FW executes it but signals an error. In the latter case
* the return value is the error code indicated by FW (negated).
*/
-int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
- void *rpl, bool sleep_ok)
+int t4_wr_mbox_meat_timeout(struct adapter *adap, int mbox, const void *cmd,
+ int size, void *rpl, bool sleep_ok, int timeout)
{
/*
* We delay in small increments at first in an effort to maintain
@@ -271,43 +276,97 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
static const int delay[] = {
1, 1, 3, 5, 10, 10, 20, 50, 100
};
-
u32 v;
u64 res;
- int i, ms, delay_idx;
+ int i, ms, delay_idx, ret;
const __be64 *p = cmd;
u32 data_reg = PF_REG(mbox, A_CIM_PF_MAILBOX_DATA);
u32 ctl_reg = PF_REG(mbox, A_CIM_PF_MAILBOX_CTRL);
+ u32 ctl;
+ __be64 cmd_rpl[MBOX_LEN/8];
+ u32 pcie_fw;
if ((size & 15) || size > MBOX_LEN)
return -EINVAL;
- v = G_MBOWNER(t4_read_reg(adap, ctl_reg));
- for (i = 0; v == X_MBOWNER_NONE && i < 3; i++)
- v = G_MBOWNER(t4_read_reg(adap, ctl_reg));
+ /*
+ * If we have a negative timeout, that implies that we can't sleep.
+ */
+ if (timeout < 0) {
+ sleep_ok = false;
+ timeout = -timeout;
+ }
+
+ /*
+ * Attempt to gain access to the mailbox.
+ */
+ for (i = 0; i < 4; i++) {
+ ctl = t4_read_reg(adap, ctl_reg);
+ v = G_MBOWNER(ctl);
+ if (v != X_MBOWNER_NONE)
+ break;
+ }
+
+ /*
+ * If we were unable to gain access, dequeue ourselves from the
+ * mailbox atomic access list and report the error to our caller.
+ */
+ if (v != X_MBOWNER_PL) {
+ t4_report_fw_error(adap);
+ ret = (v == X_MBOWNER_FW) ? -EBUSY : -ETIMEDOUT;
+ return ret;
+ }
- if (v != X_MBOWNER_PL)
- return v ? -EBUSY : -ETIMEDOUT;
+ /*
+ * If we gain ownership of the mailbox and there's a "valid" message
+ * in it, this is likely an asynchronous error message from the
+ * firmware. So we'll report that and then proceed on with attempting
+ * to issue our own command ... which may well fail if the error
+ * presaged the firmware crashing ...
+ */
+ if (ctl & F_MBMSGVALID) {
+ CH_ERR(adap, "found VALID command in mbox %u: "
+ "%llx %llx %llx %llx %llx %llx %llx %llx\n", mbox,
+ (unsigned long long)t4_read_reg64(adap, data_reg),
+ (unsigned long long)t4_read_reg64(adap, data_reg + 8),
+ (unsigned long long)t4_read_reg64(adap, data_reg + 16),
+ (unsigned long long)t4_read_reg64(adap, data_reg + 24),
+ (unsigned long long)t4_read_reg64(adap, data_reg + 32),
+ (unsigned long long)t4_read_reg64(adap, data_reg + 40),
+ (unsigned long long)t4_read_reg64(adap, data_reg + 48),
+ (unsigned long long)t4_read_reg64(adap, data_reg + 56));
+ }
+ /*
+ * Copy in the new mailbox command and send it on its way ...
+ */
for (i = 0; i < size; i += 8, p++)
t4_write_reg64(adap, data_reg + i, be64_to_cpu(*p));
CH_DUMP_MBOX(adap, mbox, data_reg);
t4_write_reg(adap, ctl_reg, F_MBMSGVALID | V_MBOWNER(X_MBOWNER_FW));
- t4_read_reg(adap, ctl_reg); /* flush write */
+ t4_read_reg(adap, ctl_reg); /* flush write */
delay_idx = 0;
ms = delay[0];
- for (i = 0; i < FW_CMD_MAX_TIMEOUT; i += ms) {
+ /*
+ * Loop waiting for the reply; bail out if we time out or the firmware
+ * reports an error.
+ */
+ for (i = 0;
+ !((pcie_fw = t4_read_reg(adap, A_PCIE_FW)) & F_PCIE_FW_ERR) &&
+ i < timeout;
+ i += ms) {
if (sleep_ok) {
ms = delay[delay_idx]; /* last element may repeat */
if (delay_idx < ARRAY_SIZE(delay) - 1)
delay_idx++;
msleep(ms);
- } else
+ } else {
mdelay(ms);
+ }
v = t4_read_reg(adap, ctl_reg);
if (v == X_CIM_PF_NOACCESS)
@@ -319,15 +378,20 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
continue;
}
+ /*
+ * Retrieve the command reply and release the mailbox.
+ */
+ get_mbox_rpl(adap, cmd_rpl, size/8, data_reg);
+ t4_write_reg(adap, ctl_reg, V_MBOWNER(X_MBOWNER_NONE));
+
CH_DUMP_MBOX(adap, mbox, data_reg);
- res = t4_read_reg64(adap, data_reg);
+ res = be64_to_cpu(cmd_rpl[0]);
if (G_FW_CMD_OP(res >> 32) == FW_DEBUG_CMD) {
- fw_asrt(adap, data_reg);
+ fw_asrt(adap, (struct fw_debug_cmd *)cmd_rpl);
res = V_FW_CMD_RETVAL(EIO);
} else if (rpl)
- get_mbox_rpl(adap, rpl, size / 8, data_reg);
- t4_write_reg(adap, ctl_reg, V_MBOWNER(X_MBOWNER_NONE));
+ memcpy(rpl, cmd_rpl, size);
return -G_FW_CMD_RETVAL((int)res);
}
}
@@ -337,11 +401,21 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
* the error and also check to see if the firmware reported any
* errors ...
*/
+ ret = (pcie_fw & F_PCIE_FW_ERR) ? -ENXIO : -ETIMEDOUT;
CH_ERR(adap, "command %#x in mailbox %d timed out\n",
*(const u8 *)cmd, mbox);
- if (t4_read_reg(adap, A_PCIE_FW) & F_PCIE_FW_ERR)
- t4_report_fw_error(adap);
- return -ETIMEDOUT;
+
+ t4_report_fw_error(adap);
+ t4_fatal_err(adap);
+ return ret;
+}
+
+int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
+ void *rpl, bool sleep_ok)
+{
+ return t4_wr_mbox_meat_timeout(adap, mbox, cmd, size, rpl,
+ sleep_ok, FW_CMD_MAX_TIMEOUT);
+
}
static int t4_edc_err_read(struct adapter *adap, int idx)
OpenPOWER on IntegriCloud