1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, v.1,  (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://opensource.org/licenses/CDDL-1.0.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 
22 /*
23 * Copyright 2014-2017 Cavium, Inc.
24 * The contents of this file are subject to the terms of the Common Development
25 * and Distribution License, v.1,  (the "License").
26 
27 * You may not use this file except in compliance with the License.
28 
29 * You can obtain a copy of the License at available
30 * at http://opensource.org/licenses/CDDL-1.0
31 
32 * See the License for the specific language governing permissions and
33 * limitations under the License.
34 */
35 
36 #include "bcm_osal.h"
37 #include "ecore.h"
38 #include "ecore_sp_commands.h"
39 #include "ecore_dev_api.h"
40 #include "ecore_mcp.h"
41 #include "nvm_map.h"
42 #include "ecore_selftest_api.h"
43 
ecore_selftest_memory(struct ecore_dev * p_dev)44 enum _ecore_status_t ecore_selftest_memory(struct ecore_dev *p_dev)
45 {
46 	enum _ecore_status_t rc = ECORE_SUCCESS;
47 	int i;
48 
49 	for_each_hwfn(p_dev, i) {
50 		rc = ecore_sp_heartbeat_ramrod(&p_dev->hwfns[i]);
51 		if (rc != ECORE_SUCCESS)
52 			return rc;
53 	}
54 
55 	return rc;
56 }
57 
ecore_selftest_interrupt(struct ecore_dev * p_dev)58 enum _ecore_status_t ecore_selftest_interrupt(struct ecore_dev *p_dev)
59 {
60 	enum _ecore_status_t rc = ECORE_SUCCESS;
61 	int i;
62 
63 	for_each_hwfn(p_dev, i) {
64 		rc = ecore_sp_heartbeat_ramrod(&p_dev->hwfns[i]);
65 		if (rc != ECORE_SUCCESS)
66 			return rc;
67 	}
68 
69 	return rc;
70 }
71 
ecore_selftest_register(struct ecore_dev * p_dev)72 enum _ecore_status_t ecore_selftest_register(struct ecore_dev *p_dev)
73 {
74 	struct ecore_hwfn *p_hwfn;
75 	struct ecore_ptt *p_ptt;
76 	enum _ecore_status_t rc = ECORE_SUCCESS;
77 	int i;
78 
79 
80 	/* although performed by MCP, this test is per engine */
81 	for_each_hwfn(p_dev, i) {
82 		p_hwfn = &p_dev->hwfns[i];
83 		p_ptt = ecore_ptt_acquire(p_hwfn);
84 		if (!p_ptt) {
85 			DP_ERR(p_hwfn, "failed to acquire ptt\n");
86 			return ECORE_BUSY;
87 		}
88 		rc = ecore_mcp_bist_register_test(p_hwfn, p_ptt);
89 		ecore_ptt_release(p_hwfn, p_ptt);
90 		if (rc != ECORE_SUCCESS)
91 			break;
92 	}
93 
94 	return rc;
95 }
96 
ecore_selftest_clock(struct ecore_dev * p_dev)97 enum _ecore_status_t ecore_selftest_clock(struct ecore_dev *p_dev)
98 {
99 	struct ecore_hwfn *p_hwfn;
100 	struct ecore_ptt *p_ptt;
101 	enum _ecore_status_t rc = ECORE_SUCCESS;
102 	int i;
103 
104 	/* although performed by MCP, this test is per engine */
105 	for_each_hwfn(p_dev, i) {
106 		p_hwfn = &p_dev->hwfns[i];
107 		p_ptt = ecore_ptt_acquire(p_hwfn);
108 		if (!p_ptt) {
109 			DP_ERR(p_hwfn, "failed to acquire ptt\n");
110 			return ECORE_BUSY;
111 		}
112 		rc = ecore_mcp_bist_clock_test(p_hwfn, p_ptt);
113 		ecore_ptt_release(p_hwfn, p_ptt);
114 		if (rc != ECORE_SUCCESS)
115 			break;
116 	}
117 
118 	return rc;
119 }
120 
ecore_selftest_nvram(struct ecore_dev * p_dev)121 enum _ecore_status_t ecore_selftest_nvram(struct ecore_dev *p_dev)
122 {
123 	struct ecore_hwfn *p_hwfn = ECORE_LEADING_HWFN(p_dev);
124 	struct ecore_ptt *p_ptt = ecore_ptt_acquire(p_hwfn);
125 	u32 num_images, i, j, nvm_crc, calc_crc;
126 	struct bist_nvm_image_att image_att;
127 	u8 *buf = OSAL_NULL;
128 	OSAL_BE32 val;
129 	enum _ecore_status_t rc;
130 
131 	if (!p_ptt) {
132 		DP_ERR(p_hwfn, "failed to acquire ptt\n");
133 		return ECORE_BUSY;
134 	}
135 
136 	/* Acquire from MFW the amount of available images */
137 	rc = ecore_mcp_bist_nvm_test_get_num_images(p_hwfn, p_ptt, &num_images);
138 	if ((rc != ECORE_SUCCESS) || (num_images == 0)) {
139 		DP_ERR(p_hwfn, "Failed getting number of images\n");
140 		return ECORE_INVAL;
141 	}
142 
143 	/* Iterate over images and validate CRC */
144 	for (i = 0; i < num_images; i++) {
145 		/* This mailbox returns information about the image required for
146 		 * reading it.
147 		 */
148 		rc = ecore_mcp_bist_nvm_test_get_image_att(p_hwfn, p_ptt,
149 							   &image_att, i);
150 		if (rc != ECORE_SUCCESS) {
151 			DP_ERR(p_hwfn,
152 			       "Failed getting image index %d attributes\n",
153 			       i);
154 			goto err0;
155 		}
156 
157 		/* After MFW crash dump is collected - the image's CRC stops
158 		 * being valid.
159 		 */
160 		if (image_att.image_type == NVM_TYPE_MDUMP)
161 			continue;
162 
163 		DP_VERBOSE(p_hwfn, ECORE_MSG_SP, "image index %d, size %x\n", i,
164 			   image_att.len);
165 
166 		/* Allocate a buffer for holding the nvram image */
167 		buf = OSAL_ZALLOC(p_hwfn->p_dev, GFP_KERNEL, image_att.len);
168 		if (!buf) {
169 			DP_ERR(p_hwfn,
170 			       "Failed allocating memory for image index %d.\n",
171 			       i);
172 			rc = ECORE_NOMEM;
173 			goto err0;
174 		}
175 
176 		/* Read image into buffer */
177 		rc = ecore_mcp_nvm_read(p_hwfn->p_dev, image_att.nvm_start_addr,
178 					buf, image_att.len);
179 		if (rc != ECORE_SUCCESS) {
180 			DP_ERR(p_hwfn,
181 			       "Failed reading image index %d from nvm.\n", i);
182 			goto err1;
183 		}
184 
185 		/* Convert the buffer into big-endian format (excluding the
186 		 * closing 4 bytes of CRC).
187 		 */
188 		for (j = 0; j < image_att.len - 4; j += 4) {
189 			val = OSAL_CPU_TO_BE32(*(u32 *)&buf[j]);
190 			*(u32 *)&buf[j] = val;
191 		}
192 
193 		/* Calc CRC for the "actual" image buffer, i.e. not including
194 		 * the last 4 CRC bytes.
195 		 */
196 		nvm_crc = *(u32 *)(buf + image_att.len - 4);
197 		calc_crc = OSAL_CRC32(0xffffffff , buf, image_att.len - 4);
198 		calc_crc = ~OSAL_CPU_TO_BE32(calc_crc);
199 		DP_VERBOSE(p_hwfn, ECORE_MSG_SP,
200 			   "nvm crc 0x%x, calc_crc 0x%x\n", nvm_crc, calc_crc);
201 
202 		if (calc_crc != nvm_crc) {
203 			rc = ECORE_UNKNOWN_ERROR;
204 			goto err1;
205 		}
206 
207 		/* Done with this image */
208 		OSAL_FREE(p_hwfn->p_dev, buf);
209 		buf = OSAL_NULL;
210 	}
211 
212 	ecore_ptt_release(p_hwfn, p_ptt);
213 	return ECORE_SUCCESS;
214 
215 err1:
216 	OSAL_FREE(p_hwfn->p_dev, buf);
217 err0:
218 	ecore_ptt_release(p_hwfn, p_ptt);
219 	return rc;
220 }
221 
222