Commit 6595d358 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'octeon_ep-deferred-probe-and-mailbox'

Veerasenareddy Burru says:

====================
octeon_ep: deferred probe and mailbox

Implement Deferred probe, mailbox enhancements and heartbeat monitor.

v4 -> v5:
   - addressed review comments
     https://lore.kernel.org/all/20230323104703.GD36557@unreal/
     replaced atomic_inc() + atomic_read() with atomic_inc_return().

v3 -> v4:
   - addressed review comments on v3
     https://lore.kernel.org/all/20230214051422.13705-1-vburru@marvell.com/
   - 0004-xxx.patch v3 is split into 0004-xxx.patch and 0005-xxx.patch
     in v4.
   - API changes to accept function ID are moved to 0005-xxx.patch.
   - fixed rct violations.
   - reverted newly added changes that do not yet have use cases.

v2 -> v3:
   - removed SRIOV VF support changes from v2, as new drivers which use
     ndo_get_vf_xxx() and ndo_set_vf_xxx() are not accepted.
     https://lore.kernel.org/all/20221207200204.6819575a@kernel.org/



     Will implement VF representors and submit again.
   - 0007-xxx.patch and 0008-xxx.patch from v2 are removed and
     0009-xxx.patch in v2 is now 0007-xxx.patch in v3.
   - accordingly, changed title for cover letter.

v1 -> v2:
   - remove separate workqueue task to wait for firmware ready.
     instead defer probe when firmware is not ready.
     Reported-by: default avatarLeon Romanovsky <leon@kernel.org>
   - This change has resulted in update of 0001-xxx.patch and
     all other patches in the patchset.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents fbf8ba56 5cb96c29
Loading
Loading
Loading
Loading
+45 −27
Original line number Diff line number Diff line
@@ -13,6 +13,12 @@
#include "octep_main.h"
#include "octep_regs_cn9k_pf.h"

#define CTRL_MBOX_MAX_PF	128
#define CTRL_MBOX_SZ		((size_t)(0x400000 / CTRL_MBOX_MAX_PF))

#define FW_HB_INTERVAL_IN_SECS		1
#define FW_HB_MISS_COUNT		10

