diff options
Diffstat (limited to 'drivers/crypto/octeontx/otx_cryptodev_hw_access.h')
-rw-r--r-- | drivers/crypto/octeontx/otx_cryptodev_hw_access.h | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/drivers/crypto/octeontx/otx_cryptodev_hw_access.h b/drivers/crypto/octeontx/otx_cryptodev_hw_access.h new file mode 100644 index 00000000..82b15eea --- /dev/null +++ b/drivers/crypto/octeontx/otx_cryptodev_hw_access.h @@ -0,0 +1,320 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018 Cavium, Inc + */ +#ifndef _OTX_CRYPTODEV_HW_ACCESS_H_ +#define _OTX_CRYPTODEV_HW_ACCESS_H_ + +#include <stdbool.h> + +#include <rte_branch_prediction.h> +#include <rte_cycles.h> +#include <rte_io.h> +#include <rte_memory.h> +#include <rte_prefetch.h> + +#include "cpt_common.h" +#include "cpt_hw_types.h" +#include "cpt_mcode_defines.h" +#include "cpt_pmd_logs.h" + +#define CPT_INTR_POLL_INTERVAL_MS (50) + +/* Default command queue length */ +#define DEFAULT_CMD_QCHUNKS 2 +#define DEFAULT_CMD_QCHUNK_SIZE 1023 +#define DEFAULT_CMD_QLEN \ + (DEFAULT_CMD_QCHUNK_SIZE * DEFAULT_CMD_QCHUNKS) + +#define CPT_CSR_REG_BASE(cpt) ((cpt)->reg_base) + +/* Read hw register */ +#define CPT_READ_CSR(__hw_addr, __offset) \ + rte_read64_relaxed((uint8_t *)__hw_addr + __offset) + +/* Write hw register */ +#define CPT_WRITE_CSR(__hw_addr, __offset, __val) \ + rte_write64_relaxed((__val), ((uint8_t *)__hw_addr + __offset)) + +/* cpt instance */ +struct cpt_instance { + uint32_t queue_id; + uintptr_t rsvd; +}; + +struct command_chunk { + /** 128-byte aligned real_vaddr */ + uint8_t *head; + /** 128-byte aligned real_dma_addr */ + phys_addr_t dma_addr; +}; + +/** + * Command queue structure + */ +struct command_queue { + /** Command queue host write idx */ + uint32_t idx; + /** Command queue chunk */ + uint32_t cchunk; + /** Command queue head; instructions are inserted here */ + uint8_t *qhead; + /** Command chunk list head */ + struct command_chunk chead[DEFAULT_CMD_QCHUNKS]; +}; + +/** + * CPT VF device structure + */ +struct cpt_vf { + /** CPT instance */ + struct cpt_instance instance; + /** Register start address */ + uint8_t *reg_base; + /** Command queue information */ + struct command_queue cqueue; + /** Pending queue information */ + struct pending_queue pqueue; + /** Meta information per vf */ + struct cptvf_meta_info meta_info; + + /** Below fields are accessed only in control path */ + + /** Env specific pdev representing the pci dev */ + void *pdev; + /** Calculated queue size */ + uint32_t qsize; + /** Device index (0...CPT_MAX_VQ_NUM)*/ + uint8_t vfid; + /** VF type of cpt_vf_type_t (SE_TYPE(2) or AE_TYPE(1) */ + uint8_t vftype; + /** VF group (0 - 8) */ + uint8_t vfgrp; + /** Operating node: Bits (46:44) in BAR0 address */ + uint8_t node; + + /** VF-PF mailbox communication */ + + /** Flag if acked */ + bool pf_acked; + /** Flag if not acked */ + bool pf_nacked; + + /** Device name */ + char dev_name[32]; +} __rte_cache_aligned; + +/* + * CPT Registers map for 81xx + */ + +/* VF registers */ +#define CPTX_VQX_CTL(a, b) (0x0000100ll + 0x1000000000ll * \ + ((a) & 0x0) + 0x100000ll * (b)) +#define CPTX_VQX_SADDR(a, b) (0x0000200ll + 0x1000000000ll * \ + ((a) & 0x0) + 0x100000ll * (b)) +#define CPTX_VQX_DONE_WAIT(a, b) (0x0000400ll + 0x1000000000ll * \ + ((a) & 0x0) + 0x100000ll * (b)) +#define CPTX_VQX_INPROG(a, b) (0x0000410ll + 0x1000000000ll * \ + ((a) & 0x0) + 0x100000ll * (b)) +#define CPTX_VQX_DONE(a, b) (0x0000420ll + 0x1000000000ll * \ + ((a) & 0x1) + 0x100000ll * (b)) +#define CPTX_VQX_DONE_ACK(a, b) (0x0000440ll + 0x1000000000ll * \ + ((a) & 0x1) + 0x100000ll * (b)) +#define CPTX_VQX_DONE_INT_W1S(a, b) (0x0000460ll + 0x1000000000ll * \ + ((a) & 0x1) + 0x100000ll * (b)) +#define CPTX_VQX_DONE_INT_W1C(a, b) (0x0000468ll + 0x1000000000ll * \ + ((a) & 0x1) + 0x100000ll * (b)) +#define CPTX_VQX_DONE_ENA_W1S(a, b) (0x0000470ll + 0x1000000000ll * \ + ((a) & 0x1) + 0x100000ll * (b)) +#define CPTX_VQX_DONE_ENA_W1C(a, b) (0x0000478ll + 0x1000000000ll * \ + ((a) & 0x1) + 0x100000ll * (b)) +#define CPTX_VQX_MISC_INT(a, b) (0x0000500ll + 0x1000000000ll * \ + ((a) & 0x1) + 0x100000ll * (b)) +#define CPTX_VQX_MISC_INT_W1S(a, b) (0x0000508ll + 0x1000000000ll * \ + ((a) & 0x1) + 0x100000ll * (b)) +#define CPTX_VQX_MISC_ENA_W1S(a, b) (0x0000510ll + 0x1000000000ll * \ + ((a) & 0x1) + 0x100000ll * (b)) +#define CPTX_VQX_MISC_ENA_W1C(a, b) (0x0000518ll + 0x1000000000ll * \ + ((a) & 0x1) + 0x100000ll * (b)) +#define CPTX_VQX_DOORBELL(a, b) (0x0000600ll + 0x1000000000ll * \ + ((a) & 0x1) + 0x100000ll * (b)) +#define CPTX_VFX_PF_MBOXX(a, b, c) (0x0001000ll + 0x1000000000ll * \ + ((a) & 0x1) + 0x100000ll * (b) + \ + 8ll * ((c) & 0x1)) + +/* VF HAL functions */ + +void +otx_cpt_poll_misc(struct cpt_vf *cptvf); + +int +otx_cpt_hw_init(struct cpt_vf *cptvf, void *pdev, void *reg_base, char *name); + +int +otx_cpt_deinit_device(void *dev); + +int +otx_cpt_get_resource(void *dev, uint8_t group, struct cpt_instance **instance); + +int +otx_cpt_put_resource(struct cpt_instance *instance); + +int +otx_cpt_start_device(void *cptvf); + +void +otx_cpt_stop_device(void *cptvf); + +/* Write to VQX_DOORBELL register + */ +static __rte_always_inline void +otx_cpt_write_vq_doorbell(struct cpt_vf *cptvf, uint32_t val) +{ + cptx_vqx_doorbell_t vqx_dbell; + + vqx_dbell.u = 0; + vqx_dbell.s.dbell_cnt = val * 8; /* Num of Instructions * 8 words */ + CPT_WRITE_CSR(CPT_CSR_REG_BASE(cptvf), + CPTX_VQX_DOORBELL(0, 0), vqx_dbell.u); +} + +static __rte_always_inline uint32_t +otx_cpt_read_vq_doorbell(struct cpt_vf *cptvf) +{ + cptx_vqx_doorbell_t vqx_dbell; + + vqx_dbell.u = CPT_READ_CSR(CPT_CSR_REG_BASE(cptvf), + CPTX_VQX_DOORBELL(0, 0)); + return vqx_dbell.s.dbell_cnt; +} + +static __rte_always_inline void +otx_cpt_ring_dbell(struct cpt_instance *instance, uint16_t count) +{ + struct cpt_vf *cptvf = (struct cpt_vf *)instance; + /* Memory barrier to flush pending writes */ + rte_smp_wmb(); + otx_cpt_write_vq_doorbell(cptvf, count); +} + +static __rte_always_inline void * +get_cpt_inst(struct command_queue *cqueue) +{ + CPT_LOG_DP_DEBUG("CPT queue idx %u\n", cqueue->idx); + return &cqueue->qhead[cqueue->idx * CPT_INST_SIZE]; +} + +static __rte_always_inline void +fill_cpt_inst(struct cpt_instance *instance, void *req) +{ + struct command_queue *cqueue; + cpt_inst_s_t *cpt_ist_p; + struct cpt_vf *cptvf = (struct cpt_vf *)instance; + struct cpt_request_info *user_req = (struct cpt_request_info *)req; + cqueue = &cptvf->cqueue; + cpt_ist_p = get_cpt_inst(cqueue); + rte_prefetch_non_temporal(cpt_ist_p); + + /* EI0, EI1, EI2, EI3 are already prepared */ + /* HW W0 */ + cpt_ist_p->u[0] = 0; + /* HW W1 */ + cpt_ist_p->s8x.res_addr = user_req->comp_baddr; + /* HW W2 */ + cpt_ist_p->u[2] = 0; + /* HW W3 */ + cpt_ist_p->s8x.wq_ptr = 0; + + /* MC EI0 */ + cpt_ist_p->s8x.ei0 = user_req->ist.ei0; + /* MC EI1 */ + cpt_ist_p->s8x.ei1 = user_req->ist.ei1; + /* MC EI2 */ + cpt_ist_p->s8x.ei2 = user_req->ist.ei2; + /* MC EI3 */ + cpt_ist_p->s8x.ei3 = user_req->ist.ei3; +} + +static __rte_always_inline void +mark_cpt_inst(struct cpt_instance *instance) +{ + struct cpt_vf *cptvf = (struct cpt_vf *)instance; + struct command_queue *queue = &cptvf->cqueue; + if (unlikely(++queue->idx >= DEFAULT_CMD_QCHUNK_SIZE)) { + uint32_t cchunk = queue->cchunk; + MOD_INC(cchunk, DEFAULT_CMD_QCHUNKS); + queue->qhead = queue->chead[cchunk].head; + queue->idx = 0; + queue->cchunk = cchunk; + } +} + +static __rte_always_inline uint8_t +check_nb_command_id(struct cpt_request_info *user_req, + struct cpt_instance *instance) +{ + uint8_t ret = ERR_REQ_PENDING; + struct cpt_vf *cptvf = (struct cpt_vf *)instance; + volatile cpt_res_s_t *cptres; + + cptres = (volatile cpt_res_s_t *)user_req->completion_addr; + + if (unlikely(cptres->s8x.compcode == CPT_8X_COMP_E_NOTDONE)) { + /* + * Wait for some time for this command to get completed + * before timing out + */ + if (rte_get_timer_cycles() < user_req->time_out) + return ret; + /* + * TODO: See if alternate caddr can be used to not loop + * longer than needed. + */ + if ((cptres->s8x.compcode == CPT_8X_COMP_E_NOTDONE) && + (user_req->extra_time < TIME_IN_RESET_COUNT)) { + user_req->extra_time++; + return ret; + } + + if (cptres->s8x.compcode != CPT_8X_COMP_E_NOTDONE) + goto complete; + + ret = ERR_REQ_TIMEOUT; + CPT_LOG_DP_ERR("Request %p timedout", user_req); + otx_cpt_poll_misc(cptvf); + goto exit; + } + +complete: + if (likely(cptres->s8x.compcode == CPT_8X_COMP_E_GOOD)) { + ret = 0; /* success */ + if (unlikely((uint8_t)*user_req->alternate_caddr)) { + ret = (uint8_t)*user_req->alternate_caddr; + CPT_LOG_DP_ERR("Request %p : failed with microcode" + " error, MC completion code : 0x%x", user_req, + ret); + } + CPT_LOG_DP_DEBUG("MC status %.8x\n", + *((volatile uint32_t *)user_req->alternate_caddr)); + CPT_LOG_DP_DEBUG("HW status %.8x\n", + *((volatile uint32_t *)user_req->completion_addr)); + } else if ((cptres->s8x.compcode == CPT_8X_COMP_E_SWERR) || + (cptres->s8x.compcode == CPT_8X_COMP_E_FAULT)) { + ret = (uint8_t)*user_req->alternate_caddr; + if (!ret) + ret = ERR_BAD_ALT_CCODE; + CPT_LOG_DP_DEBUG("Request %p : failed with %s : err code :%x", + user_req, + (cptres->s8x.compcode == CPT_8X_COMP_E_FAULT) ? + "DMA Fault" : "Software error", ret); + } else { + CPT_LOG_DP_ERR("Request %p : unexpected completion code %d", + user_req, cptres->s8x.compcode); + ret = (uint8_t)*user_req->alternate_caddr; + } + +exit: + return ret; +} + +#endif /* _OTX_CRYPTODEV_HW_ACCESS_H_ */ |