|
@@ -284,6 +284,7 @@ int t4_wr_mbox_meat_timeout(struct adapter *adap, int mbox, const void *cmd,
|
|
1, 1, 3, 5, 10, 10, 20, 50, 100, 200
|
|
1, 1, 3, 5, 10, 10, 20, 50, 100, 200
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+ struct mbox_list entry;
|
|
u16 access = 0;
|
|
u16 access = 0;
|
|
u16 execute = 0;
|
|
u16 execute = 0;
|
|
u32 v;
|
|
u32 v;
|
|
@@ -311,11 +312,61 @@ int t4_wr_mbox_meat_timeout(struct adapter *adap, int mbox, const void *cmd,
|
|
timeout = -timeout;
|
|
timeout = -timeout;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* Queue ourselves onto the mailbox access list. When our entry is at
|
|
|
|
+ * the front of the list, we have rights to access the mailbox. So we
|
|
|
|
+ * wait [for a while] till we're at the front [or bail out with an
|
|
|
|
+ * EBUSY] ...
|
|
|
|
+ */
|
|
|
|
+ spin_lock(&adap->mbox_lock);
|
|
|
|
+ list_add_tail(&entry.list, &adap->mlist.list);
|
|
|
|
+ spin_unlock(&adap->mbox_lock);
|
|
|
|
+
|
|
|
|
+ delay_idx = 0;
|
|
|
|
+ ms = delay[0];
|
|
|
|
+
|
|
|
|
+ for (i = 0; ; i += ms) {
|
|
|
|
+ /* If we've waited too long, return a busy indication. This
|
|
|
|
+ * really ought to be based on our initial position in the
|
|
|
|
+ * mailbox access list but this is a start. We very rearely
|
|
|
|
+ * contend on access to the mailbox ...
|
|
|
|
+ */
|
|
|
|
+ if (i > FW_CMD_MAX_TIMEOUT) {
|
|
|
|
+ spin_lock(&adap->mbox_lock);
|
|
|
|
+ list_del(&entry.list);
|
|
|
|
+ spin_unlock(&adap->mbox_lock);
|
|
|
|
+ ret = -EBUSY;
|
|
|
|
+ t4_record_mbox(adap, cmd, size, access, ret);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* If we're at the head, break out and start the mailbox
|
|
|
|
+ * protocol.
|
|
|
|
+ */
|
|
|
|
+ if (list_first_entry(&adap->mlist.list, struct mbox_list,
|
|
|
|
+ list) == &entry)
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ /* Delay for a bit before checking again ... */
|
|
|
|
+ if (sleep_ok) {
|
|
|
|
+ ms = delay[delay_idx]; /* last element may repeat */
|
|
|
|
+ if (delay_idx < ARRAY_SIZE(delay) - 1)
|
|
|
|
+ delay_idx++;
|
|
|
|
+ msleep(ms);
|
|
|
|
+ } else {
|
|
|
|
+ mdelay(ms);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Loop trying to get ownership of the mailbox. Return an error
|
|
|
|
+ * if we can't gain ownership.
|
|
|
|
+ */
|
|
v = MBOWNER_G(t4_read_reg(adap, ctl_reg));
|
|
v = MBOWNER_G(t4_read_reg(adap, ctl_reg));
|
|
for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++)
|
|
for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++)
|
|
v = MBOWNER_G(t4_read_reg(adap, ctl_reg));
|
|
v = MBOWNER_G(t4_read_reg(adap, ctl_reg));
|
|
-
|
|
|
|
if (v != MBOX_OWNER_DRV) {
|
|
if (v != MBOX_OWNER_DRV) {
|
|
|
|
+ spin_lock(&adap->mbox_lock);
|
|
|
|
+ list_del(&entry.list);
|
|
|
|
+ spin_unlock(&adap->mbox_lock);
|
|
ret = (v == MBOX_OWNER_FW) ? -EBUSY : -ETIMEDOUT;
|
|
ret = (v == MBOX_OWNER_FW) ? -EBUSY : -ETIMEDOUT;
|
|
t4_record_mbox(adap, cmd, MBOX_LEN, access, ret);
|
|
t4_record_mbox(adap, cmd, MBOX_LEN, access, ret);
|
|
return ret;
|
|
return ret;
|
|
@@ -366,6 +417,9 @@ int t4_wr_mbox_meat_timeout(struct adapter *adap, int mbox, const void *cmd,
|
|
execute = i + ms;
|
|
execute = i + ms;
|
|
t4_record_mbox(adap, cmd_rpl,
|
|
t4_record_mbox(adap, cmd_rpl,
|
|
MBOX_LEN, access, execute);
|
|
MBOX_LEN, access, execute);
|
|
|
|
+ spin_lock(&adap->mbox_lock);
|
|
|
|
+ list_del(&entry.list);
|
|
|
|
+ spin_unlock(&adap->mbox_lock);
|
|
return -FW_CMD_RETVAL_G((int)res);
|
|
return -FW_CMD_RETVAL_G((int)res);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -375,6 +429,9 @@ int t4_wr_mbox_meat_timeout(struct adapter *adap, int mbox, const void *cmd,
|
|
dev_err(adap->pdev_dev, "command %#x in mailbox %d timed out\n",
|
|
dev_err(adap->pdev_dev, "command %#x in mailbox %d timed out\n",
|
|
*(const u8 *)cmd, mbox);
|
|
*(const u8 *)cmd, mbox);
|
|
t4_report_fw_error(adap);
|
|
t4_report_fw_error(adap);
|
|
|
|
+ spin_lock(&adap->mbox_lock);
|
|
|
|
+ list_del(&entry.list);
|
|
|
|
+ spin_unlock(&adap->mbox_lock);
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|