Path: blob/master/drivers/crypto/inside-secure/safexcel_ring.c
26285 views
// SPDX-License-Identifier: GPL-2.01/*2* Copyright (C) 2017 Marvell3*4* Antoine Tenart <[email protected]>5*/67#include <linux/dma-mapping.h>8#include <linux/spinlock.h>910#include "safexcel.h"1112int safexcel_init_ring_descriptors(struct safexcel_crypto_priv *priv,13struct safexcel_desc_ring *cdr,14struct safexcel_desc_ring *rdr)15{16int i;17struct safexcel_command_desc *cdesc;18dma_addr_t atok;1920/* Actual command descriptor ring */21cdr->offset = priv->config.cd_offset;22cdr->base = dmam_alloc_coherent(priv->dev,23cdr->offset * EIP197_DEFAULT_RING_SIZE,24&cdr->base_dma, GFP_KERNEL);25if (!cdr->base)26return -ENOMEM;27cdr->write = cdr->base;28cdr->base_end = cdr->base + cdr->offset * (EIP197_DEFAULT_RING_SIZE - 1);29cdr->read = cdr->base;3031/* Command descriptor shadow ring for storing additional token data */32cdr->shoffset = priv->config.cdsh_offset;33cdr->shbase = dmam_alloc_coherent(priv->dev,34cdr->shoffset *35EIP197_DEFAULT_RING_SIZE,36&cdr->shbase_dma, GFP_KERNEL);37if (!cdr->shbase)38return -ENOMEM;39cdr->shwrite = cdr->shbase;40cdr->shbase_end = cdr->shbase + cdr->shoffset *41(EIP197_DEFAULT_RING_SIZE - 1);4243/*44* Populate command descriptors with physical pointers to shadow descs.45* Note that we only need to do this once if we don't overwrite them.46*/47cdesc = cdr->base;48atok = cdr->shbase_dma;49for (i = 0; i < EIP197_DEFAULT_RING_SIZE; i++) {50cdesc->atok_lo = lower_32_bits(atok);51cdesc->atok_hi = upper_32_bits(atok);52cdesc = (void *)cdesc + cdr->offset;53atok += cdr->shoffset;54}5556rdr->offset = priv->config.rd_offset;57/* Use shoffset for result token offset here */58rdr->shoffset = priv->config.res_offset;59rdr->base = dmam_alloc_coherent(priv->dev,60rdr->offset * EIP197_DEFAULT_RING_SIZE,61&rdr->base_dma, GFP_KERNEL);62if (!rdr->base)63return -ENOMEM;64rdr->write = rdr->base;65rdr->base_end = rdr->base + rdr->offset * (EIP197_DEFAULT_RING_SIZE - 1);66rdr->read = rdr->base;6768return 0;69}7071inline int safexcel_select_ring(struct safexcel_crypto_priv *priv)72{73return (atomic_inc_return(&priv->ring_used) % priv->config.rings);74}7576static void *safexcel_ring_next_cwptr(struct safexcel_crypto_priv *priv,77struct safexcel_desc_ring *ring,78bool first,79struct safexcel_token **atoken)80{81void *ptr = ring->write;8283if (first)84*atoken = ring->shwrite;8586if ((ring->write == ring->read - ring->offset) ||87(ring->read == ring->base && ring->write == ring->base_end))88return ERR_PTR(-ENOMEM);8990if (ring->write == ring->base_end) {91ring->write = ring->base;92ring->shwrite = ring->shbase;93} else {94ring->write += ring->offset;95ring->shwrite += ring->shoffset;96}9798return ptr;99}100101static void *safexcel_ring_next_rwptr(struct safexcel_crypto_priv *priv,102struct safexcel_desc_ring *ring,103struct result_data_desc **rtoken)104{105void *ptr = ring->write;106107/* Result token at relative offset shoffset */108*rtoken = ring->write + ring->shoffset;109110if ((ring->write == ring->read - ring->offset) ||111(ring->read == ring->base && ring->write == ring->base_end))112return ERR_PTR(-ENOMEM);113114if (ring->write == ring->base_end)115ring->write = ring->base;116else117ring->write += ring->offset;118119return ptr;120}121122void *safexcel_ring_next_rptr(struct safexcel_crypto_priv *priv,123struct safexcel_desc_ring *ring)124{125void *ptr = ring->read;126127if (ring->write == ring->read)128return ERR_PTR(-ENOENT);129130if (ring->read == ring->base_end)131ring->read = ring->base;132else133ring->read += ring->offset;134135return ptr;136}137138inline void *safexcel_ring_curr_rptr(struct safexcel_crypto_priv *priv,139int ring)140{141struct safexcel_desc_ring *rdr = &priv->ring[ring].rdr;142143return rdr->read;144}145146inline int safexcel_ring_first_rdr_index(struct safexcel_crypto_priv *priv,147int ring)148{149struct safexcel_desc_ring *rdr = &priv->ring[ring].rdr;150151return (rdr->read - rdr->base) / rdr->offset;152}153154inline int safexcel_ring_rdr_rdesc_index(struct safexcel_crypto_priv *priv,155int ring,156struct safexcel_result_desc *rdesc)157{158struct safexcel_desc_ring *rdr = &priv->ring[ring].rdr;159160return ((void *)rdesc - rdr->base) / rdr->offset;161}162163void safexcel_ring_rollback_wptr(struct safexcel_crypto_priv *priv,164struct safexcel_desc_ring *ring)165{166if (ring->write == ring->read)167return;168169if (ring->write == ring->base) {170ring->write = ring->base_end;171ring->shwrite = ring->shbase_end;172} else {173ring->write -= ring->offset;174ring->shwrite -= ring->shoffset;175}176}177178struct safexcel_command_desc *safexcel_add_cdesc(struct safexcel_crypto_priv *priv,179int ring_id,180bool first, bool last,181dma_addr_t data, u32 data_len,182u32 full_data_len,183dma_addr_t context,184struct safexcel_token **atoken)185{186struct safexcel_command_desc *cdesc;187188cdesc = safexcel_ring_next_cwptr(priv, &priv->ring[ring_id].cdr,189first, atoken);190if (IS_ERR(cdesc))191return cdesc;192193cdesc->particle_size = data_len;194cdesc->rsvd0 = 0;195cdesc->last_seg = last;196cdesc->first_seg = first;197cdesc->additional_cdata_size = 0;198cdesc->rsvd1 = 0;199cdesc->data_lo = lower_32_bits(data);200cdesc->data_hi = upper_32_bits(data);201202if (first) {203/*204* Note that the length here MUST be >0 or else the EIP(1)97205* may hang. Newer EIP197 firmware actually incorporates this206* fix already, but that doesn't help the EIP97 and we may207* also be running older firmware.208*/209cdesc->control_data.packet_length = full_data_len ?: 1;210cdesc->control_data.options = EIP197_OPTION_MAGIC_VALUE |211EIP197_OPTION_64BIT_CTX |212EIP197_OPTION_CTX_CTRL_IN_CMD |213EIP197_OPTION_RC_AUTO;214cdesc->control_data.type = EIP197_TYPE_BCLA;215cdesc->control_data.context_lo = lower_32_bits(context) |216EIP197_CONTEXT_SMALL;217cdesc->control_data.context_hi = upper_32_bits(context);218}219220return cdesc;221}222223struct safexcel_result_desc *safexcel_add_rdesc(struct safexcel_crypto_priv *priv,224int ring_id,225bool first, bool last,226dma_addr_t data, u32 len)227{228struct safexcel_result_desc *rdesc;229struct result_data_desc *rtoken;230231rdesc = safexcel_ring_next_rwptr(priv, &priv->ring[ring_id].rdr,232&rtoken);233if (IS_ERR(rdesc))234return rdesc;235236rdesc->particle_size = len;237rdesc->rsvd0 = 0;238rdesc->descriptor_overflow = 1; /* assume error */239rdesc->buffer_overflow = 1; /* assume error */240rdesc->last_seg = last;241rdesc->first_seg = first;242rdesc->result_size = EIP197_RD64_RESULT_SIZE;243rdesc->rsvd1 = 0;244rdesc->data_lo = lower_32_bits(data);245rdesc->data_hi = upper_32_bits(data);246247/* Clear length in result token */248rtoken->packet_length = 0;249/* Assume errors - HW will clear if not the case */250rtoken->error_code = 0x7fff;251252return rdesc;253}254255256