/* Names of Hardware non-queue generic interrupts */
static char *cn93_non_ioq_msix_names[] = {
	"epf_ire_rint",
@@ -198,7 +204,9 @@ static void octep_init_config_cn93_pf(struct octep_device *oct)
{
	struct octep_config *conf = oct->conf;
	struct pci_dev *pdev = oct->pdev;
	u8 link = 0;
	u64 val;
	int pos;

	/* Read ring configuration:
	 * PF ring count, number of VFs and rings per VF supported
@@ -234,7 +242,20 @@ static void octep_init_config_cn93_pf(struct octep_device *oct)
	conf->msix_cfg.ioq_msix = conf->pf_ring_cfg.active_io_rings;
	conf->msix_cfg.non_ioq_msix_names = cn93_non_ioq_msix_names;

	conf->ctrl_mbox_cfg.barmem_addr = (void __iomem *)oct->mmio[2].hw_addr + (0x400000ull * 7);
	pos = pci_find_ext_capability(oct->pdev, PCI_EXT_CAP_ID_SRIOV);
	if (pos) {
		pci_read_config_byte(oct->pdev,
				     pos + PCI_SRIOV_FUNC_LINK,
				     &link);
		link = PCI_DEVFN(PCI_SLOT(oct->pdev->devfn), link);
	}
	conf->ctrl_mbox_cfg.barmem_addr = (void __iomem *)oct->mmio[2].hw_addr +
					   (0x400000ull * 7) +
					   (link * CTRL_MBOX_SZ);

	conf->hb_interval = FW_HB_INTERVAL_IN_SECS;
	conf->max_hb_miss_cnt = FW_HB_MISS_COUNT;

}

/* Setup registers for a hardware Tx Queue  */
@@ -352,19 +373,30 @@ static void octep_setup_mbox_regs_cn93_pf(struct octep_device *oct, int q_no)
	mbox->mbox_read_reg = oct->mmio[0].hw_addr + CN93_SDP_R_MBOX_VF_PF_DATA(q_no);
}

/* Mailbox Interrupt handler */
static void cn93_handle_pf_mbox_intr(struct octep_device *oct)
/* Process non-ioq interrupts required to keep pf interface running.
 * OEI_RINT is needed for control mailbox
 */
static bool octep_poll_non_ioq_interrupts_cn93_pf(struct octep_device *oct)
{
	u64 mbox_int_val = 0ULL, val = 0ULL, qno = 0ULL;
	bool handled = false;
	u64 reg0;

	/* Check for OEI INTR */
	reg0 = octep_read_csr64(oct, CN93_SDP_EPF_OEI_RINT);
	if (reg0) {
		dev_info(&oct->pdev->dev,
			 "Received OEI_RINT intr: 0x%llx\n",
			 reg0);
		octep_write_csr64(oct, CN93_SDP_EPF_OEI_RINT, reg0);
		if (reg0 & CN93_SDP_EPF_OEI_RINT_DATA_BIT_MBOX)
			queue_work(octep_wq, &oct->ctrl_mbox_task);
		else if (reg0 & CN93_SDP_EPF_OEI_RINT_DATA_BIT_HBEAT)
			atomic_set(&oct->hb_miss_cnt, 0);

	mbox_int_val = readq(oct->mbox[0]->mbox_int_reg);
	for (qno = 0; qno < OCTEP_MAX_VF; qno++) {
		val = readq(oct->mbox[qno]->mbox_read_reg);
		dev_dbg(&oct->pdev->dev,
			"PF MBOX READ: val:%llx from VF:%llx\n", val, qno);
		handled = true;
	}

	writeq(mbox_int_val, oct->mbox[0]->mbox_int_reg);
	return handled;
}

/* Interrupts handler for all non-queue generic interrupts. */
@@ -434,24 +466,9 @@ static irqreturn_t octep_non_ioq_intr_handler_cn93_pf(void *dev)
		goto irq_handled;
	}

	/* Check for MBOX INTR */
	reg_val = octep_read_csr64(oct, CN93_SDP_EPF_MBOX_RINT(0));
	if (reg_val) {
		dev_info(&pdev->dev,
			 "Received MBOX_RINT intr: 0x%llx\n", reg_val);
		cn93_handle_pf_mbox_intr(oct);
		goto irq_handled;
	}

	/* Check for OEI INTR */
	reg_val = octep_read_csr64(oct, CN93_SDP_EPF_OEI_RINT);
	if (reg_val) {
		dev_info(&pdev->dev,
			 "Received OEI_EINT intr: 0x%llx\n", reg_val);
		octep_write_csr64(oct, CN93_SDP_EPF_OEI_RINT, reg_val);
		queue_work(octep_wq, &oct->ctrl_mbox_task);
	/* Check for MBOX INTR and OEI INTR */
	if (octep_poll_non_ioq_interrupts_cn93_pf(oct))
		goto irq_handled;
	}

	/* Check for DMA INTR */
	reg_val = octep_read_csr64(oct, CN93_SDP_EPF_DMA_RINT);
@@ -712,6 +729,7 @@ void octep_device_setup_cn93_pf(struct octep_device *oct)

	oct->hw_ops.enable_interrupts = octep_enable_interrupts_cn93_pf;
	oct->hw_ops.disable_interrupts = octep_disable_interrupts_cn93_pf;
	oct->hw_ops.poll_non_ioq_interrupts = octep_poll_non_ioq_interrupts_cn93_pf;

	oct->hw_ops.update_iq_read_idx = octep_update_iq_read_index_cn93_pf;

+6 −0
Original line number Diff line number Diff line
@@ -200,5 +200,11 @@ struct octep_config {

	/* ctrl mbox config */
	struct octep_ctrl_mbox_config ctrl_mbox_cfg;

	/* Configured maximum heartbeat miss count */
	u32 max_hb_miss_cnt;

	/* Configured firmware heartbeat interval in secs */
	u32 hb_interval;
};
#endif /* _OCTEP_CONFIG_H_ */
+150 −126
Original line number Diff line number Diff line
@@ -24,41 +24,49 @@
/* Time in msecs to wait for message response */
#define OCTEP_CTRL_MBOX_MSG_WAIT_MS			10

#define OCTEP_CTRL_MBOX_INFO_MAGIC_NUM_OFFSET(m)	(m)
#define OCTEP_CTRL_MBOX_INFO_BARMEM_SZ_OFFSET(m)	((m) + 8)
#define OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(m)	((m) + 24)
#define OCTEP_CTRL_MBOX_INFO_FW_STATUS_OFFSET(m)	((m) + 144)

#define OCTEP_CTRL_MBOX_H2FQ_INFO_OFFSET(m)		((m) + OCTEP_CTRL_MBOX_INFO_SZ)
#define OCTEP_CTRL_MBOX_H2FQ_PROD_OFFSET(m)		(OCTEP_CTRL_MBOX_H2FQ_INFO_OFFSET(m))
#define OCTEP_CTRL_MBOX_H2FQ_CONS_OFFSET(m)		((OCTEP_CTRL_MBOX_H2FQ_INFO_OFFSET(m)) + 4)
#define OCTEP_CTRL_MBOX_H2FQ_ELEM_SZ_OFFSET(m)		((OCTEP_CTRL_MBOX_H2FQ_INFO_OFFSET(m)) + 8)
#define OCTEP_CTRL_MBOX_H2FQ_ELEM_CNT_OFFSET(m)		((OCTEP_CTRL_MBOX_H2FQ_INFO_OFFSET(m)) + 12)

#define OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m)		((m) + \
/* Size of mbox info in bytes */
#define OCTEP_CTRL_MBOX_INFO_SZ				256
/* Size of mbox host to fw queue info in bytes */
#define OCTEP_CTRL_MBOX_H2FQ_INFO_SZ			16
/* Size of mbox fw to host queue info in bytes */
#define OCTEP_CTRL_MBOX_F2HQ_INFO_SZ			16

#define OCTEP_CTRL_MBOX_TOTAL_INFO_SZ	(OCTEP_CTRL_MBOX_INFO_SZ + \
					 OCTEP_CTRL_MBOX_H2FQ_INFO_SZ + \
					 OCTEP_CTRL_MBOX_F2HQ_INFO_SZ)

