123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (C) 2017 Marvell
- *
- * Antoine Tenart <[email protected]>
- */
- #include <linux/dma-mapping.h>
- #include <linux/spinlock.h>
- #include "safexcel.h"
- int safexcel_init_ring_descriptors(struct safexcel_crypto_priv *priv,
- struct safexcel_desc_ring *cdr,
- struct safexcel_desc_ring *rdr)
- {
- int i;
- struct safexcel_command_desc *cdesc;
- dma_addr_t atok;
- /* Actual command descriptor ring */
- cdr->offset = priv->config.cd_offset;
- cdr->base = dmam_alloc_coherent(priv->dev,
- cdr->offset * EIP197_DEFAULT_RING_SIZE,
- &cdr->base_dma, GFP_KERNEL);
- if (!cdr->base)
- return -ENOMEM;
- cdr->write = cdr->base;
- cdr->base_end = cdr->base + cdr->offset * (EIP197_DEFAULT_RING_SIZE - 1);
- cdr->read = cdr->base;
- /* Command descriptor shadow ring for storing additional token data */
- cdr->shoffset = priv->config.cdsh_offset;
- cdr->shbase = dmam_alloc_coherent(priv->dev,
- cdr->shoffset *
- EIP197_DEFAULT_RING_SIZE,
- &cdr->shbase_dma, GFP_KERNEL);
- if (!cdr->shbase)
- return -ENOMEM;
- cdr->shwrite = cdr->shbase;
- cdr->shbase_end = cdr->shbase + cdr->shoffset *
- (EIP197_DEFAULT_RING_SIZE - 1);
- /*
- * Populate command descriptors with physical pointers to shadow descs.
- * Note that we only need to do this once if we don't overwrite them.
- */
- cdesc = cdr->base;
- atok = cdr->shbase_dma;
- for (i = 0; i < EIP197_DEFAULT_RING_SIZE; i++) {
- cdesc->atok_lo = lower_32_bits(atok);
- cdesc->atok_hi = upper_32_bits(atok);
- cdesc = (void *)cdesc + cdr->offset;
- atok += cdr->shoffset;
- }
- rdr->offset = priv->config.rd_offset;
- /* Use shoffset for result token offset here */
- rdr->shoffset = priv->config.res_offset;
- rdr->base = dmam_alloc_coherent(priv->dev,
- rdr->offset * EIP197_DEFAULT_RING_SIZE,
- &rdr->base_dma, GFP_KERNEL);
- if (!rdr->base)
- return -ENOMEM;
- rdr->write = rdr->base;
- rdr->base_end = rdr->base + rdr->offset * (EIP197_DEFAULT_RING_SIZE - 1);
- rdr->read = rdr->base;
- return 0;
- }
- inline int safexcel_select_ring(struct safexcel_crypto_priv *priv)
- {
- return (atomic_inc_return(&priv->ring_used) % priv->config.rings);
- }
- static void *safexcel_ring_next_cwptr(struct safexcel_crypto_priv *priv,
- struct safexcel_desc_ring *ring,
- bool first,
- struct safexcel_token **atoken)
- {
- void *ptr = ring->write;
- if (first)
- *atoken = ring->shwrite;
- if ((ring->write == ring->read - ring->offset) ||
- (ring->read == ring->base && ring->write == ring->base_end))
- return ERR_PTR(-ENOMEM);
- if (ring->write == ring->base_end) {
- ring->write = ring->base;
- ring->shwrite = ring->shbase;
- } else {
- ring->write += ring->offset;
- ring->shwrite += ring->shoffset;
- }
- return ptr;
- }
- static void *safexcel_ring_next_rwptr(struct safexcel_crypto_priv *priv,
- struct safexcel_desc_ring *ring,
- struct result_data_desc **rtoken)
- {
- void *ptr = ring->write;
- /* Result token at relative offset shoffset */
- *rtoken = ring->write + ring->shoffset;
- if ((ring->write == ring->read - ring->offset) ||
- (ring->read == ring->base && ring->write == ring->base_end))
- return ERR_PTR(-ENOMEM);
- if (ring->write == ring->base_end)
- ring->write = ring->base;
- else
- ring->write += ring->offset;
- return ptr;
- }
- void *safexcel_ring_next_rptr(struct safexcel_crypto_priv *priv,
- struct safexcel_desc_ring *ring)
- {
- void *ptr = ring->read;
- if (ring->write == ring->read)
- return ERR_PTR(-ENOENT);
- if (ring->read == ring->base_end)
- ring->read = ring->base;
- else
- ring->read += ring->offset;
- return ptr;
- }
- inline void *safexcel_ring_curr_rptr(struct safexcel_crypto_priv *priv,
- int ring)
- {
- struct safexcel_desc_ring *rdr = &priv->ring[ring].rdr;
- return rdr->read;
- }
- inline int safexcel_ring_first_rdr_index(struct safexcel_crypto_priv *priv,
- int ring)
- {
- struct safexcel_desc_ring *rdr = &priv->ring[ring].rdr;
- return (rdr->read - rdr->base) / rdr->offset;
- }
- inline int safexcel_ring_rdr_rdesc_index(struct safexcel_crypto_priv *priv,
- int ring,
- struct safexcel_result_desc *rdesc)
- {
- struct safexcel_desc_ring *rdr = &priv->ring[ring].rdr;
- return ((void *)rdesc - rdr->base) / rdr->offset;
- }
- void safexcel_ring_rollback_wptr(struct safexcel_crypto_priv *priv,
- struct safexcel_desc_ring *ring)
- {
- if (ring->write == ring->read)
- return;
- if (ring->write == ring->base) {
- ring->write = ring->base_end;
- ring->shwrite = ring->shbase_end;
- } else {
- ring->write -= ring->offset;
- ring->shwrite -= ring->shoffset;
- }
- }
- struct safexcel_command_desc *safexcel_add_cdesc(struct safexcel_crypto_priv *priv,
- int ring_id,
- bool first, bool last,
- dma_addr_t data, u32 data_len,
- u32 full_data_len,
- dma_addr_t context,
- struct safexcel_token **atoken)
- {
- struct safexcel_command_desc *cdesc;
- cdesc = safexcel_ring_next_cwptr(priv, &priv->ring[ring_id].cdr,
- first, atoken);
- if (IS_ERR(cdesc))
- return cdesc;
- cdesc->particle_size = data_len;
- cdesc->rsvd0 = 0;
- cdesc->last_seg = last;
- cdesc->first_seg = first;
- cdesc->additional_cdata_size = 0;
- cdesc->rsvd1 = 0;
- cdesc->data_lo = lower_32_bits(data);
- cdesc->data_hi = upper_32_bits(data);
- if (first) {
- /*
- * Note that the length here MUST be >0 or else the EIP(1)97
- * may hang. Newer EIP197 firmware actually incorporates this
- * fix already, but that doesn't help the EIP97 and we may
- * also be running older firmware.
- */
- cdesc->control_data.packet_length = full_data_len ?: 1;
- cdesc->control_data.options = EIP197_OPTION_MAGIC_VALUE |
- EIP197_OPTION_64BIT_CTX |
- EIP197_OPTION_CTX_CTRL_IN_CMD |
- EIP197_OPTION_RC_AUTO;
- cdesc->control_data.type = EIP197_TYPE_BCLA;
- cdesc->control_data.context_lo = lower_32_bits(context) |
- EIP197_CONTEXT_SMALL;
- cdesc->control_data.context_hi = upper_32_bits(context);
- }
- return cdesc;
- }
- struct safexcel_result_desc *safexcel_add_rdesc(struct safexcel_crypto_priv *priv,
- int ring_id,
- bool first, bool last,
- dma_addr_t data, u32 len)
- {
- struct safexcel_result_desc *rdesc;
- struct result_data_desc *rtoken;
- rdesc = safexcel_ring_next_rwptr(priv, &priv->ring[ring_id].rdr,
- &rtoken);
- if (IS_ERR(rdesc))
- return rdesc;
- rdesc->particle_size = len;
- rdesc->rsvd0 = 0;
- rdesc->descriptor_overflow = 1; /* assume error */
- rdesc->buffer_overflow = 1; /* assume error */
- rdesc->last_seg = last;
- rdesc->first_seg = first;
- rdesc->result_size = EIP197_RD64_RESULT_SIZE;
- rdesc->rsvd1 = 0;
- rdesc->data_lo = lower_32_bits(data);
- rdesc->data_hi = upper_32_bits(data);
- /* Clear length in result token */
- rtoken->packet_length = 0;
- /* Assume errors - HW will clear if not the case */
- rtoken->error_code = 0x7fff;
- return rdesc;
- }
|