mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-24 02:01:36 +03:00
crypto: tegra: Add Tegra SE driver for T264
Add Tegra Security Engine driver which supports AES-ECB/CBC/CTR/XTS SHA1/SHA2/SHA3 AES-GCM, AES CCM, SM4, SM3 algorithms. Signed-off-by: Akhil R <akhilrajeev@nvidia.com> Change-Id: I86be2fcc485c31988496395183cb44a386907668
This commit is contained in:
@@ -59,7 +59,7 @@ static unsigned int tegra_key_prep_ins_cmd(struct tegra_se *se, u32 *cpuvaddr,
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->manifest);
|
||||
cpuvaddr[i++] = se->manifest(se->owner, alg, keylen);
|
||||
cpuvaddr[i++] = se->regcfg->manifest(se->owner, alg, keylen);
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->key_dst);
|
||||
|
||||
@@ -91,7 +91,69 @@ static unsigned int tegra_key_prep_ins_cmd(struct tegra_se *se, u32 *cpuvaddr,
|
||||
host1x_uclass_incr_syncpt_indx_f(se->syncpt_id);
|
||||
|
||||
dev_dbg(se->dev, "key-slot %u key-manifest %#x\n",
|
||||
slot, se->manifest(se->owner, alg, keylen));
|
||||
slot, se->regcfg->manifest(se->owner, alg, keylen));
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static unsigned int tegra_key_prep_mov_cmd(struct tegra_se *se, u32 *cpuvaddr,
|
||||
u32 src_keyid, u32 tgt_keyid)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->op);
|
||||
cpuvaddr[i++] = SE_AES_OP_WRSTALL | SE_AES_OP_DUMMY;
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(2);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->src_kslt);
|
||||
cpuvaddr[i++] = src_keyid;
|
||||
cpuvaddr[i++] = tgt_keyid;
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->config);
|
||||
cpuvaddr[i++] = SE_CFG_MOV;
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->op);
|
||||
cpuvaddr[i++] = SE_AES_OP_WRSTALL | SE_AES_OP_START |
|
||||
SE_AES_OP_LASTBUF;
|
||||
|
||||
cpuvaddr[i++] = se_host1x_opcode_nonincr(host1x_uclass_incr_syncpt_r(), 1);
|
||||
cpuvaddr[i++] = host1x_uclass_incr_syncpt_cond_f(1) |
|
||||
host1x_uclass_incr_syncpt_indx_f(se->syncpt_id);
|
||||
|
||||
dev_dbg(se->dev, "keymov: src keyid %u target keyid %u\n", src_keyid, tgt_keyid);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static unsigned int tegra_key_prep_invld_cmd(struct tegra_se *se, u32 *cpuvaddr, u32 keyid)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->op);
|
||||
cpuvaddr[i++] = SE_AES_OP_WRSTALL | SE_AES_OP_DUMMY;
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->tgt_kslt);
|
||||
cpuvaddr[i++] = keyid;
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->config);
|
||||
cpuvaddr[i++] = SE_CFG_INVLD;
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->op);
|
||||
cpuvaddr[i++] = SE_AES_OP_WRSTALL | SE_AES_OP_START |
|
||||
SE_AES_OP_LASTBUF;
|
||||
|
||||
cpuvaddr[i++] = se_host1x_opcode_nonincr(host1x_uclass_incr_syncpt_r(), 1);
|
||||
cpuvaddr[i++] = host1x_uclass_incr_syncpt_cond_f(1) |
|
||||
host1x_uclass_incr_syncpt_indx_f(se->syncpt_id);
|
||||
|
||||
dev_dbg(se->dev, "invalidate keyid %u\n", keyid);
|
||||
|
||||
return i;
|
||||
}
|
||||
@@ -122,6 +184,64 @@ static int tegra_key_insert(struct tegra_se *se, const u8 *key,
|
||||
return tegra_se_host1x_submit(se, size);
|
||||
}
|
||||
|
||||
static int tegra_key_move_to_kds(struct tegra_se *se, u32 slot, u32 kds_id)
|
||||
{
|
||||
u32 src_keyid, size;
|
||||
int ret;
|
||||
|
||||
src_keyid = SE_KSLT_REGION_ID_SYM | slot;
|
||||
size = tegra_key_prep_mov_cmd(se, se->cmdbuf->addr, src_keyid, kds_id);
|
||||
|
||||
ret = tegra_se_host1x_submit(se, size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int tegra_kac_get_from_kds(struct tegra_se *se, u32 keyid, u16 slot)
|
||||
{
|
||||
u32 tgt_keyid, size;
|
||||
int ret;
|
||||
|
||||
tgt_keyid = SE_KSLT_REGION_ID_SYM | slot;
|
||||
size = tegra_key_prep_mov_cmd(se, se->cmdbuf->addr, keyid, tgt_keyid);
|
||||
|
||||
ret = tegra_se_host1x_submit(se, size);
|
||||
if (ret)
|
||||
tegra_keyslot_free(slot);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void tegra_key_kds_invalidate(struct tegra_se *se, u32 keyid)
|
||||
{
|
||||
unsigned int size;
|
||||
|
||||
size = tegra_key_prep_invld_cmd(se, se->cmdbuf->addr, keyid);
|
||||
tegra_se_host1x_submit(se, size);
|
||||
tegra_kds_free_id(keyid);
|
||||
}
|
||||
|
||||
unsigned int tegra_key_get_idx(struct tegra_se *se, u32 keyid)
|
||||
{
|
||||
u16 slot;
|
||||
|
||||
if (tegra_key_in_kslt(keyid))
|
||||
return keyid;
|
||||
|
||||
if (!tegra_key_in_kds(keyid))
|
||||
return 0;
|
||||
|
||||
slot = tegra_keyslot_alloc();
|
||||
if (!slot)
|
||||
return 0;
|
||||
|
||||
tegra_kac_get_from_kds(se, keyid, slot);
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
void tegra_key_invalidate(struct tegra_se *se, u32 keyid, u32 alg)
|
||||
{
|
||||
u8 zkey[AES_MAX_KEY_SIZE] = {0};
|
||||
@@ -129,14 +249,17 @@ void tegra_key_invalidate(struct tegra_se *se, u32 keyid, u32 alg)
|
||||
if (!keyid)
|
||||
return;
|
||||
|
||||
/* Overwrite the key with 0s */
|
||||
tegra_key_insert(se, zkey, AES_MAX_KEY_SIZE, keyid, alg);
|
||||
|
||||
tegra_keyslot_free(keyid);
|
||||
if (tegra_key_in_kds(keyid)) {
|
||||
tegra_key_kds_invalidate(se, keyid);
|
||||
} else {
|
||||
tegra_key_insert(se, zkey, AES_MAX_KEY_SIZE, keyid, alg);
|
||||
tegra_keyslot_free(keyid);
|
||||
}
|
||||
}
|
||||
|
||||
int tegra_key_submit(struct tegra_se *se, const u8 *key, u32 keylen, u32 alg, u32 *keyid)
|
||||
{
|
||||
u32 kds_id, orig_id = *keyid;
|
||||
int ret;
|
||||
|
||||
/* Use the existing slot if it is already allocated */
|
||||
@@ -152,5 +275,36 @@ int tegra_key_submit(struct tegra_se *se, const u8 *key, u32 keylen, u32 alg, u3
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!se->hw->support_kds)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Move the key to KDS and free the slot if HW supports.
|
||||
* The key will have to be brought back to local KSLT for any task.
|
||||
*/
|
||||
|
||||
/* If it is a valid key, invalidate it */
|
||||
if (tegra_key_in_kds(orig_id))
|
||||
tegra_key_kds_invalidate(se, orig_id);
|
||||
|
||||
kds_id = tegra_kds_get_id();
|
||||
if (!kds_id) {
|
||||
/* Not a fatal error. Key can still reside in KSLT */
|
||||
dev_err(se->dev, "Failed to get KDS slot.The key is in local key slot\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = tegra_key_move_to_kds(se, *keyid, kds_id);
|
||||
if (ret) {
|
||||
/* Not a fatal error. Key can still reside in KSLT */
|
||||
dev_err(se->dev, "Failed to move key to KDS. The key is in local key slot\n");
|
||||
tegra_kds_free_id(kds_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Free the local keyslot. */
|
||||
tegra_key_invalidate(se, *keyid, alg);
|
||||
*keyid = kds_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user