/* mailbox */
#define QM_MB_PING_ALL_VFS 0xffff
#define QM_MB_STATUS_MASK GENMASK(12, 9)
+#define QM_MB_BUSY_MASK BIT(13)
/* sqc shift */
#define QM_SQ_HOP_NUM_SHIFT 0
mailbox->rsvd = 0;
}
-/* return 0 mailbox ready, -ETIMEDOUT hardware timeout */
-int hisi_qm_wait_mb_ready(struct hisi_qm *qm)
+/*
+ * The mailbox is 128 bits and requires a single read/write operation.
+ * Since there is no general 128-bit IO memory access API in the current
+ * ARM64 architecture, this needs to be implemented in the driver.
+ */
+static struct qm_mailbox qm_mb_read(struct hisi_qm *qm)
{
- u32 val;
+ struct qm_mailbox mailbox = {0};
+
+#if IS_ENABLED(CONFIG_ARM64)
+ const void __iomem *fun_base = qm->io_base + QM_MB_CMD_SEND_BASE;
+ unsigned long tmp0, tmp1;
- return readl_relaxed_poll_timeout(qm->io_base + QM_MB_CMD_SEND_BASE,
- val, !((val >> QM_MB_BUSY_SHIFT) &
- 0x1), POLL_PERIOD, POLL_TIMEOUT);
+ asm volatile("ldp %0, %1, %3\n"
+ "stp %0, %1, %2\n"
+ : "=&r" (tmp0),
+ "=&r" (tmp1),
+ "+Q" (mailbox)
+ : "Q" (*((char __iomem *)fun_base))
+ : "memory");
+#endif
+
+ return mailbox;
}
-EXPORT_SYMBOL_GPL(hisi_qm_wait_mb_ready);
/* 128 bit should be written to hardware at one time to trigger a mailbox */
static void qm_mb_write(struct hisi_qm *qm, const void *src)
#endif
}
-static int qm_mb_nolock(struct hisi_qm *qm, struct qm_mailbox *mailbox)
+int hisi_qm_wait_mb_ready(struct hisi_qm *qm)
{
+ struct qm_mailbox mailbox = {0};
int ret;
- u32 val;
- if (unlikely(hisi_qm_wait_mb_ready(qm))) {
+ ret = read_poll_timeout(qm_mb_read, mailbox,
+ !(le16_to_cpu(mailbox.w0) & QM_MB_BUSY_MASK),
+ POLL_PERIOD, POLL_TIMEOUT,
+ true, qm);
+ if (ret)
dev_err(&qm->pdev->dev, "QM mailbox is busy to start!\n");
- ret = -EBUSY;
- goto mb_busy;
- }
- qm_mb_write(qm, mailbox);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(hisi_qm_wait_mb_ready);
+
+static int qm_wait_mb_finish(struct hisi_qm *qm, struct qm_mailbox *mailbox)
+{
+ struct device *dev = &qm->pdev->dev;
+ int ret;
- if (unlikely(hisi_qm_wait_mb_ready(qm))) {
- dev_err(&qm->pdev->dev, "QM mailbox operation timeout!\n");
- ret = -ETIMEDOUT;
- goto mb_busy;
+ ret = read_poll_timeout(qm_mb_read, *mailbox,
+ !(le16_to_cpu(mailbox->w0) & QM_MB_BUSY_MASK),
+ POLL_PERIOD, POLL_TIMEOUT,
+ true, qm);
+ if (ret) {
+ dev_err(dev, "QM mailbox operation timeout!\n");
+ return ret;
}
- val = readl(qm->io_base + QM_MB_CMD_SEND_BASE);
- if (val & QM_MB_STATUS_MASK) {
- dev_err(&qm->pdev->dev, "QM mailbox operation failed!\n");
- ret = -EIO;
- goto mb_busy;
+ if (le16_to_cpu(mailbox->w0) & QM_MB_STATUS_MASK) {
+ dev_err(dev, "QM mailbox operation failed!\n");
+ return -EIO;
}
return 0;
+}
+
+static int qm_mb_nolock(struct hisi_qm *qm, struct qm_mailbox *mailbox)
+{
+ int ret;
+
+ ret = hisi_qm_wait_mb_ready(qm);
+ if (ret)
+ goto mb_err_cnt_increase;
+
+ qm_mb_write(qm, mailbox);
+
+ ret = qm_wait_mb_finish(qm, mailbox);
+ if (ret)
+ goto mb_err_cnt_increase;
+
+ return 0;
-mb_busy:
+mb_err_cnt_increase:
atomic64_inc(&qm->debug.dfx.mb_err_cnt);
return ret;
}
}
EXPORT_SYMBOL_GPL(hisi_qm_mb);
+int hisi_qm_mb_read(struct hisi_qm *qm, u64 *base, u8 cmd, u16 queue)
+{
+ struct qm_mailbox mailbox;
+ int ret;
+
+ qm_mb_pre_init(&mailbox, cmd, 0, queue, 1);
+ mutex_lock(&qm->mailbox_lock);
+ ret = qm_mb_nolock(qm, &mailbox);
+ mutex_unlock(&qm->mailbox_lock);
+ if (ret)
+ return ret;
+
+ *base = le32_to_cpu(mailbox.base_l) |
+ ((u64)le32_to_cpu(mailbox.base_h) << 32);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hisi_qm_mb_read);
+
/* op 0: set xqc information to hardware, 1: get xqc information from hardware. */
int qm_set_and_get_xqc(struct hisi_qm *qm, u8 cmd, void *xqc, u32 qp_id, bool op)
{
u64 sqc_vft;
int ret;
- ret = hisi_qm_mb(qm, QM_MB_CMD_SQC_VFT_V2, 0, 0, 1);
+ ret = hisi_qm_mb_read(qm, &sqc_vft, QM_MB_CMD_SQC_VFT_V2, 0);
if (ret)
return ret;
- sqc_vft = readl(qm->io_base + QM_MB_CMD_DATA_ADDR_L) |
- ((u64)readl(qm->io_base + QM_MB_CMD_DATA_ADDR_H) << 32);
*base = QM_SQC_VFT_BASE_MASK_V2 & (sqc_vft >> QM_SQC_VFT_BASE_SHIFT_V2);
*number = (QM_SQC_VFT_NUM_MASK_V2 &
(sqc_vft >> QM_SQC_VFT_NUM_SHIFT_V2)) + 1;
return ACC_ERR_RECOVERED;
}
-static int qm_get_mb_cmd(struct hisi_qm *qm, u64 *msg, u16 fun_num)
-{
- struct qm_mailbox mailbox;
- int ret;
-
- qm_mb_pre_init(&mailbox, QM_MB_CMD_DST, 0, fun_num, 0);
- mutex_lock(&qm->mailbox_lock);
- ret = qm_mb_nolock(qm, &mailbox);
- if (ret)
- goto err_unlock;
-
- *msg = readl(qm->io_base + QM_MB_CMD_DATA_ADDR_L) |
- ((u64)readl(qm->io_base + QM_MB_CMD_DATA_ADDR_H) << 32);
-
-err_unlock:
- mutex_unlock(&qm->mailbox_lock);
- return ret;
-}
-
static void qm_clear_cmd_interrupt(struct hisi_qm *qm, u64 vf_mask)
{
u32 val;
u64 msg;
int ret;
- ret = qm_get_mb_cmd(qm, &msg, fun_num);
+ ret = hisi_qm_mb_read(qm, &msg, QM_MB_CMD_DST, fun_num);
if (ret)
return ret;