Commit c694b233 authored by George Cherian's avatar George Cherian Committed by Herbert Xu

crypto: cavium - Add the Virtual Function driver for CPT

Enable the CPT VF driver. CPT is the cryptographic Acceleration Unit
in Octeon-tx series of processors.
Signed-off-by: default avatarGeorge Cherian <george.cherian@cavium.com>
Reviewed-by: default avatarDavid Daney <david.daney@cavium.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 9e2c7d99
obj-$(CONFIG_CAVIUM_CPT) += cptpf.o
obj-$(CONFIG_CAVIUM_CPT) += cptpf.o cptvf.o
cptpf-objs := cptpf_main.o cptpf_mbox.o
cptvf-objs := cptvf_main.o cptvf_reqmanager.o cptvf_mbox.o cptvf_algs.o
/*
* Copyright (C) 2016 Cavium, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License
* as published by the Free Software Foundation.
*/
#ifndef __CPTVF_H
#define __CPTVF_H
#include <linux/list.h>
#include "cpt_common.h"
/* Default command queue length */
#define CPT_CMD_QLEN 2046
#define CPT_CMD_QCHUNK_SIZE 1023
/* Default command timeout in seconds */
#define CPT_COMMAND_TIMEOUT 4
#define CPT_TIMER_THOLD 0xFFFF
#define CPT_NUM_QS_PER_VF 1
#define CPT_INST_SIZE 64
#define CPT_NEXT_CHUNK_PTR_SIZE 8
#define CPT_VF_MSIX_VECTORS 2
#define CPT_VF_INTR_MBOX_MASK BIT(0)
#define CPT_VF_INTR_DOVF_MASK BIT(1)
#define CPT_VF_INTR_IRDE_MASK BIT(2)
#define CPT_VF_INTR_NWRP_MASK BIT(3)
#define CPT_VF_INTR_SERR_MASK BIT(4)
#define DMA_DIRECT_DIRECT 0 /* Input DIRECT, Output DIRECT */
#define DMA_GATHER_SCATTER 1
#define FROM_DPTR 1
/**
* Enumeration cpt_vf_int_vec_e
*
* CPT VF MSI-X Vector Enumeration
* Enumerates the MSI-X interrupt vectors.
*/
enum cpt_vf_int_vec_e {
CPT_VF_INT_VEC_E_MISC = 0x00,
CPT_VF_INT_VEC_E_DONE = 0x01
};
struct command_chunk {
u8 *head;
dma_addr_t dma_addr;
u32 size; /* Chunk size, max CPT_INST_CHUNK_MAX_SIZE */
struct hlist_node nextchunk;
};
struct command_queue {
spinlock_t lock; /* command queue lock */
u32 idx; /* Command queue host write idx */
u32 nchunks; /* Number of command chunks */
struct command_chunk *qhead; /* Command queue head, instructions
* are inserted here
*/
struct hlist_head chead;
};
struct command_qinfo {
u32 cmd_size;
u32 qchunksize; /* Command queue chunk size */
struct command_queue queue[CPT_NUM_QS_PER_VF];
};
struct pending_entry {
u8 busy; /* Entry status (free/busy) */
volatile u64 *completion_addr; /* Completion address */
void *post_arg;
void (*callback)(int, void *); /* Kernel ASYNC request callabck */
void *callback_arg; /* Kernel ASYNC request callabck arg */
};
struct pending_queue {
struct pending_entry *head; /* head of the queue */
u32 front; /* Process work from here */
u32 rear; /* Append new work here */
atomic64_t pending_count;
spinlock_t lock; /* Queue lock */
};
struct pending_qinfo {
u32 nr_queues; /* Number of queues supported */
u32 qlen; /* Queue length */
struct pending_queue queue[CPT_NUM_QS_PER_VF];
};
#define for_each_pending_queue(qinfo, q, i) \
for (i = 0, q = &qinfo->queue[i]; i < qinfo->nr_queues; i++, \
q = &qinfo->queue[i])
struct cpt_vf {
u16 flags; /* Flags to hold device status bits */
u8 vfid; /* Device Index 0...CPT_MAX_VF_NUM */
u8 vftype; /* VF type of SE_TYPE(1) or AE_TYPE(1) */
u8 vfgrp; /* VF group (0 - 8) */
u8 node; /* Operating node: Bits (46:44) in BAR0 address */
u8 priority; /* VF priority ring: 1-High proirity round
* robin ring;0-Low priority round robin ring;
*/
struct pci_dev *pdev; /* pci device handle */
void __iomem *reg_base; /* Register start address */
void *wqe_info; /* BH worker info */
/* MSI-X */
bool msix_enabled;
struct msix_entry msix_entries[CPT_VF_MSIX_VECTORS];
bool irq_allocated[CPT_VF_MSIX_VECTORS];
cpumask_var_t affinity_mask[CPT_VF_MSIX_VECTORS];
/* Command and Pending queues */
u32 qsize;
u32 nr_queues;
struct command_qinfo cqinfo; /* Command queue information */
struct pending_qinfo pqinfo; /* Pending queue information */
/* VF-PF mailbox communication */
bool pf_acked;
bool pf_nacked;
};
int cptvf_send_vf_up(struct cpt_vf *cptvf);
int cptvf_send_vf_down(struct cpt_vf *cptvf);
int cptvf_send_vf_to_grp_msg(struct cpt_vf *cptvf);
int cptvf_send_vf_priority_msg(struct cpt_vf *cptvf);
int cptvf_send_vq_size_msg(struct cpt_vf *cptvf);
int cptvf_check_pf_ready(struct cpt_vf *cptvf);
void cptvf_handle_mbox_intr(struct cpt_vf *cptvf);
void cvm_crypto_exit(void);
int cvm_crypto_init(struct cpt_vf *cptvf);
void vq_post_process(struct cpt_vf *cptvf, u32 qno);
void cptvf_write_vq_doorbell(struct cpt_vf *cptvf, u32 val);
#endif /* __CPTVF_H */
This diff is collapsed.
/*
* Copyright (C) 2016 Cavium, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License
* as published by the Free Software Foundation.
*/
#ifndef _CPTVF_ALGS_H_
#define _CPTVF_ALGS_H_
#include "request_manager.h"
#define MAX_DEVICES 16
#define MAJOR_OP_FC 0x33
#define MAX_ENC_KEY_SIZE 32
#define MAX_HASH_KEY_SIZE 64
#define MAX_KEY_SIZE (MAX_ENC_KEY_SIZE + MAX_HASH_KEY_SIZE)
#define CONTROL_WORD_LEN 8
#define KEY2_OFFSET 48
#define DMA_MODE_FLAG(dma_mode) \
(((dma_mode) == DMA_GATHER_SCATTER) ? (1 << 7) : 0)
enum req_type {
AE_CORE_REQ,
SE_CORE_REQ,
};
enum cipher_type {
DES3_CBC = 0x1,
DES3_ECB = 0x2,
AES_CBC = 0x3,
AES_ECB = 0x4,
AES_CFB = 0x5,
AES_CTR = 0x6,
AES_GCM = 0x7,
AES_XTS = 0x8
};
enum aes_type {
AES_128_BIT = 0x1,
AES_192_BIT = 0x2,
AES_256_BIT = 0x3
};
union encr_ctrl {
u64 flags;
struct {
#if defined(__BIG_ENDIAN_BITFIELD)
u64 enc_cipher:4;
u64 reserved1:1;
u64 aes_key:2;
u64 iv_source:1;
u64 hash_type:4;
u64 reserved2:3;
u64 auth_input_type:1;
u64 mac_len:8;
u64 reserved3:8;
u64 encr_offset:16;
u64 iv_offset:8;
u64 auth_offset:8;
#else
u64 auth_offset:8;
u64 iv_offset:8;
u64 encr_offset:16;
u64 reserved3:8;
u64 mac_len:8;
u64 auth_input_type:1;
u64 reserved2:3;
u64 hash_type:4;
u64 iv_source:1;
u64 aes_key:2;
u64 reserved1:1;
u64 enc_cipher:4;
#endif
} e;
};
struct enc_context {
union encr_ctrl enc_ctrl;
u8 encr_key[32];
u8 encr_iv[16];
};
struct fchmac_context {
u8 ipad[64];
u8 opad[64]; /* or OPAD */
};
struct fc_context {
struct enc_context enc;
struct fchmac_context hmac;
};
struct cvm_enc_ctx {
u32 key_len;
u8 enc_key[MAX_KEY_SIZE];
};
struct cvm_des3_ctx {
u32 key_len;
u8 des3_key[MAX_KEY_SIZE];
};
struct cvm_req_ctx {
struct cpt_request_info cpt_req;
u64 control_word;
struct fc_context fctx;
};
int cptvf_do_request(void *cptvf, struct cpt_request_info *req);
#endif /*_CPTVF_ALGS_H_*/
This diff is collapsed.
/*
* Copyright (C) 2016 Cavium, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License
* as published by the Free Software Foundation.
*/
#include "cptvf.h"
static void cptvf_send_msg_to_pf(struct cpt_vf *cptvf, struct cpt_mbox *mbx)
{
/* Writing mbox(1) causes interrupt */
cpt_write_csr64(cptvf->reg_base, CPTX_VFX_PF_MBOXX(0, 0, 0),
mbx->msg);
cpt_write_csr64(cptvf->reg_base, CPTX_VFX_PF_MBOXX(0, 0, 1),
mbx->data);
}
/* ACKs PF's mailbox message
*/
void cptvf_mbox_send_ack(struct cpt_vf *cptvf, struct cpt_mbox *mbx)
{
mbx->msg = CPT_MBOX_MSG_TYPE_ACK;
cptvf_send_msg_to_pf(cptvf, mbx);
}
/* NACKs PF's mailbox message that VF is not able to
* complete the action
*/
void cptvf_mbox_send_nack(struct cpt_vf *cptvf, struct cpt_mbox *mbx)
{
mbx->msg = CPT_MBOX_MSG_TYPE_NACK;
cptvf_send_msg_to_pf(cptvf, mbx);
}
/* Interrupt handler to handle mailbox messages from VFs */
void cptvf_handle_mbox_intr(struct cpt_vf *cptvf)
{
struct cpt_mbox mbx = {};
/*
* MBOX[0] contains msg
* MBOX[1] contains data
*/
mbx.msg = cpt_read_csr64(cptvf->reg_base, CPTX_VFX_PF_MBOXX(0, 0, 0));
mbx.data = cpt_read_csr64(cptvf->reg_base, CPTX_VFX_PF_MBOXX(0, 0, 1));
dev_dbg(&cptvf->pdev->dev, "%s: Mailbox msg 0x%llx from PF\n",
__func__, mbx.msg);
switch (mbx.msg) {
case CPT_MSG_READY:
{
cptvf->pf_acked = true;
cptvf->vfid = mbx.data;
dev_dbg(&cptvf->pdev->dev, "Received VFID %d\n", cptvf->vfid);
break;
}
case CPT_MSG_QBIND_GRP:
cptvf->pf_acked = true;
cptvf->vftype = mbx.data;
dev_dbg(&cptvf->pdev->dev, "VF %d type %s group %d\n",
cptvf->vfid, ((mbx.data == SE_TYPES) ? "SE" : "AE"),
cptvf->vfgrp);
break;
case CPT_MBOX_MSG_TYPE_ACK:
cptvf->pf_acked = true;
break;
case CPT_MBOX_MSG_TYPE_NACK:
cptvf->pf_nacked = true;
break;
default:
dev_err(&cptvf->pdev->dev, "Invalid msg from PF, msg 0x%llx\n",
mbx.msg);
break;
}
}
static int cptvf_send_msg_to_pf_timeout(struct cpt_vf *cptvf,
struct cpt_mbox *mbx)
{
int timeout = CPT_MBOX_MSG_TIMEOUT;
int sleep = 10;
cptvf->pf_acked = false;
cptvf->pf_nacked = false;
cptvf_send_msg_to_pf(cptvf, mbx);
/* Wait for previous message to be acked, timeout 2sec */
while (!cptvf->pf_acked) {
if (cptvf->pf_nacked)
return -EINVAL;
msleep(sleep);
if (cptvf->pf_acked)
break;
timeout -= sleep;
if (!timeout) {
dev_err(&cptvf->pdev->dev, "PF didn't ack to mbox msg %llx from VF%u\n",
(mbx->msg & 0xFF), cptvf->vfid);
return -EBUSY;
}
}
return 0;
}
/*
* Checks if VF is able to comminicate with PF
* and also gets the CPT number this VF is associated to.
*/
int cptvf_check_pf_ready(struct cpt_vf *cptvf)
{
struct pci_dev *pdev = cptvf->pdev;
struct cpt_mbox mbx = {};
mbx.msg = CPT_MSG_READY;
if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) {
dev_err(&pdev->dev, "PF didn't respond to READY msg\n");
return -EBUSY;
}
return 0;
}
/*
* Communicate VQs size to PF to program CPT(0)_PF_Q(0-15)_CTL of the VF.
* Must be ACKed.
*/
int cptvf_send_vq_size_msg(struct cpt_vf *cptvf)
{
struct pci_dev *pdev = cptvf->pdev;
struct cpt_mbox mbx = {};
mbx.msg = CPT_MSG_QLEN;
mbx.data = cptvf->qsize;
if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) {
dev_err(&pdev->dev, "PF didn't respond to vq_size msg\n");
return -EBUSY;
}
return 0;
}
/*
* Communicate VF group required to PF and get the VQ binded to that group
*/
int cptvf_send_vf_to_grp_msg(struct cpt_vf *cptvf)
{
struct pci_dev *pdev = cptvf->pdev;
struct cpt_mbox mbx = {};
mbx.msg = CPT_MSG_QBIND_GRP;
/* Convey group of the VF */
mbx.data = cptvf->vfgrp;
if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) {
dev_err(&pdev->dev, "PF didn't respond to vf_type msg\n");
return -EBUSY;
}
return 0;
}
/*
* Communicate VF group required to PF and get the VQ binded to that group
*/
int cptvf_send_vf_priority_msg(struct cpt_vf *cptvf)
{
struct pci_dev *pdev = cptvf->pdev;
struct cpt_mbox mbx = {};
mbx.msg = CPT_MSG_VQ_PRIORITY;
/* Convey group of the VF */
mbx.data = cptvf->priority;
if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) {
dev_err(&pdev->dev, "PF didn't respond to vf_type msg\n");
return -EBUSY;
}
return 0;
}
/*
* Communicate to PF that VF is UP and running
*/
int cptvf_send_vf_up(struct cpt_vf *cptvf)
{
struct pci_dev *pdev = cptvf->pdev;
struct cpt_mbox mbx = {};
mbx.msg = CPT_MSG_VF_UP;
if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) {
dev_err(&pdev->dev, "PF didn't respond to UP msg\n");
return -EBUSY;
}
return 0;
}
/*
* Communicate to PF that VF is DOWN and running
*/
int cptvf_send_vf_down(struct cpt_vf *cptvf)
{
struct pci_dev *pdev = cptvf->pdev;
struct cpt_mbox mbx = {};
mbx.msg = CPT_MSG_VF_DOWN;
if (cptvf_send_msg_to_pf_timeout(cptvf, &mbx)) {
dev_err(&pdev->dev, "PF didn't respond to DOWN msg\n");
return -EBUSY;
}
return 0;
}
This diff is collapsed.
/*
* Copyright (C) 2016 Cavium, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License
* as published by the Free Software Foundation.
*/
#ifndef __REQUEST_MANAGER_H
#define __REQUEST_MANAGER_H
#include "cpt_common.h"
#define TIME_IN_RESET_COUNT 5
#define COMPLETION_CODE_SIZE 8
#define COMPLETION_CODE_INIT 0
#define PENDING_THOLD 100
#define MAX_SG_IN_CNT 12
#define MAX_SG_OUT_CNT 13
#define SG_LIST_HDR_SIZE 8
#define MAX_BUF_CNT 16
union ctrl_info {
u32 flags;
struct {
#if defined(__BIG_ENDIAN_BITFIELD)
u32 reserved0:26;
u32 grp:3; /* Group bits */
u32 dma_mode:2; /* DMA mode */
u32 se_req:1;/* To SE core */
#else
u32 se_req:1; /* To SE core */
u32 dma_mode:2; /* DMA mode */
u32 grp:3; /* Group bits */
u32 reserved0:26;
#endif
} s;
};
union opcode_info {
u16 flags;
struct {
u8 major;
u8 minor;
} s;
};
struct cptvf_request {
union opcode_info opcode;
u16 param1;
u16 param2;
u16 dlen;
};
struct buf_ptr {
u8 *vptr;
dma_addr_t dma_addr;
u16 size;
};
struct cpt_request_info {
u8 incnt; /* Number of input buffers */
u8 outcnt; /* Number of output buffers */
u16 rlen; /* Output length */
union ctrl_info ctrl; /* User control information */
struct cptvf_request req; /* Request Information (Core specific) */
struct buf_ptr in[MAX_BUF_CNT];
struct buf_ptr out[MAX_BUF_CNT];
void (*callback)(int, void *); /* Kernel ASYNC request callabck */
void *callback_arg; /* Kernel ASYNC request callabck arg */
};
struct sglist_component {
union {
u64 len;
struct {
u16 len0;
u16 len1;
u16 len2;
u16 len3;
} s;
} u;
u64 ptr0;
u64 ptr1;
u64 ptr2;
u64 ptr3;
};
struct cpt_info_buffer {
struct cpt_vf *cptvf;
unsigned long time_in;
u8 extra_time;
struct cpt_request_info *req;
dma_addr_t dptr_baddr;
u32 dlen;
dma_addr_t rptr_baddr;
dma_addr_t comp_baddr;
u8 *in_buffer;
u8 *out_buffer;
u8 *gather_components;
u8 *scatter_components;
struct pending_entry *pentry;
volatile u64 *completion_addr;
volatile u64 *alternate_caddr;
};
/*
* CPT_INST_S software command definitions
* Words EI (0-3)
*/
union vq_cmd_word0 {
u64 u64;
struct {
u16 opcode;
u16 param1;
u16 param2;
u16 dlen;
} s;
};
union vq_cmd_word3 {
u64 u64;
struct {
#if defined(__BIG_ENDIAN_BITFIELD)
u64 grp:3;
u64 cptr:61;
#else
u64 cptr:61;
u64 grp:3;
#endif
} s;
};
struct cpt_vq_command {
union vq_cmd_word0 cmd;
u64 dptr;
u64 rptr;
union vq_cmd_word3 cptr;
};
void vq_post_process(struct cpt_vf *cptvf, u32 qno);
int process_request(struct cpt_vf *cptvf, struct cpt_request_info *req);
#endif /* __REQUEST_MANAGER_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment