linux/drivers/crypto/ccree/cc_fips.c
<<
>>
Prefs
   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
  10static void fips_dsr(unsigned long devarg);
  11
  12struct 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 */
  19static 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        return (reg == (CC_FIPS_SYNC_TEE_STATUS | CC_FIPS_SYNC_MODULE_OK));
  25}
  26
  27/*
  28 * This function should push the FIPS REE library status towards the TEE library
  29 * by writing the error state to HOST_GPR0 register.
  30 */
  31void cc_set_ree_fips_status(struct cc_drvdata *drvdata, bool status)
  32{
  33        int val = CC_FIPS_SYNC_REE_STATUS;
  34
  35        if (drvdata->hw_rev < CC_HW_REV_712)
  36                return;
  37
  38        val |= (status ? CC_FIPS_SYNC_MODULE_OK : CC_FIPS_SYNC_MODULE_ERROR);
  39
  40        cc_iowrite(drvdata, CC_REG(HOST_GPR0), val);
  41}
  42
  43void cc_fips_fini(struct cc_drvdata *drvdata)
  44{
  45        struct cc_fips_handle *fips_h = drvdata->fips_handle;
  46
  47        if (drvdata->hw_rev < CC_HW_REV_712 || !fips_h)
  48                return;
  49
  50        /* Kill tasklet */
  51        tasklet_kill(&fips_h->tasklet);
  52        drvdata->fips_handle = NULL;
  53}
  54
  55void fips_handler(struct cc_drvdata *drvdata)
  56{
  57        struct cc_fips_handle *fips_handle_ptr = drvdata->fips_handle;
  58
  59        if (drvdata->hw_rev < CC_HW_REV_712)
  60                return;
  61
  62        tasklet_schedule(&fips_handle_ptr->tasklet);
  63}
  64
  65static inline void tee_fips_error(struct device *dev)
  66{
  67        if (fips_enabled)
  68                panic("ccree: TEE reported cryptographic error in fips mode!\n");
  69        else
  70                dev_err(dev, "TEE reported error!\n");
  71}
  72
  73/*
  74 * This function check if cryptocell tee fips error occurred
  75 * and in such case triggers system error
  76 */
  77void cc_tee_handle_fips_error(struct cc_drvdata *p_drvdata)
  78{
  79        struct device *dev = drvdata_to_dev(p_drvdata);
  80
  81        if (!cc_get_tee_fips_status(p_drvdata))
  82                tee_fips_error(dev);
  83}
  84
  85/* Deferred service handler, run as interrupt-fired tasklet */
  86static void fips_dsr(unsigned long devarg)
  87{
  88        struct cc_drvdata *drvdata = (struct cc_drvdata *)devarg;
  89        u32 irq, val;
  90
  91        irq = (drvdata->irq & (CC_GPR0_IRQ_MASK));
  92
  93        if (irq) {
  94                cc_tee_handle_fips_error(drvdata);
  95        }
  96
  97        /* after verifing that there is nothing to do,
  98         * unmask AXI completion interrupt.
  99         */
 100        val = (CC_REG(HOST_IMR) & ~irq);
 101        cc_iowrite(drvdata, CC_REG(HOST_IMR), val);
 102}
 103
 104/* The function called once at driver entry point .*/
 105int cc_fips_init(struct cc_drvdata *p_drvdata)
 106{
 107        struct cc_fips_handle *fips_h;
 108        struct device *dev = drvdata_to_dev(p_drvdata);
 109
 110        if (p_drvdata->hw_rev < CC_HW_REV_712)
 111                return 0;
 112
 113        fips_h = devm_kzalloc(dev, sizeof(*fips_h), GFP_KERNEL);
 114        if (!fips_h)
 115                return -ENOMEM;
 116
 117        p_drvdata->fips_handle = fips_h;
 118
 119        dev_dbg(dev, "Initializing fips tasklet\n");
 120        tasklet_init(&fips_h->tasklet, fips_dsr, (unsigned long)p_drvdata);
 121
 122        cc_tee_handle_fips_error(p_drvdata);
 123
 124        return 0;
 125}
 126