Path: blob/master/drivers/crypto/intel/keembay/ocs-hcu.c
29278 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* Intel Keem Bay OCS HCU Crypto Driver.3*4* Copyright (C) 2018-2020 Intel Corporation5*/67#include <linux/delay.h>8#include <linux/device.h>9#include <linux/iopoll.h>10#include <linux/irq.h>11#include <linux/module.h>1213#include <crypto/sha2.h>1415#include "ocs-hcu.h"1617/* Registers. */18#define OCS_HCU_MODE 0x0019#define OCS_HCU_CHAIN 0x0420#define OCS_HCU_OPERATION 0x0821#define OCS_HCU_KEY_0 0x0C22#define OCS_HCU_ISR 0x5023#define OCS_HCU_IER 0x5424#define OCS_HCU_STATUS 0x5825#define OCS_HCU_MSG_LEN_LO 0x6026#define OCS_HCU_MSG_LEN_HI 0x6427#define OCS_HCU_KEY_BYTE_ORDER_CFG 0x8028#define OCS_HCU_DMA_SRC_ADDR 0x40029#define OCS_HCU_DMA_SRC_SIZE 0x40830#define OCS_HCU_DMA_DST_SIZE 0x40C31#define OCS_HCU_DMA_DMA_MODE 0x41032#define OCS_HCU_DMA_NEXT_SRC_DESCR 0x41833#define OCS_HCU_DMA_MSI_ISR 0x48034#define OCS_HCU_DMA_MSI_IER 0x48435#define OCS_HCU_DMA_MSI_MASK 0x4883637/* Register bit definitions. */38#define HCU_MODE_ALGO_SHIFT 1639#define HCU_MODE_HMAC_SHIFT 224041#define HCU_STATUS_BUSY BIT(0)4243#define HCU_BYTE_ORDER_SWAP BIT(0)4445#define HCU_IRQ_HASH_DONE BIT(2)46#define HCU_IRQ_HASH_ERR_MASK (BIT(3) | BIT(1) | BIT(0))4748#define HCU_DMA_IRQ_SRC_DONE BIT(0)49#define HCU_DMA_IRQ_SAI_ERR BIT(2)50#define HCU_DMA_IRQ_BAD_COMP_ERR BIT(3)51#define HCU_DMA_IRQ_INBUF_RD_ERR BIT(4)52#define HCU_DMA_IRQ_INBUF_WD_ERR BIT(5)53#define HCU_DMA_IRQ_OUTBUF_WR_ERR BIT(6)54#define HCU_DMA_IRQ_OUTBUF_RD_ERR BIT(7)55#define HCU_DMA_IRQ_CRD_ERR BIT(8)56#define HCU_DMA_IRQ_ERR_MASK (HCU_DMA_IRQ_SAI_ERR | \57HCU_DMA_IRQ_BAD_COMP_ERR | \58HCU_DMA_IRQ_INBUF_RD_ERR | \59HCU_DMA_IRQ_INBUF_WD_ERR | \60HCU_DMA_IRQ_OUTBUF_WR_ERR | \61HCU_DMA_IRQ_OUTBUF_RD_ERR | \62HCU_DMA_IRQ_CRD_ERR)6364#define HCU_DMA_SNOOP_MASK (0x7 << 28)65#define HCU_DMA_SRC_LL_EN BIT(25)66#define HCU_DMA_EN BIT(31)6768#define OCS_HCU_ENDIANNESS_VALUE 0x2A6970#define HCU_DMA_MSI_UNMASK BIT(0)71#define HCU_DMA_MSI_DISABLE 072#define HCU_IRQ_DISABLE 07374#define OCS_HCU_START BIT(0)75#define OCS_HCU_TERMINATE BIT(1)7677#define OCS_LL_DMA_FLAG_TERMINATE BIT(31)7879#define OCS_HCU_HW_KEY_LEN_U32 (OCS_HCU_HW_KEY_LEN / sizeof(u32))8081#define HCU_DATA_WRITE_ENDIANNESS_OFFSET 268283#define OCS_HCU_NUM_CHAINS_SHA256_224_SM3 (SHA256_DIGEST_SIZE / sizeof(u32))84#define OCS_HCU_NUM_CHAINS_SHA384_512 (SHA512_DIGEST_SIZE / sizeof(u32))8586/*87* While polling on a busy HCU, wait maximum 200us between one check and the88* other.89*/90#define OCS_HCU_WAIT_BUSY_RETRY_DELAY_US 20091/* Wait on a busy HCU for maximum 1 second. */92#define OCS_HCU_WAIT_BUSY_TIMEOUT_US 10000009394/**95* struct ocs_hcu_dma_entry - An entry in an OCS DMA linked list.96* @src_addr: Source address of the data.97* @src_len: Length of data to be fetched.98* @nxt_desc: Next descriptor to fetch.99* @ll_flags: Flags (Freeze @ terminate) for the DMA engine.100*/101struct ocs_hcu_dma_entry {102u32 src_addr;103u32 src_len;104u32 nxt_desc;105u32 ll_flags;106};107108/**109* struct ocs_hcu_dma_list - OCS-specific DMA linked list.110* @head: The head of the list (points to the array backing the list).111* @tail: The current tail of the list; NULL if the list is empty.112* @dma_addr: The DMA address of @head (i.e., the DMA address of the backing113* array).114* @max_nents: Maximum number of entries in the list (i.e., number of elements115* in the backing array).116*117* The OCS DMA list is an array-backed list of OCS DMA descriptors. The array118* backing the list is allocated with dma_alloc_coherent() and pointed by119* @head.120*/121struct ocs_hcu_dma_list {122struct ocs_hcu_dma_entry *head;123struct ocs_hcu_dma_entry *tail;124dma_addr_t dma_addr;125size_t max_nents;126};127128static inline u32 ocs_hcu_num_chains(enum ocs_hcu_algo algo)129{130switch (algo) {131case OCS_HCU_ALGO_SHA224:132case OCS_HCU_ALGO_SHA256:133case OCS_HCU_ALGO_SM3:134return OCS_HCU_NUM_CHAINS_SHA256_224_SM3;135case OCS_HCU_ALGO_SHA384:136case OCS_HCU_ALGO_SHA512:137return OCS_HCU_NUM_CHAINS_SHA384_512;138default:139return 0;140};141}142143static inline u32 ocs_hcu_digest_size(enum ocs_hcu_algo algo)144{145switch (algo) {146case OCS_HCU_ALGO_SHA224:147return SHA224_DIGEST_SIZE;148case OCS_HCU_ALGO_SHA256:149case OCS_HCU_ALGO_SM3:150/* SM3 shares the same block size. */151return SHA256_DIGEST_SIZE;152case OCS_HCU_ALGO_SHA384:153return SHA384_DIGEST_SIZE;154case OCS_HCU_ALGO_SHA512:155return SHA512_DIGEST_SIZE;156default:157return 0;158}159}160161/**162* ocs_hcu_wait_busy() - Wait for HCU OCS hardware to became usable.163* @hcu_dev: OCS HCU device to wait for.164*165* Return: 0 if device free, -ETIMEOUT if device busy and internal timeout has166* expired.167*/168static int ocs_hcu_wait_busy(struct ocs_hcu_dev *hcu_dev)169{170long val;171172return readl_poll_timeout(hcu_dev->io_base + OCS_HCU_STATUS, val,173!(val & HCU_STATUS_BUSY),174OCS_HCU_WAIT_BUSY_RETRY_DELAY_US,175OCS_HCU_WAIT_BUSY_TIMEOUT_US);176}177178static void ocs_hcu_done_irq_en(struct ocs_hcu_dev *hcu_dev)179{180/* Clear any pending interrupts. */181writel(0xFFFFFFFF, hcu_dev->io_base + OCS_HCU_ISR);182hcu_dev->irq_err = false;183/* Enable error and HCU done interrupts. */184writel(HCU_IRQ_HASH_DONE | HCU_IRQ_HASH_ERR_MASK,185hcu_dev->io_base + OCS_HCU_IER);186}187188static void ocs_hcu_dma_irq_en(struct ocs_hcu_dev *hcu_dev)189{190/* Clear any pending interrupts. */191writel(0xFFFFFFFF, hcu_dev->io_base + OCS_HCU_DMA_MSI_ISR);192hcu_dev->irq_err = false;193/* Only operating on DMA source completion and error interrupts. */194writel(HCU_DMA_IRQ_ERR_MASK | HCU_DMA_IRQ_SRC_DONE,195hcu_dev->io_base + OCS_HCU_DMA_MSI_IER);196/* Unmask */197writel(HCU_DMA_MSI_UNMASK, hcu_dev->io_base + OCS_HCU_DMA_MSI_MASK);198}199200static void ocs_hcu_irq_dis(struct ocs_hcu_dev *hcu_dev)201{202writel(HCU_IRQ_DISABLE, hcu_dev->io_base + OCS_HCU_IER);203writel(HCU_DMA_MSI_DISABLE, hcu_dev->io_base + OCS_HCU_DMA_MSI_IER);204}205206static int ocs_hcu_wait_and_disable_irq(struct ocs_hcu_dev *hcu_dev)207{208int rc;209210rc = wait_for_completion_interruptible(&hcu_dev->irq_done);211if (rc)212goto exit;213214if (hcu_dev->irq_err) {215/* Unset flag and return error. */216hcu_dev->irq_err = false;217rc = -EIO;218goto exit;219}220221exit:222ocs_hcu_irq_dis(hcu_dev);223224return rc;225}226227/**228* ocs_hcu_get_intermediate_data() - Get intermediate data.229* @hcu_dev: The target HCU device.230* @data: Where to store the intermediate.231* @algo: The algorithm being used.232*233* This function is used to save the current hashing process state in order to234* continue it in the future.235*236* Note: once all data has been processed, the intermediate data actually237* contains the hashing result. So this function is also used to retrieve the238* final result of a hashing process.239*240* Return: 0 on success, negative error code otherwise.241*/242static int ocs_hcu_get_intermediate_data(struct ocs_hcu_dev *hcu_dev,243struct ocs_hcu_idata *data,244enum ocs_hcu_algo algo)245{246const int n = ocs_hcu_num_chains(algo);247u32 *chain;248int rc;249int i;250251/* Data not requested. */252if (!data)253return -EINVAL;254255chain = (u32 *)data->digest;256257/* Ensure that the OCS is no longer busy before reading the chains. */258rc = ocs_hcu_wait_busy(hcu_dev);259if (rc)260return rc;261262/*263* This loops is safe because data->digest is an array of264* SHA512_DIGEST_SIZE bytes and the maximum value returned by265* ocs_hcu_num_chains() is OCS_HCU_NUM_CHAINS_SHA384_512 which is equal266* to SHA512_DIGEST_SIZE / sizeof(u32).267*/268for (i = 0; i < n; i++)269chain[i] = readl(hcu_dev->io_base + OCS_HCU_CHAIN);270271data->msg_len_lo = readl(hcu_dev->io_base + OCS_HCU_MSG_LEN_LO);272data->msg_len_hi = readl(hcu_dev->io_base + OCS_HCU_MSG_LEN_HI);273274return 0;275}276277/**278* ocs_hcu_set_intermediate_data() - Set intermediate data.279* @hcu_dev: The target HCU device.280* @data: The intermediate data to be set.281* @algo: The algorithm being used.282*283* This function is used to continue a previous hashing process.284*/285static void ocs_hcu_set_intermediate_data(struct ocs_hcu_dev *hcu_dev,286const struct ocs_hcu_idata *data,287enum ocs_hcu_algo algo)288{289const int n = ocs_hcu_num_chains(algo);290u32 *chain = (u32 *)data->digest;291int i;292293/*294* This loops is safe because data->digest is an array of295* SHA512_DIGEST_SIZE bytes and the maximum value returned by296* ocs_hcu_num_chains() is OCS_HCU_NUM_CHAINS_SHA384_512 which is equal297* to SHA512_DIGEST_SIZE / sizeof(u32).298*/299for (i = 0; i < n; i++)300writel(chain[i], hcu_dev->io_base + OCS_HCU_CHAIN);301302writel(data->msg_len_lo, hcu_dev->io_base + OCS_HCU_MSG_LEN_LO);303writel(data->msg_len_hi, hcu_dev->io_base + OCS_HCU_MSG_LEN_HI);304}305306static int ocs_hcu_get_digest(struct ocs_hcu_dev *hcu_dev,307enum ocs_hcu_algo algo, u8 *dgst, size_t dgst_len)308{309u32 *chain;310int rc;311int i;312313if (!dgst)314return -EINVAL;315316/* Length of the output buffer must match the algo digest size. */317if (dgst_len != ocs_hcu_digest_size(algo))318return -EINVAL;319320/* Ensure that the OCS is no longer busy before reading the chains. */321rc = ocs_hcu_wait_busy(hcu_dev);322if (rc)323return rc;324325chain = (u32 *)dgst;326for (i = 0; i < dgst_len / sizeof(u32); i++)327chain[i] = readl(hcu_dev->io_base + OCS_HCU_CHAIN);328329return 0;330}331332/**333* ocs_hcu_hw_cfg() - Configure the HCU hardware.334* @hcu_dev: The HCU device to configure.335* @algo: The algorithm to be used by the HCU device.336* @use_hmac: Whether or not HW HMAC should be used.337*338* Return: 0 on success, negative error code otherwise.339*/340static int ocs_hcu_hw_cfg(struct ocs_hcu_dev *hcu_dev, enum ocs_hcu_algo algo,341bool use_hmac)342{343u32 cfg;344int rc;345346if (algo != OCS_HCU_ALGO_SHA256 && algo != OCS_HCU_ALGO_SHA224 &&347algo != OCS_HCU_ALGO_SHA384 && algo != OCS_HCU_ALGO_SHA512 &&348algo != OCS_HCU_ALGO_SM3)349return -EINVAL;350351rc = ocs_hcu_wait_busy(hcu_dev);352if (rc)353return rc;354355/* Ensure interrupts are disabled. */356ocs_hcu_irq_dis(hcu_dev);357358/* Configure endianness, hashing algorithm and HW HMAC (if needed) */359cfg = OCS_HCU_ENDIANNESS_VALUE << HCU_DATA_WRITE_ENDIANNESS_OFFSET;360cfg |= algo << HCU_MODE_ALGO_SHIFT;361if (use_hmac)362cfg |= BIT(HCU_MODE_HMAC_SHIFT);363364writel(cfg, hcu_dev->io_base + OCS_HCU_MODE);365366return 0;367}368369/**370* ocs_hcu_clear_key() - Clear key stored in OCS HMAC KEY registers.371* @hcu_dev: The OCS HCU device whose key registers should be cleared.372*/373static void ocs_hcu_clear_key(struct ocs_hcu_dev *hcu_dev)374{375int reg_off;376377/* Clear OCS_HCU_KEY_[0..15] */378for (reg_off = 0; reg_off < OCS_HCU_HW_KEY_LEN; reg_off += sizeof(u32))379writel(0, hcu_dev->io_base + OCS_HCU_KEY_0 + reg_off);380}381382/**383* ocs_hcu_write_key() - Write key to OCS HMAC KEY registers.384* @hcu_dev: The OCS HCU device the key should be written to.385* @key: The key to be written.386* @len: The size of the key to write. It must be OCS_HCU_HW_KEY_LEN.387*388* Return: 0 on success, negative error code otherwise.389*/390static int ocs_hcu_write_key(struct ocs_hcu_dev *hcu_dev, const u8 *key, size_t len)391{392u32 key_u32[OCS_HCU_HW_KEY_LEN_U32];393int i;394395if (len > OCS_HCU_HW_KEY_LEN)396return -EINVAL;397398/* Copy key into temporary u32 array. */399memcpy(key_u32, key, len);400401/*402* Hardware requires all the bytes of the HW Key vector to be403* written. So pad with zero until we reach OCS_HCU_HW_KEY_LEN.404*/405memzero_explicit((u8 *)key_u32 + len, OCS_HCU_HW_KEY_LEN - len);406407/*408* OCS hardware expects the MSB of the key to be written at the highest409* address of the HCU Key vector; in other word, the key must be410* written in reverse order.411*412* Therefore, we first enable byte swapping for the HCU key vector;413* so that bytes of 32-bit word written to OCS_HCU_KEY_[0..15] will be414* swapped:415* 3 <---> 0, 2 <---> 1.416*/417writel(HCU_BYTE_ORDER_SWAP,418hcu_dev->io_base + OCS_HCU_KEY_BYTE_ORDER_CFG);419/*420* And then we write the 32-bit words composing the key starting from421* the end of the key.422*/423for (i = 0; i < OCS_HCU_HW_KEY_LEN_U32; i++)424writel(key_u32[OCS_HCU_HW_KEY_LEN_U32 - 1 - i],425hcu_dev->io_base + OCS_HCU_KEY_0 + (sizeof(u32) * i));426427memzero_explicit(key_u32, OCS_HCU_HW_KEY_LEN);428429return 0;430}431432/**433* ocs_hcu_ll_dma_start() - Start OCS HCU hashing via DMA434* @hcu_dev: The OCS HCU device to use.435* @dma_list: The OCS DMA list mapping the data to hash.436* @finalize: Whether or not this is the last hashing operation and therefore437* the final hash should be compute even if data is not438* block-aligned.439*440* Return: 0 on success, negative error code otherwise.441*/442static int ocs_hcu_ll_dma_start(struct ocs_hcu_dev *hcu_dev,443const struct ocs_hcu_dma_list *dma_list,444bool finalize)445{446u32 cfg = HCU_DMA_SNOOP_MASK | HCU_DMA_SRC_LL_EN | HCU_DMA_EN;447int rc;448449if (!dma_list)450return -EINVAL;451452/*453* For final requests we use HCU_DONE IRQ to be notified when all input454* data has been processed by the HCU; however, we cannot do so for455* non-final requests, because we don't get a HCU_DONE IRQ when we456* don't terminate the operation.457*458* Therefore, for non-final requests, we use the DMA IRQ, which459* triggers when DMA has finishing feeding all the input data to the460* HCU, but the HCU may still be processing it. This is fine, since we461* will wait for the HCU processing to be completed when we try to read462* intermediate results, in ocs_hcu_get_intermediate_data().463*/464if (finalize)465ocs_hcu_done_irq_en(hcu_dev);466else467ocs_hcu_dma_irq_en(hcu_dev);468469reinit_completion(&hcu_dev->irq_done);470writel(dma_list->dma_addr, hcu_dev->io_base + OCS_HCU_DMA_NEXT_SRC_DESCR);471writel(0, hcu_dev->io_base + OCS_HCU_DMA_SRC_SIZE);472writel(0, hcu_dev->io_base + OCS_HCU_DMA_DST_SIZE);473474writel(OCS_HCU_START, hcu_dev->io_base + OCS_HCU_OPERATION);475476writel(cfg, hcu_dev->io_base + OCS_HCU_DMA_DMA_MODE);477478if (finalize)479writel(OCS_HCU_TERMINATE, hcu_dev->io_base + OCS_HCU_OPERATION);480481rc = ocs_hcu_wait_and_disable_irq(hcu_dev);482if (rc)483return rc;484485return 0;486}487488struct ocs_hcu_dma_list *ocs_hcu_dma_list_alloc(struct ocs_hcu_dev *hcu_dev,489int max_nents)490{491struct ocs_hcu_dma_list *dma_list;492493dma_list = kmalloc(sizeof(*dma_list), GFP_KERNEL);494if (!dma_list)495return NULL;496497/* Total size of the DMA list to allocate. */498dma_list->head = dma_alloc_coherent(hcu_dev->dev,499sizeof(*dma_list->head) * max_nents,500&dma_list->dma_addr, GFP_KERNEL);501if (!dma_list->head) {502kfree(dma_list);503return NULL;504}505dma_list->max_nents = max_nents;506dma_list->tail = NULL;507508return dma_list;509}510511void ocs_hcu_dma_list_free(struct ocs_hcu_dev *hcu_dev,512struct ocs_hcu_dma_list *dma_list)513{514if (!dma_list)515return;516517dma_free_coherent(hcu_dev->dev,518sizeof(*dma_list->head) * dma_list->max_nents,519dma_list->head, dma_list->dma_addr);520521kfree(dma_list);522}523524/* Add a new DMA entry at the end of the OCS DMA list. */525int ocs_hcu_dma_list_add_tail(struct ocs_hcu_dev *hcu_dev,526struct ocs_hcu_dma_list *dma_list,527dma_addr_t addr, u32 len)528{529struct device *dev = hcu_dev->dev;530struct ocs_hcu_dma_entry *old_tail;531struct ocs_hcu_dma_entry *new_tail;532533if (!len)534return 0;535536if (!dma_list)537return -EINVAL;538539if (addr & ~OCS_HCU_DMA_BIT_MASK) {540dev_err(dev,541"Unexpected error: Invalid DMA address for OCS HCU\n");542return -EINVAL;543}544545old_tail = dma_list->tail;546new_tail = old_tail ? old_tail + 1 : dma_list->head;547548/* Check if list is full. */549if (new_tail - dma_list->head >= dma_list->max_nents)550return -ENOMEM;551552/*553* If there was an old tail (i.e., this is not the first element we are554* adding), un-terminate the old tail and make it point to the new one.555*/556if (old_tail) {557old_tail->ll_flags &= ~OCS_LL_DMA_FLAG_TERMINATE;558/*559* The old tail 'nxt_desc' must point to the DMA address of the560* new tail.561*/562old_tail->nxt_desc = dma_list->dma_addr +563sizeof(*dma_list->tail) * (new_tail -564dma_list->head);565}566567new_tail->src_addr = (u32)addr;568new_tail->src_len = (u32)len;569new_tail->ll_flags = OCS_LL_DMA_FLAG_TERMINATE;570new_tail->nxt_desc = 0;571572/* Update list tail with new tail. */573dma_list->tail = new_tail;574575return 0;576}577578/**579* ocs_hcu_hash_init() - Initialize hash operation context.580* @ctx: The context to initialize.581* @algo: The hashing algorithm to use.582*583* Return: 0 on success, negative error code otherwise.584*/585int ocs_hcu_hash_init(struct ocs_hcu_hash_ctx *ctx, enum ocs_hcu_algo algo)586{587if (!ctx)588return -EINVAL;589590ctx->algo = algo;591ctx->idata.msg_len_lo = 0;592ctx->idata.msg_len_hi = 0;593/* No need to set idata.digest to 0. */594595return 0;596}597598/**599* ocs_hcu_hash_update() - Perform a hashing iteration.600* @hcu_dev: The OCS HCU device to use.601* @ctx: The OCS HCU hashing context.602* @dma_list: The OCS DMA list mapping the input data to process.603*604* Return: 0 on success; negative error code otherwise.605*/606int ocs_hcu_hash_update(struct ocs_hcu_dev *hcu_dev,607struct ocs_hcu_hash_ctx *ctx,608const struct ocs_hcu_dma_list *dma_list)609{610int rc;611612if (!hcu_dev || !ctx)613return -EINVAL;614615/* Configure the hardware for the current request. */616rc = ocs_hcu_hw_cfg(hcu_dev, ctx->algo, false);617if (rc)618return rc;619620/* If we already processed some data, idata needs to be set. */621if (ctx->idata.msg_len_lo || ctx->idata.msg_len_hi)622ocs_hcu_set_intermediate_data(hcu_dev, &ctx->idata, ctx->algo);623624/* Start linked-list DMA hashing. */625rc = ocs_hcu_ll_dma_start(hcu_dev, dma_list, false);626if (rc)627return rc;628629/* Update idata and return. */630return ocs_hcu_get_intermediate_data(hcu_dev, &ctx->idata, ctx->algo);631}632633/**634* ocs_hcu_hash_finup() - Update and finalize hash computation.635* @hcu_dev: The OCS HCU device to use.636* @ctx: The OCS HCU hashing context.637* @dma_list: The OCS DMA list mapping the input data to process.638* @dgst: The buffer where to save the computed digest.639* @dgst_len: The length of @dgst.640*641* Return: 0 on success; negative error code otherwise.642*/643int ocs_hcu_hash_finup(struct ocs_hcu_dev *hcu_dev,644const struct ocs_hcu_hash_ctx *ctx,645const struct ocs_hcu_dma_list *dma_list,646u8 *dgst, size_t dgst_len)647{648int rc;649650if (!hcu_dev || !ctx)651return -EINVAL;652653/* Configure the hardware for the current request. */654rc = ocs_hcu_hw_cfg(hcu_dev, ctx->algo, false);655if (rc)656return rc;657658/* If we already processed some data, idata needs to be set. */659if (ctx->idata.msg_len_lo || ctx->idata.msg_len_hi)660ocs_hcu_set_intermediate_data(hcu_dev, &ctx->idata, ctx->algo);661662/* Start linked-list DMA hashing. */663rc = ocs_hcu_ll_dma_start(hcu_dev, dma_list, true);664if (rc)665return rc;666667/* Get digest and return. */668return ocs_hcu_get_digest(hcu_dev, ctx->algo, dgst, dgst_len);669}670671/**672* ocs_hcu_hash_final() - Finalize hash computation.673* @hcu_dev: The OCS HCU device to use.674* @ctx: The OCS HCU hashing context.675* @dgst: The buffer where to save the computed digest.676* @dgst_len: The length of @dgst.677*678* Return: 0 on success; negative error code otherwise.679*/680int ocs_hcu_hash_final(struct ocs_hcu_dev *hcu_dev,681const struct ocs_hcu_hash_ctx *ctx, u8 *dgst,682size_t dgst_len)683{684int rc;685686if (!hcu_dev || !ctx)687return -EINVAL;688689/* Configure the hardware for the current request. */690rc = ocs_hcu_hw_cfg(hcu_dev, ctx->algo, false);691if (rc)692return rc;693694/* If we already processed some data, idata needs to be set. */695if (ctx->idata.msg_len_lo || ctx->idata.msg_len_hi)696ocs_hcu_set_intermediate_data(hcu_dev, &ctx->idata, ctx->algo);697698/*699* Enable HCU interrupts, so that HCU_DONE will be triggered once the700* final hash is computed.701*/702ocs_hcu_done_irq_en(hcu_dev);703reinit_completion(&hcu_dev->irq_done);704writel(OCS_HCU_TERMINATE, hcu_dev->io_base + OCS_HCU_OPERATION);705706rc = ocs_hcu_wait_and_disable_irq(hcu_dev);707if (rc)708return rc;709710/* Get digest and return. */711return ocs_hcu_get_digest(hcu_dev, ctx->algo, dgst, dgst_len);712}713714/**715* ocs_hcu_digest() - Compute hash digest.716* @hcu_dev: The OCS HCU device to use.717* @algo: The hash algorithm to use.718* @data: The input data to process.719* @data_len: The length of @data.720* @dgst: The buffer where to save the computed digest.721* @dgst_len: The length of @dgst.722*723* Return: 0 on success; negative error code otherwise.724*/725int ocs_hcu_digest(struct ocs_hcu_dev *hcu_dev, enum ocs_hcu_algo algo,726void *data, size_t data_len, u8 *dgst, size_t dgst_len)727{728struct device *dev = hcu_dev->dev;729dma_addr_t dma_handle;730u32 reg;731int rc;732733/* Configure the hardware for the current request. */734rc = ocs_hcu_hw_cfg(hcu_dev, algo, false);735if (rc)736return rc;737738dma_handle = dma_map_single(dev, data, data_len, DMA_TO_DEVICE);739if (dma_mapping_error(dev, dma_handle))740return -EIO;741742reg = HCU_DMA_SNOOP_MASK | HCU_DMA_EN;743744ocs_hcu_done_irq_en(hcu_dev);745746reinit_completion(&hcu_dev->irq_done);747748writel(dma_handle, hcu_dev->io_base + OCS_HCU_DMA_SRC_ADDR);749writel(data_len, hcu_dev->io_base + OCS_HCU_DMA_SRC_SIZE);750writel(OCS_HCU_START, hcu_dev->io_base + OCS_HCU_OPERATION);751writel(reg, hcu_dev->io_base + OCS_HCU_DMA_DMA_MODE);752753writel(OCS_HCU_TERMINATE, hcu_dev->io_base + OCS_HCU_OPERATION);754755rc = ocs_hcu_wait_and_disable_irq(hcu_dev);756if (rc)757return rc;758759dma_unmap_single(dev, dma_handle, data_len, DMA_TO_DEVICE);760761return ocs_hcu_get_digest(hcu_dev, algo, dgst, dgst_len);762}763764/**765* ocs_hcu_hmac() - Compute HMAC.766* @hcu_dev: The OCS HCU device to use.767* @algo: The hash algorithm to use with HMAC.768* @key: The key to use.769* @dma_list: The OCS DMA list mapping the input data to process.770* @key_len: The length of @key.771* @dgst: The buffer where to save the computed HMAC.772* @dgst_len: The length of @dgst.773*774* Return: 0 on success; negative error code otherwise.775*/776int ocs_hcu_hmac(struct ocs_hcu_dev *hcu_dev, enum ocs_hcu_algo algo,777const u8 *key, size_t key_len,778const struct ocs_hcu_dma_list *dma_list,779u8 *dgst, size_t dgst_len)780{781int rc;782783/* Ensure 'key' is not NULL. */784if (!key || key_len == 0)785return -EINVAL;786787/* Configure the hardware for the current request. */788rc = ocs_hcu_hw_cfg(hcu_dev, algo, true);789if (rc)790return rc;791792rc = ocs_hcu_write_key(hcu_dev, key, key_len);793if (rc)794return rc;795796rc = ocs_hcu_ll_dma_start(hcu_dev, dma_list, true);797798/* Clear HW key before processing return code. */799ocs_hcu_clear_key(hcu_dev);800801if (rc)802return rc;803804return ocs_hcu_get_digest(hcu_dev, algo, dgst, dgst_len);805}806807irqreturn_t ocs_hcu_irq_handler(int irq, void *dev_id)808{809struct ocs_hcu_dev *hcu_dev = dev_id;810u32 hcu_irq;811u32 dma_irq;812813/* Read and clear the HCU interrupt. */814hcu_irq = readl(hcu_dev->io_base + OCS_HCU_ISR);815writel(hcu_irq, hcu_dev->io_base + OCS_HCU_ISR);816817/* Read and clear the HCU DMA interrupt. */818dma_irq = readl(hcu_dev->io_base + OCS_HCU_DMA_MSI_ISR);819writel(dma_irq, hcu_dev->io_base + OCS_HCU_DMA_MSI_ISR);820821/* Check for errors. */822if (hcu_irq & HCU_IRQ_HASH_ERR_MASK || dma_irq & HCU_DMA_IRQ_ERR_MASK) {823hcu_dev->irq_err = true;824goto complete;825}826827/* Check for DONE IRQs. */828if (hcu_irq & HCU_IRQ_HASH_DONE || dma_irq & HCU_DMA_IRQ_SRC_DONE)829goto complete;830831return IRQ_NONE;832833complete:834complete(&hcu_dev->irq_done);835836return IRQ_HANDLED;837}838839MODULE_DESCRIPTION("Intel Keem Bay OCS HCU Crypto Driver");840MODULE_LICENSE("GPL");841842843