File Index
Files and directories
Sign in
FILE

dae_main.c

File preview with syntax highlighting.

linux-6.19.14/drivers/crypto/hisilicon/zip/dae_main.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) 2024 HiSilicon Limited. */
  3
  4#include <linux/bitops.h>
  5#include <linux/io.h>
  6#include <linux/uacce.h>
  7#include "zip.h"
  8
  9/* memory */
 10#define DAE_MEM_START_OFFSET		0x331040
 11#define DAE_MEM_DONE_OFFSET		0x331044
 12#define DAE_MEM_START_MASK		0x1
 13#define DAE_MEM_DONE_MASK		0x1
 14#define DAE_REG_RD_INTVRL_US		10
 15#define DAE_REG_RD_TMOUT_US		USEC_PER_SEC
 16
 17#define DAE_ALG_NAME			"hashagg"
 18#define DAE_V5_ALG_NAME			"hashagg\nudma\nhashjoin\ngather"
 19
 20/* error */
 21#define DAE_AXI_CFG_OFFSET		0x331000
 22#define DAE_AXI_SHUTDOWN_MASK		(BIT(0) | BIT(5))
 23#define DAE_ERR_SOURCE_OFFSET		0x331C84
 24#define DAE_ERR_STATUS_OFFSET		0x331C88
 25#define DAE_ERR_CE_OFFSET		0x331CA0
 26#define DAE_ERR_CE_MASK			BIT(3)
 27#define DAE_ERR_NFE_OFFSET		0x331CA4
 28#define DAE_ERR_NFE_MASK		0x17
 29#define DAE_ERR_FE_OFFSET		0x331CA8
 30#define DAE_ERR_FE_MASK			0
 31#define DAE_ECC_MBIT_MASK		BIT(2)
 32#define DAE_ECC_INFO_OFFSET		0x33400C
 33#define DAE_ERR_SHUTDOWN_OFFSET		0x331CAC
 34#define DAE_ERR_SHUTDOWN_MASK		0x17
 35#define DAE_ERR_ENABLE_OFFSET		0x331C80
 36#define DAE_ERR_ENABLE_MASK		(DAE_ERR_FE_MASK | DAE_ERR_NFE_MASK | DAE_ERR_CE_MASK)
 37#define DAE_AM_CTRL_GLOBAL_OFFSET	0x330000
 38#define DAE_AM_RETURN_OFFSET		0x330150
 39#define DAE_AM_RETURN_MASK		0x3
 40#define DAE_AXI_CFG_OFFSET		0x331000
 41#define DAE_AXI_SHUTDOWN_EN_MASK	(BIT(0) | BIT(5))
 42
 43struct hisi_dae_hw_error {
 44	u32 int_msk;
 45	const char *msg;
 46};
 47
 48static const struct hisi_dae_hw_error dae_hw_error[] = {
 49	{ .int_msk = BIT(0), .msg = "dae_axi_bus_err" },
 50	{ .int_msk = BIT(1), .msg = "dae_axi_poison_err" },
 51	{ .int_msk = BIT(2), .msg = "dae_ecc_2bit_err" },
 52	{ .int_msk = BIT(3), .msg = "dae_ecc_1bit_err" },
 53	{ .int_msk = BIT(4), .msg = "dae_fsm_hbeat_err" },
 54};
 55
 56static inline bool dae_is_support(struct hisi_qm *qm)
 57{
 58	if (test_bit(QM_SUPPORT_DAE, &qm->caps))
 59		return true;
 60
 61	return false;
 62}
 63
 64int hisi_dae_set_user_domain(struct hisi_qm *qm)
 65{
 66	u32 val;
 67	int ret;
 68
 69	if (!dae_is_support(qm))
 70		return 0;
 71
 72	val = readl(qm->io_base + DAE_MEM_START_OFFSET);
 73	val |= DAE_MEM_START_MASK;
 74	writel(val, qm->io_base + DAE_MEM_START_OFFSET);
 75	ret = readl_relaxed_poll_timeout(qm->io_base + DAE_MEM_DONE_OFFSET, val,
 76					 val & DAE_MEM_DONE_MASK,
 77					 DAE_REG_RD_INTVRL_US, DAE_REG_RD_TMOUT_US);
 78	if (ret)
 79		pci_err(qm->pdev, "failed to init dae memory!\n");
 80
 81	return ret;
 82}
 83
 84int hisi_dae_set_alg(struct hisi_qm *qm)
 85{
 86	const char *alg_name;
 87	size_t len;
 88
 89	if (!dae_is_support(qm))
 90		return 0;
 91
 92	if (!qm->uacce)
 93		return 0;
 94
 95	if (qm->ver >= QM_HW_V5)
 96		alg_name = DAE_V5_ALG_NAME;
 97	else
 98		alg_name = DAE_ALG_NAME;
 99
100	len = strlen(qm->uacce->algs);
101	/* A line break may be required */
102	if (len + strlen(alg_name) + 1 >= QM_DEV_ALG_MAX_LEN) {
103		pci_err(qm->pdev, "algorithm name is too long!\n");
104		return -EINVAL;
105	}
106
107	if (len)
108		strcat((char *)qm->uacce->algs, "\n");
109
110	strcat((char *)qm->uacce->algs, alg_name);
111
112	return 0;
113}
114
115static void hisi_dae_master_ooo_ctrl(struct hisi_qm *qm, bool enable)
116{
117	u32 axi_val, err_val;
118
119	axi_val = readl(qm->io_base + DAE_AXI_CFG_OFFSET);
120	if (enable) {
121		axi_val |= DAE_AXI_SHUTDOWN_MASK;
122		err_val = DAE_ERR_SHUTDOWN_MASK;
123	} else {
124		axi_val &= ~DAE_AXI_SHUTDOWN_MASK;
125		err_val = 0;
126	}
127
128	writel(axi_val, qm->io_base + DAE_AXI_CFG_OFFSET);
129	writel(err_val, qm->io_base + DAE_ERR_SHUTDOWN_OFFSET);
130}
131
132void hisi_dae_hw_error_enable(struct hisi_qm *qm)
133{
134	if (!dae_is_support(qm))
135		return;
136
137	/* clear dae hw error source if having */
138	writel(DAE_ERR_ENABLE_MASK, qm->io_base + DAE_ERR_SOURCE_OFFSET);
139
140	/* configure error type */
141	writel(DAE_ERR_CE_MASK, qm->io_base + DAE_ERR_CE_OFFSET);
142	writel(DAE_ERR_NFE_MASK, qm->io_base + DAE_ERR_NFE_OFFSET);
143	writel(DAE_ERR_FE_MASK, qm->io_base + DAE_ERR_FE_OFFSET);
144
145	hisi_dae_master_ooo_ctrl(qm, true);
146
147	/* enable dae hw error interrupts */
148	writel(DAE_ERR_ENABLE_MASK, qm->io_base + DAE_ERR_ENABLE_OFFSET);
149}
150
151void hisi_dae_hw_error_disable(struct hisi_qm *qm)
152{
153	if (!dae_is_support(qm))
154		return;
155
156	writel(0, qm->io_base + DAE_ERR_ENABLE_OFFSET);
157	hisi_dae_master_ooo_ctrl(qm, false);
158}
159
160static u32 hisi_dae_get_hw_err_status(struct hisi_qm *qm)
161{
162	return readl(qm->io_base + DAE_ERR_STATUS_OFFSET);
163}
164
165static void hisi_dae_clear_hw_err_status(struct hisi_qm *qm, u32 err_sts)
166{
167	if (!dae_is_support(qm))
168		return;
169
170	writel(err_sts, qm->io_base + DAE_ERR_SOURCE_OFFSET);
171}
172
173static void hisi_dae_disable_error_report(struct hisi_qm *qm, u32 err_type)
174{
175	writel(DAE_ERR_NFE_MASK & (~err_type), qm->io_base + DAE_ERR_NFE_OFFSET);
176}
177
178static void hisi_dae_enable_error_report(struct hisi_qm *qm)
179{
180	writel(DAE_ERR_CE_MASK, qm->io_base + DAE_ERR_CE_OFFSET);
181	writel(DAE_ERR_NFE_MASK, qm->io_base + DAE_ERR_NFE_OFFSET);
182}
183
184static void hisi_dae_log_hw_error(struct hisi_qm *qm, u32 err_type)
185{
186	const struct hisi_dae_hw_error *err = dae_hw_error;
187	struct device *dev = &qm->pdev->dev;
188	u32 ecc_info;
189	size_t i;
190
191	for (i = 0; i < ARRAY_SIZE(dae_hw_error); i++) {
192		err = &dae_hw_error[i];
193		if (!(err->int_msk & err_type))
194			continue;
195
196		dev_err(dev, "%s [error status=0x%x] found\n",
197			err->msg, err->int_msk);
198
199		if (err->int_msk & DAE_ECC_MBIT_MASK) {
200			ecc_info = readl(qm->io_base + DAE_ECC_INFO_OFFSET);
201			dev_err(dev, "dae multi ecc sram info 0x%x\n", ecc_info);
202		}
203	}
204}
205
206enum acc_err_result hisi_dae_get_err_result(struct hisi_qm *qm)
207{
208	u32 err_status;
209
210	if (!dae_is_support(qm))
211		return ACC_ERR_NONE;
212
213	err_status = hisi_dae_get_hw_err_status(qm);
214	if (!err_status)
215		return ACC_ERR_NONE;
216
217	hisi_dae_log_hw_error(qm, err_status);
218
219	if (err_status & DAE_ERR_NFE_MASK) {
220		/* Disable the same error reporting until device is recovered. */
221		hisi_dae_disable_error_report(qm, err_status);
222		return ACC_ERR_NEED_RESET;
223	}
224	hisi_dae_clear_hw_err_status(qm, err_status);
225	/* Avoid firmware disable error report, re-enable. */
226	hisi_dae_enable_error_report(qm);
227
228	return ACC_ERR_RECOVERED;
229}
230
231bool hisi_dae_dev_is_abnormal(struct hisi_qm *qm)
232{
233	u32 err_status;
234
235	if (!dae_is_support(qm))
236		return false;
237
238	err_status = hisi_dae_get_hw_err_status(qm);
239	if (err_status & DAE_ERR_NFE_MASK)
240		return true;
241
242	return false;
243}
244
245int hisi_dae_close_axi_master_ooo(struct hisi_qm *qm)
246{
247	u32 val;
248	int ret;
249
250	if (!dae_is_support(qm))
251		return 0;
252
253	val = readl(qm->io_base + DAE_AM_CTRL_GLOBAL_OFFSET);
254	val |= BIT(0);
255	writel(val, qm->io_base + DAE_AM_CTRL_GLOBAL_OFFSET);
256
257	ret = readl_relaxed_poll_timeout(qm->io_base + DAE_AM_RETURN_OFFSET,
258					 val, (val == DAE_AM_RETURN_MASK),
259					 DAE_REG_RD_INTVRL_US, DAE_REG_RD_TMOUT_US);
260	if (ret)
261		dev_err(&qm->pdev->dev, "failed to close dae axi ooo!\n");
262
263	return ret;
264}
265
266void hisi_dae_open_axi_master_ooo(struct hisi_qm *qm)
267{
268	u32 val;
269
270	if (!dae_is_support(qm))
271		return;
272
273	val = readl(qm->io_base + DAE_AXI_CFG_OFFSET);
274
275	writel(val & ~DAE_AXI_SHUTDOWN_EN_MASK, qm->io_base + DAE_AXI_CFG_OFFSET);
276	writel(val | DAE_AXI_SHUTDOWN_EN_MASK, qm->io_base + DAE_AXI_CFG_OFFSET);
277}
~/ Read-only file preview.