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 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 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 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 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 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