162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2017 Marvell 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Antoine Tenart <antoine.tenart@free-electrons.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/clk.h> 962306a36Sopenharmony_ci#include <linux/device.h> 1062306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1162306a36Sopenharmony_ci#include <linux/dmapool.h> 1262306a36Sopenharmony_ci#include <linux/firmware.h> 1362306a36Sopenharmony_ci#include <linux/interrupt.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/of_platform.h> 1662306a36Sopenharmony_ci#include <linux/of_irq.h> 1762306a36Sopenharmony_ci#include <linux/pci.h> 1862306a36Sopenharmony_ci#include <linux/platform_device.h> 1962306a36Sopenharmony_ci#include <linux/workqueue.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <crypto/internal/aead.h> 2262306a36Sopenharmony_ci#include <crypto/internal/hash.h> 2362306a36Sopenharmony_ci#include <crypto/internal/skcipher.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include "safexcel.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic u32 max_rings = EIP197_MAX_RINGS; 2862306a36Sopenharmony_cimodule_param(max_rings, uint, 0644); 2962306a36Sopenharmony_ciMODULE_PARM_DESC(max_rings, "Maximum number of rings to use."); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic void eip197_trc_cache_setupvirt(struct safexcel_crypto_priv *priv) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci int i; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci /* 3662306a36Sopenharmony_ci * Map all interfaces/rings to register index 0 3762306a36Sopenharmony_ci * so they can share contexts. Without this, the EIP197 will 3862306a36Sopenharmony_ci * assume each interface/ring to be in its own memory domain 3962306a36Sopenharmony_ci * i.e. have its own subset of UNIQUE memory addresses. 4062306a36Sopenharmony_ci * Which would cause records with the SAME memory address to 4162306a36Sopenharmony_ci * use DIFFERENT cache buffers, causing both poor cache utilization 4262306a36Sopenharmony_ci * AND serious coherence/invalidation issues. 4362306a36Sopenharmony_ci */ 4462306a36Sopenharmony_ci for (i = 0; i < 4; i++) 4562306a36Sopenharmony_ci writel(0, priv->base + EIP197_FLUE_IFC_LUT(i)); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci /* 4862306a36Sopenharmony_ci * Initialize other virtualization regs for cache 4962306a36Sopenharmony_ci * These may not be in their reset state ... 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_ci for (i = 0; i < priv->config.rings; i++) { 5262306a36Sopenharmony_ci writel(0, priv->base + EIP197_FLUE_CACHEBASE_LO(i)); 5362306a36Sopenharmony_ci writel(0, priv->base + EIP197_FLUE_CACHEBASE_HI(i)); 5462306a36Sopenharmony_ci writel(EIP197_FLUE_CONFIG_MAGIC, 5562306a36Sopenharmony_ci priv->base + EIP197_FLUE_CONFIG(i)); 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci writel(0, priv->base + EIP197_FLUE_OFFSETS); 5862306a36Sopenharmony_ci writel(0, priv->base + EIP197_FLUE_ARC4_OFFSET); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic void eip197_trc_cache_banksel(struct safexcel_crypto_priv *priv, 6262306a36Sopenharmony_ci u32 addrmid, int *actbank) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci u32 val; 6562306a36Sopenharmony_ci int curbank; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci curbank = addrmid >> 16; 6862306a36Sopenharmony_ci if (curbank != *actbank) { 6962306a36Sopenharmony_ci val = readl(priv->base + EIP197_CS_RAM_CTRL); 7062306a36Sopenharmony_ci val = (val & ~EIP197_CS_BANKSEL_MASK) | 7162306a36Sopenharmony_ci (curbank << EIP197_CS_BANKSEL_OFS); 7262306a36Sopenharmony_ci writel(val, priv->base + EIP197_CS_RAM_CTRL); 7362306a36Sopenharmony_ci *actbank = curbank; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic u32 eip197_trc_cache_probe(struct safexcel_crypto_priv *priv, 7862306a36Sopenharmony_ci int maxbanks, u32 probemask, u32 stride) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci u32 val, addrhi, addrlo, addrmid, addralias, delta, marker; 8162306a36Sopenharmony_ci int actbank; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci /* 8462306a36Sopenharmony_ci * And probe the actual size of the physically attached cache data RAM 8562306a36Sopenharmony_ci * Using a binary subdivision algorithm downto 32 byte cache lines. 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ci addrhi = 1 << (16 + maxbanks); 8862306a36Sopenharmony_ci addrlo = 0; 8962306a36Sopenharmony_ci actbank = min(maxbanks - 1, 0); 9062306a36Sopenharmony_ci while ((addrhi - addrlo) > stride) { 9162306a36Sopenharmony_ci /* write marker to lowest address in top half */ 9262306a36Sopenharmony_ci addrmid = (addrhi + addrlo) >> 1; 9362306a36Sopenharmony_ci marker = (addrmid ^ 0xabadbabe) & probemask; /* Unique */ 9462306a36Sopenharmony_ci eip197_trc_cache_banksel(priv, addrmid, &actbank); 9562306a36Sopenharmony_ci writel(marker, 9662306a36Sopenharmony_ci priv->base + EIP197_CLASSIFICATION_RAMS + 9762306a36Sopenharmony_ci (addrmid & 0xffff)); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* write invalid markers to possible aliases */ 10062306a36Sopenharmony_ci delta = 1 << __fls(addrmid); 10162306a36Sopenharmony_ci while (delta >= stride) { 10262306a36Sopenharmony_ci addralias = addrmid - delta; 10362306a36Sopenharmony_ci eip197_trc_cache_banksel(priv, addralias, &actbank); 10462306a36Sopenharmony_ci writel(~marker, 10562306a36Sopenharmony_ci priv->base + EIP197_CLASSIFICATION_RAMS + 10662306a36Sopenharmony_ci (addralias & 0xffff)); 10762306a36Sopenharmony_ci delta >>= 1; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* read back marker from top half */ 11162306a36Sopenharmony_ci eip197_trc_cache_banksel(priv, addrmid, &actbank); 11262306a36Sopenharmony_ci val = readl(priv->base + EIP197_CLASSIFICATION_RAMS + 11362306a36Sopenharmony_ci (addrmid & 0xffff)); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci if ((val & probemask) == marker) 11662306a36Sopenharmony_ci /* read back correct, continue with top half */ 11762306a36Sopenharmony_ci addrlo = addrmid; 11862306a36Sopenharmony_ci else 11962306a36Sopenharmony_ci /* not read back correct, continue with bottom half */ 12062306a36Sopenharmony_ci addrhi = addrmid; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci return addrhi; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic void eip197_trc_cache_clear(struct safexcel_crypto_priv *priv, 12662306a36Sopenharmony_ci int cs_rc_max, int cs_ht_wc) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci int i; 12962306a36Sopenharmony_ci u32 htable_offset, val, offset; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* Clear all records in administration RAM */ 13262306a36Sopenharmony_ci for (i = 0; i < cs_rc_max; i++) { 13362306a36Sopenharmony_ci offset = EIP197_CLASSIFICATION_RAMS + i * EIP197_CS_RC_SIZE; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci writel(EIP197_CS_RC_NEXT(EIP197_RC_NULL) | 13662306a36Sopenharmony_ci EIP197_CS_RC_PREV(EIP197_RC_NULL), 13762306a36Sopenharmony_ci priv->base + offset); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci val = EIP197_CS_RC_NEXT(i + 1) | EIP197_CS_RC_PREV(i - 1); 14062306a36Sopenharmony_ci if (i == 0) 14162306a36Sopenharmony_ci val |= EIP197_CS_RC_PREV(EIP197_RC_NULL); 14262306a36Sopenharmony_ci else if (i == cs_rc_max - 1) 14362306a36Sopenharmony_ci val |= EIP197_CS_RC_NEXT(EIP197_RC_NULL); 14462306a36Sopenharmony_ci writel(val, priv->base + offset + 4); 14562306a36Sopenharmony_ci /* must also initialize the address key due to ECC! */ 14662306a36Sopenharmony_ci writel(0, priv->base + offset + 8); 14762306a36Sopenharmony_ci writel(0, priv->base + offset + 12); 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* Clear the hash table entries */ 15162306a36Sopenharmony_ci htable_offset = cs_rc_max * EIP197_CS_RC_SIZE; 15262306a36Sopenharmony_ci for (i = 0; i < cs_ht_wc; i++) 15362306a36Sopenharmony_ci writel(GENMASK(29, 0), 15462306a36Sopenharmony_ci priv->base + EIP197_CLASSIFICATION_RAMS + 15562306a36Sopenharmony_ci htable_offset + i * sizeof(u32)); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic int eip197_trc_cache_init(struct safexcel_crypto_priv *priv) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci u32 val, dsize, asize; 16162306a36Sopenharmony_ci int cs_rc_max, cs_ht_wc, cs_trc_rec_wc, cs_trc_lg_rec_wc; 16262306a36Sopenharmony_ci int cs_rc_abs_max, cs_ht_sz; 16362306a36Sopenharmony_ci int maxbanks; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci /* Setup (dummy) virtualization for cache */ 16662306a36Sopenharmony_ci eip197_trc_cache_setupvirt(priv); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci /* 16962306a36Sopenharmony_ci * Enable the record cache memory access and 17062306a36Sopenharmony_ci * probe the bank select width 17162306a36Sopenharmony_ci */ 17262306a36Sopenharmony_ci val = readl(priv->base + EIP197_CS_RAM_CTRL); 17362306a36Sopenharmony_ci val &= ~EIP197_TRC_ENABLE_MASK; 17462306a36Sopenharmony_ci val |= EIP197_TRC_ENABLE_0 | EIP197_CS_BANKSEL_MASK; 17562306a36Sopenharmony_ci writel(val, priv->base + EIP197_CS_RAM_CTRL); 17662306a36Sopenharmony_ci val = readl(priv->base + EIP197_CS_RAM_CTRL); 17762306a36Sopenharmony_ci maxbanks = ((val&EIP197_CS_BANKSEL_MASK)>>EIP197_CS_BANKSEL_OFS) + 1; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci /* Clear all ECC errors */ 18062306a36Sopenharmony_ci writel(0, priv->base + EIP197_TRC_ECCCTRL); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* 18362306a36Sopenharmony_ci * Make sure the cache memory is accessible by taking record cache into 18462306a36Sopenharmony_ci * reset. Need data memory access here, not admin access. 18562306a36Sopenharmony_ci */ 18662306a36Sopenharmony_ci val = readl(priv->base + EIP197_TRC_PARAMS); 18762306a36Sopenharmony_ci val |= EIP197_TRC_PARAMS_SW_RESET | EIP197_TRC_PARAMS_DATA_ACCESS; 18862306a36Sopenharmony_ci writel(val, priv->base + EIP197_TRC_PARAMS); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* Probed data RAM size in bytes */ 19162306a36Sopenharmony_ci dsize = eip197_trc_cache_probe(priv, maxbanks, 0xffffffff, 32); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci /* 19462306a36Sopenharmony_ci * Now probe the administration RAM size pretty much the same way 19562306a36Sopenharmony_ci * Except that only the lower 30 bits are writable and we don't need 19662306a36Sopenharmony_ci * bank selects 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_ci val = readl(priv->base + EIP197_TRC_PARAMS); 19962306a36Sopenharmony_ci /* admin access now */ 20062306a36Sopenharmony_ci val &= ~(EIP197_TRC_PARAMS_DATA_ACCESS | EIP197_CS_BANKSEL_MASK); 20162306a36Sopenharmony_ci writel(val, priv->base + EIP197_TRC_PARAMS); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* Probed admin RAM size in admin words */ 20462306a36Sopenharmony_ci asize = eip197_trc_cache_probe(priv, 0, 0x3fffffff, 16) >> 4; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* Clear any ECC errors detected while probing! */ 20762306a36Sopenharmony_ci writel(0, priv->base + EIP197_TRC_ECCCTRL); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* Sanity check probing results */ 21062306a36Sopenharmony_ci if (dsize < EIP197_MIN_DSIZE || asize < EIP197_MIN_ASIZE) { 21162306a36Sopenharmony_ci dev_err(priv->dev, "Record cache probing failed (%d,%d).", 21262306a36Sopenharmony_ci dsize, asize); 21362306a36Sopenharmony_ci return -ENODEV; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* 21762306a36Sopenharmony_ci * Determine optimal configuration from RAM sizes 21862306a36Sopenharmony_ci * Note that we assume that the physical RAM configuration is sane 21962306a36Sopenharmony_ci * Therefore, we don't do any parameter error checking here ... 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* For now, just use a single record format covering everything */ 22362306a36Sopenharmony_ci cs_trc_rec_wc = EIP197_CS_TRC_REC_WC; 22462306a36Sopenharmony_ci cs_trc_lg_rec_wc = EIP197_CS_TRC_REC_WC; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* 22762306a36Sopenharmony_ci * Step #1: How many records will physically fit? 22862306a36Sopenharmony_ci * Hard upper limit is 1023! 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_ci cs_rc_abs_max = min_t(uint, ((dsize >> 2) / cs_trc_lg_rec_wc), 1023); 23162306a36Sopenharmony_ci /* Step #2: Need at least 2 words in the admin RAM per record */ 23262306a36Sopenharmony_ci cs_rc_max = min_t(uint, cs_rc_abs_max, (asize >> 1)); 23362306a36Sopenharmony_ci /* Step #3: Determine log2 of hash table size */ 23462306a36Sopenharmony_ci cs_ht_sz = __fls(asize - cs_rc_max) - 2; 23562306a36Sopenharmony_ci /* Step #4: determine current size of hash table in dwords */ 23662306a36Sopenharmony_ci cs_ht_wc = 16 << cs_ht_sz; /* dwords, not admin words */ 23762306a36Sopenharmony_ci /* Step #5: add back excess words and see if we can fit more records */ 23862306a36Sopenharmony_ci cs_rc_max = min_t(uint, cs_rc_abs_max, asize - (cs_ht_wc >> 2)); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* Clear the cache RAMs */ 24162306a36Sopenharmony_ci eip197_trc_cache_clear(priv, cs_rc_max, cs_ht_wc); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci /* Disable the record cache memory access */ 24462306a36Sopenharmony_ci val = readl(priv->base + EIP197_CS_RAM_CTRL); 24562306a36Sopenharmony_ci val &= ~EIP197_TRC_ENABLE_MASK; 24662306a36Sopenharmony_ci writel(val, priv->base + EIP197_CS_RAM_CTRL); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* Write head and tail pointers of the record free chain */ 24962306a36Sopenharmony_ci val = EIP197_TRC_FREECHAIN_HEAD_PTR(0) | 25062306a36Sopenharmony_ci EIP197_TRC_FREECHAIN_TAIL_PTR(cs_rc_max - 1); 25162306a36Sopenharmony_ci writel(val, priv->base + EIP197_TRC_FREECHAIN); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* Configure the record cache #1 */ 25462306a36Sopenharmony_ci val = EIP197_TRC_PARAMS2_RC_SZ_SMALL(cs_trc_rec_wc) | 25562306a36Sopenharmony_ci EIP197_TRC_PARAMS2_HTABLE_PTR(cs_rc_max); 25662306a36Sopenharmony_ci writel(val, priv->base + EIP197_TRC_PARAMS2); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* Configure the record cache #2 */ 25962306a36Sopenharmony_ci val = EIP197_TRC_PARAMS_RC_SZ_LARGE(cs_trc_lg_rec_wc) | 26062306a36Sopenharmony_ci EIP197_TRC_PARAMS_BLK_TIMER_SPEED(1) | 26162306a36Sopenharmony_ci EIP197_TRC_PARAMS_HTABLE_SZ(cs_ht_sz); 26262306a36Sopenharmony_ci writel(val, priv->base + EIP197_TRC_PARAMS); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci dev_info(priv->dev, "TRC init: %dd,%da (%dr,%dh)\n", 26562306a36Sopenharmony_ci dsize, asize, cs_rc_max, cs_ht_wc + cs_ht_wc); 26662306a36Sopenharmony_ci return 0; 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic void eip197_init_firmware(struct safexcel_crypto_priv *priv) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci int pe, i; 27262306a36Sopenharmony_ci u32 val; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci for (pe = 0; pe < priv->config.pes; pe++) { 27562306a36Sopenharmony_ci /* Configure the token FIFO's */ 27662306a36Sopenharmony_ci writel(3, EIP197_PE(priv) + EIP197_PE_ICE_PUTF_CTRL(pe)); 27762306a36Sopenharmony_ci writel(0, EIP197_PE(priv) + EIP197_PE_ICE_PPTF_CTRL(pe)); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci /* Clear the ICE scratchpad memory */ 28062306a36Sopenharmony_ci val = readl(EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_CTRL(pe)); 28162306a36Sopenharmony_ci val |= EIP197_PE_ICE_SCRATCH_CTRL_CHANGE_TIMER | 28262306a36Sopenharmony_ci EIP197_PE_ICE_SCRATCH_CTRL_TIMER_EN | 28362306a36Sopenharmony_ci EIP197_PE_ICE_SCRATCH_CTRL_SCRATCH_ACCESS | 28462306a36Sopenharmony_ci EIP197_PE_ICE_SCRATCH_CTRL_CHANGE_ACCESS; 28562306a36Sopenharmony_ci writel(val, EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_CTRL(pe)); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci /* clear the scratchpad RAM using 32 bit writes only */ 28862306a36Sopenharmony_ci for (i = 0; i < EIP197_NUM_OF_SCRATCH_BLOCKS; i++) 28962306a36Sopenharmony_ci writel(0, EIP197_PE(priv) + 29062306a36Sopenharmony_ci EIP197_PE_ICE_SCRATCH_RAM(pe) + (i << 2)); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* Reset the IFPP engine to make its program mem accessible */ 29362306a36Sopenharmony_ci writel(EIP197_PE_ICE_x_CTRL_SW_RESET | 29462306a36Sopenharmony_ci EIP197_PE_ICE_x_CTRL_CLR_ECC_CORR | 29562306a36Sopenharmony_ci EIP197_PE_ICE_x_CTRL_CLR_ECC_NON_CORR, 29662306a36Sopenharmony_ci EIP197_PE(priv) + EIP197_PE_ICE_FPP_CTRL(pe)); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci /* Reset the IPUE engine to make its program mem accessible */ 29962306a36Sopenharmony_ci writel(EIP197_PE_ICE_x_CTRL_SW_RESET | 30062306a36Sopenharmony_ci EIP197_PE_ICE_x_CTRL_CLR_ECC_CORR | 30162306a36Sopenharmony_ci EIP197_PE_ICE_x_CTRL_CLR_ECC_NON_CORR, 30262306a36Sopenharmony_ci EIP197_PE(priv) + EIP197_PE_ICE_PUE_CTRL(pe)); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* Enable access to all IFPP program memories */ 30562306a36Sopenharmony_ci writel(EIP197_PE_ICE_RAM_CTRL_FPP_PROG_EN, 30662306a36Sopenharmony_ci EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe)); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci /* bypass the OCE, if present */ 30962306a36Sopenharmony_ci if (priv->flags & EIP197_OCE) 31062306a36Sopenharmony_ci writel(EIP197_DEBUG_OCE_BYPASS, EIP197_PE(priv) + 31162306a36Sopenharmony_ci EIP197_PE_DEBUG(pe)); 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cistatic int eip197_write_firmware(struct safexcel_crypto_priv *priv, 31762306a36Sopenharmony_ci const struct firmware *fw) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci u32 val; 32062306a36Sopenharmony_ci int i; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* Write the firmware */ 32362306a36Sopenharmony_ci for (i = 0; i < fw->size / sizeof(u32); i++) { 32462306a36Sopenharmony_ci if (priv->data->fw_little_endian) 32562306a36Sopenharmony_ci val = le32_to_cpu(((const __le32 *)fw->data)[i]); 32662306a36Sopenharmony_ci else 32762306a36Sopenharmony_ci val = be32_to_cpu(((const __be32 *)fw->data)[i]); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci writel(val, 33062306a36Sopenharmony_ci priv->base + EIP197_CLASSIFICATION_RAMS + 33162306a36Sopenharmony_ci i * sizeof(val)); 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci /* Exclude final 2 NOPs from size */ 33562306a36Sopenharmony_ci return i - EIP197_FW_TERMINAL_NOPS; 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci/* 33962306a36Sopenharmony_ci * If FW is actual production firmware, then poll for its initialization 34062306a36Sopenharmony_ci * to complete and check if it is good for the HW, otherwise just return OK. 34162306a36Sopenharmony_ci */ 34262306a36Sopenharmony_cistatic bool poll_fw_ready(struct safexcel_crypto_priv *priv, int fpp) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci int pe, pollcnt; 34562306a36Sopenharmony_ci u32 base, pollofs; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (fpp) 34862306a36Sopenharmony_ci pollofs = EIP197_FW_FPP_READY; 34962306a36Sopenharmony_ci else 35062306a36Sopenharmony_ci pollofs = EIP197_FW_PUE_READY; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci for (pe = 0; pe < priv->config.pes; pe++) { 35362306a36Sopenharmony_ci base = EIP197_PE_ICE_SCRATCH_RAM(pe); 35462306a36Sopenharmony_ci pollcnt = EIP197_FW_START_POLLCNT; 35562306a36Sopenharmony_ci while (pollcnt && 35662306a36Sopenharmony_ci (readl_relaxed(EIP197_PE(priv) + base + 35762306a36Sopenharmony_ci pollofs) != 1)) { 35862306a36Sopenharmony_ci pollcnt--; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci if (!pollcnt) { 36162306a36Sopenharmony_ci dev_err(priv->dev, "FW(%d) for PE %d failed to start\n", 36262306a36Sopenharmony_ci fpp, pe); 36362306a36Sopenharmony_ci return false; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci return true; 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic bool eip197_start_firmware(struct safexcel_crypto_priv *priv, 37062306a36Sopenharmony_ci int ipuesz, int ifppsz, int minifw) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci int pe; 37362306a36Sopenharmony_ci u32 val; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci for (pe = 0; pe < priv->config.pes; pe++) { 37662306a36Sopenharmony_ci /* Disable access to all program memory */ 37762306a36Sopenharmony_ci writel(0, EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe)); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci /* Start IFPP microengines */ 38062306a36Sopenharmony_ci if (minifw) 38162306a36Sopenharmony_ci val = 0; 38262306a36Sopenharmony_ci else 38362306a36Sopenharmony_ci val = EIP197_PE_ICE_UENG_START_OFFSET((ifppsz - 1) & 38462306a36Sopenharmony_ci EIP197_PE_ICE_UENG_INIT_ALIGN_MASK) | 38562306a36Sopenharmony_ci EIP197_PE_ICE_UENG_DEBUG_RESET; 38662306a36Sopenharmony_ci writel(val, EIP197_PE(priv) + EIP197_PE_ICE_FPP_CTRL(pe)); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci /* Start IPUE microengines */ 38962306a36Sopenharmony_ci if (minifw) 39062306a36Sopenharmony_ci val = 0; 39162306a36Sopenharmony_ci else 39262306a36Sopenharmony_ci val = EIP197_PE_ICE_UENG_START_OFFSET((ipuesz - 1) & 39362306a36Sopenharmony_ci EIP197_PE_ICE_UENG_INIT_ALIGN_MASK) | 39462306a36Sopenharmony_ci EIP197_PE_ICE_UENG_DEBUG_RESET; 39562306a36Sopenharmony_ci writel(val, EIP197_PE(priv) + EIP197_PE_ICE_PUE_CTRL(pe)); 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci /* For miniFW startup, there is no initialization, so always succeed */ 39962306a36Sopenharmony_ci if (minifw) 40062306a36Sopenharmony_ci return true; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci /* Wait until all the firmwares have properly started up */ 40362306a36Sopenharmony_ci if (!poll_fw_ready(priv, 1)) 40462306a36Sopenharmony_ci return false; 40562306a36Sopenharmony_ci if (!poll_fw_ready(priv, 0)) 40662306a36Sopenharmony_ci return false; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci return true; 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic int eip197_load_firmwares(struct safexcel_crypto_priv *priv) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci const char *fw_name[] = {"ifpp.bin", "ipue.bin"}; 41462306a36Sopenharmony_ci const struct firmware *fw[FW_NB]; 41562306a36Sopenharmony_ci char fw_path[37], *dir = NULL; 41662306a36Sopenharmony_ci int i, j, ret = 0, pe; 41762306a36Sopenharmony_ci int ipuesz, ifppsz, minifw = 0; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (priv->data->version == EIP197D_MRVL) 42062306a36Sopenharmony_ci dir = "eip197d"; 42162306a36Sopenharmony_ci else if (priv->data->version == EIP197B_MRVL || 42262306a36Sopenharmony_ci priv->data->version == EIP197_DEVBRD) 42362306a36Sopenharmony_ci dir = "eip197b"; 42462306a36Sopenharmony_ci else if (priv->data->version == EIP197C_MXL) 42562306a36Sopenharmony_ci dir = "eip197c"; 42662306a36Sopenharmony_ci else 42762306a36Sopenharmony_ci return -ENODEV; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ciretry_fw: 43062306a36Sopenharmony_ci for (i = 0; i < FW_NB; i++) { 43162306a36Sopenharmony_ci snprintf(fw_path, 37, "inside-secure/%s/%s", dir, fw_name[i]); 43262306a36Sopenharmony_ci ret = firmware_request_nowarn(&fw[i], fw_path, priv->dev); 43362306a36Sopenharmony_ci if (ret) { 43462306a36Sopenharmony_ci if (minifw || priv->data->version != EIP197B_MRVL) 43562306a36Sopenharmony_ci goto release_fw; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* Fallback to the old firmware location for the 43862306a36Sopenharmony_ci * EIP197b. 43962306a36Sopenharmony_ci */ 44062306a36Sopenharmony_ci ret = firmware_request_nowarn(&fw[i], fw_name[i], 44162306a36Sopenharmony_ci priv->dev); 44262306a36Sopenharmony_ci if (ret) 44362306a36Sopenharmony_ci goto release_fw; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci eip197_init_firmware(priv); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci ifppsz = eip197_write_firmware(priv, fw[FW_IFPP]); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci /* Enable access to IPUE program memories */ 45262306a36Sopenharmony_ci for (pe = 0; pe < priv->config.pes; pe++) 45362306a36Sopenharmony_ci writel(EIP197_PE_ICE_RAM_CTRL_PUE_PROG_EN, 45462306a36Sopenharmony_ci EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe)); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci ipuesz = eip197_write_firmware(priv, fw[FW_IPUE]); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (eip197_start_firmware(priv, ipuesz, ifppsz, minifw)) { 45962306a36Sopenharmony_ci dev_dbg(priv->dev, "Firmware loaded successfully\n"); 46062306a36Sopenharmony_ci return 0; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci ret = -ENODEV; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cirelease_fw: 46662306a36Sopenharmony_ci for (j = 0; j < i; j++) 46762306a36Sopenharmony_ci release_firmware(fw[j]); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (!minifw) { 47062306a36Sopenharmony_ci /* Retry with minifw path */ 47162306a36Sopenharmony_ci dev_dbg(priv->dev, "Firmware set not (fully) present or init failed, falling back to BCLA mode\n"); 47262306a36Sopenharmony_ci dir = "eip197_minifw"; 47362306a36Sopenharmony_ci minifw = 1; 47462306a36Sopenharmony_ci goto retry_fw; 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci dev_err(priv->dev, "Firmware load failed.\n"); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci return ret; 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistatic int safexcel_hw_setup_cdesc_rings(struct safexcel_crypto_priv *priv) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci u32 cd_size_rnd, val; 48562306a36Sopenharmony_ci int i, cd_fetch_cnt; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci cd_size_rnd = (priv->config.cd_size + 48862306a36Sopenharmony_ci (BIT(priv->hwconfig.hwdataw) - 1)) >> 48962306a36Sopenharmony_ci priv->hwconfig.hwdataw; 49062306a36Sopenharmony_ci /* determine number of CD's we can fetch into the CD FIFO as 1 block */ 49162306a36Sopenharmony_ci if (priv->flags & SAFEXCEL_HW_EIP197) { 49262306a36Sopenharmony_ci /* EIP197: try to fetch enough in 1 go to keep all pipes busy */ 49362306a36Sopenharmony_ci cd_fetch_cnt = (1 << priv->hwconfig.hwcfsize) / cd_size_rnd; 49462306a36Sopenharmony_ci cd_fetch_cnt = min_t(uint, cd_fetch_cnt, 49562306a36Sopenharmony_ci (priv->config.pes * EIP197_FETCH_DEPTH)); 49662306a36Sopenharmony_ci } else { 49762306a36Sopenharmony_ci /* for the EIP97, just fetch all that fits minus 1 */ 49862306a36Sopenharmony_ci cd_fetch_cnt = ((1 << priv->hwconfig.hwcfsize) / 49962306a36Sopenharmony_ci cd_size_rnd) - 1; 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci /* 50262306a36Sopenharmony_ci * Since we're using command desc's way larger than formally specified, 50362306a36Sopenharmony_ci * we need to check whether we can fit even 1 for low-end EIP196's! 50462306a36Sopenharmony_ci */ 50562306a36Sopenharmony_ci if (!cd_fetch_cnt) { 50662306a36Sopenharmony_ci dev_err(priv->dev, "Unable to fit even 1 command desc!\n"); 50762306a36Sopenharmony_ci return -ENODEV; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci for (i = 0; i < priv->config.rings; i++) { 51162306a36Sopenharmony_ci /* ring base address */ 51262306a36Sopenharmony_ci writel(lower_32_bits(priv->ring[i].cdr.base_dma), 51362306a36Sopenharmony_ci EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_LO); 51462306a36Sopenharmony_ci writel(upper_32_bits(priv->ring[i].cdr.base_dma), 51562306a36Sopenharmony_ci EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_HI); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci writel(EIP197_xDR_DESC_MODE_64BIT | EIP197_CDR_DESC_MODE_ADCP | 51862306a36Sopenharmony_ci (priv->config.cd_offset << 14) | priv->config.cd_size, 51962306a36Sopenharmony_ci EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_DESC_SIZE); 52062306a36Sopenharmony_ci writel(((cd_fetch_cnt * 52162306a36Sopenharmony_ci (cd_size_rnd << priv->hwconfig.hwdataw)) << 16) | 52262306a36Sopenharmony_ci (cd_fetch_cnt * (priv->config.cd_offset / sizeof(u32))), 52362306a36Sopenharmony_ci EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_CFG); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci /* Configure DMA tx control */ 52662306a36Sopenharmony_ci val = EIP197_HIA_xDR_CFG_WR_CACHE(WR_CACHE_3BITS); 52762306a36Sopenharmony_ci val |= EIP197_HIA_xDR_CFG_RD_CACHE(RD_CACHE_3BITS); 52862306a36Sopenharmony_ci writel(val, EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_DMA_CFG); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci /* clear any pending interrupt */ 53162306a36Sopenharmony_ci writel(GENMASK(5, 0), 53262306a36Sopenharmony_ci EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_STAT); 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci return 0; 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic int safexcel_hw_setup_rdesc_rings(struct safexcel_crypto_priv *priv) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci u32 rd_size_rnd, val; 54162306a36Sopenharmony_ci int i, rd_fetch_cnt; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci /* determine number of RD's we can fetch into the FIFO as one block */ 54462306a36Sopenharmony_ci rd_size_rnd = (EIP197_RD64_FETCH_SIZE + 54562306a36Sopenharmony_ci (BIT(priv->hwconfig.hwdataw) - 1)) >> 54662306a36Sopenharmony_ci priv->hwconfig.hwdataw; 54762306a36Sopenharmony_ci if (priv->flags & SAFEXCEL_HW_EIP197) { 54862306a36Sopenharmony_ci /* EIP197: try to fetch enough in 1 go to keep all pipes busy */ 54962306a36Sopenharmony_ci rd_fetch_cnt = (1 << priv->hwconfig.hwrfsize) / rd_size_rnd; 55062306a36Sopenharmony_ci rd_fetch_cnt = min_t(uint, rd_fetch_cnt, 55162306a36Sopenharmony_ci (priv->config.pes * EIP197_FETCH_DEPTH)); 55262306a36Sopenharmony_ci } else { 55362306a36Sopenharmony_ci /* for the EIP97, just fetch all that fits minus 1 */ 55462306a36Sopenharmony_ci rd_fetch_cnt = ((1 << priv->hwconfig.hwrfsize) / 55562306a36Sopenharmony_ci rd_size_rnd) - 1; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci for (i = 0; i < priv->config.rings; i++) { 55962306a36Sopenharmony_ci /* ring base address */ 56062306a36Sopenharmony_ci writel(lower_32_bits(priv->ring[i].rdr.base_dma), 56162306a36Sopenharmony_ci EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_LO); 56262306a36Sopenharmony_ci writel(upper_32_bits(priv->ring[i].rdr.base_dma), 56362306a36Sopenharmony_ci EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_HI); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci writel(EIP197_xDR_DESC_MODE_64BIT | (priv->config.rd_offset << 14) | 56662306a36Sopenharmony_ci priv->config.rd_size, 56762306a36Sopenharmony_ci EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_DESC_SIZE); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci writel(((rd_fetch_cnt * 57062306a36Sopenharmony_ci (rd_size_rnd << priv->hwconfig.hwdataw)) << 16) | 57162306a36Sopenharmony_ci (rd_fetch_cnt * (priv->config.rd_offset / sizeof(u32))), 57262306a36Sopenharmony_ci EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_CFG); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci /* Configure DMA tx control */ 57562306a36Sopenharmony_ci val = EIP197_HIA_xDR_CFG_WR_CACHE(WR_CACHE_3BITS); 57662306a36Sopenharmony_ci val |= EIP197_HIA_xDR_CFG_RD_CACHE(RD_CACHE_3BITS); 57762306a36Sopenharmony_ci val |= EIP197_HIA_xDR_WR_RES_BUF | EIP197_HIA_xDR_WR_CTRL_BUF; 57862306a36Sopenharmony_ci writel(val, 57962306a36Sopenharmony_ci EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_DMA_CFG); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci /* clear any pending interrupt */ 58262306a36Sopenharmony_ci writel(GENMASK(7, 0), 58362306a36Sopenharmony_ci EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_STAT); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci /* enable ring interrupt */ 58662306a36Sopenharmony_ci val = readl(EIP197_HIA_AIC_R(priv) + EIP197_HIA_AIC_R_ENABLE_CTRL(i)); 58762306a36Sopenharmony_ci val |= EIP197_RDR_IRQ(i); 58862306a36Sopenharmony_ci writel(val, EIP197_HIA_AIC_R(priv) + EIP197_HIA_AIC_R_ENABLE_CTRL(i)); 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci return 0; 59262306a36Sopenharmony_ci} 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_cistatic int safexcel_hw_init(struct safexcel_crypto_priv *priv) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci u32 val; 59762306a36Sopenharmony_ci int i, ret, pe, opbuflo, opbufhi; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci dev_dbg(priv->dev, "HW init: using %d pipe(s) and %d ring(s)\n", 60062306a36Sopenharmony_ci priv->config.pes, priv->config.rings); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci /* 60362306a36Sopenharmony_ci * For EIP197's only set maximum number of TX commands to 2^5 = 32 60462306a36Sopenharmony_ci * Skip for the EIP97 as it does not have this field. 60562306a36Sopenharmony_ci */ 60662306a36Sopenharmony_ci if (priv->flags & SAFEXCEL_HW_EIP197) { 60762306a36Sopenharmony_ci val = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL); 60862306a36Sopenharmony_ci val |= EIP197_MST_CTRL_TX_MAX_CMD(5); 60962306a36Sopenharmony_ci writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL); 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci /* Configure wr/rd cache values */ 61362306a36Sopenharmony_ci writel(EIP197_MST_CTRL_RD_CACHE(RD_CACHE_4BITS) | 61462306a36Sopenharmony_ci EIP197_MST_CTRL_WD_CACHE(WR_CACHE_4BITS), 61562306a36Sopenharmony_ci EIP197_HIA_GEN_CFG(priv) + EIP197_MST_CTRL); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci /* Interrupts reset */ 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci /* Disable all global interrupts */ 62062306a36Sopenharmony_ci writel(0, EIP197_HIA_AIC_G(priv) + EIP197_HIA_AIC_G_ENABLE_CTRL); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci /* Clear any pending interrupt */ 62362306a36Sopenharmony_ci writel(GENMASK(31, 0), EIP197_HIA_AIC_G(priv) + EIP197_HIA_AIC_G_ACK); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci /* Processing Engine configuration */ 62662306a36Sopenharmony_ci for (pe = 0; pe < priv->config.pes; pe++) { 62762306a36Sopenharmony_ci /* Data Fetch Engine configuration */ 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci /* Reset all DFE threads */ 63062306a36Sopenharmony_ci writel(EIP197_DxE_THR_CTRL_RESET_PE, 63162306a36Sopenharmony_ci EIP197_HIA_DFE_THR(priv) + EIP197_HIA_DFE_THR_CTRL(pe)); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci if (priv->flags & EIP197_PE_ARB) 63462306a36Sopenharmony_ci /* Reset HIA input interface arbiter (if present) */ 63562306a36Sopenharmony_ci writel(EIP197_HIA_RA_PE_CTRL_RESET, 63662306a36Sopenharmony_ci EIP197_HIA_AIC(priv) + EIP197_HIA_RA_PE_CTRL(pe)); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* DMA transfer size to use */ 63962306a36Sopenharmony_ci val = EIP197_HIA_DFE_CFG_DIS_DEBUG; 64062306a36Sopenharmony_ci val |= EIP197_HIA_DxE_CFG_MIN_DATA_SIZE(6) | 64162306a36Sopenharmony_ci EIP197_HIA_DxE_CFG_MAX_DATA_SIZE(9); 64262306a36Sopenharmony_ci val |= EIP197_HIA_DxE_CFG_MIN_CTRL_SIZE(6) | 64362306a36Sopenharmony_ci EIP197_HIA_DxE_CFG_MAX_CTRL_SIZE(7); 64462306a36Sopenharmony_ci val |= EIP197_HIA_DxE_CFG_DATA_CACHE_CTRL(RD_CACHE_3BITS); 64562306a36Sopenharmony_ci val |= EIP197_HIA_DxE_CFG_CTRL_CACHE_CTRL(RD_CACHE_3BITS); 64662306a36Sopenharmony_ci writel(val, EIP197_HIA_DFE(priv) + EIP197_HIA_DFE_CFG(pe)); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci /* Leave the DFE threads reset state */ 64962306a36Sopenharmony_ci writel(0, EIP197_HIA_DFE_THR(priv) + EIP197_HIA_DFE_THR_CTRL(pe)); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci /* Configure the processing engine thresholds */ 65262306a36Sopenharmony_ci writel(EIP197_PE_IN_xBUF_THRES_MIN(6) | 65362306a36Sopenharmony_ci EIP197_PE_IN_xBUF_THRES_MAX(9), 65462306a36Sopenharmony_ci EIP197_PE(priv) + EIP197_PE_IN_DBUF_THRES(pe)); 65562306a36Sopenharmony_ci writel(EIP197_PE_IN_xBUF_THRES_MIN(6) | 65662306a36Sopenharmony_ci EIP197_PE_IN_xBUF_THRES_MAX(7), 65762306a36Sopenharmony_ci EIP197_PE(priv) + EIP197_PE_IN_TBUF_THRES(pe)); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci if (priv->flags & SAFEXCEL_HW_EIP197) 66062306a36Sopenharmony_ci /* enable HIA input interface arbiter and rings */ 66162306a36Sopenharmony_ci writel(EIP197_HIA_RA_PE_CTRL_EN | 66262306a36Sopenharmony_ci GENMASK(priv->config.rings - 1, 0), 66362306a36Sopenharmony_ci EIP197_HIA_AIC(priv) + EIP197_HIA_RA_PE_CTRL(pe)); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci /* Data Store Engine configuration */ 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* Reset all DSE threads */ 66862306a36Sopenharmony_ci writel(EIP197_DxE_THR_CTRL_RESET_PE, 66962306a36Sopenharmony_ci EIP197_HIA_DSE_THR(priv) + EIP197_HIA_DSE_THR_CTRL(pe)); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci /* Wait for all DSE threads to complete */ 67262306a36Sopenharmony_ci while ((readl(EIP197_HIA_DSE_THR(priv) + EIP197_HIA_DSE_THR_STAT(pe)) & 67362306a36Sopenharmony_ci GENMASK(15, 12)) != GENMASK(15, 12)) 67462306a36Sopenharmony_ci ; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci /* DMA transfer size to use */ 67762306a36Sopenharmony_ci if (priv->hwconfig.hwnumpes > 4) { 67862306a36Sopenharmony_ci opbuflo = 9; 67962306a36Sopenharmony_ci opbufhi = 10; 68062306a36Sopenharmony_ci } else { 68162306a36Sopenharmony_ci opbuflo = 7; 68262306a36Sopenharmony_ci opbufhi = 8; 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci val = EIP197_HIA_DSE_CFG_DIS_DEBUG; 68562306a36Sopenharmony_ci val |= EIP197_HIA_DxE_CFG_MIN_DATA_SIZE(opbuflo) | 68662306a36Sopenharmony_ci EIP197_HIA_DxE_CFG_MAX_DATA_SIZE(opbufhi); 68762306a36Sopenharmony_ci val |= EIP197_HIA_DxE_CFG_DATA_CACHE_CTRL(WR_CACHE_3BITS); 68862306a36Sopenharmony_ci val |= EIP197_HIA_DSE_CFG_ALWAYS_BUFFERABLE; 68962306a36Sopenharmony_ci /* FIXME: instability issues can occur for EIP97 but disabling 69062306a36Sopenharmony_ci * it impacts performance. 69162306a36Sopenharmony_ci */ 69262306a36Sopenharmony_ci if (priv->flags & SAFEXCEL_HW_EIP197) 69362306a36Sopenharmony_ci val |= EIP197_HIA_DSE_CFG_EN_SINGLE_WR; 69462306a36Sopenharmony_ci writel(val, EIP197_HIA_DSE(priv) + EIP197_HIA_DSE_CFG(pe)); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci /* Leave the DSE threads reset state */ 69762306a36Sopenharmony_ci writel(0, EIP197_HIA_DSE_THR(priv) + EIP197_HIA_DSE_THR_CTRL(pe)); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci /* Configure the processing engine thresholds */ 70062306a36Sopenharmony_ci writel(EIP197_PE_OUT_DBUF_THRES_MIN(opbuflo) | 70162306a36Sopenharmony_ci EIP197_PE_OUT_DBUF_THRES_MAX(opbufhi), 70262306a36Sopenharmony_ci EIP197_PE(priv) + EIP197_PE_OUT_DBUF_THRES(pe)); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci /* Processing Engine configuration */ 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci /* Token & context configuration */ 70762306a36Sopenharmony_ci val = EIP197_PE_EIP96_TOKEN_CTRL_CTX_UPDATES | 70862306a36Sopenharmony_ci EIP197_PE_EIP96_TOKEN_CTRL_NO_TOKEN_WAIT | 70962306a36Sopenharmony_ci EIP197_PE_EIP96_TOKEN_CTRL_ENABLE_TIMEOUT; 71062306a36Sopenharmony_ci writel(val, EIP197_PE(priv) + EIP197_PE_EIP96_TOKEN_CTRL(pe)); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci /* H/W capabilities selection: just enable everything */ 71362306a36Sopenharmony_ci writel(EIP197_FUNCTION_ALL, 71462306a36Sopenharmony_ci EIP197_PE(priv) + EIP197_PE_EIP96_FUNCTION_EN(pe)); 71562306a36Sopenharmony_ci writel(EIP197_FUNCTION_ALL, 71662306a36Sopenharmony_ci EIP197_PE(priv) + EIP197_PE_EIP96_FUNCTION2_EN(pe)); 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci /* Command Descriptor Rings prepare */ 72062306a36Sopenharmony_ci for (i = 0; i < priv->config.rings; i++) { 72162306a36Sopenharmony_ci /* Clear interrupts for this ring */ 72262306a36Sopenharmony_ci writel(GENMASK(31, 0), 72362306a36Sopenharmony_ci EIP197_HIA_AIC_R(priv) + EIP197_HIA_AIC_R_ENABLE_CLR(i)); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci /* Disable external triggering */ 72662306a36Sopenharmony_ci writel(0, EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_CFG); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci /* Clear the pending prepared counter */ 72962306a36Sopenharmony_ci writel(EIP197_xDR_PREP_CLR_COUNT, 73062306a36Sopenharmony_ci EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_PREP_COUNT); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci /* Clear the pending processed counter */ 73362306a36Sopenharmony_ci writel(EIP197_xDR_PROC_CLR_COUNT, 73462306a36Sopenharmony_ci EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_PROC_COUNT); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci writel(0, 73762306a36Sopenharmony_ci EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_PREP_PNTR); 73862306a36Sopenharmony_ci writel(0, 73962306a36Sopenharmony_ci EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_PROC_PNTR); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci writel((EIP197_DEFAULT_RING_SIZE * priv->config.cd_offset), 74262306a36Sopenharmony_ci EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_RING_SIZE); 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci /* Result Descriptor Ring prepare */ 74662306a36Sopenharmony_ci for (i = 0; i < priv->config.rings; i++) { 74762306a36Sopenharmony_ci /* Disable external triggering*/ 74862306a36Sopenharmony_ci writel(0, EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_CFG); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci /* Clear the pending prepared counter */ 75162306a36Sopenharmony_ci writel(EIP197_xDR_PREP_CLR_COUNT, 75262306a36Sopenharmony_ci EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_PREP_COUNT); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci /* Clear the pending processed counter */ 75562306a36Sopenharmony_ci writel(EIP197_xDR_PROC_CLR_COUNT, 75662306a36Sopenharmony_ci EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_PROC_COUNT); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci writel(0, 75962306a36Sopenharmony_ci EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_PREP_PNTR); 76062306a36Sopenharmony_ci writel(0, 76162306a36Sopenharmony_ci EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_PROC_PNTR); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci /* Ring size */ 76462306a36Sopenharmony_ci writel((EIP197_DEFAULT_RING_SIZE * priv->config.rd_offset), 76562306a36Sopenharmony_ci EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_RING_SIZE); 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci for (pe = 0; pe < priv->config.pes; pe++) { 76962306a36Sopenharmony_ci /* Enable command descriptor rings */ 77062306a36Sopenharmony_ci writel(EIP197_DxE_THR_CTRL_EN | GENMASK(priv->config.rings - 1, 0), 77162306a36Sopenharmony_ci EIP197_HIA_DFE_THR(priv) + EIP197_HIA_DFE_THR_CTRL(pe)); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci /* Enable result descriptor rings */ 77462306a36Sopenharmony_ci writel(EIP197_DxE_THR_CTRL_EN | GENMASK(priv->config.rings - 1, 0), 77562306a36Sopenharmony_ci EIP197_HIA_DSE_THR(priv) + EIP197_HIA_DSE_THR_CTRL(pe)); 77662306a36Sopenharmony_ci } 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci /* Clear any HIA interrupt */ 77962306a36Sopenharmony_ci writel(GENMASK(30, 20), EIP197_HIA_AIC_G(priv) + EIP197_HIA_AIC_G_ACK); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci if (priv->flags & EIP197_SIMPLE_TRC) { 78262306a36Sopenharmony_ci writel(EIP197_STRC_CONFIG_INIT | 78362306a36Sopenharmony_ci EIP197_STRC_CONFIG_LARGE_REC(EIP197_CS_TRC_REC_WC) | 78462306a36Sopenharmony_ci EIP197_STRC_CONFIG_SMALL_REC(EIP197_CS_TRC_REC_WC), 78562306a36Sopenharmony_ci priv->base + EIP197_STRC_CONFIG); 78662306a36Sopenharmony_ci writel(EIP197_PE_EIP96_TOKEN_CTRL2_CTX_DONE, 78762306a36Sopenharmony_ci EIP197_PE(priv) + EIP197_PE_EIP96_TOKEN_CTRL2(0)); 78862306a36Sopenharmony_ci } else if (priv->flags & SAFEXCEL_HW_EIP197) { 78962306a36Sopenharmony_ci ret = eip197_trc_cache_init(priv); 79062306a36Sopenharmony_ci if (ret) 79162306a36Sopenharmony_ci return ret; 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci if (priv->flags & EIP197_ICE) { 79562306a36Sopenharmony_ci ret = eip197_load_firmwares(priv); 79662306a36Sopenharmony_ci if (ret) 79762306a36Sopenharmony_ci return ret; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci return safexcel_hw_setup_cdesc_rings(priv) ?: 80162306a36Sopenharmony_ci safexcel_hw_setup_rdesc_rings(priv) ?: 80262306a36Sopenharmony_ci 0; 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci/* Called with ring's lock taken */ 80662306a36Sopenharmony_cistatic void safexcel_try_push_requests(struct safexcel_crypto_priv *priv, 80762306a36Sopenharmony_ci int ring) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci int coal = min_t(int, priv->ring[ring].requests, EIP197_MAX_BATCH_SZ); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci if (!coal) 81262306a36Sopenharmony_ci return; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci /* Configure when we want an interrupt */ 81562306a36Sopenharmony_ci writel(EIP197_HIA_RDR_THRESH_PKT_MODE | 81662306a36Sopenharmony_ci EIP197_HIA_RDR_THRESH_PROC_PKT(coal), 81762306a36Sopenharmony_ci EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_THRESH); 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_civoid safexcel_dequeue(struct safexcel_crypto_priv *priv, int ring) 82162306a36Sopenharmony_ci{ 82262306a36Sopenharmony_ci struct crypto_async_request *req, *backlog; 82362306a36Sopenharmony_ci struct safexcel_context *ctx; 82462306a36Sopenharmony_ci int ret, nreq = 0, cdesc = 0, rdesc = 0, commands, results; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci /* If a request wasn't properly dequeued because of a lack of resources, 82762306a36Sopenharmony_ci * proceeded it first, 82862306a36Sopenharmony_ci */ 82962306a36Sopenharmony_ci req = priv->ring[ring].req; 83062306a36Sopenharmony_ci backlog = priv->ring[ring].backlog; 83162306a36Sopenharmony_ci if (req) 83262306a36Sopenharmony_ci goto handle_req; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci while (true) { 83562306a36Sopenharmony_ci spin_lock_bh(&priv->ring[ring].queue_lock); 83662306a36Sopenharmony_ci backlog = crypto_get_backlog(&priv->ring[ring].queue); 83762306a36Sopenharmony_ci req = crypto_dequeue_request(&priv->ring[ring].queue); 83862306a36Sopenharmony_ci spin_unlock_bh(&priv->ring[ring].queue_lock); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci if (!req) { 84162306a36Sopenharmony_ci priv->ring[ring].req = NULL; 84262306a36Sopenharmony_ci priv->ring[ring].backlog = NULL; 84362306a36Sopenharmony_ci goto finalize; 84462306a36Sopenharmony_ci } 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_cihandle_req: 84762306a36Sopenharmony_ci ctx = crypto_tfm_ctx(req->tfm); 84862306a36Sopenharmony_ci ret = ctx->send(req, ring, &commands, &results); 84962306a36Sopenharmony_ci if (ret) 85062306a36Sopenharmony_ci goto request_failed; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci if (backlog) 85362306a36Sopenharmony_ci crypto_request_complete(backlog, -EINPROGRESS); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci /* In case the send() helper did not issue any command to push 85662306a36Sopenharmony_ci * to the engine because the input data was cached, continue to 85762306a36Sopenharmony_ci * dequeue other requests as this is valid and not an error. 85862306a36Sopenharmony_ci */ 85962306a36Sopenharmony_ci if (!commands && !results) 86062306a36Sopenharmony_ci continue; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci cdesc += commands; 86362306a36Sopenharmony_ci rdesc += results; 86462306a36Sopenharmony_ci nreq++; 86562306a36Sopenharmony_ci } 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_cirequest_failed: 86862306a36Sopenharmony_ci /* Not enough resources to handle all the requests. Bail out and save 86962306a36Sopenharmony_ci * the request and the backlog for the next dequeue call (per-ring). 87062306a36Sopenharmony_ci */ 87162306a36Sopenharmony_ci priv->ring[ring].req = req; 87262306a36Sopenharmony_ci priv->ring[ring].backlog = backlog; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_cifinalize: 87562306a36Sopenharmony_ci if (!nreq) 87662306a36Sopenharmony_ci return; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci spin_lock_bh(&priv->ring[ring].lock); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci priv->ring[ring].requests += nreq; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci if (!priv->ring[ring].busy) { 88362306a36Sopenharmony_ci safexcel_try_push_requests(priv, ring); 88462306a36Sopenharmony_ci priv->ring[ring].busy = true; 88562306a36Sopenharmony_ci } 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci spin_unlock_bh(&priv->ring[ring].lock); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci /* let the RDR know we have pending descriptors */ 89062306a36Sopenharmony_ci writel((rdesc * priv->config.rd_offset), 89162306a36Sopenharmony_ci EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_PREP_COUNT); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci /* let the CDR know we have pending descriptors */ 89462306a36Sopenharmony_ci writel((cdesc * priv->config.cd_offset), 89562306a36Sopenharmony_ci EIP197_HIA_CDR(priv, ring) + EIP197_HIA_xDR_PREP_COUNT); 89662306a36Sopenharmony_ci} 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ciinline int safexcel_rdesc_check_errors(struct safexcel_crypto_priv *priv, 89962306a36Sopenharmony_ci void *rdp) 90062306a36Sopenharmony_ci{ 90162306a36Sopenharmony_ci struct safexcel_result_desc *rdesc = rdp; 90262306a36Sopenharmony_ci struct result_data_desc *result_data = rdp + priv->config.res_offset; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci if (likely((!rdesc->last_seg) || /* Rest only valid if last seg! */ 90562306a36Sopenharmony_ci ((!rdesc->descriptor_overflow) && 90662306a36Sopenharmony_ci (!rdesc->buffer_overflow) && 90762306a36Sopenharmony_ci (!result_data->error_code)))) 90862306a36Sopenharmony_ci return 0; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci if (rdesc->descriptor_overflow) 91162306a36Sopenharmony_ci dev_err(priv->dev, "Descriptor overflow detected"); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci if (rdesc->buffer_overflow) 91462306a36Sopenharmony_ci dev_err(priv->dev, "Buffer overflow detected"); 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci if (result_data->error_code & 0x4066) { 91762306a36Sopenharmony_ci /* Fatal error (bits 1,2,5,6 & 14) */ 91862306a36Sopenharmony_ci dev_err(priv->dev, 91962306a36Sopenharmony_ci "result descriptor error (%x)", 92062306a36Sopenharmony_ci result_data->error_code); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci return -EIO; 92362306a36Sopenharmony_ci } else if (result_data->error_code & 92462306a36Sopenharmony_ci (BIT(7) | BIT(4) | BIT(3) | BIT(0))) { 92562306a36Sopenharmony_ci /* 92662306a36Sopenharmony_ci * Give priority over authentication fails: 92762306a36Sopenharmony_ci * Blocksize, length & overflow errors, 92862306a36Sopenharmony_ci * something wrong with the input! 92962306a36Sopenharmony_ci */ 93062306a36Sopenharmony_ci return -EINVAL; 93162306a36Sopenharmony_ci } else if (result_data->error_code & BIT(9)) { 93262306a36Sopenharmony_ci /* Authentication failed */ 93362306a36Sopenharmony_ci return -EBADMSG; 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci /* All other non-fatal errors */ 93762306a36Sopenharmony_ci return -EINVAL; 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ciinline void safexcel_rdr_req_set(struct safexcel_crypto_priv *priv, 94162306a36Sopenharmony_ci int ring, 94262306a36Sopenharmony_ci struct safexcel_result_desc *rdesc, 94362306a36Sopenharmony_ci struct crypto_async_request *req) 94462306a36Sopenharmony_ci{ 94562306a36Sopenharmony_ci int i = safexcel_ring_rdr_rdesc_index(priv, ring, rdesc); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci priv->ring[ring].rdr_req[i] = req; 94862306a36Sopenharmony_ci} 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ciinline struct crypto_async_request * 95162306a36Sopenharmony_cisafexcel_rdr_req_get(struct safexcel_crypto_priv *priv, int ring) 95262306a36Sopenharmony_ci{ 95362306a36Sopenharmony_ci int i = safexcel_ring_first_rdr_index(priv, ring); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci return priv->ring[ring].rdr_req[i]; 95662306a36Sopenharmony_ci} 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_civoid safexcel_complete(struct safexcel_crypto_priv *priv, int ring) 95962306a36Sopenharmony_ci{ 96062306a36Sopenharmony_ci struct safexcel_command_desc *cdesc; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci /* Acknowledge the command descriptors */ 96362306a36Sopenharmony_ci do { 96462306a36Sopenharmony_ci cdesc = safexcel_ring_next_rptr(priv, &priv->ring[ring].cdr); 96562306a36Sopenharmony_ci if (IS_ERR(cdesc)) { 96662306a36Sopenharmony_ci dev_err(priv->dev, 96762306a36Sopenharmony_ci "Could not retrieve the command descriptor\n"); 96862306a36Sopenharmony_ci return; 96962306a36Sopenharmony_ci } 97062306a36Sopenharmony_ci } while (!cdesc->last_seg); 97162306a36Sopenharmony_ci} 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ciint safexcel_invalidate_cache(struct crypto_async_request *async, 97462306a36Sopenharmony_ci struct safexcel_crypto_priv *priv, 97562306a36Sopenharmony_ci dma_addr_t ctxr_dma, int ring) 97662306a36Sopenharmony_ci{ 97762306a36Sopenharmony_ci struct safexcel_command_desc *cdesc; 97862306a36Sopenharmony_ci struct safexcel_result_desc *rdesc; 97962306a36Sopenharmony_ci struct safexcel_token *dmmy; 98062306a36Sopenharmony_ci int ret = 0; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci /* Prepare command descriptor */ 98362306a36Sopenharmony_ci cdesc = safexcel_add_cdesc(priv, ring, true, true, 0, 0, 0, ctxr_dma, 98462306a36Sopenharmony_ci &dmmy); 98562306a36Sopenharmony_ci if (IS_ERR(cdesc)) 98662306a36Sopenharmony_ci return PTR_ERR(cdesc); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci cdesc->control_data.type = EIP197_TYPE_EXTENDED; 98962306a36Sopenharmony_ci cdesc->control_data.options = 0; 99062306a36Sopenharmony_ci cdesc->control_data.context_lo &= ~EIP197_CONTEXT_SIZE_MASK; 99162306a36Sopenharmony_ci cdesc->control_data.control0 = CONTEXT_CONTROL_INV_TR; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci /* Prepare result descriptor */ 99462306a36Sopenharmony_ci rdesc = safexcel_add_rdesc(priv, ring, true, true, 0, 0); 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci if (IS_ERR(rdesc)) { 99762306a36Sopenharmony_ci ret = PTR_ERR(rdesc); 99862306a36Sopenharmony_ci goto cdesc_rollback; 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci safexcel_rdr_req_set(priv, ring, rdesc, async); 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci return ret; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_cicdesc_rollback: 100662306a36Sopenharmony_ci safexcel_ring_rollback_wptr(priv, &priv->ring[ring].cdr); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci return ret; 100962306a36Sopenharmony_ci} 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_cistatic inline void safexcel_handle_result_descriptor(struct safexcel_crypto_priv *priv, 101262306a36Sopenharmony_ci int ring) 101362306a36Sopenharmony_ci{ 101462306a36Sopenharmony_ci struct crypto_async_request *req; 101562306a36Sopenharmony_ci struct safexcel_context *ctx; 101662306a36Sopenharmony_ci int ret, i, nreq, ndesc, tot_descs, handled = 0; 101762306a36Sopenharmony_ci bool should_complete; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_cihandle_results: 102062306a36Sopenharmony_ci tot_descs = 0; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci nreq = readl(EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_PROC_COUNT); 102362306a36Sopenharmony_ci nreq >>= EIP197_xDR_PROC_xD_PKT_OFFSET; 102462306a36Sopenharmony_ci nreq &= EIP197_xDR_PROC_xD_PKT_MASK; 102562306a36Sopenharmony_ci if (!nreq) 102662306a36Sopenharmony_ci goto requests_left; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci for (i = 0; i < nreq; i++) { 102962306a36Sopenharmony_ci req = safexcel_rdr_req_get(priv, ring); 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci ctx = crypto_tfm_ctx(req->tfm); 103262306a36Sopenharmony_ci ndesc = ctx->handle_result(priv, ring, req, 103362306a36Sopenharmony_ci &should_complete, &ret); 103462306a36Sopenharmony_ci if (ndesc < 0) { 103562306a36Sopenharmony_ci dev_err(priv->dev, "failed to handle result (%d)\n", 103662306a36Sopenharmony_ci ndesc); 103762306a36Sopenharmony_ci goto acknowledge; 103862306a36Sopenharmony_ci } 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci if (should_complete) { 104162306a36Sopenharmony_ci local_bh_disable(); 104262306a36Sopenharmony_ci crypto_request_complete(req, ret); 104362306a36Sopenharmony_ci local_bh_enable(); 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci tot_descs += ndesc; 104762306a36Sopenharmony_ci handled++; 104862306a36Sopenharmony_ci } 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ciacknowledge: 105162306a36Sopenharmony_ci if (i) 105262306a36Sopenharmony_ci writel(EIP197_xDR_PROC_xD_PKT(i) | 105362306a36Sopenharmony_ci (tot_descs * priv->config.rd_offset), 105462306a36Sopenharmony_ci EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_PROC_COUNT); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci /* If the number of requests overflowed the counter, try to proceed more 105762306a36Sopenharmony_ci * requests. 105862306a36Sopenharmony_ci */ 105962306a36Sopenharmony_ci if (nreq == EIP197_xDR_PROC_xD_PKT_MASK) 106062306a36Sopenharmony_ci goto handle_results; 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_cirequests_left: 106362306a36Sopenharmony_ci spin_lock_bh(&priv->ring[ring].lock); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci priv->ring[ring].requests -= handled; 106662306a36Sopenharmony_ci safexcel_try_push_requests(priv, ring); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci if (!priv->ring[ring].requests) 106962306a36Sopenharmony_ci priv->ring[ring].busy = false; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci spin_unlock_bh(&priv->ring[ring].lock); 107262306a36Sopenharmony_ci} 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_cistatic void safexcel_dequeue_work(struct work_struct *work) 107562306a36Sopenharmony_ci{ 107662306a36Sopenharmony_ci struct safexcel_work_data *data = 107762306a36Sopenharmony_ci container_of(work, struct safexcel_work_data, work); 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci safexcel_dequeue(data->priv, data->ring); 108062306a36Sopenharmony_ci} 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_cistruct safexcel_ring_irq_data { 108362306a36Sopenharmony_ci struct safexcel_crypto_priv *priv; 108462306a36Sopenharmony_ci int ring; 108562306a36Sopenharmony_ci}; 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_cistatic irqreturn_t safexcel_irq_ring(int irq, void *data) 108862306a36Sopenharmony_ci{ 108962306a36Sopenharmony_ci struct safexcel_ring_irq_data *irq_data = data; 109062306a36Sopenharmony_ci struct safexcel_crypto_priv *priv = irq_data->priv; 109162306a36Sopenharmony_ci int ring = irq_data->ring, rc = IRQ_NONE; 109262306a36Sopenharmony_ci u32 status, stat; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci status = readl(EIP197_HIA_AIC_R(priv) + EIP197_HIA_AIC_R_ENABLED_STAT(ring)); 109562306a36Sopenharmony_ci if (!status) 109662306a36Sopenharmony_ci return rc; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci /* RDR interrupts */ 109962306a36Sopenharmony_ci if (status & EIP197_RDR_IRQ(ring)) { 110062306a36Sopenharmony_ci stat = readl(EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_STAT); 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci if (unlikely(stat & EIP197_xDR_ERR)) { 110362306a36Sopenharmony_ci /* 110462306a36Sopenharmony_ci * Fatal error, the RDR is unusable and must be 110562306a36Sopenharmony_ci * reinitialized. This should not happen under 110662306a36Sopenharmony_ci * normal circumstances. 110762306a36Sopenharmony_ci */ 110862306a36Sopenharmony_ci dev_err(priv->dev, "RDR: fatal error.\n"); 110962306a36Sopenharmony_ci } else if (likely(stat & EIP197_xDR_THRESH)) { 111062306a36Sopenharmony_ci rc = IRQ_WAKE_THREAD; 111162306a36Sopenharmony_ci } 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci /* ACK the interrupts */ 111462306a36Sopenharmony_ci writel(stat & 0xff, 111562306a36Sopenharmony_ci EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_STAT); 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci /* ACK the interrupts */ 111962306a36Sopenharmony_ci writel(status, EIP197_HIA_AIC_R(priv) + EIP197_HIA_AIC_R_ACK(ring)); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci return rc; 112262306a36Sopenharmony_ci} 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_cistatic irqreturn_t safexcel_irq_ring_thread(int irq, void *data) 112562306a36Sopenharmony_ci{ 112662306a36Sopenharmony_ci struct safexcel_ring_irq_data *irq_data = data; 112762306a36Sopenharmony_ci struct safexcel_crypto_priv *priv = irq_data->priv; 112862306a36Sopenharmony_ci int ring = irq_data->ring; 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci safexcel_handle_result_descriptor(priv, ring); 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci queue_work(priv->ring[ring].workqueue, 113362306a36Sopenharmony_ci &priv->ring[ring].work_data.work); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci return IRQ_HANDLED; 113662306a36Sopenharmony_ci} 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_cistatic int safexcel_request_ring_irq(void *pdev, int irqid, 113962306a36Sopenharmony_ci int is_pci_dev, 114062306a36Sopenharmony_ci int ring_id, 114162306a36Sopenharmony_ci irq_handler_t handler, 114262306a36Sopenharmony_ci irq_handler_t threaded_handler, 114362306a36Sopenharmony_ci struct safexcel_ring_irq_data *ring_irq_priv) 114462306a36Sopenharmony_ci{ 114562306a36Sopenharmony_ci int ret, irq, cpu; 114662306a36Sopenharmony_ci struct device *dev; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_PCI) && is_pci_dev) { 114962306a36Sopenharmony_ci struct pci_dev *pci_pdev = pdev; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci dev = &pci_pdev->dev; 115262306a36Sopenharmony_ci irq = pci_irq_vector(pci_pdev, irqid); 115362306a36Sopenharmony_ci if (irq < 0) { 115462306a36Sopenharmony_ci dev_err(dev, "unable to get device MSI IRQ %d (err %d)\n", 115562306a36Sopenharmony_ci irqid, irq); 115662306a36Sopenharmony_ci return irq; 115762306a36Sopenharmony_ci } 115862306a36Sopenharmony_ci } else if (IS_ENABLED(CONFIG_OF)) { 115962306a36Sopenharmony_ci struct platform_device *plf_pdev = pdev; 116062306a36Sopenharmony_ci char irq_name[6] = {0}; /* "ringX\0" */ 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci snprintf(irq_name, 6, "ring%d", irqid); 116362306a36Sopenharmony_ci dev = &plf_pdev->dev; 116462306a36Sopenharmony_ci irq = platform_get_irq_byname(plf_pdev, irq_name); 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci if (irq < 0) 116762306a36Sopenharmony_ci return irq; 116862306a36Sopenharmony_ci } else { 116962306a36Sopenharmony_ci return -ENXIO; 117062306a36Sopenharmony_ci } 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci ret = devm_request_threaded_irq(dev, irq, handler, 117362306a36Sopenharmony_ci threaded_handler, IRQF_ONESHOT, 117462306a36Sopenharmony_ci dev_name(dev), ring_irq_priv); 117562306a36Sopenharmony_ci if (ret) { 117662306a36Sopenharmony_ci dev_err(dev, "unable to request IRQ %d\n", irq); 117762306a36Sopenharmony_ci return ret; 117862306a36Sopenharmony_ci } 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci /* Set affinity */ 118162306a36Sopenharmony_ci cpu = cpumask_local_spread(ring_id, NUMA_NO_NODE); 118262306a36Sopenharmony_ci irq_set_affinity_hint(irq, get_cpu_mask(cpu)); 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci return irq; 118562306a36Sopenharmony_ci} 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_cistatic struct safexcel_alg_template *safexcel_algs[] = { 118862306a36Sopenharmony_ci &safexcel_alg_ecb_des, 118962306a36Sopenharmony_ci &safexcel_alg_cbc_des, 119062306a36Sopenharmony_ci &safexcel_alg_ecb_des3_ede, 119162306a36Sopenharmony_ci &safexcel_alg_cbc_des3_ede, 119262306a36Sopenharmony_ci &safexcel_alg_ecb_aes, 119362306a36Sopenharmony_ci &safexcel_alg_cbc_aes, 119462306a36Sopenharmony_ci &safexcel_alg_cfb_aes, 119562306a36Sopenharmony_ci &safexcel_alg_ofb_aes, 119662306a36Sopenharmony_ci &safexcel_alg_ctr_aes, 119762306a36Sopenharmony_ci &safexcel_alg_md5, 119862306a36Sopenharmony_ci &safexcel_alg_sha1, 119962306a36Sopenharmony_ci &safexcel_alg_sha224, 120062306a36Sopenharmony_ci &safexcel_alg_sha256, 120162306a36Sopenharmony_ci &safexcel_alg_sha384, 120262306a36Sopenharmony_ci &safexcel_alg_sha512, 120362306a36Sopenharmony_ci &safexcel_alg_hmac_md5, 120462306a36Sopenharmony_ci &safexcel_alg_hmac_sha1, 120562306a36Sopenharmony_ci &safexcel_alg_hmac_sha224, 120662306a36Sopenharmony_ci &safexcel_alg_hmac_sha256, 120762306a36Sopenharmony_ci &safexcel_alg_hmac_sha384, 120862306a36Sopenharmony_ci &safexcel_alg_hmac_sha512, 120962306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sha1_cbc_aes, 121062306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sha224_cbc_aes, 121162306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sha256_cbc_aes, 121262306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sha384_cbc_aes, 121362306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sha512_cbc_aes, 121462306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sha1_cbc_des3_ede, 121562306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sha1_ctr_aes, 121662306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sha224_ctr_aes, 121762306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sha256_ctr_aes, 121862306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sha384_ctr_aes, 121962306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sha512_ctr_aes, 122062306a36Sopenharmony_ci &safexcel_alg_xts_aes, 122162306a36Sopenharmony_ci &safexcel_alg_gcm, 122262306a36Sopenharmony_ci &safexcel_alg_ccm, 122362306a36Sopenharmony_ci &safexcel_alg_crc32, 122462306a36Sopenharmony_ci &safexcel_alg_cbcmac, 122562306a36Sopenharmony_ci &safexcel_alg_xcbcmac, 122662306a36Sopenharmony_ci &safexcel_alg_cmac, 122762306a36Sopenharmony_ci &safexcel_alg_chacha20, 122862306a36Sopenharmony_ci &safexcel_alg_chachapoly, 122962306a36Sopenharmony_ci &safexcel_alg_chachapoly_esp, 123062306a36Sopenharmony_ci &safexcel_alg_sm3, 123162306a36Sopenharmony_ci &safexcel_alg_hmac_sm3, 123262306a36Sopenharmony_ci &safexcel_alg_ecb_sm4, 123362306a36Sopenharmony_ci &safexcel_alg_cbc_sm4, 123462306a36Sopenharmony_ci &safexcel_alg_ofb_sm4, 123562306a36Sopenharmony_ci &safexcel_alg_cfb_sm4, 123662306a36Sopenharmony_ci &safexcel_alg_ctr_sm4, 123762306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sha1_cbc_sm4, 123862306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sm3_cbc_sm4, 123962306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sha1_ctr_sm4, 124062306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sm3_ctr_sm4, 124162306a36Sopenharmony_ci &safexcel_alg_sha3_224, 124262306a36Sopenharmony_ci &safexcel_alg_sha3_256, 124362306a36Sopenharmony_ci &safexcel_alg_sha3_384, 124462306a36Sopenharmony_ci &safexcel_alg_sha3_512, 124562306a36Sopenharmony_ci &safexcel_alg_hmac_sha3_224, 124662306a36Sopenharmony_ci &safexcel_alg_hmac_sha3_256, 124762306a36Sopenharmony_ci &safexcel_alg_hmac_sha3_384, 124862306a36Sopenharmony_ci &safexcel_alg_hmac_sha3_512, 124962306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sha1_cbc_des, 125062306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sha256_cbc_des3_ede, 125162306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sha224_cbc_des3_ede, 125262306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sha512_cbc_des3_ede, 125362306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sha384_cbc_des3_ede, 125462306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sha256_cbc_des, 125562306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sha224_cbc_des, 125662306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sha512_cbc_des, 125762306a36Sopenharmony_ci &safexcel_alg_authenc_hmac_sha384_cbc_des, 125862306a36Sopenharmony_ci &safexcel_alg_rfc4106_gcm, 125962306a36Sopenharmony_ci &safexcel_alg_rfc4543_gcm, 126062306a36Sopenharmony_ci &safexcel_alg_rfc4309_ccm, 126162306a36Sopenharmony_ci}; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_cistatic int safexcel_register_algorithms(struct safexcel_crypto_priv *priv) 126462306a36Sopenharmony_ci{ 126562306a36Sopenharmony_ci int i, j, ret = 0; 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(safexcel_algs); i++) { 126862306a36Sopenharmony_ci safexcel_algs[i]->priv = priv; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci /* Do we have all required base algorithms available? */ 127162306a36Sopenharmony_ci if ((safexcel_algs[i]->algo_mask & priv->hwconfig.algo_flags) != 127262306a36Sopenharmony_ci safexcel_algs[i]->algo_mask) 127362306a36Sopenharmony_ci /* No, so don't register this ciphersuite */ 127462306a36Sopenharmony_ci continue; 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci if (safexcel_algs[i]->type == SAFEXCEL_ALG_TYPE_SKCIPHER) 127762306a36Sopenharmony_ci ret = crypto_register_skcipher(&safexcel_algs[i]->alg.skcipher); 127862306a36Sopenharmony_ci else if (safexcel_algs[i]->type == SAFEXCEL_ALG_TYPE_AEAD) 127962306a36Sopenharmony_ci ret = crypto_register_aead(&safexcel_algs[i]->alg.aead); 128062306a36Sopenharmony_ci else 128162306a36Sopenharmony_ci ret = crypto_register_ahash(&safexcel_algs[i]->alg.ahash); 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci if (ret) 128462306a36Sopenharmony_ci goto fail; 128562306a36Sopenharmony_ci } 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci return 0; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_cifail: 129062306a36Sopenharmony_ci for (j = 0; j < i; j++) { 129162306a36Sopenharmony_ci /* Do we have all required base algorithms available? */ 129262306a36Sopenharmony_ci if ((safexcel_algs[j]->algo_mask & priv->hwconfig.algo_flags) != 129362306a36Sopenharmony_ci safexcel_algs[j]->algo_mask) 129462306a36Sopenharmony_ci /* No, so don't unregister this ciphersuite */ 129562306a36Sopenharmony_ci continue; 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci if (safexcel_algs[j]->type == SAFEXCEL_ALG_TYPE_SKCIPHER) 129862306a36Sopenharmony_ci crypto_unregister_skcipher(&safexcel_algs[j]->alg.skcipher); 129962306a36Sopenharmony_ci else if (safexcel_algs[j]->type == SAFEXCEL_ALG_TYPE_AEAD) 130062306a36Sopenharmony_ci crypto_unregister_aead(&safexcel_algs[j]->alg.aead); 130162306a36Sopenharmony_ci else 130262306a36Sopenharmony_ci crypto_unregister_ahash(&safexcel_algs[j]->alg.ahash); 130362306a36Sopenharmony_ci } 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci return ret; 130662306a36Sopenharmony_ci} 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_cistatic void safexcel_unregister_algorithms(struct safexcel_crypto_priv *priv) 130962306a36Sopenharmony_ci{ 131062306a36Sopenharmony_ci int i; 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(safexcel_algs); i++) { 131362306a36Sopenharmony_ci /* Do we have all required base algorithms available? */ 131462306a36Sopenharmony_ci if ((safexcel_algs[i]->algo_mask & priv->hwconfig.algo_flags) != 131562306a36Sopenharmony_ci safexcel_algs[i]->algo_mask) 131662306a36Sopenharmony_ci /* No, so don't unregister this ciphersuite */ 131762306a36Sopenharmony_ci continue; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci if (safexcel_algs[i]->type == SAFEXCEL_ALG_TYPE_SKCIPHER) 132062306a36Sopenharmony_ci crypto_unregister_skcipher(&safexcel_algs[i]->alg.skcipher); 132162306a36Sopenharmony_ci else if (safexcel_algs[i]->type == SAFEXCEL_ALG_TYPE_AEAD) 132262306a36Sopenharmony_ci crypto_unregister_aead(&safexcel_algs[i]->alg.aead); 132362306a36Sopenharmony_ci else 132462306a36Sopenharmony_ci crypto_unregister_ahash(&safexcel_algs[i]->alg.ahash); 132562306a36Sopenharmony_ci } 132662306a36Sopenharmony_ci} 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_cistatic void safexcel_configure(struct safexcel_crypto_priv *priv) 132962306a36Sopenharmony_ci{ 133062306a36Sopenharmony_ci u32 mask = BIT(priv->hwconfig.hwdataw) - 1; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci priv->config.pes = priv->hwconfig.hwnumpes; 133362306a36Sopenharmony_ci priv->config.rings = min_t(u32, priv->hwconfig.hwnumrings, max_rings); 133462306a36Sopenharmony_ci /* Cannot currently support more rings than we have ring AICs! */ 133562306a36Sopenharmony_ci priv->config.rings = min_t(u32, priv->config.rings, 133662306a36Sopenharmony_ci priv->hwconfig.hwnumraic); 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci priv->config.cd_size = EIP197_CD64_FETCH_SIZE; 133962306a36Sopenharmony_ci priv->config.cd_offset = (priv->config.cd_size + mask) & ~mask; 134062306a36Sopenharmony_ci priv->config.cdsh_offset = (EIP197_MAX_TOKENS + mask) & ~mask; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci /* res token is behind the descr, but ofs must be rounded to buswdth */ 134362306a36Sopenharmony_ci priv->config.res_offset = (EIP197_RD64_FETCH_SIZE + mask) & ~mask; 134462306a36Sopenharmony_ci /* now the size of the descr is this 1st part plus the result struct */ 134562306a36Sopenharmony_ci priv->config.rd_size = priv->config.res_offset + 134662306a36Sopenharmony_ci EIP197_RD64_RESULT_SIZE; 134762306a36Sopenharmony_ci priv->config.rd_offset = (priv->config.rd_size + mask) & ~mask; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci /* convert dwords to bytes */ 135062306a36Sopenharmony_ci priv->config.cd_offset *= sizeof(u32); 135162306a36Sopenharmony_ci priv->config.cdsh_offset *= sizeof(u32); 135262306a36Sopenharmony_ci priv->config.rd_offset *= sizeof(u32); 135362306a36Sopenharmony_ci priv->config.res_offset *= sizeof(u32); 135462306a36Sopenharmony_ci} 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_cistatic void safexcel_init_register_offsets(struct safexcel_crypto_priv *priv) 135762306a36Sopenharmony_ci{ 135862306a36Sopenharmony_ci struct safexcel_register_offsets *offsets = &priv->offsets; 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci if (priv->flags & SAFEXCEL_HW_EIP197) { 136162306a36Sopenharmony_ci offsets->hia_aic = EIP197_HIA_AIC_BASE; 136262306a36Sopenharmony_ci offsets->hia_aic_g = EIP197_HIA_AIC_G_BASE; 136362306a36Sopenharmony_ci offsets->hia_aic_r = EIP197_HIA_AIC_R_BASE; 136462306a36Sopenharmony_ci offsets->hia_aic_xdr = EIP197_HIA_AIC_xDR_BASE; 136562306a36Sopenharmony_ci offsets->hia_dfe = EIP197_HIA_DFE_BASE; 136662306a36Sopenharmony_ci offsets->hia_dfe_thr = EIP197_HIA_DFE_THR_BASE; 136762306a36Sopenharmony_ci offsets->hia_dse = EIP197_HIA_DSE_BASE; 136862306a36Sopenharmony_ci offsets->hia_dse_thr = EIP197_HIA_DSE_THR_BASE; 136962306a36Sopenharmony_ci offsets->hia_gen_cfg = EIP197_HIA_GEN_CFG_BASE; 137062306a36Sopenharmony_ci offsets->pe = EIP197_PE_BASE; 137162306a36Sopenharmony_ci offsets->global = EIP197_GLOBAL_BASE; 137262306a36Sopenharmony_ci } else { 137362306a36Sopenharmony_ci offsets->hia_aic = EIP97_HIA_AIC_BASE; 137462306a36Sopenharmony_ci offsets->hia_aic_g = EIP97_HIA_AIC_G_BASE; 137562306a36Sopenharmony_ci offsets->hia_aic_r = EIP97_HIA_AIC_R_BASE; 137662306a36Sopenharmony_ci offsets->hia_aic_xdr = EIP97_HIA_AIC_xDR_BASE; 137762306a36Sopenharmony_ci offsets->hia_dfe = EIP97_HIA_DFE_BASE; 137862306a36Sopenharmony_ci offsets->hia_dfe_thr = EIP97_HIA_DFE_THR_BASE; 137962306a36Sopenharmony_ci offsets->hia_dse = EIP97_HIA_DSE_BASE; 138062306a36Sopenharmony_ci offsets->hia_dse_thr = EIP97_HIA_DSE_THR_BASE; 138162306a36Sopenharmony_ci offsets->hia_gen_cfg = EIP97_HIA_GEN_CFG_BASE; 138262306a36Sopenharmony_ci offsets->pe = EIP97_PE_BASE; 138362306a36Sopenharmony_ci offsets->global = EIP97_GLOBAL_BASE; 138462306a36Sopenharmony_ci } 138562306a36Sopenharmony_ci} 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci/* 138862306a36Sopenharmony_ci * Generic part of probe routine, shared by platform and PCI driver 138962306a36Sopenharmony_ci * 139062306a36Sopenharmony_ci * Assumes IO resources have been mapped, private data mem has been allocated, 139162306a36Sopenharmony_ci * clocks have been enabled, device pointer has been assigned etc. 139262306a36Sopenharmony_ci * 139362306a36Sopenharmony_ci */ 139462306a36Sopenharmony_cistatic int safexcel_probe_generic(void *pdev, 139562306a36Sopenharmony_ci struct safexcel_crypto_priv *priv, 139662306a36Sopenharmony_ci int is_pci_dev) 139762306a36Sopenharmony_ci{ 139862306a36Sopenharmony_ci struct device *dev = priv->dev; 139962306a36Sopenharmony_ci u32 peid, version, mask, val, hiaopt, hwopt, peopt; 140062306a36Sopenharmony_ci int i, ret, hwctg; 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci priv->context_pool = dmam_pool_create("safexcel-context", dev, 140362306a36Sopenharmony_ci sizeof(struct safexcel_context_record), 140462306a36Sopenharmony_ci 1, 0); 140562306a36Sopenharmony_ci if (!priv->context_pool) 140662306a36Sopenharmony_ci return -ENOMEM; 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci /* 140962306a36Sopenharmony_ci * First try the EIP97 HIA version regs 141062306a36Sopenharmony_ci * For the EIP197, this is guaranteed to NOT return any of the test 141162306a36Sopenharmony_ci * values 141262306a36Sopenharmony_ci */ 141362306a36Sopenharmony_ci version = readl(priv->base + EIP97_HIA_AIC_BASE + EIP197_HIA_VERSION); 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci mask = 0; /* do not swap */ 141662306a36Sopenharmony_ci if (EIP197_REG_LO16(version) == EIP197_HIA_VERSION_LE) { 141762306a36Sopenharmony_ci priv->hwconfig.hiaver = EIP197_VERSION_MASK(version); 141862306a36Sopenharmony_ci } else if (EIP197_REG_HI16(version) == EIP197_HIA_VERSION_BE) { 141962306a36Sopenharmony_ci /* read back byte-swapped, so complement byte swap bits */ 142062306a36Sopenharmony_ci mask = EIP197_MST_CTRL_BYTE_SWAP_BITS; 142162306a36Sopenharmony_ci priv->hwconfig.hiaver = EIP197_VERSION_SWAP(version); 142262306a36Sopenharmony_ci } else { 142362306a36Sopenharmony_ci /* So it wasn't an EIP97 ... maybe it's an EIP197? */ 142462306a36Sopenharmony_ci version = readl(priv->base + EIP197_HIA_AIC_BASE + 142562306a36Sopenharmony_ci EIP197_HIA_VERSION); 142662306a36Sopenharmony_ci if (EIP197_REG_LO16(version) == EIP197_HIA_VERSION_LE) { 142762306a36Sopenharmony_ci priv->hwconfig.hiaver = EIP197_VERSION_MASK(version); 142862306a36Sopenharmony_ci priv->flags |= SAFEXCEL_HW_EIP197; 142962306a36Sopenharmony_ci } else if (EIP197_REG_HI16(version) == 143062306a36Sopenharmony_ci EIP197_HIA_VERSION_BE) { 143162306a36Sopenharmony_ci /* read back byte-swapped, so complement swap bits */ 143262306a36Sopenharmony_ci mask = EIP197_MST_CTRL_BYTE_SWAP_BITS; 143362306a36Sopenharmony_ci priv->hwconfig.hiaver = EIP197_VERSION_SWAP(version); 143462306a36Sopenharmony_ci priv->flags |= SAFEXCEL_HW_EIP197; 143562306a36Sopenharmony_ci } else { 143662306a36Sopenharmony_ci return -ENODEV; 143762306a36Sopenharmony_ci } 143862306a36Sopenharmony_ci } 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci /* Now initialize the reg offsets based on the probing info so far */ 144162306a36Sopenharmony_ci safexcel_init_register_offsets(priv); 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci /* 144462306a36Sopenharmony_ci * If the version was read byte-swapped, we need to flip the device 144562306a36Sopenharmony_ci * swapping Keep in mind here, though, that what we write will also be 144662306a36Sopenharmony_ci * byte-swapped ... 144762306a36Sopenharmony_ci */ 144862306a36Sopenharmony_ci if (mask) { 144962306a36Sopenharmony_ci val = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL); 145062306a36Sopenharmony_ci val = val ^ (mask >> 24); /* toggle byte swap bits */ 145162306a36Sopenharmony_ci writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL); 145262306a36Sopenharmony_ci } 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci /* 145562306a36Sopenharmony_ci * We're not done probing yet! We may fall through to here if no HIA 145662306a36Sopenharmony_ci * was found at all. So, with the endianness presumably correct now and 145762306a36Sopenharmony_ci * the offsets setup, *really* probe for the EIP97/EIP197. 145862306a36Sopenharmony_ci */ 145962306a36Sopenharmony_ci version = readl(EIP197_GLOBAL(priv) + EIP197_VERSION); 146062306a36Sopenharmony_ci if (((priv->flags & SAFEXCEL_HW_EIP197) && 146162306a36Sopenharmony_ci (EIP197_REG_LO16(version) != EIP197_VERSION_LE) && 146262306a36Sopenharmony_ci (EIP197_REG_LO16(version) != EIP196_VERSION_LE)) || 146362306a36Sopenharmony_ci ((!(priv->flags & SAFEXCEL_HW_EIP197) && 146462306a36Sopenharmony_ci (EIP197_REG_LO16(version) != EIP97_VERSION_LE)))) { 146562306a36Sopenharmony_ci /* 146662306a36Sopenharmony_ci * We did not find the device that matched our initial probing 146762306a36Sopenharmony_ci * (or our initial probing failed) Report appropriate error. 146862306a36Sopenharmony_ci */ 146962306a36Sopenharmony_ci dev_err(priv->dev, "Probing for EIP97/EIP19x failed - no such device (read %08x)\n", 147062306a36Sopenharmony_ci version); 147162306a36Sopenharmony_ci return -ENODEV; 147262306a36Sopenharmony_ci } 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci priv->hwconfig.hwver = EIP197_VERSION_MASK(version); 147562306a36Sopenharmony_ci hwctg = version >> 28; 147662306a36Sopenharmony_ci peid = version & 255; 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci /* Detect EIP206 processing pipe */ 147962306a36Sopenharmony_ci version = readl(EIP197_PE(priv) + + EIP197_PE_VERSION(0)); 148062306a36Sopenharmony_ci if (EIP197_REG_LO16(version) != EIP206_VERSION_LE) { 148162306a36Sopenharmony_ci dev_err(priv->dev, "EIP%d: EIP206 not detected\n", peid); 148262306a36Sopenharmony_ci return -ENODEV; 148362306a36Sopenharmony_ci } 148462306a36Sopenharmony_ci priv->hwconfig.ppver = EIP197_VERSION_MASK(version); 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci /* Detect EIP96 packet engine and version */ 148762306a36Sopenharmony_ci version = readl(EIP197_PE(priv) + EIP197_PE_EIP96_VERSION(0)); 148862306a36Sopenharmony_ci if (EIP197_REG_LO16(version) != EIP96_VERSION_LE) { 148962306a36Sopenharmony_ci dev_err(dev, "EIP%d: EIP96 not detected.\n", peid); 149062306a36Sopenharmony_ci return -ENODEV; 149162306a36Sopenharmony_ci } 149262306a36Sopenharmony_ci priv->hwconfig.pever = EIP197_VERSION_MASK(version); 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci hwopt = readl(EIP197_GLOBAL(priv) + EIP197_OPTIONS); 149562306a36Sopenharmony_ci hiaopt = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_OPTIONS); 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci priv->hwconfig.icever = 0; 149862306a36Sopenharmony_ci priv->hwconfig.ocever = 0; 149962306a36Sopenharmony_ci priv->hwconfig.psever = 0; 150062306a36Sopenharmony_ci if (priv->flags & SAFEXCEL_HW_EIP197) { 150162306a36Sopenharmony_ci /* EIP197 */ 150262306a36Sopenharmony_ci peopt = readl(EIP197_PE(priv) + EIP197_PE_OPTIONS(0)); 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci priv->hwconfig.hwdataw = (hiaopt >> EIP197_HWDATAW_OFFSET) & 150562306a36Sopenharmony_ci EIP197_HWDATAW_MASK; 150662306a36Sopenharmony_ci priv->hwconfig.hwcfsize = ((hiaopt >> EIP197_CFSIZE_OFFSET) & 150762306a36Sopenharmony_ci EIP197_CFSIZE_MASK) + 150862306a36Sopenharmony_ci EIP197_CFSIZE_ADJUST; 150962306a36Sopenharmony_ci priv->hwconfig.hwrfsize = ((hiaopt >> EIP197_RFSIZE_OFFSET) & 151062306a36Sopenharmony_ci EIP197_RFSIZE_MASK) + 151162306a36Sopenharmony_ci EIP197_RFSIZE_ADJUST; 151262306a36Sopenharmony_ci priv->hwconfig.hwnumpes = (hiaopt >> EIP197_N_PES_OFFSET) & 151362306a36Sopenharmony_ci EIP197_N_PES_MASK; 151462306a36Sopenharmony_ci priv->hwconfig.hwnumrings = (hiaopt >> EIP197_N_RINGS_OFFSET) & 151562306a36Sopenharmony_ci EIP197_N_RINGS_MASK; 151662306a36Sopenharmony_ci if (hiaopt & EIP197_HIA_OPT_HAS_PE_ARB) 151762306a36Sopenharmony_ci priv->flags |= EIP197_PE_ARB; 151862306a36Sopenharmony_ci if (EIP206_OPT_ICE_TYPE(peopt) == 1) { 151962306a36Sopenharmony_ci priv->flags |= EIP197_ICE; 152062306a36Sopenharmony_ci /* Detect ICE EIP207 class. engine and version */ 152162306a36Sopenharmony_ci version = readl(EIP197_PE(priv) + 152262306a36Sopenharmony_ci EIP197_PE_ICE_VERSION(0)); 152362306a36Sopenharmony_ci if (EIP197_REG_LO16(version) != EIP207_VERSION_LE) { 152462306a36Sopenharmony_ci dev_err(dev, "EIP%d: ICE EIP207 not detected.\n", 152562306a36Sopenharmony_ci peid); 152662306a36Sopenharmony_ci return -ENODEV; 152762306a36Sopenharmony_ci } 152862306a36Sopenharmony_ci priv->hwconfig.icever = EIP197_VERSION_MASK(version); 152962306a36Sopenharmony_ci } 153062306a36Sopenharmony_ci if (EIP206_OPT_OCE_TYPE(peopt) == 1) { 153162306a36Sopenharmony_ci priv->flags |= EIP197_OCE; 153262306a36Sopenharmony_ci /* Detect EIP96PP packet stream editor and version */ 153362306a36Sopenharmony_ci version = readl(EIP197_PE(priv) + EIP197_PE_PSE_VERSION(0)); 153462306a36Sopenharmony_ci if (EIP197_REG_LO16(version) != EIP96_VERSION_LE) { 153562306a36Sopenharmony_ci dev_err(dev, "EIP%d: EIP96PP not detected.\n", peid); 153662306a36Sopenharmony_ci return -ENODEV; 153762306a36Sopenharmony_ci } 153862306a36Sopenharmony_ci priv->hwconfig.psever = EIP197_VERSION_MASK(version); 153962306a36Sopenharmony_ci /* Detect OCE EIP207 class. engine and version */ 154062306a36Sopenharmony_ci version = readl(EIP197_PE(priv) + 154162306a36Sopenharmony_ci EIP197_PE_ICE_VERSION(0)); 154262306a36Sopenharmony_ci if (EIP197_REG_LO16(version) != EIP207_VERSION_LE) { 154362306a36Sopenharmony_ci dev_err(dev, "EIP%d: OCE EIP207 not detected.\n", 154462306a36Sopenharmony_ci peid); 154562306a36Sopenharmony_ci return -ENODEV; 154662306a36Sopenharmony_ci } 154762306a36Sopenharmony_ci priv->hwconfig.ocever = EIP197_VERSION_MASK(version); 154862306a36Sopenharmony_ci } 154962306a36Sopenharmony_ci /* If not a full TRC, then assume simple TRC */ 155062306a36Sopenharmony_ci if (!(hwopt & EIP197_OPT_HAS_TRC)) 155162306a36Sopenharmony_ci priv->flags |= EIP197_SIMPLE_TRC; 155262306a36Sopenharmony_ci /* EIP197 always has SOME form of TRC */ 155362306a36Sopenharmony_ci priv->flags |= EIP197_TRC_CACHE; 155462306a36Sopenharmony_ci } else { 155562306a36Sopenharmony_ci /* EIP97 */ 155662306a36Sopenharmony_ci priv->hwconfig.hwdataw = (hiaopt >> EIP197_HWDATAW_OFFSET) & 155762306a36Sopenharmony_ci EIP97_HWDATAW_MASK; 155862306a36Sopenharmony_ci priv->hwconfig.hwcfsize = (hiaopt >> EIP97_CFSIZE_OFFSET) & 155962306a36Sopenharmony_ci EIP97_CFSIZE_MASK; 156062306a36Sopenharmony_ci priv->hwconfig.hwrfsize = (hiaopt >> EIP97_RFSIZE_OFFSET) & 156162306a36Sopenharmony_ci EIP97_RFSIZE_MASK; 156262306a36Sopenharmony_ci priv->hwconfig.hwnumpes = 1; /* by definition */ 156362306a36Sopenharmony_ci priv->hwconfig.hwnumrings = (hiaopt >> EIP197_N_RINGS_OFFSET) & 156462306a36Sopenharmony_ci EIP197_N_RINGS_MASK; 156562306a36Sopenharmony_ci } 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci /* Scan for ring AIC's */ 156862306a36Sopenharmony_ci for (i = 0; i < EIP197_MAX_RING_AIC; i++) { 156962306a36Sopenharmony_ci version = readl(EIP197_HIA_AIC_R(priv) + 157062306a36Sopenharmony_ci EIP197_HIA_AIC_R_VERSION(i)); 157162306a36Sopenharmony_ci if (EIP197_REG_LO16(version) != EIP201_VERSION_LE) 157262306a36Sopenharmony_ci break; 157362306a36Sopenharmony_ci } 157462306a36Sopenharmony_ci priv->hwconfig.hwnumraic = i; 157562306a36Sopenharmony_ci /* Low-end EIP196 may not have any ring AIC's ... */ 157662306a36Sopenharmony_ci if (!priv->hwconfig.hwnumraic) { 157762306a36Sopenharmony_ci dev_err(priv->dev, "No ring interrupt controller present!\n"); 157862306a36Sopenharmony_ci return -ENODEV; 157962306a36Sopenharmony_ci } 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci /* Get supported algorithms from EIP96 transform engine */ 158262306a36Sopenharmony_ci priv->hwconfig.algo_flags = readl(EIP197_PE(priv) + 158362306a36Sopenharmony_ci EIP197_PE_EIP96_OPTIONS(0)); 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci /* Print single info line describing what we just detected */ 158662306a36Sopenharmony_ci dev_info(priv->dev, "EIP%d:%x(%d,%d,%d,%d)-HIA:%x(%d,%d,%d),PE:%x/%x(alg:%08x)/%x/%x/%x\n", 158762306a36Sopenharmony_ci peid, priv->hwconfig.hwver, hwctg, priv->hwconfig.hwnumpes, 158862306a36Sopenharmony_ci priv->hwconfig.hwnumrings, priv->hwconfig.hwnumraic, 158962306a36Sopenharmony_ci priv->hwconfig.hiaver, priv->hwconfig.hwdataw, 159062306a36Sopenharmony_ci priv->hwconfig.hwcfsize, priv->hwconfig.hwrfsize, 159162306a36Sopenharmony_ci priv->hwconfig.ppver, priv->hwconfig.pever, 159262306a36Sopenharmony_ci priv->hwconfig.algo_flags, priv->hwconfig.icever, 159362306a36Sopenharmony_ci priv->hwconfig.ocever, priv->hwconfig.psever); 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci safexcel_configure(priv); 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_PCI) && priv->data->version == EIP197_DEVBRD) { 159862306a36Sopenharmony_ci /* 159962306a36Sopenharmony_ci * Request MSI vectors for global + 1 per ring - 160062306a36Sopenharmony_ci * or just 1 for older dev images 160162306a36Sopenharmony_ci */ 160262306a36Sopenharmony_ci struct pci_dev *pci_pdev = pdev; 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci ret = pci_alloc_irq_vectors(pci_pdev, 160562306a36Sopenharmony_ci priv->config.rings + 1, 160662306a36Sopenharmony_ci priv->config.rings + 1, 160762306a36Sopenharmony_ci PCI_IRQ_MSI | PCI_IRQ_MSIX); 160862306a36Sopenharmony_ci if (ret < 0) { 160962306a36Sopenharmony_ci dev_err(dev, "Failed to allocate PCI MSI interrupts\n"); 161062306a36Sopenharmony_ci return ret; 161162306a36Sopenharmony_ci } 161262306a36Sopenharmony_ci } 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci /* Register the ring IRQ handlers and configure the rings */ 161562306a36Sopenharmony_ci priv->ring = devm_kcalloc(dev, priv->config.rings, 161662306a36Sopenharmony_ci sizeof(*priv->ring), 161762306a36Sopenharmony_ci GFP_KERNEL); 161862306a36Sopenharmony_ci if (!priv->ring) 161962306a36Sopenharmony_ci return -ENOMEM; 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci for (i = 0; i < priv->config.rings; i++) { 162262306a36Sopenharmony_ci char wq_name[9] = {0}; 162362306a36Sopenharmony_ci int irq; 162462306a36Sopenharmony_ci struct safexcel_ring_irq_data *ring_irq; 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci ret = safexcel_init_ring_descriptors(priv, 162762306a36Sopenharmony_ci &priv->ring[i].cdr, 162862306a36Sopenharmony_ci &priv->ring[i].rdr); 162962306a36Sopenharmony_ci if (ret) { 163062306a36Sopenharmony_ci dev_err(dev, "Failed to initialize rings\n"); 163162306a36Sopenharmony_ci goto err_cleanup_rings; 163262306a36Sopenharmony_ci } 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci priv->ring[i].rdr_req = devm_kcalloc(dev, 163562306a36Sopenharmony_ci EIP197_DEFAULT_RING_SIZE, 163662306a36Sopenharmony_ci sizeof(*priv->ring[i].rdr_req), 163762306a36Sopenharmony_ci GFP_KERNEL); 163862306a36Sopenharmony_ci if (!priv->ring[i].rdr_req) { 163962306a36Sopenharmony_ci ret = -ENOMEM; 164062306a36Sopenharmony_ci goto err_cleanup_rings; 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci ring_irq = devm_kzalloc(dev, sizeof(*ring_irq), GFP_KERNEL); 164462306a36Sopenharmony_ci if (!ring_irq) { 164562306a36Sopenharmony_ci ret = -ENOMEM; 164662306a36Sopenharmony_ci goto err_cleanup_rings; 164762306a36Sopenharmony_ci } 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci ring_irq->priv = priv; 165062306a36Sopenharmony_ci ring_irq->ring = i; 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci irq = safexcel_request_ring_irq(pdev, 165362306a36Sopenharmony_ci EIP197_IRQ_NUMBER(i, is_pci_dev), 165462306a36Sopenharmony_ci is_pci_dev, 165562306a36Sopenharmony_ci i, 165662306a36Sopenharmony_ci safexcel_irq_ring, 165762306a36Sopenharmony_ci safexcel_irq_ring_thread, 165862306a36Sopenharmony_ci ring_irq); 165962306a36Sopenharmony_ci if (irq < 0) { 166062306a36Sopenharmony_ci dev_err(dev, "Failed to get IRQ ID for ring %d\n", i); 166162306a36Sopenharmony_ci ret = irq; 166262306a36Sopenharmony_ci goto err_cleanup_rings; 166362306a36Sopenharmony_ci } 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci priv->ring[i].irq = irq; 166662306a36Sopenharmony_ci priv->ring[i].work_data.priv = priv; 166762306a36Sopenharmony_ci priv->ring[i].work_data.ring = i; 166862306a36Sopenharmony_ci INIT_WORK(&priv->ring[i].work_data.work, 166962306a36Sopenharmony_ci safexcel_dequeue_work); 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci snprintf(wq_name, 9, "wq_ring%d", i); 167262306a36Sopenharmony_ci priv->ring[i].workqueue = 167362306a36Sopenharmony_ci create_singlethread_workqueue(wq_name); 167462306a36Sopenharmony_ci if (!priv->ring[i].workqueue) { 167562306a36Sopenharmony_ci ret = -ENOMEM; 167662306a36Sopenharmony_ci goto err_cleanup_rings; 167762306a36Sopenharmony_ci } 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci priv->ring[i].requests = 0; 168062306a36Sopenharmony_ci priv->ring[i].busy = false; 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci crypto_init_queue(&priv->ring[i].queue, 168362306a36Sopenharmony_ci EIP197_DEFAULT_RING_SIZE); 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci spin_lock_init(&priv->ring[i].lock); 168662306a36Sopenharmony_ci spin_lock_init(&priv->ring[i].queue_lock); 168762306a36Sopenharmony_ci } 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci atomic_set(&priv->ring_used, 0); 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci ret = safexcel_hw_init(priv); 169262306a36Sopenharmony_ci if (ret) { 169362306a36Sopenharmony_ci dev_err(dev, "HW init failed (%d)\n", ret); 169462306a36Sopenharmony_ci goto err_cleanup_rings; 169562306a36Sopenharmony_ci } 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci ret = safexcel_register_algorithms(priv); 169862306a36Sopenharmony_ci if (ret) { 169962306a36Sopenharmony_ci dev_err(dev, "Failed to register algorithms (%d)\n", ret); 170062306a36Sopenharmony_ci goto err_cleanup_rings; 170162306a36Sopenharmony_ci } 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci return 0; 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_cierr_cleanup_rings: 170662306a36Sopenharmony_ci for (i = 0; i < priv->config.rings; i++) { 170762306a36Sopenharmony_ci if (priv->ring[i].irq) 170862306a36Sopenharmony_ci irq_set_affinity_hint(priv->ring[i].irq, NULL); 170962306a36Sopenharmony_ci if (priv->ring[i].workqueue) 171062306a36Sopenharmony_ci destroy_workqueue(priv->ring[i].workqueue); 171162306a36Sopenharmony_ci } 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci return ret; 171462306a36Sopenharmony_ci} 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_cistatic void safexcel_hw_reset_rings(struct safexcel_crypto_priv *priv) 171762306a36Sopenharmony_ci{ 171862306a36Sopenharmony_ci int i; 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci for (i = 0; i < priv->config.rings; i++) { 172162306a36Sopenharmony_ci /* clear any pending interrupt */ 172262306a36Sopenharmony_ci writel(GENMASK(5, 0), EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_STAT); 172362306a36Sopenharmony_ci writel(GENMASK(7, 0), EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_STAT); 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci /* Reset the CDR base address */ 172662306a36Sopenharmony_ci writel(0, EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_LO); 172762306a36Sopenharmony_ci writel(0, EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_HI); 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci /* Reset the RDR base address */ 173062306a36Sopenharmony_ci writel(0, EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_LO); 173162306a36Sopenharmony_ci writel(0, EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_HI); 173262306a36Sopenharmony_ci } 173362306a36Sopenharmony_ci} 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci/* for Device Tree platform driver */ 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_cistatic int safexcel_probe(struct platform_device *pdev) 173862306a36Sopenharmony_ci{ 173962306a36Sopenharmony_ci struct device *dev = &pdev->dev; 174062306a36Sopenharmony_ci struct safexcel_crypto_priv *priv; 174162306a36Sopenharmony_ci int ret; 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 174462306a36Sopenharmony_ci if (!priv) 174562306a36Sopenharmony_ci return -ENOMEM; 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci priv->dev = dev; 174862306a36Sopenharmony_ci priv->data = (struct safexcel_priv_data *)of_device_get_match_data(dev); 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci platform_set_drvdata(pdev, priv); 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci priv->base = devm_platform_ioremap_resource(pdev, 0); 175362306a36Sopenharmony_ci if (IS_ERR(priv->base)) { 175462306a36Sopenharmony_ci dev_err(dev, "failed to get resource\n"); 175562306a36Sopenharmony_ci return PTR_ERR(priv->base); 175662306a36Sopenharmony_ci } 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci priv->clk = devm_clk_get(&pdev->dev, NULL); 175962306a36Sopenharmony_ci ret = PTR_ERR_OR_ZERO(priv->clk); 176062306a36Sopenharmony_ci /* The clock isn't mandatory */ 176162306a36Sopenharmony_ci if (ret != -ENOENT) { 176262306a36Sopenharmony_ci if (ret) 176362306a36Sopenharmony_ci return ret; 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci ret = clk_prepare_enable(priv->clk); 176662306a36Sopenharmony_ci if (ret) { 176762306a36Sopenharmony_ci dev_err(dev, "unable to enable clk (%d)\n", ret); 176862306a36Sopenharmony_ci return ret; 176962306a36Sopenharmony_ci } 177062306a36Sopenharmony_ci } 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci priv->reg_clk = devm_clk_get(&pdev->dev, "reg"); 177362306a36Sopenharmony_ci ret = PTR_ERR_OR_ZERO(priv->reg_clk); 177462306a36Sopenharmony_ci /* The clock isn't mandatory */ 177562306a36Sopenharmony_ci if (ret != -ENOENT) { 177662306a36Sopenharmony_ci if (ret) 177762306a36Sopenharmony_ci goto err_core_clk; 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci ret = clk_prepare_enable(priv->reg_clk); 178062306a36Sopenharmony_ci if (ret) { 178162306a36Sopenharmony_ci dev_err(dev, "unable to enable reg clk (%d)\n", ret); 178262306a36Sopenharmony_ci goto err_core_clk; 178362306a36Sopenharmony_ci } 178462306a36Sopenharmony_ci } 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); 178762306a36Sopenharmony_ci if (ret) 178862306a36Sopenharmony_ci goto err_reg_clk; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci /* Generic EIP97/EIP197 device probing */ 179162306a36Sopenharmony_ci ret = safexcel_probe_generic(pdev, priv, 0); 179262306a36Sopenharmony_ci if (ret) 179362306a36Sopenharmony_ci goto err_reg_clk; 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci return 0; 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_cierr_reg_clk: 179862306a36Sopenharmony_ci clk_disable_unprepare(priv->reg_clk); 179962306a36Sopenharmony_cierr_core_clk: 180062306a36Sopenharmony_ci clk_disable_unprepare(priv->clk); 180162306a36Sopenharmony_ci return ret; 180262306a36Sopenharmony_ci} 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_cistatic int safexcel_remove(struct platform_device *pdev) 180562306a36Sopenharmony_ci{ 180662306a36Sopenharmony_ci struct safexcel_crypto_priv *priv = platform_get_drvdata(pdev); 180762306a36Sopenharmony_ci int i; 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci safexcel_unregister_algorithms(priv); 181062306a36Sopenharmony_ci safexcel_hw_reset_rings(priv); 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci clk_disable_unprepare(priv->reg_clk); 181362306a36Sopenharmony_ci clk_disable_unprepare(priv->clk); 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci for (i = 0; i < priv->config.rings; i++) { 181662306a36Sopenharmony_ci irq_set_affinity_hint(priv->ring[i].irq, NULL); 181762306a36Sopenharmony_ci destroy_workqueue(priv->ring[i].workqueue); 181862306a36Sopenharmony_ci } 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci return 0; 182162306a36Sopenharmony_ci} 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_cistatic const struct safexcel_priv_data eip97ies_mrvl_data = { 182462306a36Sopenharmony_ci .version = EIP97IES_MRVL, 182562306a36Sopenharmony_ci}; 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_cistatic const struct safexcel_priv_data eip197b_mrvl_data = { 182862306a36Sopenharmony_ci .version = EIP197B_MRVL, 182962306a36Sopenharmony_ci}; 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_cistatic const struct safexcel_priv_data eip197d_mrvl_data = { 183262306a36Sopenharmony_ci .version = EIP197D_MRVL, 183362306a36Sopenharmony_ci}; 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_cistatic const struct safexcel_priv_data eip197_devbrd_data = { 183662306a36Sopenharmony_ci .version = EIP197_DEVBRD, 183762306a36Sopenharmony_ci}; 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_cistatic const struct safexcel_priv_data eip197c_mxl_data = { 184062306a36Sopenharmony_ci .version = EIP197C_MXL, 184162306a36Sopenharmony_ci .fw_little_endian = true, 184262306a36Sopenharmony_ci}; 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_cistatic const struct of_device_id safexcel_of_match_table[] = { 184562306a36Sopenharmony_ci { 184662306a36Sopenharmony_ci .compatible = "inside-secure,safexcel-eip97ies", 184762306a36Sopenharmony_ci .data = &eip97ies_mrvl_data, 184862306a36Sopenharmony_ci }, 184962306a36Sopenharmony_ci { 185062306a36Sopenharmony_ci .compatible = "inside-secure,safexcel-eip197b", 185162306a36Sopenharmony_ci .data = &eip197b_mrvl_data, 185262306a36Sopenharmony_ci }, 185362306a36Sopenharmony_ci { 185462306a36Sopenharmony_ci .compatible = "inside-secure,safexcel-eip197d", 185562306a36Sopenharmony_ci .data = &eip197d_mrvl_data, 185662306a36Sopenharmony_ci }, 185762306a36Sopenharmony_ci { 185862306a36Sopenharmony_ci .compatible = "inside-secure,safexcel-eip197c-mxl", 185962306a36Sopenharmony_ci .data = &eip197c_mxl_data, 186062306a36Sopenharmony_ci }, 186162306a36Sopenharmony_ci /* For backward compatibility and intended for generic use */ 186262306a36Sopenharmony_ci { 186362306a36Sopenharmony_ci .compatible = "inside-secure,safexcel-eip97", 186462306a36Sopenharmony_ci .data = &eip97ies_mrvl_data, 186562306a36Sopenharmony_ci }, 186662306a36Sopenharmony_ci { 186762306a36Sopenharmony_ci .compatible = "inside-secure,safexcel-eip197", 186862306a36Sopenharmony_ci .data = &eip197b_mrvl_data, 186962306a36Sopenharmony_ci }, 187062306a36Sopenharmony_ci {}, 187162306a36Sopenharmony_ci}; 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, safexcel_of_match_table); 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_cistatic struct platform_driver crypto_safexcel = { 187662306a36Sopenharmony_ci .probe = safexcel_probe, 187762306a36Sopenharmony_ci .remove = safexcel_remove, 187862306a36Sopenharmony_ci .driver = { 187962306a36Sopenharmony_ci .name = "crypto-safexcel", 188062306a36Sopenharmony_ci .of_match_table = safexcel_of_match_table, 188162306a36Sopenharmony_ci }, 188262306a36Sopenharmony_ci}; 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_ci/* PCIE devices - i.e. Inside Secure development boards */ 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_cistatic int safexcel_pci_probe(struct pci_dev *pdev, 188762306a36Sopenharmony_ci const struct pci_device_id *ent) 188862306a36Sopenharmony_ci{ 188962306a36Sopenharmony_ci struct device *dev = &pdev->dev; 189062306a36Sopenharmony_ci struct safexcel_crypto_priv *priv; 189162306a36Sopenharmony_ci void __iomem *pciebase; 189262306a36Sopenharmony_ci int rc; 189362306a36Sopenharmony_ci u32 val; 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci dev_dbg(dev, "Probing PCIE device: vendor %04x, device %04x, subv %04x, subdev %04x, ctxt %lx\n", 189662306a36Sopenharmony_ci ent->vendor, ent->device, ent->subvendor, 189762306a36Sopenharmony_ci ent->subdevice, ent->driver_data); 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci priv = kzalloc(sizeof(*priv), GFP_KERNEL); 190062306a36Sopenharmony_ci if (!priv) 190162306a36Sopenharmony_ci return -ENOMEM; 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci priv->dev = dev; 190462306a36Sopenharmony_ci priv->data = (struct safexcel_priv_data *)ent->driver_data; 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci pci_set_drvdata(pdev, priv); 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci /* enable the device */ 190962306a36Sopenharmony_ci rc = pcim_enable_device(pdev); 191062306a36Sopenharmony_ci if (rc) { 191162306a36Sopenharmony_ci dev_err(dev, "Failed to enable PCI device\n"); 191262306a36Sopenharmony_ci return rc; 191362306a36Sopenharmony_ci } 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci /* take ownership of PCI BAR0 */ 191662306a36Sopenharmony_ci rc = pcim_iomap_regions(pdev, 1, "crypto_safexcel"); 191762306a36Sopenharmony_ci if (rc) { 191862306a36Sopenharmony_ci dev_err(dev, "Failed to map IO region for BAR0\n"); 191962306a36Sopenharmony_ci return rc; 192062306a36Sopenharmony_ci } 192162306a36Sopenharmony_ci priv->base = pcim_iomap_table(pdev)[0]; 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci if (priv->data->version == EIP197_DEVBRD) { 192462306a36Sopenharmony_ci dev_dbg(dev, "Device identified as FPGA based development board - applying HW reset\n"); 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci rc = pcim_iomap_regions(pdev, 4, "crypto_safexcel"); 192762306a36Sopenharmony_ci if (rc) { 192862306a36Sopenharmony_ci dev_err(dev, "Failed to map IO region for BAR4\n"); 192962306a36Sopenharmony_ci return rc; 193062306a36Sopenharmony_ci } 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci pciebase = pcim_iomap_table(pdev)[2]; 193362306a36Sopenharmony_ci val = readl(pciebase + EIP197_XLX_IRQ_BLOCK_ID_ADDR); 193462306a36Sopenharmony_ci if ((val >> 16) == EIP197_XLX_IRQ_BLOCK_ID_VALUE) { 193562306a36Sopenharmony_ci dev_dbg(dev, "Detected Xilinx PCIE IRQ block version %d, multiple MSI support enabled\n", 193662306a36Sopenharmony_ci (val & 0xff)); 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci /* Setup MSI identity map mapping */ 193962306a36Sopenharmony_ci writel(EIP197_XLX_USER_VECT_LUT0_IDENT, 194062306a36Sopenharmony_ci pciebase + EIP197_XLX_USER_VECT_LUT0_ADDR); 194162306a36Sopenharmony_ci writel(EIP197_XLX_USER_VECT_LUT1_IDENT, 194262306a36Sopenharmony_ci pciebase + EIP197_XLX_USER_VECT_LUT1_ADDR); 194362306a36Sopenharmony_ci writel(EIP197_XLX_USER_VECT_LUT2_IDENT, 194462306a36Sopenharmony_ci pciebase + EIP197_XLX_USER_VECT_LUT2_ADDR); 194562306a36Sopenharmony_ci writel(EIP197_XLX_USER_VECT_LUT3_IDENT, 194662306a36Sopenharmony_ci pciebase + EIP197_XLX_USER_VECT_LUT3_ADDR); 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci /* Enable all device interrupts */ 194962306a36Sopenharmony_ci writel(GENMASK(31, 0), 195062306a36Sopenharmony_ci pciebase + EIP197_XLX_USER_INT_ENB_MSK); 195162306a36Sopenharmony_ci } else { 195262306a36Sopenharmony_ci dev_err(dev, "Unrecognised IRQ block identifier %x\n", 195362306a36Sopenharmony_ci val); 195462306a36Sopenharmony_ci return -ENODEV; 195562306a36Sopenharmony_ci } 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci /* HW reset FPGA dev board */ 195862306a36Sopenharmony_ci /* assert reset */ 195962306a36Sopenharmony_ci writel(1, priv->base + EIP197_XLX_GPIO_BASE); 196062306a36Sopenharmony_ci wmb(); /* maintain strict ordering for accesses here */ 196162306a36Sopenharmony_ci /* deassert reset */ 196262306a36Sopenharmony_ci writel(0, priv->base + EIP197_XLX_GPIO_BASE); 196362306a36Sopenharmony_ci wmb(); /* maintain strict ordering for accesses here */ 196462306a36Sopenharmony_ci } 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci /* enable bus mastering */ 196762306a36Sopenharmony_ci pci_set_master(pdev); 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci /* Generic EIP97/EIP197 device probing */ 197062306a36Sopenharmony_ci rc = safexcel_probe_generic(pdev, priv, 1); 197162306a36Sopenharmony_ci return rc; 197262306a36Sopenharmony_ci} 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_cistatic void safexcel_pci_remove(struct pci_dev *pdev) 197562306a36Sopenharmony_ci{ 197662306a36Sopenharmony_ci struct safexcel_crypto_priv *priv = pci_get_drvdata(pdev); 197762306a36Sopenharmony_ci int i; 197862306a36Sopenharmony_ci 197962306a36Sopenharmony_ci safexcel_unregister_algorithms(priv); 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_ci for (i = 0; i < priv->config.rings; i++) 198262306a36Sopenharmony_ci destroy_workqueue(priv->ring[i].workqueue); 198362306a36Sopenharmony_ci 198462306a36Sopenharmony_ci safexcel_hw_reset_rings(priv); 198562306a36Sopenharmony_ci} 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_cistatic const struct pci_device_id safexcel_pci_ids[] = { 198862306a36Sopenharmony_ci { 198962306a36Sopenharmony_ci PCI_DEVICE_SUB(PCI_VENDOR_ID_XILINX, 0x9038, 199062306a36Sopenharmony_ci 0x16ae, 0xc522), 199162306a36Sopenharmony_ci .driver_data = (kernel_ulong_t)&eip197_devbrd_data, 199262306a36Sopenharmony_ci }, 199362306a36Sopenharmony_ci {}, 199462306a36Sopenharmony_ci}; 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, safexcel_pci_ids); 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_cistatic struct pci_driver safexcel_pci_driver = { 199962306a36Sopenharmony_ci .name = "crypto-safexcel", 200062306a36Sopenharmony_ci .id_table = safexcel_pci_ids, 200162306a36Sopenharmony_ci .probe = safexcel_pci_probe, 200262306a36Sopenharmony_ci .remove = safexcel_pci_remove, 200362306a36Sopenharmony_ci}; 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_cistatic int __init safexcel_init(void) 200662306a36Sopenharmony_ci{ 200762306a36Sopenharmony_ci int ret; 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci /* Register PCI driver */ 201062306a36Sopenharmony_ci ret = pci_register_driver(&safexcel_pci_driver); 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci /* Register platform driver */ 201362306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_OF) && !ret) { 201462306a36Sopenharmony_ci ret = platform_driver_register(&crypto_safexcel); 201562306a36Sopenharmony_ci if (ret) 201662306a36Sopenharmony_ci pci_unregister_driver(&safexcel_pci_driver); 201762306a36Sopenharmony_ci } 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_ci return ret; 202062306a36Sopenharmony_ci} 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_cistatic void __exit safexcel_exit(void) 202362306a36Sopenharmony_ci{ 202462306a36Sopenharmony_ci /* Unregister platform driver */ 202562306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_OF)) 202662306a36Sopenharmony_ci platform_driver_unregister(&crypto_safexcel); 202762306a36Sopenharmony_ci 202862306a36Sopenharmony_ci /* Unregister PCI driver if successfully registered before */ 202962306a36Sopenharmony_ci pci_unregister_driver(&safexcel_pci_driver); 203062306a36Sopenharmony_ci} 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_cimodule_init(safexcel_init); 203362306a36Sopenharmony_cimodule_exit(safexcel_exit); 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_ciMODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>"); 203662306a36Sopenharmony_ciMODULE_AUTHOR("Ofer Heifetz <oferh@marvell.com>"); 203762306a36Sopenharmony_ciMODULE_AUTHOR("Igal Liberman <igall@marvell.com>"); 203862306a36Sopenharmony_ciMODULE_DESCRIPTION("Support for SafeXcel cryptographic engines: EIP97 & EIP197"); 203962306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 204062306a36Sopenharmony_ciMODULE_IMPORT_NS(CRYPTO_INTERNAL); 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ciMODULE_FIRMWARE("ifpp.bin"); 204362306a36Sopenharmony_ciMODULE_FIRMWARE("ipue.bin"); 204462306a36Sopenharmony_ciMODULE_FIRMWARE("inside-secure/eip197b/ifpp.bin"); 204562306a36Sopenharmony_ciMODULE_FIRMWARE("inside-secure/eip197b/ipue.bin"); 204662306a36Sopenharmony_ciMODULE_FIRMWARE("inside-secure/eip197d/ifpp.bin"); 204762306a36Sopenharmony_ciMODULE_FIRMWARE("inside-secure/eip197d/ipue.bin"); 204862306a36Sopenharmony_ciMODULE_FIRMWARE("inside-secure/eip197_minifw/ifpp.bin"); 204962306a36Sopenharmony_ciMODULE_FIRMWARE("inside-secure/eip197_minifw/ipue.bin"); 2050