All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alfredo Cardigliano <cardigliano@ntop.org>
To: dev@dpdk.org
Subject: [dpdk-dev] [PATCH 08/17] net/ionic: add adminq support
Date: Sat, 12 Oct 2019 02:27:07 +0200	[thread overview]
Message-ID: <157084002711.11524.9195394378752943090.stgit@devele> (raw)
In-Reply-To: <157083994018.11524.11276616720287263690.stgit@devele>

Add support for the admin queue, which is used for most
of the NIC configurations.

Signed-off-by: Alfredo Cardigliano <cardigliano@ntop.org>
Reviewed-by: Shannon Nelson <snelson@pensando.io>
---
 drivers/net/ionic/ionic.h      |    4 
 drivers/net/ionic/ionic_dev.c  |  256 +++++++++++++++++++++++++++++
 drivers/net/ionic/ionic_dev.h  |   96 +++++++++++
 drivers/net/ionic/ionic_lif.c  |  356 ++++++++++++++++++++++++++++++++++++++++
 drivers/net/ionic/ionic_lif.h  |   36 ++++
 drivers/net/ionic/ionic_main.c |  188 +++++++++++++++++++++
 6 files changed, 934 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ionic/ionic.h b/drivers/net/ionic/ionic.h
index a30e1cf20..3a9bb7b22 100644
--- a/drivers/net/ionic/ionic.h
+++ b/drivers/net/ionic/ionic.h
@@ -55,11 +55,15 @@ struct ionic_adapter {
 	uint32_t max_ntxqs_per_lif;
 	uint32_t max_nrxqs_per_lif;
 	uint32_t nintrs;
+	bool intrs[IONIC_INTR_CTRL_REGS_MAX];
 	bool is_mgmt_nic;
 	struct rte_pci_device *pci_dev;
 	LIST_ENTRY(ionic_adapter) pci_adapters;
 };
 
+int ionic_adminq_check_err(struct ionic_lif *lif, struct ionic_admin_ctx *ctx,
+		bool timeout);
+int ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx);
 int ionic_dev_cmd_wait_check(struct ionic_dev *idev, unsigned long max_wait);
 int ionic_setup(struct ionic_adapter *adapter);
 
diff --git a/drivers/net/ionic/ionic_dev.c b/drivers/net/ionic/ionic_dev.c
index d0a4d5268..fc165d0a8 100644
--- a/drivers/net/ionic/ionic_dev.c
+++ b/drivers/net/ionic/ionic_dev.c
@@ -293,6 +293,12 @@ ionic_dev_cmd_lif_reset(struct ionic_dev *idev, uint16_t lif_index)
 	ionic_dev_cmd_go(idev, &cmd);
 }
 
