162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 2007+ Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru> 462306a36Sopenharmony_ci * All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/moduleparam.h> 1062306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 1162306a36Sopenharmony_ci#include <linux/interrupt.h> 1262306a36Sopenharmony_ci#include <linux/pci.h> 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci#include <linux/delay.h> 1562306a36Sopenharmony_ci#include <linux/mm.h> 1662306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1762306a36Sopenharmony_ci#include <linux/scatterlist.h> 1862306a36Sopenharmony_ci#include <linux/highmem.h> 1962306a36Sopenharmony_ci#include <linux/crypto.h> 2062306a36Sopenharmony_ci#include <linux/hw_random.h> 2162306a36Sopenharmony_ci#include <linux/ktime.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <crypto/algapi.h> 2462306a36Sopenharmony_ci#include <crypto/internal/des.h> 2562306a36Sopenharmony_ci#include <crypto/internal/skcipher.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic char hifn_pll_ref[sizeof("extNNN")] = "ext"; 2862306a36Sopenharmony_cimodule_param_string(hifn_pll_ref, hifn_pll_ref, sizeof(hifn_pll_ref), 0444); 2962306a36Sopenharmony_ciMODULE_PARM_DESC(hifn_pll_ref, 3062306a36Sopenharmony_ci "PLL reference clock (pci[freq] or ext[freq], default ext)"); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic atomic_t hifn_dev_number; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define ACRYPTO_OP_DECRYPT 0 3562306a36Sopenharmony_ci#define ACRYPTO_OP_ENCRYPT 1 3662306a36Sopenharmony_ci#define ACRYPTO_OP_HMAC 2 3762306a36Sopenharmony_ci#define ACRYPTO_OP_RNG 3 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define ACRYPTO_MODE_ECB 0 4062306a36Sopenharmony_ci#define ACRYPTO_MODE_CBC 1 4162306a36Sopenharmony_ci#define ACRYPTO_MODE_CFB 2 4262306a36Sopenharmony_ci#define ACRYPTO_MODE_OFB 3 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define ACRYPTO_TYPE_AES_128 0 4562306a36Sopenharmony_ci#define ACRYPTO_TYPE_AES_192 1 4662306a36Sopenharmony_ci#define ACRYPTO_TYPE_AES_256 2 4762306a36Sopenharmony_ci#define ACRYPTO_TYPE_3DES 3 4862306a36Sopenharmony_ci#define ACRYPTO_TYPE_DES 4 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define PCI_VENDOR_ID_HIFN 0x13A3 5162306a36Sopenharmony_ci#define PCI_DEVICE_ID_HIFN_7955 0x0020 5262306a36Sopenharmony_ci#define PCI_DEVICE_ID_HIFN_7956 0x001d 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* I/O region sizes */ 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define HIFN_BAR0_SIZE 0x1000 5762306a36Sopenharmony_ci#define HIFN_BAR1_SIZE 0x2000 5862306a36Sopenharmony_ci#define HIFN_BAR2_SIZE 0x8000 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* DMA registres */ 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#define HIFN_DMA_CRA 0x0C /* DMA Command Ring Address */ 6362306a36Sopenharmony_ci#define HIFN_DMA_SDRA 0x1C /* DMA Source Data Ring Address */ 6462306a36Sopenharmony_ci#define HIFN_DMA_RRA 0x2C /* DMA Result Ring Address */ 6562306a36Sopenharmony_ci#define HIFN_DMA_DDRA 0x3C /* DMA Destination Data Ring Address */ 6662306a36Sopenharmony_ci#define HIFN_DMA_STCTL 0x40 /* DMA Status and Control */ 6762306a36Sopenharmony_ci#define HIFN_DMA_INTREN 0x44 /* DMA Interrupt Enable */ 6862306a36Sopenharmony_ci#define HIFN_DMA_CFG1 0x48 /* DMA Configuration #1 */ 6962306a36Sopenharmony_ci#define HIFN_DMA_CFG2 0x6C /* DMA Configuration #2 */ 7062306a36Sopenharmony_ci#define HIFN_CHIP_ID 0x98 /* Chip ID */ 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* 7362306a36Sopenharmony_ci * Processing Unit Registers (offset from BASEREG0) 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_ci#define HIFN_0_PUDATA 0x00 /* Processing Unit Data */ 7662306a36Sopenharmony_ci#define HIFN_0_PUCTRL 0x04 /* Processing Unit Control */ 7762306a36Sopenharmony_ci#define HIFN_0_PUISR 0x08 /* Processing Unit Interrupt Status */ 7862306a36Sopenharmony_ci#define HIFN_0_PUCNFG 0x0c /* Processing Unit Configuration */ 7962306a36Sopenharmony_ci#define HIFN_0_PUIER 0x10 /* Processing Unit Interrupt Enable */ 8062306a36Sopenharmony_ci#define HIFN_0_PUSTAT 0x14 /* Processing Unit Status/Chip ID */ 8162306a36Sopenharmony_ci#define HIFN_0_FIFOSTAT 0x18 /* FIFO Status */ 8262306a36Sopenharmony_ci#define HIFN_0_FIFOCNFG 0x1c /* FIFO Configuration */ 8362306a36Sopenharmony_ci#define HIFN_0_SPACESIZE 0x20 /* Register space size */ 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* Processing Unit Control Register (HIFN_0_PUCTRL) */ 8662306a36Sopenharmony_ci#define HIFN_PUCTRL_CLRSRCFIFO 0x0010 /* clear source fifo */ 8762306a36Sopenharmony_ci#define HIFN_PUCTRL_STOP 0x0008 /* stop pu */ 8862306a36Sopenharmony_ci#define HIFN_PUCTRL_LOCKRAM 0x0004 /* lock ram */ 8962306a36Sopenharmony_ci#define HIFN_PUCTRL_DMAENA 0x0002 /* enable dma */ 9062306a36Sopenharmony_ci#define HIFN_PUCTRL_RESET 0x0001 /* Reset processing unit */ 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/* Processing Unit Interrupt Status Register (HIFN_0_PUISR) */ 9362306a36Sopenharmony_ci#define HIFN_PUISR_CMDINVAL 0x8000 /* Invalid command interrupt */ 9462306a36Sopenharmony_ci#define HIFN_PUISR_DATAERR 0x4000 /* Data error interrupt */ 9562306a36Sopenharmony_ci#define HIFN_PUISR_SRCFIFO 0x2000 /* Source FIFO ready interrupt */ 9662306a36Sopenharmony_ci#define HIFN_PUISR_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */ 9762306a36Sopenharmony_ci#define HIFN_PUISR_DSTOVER 0x0200 /* Destination overrun interrupt */ 9862306a36Sopenharmony_ci#define HIFN_PUISR_SRCCMD 0x0080 /* Source command interrupt */ 9962306a36Sopenharmony_ci#define HIFN_PUISR_SRCCTX 0x0040 /* Source context interrupt */ 10062306a36Sopenharmony_ci#define HIFN_PUISR_SRCDATA 0x0020 /* Source data interrupt */ 10162306a36Sopenharmony_ci#define HIFN_PUISR_DSTDATA 0x0010 /* Destination data interrupt */ 10262306a36Sopenharmony_ci#define HIFN_PUISR_DSTRESULT 0x0004 /* Destination result interrupt */ 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* Processing Unit Configuration Register (HIFN_0_PUCNFG) */ 10562306a36Sopenharmony_ci#define HIFN_PUCNFG_DRAMMASK 0xe000 /* DRAM size mask */ 10662306a36Sopenharmony_ci#define HIFN_PUCNFG_DSZ_256K 0x0000 /* 256k dram */ 10762306a36Sopenharmony_ci#define HIFN_PUCNFG_DSZ_512K 0x2000 /* 512k dram */ 10862306a36Sopenharmony_ci#define HIFN_PUCNFG_DSZ_1M 0x4000 /* 1m dram */ 10962306a36Sopenharmony_ci#define HIFN_PUCNFG_DSZ_2M 0x6000 /* 2m dram */ 11062306a36Sopenharmony_ci#define HIFN_PUCNFG_DSZ_4M 0x8000 /* 4m dram */ 11162306a36Sopenharmony_ci#define HIFN_PUCNFG_DSZ_8M 0xa000 /* 8m dram */ 11262306a36Sopenharmony_ci#define HIFN_PUNCFG_DSZ_16M 0xc000 /* 16m dram */ 11362306a36Sopenharmony_ci#define HIFN_PUCNFG_DSZ_32M 0xe000 /* 32m dram */ 11462306a36Sopenharmony_ci#define HIFN_PUCNFG_DRAMREFRESH 0x1800 /* DRAM refresh rate mask */ 11562306a36Sopenharmony_ci#define HIFN_PUCNFG_DRFR_512 0x0000 /* 512 divisor of ECLK */ 11662306a36Sopenharmony_ci#define HIFN_PUCNFG_DRFR_256 0x0800 /* 256 divisor of ECLK */ 11762306a36Sopenharmony_ci#define HIFN_PUCNFG_DRFR_128 0x1000 /* 128 divisor of ECLK */ 11862306a36Sopenharmony_ci#define HIFN_PUCNFG_TCALLPHASES 0x0200 /* your guess is as good as mine... */ 11962306a36Sopenharmony_ci#define HIFN_PUCNFG_TCDRVTOTEM 0x0100 /* your guess is as good as mine... */ 12062306a36Sopenharmony_ci#define HIFN_PUCNFG_BIGENDIAN 0x0080 /* DMA big endian mode */ 12162306a36Sopenharmony_ci#define HIFN_PUCNFG_BUS32 0x0040 /* Bus width 32bits */ 12262306a36Sopenharmony_ci#define HIFN_PUCNFG_BUS16 0x0000 /* Bus width 16 bits */ 12362306a36Sopenharmony_ci#define HIFN_PUCNFG_CHIPID 0x0020 /* Allow chipid from PUSTAT */ 12462306a36Sopenharmony_ci#define HIFN_PUCNFG_DRAM 0x0010 /* Context RAM is DRAM */ 12562306a36Sopenharmony_ci#define HIFN_PUCNFG_SRAM 0x0000 /* Context RAM is SRAM */ 12662306a36Sopenharmony_ci#define HIFN_PUCNFG_COMPSING 0x0004 /* Enable single compression context */ 12762306a36Sopenharmony_ci#define HIFN_PUCNFG_ENCCNFG 0x0002 /* Encryption configuration */ 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci/* Processing Unit Interrupt Enable Register (HIFN_0_PUIER) */ 13062306a36Sopenharmony_ci#define HIFN_PUIER_CMDINVAL 0x8000 /* Invalid command interrupt */ 13162306a36Sopenharmony_ci#define HIFN_PUIER_DATAERR 0x4000 /* Data error interrupt */ 13262306a36Sopenharmony_ci#define HIFN_PUIER_SRCFIFO 0x2000 /* Source FIFO ready interrupt */ 13362306a36Sopenharmony_ci#define HIFN_PUIER_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */ 13462306a36Sopenharmony_ci#define HIFN_PUIER_DSTOVER 0x0200 /* Destination overrun interrupt */ 13562306a36Sopenharmony_ci#define HIFN_PUIER_SRCCMD 0x0080 /* Source command interrupt */ 13662306a36Sopenharmony_ci#define HIFN_PUIER_SRCCTX 0x0040 /* Source context interrupt */ 13762306a36Sopenharmony_ci#define HIFN_PUIER_SRCDATA 0x0020 /* Source data interrupt */ 13862306a36Sopenharmony_ci#define HIFN_PUIER_DSTDATA 0x0010 /* Destination data interrupt */ 13962306a36Sopenharmony_ci#define HIFN_PUIER_DSTRESULT 0x0004 /* Destination result interrupt */ 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci/* Processing Unit Status Register/Chip ID (HIFN_0_PUSTAT) */ 14262306a36Sopenharmony_ci#define HIFN_PUSTAT_CMDINVAL 0x8000 /* Invalid command interrupt */ 14362306a36Sopenharmony_ci#define HIFN_PUSTAT_DATAERR 0x4000 /* Data error interrupt */ 14462306a36Sopenharmony_ci#define HIFN_PUSTAT_SRCFIFO 0x2000 /* Source FIFO ready interrupt */ 14562306a36Sopenharmony_ci#define HIFN_PUSTAT_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */ 14662306a36Sopenharmony_ci#define HIFN_PUSTAT_DSTOVER 0x0200 /* Destination overrun interrupt */ 14762306a36Sopenharmony_ci#define HIFN_PUSTAT_SRCCMD 0x0080 /* Source command interrupt */ 14862306a36Sopenharmony_ci#define HIFN_PUSTAT_SRCCTX 0x0040 /* Source context interrupt */ 14962306a36Sopenharmony_ci#define HIFN_PUSTAT_SRCDATA 0x0020 /* Source data interrupt */ 15062306a36Sopenharmony_ci#define HIFN_PUSTAT_DSTDATA 0x0010 /* Destination data interrupt */ 15162306a36Sopenharmony_ci#define HIFN_PUSTAT_DSTRESULT 0x0004 /* Destination result interrupt */ 15262306a36Sopenharmony_ci#define HIFN_PUSTAT_CHIPREV 0x00ff /* Chip revision mask */ 15362306a36Sopenharmony_ci#define HIFN_PUSTAT_CHIPENA 0xff00 /* Chip enabled mask */ 15462306a36Sopenharmony_ci#define HIFN_PUSTAT_ENA_2 0x1100 /* Level 2 enabled */ 15562306a36Sopenharmony_ci#define HIFN_PUSTAT_ENA_1 0x1000 /* Level 1 enabled */ 15662306a36Sopenharmony_ci#define HIFN_PUSTAT_ENA_0 0x3000 /* Level 0 enabled */ 15762306a36Sopenharmony_ci#define HIFN_PUSTAT_REV_2 0x0020 /* 7751 PT6/2 */ 15862306a36Sopenharmony_ci#define HIFN_PUSTAT_REV_3 0x0030 /* 7751 PT6/3 */ 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci/* FIFO Status Register (HIFN_0_FIFOSTAT) */ 16162306a36Sopenharmony_ci#define HIFN_FIFOSTAT_SRC 0x7f00 /* Source FIFO available */ 16262306a36Sopenharmony_ci#define HIFN_FIFOSTAT_DST 0x007f /* Destination FIFO available */ 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/* FIFO Configuration Register (HIFN_0_FIFOCNFG) */ 16562306a36Sopenharmony_ci#define HIFN_FIFOCNFG_THRESHOLD 0x0400 /* must be written as 1 */ 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci/* 16862306a36Sopenharmony_ci * DMA Interface Registers (offset from BASEREG1) 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_ci#define HIFN_1_DMA_CRAR 0x0c /* DMA Command Ring Address */ 17162306a36Sopenharmony_ci#define HIFN_1_DMA_SRAR 0x1c /* DMA Source Ring Address */ 17262306a36Sopenharmony_ci#define HIFN_1_DMA_RRAR 0x2c /* DMA Result Ring Address */ 17362306a36Sopenharmony_ci#define HIFN_1_DMA_DRAR 0x3c /* DMA Destination Ring Address */ 17462306a36Sopenharmony_ci#define HIFN_1_DMA_CSR 0x40 /* DMA Status and Control */ 17562306a36Sopenharmony_ci#define HIFN_1_DMA_IER 0x44 /* DMA Interrupt Enable */ 17662306a36Sopenharmony_ci#define HIFN_1_DMA_CNFG 0x48 /* DMA Configuration */ 17762306a36Sopenharmony_ci#define HIFN_1_PLL 0x4c /* 795x: PLL config */ 17862306a36Sopenharmony_ci#define HIFN_1_7811_RNGENA 0x60 /* 7811: rng enable */ 17962306a36Sopenharmony_ci#define HIFN_1_7811_RNGCFG 0x64 /* 7811: rng config */ 18062306a36Sopenharmony_ci#define HIFN_1_7811_RNGDAT 0x68 /* 7811: rng data */ 18162306a36Sopenharmony_ci#define HIFN_1_7811_RNGSTS 0x6c /* 7811: rng status */ 18262306a36Sopenharmony_ci#define HIFN_1_7811_MIPSRST 0x94 /* 7811: MIPS reset */ 18362306a36Sopenharmony_ci#define HIFN_1_REVID 0x98 /* Revision ID */ 18462306a36Sopenharmony_ci#define HIFN_1_UNLOCK_SECRET1 0xf4 18562306a36Sopenharmony_ci#define HIFN_1_UNLOCK_SECRET2 0xfc 18662306a36Sopenharmony_ci#define HIFN_1_PUB_RESET 0x204 /* Public/RNG Reset */ 18762306a36Sopenharmony_ci#define HIFN_1_PUB_BASE 0x300 /* Public Base Address */ 18862306a36Sopenharmony_ci#define HIFN_1_PUB_OPLEN 0x304 /* Public Operand Length */ 18962306a36Sopenharmony_ci#define HIFN_1_PUB_OP 0x308 /* Public Operand */ 19062306a36Sopenharmony_ci#define HIFN_1_PUB_STATUS 0x30c /* Public Status */ 19162306a36Sopenharmony_ci#define HIFN_1_PUB_IEN 0x310 /* Public Interrupt enable */ 19262306a36Sopenharmony_ci#define HIFN_1_RNG_CONFIG 0x314 /* RNG config */ 19362306a36Sopenharmony_ci#define HIFN_1_RNG_DATA 0x318 /* RNG data */ 19462306a36Sopenharmony_ci#define HIFN_1_PUB_MEM 0x400 /* start of Public key memory */ 19562306a36Sopenharmony_ci#define HIFN_1_PUB_MEMEND 0xbff /* end of Public key memory */ 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci/* DMA Status and Control Register (HIFN_1_DMA_CSR) */ 19862306a36Sopenharmony_ci#define HIFN_DMACSR_D_CTRLMASK 0xc0000000 /* Destinition Ring Control */ 19962306a36Sopenharmony_ci#define HIFN_DMACSR_D_CTRL_NOP 0x00000000 /* Dest. Control: no-op */ 20062306a36Sopenharmony_ci#define HIFN_DMACSR_D_CTRL_DIS 0x40000000 /* Dest. Control: disable */ 20162306a36Sopenharmony_ci#define HIFN_DMACSR_D_CTRL_ENA 0x80000000 /* Dest. Control: enable */ 20262306a36Sopenharmony_ci#define HIFN_DMACSR_D_ABORT 0x20000000 /* Destinition Ring PCIAbort */ 20362306a36Sopenharmony_ci#define HIFN_DMACSR_D_DONE 0x10000000 /* Destinition Ring Done */ 20462306a36Sopenharmony_ci#define HIFN_DMACSR_D_LAST 0x08000000 /* Destinition Ring Last */ 20562306a36Sopenharmony_ci#define HIFN_DMACSR_D_WAIT 0x04000000 /* Destinition Ring Waiting */ 20662306a36Sopenharmony_ci#define HIFN_DMACSR_D_OVER 0x02000000 /* Destinition Ring Overflow */ 20762306a36Sopenharmony_ci#define HIFN_DMACSR_R_CTRL 0x00c00000 /* Result Ring Control */ 20862306a36Sopenharmony_ci#define HIFN_DMACSR_R_CTRL_NOP 0x00000000 /* Result Control: no-op */ 20962306a36Sopenharmony_ci#define HIFN_DMACSR_R_CTRL_DIS 0x00400000 /* Result Control: disable */ 21062306a36Sopenharmony_ci#define HIFN_DMACSR_R_CTRL_ENA 0x00800000 /* Result Control: enable */ 21162306a36Sopenharmony_ci#define HIFN_DMACSR_R_ABORT 0x00200000 /* Result Ring PCI Abort */ 21262306a36Sopenharmony_ci#define HIFN_DMACSR_R_DONE 0x00100000 /* Result Ring Done */ 21362306a36Sopenharmony_ci#define HIFN_DMACSR_R_LAST 0x00080000 /* Result Ring Last */ 21462306a36Sopenharmony_ci#define HIFN_DMACSR_R_WAIT 0x00040000 /* Result Ring Waiting */ 21562306a36Sopenharmony_ci#define HIFN_DMACSR_R_OVER 0x00020000 /* Result Ring Overflow */ 21662306a36Sopenharmony_ci#define HIFN_DMACSR_S_CTRL 0x0000c000 /* Source Ring Control */ 21762306a36Sopenharmony_ci#define HIFN_DMACSR_S_CTRL_NOP 0x00000000 /* Source Control: no-op */ 21862306a36Sopenharmony_ci#define HIFN_DMACSR_S_CTRL_DIS 0x00004000 /* Source Control: disable */ 21962306a36Sopenharmony_ci#define HIFN_DMACSR_S_CTRL_ENA 0x00008000 /* Source Control: enable */ 22062306a36Sopenharmony_ci#define HIFN_DMACSR_S_ABORT 0x00002000 /* Source Ring PCI Abort */ 22162306a36Sopenharmony_ci#define HIFN_DMACSR_S_DONE 0x00001000 /* Source Ring Done */ 22262306a36Sopenharmony_ci#define HIFN_DMACSR_S_LAST 0x00000800 /* Source Ring Last */ 22362306a36Sopenharmony_ci#define HIFN_DMACSR_S_WAIT 0x00000400 /* Source Ring Waiting */ 22462306a36Sopenharmony_ci#define HIFN_DMACSR_ILLW 0x00000200 /* Illegal write (7811 only) */ 22562306a36Sopenharmony_ci#define HIFN_DMACSR_ILLR 0x00000100 /* Illegal read (7811 only) */ 22662306a36Sopenharmony_ci#define HIFN_DMACSR_C_CTRL 0x000000c0 /* Command Ring Control */ 22762306a36Sopenharmony_ci#define HIFN_DMACSR_C_CTRL_NOP 0x00000000 /* Command Control: no-op */ 22862306a36Sopenharmony_ci#define HIFN_DMACSR_C_CTRL_DIS 0x00000040 /* Command Control: disable */ 22962306a36Sopenharmony_ci#define HIFN_DMACSR_C_CTRL_ENA 0x00000080 /* Command Control: enable */ 23062306a36Sopenharmony_ci#define HIFN_DMACSR_C_ABORT 0x00000020 /* Command Ring PCI Abort */ 23162306a36Sopenharmony_ci#define HIFN_DMACSR_C_DONE 0x00000010 /* Command Ring Done */ 23262306a36Sopenharmony_ci#define HIFN_DMACSR_C_LAST 0x00000008 /* Command Ring Last */ 23362306a36Sopenharmony_ci#define HIFN_DMACSR_C_WAIT 0x00000004 /* Command Ring Waiting */ 23462306a36Sopenharmony_ci#define HIFN_DMACSR_PUBDONE 0x00000002 /* Public op done (7951 only) */ 23562306a36Sopenharmony_ci#define HIFN_DMACSR_ENGINE 0x00000001 /* Command Ring Engine IRQ */ 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci/* DMA Interrupt Enable Register (HIFN_1_DMA_IER) */ 23862306a36Sopenharmony_ci#define HIFN_DMAIER_D_ABORT 0x20000000 /* Destination Ring PCIAbort */ 23962306a36Sopenharmony_ci#define HIFN_DMAIER_D_DONE 0x10000000 /* Destination Ring Done */ 24062306a36Sopenharmony_ci#define HIFN_DMAIER_D_LAST 0x08000000 /* Destination Ring Last */ 24162306a36Sopenharmony_ci#define HIFN_DMAIER_D_WAIT 0x04000000 /* Destination Ring Waiting */ 24262306a36Sopenharmony_ci#define HIFN_DMAIER_D_OVER 0x02000000 /* Destination Ring Overflow */ 24362306a36Sopenharmony_ci#define HIFN_DMAIER_R_ABORT 0x00200000 /* Result Ring PCI Abort */ 24462306a36Sopenharmony_ci#define HIFN_DMAIER_R_DONE 0x00100000 /* Result Ring Done */ 24562306a36Sopenharmony_ci#define HIFN_DMAIER_R_LAST 0x00080000 /* Result Ring Last */ 24662306a36Sopenharmony_ci#define HIFN_DMAIER_R_WAIT 0x00040000 /* Result Ring Waiting */ 24762306a36Sopenharmony_ci#define HIFN_DMAIER_R_OVER 0x00020000 /* Result Ring Overflow */ 24862306a36Sopenharmony_ci#define HIFN_DMAIER_S_ABORT 0x00002000 /* Source Ring PCI Abort */ 24962306a36Sopenharmony_ci#define HIFN_DMAIER_S_DONE 0x00001000 /* Source Ring Done */ 25062306a36Sopenharmony_ci#define HIFN_DMAIER_S_LAST 0x00000800 /* Source Ring Last */ 25162306a36Sopenharmony_ci#define HIFN_DMAIER_S_WAIT 0x00000400 /* Source Ring Waiting */ 25262306a36Sopenharmony_ci#define HIFN_DMAIER_ILLW 0x00000200 /* Illegal write (7811 only) */ 25362306a36Sopenharmony_ci#define HIFN_DMAIER_ILLR 0x00000100 /* Illegal read (7811 only) */ 25462306a36Sopenharmony_ci#define HIFN_DMAIER_C_ABORT 0x00000020 /* Command Ring PCI Abort */ 25562306a36Sopenharmony_ci#define HIFN_DMAIER_C_DONE 0x00000010 /* Command Ring Done */ 25662306a36Sopenharmony_ci#define HIFN_DMAIER_C_LAST 0x00000008 /* Command Ring Last */ 25762306a36Sopenharmony_ci#define HIFN_DMAIER_C_WAIT 0x00000004 /* Command Ring Waiting */ 25862306a36Sopenharmony_ci#define HIFN_DMAIER_PUBDONE 0x00000002 /* public op done (7951 only) */ 25962306a36Sopenharmony_ci#define HIFN_DMAIER_ENGINE 0x00000001 /* Engine IRQ */ 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci/* DMA Configuration Register (HIFN_1_DMA_CNFG) */ 26262306a36Sopenharmony_ci#define HIFN_DMACNFG_BIGENDIAN 0x10000000 /* big endian mode */ 26362306a36Sopenharmony_ci#define HIFN_DMACNFG_POLLFREQ 0x00ff0000 /* Poll frequency mask */ 26462306a36Sopenharmony_ci#define HIFN_DMACNFG_UNLOCK 0x00000800 26562306a36Sopenharmony_ci#define HIFN_DMACNFG_POLLINVAL 0x00000700 /* Invalid Poll Scalar */ 26662306a36Sopenharmony_ci#define HIFN_DMACNFG_LAST 0x00000010 /* Host control LAST bit */ 26762306a36Sopenharmony_ci#define HIFN_DMACNFG_MODE 0x00000004 /* DMA mode */ 26862306a36Sopenharmony_ci#define HIFN_DMACNFG_DMARESET 0x00000002 /* DMA Reset # */ 26962306a36Sopenharmony_ci#define HIFN_DMACNFG_MSTRESET 0x00000001 /* Master Reset # */ 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci/* PLL configuration register */ 27262306a36Sopenharmony_ci#define HIFN_PLL_REF_CLK_HBI 0x00000000 /* HBI reference clock */ 27362306a36Sopenharmony_ci#define HIFN_PLL_REF_CLK_PLL 0x00000001 /* PLL reference clock */ 27462306a36Sopenharmony_ci#define HIFN_PLL_BP 0x00000002 /* Reference clock bypass */ 27562306a36Sopenharmony_ci#define HIFN_PLL_PK_CLK_HBI 0x00000000 /* PK engine HBI clock */ 27662306a36Sopenharmony_ci#define HIFN_PLL_PK_CLK_PLL 0x00000008 /* PK engine PLL clock */ 27762306a36Sopenharmony_ci#define HIFN_PLL_PE_CLK_HBI 0x00000000 /* PE engine HBI clock */ 27862306a36Sopenharmony_ci#define HIFN_PLL_PE_CLK_PLL 0x00000010 /* PE engine PLL clock */ 27962306a36Sopenharmony_ci#define HIFN_PLL_RESERVED_1 0x00000400 /* Reserved bit, must be 1 */ 28062306a36Sopenharmony_ci#define HIFN_PLL_ND_SHIFT 11 /* Clock multiplier shift */ 28162306a36Sopenharmony_ci#define HIFN_PLL_ND_MULT_2 0x00000000 /* PLL clock multiplier 2 */ 28262306a36Sopenharmony_ci#define HIFN_PLL_ND_MULT_4 0x00000800 /* PLL clock multiplier 4 */ 28362306a36Sopenharmony_ci#define HIFN_PLL_ND_MULT_6 0x00001000 /* PLL clock multiplier 6 */ 28462306a36Sopenharmony_ci#define HIFN_PLL_ND_MULT_8 0x00001800 /* PLL clock multiplier 8 */ 28562306a36Sopenharmony_ci#define HIFN_PLL_ND_MULT_10 0x00002000 /* PLL clock multiplier 10 */ 28662306a36Sopenharmony_ci#define HIFN_PLL_ND_MULT_12 0x00002800 /* PLL clock multiplier 12 */ 28762306a36Sopenharmony_ci#define HIFN_PLL_IS_1_8 0x00000000 /* charge pump (mult. 1-8) */ 28862306a36Sopenharmony_ci#define HIFN_PLL_IS_9_12 0x00010000 /* charge pump (mult. 9-12) */ 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci#define HIFN_PLL_FCK_MAX 266 /* Maximum PLL frequency */ 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci/* Public key reset register (HIFN_1_PUB_RESET) */ 29362306a36Sopenharmony_ci#define HIFN_PUBRST_RESET 0x00000001 /* reset public/rng unit */ 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci/* Public base address register (HIFN_1_PUB_BASE) */ 29662306a36Sopenharmony_ci#define HIFN_PUBBASE_ADDR 0x00003fff /* base address */ 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci/* Public operand length register (HIFN_1_PUB_OPLEN) */ 29962306a36Sopenharmony_ci#define HIFN_PUBOPLEN_MOD_M 0x0000007f /* modulus length mask */ 30062306a36Sopenharmony_ci#define HIFN_PUBOPLEN_MOD_S 0 /* modulus length shift */ 30162306a36Sopenharmony_ci#define HIFN_PUBOPLEN_EXP_M 0x0003ff80 /* exponent length mask */ 30262306a36Sopenharmony_ci#define HIFN_PUBOPLEN_EXP_S 7 /* exponent length shift */ 30362306a36Sopenharmony_ci#define HIFN_PUBOPLEN_RED_M 0x003c0000 /* reducend length mask */ 30462306a36Sopenharmony_ci#define HIFN_PUBOPLEN_RED_S 18 /* reducend length shift */ 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci/* Public operation register (HIFN_1_PUB_OP) */ 30762306a36Sopenharmony_ci#define HIFN_PUBOP_AOFFSET_M 0x0000007f /* A offset mask */ 30862306a36Sopenharmony_ci#define HIFN_PUBOP_AOFFSET_S 0 /* A offset shift */ 30962306a36Sopenharmony_ci#define HIFN_PUBOP_BOFFSET_M 0x00000f80 /* B offset mask */ 31062306a36Sopenharmony_ci#define HIFN_PUBOP_BOFFSET_S 7 /* B offset shift */ 31162306a36Sopenharmony_ci#define HIFN_PUBOP_MOFFSET_M 0x0003f000 /* M offset mask */ 31262306a36Sopenharmony_ci#define HIFN_PUBOP_MOFFSET_S 12 /* M offset shift */ 31362306a36Sopenharmony_ci#define HIFN_PUBOP_OP_MASK 0x003c0000 /* Opcode: */ 31462306a36Sopenharmony_ci#define HIFN_PUBOP_OP_NOP 0x00000000 /* NOP */ 31562306a36Sopenharmony_ci#define HIFN_PUBOP_OP_ADD 0x00040000 /* ADD */ 31662306a36Sopenharmony_ci#define HIFN_PUBOP_OP_ADDC 0x00080000 /* ADD w/carry */ 31762306a36Sopenharmony_ci#define HIFN_PUBOP_OP_SUB 0x000c0000 /* SUB */ 31862306a36Sopenharmony_ci#define HIFN_PUBOP_OP_SUBC 0x00100000 /* SUB w/carry */ 31962306a36Sopenharmony_ci#define HIFN_PUBOP_OP_MODADD 0x00140000 /* Modular ADD */ 32062306a36Sopenharmony_ci#define HIFN_PUBOP_OP_MODSUB 0x00180000 /* Modular SUB */ 32162306a36Sopenharmony_ci#define HIFN_PUBOP_OP_INCA 0x001c0000 /* INC A */ 32262306a36Sopenharmony_ci#define HIFN_PUBOP_OP_DECA 0x00200000 /* DEC A */ 32362306a36Sopenharmony_ci#define HIFN_PUBOP_OP_MULT 0x00240000 /* MULT */ 32462306a36Sopenharmony_ci#define HIFN_PUBOP_OP_MODMULT 0x00280000 /* Modular MULT */ 32562306a36Sopenharmony_ci#define HIFN_PUBOP_OP_MODRED 0x002c0000 /* Modular RED */ 32662306a36Sopenharmony_ci#define HIFN_PUBOP_OP_MODEXP 0x00300000 /* Modular EXP */ 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci/* Public status register (HIFN_1_PUB_STATUS) */ 32962306a36Sopenharmony_ci#define HIFN_PUBSTS_DONE 0x00000001 /* operation done */ 33062306a36Sopenharmony_ci#define HIFN_PUBSTS_CARRY 0x00000002 /* carry */ 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci/* Public interrupt enable register (HIFN_1_PUB_IEN) */ 33362306a36Sopenharmony_ci#define HIFN_PUBIEN_DONE 0x00000001 /* operation done interrupt */ 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci/* Random number generator config register (HIFN_1_RNG_CONFIG) */ 33662306a36Sopenharmony_ci#define HIFN_RNGCFG_ENA 0x00000001 /* enable rng */ 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci#define HIFN_NAMESIZE 32 33962306a36Sopenharmony_ci#define HIFN_MAX_RESULT_ORDER 5 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci#define HIFN_D_CMD_RSIZE (24 * 1) 34262306a36Sopenharmony_ci#define HIFN_D_SRC_RSIZE (80 * 1) 34362306a36Sopenharmony_ci#define HIFN_D_DST_RSIZE (80 * 1) 34462306a36Sopenharmony_ci#define HIFN_D_RES_RSIZE (24 * 1) 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci#define HIFN_D_DST_DALIGN 4 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci#define HIFN_QUEUE_LENGTH (HIFN_D_CMD_RSIZE - 1) 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci#define AES_MIN_KEY_SIZE 16 35162306a36Sopenharmony_ci#define AES_MAX_KEY_SIZE 32 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci#define HIFN_DES_KEY_LENGTH 8 35462306a36Sopenharmony_ci#define HIFN_3DES_KEY_LENGTH 24 35562306a36Sopenharmony_ci#define HIFN_MAX_CRYPT_KEY_LENGTH AES_MAX_KEY_SIZE 35662306a36Sopenharmony_ci#define HIFN_IV_LENGTH 8 35762306a36Sopenharmony_ci#define HIFN_AES_IV_LENGTH 16 35862306a36Sopenharmony_ci#define HIFN_MAX_IV_LENGTH HIFN_AES_IV_LENGTH 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci#define HIFN_MAC_KEY_LENGTH 64 36162306a36Sopenharmony_ci#define HIFN_MD5_LENGTH 16 36262306a36Sopenharmony_ci#define HIFN_SHA1_LENGTH 20 36362306a36Sopenharmony_ci#define HIFN_MAC_TRUNC_LENGTH 12 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci#define HIFN_MAX_COMMAND (8 + 8 + 8 + 64 + 260) 36662306a36Sopenharmony_ci#define HIFN_MAX_RESULT (8 + 4 + 4 + 20 + 4) 36762306a36Sopenharmony_ci#define HIFN_USED_RESULT 12 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistruct hifn_desc { 37062306a36Sopenharmony_ci volatile __le32 l; 37162306a36Sopenharmony_ci volatile __le32 p; 37262306a36Sopenharmony_ci}; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistruct hifn_dma { 37562306a36Sopenharmony_ci struct hifn_desc cmdr[HIFN_D_CMD_RSIZE + 1]; 37662306a36Sopenharmony_ci struct hifn_desc srcr[HIFN_D_SRC_RSIZE + 1]; 37762306a36Sopenharmony_ci struct hifn_desc dstr[HIFN_D_DST_RSIZE + 1]; 37862306a36Sopenharmony_ci struct hifn_desc resr[HIFN_D_RES_RSIZE + 1]; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci u8 command_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_COMMAND]; 38162306a36Sopenharmony_ci u8 result_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_RESULT]; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* 38462306a36Sopenharmony_ci * Our current positions for insertion and removal from the descriptor 38562306a36Sopenharmony_ci * rings. 38662306a36Sopenharmony_ci */ 38762306a36Sopenharmony_ci volatile int cmdi, srci, dsti, resi; 38862306a36Sopenharmony_ci volatile int cmdu, srcu, dstu, resu; 38962306a36Sopenharmony_ci int cmdk, srck, dstk, resk; 39062306a36Sopenharmony_ci}; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci#define HIFN_FLAG_CMD_BUSY (1 << 0) 39362306a36Sopenharmony_ci#define HIFN_FLAG_SRC_BUSY (1 << 1) 39462306a36Sopenharmony_ci#define HIFN_FLAG_DST_BUSY (1 << 2) 39562306a36Sopenharmony_ci#define HIFN_FLAG_RES_BUSY (1 << 3) 39662306a36Sopenharmony_ci#define HIFN_FLAG_OLD_KEY (1 << 4) 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci#define HIFN_DEFAULT_ACTIVE_NUM 5 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistruct hifn_device { 40162306a36Sopenharmony_ci char name[HIFN_NAMESIZE]; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci int irq; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci struct pci_dev *pdev; 40662306a36Sopenharmony_ci void __iomem *bar[3]; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci void *desc_virt; 40962306a36Sopenharmony_ci dma_addr_t desc_dma; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci u32 dmareg; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci void *sa[HIFN_D_RES_RSIZE]; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci spinlock_t lock; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci u32 flags; 41862306a36Sopenharmony_ci int active, started; 41962306a36Sopenharmony_ci struct delayed_work work; 42062306a36Sopenharmony_ci unsigned long reset; 42162306a36Sopenharmony_ci unsigned long success; 42262306a36Sopenharmony_ci unsigned long prev_success; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci u8 snum; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci struct tasklet_struct tasklet; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci struct crypto_queue queue; 42962306a36Sopenharmony_ci struct list_head alg_list; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci unsigned int pk_clk_freq; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_HIFN_795X_RNG 43462306a36Sopenharmony_ci unsigned int rng_wait_time; 43562306a36Sopenharmony_ci ktime_t rngtime; 43662306a36Sopenharmony_ci struct hwrng rng; 43762306a36Sopenharmony_ci#endif 43862306a36Sopenharmony_ci}; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci#define HIFN_D_LENGTH 0x0000ffff 44162306a36Sopenharmony_ci#define HIFN_D_NOINVALID 0x01000000 44262306a36Sopenharmony_ci#define HIFN_D_MASKDONEIRQ 0x02000000 44362306a36Sopenharmony_ci#define HIFN_D_DESTOVER 0x04000000 44462306a36Sopenharmony_ci#define HIFN_D_OVER 0x08000000 44562306a36Sopenharmony_ci#define HIFN_D_LAST 0x20000000 44662306a36Sopenharmony_ci#define HIFN_D_JUMP 0x40000000 44762306a36Sopenharmony_ci#define HIFN_D_VALID 0x80000000 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistruct hifn_base_command { 45062306a36Sopenharmony_ci volatile __le16 masks; 45162306a36Sopenharmony_ci volatile __le16 session_num; 45262306a36Sopenharmony_ci volatile __le16 total_source_count; 45362306a36Sopenharmony_ci volatile __le16 total_dest_count; 45462306a36Sopenharmony_ci}; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci#define HIFN_BASE_CMD_COMP 0x0100 /* enable compression engine */ 45762306a36Sopenharmony_ci#define HIFN_BASE_CMD_PAD 0x0200 /* enable padding engine */ 45862306a36Sopenharmony_ci#define HIFN_BASE_CMD_MAC 0x0400 /* enable MAC engine */ 45962306a36Sopenharmony_ci#define HIFN_BASE_CMD_CRYPT 0x0800 /* enable crypt engine */ 46062306a36Sopenharmony_ci#define HIFN_BASE_CMD_DECODE 0x2000 46162306a36Sopenharmony_ci#define HIFN_BASE_CMD_SRCLEN_M 0xc000 46262306a36Sopenharmony_ci#define HIFN_BASE_CMD_SRCLEN_S 14 46362306a36Sopenharmony_ci#define HIFN_BASE_CMD_DSTLEN_M 0x3000 46462306a36Sopenharmony_ci#define HIFN_BASE_CMD_DSTLEN_S 12 46562306a36Sopenharmony_ci#define HIFN_BASE_CMD_LENMASK_HI 0x30000 46662306a36Sopenharmony_ci#define HIFN_BASE_CMD_LENMASK_LO 0x0ffff 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci/* 46962306a36Sopenharmony_ci * Structure to help build up the command data structure. 47062306a36Sopenharmony_ci */ 47162306a36Sopenharmony_cistruct hifn_crypt_command { 47262306a36Sopenharmony_ci volatile __le16 masks; 47362306a36Sopenharmony_ci volatile __le16 header_skip; 47462306a36Sopenharmony_ci volatile __le16 source_count; 47562306a36Sopenharmony_ci volatile __le16 reserved; 47662306a36Sopenharmony_ci}; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci#define HIFN_CRYPT_CMD_ALG_MASK 0x0003 /* algorithm: */ 47962306a36Sopenharmony_ci#define HIFN_CRYPT_CMD_ALG_DES 0x0000 /* DES */ 48062306a36Sopenharmony_ci#define HIFN_CRYPT_CMD_ALG_3DES 0x0001 /* 3DES */ 48162306a36Sopenharmony_ci#define HIFN_CRYPT_CMD_ALG_RC4 0x0002 /* RC4 */ 48262306a36Sopenharmony_ci#define HIFN_CRYPT_CMD_ALG_AES 0x0003 /* AES */ 48362306a36Sopenharmony_ci#define HIFN_CRYPT_CMD_MODE_MASK 0x0018 /* Encrypt mode: */ 48462306a36Sopenharmony_ci#define HIFN_CRYPT_CMD_MODE_ECB 0x0000 /* ECB */ 48562306a36Sopenharmony_ci#define HIFN_CRYPT_CMD_MODE_CBC 0x0008 /* CBC */ 48662306a36Sopenharmony_ci#define HIFN_CRYPT_CMD_MODE_CFB 0x0010 /* CFB */ 48762306a36Sopenharmony_ci#define HIFN_CRYPT_CMD_MODE_OFB 0x0018 /* OFB */ 48862306a36Sopenharmony_ci#define HIFN_CRYPT_CMD_CLR_CTX 0x0040 /* clear context */ 48962306a36Sopenharmony_ci#define HIFN_CRYPT_CMD_KSZ_MASK 0x0600 /* AES key size: */ 49062306a36Sopenharmony_ci#define HIFN_CRYPT_CMD_KSZ_128 0x0000 /* 128 bit */ 49162306a36Sopenharmony_ci#define HIFN_CRYPT_CMD_KSZ_192 0x0200 /* 192 bit */ 49262306a36Sopenharmony_ci#define HIFN_CRYPT_CMD_KSZ_256 0x0400 /* 256 bit */ 49362306a36Sopenharmony_ci#define HIFN_CRYPT_CMD_NEW_KEY 0x0800 /* expect new key */ 49462306a36Sopenharmony_ci#define HIFN_CRYPT_CMD_NEW_IV 0x1000 /* expect new iv */ 49562306a36Sopenharmony_ci#define HIFN_CRYPT_CMD_SRCLEN_M 0xc000 49662306a36Sopenharmony_ci#define HIFN_CRYPT_CMD_SRCLEN_S 14 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci/* 49962306a36Sopenharmony_ci * Structure to help build up the command data structure. 50062306a36Sopenharmony_ci */ 50162306a36Sopenharmony_cistruct hifn_mac_command { 50262306a36Sopenharmony_ci volatile __le16 masks; 50362306a36Sopenharmony_ci volatile __le16 header_skip; 50462306a36Sopenharmony_ci volatile __le16 source_count; 50562306a36Sopenharmony_ci volatile __le16 reserved; 50662306a36Sopenharmony_ci}; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci#define HIFN_MAC_CMD_ALG_MASK 0x0001 50962306a36Sopenharmony_ci#define HIFN_MAC_CMD_ALG_SHA1 0x0000 51062306a36Sopenharmony_ci#define HIFN_MAC_CMD_ALG_MD5 0x0001 51162306a36Sopenharmony_ci#define HIFN_MAC_CMD_MODE_MASK 0x000c 51262306a36Sopenharmony_ci#define HIFN_MAC_CMD_MODE_HMAC 0x0000 51362306a36Sopenharmony_ci#define HIFN_MAC_CMD_MODE_SSL_MAC 0x0004 51462306a36Sopenharmony_ci#define HIFN_MAC_CMD_MODE_HASH 0x0008 51562306a36Sopenharmony_ci#define HIFN_MAC_CMD_MODE_FULL 0x0004 51662306a36Sopenharmony_ci#define HIFN_MAC_CMD_TRUNC 0x0010 51762306a36Sopenharmony_ci#define HIFN_MAC_CMD_RESULT 0x0020 51862306a36Sopenharmony_ci#define HIFN_MAC_CMD_APPEND 0x0040 51962306a36Sopenharmony_ci#define HIFN_MAC_CMD_SRCLEN_M 0xc000 52062306a36Sopenharmony_ci#define HIFN_MAC_CMD_SRCLEN_S 14 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci/* 52362306a36Sopenharmony_ci * MAC POS IPsec initiates authentication after encryption on encodes 52462306a36Sopenharmony_ci * and before decryption on decodes. 52562306a36Sopenharmony_ci */ 52662306a36Sopenharmony_ci#define HIFN_MAC_CMD_POS_IPSEC 0x0200 52762306a36Sopenharmony_ci#define HIFN_MAC_CMD_NEW_KEY 0x0800 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistruct hifn_comp_command { 53062306a36Sopenharmony_ci volatile __le16 masks; 53162306a36Sopenharmony_ci volatile __le16 header_skip; 53262306a36Sopenharmony_ci volatile __le16 source_count; 53362306a36Sopenharmony_ci volatile __le16 reserved; 53462306a36Sopenharmony_ci}; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci#define HIFN_COMP_CMD_SRCLEN_M 0xc000 53762306a36Sopenharmony_ci#define HIFN_COMP_CMD_SRCLEN_S 14 53862306a36Sopenharmony_ci#define HIFN_COMP_CMD_ONE 0x0100 /* must be one */ 53962306a36Sopenharmony_ci#define HIFN_COMP_CMD_CLEARHIST 0x0010 /* clear history */ 54062306a36Sopenharmony_ci#define HIFN_COMP_CMD_UPDATEHIST 0x0008 /* update history */ 54162306a36Sopenharmony_ci#define HIFN_COMP_CMD_LZS_STRIP0 0x0004 /* LZS: strip zero */ 54262306a36Sopenharmony_ci#define HIFN_COMP_CMD_MPPC_RESTART 0x0004 /* MPPC: restart */ 54362306a36Sopenharmony_ci#define HIFN_COMP_CMD_ALG_MASK 0x0001 /* compression mode: */ 54462306a36Sopenharmony_ci#define HIFN_COMP_CMD_ALG_MPPC 0x0001 /* MPPC */ 54562306a36Sopenharmony_ci#define HIFN_COMP_CMD_ALG_LZS 0x0000 /* LZS */ 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistruct hifn_base_result { 54862306a36Sopenharmony_ci volatile __le16 flags; 54962306a36Sopenharmony_ci volatile __le16 session; 55062306a36Sopenharmony_ci volatile __le16 src_cnt; /* 15:0 of source count */ 55162306a36Sopenharmony_ci volatile __le16 dst_cnt; /* 15:0 of dest count */ 55262306a36Sopenharmony_ci}; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci#define HIFN_BASE_RES_DSTOVERRUN 0x0200 /* destination overrun */ 55562306a36Sopenharmony_ci#define HIFN_BASE_RES_SRCLEN_M 0xc000 /* 17:16 of source count */ 55662306a36Sopenharmony_ci#define HIFN_BASE_RES_SRCLEN_S 14 55762306a36Sopenharmony_ci#define HIFN_BASE_RES_DSTLEN_M 0x3000 /* 17:16 of dest count */ 55862306a36Sopenharmony_ci#define HIFN_BASE_RES_DSTLEN_S 12 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_cistruct hifn_comp_result { 56162306a36Sopenharmony_ci volatile __le16 flags; 56262306a36Sopenharmony_ci volatile __le16 crc; 56362306a36Sopenharmony_ci}; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci#define HIFN_COMP_RES_LCB_M 0xff00 /* longitudinal check byte */ 56662306a36Sopenharmony_ci#define HIFN_COMP_RES_LCB_S 8 56762306a36Sopenharmony_ci#define HIFN_COMP_RES_RESTART 0x0004 /* MPPC: restart */ 56862306a36Sopenharmony_ci#define HIFN_COMP_RES_ENDMARKER 0x0002 /* LZS: end marker seen */ 56962306a36Sopenharmony_ci#define HIFN_COMP_RES_SRC_NOTZERO 0x0001 /* source expired */ 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistruct hifn_mac_result { 57262306a36Sopenharmony_ci volatile __le16 flags; 57362306a36Sopenharmony_ci volatile __le16 reserved; 57462306a36Sopenharmony_ci /* followed by 0, 6, 8, or 10 u16's of the MAC, then crypt */ 57562306a36Sopenharmony_ci}; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci#define HIFN_MAC_RES_MISCOMPARE 0x0002 /* compare failed */ 57862306a36Sopenharmony_ci#define HIFN_MAC_RES_SRC_NOTZERO 0x0001 /* source expired */ 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistruct hifn_crypt_result { 58162306a36Sopenharmony_ci volatile __le16 flags; 58262306a36Sopenharmony_ci volatile __le16 reserved; 58362306a36Sopenharmony_ci}; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci#define HIFN_CRYPT_RES_SRC_NOTZERO 0x0001 /* source expired */ 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci#ifndef HIFN_POLL_FREQUENCY 58862306a36Sopenharmony_ci#define HIFN_POLL_FREQUENCY 0x1 58962306a36Sopenharmony_ci#endif 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci#ifndef HIFN_POLL_SCALAR 59262306a36Sopenharmony_ci#define HIFN_POLL_SCALAR 0x0 59362306a36Sopenharmony_ci#endif 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci#define HIFN_MAX_SEGLEN 0xffff /* maximum dma segment len */ 59662306a36Sopenharmony_ci#define HIFN_MAX_DMALEN 0x3ffff /* maximum dma length */ 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cistruct hifn_crypto_alg { 59962306a36Sopenharmony_ci struct list_head entry; 60062306a36Sopenharmony_ci struct skcipher_alg alg; 60162306a36Sopenharmony_ci struct hifn_device *dev; 60262306a36Sopenharmony_ci}; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci#define ASYNC_SCATTERLIST_CACHE 16 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci#define ASYNC_FLAGS_MISALIGNED (1 << 0) 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_cistruct hifn_cipher_walk { 60962306a36Sopenharmony_ci struct scatterlist cache[ASYNC_SCATTERLIST_CACHE]; 61062306a36Sopenharmony_ci u32 flags; 61162306a36Sopenharmony_ci int num; 61262306a36Sopenharmony_ci}; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_cistruct hifn_context { 61562306a36Sopenharmony_ci u8 key[HIFN_MAX_CRYPT_KEY_LENGTH]; 61662306a36Sopenharmony_ci struct hifn_device *dev; 61762306a36Sopenharmony_ci unsigned int keysize; 61862306a36Sopenharmony_ci}; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_cistruct hifn_request_context { 62162306a36Sopenharmony_ci u8 *iv; 62262306a36Sopenharmony_ci unsigned int ivsize; 62362306a36Sopenharmony_ci u8 op, type, mode, unused; 62462306a36Sopenharmony_ci struct hifn_cipher_walk walk; 62562306a36Sopenharmony_ci}; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci#define crypto_alg_to_hifn(a) container_of(a, struct hifn_crypto_alg, alg) 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_cistatic inline u32 hifn_read_0(struct hifn_device *dev, u32 reg) 63062306a36Sopenharmony_ci{ 63162306a36Sopenharmony_ci return readl(dev->bar[0] + reg); 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_cistatic inline u32 hifn_read_1(struct hifn_device *dev, u32 reg) 63562306a36Sopenharmony_ci{ 63662306a36Sopenharmony_ci return readl(dev->bar[1] + reg); 63762306a36Sopenharmony_ci} 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_cistatic inline void hifn_write_0(struct hifn_device *dev, u32 reg, u32 val) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci writel((__force u32)cpu_to_le32(val), dev->bar[0] + reg); 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_cistatic inline void hifn_write_1(struct hifn_device *dev, u32 reg, u32 val) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci writel((__force u32)cpu_to_le32(val), dev->bar[1] + reg); 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistatic void hifn_wait_puc(struct hifn_device *dev) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci int i; 65262306a36Sopenharmony_ci u32 ret; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci for (i = 10000; i > 0; --i) { 65562306a36Sopenharmony_ci ret = hifn_read_0(dev, HIFN_0_PUCTRL); 65662306a36Sopenharmony_ci if (!(ret & HIFN_PUCTRL_RESET)) 65762306a36Sopenharmony_ci break; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci udelay(1); 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci if (!i) 66362306a36Sopenharmony_ci dev_err(&dev->pdev->dev, "Failed to reset PUC unit.\n"); 66462306a36Sopenharmony_ci} 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_cistatic void hifn_reset_puc(struct hifn_device *dev) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci hifn_write_0(dev, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA); 66962306a36Sopenharmony_ci hifn_wait_puc(dev); 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_cistatic void hifn_stop_device(struct hifn_device *dev) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CSR, 67562306a36Sopenharmony_ci HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS | 67662306a36Sopenharmony_ci HIFN_DMACSR_S_CTRL_DIS | HIFN_DMACSR_C_CTRL_DIS); 67762306a36Sopenharmony_ci hifn_write_0(dev, HIFN_0_PUIER, 0); 67862306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_IER, 0); 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_cistatic void hifn_reset_dma(struct hifn_device *dev, int full) 68262306a36Sopenharmony_ci{ 68362306a36Sopenharmony_ci hifn_stop_device(dev); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci /* 68662306a36Sopenharmony_ci * Setting poll frequency and others to 0. 68762306a36Sopenharmony_ci */ 68862306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | 68962306a36Sopenharmony_ci HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); 69062306a36Sopenharmony_ci mdelay(1); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci /* 69362306a36Sopenharmony_ci * Reset DMA. 69462306a36Sopenharmony_ci */ 69562306a36Sopenharmony_ci if (full) { 69662306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MODE); 69762306a36Sopenharmony_ci mdelay(1); 69862306a36Sopenharmony_ci } else { 69962306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MODE | 70062306a36Sopenharmony_ci HIFN_DMACNFG_MSTRESET); 70162306a36Sopenharmony_ci hifn_reset_puc(dev); 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | 70562306a36Sopenharmony_ci HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci hifn_reset_puc(dev); 70862306a36Sopenharmony_ci} 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cistatic u32 hifn_next_signature(u32 a, u_int cnt) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci int i; 71362306a36Sopenharmony_ci u32 v; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci for (i = 0; i < cnt; i++) { 71662306a36Sopenharmony_ci /* get the parity */ 71762306a36Sopenharmony_ci v = a & 0x80080125; 71862306a36Sopenharmony_ci v ^= v >> 16; 71962306a36Sopenharmony_ci v ^= v >> 8; 72062306a36Sopenharmony_ci v ^= v >> 4; 72162306a36Sopenharmony_ci v ^= v >> 2; 72262306a36Sopenharmony_ci v ^= v >> 1; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci a = (v & 1) ^ (a << 1); 72562306a36Sopenharmony_ci } 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci return a; 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_cistatic struct pci2id { 73162306a36Sopenharmony_ci u_short pci_vendor; 73262306a36Sopenharmony_ci u_short pci_prod; 73362306a36Sopenharmony_ci char card_id[13]; 73462306a36Sopenharmony_ci} pci2id[] = { 73562306a36Sopenharmony_ci { 73662306a36Sopenharmony_ci PCI_VENDOR_ID_HIFN, 73762306a36Sopenharmony_ci PCI_DEVICE_ID_HIFN_7955, 73862306a36Sopenharmony_ci { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 73962306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00 } 74062306a36Sopenharmony_ci }, 74162306a36Sopenharmony_ci { 74262306a36Sopenharmony_ci PCI_VENDOR_ID_HIFN, 74362306a36Sopenharmony_ci PCI_DEVICE_ID_HIFN_7956, 74462306a36Sopenharmony_ci { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 74562306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00 } 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci}; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_HIFN_795X_RNG 75062306a36Sopenharmony_cistatic int hifn_rng_data_present(struct hwrng *rng, int wait) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci struct hifn_device *dev = (struct hifn_device *)rng->priv; 75362306a36Sopenharmony_ci s64 nsec; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci nsec = ktime_to_ns(ktime_sub(ktime_get(), dev->rngtime)); 75662306a36Sopenharmony_ci nsec -= dev->rng_wait_time; 75762306a36Sopenharmony_ci if (nsec <= 0) 75862306a36Sopenharmony_ci return 1; 75962306a36Sopenharmony_ci if (!wait) 76062306a36Sopenharmony_ci return 0; 76162306a36Sopenharmony_ci ndelay(nsec); 76262306a36Sopenharmony_ci return 1; 76362306a36Sopenharmony_ci} 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_cistatic int hifn_rng_data_read(struct hwrng *rng, u32 *data) 76662306a36Sopenharmony_ci{ 76762306a36Sopenharmony_ci struct hifn_device *dev = (struct hifn_device *)rng->priv; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci *data = hifn_read_1(dev, HIFN_1_RNG_DATA); 77062306a36Sopenharmony_ci dev->rngtime = ktime_get(); 77162306a36Sopenharmony_ci return 4; 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic int hifn_register_rng(struct hifn_device *dev) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci /* 77762306a36Sopenharmony_ci * We must wait at least 256 Pk_clk cycles between two reads of the rng. 77862306a36Sopenharmony_ci */ 77962306a36Sopenharmony_ci dev->rng_wait_time = DIV_ROUND_UP_ULL(NSEC_PER_SEC, 78062306a36Sopenharmony_ci dev->pk_clk_freq) * 256; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci dev->rng.name = dev->name; 78362306a36Sopenharmony_ci dev->rng.data_present = hifn_rng_data_present; 78462306a36Sopenharmony_ci dev->rng.data_read = hifn_rng_data_read; 78562306a36Sopenharmony_ci dev->rng.priv = (unsigned long)dev; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci return hwrng_register(&dev->rng); 78862306a36Sopenharmony_ci} 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_cistatic void hifn_unregister_rng(struct hifn_device *dev) 79162306a36Sopenharmony_ci{ 79262306a36Sopenharmony_ci hwrng_unregister(&dev->rng); 79362306a36Sopenharmony_ci} 79462306a36Sopenharmony_ci#else 79562306a36Sopenharmony_ci#define hifn_register_rng(dev) 0 79662306a36Sopenharmony_ci#define hifn_unregister_rng(dev) 79762306a36Sopenharmony_ci#endif 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_cistatic int hifn_init_pubrng(struct hifn_device *dev) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci int i; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_PUB_RESET, hifn_read_1(dev, HIFN_1_PUB_RESET) | 80462306a36Sopenharmony_ci HIFN_PUBRST_RESET); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci for (i = 100; i > 0; --i) { 80762306a36Sopenharmony_ci mdelay(1); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci if ((hifn_read_1(dev, HIFN_1_PUB_RESET) & HIFN_PUBRST_RESET) == 0) 81062306a36Sopenharmony_ci break; 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci if (!i) { 81462306a36Sopenharmony_ci dev_err(&dev->pdev->dev, "Failed to initialise public key engine.\n"); 81562306a36Sopenharmony_ci } else { 81662306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_PUB_IEN, HIFN_PUBIEN_DONE); 81762306a36Sopenharmony_ci dev->dmareg |= HIFN_DMAIER_PUBDONE; 81862306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci dev_dbg(&dev->pdev->dev, "Public key engine has been successfully initialised.\n"); 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci /* Enable RNG engine. */ 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_RNG_CONFIG, 82662306a36Sopenharmony_ci hifn_read_1(dev, HIFN_1_RNG_CONFIG) | HIFN_RNGCFG_ENA); 82762306a36Sopenharmony_ci dev_dbg(&dev->pdev->dev, "RNG engine has been successfully initialised.\n"); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_HIFN_795X_RNG 83062306a36Sopenharmony_ci /* First value must be discarded */ 83162306a36Sopenharmony_ci hifn_read_1(dev, HIFN_1_RNG_DATA); 83262306a36Sopenharmony_ci dev->rngtime = ktime_get(); 83362306a36Sopenharmony_ci#endif 83462306a36Sopenharmony_ci return 0; 83562306a36Sopenharmony_ci} 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_cistatic int hifn_enable_crypto(struct hifn_device *dev) 83862306a36Sopenharmony_ci{ 83962306a36Sopenharmony_ci u32 dmacfg, addr; 84062306a36Sopenharmony_ci char *offtbl = NULL; 84162306a36Sopenharmony_ci int i; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pci2id); i++) { 84462306a36Sopenharmony_ci if (pci2id[i].pci_vendor == dev->pdev->vendor && 84562306a36Sopenharmony_ci pci2id[i].pci_prod == dev->pdev->device) { 84662306a36Sopenharmony_ci offtbl = pci2id[i].card_id; 84762306a36Sopenharmony_ci break; 84862306a36Sopenharmony_ci } 84962306a36Sopenharmony_ci } 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci if (!offtbl) { 85262306a36Sopenharmony_ci dev_err(&dev->pdev->dev, "Unknown card!\n"); 85362306a36Sopenharmony_ci return -ENODEV; 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci dmacfg = hifn_read_1(dev, HIFN_1_DMA_CNFG); 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CNFG, 85962306a36Sopenharmony_ci HIFN_DMACNFG_UNLOCK | HIFN_DMACNFG_MSTRESET | 86062306a36Sopenharmony_ci HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); 86162306a36Sopenharmony_ci mdelay(1); 86262306a36Sopenharmony_ci addr = hifn_read_1(dev, HIFN_1_UNLOCK_SECRET1); 86362306a36Sopenharmony_ci mdelay(1); 86462306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_UNLOCK_SECRET2, 0); 86562306a36Sopenharmony_ci mdelay(1); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci for (i = 0; i < 12; ++i) { 86862306a36Sopenharmony_ci addr = hifn_next_signature(addr, offtbl[i] + 0x101); 86962306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_UNLOCK_SECRET2, addr); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci mdelay(1); 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CNFG, dmacfg); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci dev_dbg(&dev->pdev->dev, "%s %s.\n", dev->name, pci_name(dev->pdev)); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci return 0; 87862306a36Sopenharmony_ci} 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_cistatic void hifn_init_dma(struct hifn_device *dev) 88162306a36Sopenharmony_ci{ 88262306a36Sopenharmony_ci struct hifn_dma *dma = dev->desc_virt; 88362306a36Sopenharmony_ci u32 dptr = dev->desc_dma; 88462306a36Sopenharmony_ci int i; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci for (i = 0; i < HIFN_D_CMD_RSIZE; ++i) 88762306a36Sopenharmony_ci dma->cmdr[i].p = __cpu_to_le32(dptr + 88862306a36Sopenharmony_ci offsetof(struct hifn_dma, command_bufs[i][0])); 88962306a36Sopenharmony_ci for (i = 0; i < HIFN_D_RES_RSIZE; ++i) 89062306a36Sopenharmony_ci dma->resr[i].p = __cpu_to_le32(dptr + 89162306a36Sopenharmony_ci offsetof(struct hifn_dma, result_bufs[i][0])); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci /* Setup LAST descriptors. */ 89462306a36Sopenharmony_ci dma->cmdr[HIFN_D_CMD_RSIZE].p = __cpu_to_le32(dptr + 89562306a36Sopenharmony_ci offsetof(struct hifn_dma, cmdr[0])); 89662306a36Sopenharmony_ci dma->srcr[HIFN_D_SRC_RSIZE].p = __cpu_to_le32(dptr + 89762306a36Sopenharmony_ci offsetof(struct hifn_dma, srcr[0])); 89862306a36Sopenharmony_ci dma->dstr[HIFN_D_DST_RSIZE].p = __cpu_to_le32(dptr + 89962306a36Sopenharmony_ci offsetof(struct hifn_dma, dstr[0])); 90062306a36Sopenharmony_ci dma->resr[HIFN_D_RES_RSIZE].p = __cpu_to_le32(dptr + 90162306a36Sopenharmony_ci offsetof(struct hifn_dma, resr[0])); 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci dma->cmdu = dma->srcu = dma->dstu = dma->resu = 0; 90462306a36Sopenharmony_ci dma->cmdi = dma->srci = dma->dsti = dma->resi = 0; 90562306a36Sopenharmony_ci dma->cmdk = dma->srck = dma->dstk = dma->resk = 0; 90662306a36Sopenharmony_ci} 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci/* 90962306a36Sopenharmony_ci * Initialize the PLL. We need to know the frequency of the reference clock 91062306a36Sopenharmony_ci * to calculate the optimal multiplier. For PCI we assume 66MHz, since that 91162306a36Sopenharmony_ci * allows us to operate without the risk of overclocking the chip. If it 91262306a36Sopenharmony_ci * actually uses 33MHz, the chip will operate at half the speed, this can be 91362306a36Sopenharmony_ci * overridden by specifying the frequency as module parameter (pci33). 91462306a36Sopenharmony_ci * 91562306a36Sopenharmony_ci * Unfortunately the PCI clock is not very suitable since the HIFN needs a 91662306a36Sopenharmony_ci * stable clock and the PCI clock frequency may vary, so the default is the 91762306a36Sopenharmony_ci * external clock. There is no way to find out its frequency, we default to 91862306a36Sopenharmony_ci * 66MHz since according to Mike Ham of HiFn, almost every board in existence 91962306a36Sopenharmony_ci * has an external crystal populated at 66MHz. 92062306a36Sopenharmony_ci */ 92162306a36Sopenharmony_cistatic void hifn_init_pll(struct hifn_device *dev) 92262306a36Sopenharmony_ci{ 92362306a36Sopenharmony_ci unsigned int freq, m; 92462306a36Sopenharmony_ci u32 pllcfg; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci pllcfg = HIFN_1_PLL | HIFN_PLL_RESERVED_1; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci if (strncmp(hifn_pll_ref, "ext", 3) == 0) 92962306a36Sopenharmony_ci pllcfg |= HIFN_PLL_REF_CLK_PLL; 93062306a36Sopenharmony_ci else 93162306a36Sopenharmony_ci pllcfg |= HIFN_PLL_REF_CLK_HBI; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci if (hifn_pll_ref[3] != '\0') 93462306a36Sopenharmony_ci freq = simple_strtoul(hifn_pll_ref + 3, NULL, 10); 93562306a36Sopenharmony_ci else { 93662306a36Sopenharmony_ci freq = 66; 93762306a36Sopenharmony_ci dev_info(&dev->pdev->dev, "assuming %uMHz clock speed, override with hifn_pll_ref=%.3s<frequency>\n", 93862306a36Sopenharmony_ci freq, hifn_pll_ref); 93962306a36Sopenharmony_ci } 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci m = HIFN_PLL_FCK_MAX / freq; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci pllcfg |= (m / 2 - 1) << HIFN_PLL_ND_SHIFT; 94462306a36Sopenharmony_ci if (m <= 8) 94562306a36Sopenharmony_ci pllcfg |= HIFN_PLL_IS_1_8; 94662306a36Sopenharmony_ci else 94762306a36Sopenharmony_ci pllcfg |= HIFN_PLL_IS_9_12; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci /* Select clock source and enable clock bypass */ 95062306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_PLL, pllcfg | 95162306a36Sopenharmony_ci HIFN_PLL_PK_CLK_HBI | HIFN_PLL_PE_CLK_HBI | HIFN_PLL_BP); 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci /* Let the chip lock to the input clock */ 95462306a36Sopenharmony_ci mdelay(10); 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci /* Disable clock bypass */ 95762306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_PLL, pllcfg | 95862306a36Sopenharmony_ci HIFN_PLL_PK_CLK_HBI | HIFN_PLL_PE_CLK_HBI); 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci /* Switch the engines to the PLL */ 96162306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_PLL, pllcfg | 96262306a36Sopenharmony_ci HIFN_PLL_PK_CLK_PLL | HIFN_PLL_PE_CLK_PLL); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci /* 96562306a36Sopenharmony_ci * The Fpk_clk runs at half the total speed. Its frequency is needed to 96662306a36Sopenharmony_ci * calculate the minimum time between two reads of the rng. Since 33MHz 96762306a36Sopenharmony_ci * is actually 33.333... we overestimate the frequency here, resulting 96862306a36Sopenharmony_ci * in slightly larger intervals. 96962306a36Sopenharmony_ci */ 97062306a36Sopenharmony_ci dev->pk_clk_freq = 1000000 * (freq + 1) * m / 2; 97162306a36Sopenharmony_ci} 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_cistatic void hifn_init_registers(struct hifn_device *dev) 97462306a36Sopenharmony_ci{ 97562306a36Sopenharmony_ci u32 dptr = dev->desc_dma; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci /* Initialization magic... */ 97862306a36Sopenharmony_ci hifn_write_0(dev, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA); 97962306a36Sopenharmony_ci hifn_write_0(dev, HIFN_0_FIFOCNFG, HIFN_FIFOCNFG_THRESHOLD); 98062306a36Sopenharmony_ci hifn_write_0(dev, HIFN_0_PUIER, HIFN_PUIER_DSTOVER); 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci /* write all 4 ring address registers */ 98362306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CRAR, dptr + 98462306a36Sopenharmony_ci offsetof(struct hifn_dma, cmdr[0])); 98562306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_SRAR, dptr + 98662306a36Sopenharmony_ci offsetof(struct hifn_dma, srcr[0])); 98762306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_DRAR, dptr + 98862306a36Sopenharmony_ci offsetof(struct hifn_dma, dstr[0])); 98962306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_RRAR, dptr + 99062306a36Sopenharmony_ci offsetof(struct hifn_dma, resr[0])); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci mdelay(2); 99362306a36Sopenharmony_ci#if 0 99462306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CSR, 99562306a36Sopenharmony_ci HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS | 99662306a36Sopenharmony_ci HIFN_DMACSR_S_CTRL_DIS | HIFN_DMACSR_C_CTRL_DIS | 99762306a36Sopenharmony_ci HIFN_DMACSR_D_ABORT | HIFN_DMACSR_D_DONE | HIFN_DMACSR_D_LAST | 99862306a36Sopenharmony_ci HIFN_DMACSR_D_WAIT | HIFN_DMACSR_D_OVER | 99962306a36Sopenharmony_ci HIFN_DMACSR_R_ABORT | HIFN_DMACSR_R_DONE | HIFN_DMACSR_R_LAST | 100062306a36Sopenharmony_ci HIFN_DMACSR_R_WAIT | HIFN_DMACSR_R_OVER | 100162306a36Sopenharmony_ci HIFN_DMACSR_S_ABORT | HIFN_DMACSR_S_DONE | HIFN_DMACSR_S_LAST | 100262306a36Sopenharmony_ci HIFN_DMACSR_S_WAIT | 100362306a36Sopenharmony_ci HIFN_DMACSR_C_ABORT | HIFN_DMACSR_C_DONE | HIFN_DMACSR_C_LAST | 100462306a36Sopenharmony_ci HIFN_DMACSR_C_WAIT | 100562306a36Sopenharmony_ci HIFN_DMACSR_ENGINE | 100662306a36Sopenharmony_ci HIFN_DMACSR_PUBDONE); 100762306a36Sopenharmony_ci#else 100862306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CSR, 100962306a36Sopenharmony_ci HIFN_DMACSR_C_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA | 101062306a36Sopenharmony_ci HIFN_DMACSR_D_CTRL_ENA | HIFN_DMACSR_R_CTRL_ENA | 101162306a36Sopenharmony_ci HIFN_DMACSR_D_ABORT | HIFN_DMACSR_D_DONE | HIFN_DMACSR_D_LAST | 101262306a36Sopenharmony_ci HIFN_DMACSR_D_WAIT | HIFN_DMACSR_D_OVER | 101362306a36Sopenharmony_ci HIFN_DMACSR_R_ABORT | HIFN_DMACSR_R_DONE | HIFN_DMACSR_R_LAST | 101462306a36Sopenharmony_ci HIFN_DMACSR_R_WAIT | HIFN_DMACSR_R_OVER | 101562306a36Sopenharmony_ci HIFN_DMACSR_S_ABORT | HIFN_DMACSR_S_DONE | HIFN_DMACSR_S_LAST | 101662306a36Sopenharmony_ci HIFN_DMACSR_S_WAIT | 101762306a36Sopenharmony_ci HIFN_DMACSR_C_ABORT | HIFN_DMACSR_C_DONE | HIFN_DMACSR_C_LAST | 101862306a36Sopenharmony_ci HIFN_DMACSR_C_WAIT | 101962306a36Sopenharmony_ci HIFN_DMACSR_ENGINE | 102062306a36Sopenharmony_ci HIFN_DMACSR_PUBDONE); 102162306a36Sopenharmony_ci#endif 102262306a36Sopenharmony_ci hifn_read_1(dev, HIFN_1_DMA_CSR); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci dev->dmareg |= HIFN_DMAIER_R_DONE | HIFN_DMAIER_C_ABORT | 102562306a36Sopenharmony_ci HIFN_DMAIER_D_OVER | HIFN_DMAIER_R_OVER | 102662306a36Sopenharmony_ci HIFN_DMAIER_S_ABORT | HIFN_DMAIER_D_ABORT | HIFN_DMAIER_R_ABORT | 102762306a36Sopenharmony_ci HIFN_DMAIER_ENGINE; 102862306a36Sopenharmony_ci dev->dmareg &= ~HIFN_DMAIER_C_WAIT; 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg); 103162306a36Sopenharmony_ci hifn_read_1(dev, HIFN_1_DMA_IER); 103262306a36Sopenharmony_ci#if 0 103362306a36Sopenharmony_ci hifn_write_0(dev, HIFN_0_PUCNFG, HIFN_PUCNFG_ENCCNFG | 103462306a36Sopenharmony_ci HIFN_PUCNFG_DRFR_128 | HIFN_PUCNFG_TCALLPHASES | 103562306a36Sopenharmony_ci HIFN_PUCNFG_TCDRVTOTEM | HIFN_PUCNFG_BUS32 | 103662306a36Sopenharmony_ci HIFN_PUCNFG_DRAM); 103762306a36Sopenharmony_ci#else 103862306a36Sopenharmony_ci hifn_write_0(dev, HIFN_0_PUCNFG, 0x10342); 103962306a36Sopenharmony_ci#endif 104062306a36Sopenharmony_ci hifn_init_pll(dev); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci hifn_write_0(dev, HIFN_0_PUISR, HIFN_PUISR_DSTOVER); 104362306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | 104462306a36Sopenharmony_ci HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE | HIFN_DMACNFG_LAST | 104562306a36Sopenharmony_ci ((HIFN_POLL_FREQUENCY << 16 ) & HIFN_DMACNFG_POLLFREQ) | 104662306a36Sopenharmony_ci ((HIFN_POLL_SCALAR << 8) & HIFN_DMACNFG_POLLINVAL)); 104762306a36Sopenharmony_ci} 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_cistatic int hifn_setup_base_command(struct hifn_device *dev, u8 *buf, 105062306a36Sopenharmony_ci unsigned dlen, unsigned slen, u16 mask, u8 snum) 105162306a36Sopenharmony_ci{ 105262306a36Sopenharmony_ci struct hifn_base_command *base_cmd; 105362306a36Sopenharmony_ci u8 *buf_pos = buf; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci base_cmd = (struct hifn_base_command *)buf_pos; 105662306a36Sopenharmony_ci base_cmd->masks = __cpu_to_le16(mask); 105762306a36Sopenharmony_ci base_cmd->total_source_count = 105862306a36Sopenharmony_ci __cpu_to_le16(slen & HIFN_BASE_CMD_LENMASK_LO); 105962306a36Sopenharmony_ci base_cmd->total_dest_count = 106062306a36Sopenharmony_ci __cpu_to_le16(dlen & HIFN_BASE_CMD_LENMASK_LO); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci dlen >>= 16; 106362306a36Sopenharmony_ci slen >>= 16; 106462306a36Sopenharmony_ci base_cmd->session_num = __cpu_to_le16(snum | 106562306a36Sopenharmony_ci ((slen << HIFN_BASE_CMD_SRCLEN_S) & HIFN_BASE_CMD_SRCLEN_M) | 106662306a36Sopenharmony_ci ((dlen << HIFN_BASE_CMD_DSTLEN_S) & HIFN_BASE_CMD_DSTLEN_M)); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci return sizeof(struct hifn_base_command); 106962306a36Sopenharmony_ci} 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_cistatic int hifn_setup_crypto_command(struct hifn_device *dev, 107262306a36Sopenharmony_ci u8 *buf, unsigned dlen, unsigned slen, 107362306a36Sopenharmony_ci u8 *key, int keylen, u8 *iv, int ivsize, u16 mode) 107462306a36Sopenharmony_ci{ 107562306a36Sopenharmony_ci struct hifn_dma *dma = dev->desc_virt; 107662306a36Sopenharmony_ci struct hifn_crypt_command *cry_cmd; 107762306a36Sopenharmony_ci u8 *buf_pos = buf; 107862306a36Sopenharmony_ci u16 cmd_len; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci cry_cmd = (struct hifn_crypt_command *)buf_pos; 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci cry_cmd->source_count = __cpu_to_le16(dlen & 0xffff); 108362306a36Sopenharmony_ci dlen >>= 16; 108462306a36Sopenharmony_ci cry_cmd->masks = __cpu_to_le16(mode | 108562306a36Sopenharmony_ci ((dlen << HIFN_CRYPT_CMD_SRCLEN_S) & 108662306a36Sopenharmony_ci HIFN_CRYPT_CMD_SRCLEN_M)); 108762306a36Sopenharmony_ci cry_cmd->header_skip = 0; 108862306a36Sopenharmony_ci cry_cmd->reserved = 0; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci buf_pos += sizeof(struct hifn_crypt_command); 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci dma->cmdu++; 109362306a36Sopenharmony_ci if (dma->cmdu > 1) { 109462306a36Sopenharmony_ci dev->dmareg |= HIFN_DMAIER_C_WAIT; 109562306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg); 109662306a36Sopenharmony_ci } 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci if (keylen) { 109962306a36Sopenharmony_ci memcpy(buf_pos, key, keylen); 110062306a36Sopenharmony_ci buf_pos += keylen; 110162306a36Sopenharmony_ci } 110262306a36Sopenharmony_ci if (ivsize) { 110362306a36Sopenharmony_ci memcpy(buf_pos, iv, ivsize); 110462306a36Sopenharmony_ci buf_pos += ivsize; 110562306a36Sopenharmony_ci } 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci cmd_len = buf_pos - buf; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci return cmd_len; 111062306a36Sopenharmony_ci} 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_cistatic int hifn_setup_cmd_desc(struct hifn_device *dev, 111362306a36Sopenharmony_ci struct hifn_context *ctx, struct hifn_request_context *rctx, 111462306a36Sopenharmony_ci void *priv, unsigned int nbytes) 111562306a36Sopenharmony_ci{ 111662306a36Sopenharmony_ci struct hifn_dma *dma = dev->desc_virt; 111762306a36Sopenharmony_ci int cmd_len, sa_idx; 111862306a36Sopenharmony_ci u8 *buf, *buf_pos; 111962306a36Sopenharmony_ci u16 mask; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci sa_idx = dma->cmdi; 112262306a36Sopenharmony_ci buf_pos = buf = dma->command_bufs[dma->cmdi]; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci mask = 0; 112562306a36Sopenharmony_ci switch (rctx->op) { 112662306a36Sopenharmony_ci case ACRYPTO_OP_DECRYPT: 112762306a36Sopenharmony_ci mask = HIFN_BASE_CMD_CRYPT | HIFN_BASE_CMD_DECODE; 112862306a36Sopenharmony_ci break; 112962306a36Sopenharmony_ci case ACRYPTO_OP_ENCRYPT: 113062306a36Sopenharmony_ci mask = HIFN_BASE_CMD_CRYPT; 113162306a36Sopenharmony_ci break; 113262306a36Sopenharmony_ci case ACRYPTO_OP_HMAC: 113362306a36Sopenharmony_ci mask = HIFN_BASE_CMD_MAC; 113462306a36Sopenharmony_ci break; 113562306a36Sopenharmony_ci default: 113662306a36Sopenharmony_ci goto err_out; 113762306a36Sopenharmony_ci } 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci buf_pos += hifn_setup_base_command(dev, buf_pos, nbytes, 114062306a36Sopenharmony_ci nbytes, mask, dev->snum); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci if (rctx->op == ACRYPTO_OP_ENCRYPT || rctx->op == ACRYPTO_OP_DECRYPT) { 114362306a36Sopenharmony_ci u16 md = 0; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci if (ctx->keysize) 114662306a36Sopenharmony_ci md |= HIFN_CRYPT_CMD_NEW_KEY; 114762306a36Sopenharmony_ci if (rctx->iv && rctx->mode != ACRYPTO_MODE_ECB) 114862306a36Sopenharmony_ci md |= HIFN_CRYPT_CMD_NEW_IV; 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci switch (rctx->mode) { 115162306a36Sopenharmony_ci case ACRYPTO_MODE_ECB: 115262306a36Sopenharmony_ci md |= HIFN_CRYPT_CMD_MODE_ECB; 115362306a36Sopenharmony_ci break; 115462306a36Sopenharmony_ci case ACRYPTO_MODE_CBC: 115562306a36Sopenharmony_ci md |= HIFN_CRYPT_CMD_MODE_CBC; 115662306a36Sopenharmony_ci break; 115762306a36Sopenharmony_ci case ACRYPTO_MODE_CFB: 115862306a36Sopenharmony_ci md |= HIFN_CRYPT_CMD_MODE_CFB; 115962306a36Sopenharmony_ci break; 116062306a36Sopenharmony_ci case ACRYPTO_MODE_OFB: 116162306a36Sopenharmony_ci md |= HIFN_CRYPT_CMD_MODE_OFB; 116262306a36Sopenharmony_ci break; 116362306a36Sopenharmony_ci default: 116462306a36Sopenharmony_ci goto err_out; 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci switch (rctx->type) { 116862306a36Sopenharmony_ci case ACRYPTO_TYPE_AES_128: 116962306a36Sopenharmony_ci if (ctx->keysize != 16) 117062306a36Sopenharmony_ci goto err_out; 117162306a36Sopenharmony_ci md |= HIFN_CRYPT_CMD_KSZ_128 | 117262306a36Sopenharmony_ci HIFN_CRYPT_CMD_ALG_AES; 117362306a36Sopenharmony_ci break; 117462306a36Sopenharmony_ci case ACRYPTO_TYPE_AES_192: 117562306a36Sopenharmony_ci if (ctx->keysize != 24) 117662306a36Sopenharmony_ci goto err_out; 117762306a36Sopenharmony_ci md |= HIFN_CRYPT_CMD_KSZ_192 | 117862306a36Sopenharmony_ci HIFN_CRYPT_CMD_ALG_AES; 117962306a36Sopenharmony_ci break; 118062306a36Sopenharmony_ci case ACRYPTO_TYPE_AES_256: 118162306a36Sopenharmony_ci if (ctx->keysize != 32) 118262306a36Sopenharmony_ci goto err_out; 118362306a36Sopenharmony_ci md |= HIFN_CRYPT_CMD_KSZ_256 | 118462306a36Sopenharmony_ci HIFN_CRYPT_CMD_ALG_AES; 118562306a36Sopenharmony_ci break; 118662306a36Sopenharmony_ci case ACRYPTO_TYPE_3DES: 118762306a36Sopenharmony_ci if (ctx->keysize != 24) 118862306a36Sopenharmony_ci goto err_out; 118962306a36Sopenharmony_ci md |= HIFN_CRYPT_CMD_ALG_3DES; 119062306a36Sopenharmony_ci break; 119162306a36Sopenharmony_ci case ACRYPTO_TYPE_DES: 119262306a36Sopenharmony_ci if (ctx->keysize != 8) 119362306a36Sopenharmony_ci goto err_out; 119462306a36Sopenharmony_ci md |= HIFN_CRYPT_CMD_ALG_DES; 119562306a36Sopenharmony_ci break; 119662306a36Sopenharmony_ci default: 119762306a36Sopenharmony_ci goto err_out; 119862306a36Sopenharmony_ci } 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci buf_pos += hifn_setup_crypto_command(dev, buf_pos, 120162306a36Sopenharmony_ci nbytes, nbytes, ctx->key, ctx->keysize, 120262306a36Sopenharmony_ci rctx->iv, rctx->ivsize, md); 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci dev->sa[sa_idx] = priv; 120662306a36Sopenharmony_ci dev->started++; 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci cmd_len = buf_pos - buf; 120962306a36Sopenharmony_ci dma->cmdr[dma->cmdi].l = __cpu_to_le32(cmd_len | HIFN_D_VALID | 121062306a36Sopenharmony_ci HIFN_D_LAST | HIFN_D_MASKDONEIRQ); 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci if (++dma->cmdi == HIFN_D_CMD_RSIZE) { 121362306a36Sopenharmony_ci dma->cmdr[dma->cmdi].l = __cpu_to_le32( 121462306a36Sopenharmony_ci HIFN_D_VALID | HIFN_D_LAST | 121562306a36Sopenharmony_ci HIFN_D_MASKDONEIRQ | HIFN_D_JUMP); 121662306a36Sopenharmony_ci dma->cmdi = 0; 121762306a36Sopenharmony_ci } else { 121862306a36Sopenharmony_ci dma->cmdr[dma->cmdi - 1].l |= __cpu_to_le32(HIFN_D_VALID); 121962306a36Sopenharmony_ci } 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci if (!(dev->flags & HIFN_FLAG_CMD_BUSY)) { 122262306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_C_CTRL_ENA); 122362306a36Sopenharmony_ci dev->flags |= HIFN_FLAG_CMD_BUSY; 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci return 0; 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_cierr_out: 122862306a36Sopenharmony_ci return -EINVAL; 122962306a36Sopenharmony_ci} 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_cistatic int hifn_setup_src_desc(struct hifn_device *dev, struct page *page, 123262306a36Sopenharmony_ci unsigned int offset, unsigned int size, int last) 123362306a36Sopenharmony_ci{ 123462306a36Sopenharmony_ci struct hifn_dma *dma = dev->desc_virt; 123562306a36Sopenharmony_ci int idx; 123662306a36Sopenharmony_ci dma_addr_t addr; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci addr = dma_map_page(&dev->pdev->dev, page, offset, size, 123962306a36Sopenharmony_ci DMA_TO_DEVICE); 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci idx = dma->srci; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci dma->srcr[idx].p = __cpu_to_le32(addr); 124462306a36Sopenharmony_ci dma->srcr[idx].l = __cpu_to_le32(size | HIFN_D_VALID | 124562306a36Sopenharmony_ci HIFN_D_MASKDONEIRQ | (last ? HIFN_D_LAST : 0)); 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci if (++idx == HIFN_D_SRC_RSIZE) { 124862306a36Sopenharmony_ci dma->srcr[idx].l = __cpu_to_le32(HIFN_D_VALID | 124962306a36Sopenharmony_ci HIFN_D_JUMP | HIFN_D_MASKDONEIRQ | 125062306a36Sopenharmony_ci (last ? HIFN_D_LAST : 0)); 125162306a36Sopenharmony_ci idx = 0; 125262306a36Sopenharmony_ci } 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci dma->srci = idx; 125562306a36Sopenharmony_ci dma->srcu++; 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci if (!(dev->flags & HIFN_FLAG_SRC_BUSY)) { 125862306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_S_CTRL_ENA); 125962306a36Sopenharmony_ci dev->flags |= HIFN_FLAG_SRC_BUSY; 126062306a36Sopenharmony_ci } 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci return size; 126362306a36Sopenharmony_ci} 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_cistatic void hifn_setup_res_desc(struct hifn_device *dev) 126662306a36Sopenharmony_ci{ 126762306a36Sopenharmony_ci struct hifn_dma *dma = dev->desc_virt; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci dma->resr[dma->resi].l = __cpu_to_le32(HIFN_USED_RESULT | 127062306a36Sopenharmony_ci HIFN_D_VALID | HIFN_D_LAST); 127162306a36Sopenharmony_ci /* 127262306a36Sopenharmony_ci * dma->resr[dma->resi].l = __cpu_to_le32(HIFN_MAX_RESULT | HIFN_D_VALID | 127362306a36Sopenharmony_ci * HIFN_D_LAST); 127462306a36Sopenharmony_ci */ 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci if (++dma->resi == HIFN_D_RES_RSIZE) { 127762306a36Sopenharmony_ci dma->resr[HIFN_D_RES_RSIZE].l = __cpu_to_le32(HIFN_D_VALID | 127862306a36Sopenharmony_ci HIFN_D_JUMP | HIFN_D_MASKDONEIRQ | HIFN_D_LAST); 127962306a36Sopenharmony_ci dma->resi = 0; 128062306a36Sopenharmony_ci } 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci dma->resu++; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci if (!(dev->flags & HIFN_FLAG_RES_BUSY)) { 128562306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_R_CTRL_ENA); 128662306a36Sopenharmony_ci dev->flags |= HIFN_FLAG_RES_BUSY; 128762306a36Sopenharmony_ci } 128862306a36Sopenharmony_ci} 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_cistatic void hifn_setup_dst_desc(struct hifn_device *dev, struct page *page, 129162306a36Sopenharmony_ci unsigned offset, unsigned size, int last) 129262306a36Sopenharmony_ci{ 129362306a36Sopenharmony_ci struct hifn_dma *dma = dev->desc_virt; 129462306a36Sopenharmony_ci int idx; 129562306a36Sopenharmony_ci dma_addr_t addr; 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci addr = dma_map_page(&dev->pdev->dev, page, offset, size, 129862306a36Sopenharmony_ci DMA_FROM_DEVICE); 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci idx = dma->dsti; 130162306a36Sopenharmony_ci dma->dstr[idx].p = __cpu_to_le32(addr); 130262306a36Sopenharmony_ci dma->dstr[idx].l = __cpu_to_le32(size | HIFN_D_VALID | 130362306a36Sopenharmony_ci HIFN_D_MASKDONEIRQ | (last ? HIFN_D_LAST : 0)); 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci if (++idx == HIFN_D_DST_RSIZE) { 130662306a36Sopenharmony_ci dma->dstr[idx].l = __cpu_to_le32(HIFN_D_VALID | 130762306a36Sopenharmony_ci HIFN_D_JUMP | HIFN_D_MASKDONEIRQ | 130862306a36Sopenharmony_ci (last ? HIFN_D_LAST : 0)); 130962306a36Sopenharmony_ci idx = 0; 131062306a36Sopenharmony_ci } 131162306a36Sopenharmony_ci dma->dsti = idx; 131262306a36Sopenharmony_ci dma->dstu++; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci if (!(dev->flags & HIFN_FLAG_DST_BUSY)) { 131562306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_D_CTRL_ENA); 131662306a36Sopenharmony_ci dev->flags |= HIFN_FLAG_DST_BUSY; 131762306a36Sopenharmony_ci } 131862306a36Sopenharmony_ci} 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_cistatic int hifn_setup_dma(struct hifn_device *dev, 132162306a36Sopenharmony_ci struct hifn_context *ctx, struct hifn_request_context *rctx, 132262306a36Sopenharmony_ci struct scatterlist *src, struct scatterlist *dst, 132362306a36Sopenharmony_ci unsigned int nbytes, void *priv) 132462306a36Sopenharmony_ci{ 132562306a36Sopenharmony_ci struct scatterlist *t; 132662306a36Sopenharmony_ci struct page *spage, *dpage; 132762306a36Sopenharmony_ci unsigned int soff, doff; 132862306a36Sopenharmony_ci unsigned int n, len; 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci n = nbytes; 133162306a36Sopenharmony_ci while (n) { 133262306a36Sopenharmony_ci spage = sg_page(src); 133362306a36Sopenharmony_ci soff = src->offset; 133462306a36Sopenharmony_ci len = min(src->length, n); 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci hifn_setup_src_desc(dev, spage, soff, len, n - len == 0); 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci src++; 133962306a36Sopenharmony_ci n -= len; 134062306a36Sopenharmony_ci } 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci t = &rctx->walk.cache[0]; 134362306a36Sopenharmony_ci n = nbytes; 134462306a36Sopenharmony_ci while (n) { 134562306a36Sopenharmony_ci if (t->length && rctx->walk.flags & ASYNC_FLAGS_MISALIGNED) { 134662306a36Sopenharmony_ci BUG_ON(!sg_page(t)); 134762306a36Sopenharmony_ci dpage = sg_page(t); 134862306a36Sopenharmony_ci doff = 0; 134962306a36Sopenharmony_ci len = t->length; 135062306a36Sopenharmony_ci } else { 135162306a36Sopenharmony_ci BUG_ON(!sg_page(dst)); 135262306a36Sopenharmony_ci dpage = sg_page(dst); 135362306a36Sopenharmony_ci doff = dst->offset; 135462306a36Sopenharmony_ci len = dst->length; 135562306a36Sopenharmony_ci } 135662306a36Sopenharmony_ci len = min(len, n); 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci hifn_setup_dst_desc(dev, dpage, doff, len, n - len == 0); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci dst++; 136162306a36Sopenharmony_ci t++; 136262306a36Sopenharmony_ci n -= len; 136362306a36Sopenharmony_ci } 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci hifn_setup_cmd_desc(dev, ctx, rctx, priv, nbytes); 136662306a36Sopenharmony_ci hifn_setup_res_desc(dev); 136762306a36Sopenharmony_ci return 0; 136862306a36Sopenharmony_ci} 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_cistatic int hifn_cipher_walk_init(struct hifn_cipher_walk *w, 137162306a36Sopenharmony_ci int num, gfp_t gfp_flags) 137262306a36Sopenharmony_ci{ 137362306a36Sopenharmony_ci int i; 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci num = min(ASYNC_SCATTERLIST_CACHE, num); 137662306a36Sopenharmony_ci sg_init_table(w->cache, num); 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci w->num = 0; 137962306a36Sopenharmony_ci for (i = 0; i < num; ++i) { 138062306a36Sopenharmony_ci struct page *page = alloc_page(gfp_flags); 138162306a36Sopenharmony_ci struct scatterlist *s; 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci if (!page) 138462306a36Sopenharmony_ci break; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci s = &w->cache[i]; 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci sg_set_page(s, page, PAGE_SIZE, 0); 138962306a36Sopenharmony_ci w->num++; 139062306a36Sopenharmony_ci } 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci return i; 139362306a36Sopenharmony_ci} 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_cistatic void hifn_cipher_walk_exit(struct hifn_cipher_walk *w) 139662306a36Sopenharmony_ci{ 139762306a36Sopenharmony_ci int i; 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci for (i = 0; i < w->num; ++i) { 140062306a36Sopenharmony_ci struct scatterlist *s = &w->cache[i]; 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci __free_page(sg_page(s)); 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci s->length = 0; 140562306a36Sopenharmony_ci } 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci w->num = 0; 140862306a36Sopenharmony_ci} 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_cistatic int skcipher_add(unsigned int *drestp, struct scatterlist *dst, 141162306a36Sopenharmony_ci unsigned int size, unsigned int *nbytesp) 141262306a36Sopenharmony_ci{ 141362306a36Sopenharmony_ci unsigned int copy, drest = *drestp, nbytes = *nbytesp; 141462306a36Sopenharmony_ci int idx = 0; 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci if (drest < size || size > nbytes) 141762306a36Sopenharmony_ci return -EINVAL; 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci while (size) { 142062306a36Sopenharmony_ci copy = min3(drest, size, dst->length); 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci size -= copy; 142362306a36Sopenharmony_ci drest -= copy; 142462306a36Sopenharmony_ci nbytes -= copy; 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci pr_debug("%s: copy: %u, size: %u, drest: %u, nbytes: %u.\n", 142762306a36Sopenharmony_ci __func__, copy, size, drest, nbytes); 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci dst++; 143062306a36Sopenharmony_ci idx++; 143162306a36Sopenharmony_ci } 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci *nbytesp = nbytes; 143462306a36Sopenharmony_ci *drestp = drest; 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci return idx; 143762306a36Sopenharmony_ci} 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_cistatic int hifn_cipher_walk(struct skcipher_request *req, 144062306a36Sopenharmony_ci struct hifn_cipher_walk *w) 144162306a36Sopenharmony_ci{ 144262306a36Sopenharmony_ci struct scatterlist *dst, *t; 144362306a36Sopenharmony_ci unsigned int nbytes = req->cryptlen, offset, copy, diff; 144462306a36Sopenharmony_ci int idx, tidx, err; 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci tidx = idx = 0; 144762306a36Sopenharmony_ci offset = 0; 144862306a36Sopenharmony_ci while (nbytes) { 144962306a36Sopenharmony_ci if (idx >= w->num && (w->flags & ASYNC_FLAGS_MISALIGNED)) 145062306a36Sopenharmony_ci return -EINVAL; 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci dst = &req->dst[idx]; 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci pr_debug("\n%s: dlen: %u, doff: %u, offset: %u, nbytes: %u.\n", 145562306a36Sopenharmony_ci __func__, dst->length, dst->offset, offset, nbytes); 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci if (!IS_ALIGNED(dst->offset, HIFN_D_DST_DALIGN) || 145862306a36Sopenharmony_ci !IS_ALIGNED(dst->length, HIFN_D_DST_DALIGN) || 145962306a36Sopenharmony_ci offset) { 146062306a36Sopenharmony_ci unsigned slen = min(dst->length - offset, nbytes); 146162306a36Sopenharmony_ci unsigned dlen = PAGE_SIZE; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci t = &w->cache[idx]; 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci err = skcipher_add(&dlen, dst, slen, &nbytes); 146662306a36Sopenharmony_ci if (err < 0) 146762306a36Sopenharmony_ci return err; 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci idx += err; 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci copy = slen & ~(HIFN_D_DST_DALIGN - 1); 147262306a36Sopenharmony_ci diff = slen & (HIFN_D_DST_DALIGN - 1); 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci if (dlen < nbytes) { 147562306a36Sopenharmony_ci /* 147662306a36Sopenharmony_ci * Destination page does not have enough space 147762306a36Sopenharmony_ci * to put there additional blocksized chunk, 147862306a36Sopenharmony_ci * so we mark that page as containing only 147962306a36Sopenharmony_ci * blocksize aligned chunks: 148062306a36Sopenharmony_ci * t->length = (slen & ~(HIFN_D_DST_DALIGN - 1)); 148162306a36Sopenharmony_ci * and increase number of bytes to be processed 148262306a36Sopenharmony_ci * in next chunk: 148362306a36Sopenharmony_ci * nbytes += diff; 148462306a36Sopenharmony_ci */ 148562306a36Sopenharmony_ci nbytes += diff; 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci /* 148862306a36Sopenharmony_ci * Temporary of course... 148962306a36Sopenharmony_ci * Kick author if you will catch this one. 149062306a36Sopenharmony_ci */ 149162306a36Sopenharmony_ci pr_err("%s: dlen: %u, nbytes: %u, slen: %u, offset: %u.\n", 149262306a36Sopenharmony_ci __func__, dlen, nbytes, slen, offset); 149362306a36Sopenharmony_ci pr_err("%s: please contact author to fix this " 149462306a36Sopenharmony_ci "issue, generally you should not catch " 149562306a36Sopenharmony_ci "this path under any condition but who " 149662306a36Sopenharmony_ci "knows how did you use crypto code.\n" 149762306a36Sopenharmony_ci "Thank you.\n", __func__); 149862306a36Sopenharmony_ci BUG(); 149962306a36Sopenharmony_ci } else { 150062306a36Sopenharmony_ci copy += diff + nbytes; 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci dst = &req->dst[idx]; 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci err = skcipher_add(&dlen, dst, nbytes, &nbytes); 150562306a36Sopenharmony_ci if (err < 0) 150662306a36Sopenharmony_ci return err; 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci idx += err; 150962306a36Sopenharmony_ci } 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci t->length = copy; 151262306a36Sopenharmony_ci t->offset = offset; 151362306a36Sopenharmony_ci } else { 151462306a36Sopenharmony_ci nbytes -= min(dst->length, nbytes); 151562306a36Sopenharmony_ci idx++; 151662306a36Sopenharmony_ci } 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci tidx++; 151962306a36Sopenharmony_ci } 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci return tidx; 152262306a36Sopenharmony_ci} 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_cistatic int hifn_setup_session(struct skcipher_request *req) 152562306a36Sopenharmony_ci{ 152662306a36Sopenharmony_ci struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm); 152762306a36Sopenharmony_ci struct hifn_request_context *rctx = skcipher_request_ctx(req); 152862306a36Sopenharmony_ci struct hifn_device *dev = ctx->dev; 152962306a36Sopenharmony_ci unsigned long dlen, flags; 153062306a36Sopenharmony_ci unsigned int nbytes = req->cryptlen, idx = 0; 153162306a36Sopenharmony_ci int err = -EINVAL, sg_num; 153262306a36Sopenharmony_ci struct scatterlist *dst; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci if (rctx->iv && !rctx->ivsize && rctx->mode != ACRYPTO_MODE_ECB) 153562306a36Sopenharmony_ci goto err_out_exit; 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci rctx->walk.flags = 0; 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci while (nbytes) { 154062306a36Sopenharmony_ci dst = &req->dst[idx]; 154162306a36Sopenharmony_ci dlen = min(dst->length, nbytes); 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci if (!IS_ALIGNED(dst->offset, HIFN_D_DST_DALIGN) || 154462306a36Sopenharmony_ci !IS_ALIGNED(dlen, HIFN_D_DST_DALIGN)) 154562306a36Sopenharmony_ci rctx->walk.flags |= ASYNC_FLAGS_MISALIGNED; 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci nbytes -= dlen; 154862306a36Sopenharmony_ci idx++; 154962306a36Sopenharmony_ci } 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci if (rctx->walk.flags & ASYNC_FLAGS_MISALIGNED) { 155262306a36Sopenharmony_ci err = hifn_cipher_walk_init(&rctx->walk, idx, GFP_ATOMIC); 155362306a36Sopenharmony_ci if (err < 0) 155462306a36Sopenharmony_ci return err; 155562306a36Sopenharmony_ci } 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci sg_num = hifn_cipher_walk(req, &rctx->walk); 155862306a36Sopenharmony_ci if (sg_num < 0) { 155962306a36Sopenharmony_ci err = sg_num; 156062306a36Sopenharmony_ci goto err_out_exit; 156162306a36Sopenharmony_ci } 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 156462306a36Sopenharmony_ci if (dev->started + sg_num > HIFN_QUEUE_LENGTH) { 156562306a36Sopenharmony_ci err = -EAGAIN; 156662306a36Sopenharmony_ci goto err_out; 156762306a36Sopenharmony_ci } 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci err = hifn_setup_dma(dev, ctx, rctx, req->src, req->dst, req->cryptlen, req); 157062306a36Sopenharmony_ci if (err) 157162306a36Sopenharmony_ci goto err_out; 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci dev->snum++; 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci dev->active = HIFN_DEFAULT_ACTIVE_NUM; 157662306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci return 0; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_cierr_out: 158162306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 158262306a36Sopenharmony_cierr_out_exit: 158362306a36Sopenharmony_ci if (err) { 158462306a36Sopenharmony_ci dev_info(&dev->pdev->dev, "iv: %p [%d], key: %p [%d], mode: %u, op: %u, " 158562306a36Sopenharmony_ci "type: %u, err: %d.\n", 158662306a36Sopenharmony_ci rctx->iv, rctx->ivsize, 158762306a36Sopenharmony_ci ctx->key, ctx->keysize, 158862306a36Sopenharmony_ci rctx->mode, rctx->op, rctx->type, err); 158962306a36Sopenharmony_ci } 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci return err; 159262306a36Sopenharmony_ci} 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_cistatic int hifn_start_device(struct hifn_device *dev) 159562306a36Sopenharmony_ci{ 159662306a36Sopenharmony_ci int err; 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci dev->started = dev->active = 0; 159962306a36Sopenharmony_ci hifn_reset_dma(dev, 1); 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci err = hifn_enable_crypto(dev); 160262306a36Sopenharmony_ci if (err) 160362306a36Sopenharmony_ci return err; 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci hifn_reset_puc(dev); 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci hifn_init_dma(dev); 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci hifn_init_registers(dev); 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci hifn_init_pubrng(dev); 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci return 0; 161462306a36Sopenharmony_ci} 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_cistatic int skcipher_get(void *saddr, unsigned int *srestp, unsigned int offset, 161762306a36Sopenharmony_ci struct scatterlist *dst, unsigned int size, unsigned int *nbytesp) 161862306a36Sopenharmony_ci{ 161962306a36Sopenharmony_ci unsigned int srest = *srestp, nbytes = *nbytesp, copy; 162062306a36Sopenharmony_ci void *daddr; 162162306a36Sopenharmony_ci int idx = 0; 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci if (srest < size || size > nbytes) 162462306a36Sopenharmony_ci return -EINVAL; 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci while (size) { 162762306a36Sopenharmony_ci copy = min3(srest, dst->length, size); 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci daddr = kmap_atomic(sg_page(dst)); 163062306a36Sopenharmony_ci memcpy(daddr + dst->offset + offset, saddr, copy); 163162306a36Sopenharmony_ci kunmap_atomic(daddr); 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci nbytes -= copy; 163462306a36Sopenharmony_ci size -= copy; 163562306a36Sopenharmony_ci srest -= copy; 163662306a36Sopenharmony_ci saddr += copy; 163762306a36Sopenharmony_ci offset = 0; 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci pr_debug("%s: copy: %u, size: %u, srest: %u, nbytes: %u.\n", 164062306a36Sopenharmony_ci __func__, copy, size, srest, nbytes); 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci dst++; 164362306a36Sopenharmony_ci idx++; 164462306a36Sopenharmony_ci } 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci *nbytesp = nbytes; 164762306a36Sopenharmony_ci *srestp = srest; 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci return idx; 165062306a36Sopenharmony_ci} 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_cistatic inline void hifn_complete_sa(struct hifn_device *dev, int i) 165362306a36Sopenharmony_ci{ 165462306a36Sopenharmony_ci unsigned long flags; 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 165762306a36Sopenharmony_ci dev->sa[i] = NULL; 165862306a36Sopenharmony_ci dev->started--; 165962306a36Sopenharmony_ci if (dev->started < 0) 166062306a36Sopenharmony_ci dev_info(&dev->pdev->dev, "%s: started: %d.\n", __func__, 166162306a36Sopenharmony_ci dev->started); 166262306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 166362306a36Sopenharmony_ci BUG_ON(dev->started < 0); 166462306a36Sopenharmony_ci} 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_cistatic void hifn_process_ready(struct skcipher_request *req, int error) 166762306a36Sopenharmony_ci{ 166862306a36Sopenharmony_ci struct hifn_request_context *rctx = skcipher_request_ctx(req); 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci if (rctx->walk.flags & ASYNC_FLAGS_MISALIGNED) { 167162306a36Sopenharmony_ci unsigned int nbytes = req->cryptlen; 167262306a36Sopenharmony_ci int idx = 0, err; 167362306a36Sopenharmony_ci struct scatterlist *dst, *t; 167462306a36Sopenharmony_ci void *saddr; 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci while (nbytes) { 167762306a36Sopenharmony_ci t = &rctx->walk.cache[idx]; 167862306a36Sopenharmony_ci dst = &req->dst[idx]; 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci pr_debug("\n%s: sg_page(t): %p, t->length: %u, " 168162306a36Sopenharmony_ci "sg_page(dst): %p, dst->length: %u, " 168262306a36Sopenharmony_ci "nbytes: %u.\n", 168362306a36Sopenharmony_ci __func__, sg_page(t), t->length, 168462306a36Sopenharmony_ci sg_page(dst), dst->length, nbytes); 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci if (!t->length) { 168762306a36Sopenharmony_ci nbytes -= min(dst->length, nbytes); 168862306a36Sopenharmony_ci idx++; 168962306a36Sopenharmony_ci continue; 169062306a36Sopenharmony_ci } 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci saddr = kmap_atomic(sg_page(t)); 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci err = skcipher_get(saddr, &t->length, t->offset, 169562306a36Sopenharmony_ci dst, nbytes, &nbytes); 169662306a36Sopenharmony_ci if (err < 0) { 169762306a36Sopenharmony_ci kunmap_atomic(saddr); 169862306a36Sopenharmony_ci break; 169962306a36Sopenharmony_ci } 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci idx += err; 170262306a36Sopenharmony_ci kunmap_atomic(saddr); 170362306a36Sopenharmony_ci } 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci hifn_cipher_walk_exit(&rctx->walk); 170662306a36Sopenharmony_ci } 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci skcipher_request_complete(req, error); 170962306a36Sopenharmony_ci} 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_cistatic void hifn_clear_rings(struct hifn_device *dev, int error) 171262306a36Sopenharmony_ci{ 171362306a36Sopenharmony_ci struct hifn_dma *dma = dev->desc_virt; 171462306a36Sopenharmony_ci int i, u; 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci dev_dbg(&dev->pdev->dev, "ring cleanup 1: i: %d.%d.%d.%d, u: %d.%d.%d.%d, " 171762306a36Sopenharmony_ci "k: %d.%d.%d.%d.\n", 171862306a36Sopenharmony_ci dma->cmdi, dma->srci, dma->dsti, dma->resi, 171962306a36Sopenharmony_ci dma->cmdu, dma->srcu, dma->dstu, dma->resu, 172062306a36Sopenharmony_ci dma->cmdk, dma->srck, dma->dstk, dma->resk); 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci i = dma->resk; u = dma->resu; 172362306a36Sopenharmony_ci while (u != 0) { 172462306a36Sopenharmony_ci if (dma->resr[i].l & __cpu_to_le32(HIFN_D_VALID)) 172562306a36Sopenharmony_ci break; 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci if (dev->sa[i]) { 172862306a36Sopenharmony_ci dev->success++; 172962306a36Sopenharmony_ci dev->reset = 0; 173062306a36Sopenharmony_ci hifn_process_ready(dev->sa[i], error); 173162306a36Sopenharmony_ci hifn_complete_sa(dev, i); 173262306a36Sopenharmony_ci } 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ci if (++i == HIFN_D_RES_RSIZE) 173562306a36Sopenharmony_ci i = 0; 173662306a36Sopenharmony_ci u--; 173762306a36Sopenharmony_ci } 173862306a36Sopenharmony_ci dma->resk = i; dma->resu = u; 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci i = dma->srck; u = dma->srcu; 174162306a36Sopenharmony_ci while (u != 0) { 174262306a36Sopenharmony_ci if (dma->srcr[i].l & __cpu_to_le32(HIFN_D_VALID)) 174362306a36Sopenharmony_ci break; 174462306a36Sopenharmony_ci if (++i == HIFN_D_SRC_RSIZE) 174562306a36Sopenharmony_ci i = 0; 174662306a36Sopenharmony_ci u--; 174762306a36Sopenharmony_ci } 174862306a36Sopenharmony_ci dma->srck = i; dma->srcu = u; 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci i = dma->cmdk; u = dma->cmdu; 175162306a36Sopenharmony_ci while (u != 0) { 175262306a36Sopenharmony_ci if (dma->cmdr[i].l & __cpu_to_le32(HIFN_D_VALID)) 175362306a36Sopenharmony_ci break; 175462306a36Sopenharmony_ci if (++i == HIFN_D_CMD_RSIZE) 175562306a36Sopenharmony_ci i = 0; 175662306a36Sopenharmony_ci u--; 175762306a36Sopenharmony_ci } 175862306a36Sopenharmony_ci dma->cmdk = i; dma->cmdu = u; 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci i = dma->dstk; u = dma->dstu; 176162306a36Sopenharmony_ci while (u != 0) { 176262306a36Sopenharmony_ci if (dma->dstr[i].l & __cpu_to_le32(HIFN_D_VALID)) 176362306a36Sopenharmony_ci break; 176462306a36Sopenharmony_ci if (++i == HIFN_D_DST_RSIZE) 176562306a36Sopenharmony_ci i = 0; 176662306a36Sopenharmony_ci u--; 176762306a36Sopenharmony_ci } 176862306a36Sopenharmony_ci dma->dstk = i; dma->dstu = u; 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci dev_dbg(&dev->pdev->dev, "ring cleanup 2: i: %d.%d.%d.%d, u: %d.%d.%d.%d, " 177162306a36Sopenharmony_ci "k: %d.%d.%d.%d.\n", 177262306a36Sopenharmony_ci dma->cmdi, dma->srci, dma->dsti, dma->resi, 177362306a36Sopenharmony_ci dma->cmdu, dma->srcu, dma->dstu, dma->resu, 177462306a36Sopenharmony_ci dma->cmdk, dma->srck, dma->dstk, dma->resk); 177562306a36Sopenharmony_ci} 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_cistatic void hifn_work(struct work_struct *work) 177862306a36Sopenharmony_ci{ 177962306a36Sopenharmony_ci struct delayed_work *dw = to_delayed_work(work); 178062306a36Sopenharmony_ci struct hifn_device *dev = container_of(dw, struct hifn_device, work); 178162306a36Sopenharmony_ci unsigned long flags; 178262306a36Sopenharmony_ci int reset = 0; 178362306a36Sopenharmony_ci u32 r = 0; 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 178662306a36Sopenharmony_ci if (dev->active == 0) { 178762306a36Sopenharmony_ci struct hifn_dma *dma = dev->desc_virt; 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci if (dma->cmdu == 0 && (dev->flags & HIFN_FLAG_CMD_BUSY)) { 179062306a36Sopenharmony_ci dev->flags &= ~HIFN_FLAG_CMD_BUSY; 179162306a36Sopenharmony_ci r |= HIFN_DMACSR_C_CTRL_DIS; 179262306a36Sopenharmony_ci } 179362306a36Sopenharmony_ci if (dma->srcu == 0 && (dev->flags & HIFN_FLAG_SRC_BUSY)) { 179462306a36Sopenharmony_ci dev->flags &= ~HIFN_FLAG_SRC_BUSY; 179562306a36Sopenharmony_ci r |= HIFN_DMACSR_S_CTRL_DIS; 179662306a36Sopenharmony_ci } 179762306a36Sopenharmony_ci if (dma->dstu == 0 && (dev->flags & HIFN_FLAG_DST_BUSY)) { 179862306a36Sopenharmony_ci dev->flags &= ~HIFN_FLAG_DST_BUSY; 179962306a36Sopenharmony_ci r |= HIFN_DMACSR_D_CTRL_DIS; 180062306a36Sopenharmony_ci } 180162306a36Sopenharmony_ci if (dma->resu == 0 && (dev->flags & HIFN_FLAG_RES_BUSY)) { 180262306a36Sopenharmony_ci dev->flags &= ~HIFN_FLAG_RES_BUSY; 180362306a36Sopenharmony_ci r |= HIFN_DMACSR_R_CTRL_DIS; 180462306a36Sopenharmony_ci } 180562306a36Sopenharmony_ci if (r) 180662306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CSR, r); 180762306a36Sopenharmony_ci } else 180862306a36Sopenharmony_ci dev->active--; 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci if ((dev->prev_success == dev->success) && dev->started) 181162306a36Sopenharmony_ci reset = 1; 181262306a36Sopenharmony_ci dev->prev_success = dev->success; 181362306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci if (reset) { 181662306a36Sopenharmony_ci if (++dev->reset >= 5) { 181762306a36Sopenharmony_ci int i; 181862306a36Sopenharmony_ci struct hifn_dma *dma = dev->desc_virt; 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci dev_info(&dev->pdev->dev, 182162306a36Sopenharmony_ci "r: %08x, active: %d, started: %d, " 182262306a36Sopenharmony_ci "success: %lu: qlen: %u/%u, reset: %d.\n", 182362306a36Sopenharmony_ci r, dev->active, dev->started, 182462306a36Sopenharmony_ci dev->success, dev->queue.qlen, dev->queue.max_qlen, 182562306a36Sopenharmony_ci reset); 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci dev_info(&dev->pdev->dev, "%s: res: ", __func__); 182862306a36Sopenharmony_ci for (i = 0; i < HIFN_D_RES_RSIZE; ++i) { 182962306a36Sopenharmony_ci pr_info("%x.%p ", dma->resr[i].l, dev->sa[i]); 183062306a36Sopenharmony_ci if (dev->sa[i]) { 183162306a36Sopenharmony_ci hifn_process_ready(dev->sa[i], -ENODEV); 183262306a36Sopenharmony_ci hifn_complete_sa(dev, i); 183362306a36Sopenharmony_ci } 183462306a36Sopenharmony_ci } 183562306a36Sopenharmony_ci pr_info("\n"); 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci hifn_reset_dma(dev, 1); 183862306a36Sopenharmony_ci hifn_stop_device(dev); 183962306a36Sopenharmony_ci hifn_start_device(dev); 184062306a36Sopenharmony_ci dev->reset = 0; 184162306a36Sopenharmony_ci } 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci tasklet_schedule(&dev->tasklet); 184462306a36Sopenharmony_ci } 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci schedule_delayed_work(&dev->work, HZ); 184762306a36Sopenharmony_ci} 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_cistatic irqreturn_t hifn_interrupt(int irq, void *data) 185062306a36Sopenharmony_ci{ 185162306a36Sopenharmony_ci struct hifn_device *dev = data; 185262306a36Sopenharmony_ci struct hifn_dma *dma = dev->desc_virt; 185362306a36Sopenharmony_ci u32 dmacsr, restart; 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_ci dmacsr = hifn_read_1(dev, HIFN_1_DMA_CSR); 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci dev_dbg(&dev->pdev->dev, "1 dmacsr: %08x, dmareg: %08x, res: %08x [%d], " 185862306a36Sopenharmony_ci "i: %d.%d.%d.%d, u: %d.%d.%d.%d.\n", 185962306a36Sopenharmony_ci dmacsr, dev->dmareg, dmacsr & dev->dmareg, dma->cmdi, 186062306a36Sopenharmony_ci dma->cmdi, dma->srci, dma->dsti, dma->resi, 186162306a36Sopenharmony_ci dma->cmdu, dma->srcu, dma->dstu, dma->resu); 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci if ((dmacsr & dev->dmareg) == 0) 186462306a36Sopenharmony_ci return IRQ_NONE; 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CSR, dmacsr & dev->dmareg); 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci if (dmacsr & HIFN_DMACSR_ENGINE) 186962306a36Sopenharmony_ci hifn_write_0(dev, HIFN_0_PUISR, hifn_read_0(dev, HIFN_0_PUISR)); 187062306a36Sopenharmony_ci if (dmacsr & HIFN_DMACSR_PUBDONE) 187162306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_PUB_STATUS, 187262306a36Sopenharmony_ci hifn_read_1(dev, HIFN_1_PUB_STATUS) | HIFN_PUBSTS_DONE); 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci restart = dmacsr & (HIFN_DMACSR_R_OVER | HIFN_DMACSR_D_OVER); 187562306a36Sopenharmony_ci if (restart) { 187662306a36Sopenharmony_ci u32 puisr = hifn_read_0(dev, HIFN_0_PUISR); 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci dev_warn(&dev->pdev->dev, "overflow: r: %d, d: %d, puisr: %08x, d: %u.\n", 187962306a36Sopenharmony_ci !!(dmacsr & HIFN_DMACSR_R_OVER), 188062306a36Sopenharmony_ci !!(dmacsr & HIFN_DMACSR_D_OVER), 188162306a36Sopenharmony_ci puisr, !!(puisr & HIFN_PUISR_DSTOVER)); 188262306a36Sopenharmony_ci if (!!(puisr & HIFN_PUISR_DSTOVER)) 188362306a36Sopenharmony_ci hifn_write_0(dev, HIFN_0_PUISR, HIFN_PUISR_DSTOVER); 188462306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_CSR, dmacsr & (HIFN_DMACSR_R_OVER | 188562306a36Sopenharmony_ci HIFN_DMACSR_D_OVER)); 188662306a36Sopenharmony_ci } 188762306a36Sopenharmony_ci 188862306a36Sopenharmony_ci restart = dmacsr & (HIFN_DMACSR_C_ABORT | HIFN_DMACSR_S_ABORT | 188962306a36Sopenharmony_ci HIFN_DMACSR_D_ABORT | HIFN_DMACSR_R_ABORT); 189062306a36Sopenharmony_ci if (restart) { 189162306a36Sopenharmony_ci dev_warn(&dev->pdev->dev, "abort: c: %d, s: %d, d: %d, r: %d.\n", 189262306a36Sopenharmony_ci !!(dmacsr & HIFN_DMACSR_C_ABORT), 189362306a36Sopenharmony_ci !!(dmacsr & HIFN_DMACSR_S_ABORT), 189462306a36Sopenharmony_ci !!(dmacsr & HIFN_DMACSR_D_ABORT), 189562306a36Sopenharmony_ci !!(dmacsr & HIFN_DMACSR_R_ABORT)); 189662306a36Sopenharmony_ci hifn_reset_dma(dev, 1); 189762306a36Sopenharmony_ci hifn_init_dma(dev); 189862306a36Sopenharmony_ci hifn_init_registers(dev); 189962306a36Sopenharmony_ci } 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci if ((dmacsr & HIFN_DMACSR_C_WAIT) && (dma->cmdu == 0)) { 190262306a36Sopenharmony_ci dev_dbg(&dev->pdev->dev, "wait on command.\n"); 190362306a36Sopenharmony_ci dev->dmareg &= ~(HIFN_DMAIER_C_WAIT); 190462306a36Sopenharmony_ci hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg); 190562306a36Sopenharmony_ci } 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci tasklet_schedule(&dev->tasklet); 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci return IRQ_HANDLED; 191062306a36Sopenharmony_ci} 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_cistatic void hifn_flush(struct hifn_device *dev) 191362306a36Sopenharmony_ci{ 191462306a36Sopenharmony_ci unsigned long flags; 191562306a36Sopenharmony_ci struct crypto_async_request *async_req; 191662306a36Sopenharmony_ci struct skcipher_request *req; 191762306a36Sopenharmony_ci struct hifn_dma *dma = dev->desc_virt; 191862306a36Sopenharmony_ci int i; 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci for (i = 0; i < HIFN_D_RES_RSIZE; ++i) { 192162306a36Sopenharmony_ci struct hifn_desc *d = &dma->resr[i]; 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci if (dev->sa[i]) { 192462306a36Sopenharmony_ci hifn_process_ready(dev->sa[i], 192562306a36Sopenharmony_ci (d->l & __cpu_to_le32(HIFN_D_VALID)) ? -ENODEV : 0); 192662306a36Sopenharmony_ci hifn_complete_sa(dev, i); 192762306a36Sopenharmony_ci } 192862306a36Sopenharmony_ci } 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 193162306a36Sopenharmony_ci while ((async_req = crypto_dequeue_request(&dev->queue))) { 193262306a36Sopenharmony_ci req = skcipher_request_cast(async_req); 193362306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci hifn_process_ready(req, -ENODEV); 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 193862306a36Sopenharmony_ci } 193962306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 194062306a36Sopenharmony_ci} 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_cistatic int hifn_setkey(struct crypto_skcipher *cipher, const u8 *key, 194362306a36Sopenharmony_ci unsigned int len) 194462306a36Sopenharmony_ci{ 194562306a36Sopenharmony_ci struct hifn_context *ctx = crypto_skcipher_ctx(cipher); 194662306a36Sopenharmony_ci struct hifn_device *dev = ctx->dev; 194762306a36Sopenharmony_ci int err; 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci err = verify_skcipher_des_key(cipher, key); 195062306a36Sopenharmony_ci if (err) 195162306a36Sopenharmony_ci return err; 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci dev->flags &= ~HIFN_FLAG_OLD_KEY; 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ci memcpy(ctx->key, key, len); 195662306a36Sopenharmony_ci ctx->keysize = len; 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci return 0; 195962306a36Sopenharmony_ci} 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_cistatic int hifn_des3_setkey(struct crypto_skcipher *cipher, const u8 *key, 196262306a36Sopenharmony_ci unsigned int len) 196362306a36Sopenharmony_ci{ 196462306a36Sopenharmony_ci struct hifn_context *ctx = crypto_skcipher_ctx(cipher); 196562306a36Sopenharmony_ci struct hifn_device *dev = ctx->dev; 196662306a36Sopenharmony_ci int err; 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci err = verify_skcipher_des3_key(cipher, key); 196962306a36Sopenharmony_ci if (err) 197062306a36Sopenharmony_ci return err; 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci dev->flags &= ~HIFN_FLAG_OLD_KEY; 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ci memcpy(ctx->key, key, len); 197562306a36Sopenharmony_ci ctx->keysize = len; 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci return 0; 197862306a36Sopenharmony_ci} 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_cistatic int hifn_handle_req(struct skcipher_request *req) 198162306a36Sopenharmony_ci{ 198262306a36Sopenharmony_ci struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm); 198362306a36Sopenharmony_ci struct hifn_device *dev = ctx->dev; 198462306a36Sopenharmony_ci int err = -EAGAIN; 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_ci if (dev->started + DIV_ROUND_UP(req->cryptlen, PAGE_SIZE) <= HIFN_QUEUE_LENGTH) 198762306a36Sopenharmony_ci err = hifn_setup_session(req); 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci if (err == -EAGAIN) { 199062306a36Sopenharmony_ci unsigned long flags; 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 199362306a36Sopenharmony_ci err = crypto_enqueue_request(&dev->queue, &req->base); 199462306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 199562306a36Sopenharmony_ci } 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci return err; 199862306a36Sopenharmony_ci} 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_cistatic int hifn_setup_crypto_req(struct skcipher_request *req, u8 op, 200162306a36Sopenharmony_ci u8 type, u8 mode) 200262306a36Sopenharmony_ci{ 200362306a36Sopenharmony_ci struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm); 200462306a36Sopenharmony_ci struct hifn_request_context *rctx = skcipher_request_ctx(req); 200562306a36Sopenharmony_ci unsigned ivsize; 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci ivsize = crypto_skcipher_ivsize(crypto_skcipher_reqtfm(req)); 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci if (req->iv && mode != ACRYPTO_MODE_ECB) { 201062306a36Sopenharmony_ci if (type == ACRYPTO_TYPE_AES_128) 201162306a36Sopenharmony_ci ivsize = HIFN_AES_IV_LENGTH; 201262306a36Sopenharmony_ci else if (type == ACRYPTO_TYPE_DES) 201362306a36Sopenharmony_ci ivsize = HIFN_DES_KEY_LENGTH; 201462306a36Sopenharmony_ci else if (type == ACRYPTO_TYPE_3DES) 201562306a36Sopenharmony_ci ivsize = HIFN_3DES_KEY_LENGTH; 201662306a36Sopenharmony_ci } 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_ci if (ctx->keysize != 16 && type == ACRYPTO_TYPE_AES_128) { 201962306a36Sopenharmony_ci if (ctx->keysize == 24) 202062306a36Sopenharmony_ci type = ACRYPTO_TYPE_AES_192; 202162306a36Sopenharmony_ci else if (ctx->keysize == 32) 202262306a36Sopenharmony_ci type = ACRYPTO_TYPE_AES_256; 202362306a36Sopenharmony_ci } 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_ci rctx->op = op; 202662306a36Sopenharmony_ci rctx->mode = mode; 202762306a36Sopenharmony_ci rctx->type = type; 202862306a36Sopenharmony_ci rctx->iv = req->iv; 202962306a36Sopenharmony_ci rctx->ivsize = ivsize; 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci /* 203262306a36Sopenharmony_ci * HEAVY TODO: needs to kick Herbert XU to write documentation. 203362306a36Sopenharmony_ci * HEAVY TODO: needs to kick Herbert XU to write documentation. 203462306a36Sopenharmony_ci * HEAVY TODO: needs to kick Herbert XU to write documentation. 203562306a36Sopenharmony_ci */ 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci return hifn_handle_req(req); 203862306a36Sopenharmony_ci} 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_cistatic int hifn_process_queue(struct hifn_device *dev) 204162306a36Sopenharmony_ci{ 204262306a36Sopenharmony_ci struct crypto_async_request *async_req, *backlog; 204362306a36Sopenharmony_ci struct skcipher_request *req; 204462306a36Sopenharmony_ci unsigned long flags; 204562306a36Sopenharmony_ci int err = 0; 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci while (dev->started < HIFN_QUEUE_LENGTH) { 204862306a36Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 204962306a36Sopenharmony_ci backlog = crypto_get_backlog(&dev->queue); 205062306a36Sopenharmony_ci async_req = crypto_dequeue_request(&dev->queue); 205162306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci if (!async_req) 205462306a36Sopenharmony_ci break; 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci if (backlog) 205762306a36Sopenharmony_ci crypto_request_complete(backlog, -EINPROGRESS); 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci req = skcipher_request_cast(async_req); 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci err = hifn_handle_req(req); 206262306a36Sopenharmony_ci if (err) 206362306a36Sopenharmony_ci break; 206462306a36Sopenharmony_ci } 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci return err; 206762306a36Sopenharmony_ci} 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_cistatic int hifn_setup_crypto(struct skcipher_request *req, u8 op, 207062306a36Sopenharmony_ci u8 type, u8 mode) 207162306a36Sopenharmony_ci{ 207262306a36Sopenharmony_ci int err; 207362306a36Sopenharmony_ci struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm); 207462306a36Sopenharmony_ci struct hifn_device *dev = ctx->dev; 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci err = hifn_setup_crypto_req(req, op, type, mode); 207762306a36Sopenharmony_ci if (err) 207862306a36Sopenharmony_ci return err; 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_ci if (dev->started < HIFN_QUEUE_LENGTH && dev->queue.qlen) 208162306a36Sopenharmony_ci hifn_process_queue(dev); 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci return -EINPROGRESS; 208462306a36Sopenharmony_ci} 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci/* 208762306a36Sopenharmony_ci * AES ecryption functions. 208862306a36Sopenharmony_ci */ 208962306a36Sopenharmony_cistatic inline int hifn_encrypt_aes_ecb(struct skcipher_request *req) 209062306a36Sopenharmony_ci{ 209162306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 209262306a36Sopenharmony_ci ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_ECB); 209362306a36Sopenharmony_ci} 209462306a36Sopenharmony_cistatic inline int hifn_encrypt_aes_cbc(struct skcipher_request *req) 209562306a36Sopenharmony_ci{ 209662306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 209762306a36Sopenharmony_ci ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CBC); 209862306a36Sopenharmony_ci} 209962306a36Sopenharmony_cistatic inline int hifn_encrypt_aes_cfb(struct skcipher_request *req) 210062306a36Sopenharmony_ci{ 210162306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 210262306a36Sopenharmony_ci ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CFB); 210362306a36Sopenharmony_ci} 210462306a36Sopenharmony_cistatic inline int hifn_encrypt_aes_ofb(struct skcipher_request *req) 210562306a36Sopenharmony_ci{ 210662306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 210762306a36Sopenharmony_ci ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_OFB); 210862306a36Sopenharmony_ci} 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_ci/* 211162306a36Sopenharmony_ci * AES decryption functions. 211262306a36Sopenharmony_ci */ 211362306a36Sopenharmony_cistatic inline int hifn_decrypt_aes_ecb(struct skcipher_request *req) 211462306a36Sopenharmony_ci{ 211562306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 211662306a36Sopenharmony_ci ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_ECB); 211762306a36Sopenharmony_ci} 211862306a36Sopenharmony_cistatic inline int hifn_decrypt_aes_cbc(struct skcipher_request *req) 211962306a36Sopenharmony_ci{ 212062306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 212162306a36Sopenharmony_ci ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CBC); 212262306a36Sopenharmony_ci} 212362306a36Sopenharmony_cistatic inline int hifn_decrypt_aes_cfb(struct skcipher_request *req) 212462306a36Sopenharmony_ci{ 212562306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 212662306a36Sopenharmony_ci ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CFB); 212762306a36Sopenharmony_ci} 212862306a36Sopenharmony_cistatic inline int hifn_decrypt_aes_ofb(struct skcipher_request *req) 212962306a36Sopenharmony_ci{ 213062306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 213162306a36Sopenharmony_ci ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_OFB); 213262306a36Sopenharmony_ci} 213362306a36Sopenharmony_ci 213462306a36Sopenharmony_ci/* 213562306a36Sopenharmony_ci * DES ecryption functions. 213662306a36Sopenharmony_ci */ 213762306a36Sopenharmony_cistatic inline int hifn_encrypt_des_ecb(struct skcipher_request *req) 213862306a36Sopenharmony_ci{ 213962306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 214062306a36Sopenharmony_ci ACRYPTO_TYPE_DES, ACRYPTO_MODE_ECB); 214162306a36Sopenharmony_ci} 214262306a36Sopenharmony_cistatic inline int hifn_encrypt_des_cbc(struct skcipher_request *req) 214362306a36Sopenharmony_ci{ 214462306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 214562306a36Sopenharmony_ci ACRYPTO_TYPE_DES, ACRYPTO_MODE_CBC); 214662306a36Sopenharmony_ci} 214762306a36Sopenharmony_cistatic inline int hifn_encrypt_des_cfb(struct skcipher_request *req) 214862306a36Sopenharmony_ci{ 214962306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 215062306a36Sopenharmony_ci ACRYPTO_TYPE_DES, ACRYPTO_MODE_CFB); 215162306a36Sopenharmony_ci} 215262306a36Sopenharmony_cistatic inline int hifn_encrypt_des_ofb(struct skcipher_request *req) 215362306a36Sopenharmony_ci{ 215462306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 215562306a36Sopenharmony_ci ACRYPTO_TYPE_DES, ACRYPTO_MODE_OFB); 215662306a36Sopenharmony_ci} 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci/* 215962306a36Sopenharmony_ci * DES decryption functions. 216062306a36Sopenharmony_ci */ 216162306a36Sopenharmony_cistatic inline int hifn_decrypt_des_ecb(struct skcipher_request *req) 216262306a36Sopenharmony_ci{ 216362306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 216462306a36Sopenharmony_ci ACRYPTO_TYPE_DES, ACRYPTO_MODE_ECB); 216562306a36Sopenharmony_ci} 216662306a36Sopenharmony_cistatic inline int hifn_decrypt_des_cbc(struct skcipher_request *req) 216762306a36Sopenharmony_ci{ 216862306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 216962306a36Sopenharmony_ci ACRYPTO_TYPE_DES, ACRYPTO_MODE_CBC); 217062306a36Sopenharmony_ci} 217162306a36Sopenharmony_cistatic inline int hifn_decrypt_des_cfb(struct skcipher_request *req) 217262306a36Sopenharmony_ci{ 217362306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 217462306a36Sopenharmony_ci ACRYPTO_TYPE_DES, ACRYPTO_MODE_CFB); 217562306a36Sopenharmony_ci} 217662306a36Sopenharmony_cistatic inline int hifn_decrypt_des_ofb(struct skcipher_request *req) 217762306a36Sopenharmony_ci{ 217862306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 217962306a36Sopenharmony_ci ACRYPTO_TYPE_DES, ACRYPTO_MODE_OFB); 218062306a36Sopenharmony_ci} 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_ci/* 218362306a36Sopenharmony_ci * 3DES ecryption functions. 218462306a36Sopenharmony_ci */ 218562306a36Sopenharmony_cistatic inline int hifn_encrypt_3des_ecb(struct skcipher_request *req) 218662306a36Sopenharmony_ci{ 218762306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 218862306a36Sopenharmony_ci ACRYPTO_TYPE_3DES, ACRYPTO_MODE_ECB); 218962306a36Sopenharmony_ci} 219062306a36Sopenharmony_cistatic inline int hifn_encrypt_3des_cbc(struct skcipher_request *req) 219162306a36Sopenharmony_ci{ 219262306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 219362306a36Sopenharmony_ci ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CBC); 219462306a36Sopenharmony_ci} 219562306a36Sopenharmony_cistatic inline int hifn_encrypt_3des_cfb(struct skcipher_request *req) 219662306a36Sopenharmony_ci{ 219762306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 219862306a36Sopenharmony_ci ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CFB); 219962306a36Sopenharmony_ci} 220062306a36Sopenharmony_cistatic inline int hifn_encrypt_3des_ofb(struct skcipher_request *req) 220162306a36Sopenharmony_ci{ 220262306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, 220362306a36Sopenharmony_ci ACRYPTO_TYPE_3DES, ACRYPTO_MODE_OFB); 220462306a36Sopenharmony_ci} 220562306a36Sopenharmony_ci 220662306a36Sopenharmony_ci/* 3DES decryption functions. */ 220762306a36Sopenharmony_cistatic inline int hifn_decrypt_3des_ecb(struct skcipher_request *req) 220862306a36Sopenharmony_ci{ 220962306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 221062306a36Sopenharmony_ci ACRYPTO_TYPE_3DES, ACRYPTO_MODE_ECB); 221162306a36Sopenharmony_ci} 221262306a36Sopenharmony_cistatic inline int hifn_decrypt_3des_cbc(struct skcipher_request *req) 221362306a36Sopenharmony_ci{ 221462306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 221562306a36Sopenharmony_ci ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CBC); 221662306a36Sopenharmony_ci} 221762306a36Sopenharmony_cistatic inline int hifn_decrypt_3des_cfb(struct skcipher_request *req) 221862306a36Sopenharmony_ci{ 221962306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 222062306a36Sopenharmony_ci ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CFB); 222162306a36Sopenharmony_ci} 222262306a36Sopenharmony_cistatic inline int hifn_decrypt_3des_ofb(struct skcipher_request *req) 222362306a36Sopenharmony_ci{ 222462306a36Sopenharmony_ci return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, 222562306a36Sopenharmony_ci ACRYPTO_TYPE_3DES, ACRYPTO_MODE_OFB); 222662306a36Sopenharmony_ci} 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_cistruct hifn_alg_template { 222962306a36Sopenharmony_ci char name[CRYPTO_MAX_ALG_NAME]; 223062306a36Sopenharmony_ci char drv_name[CRYPTO_MAX_ALG_NAME]; 223162306a36Sopenharmony_ci unsigned int bsize; 223262306a36Sopenharmony_ci struct skcipher_alg skcipher; 223362306a36Sopenharmony_ci}; 223462306a36Sopenharmony_ci 223562306a36Sopenharmony_cistatic const struct hifn_alg_template hifn_alg_templates[] = { 223662306a36Sopenharmony_ci /* 223762306a36Sopenharmony_ci * 3DES ECB, CBC, CFB and OFB modes. 223862306a36Sopenharmony_ci */ 223962306a36Sopenharmony_ci { 224062306a36Sopenharmony_ci .name = "cfb(des3_ede)", .drv_name = "cfb-3des", .bsize = 8, 224162306a36Sopenharmony_ci .skcipher = { 224262306a36Sopenharmony_ci .min_keysize = HIFN_3DES_KEY_LENGTH, 224362306a36Sopenharmony_ci .max_keysize = HIFN_3DES_KEY_LENGTH, 224462306a36Sopenharmony_ci .setkey = hifn_des3_setkey, 224562306a36Sopenharmony_ci .encrypt = hifn_encrypt_3des_cfb, 224662306a36Sopenharmony_ci .decrypt = hifn_decrypt_3des_cfb, 224762306a36Sopenharmony_ci }, 224862306a36Sopenharmony_ci }, 224962306a36Sopenharmony_ci { 225062306a36Sopenharmony_ci .name = "ofb(des3_ede)", .drv_name = "ofb-3des", .bsize = 8, 225162306a36Sopenharmony_ci .skcipher = { 225262306a36Sopenharmony_ci .min_keysize = HIFN_3DES_KEY_LENGTH, 225362306a36Sopenharmony_ci .max_keysize = HIFN_3DES_KEY_LENGTH, 225462306a36Sopenharmony_ci .setkey = hifn_des3_setkey, 225562306a36Sopenharmony_ci .encrypt = hifn_encrypt_3des_ofb, 225662306a36Sopenharmony_ci .decrypt = hifn_decrypt_3des_ofb, 225762306a36Sopenharmony_ci }, 225862306a36Sopenharmony_ci }, 225962306a36Sopenharmony_ci { 226062306a36Sopenharmony_ci .name = "cbc(des3_ede)", .drv_name = "cbc-3des", .bsize = 8, 226162306a36Sopenharmony_ci .skcipher = { 226262306a36Sopenharmony_ci .ivsize = HIFN_IV_LENGTH, 226362306a36Sopenharmony_ci .min_keysize = HIFN_3DES_KEY_LENGTH, 226462306a36Sopenharmony_ci .max_keysize = HIFN_3DES_KEY_LENGTH, 226562306a36Sopenharmony_ci .setkey = hifn_des3_setkey, 226662306a36Sopenharmony_ci .encrypt = hifn_encrypt_3des_cbc, 226762306a36Sopenharmony_ci .decrypt = hifn_decrypt_3des_cbc, 226862306a36Sopenharmony_ci }, 226962306a36Sopenharmony_ci }, 227062306a36Sopenharmony_ci { 227162306a36Sopenharmony_ci .name = "ecb(des3_ede)", .drv_name = "ecb-3des", .bsize = 8, 227262306a36Sopenharmony_ci .skcipher = { 227362306a36Sopenharmony_ci .min_keysize = HIFN_3DES_KEY_LENGTH, 227462306a36Sopenharmony_ci .max_keysize = HIFN_3DES_KEY_LENGTH, 227562306a36Sopenharmony_ci .setkey = hifn_des3_setkey, 227662306a36Sopenharmony_ci .encrypt = hifn_encrypt_3des_ecb, 227762306a36Sopenharmony_ci .decrypt = hifn_decrypt_3des_ecb, 227862306a36Sopenharmony_ci }, 227962306a36Sopenharmony_ci }, 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci /* 228262306a36Sopenharmony_ci * DES ECB, CBC, CFB and OFB modes. 228362306a36Sopenharmony_ci */ 228462306a36Sopenharmony_ci { 228562306a36Sopenharmony_ci .name = "cfb(des)", .drv_name = "cfb-des", .bsize = 8, 228662306a36Sopenharmony_ci .skcipher = { 228762306a36Sopenharmony_ci .min_keysize = HIFN_DES_KEY_LENGTH, 228862306a36Sopenharmony_ci .max_keysize = HIFN_DES_KEY_LENGTH, 228962306a36Sopenharmony_ci .setkey = hifn_setkey, 229062306a36Sopenharmony_ci .encrypt = hifn_encrypt_des_cfb, 229162306a36Sopenharmony_ci .decrypt = hifn_decrypt_des_cfb, 229262306a36Sopenharmony_ci }, 229362306a36Sopenharmony_ci }, 229462306a36Sopenharmony_ci { 229562306a36Sopenharmony_ci .name = "ofb(des)", .drv_name = "ofb-des", .bsize = 8, 229662306a36Sopenharmony_ci .skcipher = { 229762306a36Sopenharmony_ci .min_keysize = HIFN_DES_KEY_LENGTH, 229862306a36Sopenharmony_ci .max_keysize = HIFN_DES_KEY_LENGTH, 229962306a36Sopenharmony_ci .setkey = hifn_setkey, 230062306a36Sopenharmony_ci .encrypt = hifn_encrypt_des_ofb, 230162306a36Sopenharmony_ci .decrypt = hifn_decrypt_des_ofb, 230262306a36Sopenharmony_ci }, 230362306a36Sopenharmony_ci }, 230462306a36Sopenharmony_ci { 230562306a36Sopenharmony_ci .name = "cbc(des)", .drv_name = "cbc-des", .bsize = 8, 230662306a36Sopenharmony_ci .skcipher = { 230762306a36Sopenharmony_ci .ivsize = HIFN_IV_LENGTH, 230862306a36Sopenharmony_ci .min_keysize = HIFN_DES_KEY_LENGTH, 230962306a36Sopenharmony_ci .max_keysize = HIFN_DES_KEY_LENGTH, 231062306a36Sopenharmony_ci .setkey = hifn_setkey, 231162306a36Sopenharmony_ci .encrypt = hifn_encrypt_des_cbc, 231262306a36Sopenharmony_ci .decrypt = hifn_decrypt_des_cbc, 231362306a36Sopenharmony_ci }, 231462306a36Sopenharmony_ci }, 231562306a36Sopenharmony_ci { 231662306a36Sopenharmony_ci .name = "ecb(des)", .drv_name = "ecb-des", .bsize = 8, 231762306a36Sopenharmony_ci .skcipher = { 231862306a36Sopenharmony_ci .min_keysize = HIFN_DES_KEY_LENGTH, 231962306a36Sopenharmony_ci .max_keysize = HIFN_DES_KEY_LENGTH, 232062306a36Sopenharmony_ci .setkey = hifn_setkey, 232162306a36Sopenharmony_ci .encrypt = hifn_encrypt_des_ecb, 232262306a36Sopenharmony_ci .decrypt = hifn_decrypt_des_ecb, 232362306a36Sopenharmony_ci }, 232462306a36Sopenharmony_ci }, 232562306a36Sopenharmony_ci 232662306a36Sopenharmony_ci /* 232762306a36Sopenharmony_ci * AES ECB, CBC, CFB and OFB modes. 232862306a36Sopenharmony_ci */ 232962306a36Sopenharmony_ci { 233062306a36Sopenharmony_ci .name = "ecb(aes)", .drv_name = "ecb-aes", .bsize = 16, 233162306a36Sopenharmony_ci .skcipher = { 233262306a36Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 233362306a36Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 233462306a36Sopenharmony_ci .setkey = hifn_setkey, 233562306a36Sopenharmony_ci .encrypt = hifn_encrypt_aes_ecb, 233662306a36Sopenharmony_ci .decrypt = hifn_decrypt_aes_ecb, 233762306a36Sopenharmony_ci }, 233862306a36Sopenharmony_ci }, 233962306a36Sopenharmony_ci { 234062306a36Sopenharmony_ci .name = "cbc(aes)", .drv_name = "cbc-aes", .bsize = 16, 234162306a36Sopenharmony_ci .skcipher = { 234262306a36Sopenharmony_ci .ivsize = HIFN_AES_IV_LENGTH, 234362306a36Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 234462306a36Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 234562306a36Sopenharmony_ci .setkey = hifn_setkey, 234662306a36Sopenharmony_ci .encrypt = hifn_encrypt_aes_cbc, 234762306a36Sopenharmony_ci .decrypt = hifn_decrypt_aes_cbc, 234862306a36Sopenharmony_ci }, 234962306a36Sopenharmony_ci }, 235062306a36Sopenharmony_ci { 235162306a36Sopenharmony_ci .name = "cfb(aes)", .drv_name = "cfb-aes", .bsize = 16, 235262306a36Sopenharmony_ci .skcipher = { 235362306a36Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 235462306a36Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 235562306a36Sopenharmony_ci .setkey = hifn_setkey, 235662306a36Sopenharmony_ci .encrypt = hifn_encrypt_aes_cfb, 235762306a36Sopenharmony_ci .decrypt = hifn_decrypt_aes_cfb, 235862306a36Sopenharmony_ci }, 235962306a36Sopenharmony_ci }, 236062306a36Sopenharmony_ci { 236162306a36Sopenharmony_ci .name = "ofb(aes)", .drv_name = "ofb-aes", .bsize = 16, 236262306a36Sopenharmony_ci .skcipher = { 236362306a36Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 236462306a36Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 236562306a36Sopenharmony_ci .setkey = hifn_setkey, 236662306a36Sopenharmony_ci .encrypt = hifn_encrypt_aes_ofb, 236762306a36Sopenharmony_ci .decrypt = hifn_decrypt_aes_ofb, 236862306a36Sopenharmony_ci }, 236962306a36Sopenharmony_ci }, 237062306a36Sopenharmony_ci}; 237162306a36Sopenharmony_ci 237262306a36Sopenharmony_cistatic int hifn_init_tfm(struct crypto_skcipher *tfm) 237362306a36Sopenharmony_ci{ 237462306a36Sopenharmony_ci struct skcipher_alg *alg = crypto_skcipher_alg(tfm); 237562306a36Sopenharmony_ci struct hifn_crypto_alg *ha = crypto_alg_to_hifn(alg); 237662306a36Sopenharmony_ci struct hifn_context *ctx = crypto_skcipher_ctx(tfm); 237762306a36Sopenharmony_ci 237862306a36Sopenharmony_ci ctx->dev = ha->dev; 237962306a36Sopenharmony_ci crypto_skcipher_set_reqsize(tfm, sizeof(struct hifn_request_context)); 238062306a36Sopenharmony_ci 238162306a36Sopenharmony_ci return 0; 238262306a36Sopenharmony_ci} 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_cistatic int hifn_alg_alloc(struct hifn_device *dev, const struct hifn_alg_template *t) 238562306a36Sopenharmony_ci{ 238662306a36Sopenharmony_ci struct hifn_crypto_alg *alg; 238762306a36Sopenharmony_ci int err; 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci alg = kzalloc(sizeof(*alg), GFP_KERNEL); 239062306a36Sopenharmony_ci if (!alg) 239162306a36Sopenharmony_ci return -ENOMEM; 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci alg->alg = t->skcipher; 239462306a36Sopenharmony_ci alg->alg.init = hifn_init_tfm; 239562306a36Sopenharmony_ci 239662306a36Sopenharmony_ci snprintf(alg->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", t->name); 239762306a36Sopenharmony_ci snprintf(alg->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s-%s", 239862306a36Sopenharmony_ci t->drv_name, dev->name); 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci alg->alg.base.cra_priority = 300; 240162306a36Sopenharmony_ci alg->alg.base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC; 240262306a36Sopenharmony_ci alg->alg.base.cra_blocksize = t->bsize; 240362306a36Sopenharmony_ci alg->alg.base.cra_ctxsize = sizeof(struct hifn_context); 240462306a36Sopenharmony_ci alg->alg.base.cra_alignmask = 0; 240562306a36Sopenharmony_ci alg->alg.base.cra_module = THIS_MODULE; 240662306a36Sopenharmony_ci 240762306a36Sopenharmony_ci alg->dev = dev; 240862306a36Sopenharmony_ci 240962306a36Sopenharmony_ci list_add_tail(&alg->entry, &dev->alg_list); 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_ci err = crypto_register_skcipher(&alg->alg); 241262306a36Sopenharmony_ci if (err) { 241362306a36Sopenharmony_ci list_del(&alg->entry); 241462306a36Sopenharmony_ci kfree(alg); 241562306a36Sopenharmony_ci } 241662306a36Sopenharmony_ci 241762306a36Sopenharmony_ci return err; 241862306a36Sopenharmony_ci} 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_cistatic void hifn_unregister_alg(struct hifn_device *dev) 242162306a36Sopenharmony_ci{ 242262306a36Sopenharmony_ci struct hifn_crypto_alg *a, *n; 242362306a36Sopenharmony_ci 242462306a36Sopenharmony_ci list_for_each_entry_safe(a, n, &dev->alg_list, entry) { 242562306a36Sopenharmony_ci list_del(&a->entry); 242662306a36Sopenharmony_ci crypto_unregister_skcipher(&a->alg); 242762306a36Sopenharmony_ci kfree(a); 242862306a36Sopenharmony_ci } 242962306a36Sopenharmony_ci} 243062306a36Sopenharmony_ci 243162306a36Sopenharmony_cistatic int hifn_register_alg(struct hifn_device *dev) 243262306a36Sopenharmony_ci{ 243362306a36Sopenharmony_ci int i, err; 243462306a36Sopenharmony_ci 243562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hifn_alg_templates); ++i) { 243662306a36Sopenharmony_ci err = hifn_alg_alloc(dev, &hifn_alg_templates[i]); 243762306a36Sopenharmony_ci if (err) 243862306a36Sopenharmony_ci goto err_out_exit; 243962306a36Sopenharmony_ci } 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci return 0; 244262306a36Sopenharmony_ci 244362306a36Sopenharmony_cierr_out_exit: 244462306a36Sopenharmony_ci hifn_unregister_alg(dev); 244562306a36Sopenharmony_ci return err; 244662306a36Sopenharmony_ci} 244762306a36Sopenharmony_ci 244862306a36Sopenharmony_cistatic void hifn_tasklet_callback(unsigned long data) 244962306a36Sopenharmony_ci{ 245062306a36Sopenharmony_ci struct hifn_device *dev = (struct hifn_device *)data; 245162306a36Sopenharmony_ci 245262306a36Sopenharmony_ci /* 245362306a36Sopenharmony_ci * This is ok to call this without lock being held, 245462306a36Sopenharmony_ci * althogh it modifies some parameters used in parallel, 245562306a36Sopenharmony_ci * (like dev->success), but they are used in process 245662306a36Sopenharmony_ci * context or update is atomic (like setting dev->sa[i] to NULL). 245762306a36Sopenharmony_ci */ 245862306a36Sopenharmony_ci hifn_clear_rings(dev, 0); 245962306a36Sopenharmony_ci 246062306a36Sopenharmony_ci if (dev->started < HIFN_QUEUE_LENGTH && dev->queue.qlen) 246162306a36Sopenharmony_ci hifn_process_queue(dev); 246262306a36Sopenharmony_ci} 246362306a36Sopenharmony_ci 246462306a36Sopenharmony_cistatic int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id) 246562306a36Sopenharmony_ci{ 246662306a36Sopenharmony_ci int err, i; 246762306a36Sopenharmony_ci struct hifn_device *dev; 246862306a36Sopenharmony_ci char name[8]; 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_ci err = pci_enable_device(pdev); 247162306a36Sopenharmony_ci if (err) 247262306a36Sopenharmony_ci return err; 247362306a36Sopenharmony_ci pci_set_master(pdev); 247462306a36Sopenharmony_ci 247562306a36Sopenharmony_ci err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); 247662306a36Sopenharmony_ci if (err) 247762306a36Sopenharmony_ci goto err_out_disable_pci_device; 247862306a36Sopenharmony_ci 247962306a36Sopenharmony_ci snprintf(name, sizeof(name), "hifn%d", 248062306a36Sopenharmony_ci atomic_inc_return(&hifn_dev_number) - 1); 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci err = pci_request_regions(pdev, name); 248362306a36Sopenharmony_ci if (err) 248462306a36Sopenharmony_ci goto err_out_disable_pci_device; 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci if (pci_resource_len(pdev, 0) < HIFN_BAR0_SIZE || 248762306a36Sopenharmony_ci pci_resource_len(pdev, 1) < HIFN_BAR1_SIZE || 248862306a36Sopenharmony_ci pci_resource_len(pdev, 2) < HIFN_BAR2_SIZE) { 248962306a36Sopenharmony_ci dev_err(&pdev->dev, "Broken hardware - I/O regions are too small.\n"); 249062306a36Sopenharmony_ci err = -ENODEV; 249162306a36Sopenharmony_ci goto err_out_free_regions; 249262306a36Sopenharmony_ci } 249362306a36Sopenharmony_ci 249462306a36Sopenharmony_ci dev = kzalloc(sizeof(struct hifn_device) + sizeof(struct crypto_alg), 249562306a36Sopenharmony_ci GFP_KERNEL); 249662306a36Sopenharmony_ci if (!dev) { 249762306a36Sopenharmony_ci err = -ENOMEM; 249862306a36Sopenharmony_ci goto err_out_free_regions; 249962306a36Sopenharmony_ci } 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_ci INIT_LIST_HEAD(&dev->alg_list); 250262306a36Sopenharmony_ci 250362306a36Sopenharmony_ci snprintf(dev->name, sizeof(dev->name), "%s", name); 250462306a36Sopenharmony_ci spin_lock_init(&dev->lock); 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci for (i = 0; i < 3; ++i) { 250762306a36Sopenharmony_ci unsigned long addr, size; 250862306a36Sopenharmony_ci 250962306a36Sopenharmony_ci addr = pci_resource_start(pdev, i); 251062306a36Sopenharmony_ci size = pci_resource_len(pdev, i); 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci dev->bar[i] = ioremap(addr, size); 251362306a36Sopenharmony_ci if (!dev->bar[i]) { 251462306a36Sopenharmony_ci err = -ENOMEM; 251562306a36Sopenharmony_ci goto err_out_unmap_bars; 251662306a36Sopenharmony_ci } 251762306a36Sopenharmony_ci } 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_ci dev->desc_virt = dma_alloc_coherent(&pdev->dev, 252062306a36Sopenharmony_ci sizeof(struct hifn_dma), 252162306a36Sopenharmony_ci &dev->desc_dma, GFP_KERNEL); 252262306a36Sopenharmony_ci if (!dev->desc_virt) { 252362306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to allocate descriptor rings.\n"); 252462306a36Sopenharmony_ci err = -ENOMEM; 252562306a36Sopenharmony_ci goto err_out_unmap_bars; 252662306a36Sopenharmony_ci } 252762306a36Sopenharmony_ci 252862306a36Sopenharmony_ci dev->pdev = pdev; 252962306a36Sopenharmony_ci dev->irq = pdev->irq; 253062306a36Sopenharmony_ci 253162306a36Sopenharmony_ci for (i = 0; i < HIFN_D_RES_RSIZE; ++i) 253262306a36Sopenharmony_ci dev->sa[i] = NULL; 253362306a36Sopenharmony_ci 253462306a36Sopenharmony_ci pci_set_drvdata(pdev, dev); 253562306a36Sopenharmony_ci 253662306a36Sopenharmony_ci tasklet_init(&dev->tasklet, hifn_tasklet_callback, (unsigned long)dev); 253762306a36Sopenharmony_ci 253862306a36Sopenharmony_ci crypto_init_queue(&dev->queue, 1); 253962306a36Sopenharmony_ci 254062306a36Sopenharmony_ci err = request_irq(dev->irq, hifn_interrupt, IRQF_SHARED, dev->name, dev); 254162306a36Sopenharmony_ci if (err) { 254262306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to request IRQ%d: err: %d.\n", 254362306a36Sopenharmony_ci dev->irq, err); 254462306a36Sopenharmony_ci dev->irq = 0; 254562306a36Sopenharmony_ci goto err_out_free_desc; 254662306a36Sopenharmony_ci } 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci err = hifn_start_device(dev); 254962306a36Sopenharmony_ci if (err) 255062306a36Sopenharmony_ci goto err_out_free_irq; 255162306a36Sopenharmony_ci 255262306a36Sopenharmony_ci err = hifn_register_rng(dev); 255362306a36Sopenharmony_ci if (err) 255462306a36Sopenharmony_ci goto err_out_stop_device; 255562306a36Sopenharmony_ci 255662306a36Sopenharmony_ci err = hifn_register_alg(dev); 255762306a36Sopenharmony_ci if (err) 255862306a36Sopenharmony_ci goto err_out_unregister_rng; 255962306a36Sopenharmony_ci 256062306a36Sopenharmony_ci INIT_DELAYED_WORK(&dev->work, hifn_work); 256162306a36Sopenharmony_ci schedule_delayed_work(&dev->work, HZ); 256262306a36Sopenharmony_ci 256362306a36Sopenharmony_ci dev_dbg(&pdev->dev, "HIFN crypto accelerator card at %s has been " 256462306a36Sopenharmony_ci "successfully registered as %s.\n", 256562306a36Sopenharmony_ci pci_name(pdev), dev->name); 256662306a36Sopenharmony_ci 256762306a36Sopenharmony_ci return 0; 256862306a36Sopenharmony_ci 256962306a36Sopenharmony_cierr_out_unregister_rng: 257062306a36Sopenharmony_ci hifn_unregister_rng(dev); 257162306a36Sopenharmony_cierr_out_stop_device: 257262306a36Sopenharmony_ci hifn_reset_dma(dev, 1); 257362306a36Sopenharmony_ci hifn_stop_device(dev); 257462306a36Sopenharmony_cierr_out_free_irq: 257562306a36Sopenharmony_ci free_irq(dev->irq, dev); 257662306a36Sopenharmony_ci tasklet_kill(&dev->tasklet); 257762306a36Sopenharmony_cierr_out_free_desc: 257862306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, sizeof(struct hifn_dma), dev->desc_virt, 257962306a36Sopenharmony_ci dev->desc_dma); 258062306a36Sopenharmony_ci 258162306a36Sopenharmony_cierr_out_unmap_bars: 258262306a36Sopenharmony_ci for (i = 0; i < 3; ++i) 258362306a36Sopenharmony_ci if (dev->bar[i]) 258462306a36Sopenharmony_ci iounmap(dev->bar[i]); 258562306a36Sopenharmony_ci kfree(dev); 258662306a36Sopenharmony_ci 258762306a36Sopenharmony_cierr_out_free_regions: 258862306a36Sopenharmony_ci pci_release_regions(pdev); 258962306a36Sopenharmony_ci 259062306a36Sopenharmony_cierr_out_disable_pci_device: 259162306a36Sopenharmony_ci pci_disable_device(pdev); 259262306a36Sopenharmony_ci 259362306a36Sopenharmony_ci return err; 259462306a36Sopenharmony_ci} 259562306a36Sopenharmony_ci 259662306a36Sopenharmony_cistatic void hifn_remove(struct pci_dev *pdev) 259762306a36Sopenharmony_ci{ 259862306a36Sopenharmony_ci int i; 259962306a36Sopenharmony_ci struct hifn_device *dev; 260062306a36Sopenharmony_ci 260162306a36Sopenharmony_ci dev = pci_get_drvdata(pdev); 260262306a36Sopenharmony_ci 260362306a36Sopenharmony_ci if (dev) { 260462306a36Sopenharmony_ci cancel_delayed_work_sync(&dev->work); 260562306a36Sopenharmony_ci 260662306a36Sopenharmony_ci hifn_unregister_rng(dev); 260762306a36Sopenharmony_ci hifn_unregister_alg(dev); 260862306a36Sopenharmony_ci hifn_reset_dma(dev, 1); 260962306a36Sopenharmony_ci hifn_stop_device(dev); 261062306a36Sopenharmony_ci 261162306a36Sopenharmony_ci free_irq(dev->irq, dev); 261262306a36Sopenharmony_ci tasklet_kill(&dev->tasklet); 261362306a36Sopenharmony_ci 261462306a36Sopenharmony_ci hifn_flush(dev); 261562306a36Sopenharmony_ci 261662306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, sizeof(struct hifn_dma), 261762306a36Sopenharmony_ci dev->desc_virt, dev->desc_dma); 261862306a36Sopenharmony_ci for (i = 0; i < 3; ++i) 261962306a36Sopenharmony_ci if (dev->bar[i]) 262062306a36Sopenharmony_ci iounmap(dev->bar[i]); 262162306a36Sopenharmony_ci 262262306a36Sopenharmony_ci kfree(dev); 262362306a36Sopenharmony_ci } 262462306a36Sopenharmony_ci 262562306a36Sopenharmony_ci pci_release_regions(pdev); 262662306a36Sopenharmony_ci pci_disable_device(pdev); 262762306a36Sopenharmony_ci} 262862306a36Sopenharmony_ci 262962306a36Sopenharmony_cistatic struct pci_device_id hifn_pci_tbl[] = { 263062306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_HIFN, PCI_DEVICE_ID_HIFN_7955) }, 263162306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_HIFN, PCI_DEVICE_ID_HIFN_7956) }, 263262306a36Sopenharmony_ci { 0 } 263362306a36Sopenharmony_ci}; 263462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, hifn_pci_tbl); 263562306a36Sopenharmony_ci 263662306a36Sopenharmony_cistatic struct pci_driver hifn_pci_driver = { 263762306a36Sopenharmony_ci .name = "hifn795x", 263862306a36Sopenharmony_ci .id_table = hifn_pci_tbl, 263962306a36Sopenharmony_ci .probe = hifn_probe, 264062306a36Sopenharmony_ci .remove = hifn_remove, 264162306a36Sopenharmony_ci}; 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_cistatic int __init hifn_init(void) 264462306a36Sopenharmony_ci{ 264562306a36Sopenharmony_ci unsigned int freq; 264662306a36Sopenharmony_ci int err; 264762306a36Sopenharmony_ci 264862306a36Sopenharmony_ci if (strncmp(hifn_pll_ref, "ext", 3) && 264962306a36Sopenharmony_ci strncmp(hifn_pll_ref, "pci", 3)) { 265062306a36Sopenharmony_ci pr_err("hifn795x: invalid hifn_pll_ref clock, must be pci or ext"); 265162306a36Sopenharmony_ci return -EINVAL; 265262306a36Sopenharmony_ci } 265362306a36Sopenharmony_ci 265462306a36Sopenharmony_ci /* 265562306a36Sopenharmony_ci * For the 7955/7956 the reference clock frequency must be in the 265662306a36Sopenharmony_ci * range of 20MHz-100MHz. For the 7954 the upper bound is 66.67MHz, 265762306a36Sopenharmony_ci * but this chip is currently not supported. 265862306a36Sopenharmony_ci */ 265962306a36Sopenharmony_ci if (hifn_pll_ref[3] != '\0') { 266062306a36Sopenharmony_ci freq = simple_strtoul(hifn_pll_ref + 3, NULL, 10); 266162306a36Sopenharmony_ci if (freq < 20 || freq > 100) { 266262306a36Sopenharmony_ci pr_err("hifn795x: invalid hifn_pll_ref frequency, must" 266362306a36Sopenharmony_ci "be in the range of 20-100"); 266462306a36Sopenharmony_ci return -EINVAL; 266562306a36Sopenharmony_ci } 266662306a36Sopenharmony_ci } 266762306a36Sopenharmony_ci 266862306a36Sopenharmony_ci err = pci_register_driver(&hifn_pci_driver); 266962306a36Sopenharmony_ci if (err < 0) { 267062306a36Sopenharmony_ci pr_err("Failed to register PCI driver for %s device.\n", 267162306a36Sopenharmony_ci hifn_pci_driver.name); 267262306a36Sopenharmony_ci return -ENODEV; 267362306a36Sopenharmony_ci } 267462306a36Sopenharmony_ci 267562306a36Sopenharmony_ci pr_info("Driver for HIFN 795x crypto accelerator chip " 267662306a36Sopenharmony_ci "has been successfully registered.\n"); 267762306a36Sopenharmony_ci 267862306a36Sopenharmony_ci return 0; 267962306a36Sopenharmony_ci} 268062306a36Sopenharmony_ci 268162306a36Sopenharmony_cistatic void __exit hifn_fini(void) 268262306a36Sopenharmony_ci{ 268362306a36Sopenharmony_ci pci_unregister_driver(&hifn_pci_driver); 268462306a36Sopenharmony_ci 268562306a36Sopenharmony_ci pr_info("Driver for HIFN 795x crypto accelerator chip " 268662306a36Sopenharmony_ci "has been successfully unregistered.\n"); 268762306a36Sopenharmony_ci} 268862306a36Sopenharmony_ci 268962306a36Sopenharmony_cimodule_init(hifn_init); 269062306a36Sopenharmony_cimodule_exit(hifn_fini); 269162306a36Sopenharmony_ci 269262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 269362306a36Sopenharmony_ciMODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>"); 269462306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for HIFN 795x crypto accelerator chip."); 2695