xref: /linux-6.15/drivers/crypto/caam/error.c (revision 8d818c10)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
28e8ec596SKim Phillips /*
38e8ec596SKim Phillips  * CAAM Error Reporting
48e8ec596SKim Phillips  *
58e8ec596SKim Phillips  * Copyright 2009-2011 Freescale Semiconductor, Inc.
68e8ec596SKim Phillips  */
78e8ec596SKim Phillips 
88e8ec596SKim Phillips #include "compat.h"
98e8ec596SKim Phillips #include "regs.h"
108e8ec596SKim Phillips #include "desc.h"
118e8ec596SKim Phillips #include "error.h"
128e8ec596SKim Phillips 
13972b812bSHoria Geantă #ifdef DEBUG
14972b812bSHoria Geantă #include <linux/highmem.h>
15972b812bSHoria Geantă 
16972b812bSHoria Geantă void caam_dump_sg(const char *level, const char *prefix_str, int prefix_type,
17972b812bSHoria Geantă 		  int rowsize, int groupsize, struct scatterlist *sg,
18972b812bSHoria Geantă 		  size_t tlen, bool ascii)
19972b812bSHoria Geantă {
20972b812bSHoria Geantă 	struct scatterlist *it;
21972b812bSHoria Geantă 	void *it_page;
22972b812bSHoria Geantă 	size_t len;
23972b812bSHoria Geantă 	void *buf;
24972b812bSHoria Geantă 
25972b812bSHoria Geantă 	for (it = sg; it && tlen > 0 ; it = sg_next(sg)) {
26972b812bSHoria Geantă 		/*
27972b812bSHoria Geantă 		 * make sure the scatterlist's page
28972b812bSHoria Geantă 		 * has a valid virtual memory mapping
29972b812bSHoria Geantă 		 */
30972b812bSHoria Geantă 		it_page = kmap_atomic(sg_page(it));
31972b812bSHoria Geantă 		if (unlikely(!it_page)) {
32972b812bSHoria Geantă 			pr_err("caam_dump_sg: kmap failed\n");
33972b812bSHoria Geantă 			return;
34972b812bSHoria Geantă 		}
35972b812bSHoria Geantă 
36972b812bSHoria Geantă 		buf = it_page + it->offset;
37972b812bSHoria Geantă 		len = min_t(size_t, tlen, it->length);
38972b812bSHoria Geantă 		print_hex_dump(level, prefix_str, prefix_type, rowsize,
39972b812bSHoria Geantă 			       groupsize, buf, len, ascii);
40972b812bSHoria Geantă 		tlen -= len;
41972b812bSHoria Geantă 
42972b812bSHoria Geantă 		kunmap_atomic(it_page);
43972b812bSHoria Geantă 	}
44972b812bSHoria Geantă }
45972b812bSHoria Geantă #else
46972b812bSHoria Geantă void caam_dump_sg(const char *level, const char *prefix_str, int prefix_type,
47972b812bSHoria Geantă 		  int rowsize, int groupsize, struct scatterlist *sg,
48972b812bSHoria Geantă 		  size_t tlen, bool ascii)
49972b812bSHoria Geantă {}
50972b812bSHoria Geantă #endif /* DEBUG */
51972b812bSHoria Geantă EXPORT_SYMBOL(caam_dump_sg);
52972b812bSHoria Geantă 
5396aef9a8SKim Phillips static const struct {
548e8ec596SKim Phillips 	u8 value;
55e397ee0fSMarek Vasut 	const char *error_text;
568e8ec596SKim Phillips } desc_error_list[] = {
57281922a1SKim Phillips 	{ 0x00, "No error." },
58da37503dSMarek Vasut 	{ 0x01, "SGT Length Error. The descriptor is trying to read more data than is contained in the SGT table." },
59281922a1SKim Phillips 	{ 0x02, "SGT Null Entry Error." },
60da37503dSMarek Vasut 	{ 0x03, "Job Ring Control Error. There is a bad value in the Job Ring Control register." },
61da37503dSMarek Vasut 	{ 0x04, "Invalid Descriptor Command. The Descriptor Command field is invalid." },
628e8ec596SKim Phillips 	{ 0x05, "Reserved." },
638e8ec596SKim Phillips 	{ 0x06, "Invalid KEY Command" },
648e8ec596SKim Phillips 	{ 0x07, "Invalid LOAD Command" },
658e8ec596SKim Phillips 	{ 0x08, "Invalid STORE Command" },
668e8ec596SKim Phillips 	{ 0x09, "Invalid OPERATION Command" },
678e8ec596SKim Phillips 	{ 0x0A, "Invalid FIFO LOAD Command" },
688e8ec596SKim Phillips 	{ 0x0B, "Invalid FIFO STORE Command" },
69281922a1SKim Phillips 	{ 0x0C, "Invalid MOVE/MOVE_LEN Command" },
70da37503dSMarek Vasut 	{ 0x0D, "Invalid JUMP Command. A nonlocal JUMP Command is invalid because the target is not a Job Header Command, or the jump is from a Trusted Descriptor to a Job Descriptor, or because the target Descriptor contains a Shared Descriptor." },
718e8ec596SKim Phillips 	{ 0x0E, "Invalid MATH Command" },
728e8ec596SKim Phillips 	{ 0x0F, "Invalid SIGNATURE Command" },
73da37503dSMarek Vasut 	{ 0x10, "Invalid Sequence Command. A SEQ IN PTR OR SEQ OUT PTR Command is invalid or a SEQ KEY, SEQ LOAD, SEQ FIFO LOAD, or SEQ FIFO STORE decremented the input or output sequence length below 0. This error may result if a built-in PROTOCOL Command has encountered a malformed PDU." },
748e8ec596SKim Phillips 	{ 0x11, "Skip data type invalid. The type must be 0xE or 0xF."},
758e8ec596SKim Phillips 	{ 0x12, "Shared Descriptor Header Error" },
76da37503dSMarek Vasut 	{ 0x13, "Header Error. Invalid length or parity, or certain other problems." },
77da37503dSMarek Vasut 	{ 0x14, "Burster Error. Burster has gotten to an illegal state" },
78da37503dSMarek Vasut 	{ 0x15, "Context Register Length Error. The descriptor is trying to read or write past the end of the Context Register. A SEQ LOAD or SEQ STORE with the VLF bit set was executed with too large a length in the variable length register (VSOL for SEQ STORE or VSIL for SEQ LOAD)." },
798e8ec596SKim Phillips 	{ 0x16, "DMA Error" },
808e8ec596SKim Phillips 	{ 0x17, "Reserved." },
818e8ec596SKim Phillips 	{ 0x1A, "Job failed due to JR reset" },
828e8ec596SKim Phillips 	{ 0x1B, "Job failed due to Fail Mode" },
838e8ec596SKim Phillips 	{ 0x1C, "DECO Watchdog timer timeout error" },
84da37503dSMarek Vasut 	{ 0x1D, "DECO tried to copy a key from another DECO but the other DECO's Key Registers were locked" },
85da37503dSMarek Vasut 	{ 0x1E, "DECO attempted to copy data from a DECO that had an unmasked Descriptor error" },
86da37503dSMarek Vasut 	{ 0x1F, "LIODN error. DECO was trying to share from itself or from another DECO but the two Non-SEQ LIODN values didn't match or the 'shared from' DECO's Descriptor required that the SEQ LIODNs be the same and they aren't." },
87da37503dSMarek Vasut 	{ 0x20, "DECO has completed a reset initiated via the DRR register" },
88da37503dSMarek Vasut 	{ 0x21, "Nonce error. When using EKT (CCM) key encryption option in the FIFO STORE Command, the Nonce counter reached its maximum value and this encryption mode can no longer be used." },
89da37503dSMarek Vasut 	{ 0x22, "Meta data is too large (> 511 bytes) for TLS decap (input frame; block ciphers) and IPsec decap (output frame, when doing the next header byte update) and DCRC (output frame)." },
90281922a1SKim Phillips 	{ 0x23, "Read Input Frame error" },
91281922a1SKim Phillips 	{ 0x24, "JDKEK, TDKEK or TDSK not loaded error" },
928e8ec596SKim Phillips 	{ 0x80, "DNR (do not run) error" },
938e8ec596SKim Phillips 	{ 0x81, "undefined protocol command" },
948e8ec596SKim Phillips 	{ 0x82, "invalid setting in PDB" },
958e8ec596SKim Phillips 	{ 0x83, "Anti-replay LATE error" },
968e8ec596SKim Phillips 	{ 0x84, "Anti-replay REPLAY error" },
978e8ec596SKim Phillips 	{ 0x85, "Sequence number overflow" },
988e8ec596SKim Phillips 	{ 0x86, "Sigver invalid signature" },
998e8ec596SKim Phillips 	{ 0x87, "DSA Sign Illegal test descriptor" },
100da37503dSMarek Vasut 	{ 0x88, "Protocol Format Error - A protocol has seen an error in the format of data received. When running RSA, this means that formatting with random padding was used, and did not follow the form: 0x00, 0x02, 8-to-N bytes of non-zero pad, 0x00, F data." },
101da37503dSMarek Vasut 	{ 0x89, "Protocol Size Error - A protocol has seen an error in size. When running RSA, pdb size N < (size of F) when no formatting is used; or pdb size N < (F + 11) when formatting is used." },
1028e8ec596SKim Phillips 	{ 0xC1, "Blob Command error: Undefined mode" },
1038e8ec596SKim Phillips 	{ 0xC2, "Blob Command error: Secure Memory Blob mode error" },
104da37503dSMarek Vasut 	{ 0xC4, "Blob Command error: Black Blob key or input size error" },
1058e8ec596SKim Phillips 	{ 0xC5, "Blob Command error: Invalid key destination" },
1068e8ec596SKim Phillips 	{ 0xC8, "Blob Command error: Trusted/Secure mode error" },
107da37503dSMarek Vasut 	{ 0xF0, "IPsec TTL or hop limit field either came in as 0, or was decremented to 0" },
1088e8ec596SKim Phillips 	{ 0xF1, "3GPP HFN matches or exceeds the Threshold" },
1098e8ec596SKim Phillips };
1109724d7adSMarek Vasut 
11194cebd9dSHoria Geantă static const struct {
11294cebd9dSHoria Geantă 	u8 value;
11394cebd9dSHoria Geantă 	const char *error_text;
11494cebd9dSHoria Geantă } qi_error_list[] = {
11594cebd9dSHoria Geantă 	{ 0x1F, "Job terminated by FQ or ICID flush" },
11694cebd9dSHoria Geantă 	{ 0x20, "FD format error"},
11794cebd9dSHoria Geantă 	{ 0x21, "FD command format error"},
11894cebd9dSHoria Geantă 	{ 0x23, "FL format error"},
11994cebd9dSHoria Geantă 	{ 0x25, "CRJD specified in FD, but not enabled in FLC"},
12094cebd9dSHoria Geantă 	{ 0x30, "Max. buffer size too small"},
12194cebd9dSHoria Geantă 	{ 0x31, "DHR exceeds max. buffer size (allocate mode, S/G format)"},
12294cebd9dSHoria Geantă 	{ 0x32, "SGT exceeds max. buffer size (allocate mode, S/G format"},
12394cebd9dSHoria Geantă 	{ 0x33, "Size over/underflow (allocate mode)"},
12494cebd9dSHoria Geantă 	{ 0x34, "Size over/underflow (reuse mode)"},
12594cebd9dSHoria Geantă 	{ 0x35, "Length exceeds max. short length (allocate mode, S/G/ format)"},
12694cebd9dSHoria Geantă 	{ 0x36, "Memory footprint exceeds max. value (allocate mode, S/G/ format)"},
12794cebd9dSHoria Geantă 	{ 0x41, "SBC frame format not supported (allocate mode)"},
12894cebd9dSHoria Geantă 	{ 0x42, "Pool 0 invalid / pool 1 size < pool 0 size (allocate mode)"},
12994cebd9dSHoria Geantă 	{ 0x43, "Annotation output enabled but ASAR = 0 (allocate mode)"},
13094cebd9dSHoria Geantă 	{ 0x44, "Unsupported or reserved frame format or SGHR = 1 (reuse mode)"},
13194cebd9dSHoria Geantă 	{ 0x45, "DHR correction underflow (reuse mode, single buffer format)"},
13294cebd9dSHoria Geantă 	{ 0x46, "Annotation length exceeds offset (reuse mode)"},
13394cebd9dSHoria Geantă 	{ 0x48, "Annotation output enabled but ASA limited by ASAR (reuse mode)"},
13494cebd9dSHoria Geantă 	{ 0x49, "Data offset correction exceeds input frame data length (reuse mode)"},
13594cebd9dSHoria Geantă 	{ 0x4B, "Annotation output enabled but ASA cannote be expanded (frame list)"},
13694cebd9dSHoria Geantă 	{ 0x51, "Unsupported IF reuse mode"},
13794cebd9dSHoria Geantă 	{ 0x52, "Unsupported FL use mode"},
13894cebd9dSHoria Geantă 	{ 0x53, "Unsupported RJD use mode"},
13994cebd9dSHoria Geantă 	{ 0x54, "Unsupported inline descriptor use mode"},
14094cebd9dSHoria Geantă 	{ 0xC0, "Table buffer pool 0 depletion"},
14194cebd9dSHoria Geantă 	{ 0xC1, "Table buffer pool 1 depletion"},
14294cebd9dSHoria Geantă 	{ 0xC2, "Data buffer pool 0 depletion, no OF allocated"},
14394cebd9dSHoria Geantă 	{ 0xC3, "Data buffer pool 1 depletion, no OF allocated"},
14494cebd9dSHoria Geantă 	{ 0xC4, "Data buffer pool 0 depletion, partial OF allocated"},
14594cebd9dSHoria Geantă 	{ 0xC5, "Data buffer pool 1 depletion, partial OF allocated"},
14694cebd9dSHoria Geantă 	{ 0xD0, "FLC read error"},
14794cebd9dSHoria Geantă 	{ 0xD1, "FL read error"},
14894cebd9dSHoria Geantă 	{ 0xD2, "FL write error"},
14994cebd9dSHoria Geantă 	{ 0xD3, "OF SGT write error"},
15094cebd9dSHoria Geantă 	{ 0xD4, "PTA read error"},
15194cebd9dSHoria Geantă 	{ 0xD5, "PTA write error"},
15294cebd9dSHoria Geantă 	{ 0xD6, "OF SGT F-bit write error"},
15394cebd9dSHoria Geantă 	{ 0xD7, "ASA write error"},
15494cebd9dSHoria Geantă 	{ 0xE1, "FLC[ICR]=0 ICID error"},
15594cebd9dSHoria Geantă 	{ 0xE2, "FLC[ICR]=1 ICID error"},
15694cebd9dSHoria Geantă 	{ 0xE4, "source of ICID flush not trusted (BDI = 0)"},
15794cebd9dSHoria Geantă };
15894cebd9dSHoria Geantă 
1599724d7adSMarek Vasut static const char * const cha_id_list[] = {
1609724d7adSMarek Vasut 	"",
1619724d7adSMarek Vasut 	"AES",
1629724d7adSMarek Vasut 	"DES",
1639724d7adSMarek Vasut 	"ARC4",
1649724d7adSMarek Vasut 	"MDHA",
1659724d7adSMarek Vasut 	"RNG",
1669724d7adSMarek Vasut 	"SNOW f8",
1679724d7adSMarek Vasut 	"Kasumi f8/9",
1689724d7adSMarek Vasut 	"PKHA",
1699724d7adSMarek Vasut 	"CRCA",
1709724d7adSMarek Vasut 	"SNOW f9",
1719724d7adSMarek Vasut 	"ZUCE",
1729724d7adSMarek Vasut 	"ZUCA",
1739724d7adSMarek Vasut };
1749724d7adSMarek Vasut 
1759724d7adSMarek Vasut static const char * const err_id_list[] = {
1769724d7adSMarek Vasut 	"No error.",
1779724d7adSMarek Vasut 	"Mode error.",
1789724d7adSMarek Vasut 	"Data size error.",
1799724d7adSMarek Vasut 	"Key size error.",
1809724d7adSMarek Vasut 	"PKHA A memory size error.",
1819724d7adSMarek Vasut 	"PKHA B memory size error.",
1829724d7adSMarek Vasut 	"Data arrived out of sequence error.",
1839724d7adSMarek Vasut 	"PKHA divide-by-zero error.",
1849724d7adSMarek Vasut 	"PKHA modulus even error.",
1859724d7adSMarek Vasut 	"DES key parity error.",
1869724d7adSMarek Vasut 	"ICV check failed.",
1879724d7adSMarek Vasut 	"Hardware error.",
1889724d7adSMarek Vasut 	"Unsupported CCM AAD size.",
1899724d7adSMarek Vasut 	"Class 1 CHA is not reset",
1909724d7adSMarek Vasut 	"Invalid CHA combination was selected",
1919724d7adSMarek Vasut 	"Invalid CHA selected.",
1929724d7adSMarek Vasut };
1939724d7adSMarek Vasut 
1949724d7adSMarek Vasut static const char * const rng_err_id_list[] = {
1959724d7adSMarek Vasut 	"",
1969724d7adSMarek Vasut 	"",
1979724d7adSMarek Vasut 	"",
1989724d7adSMarek Vasut 	"Instantiate",
1999724d7adSMarek Vasut 	"Not instantiated",
2009724d7adSMarek Vasut 	"Test instantiate",
2019724d7adSMarek Vasut 	"Prediction resistance",
2029724d7adSMarek Vasut 	"Prediction resistance and test request",
2039724d7adSMarek Vasut 	"Uninstantiate",
2049724d7adSMarek Vasut 	"Secure key generation",
2059724d7adSMarek Vasut };
2069724d7adSMarek Vasut 
207e397ee0fSMarek Vasut static void report_ccb_status(struct device *jrdev, const u32 status,
208e397ee0fSMarek Vasut 			      const char *error)
2099724d7adSMarek Vasut {
2109724d7adSMarek Vasut 	u8 cha_id = (status & JRSTA_CCBERR_CHAID_MASK) >>
2119724d7adSMarek Vasut 		    JRSTA_CCBERR_CHAID_SHIFT;
2129724d7adSMarek Vasut 	u8 err_id = status & JRSTA_CCBERR_ERRID_MASK;
213526243ccSMarek Vasut 	u8 idx = (status & JRSTA_DECOERR_INDEX_MASK) >>
214526243ccSMarek Vasut 		  JRSTA_DECOERR_INDEX_SHIFT;
2151e16322dSMarek Vasut 	char *idx_str;
2161e16322dSMarek Vasut 	const char *cha_str = "unidentified cha_id value 0x";
2171e16322dSMarek Vasut 	char cha_err_code[3] = { 0 };
2181e16322dSMarek Vasut 	const char *err_str = "unidentified err_id value 0x";
2191e16322dSMarek Vasut 	char err_err_code[3] = { 0 };
2208a475826SMarek Vasut 
221526243ccSMarek Vasut 	if (status & JRSTA_DECOERR_JUMP)
2221e16322dSMarek Vasut 		idx_str = "jump tgt desc idx";
223526243ccSMarek Vasut 	else
2241e16322dSMarek Vasut 		idx_str = "desc idx";
225526243ccSMarek Vasut 
2261e16322dSMarek Vasut 	if (cha_id < ARRAY_SIZE(cha_id_list))
2271e16322dSMarek Vasut 		cha_str = cha_id_list[cha_id];
2281e16322dSMarek Vasut 	else
2291e16322dSMarek Vasut 		snprintf(cha_err_code, sizeof(cha_err_code), "%02x", cha_id);
2309724d7adSMarek Vasut 
2319724d7adSMarek Vasut 	if ((cha_id << JRSTA_CCBERR_CHAID_SHIFT) == JRSTA_CCBERR_CHAID_RNG &&
2329724d7adSMarek Vasut 	    err_id < ARRAY_SIZE(rng_err_id_list) &&
2339724d7adSMarek Vasut 	    strlen(rng_err_id_list[err_id])) {
2349724d7adSMarek Vasut 		/* RNG-only error */
2351e16322dSMarek Vasut 		err_str = rng_err_id_list[err_id];
2369305dff7SHoria Geantă 	} else {
2371e16322dSMarek Vasut 		err_str = err_id_list[err_id];
2389305dff7SHoria Geantă 	}
239e75880ddSMarek Vasut 
2403f80be02SKim Phillips 	/*
2413f80be02SKim Phillips 	 * CCB ICV check failures are part of normal operation life;
2423f80be02SKim Phillips 	 * we leave the upper layers to do what they want with them.
2433f80be02SKim Phillips 	 */
2443f80be02SKim Phillips 	if (err_id != JRSTA_CCBERR_ERRID_ICVCHK)
2451e16322dSMarek Vasut 		dev_err(jrdev, "%08x: %s: %s %d: %s%s: %s%s\n",
2461e16322dSMarek Vasut 			status, error, idx_str, idx,
2471e16322dSMarek Vasut 			cha_str, cha_err_code,
2481e16322dSMarek Vasut 			err_str, err_err_code);
2499724d7adSMarek Vasut }
2509724d7adSMarek Vasut 
251e397ee0fSMarek Vasut static void report_jump_status(struct device *jrdev, const u32 status,
252e397ee0fSMarek Vasut 			       const char *error)
2539724d7adSMarek Vasut {
254e75880ddSMarek Vasut 	dev_err(jrdev, "%08x: %s: %s() not implemented\n",
255e75880ddSMarek Vasut 		status, error, __func__);
2569724d7adSMarek Vasut }
2579724d7adSMarek Vasut 
258e397ee0fSMarek Vasut static void report_deco_status(struct device *jrdev, const u32 status,
259e397ee0fSMarek Vasut 			       const char *error)
2609724d7adSMarek Vasut {
2614f0fa52aSMarek Vasut 	u8 err_id = status & JRSTA_DECOERR_ERROR_MASK;
262526243ccSMarek Vasut 	u8 idx = (status & JRSTA_DECOERR_INDEX_MASK) >>
263526243ccSMarek Vasut 		  JRSTA_DECOERR_INDEX_SHIFT;
2644f0fa52aSMarek Vasut 	char *idx_str;
265e397ee0fSMarek Vasut 	const char *err_str = "unidentified error value 0x";
2664f0fa52aSMarek Vasut 	char err_err_code[3] = { 0 };
2678e8ec596SKim Phillips 	int i;
2688e8ec596SKim Phillips 
269526243ccSMarek Vasut 	if (status & JRSTA_DECOERR_JUMP)
2704f0fa52aSMarek Vasut 		idx_str = "jump tgt desc idx";
271526243ccSMarek Vasut 	else
2724f0fa52aSMarek Vasut 		idx_str = "desc idx";
2738e8ec596SKim Phillips 
2746d00376aSDan Carpenter 	for (i = 0; i < ARRAY_SIZE(desc_error_list); i++)
2754f0fa52aSMarek Vasut 		if (desc_error_list[i].value == err_id)
2768e8ec596SKim Phillips 			break;
2778e8ec596SKim Phillips 
2784f0fa52aSMarek Vasut 	if (i != ARRAY_SIZE(desc_error_list) && desc_error_list[i].error_text)
2794f0fa52aSMarek Vasut 		err_str = desc_error_list[i].error_text;
2804f0fa52aSMarek Vasut 	else
2814f0fa52aSMarek Vasut 		snprintf(err_err_code, sizeof(err_err_code), "%02x", err_id);
282e75880ddSMarek Vasut 
2834f0fa52aSMarek Vasut 	dev_err(jrdev, "%08x: %s: %s %d: %s%s\n",
2844f0fa52aSMarek Vasut 		status, error, idx_str, idx, err_str, err_err_code);
2858e8ec596SKim Phillips }
2868e8ec596SKim Phillips 
28794cebd9dSHoria Geantă static void report_qi_status(struct device *qidev, const u32 status,
28894cebd9dSHoria Geantă 			     const char *error)
28994cebd9dSHoria Geantă {
29094cebd9dSHoria Geantă 	u8 err_id = status & JRSTA_QIERR_ERROR_MASK;
29194cebd9dSHoria Geantă 	const char *err_str = "unidentified error value 0x";
29294cebd9dSHoria Geantă 	char err_err_code[3] = { 0 };
29394cebd9dSHoria Geantă 	int i;
29494cebd9dSHoria Geantă 
29594cebd9dSHoria Geantă 	for (i = 0; i < ARRAY_SIZE(qi_error_list); i++)
29694cebd9dSHoria Geantă 		if (qi_error_list[i].value == err_id)
29794cebd9dSHoria Geantă 			break;
29894cebd9dSHoria Geantă 
29994cebd9dSHoria Geantă 	if (i != ARRAY_SIZE(qi_error_list) && qi_error_list[i].error_text)
30094cebd9dSHoria Geantă 		err_str = qi_error_list[i].error_text;
30194cebd9dSHoria Geantă 	else
30294cebd9dSHoria Geantă 		snprintf(err_err_code, sizeof(err_err_code), "%02x", err_id);
30394cebd9dSHoria Geantă 
30494cebd9dSHoria Geantă 	dev_err(qidev, "%08x: %s: %s%s\n",
30594cebd9dSHoria Geantă 		status, error, err_str, err_err_code);
30694cebd9dSHoria Geantă }
30794cebd9dSHoria Geantă 
308e397ee0fSMarek Vasut static void report_jr_status(struct device *jrdev, const u32 status,
309e397ee0fSMarek Vasut 			     const char *error)
3108e8ec596SKim Phillips {
311e75880ddSMarek Vasut 	dev_err(jrdev, "%08x: %s: %s() not implemented\n",
312e75880ddSMarek Vasut 		status, error, __func__);
3138e8ec596SKim Phillips }
3148e8ec596SKim Phillips 
315e397ee0fSMarek Vasut static void report_cond_code_status(struct device *jrdev, const u32 status,
316e397ee0fSMarek Vasut 				    const char *error)
3178e8ec596SKim Phillips {
318e75880ddSMarek Vasut 	dev_err(jrdev, "%08x: %s: %s() not implemented\n",
319e75880ddSMarek Vasut 		status, error, __func__);
3208e8ec596SKim Phillips }
3218e8ec596SKim Phillips 
32294cebd9dSHoria Geantă void caam_strstatus(struct device *jrdev, u32 status, bool qi_v2)
3238e8ec596SKim Phillips {
32496aef9a8SKim Phillips 	static const struct stat_src {
325e397ee0fSMarek Vasut 		void (*report_ssed)(struct device *jrdev, const u32 status,
326e397ee0fSMarek Vasut 				    const char *error);
3278a475826SMarek Vasut 		const char *error;
32849783d0fSCristian Stoica 	} status_src[16] = {
3298e8ec596SKim Phillips 		{ NULL, "No error" },
3308e8ec596SKim Phillips 		{ NULL, NULL },
3318e8ec596SKim Phillips 		{ report_ccb_status, "CCB" },
3328e8ec596SKim Phillips 		{ report_jump_status, "Jump" },
3338e8ec596SKim Phillips 		{ report_deco_status, "DECO" },
33494cebd9dSHoria Geantă 		{ report_qi_status, "Queue Manager Interface" },
3358e8ec596SKim Phillips 		{ report_jr_status, "Job Ring" },
3368e8ec596SKim Phillips 		{ report_cond_code_status, "Condition Code" },
33749783d0fSCristian Stoica 		{ NULL, NULL },
33849783d0fSCristian Stoica 		{ NULL, NULL },
33949783d0fSCristian Stoica 		{ NULL, NULL },
34049783d0fSCristian Stoica 		{ NULL, NULL },
34149783d0fSCristian Stoica 		{ NULL, NULL },
34249783d0fSCristian Stoica 		{ NULL, NULL },
34349783d0fSCristian Stoica 		{ NULL, NULL },
34449783d0fSCristian Stoica 		{ NULL, NULL },
3458e8ec596SKim Phillips 	};
3468e8ec596SKim Phillips 	u32 ssrc = status >> JRSTA_SSRC_SHIFT;
347e397ee0fSMarek Vasut 	const char *error = status_src[ssrc].error;
3488e8ec596SKim Phillips 
349867e1ee3SMarek Vasut 	/*
35049783d0fSCristian Stoica 	 * If there is an error handling function, call it to report the error.
35149783d0fSCristian Stoica 	 * Otherwise print the error source name.
352867e1ee3SMarek Vasut 	 */
35349783d0fSCristian Stoica 	if (status_src[ssrc].report_ssed)
354e397ee0fSMarek Vasut 		status_src[ssrc].report_ssed(jrdev, status, error);
35549783d0fSCristian Stoica 	else if (error)
35649783d0fSCristian Stoica 		dev_err(jrdev, "%d: %s\n", ssrc, error);
35749783d0fSCristian Stoica 	else
35849783d0fSCristian Stoica 		dev_err(jrdev, "%d: unknown error source\n", ssrc);
3598e8ec596SKim Phillips }
36094cebd9dSHoria Geantă EXPORT_SYMBOL(caam_strstatus);
361*8d818c10SHoria Geantă 
362*8d818c10SHoria Geantă MODULE_LICENSE("GPL");
363*8d818c10SHoria Geantă MODULE_DESCRIPTION("FSL CAAM error reporting");
364*8d818c10SHoria Geantă MODULE_AUTHOR("Freescale Semiconductor");
365