@@ -22,6 +22,10 @@
/* Devargs */
/* NONE */
+#define IOCPT_MAX_RING_DESC 32768
+#define IOCPT_MIN_RING_DESC 16
+#define IOCPT_ADMINQ_LENGTH 16 /* must be a power of two */
+
extern int iocpt_logtype;
#define RTE_LOGTYPE_IOCPT iocpt_logtype
@@ -91,6 +95,63 @@ struct iocpt_qtype_info {
uint16_t sg_desc_stride;
};
+#define IOCPT_Q_F_INITED BIT(0)
+#define IOCPT_Q_F_DEFERRED BIT(1)
+#define IOCPT_Q_F_SG BIT(2)
+
+#define Q_NEXT_TO_POST(_q, _n) (((_q)->head_idx + (_n)) & ((_q)->size_mask))
+#define Q_NEXT_TO_SRVC(_q, _n) (((_q)->tail_idx + (_n)) & ((_q)->size_mask))
+
+#define IOCPT_INFO_SZ(_q) ((_q)->num_segs * sizeof(void *))
+#define IOCPT_INFO_IDX(_q, _i) ((_i) * (_q)->num_segs)
+#define IOCPT_INFO_PTR(_q, _i) (&(_q)->info[IOCPT_INFO_IDX((_q), _i)])
+
+struct iocpt_queue {
+ uint16_t num_descs;
+ uint16_t num_segs;
+ uint16_t head_idx;
+ uint16_t tail_idx;
+ uint16_t size_mask;
+ uint8_t type;
+ uint8_t hw_type;
+ void *base;
+ void *sg_base;
+ struct ionic_doorbell __iomem *db;
+ void **info;
+
+ uint32_t index;
+ uint32_t hw_index;
+ rte_iova_t base_pa;
+ rte_iova_t sg_base_pa;
+};
+
+struct iocpt_cq {
+ uint16_t tail_idx;
+ uint16_t num_descs;
+ uint16_t size_mask;
+ bool done_color;
+ void *base;
+ rte_iova_t base_pa;
+};
+
+#define IOCPT_COMMON_FIELDS \
+ struct iocpt_queue q; \
+ struct iocpt_cq cq; \
+ struct iocpt_dev *dev; \
+ const struct rte_memzone *base_z; \
+ void *base; \
+ rte_iova_t base_pa
+
+struct iocpt_common_q {
+ IOCPT_COMMON_FIELDS;
+};
+
+struct iocpt_admin_q {
+ IOCPT_COMMON_FIELDS;
+
+ uint16_t flags;
+};
+
#define IOCPT_DEV_F_INITED BIT(0)
#define IOCPT_DEV_F_UP BIT(1)
#define IOCPT_DEV_F_FW_RESET BIT(2)
@@ -118,6 +179,11 @@ struct iocpt_dev {
uint8_t driver_id;
uint8_t socket_id;
+ rte_spinlock_t adminq_lock;
+ rte_spinlock_t adminq_service_lock;
+
+ struct iocpt_admin_q *adminq;
+
uint64_t features;
uint32_t hw_features;
@@ -144,6 +210,17 @@ iocpt_setup_bars(struct iocpt_dev *dev)
return (*dev->intf->setup_bars)(dev);
}
+/** iocpt_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 iocpt_admin_ctx {
+ bool pending_work;
+ union iocpt_adminq_cmd cmd;
+ union iocpt_adminq_comp comp;
+};
+
int iocpt_probe(void *bus_dev, struct rte_device *rte_dev,
struct iocpt_dev_bars *bars, const struct iocpt_dev_intf *intf,
uint8_t driver_id, uint8_t socket_id);
@@ -154,8 +231,46 @@ void iocpt_deinit(struct iocpt_dev *dev);
int iocpt_dev_identify(struct iocpt_dev *dev);
int iocpt_dev_init(struct iocpt_dev *dev, rte_iova_t info_pa);
+int iocpt_dev_adminq_init(struct iocpt_dev *dev);
void iocpt_dev_reset(struct iocpt_dev *dev);
+int iocpt_adminq_post_wait(struct iocpt_dev *dev, struct iocpt_admin_ctx *ctx);
+
+struct ionic_doorbell __iomem *iocpt_db_map(struct iocpt_dev *dev,
+ struct iocpt_queue *q);
+
+typedef bool (*iocpt_cq_cb)(struct iocpt_cq *cq, uint16_t cq_desc_index,
+ void *cb_arg);
+uint32_t iocpt_cq_service(struct iocpt_cq *cq, uint32_t work_to_do,
+ iocpt_cq_cb cb, void *cb_arg);
+
+static inline uint16_t
+iocpt_q_space_avail(struct iocpt_queue *q)
+{
+ uint16_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;
+}
+
+static inline void
+iocpt_q_flush(struct iocpt_queue *q)
+{
+ uint64_t val = IONIC_DBELL_QID(q->hw_index) | q->head_idx;
+
+#if defined(RTE_LIBRTE_IONIC_PMD_BARRIER_ERRATA)
+ /* On some devices the standard 'dmb' barrier is insufficient */
+ asm volatile("dsb st" : : : "memory");
+ rte_write64_relaxed(rte_cpu_to_le_64(val), q->db);
+#else
+ rte_write64(rte_cpu_to_le_64(val), q->db);
+#endif
+}
+
static inline bool
iocpt_is_embedded(void)
{
@@ -16,6 +16,55 @@ static const uint8_t iocpt_qtype_vers[IOCPT_QTYPE_MAX] = {
[IOCPT_QTYPE_CRYPTOQ] = 0, /* 0 = Base version */
};
+static const char *
+iocpt_error_to_str(enum iocpt_status_code code)
+{
+ switch (code) {
+ case IOCPT_RC_SUCCESS:
+ return "IOCPT_RC_SUCCESS";
+ case IOCPT_RC_EVERSION:
+ return "IOCPT_RC_EVERSION";
+ case IOCPT_RC_EOPCODE:
+ return "IOCPT_RC_EOPCODE";
+ case IOCPT_RC_EIO:
+ return "IOCPT_RC_EIO";
+ case IOCPT_RC_EPERM:
+ return "IOCPT_RC_EPERM";
+ case IOCPT_RC_EQID:
+ return "IOCPT_RC_EQID";
+ case IOCPT_RC_EQTYPE:
+ return "IOCPT_RC_EQTYPE";
+ case IOCPT_RC_ENOENT:
+ return "IOCPT_RC_ENOENT";
+ case IOCPT_RC_EINTR:
+ return "IOCPT_RC_EINTR";
+ case IOCPT_RC_EAGAIN:
+ return "IOCPT_RC_EAGAIN";
+ case IOCPT_RC_ENOMEM:
+ return "IOCPT_RC_ENOMEM";
+ case IOCPT_RC_EFAULT:
+ return "IOCPT_RC_EFAULT";
+ case IOCPT_RC_EBUSY:
+ return "IOCPT_RC_EBUSY";
+ case IOCPT_RC_EEXIST:
+ return "IOCPT_RC_EEXIST";
+ case IOCPT_RC_EINVAL:
+ return "IOCPT_RC_EINVAL";
+ case IOCPT_RC_ENOSPC:
+ return "IOCPT_RC_ENOSPC";
+ case IOCPT_RC_ERANGE:
+ return "IOCPT_RC_ERANGE";
+ case IOCPT_RC_BAD_ADDR:
+ return "IOCPT_RC_BAD_ADDR";
+ case IOCPT_RC_DEV_CMD:
+ return "IOCPT_RC_DEV_CMD";
+ case IOCPT_RC_ERROR:
+ return "IOCPT_RC_ERROR";
+ default:
+ return "IOCPT_RC_UNKNOWN";
+ }
+}
+
static const char *
iocpt_opcode_to_str(enum iocpt_cmd_opcode opcode)
{
@@ -97,6 +146,17 @@ iocpt_dev_cmd_wait(struct iocpt_dev *dev, unsigned long max_wait)
return -ETIMEDOUT;
}
+static void
+iocpt_dev_cmd_comp(struct iocpt_dev *dev, void *mem)
+{
+ union iocpt_dev_cmd_comp *comp = mem;
+ uint32_t comp_size = RTE_DIM(comp->words);
+ uint32_t i;
+
+ for (i = 0; i < comp_size; i++)
+ comp->words[i] = ioread32(&dev->dev_cmd->comp.words[i]);
+}
+
static int
iocpt_dev_cmd_wait_check(struct iocpt_dev *dev, unsigned long max_wait)
{
@@ -175,6 +235,29 @@ iocpt_dev_cmd_queue_identify(struct iocpt_dev *dev,
iocpt_dev_cmd_go(dev, &cmd);
}
+static void
+iocpt_dev_cmd_adminq_init(struct iocpt_dev *dev)
+{
+ struct iocpt_queue *q = &dev->adminq->q;
+ struct iocpt_cq *cq = &dev->adminq->cq;
+
+ union iocpt_dev_cmd cmd = {
+ .q_init.opcode = IOCPT_CMD_Q_INIT,
+ .q_init.type = q->type,
+ .q_init.ver = dev->qtype_info[q->type].version,
+ .q_init.index = rte_cpu_to_le_32(q->index),
+ .q_init.flags = rte_cpu_to_le_16(IOCPT_QINIT_F_ENA),
+ .q_init.intr_index = rte_cpu_to_le_16(IONIC_INTR_NONE),
+ .q_init.ring_size = rte_log2_u32(q->num_descs),
+ .q_init.ring_base = rte_cpu_to_le_64(q->base_pa),
+ .q_init.cq_ring_base = rte_cpu_to_le_64(cq->base_pa),
+ };
+
+ IOCPT_PRINT(DEBUG, "adminq.q_init.ver %u", cmd.q_init.ver);
+
+ iocpt_dev_cmd_go(dev, &cmd);
+}
+
/* Dev_cmd consumers */
static void
@@ -346,3 +429,222 @@ iocpt_dev_reset(struct iocpt_dev *dev)
iocpt_dev_cmd_reset(dev);
(void)iocpt_dev_cmd_wait_check(dev, IONIC_DEVCMD_TIMEOUT);
}
+
+int
+iocpt_dev_adminq_init(struct iocpt_dev *dev)
+{
+ struct iocpt_queue *q = &dev->adminq->q;
+ struct iocpt_q_init_comp comp;
+ uint32_t retries = 5;
+ int err;
+
+retry_adminq_init:
+ iocpt_dev_cmd_adminq_init(dev);
+
+ err = iocpt_dev_cmd_wait_check(dev, IONIC_DEVCMD_TIMEOUT);
+ if (err == -EAGAIN && retries > 0) {
+ retries--;
+ rte_delay_us_block(IONIC_DEVCMD_RETRY_WAIT_US);
+ goto retry_adminq_init;
+ }
+ if (err != 0)
+ return err;
+
+ iocpt_dev_cmd_comp(dev, &comp);
+
+ q->hw_type = comp.hw_type;
+ q->hw_index = rte_le_to_cpu_32(comp.hw_index);
+ q->db = iocpt_db_map(dev, q);
+
+ IOCPT_PRINT(DEBUG, "adminq->hw_type %d", q->hw_type);
+ IOCPT_PRINT(DEBUG, "adminq->hw_index %d", q->hw_index);
+ IOCPT_PRINT(DEBUG, "adminq->db %p", q->db);
+
+ dev->adminq->flags |= IOCPT_Q_F_INITED;
+
+ return 0;
+}
+
+/* Admin_cmd interface */
+
+static bool
+iocpt_adminq_service(struct iocpt_cq *cq, uint16_t cq_desc_index,
+ void *cb_arg __rte_unused)
+{
+ struct iocpt_admin_comp *cq_desc_base = cq->base;
+ struct iocpt_admin_comp *cq_desc = &cq_desc_base[cq_desc_index];
+ struct iocpt_admin_q *adminq =
+ container_of(cq, struct iocpt_admin_q, cq);
+ struct iocpt_queue *q = &adminq->q;
+ struct iocpt_admin_ctx *ctx;
+ uint16_t curr_q_tail_idx;
+ uint16_t stop_index;
+ void **info;
+
+ if (!iocpt_color_match(cq_desc->color, cq->done_color))
+ return false;
+
+ stop_index = rte_le_to_cpu_16(cq_desc->comp_index);
+
+ do {
+ info = IOCPT_INFO_PTR(q, q->tail_idx);
+
+ ctx = info[0];
+ if (ctx != NULL) {
+ memcpy(&ctx->comp, cq_desc, sizeof(*cq_desc));
+ ctx->pending_work = false; /* done */
+ }
+
+ curr_q_tail_idx = q->tail_idx;
+ q->tail_idx = Q_NEXT_TO_SRVC(q, 1);
+ } while (curr_q_tail_idx != stop_index);
+
+ return true;
+}
+
+/** iocpt_adminq_post - Post an admin command.
+ * @dev: Handle to dev.
+ * @cmd_ctx: Api admin command context.
+ *
+ * Return: zero or negative error status.
+ */
+static int
+iocpt_adminq_post(struct iocpt_dev *dev, struct iocpt_admin_ctx *ctx)
+{
+ struct iocpt_queue *q = &dev->adminq->q;
+ struct iocpt_admin_cmd *q_desc_base = q->base;
+ struct iocpt_admin_cmd *q_desc;
+ void **info;
+ int err = 0;
+
+ rte_spinlock_lock(&dev->adminq_lock);
+
+ if (iocpt_q_space_avail(q) < 1) {
+ err = -ENOSPC;
+ goto err_out;
+ }
+
+ q_desc = &q_desc_base[q->head_idx];
+
+ memcpy(q_desc, &ctx->cmd, sizeof(ctx->cmd));
+
+ info = IOCPT_INFO_PTR(q, q->head_idx);
+ info[0] = ctx;
+
+ q->head_idx = Q_NEXT_TO_POST(q, 1);
+
+ /* Ring doorbell */
+ iocpt_q_flush(q);
+
+err_out:
+ rte_spinlock_unlock(&dev->adminq_lock);
+
+ return err;
+}
+
+static int
+iocpt_adminq_wait_for_completion(struct iocpt_dev *dev,
+ struct iocpt_admin_ctx *ctx, unsigned long max_wait)
+{
+ struct iocpt_queue *q = &dev->adminq->q;
+ unsigned long step_usec = IONIC_DEVCMD_CHECK_PERIOD_US;
+ unsigned long step_deadline;
+ unsigned long max_wait_usec = max_wait * 1000000L;
+ unsigned long elapsed_usec = 0;
+ int budget = 8;
+ uint16_t idx;
+ void **info;
+
+ step_deadline = IONIC_ADMINQ_WDOG_MS * 1000 / step_usec;
+
+ while (ctx->pending_work && elapsed_usec < max_wait_usec) {
+ /*
+ * Locking here as adminq is served inline and could be
+ * called from multiple places
+ */
+ rte_spinlock_lock(&dev->adminq_service_lock);
+
+ iocpt_cq_service(&dev->adminq->cq, budget,
+ iocpt_adminq_service, NULL);
+
+ /*
+ * Ring the doorbell again if work is pending after step_usec.
+ */
+ if (ctx->pending_work && !step_deadline) {
+ step_deadline = IONIC_ADMINQ_WDOG_MS *
+ 1000 / step_usec;
+
+ rte_spinlock_lock(&dev->adminq_lock);
+ idx = Q_NEXT_TO_POST(q, -1);
+ info = IOCPT_INFO_PTR(q, idx);
+ if (info[0] == ctx)
+ iocpt_q_flush(q);
+ rte_spinlock_unlock(&dev->adminq_lock);
+ }
+
+ rte_spinlock_unlock(&dev->adminq_service_lock);
+
+ rte_delay_us_block(step_usec);
+ elapsed_usec += step_usec;
+ step_deadline--;
+ }
+
+ return (!ctx->pending_work);
+}
+
+static int
+iocpt_adminq_check_err(struct iocpt_admin_ctx *ctx, bool timeout)
+{
+ const char *name;
+ const char *status;
+
+ name = iocpt_opcode_to_str(ctx->cmd.cmd.opcode);
+
+ if (ctx->comp.comp.status == IOCPT_RC_EAGAIN) {
+ IOCPT_PRINT(DEBUG, "%s (%d) returned EAGAIN (%d)",
+ name, ctx->cmd.cmd.opcode,
+ ctx->comp.comp.status);
+ return -EAGAIN;
+ }
+ if (ctx->comp.comp.status != 0 || timeout) {
+ status = iocpt_error_to_str(ctx->comp.comp.status);
+ IOCPT_PRINT(ERR, "%s (%d) failed: %s (%d)",
+ name,
+ ctx->cmd.cmd.opcode,
+ timeout ? "TIMEOUT" : status,
+ timeout ? -1 : ctx->comp.comp.status);
+ return -EIO;
+ }
+
+ if (ctx->cmd.cmd.opcode != IOCPT_CMD_SESS_CONTROL) {
+ IOCPT_PRINT(DEBUG, "%s (%d) succeeded",
+ name, ctx->cmd.cmd.opcode);
+ }
+
+ return 0;
+}
+
+int
+iocpt_adminq_post_wait(struct iocpt_dev *dev, struct iocpt_admin_ctx *ctx)
+{
+ bool done;
+ int err;
+
+ if (ctx->cmd.cmd.opcode != IOCPT_CMD_SESS_CONTROL) {
+ IOCPT_PRINT(DEBUG, "Sending %s (%d) via the admin queue",
+ iocpt_opcode_to_str(ctx->cmd.cmd.opcode),
+ ctx->cmd.cmd.opcode);
+ }
+
+ err = iocpt_adminq_post(dev, ctx);
+ if (err != 0) {
+ IOCPT_PRINT(ERR, "Failure posting %d to the admin queue (%d)",
+ ctx->cmd.cmd.opcode, err);
+ return err;
+ }
+
+ done = iocpt_adminq_wait_for_completion(dev, ctx,
+ IONIC_DEVCMD_TIMEOUT);
+
+ return iocpt_adminq_check_err(ctx, !done /* timed out */);
+}
@@ -10,6 +10,108 @@
#include "ionic_crypto.h"
+static int
+iocpt_cq_init(struct iocpt_cq *cq, uint16_t num_descs)
+{
+ if (!rte_is_power_of_2(num_descs) ||
+ num_descs < IOCPT_MIN_RING_DESC ||
+ num_descs > IOCPT_MAX_RING_DESC) {
+ IOCPT_PRINT(ERR, "%u descriptors (min: %u max: %u)",
+ num_descs, IOCPT_MIN_RING_DESC, IOCPT_MAX_RING_DESC);
+ return -EINVAL;
+ }
+
+ cq->num_descs = num_descs;
+ cq->size_mask = num_descs - 1;
+ cq->tail_idx = 0;
+ cq->done_color = 1;
+
+ return 0;
+}
+
+static void
+iocpt_cq_map(struct iocpt_cq *cq, void *base, rte_iova_t base_pa)
+{
+ cq->base = base;
+ cq->base_pa = base_pa;
+}
+
+uint32_t
+iocpt_cq_service(struct iocpt_cq *cq, uint32_t work_to_do,
+ iocpt_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 = Q_NEXT_TO_SRVC(cq, 1);
+ if (cq->tail_idx == 0)
+ cq->done_color = !cq->done_color;
+
+ if (++work_done == work_to_do)
+ break;
+ }
+
+ return work_done;
+}
+
+static int
+iocpt_q_init(struct iocpt_queue *q, uint8_t type, uint32_t index,
+ uint16_t num_descs, uint16_t num_segs, uint32_t socket_id)
+{
+ uint32_t ring_size;
+
+ if (!rte_is_power_of_2(num_descs))
+ return -EINVAL;
+
+ ring_size = rte_log2_u32(num_descs);
+ if (ring_size < 2 || ring_size > 16)
+ return -EINVAL;
+
+ q->type = type;
+ q->index = index;
+ q->num_descs = num_descs;
+ q->num_segs = num_segs;
+ q->size_mask = num_descs - 1;
+ q->head_idx = 0;
+ q->tail_idx = 0;
+
+ q->info = rte_calloc_socket("iocpt",
+ num_descs * num_segs, sizeof(void *),
+ rte_mem_page_size(), socket_id);
+ if (q->info == NULL) {
+ IOCPT_PRINT(ERR, "Cannot allocate queue info");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void
+iocpt_q_map(struct iocpt_queue *q, void *base, rte_iova_t base_pa)
+{
+ q->base = base;
+ q->base_pa = base_pa;
+}
+
+static void
+iocpt_q_sg_map(struct iocpt_queue *q, void *base, rte_iova_t base_pa)
+{
+ q->sg_base = base;
+ q->sg_base_pa = base_pa;
+}
+
+static void
+iocpt_q_free(struct iocpt_queue *q)
+{
+ if (q->info != NULL) {
+ rte_free(q->info);
+ q->info = NULL;
+ }
+}
+
static const struct rte_memzone *
iocpt_dma_zone_reserve(const char *type_name, uint16_t qid, size_t size,
unsigned int align, int socket_id)
@@ -33,6 +135,173 @@ iocpt_dma_zone_reserve(const char *type_name, uint16_t qid, size_t size,
RTE_MEMZONE_IOVA_CONTIG, align);
}
+static int
+iocpt_commonq_alloc(struct iocpt_dev *dev,
+ uint8_t type,
+ size_t struct_size,
+ uint32_t socket_id,
+ uint32_t index,
+ const char *type_name,
+ uint16_t flags,
+ uint16_t num_descs,
+ uint16_t num_segs,
+ uint16_t desc_size,
+ uint16_t cq_desc_size,
+ uint16_t sg_desc_size,
+ struct iocpt_common_q **comq)
+{
+ struct iocpt_common_q *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;
+ size_t page_size = rte_mem_page_size();
+ int err;
+
+ *comq = NULL;
+
+ q_size = num_descs * desc_size;
+ cq_size = num_descs * cq_desc_size;
+ sg_size = num_descs * sg_desc_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 = RTE_ALIGN(q_size, page_size) +
+ RTE_ALIGN(cq_size, page_size) + page_size;
+ if (flags & IOCPT_Q_F_SG)
+ total_size += RTE_ALIGN(sg_size, page_size) + page_size;
+
+ new = rte_zmalloc_socket("iocpt", struct_size,
+ RTE_CACHE_LINE_SIZE, socket_id);
+ if (new == NULL) {
+ IOCPT_PRINT(ERR, "Cannot allocate queue structure");
+ return -ENOMEM;
+ }
+
+ new->dev = dev;
+
+ err = iocpt_q_init(&new->q, type, index, num_descs, num_segs,
+ socket_id);
+ if (err != 0) {
+ IOCPT_PRINT(ERR, "Queue initialization failed");
+ goto err_free_q;
+ }
+
+ err = iocpt_cq_init(&new->cq, num_descs);
+ if (err != 0) {
+ IOCPT_PRINT(ERR, "Completion queue initialization failed");
+ goto err_deinit_q;
+ }
+
+ new->base_z = iocpt_dma_zone_reserve(type_name, index, total_size,
+ IONIC_ALIGN, socket_id);
+ if (new->base_z == NULL) {
+ IOCPT_PRINT(ERR, "Cannot reserve queue DMA memory");
+ err = -ENOMEM;
+ goto err_deinit_cq;
+ }
+
+ new->base = new->base_z->addr;
+ new->base_pa = new->base_z->iova;
+
+ q_base = new->base;
+ q_base_pa = new->base_pa;
+ iocpt_q_map(&new->q, q_base, q_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);
+ iocpt_cq_map(&new->cq, cq_base, cq_base_pa);
+
+ if (flags & IOCPT_Q_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);
+ iocpt_q_sg_map(&new->q, sg_base, sg_base_pa);
+ }
+
+ IOCPT_PRINT(DEBUG, "q_base_pa %#jx cq_base_pa %#jx sg_base_pa %#jx",
+ q_base_pa, cq_base_pa, sg_base_pa);
+
+ *comq = new;
+
+ return 0;
+
+err_deinit_cq:
+err_deinit_q:
+ iocpt_q_free(&new->q);
+err_free_q:
+ rte_free(new);
+ return err;
+}
+
+struct ionic_doorbell *
+iocpt_db_map(struct iocpt_dev *dev, struct iocpt_queue *q)
+{
+ return dev->db_pages + q->hw_type;
+}
+
+static int
+iocpt_adminq_alloc(struct iocpt_dev *dev)
+{
+ struct iocpt_admin_q *aq;
+ uint16_t num_descs = IOCPT_ADMINQ_LENGTH;
+ uint16_t flags = 0;
+ int err;
+
+ err = iocpt_commonq_alloc(dev,
+ IOCPT_QTYPE_ADMINQ,
+ sizeof(struct iocpt_admin_q),
+ rte_socket_id(),
+ 0,
+ "admin",
+ flags,
+ num_descs,
+ 1,
+ sizeof(struct iocpt_admin_cmd),
+ sizeof(struct iocpt_admin_comp),
+ 0,
+ (struct iocpt_common_q **)&aq);
+ if (err != 0)
+ return err;
+
+ aq->flags = flags;
+
+ dev->adminq = aq;
+
+ return 0;
+}
+
+static int
+iocpt_adminq_init(struct iocpt_dev *dev)
+{
+ return iocpt_dev_adminq_init(dev);
+}
+
+static void
+iocpt_adminq_deinit(struct iocpt_dev *dev)
+{
+ dev->adminq->flags &= ~IOCPT_Q_F_INITED;
+}
+
+static void
+iocpt_adminq_free(struct iocpt_admin_q *aq)
+{
+ if (aq->base_z != NULL) {
+ rte_memzone_free(aq->base_z);
+ aq->base_z = NULL;
+ aq->base = NULL;
+ aq->base_pa = 0;
+ }
+
+ iocpt_q_free(&aq->q);
+
+ rte_free(aq);
+}
+
static int
iocpt_alloc_objs(struct iocpt_dev *dev)
{
@@ -40,13 +309,23 @@ iocpt_alloc_objs(struct iocpt_dev *dev)
IOCPT_PRINT(DEBUG, "Crypto: %s", dev->name);
+ rte_spinlock_init(&dev->adminq_lock);
+ rte_spinlock_init(&dev->adminq_service_lock);
+
+ err = iocpt_adminq_alloc(dev);
+ if (err != 0) {
+ IOCPT_PRINT(ERR, "Cannot allocate admin queue");
+ err = -ENOMEM;
+ goto err_out;
+ }
+
dev->info_sz = RTE_ALIGN(sizeof(*dev->info), rte_mem_page_size());
dev->info_z = iocpt_dma_zone_reserve("info", 0, dev->info_sz,
IONIC_ALIGN, dev->socket_id);
if (dev->info_z == NULL) {
IOCPT_PRINT(ERR, "Cannot allocate dev info memory");
err = -ENOMEM;
- goto err_out;
+ goto err_free_adminq;
}
dev->info = dev->info_z->addr;
@@ -54,6 +333,9 @@ iocpt_alloc_objs(struct iocpt_dev *dev)
return 0;
+err_free_adminq:
+ iocpt_adminq_free(dev->adminq);
+ dev->adminq = NULL;
err_out:
return err;
}
@@ -68,6 +350,10 @@ iocpt_init(struct iocpt_dev *dev)
if (err != 0)
return err;
+ err = iocpt_adminq_init(dev);
+ if (err != 0)
+ return err;
+
dev->state |= IOCPT_DEV_F_INITED;
return 0;
@@ -87,6 +373,8 @@ iocpt_deinit(struct iocpt_dev *dev)
if (!(dev->state & IOCPT_DEV_F_INITED))
return;
+ iocpt_adminq_deinit(dev);
+
dev->state &= ~IOCPT_DEV_F_INITED;
}
@@ -95,6 +383,11 @@ iocpt_free_objs(struct iocpt_dev *dev)
{
IOCPT_PRINT_CALL();
+ if (dev->adminq != NULL) {
+ iocpt_adminq_free(dev->adminq);
+ dev->adminq = NULL;
+ }
+
if (dev->info != NULL) {
rte_memzone_free(dev->info_z);
dev->info_z = NULL;