The original logic don't support load firmware for cards which has no
DDR, add the related logic to make it can load firmware successfully.

Signed-off-by: Chaoyong He <chaoyong...@corigine.com>
Reviewed-by: Long Wu <long...@corigine.com>
Reviewed-by: Peng Zhang <peng.zh...@corigine.com>
---
 drivers/net/nfp/nfpcore/nfp_nsp.c | 131 +++++++++++++++++++++++++++++-
 1 file changed, 128 insertions(+), 3 deletions(-)

diff --git a/drivers/net/nfp/nfpcore/nfp_nsp.c 
b/drivers/net/nfp/nfpcore/nfp_nsp.c
index 9837b3354b..dd212a6d7c 100644
--- a/drivers/net/nfp/nfpcore/nfp_nsp.c
+++ b/drivers/net/nfp/nfpcore/nfp_nsp.c
@@ -37,9 +37,12 @@
 #define   NSP_DFLT_BUFFER_ADDRESS      GENMASK_ULL(39, 0)
 
 #define NSP_DFLT_BUFFER_CONFIG  0x20
+#define   NSP_DFLT_BUFFER_DMA_CHUNK_ORDER    GENMASK_ULL(63, 58)
 #define   NSP_DFLT_BUFFER_SIZE_4KB     GENMASK_ULL(15, 8)
 #define   NSP_DFLT_BUFFER_SIZE_MB      GENMASK_ULL(7, 0)
 
+#define NFP_CAP_CMD_DMA_SG      0x28
+
 #define NSP_MAGIC               0xab10
 
 /*
@@ -85,6 +88,18 @@ enum nfp_nsp_cmd {
        SPCODE_DEV_ACTIVATE     = 29, /* Activate hardware for multiple pfs 
case */
 };
 