+struct ionic_doorbell *
+ionic_db_map(struct ionic_lif *lif, struct ionic_queue *q)
+{
+	return lif->kern_dbpage + q->hw_type;
+}
+
 int
 ionic_db_page_num(struct ionic_lif *lif, int pid)
 {
@@ -306,3 +312,253 @@ ionic_intr_init(struct ionic_dev *idev, struct ionic_intr_info *intr,
 	ionic_intr_clean(idev->intr_ctrl, index);
 	intr->index = index;
 }
+
+void
+ionic_dev_cmd_adminq_init(struct ionic_dev *idev,
+			  struct ionic_qcq *qcq,
+			  uint16_t lif_index, uint16_t intr_index)
+{
+	struct ionic_queue *q = &qcq->q;
+	struct ionic_cq *cq = &qcq->cq;
+
+	union ionic_dev_cmd cmd = {
+		.q_init.opcode = IONIC_CMD_Q_INIT,
+		.q_init.lif_index = lif_index,
+		.q_init.type = q->type,
+		.q_init.index = q->index,
+		.q_init.flags = IONIC_QINIT_F_ENA,
+		.q_init.pid = q->pid,
+		.q_init.intr_index = intr_index,
+		.q_init.ring_size = ilog2(q->num_descs),
+		.q_init.ring_base = q->base_pa,
+		.q_init.cq_ring_base = cq->base_pa,
+	};
+
+	ionic_dev_cmd_go(idev, &cmd);
+}
+
+int
+ionic_cq_init(struct ionic_lif *lif, struct ionic_cq *cq,
+		struct ionic_intr_info *intr,
+		uint32_t num_descs, size_t desc_size)
+{
+	if (desc_size == 0) {
+		ionic_init_print(ERR, "Descriptor size is %lu", desc_size);
+		return -EINVAL;
+	}
+
+	if (!rte_is_power_of_2(num_descs) ||
+	    num_descs < IONIC_MIN_RING_DESC ||
+	    num_descs > IONIC_MAX_RING_DESC) {
+		ionic_init_print(ERR, "%u descriptors (min: %u max: %u)",
+			num_descs, IONIC_MIN_RING_DESC, IONIC_MAX_RING_DESC);
+		return -EINVAL;
+	}
+
+	cq->lif = lif;
+	cq->bound_intr = intr;
+	cq->num_descs = num_descs;
+	cq->desc_size = desc_size;
+	cq->tail_idx = 0;
+	cq->done_color = 1;
+
+	return 0;
+}
+
+void
+ionic_cq_map(struct ionic_cq *cq, void *base, rte_iova_t base_pa)
+{
+	cq->base = base;
+	cq->base_pa = base_pa;
+}
+
+void
+ionic_cq_bind(struct ionic_cq *cq, struct ionic_queue *q)
+{
+	cq->bound_q = q;
+	q->bound_cq = cq;
+}
+
+uint32_t
+ionic_cq_service(struct ionic_cq *cq, uint32_t work_to_do,
+		 ionic_cq_cb cb, void *cb_arg)
+{
+	uint32_t work_done = 0;
+
+	if (work_to_do == 0)
+		return 0;
+
+	while (cb(cq, cq->tail_idx, cb_arg)) {
+		cq->tail_idx = (cq->tail_idx + 1) & (cq->num_descs - 1);
+		if (cq->tail_idx == 0)
+			cq->done_color = !cq->done_color;
+
+		if (++work_done == work_to_do)
+			break;
+	}
+
+	return work_done;
+}
+
+int
+ionic_q_init(struct ionic_lif *lif, struct ionic_dev *idev,
+	     struct ionic_queue *q,
+	     uint32_t index, const char *base, uint32_t num_descs,
+	     size_t desc_size, size_t sg_desc_size, uint32_t pid)
+{
+	uint32_t ring_size;
+
+	if (desc_size == 0 || !rte_is_power_of_2(num_descs))
+		return -EINVAL;
+
+	ring_size = ilog2(num_descs);
+
+	if (ring_size < 2 || ring_size > 16)
+		return -EINVAL;
+
+	q->lif = lif;
+	q->idev = idev;
+	q->index = index;
+	q->num_descs = num_descs;
+	q->desc_size = desc_size;
+	q->sg_desc_size = sg_desc_size;
+	q->head_idx = 0;
+	q->tail_idx = 0;
+	q->pid = pid;
+
+	return 0;
+}
+
+void
+ionic_q_map(struct ionic_queue *q, void *base, rte_iova_t base_pa)
+{
+	q->base = base;
+	q->base_pa = base_pa;
+}
+
+void
+ionic_q_sg_map(struct ionic_queue *q, void *base, rte_iova_t base_pa)
+{
+	q->sg_base = base;
+	q->sg_base_pa = base_pa;
+}
+
+void
+ionic_q_flush(struct ionic_queue *q)
+{
+	writeq(IONIC_DBELL_QID(q->hw_index) | q->head_idx, q->db);
+}
+
+void
+ionic_q_post(struct ionic_queue *q, bool ring_doorbell, desc_cb cb,
+	     void *cb_arg)
+{
+	struct ionic_desc_info *head = &q->info[q->head_idx];
+
+	head->cb = cb;
+	head->cb_arg = cb_arg;
+
+	q->head_idx = (q->head_idx + 1) & (q->num_descs - 1);
+
+	if (ring_doorbell)
+		ionic_q_flush(q);
+}
+
+uint32_t
+ionic_q_space_avail(struct ionic_queue *q)
+{
+	uint32_t avail = q->tail_idx;
+
+	if (q->head_idx >= avail)
+		avail += q->num_descs - q->head_idx - 1;
+	else
+		avail -= q->head_idx + 1;
+
+	return avail;
+}
+
+bool
+ionic_q_has_space(struct ionic_queue *q, uint32_t want)
+{
+	return ionic_q_space_avail(q) >= want;
+}
+
+void
+ionic_q_service(struct ionic_queue *q, uint32_t cq_desc_index,
+		uint32_t stop_index, void *service_cb_arg)
+{
+	struct ionic_desc_info *desc_info;
+	uint32_t curr_q_tail_idx;
+
+	do {
+		desc_info = &q->info[q->tail_idx];
+
+		if (desc_info->cb)
+			desc_info->cb(q, q->tail_idx, cq_desc_index,
+				      desc_info->cb_arg, service_cb_arg);
+
+		desc_info->cb = NULL;
+		desc_info->cb_arg = NULL;
+
+		curr_q_tail_idx = q->tail_idx;
+		q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1);
+
+	} while (curr_q_tail_idx != stop_index);
+}
+
+static void
+ionic_adminq_cb(struct ionic_queue *q,
+		uint32_t q_desc_index, uint32_t cq_desc_index,
+		void *cb_arg, void *service_cb_arg __rte_unused)
+{
+	struct ionic_admin_ctx *ctx = cb_arg;
+	struct ionic_admin_comp *cq_desc_base = q->bound_cq->base;
+	struct ionic_admin_comp *cq_desc = &cq_desc_base[cq_desc_index];
+
+	if (unlikely(cq_desc->comp_index != q_desc_index)) {
+		IONIC_WARN_ON(cq_desc->comp_index != q_desc_index);
+		return;
+	}
+
+	memcpy(&ctx->comp, cq_desc, sizeof(*cq_desc));
+
+	ctx->pending_work = false; /* done */
+}
+
+/** ionic_adminq_post - Post an admin command.
+ * @lif:		Handle to lif.
+ * @cmd_ctx:		Api admin command context.
+ *
+ * Post the command to an admin queue in the ethernet driver.  If this command
+ * succeeds, then the command has been posted, but that does not indicate a
+ * completion.  If this command returns success, then the completion callback
+ * will eventually be called.
+ *
+ * Return: zero or negative error status.
+ */
+int
+ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
+{
+	struct ionic_queue *adminq = &lif->adminqcq->q;
+	struct ionic_admin_cmd *q_desc_base = adminq->base;
+	struct ionic_admin_cmd *q_desc;
+	int err = 0;
+
+	rte_spinlock_lock(&lif->adminq_lock);
+
+	if (!ionic_q_has_space(adminq, 1)) {
+		err = -ENOSPC;
+		goto err_out;
+	}
+
+	q_desc = &q_desc_base[adminq->head_idx];
+
+	memcpy(q_desc, &ctx->cmd, sizeof(ctx->cmd));
+
+	ionic_q_post(adminq, true, ionic_adminq_cb, ctx);
+
+err_out:
+	rte_spinlock_unlock(&lif->adminq_lock);
+
+	return err;
+}
diff --git a/drivers/net/ionic/ionic_dev.h b/drivers/net/ionic/ionic_dev.h
index 812d800d9..ada07edff 100644
--- a/drivers/net/ionic/ionic_dev.h
+++ b/drivers/net/ionic/ionic_dev.h
@@ -20,6 +20,9 @@
  */
 #define IONIC_API_VERSION		"3"
 
