1e33ad06eSKevin Laatz /* SPDX-License-Identifier: BSD-3-Clause 2e33ad06eSKevin Laatz * Copyright 2021 Intel Corporation 3e33ad06eSKevin Laatz */ 4e33ad06eSKevin Laatz 53d36a0a1SKevin Laatz #include <x86intrin.h> 63d36a0a1SKevin Laatz 755dc0f60SKevin Laatz #include <rte_malloc.h> 855dc0f60SKevin Laatz #include <rte_common.h> 9e33ad06eSKevin Laatz #include <rte_log.h> 103d36a0a1SKevin Laatz #include <rte_prefetch.h> 11e33ad06eSKevin Laatz 12e33ad06eSKevin Laatz #include "idxd_internal.h" 13e33ad06eSKevin Laatz 1455dc0f60SKevin Laatz #define IDXD_PMD_NAME_STR "dmadev_idxd" 1555dc0f60SKevin Laatz 16aa802b10SBruce Richardson /* systems with DSA all support AVX2 so allow our data-path functions to 17aa802b10SBruce Richardson * always use at least that instruction set 18aa802b10SBruce Richardson */ 19aa802b10SBruce Richardson #ifndef __AVX2__ 20aa802b10SBruce Richardson #define __use_avx2 __attribute__((target("avx2"))) 21aa802b10SBruce Richardson #else 22aa802b10SBruce Richardson #define __use_avx2 23aa802b10SBruce Richardson #endif 24aa802b10SBruce Richardson 25aa802b10SBruce Richardson __use_avx2 263d36a0a1SKevin Laatz static __rte_always_inline rte_iova_t 273d36a0a1SKevin Laatz __desc_idx_to_iova(struct idxd_dmadev *idxd, uint16_t n) 283d36a0a1SKevin Laatz { 293d36a0a1SKevin Laatz return idxd->desc_iova + (n * sizeof(struct idxd_hw_desc)); 303d36a0a1SKevin Laatz } 313d36a0a1SKevin Laatz 32aa802b10SBruce Richardson __use_avx2 333d36a0a1SKevin Laatz static __rte_always_inline void 343d36a0a1SKevin Laatz __idxd_movdir64b(volatile void *dst, const struct idxd_hw_desc *src) 353d36a0a1SKevin Laatz { 363d36a0a1SKevin Laatz asm volatile (".byte 0x66, 0x0f, 0x38, 0xf8, 0x02" 373d36a0a1SKevin Laatz : 383d36a0a1SKevin Laatz : "a" (dst), "d" (src) 393d36a0a1SKevin Laatz : "memory"); 403d36a0a1SKevin Laatz } 413d36a0a1SKevin Laatz 42aa802b10SBruce Richardson __use_avx2 433d36a0a1SKevin Laatz static __rte_always_inline void 443d36a0a1SKevin Laatz __submit(struct idxd_dmadev *idxd) 453d36a0a1SKevin Laatz { 463d36a0a1SKevin Laatz rte_prefetch1(&idxd->batch_comp_ring[idxd->batch_idx_read]); 473d36a0a1SKevin Laatz 483d36a0a1SKevin Laatz if (idxd->batch_size == 0) 493d36a0a1SKevin Laatz return; 503d36a0a1SKevin Laatz 513d36a0a1SKevin Laatz /* write completion to batch comp ring */ 523d36a0a1SKevin Laatz rte_iova_t comp_addr = idxd->batch_iova + 533d36a0a1SKevin Laatz (idxd->batch_idx_write * sizeof(struct idxd_completion)); 543d36a0a1SKevin Laatz 553d36a0a1SKevin Laatz if (idxd->batch_size == 1) { 563d36a0a1SKevin Laatz /* submit batch directly */ 573d36a0a1SKevin Laatz struct idxd_hw_desc desc = 583d36a0a1SKevin Laatz idxd->desc_ring[idxd->batch_start & idxd->desc_ring_mask]; 593d36a0a1SKevin Laatz desc.completion = comp_addr; 603d36a0a1SKevin Laatz desc.op_flags |= IDXD_FLAG_REQUEST_COMPLETION; 613d36a0a1SKevin Laatz _mm_sfence(); /* fence before writing desc to device */ 623d36a0a1SKevin Laatz __idxd_movdir64b(idxd->portal, &desc); 633d36a0a1SKevin Laatz } else { 643d36a0a1SKevin Laatz const struct idxd_hw_desc batch_desc = { 653d36a0a1SKevin Laatz .op_flags = (idxd_op_batch << IDXD_CMD_OP_SHIFT) | 663d36a0a1SKevin Laatz IDXD_FLAG_COMPLETION_ADDR_VALID | 673d36a0a1SKevin Laatz IDXD_FLAG_REQUEST_COMPLETION, 683d36a0a1SKevin Laatz .desc_addr = __desc_idx_to_iova(idxd, 693d36a0a1SKevin Laatz idxd->batch_start & idxd->desc_ring_mask), 703d36a0a1SKevin Laatz .completion = comp_addr, 713d36a0a1SKevin Laatz .size = idxd->batch_size, 723d36a0a1SKevin Laatz }; 733d36a0a1SKevin Laatz _mm_sfence(); /* fence before writing desc to device */ 743d36a0a1SKevin Laatz __idxd_movdir64b(idxd->portal, &batch_desc); 753d36a0a1SKevin Laatz } 763d36a0a1SKevin Laatz 773d36a0a1SKevin Laatz if (++idxd->batch_idx_write > idxd->max_batches) 783d36a0a1SKevin Laatz idxd->batch_idx_write = 0; 793d36a0a1SKevin Laatz 80280c3ca0SKevin Laatz idxd->stats.submitted += idxd->batch_size; 81280c3ca0SKevin Laatz 823d36a0a1SKevin Laatz idxd->batch_start += idxd->batch_size; 833d36a0a1SKevin Laatz idxd->batch_size = 0; 843d36a0a1SKevin Laatz idxd->batch_idx_ring[idxd->batch_idx_write] = idxd->batch_start; 853d36a0a1SKevin Laatz _mm256_store_si256((void *)&idxd->batch_comp_ring[idxd->batch_idx_write], 863d36a0a1SKevin Laatz _mm256_setzero_si256()); 873d36a0a1SKevin Laatz } 883d36a0a1SKevin Laatz 89aa802b10SBruce Richardson __use_avx2 903d36a0a1SKevin Laatz static __rte_always_inline int 913d36a0a1SKevin Laatz __idxd_write_desc(struct idxd_dmadev *idxd, 923d36a0a1SKevin Laatz const uint32_t op_flags, 933d36a0a1SKevin Laatz const rte_iova_t src, 943d36a0a1SKevin Laatz const rte_iova_t dst, 953d36a0a1SKevin Laatz const uint32_t size, 963d36a0a1SKevin Laatz const uint32_t flags) 973d36a0a1SKevin Laatz { 983d36a0a1SKevin Laatz uint16_t mask = idxd->desc_ring_mask; 993d36a0a1SKevin Laatz uint16_t job_id = idxd->batch_start + idxd->batch_size; 1003d36a0a1SKevin Laatz /* we never wrap batches, so we only mask the start and allow start+size to overflow */ 1013d36a0a1SKevin Laatz uint16_t write_idx = (idxd->batch_start & mask) + idxd->batch_size; 1023d36a0a1SKevin Laatz 1033d36a0a1SKevin Laatz /* first check batch ring space then desc ring space */ 1043d36a0a1SKevin Laatz if ((idxd->batch_idx_read == 0 && idxd->batch_idx_write == idxd->max_batches) || 1053d36a0a1SKevin Laatz idxd->batch_idx_write + 1 == idxd->batch_idx_read) 1063d36a0a1SKevin Laatz return -ENOSPC; 1073d36a0a1SKevin Laatz if (((write_idx + 1) & mask) == (idxd->ids_returned & mask)) 1083d36a0a1SKevin Laatz return -ENOSPC; 1093d36a0a1SKevin Laatz 1103d36a0a1SKevin Laatz /* write desc. Note: descriptors don't wrap, but the completion address does */ 1113d36a0a1SKevin Laatz const uint64_t op_flags64 = (uint64_t)(op_flags | IDXD_FLAG_COMPLETION_ADDR_VALID) << 32; 1123d36a0a1SKevin Laatz const uint64_t comp_addr = __desc_idx_to_iova(idxd, write_idx & mask); 1133d36a0a1SKevin Laatz _mm256_store_si256((void *)&idxd->desc_ring[write_idx], 1143d36a0a1SKevin Laatz _mm256_set_epi64x(dst, src, comp_addr, op_flags64)); 1153d36a0a1SKevin Laatz _mm256_store_si256((void *)&idxd->desc_ring[write_idx].size, 1163d36a0a1SKevin Laatz _mm256_set_epi64x(0, 0, 0, size)); 1173d36a0a1SKevin Laatz 1183d36a0a1SKevin Laatz idxd->batch_size++; 1193d36a0a1SKevin Laatz 1203d36a0a1SKevin Laatz rte_prefetch0_write(&idxd->desc_ring[write_idx + 1]); 1213d36a0a1SKevin Laatz 1223d36a0a1SKevin Laatz if (flags & RTE_DMA_OP_FLAG_SUBMIT) 1233d36a0a1SKevin Laatz __submit(idxd); 1243d36a0a1SKevin Laatz 1253d36a0a1SKevin Laatz return job_id; 1263d36a0a1SKevin Laatz } 1273d36a0a1SKevin Laatz 128aa802b10SBruce Richardson __use_avx2 1293d36a0a1SKevin Laatz int 1303d36a0a1SKevin Laatz idxd_enqueue_copy(void *dev_private, uint16_t qid __rte_unused, rte_iova_t src, 1313d36a0a1SKevin Laatz rte_iova_t dst, unsigned int length, uint64_t flags) 1323d36a0a1SKevin Laatz { 1333d36a0a1SKevin Laatz /* we can take advantage of the fact that the fence flag in dmadev and DSA are the same, 1343d36a0a1SKevin Laatz * but check it at compile time to be sure. 1353d36a0a1SKevin Laatz */ 1363d36a0a1SKevin Laatz RTE_BUILD_BUG_ON(RTE_DMA_OP_FLAG_FENCE != IDXD_FLAG_FENCE); 1373d36a0a1SKevin Laatz uint32_t memmove = (idxd_op_memmove << IDXD_CMD_OP_SHIFT) | 1383d36a0a1SKevin Laatz IDXD_FLAG_CACHE_CONTROL | (flags & IDXD_FLAG_FENCE); 1393d36a0a1SKevin Laatz return __idxd_write_desc(dev_private, memmove, src, dst, length, 1403d36a0a1SKevin Laatz flags); 1413d36a0a1SKevin Laatz } 1423d36a0a1SKevin Laatz 143aa802b10SBruce Richardson __use_avx2 1443d36a0a1SKevin Laatz int 1453d36a0a1SKevin Laatz idxd_enqueue_fill(void *dev_private, uint16_t qid __rte_unused, uint64_t pattern, 1463d36a0a1SKevin Laatz rte_iova_t dst, unsigned int length, uint64_t flags) 1473d36a0a1SKevin Laatz { 1483d36a0a1SKevin Laatz uint32_t fill = (idxd_op_fill << IDXD_CMD_OP_SHIFT) | 1493d36a0a1SKevin Laatz IDXD_FLAG_CACHE_CONTROL | (flags & IDXD_FLAG_FENCE); 1503d36a0a1SKevin Laatz return __idxd_write_desc(dev_private, fill, pattern, dst, length, 1513d36a0a1SKevin Laatz flags); 1523d36a0a1SKevin Laatz } 1533d36a0a1SKevin Laatz 154aa802b10SBruce Richardson __use_avx2 1553d36a0a1SKevin Laatz int 1563d36a0a1SKevin Laatz idxd_submit(void *dev_private, uint16_t qid __rte_unused) 1573d36a0a1SKevin Laatz { 1583d36a0a1SKevin Laatz __submit(dev_private); 1593d36a0a1SKevin Laatz return 0; 1603d36a0a1SKevin Laatz } 1613d36a0a1SKevin Laatz 162aa802b10SBruce Richardson __use_avx2 16397aeed56SKevin Laatz static enum rte_dma_status_code 16497aeed56SKevin Laatz get_comp_status(struct idxd_completion *c) 16597aeed56SKevin Laatz { 16697aeed56SKevin Laatz uint8_t st = c->status; 16797aeed56SKevin Laatz switch (st) { 16897aeed56SKevin Laatz /* successful descriptors are not written back normally */ 16997aeed56SKevin Laatz case IDXD_COMP_STATUS_INCOMPLETE: 17097aeed56SKevin Laatz case IDXD_COMP_STATUS_SUCCESS: 17197aeed56SKevin Laatz return RTE_DMA_STATUS_SUCCESSFUL; 172fe1a5a9bSSean Morrissey case IDXD_COMP_STATUS_PAGE_FAULT: 173fe1a5a9bSSean Morrissey return RTE_DMA_STATUS_PAGE_FAULT; 17497aeed56SKevin Laatz case IDXD_COMP_STATUS_INVALID_OPCODE: 17597aeed56SKevin Laatz return RTE_DMA_STATUS_INVALID_OPCODE; 17697aeed56SKevin Laatz case IDXD_COMP_STATUS_INVALID_SIZE: 17797aeed56SKevin Laatz return RTE_DMA_STATUS_INVALID_LENGTH; 17897aeed56SKevin Laatz case IDXD_COMP_STATUS_SKIPPED: 17997aeed56SKevin Laatz return RTE_DMA_STATUS_NOT_ATTEMPTED; 18097aeed56SKevin Laatz default: 18197aeed56SKevin Laatz return RTE_DMA_STATUS_ERROR_UNKNOWN; 18297aeed56SKevin Laatz } 18397aeed56SKevin Laatz } 18497aeed56SKevin Laatz 185aa802b10SBruce Richardson __use_avx2 1865a23df34SKevin Laatz int 1875a23df34SKevin Laatz idxd_vchan_status(const struct rte_dma_dev *dev, uint16_t vchan __rte_unused, 1885a23df34SKevin Laatz enum rte_dma_vchan_status *status) 1895a23df34SKevin Laatz { 1905a23df34SKevin Laatz struct idxd_dmadev *idxd = dev->fp_obj->dev_private; 1915a23df34SKevin Laatz uint16_t last_batch_write = idxd->batch_idx_write == 0 ? idxd->max_batches : 1925a23df34SKevin Laatz idxd->batch_idx_write - 1; 1935a23df34SKevin Laatz uint8_t bstatus = (idxd->batch_comp_ring[last_batch_write].status != 0); 1945a23df34SKevin Laatz 1955a23df34SKevin Laatz /* An IDXD device will always be either active or idle. 1965a23df34SKevin Laatz * RTE_DMA_VCHAN_HALTED_ERROR is therefore not supported by IDXD. 1975a23df34SKevin Laatz */ 1985a23df34SKevin Laatz *status = bstatus ? RTE_DMA_VCHAN_IDLE : RTE_DMA_VCHAN_ACTIVE; 1995a23df34SKevin Laatz 2005a23df34SKevin Laatz return 0; 2015a23df34SKevin Laatz } 2025a23df34SKevin Laatz 203aa802b10SBruce Richardson __use_avx2 20497aeed56SKevin Laatz static __rte_always_inline int 20597aeed56SKevin Laatz batch_ok(struct idxd_dmadev *idxd, uint16_t max_ops, enum rte_dma_status_code *status) 20697aeed56SKevin Laatz { 20797aeed56SKevin Laatz uint16_t ret; 20897aeed56SKevin Laatz uint8_t bstatus; 20997aeed56SKevin Laatz 21097aeed56SKevin Laatz if (max_ops == 0) 21197aeed56SKevin Laatz return 0; 21297aeed56SKevin Laatz 21397aeed56SKevin Laatz /* first check if there are any unreturned handles from last time */ 21497aeed56SKevin Laatz if (idxd->ids_avail != idxd->ids_returned) { 21597aeed56SKevin Laatz ret = RTE_MIN((uint16_t)(idxd->ids_avail - idxd->ids_returned), max_ops); 21697aeed56SKevin Laatz idxd->ids_returned += ret; 21797aeed56SKevin Laatz if (status) 21897aeed56SKevin Laatz memset(status, RTE_DMA_STATUS_SUCCESSFUL, ret * sizeof(*status)); 21997aeed56SKevin Laatz return ret; 22097aeed56SKevin Laatz } 22197aeed56SKevin Laatz 22297aeed56SKevin Laatz if (idxd->batch_idx_read == idxd->batch_idx_write) 22397aeed56SKevin Laatz return 0; 22497aeed56SKevin Laatz 22597aeed56SKevin Laatz bstatus = idxd->batch_comp_ring[idxd->batch_idx_read].status; 22697aeed56SKevin Laatz /* now check if next batch is complete and successful */ 22797aeed56SKevin Laatz if (bstatus == IDXD_COMP_STATUS_SUCCESS) { 22897aeed56SKevin Laatz /* since the batch idx ring stores the start of each batch, pre-increment to lookup 22997aeed56SKevin Laatz * start of next batch. 23097aeed56SKevin Laatz */ 23197aeed56SKevin Laatz if (++idxd->batch_idx_read > idxd->max_batches) 23297aeed56SKevin Laatz idxd->batch_idx_read = 0; 23397aeed56SKevin Laatz idxd->ids_avail = idxd->batch_idx_ring[idxd->batch_idx_read]; 23497aeed56SKevin Laatz 23597aeed56SKevin Laatz ret = RTE_MIN((uint16_t)(idxd->ids_avail - idxd->ids_returned), max_ops); 23697aeed56SKevin Laatz idxd->ids_returned += ret; 23797aeed56SKevin Laatz if (status) 23897aeed56SKevin Laatz memset(status, RTE_DMA_STATUS_SUCCESSFUL, ret * sizeof(*status)); 23997aeed56SKevin Laatz return ret; 24097aeed56SKevin Laatz } 24197aeed56SKevin Laatz /* check if batch is incomplete */ 24297aeed56SKevin Laatz else if (bstatus == IDXD_COMP_STATUS_INCOMPLETE) 24397aeed56SKevin Laatz return 0; 24497aeed56SKevin Laatz 24597aeed56SKevin Laatz return -1; /* error case */ 24697aeed56SKevin Laatz } 24797aeed56SKevin Laatz 248aa802b10SBruce Richardson __use_avx2 24997aeed56SKevin Laatz static inline uint16_t 25097aeed56SKevin Laatz batch_completed(struct idxd_dmadev *idxd, uint16_t max_ops, bool *has_error) 25197aeed56SKevin Laatz { 25297aeed56SKevin Laatz uint16_t i; 25397aeed56SKevin Laatz uint16_t b_start, b_end, next_batch; 25497aeed56SKevin Laatz 25597aeed56SKevin Laatz int ret = batch_ok(idxd, max_ops, NULL); 25697aeed56SKevin Laatz if (ret >= 0) 25797aeed56SKevin Laatz return ret; 25897aeed56SKevin Laatz 25997aeed56SKevin Laatz /* ERROR case, not successful, not incomplete */ 26097aeed56SKevin Laatz /* Get the batch size, and special case size 1. 26197aeed56SKevin Laatz * once we identify the actual failure job, return other jobs, then update 26297aeed56SKevin Laatz * the batch ring indexes to make it look like the first job of the batch has failed. 26397aeed56SKevin Laatz * Subsequent calls here will always return zero packets, and the error must be cleared by 26497aeed56SKevin Laatz * calling the completed_status() function. 26597aeed56SKevin Laatz */ 26697aeed56SKevin Laatz next_batch = (idxd->batch_idx_read + 1); 26797aeed56SKevin Laatz if (next_batch > idxd->max_batches) 26897aeed56SKevin Laatz next_batch = 0; 26997aeed56SKevin Laatz b_start = idxd->batch_idx_ring[idxd->batch_idx_read]; 27097aeed56SKevin Laatz b_end = idxd->batch_idx_ring[next_batch]; 27197aeed56SKevin Laatz 27297aeed56SKevin Laatz if (b_end - b_start == 1) { /* not a batch */ 27397aeed56SKevin Laatz *has_error = true; 27497aeed56SKevin Laatz return 0; 27597aeed56SKevin Laatz } 27697aeed56SKevin Laatz 27797aeed56SKevin Laatz for (i = b_start; i < b_end; i++) { 27897aeed56SKevin Laatz struct idxd_completion *c = (void *)&idxd->desc_ring[i & idxd->desc_ring_mask]; 27997aeed56SKevin Laatz if (c->status > IDXD_COMP_STATUS_SUCCESS) /* ignore incomplete(0) and success(1) */ 28097aeed56SKevin Laatz break; 28197aeed56SKevin Laatz } 28297aeed56SKevin Laatz ret = RTE_MIN((uint16_t)(i - idxd->ids_returned), max_ops); 28397aeed56SKevin Laatz if (ret < max_ops) 28497aeed56SKevin Laatz *has_error = true; /* we got up to the point of error */ 28597aeed56SKevin Laatz idxd->ids_avail = idxd->ids_returned += ret; 28697aeed56SKevin Laatz 28797aeed56SKevin Laatz /* to ensure we can call twice and just return 0, set start of batch to where we finished */ 28897aeed56SKevin Laatz idxd->batch_comp_ring[idxd->batch_idx_read].completed_size -= ret; 28997aeed56SKevin Laatz idxd->batch_idx_ring[idxd->batch_idx_read] += ret; 29097aeed56SKevin Laatz if (idxd->batch_idx_ring[next_batch] - idxd->batch_idx_ring[idxd->batch_idx_read] == 1) { 29197aeed56SKevin Laatz /* copy over the descriptor status to the batch ring as if no batch */ 29297aeed56SKevin Laatz uint16_t d_idx = idxd->batch_idx_ring[idxd->batch_idx_read] & idxd->desc_ring_mask; 29397aeed56SKevin Laatz struct idxd_completion *desc_comp = (void *)&idxd->desc_ring[d_idx]; 29497aeed56SKevin Laatz idxd->batch_comp_ring[idxd->batch_idx_read].status = desc_comp->status; 29597aeed56SKevin Laatz } 29697aeed56SKevin Laatz 29797aeed56SKevin Laatz return ret; 29897aeed56SKevin Laatz } 29997aeed56SKevin Laatz 300aa802b10SBruce Richardson __use_avx2 30197aeed56SKevin Laatz static uint16_t 30297aeed56SKevin Laatz batch_completed_status(struct idxd_dmadev *idxd, uint16_t max_ops, enum rte_dma_status_code *status) 30397aeed56SKevin Laatz { 30497aeed56SKevin Laatz uint16_t next_batch; 30597aeed56SKevin Laatz 30697aeed56SKevin Laatz int ret = batch_ok(idxd, max_ops, status); 30797aeed56SKevin Laatz if (ret >= 0) 30897aeed56SKevin Laatz return ret; 30997aeed56SKevin Laatz 31097aeed56SKevin Laatz /* ERROR case, not successful, not incomplete */ 31197aeed56SKevin Laatz /* Get the batch size, and special case size 1. 31297aeed56SKevin Laatz */ 31397aeed56SKevin Laatz next_batch = (idxd->batch_idx_read + 1); 31497aeed56SKevin Laatz if (next_batch > idxd->max_batches) 31597aeed56SKevin Laatz next_batch = 0; 31697aeed56SKevin Laatz const uint16_t b_start = idxd->batch_idx_ring[idxd->batch_idx_read]; 31797aeed56SKevin Laatz const uint16_t b_end = idxd->batch_idx_ring[next_batch]; 31897aeed56SKevin Laatz const uint16_t b_len = b_end - b_start; 31997aeed56SKevin Laatz if (b_len == 1) {/* not a batch */ 32097aeed56SKevin Laatz *status = get_comp_status(&idxd->batch_comp_ring[idxd->batch_idx_read]); 321280c3ca0SKevin Laatz if (status != RTE_DMA_STATUS_SUCCESSFUL) 322280c3ca0SKevin Laatz idxd->stats.errors++; 32397aeed56SKevin Laatz idxd->ids_avail++; 32497aeed56SKevin Laatz idxd->ids_returned++; 32597aeed56SKevin Laatz idxd->batch_idx_read = next_batch; 32697aeed56SKevin Laatz return 1; 32797aeed56SKevin Laatz } 32897aeed56SKevin Laatz 32997aeed56SKevin Laatz /* not a single-element batch, need to process more. 33097aeed56SKevin Laatz * Scenarios: 33197aeed56SKevin Laatz * 1. max_ops >= batch_size - can fit everything, simple case 33297aeed56SKevin Laatz * - loop through completed ops and then add on any not-attempted ones 33397aeed56SKevin Laatz * 2. max_ops < batch_size - can't fit everything, more complex case 33497aeed56SKevin Laatz * - loop through completed/incomplete and stop when hit max_ops 33597aeed56SKevin Laatz * - adjust the batch descriptor to update where we stopped, with appropriate bcount 33697aeed56SKevin Laatz * - if bcount is to be exactly 1, update the batch descriptor as it will be treated as 33797aeed56SKevin Laatz * non-batch next time. 33897aeed56SKevin Laatz */ 33997aeed56SKevin Laatz const uint16_t bcount = idxd->batch_comp_ring[idxd->batch_idx_read].completed_size; 34097aeed56SKevin Laatz for (ret = 0; ret < b_len && ret < max_ops; ret++) { 34197aeed56SKevin Laatz struct idxd_completion *c = (void *) 34297aeed56SKevin Laatz &idxd->desc_ring[(b_start + ret) & idxd->desc_ring_mask]; 34397aeed56SKevin Laatz status[ret] = (ret < bcount) ? get_comp_status(c) : RTE_DMA_STATUS_NOT_ATTEMPTED; 344280c3ca0SKevin Laatz if (status[ret] != RTE_DMA_STATUS_SUCCESSFUL) 345280c3ca0SKevin Laatz idxd->stats.errors++; 34697aeed56SKevin Laatz } 34797aeed56SKevin Laatz idxd->ids_avail = idxd->ids_returned += ret; 34897aeed56SKevin Laatz 34997aeed56SKevin Laatz /* everything fit */ 35097aeed56SKevin Laatz if (ret == b_len) { 35197aeed56SKevin Laatz idxd->batch_idx_read = next_batch; 35297aeed56SKevin Laatz return ret; 35397aeed56SKevin Laatz } 35497aeed56SKevin Laatz 35597aeed56SKevin Laatz /* set up for next time, update existing batch descriptor & start idx at batch_idx_read */ 35697aeed56SKevin Laatz idxd->batch_idx_ring[idxd->batch_idx_read] += ret; 35797aeed56SKevin Laatz if (ret > bcount) { 35897aeed56SKevin Laatz /* we have only incomplete ones - set batch completed size to 0 */ 35997aeed56SKevin Laatz struct idxd_completion *comp = &idxd->batch_comp_ring[idxd->batch_idx_read]; 36097aeed56SKevin Laatz comp->completed_size = 0; 36197aeed56SKevin Laatz /* if there is only one descriptor left, job skipped so set flag appropriately */ 36297aeed56SKevin Laatz if (b_len - ret == 1) 36397aeed56SKevin Laatz comp->status = IDXD_COMP_STATUS_SKIPPED; 36497aeed56SKevin Laatz } else { 36597aeed56SKevin Laatz struct idxd_completion *comp = &idxd->batch_comp_ring[idxd->batch_idx_read]; 36697aeed56SKevin Laatz comp->completed_size -= ret; 36797aeed56SKevin Laatz /* if there is only one descriptor left, copy status info straight to desc */ 36897aeed56SKevin Laatz if (comp->completed_size == 1) { 36997aeed56SKevin Laatz struct idxd_completion *c = (void *) 37097aeed56SKevin Laatz &idxd->desc_ring[(b_start + ret) & idxd->desc_ring_mask]; 37197aeed56SKevin Laatz comp->status = c->status; 37297aeed56SKevin Laatz /* individual descs can be ok without writeback, but not batches */ 37397aeed56SKevin Laatz if (comp->status == IDXD_COMP_STATUS_INCOMPLETE) 37497aeed56SKevin Laatz comp->status = IDXD_COMP_STATUS_SUCCESS; 37597aeed56SKevin Laatz } else if (bcount == b_len) { 37697aeed56SKevin Laatz /* check if we still have an error, and clear flag if not */ 37797aeed56SKevin Laatz uint16_t i; 37897aeed56SKevin Laatz for (i = b_start + ret; i < b_end; i++) { 37997aeed56SKevin Laatz struct idxd_completion *c = (void *) 38097aeed56SKevin Laatz &idxd->desc_ring[i & idxd->desc_ring_mask]; 38197aeed56SKevin Laatz if (c->status > IDXD_COMP_STATUS_SUCCESS) 38297aeed56SKevin Laatz break; 38397aeed56SKevin Laatz } 38497aeed56SKevin Laatz if (i == b_end) /* no errors */ 38597aeed56SKevin Laatz comp->status = IDXD_COMP_STATUS_SUCCESS; 38697aeed56SKevin Laatz } 38797aeed56SKevin Laatz } 38897aeed56SKevin Laatz 38997aeed56SKevin Laatz return ret; 39097aeed56SKevin Laatz } 39197aeed56SKevin Laatz 392aa802b10SBruce Richardson __use_avx2 39397aeed56SKevin Laatz uint16_t 39497aeed56SKevin Laatz idxd_completed(void *dev_private, uint16_t qid __rte_unused, uint16_t max_ops, 39597aeed56SKevin Laatz uint16_t *last_idx, bool *has_error) 39697aeed56SKevin Laatz { 39797aeed56SKevin Laatz struct idxd_dmadev *idxd = dev_private; 39897aeed56SKevin Laatz uint16_t batch, ret = 0; 39997aeed56SKevin Laatz 40097aeed56SKevin Laatz do { 40197aeed56SKevin Laatz batch = batch_completed(idxd, max_ops - ret, has_error); 40297aeed56SKevin Laatz ret += batch; 40397aeed56SKevin Laatz } while (batch > 0 && *has_error == false); 40497aeed56SKevin Laatz 405280c3ca0SKevin Laatz idxd->stats.completed += ret; 40697aeed56SKevin Laatz *last_idx = idxd->ids_returned - 1; 40797aeed56SKevin Laatz return ret; 40897aeed56SKevin Laatz } 40997aeed56SKevin Laatz 410aa802b10SBruce Richardson __use_avx2 41197aeed56SKevin Laatz uint16_t 41297aeed56SKevin Laatz idxd_completed_status(void *dev_private, uint16_t qid __rte_unused, uint16_t max_ops, 41397aeed56SKevin Laatz uint16_t *last_idx, enum rte_dma_status_code *status) 41497aeed56SKevin Laatz { 41597aeed56SKevin Laatz struct idxd_dmadev *idxd = dev_private; 41697aeed56SKevin Laatz uint16_t batch, ret = 0; 41797aeed56SKevin Laatz 41897aeed56SKevin Laatz do { 41997aeed56SKevin Laatz batch = batch_completed_status(idxd, max_ops - ret, &status[ret]); 42097aeed56SKevin Laatz ret += batch; 42197aeed56SKevin Laatz } while (batch > 0); 42297aeed56SKevin Laatz 423280c3ca0SKevin Laatz idxd->stats.completed += ret; 42497aeed56SKevin Laatz *last_idx = idxd->ids_returned - 1; 42597aeed56SKevin Laatz return ret; 42697aeed56SKevin Laatz } 42797aeed56SKevin Laatz 42855dc0f60SKevin Laatz int 42982147042SKevin Laatz idxd_dump(const struct rte_dma_dev *dev, FILE *f) 43082147042SKevin Laatz { 43182147042SKevin Laatz struct idxd_dmadev *idxd = dev->fp_obj->dev_private; 43282147042SKevin Laatz unsigned int i; 43382147042SKevin Laatz 43482147042SKevin Laatz fprintf(f, "== IDXD Private Data ==\n"); 43582147042SKevin Laatz fprintf(f, " Portal: %p\n", idxd->portal); 43682147042SKevin Laatz fprintf(f, " Config: { ring_size: %u }\n", 43782147042SKevin Laatz idxd->qcfg.nb_desc); 43882147042SKevin Laatz fprintf(f, " Batch ring (sz = %u, max_batches = %u):\n\t", 43982147042SKevin Laatz idxd->max_batches + 1, idxd->max_batches); 44082147042SKevin Laatz for (i = 0; i <= idxd->max_batches; i++) { 44182147042SKevin Laatz fprintf(f, " %u ", idxd->batch_idx_ring[i]); 44282147042SKevin Laatz if (i == idxd->batch_idx_read && i == idxd->batch_idx_write) 44382147042SKevin Laatz fprintf(f, "[rd ptr, wr ptr] "); 44482147042SKevin Laatz else if (i == idxd->batch_idx_read) 44582147042SKevin Laatz fprintf(f, "[rd ptr] "); 44682147042SKevin Laatz else if (i == idxd->batch_idx_write) 44782147042SKevin Laatz fprintf(f, "[wr ptr] "); 44882147042SKevin Laatz if (i == idxd->max_batches) 44982147042SKevin Laatz fprintf(f, "\n"); 45082147042SKevin Laatz } 45182147042SKevin Laatz 45282147042SKevin Laatz fprintf(f, " Curr batch: start = %u, size = %u\n", idxd->batch_start, idxd->batch_size); 45382147042SKevin Laatz fprintf(f, " IDS: avail = %u, returned: %u\n", idxd->ids_avail, idxd->ids_returned); 45482147042SKevin Laatz return 0; 45582147042SKevin Laatz } 45682147042SKevin Laatz 45782147042SKevin Laatz int 458280c3ca0SKevin Laatz idxd_stats_get(const struct rte_dma_dev *dev, uint16_t vchan __rte_unused, 459280c3ca0SKevin Laatz struct rte_dma_stats *stats, uint32_t stats_sz) 460280c3ca0SKevin Laatz { 461280c3ca0SKevin Laatz struct idxd_dmadev *idxd = dev->fp_obj->dev_private; 462280c3ca0SKevin Laatz if (stats_sz < sizeof(*stats)) 463280c3ca0SKevin Laatz return -EINVAL; 464280c3ca0SKevin Laatz *stats = idxd->stats; 465280c3ca0SKevin Laatz return 0; 466280c3ca0SKevin Laatz } 467280c3ca0SKevin Laatz 468280c3ca0SKevin Laatz int 469280c3ca0SKevin Laatz idxd_stats_reset(struct rte_dma_dev *dev, uint16_t vchan __rte_unused) 470280c3ca0SKevin Laatz { 471280c3ca0SKevin Laatz struct idxd_dmadev *idxd = dev->fp_obj->dev_private; 472280c3ca0SKevin Laatz idxd->stats = (struct rte_dma_stats){0}; 473280c3ca0SKevin Laatz return 0; 474280c3ca0SKevin Laatz } 475280c3ca0SKevin Laatz 476280c3ca0SKevin Laatz int 4772f7d42c6SKevin Laatz idxd_info_get(const struct rte_dma_dev *dev, struct rte_dma_info *info, uint32_t size) 4782f7d42c6SKevin Laatz { 4792f7d42c6SKevin Laatz struct idxd_dmadev *idxd = dev->fp_obj->dev_private; 4802f7d42c6SKevin Laatz 4812f7d42c6SKevin Laatz if (size < sizeof(*info)) 4822f7d42c6SKevin Laatz return -EINVAL; 4832f7d42c6SKevin Laatz 4842f7d42c6SKevin Laatz *info = (struct rte_dma_info) { 4852f7d42c6SKevin Laatz .dev_capa = RTE_DMA_CAPA_MEM_TO_MEM | RTE_DMA_CAPA_HANDLES_ERRORS | 4862f7d42c6SKevin Laatz RTE_DMA_CAPA_OPS_COPY | RTE_DMA_CAPA_OPS_FILL, 4872f7d42c6SKevin Laatz .max_vchans = 1, 4882f7d42c6SKevin Laatz .max_desc = 4096, 4892f7d42c6SKevin Laatz .min_desc = 64, 4902f7d42c6SKevin Laatz }; 4912f7d42c6SKevin Laatz if (idxd->sva_support) 4922f7d42c6SKevin Laatz info->dev_capa |= RTE_DMA_CAPA_SVA; 4932f7d42c6SKevin Laatz return 0; 4942f7d42c6SKevin Laatz } 4952f7d42c6SKevin Laatz 4969459de4eSKevin Laatz uint16_t 4979459de4eSKevin Laatz idxd_burst_capacity(const void *dev_private, uint16_t vchan __rte_unused) 4989459de4eSKevin Laatz { 4999459de4eSKevin Laatz const struct idxd_dmadev *idxd = dev_private; 5009459de4eSKevin Laatz uint16_t write_idx = idxd->batch_start + idxd->batch_size; 5019459de4eSKevin Laatz uint16_t used_space; 5029459de4eSKevin Laatz 5039459de4eSKevin Laatz /* Check for space in the batch ring */ 5049459de4eSKevin Laatz if ((idxd->batch_idx_read == 0 && idxd->batch_idx_write == idxd->max_batches) || 5059459de4eSKevin Laatz idxd->batch_idx_write + 1 == idxd->batch_idx_read) 5069459de4eSKevin Laatz return 0; 5079459de4eSKevin Laatz 50863990aebSBruce Richardson /* Subtract and mask to get in correct range */ 50963990aebSBruce Richardson used_space = (write_idx - idxd->ids_returned) & idxd->desc_ring_mask; 5109459de4eSKevin Laatz 511a2b43447SBruce Richardson const int ret = RTE_MIN((idxd->desc_ring_mask - used_space), 512a2b43447SBruce Richardson (idxd->max_batch_size - idxd->batch_size)); 513a2b43447SBruce Richardson return ret < 0 ? 0 : (uint16_t)ret; 5149459de4eSKevin Laatz } 5159459de4eSKevin Laatz 5162f7d42c6SKevin Laatz int 5172f7d42c6SKevin Laatz idxd_configure(struct rte_dma_dev *dev __rte_unused, const struct rte_dma_conf *dev_conf, 5182f7d42c6SKevin Laatz uint32_t conf_sz) 5192f7d42c6SKevin Laatz { 5202f7d42c6SKevin Laatz if (sizeof(struct rte_dma_conf) != conf_sz) 5212f7d42c6SKevin Laatz return -EINVAL; 5222f7d42c6SKevin Laatz 5232f7d42c6SKevin Laatz if (dev_conf->nb_vchans != 1) 5242f7d42c6SKevin Laatz return -EINVAL; 5252f7d42c6SKevin Laatz return 0; 5262f7d42c6SKevin Laatz } 5272f7d42c6SKevin Laatz 5282f7d42c6SKevin Laatz int 5292f7d42c6SKevin Laatz idxd_vchan_setup(struct rte_dma_dev *dev, uint16_t vchan __rte_unused, 5302f7d42c6SKevin Laatz const struct rte_dma_vchan_conf *qconf, uint32_t qconf_sz) 5312f7d42c6SKevin Laatz { 5322f7d42c6SKevin Laatz struct idxd_dmadev *idxd = dev->fp_obj->dev_private; 5332f7d42c6SKevin Laatz uint16_t max_desc = qconf->nb_desc; 5342f7d42c6SKevin Laatz 5352f7d42c6SKevin Laatz if (sizeof(struct rte_dma_vchan_conf) != qconf_sz) 5362f7d42c6SKevin Laatz return -EINVAL; 5372f7d42c6SKevin Laatz 5382f7d42c6SKevin Laatz idxd->qcfg = *qconf; 5392f7d42c6SKevin Laatz 5402f7d42c6SKevin Laatz if (!rte_is_power_of_2(max_desc)) 5412f7d42c6SKevin Laatz max_desc = rte_align32pow2(max_desc); 5422f7d42c6SKevin Laatz IDXD_PMD_DEBUG("DMA dev %u using %u descriptors", dev->data->dev_id, max_desc); 5432f7d42c6SKevin Laatz idxd->desc_ring_mask = max_desc - 1; 5442f7d42c6SKevin Laatz idxd->qcfg.nb_desc = max_desc; 5452f7d42c6SKevin Laatz 5462f7d42c6SKevin Laatz /* in case we are reconfiguring a device, free any existing memory */ 5472f7d42c6SKevin Laatz rte_free(idxd->desc_ring); 5482f7d42c6SKevin Laatz 5492f7d42c6SKevin Laatz /* allocate the descriptor ring at 2x size as batches can't wrap */ 5502f7d42c6SKevin Laatz idxd->desc_ring = rte_zmalloc(NULL, sizeof(*idxd->desc_ring) * max_desc * 2, 0); 5512f7d42c6SKevin Laatz if (idxd->desc_ring == NULL) 5522f7d42c6SKevin Laatz return -ENOMEM; 5532f7d42c6SKevin Laatz idxd->desc_iova = rte_mem_virt2iova(idxd->desc_ring); 5542f7d42c6SKevin Laatz 5552f7d42c6SKevin Laatz idxd->batch_idx_read = 0; 5562f7d42c6SKevin Laatz idxd->batch_idx_write = 0; 5572f7d42c6SKevin Laatz idxd->batch_start = 0; 5582f7d42c6SKevin Laatz idxd->batch_size = 0; 5592f7d42c6SKevin Laatz idxd->ids_returned = 0; 5602f7d42c6SKevin Laatz idxd->ids_avail = 0; 5612f7d42c6SKevin Laatz 5622f7d42c6SKevin Laatz memset(idxd->batch_comp_ring, 0, sizeof(*idxd->batch_comp_ring) * 5632f7d42c6SKevin Laatz (idxd->max_batches + 1)); 5642f7d42c6SKevin Laatz return 0; 5652f7d42c6SKevin Laatz } 5662f7d42c6SKevin Laatz 5672f7d42c6SKevin Laatz int 56855dc0f60SKevin Laatz idxd_dmadev_create(const char *name, struct rte_device *dev, 56955dc0f60SKevin Laatz const struct idxd_dmadev *base_idxd, 57055dc0f60SKevin Laatz const struct rte_dma_dev_ops *ops) 57155dc0f60SKevin Laatz { 57255dc0f60SKevin Laatz struct idxd_dmadev *idxd = NULL; 57355dc0f60SKevin Laatz struct rte_dma_dev *dmadev = NULL; 57455dc0f60SKevin Laatz int ret = 0; 57555dc0f60SKevin Laatz 57682147042SKevin Laatz RTE_BUILD_BUG_ON(sizeof(struct idxd_hw_desc) != 64); 57782147042SKevin Laatz RTE_BUILD_BUG_ON(offsetof(struct idxd_hw_desc, size) != 32); 57882147042SKevin Laatz RTE_BUILD_BUG_ON(sizeof(struct idxd_completion) != 32); 57982147042SKevin Laatz 58055dc0f60SKevin Laatz if (!name) { 58155dc0f60SKevin Laatz IDXD_PMD_ERR("Invalid name of the device!"); 58255dc0f60SKevin Laatz ret = -EINVAL; 58355dc0f60SKevin Laatz goto cleanup; 58455dc0f60SKevin Laatz } 58555dc0f60SKevin Laatz 58655dc0f60SKevin Laatz /* Allocate device structure */ 58755dc0f60SKevin Laatz dmadev = rte_dma_pmd_allocate(name, dev->numa_node, sizeof(struct idxd_dmadev)); 58855dc0f60SKevin Laatz if (dmadev == NULL) { 58955dc0f60SKevin Laatz IDXD_PMD_ERR("Unable to allocate dma device"); 59055dc0f60SKevin Laatz ret = -ENOMEM; 59155dc0f60SKevin Laatz goto cleanup; 59255dc0f60SKevin Laatz } 59355dc0f60SKevin Laatz dmadev->dev_ops = ops; 59455dc0f60SKevin Laatz dmadev->device = dev; 59555dc0f60SKevin Laatz 5963d36a0a1SKevin Laatz dmadev->fp_obj->copy = idxd_enqueue_copy; 5973d36a0a1SKevin Laatz dmadev->fp_obj->fill = idxd_enqueue_fill; 5983d36a0a1SKevin Laatz dmadev->fp_obj->submit = idxd_submit; 59997aeed56SKevin Laatz dmadev->fp_obj->completed = idxd_completed; 60097aeed56SKevin Laatz dmadev->fp_obj->completed_status = idxd_completed_status; 6019459de4eSKevin Laatz dmadev->fp_obj->burst_capacity = idxd_burst_capacity; 6021ea2cdc1SBruce Richardson dmadev->fp_obj->dev_private = dmadev->data->dev_private; 6031ea2cdc1SBruce Richardson 6041ea2cdc1SBruce Richardson if (rte_eal_process_type() != RTE_PROC_PRIMARY) 6051ea2cdc1SBruce Richardson return 0; 6063d36a0a1SKevin Laatz 60755dc0f60SKevin Laatz idxd = dmadev->data->dev_private; 60855dc0f60SKevin Laatz *idxd = *base_idxd; /* copy over the main fields already passed in */ 60955dc0f60SKevin Laatz idxd->dmadev = dmadev; 61055dc0f60SKevin Laatz 61155dc0f60SKevin Laatz /* allocate batch index ring and completion ring. 61255dc0f60SKevin Laatz * The +1 is because we can never fully use 61355dc0f60SKevin Laatz * the ring, otherwise read == write means both full and empty. 61455dc0f60SKevin Laatz */ 61555dc0f60SKevin Laatz idxd->batch_comp_ring = rte_zmalloc_socket(NULL, (sizeof(idxd->batch_idx_ring[0]) + 61655dc0f60SKevin Laatz sizeof(idxd->batch_comp_ring[0])) * (idxd->max_batches + 1), 61755dc0f60SKevin Laatz sizeof(idxd->batch_comp_ring[0]), dev->numa_node); 61855dc0f60SKevin Laatz if (idxd->batch_comp_ring == NULL) { 619*f665790aSDavid Marchand IDXD_PMD_ERR("Unable to reserve memory for batch data"); 62055dc0f60SKevin Laatz ret = -ENOMEM; 62155dc0f60SKevin Laatz goto cleanup; 62255dc0f60SKevin Laatz } 62355dc0f60SKevin Laatz idxd->batch_idx_ring = (void *)&idxd->batch_comp_ring[idxd->max_batches+1]; 62455dc0f60SKevin Laatz idxd->batch_iova = rte_mem_virt2iova(idxd->batch_comp_ring); 62555dc0f60SKevin Laatz 62655dc0f60SKevin Laatz idxd->dmadev->state = RTE_DMA_DEV_READY; 62755dc0f60SKevin Laatz 62855dc0f60SKevin Laatz return 0; 62955dc0f60SKevin Laatz 63055dc0f60SKevin Laatz cleanup: 63155dc0f60SKevin Laatz if (dmadev) 63255dc0f60SKevin Laatz rte_dma_pmd_release(name); 63355dc0f60SKevin Laatz 63455dc0f60SKevin Laatz return ret; 63555dc0f60SKevin Laatz } 63655dc0f60SKevin Laatz 637e33ad06eSKevin Laatz int idxd_pmd_logtype; 638e33ad06eSKevin Laatz 639e33ad06eSKevin Laatz RTE_LOG_REGISTER_DEFAULT(idxd_pmd_logtype, WARNING); 640