crypto: caam - enable instantiation of all RNG4 state handles

RNG4 block contains multiple (i.e. 2) state handles that can be
initialized. This patch adds the necessary code for detecting
which of the two state handles has been instantiated by another
piece of software e.g. u-boot and instantiate the other one (or
both if none was instantiated). Only the state handle(s)
instantiated by this driver will be deinstantiated when removing
the module.

Signed-off-by: Alex Porosanu <alexandru.porosanu@freescale.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
Alex Porosanu 2013-09-09 18:56:34 +03:00 committed by Herbert Xu
parent f1157a5bf3
commit 1005bccd7a
3 changed files with 167 additions and 50 deletions

View File

@ -17,15 +17,22 @@
* Descriptor to instantiate RNG State Handle 0 in normal mode and * Descriptor to instantiate RNG State Handle 0 in normal mode and
* load the JDKEK, TDKEK and TDSK registers * load the JDKEK, TDKEK and TDSK registers
*/ */
static void build_instantiation_desc(u32 *desc) static void build_instantiation_desc(u32 *desc, int handle, int do_sk)
{ {
u32 *jump_cmd; u32 *jump_cmd, op_flags;
init_job_desc(desc, 0); init_job_desc(desc, 0);
op_flags = OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
(handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INIT;
/* INIT RNG in non-test mode */ /* INIT RNG in non-test mode */
append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | append_operation(desc, op_flags);
OP_ALG_AS_INIT);
if (!handle && do_sk) {
/*
* For SH0, Secure Keys must be generated as well
*/
/* wait for done */ /* wait for done */
jump_cmd = append_jump(desc, JUMP_CLASS_CLASS1); jump_cmd = append_jump(desc, JUMP_CLASS_CLASS1);
@ -33,25 +40,26 @@ static void build_instantiation_desc(u32 *desc)
/* /*
* load 1 to clear written reg: * load 1 to clear written reg:
* resets the done interrupt and returns the RNG to idle. * resets the done interrrupt and returns the RNG to idle.
*/ */
append_load_imm_u32(desc, 1, LDST_SRCDST_WORD_CLRW); append_load_imm_u32(desc, 1, LDST_SRCDST_WORD_CLRW);
/* generate secure keys (non-test) */ /* Initialize State Handle */
append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
OP_ALG_AAI_RNG4_SK); OP_ALG_AAI_RNG4_SK);
}
append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TYPE_HALT); append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TYPE_HALT);
} }
/* Descriptor for deinstantiation of State Handle 0 of the RNG block. */ /* Descriptor for deinstantiation of State Handle 0 of the RNG block. */
static void build_deinstantiation_desc(u32 *desc) static void build_deinstantiation_desc(u32 *desc, int handle)
{ {
init_job_desc(desc, 0); init_job_desc(desc, 0);
/* Uninstantiate State Handle 0 */ /* Uninstantiate State Handle 0 */
append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
OP_ALG_AS_INITFINAL); (handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INITFINAL);
append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TYPE_HALT); append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TYPE_HALT);
} }
@ -60,11 +68,14 @@ static void build_deinstantiation_desc(u32 *desc)
* run_descriptor_deco0 - runs a descriptor on DECO0, under direct control of * run_descriptor_deco0 - runs a descriptor on DECO0, under direct control of
* the software (no JR/QI used). * the software (no JR/QI used).
* @ctrldev - pointer to device * @ctrldev - pointer to device
* @status - descriptor status, after being run
*
* Return: - 0 if no error occurred * Return: - 0 if no error occurred
* - -ENODEV if the DECO couldn't be acquired * - -ENODEV if the DECO couldn't be acquired
* - -EAGAIN if an error occurred while executing the descriptor * - -EAGAIN if an error occurred while executing the descriptor
*/ */
static inline int run_descriptor_deco0(struct device *ctrldev, u32 *desc) static inline int run_descriptor_deco0(struct device *ctrldev, u32 *desc,
u32 *status)
{ {
struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev);
struct caam_full __iomem *topregs; struct caam_full __iomem *topregs;
@ -113,6 +124,9 @@ static inline int run_descriptor_deco0(struct device *ctrldev, u32 *desc)
cpu_relax(); cpu_relax();
} while ((deco_dbg_reg & DESC_DBG_DECO_STAT_VALID) && --timeout); } while ((deco_dbg_reg & DESC_DBG_DECO_STAT_VALID) && --timeout);
*status = rd_reg32(&topregs->deco.op_status_hi) &
DECO_OP_STATUS_HI_ERR_MASK;
/* Mark the DECO as free */ /* Mark the DECO as free */
clrbits32(&topregs->ctrl.deco_rq, DECORR_RQD0ENABLE); clrbits32(&topregs->ctrl.deco_rq, DECORR_RQD0ENABLE);
@ -126,6 +140,14 @@ static inline int run_descriptor_deco0(struct device *ctrldev, u32 *desc)
* instantiate_rng - builds and executes a descriptor on DECO0, * instantiate_rng - builds and executes a descriptor on DECO0,
* which initializes the RNG block. * which initializes the RNG block.
* @ctrldev - pointer to device * @ctrldev - pointer to device
* @state_handle_mask - bitmask containing the instantiation status
* for the RNG4 state handles which exist in
* the RNG4 block: 1 if it's been instantiated
* by an external entry, 0 otherwise.
* @gen_sk - generate data to be loaded into the JDKEK, TDKEK and TDSK;
* Caution: this can be done only once; if the keys need to be
* regenerated, a POR is required
*
* Return: - 0 if no error occurred * Return: - 0 if no error occurred
* - -ENOMEM if there isn't enough memory to allocate the descriptor * - -ENOMEM if there isn't enough memory to allocate the descriptor
* - -ENODEV if DECO0 couldn't be acquired * - -ENODEV if DECO0 couldn't be acquired
@ -133,19 +155,56 @@ static inline int run_descriptor_deco0(struct device *ctrldev, u32 *desc)
* f.i. there was a RNG hardware error due to not "good enough" * f.i. there was a RNG hardware error due to not "good enough"
* entropy being aquired. * entropy being aquired.
*/ */
static int instantiate_rng(struct device *ctrldev) static int instantiate_rng(struct device *ctrldev, int state_handle_mask,
int gen_sk)
{ {
u32 *desc; struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev);
int ret = 0; struct caam_full __iomem *topregs;
struct rng4tst __iomem *r4tst;
u32 *desc, status, rdsta_val;
int ret = 0, sh_idx;
topregs = (struct caam_full __iomem *)ctrlpriv->ctrl;
r4tst = &topregs->ctrl.r4tst[0];
desc = kmalloc(CAAM_CMD_SZ * 7, GFP_KERNEL); desc = kmalloc(CAAM_CMD_SZ * 7, GFP_KERNEL);
if (!desc) if (!desc)
return -ENOMEM; return -ENOMEM;
/* Create the descriptor for instantiating RNG State Handle 0 */
build_instantiation_desc(desc); for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) {
/*
* If the corresponding bit is set, this state handle
* was initialized by somebody else, so it's left alone.
*/
if ((1 << sh_idx) & state_handle_mask)
continue;
/* Create the descriptor for instantiating RNG State Handle */
build_instantiation_desc(desc, sh_idx, gen_sk);
/* Try to run it through DECO0 */ /* Try to run it through DECO0 */
ret = run_descriptor_deco0(ctrldev, desc); ret = run_descriptor_deco0(ctrldev, desc, &status);
/*
* If ret is not 0, or descriptor status is not 0, then
* something went wrong. No need to try the next state
* handle (if available), bail out here.
* Also, if for some reason, the State Handle didn't get
* instantiated although the descriptor has finished
* without any error (HW optimizations for later
* CAAM eras), then try again.
*/
rdsta_val =
rd_reg32(&topregs->ctrl.r4tst[0].rdsta) & RDSTA_IFMASK;
if (status || !(rdsta_val & (1 << sh_idx)))
ret = -EAGAIN;
if (ret)
break;
dev_info(ctrldev, "Instantiated RNG4 SH%d\n", sh_idx);
/* Clear the contents before recreating the descriptor */
memset(desc, 0x00, CAAM_CMD_SZ * 7);
}
kfree(desc); kfree(desc);
@ -156,29 +215,49 @@ static int instantiate_rng(struct device *ctrldev)
* deinstantiate_rng - builds and executes a descriptor on DECO0, * deinstantiate_rng - builds and executes a descriptor on DECO0,
* which deinitializes the RNG block. * which deinitializes the RNG block.
* @ctrldev - pointer to device * @ctrldev - pointer to device
* @state_handle_mask - bitmask containing the instantiation status
* for the RNG4 state handles which exist in
* the RNG4 block: 1 if it's been instantiated
* *
* Return: - 0 if no error occurred * Return: - 0 if no error occurred
* - -ENOMEM if there isn't enough memory to allocate the descriptor * - -ENOMEM if there isn't enough memory to allocate the descriptor
* - -ENODEV if DECO0 couldn't be acquired * - -ENODEV if DECO0 couldn't be acquired
* - -EAGAIN if an error occurred when executing the descriptor * - -EAGAIN if an error occurred when executing the descriptor
*/ */
static int deinstantiate_rng(struct device *ctrldev) static int deinstantiate_rng(struct device *ctrldev, int state_handle_mask)
{ {
u32 *desc; u32 *desc, status;
int i, ret = 0; int sh_idx, ret = 0;
desc = kmalloc(CAAM_CMD_SZ * 3, GFP_KERNEL); desc = kmalloc(CAAM_CMD_SZ * 3, GFP_KERNEL);
if (!desc) if (!desc)
return -ENOMEM; return -ENOMEM;
/* Create the descriptor for deinstantating RNG State Handle 0 */ for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) {
build_deinstantiation_desc(desc); /*
* If the corresponding bit is set, then it means the state
* handle was initialized by us, and thus it needs to be
* deintialized as well
*/
if ((1 << sh_idx) & state_handle_mask) {
/*
* Create the descriptor for deinstantating this state
* handle
*/
build_deinstantiation_desc(desc, sh_idx);
/* Try to run it through DECO0 */ /* Try to run it through DECO0 */
ret = run_descriptor_deco0(ctrldev, desc); ret = run_descriptor_deco0(ctrldev, desc, &status);
if (ret) if (ret || status) {
dev_err(ctrldev, "failed to deinstantiate RNG\n"); dev_err(ctrldev,
"Failed to deinstantiate RNG4 SH%d\n",
sh_idx);
break;
}
dev_info(ctrldev, "Deinstantiated RNG4 SH%d\n", sh_idx);
}
}
kfree(desc); kfree(desc);
@ -204,9 +283,9 @@ static int caam_remove(struct platform_device *pdev)
irq_dispose_mapping(jrpriv->irq); irq_dispose_mapping(jrpriv->irq);
} }
/* De-initialize RNG if it was initialized by this driver. */ /* De-initialize RNG state handles initialized by this driver. */
if (ctrlpriv->rng4_init) if (ctrlpriv->rng4_sh_init)
deinstantiate_rng(ctrldev); deinstantiate_rng(ctrldev, ctrlpriv->rng4_sh_init);
/* Shut down debug views */ /* Shut down debug views */
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
@ -306,7 +385,7 @@ EXPORT_SYMBOL(caam_get_era);
/* Probe routine for CAAM top (controller) level */ /* Probe routine for CAAM top (controller) level */
static int caam_probe(struct platform_device *pdev) static int caam_probe(struct platform_device *pdev)
{ {
int ret, ring, rspec, ent_delay = RTSDCTL_ENT_DLY_MIN; int ret, ring, rspec, gen_sk, ent_delay = RTSDCTL_ENT_DLY_MIN;
u64 caam_id; u64 caam_id;
struct device *dev; struct device *dev;
struct device_node *nprop, *np; struct device_node *nprop, *np;
@ -414,20 +493,53 @@ static int caam_probe(struct platform_device *pdev)
* If SEC has RNG version >= 4 and RNG state handle has not been * If SEC has RNG version >= 4 and RNG state handle has not been
* already instantiated, do RNG instantiation * already instantiated, do RNG instantiation
*/ */
if ((cha_vid & CHA_ID_RNG_MASK) >> CHA_ID_RNG_SHIFT >= 4 && if ((cha_vid & CHA_ID_RNG_MASK) >> CHA_ID_RNG_SHIFT >= 4) {
!(rd_reg32(&topregs->ctrl.r4tst[0].rdsta) & RDSTA_IF0)) { ctrlpriv->rng4_sh_init =
rd_reg32(&topregs->ctrl.r4tst[0].rdsta);
/*
* If the secure keys (TDKEK, JDKEK, TDSK), were already
* generated, signal this to the function that is instantiating
* the state handles. An error would occur if RNG4 attempts
* to regenerate these keys before the next POR.
*/
gen_sk = ctrlpriv->rng4_sh_init & RDSTA_SKVN ? 0 : 1;
ctrlpriv->rng4_sh_init &= RDSTA_IFMASK;
do { do {
int inst_handles =
rd_reg32(&topregs->ctrl.r4tst[0].rdsta) &
RDSTA_IFMASK;
/*
* If either SH were instantiated by somebody else
* (e.g. u-boot) then it is assumed that the entropy
* parameters are properly set and thus the function
* setting these (kick_trng(...)) is skipped.
* Also, if a handle was instantiated, do not change
* the TRNG parameters.
*/
if (!(ctrlpriv->rng4_sh_init || inst_handles)) {
kick_trng(pdev, ent_delay); kick_trng(pdev, ent_delay);
ret = instantiate_rng(dev);
ent_delay += 400; ent_delay += 400;
}
/*
* if instantiate_rng(...) fails, the loop will rerun
* and the kick_trng(...) function will modfiy the
* upper and lower limits of the entropy sampling
* interval, leading to a sucessful initialization of
* the RNG.
*/
ret = instantiate_rng(dev, inst_handles,
gen_sk);
} while ((ret == -EAGAIN) && (ent_delay < RTSDCTL_ENT_DLY_MAX)); } while ((ret == -EAGAIN) && (ent_delay < RTSDCTL_ENT_DLY_MAX));
if (ret) { if (ret) {
dev_err(dev, "failed to instantiate RNG"); dev_err(dev, "failed to instantiate RNG");
caam_remove(pdev); caam_remove(pdev);
return ret; return ret;
} }
/*
ctrlpriv->rng4_init = 1; * Set handles init'ed by this module as the complement of the
* already initialized ones
*/
ctrlpriv->rng4_sh_init = ~ctrlpriv->rng4_sh_init & RDSTA_IFMASK;
/* Enable RDB bit so that RNG works faster */ /* Enable RDB bit so that RNG works faster */
setbits32(&topregs->ctrl.scfgr, SCFGR_RDBENABLE); setbits32(&topregs->ctrl.scfgr, SCFGR_RDBENABLE);

View File

@ -87,11 +87,11 @@ struct caam_drv_private {
/* list of registered hash algorithms (mk generic context handle?) */ /* list of registered hash algorithms (mk generic context handle?) */
struct list_head hash_list; struct list_head hash_list;
#define RNG4_MAX_HANDLES 2
/* RNG4 block */ /* RNG4 block */
bool rng4_init; /* If RNG4 block is initialized by this driver, u32 rng4_sh_init; /* This bitmap shows which of the State
then this will be set; if it was initialized Handles of the RNG4 block are initialized
by another entity (e.g. u-boot), it will be by this driver */
cleared. */
/* /*
* debugfs entries for developer view into driver/device * debugfs entries for developer view into driver/device

View File

@ -268,7 +268,11 @@ struct rng4tst {
u32 rtfrqcnt; /* PRGM=0: freq. count register */ u32 rtfrqcnt; /* PRGM=0: freq. count register */
}; };
u32 rsvd1[40]; u32 rsvd1[40];
#define RDSTA_SKVT 0x80000000
#define RDSTA_SKVN 0x40000000
#define RDSTA_IF0 0x00000001 #define RDSTA_IF0 0x00000001
#define RDSTA_IF1 0x00000002
#define RDSTA_IFMASK (RDSTA_IF1 | RDSTA_IF0)
u32 rdsta; u32 rdsta;
u32 rsvd2[15]; u32 rsvd2[15];
}; };
@ -694,6 +698,7 @@ struct caam_deco {
u32 jr_ctl_hi; /* CxJRR - JobR Control Register @800 */ u32 jr_ctl_hi; /* CxJRR - JobR Control Register @800 */
u32 jr_ctl_lo; u32 jr_ctl_lo;
u64 jr_descaddr; /* CxDADR - JobR Descriptor Address */ u64 jr_descaddr; /* CxDADR - JobR Descriptor Address */
#define DECO_OP_STATUS_HI_ERR_MASK 0xF00000FF
u32 op_status_hi; /* DxOPSTA - DECO Operation Status */ u32 op_status_hi; /* DxOPSTA - DECO Operation Status */
u32 op_status_lo; u32 op_status_lo;
u32 rsvd24[2]; u32 rsvd24[2];