+#define IONIC_MAX_RING_DESC		32768
+#define IONIC_MIN_RING_DESC		16
+
 #define IONIC_LIFS_MAX			1024
 
 #define IONIC_DEVCMD_TIMEOUT	30 /* devcmd_timeout */
@@ -132,6 +135,44 @@ struct ionic_dev {
 	uint32_t port_info_sz;
 };
 
+struct ionic_queue;
+struct ionic_desc_info;
+
+typedef void (*desc_cb)(struct ionic_queue *q,
+			uint32_t q_desc_index,
+			uint32_t cq_desc_index,
+			void *cb_arg, void *service_cb_arg);
+
+struct ionic_desc_info {
+	desc_cb cb;
+	void *cb_arg;
+};
+
+struct ionic_queue {
+	struct ionic_dev *idev;
+	struct ionic_lif *lif;
+	struct ionic_cq *bound_cq;
+	uint32_t index;
+	uint32_t type;
+	uint32_t hw_index;
+	uint32_t hw_type;
+	void *base;
+	void *sg_base;
+	rte_iova_t base_pa;
+	rte_iova_t sg_base_pa;
+	struct ionic_desc_info *info;
+	uint32_t tail_idx;
+	uint32_t head_idx;
+	uint32_t num_descs;
+	uint32_t desc_size;
+	uint32_t sg_desc_size;
+	uint32_t pid;
+	uint32_t qid;
+	uint32_t qtype;
+	struct ionic_doorbell __iomem *db;
+	void *nop_desc;
+};
+
 #define IONIC_INTR_INDEX_NOT_ASSIGNED	(-1)
 #define IONIC_INTR_NAME_MAX_SZ		(32)
 
@@ -140,11 +181,34 @@ struct ionic_intr_info {
 	int index;
 	uint32_t vector;
 	struct ionic_intr __iomem *ctrl;
-	uint64_t rearm_count;
+};
+
+struct ionic_cq {
+	struct ionic_lif *lif;
+	struct ionic_queue *bound_q;
+	uint32_t tail_idx;
+	uint32_t num_descs;
+	uint32_t desc_size;
+	bool done_color;
+	void *base;
+	rte_iova_t base_pa;
+	struct ionic_intr_info *bound_intr;
+};
+
+/** ionic_admin_ctx - Admin command context.
+ * @pending_work:	Flag that indicates a completion.
+ * @cmd:		Admin command (64B) to be copied to the queue.
+ * @comp:		Admin completion (16B) copied from the queue.
+ */
+struct ionic_admin_ctx {
+	bool pending_work;
+	union ionic_adminq_cmd cmd;
+	union ionic_adminq_comp comp;
 };
 
 struct ionic_lif;
 struct ionic_adapter;
+struct ionic_qcq;
 
 void ionic_intr_init(struct ionic_dev *idev, struct ionic_intr_info *intr,
 		unsigned long index);
@@ -177,7 +241,37 @@ void ionic_dev_cmd_lif_identify(struct ionic_dev *idev, uint8_t type,
 void ionic_dev_cmd_lif_init(struct ionic_dev *idev, uint16_t lif_index,
 		rte_iova_t addr);
 void ionic_dev_cmd_lif_reset(struct ionic_dev *idev, uint16_t lif_index);
+void ionic_dev_cmd_adminq_init(struct ionic_dev *idev, struct ionic_qcq *qcq,
+		uint16_t lif_index, uint16_t intr_index);
 
+struct ionic_doorbell __iomem *ionic_db_map(struct ionic_lif *lif,
+		struct ionic_queue *q);
 int ionic_db_page_num(struct ionic_lif *lif, int pid);
 
+int ionic_cq_init(struct ionic_lif *lif, struct ionic_cq *cq,
+		struct ionic_intr_info *intr, uint32_t num_descs,
+		size_t desc_size);
+void ionic_cq_map(struct ionic_cq *cq, void *base, rte_iova_t base_pa);
+void ionic_cq_bind(struct ionic_cq *cq, struct ionic_queue *q);
+typedef bool (*ionic_cq_cb)(struct ionic_cq *cq, uint32_t cq_desc_index,
+		void *cb_arg);
+uint32_t ionic_cq_service(struct ionic_cq *cq, uint32_t work_to_do,
+		ionic_cq_cb cb, void *cb_arg);
+
+int ionic_q_init(struct ionic_lif *lif, struct ionic_dev *idev,
+		struct ionic_queue *q,
+		uint32_t index, const char *base, uint32_t num_descs,
+		size_t desc_size, size_t sg_desc_size, uint32_t pid);
+void ionic_q_map(struct ionic_queue *q, void *base, rte_iova_t base_pa);
+void ionic_q_sg_map(struct ionic_queue *q, void *base, rte_iova_t base_pa);
+void ionic_q_flush(struct ionic_queue *q);
+void ionic_q_post(struct ionic_queue *q, bool ring_doorbell, desc_cb cb,
+		void *cb_arg);
+uint32_t ionic_q_space_avail(struct ionic_queue *q);
+bool ionic_q_has_space(struct ionic_queue *q, uint32_t want);
+void ionic_q_service(struct ionic_queue *q, uint32_t cq_desc_index,
+		uint32_t stop_index, void *service_cb_arg);
+
+int ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx);
+
 #endif /* _IONIC_DEV_H_ */
