Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2001-2020 Intel Corporation
3 : : */
4 : :
5 : : #include <inttypes.h>
6 : :
7 : : #include "i40e_prototype.h"
8 : :
9 : : /**
10 : : * i40e_init_nvm - Initialize NVM function pointers
11 : : * @hw: pointer to the HW structure
12 : : *
13 : : * Setup the function pointers and the NVM info structure. Should be called
14 : : * once per NVM initialization, e.g. inside the i40e_init_shared_code().
15 : : * Please notice that the NVM term is used here (& in all methods covered
16 : : * in this file) as an equivalent of the FLASH part mapped into the SR.
17 : : * We are accessing FLASH always through the Shadow RAM.
18 : : **/
19 : 0 : enum i40e_status_code i40e_init_nvm(struct i40e_hw *hw)
20 : : {
21 : : struct i40e_nvm_info *nvm = &hw->nvm;
22 : : enum i40e_status_code ret_code = I40E_SUCCESS;
23 : : u32 fla, gens;
24 : : u8 sr_size;
25 : :
26 : 0 : DEBUGFUNC("i40e_init_nvm");
27 : :
28 : : /* The SR size is stored regardless of the nvm programming mode
29 : : * as the blank mode may be used in the factory line.
30 : : */
31 : 0 : gens = rd32(hw, I40E_GLNVM_GENS);
32 : 0 : sr_size = ((gens & I40E_GLNVM_GENS_SR_SIZE_MASK) >>
33 : : I40E_GLNVM_GENS_SR_SIZE_SHIFT);
34 : : /* Switching to words (sr_size contains power of 2KB) */
35 : 0 : nvm->sr_size = BIT(sr_size) * I40E_SR_WORDS_IN_1KB;
36 : :
37 : : /* Check if we are in the normal or blank NVM programming mode */
38 : 0 : fla = rd32(hw, I40E_GLNVM_FLA);
39 [ # # ]: 0 : if (fla & I40E_GLNVM_FLA_LOCKED_MASK) { /* Normal programming mode */
40 : : /* Max NVM timeout */
41 : 0 : nvm->timeout = I40E_MAX_NVM_TIMEOUT;
42 : 0 : nvm->blank_nvm_mode = false;
43 : : } else { /* Blank programming mode */
44 : 0 : nvm->blank_nvm_mode = true;
45 : : ret_code = I40E_ERR_NVM_BLANK_MODE;
46 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM, "NVM init error: unsupported blank mode.\n");
47 : : }
48 : :
49 : 0 : return ret_code;
50 : : }
51 : :
52 : : /**
53 : : * i40e_acquire_nvm - Generic request for acquiring the NVM ownership
54 : : * @hw: pointer to the HW structure
55 : : * @access: NVM access type (read or write)
56 : : *
57 : : * This function will request NVM ownership for reading
58 : : * via the proper Admin Command.
59 : : **/
60 : 0 : enum i40e_status_code i40e_acquire_nvm(struct i40e_hw *hw,
61 : : enum i40e_aq_resource_access_type access)
62 : : {
63 : : enum i40e_status_code ret_code = I40E_SUCCESS;
64 : : u32 gtime, timeout;
65 : 0 : u32 time_left = 0;
66 : :
67 : 0 : DEBUGFUNC("i40e_acquire_nvm");
68 : :
69 [ # # ]: 0 : if (hw->nvm.blank_nvm_mode)
70 : 0 : goto i40e_i40e_acquire_nvm_exit;
71 : :
72 : 0 : ret_code = i40e_aq_request_resource(hw, I40E_NVM_RESOURCE_ID, access,
73 : : 0, &time_left, NULL);
74 : : /* Reading the Global Device Timer */
75 : 0 : gtime = rd32(hw, I40E_GLVFGEN_TIMER);
76 : :
77 : : /* Store the timeout */
78 : 0 : hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time_left) + gtime;
79 : :
80 [ # # ]: 0 : if (ret_code)
81 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
82 : : "NVM acquire type %d failed time_left=%" PRIu32 " ret=%d aq_err=%d\n",
83 : : access, time_left, ret_code, hw->aq.asq_last_status);
84 : :
85 [ # # # # ]: 0 : if (ret_code && time_left) {
86 : : /* Poll until the current NVM owner timeouts */
87 : 0 : timeout = I40E_MS_TO_GTIME(I40E_MAX_NVM_TIMEOUT) + gtime;
88 [ # # # # ]: 0 : while ((s32)(gtime - timeout) < 0 && time_left) {
89 : 0 : i40e_msec_delay(10);
90 : 0 : gtime = rd32(hw, I40E_GLVFGEN_TIMER);
91 : 0 : ret_code = i40e_aq_request_resource(hw,
92 : : I40E_NVM_RESOURCE_ID,
93 : : access, 0, &time_left,
94 : : NULL);
95 [ # # ]: 0 : if (ret_code == I40E_SUCCESS) {
96 : 0 : hw->nvm.hw_semaphore_timeout =
97 : 0 : I40E_MS_TO_GTIME(time_left) + gtime;
98 : 0 : break;
99 : : }
100 : : }
101 [ # # ]: 0 : if (ret_code != I40E_SUCCESS) {
102 : 0 : hw->nvm.hw_semaphore_timeout = 0;
103 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
104 : : "NVM acquire timed out, wait %" PRIu32 " ms before trying again. status=%d aq_err=%d\n",
105 : : time_left, ret_code, hw->aq.asq_last_status);
106 : : }
107 : : }
108 : :
109 : 0 : i40e_i40e_acquire_nvm_exit:
110 : 0 : return ret_code;
111 : : }
112 : :
113 : :
114 : : /**
115 : : * i40e_acquire_nvm_ex - Specific request only for
116 : : * OID_INTEL_FLASH_INFO_TIMEOUT for acquiring the NVM ownership
117 : : * @hw: pointer to the HW structure
118 : : * @access: NVM access type (read or write)
119 : : * @custom_timeout: timeout for aquire NVM (read)
120 : : *
121 : : * This function will request NVM ownership for reading
122 : : * via the proper Admin Command.
123 : : **/
124 : :
125 : 0 : enum i40e_status_code i40e_acquire_nvm_ex(struct i40e_hw *hw,
126 : : enum i40e_aq_resource_access_type access,
127 : : u32 custom_timeout)
128 : : {
129 : : enum i40e_status_code ret_code = I40E_SUCCESS;
130 : : u32 gtime, timeout;
131 : 0 : u32 time_left = 0;
132 : :
133 : 0 : DEBUGFUNC("i40e_acquire_nvm");
134 : :
135 [ # # ]: 0 : if (hw->nvm.blank_nvm_mode)
136 : 0 : goto i40e_i40e_acquire_nvm_exit;
137 : :
138 : 0 : ret_code = i40e_aq_request_resource(hw, I40E_NVM_RESOURCE_ID, access,
139 : : 0, &time_left, NULL);
140 : : /* Reading the Global Device Timer */
141 : 0 : gtime = rd32(hw, I40E_GLVFGEN_TIMER);
142 : :
143 : : /* Store the timeout */
144 : 0 : hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time_left) + gtime;
145 : :
146 [ # # ]: 0 : if (ret_code)
147 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
148 : : "NVM acquire type %d failed time_left=%llu ret=%d aq_err=%d\n",
149 : : access, (unsigned long long)time_left, ret_code,
150 : : hw->aq.asq_last_status);
151 : :
152 [ # # # # ]: 0 : if (ret_code && time_left) {
153 : : /* Poll until the current NVM owner timeouts */
154 : 0 : timeout = I40E_MS_TO_GTIME(custom_timeout) + gtime;
155 [ # # # # ]: 0 : while ((gtime < timeout) && time_left) {
156 : 0 : i40e_msec_delay(10);
157 : 0 : gtime = rd32(hw, I40E_GLVFGEN_TIMER);
158 : 0 : ret_code = i40e_aq_request_resource(hw,
159 : : I40E_NVM_RESOURCE_ID,
160 : : access, 0, &time_left,
161 : : NULL);
162 [ # # ]: 0 : if (ret_code == I40E_SUCCESS) {
163 : 0 : hw->nvm.hw_semaphore_timeout =
164 : 0 : I40E_MS_TO_GTIME(time_left) + gtime;
165 : 0 : break;
166 : : }
167 : : }
168 [ # # ]: 0 : if (ret_code != I40E_SUCCESS) {
169 : 0 : hw->nvm.hw_semaphore_timeout = 0;
170 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
171 : : "NVM acquire timed out, wait %llu ms before trying again. status=%d aq_err=%d\n",
172 : : (unsigned long long)time_left, ret_code,
173 : : hw->aq.asq_last_status);
174 : : }
175 : : }
176 : :
177 : 0 : i40e_i40e_acquire_nvm_exit:
178 : 0 : return ret_code;
179 : : }
180 : :
181 : :
182 : : /**
183 : : * i40e_release_nvm - Generic request for releasing the NVM ownership
184 : : * @hw: pointer to the HW structure
185 : : *
186 : : * This function will release NVM resource via the proper Admin Command.
187 : : **/
188 : 0 : void i40e_release_nvm(struct i40e_hw *hw)
189 : : {
190 : : enum i40e_status_code ret_code = I40E_SUCCESS;
191 : : u32 total_delay = 0;
192 : :
193 : 0 : DEBUGFUNC("i40e_release_nvm");
194 : :
195 [ # # ]: 0 : if (hw->nvm.blank_nvm_mode)
196 : : return;
197 : :
198 : 0 : ret_code = i40e_aq_release_resource(hw, I40E_NVM_RESOURCE_ID, 0, NULL);
199 : :
200 : : /* there are some rare cases when trying to release the resource
201 : : * results in an admin Q timeout, so handle them correctly
202 : : */
203 [ # # ]: 0 : while ((ret_code == I40E_ERR_ADMIN_QUEUE_TIMEOUT) &&
204 [ # # ]: 0 : (total_delay < hw->aq.asq_cmd_timeout)) {
205 : 0 : i40e_msec_delay(1);
206 : 0 : ret_code = i40e_aq_release_resource(hw,
207 : : I40E_NVM_RESOURCE_ID, 0, NULL);
208 : 0 : total_delay++;
209 : : }
210 : : }
211 : :
212 : : /**
213 : : * i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit
214 : : * @hw: pointer to the HW structure
215 : : *
216 : : * Polls the SRCTL Shadow RAM register done bit.
217 : : **/
218 : 0 : static enum i40e_status_code i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw)
219 : : {
220 : : enum i40e_status_code ret_code = I40E_ERR_TIMEOUT;
221 : : u32 srctl, wait_cnt;
222 : :
223 : 0 : DEBUGFUNC("i40e_poll_sr_srctl_done_bit");
224 : :
225 : : /* Poll the I40E_GLNVM_SRCTL until the done bit is set */
226 [ # # ]: 0 : for (wait_cnt = 0; wait_cnt < I40E_SRRD_SRCTL_ATTEMPTS; wait_cnt++) {
227 : 0 : srctl = rd32(hw, I40E_GLNVM_SRCTL);
228 [ # # ]: 0 : if (srctl & I40E_GLNVM_SRCTL_DONE_MASK) {
229 : : ret_code = I40E_SUCCESS;
230 : : break;
231 : : }
232 : 0 : i40e_usec_delay(5);
233 : : }
234 [ # # ]: 0 : if (ret_code == I40E_ERR_TIMEOUT)
235 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM, "Done bit in GLNVM_SRCTL not set");
236 : 0 : return ret_code;
237 : : }
238 : :
239 : : /**
240 : : * i40e_read_nvm_word_srctl - Reads Shadow RAM via SRCTL register
241 : : * @hw: pointer to the HW structure
242 : : * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
243 : : * @data: word read from the Shadow RAM
244 : : *
245 : : * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.
246 : : **/
247 : 0 : STATIC enum i40e_status_code i40e_read_nvm_word_srctl(struct i40e_hw *hw,
248 : : u16 offset,
249 : : u16 *data)
250 : : {
251 : : enum i40e_status_code ret_code = I40E_ERR_TIMEOUT;
252 : : u32 sr_reg;
253 : :
254 : 0 : DEBUGFUNC("i40e_read_nvm_word_srctl");
255 : :
256 [ # # ]: 0 : if (offset >= hw->nvm.sr_size) {
257 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
258 : : "NVM read error: Offset %d beyond Shadow RAM limit %d\n",
259 : : offset, hw->nvm.sr_size);
260 : : ret_code = I40E_ERR_PARAM;
261 : 0 : goto read_nvm_exit;
262 : : }
263 : :
264 : : /* Poll the done bit first */
265 : 0 : ret_code = i40e_poll_sr_srctl_done_bit(hw);
266 [ # # ]: 0 : if (ret_code == I40E_SUCCESS) {
267 : : /* Write the address and start reading */
268 : 0 : sr_reg = ((u32)offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) |
269 : : BIT(I40E_GLNVM_SRCTL_START_SHIFT);
270 : 0 : wr32(hw, I40E_GLNVM_SRCTL, sr_reg);
271 : :
272 : : /* Poll I40E_GLNVM_SRCTL until the done bit is set */
273 : 0 : ret_code = i40e_poll_sr_srctl_done_bit(hw);
274 [ # # ]: 0 : if (ret_code == I40E_SUCCESS) {
275 : 0 : sr_reg = rd32(hw, I40E_GLNVM_SRDATA);
276 : 0 : *data = (u16)((sr_reg &
277 : : I40E_GLNVM_SRDATA_RDDATA_MASK)
278 : 0 : >> I40E_GLNVM_SRDATA_RDDATA_SHIFT);
279 : : }
280 : : }
281 [ # # ]: 0 : if (ret_code != I40E_SUCCESS)
282 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
283 : : "NVM read error: Couldn't access Shadow RAM address: 0x%x\n",
284 : : offset);
285 : :
286 : 0 : read_nvm_exit:
287 : 0 : return ret_code;
288 : : }
289 : :
290 : : /**
291 : : * i40e_read_nvm_aq - Read Shadow RAM.
292 : : * @hw: pointer to the HW structure.
293 : : * @module_pointer: module pointer location in words from the NVM beginning
294 : : * @offset: offset in words from module start
295 : : * @words: number of words to read
296 : : * @data: buffer with words to read from the Shadow RAM
297 : : * @last_command: tells the AdminQ that this is the last command
298 : : *
299 : : * Reads a 16 bit words buffer to the Shadow RAM using the admin command.
300 : : **/
301 : 0 : STATIC enum i40e_status_code i40e_read_nvm_aq(struct i40e_hw *hw,
302 : : u8 module_pointer, u32 offset,
303 : : u16 words, void *data,
304 : : bool last_command)
305 : : {
306 : : enum i40e_status_code ret_code = I40E_ERR_NVM;
307 : : struct i40e_asq_cmd_details cmd_details;
308 : :
309 : 0 : DEBUGFUNC("i40e_read_nvm_aq");
310 : :
311 : : memset(&cmd_details, 0, sizeof(cmd_details));
312 : 0 : cmd_details.wb_desc = &hw->nvm_wb_desc;
313 : :
314 : : /* Here we are checking the SR limit only for the flat memory model.
315 : : * We cannot do it for the module-based model, as we did not acquire
316 : : * the NVM resource yet (we cannot get the module pointer value).
317 : : * Firmware will check the module-based model.
318 : : */
319 [ # # ]: 0 : if ((offset + words) > hw->nvm.sr_size)
320 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
321 : : "NVM read error: offset %d beyond Shadow RAM limit %d\n",
322 : : (offset + words), hw->nvm.sr_size);
323 [ # # ]: 0 : else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS)
324 : : /* We can read only up to 4KB (one sector), in one AQ read */
325 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
326 : : "NVM read fail error: tried to read %d words, limit is %d.\n",
327 : : words, I40E_SR_SECTOR_SIZE_IN_WORDS);
328 : 0 : else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS)
329 [ # # ]: 0 : != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS))
330 : : /* A single read cannot spread over two sectors */
331 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
332 : : "NVM read error: cannot spread over two sectors in a single read offset=%d words=%d\n",
333 : : offset, words);
334 : : else
335 : 0 : ret_code = i40e_aq_read_nvm(hw, module_pointer,
336 : : 2 * offset, /*bytes*/
337 : : 2 * words, /*bytes*/
338 : : data, last_command, &cmd_details);
339 : :
340 : 0 : return ret_code;
341 : : }
342 : :
343 : : /**
344 : : * i40e_read_nvm_word_aq - Reads Shadow RAM via AQ
345 : : * @hw: pointer to the HW structure
346 : : * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
347 : : * @data: word read from the Shadow RAM
348 : : *
349 : : * Reads one 16 bit word from the Shadow RAM using the AdminQ
350 : : **/
351 : 0 : STATIC enum i40e_status_code i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset,
352 : : u16 *data)
353 : : {
354 : : enum i40e_status_code ret_code = I40E_ERR_TIMEOUT;
355 : :
356 : 0 : DEBUGFUNC("i40e_read_nvm_word_aq");
357 : :
358 : 0 : ret_code = i40e_read_nvm_aq(hw, 0x0, offset, 1, data, true);
359 : : *data = LE16_TO_CPU(*(__le16 *)data);
360 : :
361 : 0 : return ret_code;
362 : : }
363 : :
364 : : /**
365 : : * __i40e_read_nvm_word - Reads NVM word, assumes caller does the locking
366 : : * @hw: pointer to the HW structure
367 : : * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
368 : : * @data: word read from the Shadow RAM
369 : : *
370 : : * Reads one 16 bit word from the Shadow RAM.
371 : : *
372 : : * Do not use this function except in cases where the nvm lock is already
373 : : * taken via i40e_acquire_nvm().
374 : : **/
375 : 0 : enum i40e_status_code __i40e_read_nvm_word(struct i40e_hw *hw,
376 : : u16 offset,
377 : : u16 *data)
378 : : {
379 : :
380 [ # # ]: 0 : if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE)
381 : 0 : return i40e_read_nvm_word_aq(hw, offset, data);
382 : :
383 : 0 : return i40e_read_nvm_word_srctl(hw, offset, data);
384 : : }
385 : :
386 : : /**
387 : : * i40e_read_nvm_word - Reads NVM word, acquires lock if necessary
388 : : * @hw: pointer to the HW structure
389 : : * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
390 : : * @data: word read from the Shadow RAM
391 : : *
392 : : * Reads one 16 bit word from the Shadow RAM.
393 : : **/
394 : 0 : enum i40e_status_code i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
395 : : u16 *data)
396 : : {
397 : : enum i40e_status_code ret_code = I40E_SUCCESS;
398 : :
399 [ # # ]: 0 : if (hw->flags & I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK)
400 : 0 : ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
401 : :
402 [ # # ]: 0 : if (ret_code)
403 : : return ret_code;
404 : 0 : ret_code = __i40e_read_nvm_word(hw, offset, data);
405 : :
406 [ # # ]: 0 : if (hw->flags & I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK)
407 : 0 : i40e_release_nvm(hw);
408 : : return ret_code;
409 : : }
410 : :
411 : : /**
412 : : * i40e_read_nvm_word_ex - Specific request only for
413 : : * OID_INTEL_FLASH_INFO_TIMEOUT for Reads NVM word, acquires lock if necessary
414 : : * @hw: pointer to the HW structure
415 : : * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
416 : : * @data: word read from the Shadow RAM
417 : : * @custom_timeout: timeout for aquire NVM (read)
418 : : *
419 : : * Reads one 16 bit word from the Shadow RAM.
420 : : **/
421 : 0 : enum i40e_status_code i40e_read_nvm_word_ex(struct i40e_hw *hw, u16 offset,
422 : : u16 *data, u32 custom_timeout)
423 : : {
424 : : enum i40e_status_code ret_code = I40E_SUCCESS;
425 : :
426 [ # # ]: 0 : if (hw->flags & I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK)
427 : 0 : ret_code = i40e_acquire_nvm_ex(hw, I40E_RESOURCE_READ, custom_timeout);
428 : :
429 [ # # ]: 0 : if (ret_code)
430 : : return ret_code;
431 : 0 : ret_code = __i40e_read_nvm_word(hw, offset, data);
432 [ # # ]: 0 : if (hw->flags & I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK)
433 : 0 : i40e_release_nvm(hw);
434 : : return ret_code;
435 : : }
436 : :
437 : : /**
438 : : * i40e_read_nvm_module_data - Reads NVM Buffer to specified memory location
439 : : * @hw: Pointer to the HW structure
440 : : * @module_ptr: Pointer to module in words with respect to NVM beginning
441 : : * @module_offset: Offset in words from module start
442 : : * @data_offset: Offset in words from reading data area start
443 : : * @words_data_size: Words to read from NVM
444 : : * @data_ptr: Pointer to memory location where resulting buffer will be stored
445 : : **/
446 : : enum i40e_status_code
447 : 0 : i40e_read_nvm_module_data(struct i40e_hw *hw, u8 module_ptr, u16 module_offset,
448 : : u16 data_offset, u16 words_data_size, u16 *data_ptr)
449 : : {
450 : : enum i40e_status_code status;
451 : 0 : u16 specific_ptr = 0;
452 : 0 : u16 ptr_value = 0;
453 : : u16 offset = 0;
454 : :
455 [ # # ]: 0 : if (module_ptr != 0) {
456 : 0 : status = i40e_read_nvm_word(hw, module_ptr, &ptr_value);
457 [ # # ]: 0 : if (status != I40E_SUCCESS) {
458 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_ALL,
459 : : "Reading nvm word failed.Error code: %d.\n",
460 : : status);
461 : 0 : return I40E_ERR_NVM;
462 : : }
463 : : }
464 : : #define I40E_NVM_INVALID_PTR_VAL 0x7FFF
465 : : #define I40E_NVM_INVALID_VAL 0xFFFF
466 : :
467 : : /* Pointer not initialized */
468 [ # # ]: 0 : if (ptr_value == I40E_NVM_INVALID_PTR_VAL ||
469 : : ptr_value == I40E_NVM_INVALID_VAL) {
470 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_ALL, "Pointer not initialized.\n");
471 : 0 : return I40E_ERR_BAD_PTR;
472 : : }
473 : :
474 : : /* Check whether the module is in SR mapped area or outside */
475 [ # # ]: 0 : if (ptr_value & I40E_PTR_TYPE) {
476 : : /* Pointer points outside of the Shared RAM mapped area */
477 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_ALL,
478 : : "Reading nvm data failed. Pointer points outside of the Shared RAM mapped area.\n");
479 : :
480 : 0 : return I40E_ERR_PARAM;
481 : : } else {
482 : : /* Read from the Shadow RAM */
483 : :
484 : 0 : status = i40e_read_nvm_word(hw, ptr_value + module_offset,
485 : : &specific_ptr);
486 [ # # ]: 0 : if (status != I40E_SUCCESS) {
487 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_ALL,
488 : : "Reading nvm word failed.Error code: %d.\n",
489 : : status);
490 : 0 : return I40E_ERR_NVM;
491 : : }
492 : :
493 : 0 : offset = ptr_value + module_offset + specific_ptr +
494 : : data_offset;
495 : :
496 : 0 : status = i40e_read_nvm_buffer(hw, offset, &words_data_size,
497 : : data_ptr);
498 [ # # ]: 0 : if (status != I40E_SUCCESS) {
499 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_ALL,
500 : : "Reading nvm buffer failed.Error code: %d.\n",
501 : : status);
502 : : }
503 : : }
504 : :
505 : : return status;
506 : : }
507 : :
508 : : /**
509 : : * i40e_read_nvm_buffer_srctl - Reads Shadow RAM buffer via SRCTL register
510 : : * @hw: pointer to the HW structure
511 : : * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
512 : : * @words: (in) number of words to read; (out) number of words actually read
513 : : * @data: words read from the Shadow RAM
514 : : *
515 : : * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
516 : : * method. The buffer read is preceded by the NVM ownership take
517 : : * and followed by the release.
518 : : **/
519 : 0 : STATIC enum i40e_status_code i40e_read_nvm_buffer_srctl(struct i40e_hw *hw, u16 offset,
520 : : u16 *words, u16 *data)
521 : : {
522 : : enum i40e_status_code ret_code = I40E_SUCCESS;
523 : : u16 index, word;
524 : :
525 : 0 : DEBUGFUNC("i40e_read_nvm_buffer_srctl");
526 : :
527 : : /* Loop through the selected region */
528 [ # # ]: 0 : for (word = 0; word < *words; word++) {
529 : 0 : index = offset + word;
530 : 0 : ret_code = i40e_read_nvm_word_srctl(hw, index, &data[word]);
531 [ # # ]: 0 : if (ret_code != I40E_SUCCESS)
532 : : break;
533 : : }
534 : :
535 : : /* Update the number of words read from the Shadow RAM */
536 : 0 : *words = word;
537 : :
538 : 0 : return ret_code;
539 : : }
540 : :
541 : : /**
542 : : * i40e_read_nvm_buffer_aq - Reads Shadow RAM buffer via AQ
543 : : * @hw: pointer to the HW structure
544 : : * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
545 : : * @words: (in) number of words to read; (out) number of words actually read
546 : : * @data: words read from the Shadow RAM
547 : : *
548 : : * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_aq()
549 : : * method. The buffer read is preceded by the NVM ownership take
550 : : * and followed by the release.
551 : : **/
552 : 0 : STATIC enum i40e_status_code i40e_read_nvm_buffer_aq(struct i40e_hw *hw, u16 offset,
553 : : u16 *words, u16 *data)
554 : : {
555 : : enum i40e_status_code ret_code;
556 : : u16 read_size = *words;
557 : : bool last_cmd = false;
558 : : u16 words_read = 0;
559 : : u16 i = 0;
560 : :
561 : 0 : DEBUGFUNC("i40e_read_nvm_buffer_aq");
562 : :
563 : : do {
564 : : /* Calculate number of bytes we should read in this step.
565 : : * FVL AQ do not allow to read more than one page at a time or
566 : : * to cross page boundaries.
567 : : */
568 [ # # ]: 0 : if (offset % I40E_SR_SECTOR_SIZE_IN_WORDS)
569 : 0 : read_size = min(*words,
570 : : (u16)(I40E_SR_SECTOR_SIZE_IN_WORDS -
571 : : (offset % I40E_SR_SECTOR_SIZE_IN_WORDS)));
572 : : else
573 : 0 : read_size = min((*words - words_read),
574 : : I40E_SR_SECTOR_SIZE_IN_WORDS);
575 : :
576 : : /* Check if this is last command, if so set proper flag */
577 [ # # ]: 0 : if ((words_read + read_size) >= *words)
578 : : last_cmd = true;
579 : :
580 : 0 : ret_code = i40e_read_nvm_aq(hw, 0x0, offset, read_size,
581 : 0 : data + words_read, last_cmd);
582 [ # # ]: 0 : if (ret_code != I40E_SUCCESS)
583 : 0 : goto read_nvm_buffer_aq_exit;
584 : :
585 : : /* Increment counter for words already read and move offset to
586 : : * new read location
587 : : */
588 : 0 : words_read += read_size;
589 : 0 : offset += read_size;
590 [ # # ]: 0 : } while (words_read < *words);
591 : :
592 : : for (i = 0; i < *words; i++)
593 : : data[i] = LE16_TO_CPU(((__le16 *)data)[i]);
594 : :
595 : 0 : read_nvm_buffer_aq_exit:
596 : 0 : *words = words_read;
597 : 0 : return ret_code;
598 : : }
599 : :
600 : : /**
601 : : * __i40e_read_nvm_buffer - Reads NVM buffer, caller must acquire lock
602 : : * @hw: pointer to the HW structure
603 : : * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
604 : : * @words: (in) number of words to read; (out) number of words actually read
605 : : * @data: words read from the Shadow RAM
606 : : *
607 : : * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
608 : : * method.
609 : : **/
610 : 0 : enum i40e_status_code __i40e_read_nvm_buffer(struct i40e_hw *hw,
611 : : u16 offset,
612 : : u16 *words, u16 *data)
613 : : {
614 [ # # ]: 0 : if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE)
615 : 0 : return i40e_read_nvm_buffer_aq(hw, offset, words, data);
616 : :
617 : 0 : return i40e_read_nvm_buffer_srctl(hw, offset, words, data);
618 : : }
619 : :
620 : : /**
621 : : * i40e_read_nvm_buffer - Reads Shadow RAM buffer and acquire lock if necessary
622 : : * @hw: pointer to the HW structure
623 : : * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
624 : : * @words: (in) number of words to read; (out) number of words actually read
625 : : * @data: words read from the Shadow RAM
626 : : *
627 : : * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
628 : : * method. The buffer read is preceded by the NVM ownership take
629 : : * and followed by the release.
630 : : **/
631 : 0 : enum i40e_status_code i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
632 : : u16 *words, u16 *data)
633 : : {
634 : : enum i40e_status_code ret_code = I40E_SUCCESS;
635 : :
636 [ # # ]: 0 : if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE) {
637 : 0 : ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
638 [ # # ]: 0 : if (!ret_code) {
639 : 0 : ret_code = i40e_read_nvm_buffer_aq(hw, offset, words,
640 : : data);
641 : 0 : i40e_release_nvm(hw);
642 : : }
643 : : } else {
644 : 0 : ret_code = i40e_read_nvm_buffer_srctl(hw, offset, words, data);
645 : : }
646 : :
647 : 0 : return ret_code;
648 : : }
649 : :
650 : : /**
651 : : * i40e_write_nvm_aq - Writes Shadow RAM.
652 : : * @hw: pointer to the HW structure.
653 : : * @module_pointer: module pointer location in words from the NVM beginning
654 : : * @offset: offset in words from module start
655 : : * @words: number of words to write
656 : : * @data: buffer with words to write to the Shadow RAM
657 : : * @last_command: tells the AdminQ that this is the last command
658 : : *
659 : : * Writes a 16 bit words buffer to the Shadow RAM using the admin command.
660 : : **/
661 : 0 : enum i40e_status_code i40e_write_nvm_aq(struct i40e_hw *hw, u8 module_pointer,
662 : : u32 offset, u16 words, void *data,
663 : : bool last_command)
664 : : {
665 : : enum i40e_status_code ret_code = I40E_ERR_NVM;
666 : : struct i40e_asq_cmd_details cmd_details;
667 : :
668 : 0 : DEBUGFUNC("i40e_write_nvm_aq");
669 : :
670 : : memset(&cmd_details, 0, sizeof(cmd_details));
671 : 0 : cmd_details.wb_desc = &hw->nvm_wb_desc;
672 : :
673 : : /* Here we are checking the SR limit only for the flat memory model.
674 : : * We cannot do it for the module-based model, as we did not acquire
675 : : * the NVM resource yet (we cannot get the module pointer value).
676 : : * Firmware will check the module-based model.
677 : : */
678 [ # # ]: 0 : if ((offset + words) > hw->nvm.sr_size)
679 : 0 : DEBUGOUT("NVM write error: offset beyond Shadow RAM limit.\n");
680 [ # # ]: 0 : else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS)
681 : : /* We can write only up to 4KB (one sector), in one AQ write */
682 : 0 : DEBUGOUT("NVM write fail error: cannot write more than 4KB in a single write.\n");
683 : 0 : else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS)
684 [ # # ]: 0 : != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS))
685 : : /* A single write cannot spread over two sectors */
686 : 0 : DEBUGOUT("NVM write error: cannot spread over two sectors in a single write.\n");
687 : : else
688 : 0 : ret_code = i40e_aq_update_nvm(hw, module_pointer,
689 : : 2 * offset, /*bytes*/
690 : : 2 * words, /*bytes*/
691 : : data, last_command, 0,
692 : : &cmd_details);
693 : :
694 : 0 : return ret_code;
695 : : }
696 : :
697 : : /**
698 : : * __i40e_write_nvm_word - Writes Shadow RAM word
699 : : * @hw: pointer to the HW structure
700 : : * @offset: offset of the Shadow RAM word to write
701 : : * @data: word to write to the Shadow RAM
702 : : *
703 : : * Writes a 16 bit word to the SR using the i40e_write_nvm_aq() method.
704 : : * NVM ownership have to be acquired and released (on ARQ completion event
705 : : * reception) by caller. To commit SR to NVM update checksum function
706 : : * should be called.
707 : : **/
708 : 0 : enum i40e_status_code __i40e_write_nvm_word(struct i40e_hw *hw, u32 offset,
709 : : void *data)
710 : : {
711 : 0 : DEBUGFUNC("i40e_write_nvm_word");
712 : :
713 : : *((__le16 *)data) = CPU_TO_LE16(*((u16 *)data));
714 : :
715 : : /* Value 0x00 below means that we treat SR as a flat mem */
716 : 0 : return i40e_write_nvm_aq(hw, 0x00, offset, 1, data, false);
717 : : }
718 : :
719 : : /**
720 : : * __i40e_write_nvm_buffer - Writes Shadow RAM buffer
721 : : * @hw: pointer to the HW structure
722 : : * @module_pointer: module pointer location in words from the NVM beginning
723 : : * @offset: offset of the Shadow RAM buffer to write
724 : : * @words: number of words to write
725 : : * @data: words to write to the Shadow RAM
726 : : *
727 : : * Writes a 16 bit words buffer to the Shadow RAM using the admin command.
728 : : * NVM ownership must be acquired before calling this function and released
729 : : * on ARQ completion event reception by caller. To commit SR to NVM update
730 : : * checksum function should be called.
731 : : **/
732 : 0 : enum i40e_status_code __i40e_write_nvm_buffer(struct i40e_hw *hw,
733 : : u8 module_pointer, u32 offset,
734 : : u16 words, void *data)
735 : : {
736 : : __le16 *le_word_ptr = (__le16 *)data;
737 : : u16 *word_ptr = (u16 *)data;
738 : : u32 i = 0;
739 : :
740 : 0 : DEBUGFUNC("i40e_write_nvm_buffer");
741 : :
742 : : for (i = 0; i < words; i++)
743 : : le_word_ptr[i] = CPU_TO_LE16(word_ptr[i]);
744 : :
745 : : /* Here we will only write one buffer as the size of the modules
746 : : * mirrored in the Shadow RAM is always less than 4K.
747 : : */
748 : 0 : return i40e_write_nvm_aq(hw, module_pointer, offset, words,
749 : : data, false);
750 : : }
751 : :
752 : : /**
753 : : * i40e_calc_nvm_checksum - Calculates and returns the checksum
754 : : * @hw: pointer to hardware structure
755 : : * @checksum: pointer to the checksum
756 : : *
757 : : * This function calculates SW Checksum that covers the whole 64kB shadow RAM
758 : : * except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD
759 : : * is customer specific and unknown. Therefore, this function skips all maximum
760 : : * possible size of VPD (1kB).
761 : : **/
762 : 0 : enum i40e_status_code i40e_calc_nvm_checksum(struct i40e_hw *hw, u16 *checksum)
763 : : {
764 : : enum i40e_status_code ret_code = I40E_SUCCESS;
765 : : struct i40e_virt_mem vmem;
766 : 0 : u16 pcie_alt_module = 0;
767 : : u16 checksum_local = 0;
768 : 0 : u16 vpd_module = 0;
769 : : u16 *data;
770 : : u16 i = 0;
771 : :
772 : 0 : DEBUGFUNC("i40e_calc_nvm_checksum");
773 : :
774 : 0 : ret_code = i40e_allocate_virt_mem(hw, &vmem,
775 : : I40E_SR_SECTOR_SIZE_IN_WORDS * sizeof(u16));
776 [ # # ]: 0 : if (ret_code)
777 : 0 : goto i40e_calc_nvm_checksum_exit;
778 : 0 : data = (u16 *)vmem.va;
779 : :
780 : : /* read pointer to VPD area */
781 : 0 : ret_code = __i40e_read_nvm_word(hw, I40E_SR_VPD_PTR, &vpd_module);
782 [ # # ]: 0 : if (ret_code != I40E_SUCCESS) {
783 : : ret_code = I40E_ERR_NVM_CHECKSUM;
784 : 0 : goto i40e_calc_nvm_checksum_exit;
785 : : }
786 : :
787 : : /* read pointer to PCIe Alt Auto-load module */
788 : 0 : ret_code = __i40e_read_nvm_word(hw, I40E_SR_PCIE_ALT_AUTO_LOAD_PTR,
789 : : &pcie_alt_module);
790 [ # # ]: 0 : if (ret_code != I40E_SUCCESS) {
791 : : ret_code = I40E_ERR_NVM_CHECKSUM;
792 : 0 : goto i40e_calc_nvm_checksum_exit;
793 : : }
794 : :
795 : : /* Calculate SW checksum that covers the whole 64kB shadow RAM
796 : : * except the VPD and PCIe ALT Auto-load modules
797 : : */
798 [ # # ]: 0 : for (i = 0; i < hw->nvm.sr_size; i++) {
799 : : /* Read SR page */
800 [ # # ]: 0 : if ((i % I40E_SR_SECTOR_SIZE_IN_WORDS) == 0) {
801 : 0 : u16 words = I40E_SR_SECTOR_SIZE_IN_WORDS;
802 : :
803 : 0 : ret_code = __i40e_read_nvm_buffer(hw, i, &words, data);
804 [ # # ]: 0 : if (ret_code != I40E_SUCCESS) {
805 : : ret_code = I40E_ERR_NVM_CHECKSUM;
806 : 0 : goto i40e_calc_nvm_checksum_exit;
807 : : }
808 : : }
809 : :
810 : : /* Skip Checksum word */
811 [ # # ]: 0 : if (i == I40E_SR_SW_CHECKSUM_WORD)
812 : 0 : continue;
813 : : /* Skip VPD module (convert byte size to word count) */
814 [ # # ]: 0 : if ((i >= (u32)vpd_module) &&
815 [ # # ]: 0 : (i < ((u32)vpd_module +
816 : : (I40E_SR_VPD_MODULE_MAX_SIZE / 2)))) {
817 : 0 : continue;
818 : : }
819 : : /* Skip PCIe ALT module (convert byte size to word count) */
820 [ # # ]: 0 : if ((i >= (u32)pcie_alt_module) &&
821 [ # # ]: 0 : (i < ((u32)pcie_alt_module +
822 : : (I40E_SR_PCIE_ALT_MODULE_MAX_SIZE / 2)))) {
823 : 0 : continue;
824 : : }
825 : :
826 : 0 : checksum_local += data[i % I40E_SR_SECTOR_SIZE_IN_WORDS];
827 : : }
828 : :
829 : 0 : *checksum = (u16)I40E_SR_SW_CHECKSUM_BASE - checksum_local;
830 : :
831 : 0 : i40e_calc_nvm_checksum_exit:
832 : 0 : i40e_free_virt_mem(hw, &vmem);
833 : 0 : return ret_code;
834 : : }
835 : :
836 : : /**
837 : : * i40e_update_nvm_checksum - Updates the NVM checksum
838 : : * @hw: pointer to hardware structure
839 : : *
840 : : * NVM ownership must be acquired before calling this function and released
841 : : * on ARQ completion event reception by caller.
842 : : * This function will commit SR to NVM.
843 : : **/
844 : 0 : enum i40e_status_code i40e_update_nvm_checksum(struct i40e_hw *hw)
845 : : {
846 : : enum i40e_status_code ret_code = I40E_SUCCESS;
847 : : u16 checksum;
848 : : __le16 le_sum;
849 : :
850 : 0 : DEBUGFUNC("i40e_update_nvm_checksum");
851 : :
852 : 0 : ret_code = i40e_calc_nvm_checksum(hw, &checksum);
853 [ # # ]: 0 : if (ret_code == I40E_SUCCESS) {
854 : 0 : le_sum = CPU_TO_LE16(checksum);
855 : 0 : ret_code = i40e_write_nvm_aq(hw, 0x00, I40E_SR_SW_CHECKSUM_WORD,
856 : : 1, &le_sum, true);
857 : : }
858 : :
859 : 0 : return ret_code;
860 : : }
861 : :
862 : : /**
863 : : * i40e_validate_nvm_checksum - Validate EEPROM checksum
864 : : * @hw: pointer to hardware structure
865 : : * @checksum: calculated checksum
866 : : *
867 : : * Performs checksum calculation and validates the NVM SW checksum. If the
868 : : * caller does not need checksum, the value can be NULL.
869 : : **/
870 : 0 : enum i40e_status_code i40e_validate_nvm_checksum(struct i40e_hw *hw,
871 : : u16 *checksum)
872 : : {
873 : : enum i40e_status_code ret_code = I40E_SUCCESS;
874 : 0 : u16 checksum_sr = 0;
875 : 0 : u16 checksum_local = 0;
876 : :
877 : 0 : DEBUGFUNC("i40e_validate_nvm_checksum");
878 : :
879 : : /* We must acquire the NVM lock in order to correctly synchronize the
880 : : * NVM accesses across multiple PFs. Without doing so it is possible
881 : : * for one of the PFs to read invalid data potentially indicating that
882 : : * the checksum is invalid.
883 : : */
884 : 0 : ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
885 [ # # ]: 0 : if (ret_code)
886 : : return ret_code;
887 : 0 : ret_code = i40e_calc_nvm_checksum(hw, &checksum_local);
888 : 0 : __i40e_read_nvm_word(hw, I40E_SR_SW_CHECKSUM_WORD, &checksum_sr);
889 : 0 : i40e_release_nvm(hw);
890 [ # # ]: 0 : if (ret_code)
891 : : return ret_code;
892 : :
893 : : /* Verify read checksum from EEPROM is the same as
894 : : * calculated checksum
895 : : */
896 [ # # ]: 0 : if (checksum_local != checksum_sr)
897 : : ret_code = I40E_ERR_NVM_CHECKSUM;
898 : :
899 : : /* If the user cares, return the calculated checksum */
900 [ # # ]: 0 : if (checksum)
901 : 0 : *checksum = checksum_local;
902 : :
903 : : return ret_code;
904 : : }
905 : :
906 : : STATIC enum i40e_status_code i40e_nvmupd_state_init(struct i40e_hw *hw,
907 : : struct i40e_nvm_access *cmd,
908 : : u8 *bytes, int *perrno);
909 : : STATIC enum i40e_status_code i40e_nvmupd_state_reading(struct i40e_hw *hw,
910 : : struct i40e_nvm_access *cmd,
911 : : u8 *bytes, int *perrno);
912 : : STATIC enum i40e_status_code i40e_nvmupd_state_writing(struct i40e_hw *hw,
913 : : struct i40e_nvm_access *cmd,
914 : : u8 *bytes, int *perrno);
915 : : STATIC enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw,
916 : : struct i40e_nvm_access *cmd,
917 : : int *perrno);
918 : : STATIC enum i40e_status_code i40e_nvmupd_nvm_erase(struct i40e_hw *hw,
919 : : struct i40e_nvm_access *cmd,
920 : : int *perrno);
921 : : STATIC enum i40e_status_code i40e_nvmupd_nvm_write(struct i40e_hw *hw,
922 : : struct i40e_nvm_access *cmd,
923 : : u8 *bytes, int *perrno);
924 : : STATIC enum i40e_status_code i40e_nvmupd_nvm_read(struct i40e_hw *hw,
925 : : struct i40e_nvm_access *cmd,
926 : : u8 *bytes, int *perrno);
927 : : STATIC enum i40e_status_code i40e_nvmupd_exec_aq(struct i40e_hw *hw,
928 : : struct i40e_nvm_access *cmd,
929 : : u8 *bytes, int *perrno);
930 : : STATIC enum i40e_status_code i40e_nvmupd_get_aq_result(struct i40e_hw *hw,
931 : : struct i40e_nvm_access *cmd,
932 : : u8 *bytes, int *perrno);
933 : : STATIC enum i40e_status_code i40e_nvmupd_get_aq_event(struct i40e_hw *hw,
934 : : struct i40e_nvm_access *cmd,
935 : : u8 *bytes, int *perrno);
936 : : STATIC INLINE u8 i40e_nvmupd_get_module(u32 val)
937 : : {
938 : 0 : return (u8)(val & I40E_NVM_MOD_PNT_MASK);
939 : : }
940 : : STATIC INLINE u8 i40e_nvmupd_get_transaction(u32 val)
941 : : {
942 : 0 : return (u8)((val & I40E_NVM_TRANS_MASK) >> I40E_NVM_TRANS_SHIFT);
943 : : }
944 : :
945 : : STATIC INLINE u8 i40e_nvmupd_get_preservation_flags(u32 val)
946 : : {
947 : 0 : return (u8)((val & I40E_NVM_PRESERVATION_FLAGS_MASK) >>
948 : : I40E_NVM_PRESERVATION_FLAGS_SHIFT);
949 : : }
950 : :
951 : : STATIC const char *i40e_nvm_update_state_str[] = {
952 : : "I40E_NVMUPD_INVALID",
953 : : "I40E_NVMUPD_READ_CON",
954 : : "I40E_NVMUPD_READ_SNT",
955 : : "I40E_NVMUPD_READ_LCB",
956 : : "I40E_NVMUPD_READ_SA",
957 : : "I40E_NVMUPD_WRITE_ERA",
958 : : "I40E_NVMUPD_WRITE_CON",
959 : : "I40E_NVMUPD_WRITE_SNT",
960 : : "I40E_NVMUPD_WRITE_LCB",
961 : : "I40E_NVMUPD_WRITE_SA",
962 : : "I40E_NVMUPD_CSUM_CON",
963 : : "I40E_NVMUPD_CSUM_SA",
964 : : "I40E_NVMUPD_CSUM_LCB",
965 : : "I40E_NVMUPD_STATUS",
966 : : "I40E_NVMUPD_EXEC_AQ",
967 : : "I40E_NVMUPD_GET_AQ_RESULT",
968 : : "I40E_NVMUPD_GET_AQ_EVENT",
969 : : "I40E_NVMUPD_GET_FEATURES",
970 : : };
971 : :
972 : : /**
973 : : * i40e_nvmupd_command - Process an NVM update command
974 : : * @hw: pointer to hardware structure
975 : : * @cmd: pointer to nvm update command
976 : : * @bytes: pointer to the data buffer
977 : : * @perrno: pointer to return error code
978 : : *
979 : : * Dispatches command depending on what update state is current
980 : : **/
981 : 0 : enum i40e_status_code i40e_nvmupd_command(struct i40e_hw *hw,
982 : : struct i40e_nvm_access *cmd,
983 : : u8 *bytes, int *perrno)
984 : : {
985 : : enum i40e_status_code status;
986 : : enum i40e_nvmupd_cmd upd_cmd;
987 : :
988 : 0 : DEBUGFUNC("i40e_nvmupd_command");
989 : :
990 : : /* assume success */
991 : 0 : *perrno = 0;
992 : :
993 : : /* early check for status command and debug msgs */
994 : 0 : upd_cmd = i40e_nvmupd_validate_command(hw, cmd, perrno);
995 : :
996 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM, "%s state %d nvm_release_on_hold %d opc 0x%04x cmd 0x%08x config 0x%08x offset 0x%08x data_size 0x%08x\n",
997 : : i40e_nvm_update_state_str[upd_cmd],
998 : : hw->nvmupd_state,
999 : : hw->nvm_release_on_done, hw->nvm_wait_opcode,
1000 : : cmd->command, cmd->config, cmd->offset, cmd->data_size);
1001 : :
1002 [ # # ]: 0 : if (upd_cmd == I40E_NVMUPD_INVALID) {
1003 : 0 : *perrno = -EFAULT;
1004 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
1005 : : "i40e_nvmupd_validate_command returns %d errno %d\n",
1006 : : upd_cmd, *perrno);
1007 : : }
1008 : :
1009 : : /* a status request returns immediately rather than
1010 : : * going into the state machine
1011 : : */
1012 [ # # ]: 0 : if (upd_cmd == I40E_NVMUPD_STATUS) {
1013 [ # # ]: 0 : if (!cmd->data_size) {
1014 : 0 : *perrno = -EFAULT;
1015 : 0 : return I40E_ERR_BUF_TOO_SHORT;
1016 : : }
1017 : :
1018 : 0 : bytes[0] = hw->nvmupd_state;
1019 : :
1020 [ # # ]: 0 : if (cmd->data_size >= 4) {
1021 : 0 : bytes[1] = 0;
1022 : 0 : *((u16 *)&bytes[2]) = hw->nvm_wait_opcode;
1023 : : }
1024 : :
1025 : : /* Clear error status on read */
1026 [ # # ]: 0 : if (hw->nvmupd_state == I40E_NVMUPD_STATE_ERROR)
1027 : 0 : hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
1028 : :
1029 : 0 : return I40E_SUCCESS;
1030 : : }
1031 : :
1032 : : /*
1033 : : * A supported features request returns immediately
1034 : : * rather than going into state machine
1035 : : */
1036 [ # # ]: 0 : if (upd_cmd == I40E_NVMUPD_FEATURES) {
1037 [ # # ]: 0 : if (cmd->data_size < hw->nvmupd_features.size) {
1038 : 0 : *perrno = -EFAULT;
1039 : 0 : return I40E_ERR_BUF_TOO_SHORT;
1040 : : }
1041 : :
1042 : : /*
1043 : : * If buffer is bigger than i40e_nvmupd_features structure,
1044 : : * make sure the trailing bytes are set to 0x0.
1045 : : */
1046 [ # # ]: 0 : if (cmd->data_size > hw->nvmupd_features.size)
1047 : 0 : i40e_memset(bytes + hw->nvmupd_features.size, 0x0,
1048 : : cmd->data_size - hw->nvmupd_features.size,
1049 : : I40E_NONDMA_MEM);
1050 : :
1051 [ # # ]: 0 : i40e_memcpy(bytes, &hw->nvmupd_features,
1052 : : hw->nvmupd_features.size, I40E_NONDMA_MEM);
1053 : :
1054 : 0 : return I40E_SUCCESS;
1055 : : }
1056 : :
1057 : : /* Clear status even it is not read and log */
1058 [ # # ]: 0 : if (hw->nvmupd_state == I40E_NVMUPD_STATE_ERROR) {
1059 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
1060 : : "Clearing I40E_NVMUPD_STATE_ERROR state without reading\n");
1061 : 0 : hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
1062 : : }
1063 : :
1064 : : /* Acquire lock to prevent race condition where adminq_task
1065 : : * can execute after i40e_nvmupd_nvm_read/write but before state
1066 : : * variables (nvm_wait_opcode, nvm_release_on_done) are updated.
1067 : : *
1068 : : * During NVMUpdate, it is observed that lock could be held for
1069 : : * ~5ms for most commands. However lock is held for ~60ms for
1070 : : * NVMUPD_CSUM_LCB command.
1071 : : */
1072 : 0 : i40e_acquire_spinlock(&hw->aq.arq_spinlock);
1073 [ # # # # : 0 : switch (hw->nvmupd_state) {
# ]
1074 : 0 : case I40E_NVMUPD_STATE_INIT:
1075 : 0 : status = i40e_nvmupd_state_init(hw, cmd, bytes, perrno);
1076 : 0 : break;
1077 : :
1078 : 0 : case I40E_NVMUPD_STATE_READING:
1079 : 0 : status = i40e_nvmupd_state_reading(hw, cmd, bytes, perrno);
1080 : 0 : break;
1081 : :
1082 : 0 : case I40E_NVMUPD_STATE_WRITING:
1083 : 0 : status = i40e_nvmupd_state_writing(hw, cmd, bytes, perrno);
1084 : 0 : break;
1085 : :
1086 : 0 : case I40E_NVMUPD_STATE_INIT_WAIT:
1087 : : case I40E_NVMUPD_STATE_WRITE_WAIT:
1088 : : /* if we need to stop waiting for an event, clear
1089 : : * the wait info and return before doing anything else
1090 : : */
1091 [ # # ]: 0 : if (cmd->offset == 0xffff) {
1092 : 0 : i40e_nvmupd_clear_wait_state(hw);
1093 : : status = I40E_SUCCESS;
1094 : 0 : break;
1095 : : }
1096 : :
1097 : : status = I40E_ERR_NOT_READY;
1098 : 0 : *perrno = -EBUSY;
1099 : 0 : break;
1100 : :
1101 : 0 : default:
1102 : : /* invalid state, should never happen */
1103 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
1104 : : "NVMUPD: no such state %d\n", hw->nvmupd_state);
1105 : : status = I40E_NOT_SUPPORTED;
1106 : 0 : *perrno = -ESRCH;
1107 : 0 : break;
1108 : : }
1109 : :
1110 : : i40e_release_spinlock(&hw->aq.arq_spinlock);
1111 : 0 : return status;
1112 : : }
1113 : :
1114 : : /**
1115 : : * i40e_nvmupd_state_init - Handle NVM update state Init
1116 : : * @hw: pointer to hardware structure
1117 : : * @cmd: pointer to nvm update command buffer
1118 : : * @bytes: pointer to the data buffer
1119 : : * @perrno: pointer to return error code
1120 : : *
1121 : : * Process legitimate commands of the Init state and conditionally set next
1122 : : * state. Reject all other commands.
1123 : : **/
1124 : 0 : STATIC enum i40e_status_code i40e_nvmupd_state_init(struct i40e_hw *hw,
1125 : : struct i40e_nvm_access *cmd,
1126 : : u8 *bytes, int *perrno)
1127 : : {
1128 : : enum i40e_status_code status = I40E_SUCCESS;
1129 : : enum i40e_nvmupd_cmd upd_cmd;
1130 : :
1131 : 0 : DEBUGFUNC("i40e_nvmupd_state_init");
1132 : :
1133 : 0 : upd_cmd = i40e_nvmupd_validate_command(hw, cmd, perrno);
1134 : :
1135 [ # # # # : 0 : switch (upd_cmd) {
# # # # #
# ]
1136 : 0 : case I40E_NVMUPD_READ_SA:
1137 : 0 : status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
1138 [ # # ]: 0 : if (status) {
1139 : 0 : *perrno = i40e_aq_rc_to_posix(status,
1140 : 0 : hw->aq.asq_last_status);
1141 : : } else {
1142 : 0 : status = i40e_nvmupd_nvm_read(hw, cmd, bytes, perrno);
1143 : 0 : i40e_release_nvm(hw);
1144 : : }
1145 : : break;
1146 : :
1147 : 0 : case I40E_NVMUPD_READ_SNT:
1148 : 0 : status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
1149 [ # # ]: 0 : if (status) {
1150 : 0 : *perrno = i40e_aq_rc_to_posix(status,
1151 : 0 : hw->aq.asq_last_status);
1152 : : } else {
1153 : 0 : status = i40e_nvmupd_nvm_read(hw, cmd, bytes, perrno);
1154 [ # # ]: 0 : if (status)
1155 : 0 : i40e_release_nvm(hw);
1156 : : else
1157 : 0 : hw->nvmupd_state = I40E_NVMUPD_STATE_READING;
1158 : : }
1159 : : break;
1160 : :
1161 : 0 : case I40E_NVMUPD_WRITE_ERA:
1162 : 0 : status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
1163 [ # # ]: 0 : if (status) {
1164 : 0 : *perrno = i40e_aq_rc_to_posix(status,
1165 : 0 : hw->aq.asq_last_status);
1166 : : } else {
1167 : 0 : status = i40e_nvmupd_nvm_erase(hw, cmd, perrno);
1168 [ # # ]: 0 : if (status) {
1169 : 0 : i40e_release_nvm(hw);
1170 : : } else {
1171 : 0 : hw->nvm_release_on_done = true;
1172 : 0 : hw->nvm_wait_opcode = i40e_aqc_opc_nvm_erase;
1173 : 0 : hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT;
1174 : : }
1175 : : }
1176 : : break;
1177 : :
1178 : 0 : case I40E_NVMUPD_WRITE_SA:
1179 : 0 : status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
1180 [ # # ]: 0 : if (status) {
1181 : 0 : *perrno = i40e_aq_rc_to_posix(status,
1182 : 0 : hw->aq.asq_last_status);
1183 : : } else {
1184 : 0 : status = i40e_nvmupd_nvm_write(hw, cmd, bytes, perrno);
1185 [ # # ]: 0 : if (status) {
1186 : 0 : i40e_release_nvm(hw);
1187 : : } else {
1188 : 0 : hw->nvm_release_on_done = true;
1189 : 0 : hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update;
1190 : 0 : hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT;
1191 : : }
1192 : : }
1193 : : break;
1194 : :
1195 : 0 : case I40E_NVMUPD_WRITE_SNT:
1196 : 0 : status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
1197 [ # # ]: 0 : if (status) {
1198 : 0 : *perrno = i40e_aq_rc_to_posix(status,
1199 : 0 : hw->aq.asq_last_status);
1200 : : } else {
1201 : 0 : status = i40e_nvmupd_nvm_write(hw, cmd, bytes, perrno);
1202 [ # # ]: 0 : if (status) {
1203 : 0 : i40e_release_nvm(hw);
1204 : : } else {
1205 : 0 : hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update;
1206 : 0 : hw->nvmupd_state = I40E_NVMUPD_STATE_WRITE_WAIT;
1207 : : }
1208 : : }
1209 : : break;
1210 : :
1211 : 0 : case I40E_NVMUPD_CSUM_SA:
1212 : 0 : status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
1213 [ # # ]: 0 : if (status) {
1214 : 0 : *perrno = i40e_aq_rc_to_posix(status,
1215 : 0 : hw->aq.asq_last_status);
1216 : : } else {
1217 : 0 : status = i40e_update_nvm_checksum(hw);
1218 [ # # ]: 0 : if (status) {
1219 : 0 : *perrno = hw->aq.asq_last_status ?
1220 : 0 : i40e_aq_rc_to_posix(status,
1221 [ # # ]: 0 : hw->aq.asq_last_status) :
1222 : : -EIO;
1223 : 0 : i40e_release_nvm(hw);
1224 : : } else {
1225 : 0 : hw->nvm_release_on_done = true;
1226 : 0 : hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update;
1227 : 0 : hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT;
1228 : : }
1229 : : }
1230 : : break;
1231 : :
1232 : 0 : case I40E_NVMUPD_EXEC_AQ:
1233 : 0 : status = i40e_nvmupd_exec_aq(hw, cmd, bytes, perrno);
1234 : 0 : break;
1235 : :
1236 : 0 : case I40E_NVMUPD_GET_AQ_RESULT:
1237 : 0 : status = i40e_nvmupd_get_aq_result(hw, cmd, bytes, perrno);
1238 : 0 : break;
1239 : :
1240 : 0 : case I40E_NVMUPD_GET_AQ_EVENT:
1241 : 0 : status = i40e_nvmupd_get_aq_event(hw, cmd, bytes, perrno);
1242 : 0 : break;
1243 : :
1244 : 0 : default:
1245 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
1246 : : "NVMUPD: bad cmd %s in init state\n",
1247 : : i40e_nvm_update_state_str[upd_cmd]);
1248 : : status = I40E_ERR_NVM;
1249 : 0 : *perrno = -ESRCH;
1250 : 0 : break;
1251 : : }
1252 : 0 : return status;
1253 : : }
1254 : :
1255 : : /**
1256 : : * i40e_nvmupd_state_reading - Handle NVM update state Reading
1257 : : * @hw: pointer to hardware structure
1258 : : * @cmd: pointer to nvm update command buffer
1259 : : * @bytes: pointer to the data buffer
1260 : : * @perrno: pointer to return error code
1261 : : *
1262 : : * NVM ownership is already held. Process legitimate commands and set any
1263 : : * change in state; reject all other commands.
1264 : : **/
1265 : 0 : STATIC enum i40e_status_code i40e_nvmupd_state_reading(struct i40e_hw *hw,
1266 : : struct i40e_nvm_access *cmd,
1267 : : u8 *bytes, int *perrno)
1268 : : {
1269 : : enum i40e_status_code status = I40E_SUCCESS;
1270 : : enum i40e_nvmupd_cmd upd_cmd;
1271 : :
1272 : 0 : DEBUGFUNC("i40e_nvmupd_state_reading");
1273 : :
1274 : 0 : upd_cmd = i40e_nvmupd_validate_command(hw, cmd, perrno);
1275 : :
1276 [ # # # ]: 0 : switch (upd_cmd) {
1277 : 0 : case I40E_NVMUPD_READ_SA:
1278 : : case I40E_NVMUPD_READ_CON:
1279 : 0 : status = i40e_nvmupd_nvm_read(hw, cmd, bytes, perrno);
1280 : 0 : break;
1281 : :
1282 : 0 : case I40E_NVMUPD_READ_LCB:
1283 : 0 : status = i40e_nvmupd_nvm_read(hw, cmd, bytes, perrno);
1284 : 0 : i40e_release_nvm(hw);
1285 : 0 : hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
1286 : 0 : break;
1287 : :
1288 : 0 : default:
1289 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
1290 : : "NVMUPD: bad cmd %s in reading state.\n",
1291 : : i40e_nvm_update_state_str[upd_cmd]);
1292 : : status = I40E_NOT_SUPPORTED;
1293 : 0 : *perrno = -ESRCH;
1294 : 0 : break;
1295 : : }
1296 : 0 : return status;
1297 : : }
1298 : :
1299 : : /**
1300 : : * i40e_nvmupd_state_writing - Handle NVM update state Writing
1301 : : * @hw: pointer to hardware structure
1302 : : * @cmd: pointer to nvm update command buffer
1303 : : * @bytes: pointer to the data buffer
1304 : : * @perrno: pointer to return error code
1305 : : *
1306 : : * NVM ownership is already held. Process legitimate commands and set any
1307 : : * change in state; reject all other commands
1308 : : **/
1309 : 0 : STATIC enum i40e_status_code i40e_nvmupd_state_writing(struct i40e_hw *hw,
1310 : : struct i40e_nvm_access *cmd,
1311 : : u8 *bytes, int *perrno)
1312 : : {
1313 : : enum i40e_status_code status = I40E_SUCCESS;
1314 : : enum i40e_nvmupd_cmd upd_cmd;
1315 : : bool retry_attempt = false;
1316 : :
1317 : 0 : DEBUGFUNC("i40e_nvmupd_state_writing");
1318 : :
1319 : 0 : upd_cmd = i40e_nvmupd_validate_command(hw, cmd, perrno);
1320 : :
1321 : 0 : retry:
1322 [ # # # # : 0 : switch (upd_cmd) {
# ]
1323 : 0 : case I40E_NVMUPD_WRITE_CON:
1324 : 0 : status = i40e_nvmupd_nvm_write(hw, cmd, bytes, perrno);
1325 [ # # ]: 0 : if (!status) {
1326 : 0 : hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update;
1327 : 0 : hw->nvmupd_state = I40E_NVMUPD_STATE_WRITE_WAIT;
1328 : : }
1329 : : break;
1330 : :
1331 : 0 : case I40E_NVMUPD_WRITE_LCB:
1332 : 0 : status = i40e_nvmupd_nvm_write(hw, cmd, bytes, perrno);
1333 [ # # ]: 0 : if (status) {
1334 : 0 : *perrno = hw->aq.asq_last_status ?
1335 : 0 : i40e_aq_rc_to_posix(status,
1336 [ # # ]: 0 : hw->aq.asq_last_status) :
1337 : : -EIO;
1338 : 0 : hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
1339 : : } else {
1340 : 0 : hw->nvm_release_on_done = true;
1341 : 0 : hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update;
1342 : 0 : hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT;
1343 : : }
1344 : : break;
1345 : :
1346 : 0 : case I40E_NVMUPD_CSUM_CON:
1347 : : /* Assumes the caller has acquired the nvm */
1348 : 0 : status = i40e_update_nvm_checksum(hw);
1349 [ # # ]: 0 : if (status) {
1350 : 0 : *perrno = hw->aq.asq_last_status ?
1351 : 0 : i40e_aq_rc_to_posix(status,
1352 [ # # ]: 0 : hw->aq.asq_last_status) :
1353 : : -EIO;
1354 : 0 : hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
1355 : : } else {
1356 : 0 : hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update;
1357 : 0 : hw->nvmupd_state = I40E_NVMUPD_STATE_WRITE_WAIT;
1358 : : }
1359 : : break;
1360 : :
1361 : 0 : case I40E_NVMUPD_CSUM_LCB:
1362 : : /* Assumes the caller has acquired the nvm */
1363 : 0 : status = i40e_update_nvm_checksum(hw);
1364 [ # # ]: 0 : if (status) {
1365 : 0 : *perrno = hw->aq.asq_last_status ?
1366 : 0 : i40e_aq_rc_to_posix(status,
1367 [ # # ]: 0 : hw->aq.asq_last_status) :
1368 : : -EIO;
1369 : 0 : hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
1370 : : } else {
1371 : 0 : hw->nvm_release_on_done = true;
1372 : 0 : hw->nvm_wait_opcode = i40e_aqc_opc_nvm_update;
1373 : 0 : hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT;
1374 : : }
1375 : : break;
1376 : :
1377 : 0 : default:
1378 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
1379 : : "NVMUPD: bad cmd %s in writing state.\n",
1380 : : i40e_nvm_update_state_str[upd_cmd]);
1381 : : status = I40E_NOT_SUPPORTED;
1382 : 0 : *perrno = -ESRCH;
1383 : : break;
1384 : : }
1385 : :
1386 : : /* In some circumstances, a multi-write transaction takes longer
1387 : : * than the default 3 minute timeout on the write semaphore. If
1388 : : * the write failed with an EBUSY status, this is likely the problem,
1389 : : * so here we try to reacquire the semaphore then retry the write.
1390 : : * We only do one retry, then give up.
1391 : : */
1392 [ # # # # : 0 : if (status && (hw->aq.asq_last_status == I40E_AQ_RC_EBUSY) &&
# # ]
1393 : : !retry_attempt) {
1394 : : enum i40e_status_code old_status = status;
1395 : : u32 old_asq_status = hw->aq.asq_last_status;
1396 : : u32 gtime;
1397 : :
1398 : 0 : gtime = rd32(hw, I40E_GLVFGEN_TIMER);
1399 [ # # ]: 0 : if ((s32)(gtime - hw->nvm.hw_semaphore_timeout) >= 0) {
1400 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_ALL,
1401 : : "NVMUPD: write semaphore expired (%d >= %" PRIu32 "), retrying\n",
1402 : : gtime, hw->nvm.hw_semaphore_timeout);
1403 : 0 : i40e_release_nvm(hw);
1404 : 0 : status = i40e_acquire_nvm(hw, I40E_RESOURCE_WRITE);
1405 [ # # ]: 0 : if (status) {
1406 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_ALL,
1407 : : "NVMUPD: write semaphore reacquire failed aq_err = %d\n",
1408 : : hw->aq.asq_last_status);
1409 : : status = old_status;
1410 : 0 : hw->aq.asq_last_status = old_asq_status;
1411 : : } else {
1412 : : retry_attempt = true;
1413 : 0 : goto retry;
1414 : : }
1415 : : }
1416 : : }
1417 : :
1418 : 0 : return status;
1419 : : }
1420 : :
1421 : : /**
1422 : : * i40e_nvmupd_clear_wait_state - clear wait state on hw
1423 : : * @hw: pointer to the hardware structure
1424 : : **/
1425 : 0 : void i40e_nvmupd_clear_wait_state(struct i40e_hw *hw)
1426 : : {
1427 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
1428 : : "NVMUPD: clearing wait on opcode 0x%04x\n",
1429 : : hw->nvm_wait_opcode);
1430 : :
1431 [ # # ]: 0 : if (hw->nvm_release_on_done) {
1432 : 0 : i40e_release_nvm(hw);
1433 : 0 : hw->nvm_release_on_done = false;
1434 : : }
1435 : 0 : hw->nvm_wait_opcode = 0;
1436 : :
1437 [ # # ]: 0 : if (hw->aq.arq_last_status) {
1438 : 0 : hw->nvmupd_state = I40E_NVMUPD_STATE_ERROR;
1439 : 0 : return;
1440 : : }
1441 : :
1442 [ # # # ]: 0 : switch (hw->nvmupd_state) {
1443 : 0 : case I40E_NVMUPD_STATE_INIT_WAIT:
1444 : 0 : hw->nvmupd_state = I40E_NVMUPD_STATE_INIT;
1445 : 0 : break;
1446 : :
1447 : 0 : case I40E_NVMUPD_STATE_WRITE_WAIT:
1448 : 0 : hw->nvmupd_state = I40E_NVMUPD_STATE_WRITING;
1449 : 0 : break;
1450 : :
1451 : : default:
1452 : : break;
1453 : : }
1454 : : }
1455 : :
1456 : : /**
1457 : : * i40e_nvmupd_check_wait_event - handle NVM update operation events
1458 : : * @hw: pointer to the hardware structure
1459 : : * @opcode: the event that just happened
1460 : : * @desc: AdminQ descriptor
1461 : : **/
1462 : 0 : void i40e_nvmupd_check_wait_event(struct i40e_hw *hw, u16 opcode,
1463 : : struct i40e_aq_desc *desc)
1464 : : {
1465 : : u32 aq_desc_len = sizeof(struct i40e_aq_desc);
1466 : :
1467 [ # # ]: 0 : if (opcode == hw->nvm_wait_opcode) {
1468 [ # # ]: 0 : i40e_memcpy(&hw->nvm_aq_event_desc, desc,
1469 : : aq_desc_len, I40E_NONDMA_TO_NONDMA);
1470 : 0 : i40e_nvmupd_clear_wait_state(hw);
1471 : : }
1472 : 0 : }
1473 : :
1474 : : /**
1475 : : * i40e_nvmupd_validate_command - Validate given command
1476 : : * @hw: pointer to hardware structure
1477 : : * @cmd: pointer to nvm update command buffer
1478 : : * @perrno: pointer to return error code
1479 : : *
1480 : : * Return one of the valid command types or I40E_NVMUPD_INVALID
1481 : : **/
1482 : 0 : STATIC enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw,
1483 : : struct i40e_nvm_access *cmd,
1484 : : int *perrno)
1485 : : {
1486 : : enum i40e_nvmupd_cmd upd_cmd;
1487 : : u8 module, transaction;
1488 : :
1489 : 0 : DEBUGFUNC("i40e_nvmupd_validate_command\n");
1490 : :
1491 : : /* anything that doesn't match a recognized case is an error */
1492 : : upd_cmd = I40E_NVMUPD_INVALID;
1493 : :
1494 : 0 : transaction = i40e_nvmupd_get_transaction(cmd->config);
1495 : : module = i40e_nvmupd_get_module(cmd->config);
1496 : :
1497 : : /* limits on data size */
1498 [ # # ]: 0 : if ((cmd->data_size < 1) ||
1499 : : (cmd->data_size > I40E_NVMUPD_MAX_DATA)) {
1500 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
1501 : : "i40e_nvmupd_validate_command data_size %d\n",
1502 : : cmd->data_size);
1503 : 0 : *perrno = -EFAULT;
1504 : 0 : return I40E_NVMUPD_INVALID;
1505 : : }
1506 : :
1507 [ # # # ]: 0 : switch (cmd->command) {
1508 [ # # # # : 0 : case I40E_NVM_READ:
# # # ]
1509 : : switch (transaction) {
1510 : 0 : case I40E_NVM_CON:
1511 : : upd_cmd = I40E_NVMUPD_READ_CON;
1512 : 0 : break;
1513 : 0 : case I40E_NVM_SNT:
1514 : : upd_cmd = I40E_NVMUPD_READ_SNT;
1515 : 0 : break;
1516 : 0 : case I40E_NVM_LCB:
1517 : : upd_cmd = I40E_NVMUPD_READ_LCB;
1518 : 0 : break;
1519 : 0 : case I40E_NVM_SA:
1520 : : upd_cmd = I40E_NVMUPD_READ_SA;
1521 : 0 : break;
1522 [ # # # # ]: 0 : case I40E_NVM_EXEC:
1523 : : switch (module) {
1524 : : case I40E_NVM_EXEC_GET_AQ_RESULT:
1525 : : upd_cmd = I40E_NVMUPD_GET_AQ_RESULT;
1526 : : break;
1527 : 0 : case I40E_NVM_EXEC_FEATURES:
1528 : : upd_cmd = I40E_NVMUPD_FEATURES;
1529 : 0 : break;
1530 : 0 : case I40E_NVM_EXEC_STATUS:
1531 : : upd_cmd = I40E_NVMUPD_STATUS;
1532 : 0 : break;
1533 : 0 : default:
1534 : 0 : *perrno = -EFAULT;
1535 : 0 : return I40E_NVMUPD_INVALID;
1536 : : }
1537 : : break;
1538 : 0 : case I40E_NVM_AQE:
1539 : : upd_cmd = I40E_NVMUPD_GET_AQ_EVENT;
1540 : 0 : break;
1541 : : }
1542 : : break;
1543 : :
1544 [ # # # # : 0 : case I40E_NVM_WRITE:
# # # # #
# ]
1545 : : switch (transaction) {
1546 : 0 : case I40E_NVM_CON:
1547 : : upd_cmd = I40E_NVMUPD_WRITE_CON;
1548 : 0 : break;
1549 : 0 : case I40E_NVM_SNT:
1550 : : upd_cmd = I40E_NVMUPD_WRITE_SNT;
1551 : 0 : break;
1552 : 0 : case I40E_NVM_LCB:
1553 : : upd_cmd = I40E_NVMUPD_WRITE_LCB;
1554 : 0 : break;
1555 : 0 : case I40E_NVM_SA:
1556 : : upd_cmd = I40E_NVMUPD_WRITE_SA;
1557 : 0 : break;
1558 : 0 : case I40E_NVM_ERA:
1559 : : upd_cmd = I40E_NVMUPD_WRITE_ERA;
1560 : 0 : break;
1561 : 0 : case I40E_NVM_CSUM:
1562 : : upd_cmd = I40E_NVMUPD_CSUM_CON;
1563 : 0 : break;
1564 : 0 : case (I40E_NVM_CSUM|I40E_NVM_SA):
1565 : : upd_cmd = I40E_NVMUPD_CSUM_SA;
1566 : 0 : break;
1567 : 0 : case (I40E_NVM_CSUM|I40E_NVM_LCB):
1568 : : upd_cmd = I40E_NVMUPD_CSUM_LCB;
1569 : 0 : break;
1570 : 0 : case I40E_NVM_EXEC:
1571 [ # # ]: 0 : if (module == 0)
1572 : : upd_cmd = I40E_NVMUPD_EXEC_AQ;
1573 : : break;
1574 : : }
1575 : : break;
1576 : : }
1577 : :
1578 : : return upd_cmd;
1579 : : }
1580 : :
1581 : : /**
1582 : : * i40e_nvmupd_exec_aq - Run an AQ command
1583 : : * @hw: pointer to hardware structure
1584 : : * @cmd: pointer to nvm update command buffer
1585 : : * @bytes: pointer to the data buffer
1586 : : * @perrno: pointer to return error code
1587 : : *
1588 : : * cmd structure contains identifiers and data buffer
1589 : : **/
1590 : 0 : STATIC enum i40e_status_code i40e_nvmupd_exec_aq(struct i40e_hw *hw,
1591 : : struct i40e_nvm_access *cmd,
1592 : : u8 *bytes, int *perrno)
1593 : : {
1594 : : struct i40e_asq_cmd_details cmd_details;
1595 : : enum i40e_status_code status;
1596 : : struct i40e_aq_desc *aq_desc;
1597 : : u32 buff_size = 0;
1598 : : u8 *buff = NULL;
1599 : : u32 aq_desc_len;
1600 : : u32 aq_data_len;
1601 : :
1602 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM, "NVMUPD: %s\n", __func__);
1603 [ # # ]: 0 : if (cmd->offset == 0xffff)
1604 : : return I40E_SUCCESS;
1605 : :
1606 : : memset(&cmd_details, 0, sizeof(cmd_details));
1607 : 0 : cmd_details.wb_desc = &hw->nvm_wb_desc;
1608 : :
1609 : : aq_desc_len = sizeof(struct i40e_aq_desc);
1610 : : memset(&hw->nvm_wb_desc, 0, aq_desc_len);
1611 : :
1612 : : /* get the aq descriptor */
1613 [ # # ]: 0 : if (cmd->data_size < aq_desc_len) {
1614 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
1615 : : "NVMUPD: not enough aq desc bytes for exec, size %d < %d\n",
1616 : : cmd->data_size, aq_desc_len);
1617 : 0 : *perrno = -EINVAL;
1618 : 0 : return I40E_ERR_PARAM;
1619 : : }
1620 : : aq_desc = (struct i40e_aq_desc *)bytes;
1621 : :
1622 : : /* if data buffer needed, make sure it's ready */
1623 : 0 : aq_data_len = cmd->data_size - aq_desc_len;
1624 : 0 : buff_size = max(aq_data_len, (u32)LE16_TO_CPU(aq_desc->datalen));
1625 [ # # ]: 0 : if (buff_size) {
1626 [ # # ]: 0 : if (!hw->nvm_buff.va) {
1627 : 0 : status = i40e_allocate_virt_mem(hw, &hw->nvm_buff,
1628 : : hw->aq.asq_buf_size);
1629 [ # # ]: 0 : if (status)
1630 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
1631 : : "NVMUPD: i40e_allocate_virt_mem for exec buff failed, %d\n",
1632 : : status);
1633 : : }
1634 : :
1635 [ # # ]: 0 : if (hw->nvm_buff.va) {
1636 : : buff = hw->nvm_buff.va;
1637 [ # # ]: 0 : i40e_memcpy(buff, &bytes[aq_desc_len], aq_data_len,
1638 : : I40E_NONDMA_TO_NONDMA);
1639 : : }
1640 : : }
1641 : :
1642 [ # # ]: 0 : if (cmd->offset)
1643 : 0 : memset(&hw->nvm_aq_event_desc, 0, aq_desc_len);
1644 : :
1645 : : /* and away we go! */
1646 : 0 : status = i40e_asq_send_command(hw, aq_desc, buff,
1647 : : buff_size, &cmd_details);
1648 [ # # ]: 0 : if (status) {
1649 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
1650 : : "i40e_nvmupd_exec_aq err %s aq_err %s\n",
1651 : : i40e_stat_str(hw, status),
1652 : : i40e_aq_str(hw, hw->aq.asq_last_status));
1653 : 0 : *perrno = i40e_aq_rc_to_posix(status, hw->aq.asq_last_status);
1654 : 0 : return status;
1655 : : }
1656 : :
1657 : : /* should we wait for a followup event? */
1658 [ # # ]: 0 : if (cmd->offset) {
1659 : 0 : hw->nvm_wait_opcode = cmd->offset;
1660 : 0 : hw->nvmupd_state = I40E_NVMUPD_STATE_INIT_WAIT;
1661 : : }
1662 : :
1663 : : return status;
1664 : : }
1665 : :
1666 : : /**
1667 : : * i40e_nvmupd_get_aq_result - Get the results from the previous exec_aq
1668 : : * @hw: pointer to hardware structure
1669 : : * @cmd: pointer to nvm update command buffer
1670 : : * @bytes: pointer to the data buffer
1671 : : * @perrno: pointer to return error code
1672 : : *
1673 : : * cmd structure contains identifiers and data buffer
1674 : : **/
1675 : 0 : STATIC enum i40e_status_code i40e_nvmupd_get_aq_result(struct i40e_hw *hw,
1676 : : struct i40e_nvm_access *cmd,
1677 : : u8 *bytes, int *perrno)
1678 : : {
1679 : : u32 aq_total_len;
1680 : : u32 aq_desc_len;
1681 : : int remainder;
1682 : : u8 *buff;
1683 : :
1684 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM, "NVMUPD: %s\n", __func__);
1685 : :
1686 : : aq_desc_len = sizeof(struct i40e_aq_desc);
1687 : 0 : aq_total_len = aq_desc_len + LE16_TO_CPU(hw->nvm_wb_desc.datalen);
1688 : :
1689 : : /* check offset range */
1690 [ # # ]: 0 : if (cmd->offset > aq_total_len) {
1691 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM, "%s: offset too big %d > %d\n",
1692 : : __func__, cmd->offset, aq_total_len);
1693 : 0 : *perrno = -EINVAL;
1694 : 0 : return I40E_ERR_PARAM;
1695 : : }
1696 : :
1697 : : /* check copylength range */
1698 [ # # ]: 0 : if (cmd->data_size > (aq_total_len - cmd->offset)) {
1699 : 0 : int new_len = aq_total_len - cmd->offset;
1700 : :
1701 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM, "%s: copy length %d too big, trimming to %d\n",
1702 : : __func__, cmd->data_size, new_len);
1703 : 0 : cmd->data_size = new_len;
1704 : : }
1705 : :
1706 : 0 : remainder = cmd->data_size;
1707 [ # # ]: 0 : if (cmd->offset < aq_desc_len) {
1708 : 0 : u32 len = aq_desc_len - cmd->offset;
1709 : :
1710 : 0 : len = min(len, cmd->data_size);
1711 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM, "%s: aq_desc bytes %d to %d\n",
1712 : : __func__, cmd->offset, cmd->offset + len);
1713 : :
1714 : 0 : buff = ((u8 *)&hw->nvm_wb_desc) + cmd->offset;
1715 [ # # ]: 0 : i40e_memcpy(bytes, buff, len, I40E_NONDMA_TO_NONDMA);
1716 : :
1717 : 0 : bytes += len;
1718 : 0 : remainder -= len;
1719 : 0 : buff = hw->nvm_buff.va;
1720 : : } else {
1721 : 0 : buff = (u8 *)hw->nvm_buff.va + (cmd->offset - aq_desc_len);
1722 : : }
1723 : :
1724 [ # # ]: 0 : if (remainder > 0) {
1725 : 0 : int start_byte = buff - (u8 *)hw->nvm_buff.va;
1726 : :
1727 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM, "%s: databuf bytes %d to %d\n",
1728 : : __func__, start_byte, start_byte + remainder);
1729 [ # # ]: 0 : i40e_memcpy(bytes, buff, remainder, I40E_NONDMA_TO_NONDMA);
1730 : : }
1731 : :
1732 : : return I40E_SUCCESS;
1733 : : }
1734 : :
1735 : : /**
1736 : : * i40e_nvmupd_get_aq_event - Get the Admin Queue event from previous exec_aq
1737 : : * @hw: pointer to hardware structure
1738 : : * @cmd: pointer to nvm update command buffer
1739 : : * @bytes: pointer to the data buffer
1740 : : * @perrno: pointer to return error code
1741 : : *
1742 : : * cmd structure contains identifiers and data buffer
1743 : : **/
1744 : 0 : STATIC enum i40e_status_code i40e_nvmupd_get_aq_event(struct i40e_hw *hw,
1745 : : struct i40e_nvm_access *cmd,
1746 : : u8 *bytes, int *perrno)
1747 : : {
1748 : : u32 aq_total_len;
1749 : : u32 aq_desc_len;
1750 : :
1751 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM, "NVMUPD: %s\n", __func__);
1752 : :
1753 : : aq_desc_len = sizeof(struct i40e_aq_desc);
1754 : 0 : aq_total_len = aq_desc_len + LE16_TO_CPU(hw->nvm_aq_event_desc.datalen);
1755 : :
1756 : : /* check copylength range */
1757 [ # # ]: 0 : if (cmd->data_size > aq_total_len) {
1758 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
1759 : : "%s: copy length %d too big, trimming to %d\n",
1760 : : __func__, cmd->data_size, aq_total_len);
1761 : 0 : cmd->data_size = aq_total_len;
1762 : : }
1763 : :
1764 [ # # ]: 0 : i40e_memcpy(bytes, &hw->nvm_aq_event_desc, cmd->data_size,
1765 : : I40E_NONDMA_TO_NONDMA);
1766 : :
1767 : 0 : return I40E_SUCCESS;
1768 : : }
1769 : :
1770 : : /**
1771 : : * i40e_nvmupd_nvm_read - Read NVM
1772 : : * @hw: pointer to hardware structure
1773 : : * @cmd: pointer to nvm update command buffer
1774 : : * @bytes: pointer to the data buffer
1775 : : * @perrno: pointer to return error code
1776 : : *
1777 : : * cmd structure contains identifiers and data buffer
1778 : : **/
1779 : 0 : STATIC enum i40e_status_code i40e_nvmupd_nvm_read(struct i40e_hw *hw,
1780 : : struct i40e_nvm_access *cmd,
1781 : : u8 *bytes, int *perrno)
1782 : : {
1783 : : struct i40e_asq_cmd_details cmd_details;
1784 : : enum i40e_status_code status;
1785 : : u8 module, transaction;
1786 : : bool last;
1787 : :
1788 : 0 : transaction = i40e_nvmupd_get_transaction(cmd->config);
1789 : : module = i40e_nvmupd_get_module(cmd->config);
1790 : 0 : last = (transaction == I40E_NVM_LCB) || (transaction == I40E_NVM_SA);
1791 : :
1792 : : memset(&cmd_details, 0, sizeof(cmd_details));
1793 : 0 : cmd_details.wb_desc = &hw->nvm_wb_desc;
1794 : :
1795 : 0 : status = i40e_aq_read_nvm(hw, module, cmd->offset, (u16)cmd->data_size,
1796 : : bytes, last, &cmd_details);
1797 [ # # ]: 0 : if (status) {
1798 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
1799 : : "i40e_nvmupd_nvm_read mod 0x%x off 0x%x len 0x%x\n",
1800 : : module, cmd->offset, cmd->data_size);
1801 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
1802 : : "i40e_nvmupd_nvm_read status %d aq %d\n",
1803 : : status, hw->aq.asq_last_status);
1804 : 0 : *perrno = i40e_aq_rc_to_posix(status, hw->aq.asq_last_status);
1805 : : }
1806 : :
1807 : 0 : return status;
1808 : : }
1809 : :
1810 : : /**
1811 : : * i40e_nvmupd_nvm_erase - Erase an NVM module
1812 : : * @hw: pointer to hardware structure
1813 : : * @cmd: pointer to nvm update command buffer
1814 : : * @perrno: pointer to return error code
1815 : : *
1816 : : * module, offset, data_size and data are in cmd structure
1817 : : **/
1818 : 0 : STATIC enum i40e_status_code i40e_nvmupd_nvm_erase(struct i40e_hw *hw,
1819 : : struct i40e_nvm_access *cmd,
1820 : : int *perrno)
1821 : : {
1822 : : enum i40e_status_code status = I40E_SUCCESS;
1823 : : struct i40e_asq_cmd_details cmd_details;
1824 : : u8 module, transaction;
1825 : : bool last;
1826 : :
1827 : 0 : transaction = i40e_nvmupd_get_transaction(cmd->config);
1828 : : module = i40e_nvmupd_get_module(cmd->config);
1829 : 0 : last = (transaction & I40E_NVM_LCB);
1830 : :
1831 : : memset(&cmd_details, 0, sizeof(cmd_details));
1832 : 0 : cmd_details.wb_desc = &hw->nvm_wb_desc;
1833 : :
1834 : 0 : status = i40e_aq_erase_nvm(hw, module, cmd->offset, (u16)cmd->data_size,
1835 : : last, &cmd_details);
1836 [ # # ]: 0 : if (status) {
1837 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
1838 : : "i40e_nvmupd_nvm_erase mod 0x%x off 0x%x len 0x%x\n",
1839 : : module, cmd->offset, cmd->data_size);
1840 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
1841 : : "i40e_nvmupd_nvm_erase status %d aq %d\n",
1842 : : status, hw->aq.asq_last_status);
1843 : 0 : *perrno = i40e_aq_rc_to_posix(status, hw->aq.asq_last_status);
1844 : : }
1845 : :
1846 : 0 : return status;
1847 : : }
1848 : :
1849 : : /**
1850 : : * i40e_nvmupd_nvm_write - Write NVM
1851 : : * @hw: pointer to hardware structure
1852 : : * @cmd: pointer to nvm update command buffer
1853 : : * @bytes: pointer to the data buffer
1854 : : * @perrno: pointer to return error code
1855 : : *
1856 : : * module, offset, data_size and data are in cmd structure
1857 : : **/
1858 : 0 : STATIC enum i40e_status_code i40e_nvmupd_nvm_write(struct i40e_hw *hw,
1859 : : struct i40e_nvm_access *cmd,
1860 : : u8 *bytes, int *perrno)
1861 : : {
1862 : : enum i40e_status_code status = I40E_SUCCESS;
1863 : : struct i40e_asq_cmd_details cmd_details;
1864 : : u8 module, transaction;
1865 : : u8 preservation_flags;
1866 : : bool last;
1867 : :
1868 : 0 : transaction = i40e_nvmupd_get_transaction(cmd->config);
1869 : : module = i40e_nvmupd_get_module(cmd->config);
1870 : 0 : last = (transaction & I40E_NVM_LCB);
1871 : : preservation_flags = i40e_nvmupd_get_preservation_flags(cmd->config);
1872 : :
1873 : : memset(&cmd_details, 0, sizeof(cmd_details));
1874 : 0 : cmd_details.wb_desc = &hw->nvm_wb_desc;
1875 : :
1876 : 0 : status = i40e_aq_update_nvm(hw, module, cmd->offset,
1877 : 0 : (u16)cmd->data_size, bytes, last,
1878 : : preservation_flags, &cmd_details);
1879 [ # # ]: 0 : if (status) {
1880 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
1881 : : "i40e_nvmupd_nvm_write mod 0x%x off 0x%x len 0x%x\n",
1882 : : module, cmd->offset, cmd->data_size);
1883 [ # # ]: 0 : i40e_debug(hw, I40E_DEBUG_NVM,
1884 : : "i40e_nvmupd_nvm_write status %d aq %d\n",
1885 : : status, hw->aq.asq_last_status);
1886 : 0 : *perrno = i40e_aq_rc_to_posix(status, hw->aq.asq_last_status);
1887 : : }
1888 : :
1889 : 0 : return status;
1890 : : }
|