18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 2007+ Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru> 48c2ecf20Sopenharmony_ci * All rights reserved. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 108c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h> 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/pci.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/delay.h> 158c2ecf20Sopenharmony_ci#include <linux/mm.h> 168c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 178c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 188c2ecf20Sopenharmony_ci#include <linux/highmem.h> 198c2ecf20Sopenharmony_ci#include <linux/crypto.h> 208c2ecf20Sopenharmony_ci#include <linux/hw_random.h> 218c2ecf20Sopenharmony_ci#include <linux/ktime.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <crypto/algapi.h> 248c2ecf20Sopenharmony_ci#include <crypto/internal/des.h> 258c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic char hifn_pll_ref[sizeof("extNNN")] = "ext"; 288c2ecf20Sopenharmony_cimodule_param_string(hifn_pll_ref, hifn_pll_ref, sizeof(hifn_pll_ref), 0444); 298c2ecf20Sopenharmony_ciMODULE_PARM_DESC(hifn_pll_ref, 308c2ecf20Sopenharmony_ci "PLL reference clock (pci[freq] or ext[freq], default ext)"); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic atomic_t hifn_dev_number; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define ACRYPTO_OP_DECRYPT 0 358c2ecf20Sopenharmony_ci#define ACRYPTO_OP_ENCRYPT 1 368c2ecf20Sopenharmony_ci#define ACRYPTO_OP_HMAC 2 378c2ecf20Sopenharmony_ci#define ACRYPTO_OP_RNG 3 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define ACRYPTO_MODE_ECB 0 408c2ecf20Sopenharmony_ci#define ACRYPTO_MODE_CBC 1 418c2ecf20Sopenharmony_ci#define ACRYPTO_MODE_CFB 2 428c2ecf20Sopenharmony_ci#define ACRYPTO_MODE_OFB 3 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define ACRYPTO_TYPE_AES_128 0 458c2ecf20Sopenharmony_ci#define ACRYPTO_TYPE_AES_192 1 468c2ecf20Sopenharmony_ci#define ACRYPTO_TYPE_AES_256 2 478c2ecf20Sopenharmony_ci#define ACRYPTO_TYPE_3DES 3 488c2ecf20Sopenharmony_ci#define ACRYPTO_TYPE_DES 4 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define PCI_VENDOR_ID_HIFN 0x13A3 518c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_HIFN_7955 0x0020 528c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_HIFN_7956 0x001d 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* I/O region sizes */ 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define HIFN_BAR0_SIZE 0x1000 578c2ecf20Sopenharmony_ci#define HIFN_BAR1_SIZE 0x2000 588c2ecf20Sopenharmony_ci#define HIFN_BAR2_SIZE 0x8000 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* DMA registres */ 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define HIFN_DMA_CRA 0x0C /* DMA Command Ring Address */ 638c2ecf20Sopenharmony_ci#define HIFN_DMA_SDRA 0x1C /* DMA Source Data Ring Address */ 648c2ecf20Sopenharmony_ci#define HIFN_DMA_RRA 0x2C /* DMA Result Ring Address */ 658c2ecf20Sopenharmony_ci#define HIFN_DMA_DDRA 0x3C /* DMA Destination Data Ring Address */ 668c2ecf20Sopenharmony_ci#define HIFN_DMA_STCTL 0x40 /* DMA Status and Control */ 678c2ecf20Sopenharmony_ci#define HIFN_DMA_INTREN 0x44 /* DMA Interrupt Enable */ 688c2ecf20Sopenharmony_ci#define HIFN_DMA_CFG1 0x48 /* DMA Configuration #1 */ 698c2ecf20Sopenharmony_ci#define HIFN_DMA_CFG2 0x6C /* DMA Configuration #2 */ 708c2ecf20Sopenharmony_ci#define HIFN_CHIP_ID 0x98 /* Chip ID */ 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* 738c2ecf20Sopenharmony_ci * Processing Unit Registers (offset from BASEREG0) 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_ci#define HIFN_0_PUDATA 0x00 /* Processing Unit Data */ 768c2ecf20Sopenharmony_ci#define HIFN_0_PUCTRL 0x04 /* Processing Unit Control */ 778c2ecf20Sopenharmony_ci#define HIFN_0_PUISR 0x08 /* Processing Unit Interrupt Status */ 788c2ecf20Sopenharmony_ci#define HIFN_0_PUCNFG 0x0c /* Processing Unit Configuration */ 798c2ecf20Sopenharmony_ci#define HIFN_0_PUIER 0x10 /* Processing Unit Interrupt Enable */ 808c2ecf20Sopenharmony_ci#define HIFN_0_PUSTAT 0x14 /* Processing Unit Status/Chip ID */ 818c2ecf20Sopenharmony_ci#define HIFN_0_FIFOSTAT 0x18 /* FIFO Status */ 828c2ecf20Sopenharmony_ci#define HIFN_0_FIFOCNFG 0x1c /* FIFO Configuration */ 838c2ecf20Sopenharmony_ci#define HIFN_0_SPACESIZE 0x20 /* Register space size */ 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/* Processing Unit Control Register (HIFN_0_PUCTRL) */ 868c2ecf20Sopenharmony_ci#define HIFN_PUCTRL_CLRSRCFIFO 0x0010 /* clear source fifo */ 878c2ecf20Sopenharmony_ci#define HIFN_PUCTRL_STOP 0x0008 /* stop pu */ 888c2ecf20Sopenharmony_ci#define HIFN_PUCTRL_LOCKRAM 0x0004 /* lock ram */ 898c2ecf20Sopenharmony_ci#define HIFN_PUCTRL_DMAENA 0x0002 /* enable dma */ 908c2ecf20Sopenharmony_ci#define HIFN_PUCTRL_RESET 0x0001 /* Reset processing unit */ 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* Processing Unit Interrupt Status Register (HIFN_0_PUISR) */ 938c2ecf20Sopenharmony_ci#define HIFN_PUISR_CMDINVAL 0x8000 /* Invalid command interrupt */ 948c2ecf20Sopenharmony_ci#define HIFN_PUISR_DATAERR 0x4000 /* Data error interrupt */ 958c2ecf20Sopenharmony_ci#define HIFN_PUISR_SRCFIFO 0x2000 /* Source FIFO ready interrupt */ 968c2ecf20Sopenharmony_ci#define HIFN_PUISR_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */ 978c2ecf20Sopenharmony_ci#define HIFN_PUISR_DSTOVER 0x0200 /* Destination overrun interrupt */ 988c2ecf20Sopenharmony_ci#define HIFN_PUISR_SRCCMD 0x0080 /* Source command interrupt */ 998c2ecf20Sopenharmony_ci#define HIFN_PUISR_SRCCTX 0x0040 /* Source context interrupt */ 1008c2ecf20Sopenharmony_ci#define HIFN_PUISR_SRCDATA 0x0020 /* Source data interrupt */ 1018c2ecf20Sopenharmony_ci#define HIFN_PUISR_DSTDATA 0x0010 /* Destination data interrupt */ 1028c2ecf20Sopenharmony_ci#define HIFN_PUISR_DSTRESULT 0x0004 /* Destination result interrupt */ 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* Processing Unit Configuration Register (HIFN_0_PUCNFG) */ 1058c2ecf20Sopenharmony_ci#define HIFN_PUCNFG_DRAMMASK 0xe000 /* DRAM size mask */ 1068c2ecf20Sopenharmony_ci#define HIFN_PUCNFG_DSZ_256K 0x0000 /* 256k dram */ 1078c2ecf20Sopenharmony_ci#define HIFN_PUCNFG_DSZ_512K 0x2000 /* 512k dram */ 1088c2ecf20Sopenharmony_ci#define HIFN_PUCNFG_DSZ_1M 0x4000 /* 1m dram */ 1098c2ecf20Sopenharmony_ci#define HIFN_PUCNFG_DSZ_2M 0x6000 /* 2m dram */ 1108c2ecf20Sopenharmony_ci#define HIFN_PUCNFG_DSZ_4M 0x8000 /* 4m dram */ 1118c2ecf20Sopenharmony_ci#define HIFN_PUCNFG_DSZ_8M 0xa000 /* 8m dram */ 1128c2ecf20Sopenharmony_ci#define HIFN_PUNCFG_DSZ_16M 0xc000 /* 16m dram */ 1138c2ecf20Sopenharmony_ci#define HIFN_PUCNFG_DSZ_32M 0xe000 /* 32m dram */ 1148c2ecf20Sopenharmony_ci#define HIFN_PUCNFG_DRAMREFRESH 0x1800 /* DRAM refresh rate mask */ 1158c2ecf20Sopenharmony_ci#define HIFN_PUCNFG_DRFR_512 0x0000 /* 512 divisor of ECLK */ 1168c2ecf20Sopenharmony_ci#define HIFN_PUCNFG_DRFR_256 0x0800 /* 256 divisor of ECLK */ 1178c2ecf20Sopenharmony_ci#define HIFN_PUCNFG_DRFR_128 0x1000 /* 128 divisor of ECLK */ 1188c2ecf20Sopenharmony_ci#define HIFN_PUCNFG_TCALLPHASES 0x0200 /* your guess is as good as mine... */ 1198c2ecf20Sopenharmony_ci#define HIFN_PUCNFG_TCDRVTOTEM 0x0100 /* your guess is as good as mine... */ 1208c2ecf20Sopenharmony_ci#define HIFN_PUCNFG_BIGENDIAN 0x0080 /* DMA big endian mode */ 1218c2ecf20Sopenharmony_ci#define HIFN_PUCNFG_BUS32 0x0040 /* Bus width 32bits */ 1228c2ecf20Sopenharmony_ci#define HIFN_PUCNFG_BUS16 0x0000 /* Bus width 16 bits */ 1238c2ecf20Sopenharmony_ci#define HIFN_PUCNFG_CHIPID 0x0020 /* Allow chipid from PUSTAT */ 1248c2ecf20Sopenharmony_ci#define HIFN_PUCNFG_DRAM 0x0010 /* Context RAM is DRAM */ 1258c2ecf20Sopenharmony_ci#define HIFN_PUCNFG_SRAM 0x0000 /* Context RAM is SRAM */ 1268c2ecf20Sopenharmony_ci#define HIFN_PUCNFG_COMPSING 0x0004 /* Enable single compression context */ 1278c2ecf20Sopenharmony_ci#define HIFN_PUCNFG_ENCCNFG 0x0002 /* Encryption configuration */ 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/* Processing Unit Interrupt Enable Register (HIFN_0_PUIER) */ 1308c2ecf20Sopenharmony_ci#define HIFN_PUIER_CMDINVAL 0x8000 /* Invalid command interrupt */ 1318c2ecf20Sopenharmony_ci#define HIFN_PUIER_DATAERR 0x4000 /* Data error interrupt */ 1328c2ecf20Sopenharmony_ci#define HIFN_PUIER_SRCFIFO 0x2000 /* Source FIFO ready interrupt */ 1338c2ecf20Sopenharmony_ci#define HIFN_PUIER_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */ 1348c2ecf20Sopenharmony_ci#define HIFN_PUIER_DSTOVER 0x0200 /* Destination overrun interrupt */ 1358c2ecf20Sopenharmony_ci#define HIFN_PUIER_SRCCMD 0x0080 /* Source command interrupt */ 1368c2ecf20Sopenharmony_ci#define HIFN_PUIER_SRCCTX 0x0040 /* Source context interrupt */ 1378c2ecf20Sopenharmony_ci#define HIFN_PUIER_SRCDATA 0x0020 /* Source data interrupt */ 1388c2ecf20Sopenharmony_ci#define HIFN_PUIER_DSTDATA 0x0010 /* Destination data interrupt */ 1398c2ecf20Sopenharmony_ci#define HIFN_PUIER_DSTRESULT 0x0004 /* Destination result interrupt */ 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci/* Processing Unit Status Register/Chip ID (HIFN_0_PUSTAT) */ 1428c2ecf20Sopenharmony_ci#define HIFN_PUSTAT_CMDINVAL 0x8000 /* Invalid command interrupt */ 1438c2ecf20Sopenharmony_ci#define HIFN_PUSTAT_DATAERR 0x4000 /* Data error interrupt */ 1448c2ecf20Sopenharmony_ci#define HIFN_PUSTAT_SRCFIFO 0x2000 /* Source FIFO ready interrupt */ 1458c2ecf20Sopenharmony_ci#define HIFN_PUSTAT_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */ 1468c2ecf20Sopenharmony_ci#define HIFN_PUSTAT_DSTOVER 0x0200 /* Destination overrun interrupt */ 1478c2ecf20Sopenharmony_ci#define HIFN_PUSTAT_SRCCMD 0x0080 /* Source command interrupt */ 1488c2ecf20Sopenharmony_ci#define HIFN_PUSTAT_SRCCTX 0x0040 /* Source context interrupt */ 1498c2ecf20Sopenharmony_ci#define HIFN_PUSTAT_SRCDATA 0x0020 /* Source data interrupt */ 1508c2ecf20Sopenharmony_ci#define HIFN_PUSTAT_DSTDATA 0x0010 /* Destination data interrupt */ 1518c2ecf20Sopenharmony_ci#define HIFN_PUSTAT_DSTRESULT 0x0004 /* Destination result interrupt */ 1528c2ecf20Sopenharmony_ci#define HIFN_PUSTAT_CHIPREV 0x00ff /* Chip revision mask */ 1538c2ecf20Sopenharmony_ci#define HIFN_PUSTAT_CHIPENA 0xff00 /* Chip enabled mask */ 1548c2ecf20Sopenharmony_ci#define HIFN_PUSTAT_ENA_2 0x1100 /* Level 2 enabled */ 1558c2ecf20Sopenharmony_ci#define HIFN_PUSTAT_ENA_1 0x1000 /* Level 1 enabled */ 1568c2ecf20Sopenharmony_ci#define HIFN_PUSTAT_ENA_0 0x3000 /* Level 0 enabled */ 1578c2ecf20Sopenharmony_ci#define HIFN_PUSTAT_REV_2 0x0020 /* 7751 PT6/2 */ 1588c2ecf20Sopenharmony_ci#define HIFN_PUSTAT_REV_3 0x0030 /* 7751 PT6/3 */ 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/* FIFO Status Register (HIFN_0_FIFOSTAT) */ 1618c2ecf20Sopenharmony_ci#define HIFN_FIFOSTAT_SRC 0x7f00 /* Source FIFO available */ 1628c2ecf20Sopenharmony_ci#define HIFN_FIFOSTAT_DST 0x007f /* Destination FIFO available */ 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/* FIFO Configuration Register (HIFN_0_FIFOCNFG) */ 1658c2ecf20Sopenharmony_ci#define HIFN_FIFOCNFG_THRESHOLD 0x0400 /* must be written as 1 */ 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci/* 1688c2ecf20Sopenharmony_ci * DMA Interface Registers (offset from BASEREG1) 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_ci#define HIFN_1_DMA_CRAR 0x0c /* DMA Command Ring Address */ 1718c2ecf20Sopenharmony_ci#define HIFN_1_DMA_SRAR 0x1c /* DMA Source Ring Address */ 1728c2ecf20Sopenharmony_ci#define HIFN_1_DMA_RRAR 0x2c /* DMA Result Ring Address */ 1738c2ecf20Sopenharmony_ci#define HIFN_1_DMA_DRAR 0x3c /* DMA Destination Ring Address */ 1748c2ecf20Sopenharmony_ci#define HIFN_1_DMA_CSR 0x40 /* DMA Status and Control */ 1758c2ecf20Sopenharmony_ci#define HIFN_1_DMA_IER 0x44 /* DMA Interrupt Enable */ 1768c2ecf20Sopenharmony_ci#define HIFN_1_DMA_CNFG 0x48 /* DMA Configuration */ 1778c2ecf20Sopenharmony_ci#define HIFN_1_PLL 0x4c /* 795x: PLL config */ 1788c2ecf20Sopenharmony_ci#define HIFN_1_7811_RNGENA 0x60 /* 7811: rng enable */ 1798c2ecf20Sopenharmony_ci#define HIFN_1_7811_RNGCFG 0x64 /* 7811: rng config */ 1808c2ecf20Sopenharmony_ci#define HIFN_1_7811_RNGDAT 0x68 /* 7811: rng data */ 1818c2ecf20Sopenharmony_ci#define HIFN_1_7811_RNGSTS 0x6c /* 7811: rng status */ 1828c2ecf20Sopenharmony_ci#define HIFN_1_7811_MIPSRST 0x94 /* 7811: MIPS reset */ 1838c2ecf20Sopenharmony_ci#define HIFN_1_REVID 0x98 /* Revision ID */ 1848c2ecf20Sopenharmony_ci#define HIFN_1_UNLOCK_SECRET1 0xf4 1858c2ecf20Sopenharmony_ci#define HIFN_1_UNLOCK_SECRET2 0xfc 1868c2ecf20Sopenharmony_ci#define HIFN_1_PUB_RESET 0x204 /* Public/RNG Reset */ 1878c2ecf20Sopenharmony_ci#define HIFN_1_PUB_BASE 0x300 /* Public Base Address */ 1888c2ecf20Sopenharmony_ci#define HIFN_1_PUB_OPLEN 0x304 /* Public Operand Length */ 1898c2ecf20Sopenharmony_ci#define HIFN_1_PUB_OP 0x308 /* Public Operand */ 1908c2ecf20Sopenharmony_ci#define HIFN_1_PUB_STATUS 0x30c /* Public Status */ 1918c2ecf20Sopenharmony_ci#define HIFN_1_PUB_IEN 0x310 /* Public Interrupt enable */ 1928c2ecf20Sopenharmony_ci#define HIFN_1_RNG_CONFIG 0x314 /* RNG config */ 1938c2ecf20Sopenharmony_ci#define HIFN_1_RNG_DATA 0x318 /* RNG data */ 1948c2ecf20Sopenharmony_ci#define HIFN_1_PUB_MEM 0x400 /* start of Public key memory */ 1958c2ecf20Sopenharmony_ci#define HIFN_1_PUB_MEMEND 0xbff /* end of Public key memory */ 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci/* DMA Status and Control Register (HIFN_1_DMA_CSR) */ 1988c2ecf20Sopenharmony_ci#define HIFN_DMACSR_D_CTRLMASK 0xc0000000 /* Destinition Ring Control */ 1998c2ecf20Sopenharmony_ci#define HIFN_DMACSR_D_CTRL_NOP 0x00000000 /* Dest. Control: no-op */ 2008c2ecf20Sopenharmony_ci#define HIFN_DMACSR_D_CTRL_DIS 0x40000000 /* Dest. Control: disable */ 2018c2ecf20Sopenharmony_ci#define HIFN_DMACSR_D_CTRL_ENA 0x80000000 /* Dest. Control: enable */ 2028c2ecf20Sopenharmony_ci#define HIFN_DMACSR_D_ABORT 0x20000000 /* Destinition Ring PCIAbort */ 2038c2ecf20Sopenharmony_ci#define HIFN_DMACSR_D_DONE 0x10000000 /* Destinition Ring Done */ 2048c2ecf20Sopenharmony_ci#define HIFN_DMACSR_D_LAST 0x08000000 /* Destinition Ring Last */ 2058c2ecf20Sopenharmony_ci#define HIFN_DMACSR_D_WAIT 0x04000000 /* Destinition Ring Waiting */ 2068c2ecf20Sopenharmony_ci#define HIFN_DMACSR_D_OVER 0x02000000 /* Destinition Ring Overflow */ 2078c2ecf20Sopenharmony_ci#define HIFN_DMACSR_R_CTRL 0x00c00000 /* Result Ring Control */ 2088c2ecf20Sopenharmony_ci#define HIFN_DMACSR_R_CTRL_NOP 0x00000000 /* Result Control: no-op */ 2098c2ecf20Sopenharmony_ci#define HIFN_DMACSR_R_CTRL_DIS 0x00400000 /* Result Control: disable */ 2108c2ecf20Sopenharmony_ci#define HIFN_DMACSR_R_CTRL_ENA 0x00800000 /* Result Control: enable */ 2118c2ecf20Sopenharmony_ci#define HIFN_DMACSR_R_ABORT 0x00200000 /* Result Ring PCI Abort */ 2128c2ecf20Sopenharmony_ci#define HIFN_DMACSR_R_DONE 0x00100000 /* Result Ring Done */ 2138c2ecf20Sopenharmony_ci#define HIFN_DMACSR_R_LAST 0x00080000 /* Result Ring Last */ 2148c2ecf20Sopenharmony_ci#define HIFN_DMACSR_R_WAIT 0x00040000 /* Result Ring Waiting */ 2158c2ecf20Sopenharmony_ci#define HIFN_DMACSR_R_OVER 0x00020000 /* Result Ring Overflow */ 2168c2ecf20Sopenharmony_ci#define HIFN_DMACSR_S_CTRL 0x0000c000 /* Source Ring Control */ 2178c2ecf20Sopenharmony_ci#define HIFN_DMACSR_S_CTRL_NOP 0x00000000 /* Source Control: no-op */ 2188c2ecf20Sopenharmony_ci#define HIFN_DMACSR_S_CTRL_DIS 0x00004000 /* Source Control: disable */ 2198c2ecf20Sopenharmony_ci#define HIFN_DMACSR_S_CTRL_ENA 0x00008000 /* Source Control: enable */ 2208c2ecf20Sopenharmony_ci#define HIFN_DMACSR_S_ABORT 0x00002000 /* Source Ring PCI Abort */ 2218c2ecf20Sopenharmony_ci#define HIFN_DMACSR_S_DONE 0x00001000 /* Source Ring Done */ 2228c2ecf20Sopenharmony_ci#define HIFN_DMACSR_S_LAST 0x00000800 /* Source Ring Last */ 2238c2ecf20Sopenharmony_ci#define HIFN_DMACSR_S_WAIT 0x00000400 /* Source Ring Waiting */ 2248c2ecf20Sopenharmony_ci#define HIFN_DMACSR_ILLW 0x00000200 /* Illegal write (7811 only) */ 2258c2ecf20Sopenharmony_ci#define HIFN_DMACSR_ILLR 0x00000100 /* Illegal read (7811 only) */ 2268c2ecf20Sopenharmony_ci#define HIFN_DMACSR_C_CTRL 0x000000c0 /* Command Ring Control */ 2278c2ecf20Sopenharmony_ci#define HIFN_DMACSR_C_CTRL_NOP 0x00000000 /* Command Control: no-op */ 2288c2ecf20Sopenharmony_ci#define HIFN_DMACSR_C_CTRL_DIS 0x00000040 /* Command Control: disable */ 2298c2ecf20Sopenharmony_ci#define HIFN_DMACSR_C_CTRL_ENA 0x00000080 /* Command Control: enable */ 2308c2ecf20Sopenharmony_ci#define HIFN_DMACSR_C_ABORT 0x00000020 /* Command Ring PCI Abort */ 2318c2ecf20Sopenharmony_ci#define HIFN_DMACSR_C_DONE 0x00000010 /* Command Ring Done */ 2328c2ecf20Sopenharmony_ci#define HIFN_DMACSR_C_LAST 0x00000008 /* Command Ring Last */ 2338c2ecf20Sopenharmony_ci#define HIFN_DMACSR_C_WAIT 0x00000004 /* Command Ring Waiting */ 2348c2ecf20Sopenharmony_ci#define HIFN_DMACSR_PUBDONE 0x00000002 /* Public op done (7951 only) */ 2358c2ecf20Sopenharmony_ci#define HIFN_DMACSR_ENGINE 0x00000001 /* Command Ring Engine IRQ */ 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci/* DMA Interrupt Enable Register (HIFN_1_DMA_IER) */ 2388c2ecf20Sopenharmony_ci#define HIFN_DMAIER_D_ABORT 0x20000000 /* Destination Ring PCIAbort */ 2398c2ecf20Sopenharmony_ci#define HIFN_DMAIER_D_DONE 0x10000000 /* Destination Ring Done */ 2408c2ecf20Sopenharmony_ci#define HIFN_DMAIER_D_LAST 0x08000000 /* Destination Ring Last */ 2418c2ecf20Sopenharmony_ci#define HIFN_DMAIER_D_WAIT 0x04000000 /* Destination Ring Waiting */ 2428c2ecf20Sopenharmony_ci#define HIFN_DMAIER_D_OVER 0x02000000 /* Destination Ring Overflow */ 2438c2ecf20Sopenharmony_ci#define HIFN_DMAIER_R_ABORT 0x00200000 /* Result Ring PCI Abort */ 2448c2ecf20Sopenharmony_ci#define HIFN_DMAIER_R_DONE 0x00100000 /* Result Ring Done */ 2458c2ecf20Sopenharmony_ci#define HIFN_DMAIER_R_LAST 0x00080000 /* Result Ring Last */ 2468c2ecf20Sopenharmony_ci#define HIFN_DMAIER_R_WAIT 0x00040000 /* Result Ring Waiting */ 2478c2ecf20Sopenharmony_ci#define HIFN_DMAIER_R_OVER 0x00020000 /* Result Ring Overflow */ 2488c2ecf20Sopenharmony_ci#define HIFN_DMAIER_S_ABORT 0x00002000 /* Source Ring PCI Abort */ 2498c2ecf20Sopenharmony_ci#define HIFN_DMAIER_S_DONE 0x00001000 /* Source Ring Done */ 2508c2ecf20Sopenharmony_ci#define HIFN_DMAIER_S_LAST 0x00000800 /* Source Ring Last */ 2518c2ecf20Sopenharmony_ci#define HIFN_DMAIER_S_WAIT 0x00000400 /* Source Ring Waiting */ 2528c2ecf20Sopenharmony_ci#define HIFN_DMAIER_ILLW 0x00000200 /* Illegal write (7811 only) */ 2538c2ecf20Sopenharmony_ci#define HIFN_DMAIER_ILLR 0x00000100 /* Illegal read (7811 only) */ 2548c2ecf20Sopenharmony_ci#define HIFN_DMAIER_C_ABORT 0x00000020 /* Command Ring PCI Abort */ 2558c2ecf20Sopenharmony_ci#define HIFN_DMAIER_C_DONE 0x00000010 /* Command Ring Done */ 2568c2ecf20Sopenharmony_ci#define HIFN_DMAIER_C_LAST 0x00000008 /* Command Ring Last */ 2578c2ecf20Sopenharmony_ci#define HIFN_DMAIER_C_WAIT 0x00000004 /* Command Ring Waiting */ 2588c2ecf20Sopenharmony_ci#define HIFN_DMAIER_PUBDONE 0x00000002 /* public op done (7951 only) */ 2598c2ecf20Sopenharmony_ci#define HIFN_DMAIER_ENGINE 0x00000001 /* Engine IRQ */ 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci/* DMA Configuration Register (HIFN_1_DMA_CNFG) */ 2628c2ecf20Sopenharmony_ci#define HIFN_DMACNFG_BIGENDIAN 0x10000000 /* big endian mode */ 2638c2ecf20Sopenharmony_ci#define HIFN_DMACNFG_POLLFREQ 0x00ff0000 /* Poll frequency mask */ 2648c2ecf20Sopenharmony_ci#define HIFN_DMACNFG_UNLOCK 0x00000800 2658c2ecf20Sopenharmony_ci#define HIFN_DMACNFG_POLLINVAL 0x00000700 /* Invalid Poll Scalar */ 2668c2ecf20Sopenharmony_ci#define HIFN_DMACNFG_LAST 0x00000010 /* Host control LAST bit */ 2678c2ecf20Sopenharmony_ci#define HIFN_DMACNFG_MODE 0x00000004 /* DMA mode */ 2688c2ecf20Sopenharmony_ci#define HIFN_DMACNFG_DMARESET 0x00000002 /* DMA Reset # */ 2698c2ecf20Sopenharmony_ci#define HIFN_DMACNFG_MSTRESET 0x00000001 /* Master Reset # */ 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci/* PLL configuration register */ 2728c2ecf20Sopenharmony_ci#define HIFN_PLL_REF_CLK_HBI 0x00000000 /* HBI reference clock */ 2738c2ecf20Sopenharmony_ci#define HIFN_PLL_REF_CLK_PLL 0x00000001 /* PLL reference clock */ 2748c2ecf20Sopenharmony_ci#define HIFN_PLL_BP 0x00000002 /* Reference clock bypass */ 2758c2ecf20Sopenharmony_ci#define HIFN_PLL_PK_CLK_HBI 0x00000000 /* PK engine HBI clock */ 2768c2ecf20Sopenharmony_ci#define HIFN_PLL_PK_CLK_PLL 0x00000008 /* PK engine PLL clock */ 2778c2ecf20Sopenharmony_ci#define HIFN_PLL_PE_CLK_HBI 0x00000000 /* PE engine HBI clock */ 2788c2ecf20Sopenharmony_ci#define HIFN_PLL_PE_CLK_PLL 0x00000010 /* PE engine PLL clock */ 2798c2ecf20Sopenharmony_ci#define HIFN_PLL_RESERVED_1 0x00000400 /* Reserved bit, must be 1 */ 2808c2ecf20Sopenharmony_ci#define HIFN_PLL_ND_SHIFT 11 /* Clock multiplier shift */ 2818c2ecf20Sopenharmony_ci#define HIFN_PLL_ND_MULT_2 0x00000000 /* PLL clock multiplier 2 */ 2828c2ecf20Sopenharmony_ci#define HIFN_PLL_ND_MULT_4 0x00000800 /* PLL clock multiplier 4 */ 2838c2ecf20Sopenharmony_ci#define HIFN_PLL_ND_MULT_6 0x00001000 /* PLL clock multiplier 6 */ 2848c2ecf20Sopenharmony_ci#define HIFN_PLL_ND_MULT_8 0x00001800 /* PLL clock multiplier 8 */ 2858c2ecf20Sopenharmony_ci#define HIFN_PLL_ND_MULT_10 0x00002000 /* PLL clock multiplier 10 */ 2868c2ecf20Sopenharmony_ci#define HIFN_PLL_ND_MULT_12 0x00002800 /* PLL clock multiplier 12 */ 2878c2ecf20Sopenharmony_ci#define HIFN_PLL_IS_1_8 0x00000000 /* charge pump (mult. 1-8) */ 2888c2ecf20Sopenharmony_ci#define HIFN_PLL_IS_9_12 0x00010000 /* charge pump (mult. 9-12) */ 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci#define HIFN_PLL_FCK_MAX 266 /* Maximum PLL frequency */ 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci/* Public key reset register (HIFN_1_PUB_RESET) */ 2938c2ecf20Sopenharmony_ci#define HIFN_PUBRST_RESET 0x00000001 /* reset public/rng unit */ 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci/* Public base address register (HIFN_1_PUB_BASE) */ 2968c2ecf20Sopenharmony_ci#define HIFN_PUBBASE_ADDR 0x00003fff /* base address */ 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci/* Public operand length register (HIFN_1_PUB_OPLEN) */ 2998c2ecf20Sopenharmony_ci#define HIFN_PUBOPLEN_MOD_M 0x0000007f /* modulus length mask */ 3008c2ecf20Sopenharmony_ci#define HIFN_PUBOPLEN_MOD_S 0 /* modulus length shift */ 3018c2ecf20Sopenharmony_ci#define HIFN_PUBOPLEN_EXP_M 0x0003ff80 /* exponent length mask */ 3028c2ecf20Sopenharmony_ci#define HIFN_PUBOPLEN_EXP_S 7 /* exponent length shift */ 3038c2ecf20Sopenharmony_ci#define HIFN_PUBOPLEN_RED_M 0x003c0000 /* reducend length mask */ 3048c2ecf20Sopenharmony_ci#define HIFN_PUBOPLEN_RED_S 18 /* reducend length shift */ 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci/* Public operation register (HIFN_1_PUB_OP) */ 3078c2ecf20Sopenharmony_ci#define HIFN_PUBOP_AOFFSET_M 0x0000007f /* A offset mask */ 3088c2ecf20Sopenharmony_ci#define HIFN_PUBOP_AOFFSET_S 0 /* A offset shift */ 3098c2ecf20Sopenharmony_ci#define HIFN_PUBOP_BOFFSET_M 0x00000f80 /* B offset mask */ 3108c2ecf20Sopenharmony_ci#define HIFN_PUBOP_BOFFSET_S 7 /* B offset shift */ 3118c2ecf20Sopenharmony_ci#define HIFN_PUBOP_MOFFSET_M 0x0003f000 /* M offset mask */ 3128c2ecf20Sopenharmony_ci#define HIFN_PUBOP_MOFFSET_S 12 /* M offset shift */ 3138c2ecf20Sopenharmony_ci#define HIFN_PUBOP_OP_MASK 0x003c0000 /* Opcode: */ 3148c2ecf20Sopenharmony_ci#define HIFN_PUBOP_OP_NOP 0x00000000 /* NOP */ 3158c2ecf20Sopenharmony_ci#define HIFN_PUBOP_OP_ADD 0x00040000 /* ADD */ 3168c2ecf20Sopenharmony_ci#define HIFN_PUBOP_OP_ADDC 0x00080000 /* ADD w/carry */ 3178c2ecf20Sopenharmony_ci#define HIFN_PUBOP_OP_SUB 0x000c0000 /* SUB */ 3188c2ecf20Sopenharmony_ci#define HIFN_PUBOP_OP_SUBC 0x00100000 /* SUB w/carry */ 3198c2ecf20Sopenharmony_ci#define HIFN_PUBOP_OP_MODADD 0x00140000 /* Modular ADD */ 3208c2ecf20Sopenharmony_ci#define HIFN_PUBOP_OP_MODSUB 0x00180000 /* Modular SUB */ 3218c2ecf20Sopenharmony_ci#define HIFN_PUBOP_OP_INCA 0x001c0000 /* INC A */ 3228c2ecf20Sopenharmony_ci#define HIFN_PUBOP_OP_DECA 0x00200000 /* DEC A */ 3238c2ecf20Sopenharmony_ci#define HIFN_PUBOP_OP_MULT 0x00240000 /* MULT */ 3248c2ecf20Sopenharmony_ci#define HIFN_PUBOP_OP_MODMULT 0x00280000 /* Modular MULT */ 3258c2ecf20Sopenharmony_ci#define HIFN_PUBOP_OP_MODRED 0x002c0000 /* Modular RED */ 3268c2ecf20Sopenharmony_ci#define HIFN_PUBOP_OP_MODEXP 0x00300000 /* Modular EXP */ 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci/* Public status register (HIFN_1_PUB_STATUS) */ 3298c2ecf20Sopenharmony_ci#define HIFN_PUBSTS_DONE 0x00000001 /* operation done */ 3308c2ecf20Sopenharmony_ci#define HIFN_PUBSTS_CARRY 0x00000002 /* carry */ 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci/* Public interrupt enable register (HIFN_1_PUB_IEN) */ 3338c2ecf20Sopenharmony_ci#define HIFN_PUBIEN_DONE 0x00000001 /* operation done interrupt */ 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci/* Random number generator config register (HIFN_1_RNG_CONFIG) */ 3368c2ecf20Sopenharmony_ci#define HIFN_RNGCFG_ENA 0x00000001 /* enable rng */ 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci#define HIFN_NAMESIZE 32 3398c2ecf20Sopenharmony_ci#define HIFN_MAX_RESULT_ORDER 5 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci#define HIFN_D_CMD_RSIZE (24 * 1) 3428c2ecf20Sopenharmony_ci#define HIFN_D_SRC_RSIZE (80 * 1) 3438c2ecf20Sopenharmony_ci#define HIFN_D_DST_RSIZE (80 * 1) 3448c2ecf20Sopenharmony_ci#define HIFN_D_RES_RSIZE (24 * 1) 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci#define HIFN_D_DST_DALIGN 4 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci#define HIFN_QUEUE_LENGTH (HIFN_D_CMD_RSIZE - 1) 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci#define AES_MIN_KEY_SIZE 16 3518c2ecf20Sopenharmony_ci#define AES_MAX_KEY_SIZE 32 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci#define HIFN_DES_KEY_LENGTH 8 3548c2ecf20Sopenharmony_ci#define HIFN_3DES_KEY_LENGTH 24 3558c2ecf20Sopenharmony_ci#define HIFN_MAX_CRYPT_KEY_LENGTH AES_MAX_KEY_SIZE 3568c2ecf20Sopenharmony_ci#define HIFN_IV_LENGTH 8 3578c2ecf20Sopenharmony_ci#define HIFN_AES_IV_LENGTH 16 3588c2ecf20Sopenharmony_ci#define HIFN_MAX_IV_LENGTH HIFN_AES_IV_LENGTH 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci#define HIFN_MAC_KEY_LENGTH 64 3618c2ecf20Sopenharmony_ci#define HIFN_MD5_LENGTH 16 3628c2ecf20Sopenharmony_ci#define HIFN_SHA1_LENGTH 20 3638c2ecf20Sopenharmony_ci#define HIFN_MAC_TRUNC_LENGTH 12 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci#define HIFN_MAX_COMMAND (8 + 8 + 8 + 64 + 260) 3668c2ecf20Sopenharmony_ci#define HIFN_MAX_RESULT (8 + 4 + 4 + 20 + 4) 3678c2ecf20Sopenharmony_ci#define HIFN_USED_RESULT 12 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistruct hifn_desc { 3708c2ecf20Sopenharmony_ci volatile __le32 l; 3718c2ecf20Sopenharmony_ci volatile __le32 p; 3728c2ecf20Sopenharmony_ci}; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistruct hifn_dma { 3758c2ecf20Sopenharmony_ci struct hifn_desc cmdr[HIFN_D_CMD_RSIZE + 1]; 3768c2ecf20Sopenharmony_ci struct hifn_desc srcr[HIFN_D_SRC_RSIZE + 1]; 3778c2ecf20Sopenharmony_ci struct hifn_desc dstr[HIFN_D_DST_RSIZE + 1]; 3788c2ecf20Sopenharmony_ci struct hifn_desc resr[HIFN_D_RES_RSIZE + 1]; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci u8 command_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_COMMAND]; 3818c2ecf20Sopenharmony_ci u8 result_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_RESULT]; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* 3848c2ecf20Sopenharmony_ci * Our current positions for insertion and removal from the descriptor 3858c2ecf20Sopenharmony_ci * rings. 3868c2ecf20Sopenharmony_ci */ 3878c2ecf20Sopenharmony_ci volatile int cmdi, srci, dsti, resi; 3888c2ecf20Sopenharmony_ci volatile int cmdu, srcu, dstu, resu; 3898c2ecf20Sopenharmony_ci int cmdk, srck, dstk, resk; 3908c2ecf20Sopenharmony_ci}; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci#define HIFN_FLAG_CMD_BUSY (1 << 0) 3938c2ecf20Sopenharmony_ci#define HIFN_FLAG_SRC_BUSY (1 << 1) 3948c2ecf20Sopenharmony_ci#define HIFN_FLAG_DST_BUSY (1 << 2) 3958c2ecf20Sopenharmony_ci#define HIFN_FLAG_RES_BUSY (1 << 3) 3968c2ecf20Sopenharmony_ci#define HIFN_FLAG_OLD_KEY (1 << 4) 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci#define HIFN_DEFAULT_ACTIVE_NUM 5 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistruct hifn_device { 4018c2ecf20Sopenharmony_ci char name[HIFN_NAMESIZE]; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci int irq; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci struct pci_dev *pdev; 4068c2ecf20Sopenharmony_ci void __iomem *bar[3]; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci void *desc_virt; 4098c2ecf20Sopenharmony_ci dma_addr_t desc_dma; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci u32 dmareg; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci void *sa[HIFN_D_RES_RSIZE]; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci spinlock_t lock; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci u32 flags; 4188c2ecf20Sopenharmony_ci int active, started; 4198c2ecf20Sopenharmony_ci struct delayed_work work; 4208c2ecf20Sopenharmony_ci unsigned long reset; 4218c2ecf20Sopenharmony_ci unsigned long success; 4228c2ecf20Sopenharmony_ci unsigned long prev_success; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci u8 snum; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci struct tasklet_struct tasklet; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci struct crypto_queue queue; 4298c2ecf20Sopenharmony_ci struct list_head alg_list; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci unsigned int pk_clk_freq; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_HIFN_795X_RNG 4348c2ecf20Sopenharmony_ci unsigned int rng_wait_time; 4358c2ecf20Sopenharmony_ci ktime_t rngtime; 4368c2ecf20Sopenharmony_ci struct hwrng rng; 4378c2ecf20Sopenharmony_ci#endif 4388c2ecf20Sopenharmony_ci}; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci#define HIFN_D_LENGTH 0x0000ffff 4418c2ecf20Sopenharmony_ci#define HIFN_D_NOINVALID 0x01000000 4428c2ecf20Sopenharmony_ci#define HIFN_D_MASKDONEIRQ 0x02000000 4438c2ecf20Sopenharmony_ci#define HIFN_D_DESTOVER 0x04000000 4448c2ecf20Sopenharmony_ci#define HIFN_D_OVER 0x08000000 4458c2ecf20Sopenharmony_ci#define HIFN_D_LAST 0x20000000 4468c2ecf20Sopenharmony_ci#define HIFN_D_JUMP 0x40000000 4478c2ecf20Sopenharmony_ci#define HIFN_D_VALID 0x80000000 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistruct hifn_base_command { 4508c2ecf20Sopenharmony_ci volatile __le16 masks; 4518c2ecf20Sopenharmony_ci volatile __le16 session_num; 4528c2ecf20Sopenharmony_ci volatile __le16 total_source_count; 4538c2ecf20Sopenharmony_ci volatile __le16 total_dest_count; 4548c2ecf20Sopenharmony_ci}; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci#define HIFN_BASE_CMD_COMP 0x0100 /* enable compression engine */ 4578c2ecf20Sopenharmony_ci#define HIFN_BASE_CMD_PAD 0x0200 /* enable padding engine */ 4588c2ecf20Sopenharmony_ci#define HIFN_BASE_CMD_MAC 0x0400 /* enable MAC engine */ 4598c2ecf20Sopenharmony_ci#define HIFN_BASE_CMD_CRYPT 0x0800 /* enable crypt engine */ 4608c2ecf20Sopenharmony_ci#define HIFN_BASE_CMD_DECODE 0x2000 4618c2ecf20Sopenharmony_ci#define HIFN_BASE_CMD_SRCLEN_M 0xc000 4628c2ecf20Sopenharmony_ci#define HIFN_BASE_CMD_SRCLEN_S 14 4638c2ecf20Sopenharmony_ci#define HIFN_BASE_CMD_DSTLEN_M 0x3000 4648c2ecf20Sopenharmony_ci#define HIFN_BASE_CMD_DSTLEN_S 12 4658c2ecf20Sopenharmony_ci#define HIFN_BASE_CMD_LENMASK_HI 0x30000 4668c2ecf20Sopenharmony_ci#define HIFN_BASE_CMD_LENMASK_LO 0x0ffff 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci/* 4698c2ecf20Sopenharmony_ci * Structure to help build up the command data structure. 4708c2ecf20Sopenharmony_ci */ 4718c2ecf20Sopenharmony_cistruct hifn_crypt_command { 4728c2ecf20Sopenharmony_ci volatile __le16 masks; 4738c2ecf20Sopenharmony_ci volatile __le16 header_skip; 4748c2ecf20Sopenharmony_ci volatile __le16 source_count; 4758c2ecf20Sopenharmony_ci volatile __le16 reserved; 4768c2ecf20Sopenharmony_ci}; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci#define HIFN_CRYPT_CMD_ALG_MASK 0x0003 /* algorithm: */ 4798c2ecf20Sopenharmony_ci#define HIFN_CRYPT_CMD_ALG_DES 0x0000 /* DES */ 4808c2ecf20Sopenharmony_ci#define HIFN_CRYPT_CMD_ALG_3DES 0x0001 /* 3DES */ 4818c2ecf20Sopenharmony_ci#define HIFN_CRYPT_CMD_ALG_RC4 0x0002 /* RC4 */ 4828c2ecf20Sopenharmony_ci#define HIFN_CRYPT_CMD_ALG_AES 0x0003 /* AES */ 4838c2ecf20Sopenharmony_ci#define HIFN_CRYPT_CMD_MODE_MASK 0x0018 /* Encrypt mode: */ 4848c2ecf20Sopenharmony_ci#define HIFN_CRYPT_CMD_MODE_ECB 0x0000 /* ECB */ 4858c2ecf20Sopenharmony_ci#define HIFN_CRYPT_CMD_MODE_CBC 0x0008 /* CBC */ 4868c2ecf20Sopenharmony_ci#define HIFN_CRYPT_CMD_MODE_CFB 0x0010 /* CFB */ 4878c2ecf20Sopenharmony_ci#define HIFN_CRYPT_CMD_MODE_OFB 0x0018 /* OFB */ 4888c2ecf20Sopenharmony_ci#define HIFN_CRYPT_CMD_CLR_CTX 0x0040 /* clear context */ 4898c2ecf20Sopenharmony_ci#define HIFN_CRYPT_CMD_KSZ_MASK 0x0600 /* AES key size: */ 4908c2ecf20Sopenharmony_ci#define HIFN_CRYPT_CMD_KSZ_128 0x0000 /* 128 bit */ 4918c2ecf20Sopenharmony_ci#define HIFN_CRYPT_CMD_KSZ_192 0x0200 /* 192 bit */ 4928c2ecf20Sopenharmony_ci#define HIFN_CRYPT_CMD_KSZ_256 0x0400 /* 256 bit */ 4938c2ecf20Sopenharmony_ci#define HIFN_CRYPT_CMD_NEW_KEY 0x0800 /* expect new key */ 4948c2ecf20Sopenharmony_ci#define HIFN_CRYPT_CMD_NEW_IV 0x1000 /* expect new iv */ 4958c2ecf20Sopenharmony_ci#define HIFN_CRYPT_CMD_SRCLEN_M 0xc000 4968c2ecf20Sopenharmony_ci#define HIFN_CRYPT_CMD_SRCLEN_S 14 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci/* 4998c2ecf20Sopenharmony_ci * Structure to help build up the command data structure. 5008c2ecf20Sopenharmony_ci */ 5018c2ecf20Sopenharmony_cistruct hifn_mac_command { 5028c2ecf20Sopenharmony_ci volatile __le16 masks; 5038c2ecf20Sopenharmony_ci volatile __le16 header_skip; 5048c2ecf20Sopenharmony_ci volatile __le16 source_count; 5058c2ecf20Sopenharmony_ci volatile __le16 reserved; 5068c2ecf20Sopenharmony_ci}; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci#define HIFN_MAC_CMD_ALG_MASK 0x0001 5098c2ecf20Sopenharmony_ci#define HIFN_MAC_CMD_ALG_SHA1 0x0000 5108c2ecf20Sopenharmony_ci#define HIFN_MAC_CMD_ALG_MD5 0x0001 5118c2ecf20Sopenharmony_ci#define HIFN_MAC_CMD_MODE_MASK 0x000c 5128c2ecf20Sopenharmony_ci#define HIFN_MAC_CMD_MODE_HMAC 0x0000 5138c2ecf20Sopenharmony_ci#define HIFN_MAC_CMD_MODE_SSL_MAC 0x0004 5148c2ecf20Sopenharmony_ci#define HIFN_MAC_CMD_MODE_HASH 0x0008 5158c2ecf20Sopenharmony_ci#define HIFN_MAC_CMD_MODE_FULL 0x0004 5168c2ecf20Sopenharmony_ci#define HIFN_MAC_CMD_TRUNC 0x0010 5178c2ecf20Sopenharmony_ci#define HIFN_MAC_CMD_RESULT 0x0020 5188c2ecf20Sopenharmony_ci#define HIFN_MAC_CMD_APPEND 0x0040 5198c2ecf20Sopenharmony_ci#define HIFN_MAC_CMD_SRCLEN_M 0xc000 5208c2ecf20Sopenharmony_ci#define HIFN_MAC_CMD_SRCLEN_S 14 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci/* 5238c2ecf20Sopenharmony_ci * MAC POS IPsec initiates authentication after encryption on encodes 5248c2ecf20Sopenharmony_ci * and before decryption on decodes. 5258c2ecf20Sopenharmony_ci */ 5268c2ecf20Sopenharmony_ci#define HIFN_MAC_CMD_POS_IPSEC 0x0200 5278c2ecf20Sopenharmony_ci#define HIFN_MAC_CMD_NEW_KEY 0x0800 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_cistruct hifn_comp_command { 5308c2ecf20Sopenharmony_ci volatile __le16 masks; 5318c2ecf20Sopenharmony_ci volatile __le16 header_skip; 5328c2ecf20Sopenharmony_ci volatile __le16 source_count; 5338c2ecf20Sopenharmony_ci volatile __le16 reserved; 5348c2ecf20Sopenharmony_ci}; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci#define HIFN_COMP_CMD_SRCLEN_M 0xc000 5378c2ecf20Sopenharmony_ci#define HIFN_COMP_CMD_SRCLEN_S 14 5388c2ecf20Sopenharmony_ci#define HIFN_COMP_CMD_ONE 0x0100 /* must be one */ 5398c2ecf20Sopenharmony_ci#define HIFN_COMP_CMD_CLEARHIST 0x0010 /* clear history */ 5408c2ecf20Sopenharmony_ci#define HIFN_COMP_CMD_UPDATEHIST 0x0008 /* update history */ 5418c2ecf20Sopenharmony_ci#define HIFN_COMP_CMD_LZS_STRIP0 0x0004 /* LZS: strip zero */ 5428c2ecf20Sopenharmony_ci#define HIFN_COMP_CMD_MPPC_RESTART 0x0004 /* MPPC: restart */ 5438c2ecf20Sopenharmony_ci#define HIFN_COMP_CMD_ALG_MASK 0x0001 /* compression mode: */ 5448c2ecf20Sopenharmony_ci#define HIFN_COMP_CMD_ALG_MPPC 0x0001 /* MPPC */ 5458c2ecf20Sopenharmony_ci#define HIFN_COMP_CMD_ALG_LZS 0x0000 /* LZS */ 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_cistruct hifn_base_result { 5488c2ecf20Sopenharmony_ci volatile __le16 flags; 5498c2ecf20Sopenharmony_ci volatile __le16 session; 5508c2ecf20Sopenharmony_ci volatile __le16 src_cnt; /* 15:0 of source count */ 5518c2ecf20Sopenharmony_ci volatile __le16 dst_cnt; /* 15:0 of dest count */ 5528c2ecf20Sopenharmony_ci}; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci#define HIFN_BASE_RES_DSTOVERRUN 0x0200 /* destination overrun */ 5558c2ecf20Sopenharmony_ci#define HIFN_BASE_RES_SRCLEN_M 0xc000 /* 17:16 of source count */ 5568c2ecf20Sopenharmony_ci#define HIFN_BASE_RES_SRCLEN_S 14 5578c2ecf20Sopenharmony_ci#define HIFN_BASE_RES_DSTLEN_M 0x3000 /* 17:16 of dest count */ 5588c2ecf20Sopenharmony_ci#define HIFN_BASE_RES_DSTLEN_S 12 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistruct hifn_comp_result { 5618c2ecf20Sopenharmony_ci volatile __le16 flags; 5628c2ecf20Sopenharmony_ci volatile __le16 crc; 5638c2ecf20Sopenharmony_ci}; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci#define HIFN_COMP_RES_LCB_M 0xff00 /* longitudinal check byte */ 5668c2ecf20Sopenharmony_ci#define HIFN_COMP_RES_LCB_S 8 5678c2ecf20Sopenharmony_ci#define HIFN_COMP_RES_RESTART 0x0004 /* MPPC: restart */ 5688c2ecf20Sopenharmony_ci#define HIFN_COMP_RES_ENDMARKER 0x0002 /* LZS: end marker seen */ 5698c2ecf20Sopenharmony_ci#define HIFN_COMP_RES_SRC_NOTZERO 0x0001 /* source expired */ 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistruct hifn_mac_result { 5728c2ecf20Sopenharmony_ci volatile __le16 flags; 5738c2ecf20Sopenharmony_ci volatile __le16 reserved; 5748c2ecf20Sopenharmony_ci /* followed by 0, 6, 8, or 10 u16's of the MAC, then crypt */ 5758c2ecf20Sopenharmony_ci}; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci#define HIFN_MAC_RES_MISCOMPARE 0x0002 /* compare failed */ 5788c2ecf20Sopenharmony_ci#define HIFN_MAC_RES_SRC_NOTZERO 0x0001 /* source expired */ 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_cistruct hifn_crypt_result { 5818c2ecf20Sopenharmony_ci volatile __le16 flags; 5828c2ecf20Sopenharmony_ci volatile __le16 reserved; 5838c2ecf20Sopenharmony_ci}; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci#define HIFN_CRYPT_RES_SRC_NOTZERO 0x0001 /* source expired */ 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci#ifndef HIFN_POLL_FREQUENCY 5888c2ecf20Sopenharmony_ci#define HIFN_POLL_FREQUENCY 0x1 5898c2ecf20Sopenharmony_ci#endif 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci#ifndef HIFN_POLL_SCALAR 5928c2ecf20Sopenharmony_ci#define HIFN_POLL_SCALAR 0x0 5938c2ecf20Sopenharmony_ci#endif 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci#define HIFN_MAX_SEGLEN 0xffff /* maximum dma segment len */ 5968c2ecf20Sopenharmony_ci#define HIFN_MAX_DMALEN 0x3ffff /* maximum dma length */ 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cistruct hifn_crypto_alg { 5998c2ecf20Sopenharmony_ci struct list_head entry; 6008c2ecf20Sopenharmony_ci struct skcipher_alg alg; 6018c2ecf20Sopenharmony_ci struct hifn_device *dev; 6028c2ecf20Sopenharmony_ci}; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci#define ASYNC_SCATTERLIST_CACHE 16 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci#define ASYNC_FLAGS_MISALIGNED (1 << 0) 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cistruct hifn_cipher_walk { 6098c2ecf20Sopenharmony_ci struct scatterlist cache[ASYNC_SCATTERLIST_CACHE]; 6108c2ecf20Sopenharmony_ci u32 flags; 6118c2ecf20Sopenharmony_ci int num; 6128c2ecf20Sopenharmony_ci}; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_cistruct hifn_context { 6158c2ecf20Sopenharmony_ci u8 key[HIFN_MAX_CRYPT_KEY_LENGTH]; 6168c2ecf20Sopenharmony_ci struct hifn_device *dev; 6178c2ecf20Sopenharmony_ci unsigned int keysize; 6188c2ecf20Sopenharmony_ci}; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_cistruct hifn_request_context { 6218c2ecf20Sopenharmony_ci u8 *iv; 6228c2ecf20Sopenharmony_ci unsigned int ivsize; 6238c2ecf20Sopenharmony_ci u8 op, type, mode, unused; 6248c2ecf20Sopenharmony_ci struct hifn_cipher_walk walk; 6258c2ecf20Sopenharmony_ci}; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci#define crypto_alg_to_hifn(a) container_of(a, struct hifn_crypto_alg, alg) 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cistatic inline u32 hifn_read_0(struct hifn_device *dev, u32 reg) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci return readl(dev->bar[0] + reg); 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_cistatic inline u32 hifn_read_1(struct hifn_device *dev, u32 reg) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci return readl(dev->bar[1] + reg); 6378c2ecf20Sopenharmony_ci} 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_cistatic inline void hifn_write_0(struct hifn_device *dev, u32 reg, u32 val) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci writel((__force u32)cpu_to_le32(val), dev->bar[0] + reg); 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_cistatic inline void hifn_write_1(struct hifn_device *dev, u32 reg, u32 val) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci writel((__force u32)cpu_to_le32(val), dev->bar[1] + reg); 6478c2ecf20Sopenharmony_ci} 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_cistatic void hifn_wait_puc(struct hifn_device *dev) 6508c2ecf20Sopenharmony_ci{ 6518c2ecf20Sopenharmony_ci int i; 6528c2ecf20Sopenharmony_ci u32 ret; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci for (i = 10000; i > 0; --i) { 6558c2ecf20Sopenharmony_ci ret = hifn_read_0(dev, HIFN_0_PUCTRL); 6568c2ecf20Sopenharmony_ci if (!(ret & HIFN_PUCTRL_RESET)) 6578c2ecf20Sopenharmony_ci break; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci udelay(1); 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci if (!i) 6638c2ecf20Sopenharmony_ci dev_err(&dev->pdev->dev, "Failed to reset PUC unit.\n"); 6648c2ecf20Sopenharmony_ci} 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_cistatic void hifn_reset_puc(struct hifn_device *dev) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci hifn_write_0(dev, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA); 6698c2ecf20Sopenharmony_ci hifn_wait_puc(dev); 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistatic void hifn_stop_device(struct hifn_device *dev) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CSR, 6758c2ecf20Sopenharmony_ci HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS | 6768c2ecf20Sopenharmony_ci HIFN_DMACSR_S_CTRL_DIS | HIFN_DMACSR_C_CTRL_DIS); 6778c2ecf20Sopenharmony_ci hifn_write_0(dev, HIFN_0_PUIER, 0); 6788c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_IER, 0); 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_cistatic void hifn_reset_dma(struct hifn_device *dev, int full) 6828c2ecf20Sopenharmony_ci{ 6838c2ecf20Sopenharmony_ci hifn_stop_device(dev); 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci /* 6868c2ecf20Sopenharmony_ci * Setting poll frequency and others to 0. 6878c2ecf20Sopenharmony_ci */ 6888c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | 6898c2ecf20Sopenharmony_ci HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); 6908c2ecf20Sopenharmony_ci mdelay(1); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci /* 6938c2ecf20Sopenharmony_ci * Reset DMA. 6948c2ecf20Sopenharmony_ci */ 6958c2ecf20Sopenharmony_ci if (full) { 6968c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MODE); 6978c2ecf20Sopenharmony_ci mdelay(1); 6988c2ecf20Sopenharmony_ci } else { 6998c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MODE | 7008c2ecf20Sopenharmony_ci HIFN_DMACNFG_MSTRESET); 7018c2ecf20Sopenharmony_ci hifn_reset_puc(dev); 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | 7058c2ecf20Sopenharmony_ci HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci hifn_reset_puc(dev); 7088c2ecf20Sopenharmony_ci} 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_cistatic u32 hifn_next_signature(u32 a, u_int cnt) 7118c2ecf20Sopenharmony_ci{ 7128c2ecf20Sopenharmony_ci int i; 7138c2ecf20Sopenharmony_ci u32 v; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci for (i = 0; i < cnt; i++) { 7168c2ecf20Sopenharmony_ci /* get the parity */ 7178c2ecf20Sopenharmony_ci v = a & 0x80080125; 7188c2ecf20Sopenharmony_ci v ^= v >> 16; 7198c2ecf20Sopenharmony_ci v ^= v >> 8; 7208c2ecf20Sopenharmony_ci v ^= v >> 4; 7218c2ecf20Sopenharmony_ci v ^= v >> 2; 7228c2ecf20Sopenharmony_ci v ^= v >> 1; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci a = (v & 1) ^ (a << 1); 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci return a; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_cistatic struct pci2id { 7318c2ecf20Sopenharmony_ci u_short pci_vendor; 7328c2ecf20Sopenharmony_ci u_short pci_prod; 7338c2ecf20Sopenharmony_ci char card_id[13]; 7348c2ecf20Sopenharmony_ci} pci2id[] = { 7358c2ecf20Sopenharmony_ci { 7368c2ecf20Sopenharmony_ci PCI_VENDOR_ID_HIFN, 7378c2ecf20Sopenharmony_ci PCI_DEVICE_ID_HIFN_7955, 7388c2ecf20Sopenharmony_ci { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 7398c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00 } 7408c2ecf20Sopenharmony_ci }, 7418c2ecf20Sopenharmony_ci { 7428c2ecf20Sopenharmony_ci PCI_VENDOR_ID_HIFN, 7438c2ecf20Sopenharmony_ci PCI_DEVICE_ID_HIFN_7956, 7448c2ecf20Sopenharmony_ci { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 7458c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00 } 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci}; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_HIFN_795X_RNG 7508c2ecf20Sopenharmony_cistatic int hifn_rng_data_present(struct hwrng *rng, int wait) 7518c2ecf20Sopenharmony_ci{ 7528c2ecf20Sopenharmony_ci struct hifn_device *dev = (struct hifn_device *)rng->priv; 7538c2ecf20Sopenharmony_ci s64 nsec; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci nsec = ktime_to_ns(ktime_sub(ktime_get(), dev->rngtime)); 7568c2ecf20Sopenharmony_ci nsec -= dev->rng_wait_time; 7578c2ecf20Sopenharmony_ci if (nsec <= 0) 7588c2ecf20Sopenharmony_ci return 1; 7598c2ecf20Sopenharmony_ci if (!wait) 7608c2ecf20Sopenharmony_ci return 0; 7618c2ecf20Sopenharmony_ci ndelay(nsec); 7628c2ecf20Sopenharmony_ci return 1; 7638c2ecf20Sopenharmony_ci} 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_cistatic int hifn_rng_data_read(struct hwrng *rng, u32 *data) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci struct hifn_device *dev = (struct hifn_device *)rng->priv; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci *data = hifn_read_1(dev, HIFN_1_RNG_DATA); 7708c2ecf20Sopenharmony_ci dev->rngtime = ktime_get(); 7718c2ecf20Sopenharmony_ci return 4; 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic int hifn_register_rng(struct hifn_device *dev) 7758c2ecf20Sopenharmony_ci{ 7768c2ecf20Sopenharmony_ci /* 7778c2ecf20Sopenharmony_ci * We must wait at least 256 Pk_clk cycles between two reads of the rng. 7788c2ecf20Sopenharmony_ci */ 7798c2ecf20Sopenharmony_ci dev->rng_wait_time = DIV_ROUND_UP_ULL(NSEC_PER_SEC, 7808c2ecf20Sopenharmony_ci dev->pk_clk_freq) * 256; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci dev->rng.name = dev->name; 7838c2ecf20Sopenharmony_ci dev->rng.data_present = hifn_rng_data_present; 7848c2ecf20Sopenharmony_ci dev->rng.data_read = hifn_rng_data_read; 7858c2ecf20Sopenharmony_ci dev->rng.priv = (unsigned long)dev; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci return hwrng_register(&dev->rng); 7888c2ecf20Sopenharmony_ci} 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_cistatic void hifn_unregister_rng(struct hifn_device *dev) 7918c2ecf20Sopenharmony_ci{ 7928c2ecf20Sopenharmony_ci hwrng_unregister(&dev->rng); 7938c2ecf20Sopenharmony_ci} 7948c2ecf20Sopenharmony_ci#else 7958c2ecf20Sopenharmony_ci#define hifn_register_rng(dev) 0 7968c2ecf20Sopenharmony_ci#define hifn_unregister_rng(dev) 7978c2ecf20Sopenharmony_ci#endif 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cistatic int hifn_init_pubrng(struct hifn_device *dev) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci int i; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_PUB_RESET, hifn_read_1(dev, HIFN_1_PUB_RESET) | 8048c2ecf20Sopenharmony_ci HIFN_PUBRST_RESET); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci for (i = 100; i > 0; --i) { 8078c2ecf20Sopenharmony_ci mdelay(1); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci if ((hifn_read_1(dev, HIFN_1_PUB_RESET) & HIFN_PUBRST_RESET) == 0) 8108c2ecf20Sopenharmony_ci break; 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci if (!i) { 8148c2ecf20Sopenharmony_ci dev_err(&dev->pdev->dev, "Failed to initialise public key engine.\n"); 8158c2ecf20Sopenharmony_ci } else { 8168c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_PUB_IEN, HIFN_PUBIEN_DONE); 8178c2ecf20Sopenharmony_ci dev->dmareg |= HIFN_DMAIER_PUBDONE; 8188c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci dev_dbg(&dev->pdev->dev, "Public key engine has been successfully initialised.\n"); 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci /* Enable RNG engine. */ 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_RNG_CONFIG, 8268c2ecf20Sopenharmony_ci hifn_read_1(dev, HIFN_1_RNG_CONFIG) | HIFN_RNGCFG_ENA); 8278c2ecf20Sopenharmony_ci dev_dbg(&dev->pdev->dev, "RNG engine has been successfully initialised.\n"); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_HIFN_795X_RNG 8308c2ecf20Sopenharmony_ci /* First value must be discarded */ 8318c2ecf20Sopenharmony_ci hifn_read_1(dev, HIFN_1_RNG_DATA); 8328c2ecf20Sopenharmony_ci dev->rngtime = ktime_get(); 8338c2ecf20Sopenharmony_ci#endif 8348c2ecf20Sopenharmony_ci return 0; 8358c2ecf20Sopenharmony_ci} 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_cistatic int hifn_enable_crypto(struct hifn_device *dev) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci u32 dmacfg, addr; 8408c2ecf20Sopenharmony_ci char *offtbl = NULL; 8418c2ecf20Sopenharmony_ci int i; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pci2id); i++) { 8448c2ecf20Sopenharmony_ci if (pci2id[i].pci_vendor == dev->pdev->vendor && 8458c2ecf20Sopenharmony_ci pci2id[i].pci_prod == dev->pdev->device) { 8468c2ecf20Sopenharmony_ci offtbl = pci2id[i].card_id; 8478c2ecf20Sopenharmony_ci break; 8488c2ecf20Sopenharmony_ci } 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci if (!offtbl) { 8528c2ecf20Sopenharmony_ci dev_err(&dev->pdev->dev, "Unknown card!\n"); 8538c2ecf20Sopenharmony_ci return -ENODEV; 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci dmacfg = hifn_read_1(dev, HIFN_1_DMA_CNFG); 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CNFG, 8598c2ecf20Sopenharmony_ci HIFN_DMACNFG_UNLOCK | HIFN_DMACNFG_MSTRESET | 8608c2ecf20Sopenharmony_ci HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); 8618c2ecf20Sopenharmony_ci mdelay(1); 8628c2ecf20Sopenharmony_ci addr = hifn_read_1(dev, HIFN_1_UNLOCK_SECRET1); 8638c2ecf20Sopenharmony_ci mdelay(1); 8648c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_UNLOCK_SECRET2, 0); 8658c2ecf20Sopenharmony_ci mdelay(1); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci for (i = 0; i < 12; ++i) { 8688c2ecf20Sopenharmony_ci addr = hifn_next_signature(addr, offtbl[i] + 0x101); 8698c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_UNLOCK_SECRET2, addr); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci mdelay(1); 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CNFG, dmacfg); 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci dev_dbg(&dev->pdev->dev, "%s %s.\n", dev->name, pci_name(dev->pdev)); 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci return 0; 8788c2ecf20Sopenharmony_ci} 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_cistatic void hifn_init_dma(struct hifn_device *dev) 8818c2ecf20Sopenharmony_ci{ 8828c2ecf20Sopenharmony_ci struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; 8838c2ecf20Sopenharmony_ci u32 dptr = dev->desc_dma; 8848c2ecf20Sopenharmony_ci int i; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci for (i = 0; i < HIFN_D_CMD_RSIZE; ++i) 8878c2ecf20Sopenharmony_ci dma->cmdr[i].p = __cpu_to_le32(dptr + 8888c2ecf20Sopenharmony_ci offsetof(struct hifn_dma, command_bufs[i][0])); 8898c2ecf20Sopenharmony_ci for (i = 0; i < HIFN_D_RES_RSIZE; ++i) 8908c2ecf20Sopenharmony_ci dma->resr[i].p = __cpu_to_le32(dptr + 8918c2ecf20Sopenharmony_ci offsetof(struct hifn_dma, result_bufs[i][0])); 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci /* Setup LAST descriptors. */ 8948c2ecf20Sopenharmony_ci dma->cmdr[HIFN_D_CMD_RSIZE].p = __cpu_to_le32(dptr + 8958c2ecf20Sopenharmony_ci offsetof(struct hifn_dma, cmdr[0])); 8968c2ecf20Sopenharmony_ci dma->srcr[HIFN_D_SRC_RSIZE].p = __cpu_to_le32(dptr + 8978c2ecf20Sopenharmony_ci offsetof(struct hifn_dma, srcr[0])); 8988c2ecf20Sopenharmony_ci dma->dstr[HIFN_D_DST_RSIZE].p = __cpu_to_le32(dptr + 8998c2ecf20Sopenharmony_ci offsetof(struct hifn_dma, dstr[0])); 9008c2ecf20Sopenharmony_ci dma->resr[HIFN_D_RES_RSIZE].p = __cpu_to_le32(dptr + 9018c2ecf20Sopenharmony_ci offsetof(struct hifn_dma, resr[0])); 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci dma->cmdu = dma->srcu = dma->dstu = dma->resu = 0; 9048c2ecf20Sopenharmony_ci dma->cmdi = dma->srci = dma->dsti = dma->resi = 0; 9058c2ecf20Sopenharmony_ci dma->cmdk = dma->srck = dma->dstk = dma->resk = 0; 9068c2ecf20Sopenharmony_ci} 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci/* 9098c2ecf20Sopenharmony_ci * Initialize the PLL. We need to know the frequency of the reference clock 9108c2ecf20Sopenharmony_ci * to calculate the optimal multiplier. For PCI we assume 66MHz, since that 9118c2ecf20Sopenharmony_ci * allows us to operate without the risk of overclocking the chip. If it 9128c2ecf20Sopenharmony_ci * actually uses 33MHz, the chip will operate at half the speed, this can be 9138c2ecf20Sopenharmony_ci * overridden by specifying the frequency as module parameter (pci33). 9148c2ecf20Sopenharmony_ci * 9158c2ecf20Sopenharmony_ci * Unfortunately the PCI clock is not very suitable since the HIFN needs a 9168c2ecf20Sopenharmony_ci * stable clock and the PCI clock frequency may vary, so the default is the 9178c2ecf20Sopenharmony_ci * external clock. There is no way to find out its frequency, we default to 9188c2ecf20Sopenharmony_ci * 66MHz since according to Mike Ham of HiFn, almost every board in existence 9198c2ecf20Sopenharmony_ci * has an external crystal populated at 66MHz. 9208c2ecf20Sopenharmony_ci */ 9218c2ecf20Sopenharmony_cistatic void hifn_init_pll(struct hifn_device *dev) 9228c2ecf20Sopenharmony_ci{ 9238c2ecf20Sopenharmony_ci unsigned int freq, m; 9248c2ecf20Sopenharmony_ci u32 pllcfg; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci pllcfg = HIFN_1_PLL | HIFN_PLL_RESERVED_1; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci if (strncmp(hifn_pll_ref, "ext", 3) == 0) 9298c2ecf20Sopenharmony_ci pllcfg |= HIFN_PLL_REF_CLK_PLL; 9308c2ecf20Sopenharmony_ci else 9318c2ecf20Sopenharmony_ci pllcfg |= HIFN_PLL_REF_CLK_HBI; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci if (hifn_pll_ref[3] != '\0') 9348c2ecf20Sopenharmony_ci freq = simple_strtoul(hifn_pll_ref + 3, NULL, 10); 9358c2ecf20Sopenharmony_ci else { 9368c2ecf20Sopenharmony_ci freq = 66; 9378c2ecf20Sopenharmony_ci dev_info(&dev->pdev->dev, "assuming %uMHz clock speed, override with hifn_pll_ref=%.3s<frequency>\n", 9388c2ecf20Sopenharmony_ci freq, hifn_pll_ref); 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci m = HIFN_PLL_FCK_MAX / freq; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci pllcfg |= (m / 2 - 1) << HIFN_PLL_ND_SHIFT; 9448c2ecf20Sopenharmony_ci if (m <= 8) 9458c2ecf20Sopenharmony_ci pllcfg |= HIFN_PLL_IS_1_8; 9468c2ecf20Sopenharmony_ci else 9478c2ecf20Sopenharmony_ci pllcfg |= HIFN_PLL_IS_9_12; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci /* Select clock source and enable clock bypass */ 9508c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_PLL, pllcfg | 9518c2ecf20Sopenharmony_ci HIFN_PLL_PK_CLK_HBI | HIFN_PLL_PE_CLK_HBI | HIFN_PLL_BP); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci /* Let the chip lock to the input clock */ 9548c2ecf20Sopenharmony_ci mdelay(10); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci /* Disable clock bypass */ 9578c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_PLL, pllcfg | 9588c2ecf20Sopenharmony_ci HIFN_PLL_PK_CLK_HBI | HIFN_PLL_PE_CLK_HBI); 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci /* Switch the engines to the PLL */ 9618c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_PLL, pllcfg | 9628c2ecf20Sopenharmony_ci HIFN_PLL_PK_CLK_PLL | HIFN_PLL_PE_CLK_PLL); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci /* 9658c2ecf20Sopenharmony_ci * The Fpk_clk runs at half the total speed. Its frequency is needed to 9668c2ecf20Sopenharmony_ci * calculate the minimum time between two reads of the rng. Since 33MHz 9678c2ecf20Sopenharmony_ci * is actually 33.333... we overestimate the frequency here, resulting 9688c2ecf20Sopenharmony_ci * in slightly larger intervals. 9698c2ecf20Sopenharmony_ci */ 9708c2ecf20Sopenharmony_ci dev->pk_clk_freq = 1000000 * (freq + 1) * m / 2; 9718c2ecf20Sopenharmony_ci} 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_cistatic void hifn_init_registers(struct hifn_device *dev) 9748c2ecf20Sopenharmony_ci{ 9758c2ecf20Sopenharmony_ci u32 dptr = dev->desc_dma; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci /* Initialization magic... */ 9788c2ecf20Sopenharmony_ci hifn_write_0(dev, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA); 9798c2ecf20Sopenharmony_ci hifn_write_0(dev, HIFN_0_FIFOCNFG, HIFN_FIFOCNFG_THRESHOLD); 9808c2ecf20Sopenharmony_ci hifn_write_0(dev, HIFN_0_PUIER, HIFN_PUIER_DSTOVER); 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci /* write all 4 ring address registers */ 9838c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CRAR, dptr + 9848c2ecf20Sopenharmony_ci offsetof(struct hifn_dma, cmdr[0])); 9858c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_SRAR, dptr + 9868c2ecf20Sopenharmony_ci offsetof(struct hifn_dma, srcr[0])); 9878c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_DRAR, dptr + 9888c2ecf20Sopenharmony_ci offsetof(struct hifn_dma, dstr[0])); 9898c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_RRAR, dptr + 9908c2ecf20Sopenharmony_ci offsetof(struct hifn_dma, resr[0])); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci mdelay(2); 9938c2ecf20Sopenharmony_ci#if 0 9948c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CSR, 9958c2ecf20Sopenharmony_ci HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS | 9968c2ecf20Sopenharmony_ci HIFN_DMACSR_S_CTRL_DIS | HIFN_DMACSR_C_CTRL_DIS | 9978c2ecf20Sopenharmony_ci HIFN_DMACSR_D_ABORT | HIFN_DMACSR_D_DONE | HIFN_DMACSR_D_LAST | 9988c2ecf20Sopenharmony_ci HIFN_DMACSR_D_WAIT | HIFN_DMACSR_D_OVER | 9998c2ecf20Sopenharmony_ci HIFN_DMACSR_R_ABORT | HIFN_DMACSR_R_DONE | HIFN_DMACSR_R_LAST | 10008c2ecf20Sopenharmony_ci HIFN_DMACSR_R_WAIT | HIFN_DMACSR_R_OVER | 10018c2ecf20Sopenharmony_ci HIFN_DMACSR_S_ABORT | HIFN_DMACSR_S_DONE | HIFN_DMACSR_S_LAST | 10028c2ecf20Sopenharmony_ci HIFN_DMACSR_S_WAIT | 10038c2ecf20Sopenharmony_ci HIFN_DMACSR_C_ABORT | HIFN_DMACSR_C_DONE | HIFN_DMACSR_C_LAST | 10048c2ecf20Sopenharmony_ci HIFN_DMACSR_C_WAIT | 10058c2ecf20Sopenharmony_ci HIFN_DMACSR_ENGINE | 10068c2ecf20Sopenharmony_ci HIFN_DMACSR_PUBDONE); 10078c2ecf20Sopenharmony_ci#else 10088c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CSR, 10098c2ecf20Sopenharmony_ci HIFN_DMACSR_C_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA | 10108c2ecf20Sopenharmony_ci HIFN_DMACSR_D_CTRL_ENA | HIFN_DMACSR_R_CTRL_ENA | 10118c2ecf20Sopenharmony_ci HIFN_DMACSR_D_ABORT | HIFN_DMACSR_D_DONE | HIFN_DMACSR_D_LAST | 10128c2ecf20Sopenharmony_ci HIFN_DMACSR_D_WAIT | HIFN_DMACSR_D_OVER | 10138c2ecf20Sopenharmony_ci HIFN_DMACSR_R_ABORT | HIFN_DMACSR_R_DONE | HIFN_DMACSR_R_LAST | 10148c2ecf20Sopenharmony_ci HIFN_DMACSR_R_WAIT | HIFN_DMACSR_R_OVER | 10158c2ecf20Sopenharmony_ci HIFN_DMACSR_S_ABORT | HIFN_DMACSR_S_DONE | HIFN_DMACSR_S_LAST | 10168c2ecf20Sopenharmony_ci HIFN_DMACSR_S_WAIT | 10178c2ecf20Sopenharmony_ci HIFN_DMACSR_C_ABORT | HIFN_DMACSR_C_DONE | HIFN_DMACSR_C_LAST | 10188c2ecf20Sopenharmony_ci HIFN_DMACSR_C_WAIT | 10198c2ecf20Sopenharmony_ci HIFN_DMACSR_ENGINE | 10208c2ecf20Sopenharmony_ci HIFN_DMACSR_PUBDONE); 10218c2ecf20Sopenharmony_ci#endif 10228c2ecf20Sopenharmony_ci hifn_read_1(dev, HIFN_1_DMA_CSR); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci dev->dmareg |= HIFN_DMAIER_R_DONE | HIFN_DMAIER_C_ABORT | 10258c2ecf20Sopenharmony_ci HIFN_DMAIER_D_OVER | HIFN_DMAIER_R_OVER | 10268c2ecf20Sopenharmony_ci HIFN_DMAIER_S_ABORT | HIFN_DMAIER_D_ABORT | HIFN_DMAIER_R_ABORT | 10278c2ecf20Sopenharmony_ci HIFN_DMAIER_ENGINE; 10288c2ecf20Sopenharmony_ci dev->dmareg &= ~HIFN_DMAIER_C_WAIT; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg); 10318c2ecf20Sopenharmony_ci hifn_read_1(dev, HIFN_1_DMA_IER); 10328c2ecf20Sopenharmony_ci#if 0 10338c2ecf20Sopenharmony_ci hifn_write_0(dev, HIFN_0_PUCNFG, HIFN_PUCNFG_ENCCNFG | 10348c2ecf20Sopenharmony_ci HIFN_PUCNFG_DRFR_128 | HIFN_PUCNFG_TCALLPHASES | 10358c2ecf20Sopenharmony_ci HIFN_PUCNFG_TCDRVTOTEM | HIFN_PUCNFG_BUS32 | 10368c2ecf20Sopenharmony_ci HIFN_PUCNFG_DRAM); 10378c2ecf20Sopenharmony_ci#else 10388c2ecf20Sopenharmony_ci hifn_write_0(dev, HIFN_0_PUCNFG, 0x10342); 10398c2ecf20Sopenharmony_ci#endif 10408c2ecf20Sopenharmony_ci hifn_init_pll(dev); 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci hifn_write_0(dev, HIFN_0_PUISR, HIFN_PUISR_DSTOVER); 10438c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | 10448c2ecf20Sopenharmony_ci HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE | HIFN_DMACNFG_LAST | 10458c2ecf20Sopenharmony_ci ((HIFN_POLL_FREQUENCY << 16 ) & HIFN_DMACNFG_POLLFREQ) | 10468c2ecf20Sopenharmony_ci ((HIFN_POLL_SCALAR << 8) & HIFN_DMACNFG_POLLINVAL)); 10478c2ecf20Sopenharmony_ci} 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_cistatic int hifn_setup_base_command(struct hifn_device *dev, u8 *buf, 10508c2ecf20Sopenharmony_ci unsigned dlen, unsigned slen, u16 mask, u8 snum) 10518c2ecf20Sopenharmony_ci{ 10528c2ecf20Sopenharmony_ci struct hifn_base_command *base_cmd; 10538c2ecf20Sopenharmony_ci u8 *buf_pos = buf; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci base_cmd = (struct hifn_base_command *)buf_pos; 10568c2ecf20Sopenharmony_ci base_cmd->masks = __cpu_to_le16(mask); 10578c2ecf20Sopenharmony_ci base_cmd->total_source_count = 10588c2ecf20Sopenharmony_ci __cpu_to_le16(slen & HIFN_BASE_CMD_LENMASK_LO); 10598c2ecf20Sopenharmony_ci base_cmd->total_dest_count = 10608c2ecf20Sopenharmony_ci __cpu_to_le16(dlen & HIFN_BASE_CMD_LENMASK_LO); 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci dlen >>= 16; 10638c2ecf20Sopenharmony_ci slen >>= 16; 10648c2ecf20Sopenharmony_ci base_cmd->session_num = __cpu_to_le16(snum | 10658c2ecf20Sopenharmony_ci ((slen << HIFN_BASE_CMD_SRCLEN_S) & HIFN_BASE_CMD_SRCLEN_M) | 10668c2ecf20Sopenharmony_ci ((dlen << HIFN_BASE_CMD_DSTLEN_S) & HIFN_BASE_CMD_DSTLEN_M)); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci return sizeof(struct hifn_base_command); 10698c2ecf20Sopenharmony_ci} 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_cistatic int hifn_setup_crypto_command(struct hifn_device *dev, 10728c2ecf20Sopenharmony_ci u8 *buf, unsigned dlen, unsigned slen, 10738c2ecf20Sopenharmony_ci u8 *key, int keylen, u8 *iv, int ivsize, u16 mode) 10748c2ecf20Sopenharmony_ci{ 10758c2ecf20Sopenharmony_ci struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; 10768c2ecf20Sopenharmony_ci struct hifn_crypt_command *cry_cmd; 10778c2ecf20Sopenharmony_ci u8 *buf_pos = buf; 10788c2ecf20Sopenharmony_ci u16 cmd_len; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci cry_cmd = (struct hifn_crypt_command *)buf_pos; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci cry_cmd->source_count = __cpu_to_le16(dlen & 0xffff); 10838c2ecf20Sopenharmony_ci dlen >>= 16; 10848c2ecf20Sopenharmony_ci cry_cmd->masks = __cpu_to_le16(mode | 10858c2ecf20Sopenharmony_ci ((dlen << HIFN_CRYPT_CMD_SRCLEN_S) & 10868c2ecf20Sopenharmony_ci HIFN_CRYPT_CMD_SRCLEN_M)); 10878c2ecf20Sopenharmony_ci cry_cmd->header_skip = 0; 10888c2ecf20Sopenharmony_ci cry_cmd->reserved = 0; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci buf_pos += sizeof(struct hifn_crypt_command); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci dma->cmdu++; 10938c2ecf20Sopenharmony_ci if (dma->cmdu > 1) { 10948c2ecf20Sopenharmony_ci dev->dmareg |= HIFN_DMAIER_C_WAIT; 10958c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg); 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci if (keylen) { 10998c2ecf20Sopenharmony_ci memcpy(buf_pos, key, keylen); 11008c2ecf20Sopenharmony_ci buf_pos += keylen; 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci if (ivsize) { 11038c2ecf20Sopenharmony_ci memcpy(buf_pos, iv, ivsize); 11048c2ecf20Sopenharmony_ci buf_pos += ivsize; 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci cmd_len = buf_pos - buf; 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci return cmd_len; 11108c2ecf20Sopenharmony_ci} 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_cistatic int hifn_setup_cmd_desc(struct hifn_device *dev, 11138c2ecf20Sopenharmony_ci struct hifn_context *ctx, struct hifn_request_context *rctx, 11148c2ecf20Sopenharmony_ci void *priv, unsigned int nbytes) 11158c2ecf20Sopenharmony_ci{ 11168c2ecf20Sopenharmony_ci struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; 11178c2ecf20Sopenharmony_ci int cmd_len, sa_idx; 11188c2ecf20Sopenharmony_ci u8 *buf, *buf_pos; 11198c2ecf20Sopenharmony_ci u16 mask; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci sa_idx = dma->cmdi; 11228c2ecf20Sopenharmony_ci buf_pos = buf = dma->command_bufs[dma->cmdi]; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci mask = 0; 11258c2ecf20Sopenharmony_ci switch (rctx->op) { 11268c2ecf20Sopenharmony_ci case ACRYPTO_OP_DECRYPT: 11278c2ecf20Sopenharmony_ci mask = HIFN_BASE_CMD_CRYPT | HIFN_BASE_CMD_DECODE; 11288c2ecf20Sopenharmony_ci break; 11298c2ecf20Sopenharmony_ci case ACRYPTO_OP_ENCRYPT: 11308c2ecf20Sopenharmony_ci mask = HIFN_BASE_CMD_CRYPT; 11318c2ecf20Sopenharmony_ci break; 11328c2ecf20Sopenharmony_ci case ACRYPTO_OP_HMAC: 11338c2ecf20Sopenharmony_ci mask = HIFN_BASE_CMD_MAC; 11348c2ecf20Sopenharmony_ci break; 11358c2ecf20Sopenharmony_ci default: 11368c2ecf20Sopenharmony_ci goto err_out; 11378c2ecf20Sopenharmony_ci } 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci buf_pos += hifn_setup_base_command(dev, buf_pos, nbytes, 11408c2ecf20Sopenharmony_ci nbytes, mask, dev->snum); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci if (rctx->op == ACRYPTO_OP_ENCRYPT || rctx->op == ACRYPTO_OP_DECRYPT) { 11438c2ecf20Sopenharmony_ci u16 md = 0; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci if (ctx->keysize) 11468c2ecf20Sopenharmony_ci md |= HIFN_CRYPT_CMD_NEW_KEY; 11478c2ecf20Sopenharmony_ci if (rctx->iv && rctx->mode != ACRYPTO_MODE_ECB) 11488c2ecf20Sopenharmony_ci md |= HIFN_CRYPT_CMD_NEW_IV; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci switch (rctx->mode) { 11518c2ecf20Sopenharmony_ci case ACRYPTO_MODE_ECB: 11528c2ecf20Sopenharmony_ci md |= HIFN_CRYPT_CMD_MODE_ECB; 11538c2ecf20Sopenharmony_ci break; 11548c2ecf20Sopenharmony_ci case ACRYPTO_MODE_CBC: 11558c2ecf20Sopenharmony_ci md |= HIFN_CRYPT_CMD_MODE_CBC; 11568c2ecf20Sopenharmony_ci break; 11578c2ecf20Sopenharmony_ci case ACRYPTO_MODE_CFB: 11588c2ecf20Sopenharmony_ci md |= HIFN_CRYPT_CMD_MODE_CFB; 11598c2ecf20Sopenharmony_ci break; 11608c2ecf20Sopenharmony_ci case ACRYPTO_MODE_OFB: 11618c2ecf20Sopenharmony_ci md |= HIFN_CRYPT_CMD_MODE_OFB; 11628c2ecf20Sopenharmony_ci break; 11638c2ecf20Sopenharmony_ci default: 11648c2ecf20Sopenharmony_ci goto err_out; 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci switch (rctx->type) { 11688c2ecf20Sopenharmony_ci case ACRYPTO_TYPE_AES_128: 11698c2ecf20Sopenharmony_ci if (ctx->keysize != 16) 11708c2ecf20Sopenharmony_ci goto err_out; 11718c2ecf20Sopenharmony_ci md |= HIFN_CRYPT_CMD_KSZ_128 | 11728c2ecf20Sopenharmony_ci HIFN_CRYPT_CMD_ALG_AES; 11738c2ecf20Sopenharmony_ci break; 11748c2ecf20Sopenharmony_ci case ACRYPTO_TYPE_AES_192: 11758c2ecf20Sopenharmony_ci if (ctx->keysize != 24) 11768c2ecf20Sopenharmony_ci goto err_out; 11778c2ecf20Sopenharmony_ci md |= HIFN_CRYPT_CMD_KSZ_192 | 11788c2ecf20Sopenharmony_ci HIFN_CRYPT_CMD_ALG_AES; 11798c2ecf20Sopenharmony_ci break; 11808c2ecf20Sopenharmony_ci case ACRYPTO_TYPE_AES_256: 11818c2ecf20Sopenharmony_ci if (ctx->keysize != 32) 11828c2ecf20Sopenharmony_ci goto err_out; 11838c2ecf20Sopenharmony_ci md |= HIFN_CRYPT_CMD_KSZ_256 | 11848c2ecf20Sopenharmony_ci HIFN_CRYPT_CMD_ALG_AES; 11858c2ecf20Sopenharmony_ci break; 11868c2ecf20Sopenharmony_ci case ACRYPTO_TYPE_3DES: 11878c2ecf20Sopenharmony_ci if (ctx->keysize != 24) 11888c2ecf20Sopenharmony_ci goto err_out; 11898c2ecf20Sopenharmony_ci md |= HIFN_CRYPT_CMD_ALG_3DES; 11908c2ecf20Sopenharmony_ci break; 11918c2ecf20Sopenharmony_ci case ACRYPTO_TYPE_DES: 11928c2ecf20Sopenharmony_ci if (ctx->keysize != 8) 11938c2ecf20Sopenharmony_ci goto err_out; 11948c2ecf20Sopenharmony_ci md |= HIFN_CRYPT_CMD_ALG_DES; 11958c2ecf20Sopenharmony_ci break; 11968c2ecf20Sopenharmony_ci default: 11978c2ecf20Sopenharmony_ci goto err_out; 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci buf_pos += hifn_setup_crypto_command(dev, buf_pos, 12018c2ecf20Sopenharmony_ci nbytes, nbytes, ctx->key, ctx->keysize, 12028c2ecf20Sopenharmony_ci rctx->iv, rctx->ivsize, md); 12038c2ecf20Sopenharmony_ci } 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci dev->sa[sa_idx] = priv; 12068c2ecf20Sopenharmony_ci dev->started++; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci cmd_len = buf_pos - buf; 12098c2ecf20Sopenharmony_ci dma->cmdr[dma->cmdi].l = __cpu_to_le32(cmd_len | HIFN_D_VALID | 12108c2ecf20Sopenharmony_ci HIFN_D_LAST | HIFN_D_MASKDONEIRQ); 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci if (++dma->cmdi == HIFN_D_CMD_RSIZE) { 12138c2ecf20Sopenharmony_ci dma->cmdr[dma->cmdi].l = __cpu_to_le32( 12148c2ecf20Sopenharmony_ci HIFN_D_VALID | HIFN_D_LAST | 12158c2ecf20Sopenharmony_ci HIFN_D_MASKDONEIRQ | HIFN_D_JUMP); 12168c2ecf20Sopenharmony_ci dma->cmdi = 0; 12178c2ecf20Sopenharmony_ci } else { 12188c2ecf20Sopenharmony_ci dma->cmdr[dma->cmdi - 1].l |= __cpu_to_le32(HIFN_D_VALID); 12198c2ecf20Sopenharmony_ci } 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci if (!(dev->flags & HIFN_FLAG_CMD_BUSY)) { 12228c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_C_CTRL_ENA); 12238c2ecf20Sopenharmony_ci dev->flags |= HIFN_FLAG_CMD_BUSY; 12248c2ecf20Sopenharmony_ci } 12258c2ecf20Sopenharmony_ci return 0; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_cierr_out: 12288c2ecf20Sopenharmony_ci return -EINVAL; 12298c2ecf20Sopenharmony_ci} 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_cistatic int hifn_setup_src_desc(struct hifn_device *dev, struct page *page, 12328c2ecf20Sopenharmony_ci unsigned int offset, unsigned int size, int last) 12338c2ecf20Sopenharmony_ci{ 12348c2ecf20Sopenharmony_ci struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; 12358c2ecf20Sopenharmony_ci int idx; 12368c2ecf20Sopenharmony_ci dma_addr_t addr; 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci addr = dma_map_page(&dev->pdev->dev, page, offset, size, 12398c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci idx = dma->srci; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci dma->srcr[idx].p = __cpu_to_le32(addr); 12448c2ecf20Sopenharmony_ci dma->srcr[idx].l = __cpu_to_le32(size | HIFN_D_VALID | 12458c2ecf20Sopenharmony_ci HIFN_D_MASKDONEIRQ | (last ? HIFN_D_LAST : 0)); 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci if (++idx == HIFN_D_SRC_RSIZE) { 12488c2ecf20Sopenharmony_ci dma->srcr[idx].l = __cpu_to_le32(HIFN_D_VALID | 12498c2ecf20Sopenharmony_ci HIFN_D_JUMP | HIFN_D_MASKDONEIRQ | 12508c2ecf20Sopenharmony_ci (last ? HIFN_D_LAST : 0)); 12518c2ecf20Sopenharmony_ci idx = 0; 12528c2ecf20Sopenharmony_ci } 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci dma->srci = idx; 12558c2ecf20Sopenharmony_ci dma->srcu++; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci if (!(dev->flags & HIFN_FLAG_SRC_BUSY)) { 12588c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_S_CTRL_ENA); 12598c2ecf20Sopenharmony_ci dev->flags |= HIFN_FLAG_SRC_BUSY; 12608c2ecf20Sopenharmony_ci } 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci return size; 12638c2ecf20Sopenharmony_ci} 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_cistatic void hifn_setup_res_desc(struct hifn_device *dev) 12668c2ecf20Sopenharmony_ci{ 12678c2ecf20Sopenharmony_ci struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci dma->resr[dma->resi].l = __cpu_to_le32(HIFN_USED_RESULT | 12708c2ecf20Sopenharmony_ci HIFN_D_VALID | HIFN_D_LAST); 12718c2ecf20Sopenharmony_ci /* 12728c2ecf20Sopenharmony_ci * dma->resr[dma->resi].l = __cpu_to_le32(HIFN_MAX_RESULT | HIFN_D_VALID | 12738c2ecf20Sopenharmony_ci * HIFN_D_LAST); 12748c2ecf20Sopenharmony_ci */ 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci if (++dma->resi == HIFN_D_RES_RSIZE) { 12778c2ecf20Sopenharmony_ci dma->resr[HIFN_D_RES_RSIZE].l = __cpu_to_le32(HIFN_D_VALID | 12788c2ecf20Sopenharmony_ci HIFN_D_JUMP | HIFN_D_MASKDONEIRQ | HIFN_D_LAST); 12798c2ecf20Sopenharmony_ci dma->resi = 0; 12808c2ecf20Sopenharmony_ci } 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci dma->resu++; 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci if (!(dev->flags & HIFN_FLAG_RES_BUSY)) { 12858c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_R_CTRL_ENA); 12868c2ecf20Sopenharmony_ci dev->flags |= HIFN_FLAG_RES_BUSY; 12878c2ecf20Sopenharmony_ci } 12888c2ecf20Sopenharmony_ci} 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_cistatic void hifn_setup_dst_desc(struct hifn_device *dev, struct page *page, 12918c2ecf20Sopenharmony_ci unsigned offset, unsigned size, int last) 12928c2ecf20Sopenharmony_ci{ 12938c2ecf20Sopenharmony_ci struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; 12948c2ecf20Sopenharmony_ci int idx; 12958c2ecf20Sopenharmony_ci dma_addr_t addr; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci addr = dma_map_page(&dev->pdev->dev, page, offset, size, 12988c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci idx = dma->dsti; 13018c2ecf20Sopenharmony_ci dma->dstr[idx].p = __cpu_to_le32(addr); 13028c2ecf20Sopenharmony_ci dma->dstr[idx].l = __cpu_to_le32(size | HIFN_D_VALID | 13038c2ecf20Sopenharmony_ci HIFN_D_MASKDONEIRQ | (last ? HIFN_D_LAST : 0)); 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci if (++idx == HIFN_D_DST_RSIZE) { 13068c2ecf20Sopenharmony_ci dma->dstr[idx].l = __cpu_to_le32(HIFN_D_VALID | 13078c2ecf20Sopenharmony_ci HIFN_D_JUMP | HIFN_D_MASKDONEIRQ | 13088c2ecf20Sopenharmony_ci (last ? HIFN_D_LAST : 0)); 13098c2ecf20Sopenharmony_ci idx = 0; 13108c2ecf20Sopenharmony_ci } 13118c2ecf20Sopenharmony_ci dma->dsti = idx; 13128c2ecf20Sopenharmony_ci dma->dstu++; 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci if (!(dev->flags & HIFN_FLAG_DST_BUSY)) { 13158c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_D_CTRL_ENA); 13168c2ecf20Sopenharmony_ci dev->flags |= HIFN_FLAG_DST_BUSY; 13178c2ecf20Sopenharmony_ci } 13188c2ecf20Sopenharmony_ci} 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_cistatic int hifn_setup_dma(struct hifn_device *dev, 13218c2ecf20Sopenharmony_ci struct hifn_context *ctx, struct hifn_request_context *rctx, 13228c2ecf20Sopenharmony_ci struct scatterlist *src, struct scatterlist *dst, 13238c2ecf20Sopenharmony_ci unsigned int nbytes, void *priv) 13248c2ecf20Sopenharmony_ci{ 13258c2ecf20Sopenharmony_ci struct scatterlist *t; 13268c2ecf20Sopenharmony_ci struct page *spage, *dpage; 13278c2ecf20Sopenharmony_ci unsigned int soff, doff; 13288c2ecf20Sopenharmony_ci unsigned int n, len; 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci n = nbytes; 13318c2ecf20Sopenharmony_ci while (n) { 13328c2ecf20Sopenharmony_ci spage = sg_page(src); 13338c2ecf20Sopenharmony_ci soff = src->offset; 13348c2ecf20Sopenharmony_ci len = min(src->length, n); 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci hifn_setup_src_desc(dev, spage, soff, len, n - len == 0); 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci src++; 13398c2ecf20Sopenharmony_ci n -= len; 13408c2ecf20Sopenharmony_ci } 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci t = &rctx->walk.cache[0]; 13438c2ecf20Sopenharmony_ci n = nbytes; 13448c2ecf20Sopenharmony_ci while (n) { 13458c2ecf20Sopenharmony_ci if (t->length && rctx->walk.flags & ASYNC_FLAGS_MISALIGNED) { 13468c2ecf20Sopenharmony_ci BUG_ON(!sg_page(t)); 13478c2ecf20Sopenharmony_ci dpage = sg_page(t); 13488c2ecf20Sopenharmony_ci doff = 0; 13498c2ecf20Sopenharmony_ci len = t->length; 13508c2ecf20Sopenharmony_ci } else { 13518c2ecf20Sopenharmony_ci BUG_ON(!sg_page(dst)); 13528c2ecf20Sopenharmony_ci dpage = sg_page(dst); 13538c2ecf20Sopenharmony_ci doff = dst->offset; 13548c2ecf20Sopenharmony_ci len = dst->length; 13558c2ecf20Sopenharmony_ci } 13568c2ecf20Sopenharmony_ci len = min(len, n); 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci hifn_setup_dst_desc(dev, dpage, doff, len, n - len == 0); 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci dst++; 13618c2ecf20Sopenharmony_ci t++; 13628c2ecf20Sopenharmony_ci n -= len; 13638c2ecf20Sopenharmony_ci } 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci hifn_setup_cmd_desc(dev, ctx, rctx, priv, nbytes); 13668c2ecf20Sopenharmony_ci hifn_setup_res_desc(dev); 13678c2ecf20Sopenharmony_ci return 0; 13688c2ecf20Sopenharmony_ci} 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_cistatic int hifn_cipher_walk_init(struct hifn_cipher_walk *w, 13718c2ecf20Sopenharmony_ci int num, gfp_t gfp_flags) 13728c2ecf20Sopenharmony_ci{ 13738c2ecf20Sopenharmony_ci int i; 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci num = min(ASYNC_SCATTERLIST_CACHE, num); 13768c2ecf20Sopenharmony_ci sg_init_table(w->cache, num); 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci w->num = 0; 13798c2ecf20Sopenharmony_ci for (i = 0; i < num; ++i) { 13808c2ecf20Sopenharmony_ci struct page *page = alloc_page(gfp_flags); 13818c2ecf20Sopenharmony_ci struct scatterlist *s; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci if (!page) 13848c2ecf20Sopenharmony_ci break; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci s = &w->cache[i]; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci sg_set_page(s, page, PAGE_SIZE, 0); 13898c2ecf20Sopenharmony_ci w->num++; 13908c2ecf20Sopenharmony_ci } 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci return i; 13938c2ecf20Sopenharmony_ci} 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_cistatic void hifn_cipher_walk_exit(struct hifn_cipher_walk *w) 13968c2ecf20Sopenharmony_ci{ 13978c2ecf20Sopenharmony_ci int i; 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci for (i = 0; i < w->num; ++i) { 14008c2ecf20Sopenharmony_ci struct scatterlist *s = &w->cache[i]; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci __free_page(sg_page(s)); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci s->length = 0; 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci w->num = 0; 14088c2ecf20Sopenharmony_ci} 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_cistatic int skcipher_add(unsigned int *drestp, struct scatterlist *dst, 14118c2ecf20Sopenharmony_ci unsigned int size, unsigned int *nbytesp) 14128c2ecf20Sopenharmony_ci{ 14138c2ecf20Sopenharmony_ci unsigned int copy, drest = *drestp, nbytes = *nbytesp; 14148c2ecf20Sopenharmony_ci int idx = 0; 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci if (drest < size || size > nbytes) 14178c2ecf20Sopenharmony_ci return -EINVAL; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci while (size) { 14208c2ecf20Sopenharmony_ci copy = min3(drest, size, dst->length); 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci size -= copy; 14238c2ecf20Sopenharmony_ci drest -= copy; 14248c2ecf20Sopenharmony_ci nbytes -= copy; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci pr_debug("%s: copy: %u, size: %u, drest: %u, nbytes: %u.\n", 14278c2ecf20Sopenharmony_ci __func__, copy, size, drest, nbytes); 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci dst++; 14308c2ecf20Sopenharmony_ci idx++; 14318c2ecf20Sopenharmony_ci } 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci *nbytesp = nbytes; 14348c2ecf20Sopenharmony_ci *drestp = drest; 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci return idx; 14378c2ecf20Sopenharmony_ci} 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_cistatic int hifn_cipher_walk(struct skcipher_request *req, 14408c2ecf20Sopenharmony_ci struct hifn_cipher_walk *w) 14418c2ecf20Sopenharmony_ci{ 14428c2ecf20Sopenharmony_ci struct scatterlist *dst, *t; 14438c2ecf20Sopenharmony_ci unsigned int nbytes = req->cryptlen, offset, copy, diff; 14448c2ecf20Sopenharmony_ci int idx, tidx, err; 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci tidx = idx = 0; 14478c2ecf20Sopenharmony_ci offset = 0; 14488c2ecf20Sopenharmony_ci while (nbytes) { 14498c2ecf20Sopenharmony_ci if (idx >= w->num && (w->flags & ASYNC_FLAGS_MISALIGNED)) 14508c2ecf20Sopenharmony_ci return -EINVAL; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci dst = &req->dst[idx]; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci pr_debug("\n%s: dlen: %u, doff: %u, offset: %u, nbytes: %u.\n", 14558c2ecf20Sopenharmony_ci __func__, dst->length, dst->offset, offset, nbytes); 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci if (!IS_ALIGNED(dst->offset, HIFN_D_DST_DALIGN) || 14588c2ecf20Sopenharmony_ci !IS_ALIGNED(dst->length, HIFN_D_DST_DALIGN) || 14598c2ecf20Sopenharmony_ci offset) { 14608c2ecf20Sopenharmony_ci unsigned slen = min(dst->length - offset, nbytes); 14618c2ecf20Sopenharmony_ci unsigned dlen = PAGE_SIZE; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci t = &w->cache[idx]; 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci err = skcipher_add(&dlen, dst, slen, &nbytes); 14668c2ecf20Sopenharmony_ci if (err < 0) 14678c2ecf20Sopenharmony_ci return err; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci idx += err; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci copy = slen & ~(HIFN_D_DST_DALIGN - 1); 14728c2ecf20Sopenharmony_ci diff = slen & (HIFN_D_DST_DALIGN - 1); 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci if (dlen < nbytes) { 14758c2ecf20Sopenharmony_ci /* 14768c2ecf20Sopenharmony_ci * Destination page does not have enough space 14778c2ecf20Sopenharmony_ci * to put there additional blocksized chunk, 14788c2ecf20Sopenharmony_ci * so we mark that page as containing only 14798c2ecf20Sopenharmony_ci * blocksize aligned chunks: 14808c2ecf20Sopenharmony_ci * t->length = (slen & ~(HIFN_D_DST_DALIGN - 1)); 14818c2ecf20Sopenharmony_ci * and increase number of bytes to be processed 14828c2ecf20Sopenharmony_ci * in next chunk: 14838c2ecf20Sopenharmony_ci * nbytes += diff; 14848c2ecf20Sopenharmony_ci */ 14858c2ecf20Sopenharmony_ci nbytes += diff; 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci /* 14888c2ecf20Sopenharmony_ci * Temporary of course... 14898c2ecf20Sopenharmony_ci * Kick author if you will catch this one. 14908c2ecf20Sopenharmony_ci */ 14918c2ecf20Sopenharmony_ci pr_err("%s: dlen: %u, nbytes: %u, slen: %u, offset: %u.\n", 14928c2ecf20Sopenharmony_ci __func__, dlen, nbytes, slen, offset); 14938c2ecf20Sopenharmony_ci pr_err("%s: please contact author to fix this " 14948c2ecf20Sopenharmony_ci "issue, generally you should not catch " 14958c2ecf20Sopenharmony_ci "this path under any condition but who " 14968c2ecf20Sopenharmony_ci "knows how did you use crypto code.\n" 14978c2ecf20Sopenharmony_ci "Thank you.\n", __func__); 14988c2ecf20Sopenharmony_ci BUG(); 14998c2ecf20Sopenharmony_ci } else { 15008c2ecf20Sopenharmony_ci copy += diff + nbytes; 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci dst = &req->dst[idx]; 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci err = skcipher_add(&dlen, dst, nbytes, &nbytes); 15058c2ecf20Sopenharmony_ci if (err < 0) 15068c2ecf20Sopenharmony_ci return err; 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci idx += err; 15098c2ecf20Sopenharmony_ci } 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci t->length = copy; 15128c2ecf20Sopenharmony_ci t->offset = offset; 15138c2ecf20Sopenharmony_ci } else { 15148c2ecf20Sopenharmony_ci nbytes -= min(dst->length, nbytes); 15158c2ecf20Sopenharmony_ci idx++; 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci tidx++; 15198c2ecf20Sopenharmony_ci } 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci return tidx; 15228c2ecf20Sopenharmony_ci} 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_cistatic int hifn_setup_session(struct skcipher_request *req) 15258c2ecf20Sopenharmony_ci{ 15268c2ecf20Sopenharmony_ci struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm); 15278c2ecf20Sopenharmony_ci struct hifn_request_context *rctx = skcipher_request_ctx(req); 15288c2ecf20Sopenharmony_ci struct hifn_device *dev = ctx->dev; 15298c2ecf20Sopenharmony_ci unsigned long dlen, flags; 15308c2ecf20Sopenharmony_ci unsigned int nbytes = req->cryptlen, idx = 0; 15318c2ecf20Sopenharmony_ci int err = -EINVAL, sg_num; 15328c2ecf20Sopenharmony_ci struct scatterlist *dst; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci if (rctx->iv && !rctx->ivsize && rctx->mode != ACRYPTO_MODE_ECB) 15358c2ecf20Sopenharmony_ci goto err_out_exit; 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci rctx->walk.flags = 0; 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci while (nbytes) { 15408c2ecf20Sopenharmony_ci dst = &req->dst[idx]; 15418c2ecf20Sopenharmony_ci dlen = min(dst->length, nbytes); 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci if (!IS_ALIGNED(dst->offset, HIFN_D_DST_DALIGN) || 15448c2ecf20Sopenharmony_ci !IS_ALIGNED(dlen, HIFN_D_DST_DALIGN)) 15458c2ecf20Sopenharmony_ci rctx->walk.flags |= ASYNC_FLAGS_MISALIGNED; 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci nbytes -= dlen; 15488c2ecf20Sopenharmony_ci idx++; 15498c2ecf20Sopenharmony_ci } 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci if (rctx->walk.flags & ASYNC_FLAGS_MISALIGNED) { 15528c2ecf20Sopenharmony_ci err = hifn_cipher_walk_init(&rctx->walk, idx, GFP_ATOMIC); 15538c2ecf20Sopenharmony_ci if (err < 0) 15548c2ecf20Sopenharmony_ci return err; 15558c2ecf20Sopenharmony_ci } 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci sg_num = hifn_cipher_walk(req, &rctx->walk); 15588c2ecf20Sopenharmony_ci if (sg_num < 0) { 15598c2ecf20Sopenharmony_ci err = sg_num; 15608c2ecf20Sopenharmony_ci goto err_out_exit; 15618c2ecf20Sopenharmony_ci } 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 15648c2ecf20Sopenharmony_ci if (dev->started + sg_num > HIFN_QUEUE_LENGTH) { 15658c2ecf20Sopenharmony_ci err = -EAGAIN; 15668c2ecf20Sopenharmony_ci goto err_out; 15678c2ecf20Sopenharmony_ci } 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci err = hifn_setup_dma(dev, ctx, rctx, req->src, req->dst, req->cryptlen, req); 15708c2ecf20Sopenharmony_ci if (err) 15718c2ecf20Sopenharmony_ci goto err_out; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci dev->snum++; 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci dev->active = HIFN_DEFAULT_ACTIVE_NUM; 15768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci return 0; 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_cierr_out: 15818c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 15828c2ecf20Sopenharmony_cierr_out_exit: 15838c2ecf20Sopenharmony_ci if (err) { 15848c2ecf20Sopenharmony_ci dev_info(&dev->pdev->dev, "iv: %p [%d], key: %p [%d], mode: %u, op: %u, " 15858c2ecf20Sopenharmony_ci "type: %u, err: %d.\n", 15868c2ecf20Sopenharmony_ci rctx->iv, rctx->ivsize, 15878c2ecf20Sopenharmony_ci ctx->key, ctx->keysize, 15888c2ecf20Sopenharmony_ci rctx->mode, rctx->op, rctx->type, err); 15898c2ecf20Sopenharmony_ci } 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci return err; 15928c2ecf20Sopenharmony_ci} 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_cistatic int hifn_start_device(struct hifn_device *dev) 15958c2ecf20Sopenharmony_ci{ 15968c2ecf20Sopenharmony_ci int err; 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci dev->started = dev->active = 0; 15998c2ecf20Sopenharmony_ci hifn_reset_dma(dev, 1); 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci err = hifn_enable_crypto(dev); 16028c2ecf20Sopenharmony_ci if (err) 16038c2ecf20Sopenharmony_ci return err; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci hifn_reset_puc(dev); 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci hifn_init_dma(dev); 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci hifn_init_registers(dev); 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci hifn_init_pubrng(dev); 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci return 0; 16148c2ecf20Sopenharmony_ci} 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_cistatic int skcipher_get(void *saddr, unsigned int *srestp, unsigned int offset, 16178c2ecf20Sopenharmony_ci struct scatterlist *dst, unsigned int size, unsigned int *nbytesp) 16188c2ecf20Sopenharmony_ci{ 16198c2ecf20Sopenharmony_ci unsigned int srest = *srestp, nbytes = *nbytesp, copy; 16208c2ecf20Sopenharmony_ci void *daddr; 16218c2ecf20Sopenharmony_ci int idx = 0; 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci if (srest < size || size > nbytes) 16248c2ecf20Sopenharmony_ci return -EINVAL; 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci while (size) { 16278c2ecf20Sopenharmony_ci copy = min3(srest, dst->length, size); 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci daddr = kmap_atomic(sg_page(dst)); 16308c2ecf20Sopenharmony_ci memcpy(daddr + dst->offset + offset, saddr, copy); 16318c2ecf20Sopenharmony_ci kunmap_atomic(daddr); 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci nbytes -= copy; 16348c2ecf20Sopenharmony_ci size -= copy; 16358c2ecf20Sopenharmony_ci srest -= copy; 16368c2ecf20Sopenharmony_ci saddr += copy; 16378c2ecf20Sopenharmony_ci offset = 0; 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci pr_debug("%s: copy: %u, size: %u, srest: %u, nbytes: %u.\n", 16408c2ecf20Sopenharmony_ci __func__, copy, size, srest, nbytes); 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci dst++; 16438c2ecf20Sopenharmony_ci idx++; 16448c2ecf20Sopenharmony_ci } 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci *nbytesp = nbytes; 16478c2ecf20Sopenharmony_ci *srestp = srest; 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci return idx; 16508c2ecf20Sopenharmony_ci} 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_cistatic inline void hifn_complete_sa(struct hifn_device *dev, int i) 16538c2ecf20Sopenharmony_ci{ 16548c2ecf20Sopenharmony_ci unsigned long flags; 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 16578c2ecf20Sopenharmony_ci dev->sa[i] = NULL; 16588c2ecf20Sopenharmony_ci dev->started--; 16598c2ecf20Sopenharmony_ci if (dev->started < 0) 16608c2ecf20Sopenharmony_ci dev_info(&dev->pdev->dev, "%s: started: %d.\n", __func__, 16618c2ecf20Sopenharmony_ci dev->started); 16628c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 16638c2ecf20Sopenharmony_ci BUG_ON(dev->started < 0); 16648c2ecf20Sopenharmony_ci} 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_cistatic void hifn_process_ready(struct skcipher_request *req, int error) 16678c2ecf20Sopenharmony_ci{ 16688c2ecf20Sopenharmony_ci struct hifn_request_context *rctx = skcipher_request_ctx(req); 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci if (rctx->walk.flags & ASYNC_FLAGS_MISALIGNED) { 16718c2ecf20Sopenharmony_ci unsigned int nbytes = req->cryptlen; 16728c2ecf20Sopenharmony_ci int idx = 0, err; 16738c2ecf20Sopenharmony_ci struct scatterlist *dst, *t; 16748c2ecf20Sopenharmony_ci void *saddr; 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci while (nbytes) { 16778c2ecf20Sopenharmony_ci t = &rctx->walk.cache[idx]; 16788c2ecf20Sopenharmony_ci dst = &req->dst[idx]; 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci pr_debug("\n%s: sg_page(t): %p, t->length: %u, " 16818c2ecf20Sopenharmony_ci "sg_page(dst): %p, dst->length: %u, " 16828c2ecf20Sopenharmony_ci "nbytes: %u.\n", 16838c2ecf20Sopenharmony_ci __func__, sg_page(t), t->length, 16848c2ecf20Sopenharmony_ci sg_page(dst), dst->length, nbytes); 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci if (!t->length) { 16878c2ecf20Sopenharmony_ci nbytes -= min(dst->length, nbytes); 16888c2ecf20Sopenharmony_ci idx++; 16898c2ecf20Sopenharmony_ci continue; 16908c2ecf20Sopenharmony_ci } 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci saddr = kmap_atomic(sg_page(t)); 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci err = skcipher_get(saddr, &t->length, t->offset, 16958c2ecf20Sopenharmony_ci dst, nbytes, &nbytes); 16968c2ecf20Sopenharmony_ci if (err < 0) { 16978c2ecf20Sopenharmony_ci kunmap_atomic(saddr); 16988c2ecf20Sopenharmony_ci break; 16998c2ecf20Sopenharmony_ci } 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci idx += err; 17028c2ecf20Sopenharmony_ci kunmap_atomic(saddr); 17038c2ecf20Sopenharmony_ci } 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci hifn_cipher_walk_exit(&rctx->walk); 17068c2ecf20Sopenharmony_ci } 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci req->base.complete(&req->base, error); 17098c2ecf20Sopenharmony_ci} 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_cistatic void hifn_clear_rings(struct hifn_device *dev, int error) 17128c2ecf20Sopenharmony_ci{ 17138c2ecf20Sopenharmony_ci struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; 17148c2ecf20Sopenharmony_ci int i, u; 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci dev_dbg(&dev->pdev->dev, "ring cleanup 1: i: %d.%d.%d.%d, u: %d.%d.%d.%d, " 17178c2ecf20Sopenharmony_ci "k: %d.%d.%d.%d.\n", 17188c2ecf20Sopenharmony_ci dma->cmdi, dma->srci, dma->dsti, dma->resi, 17198c2ecf20Sopenharmony_ci dma->cmdu, dma->srcu, dma->dstu, dma->resu, 17208c2ecf20Sopenharmony_ci dma->cmdk, dma->srck, dma->dstk, dma->resk); 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci i = dma->resk; u = dma->resu; 17238c2ecf20Sopenharmony_ci while (u != 0) { 17248c2ecf20Sopenharmony_ci if (dma->resr[i].l & __cpu_to_le32(HIFN_D_VALID)) 17258c2ecf20Sopenharmony_ci break; 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci if (dev->sa[i]) { 17288c2ecf20Sopenharmony_ci dev->success++; 17298c2ecf20Sopenharmony_ci dev->reset = 0; 17308c2ecf20Sopenharmony_ci hifn_process_ready(dev->sa[i], error); 17318c2ecf20Sopenharmony_ci hifn_complete_sa(dev, i); 17328c2ecf20Sopenharmony_ci } 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci if (++i == HIFN_D_RES_RSIZE) 17358c2ecf20Sopenharmony_ci i = 0; 17368c2ecf20Sopenharmony_ci u--; 17378c2ecf20Sopenharmony_ci } 17388c2ecf20Sopenharmony_ci dma->resk = i; dma->resu = u; 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci i = dma->srck; u = dma->srcu; 17418c2ecf20Sopenharmony_ci while (u != 0) { 17428c2ecf20Sopenharmony_ci if (dma->srcr[i].l & __cpu_to_le32(HIFN_D_VALID)) 17438c2ecf20Sopenharmony_ci break; 17448c2ecf20Sopenharmony_ci if (++i == HIFN_D_SRC_RSIZE) 17458c2ecf20Sopenharmony_ci i = 0; 17468c2ecf20Sopenharmony_ci u--; 17478c2ecf20Sopenharmony_ci } 17488c2ecf20Sopenharmony_ci dma->srck = i; dma->srcu = u; 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci i = dma->cmdk; u = dma->cmdu; 17518c2ecf20Sopenharmony_ci while (u != 0) { 17528c2ecf20Sopenharmony_ci if (dma->cmdr[i].l & __cpu_to_le32(HIFN_D_VALID)) 17538c2ecf20Sopenharmony_ci break; 17548c2ecf20Sopenharmony_ci if (++i == HIFN_D_CMD_RSIZE) 17558c2ecf20Sopenharmony_ci i = 0; 17568c2ecf20Sopenharmony_ci u--; 17578c2ecf20Sopenharmony_ci } 17588c2ecf20Sopenharmony_ci dma->cmdk = i; dma->cmdu = u; 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci i = dma->dstk; u = dma->dstu; 17618c2ecf20Sopenharmony_ci while (u != 0) { 17628c2ecf20Sopenharmony_ci if (dma->dstr[i].l & __cpu_to_le32(HIFN_D_VALID)) 17638c2ecf20Sopenharmony_ci break; 17648c2ecf20Sopenharmony_ci if (++i == HIFN_D_DST_RSIZE) 17658c2ecf20Sopenharmony_ci i = 0; 17668c2ecf20Sopenharmony_ci u--; 17678c2ecf20Sopenharmony_ci } 17688c2ecf20Sopenharmony_ci dma->dstk = i; dma->dstu = u; 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci dev_dbg(&dev->pdev->dev, "ring cleanup 2: i: %d.%d.%d.%d, u: %d.%d.%d.%d, " 17718c2ecf20Sopenharmony_ci "k: %d.%d.%d.%d.\n", 17728c2ecf20Sopenharmony_ci dma->cmdi, dma->srci, dma->dsti, dma->resi, 17738c2ecf20Sopenharmony_ci dma->cmdu, dma->srcu, dma->dstu, dma->resu, 17748c2ecf20Sopenharmony_ci dma->cmdk, dma->srck, dma->dstk, dma->resk); 17758c2ecf20Sopenharmony_ci} 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_cistatic void hifn_work(struct work_struct *work) 17788c2ecf20Sopenharmony_ci{ 17798c2ecf20Sopenharmony_ci struct delayed_work *dw = to_delayed_work(work); 17808c2ecf20Sopenharmony_ci struct hifn_device *dev = container_of(dw, struct hifn_device, work); 17818c2ecf20Sopenharmony_ci unsigned long flags; 17828c2ecf20Sopenharmony_ci int reset = 0; 17838c2ecf20Sopenharmony_ci u32 r = 0; 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 17868c2ecf20Sopenharmony_ci if (dev->active == 0) { 17878c2ecf20Sopenharmony_ci struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci if (dma->cmdu == 0 && (dev->flags & HIFN_FLAG_CMD_BUSY)) { 17908c2ecf20Sopenharmony_ci dev->flags &= ~HIFN_FLAG_CMD_BUSY; 17918c2ecf20Sopenharmony_ci r |= HIFN_DMACSR_C_CTRL_DIS; 17928c2ecf20Sopenharmony_ci } 17938c2ecf20Sopenharmony_ci if (dma->srcu == 0 && (dev->flags & HIFN_FLAG_SRC_BUSY)) { 17948c2ecf20Sopenharmony_ci dev->flags &= ~HIFN_FLAG_SRC_BUSY; 17958c2ecf20Sopenharmony_ci r |= HIFN_DMACSR_S_CTRL_DIS; 17968c2ecf20Sopenharmony_ci } 17978c2ecf20Sopenharmony_ci if (dma->dstu == 0 && (dev->flags & HIFN_FLAG_DST_BUSY)) { 17988c2ecf20Sopenharmony_ci dev->flags &= ~HIFN_FLAG_DST_BUSY; 17998c2ecf20Sopenharmony_ci r |= HIFN_DMACSR_D_CTRL_DIS; 18008c2ecf20Sopenharmony_ci } 18018c2ecf20Sopenharmony_ci if (dma->resu == 0 && (dev->flags & HIFN_FLAG_RES_BUSY)) { 18028c2ecf20Sopenharmony_ci dev->flags &= ~HIFN_FLAG_RES_BUSY; 18038c2ecf20Sopenharmony_ci r |= HIFN_DMACSR_R_CTRL_DIS; 18048c2ecf20Sopenharmony_ci } 18058c2ecf20Sopenharmony_ci if (r) 18068c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CSR, r); 18078c2ecf20Sopenharmony_ci } else 18088c2ecf20Sopenharmony_ci dev->active--; 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci if ((dev->prev_success == dev->success) && dev->started) 18118c2ecf20Sopenharmony_ci reset = 1; 18128c2ecf20Sopenharmony_ci dev->prev_success = dev->success; 18138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci if (reset) { 18168c2ecf20Sopenharmony_ci if (++dev->reset >= 5) { 18178c2ecf20Sopenharmony_ci int i; 18188c2ecf20Sopenharmony_ci struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci dev_info(&dev->pdev->dev, 18218c2ecf20Sopenharmony_ci "r: %08x, active: %d, started: %d, " 18228c2ecf20Sopenharmony_ci "success: %lu: qlen: %u/%u, reset: %d.\n", 18238c2ecf20Sopenharmony_ci r, dev->active, dev->started, 18248c2ecf20Sopenharmony_ci dev->success, dev->queue.qlen, dev->queue.max_qlen, 18258c2ecf20Sopenharmony_ci reset); 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci dev_info(&dev->pdev->dev, "%s: res: ", __func__); 18288c2ecf20Sopenharmony_ci for (i = 0; i < HIFN_D_RES_RSIZE; ++i) { 18298c2ecf20Sopenharmony_ci pr_info("%x.%p ", dma->resr[i].l, dev->sa[i]); 18308c2ecf20Sopenharmony_ci if (dev->sa[i]) { 18318c2ecf20Sopenharmony_ci hifn_process_ready(dev->sa[i], -ENODEV); 18328c2ecf20Sopenharmony_ci hifn_complete_sa(dev, i); 18338c2ecf20Sopenharmony_ci } 18348c2ecf20Sopenharmony_ci } 18358c2ecf20Sopenharmony_ci pr_info("\n"); 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci hifn_reset_dma(dev, 1); 18388c2ecf20Sopenharmony_ci hifn_stop_device(dev); 18398c2ecf20Sopenharmony_ci hifn_start_device(dev); 18408c2ecf20Sopenharmony_ci dev->reset = 0; 18418c2ecf20Sopenharmony_ci } 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci tasklet_schedule(&dev->tasklet); 18448c2ecf20Sopenharmony_ci } 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci schedule_delayed_work(&dev->work, HZ); 18478c2ecf20Sopenharmony_ci} 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_cistatic irqreturn_t hifn_interrupt(int irq, void *data) 18508c2ecf20Sopenharmony_ci{ 18518c2ecf20Sopenharmony_ci struct hifn_device *dev = (struct hifn_device *)data; 18528c2ecf20Sopenharmony_ci struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; 18538c2ecf20Sopenharmony_ci u32 dmacsr, restart; 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci dmacsr = hifn_read_1(dev, HIFN_1_DMA_CSR); 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci dev_dbg(&dev->pdev->dev, "1 dmacsr: %08x, dmareg: %08x, res: %08x [%d], " 18588c2ecf20Sopenharmony_ci "i: %d.%d.%d.%d, u: %d.%d.%d.%d.\n", 18598c2ecf20Sopenharmony_ci dmacsr, dev->dmareg, dmacsr & dev->dmareg, dma->cmdi, 18608c2ecf20Sopenharmony_ci dma->cmdi, dma->srci, dma->dsti, dma->resi, 18618c2ecf20Sopenharmony_ci dma->cmdu, dma->srcu, dma->dstu, dma->resu); 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci if ((dmacsr & dev->dmareg) == 0) 18648c2ecf20Sopenharmony_ci return IRQ_NONE; 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CSR, dmacsr & dev->dmareg); 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci if (dmacsr & HIFN_DMACSR_ENGINE) 18698c2ecf20Sopenharmony_ci hifn_write_0(dev, HIFN_0_PUISR, hifn_read_0(dev, HIFN_0_PUISR)); 18708c2ecf20Sopenharmony_ci if (dmacsr & HIFN_DMACSR_PUBDONE) 18718c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_PUB_STATUS, 18728c2ecf20Sopenharmony_ci hifn_read_1(dev, HIFN_1_PUB_STATUS) | HIFN_PUBSTS_DONE); 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci restart = dmacsr & (HIFN_DMACSR_R_OVER | HIFN_DMACSR_D_OVER); 18758c2ecf20Sopenharmony_ci if (restart) { 18768c2ecf20Sopenharmony_ci u32 puisr = hifn_read_0(dev, HIFN_0_PUISR); 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci dev_warn(&dev->pdev->dev, "overflow: r: %d, d: %d, puisr: %08x, d: %u.\n", 18798c2ecf20Sopenharmony_ci !!(dmacsr & HIFN_DMACSR_R_OVER), 18808c2ecf20Sopenharmony_ci !!(dmacsr & HIFN_DMACSR_D_OVER), 18818c2ecf20Sopenharmony_ci puisr, !!(puisr & HIFN_PUISR_DSTOVER)); 18828c2ecf20Sopenharmony_ci if (!!(puisr & HIFN_PUISR_DSTOVER)) 18838c2ecf20Sopenharmony_ci hifn_write_0(dev, HIFN_0_PUISR, HIFN_PUISR_DSTOVER); 18848c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CSR, dmacsr & (HIFN_DMACSR_R_OVER | 18858c2ecf20Sopenharmony_ci HIFN_DMACSR_D_OVER)); 18868c2ecf20Sopenharmony_ci } 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci restart = dmacsr & (HIFN_DMACSR_C_ABORT | HIFN_DMACSR_S_ABORT | 18898c2ecf20Sopenharmony_ci HIFN_DMACSR_D_ABORT | HIFN_DMACSR_R_ABORT); 18908c2ecf20Sopenharmony_ci if (restart) { 18918c2ecf20Sopenharmony_ci dev_warn(&dev->pdev->dev, "abort: c: %d, s: %d, d: %d, r: %d.\n", 18928c2ecf20Sopenharmony_ci !!(dmacsr & HIFN_DMACSR_C_ABORT), 18938c2ecf20Sopenharmony_ci !!(dmacsr & HIFN_DMACSR_S_ABORT), 18948c2ecf20Sopenharmony_ci !!(dmacsr & HIFN_DMACSR_D_ABORT), 18958c2ecf20Sopenharmony_ci !!(dmacsr & HIFN_DMACSR_R_ABORT)); 18968c2ecf20Sopenharmony_ci hifn_reset_dma(dev, 1); 18978c2ecf20Sopenharmony_ci hifn_init_dma(dev); 18988c2ecf20Sopenharmony_ci hifn_init_registers(dev); 18998c2ecf20Sopenharmony_ci } 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci if ((dmacsr & HIFN_DMACSR_C_WAIT) && (dma->cmdu == 0)) { 19028c2ecf20Sopenharmony_ci dev_dbg(&dev->pdev->dev, "wait on command.\n"); 19038c2ecf20Sopenharmony_ci dev->dmareg &= ~(HIFN_DMAIER_C_WAIT); 19048c2ecf20Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg); 19058c2ecf20Sopenharmony_ci } 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci tasklet_schedule(&dev->tasklet); 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci return IRQ_HANDLED; 19108c2ecf20Sopenharmony_ci} 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_cistatic void hifn_flush(struct hifn_device *dev) 19138c2ecf20Sopenharmony_ci{ 19148c2ecf20Sopenharmony_ci unsigned long flags; 19158c2ecf20Sopenharmony_ci struct crypto_async_request *async_req; 19168c2ecf20Sopenharmony_ci struct skcipher_request *req; 19178c2ecf20Sopenharmony_ci struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; 19188c2ecf20Sopenharmony_ci int i; 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci for (i = 0; i < HIFN_D_RES_RSIZE; ++i) { 19218c2ecf20Sopenharmony_ci struct hifn_desc *d = &dma->resr[i]; 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci if (dev->sa[i]) { 19248c2ecf20Sopenharmony_ci hifn_process_ready(dev->sa[i], 19258c2ecf20Sopenharmony_ci (d->l & __cpu_to_le32(HIFN_D_VALID)) ? -ENODEV : 0); 19268c2ecf20Sopenharmony_ci hifn_complete_sa(dev, i); 19278c2ecf20Sopenharmony_ci } 19288c2ecf20Sopenharmony_ci } 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 19318c2ecf20Sopenharmony_ci while ((async_req = crypto_dequeue_request(&dev->queue))) { 19328c2ecf20Sopenharmony_ci req = skcipher_request_cast(async_req); 19338c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci hifn_process_ready(req, -ENODEV); 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 19388c2ecf20Sopenharmony_ci } 19398c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 19408c2ecf20Sopenharmony_ci} 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_cistatic int hifn_setkey(struct crypto_skcipher *cipher, const u8 *key, 19438c2ecf20Sopenharmony_ci unsigned int len) 19448c2ecf20Sopenharmony_ci{ 19458c2ecf20Sopenharmony_ci struct hifn_context *ctx = crypto_skcipher_ctx(cipher); 19468c2ecf20Sopenharmony_ci struct hifn_device *dev = ctx->dev; 19478c2ecf20Sopenharmony_ci int err; 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci err = verify_skcipher_des_key(cipher, key); 19508c2ecf20Sopenharmony_ci if (err) 19518c2ecf20Sopenharmony_ci return err; 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci dev->flags &= ~HIFN_FLAG_OLD_KEY; 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci memcpy(ctx->key, key, len); 19568c2ecf20Sopenharmony_ci ctx->keysize = len; 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci return 0; 19598c2ecf20Sopenharmony_ci} 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_cistatic int hifn_des3_setkey(struct crypto_skcipher *cipher, const u8 *key, 19628c2ecf20Sopenharmony_ci unsigned int len) 19638c2ecf20Sopenharmony_ci{ 19648c2ecf20Sopenharmony_ci struct hifn_context *ctx = crypto_skcipher_ctx(cipher); 19658c2ecf20Sopenharmony_ci struct hifn_device *dev = ctx->dev; 19668c2ecf20Sopenharmony_ci int err; 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci err = verify_skcipher_des3_key(cipher, key); 19698c2ecf20Sopenharmony_ci if (err) 19708c2ecf20Sopenharmony_ci return err; 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci dev->flags &= ~HIFN_FLAG_OLD_KEY; 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci memcpy(ctx->key, key, len); 19758c2ecf20Sopenharmony_ci ctx->keysize = len; 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ci return 0; 19788c2ecf20Sopenharmony_ci} 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_cistatic int hifn_handle_req(struct skcipher_request *req) 19818c2ecf20Sopenharmony_ci{ 19828c2ecf20Sopenharmony_ci struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm); 19838c2ecf20Sopenharmony_ci struct hifn_device *dev = ctx->dev; 19848c2ecf20Sopenharmony_ci int err = -EAGAIN; 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci if (dev->started + DIV_ROUND_UP(req->cryptlen, PAGE_SIZE) <= HIFN_QUEUE_LENGTH) 19878c2ecf20Sopenharmony_ci err = hifn_setup_session(req); 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci if (err == -EAGAIN) { 19908c2ecf20Sopenharmony_ci unsigned long flags; 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 19938c2ecf20Sopenharmony_ci err = crypto_enqueue_request(&dev->queue, &req->base); 19948c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 19958c2ecf20Sopenharmony_ci } 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci return err; 19988c2ecf20Sopenharmony_ci} 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_cistatic int hifn_setup_crypto_req(struct skcipher_request *req, u8 op, 20018c2ecf20Sopenharmony_ci u8 type, u8 mode) 20028c2ecf20Sopenharmony_ci{ 20038c2ecf20Sopenharmony_ci struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm); 20048c2ecf20Sopenharmony_ci struct hifn_request_context *rctx = skcipher_request_ctx(req); 20058c2ecf20Sopenharmony_ci unsigned ivsize; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci ivsize = crypto_skcipher_ivsize(crypto_skcipher_reqtfm(req)); 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci if (req->iv && mode != ACRYPTO_MODE_ECB) { 20108c2ecf20Sopenharmony_ci if (type == ACRYPTO_TYPE_AES_128) 20118c2ecf20Sopenharmony_ci ivsize = HIFN_AES_IV_LENGTH; 20128c2ecf20Sopenharmony_ci else if (type == ACRYPTO_TYPE_DES) 20138c2ecf20Sopenharmony_ci ivsize = HIFN_DES_KEY_LENGTH; 20148c2ecf20Sopenharmony_ci else if (type == ACRYPTO_TYPE_3DES) 20158c2ecf20Sopenharmony_ci ivsize = HIFN_3DES_KEY_LENGTH; 20168c2ecf20Sopenharmony_ci } 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci if (ctx->keysize != 16 && type == ACRYPTO_TYPE_AES_128) { 20198c2ecf20Sopenharmony_ci if (ctx->keysize == 24) 20208c2ecf20Sopenharmony_ci type = ACRYPTO_TYPE_AES_192; 20218c2ecf20Sopenharmony_ci else if (ctx->keysize == 32) 20228c2ecf20Sopenharmony_ci type = ACRYPTO_TYPE_AES_256; 20238c2ecf20Sopenharmony_ci } 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci rctx->op = op; 20268c2ecf20Sopenharmony_ci rctx->mode = mode; 20278c2ecf20Sopenharmony_ci rctx->type = type; 20288c2ecf20Sopenharmony_ci rctx->iv = req->iv; 20298c2ecf20Sopenharmony_ci rctx->ivsize = ivsize; 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci /* 20328c2ecf20Sopenharmony_ci * HEAVY TODO: needs to kick Herbert XU to write documentation. 20338c2ecf20Sopenharmony_ci * HEAVY TODO: needs to kick Herbert XU to write documentation. 20348c2ecf20Sopenharmony_ci * HEAVY TODO: needs to kick Herbert XU to write documentation. 20358c2ecf20Sopenharmony_ci */ 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci return hifn_handle_req(req); 20388c2ecf20Sopenharmony_ci} 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_cistatic int hifn_process_queue(struct hifn_device *dev) 20418c2ecf20Sopenharmony_ci{ 20428c2ecf20Sopenharmony_ci struct crypto_async_request *async_req, *backlog; 20438c2ecf20Sopenharmony_ci struct skcipher_request *req; 20448c2ecf20Sopenharmony_ci unsigned long flags; 20458c2ecf20Sopenharmony_ci int err = 0; 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci while (dev->started < HIFN_QUEUE_LENGTH) { 20488c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 20498c2ecf20Sopenharmony_ci backlog = crypto_get_backlog(&dev->queue); 20508c2ecf20Sopenharmony_ci async_req = crypto_dequeue_request(&dev->queue); 20518c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci if (!async_req) 20548c2ecf20Sopenharmony_ci break; 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci if (backlog) 20578c2ecf20Sopenharmony_ci backlog->complete(backlog, -EINPROGRESS); 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci req = skcipher_request_cast(async_req); 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci err = hifn_handle_req(req); 20628c2ecf20Sopenharmony_ci if (err) 20638c2ecf20Sopenharmony_ci break; 20648c2ecf20Sopenharmony_ci } 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci return err; 20678c2ecf20Sopenharmony_ci} 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_cistatic int hifn_setup_crypto(struct skcipher_request *req, u8 op, 20708c2ecf20Sopenharmony_ci u8 type, u8 mode) 20718c2ecf20Sopenharmony_ci{ 20728c2ecf20Sopenharmony_ci int err; 20738c2ecf20Sopenharmony_ci struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm); 20748c2ecf20Sopenharmony_ci struct hifn_device *dev = ctx->dev; 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci err = hifn_setup_crypto_req(req, op, type, mode); 20778c2ecf20Sopenharmony_ci if (err) 20788c2ecf20Sopenharmony_ci return err; 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci if (dev->started < HIFN_QUEUE_LENGTH && dev->queue.qlen) 20818c2ecf20Sopenharmony_ci hifn_process_queue(dev); 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci return -EINPROGRESS; 20848c2ecf20Sopenharmony_ci} 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci/* 20878c2ecf20Sopenharmony_ci * AES ecryption functions. 20888c2ecf20Sopenharmony_ci */ 20898c2ecf20Sopenharmony_cistatic inline int hifn_encrypt_aes_ecb(struct skcipher_request *req) 20908c2ecf20Sopenharmony_ci{ 20918c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 20928c2ecf20Sopenharmony_ci ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_ECB); 20938c2ecf20Sopenharmony_ci} 20948c2ecf20Sopenharmony_cistatic inline int hifn_encrypt_aes_cbc(struct skcipher_request *req) 20958c2ecf20Sopenharmony_ci{ 20968c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 20978c2ecf20Sopenharmony_ci ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CBC); 20988c2ecf20Sopenharmony_ci} 20998c2ecf20Sopenharmony_cistatic inline int hifn_encrypt_aes_cfb(struct skcipher_request *req) 21008c2ecf20Sopenharmony_ci{ 21018c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 21028c2ecf20Sopenharmony_ci ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CFB); 21038c2ecf20Sopenharmony_ci} 21048c2ecf20Sopenharmony_cistatic inline int hifn_encrypt_aes_ofb(struct skcipher_request *req) 21058c2ecf20Sopenharmony_ci{ 21068c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 21078c2ecf20Sopenharmony_ci ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_OFB); 21088c2ecf20Sopenharmony_ci} 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci/* 21118c2ecf20Sopenharmony_ci * AES decryption functions. 21128c2ecf20Sopenharmony_ci */ 21138c2ecf20Sopenharmony_cistatic inline int hifn_decrypt_aes_ecb(struct skcipher_request *req) 21148c2ecf20Sopenharmony_ci{ 21158c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 21168c2ecf20Sopenharmony_ci ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_ECB); 21178c2ecf20Sopenharmony_ci} 21188c2ecf20Sopenharmony_cistatic inline int hifn_decrypt_aes_cbc(struct skcipher_request *req) 21198c2ecf20Sopenharmony_ci{ 21208c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 21218c2ecf20Sopenharmony_ci ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CBC); 21228c2ecf20Sopenharmony_ci} 21238c2ecf20Sopenharmony_cistatic inline int hifn_decrypt_aes_cfb(struct skcipher_request *req) 21248c2ecf20Sopenharmony_ci{ 21258c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 21268c2ecf20Sopenharmony_ci ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CFB); 21278c2ecf20Sopenharmony_ci} 21288c2ecf20Sopenharmony_cistatic inline int hifn_decrypt_aes_ofb(struct skcipher_request *req) 21298c2ecf20Sopenharmony_ci{ 21308c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 21318c2ecf20Sopenharmony_ci ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_OFB); 21328c2ecf20Sopenharmony_ci} 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci/* 21358c2ecf20Sopenharmony_ci * DES ecryption functions. 21368c2ecf20Sopenharmony_ci */ 21378c2ecf20Sopenharmony_cistatic inline int hifn_encrypt_des_ecb(struct skcipher_request *req) 21388c2ecf20Sopenharmony_ci{ 21398c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 21408c2ecf20Sopenharmony_ci ACRYPTO_TYPE_DES, ACRYPTO_MODE_ECB); 21418c2ecf20Sopenharmony_ci} 21428c2ecf20Sopenharmony_cistatic inline int hifn_encrypt_des_cbc(struct skcipher_request *req) 21438c2ecf20Sopenharmony_ci{ 21448c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 21458c2ecf20Sopenharmony_ci ACRYPTO_TYPE_DES, ACRYPTO_MODE_CBC); 21468c2ecf20Sopenharmony_ci} 21478c2ecf20Sopenharmony_cistatic inline int hifn_encrypt_des_cfb(struct skcipher_request *req) 21488c2ecf20Sopenharmony_ci{ 21498c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 21508c2ecf20Sopenharmony_ci ACRYPTO_TYPE_DES, ACRYPTO_MODE_CFB); 21518c2ecf20Sopenharmony_ci} 21528c2ecf20Sopenharmony_cistatic inline int hifn_encrypt_des_ofb(struct skcipher_request *req) 21538c2ecf20Sopenharmony_ci{ 21548c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 21558c2ecf20Sopenharmony_ci ACRYPTO_TYPE_DES, ACRYPTO_MODE_OFB); 21568c2ecf20Sopenharmony_ci} 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci/* 21598c2ecf20Sopenharmony_ci * DES decryption functions. 21608c2ecf20Sopenharmony_ci */ 21618c2ecf20Sopenharmony_cistatic inline int hifn_decrypt_des_ecb(struct skcipher_request *req) 21628c2ecf20Sopenharmony_ci{ 21638c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 21648c2ecf20Sopenharmony_ci ACRYPTO_TYPE_DES, ACRYPTO_MODE_ECB); 21658c2ecf20Sopenharmony_ci} 21668c2ecf20Sopenharmony_cistatic inline int hifn_decrypt_des_cbc(struct skcipher_request *req) 21678c2ecf20Sopenharmony_ci{ 21688c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 21698c2ecf20Sopenharmony_ci ACRYPTO_TYPE_DES, ACRYPTO_MODE_CBC); 21708c2ecf20Sopenharmony_ci} 21718c2ecf20Sopenharmony_cistatic inline int hifn_decrypt_des_cfb(struct skcipher_request *req) 21728c2ecf20Sopenharmony_ci{ 21738c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 21748c2ecf20Sopenharmony_ci ACRYPTO_TYPE_DES, ACRYPTO_MODE_CFB); 21758c2ecf20Sopenharmony_ci} 21768c2ecf20Sopenharmony_cistatic inline int hifn_decrypt_des_ofb(struct skcipher_request *req) 21778c2ecf20Sopenharmony_ci{ 21788c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 21798c2ecf20Sopenharmony_ci ACRYPTO_TYPE_DES, ACRYPTO_MODE_OFB); 21808c2ecf20Sopenharmony_ci} 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci/* 21838c2ecf20Sopenharmony_ci * 3DES ecryption functions. 21848c2ecf20Sopenharmony_ci */ 21858c2ecf20Sopenharmony_cistatic inline int hifn_encrypt_3des_ecb(struct skcipher_request *req) 21868c2ecf20Sopenharmony_ci{ 21878c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 21888c2ecf20Sopenharmony_ci ACRYPTO_TYPE_3DES, ACRYPTO_MODE_ECB); 21898c2ecf20Sopenharmony_ci} 21908c2ecf20Sopenharmony_cistatic inline int hifn_encrypt_3des_cbc(struct skcipher_request *req) 21918c2ecf20Sopenharmony_ci{ 21928c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 21938c2ecf20Sopenharmony_ci ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CBC); 21948c2ecf20Sopenharmony_ci} 21958c2ecf20Sopenharmony_cistatic inline int hifn_encrypt_3des_cfb(struct skcipher_request *req) 21968c2ecf20Sopenharmony_ci{ 21978c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 21988c2ecf20Sopenharmony_ci ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CFB); 21998c2ecf20Sopenharmony_ci} 22008c2ecf20Sopenharmony_cistatic inline int hifn_encrypt_3des_ofb(struct skcipher_request *req) 22018c2ecf20Sopenharmony_ci{ 22028c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 22038c2ecf20Sopenharmony_ci ACRYPTO_TYPE_3DES, ACRYPTO_MODE_OFB); 22048c2ecf20Sopenharmony_ci} 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci/* 3DES decryption functions. */ 22078c2ecf20Sopenharmony_cistatic inline int hifn_decrypt_3des_ecb(struct skcipher_request *req) 22088c2ecf20Sopenharmony_ci{ 22098c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 22108c2ecf20Sopenharmony_ci ACRYPTO_TYPE_3DES, ACRYPTO_MODE_ECB); 22118c2ecf20Sopenharmony_ci} 22128c2ecf20Sopenharmony_cistatic inline int hifn_decrypt_3des_cbc(struct skcipher_request *req) 22138c2ecf20Sopenharmony_ci{ 22148c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 22158c2ecf20Sopenharmony_ci ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CBC); 22168c2ecf20Sopenharmony_ci} 22178c2ecf20Sopenharmony_cistatic inline int hifn_decrypt_3des_cfb(struct skcipher_request *req) 22188c2ecf20Sopenharmony_ci{ 22198c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 22208c2ecf20Sopenharmony_ci ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CFB); 22218c2ecf20Sopenharmony_ci} 22228c2ecf20Sopenharmony_cistatic inline int hifn_decrypt_3des_ofb(struct skcipher_request *req) 22238c2ecf20Sopenharmony_ci{ 22248c2ecf20Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 22258c2ecf20Sopenharmony_ci ACRYPTO_TYPE_3DES, ACRYPTO_MODE_OFB); 22268c2ecf20Sopenharmony_ci} 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_cistruct hifn_alg_template { 22298c2ecf20Sopenharmony_ci char name[CRYPTO_MAX_ALG_NAME]; 22308c2ecf20Sopenharmony_ci char drv_name[CRYPTO_MAX_ALG_NAME]; 22318c2ecf20Sopenharmony_ci unsigned int bsize; 22328c2ecf20Sopenharmony_ci struct skcipher_alg skcipher; 22338c2ecf20Sopenharmony_ci}; 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_cistatic const struct hifn_alg_template hifn_alg_templates[] = { 22368c2ecf20Sopenharmony_ci /* 22378c2ecf20Sopenharmony_ci * 3DES ECB, CBC, CFB and OFB modes. 22388c2ecf20Sopenharmony_ci */ 22398c2ecf20Sopenharmony_ci { 22408c2ecf20Sopenharmony_ci .name = "cfb(des3_ede)", .drv_name = "cfb-3des", .bsize = 8, 22418c2ecf20Sopenharmony_ci .skcipher = { 22428c2ecf20Sopenharmony_ci .min_keysize = HIFN_3DES_KEY_LENGTH, 22438c2ecf20Sopenharmony_ci .max_keysize = HIFN_3DES_KEY_LENGTH, 22448c2ecf20Sopenharmony_ci .setkey = hifn_des3_setkey, 22458c2ecf20Sopenharmony_ci .encrypt = hifn_encrypt_3des_cfb, 22468c2ecf20Sopenharmony_ci .decrypt = hifn_decrypt_3des_cfb, 22478c2ecf20Sopenharmony_ci }, 22488c2ecf20Sopenharmony_ci }, 22498c2ecf20Sopenharmony_ci { 22508c2ecf20Sopenharmony_ci .name = "ofb(des3_ede)", .drv_name = "ofb-3des", .bsize = 8, 22518c2ecf20Sopenharmony_ci .skcipher = { 22528c2ecf20Sopenharmony_ci .min_keysize = HIFN_3DES_KEY_LENGTH, 22538c2ecf20Sopenharmony_ci .max_keysize = HIFN_3DES_KEY_LENGTH, 22548c2ecf20Sopenharmony_ci .setkey = hifn_des3_setkey, 22558c2ecf20Sopenharmony_ci .encrypt = hifn_encrypt_3des_ofb, 22568c2ecf20Sopenharmony_ci .decrypt = hifn_decrypt_3des_ofb, 22578c2ecf20Sopenharmony_ci }, 22588c2ecf20Sopenharmony_ci }, 22598c2ecf20Sopenharmony_ci { 22608c2ecf20Sopenharmony_ci .name = "cbc(des3_ede)", .drv_name = "cbc-3des", .bsize = 8, 22618c2ecf20Sopenharmony_ci .skcipher = { 22628c2ecf20Sopenharmony_ci .ivsize = HIFN_IV_LENGTH, 22638c2ecf20Sopenharmony_ci .min_keysize = HIFN_3DES_KEY_LENGTH, 22648c2ecf20Sopenharmony_ci .max_keysize = HIFN_3DES_KEY_LENGTH, 22658c2ecf20Sopenharmony_ci .setkey = hifn_des3_setkey, 22668c2ecf20Sopenharmony_ci .encrypt = hifn_encrypt_3des_cbc, 22678c2ecf20Sopenharmony_ci .decrypt = hifn_decrypt_3des_cbc, 22688c2ecf20Sopenharmony_ci }, 22698c2ecf20Sopenharmony_ci }, 22708c2ecf20Sopenharmony_ci { 22718c2ecf20Sopenharmony_ci .name = "ecb(des3_ede)", .drv_name = "ecb-3des", .bsize = 8, 22728c2ecf20Sopenharmony_ci .skcipher = { 22738c2ecf20Sopenharmony_ci .min_keysize = HIFN_3DES_KEY_LENGTH, 22748c2ecf20Sopenharmony_ci .max_keysize = HIFN_3DES_KEY_LENGTH, 22758c2ecf20Sopenharmony_ci .setkey = hifn_des3_setkey, 22768c2ecf20Sopenharmony_ci .encrypt = hifn_encrypt_3des_ecb, 22778c2ecf20Sopenharmony_ci .decrypt = hifn_decrypt_3des_ecb, 22788c2ecf20Sopenharmony_ci }, 22798c2ecf20Sopenharmony_ci }, 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci /* 22828c2ecf20Sopenharmony_ci * DES ECB, CBC, CFB and OFB modes. 22838c2ecf20Sopenharmony_ci */ 22848c2ecf20Sopenharmony_ci { 22858c2ecf20Sopenharmony_ci .name = "cfb(des)", .drv_name = "cfb-des", .bsize = 8, 22868c2ecf20Sopenharmony_ci .skcipher = { 22878c2ecf20Sopenharmony_ci .min_keysize = HIFN_DES_KEY_LENGTH, 22888c2ecf20Sopenharmony_ci .max_keysize = HIFN_DES_KEY_LENGTH, 22898c2ecf20Sopenharmony_ci .setkey = hifn_setkey, 22908c2ecf20Sopenharmony_ci .encrypt = hifn_encrypt_des_cfb, 22918c2ecf20Sopenharmony_ci .decrypt = hifn_decrypt_des_cfb, 22928c2ecf20Sopenharmony_ci }, 22938c2ecf20Sopenharmony_ci }, 22948c2ecf20Sopenharmony_ci { 22958c2ecf20Sopenharmony_ci .name = "ofb(des)", .drv_name = "ofb-des", .bsize = 8, 22968c2ecf20Sopenharmony_ci .skcipher = { 22978c2ecf20Sopenharmony_ci .min_keysize = HIFN_DES_KEY_LENGTH, 22988c2ecf20Sopenharmony_ci .max_keysize = HIFN_DES_KEY_LENGTH, 22998c2ecf20Sopenharmony_ci .setkey = hifn_setkey, 23008c2ecf20Sopenharmony_ci .encrypt = hifn_encrypt_des_ofb, 23018c2ecf20Sopenharmony_ci .decrypt = hifn_decrypt_des_ofb, 23028c2ecf20Sopenharmony_ci }, 23038c2ecf20Sopenharmony_ci }, 23048c2ecf20Sopenharmony_ci { 23058c2ecf20Sopenharmony_ci .name = "cbc(des)", .drv_name = "cbc-des", .bsize = 8, 23068c2ecf20Sopenharmony_ci .skcipher = { 23078c2ecf20Sopenharmony_ci .ivsize = HIFN_IV_LENGTH, 23088c2ecf20Sopenharmony_ci .min_keysize = HIFN_DES_KEY_LENGTH, 23098c2ecf20Sopenharmony_ci .max_keysize = HIFN_DES_KEY_LENGTH, 23108c2ecf20Sopenharmony_ci .setkey = hifn_setkey, 23118c2ecf20Sopenharmony_ci .encrypt = hifn_encrypt_des_cbc, 23128c2ecf20Sopenharmony_ci .decrypt = hifn_decrypt_des_cbc, 23138c2ecf20Sopenharmony_ci }, 23148c2ecf20Sopenharmony_ci }, 23158c2ecf20Sopenharmony_ci { 23168c2ecf20Sopenharmony_ci .name = "ecb(des)", .drv_name = "ecb-des", .bsize = 8, 23178c2ecf20Sopenharmony_ci .skcipher = { 23188c2ecf20Sopenharmony_ci .min_keysize = HIFN_DES_KEY_LENGTH, 23198c2ecf20Sopenharmony_ci .max_keysize = HIFN_DES_KEY_LENGTH, 23208c2ecf20Sopenharmony_ci .setkey = hifn_setkey, 23218c2ecf20Sopenharmony_ci .encrypt = hifn_encrypt_des_ecb, 23228c2ecf20Sopenharmony_ci .decrypt = hifn_decrypt_des_ecb, 23238c2ecf20Sopenharmony_ci }, 23248c2ecf20Sopenharmony_ci }, 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_ci /* 23278c2ecf20Sopenharmony_ci * AES ECB, CBC, CFB and OFB modes. 23288c2ecf20Sopenharmony_ci */ 23298c2ecf20Sopenharmony_ci { 23308c2ecf20Sopenharmony_ci .name = "ecb(aes)", .drv_name = "ecb-aes", .bsize = 16, 23318c2ecf20Sopenharmony_ci .skcipher = { 23328c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 23338c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 23348c2ecf20Sopenharmony_ci .setkey = hifn_setkey, 23358c2ecf20Sopenharmony_ci .encrypt = hifn_encrypt_aes_ecb, 23368c2ecf20Sopenharmony_ci .decrypt = hifn_decrypt_aes_ecb, 23378c2ecf20Sopenharmony_ci }, 23388c2ecf20Sopenharmony_ci }, 23398c2ecf20Sopenharmony_ci { 23408c2ecf20Sopenharmony_ci .name = "cbc(aes)", .drv_name = "cbc-aes", .bsize = 16, 23418c2ecf20Sopenharmony_ci .skcipher = { 23428c2ecf20Sopenharmony_ci .ivsize = HIFN_AES_IV_LENGTH, 23438c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 23448c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 23458c2ecf20Sopenharmony_ci .setkey = hifn_setkey, 23468c2ecf20Sopenharmony_ci .encrypt = hifn_encrypt_aes_cbc, 23478c2ecf20Sopenharmony_ci .decrypt = hifn_decrypt_aes_cbc, 23488c2ecf20Sopenharmony_ci }, 23498c2ecf20Sopenharmony_ci }, 23508c2ecf20Sopenharmony_ci { 23518c2ecf20Sopenharmony_ci .name = "cfb(aes)", .drv_name = "cfb-aes", .bsize = 16, 23528c2ecf20Sopenharmony_ci .skcipher = { 23538c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 23548c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 23558c2ecf20Sopenharmony_ci .setkey = hifn_setkey, 23568c2ecf20Sopenharmony_ci .encrypt = hifn_encrypt_aes_cfb, 23578c2ecf20Sopenharmony_ci .decrypt = hifn_decrypt_aes_cfb, 23588c2ecf20Sopenharmony_ci }, 23598c2ecf20Sopenharmony_ci }, 23608c2ecf20Sopenharmony_ci { 23618c2ecf20Sopenharmony_ci .name = "ofb(aes)", .drv_name = "ofb-aes", .bsize = 16, 23628c2ecf20Sopenharmony_ci .skcipher = { 23638c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 23648c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 23658c2ecf20Sopenharmony_ci .setkey = hifn_setkey, 23668c2ecf20Sopenharmony_ci .encrypt = hifn_encrypt_aes_ofb, 23678c2ecf20Sopenharmony_ci .decrypt = hifn_decrypt_aes_ofb, 23688c2ecf20Sopenharmony_ci }, 23698c2ecf20Sopenharmony_ci }, 23708c2ecf20Sopenharmony_ci}; 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_cistatic int hifn_init_tfm(struct crypto_skcipher *tfm) 23738c2ecf20Sopenharmony_ci{ 23748c2ecf20Sopenharmony_ci struct skcipher_alg *alg = crypto_skcipher_alg(tfm); 23758c2ecf20Sopenharmony_ci struct hifn_crypto_alg *ha = crypto_alg_to_hifn(alg); 23768c2ecf20Sopenharmony_ci struct hifn_context *ctx = crypto_skcipher_ctx(tfm); 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_ci ctx->dev = ha->dev; 23798c2ecf20Sopenharmony_ci crypto_skcipher_set_reqsize(tfm, sizeof(struct hifn_request_context)); 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci return 0; 23828c2ecf20Sopenharmony_ci} 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_cistatic int hifn_alg_alloc(struct hifn_device *dev, const struct hifn_alg_template *t) 23858c2ecf20Sopenharmony_ci{ 23868c2ecf20Sopenharmony_ci struct hifn_crypto_alg *alg; 23878c2ecf20Sopenharmony_ci int err; 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_ci alg = kzalloc(sizeof(*alg), GFP_KERNEL); 23908c2ecf20Sopenharmony_ci if (!alg) 23918c2ecf20Sopenharmony_ci return -ENOMEM; 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci alg->alg = t->skcipher; 23948c2ecf20Sopenharmony_ci alg->alg.init = hifn_init_tfm; 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_ci snprintf(alg->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", t->name); 23978c2ecf20Sopenharmony_ci snprintf(alg->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s-%s", 23988c2ecf20Sopenharmony_ci t->drv_name, dev->name); 23998c2ecf20Sopenharmony_ci 24008c2ecf20Sopenharmony_ci alg->alg.base.cra_priority = 300; 24018c2ecf20Sopenharmony_ci alg->alg.base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC; 24028c2ecf20Sopenharmony_ci alg->alg.base.cra_blocksize = t->bsize; 24038c2ecf20Sopenharmony_ci alg->alg.base.cra_ctxsize = sizeof(struct hifn_context); 24048c2ecf20Sopenharmony_ci alg->alg.base.cra_alignmask = 0; 24058c2ecf20Sopenharmony_ci alg->alg.base.cra_module = THIS_MODULE; 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci alg->dev = dev; 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_ci list_add_tail(&alg->entry, &dev->alg_list); 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_ci err = crypto_register_skcipher(&alg->alg); 24128c2ecf20Sopenharmony_ci if (err) { 24138c2ecf20Sopenharmony_ci list_del(&alg->entry); 24148c2ecf20Sopenharmony_ci kfree(alg); 24158c2ecf20Sopenharmony_ci } 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci return err; 24188c2ecf20Sopenharmony_ci} 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_cistatic void hifn_unregister_alg(struct hifn_device *dev) 24218c2ecf20Sopenharmony_ci{ 24228c2ecf20Sopenharmony_ci struct hifn_crypto_alg *a, *n; 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci list_for_each_entry_safe(a, n, &dev->alg_list, entry) { 24258c2ecf20Sopenharmony_ci list_del(&a->entry); 24268c2ecf20Sopenharmony_ci crypto_unregister_skcipher(&a->alg); 24278c2ecf20Sopenharmony_ci kfree(a); 24288c2ecf20Sopenharmony_ci } 24298c2ecf20Sopenharmony_ci} 24308c2ecf20Sopenharmony_ci 24318c2ecf20Sopenharmony_cistatic int hifn_register_alg(struct hifn_device *dev) 24328c2ecf20Sopenharmony_ci{ 24338c2ecf20Sopenharmony_ci int i, err; 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hifn_alg_templates); ++i) { 24368c2ecf20Sopenharmony_ci err = hifn_alg_alloc(dev, &hifn_alg_templates[i]); 24378c2ecf20Sopenharmony_ci if (err) 24388c2ecf20Sopenharmony_ci goto err_out_exit; 24398c2ecf20Sopenharmony_ci } 24408c2ecf20Sopenharmony_ci 24418c2ecf20Sopenharmony_ci return 0; 24428c2ecf20Sopenharmony_ci 24438c2ecf20Sopenharmony_cierr_out_exit: 24448c2ecf20Sopenharmony_ci hifn_unregister_alg(dev); 24458c2ecf20Sopenharmony_ci return err; 24468c2ecf20Sopenharmony_ci} 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_cistatic void hifn_tasklet_callback(unsigned long data) 24498c2ecf20Sopenharmony_ci{ 24508c2ecf20Sopenharmony_ci struct hifn_device *dev = (struct hifn_device *)data; 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci /* 24538c2ecf20Sopenharmony_ci * This is ok to call this without lock being held, 24548c2ecf20Sopenharmony_ci * althogh it modifies some parameters used in parallel, 24558c2ecf20Sopenharmony_ci * (like dev->success), but they are used in process 24568c2ecf20Sopenharmony_ci * context or update is atomic (like setting dev->sa[i] to NULL). 24578c2ecf20Sopenharmony_ci */ 24588c2ecf20Sopenharmony_ci hifn_clear_rings(dev, 0); 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci if (dev->started < HIFN_QUEUE_LENGTH && dev->queue.qlen) 24618c2ecf20Sopenharmony_ci hifn_process_queue(dev); 24628c2ecf20Sopenharmony_ci} 24638c2ecf20Sopenharmony_ci 24648c2ecf20Sopenharmony_cistatic int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id) 24658c2ecf20Sopenharmony_ci{ 24668c2ecf20Sopenharmony_ci int err, i; 24678c2ecf20Sopenharmony_ci struct hifn_device *dev; 24688c2ecf20Sopenharmony_ci char name[8]; 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ci err = pci_enable_device(pdev); 24718c2ecf20Sopenharmony_ci if (err) 24728c2ecf20Sopenharmony_ci return err; 24738c2ecf20Sopenharmony_ci pci_set_master(pdev); 24748c2ecf20Sopenharmony_ci 24758c2ecf20Sopenharmony_ci err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); 24768c2ecf20Sopenharmony_ci if (err) 24778c2ecf20Sopenharmony_ci goto err_out_disable_pci_device; 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), "hifn%d", 24808c2ecf20Sopenharmony_ci atomic_inc_return(&hifn_dev_number) - 1); 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci err = pci_request_regions(pdev, name); 24838c2ecf20Sopenharmony_ci if (err) 24848c2ecf20Sopenharmony_ci goto err_out_disable_pci_device; 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_ci if (pci_resource_len(pdev, 0) < HIFN_BAR0_SIZE || 24878c2ecf20Sopenharmony_ci pci_resource_len(pdev, 1) < HIFN_BAR1_SIZE || 24888c2ecf20Sopenharmony_ci pci_resource_len(pdev, 2) < HIFN_BAR2_SIZE) { 24898c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Broken hardware - I/O regions are too small.\n"); 24908c2ecf20Sopenharmony_ci err = -ENODEV; 24918c2ecf20Sopenharmony_ci goto err_out_free_regions; 24928c2ecf20Sopenharmony_ci } 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci dev = kzalloc(sizeof(struct hifn_device) + sizeof(struct crypto_alg), 24958c2ecf20Sopenharmony_ci GFP_KERNEL); 24968c2ecf20Sopenharmony_ci if (!dev) { 24978c2ecf20Sopenharmony_ci err = -ENOMEM; 24988c2ecf20Sopenharmony_ci goto err_out_free_regions; 24998c2ecf20Sopenharmony_ci } 25008c2ecf20Sopenharmony_ci 25018c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dev->alg_list); 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci snprintf(dev->name, sizeof(dev->name), "%s", name); 25048c2ecf20Sopenharmony_ci spin_lock_init(&dev->lock); 25058c2ecf20Sopenharmony_ci 25068c2ecf20Sopenharmony_ci for (i = 0; i < 3; ++i) { 25078c2ecf20Sopenharmony_ci unsigned long addr, size; 25088c2ecf20Sopenharmony_ci 25098c2ecf20Sopenharmony_ci addr = pci_resource_start(pdev, i); 25108c2ecf20Sopenharmony_ci size = pci_resource_len(pdev, i); 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_ci dev->bar[i] = ioremap(addr, size); 25138c2ecf20Sopenharmony_ci if (!dev->bar[i]) { 25148c2ecf20Sopenharmony_ci err = -ENOMEM; 25158c2ecf20Sopenharmony_ci goto err_out_unmap_bars; 25168c2ecf20Sopenharmony_ci } 25178c2ecf20Sopenharmony_ci } 25188c2ecf20Sopenharmony_ci 25198c2ecf20Sopenharmony_ci dev->desc_virt = dma_alloc_coherent(&pdev->dev, 25208c2ecf20Sopenharmony_ci sizeof(struct hifn_dma), 25218c2ecf20Sopenharmony_ci &dev->desc_dma, GFP_KERNEL); 25228c2ecf20Sopenharmony_ci if (!dev->desc_virt) { 25238c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to allocate descriptor rings.\n"); 25248c2ecf20Sopenharmony_ci err = -ENOMEM; 25258c2ecf20Sopenharmony_ci goto err_out_unmap_bars; 25268c2ecf20Sopenharmony_ci } 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_ci dev->pdev = pdev; 25298c2ecf20Sopenharmony_ci dev->irq = pdev->irq; 25308c2ecf20Sopenharmony_ci 25318c2ecf20Sopenharmony_ci for (i = 0; i < HIFN_D_RES_RSIZE; ++i) 25328c2ecf20Sopenharmony_ci dev->sa[i] = NULL; 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, dev); 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci tasklet_init(&dev->tasklet, hifn_tasklet_callback, (unsigned long)dev); 25378c2ecf20Sopenharmony_ci 25388c2ecf20Sopenharmony_ci crypto_init_queue(&dev->queue, 1); 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci err = request_irq(dev->irq, hifn_interrupt, IRQF_SHARED, dev->name, dev); 25418c2ecf20Sopenharmony_ci if (err) { 25428c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to request IRQ%d: err: %d.\n", 25438c2ecf20Sopenharmony_ci dev->irq, err); 25448c2ecf20Sopenharmony_ci dev->irq = 0; 25458c2ecf20Sopenharmony_ci goto err_out_free_desc; 25468c2ecf20Sopenharmony_ci } 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_ci err = hifn_start_device(dev); 25498c2ecf20Sopenharmony_ci if (err) 25508c2ecf20Sopenharmony_ci goto err_out_free_irq; 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_ci err = hifn_register_rng(dev); 25538c2ecf20Sopenharmony_ci if (err) 25548c2ecf20Sopenharmony_ci goto err_out_stop_device; 25558c2ecf20Sopenharmony_ci 25568c2ecf20Sopenharmony_ci err = hifn_register_alg(dev); 25578c2ecf20Sopenharmony_ci if (err) 25588c2ecf20Sopenharmony_ci goto err_out_unregister_rng; 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&dev->work, hifn_work); 25618c2ecf20Sopenharmony_ci schedule_delayed_work(&dev->work, HZ); 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "HIFN crypto accelerator card at %s has been " 25648c2ecf20Sopenharmony_ci "successfully registered as %s.\n", 25658c2ecf20Sopenharmony_ci pci_name(pdev), dev->name); 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci return 0; 25688c2ecf20Sopenharmony_ci 25698c2ecf20Sopenharmony_cierr_out_unregister_rng: 25708c2ecf20Sopenharmony_ci hifn_unregister_rng(dev); 25718c2ecf20Sopenharmony_cierr_out_stop_device: 25728c2ecf20Sopenharmony_ci hifn_reset_dma(dev, 1); 25738c2ecf20Sopenharmony_ci hifn_stop_device(dev); 25748c2ecf20Sopenharmony_cierr_out_free_irq: 25758c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 25768c2ecf20Sopenharmony_ci tasklet_kill(&dev->tasklet); 25778c2ecf20Sopenharmony_cierr_out_free_desc: 25788c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, sizeof(struct hifn_dma), dev->desc_virt, 25798c2ecf20Sopenharmony_ci dev->desc_dma); 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_cierr_out_unmap_bars: 25828c2ecf20Sopenharmony_ci for (i = 0; i < 3; ++i) 25838c2ecf20Sopenharmony_ci if (dev->bar[i]) 25848c2ecf20Sopenharmony_ci iounmap(dev->bar[i]); 25858c2ecf20Sopenharmony_ci kfree(dev); 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_cierr_out_free_regions: 25888c2ecf20Sopenharmony_ci pci_release_regions(pdev); 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_cierr_out_disable_pci_device: 25918c2ecf20Sopenharmony_ci pci_disable_device(pdev); 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci return err; 25948c2ecf20Sopenharmony_ci} 25958c2ecf20Sopenharmony_ci 25968c2ecf20Sopenharmony_cistatic void hifn_remove(struct pci_dev *pdev) 25978c2ecf20Sopenharmony_ci{ 25988c2ecf20Sopenharmony_ci int i; 25998c2ecf20Sopenharmony_ci struct hifn_device *dev; 26008c2ecf20Sopenharmony_ci 26018c2ecf20Sopenharmony_ci dev = pci_get_drvdata(pdev); 26028c2ecf20Sopenharmony_ci 26038c2ecf20Sopenharmony_ci if (dev) { 26048c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&dev->work); 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ci hifn_unregister_rng(dev); 26078c2ecf20Sopenharmony_ci hifn_unregister_alg(dev); 26088c2ecf20Sopenharmony_ci hifn_reset_dma(dev, 1); 26098c2ecf20Sopenharmony_ci hifn_stop_device(dev); 26108c2ecf20Sopenharmony_ci 26118c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 26128c2ecf20Sopenharmony_ci tasklet_kill(&dev->tasklet); 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci hifn_flush(dev); 26158c2ecf20Sopenharmony_ci 26168c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, sizeof(struct hifn_dma), 26178c2ecf20Sopenharmony_ci dev->desc_virt, dev->desc_dma); 26188c2ecf20Sopenharmony_ci for (i = 0; i < 3; ++i) 26198c2ecf20Sopenharmony_ci if (dev->bar[i]) 26208c2ecf20Sopenharmony_ci iounmap(dev->bar[i]); 26218c2ecf20Sopenharmony_ci 26228c2ecf20Sopenharmony_ci kfree(dev); 26238c2ecf20Sopenharmony_ci } 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci pci_release_regions(pdev); 26268c2ecf20Sopenharmony_ci pci_disable_device(pdev); 26278c2ecf20Sopenharmony_ci} 26288c2ecf20Sopenharmony_ci 26298c2ecf20Sopenharmony_cistatic struct pci_device_id hifn_pci_tbl[] = { 26308c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_HIFN, PCI_DEVICE_ID_HIFN_7955) }, 26318c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_HIFN, PCI_DEVICE_ID_HIFN_7956) }, 26328c2ecf20Sopenharmony_ci { 0 } 26338c2ecf20Sopenharmony_ci}; 26348c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, hifn_pci_tbl); 26358c2ecf20Sopenharmony_ci 26368c2ecf20Sopenharmony_cistatic struct pci_driver hifn_pci_driver = { 26378c2ecf20Sopenharmony_ci .name = "hifn795x", 26388c2ecf20Sopenharmony_ci .id_table = hifn_pci_tbl, 26398c2ecf20Sopenharmony_ci .probe = hifn_probe, 26408c2ecf20Sopenharmony_ci .remove = hifn_remove, 26418c2ecf20Sopenharmony_ci}; 26428c2ecf20Sopenharmony_ci 26438c2ecf20Sopenharmony_cistatic int __init hifn_init(void) 26448c2ecf20Sopenharmony_ci{ 26458c2ecf20Sopenharmony_ci unsigned int freq; 26468c2ecf20Sopenharmony_ci int err; 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ci if (strncmp(hifn_pll_ref, "ext", 3) && 26498c2ecf20Sopenharmony_ci strncmp(hifn_pll_ref, "pci", 3)) { 26508c2ecf20Sopenharmony_ci pr_err("hifn795x: invalid hifn_pll_ref clock, must be pci or ext"); 26518c2ecf20Sopenharmony_ci return -EINVAL; 26528c2ecf20Sopenharmony_ci } 26538c2ecf20Sopenharmony_ci 26548c2ecf20Sopenharmony_ci /* 26558c2ecf20Sopenharmony_ci * For the 7955/7956 the reference clock frequency must be in the 26568c2ecf20Sopenharmony_ci * range of 20MHz-100MHz. For the 7954 the upper bound is 66.67MHz, 26578c2ecf20Sopenharmony_ci * but this chip is currently not supported. 26588c2ecf20Sopenharmony_ci */ 26598c2ecf20Sopenharmony_ci if (hifn_pll_ref[3] != '\0') { 26608c2ecf20Sopenharmony_ci freq = simple_strtoul(hifn_pll_ref + 3, NULL, 10); 26618c2ecf20Sopenharmony_ci if (freq < 20 || freq > 100) { 26628c2ecf20Sopenharmony_ci pr_err("hifn795x: invalid hifn_pll_ref frequency, must" 26638c2ecf20Sopenharmony_ci "be in the range of 20-100"); 26648c2ecf20Sopenharmony_ci return -EINVAL; 26658c2ecf20Sopenharmony_ci } 26668c2ecf20Sopenharmony_ci } 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci err = pci_register_driver(&hifn_pci_driver); 26698c2ecf20Sopenharmony_ci if (err < 0) { 26708c2ecf20Sopenharmony_ci pr_err("Failed to register PCI driver for %s device.\n", 26718c2ecf20Sopenharmony_ci hifn_pci_driver.name); 26728c2ecf20Sopenharmony_ci return -ENODEV; 26738c2ecf20Sopenharmony_ci } 26748c2ecf20Sopenharmony_ci 26758c2ecf20Sopenharmony_ci pr_info("Driver for HIFN 795x crypto accelerator chip " 26768c2ecf20Sopenharmony_ci "has been successfully registered.\n"); 26778c2ecf20Sopenharmony_ci 26788c2ecf20Sopenharmony_ci return 0; 26798c2ecf20Sopenharmony_ci} 26808c2ecf20Sopenharmony_ci 26818c2ecf20Sopenharmony_cistatic void __exit hifn_fini(void) 26828c2ecf20Sopenharmony_ci{ 26838c2ecf20Sopenharmony_ci pci_unregister_driver(&hifn_pci_driver); 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_ci pr_info("Driver for HIFN 795x crypto accelerator chip " 26868c2ecf20Sopenharmony_ci "has been successfully unregistered.\n"); 26878c2ecf20Sopenharmony_ci} 26888c2ecf20Sopenharmony_ci 26898c2ecf20Sopenharmony_cimodule_init(hifn_init); 26908c2ecf20Sopenharmony_cimodule_exit(hifn_fini); 26918c2ecf20Sopenharmony_ci 26928c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 26938c2ecf20Sopenharmony_ciMODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>"); 26948c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for HIFN 795x crypto accelerator chip."); 2695