diff --git a/drivers/net/ionic/ionic_lif.c b/drivers/net/ionic/ionic_lif.c
index c36bb6bc3..f2ede6d23 100644
--- a/drivers/net/ionic/ionic_lif.c
+++ b/drivers/net/ionic/ionic_lif.c
@@ -10,6 +10,259 @@
 #include "ionic_lif.h"
 #include "ionic_ethdev.h"
 
+int
+ionic_qcq_enable(struct ionic_qcq *qcq)
+{
+	struct ionic_queue *q = &qcq->q;
+	struct ionic_lif *lif = q->lif;
+	struct ionic_dev *idev = &lif->adapter->idev;
+	struct ionic_admin_ctx ctx = {
+		.pending_work = true,
+		.cmd.q_control = {
+			.opcode = IONIC_CMD_Q_CONTROL,
+			.lif_index = lif->index,
+			.type = q->type,
+			.index = q->index,
+			.oper = IONIC_Q_ENABLE,
+		},
+	};
+
+	if (qcq->flags & IONIC_QCQ_F_INTR) {
+		ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
+				IONIC_INTR_MASK_CLEAR);
+	}
+
+	return ionic_adminq_post_wait(lif, &ctx);
+}
+
+int
+ionic_qcq_disable(struct ionic_qcq *qcq)
+{
+	struct ionic_queue *q = &qcq->q;
+	struct ionic_lif *lif = q->lif;
+	struct ionic_dev *idev = &lif->adapter->idev;
+	struct ionic_admin_ctx ctx = {
+		.pending_work = true,
+		.cmd.q_control = {
+			.opcode = IONIC_CMD_Q_CONTROL,
+			.lif_index = lif->index,
+			.type = q->type,
+			.index = q->index,
+			.oper = IONIC_Q_DISABLE,
+		},
+	};
+
+	if (qcq->flags & IONIC_QCQ_F_INTR) {
+		ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
+				IONIC_INTR_MASK_SET);
+	}
+
+	return ionic_adminq_post_wait(lif, &ctx);
+}
+
+int
+ionic_intr_alloc(struct ionic_lif *lif, struct ionic_intr_info *intr)
+{
+	struct ionic_adapter *adapter = lif->adapter;
+	struct ionic_dev *idev = &adapter->idev;
+	unsigned long index;
+
+	/*
+	 * Note: interrupt handler is called for index = 0 only
+	 * (we use interrupts for the notifyq only anyway,
+	 * which hash index = 0)
+	 */
+
+	for (index = 0; index < adapter->nintrs; index++)
+		if (!adapter->intrs[index])
+			break;
+
+	if (index == adapter->nintrs)
+		return -ENOSPC;
+
+	adapter->intrs[index] = true;
+
+	ionic_intr_init(idev, intr, index);
+
+	return 0;
+}
+
+void
+ionic_intr_free(struct ionic_lif *lif, struct ionic_intr_info *intr)
+{
+	if (intr->index != IONIC_INTR_INDEX_NOT_ASSIGNED)
+		lif->adapter->intrs[intr->index] = false;
+}
+
+static int
+ionic_qcq_alloc(struct ionic_lif *lif, uint8_t type,
+		uint32_t index,
+		const char *base, uint32_t flags,
+		uint32_t num_descs,
+		uint32_t desc_size,
+		uint32_t cq_desc_size,
+		uint32_t sg_desc_size,
+		uint32_t pid, struct ionic_qcq **qcq)
+{
+	struct ionic_dev *idev = &lif->adapter->idev;
+	struct ionic_qcq *new;
+	uint32_t q_size, cq_size, sg_size, total_size;
+	void *q_base, *cq_base, *sg_base;
+	rte_iova_t q_base_pa = 0;
+	rte_iova_t cq_base_pa = 0;
+	rte_iova_t sg_base_pa = 0;
+	uint32_t socket_id = rte_socket_id();
+	int err;
+
+	*qcq = NULL;
+
+	q_size  = num_descs * desc_size;
+	cq_size = num_descs * cq_desc_size;
+	sg_size = num_descs * sg_desc_size;
+
+	total_size = RTE_ALIGN(q_size, PAGE_SIZE) +
+			RTE_ALIGN(cq_size, PAGE_SIZE);
+	/*
+	 * Note: aligning q_size/cq_size is not enough due to cq_base address
+	 * aligning as q_base could be not aligned to the page.
+	 * Adding PAGE_SIZE.
+	 */
+	total_size += PAGE_SIZE;
+
+	if (flags & IONIC_QCQ_F_SG) {
+		total_size += RTE_ALIGN(sg_size, PAGE_SIZE);
+		total_size += PAGE_SIZE;
+	}
+
+	new = rte_zmalloc("ionic", sizeof(*new), 0);
+
+	if (!new) {
+		ionic_init_print(ERR, "Cannot allocate queue structure");
+		return -ENOMEM;
+	}
+
+	new->lif = lif;
+	new->flags = flags;
+
+	new->q.info = rte_zmalloc("ionic", sizeof(*new->q.info) * num_descs, 0);
+
+	if (!new->q.info) {
+		ionic_init_print(ERR, "Cannot allocate queue info");
+		return -ENOMEM;
+	}
+
+	new->q.type = type;
+
+	err = ionic_q_init(lif, idev, &new->q, index, base, num_descs,
+			desc_size, sg_desc_size, pid);
+
+	if (err) {
+		ionic_init_print(ERR, "Queue initialization failed");
+		return err;
+	}
+
+	if (flags & IONIC_QCQ_F_INTR) {
+		err = ionic_intr_alloc(lif, &new->intr);
+		if (err)
+			return err;
+
+		ionic_intr_mask_assert(idev->intr_ctrl, new->intr.index,
+				IONIC_INTR_MASK_SET);
+	} else {
+		new->intr.index = IONIC_INTR_INDEX_NOT_ASSIGNED;
+	}
+
+	err = ionic_cq_init(lif, &new->cq, &new->intr,
+			num_descs, cq_desc_size);
+	if (err) {
+		ionic_init_print(ERR, "Completion queue initialization failed");
+		goto err_out_free_intr;
+	}
+
+	new->base_z = rte_eth_dma_zone_reserve(lif->eth_dev,
+			base /* name */, index /* queue_idx */,
+			total_size, IONIC_ALIGN, socket_id);
+
+	if (!new->base_z) {
+		ionic_init_print(ERR, "Cannot reserve queue DMA memory");
+		err = -ENOMEM;
+		goto err_out_free_intr;
+	}
+
+	new->base = new->base_z->addr;
+	new->base_pa = new->base_z->iova;
+	new->total_size = total_size;
+
+	q_base = new->base;
+	q_base_pa = new->base_pa;
+
+	cq_base = (void *)RTE_ALIGN((uintptr_t)q_base + q_size, PAGE_SIZE);
+	cq_base_pa = RTE_ALIGN(q_base_pa + q_size, PAGE_SIZE);
+
+	if (flags & IONIC_QCQ_F_SG) {
+		sg_base = (void *)RTE_ALIGN((uintptr_t)cq_base + cq_size,
+				PAGE_SIZE);
+		sg_base_pa = RTE_ALIGN(cq_base_pa + cq_size, PAGE_SIZE);
+		ionic_q_sg_map(&new->q, sg_base, sg_base_pa);
+	}
+
+	ionic_init_print(DEBUG, "Q-Base-PA = %ju CQ-Base-PA = %ju "
+			"SG-base-PA = %ju",
+			q_base_pa, cq_base_pa, sg_base_pa);
+
+	ionic_q_map(&new->q, q_base, q_base_pa);
+	ionic_cq_map(&new->cq, cq_base, cq_base_pa);
+	ionic_cq_bind(&new->cq, &new->q);
+
+	*qcq = new;
+
+	return 0;
+
+err_out_free_intr:
+	if (flags & IONIC_QCQ_F_INTR)
+		ionic_intr_free(lif, &new->intr);
+
+	return err;
+}
+
+void
+ionic_qcq_free(struct ionic_qcq *qcq)
+{
+	if (qcq->base_z) {
+		qcq->base = NULL;
+		qcq->base_pa = 0;
+		rte_memzone_free(qcq->base_z);
+		qcq->base_z = NULL;
+	}
+
+	if (qcq->q.info) {
+		rte_free(qcq->q.info);
+		qcq->q.info = NULL;
+	}
+
+	rte_free(qcq);
+}
+
+static int
+ionic_admin_qcq_alloc(struct ionic_lif *lif)
+{
+	uint32_t flags;
+	int err = -ENOMEM;
+
+	flags = 0;
+	err = ionic_qcq_alloc(lif, IONIC_QTYPE_ADMINQ, 0, "admin", flags,
+			IONIC_ADMINQ_LENGTH,
+			sizeof(struct ionic_admin_cmd),
+			sizeof(struct ionic_admin_comp),
+			0,
+			lif->kern_pid, &lif->adminqcq);
+
+	if (err)
+		return err;
+
+	return 0;
+}
+
 static void *
 ionic_bus_map_dbpage(struct ionic_adapter *adapter, int page_num)
 {
@@ -27,10 +280,12 @@ ionic_lif_alloc(struct ionic_lif *lif)
 	struct ionic_adapter *adapter = lif->adapter;
 	uint32_t socket_id = rte_socket_id();
 	int dbpage_num;
+	int err;
 
 	snprintf(lif->name, sizeof(lif->name), "lif%u", lif->index);
 
-	ionic_init_print(DEBUG, "Allocating Lif Info");
+	rte_spinlock_init(&lif->adminq_lock);
+	rte_spinlock_init(&lif->adminq_service_lock);
 
 	lif->kern_pid = 0;
 
@@ -43,6 +298,17 @@ ionic_lif_alloc(struct ionic_lif *lif)
 		return -ENOMEM;
 	}
 
