18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2017 Marvell 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Antoine Tenart <antoine.tenart@free-electrons.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/clk.h> 98c2ecf20Sopenharmony_ci#include <linux/device.h> 108c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 118c2ecf20Sopenharmony_ci#include <linux/dmapool.h> 128c2ecf20Sopenharmony_ci#include <linux/firmware.h> 138c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 168c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 178c2ecf20Sopenharmony_ci#include <linux/pci.h> 188c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 198c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <crypto/internal/aead.h> 228c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h> 238c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "safexcel.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic u32 max_rings = EIP197_MAX_RINGS; 288c2ecf20Sopenharmony_cimodule_param(max_rings, uint, 0644); 298c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_rings, "Maximum number of rings to use."); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic void eip197_trc_cache_setupvirt(struct safexcel_crypto_priv *priv) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci int i; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci /* 368c2ecf20Sopenharmony_ci * Map all interfaces/rings to register index 0 378c2ecf20Sopenharmony_ci * so they can share contexts. Without this, the EIP197 will 388c2ecf20Sopenharmony_ci * assume each interface/ring to be in its own memory domain 398c2ecf20Sopenharmony_ci * i.e. have its own subset of UNIQUE memory addresses. 408c2ecf20Sopenharmony_ci * Which would cause records with the SAME memory address to 418c2ecf20Sopenharmony_ci * use DIFFERENT cache buffers, causing both poor cache utilization 428c2ecf20Sopenharmony_ci * AND serious coherence/invalidation issues. 438c2ecf20Sopenharmony_ci */ 448c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 458c2ecf20Sopenharmony_ci writel(0, priv->base + EIP197_FLUE_IFC_LUT(i)); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci /* 488c2ecf20Sopenharmony_ci * Initialize other virtualization regs for cache 498c2ecf20Sopenharmony_ci * These may not be in their reset state ... 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci for (i = 0; i < priv->config.rings; i++) { 528c2ecf20Sopenharmony_ci writel(0, priv->base + EIP197_FLUE_CACHEBASE_LO(i)); 538c2ecf20Sopenharmony_ci writel(0, priv->base + EIP197_FLUE_CACHEBASE_HI(i)); 548c2ecf20Sopenharmony_ci writel(EIP197_FLUE_CONFIG_MAGIC, 558c2ecf20Sopenharmony_ci priv->base + EIP197_FLUE_CONFIG(i)); 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci writel(0, priv->base + EIP197_FLUE_OFFSETS); 588c2ecf20Sopenharmony_ci writel(0, priv->base + EIP197_FLUE_ARC4_OFFSET); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic void eip197_trc_cache_banksel(struct safexcel_crypto_priv *priv, 628c2ecf20Sopenharmony_ci u32 addrmid, int *actbank) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci u32 val; 658c2ecf20Sopenharmony_ci int curbank; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci curbank = addrmid >> 16; 688c2ecf20Sopenharmony_ci if (curbank != *actbank) { 698c2ecf20Sopenharmony_ci val = readl(priv->base + EIP197_CS_RAM_CTRL); 708c2ecf20Sopenharmony_ci val = (val & ~EIP197_CS_BANKSEL_MASK) | 718c2ecf20Sopenharmony_ci (curbank << EIP197_CS_BANKSEL_OFS); 728c2ecf20Sopenharmony_ci writel(val, priv->base + EIP197_CS_RAM_CTRL); 738c2ecf20Sopenharmony_ci *actbank = curbank; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic u32 eip197_trc_cache_probe(struct safexcel_crypto_priv *priv, 788c2ecf20Sopenharmony_ci int maxbanks, u32 probemask, u32 stride) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci u32 val, addrhi, addrlo, addrmid, addralias, delta, marker; 818c2ecf20Sopenharmony_ci int actbank; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* 848c2ecf20Sopenharmony_ci * And probe the actual size of the physically attached cache data RAM 858c2ecf20Sopenharmony_ci * Using a binary subdivision algorithm downto 32 byte cache lines. 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_ci addrhi = 1 << (16 + maxbanks); 888c2ecf20Sopenharmony_ci addrlo = 0; 898c2ecf20Sopenharmony_ci actbank = min(maxbanks - 1, 0); 908c2ecf20Sopenharmony_ci while ((addrhi - addrlo) > stride) { 918c2ecf20Sopenharmony_ci /* write marker to lowest address in top half */ 928c2ecf20Sopenharmony_ci addrmid = (addrhi + addrlo) >> 1; 938c2ecf20Sopenharmony_ci marker = (addrmid ^ 0xabadbabe) & probemask; /* Unique */ 948c2ecf20Sopenharmony_ci eip197_trc_cache_banksel(priv, addrmid, &actbank); 958c2ecf20Sopenharmony_ci writel(marker, 968c2ecf20Sopenharmony_ci priv->base + EIP197_CLASSIFICATION_RAMS + 978c2ecf20Sopenharmony_ci (addrmid & 0xffff)); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci /* write invalid markers to possible aliases */ 1008c2ecf20Sopenharmony_ci delta = 1 << __fls(addrmid); 1018c2ecf20Sopenharmony_ci while (delta >= stride) { 1028c2ecf20Sopenharmony_ci addralias = addrmid - delta; 1038c2ecf20Sopenharmony_ci eip197_trc_cache_banksel(priv, addralias, &actbank); 1048c2ecf20Sopenharmony_ci writel(~marker, 1058c2ecf20Sopenharmony_ci priv->base + EIP197_CLASSIFICATION_RAMS + 1068c2ecf20Sopenharmony_ci (addralias & 0xffff)); 1078c2ecf20Sopenharmony_ci delta >>= 1; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* read back marker from top half */ 1118c2ecf20Sopenharmony_ci eip197_trc_cache_banksel(priv, addrmid, &actbank); 1128c2ecf20Sopenharmony_ci val = readl(priv->base + EIP197_CLASSIFICATION_RAMS + 1138c2ecf20Sopenharmony_ci (addrmid & 0xffff)); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if ((val & probemask) == marker) 1168c2ecf20Sopenharmony_ci /* read back correct, continue with top half */ 1178c2ecf20Sopenharmony_ci addrlo = addrmid; 1188c2ecf20Sopenharmony_ci else 1198c2ecf20Sopenharmony_ci /* not read back correct, continue with bottom half */ 1208c2ecf20Sopenharmony_ci addrhi = addrmid; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci return addrhi; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic void eip197_trc_cache_clear(struct safexcel_crypto_priv *priv, 1268c2ecf20Sopenharmony_ci int cs_rc_max, int cs_ht_wc) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci int i; 1298c2ecf20Sopenharmony_ci u32 htable_offset, val, offset; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* Clear all records in administration RAM */ 1328c2ecf20Sopenharmony_ci for (i = 0; i < cs_rc_max; i++) { 1338c2ecf20Sopenharmony_ci offset = EIP197_CLASSIFICATION_RAMS + i * EIP197_CS_RC_SIZE; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci writel(EIP197_CS_RC_NEXT(EIP197_RC_NULL) | 1368c2ecf20Sopenharmony_ci EIP197_CS_RC_PREV(EIP197_RC_NULL), 1378c2ecf20Sopenharmony_ci priv->base + offset); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci val = EIP197_CS_RC_NEXT(i + 1) | EIP197_CS_RC_PREV(i - 1); 1408c2ecf20Sopenharmony_ci if (i == 0) 1418c2ecf20Sopenharmony_ci val |= EIP197_CS_RC_PREV(EIP197_RC_NULL); 1428c2ecf20Sopenharmony_ci else if (i == cs_rc_max - 1) 1438c2ecf20Sopenharmony_ci val |= EIP197_CS_RC_NEXT(EIP197_RC_NULL); 1448c2ecf20Sopenharmony_ci writel(val, priv->base + offset + 4); 1458c2ecf20Sopenharmony_ci /* must also initialize the address key due to ECC! */ 1468c2ecf20Sopenharmony_ci writel(0, priv->base + offset + 8); 1478c2ecf20Sopenharmony_ci writel(0, priv->base + offset + 12); 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci /* Clear the hash table entries */ 1518c2ecf20Sopenharmony_ci htable_offset = cs_rc_max * EIP197_CS_RC_SIZE; 1528c2ecf20Sopenharmony_ci for (i = 0; i < cs_ht_wc; i++) 1538c2ecf20Sopenharmony_ci writel(GENMASK(29, 0), 1548c2ecf20Sopenharmony_ci priv->base + EIP197_CLASSIFICATION_RAMS + 1558c2ecf20Sopenharmony_ci htable_offset + i * sizeof(u32)); 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic int eip197_trc_cache_init(struct safexcel_crypto_priv *priv) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci u32 val, dsize, asize; 1618c2ecf20Sopenharmony_ci int cs_rc_max, cs_ht_wc, cs_trc_rec_wc, cs_trc_lg_rec_wc; 1628c2ecf20Sopenharmony_ci int cs_rc_abs_max, cs_ht_sz; 1638c2ecf20Sopenharmony_ci int maxbanks; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* Setup (dummy) virtualization for cache */ 1668c2ecf20Sopenharmony_ci eip197_trc_cache_setupvirt(priv); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* 1698c2ecf20Sopenharmony_ci * Enable the record cache memory access and 1708c2ecf20Sopenharmony_ci * probe the bank select width 1718c2ecf20Sopenharmony_ci */ 1728c2ecf20Sopenharmony_ci val = readl(priv->base + EIP197_CS_RAM_CTRL); 1738c2ecf20Sopenharmony_ci val &= ~EIP197_TRC_ENABLE_MASK; 1748c2ecf20Sopenharmony_ci val |= EIP197_TRC_ENABLE_0 | EIP197_CS_BANKSEL_MASK; 1758c2ecf20Sopenharmony_ci writel(val, priv->base + EIP197_CS_RAM_CTRL); 1768c2ecf20Sopenharmony_ci val = readl(priv->base + EIP197_CS_RAM_CTRL); 1778c2ecf20Sopenharmony_ci maxbanks = ((val&EIP197_CS_BANKSEL_MASK)>>EIP197_CS_BANKSEL_OFS) + 1; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* Clear all ECC errors */ 1808c2ecf20Sopenharmony_ci writel(0, priv->base + EIP197_TRC_ECCCTRL); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* 1838c2ecf20Sopenharmony_ci * Make sure the cache memory is accessible by taking record cache into 1848c2ecf20Sopenharmony_ci * reset. Need data memory access here, not admin access. 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_ci val = readl(priv->base + EIP197_TRC_PARAMS); 1878c2ecf20Sopenharmony_ci val |= EIP197_TRC_PARAMS_SW_RESET | EIP197_TRC_PARAMS_DATA_ACCESS; 1888c2ecf20Sopenharmony_ci writel(val, priv->base + EIP197_TRC_PARAMS); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* Probed data RAM size in bytes */ 1918c2ecf20Sopenharmony_ci dsize = eip197_trc_cache_probe(priv, maxbanks, 0xffffffff, 32); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* 1948c2ecf20Sopenharmony_ci * Now probe the administration RAM size pretty much the same way 1958c2ecf20Sopenharmony_ci * Except that only the lower 30 bits are writable and we don't need 1968c2ecf20Sopenharmony_ci * bank selects 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_ci val = readl(priv->base + EIP197_TRC_PARAMS); 1998c2ecf20Sopenharmony_ci /* admin access now */ 2008c2ecf20Sopenharmony_ci val &= ~(EIP197_TRC_PARAMS_DATA_ACCESS | EIP197_CS_BANKSEL_MASK); 2018c2ecf20Sopenharmony_ci writel(val, priv->base + EIP197_TRC_PARAMS); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* Probed admin RAM size in admin words */ 2048c2ecf20Sopenharmony_ci asize = eip197_trc_cache_probe(priv, 0, 0x3fffffff, 16) >> 4; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* Clear any ECC errors detected while probing! */ 2078c2ecf20Sopenharmony_ci writel(0, priv->base + EIP197_TRC_ECCCTRL); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci /* Sanity check probing results */ 2108c2ecf20Sopenharmony_ci if (dsize < EIP197_MIN_DSIZE || asize < EIP197_MIN_ASIZE) { 2118c2ecf20Sopenharmony_ci dev_err(priv->dev, "Record cache probing failed (%d,%d).", 2128c2ecf20Sopenharmony_ci dsize, asize); 2138c2ecf20Sopenharmony_ci return -ENODEV; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* 2178c2ecf20Sopenharmony_ci * Determine optimal configuration from RAM sizes 2188c2ecf20Sopenharmony_ci * Note that we assume that the physical RAM configuration is sane 2198c2ecf20Sopenharmony_ci * Therefore, we don't do any parameter error checking here ... 2208c2ecf20Sopenharmony_ci */ 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci /* For now, just use a single record format covering everything */ 2238c2ecf20Sopenharmony_ci cs_trc_rec_wc = EIP197_CS_TRC_REC_WC; 2248c2ecf20Sopenharmony_ci cs_trc_lg_rec_wc = EIP197_CS_TRC_REC_WC; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* 2278c2ecf20Sopenharmony_ci * Step #1: How many records will physically fit? 2288c2ecf20Sopenharmony_ci * Hard upper limit is 1023! 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_ci cs_rc_abs_max = min_t(uint, ((dsize >> 2) / cs_trc_lg_rec_wc), 1023); 2318c2ecf20Sopenharmony_ci /* Step #2: Need at least 2 words in the admin RAM per record */ 2328c2ecf20Sopenharmony_ci cs_rc_max = min_t(uint, cs_rc_abs_max, (asize >> 1)); 2338c2ecf20Sopenharmony_ci /* Step #3: Determine log2 of hash table size */ 2348c2ecf20Sopenharmony_ci cs_ht_sz = __fls(asize - cs_rc_max) - 2; 2358c2ecf20Sopenharmony_ci /* Step #4: determine current size of hash table in dwords */ 2368c2ecf20Sopenharmony_ci cs_ht_wc = 16 << cs_ht_sz; /* dwords, not admin words */ 2378c2ecf20Sopenharmony_ci /* Step #5: add back excess words and see if we can fit more records */ 2388c2ecf20Sopenharmony_ci cs_rc_max = min_t(uint, cs_rc_abs_max, asize - (cs_ht_wc >> 2)); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* Clear the cache RAMs */ 2418c2ecf20Sopenharmony_ci eip197_trc_cache_clear(priv, cs_rc_max, cs_ht_wc); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* Disable the record cache memory access */ 2448c2ecf20Sopenharmony_ci val = readl(priv->base + EIP197_CS_RAM_CTRL); 2458c2ecf20Sopenharmony_ci val &= ~EIP197_TRC_ENABLE_MASK; 2468c2ecf20Sopenharmony_ci writel(val, priv->base + EIP197_CS_RAM_CTRL); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* Write head and tail pointers of the record free chain */ 2498c2ecf20Sopenharmony_ci val = EIP197_TRC_FREECHAIN_HEAD_PTR(0) | 2508c2ecf20Sopenharmony_ci EIP197_TRC_FREECHAIN_TAIL_PTR(cs_rc_max - 1); 2518c2ecf20Sopenharmony_ci writel(val, priv->base + EIP197_TRC_FREECHAIN); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* Configure the record cache #1 */ 2548c2ecf20Sopenharmony_ci val = EIP197_TRC_PARAMS2_RC_SZ_SMALL(cs_trc_rec_wc) | 2558c2ecf20Sopenharmony_ci EIP197_TRC_PARAMS2_HTABLE_PTR(cs_rc_max); 2568c2ecf20Sopenharmony_ci writel(val, priv->base + EIP197_TRC_PARAMS2); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* Configure the record cache #2 */ 2598c2ecf20Sopenharmony_ci val = EIP197_TRC_PARAMS_RC_SZ_LARGE(cs_trc_lg_rec_wc) | 2608c2ecf20Sopenharmony_ci EIP197_TRC_PARAMS_BLK_TIMER_SPEED(1) | 2618c2ecf20Sopenharmony_ci EIP197_TRC_PARAMS_HTABLE_SZ(cs_ht_sz); 2628c2ecf20Sopenharmony_ci writel(val, priv->base + EIP197_TRC_PARAMS); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci dev_info(priv->dev, "TRC init: %dd,%da (%dr,%dh)\n", 2658c2ecf20Sopenharmony_ci dsize, asize, cs_rc_max, cs_ht_wc + cs_ht_wc); 2668c2ecf20Sopenharmony_ci return 0; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic void eip197_init_firmware(struct safexcel_crypto_priv *priv) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci int pe, i; 2728c2ecf20Sopenharmony_ci u32 val; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci for (pe = 0; pe < priv->config.pes; pe++) { 2758c2ecf20Sopenharmony_ci /* Configure the token FIFO's */ 2768c2ecf20Sopenharmony_ci writel(3, EIP197_PE(priv) + EIP197_PE_ICE_PUTF_CTRL(pe)); 2778c2ecf20Sopenharmony_ci writel(0, EIP197_PE(priv) + EIP197_PE_ICE_PPTF_CTRL(pe)); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* Clear the ICE scratchpad memory */ 2808c2ecf20Sopenharmony_ci val = readl(EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_CTRL(pe)); 2818c2ecf20Sopenharmony_ci val |= EIP197_PE_ICE_SCRATCH_CTRL_CHANGE_TIMER | 2828c2ecf20Sopenharmony_ci EIP197_PE_ICE_SCRATCH_CTRL_TIMER_EN | 2838c2ecf20Sopenharmony_ci EIP197_PE_ICE_SCRATCH_CTRL_SCRATCH_ACCESS | 2848c2ecf20Sopenharmony_ci EIP197_PE_ICE_SCRATCH_CTRL_CHANGE_ACCESS; 2858c2ecf20Sopenharmony_ci writel(val, EIP197_PE(priv) + EIP197_PE_ICE_SCRATCH_CTRL(pe)); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci /* clear the scratchpad RAM using 32 bit writes only */ 2888c2ecf20Sopenharmony_ci for (i = 0; i < EIP197_NUM_OF_SCRATCH_BLOCKS; i++) 2898c2ecf20Sopenharmony_ci writel(0, EIP197_PE(priv) + 2908c2ecf20Sopenharmony_ci EIP197_PE_ICE_SCRATCH_RAM(pe) + (i << 2)); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* Reset the IFPP engine to make its program mem accessible */ 2938c2ecf20Sopenharmony_ci writel(EIP197_PE_ICE_x_CTRL_SW_RESET | 2948c2ecf20Sopenharmony_ci EIP197_PE_ICE_x_CTRL_CLR_ECC_CORR | 2958c2ecf20Sopenharmony_ci EIP197_PE_ICE_x_CTRL_CLR_ECC_NON_CORR, 2968c2ecf20Sopenharmony_ci EIP197_PE(priv) + EIP197_PE_ICE_FPP_CTRL(pe)); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci /* Reset the IPUE engine to make its program mem accessible */ 2998c2ecf20Sopenharmony_ci writel(EIP197_PE_ICE_x_CTRL_SW_RESET | 3008c2ecf20Sopenharmony_ci EIP197_PE_ICE_x_CTRL_CLR_ECC_CORR | 3018c2ecf20Sopenharmony_ci EIP197_PE_ICE_x_CTRL_CLR_ECC_NON_CORR, 3028c2ecf20Sopenharmony_ci EIP197_PE(priv) + EIP197_PE_ICE_PUE_CTRL(pe)); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci /* Enable access to all IFPP program memories */ 3058c2ecf20Sopenharmony_ci writel(EIP197_PE_ICE_RAM_CTRL_FPP_PROG_EN, 3068c2ecf20Sopenharmony_ci EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe)); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* bypass the OCE, if present */ 3098c2ecf20Sopenharmony_ci if (priv->flags & EIP197_OCE) 3108c2ecf20Sopenharmony_ci writel(EIP197_DEBUG_OCE_BYPASS, EIP197_PE(priv) + 3118c2ecf20Sopenharmony_ci EIP197_PE_DEBUG(pe)); 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic int eip197_write_firmware(struct safexcel_crypto_priv *priv, 3178c2ecf20Sopenharmony_ci const struct firmware *fw) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci const __be32 *data = (const __be32 *)fw->data; 3208c2ecf20Sopenharmony_ci int i; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* Write the firmware */ 3238c2ecf20Sopenharmony_ci for (i = 0; i < fw->size / sizeof(u32); i++) 3248c2ecf20Sopenharmony_ci writel(be32_to_cpu(data[i]), 3258c2ecf20Sopenharmony_ci priv->base + EIP197_CLASSIFICATION_RAMS + 3268c2ecf20Sopenharmony_ci i * sizeof(__be32)); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci /* Exclude final 2 NOPs from size */ 3298c2ecf20Sopenharmony_ci return i - EIP197_FW_TERMINAL_NOPS; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci/* 3338c2ecf20Sopenharmony_ci * If FW is actual production firmware, then poll for its initialization 3348c2ecf20Sopenharmony_ci * to complete and check if it is good for the HW, otherwise just return OK. 3358c2ecf20Sopenharmony_ci */ 3368c2ecf20Sopenharmony_cistatic bool poll_fw_ready(struct safexcel_crypto_priv *priv, int fpp) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci int pe, pollcnt; 3398c2ecf20Sopenharmony_ci u32 base, pollofs; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (fpp) 3428c2ecf20Sopenharmony_ci pollofs = EIP197_FW_FPP_READY; 3438c2ecf20Sopenharmony_ci else 3448c2ecf20Sopenharmony_ci pollofs = EIP197_FW_PUE_READY; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci for (pe = 0; pe < priv->config.pes; pe++) { 3478c2ecf20Sopenharmony_ci base = EIP197_PE_ICE_SCRATCH_RAM(pe); 3488c2ecf20Sopenharmony_ci pollcnt = EIP197_FW_START_POLLCNT; 3498c2ecf20Sopenharmony_ci while (pollcnt && 3508c2ecf20Sopenharmony_ci (readl_relaxed(EIP197_PE(priv) + base + 3518c2ecf20Sopenharmony_ci pollofs) != 1)) { 3528c2ecf20Sopenharmony_ci pollcnt--; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci if (!pollcnt) { 3558c2ecf20Sopenharmony_ci dev_err(priv->dev, "FW(%d) for PE %d failed to start\n", 3568c2ecf20Sopenharmony_ci fpp, pe); 3578c2ecf20Sopenharmony_ci return false; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci return true; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic bool eip197_start_firmware(struct safexcel_crypto_priv *priv, 3648c2ecf20Sopenharmony_ci int ipuesz, int ifppsz, int minifw) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci int pe; 3678c2ecf20Sopenharmony_ci u32 val; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci for (pe = 0; pe < priv->config.pes; pe++) { 3708c2ecf20Sopenharmony_ci /* Disable access to all program memory */ 3718c2ecf20Sopenharmony_ci writel(0, EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe)); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci /* Start IFPP microengines */ 3748c2ecf20Sopenharmony_ci if (minifw) 3758c2ecf20Sopenharmony_ci val = 0; 3768c2ecf20Sopenharmony_ci else 3778c2ecf20Sopenharmony_ci val = EIP197_PE_ICE_UENG_START_OFFSET((ifppsz - 1) & 3788c2ecf20Sopenharmony_ci EIP197_PE_ICE_UENG_INIT_ALIGN_MASK) | 3798c2ecf20Sopenharmony_ci EIP197_PE_ICE_UENG_DEBUG_RESET; 3808c2ecf20Sopenharmony_ci writel(val, EIP197_PE(priv) + EIP197_PE_ICE_FPP_CTRL(pe)); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* Start IPUE microengines */ 3838c2ecf20Sopenharmony_ci if (minifw) 3848c2ecf20Sopenharmony_ci val = 0; 3858c2ecf20Sopenharmony_ci else 3868c2ecf20Sopenharmony_ci val = EIP197_PE_ICE_UENG_START_OFFSET((ipuesz - 1) & 3878c2ecf20Sopenharmony_ci EIP197_PE_ICE_UENG_INIT_ALIGN_MASK) | 3888c2ecf20Sopenharmony_ci EIP197_PE_ICE_UENG_DEBUG_RESET; 3898c2ecf20Sopenharmony_ci writel(val, EIP197_PE(priv) + EIP197_PE_ICE_PUE_CTRL(pe)); 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci /* For miniFW startup, there is no initialization, so always succeed */ 3938c2ecf20Sopenharmony_ci if (minifw) 3948c2ecf20Sopenharmony_ci return true; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci /* Wait until all the firmwares have properly started up */ 3978c2ecf20Sopenharmony_ci if (!poll_fw_ready(priv, 1)) 3988c2ecf20Sopenharmony_ci return false; 3998c2ecf20Sopenharmony_ci if (!poll_fw_ready(priv, 0)) 4008c2ecf20Sopenharmony_ci return false; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci return true; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic int eip197_load_firmwares(struct safexcel_crypto_priv *priv) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci const char *fw_name[] = {"ifpp.bin", "ipue.bin"}; 4088c2ecf20Sopenharmony_ci const struct firmware *fw[FW_NB]; 4098c2ecf20Sopenharmony_ci char fw_path[37], *dir = NULL; 4108c2ecf20Sopenharmony_ci int i, j, ret = 0, pe; 4118c2ecf20Sopenharmony_ci int ipuesz, ifppsz, minifw = 0; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (priv->version == EIP197D_MRVL) 4148c2ecf20Sopenharmony_ci dir = "eip197d"; 4158c2ecf20Sopenharmony_ci else if (priv->version == EIP197B_MRVL || 4168c2ecf20Sopenharmony_ci priv->version == EIP197_DEVBRD) 4178c2ecf20Sopenharmony_ci dir = "eip197b"; 4188c2ecf20Sopenharmony_ci else 4198c2ecf20Sopenharmony_ci return -ENODEV; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ciretry_fw: 4228c2ecf20Sopenharmony_ci for (i = 0; i < FW_NB; i++) { 4238c2ecf20Sopenharmony_ci snprintf(fw_path, 37, "inside-secure/%s/%s", dir, fw_name[i]); 4248c2ecf20Sopenharmony_ci ret = firmware_request_nowarn(&fw[i], fw_path, priv->dev); 4258c2ecf20Sopenharmony_ci if (ret) { 4268c2ecf20Sopenharmony_ci if (minifw || priv->version != EIP197B_MRVL) 4278c2ecf20Sopenharmony_ci goto release_fw; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci /* Fallback to the old firmware location for the 4308c2ecf20Sopenharmony_ci * EIP197b. 4318c2ecf20Sopenharmony_ci */ 4328c2ecf20Sopenharmony_ci ret = firmware_request_nowarn(&fw[i], fw_name[i], 4338c2ecf20Sopenharmony_ci priv->dev); 4348c2ecf20Sopenharmony_ci if (ret) 4358c2ecf20Sopenharmony_ci goto release_fw; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci eip197_init_firmware(priv); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci ifppsz = eip197_write_firmware(priv, fw[FW_IFPP]); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci /* Enable access to IPUE program memories */ 4448c2ecf20Sopenharmony_ci for (pe = 0; pe < priv->config.pes; pe++) 4458c2ecf20Sopenharmony_ci writel(EIP197_PE_ICE_RAM_CTRL_PUE_PROG_EN, 4468c2ecf20Sopenharmony_ci EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe)); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci ipuesz = eip197_write_firmware(priv, fw[FW_IPUE]); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci if (eip197_start_firmware(priv, ipuesz, ifppsz, minifw)) { 4518c2ecf20Sopenharmony_ci dev_dbg(priv->dev, "Firmware loaded successfully\n"); 4528c2ecf20Sopenharmony_ci return 0; 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci ret = -ENODEV; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cirelease_fw: 4588c2ecf20Sopenharmony_ci for (j = 0; j < i; j++) 4598c2ecf20Sopenharmony_ci release_firmware(fw[j]); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (!minifw) { 4628c2ecf20Sopenharmony_ci /* Retry with minifw path */ 4638c2ecf20Sopenharmony_ci dev_dbg(priv->dev, "Firmware set not (fully) present or init failed, falling back to BCLA mode\n"); 4648c2ecf20Sopenharmony_ci dir = "eip197_minifw"; 4658c2ecf20Sopenharmony_ci minifw = 1; 4668c2ecf20Sopenharmony_ci goto retry_fw; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci dev_dbg(priv->dev, "Firmware load failed.\n"); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci return ret; 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_cistatic int safexcel_hw_setup_cdesc_rings(struct safexcel_crypto_priv *priv) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci u32 cd_size_rnd, val; 4778c2ecf20Sopenharmony_ci int i, cd_fetch_cnt; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci cd_size_rnd = (priv->config.cd_size + 4808c2ecf20Sopenharmony_ci (BIT(priv->hwconfig.hwdataw) - 1)) >> 4818c2ecf20Sopenharmony_ci priv->hwconfig.hwdataw; 4828c2ecf20Sopenharmony_ci /* determine number of CD's we can fetch into the CD FIFO as 1 block */ 4838c2ecf20Sopenharmony_ci if (priv->flags & SAFEXCEL_HW_EIP197) { 4848c2ecf20Sopenharmony_ci /* EIP197: try to fetch enough in 1 go to keep all pipes busy */ 4858c2ecf20Sopenharmony_ci cd_fetch_cnt = (1 << priv->hwconfig.hwcfsize) / cd_size_rnd; 4868c2ecf20Sopenharmony_ci cd_fetch_cnt = min_t(uint, cd_fetch_cnt, 4878c2ecf20Sopenharmony_ci (priv->config.pes * EIP197_FETCH_DEPTH)); 4888c2ecf20Sopenharmony_ci } else { 4898c2ecf20Sopenharmony_ci /* for the EIP97, just fetch all that fits minus 1 */ 4908c2ecf20Sopenharmony_ci cd_fetch_cnt = ((1 << priv->hwconfig.hwcfsize) / 4918c2ecf20Sopenharmony_ci cd_size_rnd) - 1; 4928c2ecf20Sopenharmony_ci } 4938c2ecf20Sopenharmony_ci /* 4948c2ecf20Sopenharmony_ci * Since we're using command desc's way larger than formally specified, 4958c2ecf20Sopenharmony_ci * we need to check whether we can fit even 1 for low-end EIP196's! 4968c2ecf20Sopenharmony_ci */ 4978c2ecf20Sopenharmony_ci if (!cd_fetch_cnt) { 4988c2ecf20Sopenharmony_ci dev_err(priv->dev, "Unable to fit even 1 command desc!\n"); 4998c2ecf20Sopenharmony_ci return -ENODEV; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci for (i = 0; i < priv->config.rings; i++) { 5038c2ecf20Sopenharmony_ci /* ring base address */ 5048c2ecf20Sopenharmony_ci writel(lower_32_bits(priv->ring[i].cdr.base_dma), 5058c2ecf20Sopenharmony_ci EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_LO); 5068c2ecf20Sopenharmony_ci writel(upper_32_bits(priv->ring[i].cdr.base_dma), 5078c2ecf20Sopenharmony_ci EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_HI); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci writel(EIP197_xDR_DESC_MODE_64BIT | EIP197_CDR_DESC_MODE_ADCP | 5108c2ecf20Sopenharmony_ci (priv->config.cd_offset << 14) | priv->config.cd_size, 5118c2ecf20Sopenharmony_ci EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_DESC_SIZE); 5128c2ecf20Sopenharmony_ci writel(((cd_fetch_cnt * 5138c2ecf20Sopenharmony_ci (cd_size_rnd << priv->hwconfig.hwdataw)) << 16) | 5148c2ecf20Sopenharmony_ci (cd_fetch_cnt * (priv->config.cd_offset / sizeof(u32))), 5158c2ecf20Sopenharmony_ci EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_CFG); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci /* Configure DMA tx control */ 5188c2ecf20Sopenharmony_ci val = EIP197_HIA_xDR_CFG_WR_CACHE(WR_CACHE_3BITS); 5198c2ecf20Sopenharmony_ci val |= EIP197_HIA_xDR_CFG_RD_CACHE(RD_CACHE_3BITS); 5208c2ecf20Sopenharmony_ci writel(val, EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_DMA_CFG); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci /* clear any pending interrupt */ 5238c2ecf20Sopenharmony_ci writel(GENMASK(5, 0), 5248c2ecf20Sopenharmony_ci EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_STAT); 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci return 0; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic int safexcel_hw_setup_rdesc_rings(struct safexcel_crypto_priv *priv) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci u32 rd_size_rnd, val; 5338c2ecf20Sopenharmony_ci int i, rd_fetch_cnt; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci /* determine number of RD's we can fetch into the FIFO as one block */ 5368c2ecf20Sopenharmony_ci rd_size_rnd = (EIP197_RD64_FETCH_SIZE + 5378c2ecf20Sopenharmony_ci (BIT(priv->hwconfig.hwdataw) - 1)) >> 5388c2ecf20Sopenharmony_ci priv->hwconfig.hwdataw; 5398c2ecf20Sopenharmony_ci if (priv->flags & SAFEXCEL_HW_EIP197) { 5408c2ecf20Sopenharmony_ci /* EIP197: try to fetch enough in 1 go to keep all pipes busy */ 5418c2ecf20Sopenharmony_ci rd_fetch_cnt = (1 << priv->hwconfig.hwrfsize) / rd_size_rnd; 5428c2ecf20Sopenharmony_ci rd_fetch_cnt = min_t(uint, rd_fetch_cnt, 5438c2ecf20Sopenharmony_ci (priv->config.pes * EIP197_FETCH_DEPTH)); 5448c2ecf20Sopenharmony_ci } else { 5458c2ecf20Sopenharmony_ci /* for the EIP97, just fetch all that fits minus 1 */ 5468c2ecf20Sopenharmony_ci rd_fetch_cnt = ((1 << priv->hwconfig.hwrfsize) / 5478c2ecf20Sopenharmony_ci rd_size_rnd) - 1; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci for (i = 0; i < priv->config.rings; i++) { 5518c2ecf20Sopenharmony_ci /* ring base address */ 5528c2ecf20Sopenharmony_ci writel(lower_32_bits(priv->ring[i].rdr.base_dma), 5538c2ecf20Sopenharmony_ci EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_LO); 5548c2ecf20Sopenharmony_ci writel(upper_32_bits(priv->ring[i].rdr.base_dma), 5558c2ecf20Sopenharmony_ci EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_HI); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci writel(EIP197_xDR_DESC_MODE_64BIT | (priv->config.rd_offset << 14) | 5588c2ecf20Sopenharmony_ci priv->config.rd_size, 5598c2ecf20Sopenharmony_ci EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_DESC_SIZE); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci writel(((rd_fetch_cnt * 5628c2ecf20Sopenharmony_ci (rd_size_rnd << priv->hwconfig.hwdataw)) << 16) | 5638c2ecf20Sopenharmony_ci (rd_fetch_cnt * (priv->config.rd_offset / sizeof(u32))), 5648c2ecf20Sopenharmony_ci EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_CFG); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci /* Configure DMA tx control */ 5678c2ecf20Sopenharmony_ci val = EIP197_HIA_xDR_CFG_WR_CACHE(WR_CACHE_3BITS); 5688c2ecf20Sopenharmony_ci val |= EIP197_HIA_xDR_CFG_RD_CACHE(RD_CACHE_3BITS); 5698c2ecf20Sopenharmony_ci val |= EIP197_HIA_xDR_WR_RES_BUF | EIP197_HIA_xDR_WR_CTRL_BUF; 5708c2ecf20Sopenharmony_ci writel(val, 5718c2ecf20Sopenharmony_ci EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_DMA_CFG); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* clear any pending interrupt */ 5748c2ecf20Sopenharmony_ci writel(GENMASK(7, 0), 5758c2ecf20Sopenharmony_ci EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_STAT); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci /* enable ring interrupt */ 5788c2ecf20Sopenharmony_ci val = readl(EIP197_HIA_AIC_R(priv) + EIP197_HIA_AIC_R_ENABLE_CTRL(i)); 5798c2ecf20Sopenharmony_ci val |= EIP197_RDR_IRQ(i); 5808c2ecf20Sopenharmony_ci writel(val, EIP197_HIA_AIC_R(priv) + EIP197_HIA_AIC_R_ENABLE_CTRL(i)); 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci return 0; 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cistatic int safexcel_hw_init(struct safexcel_crypto_priv *priv) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci u32 val; 5898c2ecf20Sopenharmony_ci int i, ret, pe, opbuflo, opbufhi; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci dev_dbg(priv->dev, "HW init: using %d pipe(s) and %d ring(s)\n", 5928c2ecf20Sopenharmony_ci priv->config.pes, priv->config.rings); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci /* 5958c2ecf20Sopenharmony_ci * For EIP197's only set maximum number of TX commands to 2^5 = 32 5968c2ecf20Sopenharmony_ci * Skip for the EIP97 as it does not have this field. 5978c2ecf20Sopenharmony_ci */ 5988c2ecf20Sopenharmony_ci if (priv->flags & SAFEXCEL_HW_EIP197) { 5998c2ecf20Sopenharmony_ci val = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL); 6008c2ecf20Sopenharmony_ci val |= EIP197_MST_CTRL_TX_MAX_CMD(5); 6018c2ecf20Sopenharmony_ci writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL); 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci /* Configure wr/rd cache values */ 6058c2ecf20Sopenharmony_ci writel(EIP197_MST_CTRL_RD_CACHE(RD_CACHE_4BITS) | 6068c2ecf20Sopenharmony_ci EIP197_MST_CTRL_WD_CACHE(WR_CACHE_4BITS), 6078c2ecf20Sopenharmony_ci EIP197_HIA_GEN_CFG(priv) + EIP197_MST_CTRL); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci /* Interrupts reset */ 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci /* Disable all global interrupts */ 6128c2ecf20Sopenharmony_ci writel(0, EIP197_HIA_AIC_G(priv) + EIP197_HIA_AIC_G_ENABLE_CTRL); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci /* Clear any pending interrupt */ 6158c2ecf20Sopenharmony_ci writel(GENMASK(31, 0), EIP197_HIA_AIC_G(priv) + EIP197_HIA_AIC_G_ACK); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci /* Processing Engine configuration */ 6188c2ecf20Sopenharmony_ci for (pe = 0; pe < priv->config.pes; pe++) { 6198c2ecf20Sopenharmony_ci /* Data Fetch Engine configuration */ 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci /* Reset all DFE threads */ 6228c2ecf20Sopenharmony_ci writel(EIP197_DxE_THR_CTRL_RESET_PE, 6238c2ecf20Sopenharmony_ci EIP197_HIA_DFE_THR(priv) + EIP197_HIA_DFE_THR_CTRL(pe)); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if (priv->flags & EIP197_PE_ARB) 6268c2ecf20Sopenharmony_ci /* Reset HIA input interface arbiter (if present) */ 6278c2ecf20Sopenharmony_ci writel(EIP197_HIA_RA_PE_CTRL_RESET, 6288c2ecf20Sopenharmony_ci EIP197_HIA_AIC(priv) + EIP197_HIA_RA_PE_CTRL(pe)); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci /* DMA transfer size to use */ 6318c2ecf20Sopenharmony_ci val = EIP197_HIA_DFE_CFG_DIS_DEBUG; 6328c2ecf20Sopenharmony_ci val |= EIP197_HIA_DxE_CFG_MIN_DATA_SIZE(6) | 6338c2ecf20Sopenharmony_ci EIP197_HIA_DxE_CFG_MAX_DATA_SIZE(9); 6348c2ecf20Sopenharmony_ci val |= EIP197_HIA_DxE_CFG_MIN_CTRL_SIZE(6) | 6358c2ecf20Sopenharmony_ci EIP197_HIA_DxE_CFG_MAX_CTRL_SIZE(7); 6368c2ecf20Sopenharmony_ci val |= EIP197_HIA_DxE_CFG_DATA_CACHE_CTRL(RD_CACHE_3BITS); 6378c2ecf20Sopenharmony_ci val |= EIP197_HIA_DxE_CFG_CTRL_CACHE_CTRL(RD_CACHE_3BITS); 6388c2ecf20Sopenharmony_ci writel(val, EIP197_HIA_DFE(priv) + EIP197_HIA_DFE_CFG(pe)); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci /* Leave the DFE threads reset state */ 6418c2ecf20Sopenharmony_ci writel(0, EIP197_HIA_DFE_THR(priv) + EIP197_HIA_DFE_THR_CTRL(pe)); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci /* Configure the processing engine thresholds */ 6448c2ecf20Sopenharmony_ci writel(EIP197_PE_IN_xBUF_THRES_MIN(6) | 6458c2ecf20Sopenharmony_ci EIP197_PE_IN_xBUF_THRES_MAX(9), 6468c2ecf20Sopenharmony_ci EIP197_PE(priv) + EIP197_PE_IN_DBUF_THRES(pe)); 6478c2ecf20Sopenharmony_ci writel(EIP197_PE_IN_xBUF_THRES_MIN(6) | 6488c2ecf20Sopenharmony_ci EIP197_PE_IN_xBUF_THRES_MAX(7), 6498c2ecf20Sopenharmony_ci EIP197_PE(priv) + EIP197_PE_IN_TBUF_THRES(pe)); 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci if (priv->flags & SAFEXCEL_HW_EIP197) 6528c2ecf20Sopenharmony_ci /* enable HIA input interface arbiter and rings */ 6538c2ecf20Sopenharmony_ci writel(EIP197_HIA_RA_PE_CTRL_EN | 6548c2ecf20Sopenharmony_ci GENMASK(priv->config.rings - 1, 0), 6558c2ecf20Sopenharmony_ci EIP197_HIA_AIC(priv) + EIP197_HIA_RA_PE_CTRL(pe)); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci /* Data Store Engine configuration */ 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* Reset all DSE threads */ 6608c2ecf20Sopenharmony_ci writel(EIP197_DxE_THR_CTRL_RESET_PE, 6618c2ecf20Sopenharmony_ci EIP197_HIA_DSE_THR(priv) + EIP197_HIA_DSE_THR_CTRL(pe)); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci /* Wait for all DSE threads to complete */ 6648c2ecf20Sopenharmony_ci while ((readl(EIP197_HIA_DSE_THR(priv) + EIP197_HIA_DSE_THR_STAT(pe)) & 6658c2ecf20Sopenharmony_ci GENMASK(15, 12)) != GENMASK(15, 12)) 6668c2ecf20Sopenharmony_ci ; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci /* DMA transfer size to use */ 6698c2ecf20Sopenharmony_ci if (priv->hwconfig.hwnumpes > 4) { 6708c2ecf20Sopenharmony_ci opbuflo = 9; 6718c2ecf20Sopenharmony_ci opbufhi = 10; 6728c2ecf20Sopenharmony_ci } else { 6738c2ecf20Sopenharmony_ci opbuflo = 7; 6748c2ecf20Sopenharmony_ci opbufhi = 8; 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci val = EIP197_HIA_DSE_CFG_DIS_DEBUG; 6778c2ecf20Sopenharmony_ci val |= EIP197_HIA_DxE_CFG_MIN_DATA_SIZE(opbuflo) | 6788c2ecf20Sopenharmony_ci EIP197_HIA_DxE_CFG_MAX_DATA_SIZE(opbufhi); 6798c2ecf20Sopenharmony_ci val |= EIP197_HIA_DxE_CFG_DATA_CACHE_CTRL(WR_CACHE_3BITS); 6808c2ecf20Sopenharmony_ci val |= EIP197_HIA_DSE_CFG_ALWAYS_BUFFERABLE; 6818c2ecf20Sopenharmony_ci /* FIXME: instability issues can occur for EIP97 but disabling 6828c2ecf20Sopenharmony_ci * it impacts performance. 6838c2ecf20Sopenharmony_ci */ 6848c2ecf20Sopenharmony_ci if (priv->flags & SAFEXCEL_HW_EIP197) 6858c2ecf20Sopenharmony_ci val |= EIP197_HIA_DSE_CFG_EN_SINGLE_WR; 6868c2ecf20Sopenharmony_ci writel(val, EIP197_HIA_DSE(priv) + EIP197_HIA_DSE_CFG(pe)); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci /* Leave the DSE threads reset state */ 6898c2ecf20Sopenharmony_ci writel(0, EIP197_HIA_DSE_THR(priv) + EIP197_HIA_DSE_THR_CTRL(pe)); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci /* Configure the procesing engine thresholds */ 6928c2ecf20Sopenharmony_ci writel(EIP197_PE_OUT_DBUF_THRES_MIN(opbuflo) | 6938c2ecf20Sopenharmony_ci EIP197_PE_OUT_DBUF_THRES_MAX(opbufhi), 6948c2ecf20Sopenharmony_ci EIP197_PE(priv) + EIP197_PE_OUT_DBUF_THRES(pe)); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci /* Processing Engine configuration */ 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci /* Token & context configuration */ 6998c2ecf20Sopenharmony_ci val = EIP197_PE_EIP96_TOKEN_CTRL_CTX_UPDATES | 7008c2ecf20Sopenharmony_ci EIP197_PE_EIP96_TOKEN_CTRL_NO_TOKEN_WAIT | 7018c2ecf20Sopenharmony_ci EIP197_PE_EIP96_TOKEN_CTRL_ENABLE_TIMEOUT; 7028c2ecf20Sopenharmony_ci writel(val, EIP197_PE(priv) + EIP197_PE_EIP96_TOKEN_CTRL(pe)); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci /* H/W capabilities selection: just enable everything */ 7058c2ecf20Sopenharmony_ci writel(EIP197_FUNCTION_ALL, 7068c2ecf20Sopenharmony_ci EIP197_PE(priv) + EIP197_PE_EIP96_FUNCTION_EN(pe)); 7078c2ecf20Sopenharmony_ci writel(EIP197_FUNCTION_ALL, 7088c2ecf20Sopenharmony_ci EIP197_PE(priv) + EIP197_PE_EIP96_FUNCTION2_EN(pe)); 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci /* Command Descriptor Rings prepare */ 7128c2ecf20Sopenharmony_ci for (i = 0; i < priv->config.rings; i++) { 7138c2ecf20Sopenharmony_ci /* Clear interrupts for this ring */ 7148c2ecf20Sopenharmony_ci writel(GENMASK(31, 0), 7158c2ecf20Sopenharmony_ci EIP197_HIA_AIC_R(priv) + EIP197_HIA_AIC_R_ENABLE_CLR(i)); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci /* Disable external triggering */ 7188c2ecf20Sopenharmony_ci writel(0, EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_CFG); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci /* Clear the pending prepared counter */ 7218c2ecf20Sopenharmony_ci writel(EIP197_xDR_PREP_CLR_COUNT, 7228c2ecf20Sopenharmony_ci EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_PREP_COUNT); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci /* Clear the pending processed counter */ 7258c2ecf20Sopenharmony_ci writel(EIP197_xDR_PROC_CLR_COUNT, 7268c2ecf20Sopenharmony_ci EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_PROC_COUNT); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci writel(0, 7298c2ecf20Sopenharmony_ci EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_PREP_PNTR); 7308c2ecf20Sopenharmony_ci writel(0, 7318c2ecf20Sopenharmony_ci EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_PROC_PNTR); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci writel((EIP197_DEFAULT_RING_SIZE * priv->config.cd_offset), 7348c2ecf20Sopenharmony_ci EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_RING_SIZE); 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci /* Result Descriptor Ring prepare */ 7388c2ecf20Sopenharmony_ci for (i = 0; i < priv->config.rings; i++) { 7398c2ecf20Sopenharmony_ci /* Disable external triggering*/ 7408c2ecf20Sopenharmony_ci writel(0, EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_CFG); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci /* Clear the pending prepared counter */ 7438c2ecf20Sopenharmony_ci writel(EIP197_xDR_PREP_CLR_COUNT, 7448c2ecf20Sopenharmony_ci EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_PREP_COUNT); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci /* Clear the pending processed counter */ 7478c2ecf20Sopenharmony_ci writel(EIP197_xDR_PROC_CLR_COUNT, 7488c2ecf20Sopenharmony_ci EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_PROC_COUNT); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci writel(0, 7518c2ecf20Sopenharmony_ci EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_PREP_PNTR); 7528c2ecf20Sopenharmony_ci writel(0, 7538c2ecf20Sopenharmony_ci EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_PROC_PNTR); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci /* Ring size */ 7568c2ecf20Sopenharmony_ci writel((EIP197_DEFAULT_RING_SIZE * priv->config.rd_offset), 7578c2ecf20Sopenharmony_ci EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_RING_SIZE); 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci for (pe = 0; pe < priv->config.pes; pe++) { 7618c2ecf20Sopenharmony_ci /* Enable command descriptor rings */ 7628c2ecf20Sopenharmony_ci writel(EIP197_DxE_THR_CTRL_EN | GENMASK(priv->config.rings - 1, 0), 7638c2ecf20Sopenharmony_ci EIP197_HIA_DFE_THR(priv) + EIP197_HIA_DFE_THR_CTRL(pe)); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci /* Enable result descriptor rings */ 7668c2ecf20Sopenharmony_ci writel(EIP197_DxE_THR_CTRL_EN | GENMASK(priv->config.rings - 1, 0), 7678c2ecf20Sopenharmony_ci EIP197_HIA_DSE_THR(priv) + EIP197_HIA_DSE_THR_CTRL(pe)); 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci /* Clear any HIA interrupt */ 7718c2ecf20Sopenharmony_ci writel(GENMASK(30, 20), EIP197_HIA_AIC_G(priv) + EIP197_HIA_AIC_G_ACK); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci if (priv->flags & EIP197_SIMPLE_TRC) { 7748c2ecf20Sopenharmony_ci writel(EIP197_STRC_CONFIG_INIT | 7758c2ecf20Sopenharmony_ci EIP197_STRC_CONFIG_LARGE_REC(EIP197_CS_TRC_REC_WC) | 7768c2ecf20Sopenharmony_ci EIP197_STRC_CONFIG_SMALL_REC(EIP197_CS_TRC_REC_WC), 7778c2ecf20Sopenharmony_ci priv->base + EIP197_STRC_CONFIG); 7788c2ecf20Sopenharmony_ci writel(EIP197_PE_EIP96_TOKEN_CTRL2_CTX_DONE, 7798c2ecf20Sopenharmony_ci EIP197_PE(priv) + EIP197_PE_EIP96_TOKEN_CTRL2(0)); 7808c2ecf20Sopenharmony_ci } else if (priv->flags & SAFEXCEL_HW_EIP197) { 7818c2ecf20Sopenharmony_ci ret = eip197_trc_cache_init(priv); 7828c2ecf20Sopenharmony_ci if (ret) 7838c2ecf20Sopenharmony_ci return ret; 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci if (priv->flags & EIP197_ICE) { 7878c2ecf20Sopenharmony_ci ret = eip197_load_firmwares(priv); 7888c2ecf20Sopenharmony_ci if (ret) 7898c2ecf20Sopenharmony_ci return ret; 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci return safexcel_hw_setup_cdesc_rings(priv) ?: 7938c2ecf20Sopenharmony_ci safexcel_hw_setup_rdesc_rings(priv) ?: 7948c2ecf20Sopenharmony_ci 0; 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci/* Called with ring's lock taken */ 7988c2ecf20Sopenharmony_cistatic void safexcel_try_push_requests(struct safexcel_crypto_priv *priv, 7998c2ecf20Sopenharmony_ci int ring) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci int coal = min_t(int, priv->ring[ring].requests, EIP197_MAX_BATCH_SZ); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci if (!coal) 8048c2ecf20Sopenharmony_ci return; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci /* Configure when we want an interrupt */ 8078c2ecf20Sopenharmony_ci writel(EIP197_HIA_RDR_THRESH_PKT_MODE | 8088c2ecf20Sopenharmony_ci EIP197_HIA_RDR_THRESH_PROC_PKT(coal), 8098c2ecf20Sopenharmony_ci EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_THRESH); 8108c2ecf20Sopenharmony_ci} 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_civoid safexcel_dequeue(struct safexcel_crypto_priv *priv, int ring) 8138c2ecf20Sopenharmony_ci{ 8148c2ecf20Sopenharmony_ci struct crypto_async_request *req, *backlog; 8158c2ecf20Sopenharmony_ci struct safexcel_context *ctx; 8168c2ecf20Sopenharmony_ci int ret, nreq = 0, cdesc = 0, rdesc = 0, commands, results; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci /* If a request wasn't properly dequeued because of a lack of resources, 8198c2ecf20Sopenharmony_ci * proceeded it first, 8208c2ecf20Sopenharmony_ci */ 8218c2ecf20Sopenharmony_ci req = priv->ring[ring].req; 8228c2ecf20Sopenharmony_ci backlog = priv->ring[ring].backlog; 8238c2ecf20Sopenharmony_ci if (req) 8248c2ecf20Sopenharmony_ci goto handle_req; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci while (true) { 8278c2ecf20Sopenharmony_ci spin_lock_bh(&priv->ring[ring].queue_lock); 8288c2ecf20Sopenharmony_ci backlog = crypto_get_backlog(&priv->ring[ring].queue); 8298c2ecf20Sopenharmony_ci req = crypto_dequeue_request(&priv->ring[ring].queue); 8308c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->ring[ring].queue_lock); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci if (!req) { 8338c2ecf20Sopenharmony_ci priv->ring[ring].req = NULL; 8348c2ecf20Sopenharmony_ci priv->ring[ring].backlog = NULL; 8358c2ecf20Sopenharmony_ci goto finalize; 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_cihandle_req: 8398c2ecf20Sopenharmony_ci ctx = crypto_tfm_ctx(req->tfm); 8408c2ecf20Sopenharmony_ci ret = ctx->send(req, ring, &commands, &results); 8418c2ecf20Sopenharmony_ci if (ret) 8428c2ecf20Sopenharmony_ci goto request_failed; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci if (backlog) 8458c2ecf20Sopenharmony_ci backlog->complete(backlog, -EINPROGRESS); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci /* In case the send() helper did not issue any command to push 8488c2ecf20Sopenharmony_ci * to the engine because the input data was cached, continue to 8498c2ecf20Sopenharmony_ci * dequeue other requests as this is valid and not an error. 8508c2ecf20Sopenharmony_ci */ 8518c2ecf20Sopenharmony_ci if (!commands && !results) 8528c2ecf20Sopenharmony_ci continue; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci cdesc += commands; 8558c2ecf20Sopenharmony_ci rdesc += results; 8568c2ecf20Sopenharmony_ci nreq++; 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_cirequest_failed: 8608c2ecf20Sopenharmony_ci /* Not enough resources to handle all the requests. Bail out and save 8618c2ecf20Sopenharmony_ci * the request and the backlog for the next dequeue call (per-ring). 8628c2ecf20Sopenharmony_ci */ 8638c2ecf20Sopenharmony_ci priv->ring[ring].req = req; 8648c2ecf20Sopenharmony_ci priv->ring[ring].backlog = backlog; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_cifinalize: 8678c2ecf20Sopenharmony_ci if (!nreq) 8688c2ecf20Sopenharmony_ci return; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci spin_lock_bh(&priv->ring[ring].lock); 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci priv->ring[ring].requests += nreq; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci if (!priv->ring[ring].busy) { 8758c2ecf20Sopenharmony_ci safexcel_try_push_requests(priv, ring); 8768c2ecf20Sopenharmony_ci priv->ring[ring].busy = true; 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->ring[ring].lock); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci /* let the RDR know we have pending descriptors */ 8828c2ecf20Sopenharmony_ci writel((rdesc * priv->config.rd_offset), 8838c2ecf20Sopenharmony_ci EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_PREP_COUNT); 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci /* let the CDR know we have pending descriptors */ 8868c2ecf20Sopenharmony_ci writel((cdesc * priv->config.cd_offset), 8878c2ecf20Sopenharmony_ci EIP197_HIA_CDR(priv, ring) + EIP197_HIA_xDR_PREP_COUNT); 8888c2ecf20Sopenharmony_ci} 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ciinline int safexcel_rdesc_check_errors(struct safexcel_crypto_priv *priv, 8918c2ecf20Sopenharmony_ci void *rdp) 8928c2ecf20Sopenharmony_ci{ 8938c2ecf20Sopenharmony_ci struct safexcel_result_desc *rdesc = rdp; 8948c2ecf20Sopenharmony_ci struct result_data_desc *result_data = rdp + priv->config.res_offset; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci if (likely((!rdesc->last_seg) || /* Rest only valid if last seg! */ 8978c2ecf20Sopenharmony_ci ((!rdesc->descriptor_overflow) && 8988c2ecf20Sopenharmony_ci (!rdesc->buffer_overflow) && 8998c2ecf20Sopenharmony_ci (!result_data->error_code)))) 9008c2ecf20Sopenharmony_ci return 0; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci if (rdesc->descriptor_overflow) 9038c2ecf20Sopenharmony_ci dev_err(priv->dev, "Descriptor overflow detected"); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci if (rdesc->buffer_overflow) 9068c2ecf20Sopenharmony_ci dev_err(priv->dev, "Buffer overflow detected"); 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci if (result_data->error_code & 0x4066) { 9098c2ecf20Sopenharmony_ci /* Fatal error (bits 1,2,5,6 & 14) */ 9108c2ecf20Sopenharmony_ci dev_err(priv->dev, 9118c2ecf20Sopenharmony_ci "result descriptor error (%x)", 9128c2ecf20Sopenharmony_ci result_data->error_code); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci return -EIO; 9158c2ecf20Sopenharmony_ci } else if (result_data->error_code & 9168c2ecf20Sopenharmony_ci (BIT(7) | BIT(4) | BIT(3) | BIT(0))) { 9178c2ecf20Sopenharmony_ci /* 9188c2ecf20Sopenharmony_ci * Give priority over authentication fails: 9198c2ecf20Sopenharmony_ci * Blocksize, length & overflow errors, 9208c2ecf20Sopenharmony_ci * something wrong with the input! 9218c2ecf20Sopenharmony_ci */ 9228c2ecf20Sopenharmony_ci return -EINVAL; 9238c2ecf20Sopenharmony_ci } else if (result_data->error_code & BIT(9)) { 9248c2ecf20Sopenharmony_ci /* Authentication failed */ 9258c2ecf20Sopenharmony_ci return -EBADMSG; 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci /* All other non-fatal errors */ 9298c2ecf20Sopenharmony_ci return -EINVAL; 9308c2ecf20Sopenharmony_ci} 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ciinline void safexcel_rdr_req_set(struct safexcel_crypto_priv *priv, 9338c2ecf20Sopenharmony_ci int ring, 9348c2ecf20Sopenharmony_ci struct safexcel_result_desc *rdesc, 9358c2ecf20Sopenharmony_ci struct crypto_async_request *req) 9368c2ecf20Sopenharmony_ci{ 9378c2ecf20Sopenharmony_ci int i = safexcel_ring_rdr_rdesc_index(priv, ring, rdesc); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci priv->ring[ring].rdr_req[i] = req; 9408c2ecf20Sopenharmony_ci} 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ciinline struct crypto_async_request * 9438c2ecf20Sopenharmony_cisafexcel_rdr_req_get(struct safexcel_crypto_priv *priv, int ring) 9448c2ecf20Sopenharmony_ci{ 9458c2ecf20Sopenharmony_ci int i = safexcel_ring_first_rdr_index(priv, ring); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci return priv->ring[ring].rdr_req[i]; 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_civoid safexcel_complete(struct safexcel_crypto_priv *priv, int ring) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci struct safexcel_command_desc *cdesc; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci /* Acknowledge the command descriptors */ 9558c2ecf20Sopenharmony_ci do { 9568c2ecf20Sopenharmony_ci cdesc = safexcel_ring_next_rptr(priv, &priv->ring[ring].cdr); 9578c2ecf20Sopenharmony_ci if (IS_ERR(cdesc)) { 9588c2ecf20Sopenharmony_ci dev_err(priv->dev, 9598c2ecf20Sopenharmony_ci "Could not retrieve the command descriptor\n"); 9608c2ecf20Sopenharmony_ci return; 9618c2ecf20Sopenharmony_ci } 9628c2ecf20Sopenharmony_ci } while (!cdesc->last_seg); 9638c2ecf20Sopenharmony_ci} 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_civoid safexcel_inv_complete(struct crypto_async_request *req, int error) 9668c2ecf20Sopenharmony_ci{ 9678c2ecf20Sopenharmony_ci struct safexcel_inv_result *result = req->data; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci if (error == -EINPROGRESS) 9708c2ecf20Sopenharmony_ci return; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci result->error = error; 9738c2ecf20Sopenharmony_ci complete(&result->completion); 9748c2ecf20Sopenharmony_ci} 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ciint safexcel_invalidate_cache(struct crypto_async_request *async, 9778c2ecf20Sopenharmony_ci struct safexcel_crypto_priv *priv, 9788c2ecf20Sopenharmony_ci dma_addr_t ctxr_dma, int ring) 9798c2ecf20Sopenharmony_ci{ 9808c2ecf20Sopenharmony_ci struct safexcel_command_desc *cdesc; 9818c2ecf20Sopenharmony_ci struct safexcel_result_desc *rdesc; 9828c2ecf20Sopenharmony_ci struct safexcel_token *dmmy; 9838c2ecf20Sopenharmony_ci int ret = 0; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci /* Prepare command descriptor */ 9868c2ecf20Sopenharmony_ci cdesc = safexcel_add_cdesc(priv, ring, true, true, 0, 0, 0, ctxr_dma, 9878c2ecf20Sopenharmony_ci &dmmy); 9888c2ecf20Sopenharmony_ci if (IS_ERR(cdesc)) 9898c2ecf20Sopenharmony_ci return PTR_ERR(cdesc); 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci cdesc->control_data.type = EIP197_TYPE_EXTENDED; 9928c2ecf20Sopenharmony_ci cdesc->control_data.options = 0; 9938c2ecf20Sopenharmony_ci cdesc->control_data.context_lo &= ~EIP197_CONTEXT_SIZE_MASK; 9948c2ecf20Sopenharmony_ci cdesc->control_data.control0 = CONTEXT_CONTROL_INV_TR; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci /* Prepare result descriptor */ 9978c2ecf20Sopenharmony_ci rdesc = safexcel_add_rdesc(priv, ring, true, true, 0, 0); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci if (IS_ERR(rdesc)) { 10008c2ecf20Sopenharmony_ci ret = PTR_ERR(rdesc); 10018c2ecf20Sopenharmony_ci goto cdesc_rollback; 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci safexcel_rdr_req_set(priv, ring, rdesc, async); 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci return ret; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_cicdesc_rollback: 10098c2ecf20Sopenharmony_ci safexcel_ring_rollback_wptr(priv, &priv->ring[ring].cdr); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci return ret; 10128c2ecf20Sopenharmony_ci} 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_cistatic inline void safexcel_handle_result_descriptor(struct safexcel_crypto_priv *priv, 10158c2ecf20Sopenharmony_ci int ring) 10168c2ecf20Sopenharmony_ci{ 10178c2ecf20Sopenharmony_ci struct crypto_async_request *req; 10188c2ecf20Sopenharmony_ci struct safexcel_context *ctx; 10198c2ecf20Sopenharmony_ci int ret, i, nreq, ndesc, tot_descs, handled = 0; 10208c2ecf20Sopenharmony_ci bool should_complete; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_cihandle_results: 10238c2ecf20Sopenharmony_ci tot_descs = 0; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci nreq = readl(EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_PROC_COUNT); 10268c2ecf20Sopenharmony_ci nreq >>= EIP197_xDR_PROC_xD_PKT_OFFSET; 10278c2ecf20Sopenharmony_ci nreq &= EIP197_xDR_PROC_xD_PKT_MASK; 10288c2ecf20Sopenharmony_ci if (!nreq) 10298c2ecf20Sopenharmony_ci goto requests_left; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci for (i = 0; i < nreq; i++) { 10328c2ecf20Sopenharmony_ci req = safexcel_rdr_req_get(priv, ring); 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci ctx = crypto_tfm_ctx(req->tfm); 10358c2ecf20Sopenharmony_ci ndesc = ctx->handle_result(priv, ring, req, 10368c2ecf20Sopenharmony_ci &should_complete, &ret); 10378c2ecf20Sopenharmony_ci if (ndesc < 0) { 10388c2ecf20Sopenharmony_ci dev_err(priv->dev, "failed to handle result (%d)\n", 10398c2ecf20Sopenharmony_ci ndesc); 10408c2ecf20Sopenharmony_ci goto acknowledge; 10418c2ecf20Sopenharmony_ci } 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci if (should_complete) { 10448c2ecf20Sopenharmony_ci local_bh_disable(); 10458c2ecf20Sopenharmony_ci req->complete(req, ret); 10468c2ecf20Sopenharmony_ci local_bh_enable(); 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci tot_descs += ndesc; 10508c2ecf20Sopenharmony_ci handled++; 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ciacknowledge: 10548c2ecf20Sopenharmony_ci if (i) 10558c2ecf20Sopenharmony_ci writel(EIP197_xDR_PROC_xD_PKT(i) | 10568c2ecf20Sopenharmony_ci (tot_descs * priv->config.rd_offset), 10578c2ecf20Sopenharmony_ci EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_PROC_COUNT); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci /* If the number of requests overflowed the counter, try to proceed more 10608c2ecf20Sopenharmony_ci * requests. 10618c2ecf20Sopenharmony_ci */ 10628c2ecf20Sopenharmony_ci if (nreq == EIP197_xDR_PROC_xD_PKT_MASK) 10638c2ecf20Sopenharmony_ci goto handle_results; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_cirequests_left: 10668c2ecf20Sopenharmony_ci spin_lock_bh(&priv->ring[ring].lock); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci priv->ring[ring].requests -= handled; 10698c2ecf20Sopenharmony_ci safexcel_try_push_requests(priv, ring); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci if (!priv->ring[ring].requests) 10728c2ecf20Sopenharmony_ci priv->ring[ring].busy = false; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->ring[ring].lock); 10758c2ecf20Sopenharmony_ci} 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_cistatic void safexcel_dequeue_work(struct work_struct *work) 10788c2ecf20Sopenharmony_ci{ 10798c2ecf20Sopenharmony_ci struct safexcel_work_data *data = 10808c2ecf20Sopenharmony_ci container_of(work, struct safexcel_work_data, work); 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci safexcel_dequeue(data->priv, data->ring); 10838c2ecf20Sopenharmony_ci} 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_cistruct safexcel_ring_irq_data { 10868c2ecf20Sopenharmony_ci struct safexcel_crypto_priv *priv; 10878c2ecf20Sopenharmony_ci int ring; 10888c2ecf20Sopenharmony_ci}; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_cistatic irqreturn_t safexcel_irq_ring(int irq, void *data) 10918c2ecf20Sopenharmony_ci{ 10928c2ecf20Sopenharmony_ci struct safexcel_ring_irq_data *irq_data = data; 10938c2ecf20Sopenharmony_ci struct safexcel_crypto_priv *priv = irq_data->priv; 10948c2ecf20Sopenharmony_ci int ring = irq_data->ring, rc = IRQ_NONE; 10958c2ecf20Sopenharmony_ci u32 status, stat; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci status = readl(EIP197_HIA_AIC_R(priv) + EIP197_HIA_AIC_R_ENABLED_STAT(ring)); 10988c2ecf20Sopenharmony_ci if (!status) 10998c2ecf20Sopenharmony_ci return rc; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci /* RDR interrupts */ 11028c2ecf20Sopenharmony_ci if (status & EIP197_RDR_IRQ(ring)) { 11038c2ecf20Sopenharmony_ci stat = readl(EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_STAT); 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci if (unlikely(stat & EIP197_xDR_ERR)) { 11068c2ecf20Sopenharmony_ci /* 11078c2ecf20Sopenharmony_ci * Fatal error, the RDR is unusable and must be 11088c2ecf20Sopenharmony_ci * reinitialized. This should not happen under 11098c2ecf20Sopenharmony_ci * normal circumstances. 11108c2ecf20Sopenharmony_ci */ 11118c2ecf20Sopenharmony_ci dev_err(priv->dev, "RDR: fatal error.\n"); 11128c2ecf20Sopenharmony_ci } else if (likely(stat & EIP197_xDR_THRESH)) { 11138c2ecf20Sopenharmony_ci rc = IRQ_WAKE_THREAD; 11148c2ecf20Sopenharmony_ci } 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci /* ACK the interrupts */ 11178c2ecf20Sopenharmony_ci writel(stat & 0xff, 11188c2ecf20Sopenharmony_ci EIP197_HIA_RDR(priv, ring) + EIP197_HIA_xDR_STAT); 11198c2ecf20Sopenharmony_ci } 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci /* ACK the interrupts */ 11228c2ecf20Sopenharmony_ci writel(status, EIP197_HIA_AIC_R(priv) + EIP197_HIA_AIC_R_ACK(ring)); 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci return rc; 11258c2ecf20Sopenharmony_ci} 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_cistatic irqreturn_t safexcel_irq_ring_thread(int irq, void *data) 11288c2ecf20Sopenharmony_ci{ 11298c2ecf20Sopenharmony_ci struct safexcel_ring_irq_data *irq_data = data; 11308c2ecf20Sopenharmony_ci struct safexcel_crypto_priv *priv = irq_data->priv; 11318c2ecf20Sopenharmony_ci int ring = irq_data->ring; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci safexcel_handle_result_descriptor(priv, ring); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci queue_work(priv->ring[ring].workqueue, 11368c2ecf20Sopenharmony_ci &priv->ring[ring].work_data.work); 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci return IRQ_HANDLED; 11398c2ecf20Sopenharmony_ci} 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_cistatic int safexcel_request_ring_irq(void *pdev, int irqid, 11428c2ecf20Sopenharmony_ci int is_pci_dev, 11438c2ecf20Sopenharmony_ci int ring_id, 11448c2ecf20Sopenharmony_ci irq_handler_t handler, 11458c2ecf20Sopenharmony_ci irq_handler_t threaded_handler, 11468c2ecf20Sopenharmony_ci struct safexcel_ring_irq_data *ring_irq_priv) 11478c2ecf20Sopenharmony_ci{ 11488c2ecf20Sopenharmony_ci int ret, irq, cpu; 11498c2ecf20Sopenharmony_ci struct device *dev; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PCI) && is_pci_dev) { 11528c2ecf20Sopenharmony_ci struct pci_dev *pci_pdev = pdev; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci dev = &pci_pdev->dev; 11558c2ecf20Sopenharmony_ci irq = pci_irq_vector(pci_pdev, irqid); 11568c2ecf20Sopenharmony_ci if (irq < 0) { 11578c2ecf20Sopenharmony_ci dev_err(dev, "unable to get device MSI IRQ %d (err %d)\n", 11588c2ecf20Sopenharmony_ci irqid, irq); 11598c2ecf20Sopenharmony_ci return irq; 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci } else if (IS_ENABLED(CONFIG_OF)) { 11628c2ecf20Sopenharmony_ci struct platform_device *plf_pdev = pdev; 11638c2ecf20Sopenharmony_ci char irq_name[6] = {0}; /* "ringX\0" */ 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci snprintf(irq_name, 6, "ring%d", irqid); 11668c2ecf20Sopenharmony_ci dev = &plf_pdev->dev; 11678c2ecf20Sopenharmony_ci irq = platform_get_irq_byname(plf_pdev, irq_name); 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci if (irq < 0) { 11708c2ecf20Sopenharmony_ci dev_err(dev, "unable to get IRQ '%s' (err %d)\n", 11718c2ecf20Sopenharmony_ci irq_name, irq); 11728c2ecf20Sopenharmony_ci return irq; 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_ci } else { 11758c2ecf20Sopenharmony_ci return -ENXIO; 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(dev, irq, handler, 11798c2ecf20Sopenharmony_ci threaded_handler, IRQF_ONESHOT, 11808c2ecf20Sopenharmony_ci dev_name(dev), ring_irq_priv); 11818c2ecf20Sopenharmony_ci if (ret) { 11828c2ecf20Sopenharmony_ci dev_err(dev, "unable to request IRQ %d\n", irq); 11838c2ecf20Sopenharmony_ci return ret; 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci /* Set affinity */ 11878c2ecf20Sopenharmony_ci cpu = cpumask_local_spread(ring_id, NUMA_NO_NODE); 11888c2ecf20Sopenharmony_ci irq_set_affinity_hint(irq, get_cpu_mask(cpu)); 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci return irq; 11918c2ecf20Sopenharmony_ci} 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_cistatic struct safexcel_alg_template *safexcel_algs[] = { 11948c2ecf20Sopenharmony_ci &safexcel_alg_ecb_des, 11958c2ecf20Sopenharmony_ci &safexcel_alg_cbc_des, 11968c2ecf20Sopenharmony_ci &safexcel_alg_ecb_des3_ede, 11978c2ecf20Sopenharmony_ci &safexcel_alg_cbc_des3_ede, 11988c2ecf20Sopenharmony_ci &safexcel_alg_ecb_aes, 11998c2ecf20Sopenharmony_ci &safexcel_alg_cbc_aes, 12008c2ecf20Sopenharmony_ci &safexcel_alg_cfb_aes, 12018c2ecf20Sopenharmony_ci &safexcel_alg_ofb_aes, 12028c2ecf20Sopenharmony_ci &safexcel_alg_ctr_aes, 12038c2ecf20Sopenharmony_ci &safexcel_alg_md5, 12048c2ecf20Sopenharmony_ci &safexcel_alg_sha1, 12058c2ecf20Sopenharmony_ci &safexcel_alg_sha224, 12068c2ecf20Sopenharmony_ci &safexcel_alg_sha256, 12078c2ecf20Sopenharmony_ci &safexcel_alg_sha384, 12088c2ecf20Sopenharmony_ci &safexcel_alg_sha512, 12098c2ecf20Sopenharmony_ci &safexcel_alg_hmac_md5, 12108c2ecf20Sopenharmony_ci &safexcel_alg_hmac_sha1, 12118c2ecf20Sopenharmony_ci &safexcel_alg_hmac_sha224, 12128c2ecf20Sopenharmony_ci &safexcel_alg_hmac_sha256, 12138c2ecf20Sopenharmony_ci &safexcel_alg_hmac_sha384, 12148c2ecf20Sopenharmony_ci &safexcel_alg_hmac_sha512, 12158c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sha1_cbc_aes, 12168c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sha224_cbc_aes, 12178c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sha256_cbc_aes, 12188c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sha384_cbc_aes, 12198c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sha512_cbc_aes, 12208c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sha1_cbc_des3_ede, 12218c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sha1_ctr_aes, 12228c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sha224_ctr_aes, 12238c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sha256_ctr_aes, 12248c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sha384_ctr_aes, 12258c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sha512_ctr_aes, 12268c2ecf20Sopenharmony_ci &safexcel_alg_xts_aes, 12278c2ecf20Sopenharmony_ci &safexcel_alg_gcm, 12288c2ecf20Sopenharmony_ci &safexcel_alg_ccm, 12298c2ecf20Sopenharmony_ci &safexcel_alg_crc32, 12308c2ecf20Sopenharmony_ci &safexcel_alg_cbcmac, 12318c2ecf20Sopenharmony_ci &safexcel_alg_xcbcmac, 12328c2ecf20Sopenharmony_ci &safexcel_alg_cmac, 12338c2ecf20Sopenharmony_ci &safexcel_alg_chacha20, 12348c2ecf20Sopenharmony_ci &safexcel_alg_chachapoly, 12358c2ecf20Sopenharmony_ci &safexcel_alg_chachapoly_esp, 12368c2ecf20Sopenharmony_ci &safexcel_alg_sm3, 12378c2ecf20Sopenharmony_ci &safexcel_alg_hmac_sm3, 12388c2ecf20Sopenharmony_ci &safexcel_alg_ecb_sm4, 12398c2ecf20Sopenharmony_ci &safexcel_alg_cbc_sm4, 12408c2ecf20Sopenharmony_ci &safexcel_alg_ofb_sm4, 12418c2ecf20Sopenharmony_ci &safexcel_alg_cfb_sm4, 12428c2ecf20Sopenharmony_ci &safexcel_alg_ctr_sm4, 12438c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sha1_cbc_sm4, 12448c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sm3_cbc_sm4, 12458c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sha1_ctr_sm4, 12468c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sm3_ctr_sm4, 12478c2ecf20Sopenharmony_ci &safexcel_alg_sha3_224, 12488c2ecf20Sopenharmony_ci &safexcel_alg_sha3_256, 12498c2ecf20Sopenharmony_ci &safexcel_alg_sha3_384, 12508c2ecf20Sopenharmony_ci &safexcel_alg_sha3_512, 12518c2ecf20Sopenharmony_ci &safexcel_alg_hmac_sha3_224, 12528c2ecf20Sopenharmony_ci &safexcel_alg_hmac_sha3_256, 12538c2ecf20Sopenharmony_ci &safexcel_alg_hmac_sha3_384, 12548c2ecf20Sopenharmony_ci &safexcel_alg_hmac_sha3_512, 12558c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sha1_cbc_des, 12568c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sha256_cbc_des3_ede, 12578c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sha224_cbc_des3_ede, 12588c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sha512_cbc_des3_ede, 12598c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sha384_cbc_des3_ede, 12608c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sha256_cbc_des, 12618c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sha224_cbc_des, 12628c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sha512_cbc_des, 12638c2ecf20Sopenharmony_ci &safexcel_alg_authenc_hmac_sha384_cbc_des, 12648c2ecf20Sopenharmony_ci &safexcel_alg_rfc4106_gcm, 12658c2ecf20Sopenharmony_ci &safexcel_alg_rfc4543_gcm, 12668c2ecf20Sopenharmony_ci &safexcel_alg_rfc4309_ccm, 12678c2ecf20Sopenharmony_ci}; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_cistatic int safexcel_register_algorithms(struct safexcel_crypto_priv *priv) 12708c2ecf20Sopenharmony_ci{ 12718c2ecf20Sopenharmony_ci int i, j, ret = 0; 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(safexcel_algs); i++) { 12748c2ecf20Sopenharmony_ci safexcel_algs[i]->priv = priv; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci /* Do we have all required base algorithms available? */ 12778c2ecf20Sopenharmony_ci if ((safexcel_algs[i]->algo_mask & priv->hwconfig.algo_flags) != 12788c2ecf20Sopenharmony_ci safexcel_algs[i]->algo_mask) 12798c2ecf20Sopenharmony_ci /* No, so don't register this ciphersuite */ 12808c2ecf20Sopenharmony_ci continue; 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci if (safexcel_algs[i]->type == SAFEXCEL_ALG_TYPE_SKCIPHER) 12838c2ecf20Sopenharmony_ci ret = crypto_register_skcipher(&safexcel_algs[i]->alg.skcipher); 12848c2ecf20Sopenharmony_ci else if (safexcel_algs[i]->type == SAFEXCEL_ALG_TYPE_AEAD) 12858c2ecf20Sopenharmony_ci ret = crypto_register_aead(&safexcel_algs[i]->alg.aead); 12868c2ecf20Sopenharmony_ci else 12878c2ecf20Sopenharmony_ci ret = crypto_register_ahash(&safexcel_algs[i]->alg.ahash); 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci if (ret) 12908c2ecf20Sopenharmony_ci goto fail; 12918c2ecf20Sopenharmony_ci } 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci return 0; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_cifail: 12968c2ecf20Sopenharmony_ci for (j = 0; j < i; j++) { 12978c2ecf20Sopenharmony_ci /* Do we have all required base algorithms available? */ 12988c2ecf20Sopenharmony_ci if ((safexcel_algs[j]->algo_mask & priv->hwconfig.algo_flags) != 12998c2ecf20Sopenharmony_ci safexcel_algs[j]->algo_mask) 13008c2ecf20Sopenharmony_ci /* No, so don't unregister this ciphersuite */ 13018c2ecf20Sopenharmony_ci continue; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci if (safexcel_algs[j]->type == SAFEXCEL_ALG_TYPE_SKCIPHER) 13048c2ecf20Sopenharmony_ci crypto_unregister_skcipher(&safexcel_algs[j]->alg.skcipher); 13058c2ecf20Sopenharmony_ci else if (safexcel_algs[j]->type == SAFEXCEL_ALG_TYPE_AEAD) 13068c2ecf20Sopenharmony_ci crypto_unregister_aead(&safexcel_algs[j]->alg.aead); 13078c2ecf20Sopenharmony_ci else 13088c2ecf20Sopenharmony_ci crypto_unregister_ahash(&safexcel_algs[j]->alg.ahash); 13098c2ecf20Sopenharmony_ci } 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci return ret; 13128c2ecf20Sopenharmony_ci} 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_cistatic void safexcel_unregister_algorithms(struct safexcel_crypto_priv *priv) 13158c2ecf20Sopenharmony_ci{ 13168c2ecf20Sopenharmony_ci int i; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(safexcel_algs); i++) { 13198c2ecf20Sopenharmony_ci /* Do we have all required base algorithms available? */ 13208c2ecf20Sopenharmony_ci if ((safexcel_algs[i]->algo_mask & priv->hwconfig.algo_flags) != 13218c2ecf20Sopenharmony_ci safexcel_algs[i]->algo_mask) 13228c2ecf20Sopenharmony_ci /* No, so don't unregister this ciphersuite */ 13238c2ecf20Sopenharmony_ci continue; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci if (safexcel_algs[i]->type == SAFEXCEL_ALG_TYPE_SKCIPHER) 13268c2ecf20Sopenharmony_ci crypto_unregister_skcipher(&safexcel_algs[i]->alg.skcipher); 13278c2ecf20Sopenharmony_ci else if (safexcel_algs[i]->type == SAFEXCEL_ALG_TYPE_AEAD) 13288c2ecf20Sopenharmony_ci crypto_unregister_aead(&safexcel_algs[i]->alg.aead); 13298c2ecf20Sopenharmony_ci else 13308c2ecf20Sopenharmony_ci crypto_unregister_ahash(&safexcel_algs[i]->alg.ahash); 13318c2ecf20Sopenharmony_ci } 13328c2ecf20Sopenharmony_ci} 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_cistatic void safexcel_configure(struct safexcel_crypto_priv *priv) 13358c2ecf20Sopenharmony_ci{ 13368c2ecf20Sopenharmony_ci u32 mask = BIT(priv->hwconfig.hwdataw) - 1; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci priv->config.pes = priv->hwconfig.hwnumpes; 13398c2ecf20Sopenharmony_ci priv->config.rings = min_t(u32, priv->hwconfig.hwnumrings, max_rings); 13408c2ecf20Sopenharmony_ci /* Cannot currently support more rings than we have ring AICs! */ 13418c2ecf20Sopenharmony_ci priv->config.rings = min_t(u32, priv->config.rings, 13428c2ecf20Sopenharmony_ci priv->hwconfig.hwnumraic); 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci priv->config.cd_size = EIP197_CD64_FETCH_SIZE; 13458c2ecf20Sopenharmony_ci priv->config.cd_offset = (priv->config.cd_size + mask) & ~mask; 13468c2ecf20Sopenharmony_ci priv->config.cdsh_offset = (EIP197_MAX_TOKENS + mask) & ~mask; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci /* res token is behind the descr, but ofs must be rounded to buswdth */ 13498c2ecf20Sopenharmony_ci priv->config.res_offset = (EIP197_RD64_FETCH_SIZE + mask) & ~mask; 13508c2ecf20Sopenharmony_ci /* now the size of the descr is this 1st part plus the result struct */ 13518c2ecf20Sopenharmony_ci priv->config.rd_size = priv->config.res_offset + 13528c2ecf20Sopenharmony_ci EIP197_RD64_RESULT_SIZE; 13538c2ecf20Sopenharmony_ci priv->config.rd_offset = (priv->config.rd_size + mask) & ~mask; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci /* convert dwords to bytes */ 13568c2ecf20Sopenharmony_ci priv->config.cd_offset *= sizeof(u32); 13578c2ecf20Sopenharmony_ci priv->config.cdsh_offset *= sizeof(u32); 13588c2ecf20Sopenharmony_ci priv->config.rd_offset *= sizeof(u32); 13598c2ecf20Sopenharmony_ci priv->config.res_offset *= sizeof(u32); 13608c2ecf20Sopenharmony_ci} 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_cistatic void safexcel_init_register_offsets(struct safexcel_crypto_priv *priv) 13638c2ecf20Sopenharmony_ci{ 13648c2ecf20Sopenharmony_ci struct safexcel_register_offsets *offsets = &priv->offsets; 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci if (priv->flags & SAFEXCEL_HW_EIP197) { 13678c2ecf20Sopenharmony_ci offsets->hia_aic = EIP197_HIA_AIC_BASE; 13688c2ecf20Sopenharmony_ci offsets->hia_aic_g = EIP197_HIA_AIC_G_BASE; 13698c2ecf20Sopenharmony_ci offsets->hia_aic_r = EIP197_HIA_AIC_R_BASE; 13708c2ecf20Sopenharmony_ci offsets->hia_aic_xdr = EIP197_HIA_AIC_xDR_BASE; 13718c2ecf20Sopenharmony_ci offsets->hia_dfe = EIP197_HIA_DFE_BASE; 13728c2ecf20Sopenharmony_ci offsets->hia_dfe_thr = EIP197_HIA_DFE_THR_BASE; 13738c2ecf20Sopenharmony_ci offsets->hia_dse = EIP197_HIA_DSE_BASE; 13748c2ecf20Sopenharmony_ci offsets->hia_dse_thr = EIP197_HIA_DSE_THR_BASE; 13758c2ecf20Sopenharmony_ci offsets->hia_gen_cfg = EIP197_HIA_GEN_CFG_BASE; 13768c2ecf20Sopenharmony_ci offsets->pe = EIP197_PE_BASE; 13778c2ecf20Sopenharmony_ci offsets->global = EIP197_GLOBAL_BASE; 13788c2ecf20Sopenharmony_ci } else { 13798c2ecf20Sopenharmony_ci offsets->hia_aic = EIP97_HIA_AIC_BASE; 13808c2ecf20Sopenharmony_ci offsets->hia_aic_g = EIP97_HIA_AIC_G_BASE; 13818c2ecf20Sopenharmony_ci offsets->hia_aic_r = EIP97_HIA_AIC_R_BASE; 13828c2ecf20Sopenharmony_ci offsets->hia_aic_xdr = EIP97_HIA_AIC_xDR_BASE; 13838c2ecf20Sopenharmony_ci offsets->hia_dfe = EIP97_HIA_DFE_BASE; 13848c2ecf20Sopenharmony_ci offsets->hia_dfe_thr = EIP97_HIA_DFE_THR_BASE; 13858c2ecf20Sopenharmony_ci offsets->hia_dse = EIP97_HIA_DSE_BASE; 13868c2ecf20Sopenharmony_ci offsets->hia_dse_thr = EIP97_HIA_DSE_THR_BASE; 13878c2ecf20Sopenharmony_ci offsets->hia_gen_cfg = EIP97_HIA_GEN_CFG_BASE; 13888c2ecf20Sopenharmony_ci offsets->pe = EIP97_PE_BASE; 13898c2ecf20Sopenharmony_ci offsets->global = EIP97_GLOBAL_BASE; 13908c2ecf20Sopenharmony_ci } 13918c2ecf20Sopenharmony_ci} 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci/* 13948c2ecf20Sopenharmony_ci * Generic part of probe routine, shared by platform and PCI driver 13958c2ecf20Sopenharmony_ci * 13968c2ecf20Sopenharmony_ci * Assumes IO resources have been mapped, private data mem has been allocated, 13978c2ecf20Sopenharmony_ci * clocks have been enabled, device pointer has been assigned etc. 13988c2ecf20Sopenharmony_ci * 13998c2ecf20Sopenharmony_ci */ 14008c2ecf20Sopenharmony_cistatic int safexcel_probe_generic(void *pdev, 14018c2ecf20Sopenharmony_ci struct safexcel_crypto_priv *priv, 14028c2ecf20Sopenharmony_ci int is_pci_dev) 14038c2ecf20Sopenharmony_ci{ 14048c2ecf20Sopenharmony_ci struct device *dev = priv->dev; 14058c2ecf20Sopenharmony_ci u32 peid, version, mask, val, hiaopt, hwopt, peopt; 14068c2ecf20Sopenharmony_ci int i, ret, hwctg; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci priv->context_pool = dmam_pool_create("safexcel-context", dev, 14098c2ecf20Sopenharmony_ci sizeof(struct safexcel_context_record), 14108c2ecf20Sopenharmony_ci 1, 0); 14118c2ecf20Sopenharmony_ci if (!priv->context_pool) 14128c2ecf20Sopenharmony_ci return -ENOMEM; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci /* 14158c2ecf20Sopenharmony_ci * First try the EIP97 HIA version regs 14168c2ecf20Sopenharmony_ci * For the EIP197, this is guaranteed to NOT return any of the test 14178c2ecf20Sopenharmony_ci * values 14188c2ecf20Sopenharmony_ci */ 14198c2ecf20Sopenharmony_ci version = readl(priv->base + EIP97_HIA_AIC_BASE + EIP197_HIA_VERSION); 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci mask = 0; /* do not swap */ 14228c2ecf20Sopenharmony_ci if (EIP197_REG_LO16(version) == EIP197_HIA_VERSION_LE) { 14238c2ecf20Sopenharmony_ci priv->hwconfig.hiaver = EIP197_VERSION_MASK(version); 14248c2ecf20Sopenharmony_ci } else if (EIP197_REG_HI16(version) == EIP197_HIA_VERSION_BE) { 14258c2ecf20Sopenharmony_ci /* read back byte-swapped, so complement byte swap bits */ 14268c2ecf20Sopenharmony_ci mask = EIP197_MST_CTRL_BYTE_SWAP_BITS; 14278c2ecf20Sopenharmony_ci priv->hwconfig.hiaver = EIP197_VERSION_SWAP(version); 14288c2ecf20Sopenharmony_ci } else { 14298c2ecf20Sopenharmony_ci /* So it wasn't an EIP97 ... maybe it's an EIP197? */ 14308c2ecf20Sopenharmony_ci version = readl(priv->base + EIP197_HIA_AIC_BASE + 14318c2ecf20Sopenharmony_ci EIP197_HIA_VERSION); 14328c2ecf20Sopenharmony_ci if (EIP197_REG_LO16(version) == EIP197_HIA_VERSION_LE) { 14338c2ecf20Sopenharmony_ci priv->hwconfig.hiaver = EIP197_VERSION_MASK(version); 14348c2ecf20Sopenharmony_ci priv->flags |= SAFEXCEL_HW_EIP197; 14358c2ecf20Sopenharmony_ci } else if (EIP197_REG_HI16(version) == 14368c2ecf20Sopenharmony_ci EIP197_HIA_VERSION_BE) { 14378c2ecf20Sopenharmony_ci /* read back byte-swapped, so complement swap bits */ 14388c2ecf20Sopenharmony_ci mask = EIP197_MST_CTRL_BYTE_SWAP_BITS; 14398c2ecf20Sopenharmony_ci priv->hwconfig.hiaver = EIP197_VERSION_SWAP(version); 14408c2ecf20Sopenharmony_ci priv->flags |= SAFEXCEL_HW_EIP197; 14418c2ecf20Sopenharmony_ci } else { 14428c2ecf20Sopenharmony_ci return -ENODEV; 14438c2ecf20Sopenharmony_ci } 14448c2ecf20Sopenharmony_ci } 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci /* Now initialize the reg offsets based on the probing info so far */ 14478c2ecf20Sopenharmony_ci safexcel_init_register_offsets(priv); 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci /* 14508c2ecf20Sopenharmony_ci * If the version was read byte-swapped, we need to flip the device 14518c2ecf20Sopenharmony_ci * swapping Keep in mind here, though, that what we write will also be 14528c2ecf20Sopenharmony_ci * byte-swapped ... 14538c2ecf20Sopenharmony_ci */ 14548c2ecf20Sopenharmony_ci if (mask) { 14558c2ecf20Sopenharmony_ci val = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL); 14568c2ecf20Sopenharmony_ci val = val ^ (mask >> 24); /* toggle byte swap bits */ 14578c2ecf20Sopenharmony_ci writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL); 14588c2ecf20Sopenharmony_ci } 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci /* 14618c2ecf20Sopenharmony_ci * We're not done probing yet! We may fall through to here if no HIA 14628c2ecf20Sopenharmony_ci * was found at all. So, with the endianness presumably correct now and 14638c2ecf20Sopenharmony_ci * the offsets setup, *really* probe for the EIP97/EIP197. 14648c2ecf20Sopenharmony_ci */ 14658c2ecf20Sopenharmony_ci version = readl(EIP197_GLOBAL(priv) + EIP197_VERSION); 14668c2ecf20Sopenharmony_ci if (((priv->flags & SAFEXCEL_HW_EIP197) && 14678c2ecf20Sopenharmony_ci (EIP197_REG_LO16(version) != EIP197_VERSION_LE) && 14688c2ecf20Sopenharmony_ci (EIP197_REG_LO16(version) != EIP196_VERSION_LE)) || 14698c2ecf20Sopenharmony_ci ((!(priv->flags & SAFEXCEL_HW_EIP197) && 14708c2ecf20Sopenharmony_ci (EIP197_REG_LO16(version) != EIP97_VERSION_LE)))) { 14718c2ecf20Sopenharmony_ci /* 14728c2ecf20Sopenharmony_ci * We did not find the device that matched our initial probing 14738c2ecf20Sopenharmony_ci * (or our initial probing failed) Report appropriate error. 14748c2ecf20Sopenharmony_ci */ 14758c2ecf20Sopenharmony_ci dev_err(priv->dev, "Probing for EIP97/EIP19x failed - no such device (read %08x)\n", 14768c2ecf20Sopenharmony_ci version); 14778c2ecf20Sopenharmony_ci return -ENODEV; 14788c2ecf20Sopenharmony_ci } 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci priv->hwconfig.hwver = EIP197_VERSION_MASK(version); 14818c2ecf20Sopenharmony_ci hwctg = version >> 28; 14828c2ecf20Sopenharmony_ci peid = version & 255; 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci /* Detect EIP206 processing pipe */ 14858c2ecf20Sopenharmony_ci version = readl(EIP197_PE(priv) + + EIP197_PE_VERSION(0)); 14868c2ecf20Sopenharmony_ci if (EIP197_REG_LO16(version) != EIP206_VERSION_LE) { 14878c2ecf20Sopenharmony_ci dev_err(priv->dev, "EIP%d: EIP206 not detected\n", peid); 14888c2ecf20Sopenharmony_ci return -ENODEV; 14898c2ecf20Sopenharmony_ci } 14908c2ecf20Sopenharmony_ci priv->hwconfig.ppver = EIP197_VERSION_MASK(version); 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci /* Detect EIP96 packet engine and version */ 14938c2ecf20Sopenharmony_ci version = readl(EIP197_PE(priv) + EIP197_PE_EIP96_VERSION(0)); 14948c2ecf20Sopenharmony_ci if (EIP197_REG_LO16(version) != EIP96_VERSION_LE) { 14958c2ecf20Sopenharmony_ci dev_err(dev, "EIP%d: EIP96 not detected.\n", peid); 14968c2ecf20Sopenharmony_ci return -ENODEV; 14978c2ecf20Sopenharmony_ci } 14988c2ecf20Sopenharmony_ci priv->hwconfig.pever = EIP197_VERSION_MASK(version); 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci hwopt = readl(EIP197_GLOBAL(priv) + EIP197_OPTIONS); 15018c2ecf20Sopenharmony_ci hiaopt = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_OPTIONS); 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci priv->hwconfig.icever = 0; 15048c2ecf20Sopenharmony_ci priv->hwconfig.ocever = 0; 15058c2ecf20Sopenharmony_ci priv->hwconfig.psever = 0; 15068c2ecf20Sopenharmony_ci if (priv->flags & SAFEXCEL_HW_EIP197) { 15078c2ecf20Sopenharmony_ci /* EIP197 */ 15088c2ecf20Sopenharmony_ci peopt = readl(EIP197_PE(priv) + EIP197_PE_OPTIONS(0)); 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci priv->hwconfig.hwdataw = (hiaopt >> EIP197_HWDATAW_OFFSET) & 15118c2ecf20Sopenharmony_ci EIP197_HWDATAW_MASK; 15128c2ecf20Sopenharmony_ci priv->hwconfig.hwcfsize = ((hiaopt >> EIP197_CFSIZE_OFFSET) & 15138c2ecf20Sopenharmony_ci EIP197_CFSIZE_MASK) + 15148c2ecf20Sopenharmony_ci EIP197_CFSIZE_ADJUST; 15158c2ecf20Sopenharmony_ci priv->hwconfig.hwrfsize = ((hiaopt >> EIP197_RFSIZE_OFFSET) & 15168c2ecf20Sopenharmony_ci EIP197_RFSIZE_MASK) + 15178c2ecf20Sopenharmony_ci EIP197_RFSIZE_ADJUST; 15188c2ecf20Sopenharmony_ci priv->hwconfig.hwnumpes = (hiaopt >> EIP197_N_PES_OFFSET) & 15198c2ecf20Sopenharmony_ci EIP197_N_PES_MASK; 15208c2ecf20Sopenharmony_ci priv->hwconfig.hwnumrings = (hiaopt >> EIP197_N_RINGS_OFFSET) & 15218c2ecf20Sopenharmony_ci EIP197_N_RINGS_MASK; 15228c2ecf20Sopenharmony_ci if (hiaopt & EIP197_HIA_OPT_HAS_PE_ARB) 15238c2ecf20Sopenharmony_ci priv->flags |= EIP197_PE_ARB; 15248c2ecf20Sopenharmony_ci if (EIP206_OPT_ICE_TYPE(peopt) == 1) { 15258c2ecf20Sopenharmony_ci priv->flags |= EIP197_ICE; 15268c2ecf20Sopenharmony_ci /* Detect ICE EIP207 class. engine and version */ 15278c2ecf20Sopenharmony_ci version = readl(EIP197_PE(priv) + 15288c2ecf20Sopenharmony_ci EIP197_PE_ICE_VERSION(0)); 15298c2ecf20Sopenharmony_ci if (EIP197_REG_LO16(version) != EIP207_VERSION_LE) { 15308c2ecf20Sopenharmony_ci dev_err(dev, "EIP%d: ICE EIP207 not detected.\n", 15318c2ecf20Sopenharmony_ci peid); 15328c2ecf20Sopenharmony_ci return -ENODEV; 15338c2ecf20Sopenharmony_ci } 15348c2ecf20Sopenharmony_ci priv->hwconfig.icever = EIP197_VERSION_MASK(version); 15358c2ecf20Sopenharmony_ci } 15368c2ecf20Sopenharmony_ci if (EIP206_OPT_OCE_TYPE(peopt) == 1) { 15378c2ecf20Sopenharmony_ci priv->flags |= EIP197_OCE; 15388c2ecf20Sopenharmony_ci /* Detect EIP96PP packet stream editor and version */ 15398c2ecf20Sopenharmony_ci version = readl(EIP197_PE(priv) + EIP197_PE_PSE_VERSION(0)); 15408c2ecf20Sopenharmony_ci if (EIP197_REG_LO16(version) != EIP96_VERSION_LE) { 15418c2ecf20Sopenharmony_ci dev_err(dev, "EIP%d: EIP96PP not detected.\n", peid); 15428c2ecf20Sopenharmony_ci return -ENODEV; 15438c2ecf20Sopenharmony_ci } 15448c2ecf20Sopenharmony_ci priv->hwconfig.psever = EIP197_VERSION_MASK(version); 15458c2ecf20Sopenharmony_ci /* Detect OCE EIP207 class. engine and version */ 15468c2ecf20Sopenharmony_ci version = readl(EIP197_PE(priv) + 15478c2ecf20Sopenharmony_ci EIP197_PE_ICE_VERSION(0)); 15488c2ecf20Sopenharmony_ci if (EIP197_REG_LO16(version) != EIP207_VERSION_LE) { 15498c2ecf20Sopenharmony_ci dev_err(dev, "EIP%d: OCE EIP207 not detected.\n", 15508c2ecf20Sopenharmony_ci peid); 15518c2ecf20Sopenharmony_ci return -ENODEV; 15528c2ecf20Sopenharmony_ci } 15538c2ecf20Sopenharmony_ci priv->hwconfig.ocever = EIP197_VERSION_MASK(version); 15548c2ecf20Sopenharmony_ci } 15558c2ecf20Sopenharmony_ci /* If not a full TRC, then assume simple TRC */ 15568c2ecf20Sopenharmony_ci if (!(hwopt & EIP197_OPT_HAS_TRC)) 15578c2ecf20Sopenharmony_ci priv->flags |= EIP197_SIMPLE_TRC; 15588c2ecf20Sopenharmony_ci /* EIP197 always has SOME form of TRC */ 15598c2ecf20Sopenharmony_ci priv->flags |= EIP197_TRC_CACHE; 15608c2ecf20Sopenharmony_ci } else { 15618c2ecf20Sopenharmony_ci /* EIP97 */ 15628c2ecf20Sopenharmony_ci priv->hwconfig.hwdataw = (hiaopt >> EIP197_HWDATAW_OFFSET) & 15638c2ecf20Sopenharmony_ci EIP97_HWDATAW_MASK; 15648c2ecf20Sopenharmony_ci priv->hwconfig.hwcfsize = (hiaopt >> EIP97_CFSIZE_OFFSET) & 15658c2ecf20Sopenharmony_ci EIP97_CFSIZE_MASK; 15668c2ecf20Sopenharmony_ci priv->hwconfig.hwrfsize = (hiaopt >> EIP97_RFSIZE_OFFSET) & 15678c2ecf20Sopenharmony_ci EIP97_RFSIZE_MASK; 15688c2ecf20Sopenharmony_ci priv->hwconfig.hwnumpes = 1; /* by definition */ 15698c2ecf20Sopenharmony_ci priv->hwconfig.hwnumrings = (hiaopt >> EIP197_N_RINGS_OFFSET) & 15708c2ecf20Sopenharmony_ci EIP197_N_RINGS_MASK; 15718c2ecf20Sopenharmony_ci } 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci /* Scan for ring AIC's */ 15748c2ecf20Sopenharmony_ci for (i = 0; i < EIP197_MAX_RING_AIC; i++) { 15758c2ecf20Sopenharmony_ci version = readl(EIP197_HIA_AIC_R(priv) + 15768c2ecf20Sopenharmony_ci EIP197_HIA_AIC_R_VERSION(i)); 15778c2ecf20Sopenharmony_ci if (EIP197_REG_LO16(version) != EIP201_VERSION_LE) 15788c2ecf20Sopenharmony_ci break; 15798c2ecf20Sopenharmony_ci } 15808c2ecf20Sopenharmony_ci priv->hwconfig.hwnumraic = i; 15818c2ecf20Sopenharmony_ci /* Low-end EIP196 may not have any ring AIC's ... */ 15828c2ecf20Sopenharmony_ci if (!priv->hwconfig.hwnumraic) { 15838c2ecf20Sopenharmony_ci dev_err(priv->dev, "No ring interrupt controller present!\n"); 15848c2ecf20Sopenharmony_ci return -ENODEV; 15858c2ecf20Sopenharmony_ci } 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci /* Get supported algorithms from EIP96 transform engine */ 15888c2ecf20Sopenharmony_ci priv->hwconfig.algo_flags = readl(EIP197_PE(priv) + 15898c2ecf20Sopenharmony_ci EIP197_PE_EIP96_OPTIONS(0)); 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci /* Print single info line describing what we just detected */ 15928c2ecf20Sopenharmony_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", 15938c2ecf20Sopenharmony_ci peid, priv->hwconfig.hwver, hwctg, priv->hwconfig.hwnumpes, 15948c2ecf20Sopenharmony_ci priv->hwconfig.hwnumrings, priv->hwconfig.hwnumraic, 15958c2ecf20Sopenharmony_ci priv->hwconfig.hiaver, priv->hwconfig.hwdataw, 15968c2ecf20Sopenharmony_ci priv->hwconfig.hwcfsize, priv->hwconfig.hwrfsize, 15978c2ecf20Sopenharmony_ci priv->hwconfig.ppver, priv->hwconfig.pever, 15988c2ecf20Sopenharmony_ci priv->hwconfig.algo_flags, priv->hwconfig.icever, 15998c2ecf20Sopenharmony_ci priv->hwconfig.ocever, priv->hwconfig.psever); 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci safexcel_configure(priv); 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PCI) && priv->version == EIP197_DEVBRD) { 16048c2ecf20Sopenharmony_ci /* 16058c2ecf20Sopenharmony_ci * Request MSI vectors for global + 1 per ring - 16068c2ecf20Sopenharmony_ci * or just 1 for older dev images 16078c2ecf20Sopenharmony_ci */ 16088c2ecf20Sopenharmony_ci struct pci_dev *pci_pdev = pdev; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci ret = pci_alloc_irq_vectors(pci_pdev, 16118c2ecf20Sopenharmony_ci priv->config.rings + 1, 16128c2ecf20Sopenharmony_ci priv->config.rings + 1, 16138c2ecf20Sopenharmony_ci PCI_IRQ_MSI | PCI_IRQ_MSIX); 16148c2ecf20Sopenharmony_ci if (ret < 0) { 16158c2ecf20Sopenharmony_ci dev_err(dev, "Failed to allocate PCI MSI interrupts\n"); 16168c2ecf20Sopenharmony_ci return ret; 16178c2ecf20Sopenharmony_ci } 16188c2ecf20Sopenharmony_ci } 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci /* Register the ring IRQ handlers and configure the rings */ 16218c2ecf20Sopenharmony_ci priv->ring = devm_kcalloc(dev, priv->config.rings, 16228c2ecf20Sopenharmony_ci sizeof(*priv->ring), 16238c2ecf20Sopenharmony_ci GFP_KERNEL); 16248c2ecf20Sopenharmony_ci if (!priv->ring) 16258c2ecf20Sopenharmony_ci return -ENOMEM; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci for (i = 0; i < priv->config.rings; i++) { 16288c2ecf20Sopenharmony_ci char wq_name[9] = {0}; 16298c2ecf20Sopenharmony_ci int irq; 16308c2ecf20Sopenharmony_ci struct safexcel_ring_irq_data *ring_irq; 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci ret = safexcel_init_ring_descriptors(priv, 16338c2ecf20Sopenharmony_ci &priv->ring[i].cdr, 16348c2ecf20Sopenharmony_ci &priv->ring[i].rdr); 16358c2ecf20Sopenharmony_ci if (ret) { 16368c2ecf20Sopenharmony_ci dev_err(dev, "Failed to initialize rings\n"); 16378c2ecf20Sopenharmony_ci goto err_cleanup_rings; 16388c2ecf20Sopenharmony_ci } 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci priv->ring[i].rdr_req = devm_kcalloc(dev, 16418c2ecf20Sopenharmony_ci EIP197_DEFAULT_RING_SIZE, 16428c2ecf20Sopenharmony_ci sizeof(*priv->ring[i].rdr_req), 16438c2ecf20Sopenharmony_ci GFP_KERNEL); 16448c2ecf20Sopenharmony_ci if (!priv->ring[i].rdr_req) { 16458c2ecf20Sopenharmony_ci ret = -ENOMEM; 16468c2ecf20Sopenharmony_ci goto err_cleanup_rings; 16478c2ecf20Sopenharmony_ci } 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci ring_irq = devm_kzalloc(dev, sizeof(*ring_irq), GFP_KERNEL); 16508c2ecf20Sopenharmony_ci if (!ring_irq) { 16518c2ecf20Sopenharmony_ci ret = -ENOMEM; 16528c2ecf20Sopenharmony_ci goto err_cleanup_rings; 16538c2ecf20Sopenharmony_ci } 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci ring_irq->priv = priv; 16568c2ecf20Sopenharmony_ci ring_irq->ring = i; 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci irq = safexcel_request_ring_irq(pdev, 16598c2ecf20Sopenharmony_ci EIP197_IRQ_NUMBER(i, is_pci_dev), 16608c2ecf20Sopenharmony_ci is_pci_dev, 16618c2ecf20Sopenharmony_ci i, 16628c2ecf20Sopenharmony_ci safexcel_irq_ring, 16638c2ecf20Sopenharmony_ci safexcel_irq_ring_thread, 16648c2ecf20Sopenharmony_ci ring_irq); 16658c2ecf20Sopenharmony_ci if (irq < 0) { 16668c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get IRQ ID for ring %d\n", i); 16678c2ecf20Sopenharmony_ci ret = irq; 16688c2ecf20Sopenharmony_ci goto err_cleanup_rings; 16698c2ecf20Sopenharmony_ci } 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci priv->ring[i].irq = irq; 16728c2ecf20Sopenharmony_ci priv->ring[i].work_data.priv = priv; 16738c2ecf20Sopenharmony_ci priv->ring[i].work_data.ring = i; 16748c2ecf20Sopenharmony_ci INIT_WORK(&priv->ring[i].work_data.work, 16758c2ecf20Sopenharmony_ci safexcel_dequeue_work); 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci snprintf(wq_name, 9, "wq_ring%d", i); 16788c2ecf20Sopenharmony_ci priv->ring[i].workqueue = 16798c2ecf20Sopenharmony_ci create_singlethread_workqueue(wq_name); 16808c2ecf20Sopenharmony_ci if (!priv->ring[i].workqueue) { 16818c2ecf20Sopenharmony_ci ret = -ENOMEM; 16828c2ecf20Sopenharmony_ci goto err_cleanup_rings; 16838c2ecf20Sopenharmony_ci } 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci priv->ring[i].requests = 0; 16868c2ecf20Sopenharmony_ci priv->ring[i].busy = false; 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci crypto_init_queue(&priv->ring[i].queue, 16898c2ecf20Sopenharmony_ci EIP197_DEFAULT_RING_SIZE); 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci spin_lock_init(&priv->ring[i].lock); 16928c2ecf20Sopenharmony_ci spin_lock_init(&priv->ring[i].queue_lock); 16938c2ecf20Sopenharmony_ci } 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci atomic_set(&priv->ring_used, 0); 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci ret = safexcel_hw_init(priv); 16988c2ecf20Sopenharmony_ci if (ret) { 16998c2ecf20Sopenharmony_ci dev_err(dev, "HW init failed (%d)\n", ret); 17008c2ecf20Sopenharmony_ci goto err_cleanup_rings; 17018c2ecf20Sopenharmony_ci } 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci ret = safexcel_register_algorithms(priv); 17048c2ecf20Sopenharmony_ci if (ret) { 17058c2ecf20Sopenharmony_ci dev_err(dev, "Failed to register algorithms (%d)\n", ret); 17068c2ecf20Sopenharmony_ci goto err_cleanup_rings; 17078c2ecf20Sopenharmony_ci } 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci return 0; 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_cierr_cleanup_rings: 17128c2ecf20Sopenharmony_ci for (i = 0; i < priv->config.rings; i++) { 17138c2ecf20Sopenharmony_ci if (priv->ring[i].irq) 17148c2ecf20Sopenharmony_ci irq_set_affinity_hint(priv->ring[i].irq, NULL); 17158c2ecf20Sopenharmony_ci if (priv->ring[i].workqueue) 17168c2ecf20Sopenharmony_ci destroy_workqueue(priv->ring[i].workqueue); 17178c2ecf20Sopenharmony_ci } 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci return ret; 17208c2ecf20Sopenharmony_ci} 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_cistatic void safexcel_hw_reset_rings(struct safexcel_crypto_priv *priv) 17238c2ecf20Sopenharmony_ci{ 17248c2ecf20Sopenharmony_ci int i; 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci for (i = 0; i < priv->config.rings; i++) { 17278c2ecf20Sopenharmony_ci /* clear any pending interrupt */ 17288c2ecf20Sopenharmony_ci writel(GENMASK(5, 0), EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_STAT); 17298c2ecf20Sopenharmony_ci writel(GENMASK(7, 0), EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_STAT); 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci /* Reset the CDR base address */ 17328c2ecf20Sopenharmony_ci writel(0, EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_LO); 17338c2ecf20Sopenharmony_ci writel(0, EIP197_HIA_CDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_HI); 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci /* Reset the RDR base address */ 17368c2ecf20Sopenharmony_ci writel(0, EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_LO); 17378c2ecf20Sopenharmony_ci writel(0, EIP197_HIA_RDR(priv, i) + EIP197_HIA_xDR_RING_BASE_ADDR_HI); 17388c2ecf20Sopenharmony_ci } 17398c2ecf20Sopenharmony_ci} 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci/* for Device Tree platform driver */ 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_cistatic int safexcel_probe(struct platform_device *pdev) 17448c2ecf20Sopenharmony_ci{ 17458c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 17468c2ecf20Sopenharmony_ci struct safexcel_crypto_priv *priv; 17478c2ecf20Sopenharmony_ci int ret; 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 17508c2ecf20Sopenharmony_ci if (!priv) 17518c2ecf20Sopenharmony_ci return -ENOMEM; 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci priv->dev = dev; 17548c2ecf20Sopenharmony_ci priv->version = (enum safexcel_eip_version)of_device_get_match_data(dev); 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, priv); 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci priv->base = devm_platform_ioremap_resource(pdev, 0); 17598c2ecf20Sopenharmony_ci if (IS_ERR(priv->base)) { 17608c2ecf20Sopenharmony_ci dev_err(dev, "failed to get resource\n"); 17618c2ecf20Sopenharmony_ci return PTR_ERR(priv->base); 17628c2ecf20Sopenharmony_ci } 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci priv->clk = devm_clk_get(&pdev->dev, NULL); 17658c2ecf20Sopenharmony_ci ret = PTR_ERR_OR_ZERO(priv->clk); 17668c2ecf20Sopenharmony_ci /* The clock isn't mandatory */ 17678c2ecf20Sopenharmony_ci if (ret != -ENOENT) { 17688c2ecf20Sopenharmony_ci if (ret) 17698c2ecf20Sopenharmony_ci return ret; 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->clk); 17728c2ecf20Sopenharmony_ci if (ret) { 17738c2ecf20Sopenharmony_ci dev_err(dev, "unable to enable clk (%d)\n", ret); 17748c2ecf20Sopenharmony_ci return ret; 17758c2ecf20Sopenharmony_ci } 17768c2ecf20Sopenharmony_ci } 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci priv->reg_clk = devm_clk_get(&pdev->dev, "reg"); 17798c2ecf20Sopenharmony_ci ret = PTR_ERR_OR_ZERO(priv->reg_clk); 17808c2ecf20Sopenharmony_ci /* The clock isn't mandatory */ 17818c2ecf20Sopenharmony_ci if (ret != -ENOENT) { 17828c2ecf20Sopenharmony_ci if (ret) 17838c2ecf20Sopenharmony_ci goto err_core_clk; 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->reg_clk); 17868c2ecf20Sopenharmony_ci if (ret) { 17878c2ecf20Sopenharmony_ci dev_err(dev, "unable to enable reg clk (%d)\n", ret); 17888c2ecf20Sopenharmony_ci goto err_core_clk; 17898c2ecf20Sopenharmony_ci } 17908c2ecf20Sopenharmony_ci } 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); 17938c2ecf20Sopenharmony_ci if (ret) 17948c2ecf20Sopenharmony_ci goto err_reg_clk; 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci /* Generic EIP97/EIP197 device probing */ 17978c2ecf20Sopenharmony_ci ret = safexcel_probe_generic(pdev, priv, 0); 17988c2ecf20Sopenharmony_ci if (ret) 17998c2ecf20Sopenharmony_ci goto err_reg_clk; 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci return 0; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_cierr_reg_clk: 18048c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->reg_clk); 18058c2ecf20Sopenharmony_cierr_core_clk: 18068c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk); 18078c2ecf20Sopenharmony_ci return ret; 18088c2ecf20Sopenharmony_ci} 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_cistatic int safexcel_remove(struct platform_device *pdev) 18118c2ecf20Sopenharmony_ci{ 18128c2ecf20Sopenharmony_ci struct safexcel_crypto_priv *priv = platform_get_drvdata(pdev); 18138c2ecf20Sopenharmony_ci int i; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci safexcel_unregister_algorithms(priv); 18168c2ecf20Sopenharmony_ci safexcel_hw_reset_rings(priv); 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->reg_clk); 18198c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk); 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci for (i = 0; i < priv->config.rings; i++) { 18228c2ecf20Sopenharmony_ci irq_set_affinity_hint(priv->ring[i].irq, NULL); 18238c2ecf20Sopenharmony_ci destroy_workqueue(priv->ring[i].workqueue); 18248c2ecf20Sopenharmony_ci } 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci return 0; 18278c2ecf20Sopenharmony_ci} 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_cistatic const struct of_device_id safexcel_of_match_table[] = { 18308c2ecf20Sopenharmony_ci { 18318c2ecf20Sopenharmony_ci .compatible = "inside-secure,safexcel-eip97ies", 18328c2ecf20Sopenharmony_ci .data = (void *)EIP97IES_MRVL, 18338c2ecf20Sopenharmony_ci }, 18348c2ecf20Sopenharmony_ci { 18358c2ecf20Sopenharmony_ci .compatible = "inside-secure,safexcel-eip197b", 18368c2ecf20Sopenharmony_ci .data = (void *)EIP197B_MRVL, 18378c2ecf20Sopenharmony_ci }, 18388c2ecf20Sopenharmony_ci { 18398c2ecf20Sopenharmony_ci .compatible = "inside-secure,safexcel-eip197d", 18408c2ecf20Sopenharmony_ci .data = (void *)EIP197D_MRVL, 18418c2ecf20Sopenharmony_ci }, 18428c2ecf20Sopenharmony_ci /* For backward compatibility and intended for generic use */ 18438c2ecf20Sopenharmony_ci { 18448c2ecf20Sopenharmony_ci .compatible = "inside-secure,safexcel-eip97", 18458c2ecf20Sopenharmony_ci .data = (void *)EIP97IES_MRVL, 18468c2ecf20Sopenharmony_ci }, 18478c2ecf20Sopenharmony_ci { 18488c2ecf20Sopenharmony_ci .compatible = "inside-secure,safexcel-eip197", 18498c2ecf20Sopenharmony_ci .data = (void *)EIP197B_MRVL, 18508c2ecf20Sopenharmony_ci }, 18518c2ecf20Sopenharmony_ci {}, 18528c2ecf20Sopenharmony_ci}; 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, safexcel_of_match_table); 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_cistatic struct platform_driver crypto_safexcel = { 18578c2ecf20Sopenharmony_ci .probe = safexcel_probe, 18588c2ecf20Sopenharmony_ci .remove = safexcel_remove, 18598c2ecf20Sopenharmony_ci .driver = { 18608c2ecf20Sopenharmony_ci .name = "crypto-safexcel", 18618c2ecf20Sopenharmony_ci .of_match_table = safexcel_of_match_table, 18628c2ecf20Sopenharmony_ci }, 18638c2ecf20Sopenharmony_ci}; 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci/* PCIE devices - i.e. Inside Secure development boards */ 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_cistatic int safexcel_pci_probe(struct pci_dev *pdev, 18688c2ecf20Sopenharmony_ci const struct pci_device_id *ent) 18698c2ecf20Sopenharmony_ci{ 18708c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 18718c2ecf20Sopenharmony_ci struct safexcel_crypto_priv *priv; 18728c2ecf20Sopenharmony_ci void __iomem *pciebase; 18738c2ecf20Sopenharmony_ci int rc; 18748c2ecf20Sopenharmony_ci u32 val; 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci dev_dbg(dev, "Probing PCIE device: vendor %04x, device %04x, subv %04x, subdev %04x, ctxt %lx\n", 18778c2ecf20Sopenharmony_ci ent->vendor, ent->device, ent->subvendor, 18788c2ecf20Sopenharmony_ci ent->subdevice, ent->driver_data); 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci priv = kzalloc(sizeof(*priv), GFP_KERNEL); 18818c2ecf20Sopenharmony_ci if (!priv) 18828c2ecf20Sopenharmony_ci return -ENOMEM; 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci priv->dev = dev; 18858c2ecf20Sopenharmony_ci priv->version = (enum safexcel_eip_version)ent->driver_data; 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, priv); 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci /* enable the device */ 18908c2ecf20Sopenharmony_ci rc = pcim_enable_device(pdev); 18918c2ecf20Sopenharmony_ci if (rc) { 18928c2ecf20Sopenharmony_ci dev_err(dev, "Failed to enable PCI device\n"); 18938c2ecf20Sopenharmony_ci return rc; 18948c2ecf20Sopenharmony_ci } 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci /* take ownership of PCI BAR0 */ 18978c2ecf20Sopenharmony_ci rc = pcim_iomap_regions(pdev, 1, "crypto_safexcel"); 18988c2ecf20Sopenharmony_ci if (rc) { 18998c2ecf20Sopenharmony_ci dev_err(dev, "Failed to map IO region for BAR0\n"); 19008c2ecf20Sopenharmony_ci return rc; 19018c2ecf20Sopenharmony_ci } 19028c2ecf20Sopenharmony_ci priv->base = pcim_iomap_table(pdev)[0]; 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci if (priv->version == EIP197_DEVBRD) { 19058c2ecf20Sopenharmony_ci dev_dbg(dev, "Device identified as FPGA based development board - applying HW reset\n"); 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci rc = pcim_iomap_regions(pdev, 4, "crypto_safexcel"); 19088c2ecf20Sopenharmony_ci if (rc) { 19098c2ecf20Sopenharmony_ci dev_err(dev, "Failed to map IO region for BAR4\n"); 19108c2ecf20Sopenharmony_ci return rc; 19118c2ecf20Sopenharmony_ci } 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci pciebase = pcim_iomap_table(pdev)[2]; 19148c2ecf20Sopenharmony_ci val = readl(pciebase + EIP197_XLX_IRQ_BLOCK_ID_ADDR); 19158c2ecf20Sopenharmony_ci if ((val >> 16) == EIP197_XLX_IRQ_BLOCK_ID_VALUE) { 19168c2ecf20Sopenharmony_ci dev_dbg(dev, "Detected Xilinx PCIE IRQ block version %d, multiple MSI support enabled\n", 19178c2ecf20Sopenharmony_ci (val & 0xff)); 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci /* Setup MSI identity map mapping */ 19208c2ecf20Sopenharmony_ci writel(EIP197_XLX_USER_VECT_LUT0_IDENT, 19218c2ecf20Sopenharmony_ci pciebase + EIP197_XLX_USER_VECT_LUT0_ADDR); 19228c2ecf20Sopenharmony_ci writel(EIP197_XLX_USER_VECT_LUT1_IDENT, 19238c2ecf20Sopenharmony_ci pciebase + EIP197_XLX_USER_VECT_LUT1_ADDR); 19248c2ecf20Sopenharmony_ci writel(EIP197_XLX_USER_VECT_LUT2_IDENT, 19258c2ecf20Sopenharmony_ci pciebase + EIP197_XLX_USER_VECT_LUT2_ADDR); 19268c2ecf20Sopenharmony_ci writel(EIP197_XLX_USER_VECT_LUT3_IDENT, 19278c2ecf20Sopenharmony_ci pciebase + EIP197_XLX_USER_VECT_LUT3_ADDR); 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci /* Enable all device interrupts */ 19308c2ecf20Sopenharmony_ci writel(GENMASK(31, 0), 19318c2ecf20Sopenharmony_ci pciebase + EIP197_XLX_USER_INT_ENB_MSK); 19328c2ecf20Sopenharmony_ci } else { 19338c2ecf20Sopenharmony_ci dev_err(dev, "Unrecognised IRQ block identifier %x\n", 19348c2ecf20Sopenharmony_ci val); 19358c2ecf20Sopenharmony_ci return -ENODEV; 19368c2ecf20Sopenharmony_ci } 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci /* HW reset FPGA dev board */ 19398c2ecf20Sopenharmony_ci /* assert reset */ 19408c2ecf20Sopenharmony_ci writel(1, priv->base + EIP197_XLX_GPIO_BASE); 19418c2ecf20Sopenharmony_ci wmb(); /* maintain strict ordering for accesses here */ 19428c2ecf20Sopenharmony_ci /* deassert reset */ 19438c2ecf20Sopenharmony_ci writel(0, priv->base + EIP197_XLX_GPIO_BASE); 19448c2ecf20Sopenharmony_ci wmb(); /* maintain strict ordering for accesses here */ 19458c2ecf20Sopenharmony_ci } 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci /* enable bus mastering */ 19488c2ecf20Sopenharmony_ci pci_set_master(pdev); 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci /* Generic EIP97/EIP197 device probing */ 19518c2ecf20Sopenharmony_ci rc = safexcel_probe_generic(pdev, priv, 1); 19528c2ecf20Sopenharmony_ci return rc; 19538c2ecf20Sopenharmony_ci} 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_cistatic void safexcel_pci_remove(struct pci_dev *pdev) 19568c2ecf20Sopenharmony_ci{ 19578c2ecf20Sopenharmony_ci struct safexcel_crypto_priv *priv = pci_get_drvdata(pdev); 19588c2ecf20Sopenharmony_ci int i; 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci safexcel_unregister_algorithms(priv); 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci for (i = 0; i < priv->config.rings; i++) 19638c2ecf20Sopenharmony_ci destroy_workqueue(priv->ring[i].workqueue); 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci safexcel_hw_reset_rings(priv); 19668c2ecf20Sopenharmony_ci} 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_cistatic const struct pci_device_id safexcel_pci_ids[] = { 19698c2ecf20Sopenharmony_ci { 19708c2ecf20Sopenharmony_ci PCI_DEVICE_SUB(PCI_VENDOR_ID_XILINX, 0x9038, 19718c2ecf20Sopenharmony_ci 0x16ae, 0xc522), 19728c2ecf20Sopenharmony_ci .driver_data = EIP197_DEVBRD, 19738c2ecf20Sopenharmony_ci }, 19748c2ecf20Sopenharmony_ci {}, 19758c2ecf20Sopenharmony_ci}; 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, safexcel_pci_ids); 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_cistatic struct pci_driver safexcel_pci_driver = { 19808c2ecf20Sopenharmony_ci .name = "crypto-safexcel", 19818c2ecf20Sopenharmony_ci .id_table = safexcel_pci_ids, 19828c2ecf20Sopenharmony_ci .probe = safexcel_pci_probe, 19838c2ecf20Sopenharmony_ci .remove = safexcel_pci_remove, 19848c2ecf20Sopenharmony_ci}; 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_cistatic int __init safexcel_init(void) 19878c2ecf20Sopenharmony_ci{ 19888c2ecf20Sopenharmony_ci int ret; 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci /* Register PCI driver */ 19918c2ecf20Sopenharmony_ci ret = pci_register_driver(&safexcel_pci_driver); 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci /* Register platform driver */ 19948c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_OF) && !ret) { 19958c2ecf20Sopenharmony_ci ret = platform_driver_register(&crypto_safexcel); 19968c2ecf20Sopenharmony_ci if (ret) 19978c2ecf20Sopenharmony_ci pci_unregister_driver(&safexcel_pci_driver); 19988c2ecf20Sopenharmony_ci } 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci return ret; 20018c2ecf20Sopenharmony_ci} 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_cistatic void __exit safexcel_exit(void) 20048c2ecf20Sopenharmony_ci{ 20058c2ecf20Sopenharmony_ci /* Unregister platform driver */ 20068c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_OF)) 20078c2ecf20Sopenharmony_ci platform_driver_unregister(&crypto_safexcel); 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci /* Unregister PCI driver if successfully registered before */ 20108c2ecf20Sopenharmony_ci pci_unregister_driver(&safexcel_pci_driver); 20118c2ecf20Sopenharmony_ci} 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_cimodule_init(safexcel_init); 20148c2ecf20Sopenharmony_cimodule_exit(safexcel_exit); 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ciMODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>"); 20178c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ofer Heifetz <oferh@marvell.com>"); 20188c2ecf20Sopenharmony_ciMODULE_AUTHOR("Igal Liberman <igall@marvell.com>"); 20198c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Support for SafeXcel cryptographic engines: EIP97 & EIP197"); 20208c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 2021