Path: blob/master/drivers/crypto/hisilicon/zip/dae_main.c
26292 views
// SPDX-License-Identifier: GPL-2.01/* Copyright (c) 2024 HiSilicon Limited. */23#include <linux/bitops.h>4#include <linux/io.h>5#include <linux/uacce.h>6#include "zip.h"78/* memory */9#define DAE_MEM_START_OFFSET 0x33104010#define DAE_MEM_DONE_OFFSET 0x33104411#define DAE_MEM_START_MASK 0x112#define DAE_MEM_DONE_MASK 0x113#define DAE_REG_RD_INTVRL_US 1014#define DAE_REG_RD_TMOUT_US USEC_PER_SEC1516#define DAE_ALG_NAME "hashagg"1718/* error */19#define DAE_AXI_CFG_OFFSET 0x33100020#define DAE_AXI_SHUTDOWN_MASK (BIT(0) | BIT(5))21#define DAE_ERR_SOURCE_OFFSET 0x331C8422#define DAE_ERR_STATUS_OFFSET 0x331C8823#define DAE_ERR_CE_OFFSET 0x331CA024#define DAE_ERR_CE_MASK BIT(3)25#define DAE_ERR_NFE_OFFSET 0x331CA426#define DAE_ERR_NFE_MASK 0x1727#define DAE_ERR_FE_OFFSET 0x331CA828#define DAE_ERR_FE_MASK 029#define DAE_ECC_MBIT_MASK BIT(2)30#define DAE_ECC_INFO_OFFSET 0x33400C31#define DAE_ERR_SHUTDOWN_OFFSET 0x331CAC32#define DAE_ERR_SHUTDOWN_MASK 0x1733#define DAE_ERR_ENABLE_OFFSET 0x331C8034#define DAE_ERR_ENABLE_MASK (DAE_ERR_FE_MASK | DAE_ERR_NFE_MASK | DAE_ERR_CE_MASK)35#define DAE_AM_CTRL_GLOBAL_OFFSET 0x33000036#define DAE_AM_RETURN_OFFSET 0x33015037#define DAE_AM_RETURN_MASK 0x338#define DAE_AXI_CFG_OFFSET 0x33100039#define DAE_AXI_SHUTDOWN_EN_MASK (BIT(0) | BIT(5))4041struct hisi_dae_hw_error {42u32 int_msk;43const char *msg;44};4546static const struct hisi_dae_hw_error dae_hw_error[] = {47{ .int_msk = BIT(0), .msg = "dae_axi_bus_err" },48{ .int_msk = BIT(1), .msg = "dae_axi_poison_err" },49{ .int_msk = BIT(2), .msg = "dae_ecc_2bit_err" },50{ .int_msk = BIT(3), .msg = "dae_ecc_1bit_err" },51{ .int_msk = BIT(4), .msg = "dae_fsm_hbeat_err" },52};5354static inline bool dae_is_support(struct hisi_qm *qm)55{56if (test_bit(QM_SUPPORT_DAE, &qm->caps))57return true;5859return false;60}6162int hisi_dae_set_user_domain(struct hisi_qm *qm)63{64u32 val;65int ret;6667if (!dae_is_support(qm))68return 0;6970val = readl(qm->io_base + DAE_MEM_START_OFFSET);71val |= DAE_MEM_START_MASK;72writel(val, qm->io_base + DAE_MEM_START_OFFSET);73ret = readl_relaxed_poll_timeout(qm->io_base + DAE_MEM_DONE_OFFSET, val,74val & DAE_MEM_DONE_MASK,75DAE_REG_RD_INTVRL_US, DAE_REG_RD_TMOUT_US);76if (ret)77pci_err(qm->pdev, "failed to init dae memory!\n");7879return ret;80}8182int hisi_dae_set_alg(struct hisi_qm *qm)83{84size_t len;8586if (!dae_is_support(qm))87return 0;8889if (!qm->uacce)90return 0;9192len = strlen(qm->uacce->algs);93/* A line break may be required */94if (len + strlen(DAE_ALG_NAME) + 1 >= QM_DEV_ALG_MAX_LEN) {95pci_err(qm->pdev, "algorithm name is too long!\n");96return -EINVAL;97}9899if (len)100strcat((char *)qm->uacce->algs, "\n");101102strcat((char *)qm->uacce->algs, DAE_ALG_NAME);103104return 0;105}106107static void hisi_dae_master_ooo_ctrl(struct hisi_qm *qm, bool enable)108{109u32 axi_val, err_val;110111axi_val = readl(qm->io_base + DAE_AXI_CFG_OFFSET);112if (enable) {113axi_val |= DAE_AXI_SHUTDOWN_MASK;114err_val = DAE_ERR_SHUTDOWN_MASK;115} else {116axi_val &= ~DAE_AXI_SHUTDOWN_MASK;117err_val = 0;118}119120writel(axi_val, qm->io_base + DAE_AXI_CFG_OFFSET);121writel(err_val, qm->io_base + DAE_ERR_SHUTDOWN_OFFSET);122}123124void hisi_dae_hw_error_enable(struct hisi_qm *qm)125{126if (!dae_is_support(qm))127return;128129/* clear dae hw error source if having */130writel(DAE_ERR_ENABLE_MASK, qm->io_base + DAE_ERR_SOURCE_OFFSET);131132/* configure error type */133writel(DAE_ERR_CE_MASK, qm->io_base + DAE_ERR_CE_OFFSET);134writel(DAE_ERR_NFE_MASK, qm->io_base + DAE_ERR_NFE_OFFSET);135writel(DAE_ERR_FE_MASK, qm->io_base + DAE_ERR_FE_OFFSET);136137hisi_dae_master_ooo_ctrl(qm, true);138139/* enable dae hw error interrupts */140writel(DAE_ERR_ENABLE_MASK, qm->io_base + DAE_ERR_ENABLE_OFFSET);141}142143void hisi_dae_hw_error_disable(struct hisi_qm *qm)144{145if (!dae_is_support(qm))146return;147148writel(0, qm->io_base + DAE_ERR_ENABLE_OFFSET);149hisi_dae_master_ooo_ctrl(qm, false);150}151152static u32 hisi_dae_get_hw_err_status(struct hisi_qm *qm)153{154return readl(qm->io_base + DAE_ERR_STATUS_OFFSET);155}156157static void hisi_dae_clear_hw_err_status(struct hisi_qm *qm, u32 err_sts)158{159if (!dae_is_support(qm))160return;161162writel(err_sts, qm->io_base + DAE_ERR_SOURCE_OFFSET);163}164165static void hisi_dae_disable_error_report(struct hisi_qm *qm, u32 err_type)166{167writel(DAE_ERR_NFE_MASK & (~err_type), qm->io_base + DAE_ERR_NFE_OFFSET);168}169170static void hisi_dae_log_hw_error(struct hisi_qm *qm, u32 err_type)171{172const struct hisi_dae_hw_error *err = dae_hw_error;173struct device *dev = &qm->pdev->dev;174u32 ecc_info;175size_t i;176177for (i = 0; i < ARRAY_SIZE(dae_hw_error); i++) {178err = &dae_hw_error[i];179if (!(err->int_msk & err_type))180continue;181182dev_err(dev, "%s [error status=0x%x] found\n",183err->msg, err->int_msk);184185if (err->int_msk & DAE_ECC_MBIT_MASK) {186ecc_info = readl(qm->io_base + DAE_ECC_INFO_OFFSET);187dev_err(dev, "dae multi ecc sram info 0x%x\n", ecc_info);188}189}190}191192enum acc_err_result hisi_dae_get_err_result(struct hisi_qm *qm)193{194u32 err_status;195196if (!dae_is_support(qm))197return ACC_ERR_NONE;198199err_status = hisi_dae_get_hw_err_status(qm);200if (!err_status)201return ACC_ERR_NONE;202203hisi_dae_log_hw_error(qm, err_status);204205if (err_status & DAE_ERR_NFE_MASK) {206/* Disable the same error reporting until device is recovered. */207hisi_dae_disable_error_report(qm, err_status);208return ACC_ERR_NEED_RESET;209}210hisi_dae_clear_hw_err_status(qm, err_status);211212return ACC_ERR_RECOVERED;213}214215bool hisi_dae_dev_is_abnormal(struct hisi_qm *qm)216{217u32 err_status;218219if (!dae_is_support(qm))220return false;221222err_status = hisi_dae_get_hw_err_status(qm);223if (err_status & DAE_ERR_NFE_MASK)224return true;225226return false;227}228229int hisi_dae_close_axi_master_ooo(struct hisi_qm *qm)230{231u32 val;232int ret;233234if (!dae_is_support(qm))235return 0;236237val = readl(qm->io_base + DAE_AM_CTRL_GLOBAL_OFFSET);238val |= BIT(0);239writel(val, qm->io_base + DAE_AM_CTRL_GLOBAL_OFFSET);240241ret = readl_relaxed_poll_timeout(qm->io_base + DAE_AM_RETURN_OFFSET,242val, (val == DAE_AM_RETURN_MASK),243DAE_REG_RD_INTVRL_US, DAE_REG_RD_TMOUT_US);244if (ret)245dev_err(&qm->pdev->dev, "failed to close dae axi ooo!\n");246247return ret;248}249250void hisi_dae_open_axi_master_ooo(struct hisi_qm *qm)251{252u32 val;253254if (!dae_is_support(qm))255return;256257val = readl(qm->io_base + DAE_AXI_CFG_OFFSET);258259writel(val & ~DAE_AXI_SHUTDOWN_EN_MASK, qm->io_base + DAE_AXI_CFG_OFFSET);260writel(val | DAE_AXI_SHUTDOWN_EN_MASK, qm->io_base + DAE_AXI_CFG_OFFSET);261}262263264