+	ionic_init_print(DEBUG, "Allocating Admin Queue");
+
+	err = ionic_admin_qcq_alloc(lif);
+
+	if (err) {
+		ionic_init_print(ERR, "Cannot allocate admin queue");
+		return err;
+	}
+
+	ionic_init_print(DEBUG, "Allocating Lif Info");
+
 	lif->info_sz = RTE_ALIGN(sizeof(*lif->info), PAGE_SIZE);
 
 	lif->info_z = rte_eth_dma_zone_reserve(lif->eth_dev,
@@ -63,10 +329,91 @@ ionic_lif_alloc(struct ionic_lif *lif)
 void
 ionic_lif_free(struct ionic_lif *lif)
 {
+	if (lif->adminqcq) {
+		ionic_qcq_free(lif->adminqcq);
+		lif->adminqcq = NULL;
+	}
+
 	if (lif->info)
 		rte_memzone_free(lif->info_z);
 }
 
+static void
+ionic_lif_qcq_deinit(struct ionic_lif *lif, struct ionic_qcq *qcq)
+{
+	struct ionic_dev *idev = &lif->adapter->idev;
+
+	if (!(qcq->flags & IONIC_QCQ_F_INITED))
+		return;
+
+	if (qcq->flags & IONIC_QCQ_F_INTR)
+		ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
+				IONIC_INTR_MASK_SET);
+
+	qcq->flags &= ~IONIC_QCQ_F_INITED;
+}
+
+bool
+ionic_adminq_service(struct ionic_cq *cq, uint32_t cq_desc_index,
+		void *cb_arg __rte_unused)
+{
+	struct ionic_admin_comp *cq_desc_base = cq->base;
+	struct ionic_admin_comp *cq_desc = &cq_desc_base[cq_desc_index];
+
+	if (!color_match(cq_desc->color, cq->done_color))
+		return false;
+
+	ionic_q_service(cq->bound_q, cq_desc_index, cq_desc->comp_index, NULL);
+
+	return true;
+}
+
+/* This acts like ionic_napi */
+int
+ionic_qcq_service(struct ionic_qcq *qcq, int budget, ionic_cq_cb cb,
+		void *cb_arg)
+{
+	struct ionic_cq *cq = &qcq->cq;
+	uint32_t work_done;
+
+	work_done = ionic_cq_service(cq, budget, cb, cb_arg);
+
+	return work_done;
+}
+
+static int
+ionic_lif_adminq_init(struct ionic_lif *lif)
+{
+	struct ionic_dev *idev = &lif->adapter->idev;
+	struct ionic_qcq *qcq = lif->adminqcq;
+	struct ionic_queue *q = &qcq->q;
+	struct ionic_q_init_comp comp;
+	int err;
+
+	ionic_dev_cmd_adminq_init(idev, qcq, lif->index, qcq->intr.index);
+	err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
+	if (err)
+		return err;
+
+	ionic_dev_cmd_comp(idev, &comp);
+
+	q->hw_type = comp.hw_type;
+	q->hw_index = comp.hw_index;
+	q->db = ionic_db_map(lif, q);
+
+	ionic_init_print(DEBUG, "adminq->hw_type %d\n", q->hw_type);
+	ionic_init_print(DEBUG, "adminq->hw_index %d\n", q->hw_index);
+	ionic_init_print(DEBUG, "adminq->db %p\n", q->db);
+
+	if (qcq->flags & IONIC_QCQ_F_INTR)
+		ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
+				IONIC_INTR_MASK_CLEAR);
+
+	qcq->flags |= IONIC_QCQ_F_INITED;
+
+	return 0;
+}
+
 int
 ionic_lif_init(struct ionic_lif *lif)
 {
@@ -82,6 +429,11 @@ ionic_lif_init(struct ionic_lif *lif)
 
 	lif->hw_index = comp.hw_index;
 
+	err = ionic_lif_adminq_init(lif);
+
+	if (err)
+		return err;
+
 	lif->state |= IONIC_LIF_F_INITED;
 
 	return 0;
@@ -93,6 +445,8 @@ ionic_lif_deinit(struct ionic_lif *lif)
 	if (!(lif->state & IONIC_LIF_F_INITED))
 		return;
 
+	ionic_lif_qcq_deinit(lif, lif->adminqcq);
+
 	lif->state &= ~IONIC_LIF_F_INITED;
 }
 