+struct nfp_nsp_dma_desc {
+       rte_le32_t size;
+       rte_le32_t reserved;
+       rte_le64_t addr;
+};
+
+struct nfp_nsp_dma_buf {
+       rte_le32_t chunk_cnt;
+       rte_le32_t reserved[3];
+       struct nfp_nsp_dma_desc descs[];
+};
+
 static const struct {
        uint32_t code;
        const char *msg;
@@ -502,6 +517,109 @@ nfp_nsp_command_buf_def(struct nfp_nsp *nsp,
        return ret;
 }
 
+static int
+nfp_nsp_command_buf_dma_sg(struct nfp_nsp *nsp,
+               struct nfp_nsp_command_buf_arg *arg,
+               size_t max_size,
+               size_t chunk_order)
+{
+       int ret;
+       void *chunks;
+       uint32_t nseg;
+       size_t total_len;
+       size_t chunk_size;
+       rte_iova_t buf_dma;
+       rte_iova_t chunks_dma;
+       struct nfp_nsp_dma_buf *buf;
+       struct nfp_nsp_dma_desc *descs;
+
+       chunk_size = RTE_BIT64(chunk_order);
+       nseg = DIV_ROUND_UP(max_size, chunk_size);
+
+       /* Malloc memory */
+       total_len = sizeof(struct nfp_nsp_dma_buf) +
+                       nseg * sizeof(struct nfp_nsp_dma_desc) +
+                       nseg * chunk_size;
+       buf = rte_zmalloc(NULL, total_len, 0);
+       buf_dma = rte_malloc_virt2iova(buf);
+
+       /* Populate struct nfp_nsp_dma_buf */
+       buf->chunk_cnt = rte_cpu_to_le_32(nseg);
+
+       /* Init start pointer of sections */
+       descs = (void *)((char *)buf + sizeof(struct nfp_nsp_dma_buf));
+       chunks = (char *)descs + nseg * sizeof(struct nfp_nsp_dma_desc);
+       chunks_dma = buf_dma + sizeof(struct nfp_nsp_dma_buf) +
+                       nseg * sizeof(struct nfp_nsp_dma_desc);
+
+       /* Copy in_arg*/
+       rte_memcpy(chunks, arg->in_buf, arg->in_size);
+
+       /* Populate struct nfp_nsp_dma_desc */
+       for (uint32_t i = 0; i < nseg; i++) {
+               descs[i].size = rte_cpu_to_le_32(chunk_size);
+               descs[i].addr = rte_cpu_to_le_64(chunks_dma + i * chunk_size);
+       }
+       descs[nseg - 1].size = rte_cpu_to_le_32(max_size - chunk_size * (nseg - 
1));
+
+       /* Send to nsp */
+       arg->arg.dma = true;
+       arg->arg.buf = buf_dma;
+       ret = nfp_nsp_command_real(nsp, &arg->arg);
+       if (ret < 0) {
+               PMD_DRV_LOG(ERR, "NSP: SG DMA failed for command 0x%04x: %d",
+                               arg->arg.code, ret);
+               goto free_exit;
+       }
+
+       /* Copy out_arg */
+       if (arg->out_buf != NULL && arg->out_size > 0)
+               rte_memcpy(arg->out_buf, chunks, arg->out_size);
+
+free_exit:
+       rte_free(buf);
+
+       return ret;
+}
+
+#define NFP_PAGE_SHIFT 12UL
+
+static int
+nfp_nsp_command_buf_dma(struct nfp_nsp *nsp,
+               struct nfp_nsp_command_buf_arg *arg,
+               size_t max_size,
+               size_t dma_order)
+{
+       int err;
+       bool sg_ok;
+       uint64_t reg;
+       size_t buf_order;
+       size_t chunk_order;
+       struct nfp_cpp *cpp = nsp->cpp;
+
+       err = nfp_cpp_readq(cpp, nfp_resource_cpp_id(nsp->res),
+                       nfp_resource_address(nsp->res) + NFP_CAP_CMD_DMA_SG,
+                       &reg);
+       if (err < 0)
+               return err;
+
+       sg_ok = reg & RTE_BIT64(arg->arg.code - 1);
+       if (!sg_ok) {
+               buf_order = rte_log2_u64(max_size);
+               if (buf_order > dma_order) {
+                       PMD_DRV_LOG(ERR, "NSP: non-SG DMA for command 0x%04x 
fail",
+                                       arg->arg.code);
+                       return -ENOMEM;
+               }
+
+               chunk_order = buf_order;
+       } else {
+               chunk_order = RTE_MIN(dma_order, NFP_PAGE_SHIFT);
+       }
+
+       return nfp_nsp_command_buf_dma_sg(nsp, arg, max_size, chunk_order);
+}
+
 #define SZ_1M 0x00100000
 #define SZ_4K 0x00001000
 
@@ -513,6 +631,7 @@ nfp_nsp_command_buf(struct nfp_nsp *nsp,
        size_t size;
        uint64_t reg;
        size_t max_size;
+       size_t dma_order;
        struct nfp_cpp *cpp = nsp->cpp;
 
        if (nsp->ver.minor < 13) {
@@ -530,13 +649,19 @@ nfp_nsp_command_buf(struct nfp_nsp *nsp,
        max_size = RTE_MAX(arg->in_size, arg->out_size);
        size = FIELD_GET(NSP_DFLT_BUFFER_SIZE_MB, reg) * SZ_1M +
                        FIELD_GET(NSP_DFLT_BUFFER_SIZE_4KB, reg) * SZ_4K;
-       if (size < max_size) {
+       dma_order = FIELD_GET(NSP_DFLT_BUFFER_DMA_CHUNK_ORDER, reg);
+
+       if (size >= max_size) {
+               err = nfp_nsp_command_buf_def(nsp, arg);
+       } else if (dma_order != 0) {
+               err = nfp_nsp_command_buf_dma(nsp, arg, max_size, dma_order);
+       } else {
                PMD_DRV_LOG(ERR, "NSP: default buffer too small for command 
%#04x (%zu < %zu).",
                                arg->arg.code, size, max_size);
-               return -EINVAL;
+               err = -EINVAL;
        }
 
-       return nfp_nsp_command_buf_def(nsp, arg);
+       return err;
 }
 
 int
-- 
2.43.5

Reply via email to