1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (C) 2012-2019 ARM Limited (or its affiliates). */ 3 4 #include <linux/kernel.h> 5 #include <linux/fips.h> 6 7 #include "cc_driver.h" 8 #include "cc_fips.h" 9 10 static void fips_dsr(unsigned long devarg); 11 12 struct cc_fips_handle { 13 struct tasklet_struct tasklet; 14 }; 15 16 /* The function called once at driver entry point to check 17 * whether TEE FIPS error occurred. 18 */ 19 static bool cc_get_tee_fips_status(struct cc_drvdata *drvdata) 20 { 21 u32 reg; 22 23 reg = cc_ioread(drvdata, CC_REG(GPR_HOST)); 24 /* Did the TEE report status? */ 25 if (reg & CC_FIPS_SYNC_TEE_STATUS) 26 /* Yes. Is it OK? */ 27 return (reg & CC_FIPS_SYNC_MODULE_OK); 28 29 /* No. It's either not in use or will be reported later */ 30 return true; 31 } 32 33 /* 34 * This function should push the FIPS REE library status towards the TEE library 35 * by writing the error state to HOST_GPR0 register. 36 */ 37 void cc_set_ree_fips_status(struct cc_drvdata *drvdata, bool status) 38 { 39 int val = CC_FIPS_SYNC_REE_STATUS; 40 41 if (drvdata->hw_rev < CC_HW_REV_712) 42 return; 43 44 val |= (status ? CC_FIPS_SYNC_MODULE_OK : CC_FIPS_SYNC_MODULE_ERROR); 45 46 cc_iowrite(drvdata, CC_REG(HOST_GPR0), val); 47 } 48 49 void cc_fips_fini(struct cc_drvdata *drvdata) 50 { 51 struct cc_fips_handle *fips_h = drvdata->fips_handle; 52 53 if (drvdata->hw_rev < CC_HW_REV_712 || !fips_h) 54 return; 55 56 /* Kill tasklet */ 57 tasklet_kill(&fips_h->tasklet); 58 drvdata->fips_handle = NULL; 59 } 60 61 void fips_handler(struct cc_drvdata *drvdata) 62 { 63 struct cc_fips_handle *fips_handle_ptr = drvdata->fips_handle; 64 65 if (drvdata->hw_rev < CC_HW_REV_712) 66 return; 67 68 tasklet_schedule(&fips_handle_ptr->tasklet); 69 } 70 71 static inline void tee_fips_error(struct device *dev) 72 { 73 if (fips_enabled) 74 panic("ccree: TEE reported cryptographic error in fips mode!\n"); 75 else 76 dev_err(dev, "TEE reported error!\n"); 77 } 78 79 /* 80 * This function check if cryptocell tee fips error occurred 81 * and in such case triggers system error 82 */ 83 void cc_tee_handle_fips_error(struct cc_drvdata *p_drvdata) 84 { 85 struct device *dev = drvdata_to_dev(p_drvdata); 86 87 if (!cc_get_tee_fips_status(p_drvdata)) 88 tee_fips_error(dev); 89 } 90 91 /* Deferred service handler, run as interrupt-fired tasklet */ 92 static void fips_dsr(unsigned long devarg) 93 { 94 struct cc_drvdata *drvdata = (struct cc_drvdata *)devarg; 95 u32 irq, val; 96 97 irq = (drvdata->irq & (CC_GPR0_IRQ_MASK)); 98 99 if (irq) { 100 cc_tee_handle_fips_error(drvdata); 101 } 102 103 /* after verifing that there is nothing to do, 104 * unmask AXI completion interrupt. 105 */ 106 val = (CC_REG(HOST_IMR) & ~irq); 107 cc_iowrite(drvdata, CC_REG(HOST_IMR), val); 108 } 109 110 /* The function called once at driver entry point .*/ 111 int cc_fips_init(struct cc_drvdata *p_drvdata) 112 { 113 struct cc_fips_handle *fips_h; 114 struct device *dev = drvdata_to_dev(p_drvdata); 115 116 if (p_drvdata->hw_rev < CC_HW_REV_712) 117 return 0; 118 119 fips_h = devm_kzalloc(dev, sizeof(*fips_h), GFP_KERNEL); 120 if (!fips_h) 121 return -ENOMEM; 122 123 p_drvdata->fips_handle = fips_h; 124 125 dev_dbg(dev, "Initializing fips tasklet\n"); 126 tasklet_init(&fips_h->tasklet, fips_dsr, (unsigned long)p_drvdata); 127 128 cc_tee_handle_fips_error(p_drvdata); 129 130 return 0; 131 } 132