diff --git a/drivers/net/ionic/ionic_lif.h b/drivers/net/ionic/ionic_lif.h
index 6b912efa0..cedd8a721 100644
--- a/drivers/net/ionic/ionic_lif.h
+++ b/drivers/net/ionic/ionic_lif.h
@@ -13,6 +13,26 @@
 #include "ionic_osdep.h"
 #include "ionic_dev.h"
 
+#define IONIC_ADMINQ_LENGTH	16	/* must be a power of two */
+
+#define IONIC_QCQ_F_INITED	BIT(0)
+#define IONIC_QCQ_F_SG		BIT(1)
+#define IONIC_QCQ_F_INTR	BIT(2)
+
+/* Queue / Completion Queue */
+struct ionic_qcq {
+	struct ionic_queue q;        /**< Queue */
+	struct ionic_cq cq;          /**< Completion Queue */
+	struct ionic_lif *lif;       /**< LIF */
+	struct rte_mempool *mb_pool; /**< mbuf pool to populate the RX ring */
+	const struct rte_memzone *base_z;
+	void *base;
+	rte_iova_t base_pa;
+	uint32_t total_size;
+	uint32_t flags;
+	struct ionic_intr_info intr;
+};
+
 #define IONIC_LIF_F_INITED		BIT(0)
 
 #define IONIC_LIF_NAME_MAX_SZ		(32)