#define OCTEP_CTRL_MBOX_INFO_MAGIC_NUM(m)	(m)
#define OCTEP_CTRL_MBOX_INFO_BARMEM_SZ(m)	((m) + 8)
#define OCTEP_CTRL_MBOX_INFO_HOST_STATUS(m)	((m) + 24)
#define OCTEP_CTRL_MBOX_INFO_FW_STATUS(m)	((m) + 144)

#define OCTEP_CTRL_MBOX_H2FQ_INFO(m)	((m) + OCTEP_CTRL_MBOX_INFO_SZ)
#define OCTEP_CTRL_MBOX_H2FQ_PROD(m)	(OCTEP_CTRL_MBOX_H2FQ_INFO(m))
#define OCTEP_CTRL_MBOX_H2FQ_CONS(m)	((OCTEP_CTRL_MBOX_H2FQ_INFO(m)) + 4)
#define OCTEP_CTRL_MBOX_H2FQ_SZ(m)	((OCTEP_CTRL_MBOX_H2FQ_INFO(m)) + 8)

#define OCTEP_CTRL_MBOX_F2HQ_INFO(m)	((m) + \
					 OCTEP_CTRL_MBOX_INFO_SZ + \
					 OCTEP_CTRL_MBOX_H2FQ_INFO_SZ)
#define OCTEP_CTRL_MBOX_F2HQ_PROD_OFFSET(m)		(OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m))
#define OCTEP_CTRL_MBOX_F2HQ_CONS_OFFSET(m)		((OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m)) + 4)
#define OCTEP_CTRL_MBOX_F2HQ_ELEM_SZ_OFFSET(m)		((OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m)) + 8)
#define OCTEP_CTRL_MBOX_F2HQ_ELEM_CNT_OFFSET(m)		((OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m)) + 12)
#define OCTEP_CTRL_MBOX_F2HQ_PROD(m)	(OCTEP_CTRL_MBOX_F2HQ_INFO(m))
#define OCTEP_CTRL_MBOX_F2HQ_CONS(m)	((OCTEP_CTRL_MBOX_F2HQ_INFO(m)) + 4)
#define OCTEP_CTRL_MBOX_F2HQ_SZ(m)	((OCTEP_CTRL_MBOX_F2HQ_INFO(m)) + 8)

#define OCTEP_CTRL_MBOX_Q_OFFSET(m, i)			((m) + \
							 (sizeof(struct octep_ctrl_mbox_msg) * (i)))
static const u32 mbox_hdr_sz = sizeof(union octep_ctrl_mbox_msg_hdr);

