diff options
Diffstat (limited to 'drivers/staging/ccree/ssi_fips.c')
-rw-r--r-- | drivers/staging/ccree/ssi_fips.c | 119 |
1 files changed, 93 insertions, 26 deletions
diff --git a/drivers/staging/ccree/ssi_fips.c b/drivers/staging/ccree/ssi_fips.c index fdc40f38332a..33d53d64603d 100644 --- a/drivers/staging/ccree/ssi_fips.c +++ b/drivers/staging/ccree/ssi_fips.c @@ -14,48 +14,115 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ -/************************************************************** - * This file defines the driver FIPS APIs * - **************************************************************/ +#include <linux/kernel.h> +#include <linux/fips.h> -#include <linux/module.h> +#include "ssi_config.h" +#include "ssi_driver.h" +#include "cc_hal.h" #include "ssi_fips.h" -extern int ssi_fips_ext_get_state(enum cc_fips_state_t *p_state); -extern int ssi_fips_ext_get_error(enum cc_fips_error *p_err); +static void fips_dsr(unsigned long devarg); + +struct ssi_fips_handle { + struct tasklet_struct tasklet; +}; + +/* The function called once at driver entry point to check + * whether TEE FIPS error occurred. + */ +static bool cc_get_tee_fips_status(struct ssi_drvdata *drvdata) +{ + u32 reg; + void __iomem *cc_base = drvdata->cc_base; + + reg = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, GPR_HOST)); + return (reg == (CC_FIPS_SYNC_TEE_STATUS | CC_FIPS_SYNC_MODULE_OK)); +} /* - * This function returns the REE FIPS state. - * It should be called by kernel module. + * This function should push the FIPS REE library status towards the TEE library + * by writing the error state to HOST_GPR0 register. */ -int ssi_fips_get_state(enum cc_fips_state_t *p_state) +void cc_set_ree_fips_status(struct ssi_drvdata *drvdata, bool status) +{ + void __iomem *cc_base = drvdata->cc_base; + int val = CC_FIPS_SYNC_REE_STATUS; + + val |= (status ? CC_FIPS_SYNC_MODULE_OK : CC_FIPS_SYNC_MODULE_ERROR); + + CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_GPR0), val); +} + +void ssi_fips_fini(struct ssi_drvdata *drvdata) { - int rc = 0; + struct ssi_fips_handle *fips_h = drvdata->fips_handle; - if (!p_state) - return -EINVAL; + if (!fips_h) + return; /* Not allocated */ - rc = ssi_fips_ext_get_state(p_state); + /* Kill tasklet */ + tasklet_kill(&fips_h->tasklet); - return rc; + kfree(fips_h); + drvdata->fips_handle = NULL; } -EXPORT_SYMBOL(ssi_fips_get_state); +void fips_handler(struct ssi_drvdata *drvdata) +{ + struct ssi_fips_handle *fips_handle_ptr = + drvdata->fips_handle; -/* - * This function returns the REE FIPS error. - * It should be called by kernel module. - */ -int ssi_fips_get_error(enum cc_fips_error *p_err) + tasklet_schedule(&fips_handle_ptr->tasklet); +} + +static inline void tee_fips_error(void) { - int rc = 0; + if (fips_enabled) + panic("ccree: TEE reported cryptographic error in fips mode!\n"); + else + SSI_LOG_ERR("TEE reported error!\n"); +} - if (!p_err) - return -EINVAL; +/* Deferred service handler, run as interrupt-fired tasklet */ +static void fips_dsr(unsigned long devarg) +{ + struct ssi_drvdata *drvdata = (struct ssi_drvdata *)devarg; + void __iomem *cc_base = drvdata->cc_base; + u32 irq, state, val; - rc = ssi_fips_ext_get_error(p_err); + irq = (drvdata->irq & (SSI_GPR0_IRQ_MASK)); - return rc; + if (irq) { + state = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, GPR_HOST)); + + if (state != (CC_FIPS_SYNC_TEE_STATUS | CC_FIPS_SYNC_MODULE_OK)) + tee_fips_error(); + } + + /* after verifing that there is nothing to do, + * unmask AXI completion interrupt. + */ + val = (CC_REG_OFFSET(HOST_RGF, HOST_IMR) & ~irq); + CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IMR), val); } -EXPORT_SYMBOL(ssi_fips_get_error); +/* The function called once at driver entry point .*/ +int ssi_fips_init(struct ssi_drvdata *p_drvdata) +{ + struct ssi_fips_handle *fips_h; + + fips_h = kzalloc(sizeof(*fips_h), GFP_KERNEL); + if (!fips_h) + return -ENOMEM; + + p_drvdata->fips_handle = fips_h; + + SSI_LOG_DEBUG("Initializing fips tasklet\n"); + tasklet_init(&fips_h->tasklet, fips_dsr, (unsigned long)p_drvdata); + + if (!cc_get_tee_fips_status(p_drvdata)) + tee_fips_error(); + + return 0; +} |