Commit | Line | Data |
---|---|---|
f31e4b6f AV |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright (c) 2018, Intel Corporation. */ | |
3 | ||
4 | #include "ice_common.h" | |
5 | ||
6 | /** | |
7 | * ice_aq_read_nvm | |
f9867df6 | 8 | * @hw: pointer to the HW struct |
f31e4b6f AV |
9 | * @module_typeid: module pointer location in words from the NVM beginning |
10 | * @offset: byte offset from the module beginning | |
11 | * @length: length of the section to be read (in bytes from the offset) | |
12 | * @data: command buffer (size [bytes] = length) | |
13 | * @last_command: tells if this is the last command in a series | |
14 | * @cd: pointer to command details structure or NULL | |
15 | * | |
16 | * Read the NVM using the admin queue commands (0x0701) | |
17 | */ | |
18 | static enum ice_status | |
43c89b16 | 19 | ice_aq_read_nvm(struct ice_hw *hw, u16 module_typeid, u32 offset, u16 length, |
f31e4b6f AV |
20 | void *data, bool last_command, struct ice_sq_cd *cd) |
21 | { | |
22 | struct ice_aq_desc desc; | |
23 | struct ice_aqc_nvm *cmd; | |
24 | ||
25 | cmd = &desc.params.nvm; | |
26 | ||
27 | /* In offset the highest byte must be zeroed. */ | |
28 | if (offset & 0xFF000000) | |
29 | return ICE_ERR_PARAM; | |
30 | ||
31 | ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_read); | |
32 | ||
33 | /* If this is the last command in a series, set the proper flag. */ | |
34 | if (last_command) | |
35 | cmd->cmd_flags |= ICE_AQC_NVM_LAST_CMD; | |
43c89b16 AV |
36 | cmd->module_typeid = cpu_to_le16(module_typeid); |
37 | cmd->offset_low = cpu_to_le16(offset & 0xFFFF); | |
38 | cmd->offset_high = (offset >> 16) & 0xFF; | |
f31e4b6f AV |
39 | cmd->length = cpu_to_le16(length); |
40 | ||
41 | return ice_aq_send_cmd(hw, &desc, data, length, cd); | |
42 | } | |
43 | ||
44 | /** | |
45 | * ice_check_sr_access_params - verify params for Shadow RAM R/W operations. | |
46 | * @hw: pointer to the HW structure | |
47 | * @offset: offset in words from module start | |
48 | * @words: number of words to access | |
49 | */ | |
50 | static enum ice_status | |
51 | ice_check_sr_access_params(struct ice_hw *hw, u32 offset, u16 words) | |
52 | { | |
53 | if ((offset + words) > hw->nvm.sr_words) { | |
54 | ice_debug(hw, ICE_DBG_NVM, | |
55 | "NVM error: offset beyond SR lmt.\n"); | |
56 | return ICE_ERR_PARAM; | |
57 | } | |
58 | ||
59 | if (words > ICE_SR_SECTOR_SIZE_IN_WORDS) { | |
60 | /* We can access only up to 4KB (one sector), in one AQ write */ | |
61 | ice_debug(hw, ICE_DBG_NVM, | |
62 | "NVM error: tried to access %d words, limit is %d.\n", | |
63 | words, ICE_SR_SECTOR_SIZE_IN_WORDS); | |
64 | return ICE_ERR_PARAM; | |
65 | } | |
66 | ||
67 | if (((offset + (words - 1)) / ICE_SR_SECTOR_SIZE_IN_WORDS) != | |
68 | (offset / ICE_SR_SECTOR_SIZE_IN_WORDS)) { | |
69 | /* A single access cannot spread over two sectors */ | |
70 | ice_debug(hw, ICE_DBG_NVM, | |
71 | "NVM error: cannot spread over two sectors.\n"); | |
72 | return ICE_ERR_PARAM; | |
73 | } | |
74 | ||
75 | return 0; | |
76 | } | |
77 | ||
78 | /** | |
79 | * ice_read_sr_aq - Read Shadow RAM. | |
80 | * @hw: pointer to the HW structure | |
81 | * @offset: offset in words from module start | |
82 | * @words: number of words to read | |
83 | * @data: buffer for words reads from Shadow RAM | |
84 | * @last_command: tells the AdminQ that this is the last command | |
85 | * | |
86 | * Reads 16-bit word buffers from the Shadow RAM using the admin command. | |
87 | */ | |
88 | static enum ice_status | |
89 | ice_read_sr_aq(struct ice_hw *hw, u32 offset, u16 words, u16 *data, | |
90 | bool last_command) | |
91 | { | |
92 | enum ice_status status; | |
93 | ||
94 | status = ice_check_sr_access_params(hw, offset, words); | |
95 | ||
96 | /* values in "offset" and "words" parameters are sized as words | |
97 | * (16 bits) but ice_aq_read_nvm expects these values in bytes. | |
98 | * So do this conversion while calling ice_aq_read_nvm. | |
99 | */ | |
100 | if (!status) | |
101 | status = ice_aq_read_nvm(hw, 0, 2 * offset, 2 * words, data, | |
102 | last_command, NULL); | |
103 | ||
104 | return status; | |
105 | } | |
106 | ||
107 | /** | |
108 | * ice_read_sr_word_aq - Reads Shadow RAM via AQ | |
109 | * @hw: pointer to the HW structure | |
110 | * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) | |
111 | * @data: word read from the Shadow RAM | |
112 | * | |
113 | * Reads one 16 bit word from the Shadow RAM using the ice_read_sr_aq method. | |
114 | */ | |
115 | static enum ice_status | |
116 | ice_read_sr_word_aq(struct ice_hw *hw, u16 offset, u16 *data) | |
117 | { | |
118 | enum ice_status status; | |
119 | ||
120 | status = ice_read_sr_aq(hw, offset, 1, data, true); | |
121 | if (!status) | |
feee3cb3 | 122 | *data = le16_to_cpu(*(__force __le16 *)data); |
f31e4b6f AV |
123 | |
124 | return status; | |
125 | } | |
126 | ||
4c98ab55 BA |
127 | /** |
128 | * ice_read_sr_buf_aq - Reads Shadow RAM buf via AQ | |
129 | * @hw: pointer to the HW structure | |
130 | * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) | |
131 | * @words: (in) number of words to read; (out) number of words actually read | |
132 | * @data: words read from the Shadow RAM | |
133 | * | |
134 | * Reads 16 bit words (data buf) from the SR using the ice_read_sr_aq | |
135 | * method. Ownership of the NVM is taken before reading the buffer and later | |
136 | * released. | |
137 | */ | |
138 | static enum ice_status | |
139 | ice_read_sr_buf_aq(struct ice_hw *hw, u16 offset, u16 *words, u16 *data) | |
140 | { | |
141 | enum ice_status status; | |
142 | bool last_cmd = false; | |
143 | u16 words_read = 0; | |
144 | u16 i = 0; | |
145 | ||
146 | do { | |
147 | u16 read_size, off_w; | |
148 | ||
149 | /* Calculate number of bytes we should read in this step. | |
150 | * It's not allowed to read more than one page at a time or | |
151 | * to cross page boundaries. | |
152 | */ | |
153 | off_w = offset % ICE_SR_SECTOR_SIZE_IN_WORDS; | |
154 | read_size = off_w ? | |
32a64994 BA |
155 | min_t(u16, *words, |
156 | (ICE_SR_SECTOR_SIZE_IN_WORDS - off_w)) : | |
157 | min_t(u16, (*words - words_read), | |
158 | ICE_SR_SECTOR_SIZE_IN_WORDS); | |
4c98ab55 BA |
159 | |
160 | /* Check if this is last command, if so set proper flag */ | |
161 | if ((words_read + read_size) >= *words) | |
162 | last_cmd = true; | |
163 | ||
164 | status = ice_read_sr_aq(hw, offset, read_size, | |
165 | data + words_read, last_cmd); | |
166 | if (status) | |
167 | goto read_nvm_buf_aq_exit; | |
168 | ||
169 | /* Increment counter for words already read and move offset to | |
170 | * new read location | |
171 | */ | |
172 | words_read += read_size; | |
173 | offset += read_size; | |
174 | } while (words_read < *words); | |
175 | ||
176 | for (i = 0; i < *words; i++) | |
feee3cb3 | 177 | data[i] = le16_to_cpu(((__force __le16 *)data)[i]); |
4c98ab55 BA |
178 | |
179 | read_nvm_buf_aq_exit: | |
180 | *words = words_read; | |
181 | return status; | |
182 | } | |
183 | ||
f31e4b6f AV |
184 | /** |
185 | * ice_acquire_nvm - Generic request for acquiring the NVM ownership | |
186 | * @hw: pointer to the HW structure | |
187 | * @access: NVM access type (read or write) | |
188 | * | |
189 | * This function will request NVM ownership. | |
190 | */ | |
3968540b AV |
191 | static enum ice_status |
192 | ice_acquire_nvm(struct ice_hw *hw, enum ice_aq_res_access_type access) | |
f31e4b6f AV |
193 | { |
194 | if (hw->nvm.blank_nvm_mode) | |
195 | return 0; | |
196 | ||
ff2b1321 | 197 | return ice_acquire_res(hw, ICE_NVM_RES_ID, access, ICE_NVM_TIMEOUT); |
f31e4b6f AV |
198 | } |
199 | ||
200 | /** | |
201 | * ice_release_nvm - Generic request for releasing the NVM ownership | |
202 | * @hw: pointer to the HW structure | |
203 | * | |
204 | * This function will release NVM ownership. | |
205 | */ | |
206 | static void ice_release_nvm(struct ice_hw *hw) | |
207 | { | |
208 | if (hw->nvm.blank_nvm_mode) | |
209 | return; | |
210 | ||
211 | ice_release_res(hw, ICE_NVM_RES_ID); | |
212 | } | |
213 | ||
214 | /** | |
215 | * ice_read_sr_word - Reads Shadow RAM word and acquire NVM if necessary | |
216 | * @hw: pointer to the HW structure | |
217 | * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) | |
218 | * @data: word read from the Shadow RAM | |
219 | * | |
220 | * Reads one 16 bit word from the Shadow RAM using the ice_read_sr_word_aq. | |
221 | */ | |
031f2147 | 222 | enum ice_status ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data) |
f31e4b6f AV |
223 | { |
224 | enum ice_status status; | |
225 | ||
226 | status = ice_acquire_nvm(hw, ICE_RES_READ); | |
227 | if (!status) { | |
228 | status = ice_read_sr_word_aq(hw, offset, data); | |
229 | ice_release_nvm(hw); | |
230 | } | |
231 | ||
232 | return status; | |
233 | } | |
234 | ||
235 | /** | |
236 | * ice_init_nvm - initializes NVM setting | |
f9867df6 | 237 | * @hw: pointer to the HW struct |
f31e4b6f AV |
238 | * |
239 | * This function reads and populates NVM settings such as Shadow RAM size, | |
240 | * max_timeout, and blank_nvm_mode | |
241 | */ | |
242 | enum ice_status ice_init_nvm(struct ice_hw *hw) | |
243 | { | |
031f2147 | 244 | u16 oem_hi, oem_lo, boot_cfg_tlv, boot_cfg_tlv_len; |
f31e4b6f AV |
245 | struct ice_nvm_info *nvm = &hw->nvm; |
246 | u16 eetrack_lo, eetrack_hi; | |
031f2147 | 247 | enum ice_status status; |
f31e4b6f AV |
248 | u32 fla, gens_stat; |
249 | u8 sr_size; | |
250 | ||
f9867df6 | 251 | /* The SR size is stored regardless of the NVM programming mode |
f31e4b6f AV |
252 | * as the blank mode may be used in the factory line. |
253 | */ | |
254 | gens_stat = rd32(hw, GLNVM_GENS); | |
255 | sr_size = (gens_stat & GLNVM_GENS_SR_SIZE_M) >> GLNVM_GENS_SR_SIZE_S; | |
256 | ||
257 | /* Switching to words (sr_size contains power of 2) */ | |
258 | nvm->sr_words = BIT(sr_size) * ICE_SR_WORDS_IN_1KB; | |
259 | ||
260 | /* Check if we are in the normal or blank NVM programming mode */ | |
261 | fla = rd32(hw, GLNVM_FLA); | |
262 | if (fla & GLNVM_FLA_LOCKED_M) { /* Normal programming mode */ | |
263 | nvm->blank_nvm_mode = false; | |
031f2147 MFIP |
264 | } else { |
265 | /* Blank programming mode */ | |
f31e4b6f | 266 | nvm->blank_nvm_mode = true; |
f31e4b6f AV |
267 | ice_debug(hw, ICE_DBG_NVM, |
268 | "NVM init error: unsupported blank mode.\n"); | |
031f2147 | 269 | return ICE_ERR_NVM_BLANK_MODE; |
f31e4b6f AV |
270 | } |
271 | ||
031f2147 | 272 | status = ice_read_sr_word(hw, ICE_SR_NVM_DEV_STARTER_VER, &nvm->ver); |
f31e4b6f AV |
273 | if (status) { |
274 | ice_debug(hw, ICE_DBG_INIT, | |
275 | "Failed to read DEV starter version.\n"); | |
276 | return status; | |
277 | } | |
278 | ||
279 | status = ice_read_sr_word(hw, ICE_SR_NVM_EETRACK_LO, &eetrack_lo); | |
280 | if (status) { | |
281 | ice_debug(hw, ICE_DBG_INIT, "Failed to read EETRACK lo.\n"); | |
282 | return status; | |
283 | } | |
284 | status = ice_read_sr_word(hw, ICE_SR_NVM_EETRACK_HI, &eetrack_hi); | |
285 | if (status) { | |
286 | ice_debug(hw, ICE_DBG_INIT, "Failed to read EETRACK hi.\n"); | |
287 | return status; | |
288 | } | |
289 | ||
031f2147 | 290 | nvm->eetrack = (eetrack_hi << 16) | eetrack_lo; |
f31e4b6f | 291 | |
031f2147 MFIP |
292 | status = ice_get_pfa_module_tlv(hw, &boot_cfg_tlv, &boot_cfg_tlv_len, |
293 | ICE_SR_BOOT_CFG_PTR); | |
294 | if (status) { | |
295 | ice_debug(hw, ICE_DBG_INIT, | |
296 | "Failed to read Boot Configuration Block TLV.\n"); | |
297 | return status; | |
298 | } | |
299 | ||
300 | /* Boot Configuration Block must have length at least 2 words | |
301 | * (Combo Image Version High and Combo Image Version Low) | |
302 | */ | |
303 | if (boot_cfg_tlv_len < 2) { | |
304 | ice_debug(hw, ICE_DBG_INIT, | |
305 | "Invalid Boot Configuration Block TLV size.\n"); | |
306 | return ICE_ERR_INVAL_SIZE; | |
307 | } | |
308 | ||
309 | status = ice_read_sr_word(hw, (boot_cfg_tlv + ICE_NVM_OEM_VER_OFF), | |
310 | &oem_hi); | |
311 | if (status) { | |
312 | ice_debug(hw, ICE_DBG_INIT, "Failed to read OEM_VER hi.\n"); | |
313 | return status; | |
314 | } | |
315 | ||
316 | status = ice_read_sr_word(hw, (boot_cfg_tlv + ICE_NVM_OEM_VER_OFF + 1), | |
317 | &oem_lo); | |
318 | if (status) { | |
319 | ice_debug(hw, ICE_DBG_INIT, "Failed to read OEM_VER lo.\n"); | |
320 | return status; | |
321 | } | |
322 | ||
323 | nvm->oem_ver = ((u32)oem_hi << 16) | oem_lo; | |
324 | ||
325 | return 0; | |
f31e4b6f | 326 | } |
4c98ab55 BA |
327 | |
328 | /** | |
329 | * ice_read_sr_buf - Reads Shadow RAM buf and acquire lock if necessary | |
330 | * @hw: pointer to the HW structure | |
331 | * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) | |
332 | * @words: (in) number of words to read; (out) number of words actually read | |
333 | * @data: words read from the Shadow RAM | |
334 | * | |
335 | * Reads 16 bit words (data buf) from the SR using the ice_read_nvm_buf_aq | |
336 | * method. The buf read is preceded by the NVM ownership take | |
337 | * and followed by the release. | |
338 | */ | |
339 | enum ice_status | |
340 | ice_read_sr_buf(struct ice_hw *hw, u16 offset, u16 *words, u16 *data) | |
341 | { | |
342 | enum ice_status status; | |
343 | ||
344 | status = ice_acquire_nvm(hw, ICE_RES_READ); | |
345 | if (!status) { | |
346 | status = ice_read_sr_buf_aq(hw, offset, words, data); | |
347 | ice_release_nvm(hw); | |
348 | } | |
349 | ||
350 | return status; | |
351 | } | |
0e674aeb AV |
352 | |
353 | /** | |
354 | * ice_nvm_validate_checksum | |
355 | * @hw: pointer to the HW struct | |
356 | * | |
357 | * Verify NVM PFA checksum validity (0x0706) | |
358 | */ | |
359 | enum ice_status ice_nvm_validate_checksum(struct ice_hw *hw) | |
360 | { | |
361 | struct ice_aqc_nvm_checksum *cmd; | |
362 | struct ice_aq_desc desc; | |
363 | enum ice_status status; | |
364 | ||
365 | status = ice_acquire_nvm(hw, ICE_RES_READ); | |
366 | if (status) | |
367 | return status; | |
368 | ||
369 | cmd = &desc.params.nvm_checksum; | |
370 | ||
371 | ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_nvm_checksum); | |
372 | cmd->flags = ICE_AQC_NVM_CHECKSUM_VERIFY; | |
373 | ||
374 | status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL); | |
375 | ice_release_nvm(hw); | |
376 | ||
377 | if (!status) | |
378 | if (le16_to_cpu(cmd->checksum) != ICE_AQC_NVM_CHECKSUM_CORRECT) | |
379 | status = ICE_ERR_NVM_CHECKSUM; | |
380 | ||
381 | return status; | |
382 | } |