#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/cpu.h>
#include <sys/kernel.h>
#include <sys/mbuf.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/sysctl.h>
#include <opencrypto/cryptodev.h>
#include "cryptodev_if.h"
#include "cpa.h"
#include "cpa_cy_im.h"
#include "cpa_cy_sym_dp.h"
#include "adf_accel_devices.h"
#include "adf_common_drv.h"
#include "lac_sym_hash_defs.h"
#include "lac_sym_qat_hash_defs_lookup.h"
#include "icp_accel_devices.h"
#include "icp_adf_accel_mgr.h"
#include "lac_sal_types.h"
#include "icp_sal_user.h"
#include "qat_ocf_mem_pool.h"
#include "qat_ocf_utils.h"
#define QAT_OCF_MAX_INSTANCES (256)
#define QAT_OCF_SESSION_WAIT_TIMEOUT_MS (1000)
MALLOC_DEFINE(M_QAT_OCF, "qat_ocf", "qat_ocf(4) memory allocations");
struct qat_ocf_softc {
device_t sc_dev;
struct sysctl_oid *rc;
uint32_t enabled;
int32_t cryptodev_id;
struct qat_ocf_instance cyInstHandles[QAT_OCF_MAX_INSTANCES];
int32_t numCyInstances;
};
static void qat_ocf_freesession(device_t dev, crypto_session_t cses);
static int qat_ocf_probesession(device_t dev,
const struct crypto_session_params *csp);
static int qat_ocf_newsession(device_t dev,
crypto_session_t cses,
const struct crypto_session_params *csp);
static int qat_ocf_attach(device_t dev);
static int qat_ocf_detach(device_t dev);
static void
symDpCallback(CpaCySymDpOpData *pOpData,
CpaStatus result,
CpaBoolean verifyResult)
{
struct qat_ocf_cookie *qat_cookie;
struct cryptop *crp;
struct qat_ocf_dsession *qat_dsession = NULL;
struct qat_ocf_session *qat_session = NULL;
struct qat_ocf_instance *qat_instance = NULL;
CpaStatus status;
int rc = 0;
qat_cookie = (struct qat_ocf_cookie *)pOpData->pCallbackTag;
if (!qat_cookie)
return;
crp = qat_cookie->crp_op;
qat_dsession = crypto_get_driver_session(crp->crp_session);
qat_instance = qat_dsession->qatInstance;
status = qat_ocf_cookie_dma_post_sync(crp, pOpData);
if (CPA_STATUS_SUCCESS != status) {
rc = EIO;
goto exit;
}
status = qat_ocf_cookie_dma_unload(crp, pOpData);
if (CPA_STATUS_SUCCESS != status) {
rc = EIO;
goto exit;
}
if (CPA_STATUS_SUCCESS != result) {
rc = EBADMSG;
goto exit;
}
if (CPA_TRUE != verifyResult) {
rc = EBADMSG;
goto exit;
}
if (CRYPTO_OP_IS_ENCRYPT(crp->crp_op))
qat_session = &qat_dsession->encSession;
else
qat_session = &qat_dsession->decSession;
if (pOpData->digestResult && qat_session->authLen > 0) {
if ((crp->crp_op & CRYPTO_OP_VERIFY_DIGEST) != 0) {
char icv[QAT_OCF_MAX_DIGEST] = { 0 };
crypto_copydata(crp,
crp->crp_digest_start,
qat_session->authLen,
icv);
if (timingsafe_bcmp(icv,
qat_cookie->qat_ocf_digest,
qat_session->authLen) != 0) {
rc = EBADMSG;
goto exit;
}
} else {
crypto_copyback(crp,
crp->crp_digest_start,
qat_session->authLen,
qat_cookie->qat_ocf_digest);
}
}
exit:
qat_ocf_cookie_free(qat_instance, qat_cookie);
crp->crp_etype = rc;
crypto_done(crp);
return;
}
static inline CpaPhysicalAddr
qatVirtToPhys(void *virtAddr)
{
return (CpaPhysicalAddr)vtophys(virtAddr);
}
static int
qat_ocf_probesession(device_t dev, const struct crypto_session_params *csp)
{
if ((csp->csp_flags & ~(CSP_F_SEPARATE_OUTPUT | CSP_F_SEPARATE_AAD)) !=
0) {
return EINVAL;
}
switch (csp->csp_mode) {
case CSP_MODE_CIPHER:
switch (csp->csp_cipher_alg) {
case CRYPTO_AES_CBC:
case CRYPTO_AES_ICM:
if (csp->csp_ivlen != AES_BLOCK_LEN)
return EINVAL;
break;
case CRYPTO_AES_XTS:
if (csp->csp_ivlen != AES_XTS_IV_LEN)
return EINVAL;
break;
default:
return EINVAL;
}
break;
case CSP_MODE_DIGEST:
switch (csp->csp_auth_alg) {
case CRYPTO_SHA1:
case CRYPTO_SHA1_HMAC:
case CRYPTO_SHA2_256:
case CRYPTO_SHA2_256_HMAC:
case CRYPTO_SHA2_384:
case CRYPTO_SHA2_384_HMAC:
case CRYPTO_SHA2_512:
case CRYPTO_SHA2_512_HMAC:
break;
case CRYPTO_AES_NIST_GMAC:
if (csp->csp_ivlen != AES_GCM_IV_LEN)
return EINVAL;
break;
default:
return EINVAL;
}
break;
case CSP_MODE_AEAD:
switch (csp->csp_cipher_alg) {
case CRYPTO_AES_NIST_GCM_16:
if (csp->csp_ivlen != AES_GCM_IV_LEN)
return EINVAL;
break;
default:
return EINVAL;
}
break;
case CSP_MODE_ETA:
switch (csp->csp_auth_alg) {
case CRYPTO_SHA1_HMAC:
case CRYPTO_SHA2_256_HMAC:
case CRYPTO_SHA2_384_HMAC:
case CRYPTO_SHA2_512_HMAC:
switch (csp->csp_cipher_alg) {
case CRYPTO_AES_CBC:
case CRYPTO_AES_ICM:
if (csp->csp_ivlen != AES_BLOCK_LEN)
return EINVAL;
break;
case CRYPTO_AES_XTS:
if (csp->csp_ivlen != AES_XTS_IV_LEN)
return EINVAL;
break;
default:
return EINVAL;
}
break;
default:
return EINVAL;
}
break;
default:
return EINVAL;
}
return CRYPTODEV_PROBE_HARDWARE;
}
static CpaStatus
qat_ocf_session_init(device_t dev,
struct cryptop *crp,
struct qat_ocf_instance *qat_instance,
struct qat_ocf_session *qat_ssession)
{
CpaStatus status = CPA_STATUS_SUCCESS;
crypto_session_t cses;
const struct crypto_session_params *csp;
CpaCySymSessionSetupData sessionSetupData = { 0 };
CpaCySymSessionCtx sessionCtx = NULL;
Cpa32U sessionCtxSize = 0;
cses = crp->crp_session;
if (NULL == cses) {
device_printf(dev, "no crypto session in cryptodev request\n");
return CPA_STATUS_FAIL;
}
csp = crypto_get_params(cses);
if (NULL == csp) {
device_printf(dev, "no session in cryptodev session\n");
return CPA_STATUS_FAIL;
}
sessionSetupData.sessionPriority = CPA_CY_PRIORITY_HIGH;
if (crp->crp_cipher_key)
sessionSetupData.cipherSetupData.pCipherKey =
crp->crp_cipher_key;
else
sessionSetupData.cipherSetupData.pCipherKey =
csp->csp_cipher_key;
sessionSetupData.cipherSetupData.cipherKeyLenInBytes =
csp->csp_cipher_klen;
if (crp->crp_auth_key)
sessionSetupData.hashSetupData.authModeSetupData.authKey =
crp->crp_auth_key;
else
sessionSetupData.hashSetupData.authModeSetupData.authKey =
csp->csp_auth_key;
sessionSetupData.hashSetupData.authModeSetupData.authKeyLenInBytes =
csp->csp_auth_klen;
qat_ssession->aadLen = crp->crp_aad_length;
if (CPA_TRUE == is_sep_aad_supported(csp))
sessionSetupData.hashSetupData.authModeSetupData.aadLenInBytes =
crp->crp_aad_length;
else
sessionSetupData.hashSetupData.authModeSetupData.aadLenInBytes =
0;
if (csp->csp_cipher_alg) {
sessionSetupData.symOperation = CPA_CY_SYM_OP_CIPHER;
switch (csp->csp_cipher_alg) {
case CRYPTO_AES_CBC:
sessionSetupData.cipherSetupData.cipherAlgorithm =
CPA_CY_SYM_CIPHER_AES_CBC;
break;
case CRYPTO_AES_ICM:
sessionSetupData.cipherSetupData.cipherAlgorithm =
CPA_CY_SYM_CIPHER_AES_CTR;
break;
case CRYPTO_AES_XTS:
sessionSetupData.cipherSetupData.cipherAlgorithm =
CPA_CY_SYM_CIPHER_AES_XTS;
break;
case CRYPTO_AES_NIST_GCM_16:
sessionSetupData.cipherSetupData.cipherAlgorithm =
CPA_CY_SYM_CIPHER_AES_GCM;
sessionSetupData.hashSetupData.hashAlgorithm =
CPA_CY_SYM_HASH_AES_GCM;
sessionSetupData.hashSetupData.hashMode =
CPA_CY_SYM_HASH_MODE_AUTH;
break;
default:
device_printf(dev,
"cipher_alg: %d not supported\n",
csp->csp_cipher_alg);
status = CPA_STATUS_UNSUPPORTED;
goto fail;
}
}
if (csp->csp_auth_alg) {
switch (csp->csp_auth_alg) {
case CRYPTO_SHA1_HMAC:
sessionSetupData.hashSetupData.hashAlgorithm =
CPA_CY_SYM_HASH_SHA1;
sessionSetupData.hashSetupData.hashMode =
CPA_CY_SYM_HASH_MODE_AUTH;
break;
case CRYPTO_SHA1:
sessionSetupData.hashSetupData.hashAlgorithm =
CPA_CY_SYM_HASH_SHA1;
sessionSetupData.hashSetupData.hashMode =
CPA_CY_SYM_HASH_MODE_PLAIN;
break;
case CRYPTO_SHA2_256_HMAC:
sessionSetupData.hashSetupData.hashAlgorithm =
CPA_CY_SYM_HASH_SHA256;
sessionSetupData.hashSetupData.hashMode =
CPA_CY_SYM_HASH_MODE_AUTH;
break;
case CRYPTO_SHA2_256:
sessionSetupData.hashSetupData.hashAlgorithm =
CPA_CY_SYM_HASH_SHA256;
sessionSetupData.hashSetupData.hashMode =
CPA_CY_SYM_HASH_MODE_PLAIN;
break;
case CRYPTO_SHA2_224_HMAC:
sessionSetupData.hashSetupData.hashAlgorithm =
CPA_CY_SYM_HASH_SHA224;
sessionSetupData.hashSetupData.hashMode =
CPA_CY_SYM_HASH_MODE_AUTH;
break;
case CRYPTO_SHA2_224:
sessionSetupData.hashSetupData.hashAlgorithm =
CPA_CY_SYM_HASH_SHA224;
sessionSetupData.hashSetupData.hashMode =
CPA_CY_SYM_HASH_MODE_PLAIN;
break;
case CRYPTO_SHA2_384_HMAC:
sessionSetupData.hashSetupData.hashAlgorithm =
CPA_CY_SYM_HASH_SHA384;
sessionSetupData.hashSetupData.hashMode =
CPA_CY_SYM_HASH_MODE_AUTH;
break;
case CRYPTO_SHA2_384:
sessionSetupData.hashSetupData.hashAlgorithm =
CPA_CY_SYM_HASH_SHA384;
sessionSetupData.hashSetupData.hashMode =
CPA_CY_SYM_HASH_MODE_PLAIN;
break;
case CRYPTO_SHA2_512_HMAC:
sessionSetupData.hashSetupData.hashAlgorithm =
CPA_CY_SYM_HASH_SHA512;
sessionSetupData.hashSetupData.hashMode =
CPA_CY_SYM_HASH_MODE_AUTH;
break;
case CRYPTO_SHA2_512:
sessionSetupData.hashSetupData.hashAlgorithm =
CPA_CY_SYM_HASH_SHA512;
sessionSetupData.hashSetupData.hashMode =
CPA_CY_SYM_HASH_MODE_PLAIN;
break;
case CRYPTO_AES_NIST_GMAC:
sessionSetupData.hashSetupData.hashAlgorithm =
CPA_CY_SYM_HASH_AES_GMAC;
break;
default:
status = CPA_STATUS_UNSUPPORTED;
goto fail;
}
}
if (csp->csp_mode != CSP_MODE_CIPHER) {
lac_sym_qat_hash_defs_t *pHashDefsInfo = NULL;
if (csp->csp_auth_mlen) {
sessionSetupData.hashSetupData.digestResultLenInBytes =
csp->csp_auth_mlen;
qat_ssession->authLen = csp->csp_auth_mlen;
} else {
LacSymQat_HashDefsLookupGet(
qat_instance->cyInstHandle,
sessionSetupData.hashSetupData.hashAlgorithm,
&pHashDefsInfo);
if (NULL == pHashDefsInfo) {
device_printf(
dev,
"unable to find corresponding hash data\n");
status = CPA_STATUS_UNSUPPORTED;
goto fail;
}
sessionSetupData.hashSetupData.digestResultLenInBytes =
pHashDefsInfo->algInfo->digestLength;
qat_ssession->authLen =
pHashDefsInfo->algInfo->digestLength;
}
sessionSetupData.verifyDigest = CPA_FALSE;
}
switch (csp->csp_mode) {
case CSP_MODE_AEAD:
case CSP_MODE_ETA:
sessionSetupData.symOperation =
CPA_CY_SYM_OP_ALGORITHM_CHAINING;
sessionSetupData.digestIsAppended = CPA_FALSE;
sessionSetupData.verifyDigest = CPA_FALSE;
if (CRYPTO_OP_IS_ENCRYPT(crp->crp_op)) {
sessionSetupData.cipherSetupData.cipherDirection =
CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT;
sessionSetupData.algChainOrder =
CPA_CY_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH;
} else {
sessionSetupData.cipherSetupData.cipherDirection =
CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT;
sessionSetupData.algChainOrder =
CPA_CY_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER;
}
break;
case CSP_MODE_CIPHER:
if (CRYPTO_OP_IS_ENCRYPT(crp->crp_op)) {
sessionSetupData.cipherSetupData.cipherDirection =
CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT;
} else {
sessionSetupData.cipherSetupData.cipherDirection =
CPA_CY_SYM_CIPHER_DIRECTION_DECRYPT;
}
sessionSetupData.symOperation = CPA_CY_SYM_OP_CIPHER;
break;
case CSP_MODE_DIGEST:
sessionSetupData.symOperation = CPA_CY_SYM_OP_HASH;
if (csp->csp_auth_alg == CRYPTO_AES_NIST_GMAC) {
sessionSetupData.symOperation =
CPA_CY_SYM_OP_ALGORITHM_CHAINING;
sessionSetupData.cipherSetupData.cipherDirection =
CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT;
sessionSetupData.algChainOrder =
CPA_CY_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH;
sessionSetupData.cipherSetupData.cipherAlgorithm =
CPA_CY_SYM_CIPHER_AES_GCM;
sessionSetupData.hashSetupData.hashAlgorithm =
CPA_CY_SYM_HASH_AES_GMAC;
sessionSetupData.hashSetupData.hashMode =
CPA_CY_SYM_HASH_MODE_AUTH;
sessionSetupData.cipherSetupData.pCipherKey =
csp->csp_auth_key;
sessionSetupData.cipherSetupData.cipherKeyLenInBytes =
csp->csp_auth_klen;
sessionSetupData.digestIsAppended = CPA_FALSE;
sessionSetupData.verifyDigest = CPA_FALSE;
sessionSetupData.hashSetupData.authModeSetupData
.aadLenInBytes = 0;
} else {
sessionSetupData.cipherSetupData.cipherDirection =
CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT;
sessionSetupData.symOperation = CPA_CY_SYM_OP_HASH;
sessionSetupData.digestIsAppended = CPA_FALSE;
}
break;
default:
device_printf(dev,
"%s: unhandled crypto algorithm %d, %d\n",
__func__,
csp->csp_cipher_alg,
csp->csp_auth_alg);
status = CPA_STATUS_FAIL;
goto fail;
}
status = cpaCySymSessionCtxGetSize(qat_instance->cyInstHandle,
&sessionSetupData,
&sessionCtxSize);
if (CPA_STATUS_SUCCESS != status) {
device_printf(dev, "unable to get session size\n");
goto fail;
}
sessionCtx = contigmalloc(sessionCtxSize,
M_QAT_OCF,
M_NOWAIT,
0,
~1UL,
1 << (ilog2(sessionCtxSize - 1) + 1),
0);
if (NULL == sessionCtx) {
device_printf(dev, "unable to allocate memory for session\n");
status = CPA_STATUS_RESOURCE;
goto fail;
}
status = cpaCySymDpInitSession(qat_instance->cyInstHandle,
&sessionSetupData,
sessionCtx);
if (CPA_STATUS_SUCCESS != status) {
device_printf(dev, "session initialization failed\n");
goto fail;
}
qat_ssession->sessionCtx = sessionCtx;
qat_ssession->sessionCtxSize = sessionCtxSize;
return CPA_STATUS_SUCCESS;
fail:
if (sessionCtx)
free(sessionCtx, M_QAT_OCF);
return status;
}
static int
qat_ocf_newsession(device_t dev,
crypto_session_t cses,
const struct crypto_session_params *csp)
{
struct qat_ocf_softc *qat_softc;
struct qat_ocf_dsession *qat_dsession;
struct qat_ocf_instance *qat_instance;
u_int cpu_id = PCPU_GET(cpuid);
qat_softc = device_get_softc(dev);
if (qat_softc->numCyInstances > 0) {
qat_instance =
&qat_softc
->cyInstHandles[cpu_id % qat_softc->numCyInstances];
qat_dsession = crypto_get_driver_session(cses);
if (NULL == qat_dsession) {
device_printf(dev, "Unable to create new session\n");
return (EINVAL);
}
qat_dsession->qatInstance = qat_instance;
} else {
return ENXIO;
}
return 0;
}
static CpaStatus
qat_ocf_remove_session(device_t dev,
CpaInstanceHandle cyInstHandle,
struct qat_ocf_session *qat_session)
{
CpaStatus status = CPA_STATUS_SUCCESS;
if (NULL == qat_session->sessionCtx)
return CPA_STATUS_SUCCESS;
status = qat_ocf_wait_for_session(qat_session->sessionCtx,
QAT_OCF_SESSION_WAIT_TIMEOUT_MS);
if (CPA_STATUS_SUCCESS != status) {
device_printf(dev, "waiting for session un-busy failed\n");
return CPA_STATUS_FAIL;
}
status = cpaCySymDpRemoveSession(cyInstHandle, qat_session->sessionCtx);
if (CPA_STATUS_SUCCESS != status) {
device_printf(dev, "error while removing session\n");
return CPA_STATUS_FAIL;
}
explicit_bzero(qat_session->sessionCtx, qat_session->sessionCtxSize);
free(qat_session->sessionCtx, M_QAT_OCF);
qat_session->sessionCtx = NULL;
qat_session->sessionCtxSize = 0;
return CPA_STATUS_SUCCESS;
}
static void
qat_ocf_freesession(device_t dev, crypto_session_t cses)
{
CpaStatus status = CPA_STATUS_SUCCESS;
struct qat_ocf_dsession *qat_dsession = NULL;
struct qat_ocf_instance *qat_instance = NULL;
qat_dsession = crypto_get_driver_session(cses);
qat_instance = qat_dsession->qatInstance;
mtx_lock(&qat_instance->cyInstMtx);
status = qat_ocf_remove_session(dev,
qat_dsession->qatInstance->cyInstHandle,
&qat_dsession->encSession);
if (CPA_STATUS_SUCCESS != status)
device_printf(dev, "unable to remove encrypt session\n");
status = qat_ocf_remove_session(dev,
qat_dsession->qatInstance->cyInstHandle,
&qat_dsession->decSession);
if (CPA_STATUS_SUCCESS != status)
device_printf(dev, "unable to remove decrypt session\n");
mtx_unlock(&qat_instance->cyInstMtx);
}
static CpaStatus
qat_ocf_load_aad_gcm(struct cryptop *crp, struct qat_ocf_cookie *qat_cookie)
{
CpaCySymDpOpData *pOpData;
pOpData = &qat_cookie->pOpdata;
if (NULL != crp->crp_aad)
memcpy(qat_cookie->qat_ocf_gcm_aad,
crp->crp_aad,
crp->crp_aad_length);
else
crypto_copydata(crp,
crp->crp_aad_start,
crp->crp_aad_length,
qat_cookie->qat_ocf_gcm_aad);
pOpData->pAdditionalAuthData = qat_cookie->qat_ocf_gcm_aad;
pOpData->additionalAuthData = qat_cookie->qat_ocf_gcm_aad_paddr;
return CPA_STATUS_SUCCESS;
}
static CpaStatus
qat_ocf_load_aad(struct cryptop *crp, struct qat_ocf_cookie *qat_cookie)
{
CpaStatus status = CPA_STATUS_SUCCESS;
const struct crypto_session_params *csp;
CpaCySymDpOpData *pOpData;
struct qat_ocf_load_cb_arg args;
pOpData = &qat_cookie->pOpdata;
pOpData->pAdditionalAuthData = NULL;
pOpData->additionalAuthData = 0UL;
if (crp->crp_aad_length == 0)
return CPA_STATUS_SUCCESS;
if (crp->crp_aad_length > ICP_QAT_FW_CCM_GCM_AAD_SZ_MAX)
return CPA_STATUS_FAIL;
csp = crypto_get_params(crp->crp_session);
if (CPA_TRUE == is_sep_aad_supported(csp))
return qat_ocf_load_aad_gcm(crp, qat_cookie);
if (NULL == crp->crp_aad) {
pOpData->messageLenToCipherInBytes = crp->crp_payload_length;
pOpData->cryptoStartSrcOffsetInBytes = crp->crp_payload_start;
pOpData->messageLenToHashInBytes =
crp->crp_aad_length + crp->crp_payload_length;
pOpData->hashStartSrcOffsetInBytes = crp->crp_aad_start;
return CPA_STATUS_SUCCESS;
}
args.crp_op = crp;
args.qat_cookie = qat_cookie;
args.pOpData = pOpData;
args.error = 0;
status = bus_dmamap_load(qat_cookie->gcm_aad_dma_mem.dma_tag,
qat_cookie->gcm_aad_dma_mem.dma_map,
crp->crp_aad,
crp->crp_aad_length,
qat_ocf_crypto_load_aadbuf_cb,
&args,
BUS_DMA_NOWAIT);
qat_cookie->is_sep_aad_used = CPA_TRUE;
pOpData->messageLenToCipherInBytes = crp->crp_payload_length;
pOpData->cryptoStartSrcOffsetInBytes =
crp->crp_aad_length + crp->crp_aad_start + crp->crp_payload_start;
pOpData->messageLenToHashInBytes =
crp->crp_aad_length + crp->crp_payload_length;
pOpData->hashStartSrcOffsetInBytes = crp->crp_aad_start;
return status;
}
static CpaStatus
qat_ocf_load(struct cryptop *crp, struct qat_ocf_cookie *qat_cookie)
{
CpaStatus status = CPA_STATUS_SUCCESS;
CpaCySymDpOpData *pOpData;
struct qat_ocf_load_cb_arg args;
const struct crypto_session_params *csp;
pOpData = &qat_cookie->pOpdata;
csp = crypto_get_params(crp->crp_session);
if (csp->csp_ivlen > 0) {
memset(qat_cookie->qat_ocf_iv_buf,
0,
sizeof(qat_cookie->qat_ocf_iv_buf));
crypto_read_iv(crp, qat_cookie->qat_ocf_iv_buf);
pOpData->iv = qat_cookie->qat_ocf_iv_buf_paddr;
pOpData->pIv = qat_cookie->qat_ocf_iv_buf;
pOpData->ivLenInBytes = csp->csp_ivlen;
}
status = qat_ocf_load_aad(crp, qat_cookie);
if (CPA_STATUS_SUCCESS != status)
goto fail;
args.crp_op = crp;
args.qat_cookie = qat_cookie;
args.pOpData = pOpData;
args.error = 0;
status = bus_dmamap_load_crp_buffer(qat_cookie->src_dma_mem.dma_tag,
qat_cookie->src_dma_mem.dma_map,
&crp->crp_buf,
qat_ocf_crypto_load_buf_cb,
&args,
BUS_DMA_NOWAIT);
if (CPA_STATUS_SUCCESS != status)
goto fail;
pOpData->srcBuffer = qat_cookie->src_buffer_list_paddr;
pOpData->srcBufferLen = CPA_DP_BUFLIST;
if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) {
status =
bus_dmamap_load_crp_buffer(qat_cookie->dst_dma_mem.dma_tag,
qat_cookie->dst_dma_mem.dma_map,
&crp->crp_obuf,
qat_ocf_crypto_load_obuf_cb,
&args,
BUS_DMA_NOWAIT);
if (CPA_STATUS_SUCCESS != status)
goto fail;
pOpData->dstBuffer = qat_cookie->dst_buffer_list_paddr;
pOpData->dstBufferLen = CPA_DP_BUFLIST;
} else {
pOpData->dstBuffer = pOpData->srcBuffer;
pOpData->dstBufferLen = pOpData->srcBufferLen;
}
if (CPA_TRUE == is_use_sep_digest(csp))
pOpData->digestResult = qat_cookie->qat_ocf_digest_paddr;
else
pOpData->digestResult = 0UL;
if (CPA_TRUE == is_gmac_exception(csp))
pOpData->messageLenToCipherInBytes = 0;
fail:
return status;
}
static int
qat_ocf_check_input(device_t dev, struct cryptop *crp)
{
const struct crypto_session_params *csp;
csp = crypto_get_params(crp->crp_session);
if (crypto_buffer_len(&crp->crp_buf) > QAT_OCF_MAX_LEN)
return E2BIG;
if (CPA_TRUE == is_sep_aad_supported(csp) &&
(crp->crp_aad_length > ICP_QAT_FW_CCM_GCM_AAD_SZ_MAX))
return EBADMSG;
return 0;
}
static int
qat_ocf_process(device_t dev, struct cryptop *crp, int hint)
{
CpaStatus status = CPA_STATUS_SUCCESS;
int rc = 0;
struct qat_ocf_dsession *qat_dsession = NULL;
struct qat_ocf_session *qat_session = NULL;
struct qat_ocf_instance *qat_instance = NULL;
CpaCySymDpOpData *pOpData = NULL;
struct qat_ocf_cookie *qat_cookie = NULL;
CpaBoolean memLoaded = CPA_FALSE;
rc = qat_ocf_check_input(dev, crp);
if (rc)
goto fail;
qat_dsession = crypto_get_driver_session(crp->crp_session);
if (CRYPTO_OP_IS_ENCRYPT(crp->crp_op))
qat_session = &qat_dsession->encSession;
else
qat_session = &qat_dsession->decSession;
qat_instance = qat_dsession->qatInstance;
status = qat_ocf_cookie_alloc(qat_instance, &qat_cookie);
if (CPA_STATUS_SUCCESS != status) {
rc = EAGAIN;
goto fail;
}
qat_cookie->crp_op = crp;
pOpData = &qat_cookie->pOpdata;
pOpData->instanceHandle = qat_instance->cyInstHandle;
pOpData->sessionCtx = NULL;
pOpData->cryptoStartSrcOffsetInBytes = crp->crp_payload_start;
pOpData->messageLenToCipherInBytes = crp->crp_payload_length;
pOpData->hashStartSrcOffsetInBytes = crp->crp_payload_start;
pOpData->messageLenToHashInBytes = crp->crp_payload_length;
status = qat_ocf_load(crp, qat_cookie);
if (CPA_STATUS_SUCCESS != status) {
device_printf(dev,
"unable to load OCF buffers to QAT DMA "
"transaction\n");
rc = EIO;
goto fail;
}
memLoaded = CPA_TRUE;
status = qat_ocf_cookie_dma_pre_sync(crp, pOpData);
if (CPA_STATUS_SUCCESS != status) {
device_printf(dev, "unable to sync DMA buffers\n");
rc = EIO;
goto fail;
}
mtx_lock(&qat_instance->cyInstMtx);
if (NULL == qat_session->sessionCtx) {
status =
qat_ocf_session_init(dev, crp, qat_instance, qat_session);
if (CPA_STATUS_SUCCESS != status) {
mtx_unlock(&qat_instance->cyInstMtx);
device_printf(dev, "unable to init session\n");
rc = EIO;
goto fail;
}
} else {
status = qat_ocf_handle_session_update(qat_dsession, crp);
if (CPA_STATUS_RESOURCE == status) {
mtx_unlock(&qat_instance->cyInstMtx);
rc = EAGAIN;
goto fail;
} else if (CPA_STATUS_SUCCESS != status) {
mtx_unlock(&qat_instance->cyInstMtx);
rc = EIO;
goto fail;
}
}
pOpData->sessionCtx = qat_session->sessionCtx;
status = cpaCySymDpEnqueueOp(pOpData, CPA_TRUE);
mtx_unlock(&qat_instance->cyInstMtx);
if (CPA_STATUS_SUCCESS != status) {
if (CPA_STATUS_RETRY == status) {
rc = EAGAIN;
goto fail;
}
device_printf(dev,
"unable to send request. Status: %d\n",
status);
rc = EIO;
goto fail;
}
return 0;
fail:
if (qat_cookie) {
if (memLoaded)
qat_ocf_cookie_dma_unload(crp, pOpData);
qat_ocf_cookie_free(qat_instance, qat_cookie);
}
crp->crp_etype = rc;
crypto_done(crp);
return 0;
}
static void
qat_ocf_identify(driver_t *drv, device_t parent)
{
if (device_find_child(parent, "qat_ocf", DEVICE_UNIT_ANY) == NULL &&
BUS_ADD_CHILD(parent, 200, "qat_ocf", DEVICE_UNIT_ANY) == 0)
device_printf(parent, "qat_ocf: could not attach!");
}
static int
qat_ocf_probe(device_t dev)
{
device_set_desc(dev, "QAT engine");
return (BUS_PROBE_NOWILDCARD);
}
static CpaStatus
qat_ocf_get_irq_instances(CpaInstanceHandle *cyInstHandles,
Cpa16U cyInstHandlesSize,
Cpa16U *foundInstances)
{
CpaStatus status = CPA_STATUS_SUCCESS;
icp_accel_dev_t **pAdfInsts = NULL;
icp_accel_dev_t *dev_addr = NULL;
sal_t *baseAddr = NULL;
sal_list_t *listTemp = NULL;
CpaInstanceHandle cyInstHandle;
CpaInstanceInfo2 info;
Cpa16U numDevices;
Cpa32U instCtr = 0;
Cpa32U i;
status = icp_amgr_getNumInstances(&numDevices);
if (CPA_STATUS_SUCCESS != status)
return status;
pAdfInsts =
malloc(numDevices * sizeof(icp_accel_dev_t *), M_QAT_OCF, M_WAITOK);
status = icp_amgr_getAllAccelDevByCapabilities(
(ICP_ACCEL_CAPABILITIES_CRYPTO_SYMMETRIC), pAdfInsts, &numDevices);
if (CPA_STATUS_SUCCESS != status) {
free(pAdfInsts, M_QAT_OCF);
return status;
}
for (i = 0; i < numDevices; i++) {
dev_addr = (icp_accel_dev_t *)pAdfInsts[i];
baseAddr = dev_addr->pSalHandle;
if (NULL == baseAddr)
continue;
listTemp = baseAddr->sym_services;
if (NULL == listTemp) {
listTemp = baseAddr->crypto_services;
}
while (NULL != listTemp) {
cyInstHandle = SalList_getObject(listTemp);
status = cpaCyInstanceGetInfo2(cyInstHandle, &info);
if (CPA_STATUS_SUCCESS != status)
continue;
listTemp = SalList_next(listTemp);
if (CPA_TRUE == info.isPolled)
continue;
if (instCtr >= cyInstHandlesSize)
break;
cyInstHandles[instCtr++] = cyInstHandle;
}
}
free(pAdfInsts, M_QAT_OCF);
*foundInstances = instCtr;
return CPA_STATUS_SUCCESS;
}
static CpaStatus
qat_ocf_start_instances(struct qat_ocf_softc *qat_softc, device_t dev)
{
CpaStatus status = CPA_STATUS_SUCCESS;
Cpa16U numInstances = 0;
CpaInstanceHandle cyInstHandles[QAT_OCF_MAX_INSTANCES] = { 0 };
CpaInstanceHandle cyInstHandle = NULL;
Cpa32U startedInstances = 0;
Cpa32U i;
qat_softc->numCyInstances = 0;
status = qat_ocf_get_irq_instances(cyInstHandles,
QAT_OCF_MAX_INSTANCES,
&numInstances);
if (CPA_STATUS_SUCCESS != status)
return status;
for (i = 0; i < numInstances; i++) {
struct qat_ocf_instance *qat_ocf_instance;
cyInstHandle = cyInstHandles[i];
if (!cyInstHandle)
continue;
status = cpaCyStartInstance(cyInstHandle);
if (CPA_STATUS_SUCCESS != status) {
device_printf(qat_softc->sc_dev,
"unable to get start instance\n");
continue;
}
qat_ocf_instance = &qat_softc->cyInstHandles[startedInstances];
qat_ocf_instance->cyInstHandle = cyInstHandle;
mtx_init(&qat_ocf_instance->cyInstMtx,
"Instance MTX",
NULL,
MTX_DEF);
status =
cpaCySetAddressTranslation(cyInstHandle, qatVirtToPhys);
if (CPA_STATUS_SUCCESS != status) {
device_printf(qat_softc->sc_dev,
"unable to add virt to phys callback\n");
goto fail;
}
status = cpaCySymDpRegCbFunc(cyInstHandle, symDpCallback);
if (CPA_STATUS_SUCCESS != status) {
device_printf(qat_softc->sc_dev,
"unable to add user callback\n");
goto fail;
}
status = qat_ocf_cookie_pool_init(qat_ocf_instance, dev);
if (CPA_STATUS_SUCCESS != status) {
device_printf(qat_softc->sc_dev,
"unable to create cookie pool\n");
goto fail;
}
status = icp_sal_setForceAEADMACVerify(cyInstHandle, CPA_FALSE);
if (CPA_STATUS_SUCCESS != status) {
device_printf(
qat_softc->sc_dev,
"unable to disable AEAD HW MAC verification\n");
goto fail;
}
qat_ocf_instance->driver_id = qat_softc->cryptodev_id;
startedInstances++;
continue;
fail:
mtx_destroy(&qat_ocf_instance->cyInstMtx);
status = cpaCyStopInstance(cyInstHandle);
if (CPA_STATUS_SUCCESS != status)
device_printf(qat_softc->sc_dev,
"unable to stop the instance\n");
}
qat_softc->numCyInstances = startedInstances;
return CPA_STATUS_SUCCESS;
}
static CpaStatus
qat_ocf_stop_instances(struct qat_ocf_softc *qat_softc)
{
CpaStatus status = CPA_STATUS_SUCCESS;
int i;
for (i = 0; i < qat_softc->numCyInstances; i++) {
struct qat_ocf_instance *qat_instance;
qat_instance = &qat_softc->cyInstHandles[i];
status = cpaCyStopInstance(qat_instance->cyInstHandle);
if (CPA_STATUS_SUCCESS != status) {
pr_err("QAT: stopping instance id: %d failed\n", i);
continue;
}
qat_ocf_cookie_pool_deinit(qat_instance);
mtx_destroy(&qat_instance->cyInstMtx);
}
qat_softc->numCyInstances = 0;
return status;
}
static int
qat_ocf_deinit(struct qat_ocf_softc *qat_softc)
{
int status = 0;
CpaStatus cpaStatus;
if (qat_softc->cryptodev_id >= 0) {
crypto_unregister_all(qat_softc->cryptodev_id);
qat_softc->cryptodev_id = -1;
}
cpaStatus = qat_ocf_stop_instances(qat_softc);
if (CPA_STATUS_SUCCESS != cpaStatus) {
device_printf(qat_softc->sc_dev, "unable to stop instances\n");
status = EIO;
}
return status;
}
static int
qat_ocf_init(struct qat_ocf_softc *qat_softc)
{
int32_t cryptodev_id;
if (qat_ocf_start_instances(qat_softc, qat_softc->sc_dev)) {
device_printf(qat_softc->sc_dev,
"unable to get QAT IRQ instances\n");
goto fail;
}
if (qat_softc->numCyInstances) {
cryptodev_id =
crypto_get_driverid(qat_softc->sc_dev,
sizeof(struct qat_ocf_dsession),
CRYPTOCAP_F_HARDWARE);
if (cryptodev_id < 0) {
device_printf(qat_softc->sc_dev,
"cannot initialize!\n");
goto fail;
}
qat_softc->cryptodev_id = cryptodev_id;
}
return 0;
fail:
qat_ocf_deinit(qat_softc);
return ENXIO;
}
static int qat_ocf_sysctl_handle(SYSCTL_HANDLER_ARGS)
{
struct qat_ocf_softc *qat_softc = NULL;
int ret = 0;
device_t dev = arg1;
u_int enabled;
qat_softc = device_get_softc(dev);
enabled = qat_softc->enabled;
ret = sysctl_handle_int(oidp, &enabled, 0, req);
if (ret || !req->newptr)
return (ret);
if (qat_softc->enabled != enabled) {
if (enabled) {
ret = qat_ocf_init(qat_softc);
} else {
ret = qat_ocf_deinit(qat_softc);
}
if (!ret)
qat_softc->enabled = enabled;
}
return ret;
}
static int
qat_ocf_attach(device_t dev)
{
int status;
struct qat_ocf_softc *qat_softc;
qat_softc = device_get_softc(dev);
qat_softc->sc_dev = dev;
qat_softc->cryptodev_id = -1;
qat_softc->enabled = 1;
qat_softc->rc =
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
OID_AUTO,
"enable",
CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
dev,
0,
qat_ocf_sysctl_handle,
"I",
"QAT OCF support enablement");
if (!qat_softc->rc)
return ENOMEM;
if (qat_softc->enabled) {
status = qat_ocf_init(qat_softc);
if (status) {
device_printf(dev, "qat_ocf init failed\n");
goto fail;
}
}
return 0;
fail:
qat_ocf_deinit(qat_softc);
return (ENXIO);
}
static int
qat_ocf_detach(device_t dev)
{
struct qat_ocf_softc *qat_softc = device_get_softc(dev);
return qat_ocf_deinit(qat_softc);
}
static device_method_t qat_ocf_methods[] =
{ DEVMETHOD(device_identify, qat_ocf_identify),
DEVMETHOD(device_probe, qat_ocf_probe),
DEVMETHOD(device_attach, qat_ocf_attach),
DEVMETHOD(device_detach, qat_ocf_detach),
DEVMETHOD(cryptodev_probesession, qat_ocf_probesession),
DEVMETHOD(cryptodev_newsession, qat_ocf_newsession),
DEVMETHOD(cryptodev_freesession, qat_ocf_freesession),
DEVMETHOD(cryptodev_process, qat_ocf_process),
DEVMETHOD_END };
static driver_t qat_ocf_driver = {
.name = "qat_ocf",
.methods = qat_ocf_methods,
.size = sizeof(struct qat_ocf_softc),
};
DRIVER_MODULE_ORDERED(qat,
nexus,
qat_ocf_driver,
NULL,
NULL,
SI_ORDER_ANY);
MODULE_VERSION(qat, 1);
MODULE_DEPEND(qat, qat_c62x, 1, 1, 1);
MODULE_DEPEND(qat, qat_200xx, 1, 1, 1);
MODULE_DEPEND(qat, qat_c3xxx, 1, 1, 1);
MODULE_DEPEND(qat, qat_c4xxx, 1, 1, 1);
MODULE_DEPEND(qat, qat_dh895xcc, 1, 1, 1);
MODULE_DEPEND(qat, qat_4xxx, 1, 1, 1);
MODULE_DEPEND(qat, crypto, 1, 1, 1);
MODULE_DEPEND(qat, qat_common, 1, 1, 1);
MODULE_DEPEND(qat, qat_api, 1, 1, 1);
MODULE_DEPEND(qat, linuxkpi, 1, 1, 1);