1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2012-2019 ARM Limited (or its affiliates). */
4 #include <linux/kernel.h>
5 #include <linux/fips.h>
6 #include <linux/notifier.h>
11 static void fips_dsr(unsigned long devarg
);
13 struct cc_fips_handle
{
14 struct tasklet_struct tasklet
;
15 struct notifier_block nb
;
16 struct cc_drvdata
*drvdata
;
19 /* The function called once at driver entry point to check
20 * whether TEE FIPS error occurred.
22 static bool cc_get_tee_fips_status(struct cc_drvdata
*drvdata
)
26 reg
= cc_ioread(drvdata
, CC_REG(GPR_HOST
));
27 /* Did the TEE report status? */
28 if (reg
& CC_FIPS_SYNC_TEE_STATUS
)
30 return (reg
& CC_FIPS_SYNC_MODULE_OK
);
32 /* No. It's either not in use or will be reported later */
37 * This function should push the FIPS REE library status towards the TEE library
38 * by writing the error state to HOST_GPR0 register.
40 void cc_set_ree_fips_status(struct cc_drvdata
*drvdata
, bool status
)
42 int val
= CC_FIPS_SYNC_REE_STATUS
;
44 if (drvdata
->hw_rev
< CC_HW_REV_712
)
47 val
|= (status
? CC_FIPS_SYNC_MODULE_OK
: CC_FIPS_SYNC_MODULE_ERROR
);
49 cc_iowrite(drvdata
, CC_REG(HOST_GPR0
), val
);
52 /* Push REE side FIPS test failure to TEE side */
53 static int cc_ree_fips_failure(struct notifier_block
*nb
, unsigned long unused1
,
56 struct cc_fips_handle
*fips_h
=
57 container_of(nb
, struct cc_fips_handle
, nb
);
58 struct cc_drvdata
*drvdata
= fips_h
->drvdata
;
59 struct device
*dev
= drvdata_to_dev(drvdata
);
61 cc_set_ree_fips_status(drvdata
, false);
62 dev_info(dev
, "Notifying TEE of FIPS test failure...\n");
67 void cc_fips_fini(struct cc_drvdata
*drvdata
)
69 struct cc_fips_handle
*fips_h
= drvdata
->fips_handle
;
71 if (drvdata
->hw_rev
< CC_HW_REV_712
|| !fips_h
)
74 atomic_notifier_chain_unregister(&fips_fail_notif_chain
, &fips_h
->nb
);
77 tasklet_kill(&fips_h
->tasklet
);
78 drvdata
->fips_handle
= NULL
;
81 void fips_handler(struct cc_drvdata
*drvdata
)
83 struct cc_fips_handle
*fips_handle_ptr
= drvdata
->fips_handle
;
85 if (drvdata
->hw_rev
< CC_HW_REV_712
)
88 tasklet_schedule(&fips_handle_ptr
->tasklet
);
91 static inline void tee_fips_error(struct device
*dev
)
94 panic("ccree: TEE reported cryptographic error in fips mode!\n");
96 dev_err(dev
, "TEE reported error!\n");
100 * This function check if cryptocell tee fips error occurred
101 * and in such case triggers system error
103 void cc_tee_handle_fips_error(struct cc_drvdata
*p_drvdata
)
105 struct device
*dev
= drvdata_to_dev(p_drvdata
);
107 if (!cc_get_tee_fips_status(p_drvdata
))
111 /* Deferred service handler, run as interrupt-fired tasklet */
112 static void fips_dsr(unsigned long devarg
)
114 struct cc_drvdata
*drvdata
= (struct cc_drvdata
*)devarg
;
117 irq
= (drvdata
->irq
& (CC_GPR0_IRQ_MASK
));
120 cc_tee_handle_fips_error(drvdata
);
123 /* after verifying that there is nothing to do,
124 * unmask AXI completion interrupt.
126 val
= (CC_REG(HOST_IMR
) & ~irq
);
127 cc_iowrite(drvdata
, CC_REG(HOST_IMR
), val
);
130 /* The function called once at driver entry point .*/
131 int cc_fips_init(struct cc_drvdata
*p_drvdata
)
133 struct cc_fips_handle
*fips_h
;
134 struct device
*dev
= drvdata_to_dev(p_drvdata
);
136 if (p_drvdata
->hw_rev
< CC_HW_REV_712
)
139 fips_h
= devm_kzalloc(dev
, sizeof(*fips_h
), GFP_KERNEL
);
143 p_drvdata
->fips_handle
= fips_h
;
145 dev_dbg(dev
, "Initializing fips tasklet\n");
146 tasklet_init(&fips_h
->tasklet
, fips_dsr
, (unsigned long)p_drvdata
);
147 fips_h
->drvdata
= p_drvdata
;
148 fips_h
->nb
.notifier_call
= cc_ree_fips_failure
;
149 atomic_notifier_chain_register(&fips_fail_notif_chain
, &fips_h
->nb
);
151 cc_tee_handle_fips_error(p_drvdata
);