// SPDX-License-Identifier: GPL-2.0 #include #include #include #include #include #include #include #include #include #include #include "nitrox_dev.h" #include "nitrox_common.h" #include "nitrox_req.h" #include "nitrox_csr.h" #define CRYPTO_CTX_SIZE 256 /* packet input ring alignments */ #define PKTIN_Q_ALIGN_BYTES 16 /* AQM Queue input alignments */ #define AQM_Q_ALIGN_BYTES 32 static int nitrox_cmdq_init(struct nitrox_cmdq *cmdq, int align_bytes) { struct nitrox_device *ndev = cmdq->ndev; cmdq->qsize = (ndev->qlen * cmdq->instr_size) + align_bytes; cmdq->unalign_base = dma_alloc_coherent(DEV(ndev), cmdq->qsize, &cmdq->unalign_dma, GFP_KERNEL); if (!cmdq->unalign_base) return -ENOMEM; cmdq->dma = PTR_ALIGN(cmdq->unalign_dma, align_bytes); cmdq->base = cmdq->unalign_base + (cmdq->dma - cmdq->unalign_dma); cmdq->write_idx = 0; spin_lock_init(&cmdq->cmd_qlock); spin_lock_init(&cmdq->resp_qlock); spin_lock_init(&cmdq->backlog_qlock); INIT_LIST_HEAD(&cmdq->response_head); INIT_LIST_HEAD(&cmdq->backlog_head); INIT_WORK(&cmdq->backlog_qflush, backlog_qflush_work); atomic_set(&cmdq->pending_count, 0); atomic_set(&cmdq->backlog_count, 0); return 0; } static void nitrox_cmdq_reset(struct nitrox_cmdq *cmdq) { cmdq->write_idx = 0; atomic_set(&cmdq->pending_count, 0); atomic_set(&cmdq->backlog_count, 0); } static void nitrox_cmdq_cleanup(struct nitrox_cmdq *cmdq) { struct nitrox_device *ndev; if (!cmdq) return; if (!cmdq->unalign_base) return; ndev = cmdq->ndev; cancel_work_sync(&cmdq->backlog_qflush); dma_free_coherent(DEV(ndev), cmdq->qsize, cmdq->unalign_base, cmdq->unalign_dma); nitrox_cmdq_reset(cmdq); cmdq->dbell_csr_addr = NULL; cmdq->compl_cnt_csr_addr = NULL; cmdq->unalign_base = NULL; cmdq->base = NULL; cmdq->unalign_dma = 0; cmdq->dma = 0; cmdq->qsize = 0; cmdq->instr_size = 0; } static void nitrox_free_aqm_queues(struct nitrox_device *ndev) { int i; for (i = 0; i < ndev->nr_queues; i++) { nitrox_cmdq_cleanup(ndev->aqmq[i]); kfree_sensitive(ndev->aqmq[i]); ndev->aqmq[i] = NULL; } } static int nitrox_alloc_aqm_queues(struct nitrox_device *ndev) { int i, err; for (i = 0; i < ndev->nr_queues; i++) { struct nitrox_cmdq *cmdq; u64 offset; cmdq = kzalloc_node(sizeof(*cmdq), GFP_KERNEL, ndev->node); if (!cmdq) { err = -ENOMEM; goto aqmq_fail; } cmdq->ndev = ndev; cmdq->qno = i; cmdq->instr_size = sizeof(struct aqmq_command_s); /* AQM Queue Doorbell Counter Register Address */ offset = AQMQ_DRBLX(i); cmdq->dbell_csr_addr = NITROX_CSR_ADDR(ndev, offset); /* AQM Queue Commands Completed Count Register Address */ offset = AQMQ_CMD_CNTX(i); cmdq->compl_cnt_csr_addr = NITROX_CSR_ADDR(ndev, offset); err = nitrox_cmdq_init(cmdq, AQM_Q_ALIGN_BYTES); if (err) { kfree_sensitive(cmdq); goto aqmq_fail; } ndev->aqmq[i] = cmdq; } return 0; aqmq_fail: nitrox_free_aqm_queues(ndev); return err; } static void nitrox_free_pktin_queues(struct nitrox_device *ndev) { int i; for (i = 0; i < ndev->nr_queues; i++) { struct nitrox_cmdq *cmdq = &ndev->pkt_inq[i]; nitrox_cmdq_cleanup(cmdq); } kfree(ndev->pkt_inq); ndev->pkt_inq = NULL; } static int nitrox_alloc_pktin_queues(struct nitrox_device *ndev) { int i, err; ndev->pkt_inq = kcalloc_node(ndev->nr_queues, sizeof(struct nitrox_cmdq), GFP_KERNEL, ndev->node); if (!ndev->pkt_inq) return -ENOMEM; for (i = 0; i < ndev->nr_queues; i++) { struct nitrox_cmdq *cmdq; u64 offset; cmdq = &ndev->pkt_inq[i]; cmdq->ndev = ndev; cmdq->qno = i; cmdq->instr_size = sizeof(struct nps_pkt_instr); /* packet input ring doorbell address */ offset = NPS_PKT_IN_INSTR_BAOFF_DBELLX(i); cmdq->dbell_csr_addr = NITROX_CSR_ADDR(ndev, offset); /* packet solicit port completion count address */ offset = NPS_PKT_SLC_CNTSX(i); cmdq->compl_cnt_csr_addr = NITROX_CSR_ADDR(ndev, offset); err = nitrox_cmdq_init(cmdq, PKTIN_Q_ALIGN_BYTES); if (err) goto pktq_fail; } return 0; pktq_fail: nitrox_free_pktin_queues(ndev); return err; } static int create_crypto_dma_pool(struct nitrox_device *ndev) { size_t size; /* Crypto context pool, 16 byte aligned */ size = CRYPTO_CTX_SIZE + sizeof(struct ctx_hdr); ndev->ctx_pool = dma_pool_create("nitrox-context", DEV(ndev), size, 16, 0); if (!ndev->ctx_pool) return -ENOMEM; return 0; } static void destroy_crypto_dma_pool(struct nitrox_device *ndev) { if (!ndev->ctx_pool) return; dma_pool_destroy(ndev->ctx_pool); ndev->ctx_pool = NULL; } /* * crypto_alloc_context - Allocate crypto context from pool * @ndev: NITROX Device */ void *crypto_alloc_context(struct nitrox_device *ndev) { struct ctx_hdr *ctx; struct crypto_ctx_hdr *chdr; void *vaddr; dma_addr_t dma; chdr = kmalloc(sizeof(*chdr), GFP_KERNEL); if (!chdr) return NULL; vaddr = dma_pool_zalloc(ndev->ctx_pool, GFP_KERNEL, &dma); if (!vaddr) { kfree(chdr); return NULL; } /* fill meta data */ ctx = vaddr; ctx->pool = ndev->ctx_pool; ctx->dma = dma; ctx->ctx_dma = dma + sizeof(struct ctx_hdr); chdr->pool = ndev->ctx_pool; chdr->dma = dma; chdr->vaddr = vaddr; return chdr; } /** * crypto_free_context - Free crypto context to pool * @ctx: context to free */ void crypto_free_context(void *ctx) { struct crypto_ctx_hdr *ctxp; if (!ctx) return; ctxp = ctx; dma_pool_free(ctxp->pool, ctxp->vaddr, ctxp->dma); kfree(ctxp); } /** * nitrox_common_sw_init - allocate software resources. * @ndev: NITROX device * * Allocates crypto context pools and command queues etc. * * Return: 0 on success, or a negative error code on error. */ int nitrox_common_sw_init(struct nitrox_device *ndev) { int err = 0; /* per device crypto context pool */ err = create_crypto_dma_pool(ndev); if (err) return err; err = nitrox_alloc_pktin_queues(ndev); if (err) destroy_crypto_dma_pool(ndev); err = nitrox_alloc_aqm_queues(ndev); if (err) { nitrox_free_pktin_queues(ndev); destroy_crypto_dma_pool(ndev); } return err; } /** * nitrox_common_sw_cleanup - free software resources. * @ndev: NITROX device */ void nitrox_common_sw_cleanup(struct nitrox_device *ndev) { nitrox_free_aqm_queues(ndev); nitrox_free_pktin_queues(ndev); destroy_crypto_dma_pool(ndev); }