static u32 octep_ctrl_mbox_circq_inc(u32 index, u32 mask)
static u32 octep_ctrl_mbox_circq_inc(u32 index, u32 inc, u32 sz)
{
	return (index + 1) & mask;
	return (index + inc) % sz;
}

static u32 octep_ctrl_mbox_circq_space(u32 pi, u32 ci, u32 mask)
static u32 octep_ctrl_mbox_circq_space(u32 pi, u32 ci, u32 sz)
{
	return mask - ((pi - ci) & mask);
	return sz - (abs(pi - ci) % sz);
}

static u32 octep_ctrl_mbox_circq_depth(u32 pi, u32 ci, u32 mask)
static u32 octep_ctrl_mbox_circq_depth(u32 pi, u32 ci, u32 sz)
{
	return ((pi - ci) & mask);
	return (abs(pi - ci) % sz);
}

int octep_ctrl_mbox_init(struct octep_ctrl_mbox *mbox)
@@ -73,153 +81,170 @@ int octep_ctrl_mbox_init(struct octep_ctrl_mbox *mbox)
		return -EINVAL;
	}

	magic_num = readq(OCTEP_CTRL_MBOX_INFO_MAGIC_NUM_OFFSET(mbox->barmem));
	magic_num = readq(OCTEP_CTRL_MBOX_INFO_MAGIC_NUM(mbox->barmem));
	if (magic_num != OCTEP_CTRL_MBOX_MAGIC_NUMBER) {
		pr_info("octep_ctrl_mbox : Invalid magic number %llx\n", magic_num);
		return -EINVAL;
	}

	status = readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS_OFFSET(mbox->barmem));
	status = readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS(mbox->barmem));
	if (status != OCTEP_CTRL_MBOX_STATUS_READY) {
		pr_info("octep_ctrl_mbox : Firmware is not ready.\n");
		return -EINVAL;
	}

	mbox->barmem_sz = readl(OCTEP_CTRL_MBOX_INFO_BARMEM_SZ_OFFSET(mbox->barmem));
	mbox->barmem_sz = readl(OCTEP_CTRL_MBOX_INFO_BARMEM_SZ(mbox->barmem));

	writeq(OCTEP_CTRL_MBOX_STATUS_INIT, OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(mbox->barmem));
	writeq(OCTEP_CTRL_MBOX_STATUS_INIT,
	       OCTEP_CTRL_MBOX_INFO_HOST_STATUS(mbox->barmem));

	mbox->h2fq.elem_cnt = readl(OCTEP_CTRL_MBOX_H2FQ_ELEM_CNT_OFFSET(mbox->barmem));
	mbox->h2fq.elem_sz = readl(OCTEP_CTRL_MBOX_H2FQ_ELEM_SZ_OFFSET(mbox->barmem));
	mbox->h2fq.mask = (mbox->h2fq.elem_cnt - 1);
	mutex_init(&mbox->h2fq_lock);
	mbox->h2fq.sz = readl(OCTEP_CTRL_MBOX_H2FQ_SZ(mbox->barmem));
	mbox->h2fq.hw_prod = OCTEP_CTRL_MBOX_H2FQ_PROD(mbox->barmem);
	mbox->h2fq.hw_cons = OCTEP_CTRL_MBOX_H2FQ_CONS(mbox->barmem);
	mbox->h2fq.hw_q = mbox->barmem + OCTEP_CTRL_MBOX_TOTAL_INFO_SZ;

	mbox->f2hq.elem_cnt = readl(OCTEP_CTRL_MBOX_F2HQ_ELEM_CNT_OFFSET(mbox->barmem));
	mbox->f2hq.elem_sz = readl(OCTEP_CTRL_MBOX_F2HQ_ELEM_SZ_OFFSET(mbox->barmem));
	mbox->f2hq.mask = (mbox->f2hq.elem_cnt - 1);
	mutex_init(&mbox->f2hq_lock);

	mbox->h2fq.hw_prod = OCTEP_CTRL_MBOX_H2FQ_PROD_OFFSET(mbox->barmem);
	mbox->h2fq.hw_cons = OCTEP_CTRL_MBOX_H2FQ_CONS_OFFSET(mbox->barmem);
	mbox->h2fq.hw_q = mbox->barmem +
			  OCTEP_CTRL_MBOX_INFO_SZ +
			  OCTEP_CTRL_MBOX_H2FQ_INFO_SZ +
			  OCTEP_CTRL_MBOX_F2HQ_INFO_SZ;

	mbox->f2hq.hw_prod = OCTEP_CTRL_MBOX_F2HQ_PROD_OFFSET(mbox->barmem);
	mbox->f2hq.hw_cons = OCTEP_CTRL_MBOX_F2HQ_CONS_OFFSET(mbox->barmem);
	mbox->f2hq.hw_q = mbox->h2fq.hw_q +
			  ((mbox->h2fq.elem_sz + sizeof(union octep_ctrl_mbox_msg_hdr)) *
			   mbox->h2fq.elem_cnt);
	mbox->f2hq.sz = readl(OCTEP_CTRL_MBOX_F2HQ_SZ(mbox->barmem));
	mbox->f2hq.hw_prod = OCTEP_CTRL_MBOX_F2HQ_PROD(mbox->barmem);
	mbox->f2hq.hw_cons = OCTEP_CTRL_MBOX_F2HQ_CONS(mbox->barmem);
	mbox->f2hq.hw_q = mbox->barmem +
			  OCTEP_CTRL_MBOX_TOTAL_INFO_SZ +
			  mbox->h2fq.sz;

	/* ensure ready state is seen after everything is initialized */
	wmb();
	writeq(OCTEP_CTRL_MBOX_STATUS_READY, OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(mbox->barmem));
	writeq(OCTEP_CTRL_MBOX_STATUS_READY,
	       OCTEP_CTRL_MBOX_INFO_HOST_STATUS(mbox->barmem));

	pr_info("Octep ctrl mbox : Init successful.\n");

	return 0;
}