@@ -25,6 +45,9 @@ struct ionic_lif {
 	uint32_t hw_index;
 	uint32_t state;
 	uint32_t kern_pid;
+	rte_spinlock_t adminq_lock;
+	rte_spinlock_t adminq_service_lock;
+	struct ionic_qcq *adminqcq;
 	struct ionic_doorbell __iomem *kern_dbpage;
 	char name[IONIC_LIF_NAME_MAX_SZ];
 	uint32_t info_sz;
@@ -48,4 +71,17 @@ int ionic_lif_stop(struct ionic_lif *lif);
 int ionic_lif_configure(struct ionic_lif *lif);
 void ionic_lif_reset(struct ionic_lif *lif);
 
+int ionic_intr_alloc(struct ionic_lif *lif, struct ionic_intr_info *intr);
+void ionic_intr_free(struct ionic_lif *lif, struct ionic_intr_info *intr);
+
+bool ionic_adminq_service(struct ionic_cq *cq, uint32_t cq_desc_index,
+		void *cb_arg);
+int ionic_qcq_service(struct ionic_qcq *qcq, int budget, ionic_cq_cb cb,
+		void *cb_arg);
+
+void ionic_qcq_free(struct ionic_qcq *qcq);
+
+int ionic_qcq_enable(struct ionic_qcq *qcq);
+int ionic_qcq_disable(struct ionic_qcq *qcq);
+
 #endif /* _IONIC_LIF_H_ */
diff --git a/drivers/net/ionic/ionic_main.c b/drivers/net/ionic/ionic_main.c
index 0feb713a9..45a6dc26c 100644
--- a/drivers/net/ionic/ionic_main.c
+++ b/drivers/net/ionic/ionic_main.c
@@ -5,6 +5,194 @@
 #include <rte_memzone.h>
 
 #include "ionic.h"
+#include "ionic_ethdev.h"
+#include "ionic_lif.h"
+
+static const char *
+ionic_error_to_str(enum ionic_status_code code)
+{
+	switch (code) {
+	case IONIC_RC_SUCCESS:
+		return "IONIC_RC_SUCCESS";
+	case IONIC_RC_EVERSION:
+		return "IONIC_RC_EVERSION";
+	case IONIC_RC_EOPCODE:
+		return "IONIC_RC_EOPCODE";
+	case IONIC_RC_EIO:
+		return "IONIC_RC_EIO";
+	case IONIC_RC_EPERM:
+		return "IONIC_RC_EPERM";
+	case IONIC_RC_EQID:
+		return "IONIC_RC_EQID";
+	case IONIC_RC_EQTYPE:
+		return "IONIC_RC_EQTYPE";
+	case IONIC_RC_ENOENT:
+		return "IONIC_RC_ENOENT";
+	case IONIC_RC_EINTR:
+		return "IONIC_RC_EINTR";
+	case IONIC_RC_EAGAIN:
+		return "IONIC_RC_EAGAIN";
+	case IONIC_RC_ENOMEM:
+		return "IONIC_RC_ENOMEM";
+	case IONIC_RC_EFAULT:
+		return "IONIC_RC_EFAULT";
+	case IONIC_RC_EBUSY:
+		return "IONIC_RC_EBUSY";
+	case IONIC_RC_EEXIST:
+		return "IONIC_RC_EEXIST";
+	case IONIC_RC_EINVAL:
+		return "IONIC_RC_EINVAL";
+	case IONIC_RC_ENOSPC:
+		return "IONIC_RC_ENOSPC";
+	case IONIC_RC_ERANGE:
+		return "IONIC_RC_ERANGE";
+	case IONIC_RC_BAD_ADDR:
+		return "IONIC_RC_BAD_ADDR";
+	case IONIC_RC_DEV_CMD:
+		return "IONIC_RC_DEV_CMD";
+	case IONIC_RC_ERROR:
+		return "IONIC_RC_ERROR";
+	case IONIC_RC_ERDMA:
+		return "IONIC_RC_ERDMA";
+	default:
+		return "IONIC_RC_UNKNOWN";
+	}
+}
+
+static const char *
+ionic_opcode_to_str(enum ionic_cmd_opcode opcode)
+{
+	switch (opcode) {
+	case IONIC_CMD_NOP:
+		return "IONIC_CMD_NOP";
+	case IONIC_CMD_INIT:
+		return "IONIC_CMD_INIT";
+	case IONIC_CMD_RESET:
+		return "IONIC_CMD_RESET";
+	case IONIC_CMD_IDENTIFY:
+		return "IONIC_CMD_IDENTIFY";
+	case IONIC_CMD_GETATTR:
+		return "IONIC_CMD_GETATTR";
+	case IONIC_CMD_SETATTR:
+		return "IONIC_CMD_SETATTR";
+	case IONIC_CMD_PORT_IDENTIFY:
+		return "IONIC_CMD_PORT_IDENTIFY";
+	case IONIC_CMD_PORT_INIT:
+		return "IONIC_CMD_PORT_INIT";
+	case IONIC_CMD_PORT_RESET:
+		return "IONIC_CMD_PORT_RESET";
+	case IONIC_CMD_PORT_GETATTR:
+		return "IONIC_CMD_PORT_GETATTR";
+	case IONIC_CMD_PORT_SETATTR:
+		return "IONIC_CMD_PORT_SETATTR";
+	case IONIC_CMD_LIF_INIT:
+		return "IONIC_CMD_LIF_INIT";
+	case IONIC_CMD_LIF_RESET:
+		return "IONIC_CMD_LIF_RESET";
+	case IONIC_CMD_LIF_IDENTIFY:
+		return "IONIC_CMD_LIF_IDENTIFY";
+	case IONIC_CMD_LIF_SETATTR:
+		return "IONIC_CMD_LIF_SETATTR";
+	case IONIC_CMD_LIF_GETATTR:
+		return "IONIC_CMD_LIF_GETATTR";
+	case IONIC_CMD_RX_MODE_SET:
+		return "IONIC_CMD_RX_MODE_SET";
+	case IONIC_CMD_RX_FILTER_ADD:
+		return "IONIC_CMD_RX_FILTER_ADD";
+	case IONIC_CMD_RX_FILTER_DEL:
+		return "IONIC_CMD_RX_FILTER_DEL";
+	case IONIC_CMD_Q_INIT:
+		return "IONIC_CMD_Q_INIT";
+	case IONIC_CMD_Q_CONTROL:
+		return "IONIC_CMD_Q_CONTROL";
+	case IONIC_CMD_RDMA_RESET_LIF:
+		return "IONIC_CMD_RDMA_RESET_LIF";
+	case IONIC_CMD_RDMA_CREATE_EQ:
+		return "IONIC_CMD_RDMA_CREATE_EQ";
+	case IONIC_CMD_RDMA_CREATE_CQ:
+		return "IONIC_CMD_RDMA_CREATE_CQ";
+	case IONIC_CMD_RDMA_CREATE_ADMINQ:
+		return "IONIC_CMD_RDMA_CREATE_ADMINQ";
+	default:
+		return "DEVCMD_UNKNOWN";
+	}
+}
+
+int
+ionic_adminq_check_err(struct ionic_lif *lif, struct ionic_admin_ctx *ctx,
+		bool timeout)
+{
+	const char *name;
+	const char *status;
+
+	if (ctx->comp.comp.status || timeout) {
+		name = ionic_opcode_to_str(ctx->cmd.cmd.opcode);
+		status = ionic_error_to_str(ctx->comp.comp.status);
+		ionic_init_print(ERR, "%s (%d) failed: %s (%d)\n",
+				name,
+				ctx->cmd.cmd.opcode,
+				timeout ? "TIMEOUT" : status,
+				timeout ? -1 : ctx->comp.comp.status);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int
+ionic_wait_ctx_for_completion(struct ionic_lif *lif, struct ionic_qcq *qcq,
+		struct ionic_admin_ctx *ctx, unsigned long max_wait)
+{
+	unsigned long step_msec = 1;
+	unsigned int max_wait_msec = max_wait * 1000;
+	unsigned long elapsed_msec = 0;
+	int budget = 8;
+
+	while (ctx->pending_work && elapsed_msec < max_wait_msec) {
+		/*
+		 * Locking here as adminq is served inline (this could be called
+		 * from multiple places)
+		 */
+		rte_spinlock_lock(&lif->adminq_service_lock);
+
+		ionic_qcq_service(qcq, budget, ionic_adminq_service, NULL);
+
+		rte_spinlock_unlock(&lif->adminq_service_lock);
+
+		msec_delay(step_msec);
+		elapsed_msec += step_msec;
+	}
+
+	return (!ctx->pending_work);
+}
+
+int
+ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
+{
+	struct ionic_qcq *qcq = lif->adminqcq;
+	bool done;
+	int err;
+
+	ionic_init_print(DEBUG, "Sending %s to the admin queue",
+		ionic_opcode_to_str(ctx->cmd.cmd.opcode));
+
+	err = ionic_adminq_post(lif, ctx);
+
+	if (err) {
+		ionic_init_print(ERR, "Failure posting to the admin queue %d "
+				"(%d)\n",
+				ctx->cmd.cmd.opcode, err);
+
+		return err;
+	}
+
+	done = ionic_wait_ctx_for_completion(lif, qcq, ctx,
+			IONIC_DEVCMD_TIMEOUT);
+
+	err = ionic_adminq_check_err(lif, ctx, !done /* timed out */);
+
+	return err;
+}
 
 static int
 ionic_dev_cmd_wait(struct ionic_dev *idev, unsigned long max_wait)


  parent reply	other threads:[~2019-10-12  0:27 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-10-12  0:26 [dpdk-dev] [PATCH 00/17] Series short description Alfredo Cardigliano
2019-10-12  0:26 ` [dpdk-dev] [PATCH 01/17] net/ionic: add skeleton Alfredo Cardigliano
2019-10-12  0:26 ` [dpdk-dev] [PATCH 02/17] net/ionic: add hardware structures definitions Alfredo Cardigliano
2019-10-12  0:26 ` [dpdk-dev] [PATCH 03/17] net/ionic: add log Alfredo Cardigliano
2019-10-12 15:23   ` Stephen Hemminger
2019-10-12  0:26 ` [dpdk-dev] [PATCH 04/17] net/ionic: register and initialize the adapter Alfredo Cardigliano
2019-10-12  0:26 ` [dpdk-dev] [PATCH 05/17] net/ionic: add port management commands Alfredo Cardigliano
2019-10-12  0:26 ` [dpdk-dev] [PATCH 06/17] net/ionic: add basic lif support Alfredo Cardigliano
2019-10-12 15:26   ` Stephen Hemminger
2019-10-12  0:27 ` [dpdk-dev] [PATCH 07/17] net/ionic: add doorbells Alfredo Cardigliano
2019-10-12  0:27 ` Alfredo Cardigliano [this message]
2019-10-12  0:27 ` [dpdk-dev] [PATCH 09/17] net/ionic: add notifyq support Alfredo Cardigliano
2019-10-12  0:27 ` [dpdk-dev] [PATCH 10/17] net/ionic: add basic port operations Alfredo Cardigliano
2019-10-12  0:27 ` [dpdk-dev] [PATCH 11/17] net/ionic: add RX filters support Alfredo Cardigliano
2019-10-12  0:27 ` [dpdk-dev] [PATCH 12/17] net/ionic: net-ionic-add-flow-control-support Alfredo Cardigliano
2019-10-12  0:27 ` [dpdk-dev] [PATCH 13/17] net/ionic: add RSS support Alfredo Cardigliano
2019-10-12  0:27 ` [dpdk-dev] [PATCH 14/17] net/ionic: add RX and TX handling Alfredo Cardigliano
2019-10-12  0:27 ` [dpdk-dev] [PATCH 15/17] net/ionic: add stats Alfredo Cardigliano
2019-10-12  0:27 ` [dpdk-dev] [PATCH 16/17] net/ionic: add TX checksum support Alfredo Cardigliano
2019-10-12  0:27 ` [dpdk-dev] [PATCH 17/17] net/ionic: read fw version Alfredo Cardigliano
2019-10-12 15:28 ` [dpdk-dev] [PATCH 00/17] Series short description Stephen Hemminger
2019-10-14  7:16   ` Alfredo Cardigliano
2019-10-14  7:56     ` Andrew Rybchenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=157084002711.11524.9195394378752943090.stgit@devele \
    --to=cardigliano@ntop.org \
    --cc=dev@dpdk.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.