crypto: cavium/nitrox - Add support for loading asymmetric crypto firmware

This patch adds support to load Asymmetric crypto firmware on
AE cores of CNN55XX device. Firmware is stored on UCD block 2
and all available AE cores are tagged to group 0.

Signed-off-by: Phani Kiran Hemadri <phemadri@marvell.com>
Reviewed-by: Srikanth Jampala <jsrikanth@marvell.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
Phani Kiran Hemadri 2019-07-09 15:24:24 +00:00 committed by Herbert Xu
parent a7c2647034
commit a7268c4d42
4 changed files with 245 additions and 32 deletions

View File

@ -40,9 +40,77 @@
#define EMU_FUSE_MAPX(_i) (0x1402708 + ((_i) * 0x40000))
/* UCD registers */
#define UCD_SE_EID_UCODE_BLOCK_NUMX(_i) (0x12C0000 + ((_i) * 0x1000))
#define UCD_AE_EID_UCODE_BLOCK_NUMX(_i) (0x12C0008 + ((_i) * 0x800))
#define UCD_UCODE_LOAD_BLOCK_NUM 0x12C0010
#define UCD_UCODE_LOAD_IDX_DATAX(_i) (0x12C0018 + ((_i) * 0x20))
#define UCD_SE_EID_UCODE_BLOCK_NUMX(_i) (0x12C0000 + ((_i) * 0x1000))
#define UCD_SE_CNTX(_i) (0x12C0040 + ((_i) * 0x1000))
#define UCD_AE_CNTX(_i) (0x12C0048 + ((_i) * 0x800))
/* AQM registers */
#define AQM_CTL 0x1300000
#define AQM_INT 0x1300008
#define AQM_DBELL_OVF_LO 0x1300010
#define AQM_DBELL_OVF_HI 0x1300018
#define AQM_DBELL_OVF_LO_W1S 0x1300020
#define AQM_DBELL_OVF_LO_ENA_W1C 0x1300028
#define AQM_DBELL_OVF_LO_ENA_W1S 0x1300030
#define AQM_DBELL_OVF_HI_W1S 0x1300038
#define AQM_DBELL_OVF_HI_ENA_W1C 0x1300040
#define AQM_DBELL_OVF_HI_ENA_W1S 0x1300048
#define AQM_DMA_RD_ERR_LO 0x1300050
#define AQM_DMA_RD_ERR_HI 0x1300058
#define AQM_DMA_RD_ERR_LO_W1S 0x1300060
#define AQM_DMA_RD_ERR_LO_ENA_W1C 0x1300068
#define AQM_DMA_RD_ERR_LO_ENA_W1S 0x1300070
#define AQM_DMA_RD_ERR_HI_W1S 0x1300078
#define AQM_DMA_RD_ERR_HI_ENA_W1C 0x1300080
#define AQM_DMA_RD_ERR_HI_ENA_W1S 0x1300088
#define AQM_EXEC_NA_LO 0x1300090
#define AQM_EXEC_NA_HI 0x1300098
#define AQM_EXEC_NA_LO_W1S 0x13000A0
#define AQM_EXEC_NA_LO_ENA_W1C 0x13000A8
#define AQM_EXEC_NA_LO_ENA_W1S 0x13000B0
#define AQM_EXEC_NA_HI_W1S 0x13000B8
#define AQM_EXEC_NA_HI_ENA_W1C 0x13000C0
#define AQM_EXEC_NA_HI_ENA_W1S 0x13000C8
#define AQM_EXEC_ERR_LO 0x13000D0
#define AQM_EXEC_ERR_HI 0x13000D8
#define AQM_EXEC_ERR_LO_W1S 0x13000E0
#define AQM_EXEC_ERR_LO_ENA_W1C 0x13000E8
#define AQM_EXEC_ERR_LO_ENA_W1S 0x13000F0
#define AQM_EXEC_ERR_HI_W1S 0x13000F8
#define AQM_EXEC_ERR_HI_ENA_W1C 0x1300100
#define AQM_EXEC_ERR_HI_ENA_W1S 0x1300108
#define AQM_ECC_INT 0x1300110
#define AQM_ECC_INT_W1S 0x1300118
#define AQM_ECC_INT_ENA_W1C 0x1300120
#define AQM_ECC_INT_ENA_W1S 0x1300128
#define AQM_ECC_CTL 0x1300130
#define AQM_BIST_STATUS 0x1300138
#define AQM_CMD_INF_THRX(x) (0x1300400 + ((x) * 0x8))
#define AQM_CMD_INFX(x) (0x1300800 + ((x) * 0x8))
#define AQM_GRP_EXECMSK_LOX(x) (0x1300C00 + ((x) * 0x10))
#define AQM_GRP_EXECMSK_HIX(x) (0x1300C08 + ((x) * 0x10))
#define AQM_ACTIVITY_STAT_LO 0x1300C80
#define AQM_ACTIVITY_STAT_HI 0x1300C88
#define AQM_Q_CMD_PROCX(x) (0x1301000 + ((x) * 0x8))
#define AQM_PERF_CTL_LO 0x1301400
#define AQM_PERF_CTL_HI 0x1301408
#define AQM_PERF_CNT 0x1301410
#define AQMQ_DRBLX(x) (0x20000 + ((x) * 0x40000))
#define AQMQ_QSZX(x) (0x20008 + ((x) * 0x40000))
#define AQMQ_BADRX(x) (0x20010 + ((x) * 0x40000))
#define AQMQ_NXT_CMDX(x) (0x20018 + ((x) * 0x40000))
#define AQMQ_CMD_CNTX(x) (0x20020 + ((x) * 0x40000))
#define AQMQ_CMP_THRX(x) (0x20028 + ((x) * 0x40000))
#define AQMQ_CMP_CNTX(x) (0x20030 + ((x) * 0x40000))
#define AQMQ_TIM_LDX(x) (0x20038 + ((x) * 0x40000))
#define AQMQ_TIMERX(x) (0x20040 + ((x) * 0x40000))
#define AQMQ_ENX(x) (0x20048 + ((x) * 0x40000))
#define AQMQ_ACTIVITY_STATX(x) (0x20050 + ((x) * 0x40000))
#define AQM_VF_CMP_STATX(x) (0x28000 + ((x) * 0x40000))
/* NPS core registers */
#define NPS_CORE_GBL_VFCFG 0x1000000
@ -134,6 +202,60 @@
/* PEM registers */
#define PEM0_INT 0x1080428
/**
* struct ucd_core_eid_ucode_block_num - Core Eid to Ucode Blk Mapping Registers
* @ucode_len: Ucode length identifier 32KB or 64KB
* @ucode_blk: Ucode Block Number
*/
union ucd_core_eid_ucode_block_num {
u64 value;
struct {
#if (defined(__BIG_ENDIAN_BITFIELD))
u64 raz_4_63 : 60;
u64 ucode_len : 1;
u64 ucode_blk : 3;
#else
u64 ucode_blk : 3;
u64 ucode_len : 1;
u64 raz_4_63 : 60;
#endif
};
};
/**
* struct aqm_grp_execmsk_lo - Available AE engines for the group
* @exec_0_to_39: AE engines 0 to 39 status
*/
union aqm_grp_execmsk_lo {
u64 value;
struct {
#if (defined(__BIG_ENDIAN_BITFIELD))
u64 raz_40_63 : 24;
u64 exec_0_to_39 : 40;
#else
u64 exec_0_to_39 : 40;
u64 raz_40_63 : 24;
#endif
};
};
/**
* struct aqm_grp_execmsk_hi - Available AE engines for the group
* @exec_40_to_79: AE engines 40 to 79 status
*/
union aqm_grp_execmsk_hi {
u64 value;
struct {
#if (defined(__BIG_ENDIAN_BITFIELD))
u64 raz_40_63 : 24;
u64 exec_40_to_79 : 40;
#else
u64 exec_40_to_79 : 40;
u64 raz_40_63 : 24;
#endif
};
};
/**
* struct emu_fuse_map - EMU Fuse Map Registers
* @ae_fuse: Fuse settings for AE 19..0

View File

@ -9,7 +9,8 @@ static int firmware_show(struct seq_file *s, void *v)
{
struct nitrox_device *ndev = s->private;
seq_printf(s, "Version: %s\n", ndev->hw.fw_name);
seq_printf(s, "Version: %s\n", ndev->hw.fw_name[0]);
seq_printf(s, "Version: %s\n", ndev->hw.fw_name[1]);
return 0;
}

View File

@ -10,6 +10,8 @@
#define VERSION_LEN 32
/* Maximum queues in PF mode */
#define MAX_PF_QUEUES 64
/* Maximum UCD Blocks */
#define CNN55XX_MAX_UCD_BLOCKS 8
/**
* struct nitrox_cmdq - NITROX command queue
@ -74,7 +76,7 @@ struct nitrox_cmdq {
*/
struct nitrox_hw {
char partname[IFNAMSIZ * 2];
char fw_name[VERSION_LEN];
char fw_name[CNN55XX_MAX_UCD_BLOCKS][VERSION_LEN];
int freq;
u16 vendor_id;

View File

@ -17,12 +17,17 @@
#define CNN55XX_DEV_ID 0x12
#define UCODE_HLEN 48
#define SE_GROUP 0
#define DEFAULT_SE_GROUP 0
#define DEFAULT_AE_GROUP 0
#define DRIVER_VERSION "1.1"
#define DRIVER_VERSION "1.2"
#define CNN55XX_UCD_BLOCK_SIZE 32768
#define CNN55XX_MAX_UCODE_SIZE (CNN55XX_UCD_BLOCK_SIZE * 2)
#define FW_DIR "cavium/"
/* SE microcode */
#define SE_FW FW_DIR "cnn55xx_se.fw"
/* AE microcode */
#define AE_FW FW_DIR "cnn55xx_ae.fw"
static const char nitrox_driver_name[] = "CNN55XX";
@ -72,10 +77,10 @@ struct ucode {
/**
* write_to_ucd_unit - Write Firmware to NITROX UCD unit
*/
static void write_to_ucd_unit(struct nitrox_device *ndev,
struct ucode *ucode)
static void write_to_ucd_unit(struct nitrox_device *ndev, u32 ucode_size,
u64 *ucode_data, int block_num)
{
u32 code_size = be32_to_cpu(ucode->code_size) * 2;
u32 code_size;
u64 offset, data;
int i = 0;
@ -96,11 +101,12 @@ static void write_to_ucd_unit(struct nitrox_device *ndev,
/* set the block number */
offset = UCD_UCODE_LOAD_BLOCK_NUM;
nitrox_write_csr(ndev, offset, 0);
nitrox_write_csr(ndev, offset, block_num);
code_size = ucode_size;
code_size = roundup(code_size, 8);
while (code_size) {
data = ucode->code[i];
data = ucode_data[i];
/* write 8 bytes at a time */
offset = UCD_UCODE_LOAD_IDX_DATAX(i);
nitrox_write_csr(ndev, offset, data);
@ -108,29 +114,23 @@ static void write_to_ucd_unit(struct nitrox_device *ndev,
i++;
}
/* put all SE cores in group 0 */
offset = POM_GRP_EXECMASKX(SE_GROUP);
nitrox_write_csr(ndev, offset, (~0ULL));
for (i = 0; i < ndev->hw.se_cores; i++) {
/*
* write block number and firware length
* bit:<2:0> block number
* bit:3 is set SE uses 32KB microcode
* bit:3 is clear SE uses 64KB microcode
*/
offset = UCD_SE_EID_UCODE_BLOCK_NUMX(i);
nitrox_write_csr(ndev, offset, 0x8);
}
usleep_range(300, 400);
}
static int nitrox_load_fw(struct nitrox_device *ndev, const char *fw_name)
static int nitrox_load_fw(struct nitrox_device *ndev)
{
const struct firmware *fw;
const char *fw_name;
struct ucode *ucode;
int ret;
u64 *ucode_data;
u64 offset;
union ucd_core_eid_ucode_block_num core_2_eid_val;
union aqm_grp_execmsk_lo aqm_grp_execmask_lo;
union aqm_grp_execmsk_hi aqm_grp_execmask_hi;
u32 ucode_size;
int ret, i = 0;
fw_name = SE_FW;
dev_info(DEV(ndev), "Loading firmware \"%s\"\n", fw_name);
ret = request_firmware(&fw, fw_name, DEV(ndev));
@ -140,13 +140,101 @@ static int nitrox_load_fw(struct nitrox_device *ndev, const char *fw_name)
}
ucode = (struct ucode *)fw->data;
/* copy the firmware version */
memcpy(ndev->hw.fw_name, ucode->version, (VERSION_LEN - 2));
ndev->hw.fw_name[VERSION_LEN - 1] = '\0';
write_to_ucd_unit(ndev, ucode);
ucode_size = be32_to_cpu(ucode->code_size) * 2;
if (!ucode_size || ucode_size > CNN55XX_MAX_UCODE_SIZE) {
dev_err(DEV(ndev), "Invalid ucode size: %u for firmware %s\n",
ucode_size, fw_name);
release_firmware(fw);
return -EINVAL;
}
ucode_data = ucode->code;
/* copy the firmware version */
memcpy(&ndev->hw.fw_name[0][0], ucode->version, (VERSION_LEN - 2));
ndev->hw.fw_name[0][VERSION_LEN - 1] = '\0';
/* Load SE Firmware on UCD Block 0 */
write_to_ucd_unit(ndev, ucode_size, ucode_data, 0);
release_firmware(fw);
/* put all SE cores in DEFAULT_SE_GROUP */
offset = POM_GRP_EXECMASKX(DEFAULT_SE_GROUP);
nitrox_write_csr(ndev, offset, (~0ULL));
/* write block number and firmware length
* bit:<2:0> block number
* bit:3 is set SE uses 32KB microcode
* bit:3 is clear SE uses 64KB microcode
*/
core_2_eid_val.value = 0ULL;
core_2_eid_val.ucode_blk = 0;
if (ucode_size <= CNN55XX_UCD_BLOCK_SIZE)
core_2_eid_val.ucode_len = 1;
else
core_2_eid_val.ucode_len = 0;
for (i = 0; i < ndev->hw.se_cores; i++) {
offset = UCD_SE_EID_UCODE_BLOCK_NUMX(i);
nitrox_write_csr(ndev, offset, core_2_eid_val.value);
}
fw_name = AE_FW;
dev_info(DEV(ndev), "Loading firmware \"%s\"\n", fw_name);
ret = request_firmware(&fw, fw_name, DEV(ndev));
if (ret < 0) {
dev_err(DEV(ndev), "failed to get firmware %s\n", fw_name);
return ret;
}
ucode = (struct ucode *)fw->data;
ucode_size = be32_to_cpu(ucode->code_size) * 2;
if (!ucode_size || ucode_size > CNN55XX_MAX_UCODE_SIZE) {
dev_err(DEV(ndev), "Invalid ucode size: %u for firmware %s\n",
ucode_size, fw_name);
release_firmware(fw);
return -EINVAL;
}
ucode_data = ucode->code;
/* copy the firmware version */
memcpy(&ndev->hw.fw_name[1][0], ucode->version, (VERSION_LEN - 2));
ndev->hw.fw_name[1][VERSION_LEN - 1] = '\0';
/* Load AE Firmware on UCD Block 2 */
write_to_ucd_unit(ndev, ucode_size, ucode_data, 2);
release_firmware(fw);
/* put all AE cores in DEFAULT_AE_GROUP */
offset = AQM_GRP_EXECMSK_LOX(DEFAULT_AE_GROUP);
aqm_grp_execmask_lo.exec_0_to_39 = 0xFFFFFFFFFFULL;
nitrox_write_csr(ndev, offset, aqm_grp_execmask_lo.value);
offset = AQM_GRP_EXECMSK_HIX(DEFAULT_AE_GROUP);
aqm_grp_execmask_hi.exec_40_to_79 = 0xFFFFFFFFFFULL;
nitrox_write_csr(ndev, offset, aqm_grp_execmask_hi.value);
/* write block number and firmware length
* bit:<2:0> block number
* bit:3 is set SE uses 32KB microcode
* bit:3 is clear SE uses 64KB microcode
*/
core_2_eid_val.value = 0ULL;
core_2_eid_val.ucode_blk = 0;
if (ucode_size <= CNN55XX_UCD_BLOCK_SIZE)
core_2_eid_val.ucode_len = 1;
else
core_2_eid_val.ucode_len = 0;
for (i = 0; i < ndev->hw.ae_cores; i++) {
offset = UCD_AE_EID_UCODE_BLOCK_NUMX(i);
nitrox_write_csr(ndev, offset, core_2_eid_val.value);
}
return 0;
}
@ -309,8 +397,8 @@ static int nitrox_pf_hw_init(struct nitrox_device *ndev)
nitrox_config_lbc_unit(ndev);
nitrox_config_rand_unit(ndev);
/* load firmware on SE cores */
err = nitrox_load_fw(ndev, SE_FW);
/* load firmware on cores */
err = nitrox_load_fw(ndev);
if (err)
return err;