static void
octep_write_mbox_data(struct octep_ctrl_mbox_q *q, u32 *pi, u32 ci, void *buf, u32 w_sz)
{
	u8 __iomem *qbuf;
	u32 cp_sz;

	/* Assumption: Caller has ensured enough write space */
	qbuf = (q->hw_q + *pi);
	if (*pi < ci) {
		/* copy entire w_sz */
		memcpy_toio(qbuf, buf, w_sz);
		*pi = octep_ctrl_mbox_circq_inc(*pi, w_sz, q->sz);
	} else {
		/* copy up to end of queue */
		cp_sz = min((q->sz - *pi), w_sz);
		memcpy_toio(qbuf, buf, cp_sz);
		w_sz -= cp_sz;
		*pi = octep_ctrl_mbox_circq_inc(*pi, cp_sz, q->sz);
		if (w_sz) {
			/* roll over and copy remaining w_sz */
			buf += cp_sz;
			qbuf = (q->hw_q + *pi);
			memcpy_toio(qbuf, buf, w_sz);
			*pi = octep_ctrl_mbox_circq_inc(*pi, w_sz, q->sz);
		}
	}
}

int octep_ctrl_mbox_send(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_msg *msg)
{
	unsigned long timeout = msecs_to_jiffies(OCTEP_CTRL_MBOX_MSG_TIMEOUT_MS);
	unsigned long period = msecs_to_jiffies(OCTEP_CTRL_MBOX_MSG_WAIT_MS);
	struct octep_ctrl_mbox_msg_buf *sg;
	struct octep_ctrl_mbox_q *q;
	unsigned long expire;
	u64 *mbuf, *word0;
	u8 __iomem *qidx;
	u16 pi, ci;
	int i;
	u32 pi, ci, buf_sz, w_sz;
	int s;

	if (!mbox || !msg)
		return -EINVAL;

	if (readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS(mbox->barmem)) != OCTEP_CTRL_MBOX_STATUS_READY)
		return -EIO;

	mutex_lock(&mbox->h2fq_lock);
	q = &mbox->h2fq;
	pi = readl(q->hw_prod);
	ci = readl(q->hw_cons);

	if (!octep_ctrl_mbox_circq_space(pi, ci, q->mask))
		return -ENOMEM;

	qidx = OCTEP_CTRL_MBOX_Q_OFFSET(q->hw_q, pi);
	mbuf = (u64 *)msg->msg;
	word0 = &msg->hdr.word0;

	mutex_lock(&mbox->h2fq_lock);
	for (i = 1; i <= msg->hdr.sizew; i++)
		writeq(*mbuf++, (qidx + (i * 8)));

	writeq(*word0, qidx);
	if (octep_ctrl_mbox_circq_space(pi, ci, q->sz) < (msg->hdr.s.sz + mbox_hdr_sz)) {
		mutex_unlock(&mbox->f2hq_lock);
		return -EAGAIN;
	}

	pi = octep_ctrl_mbox_circq_inc(pi, q->mask);
	octep_write_mbox_data(q, &pi, ci, (void *)&msg->hdr, mbox_hdr_sz);
	buf_sz = msg->hdr.s.sz;
	for (s = 0; ((s < msg->sg_num) && (buf_sz > 0)); s++) {
		sg = &msg->sg_list[s];
		w_sz = (sg->sz <= buf_sz) ? sg->sz : buf_sz;
		octep_write_mbox_data(q, &pi, ci, sg->msg, w_sz);
		buf_sz -= w_sz;
	}
	writel(pi, q->hw_prod);
	mutex_unlock(&mbox->h2fq_lock);

	/* don't check for notification response */
	if (msg->hdr.flags & OCTEP_CTRL_MBOX_MSG_HDR_FLAG_NOTIFY)
	return 0;
}

	expire = jiffies + timeout;
	while (true) {
		*word0 = readq(qidx);
		if (msg->hdr.flags == OCTEP_CTRL_MBOX_MSG_HDR_FLAG_RESP)
			break;
		schedule_timeout_interruptible(period);
		if (signal_pending(current) || time_after(jiffies, expire)) {
			pr_info("octep_ctrl_mbox: Timed out\n");
			return -EBUSY;
static void
octep_read_mbox_data(struct octep_ctrl_mbox_q *q, u32 pi, u32 *ci, void *buf, u32 r_sz)
{
	u8 __iomem *qbuf;
	u32 cp_sz;

	/* Assumption: Caller has ensured enough read space */
	qbuf = (q->hw_q + *ci);
	if (*ci < pi) {
		/* copy entire r_sz */
		memcpy_fromio(buf, qbuf, r_sz);
		*ci = octep_ctrl_mbox_circq_inc(*ci, r_sz, q->sz);
	} else {
		/* copy up to end of queue */
		cp_sz = min((q->sz - *ci), r_sz);
		memcpy_fromio(buf, qbuf, cp_sz);
		r_sz -= cp_sz;
		*ci = octep_ctrl_mbox_circq_inc(*ci, cp_sz, q->sz);
		if (r_sz) {
			/* roll over and copy remaining r_sz */
			buf += cp_sz;
			qbuf = (q->hw_q + *ci);
			memcpy_fromio(buf, qbuf, r_sz);
			*ci = octep_ctrl_mbox_circq_inc(*ci, r_sz, q->sz);
		}
	}
	mbuf = (u64 *)msg->msg;
	for (i = 1; i <= msg->hdr.sizew; i++)
		*mbuf++ = readq(qidx + (i * 8));

	return 0;
}

int octep_ctrl_mbox_recv(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_msg *msg)
{
	struct octep_ctrl_mbox_msg_buf *sg;
	u32 pi, ci, r_sz, buf_sz, q_depth;
	struct octep_ctrl_mbox_q *q;
	u32 count, pi, ci;
	u8 __iomem *qidx;
	u64 *mbuf;
	int i;
	int s;

	if (!mbox || !msg)
		return -EINVAL;
	if (readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS(mbox->barmem)) != OCTEP_CTRL_MBOX_STATUS_READY)
		return -EIO;

	mutex_lock(&mbox->f2hq_lock);
	q = &mbox->f2hq;
	pi = readl(q->hw_prod);
	ci = readl(q->hw_cons);
	count = octep_ctrl_mbox_circq_depth(pi, ci, q->mask);
	if (!count)
		return -EAGAIN;

	qidx = OCTEP_CTRL_MBOX_Q_OFFSET(q->hw_q, ci);
	mbuf = (u64 *)msg->msg;

	mutex_lock(&mbox->f2hq_lock);

	msg->hdr.word0 = readq(qidx);
	for (i = 1; i <= msg->hdr.sizew; i++)
		*mbuf++ = readq(qidx + (i * 8));
	q_depth = octep_ctrl_mbox_circq_depth(pi, ci, q->sz);
	if (q_depth < mbox_hdr_sz) {
		mutex_unlock(&mbox->f2hq_lock);
		return -EAGAIN;
	}

	ci = octep_ctrl_mbox_circq_inc(ci, q->mask);
	octep_read_mbox_data(q, pi, &ci, (void *)&msg->hdr, mbox_hdr_sz);
	buf_sz = msg->hdr.s.sz;
	for (s = 0; ((s < msg->sg_num) && (buf_sz > 0)); s++) {
		sg = &msg->sg_list[s];
		r_sz = (sg->sz <= buf_sz) ? sg->sz : buf_sz;
		octep_read_mbox_data(q, pi, &ci, sg->msg, r_sz);
		buf_sz -= r_sz;
	}
	writel(ci, q->hw_cons);

	mutex_unlock(&mbox->f2hq_lock);

	if (msg->hdr.flags != OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ || !mbox->process_req)
		return 0;

	mbox->process_req(mbox->user_ctx, msg);
	mbuf = (u64 *)msg->msg;
	for (i = 1; i <= msg->hdr.sizew; i++)
		writeq(*mbuf++, (qidx + (i * 8)));

	writeq(msg->hdr.word0, qidx);

	return 0;
}

@@ -227,18 +252,17 @@ int octep_ctrl_mbox_uninit(struct octep_ctrl_mbox *mbox)
{
	if (!mbox)
		return -EINVAL;
	if (!mbox->barmem)
		return -EINVAL;

	writeq(OCTEP_CTRL_MBOX_STATUS_UNINIT,
	       OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(mbox->barmem));
	writeq(OCTEP_CTRL_MBOX_STATUS_INVALID,
	       OCTEP_CTRL_MBOX_INFO_HOST_STATUS(mbox->barmem));
	/* ensure uninit state is written before uninitialization */
	wmb();

	mutex_destroy(&mbox->h2fq_lock);
	mutex_destroy(&mbox->f2hq_lock);

	writeq(OCTEP_CTRL_MBOX_STATUS_INVALID,
	       OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(mbox->barmem));

	pr_info("Octep ctrl mbox : Uninit successful.\n");

	return 0;
+46 −42
Original line number Diff line number Diff line
@@ -27,50 +27,39 @@
 * |-------------------------------------------|
 * |producer index (4 bytes)                   |
 * |consumer index (4 bytes)                   |
 * |element size (4 bytes)                     |
 * |element count (4 bytes)                    |
 * |max element size (4 bytes)                 |
 * |reserved (4 bytes)                         |
 * |===========================================|
 * |Fw to Host Queue info (16 bytes)           |
 * |-------------------------------------------|
 * |producer index (4 bytes)                   |
 * |consumer index (4 bytes)                   |
 * |element size (4 bytes)                     |
 * |element count (4 bytes)                    |
 * |max element size (4 bytes)                 |
 * |reserved (4 bytes)                         |
 * |===========================================|
 * |Host to Fw Queue                           |
 * |Host to Fw Queue ((total size-288/2) bytes)|
 * |-------------------------------------------|
 * |((elem_sz + hdr(8 bytes)) * elem_cnt) bytes|
 * |                                           |
 * |===========================================|
 * |===========================================|
 * |Fw to Host Queue                           |
 * |Fw to Host Queue ((total size-288/2) bytes)|
 * |-------------------------------------------|
 * |((elem_sz + hdr(8 bytes)) * elem_cnt) bytes|
 * |                                           |
 * |===========================================|
 */

#define OCTEP_CTRL_MBOX_MAGIC_NUMBER			0xdeaddeadbeefbeefull

/* Size of mbox info in bytes */
#define OCTEP_CTRL_MBOX_INFO_SZ				256
/* Size of mbox host to target queue info in bytes */
#define OCTEP_CTRL_MBOX_H2FQ_INFO_SZ			16
/* Size of mbox target to host queue info in bytes */
#define OCTEP_CTRL_MBOX_F2HQ_INFO_SZ			16
/* Size of mbox queue in bytes */
#define OCTEP_CTRL_MBOX_Q_SZ(sz, cnt)			(((sz) + 8) * (cnt))
/* Size of mbox in bytes */
#define OCTEP_CTRL_MBOX_SZ(hsz, hcnt, fsz, fcnt)	(OCTEP_CTRL_MBOX_INFO_SZ + \
							 OCTEP_CTRL_MBOX_H2FQ_INFO_SZ + \
							 OCTEP_CTRL_MBOX_F2HQ_INFO_SZ + \
							 OCTEP_CTRL_MBOX_Q_SZ(hsz, hcnt) + \
							 OCTEP_CTRL_MBOX_Q_SZ(fsz, fcnt))

/* Valid request message */
#define OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ		BIT(0)
/* Valid response message */
#define OCTEP_CTRL_MBOX_MSG_HDR_FLAG_RESP		BIT(1)
/* Valid notification, no response required */
#define OCTEP_CTRL_MBOX_MSG_HDR_FLAG_NOTIFY		BIT(2)
/* Valid custom message */
#define OCTEP_CTRL_MBOX_MSG_HDR_FLAG_CUSTOM		BIT(3)

#define OCTEP_CTRL_MBOX_MSG_DESC_MAX			4

enum octep_ctrl_mbox_status {
	OCTEP_CTRL_MBOX_STATUS_INVALID = 0,
@@ -81,31 +70,48 @@ enum octep_ctrl_mbox_status {

/* mbox message */
union octep_ctrl_mbox_msg_hdr {
	u64 word0;
	u64 words[2];
	struct {
		/* must be 0 */
		u16 reserved1:15;
		/* vf_idx is valid if 1 */
		u16 is_vf:1;
		/* sender vf index 0-(n-1), 0 if (is_vf==0) */
		u16 vf_idx;
		/* total size of message excluding header */
		u32 sz;
		/* OCTEP_CTRL_MBOX_MSG_HDR_FLAG_* */
		u32 flags;
		/* size of message in words excluding header */
		u32 sizew;
		/* identifier to match responses */
		u16 msg_id;
		u16 reserved2;
	} s;
};

/* mbox message buffer */
struct octep_ctrl_mbox_msg_buf {
	u32 reserved1;
	u16 reserved2;
	/* size of buffer */
	u16 sz;
	/* pointer to message buffer */
	void *msg;
};

/* mbox message */
struct octep_ctrl_mbox_msg {
	/* mbox transaction header */
	union octep_ctrl_mbox_msg_hdr hdr;
	/* pointer to message buffer */
	void *msg;
	/* number of sg buffer's */
	int sg_num;
	/* message buffer's */
	struct octep_ctrl_mbox_msg_buf sg_list[OCTEP_CTRL_MBOX_MSG_DESC_MAX];
};

/* Mbox queue */
struct octep_ctrl_mbox_q {
	/* q element size, should be aligned to unsigned long */
	u16 elem_sz;
	/* q element count, should be power of 2 */
	u16 elem_cnt;
	/* q mask */
	u16 mask;
	/* size of queue buffer */
	u32 sz;
	/* producer address in bar mem */
	u8 __iomem *hw_prod;
	/* consumer address in bar mem */
@@ -115,16 +121,10 @@ struct octep_ctrl_mbox_q {
};

struct octep_ctrl_mbox {
	/* host driver version */
	u64 version;
	/* size of bar memory */
	u32 barmem_sz;
	/* pointer to BAR memory */
	u8 __iomem *barmem;
	/* user context for callback, can be null */
	void *user_ctx;
	/* callback handler for processing request, called from octep_ctrl_mbox_recv */
	int (*process_req)(void *user_ctx, struct octep_ctrl_mbox_msg *msg);
	/* host-to-fw queue */
	struct octep_ctrl_mbox_q h2fq;
	/* fw-to-host queue */
@@ -146,6 +146,8 @@ int octep_ctrl_mbox_init(struct octep_ctrl_mbox *mbox);
/* Send mbox message.
 *
 * @param mbox: non-null pointer to struct octep_ctrl_mbox.
 * @param msg:  non-null pointer to struct octep_ctrl_mbox_msg.
 *              Caller should fill msg.sz and msg.desc.sz for each message.
 *
 * return value: 0 on success, -errno on failure.
 */
@@ -154,6 +156,8 @@ int octep_ctrl_mbox_send(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_ms
/* Retrieve mbox message.
 *
 * @param mbox: non-null pointer to struct octep_ctrl_mbox.
 * @param msg:  non-null pointer to struct octep_ctrl_mbox_msg.
 *              Caller should fill msg.sz and msg.desc.sz for each message.
 *
 * return value: 0 on success, -errno on failure.
 */
@@ -161,7 +165,7 @@ int octep_ctrl_mbox_recv(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_ms

/* Uninitialize control mbox.
 *
 * @param ep: non-null pointer to struct octep_ctrl_mbox.
 * @param mbox: non-null pointer to struct octep_ctrl_mbox.
 *
 * return value: 0 on success, -errno on failure.
 */
+264 −123

File changed.

Preview size limit exceeded, changes collapsed.

Loading