1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright (c) 2022, Intel Corporation. */ |
3 | |
4 | #include "ice_common.h" |
5 | #include "ice.h" |
6 | #include "ice_ddp.h" |
7 | |
8 | /* For supporting double VLAN mode, it is necessary to enable or disable certain |
9 | * boost tcam entries. The metadata labels names that match the following |
10 | * prefixes will be saved to allow enabling double VLAN mode. |
11 | */ |
12 | #define ICE_DVM_PRE "BOOST_MAC_VLAN_DVM" /* enable these entries */ |
13 | #define ICE_SVM_PRE "BOOST_MAC_VLAN_SVM" /* disable these entries */ |
14 | |
15 | /* To support tunneling entries by PF, the package will append the PF number to |
16 | * the label; for example TNL_VXLAN_PF0, TNL_VXLAN_PF1, TNL_VXLAN_PF2, etc. |
17 | */ |
18 | #define ICE_TNL_PRE "TNL_" |
19 | static const struct ice_tunnel_type_scan tnls[] = { |
20 | { TNL_VXLAN, "TNL_VXLAN_PF" }, |
21 | { TNL_GENEVE, "TNL_GENEVE_PF" }, |
22 | { TNL_LAST, "" } |
23 | }; |
24 | |
25 | /** |
26 | * ice_verify_pkg - verify package |
27 | * @pkg: pointer to the package buffer |
28 | * @len: size of the package buffer |
29 | * |
30 | * Verifies various attributes of the package file, including length, format |
31 | * version, and the requirement of at least one segment. |
32 | */ |
33 | static enum ice_ddp_state ice_verify_pkg(struct ice_pkg_hdr *pkg, u32 len) |
34 | { |
35 | u32 seg_count; |
36 | u32 i; |
37 | |
38 | if (len < struct_size(pkg, seg_offset, 1)) |
39 | return ICE_DDP_PKG_INVALID_FILE; |
40 | |
41 | if (pkg->pkg_format_ver.major != ICE_PKG_FMT_VER_MAJ || |
42 | pkg->pkg_format_ver.minor != ICE_PKG_FMT_VER_MNR || |
43 | pkg->pkg_format_ver.update != ICE_PKG_FMT_VER_UPD || |
44 | pkg->pkg_format_ver.draft != ICE_PKG_FMT_VER_DFT) |
45 | return ICE_DDP_PKG_INVALID_FILE; |
46 | |
47 | /* pkg must have at least one segment */ |
48 | seg_count = le32_to_cpu(pkg->seg_count); |
49 | if (seg_count < 1) |
50 | return ICE_DDP_PKG_INVALID_FILE; |
51 | |
52 | /* make sure segment array fits in package length */ |
53 | if (len < struct_size(pkg, seg_offset, seg_count)) |
54 | return ICE_DDP_PKG_INVALID_FILE; |
55 | |
56 | /* all segments must fit within length */ |
57 | for (i = 0; i < seg_count; i++) { |
58 | u32 off = le32_to_cpu(pkg->seg_offset[i]); |
59 | struct ice_generic_seg_hdr *seg; |
60 | |
61 | /* segment header must fit */ |
62 | if (len < off + sizeof(*seg)) |
63 | return ICE_DDP_PKG_INVALID_FILE; |
64 | |
65 | seg = (struct ice_generic_seg_hdr *)((u8 *)pkg + off); |
66 | |
67 | /* segment body must fit */ |
68 | if (len < off + le32_to_cpu(seg->seg_size)) |
69 | return ICE_DDP_PKG_INVALID_FILE; |
70 | } |
71 | |
72 | return ICE_DDP_PKG_SUCCESS; |
73 | } |
74 | |
75 | /** |
76 | * ice_free_seg - free package segment pointer |
77 | * @hw: pointer to the hardware structure |
78 | * |
79 | * Frees the package segment pointer in the proper manner, depending on if the |
80 | * segment was allocated or just the passed in pointer was stored. |
81 | */ |
82 | void ice_free_seg(struct ice_hw *hw) |
83 | { |
84 | if (hw->pkg_copy) { |
85 | devm_kfree(dev: ice_hw_to_dev(hw), p: hw->pkg_copy); |
86 | hw->pkg_copy = NULL; |
87 | hw->pkg_size = 0; |
88 | } |
89 | hw->seg = NULL; |
90 | } |
91 | |
92 | /** |
93 | * ice_chk_pkg_version - check package version for compatibility with driver |
94 | * @pkg_ver: pointer to a version structure to check |
95 | * |
96 | * Check to make sure that the package about to be downloaded is compatible with |
97 | * the driver. To be compatible, the major and minor components of the package |
98 | * version must match our ICE_PKG_SUPP_VER_MAJ and ICE_PKG_SUPP_VER_MNR |
99 | * definitions. |
100 | */ |
101 | static enum ice_ddp_state ice_chk_pkg_version(struct ice_pkg_ver *pkg_ver) |
102 | { |
103 | if (pkg_ver->major > ICE_PKG_SUPP_VER_MAJ || |
104 | (pkg_ver->major == ICE_PKG_SUPP_VER_MAJ && |
105 | pkg_ver->minor > ICE_PKG_SUPP_VER_MNR)) |
106 | return ICE_DDP_PKG_FILE_VERSION_TOO_HIGH; |
107 | else if (pkg_ver->major < ICE_PKG_SUPP_VER_MAJ || |
108 | (pkg_ver->major == ICE_PKG_SUPP_VER_MAJ && |
109 | pkg_ver->minor < ICE_PKG_SUPP_VER_MNR)) |
110 | return ICE_DDP_PKG_FILE_VERSION_TOO_LOW; |
111 | |
112 | return ICE_DDP_PKG_SUCCESS; |
113 | } |
114 | |
115 | /** |
116 | * ice_pkg_val_buf |
117 | * @buf: pointer to the ice buffer |
118 | * |
119 | * This helper function validates a buffer's header. |
120 | */ |
121 | static struct ice_buf_hdr *ice_pkg_val_buf(struct ice_buf *buf) |
122 | { |
123 | struct ice_buf_hdr *hdr; |
124 | u16 section_count; |
125 | u16 data_end; |
126 | |
127 | hdr = (struct ice_buf_hdr *)buf->buf; |
128 | /* verify data */ |
129 | section_count = le16_to_cpu(hdr->section_count); |
130 | if (section_count < ICE_MIN_S_COUNT || section_count > ICE_MAX_S_COUNT) |
131 | return NULL; |
132 | |
133 | data_end = le16_to_cpu(hdr->data_end); |
134 | if (data_end < ICE_MIN_S_DATA_END || data_end > ICE_MAX_S_DATA_END) |
135 | return NULL; |
136 | |
137 | return hdr; |
138 | } |
139 | |
140 | /** |
141 | * ice_find_buf_table |
142 | * @ice_seg: pointer to the ice segment |
143 | * |
144 | * Returns the address of the buffer table within the ice segment. |
145 | */ |
146 | static struct ice_buf_table *ice_find_buf_table(struct ice_seg *ice_seg) |
147 | { |
148 | struct ice_nvm_table *nvms = (struct ice_nvm_table *) |
149 | (ice_seg->device_table + le32_to_cpu(ice_seg->device_table_count)); |
150 | |
151 | return (__force struct ice_buf_table *)(nvms->vers + |
152 | le32_to_cpu(nvms->table_count)); |
153 | } |
154 | |
155 | /** |
156 | * ice_pkg_enum_buf |
157 | * @ice_seg: pointer to the ice segment (or NULL on subsequent calls) |
158 | * @state: pointer to the enum state |
159 | * |
160 | * This function will enumerate all the buffers in the ice segment. The first |
161 | * call is made with the ice_seg parameter non-NULL; on subsequent calls, |
162 | * ice_seg is set to NULL which continues the enumeration. When the function |
163 | * returns a NULL pointer, then the end of the buffers has been reached, or an |
164 | * unexpected value has been detected (for example an invalid section count or |
165 | * an invalid buffer end value). |
166 | */ |
167 | static struct ice_buf_hdr *ice_pkg_enum_buf(struct ice_seg *ice_seg, |
168 | struct ice_pkg_enum *state) |
169 | { |
170 | if (ice_seg) { |
171 | state->buf_table = ice_find_buf_table(ice_seg); |
172 | if (!state->buf_table) |
173 | return NULL; |
174 | |
175 | state->buf_idx = 0; |
176 | return ice_pkg_val_buf(buf: state->buf_table->buf_array); |
177 | } |
178 | |
179 | if (++state->buf_idx < le32_to_cpu(state->buf_table->buf_count)) |
180 | return ice_pkg_val_buf(buf: state->buf_table->buf_array + |
181 | state->buf_idx); |
182 | else |
183 | return NULL; |
184 | } |
185 | |
186 | /** |
187 | * ice_pkg_advance_sect |
188 | * @ice_seg: pointer to the ice segment (or NULL on subsequent calls) |
189 | * @state: pointer to the enum state |
190 | * |
191 | * This helper function will advance the section within the ice segment, |
192 | * also advancing the buffer if needed. |
193 | */ |
194 | static bool ice_pkg_advance_sect(struct ice_seg *ice_seg, |
195 | struct ice_pkg_enum *state) |
196 | { |
197 | if (!ice_seg && !state->buf) |
198 | return false; |
199 | |
200 | if (!ice_seg && state->buf) |
201 | if (++state->sect_idx < le16_to_cpu(state->buf->section_count)) |
202 | return true; |
203 | |
204 | state->buf = ice_pkg_enum_buf(ice_seg, state); |
205 | if (!state->buf) |
206 | return false; |
207 | |
208 | /* start of new buffer, reset section index */ |
209 | state->sect_idx = 0; |
210 | return true; |
211 | } |
212 | |
213 | /** |
214 | * ice_pkg_enum_section |
215 | * @ice_seg: pointer to the ice segment (or NULL on subsequent calls) |
216 | * @state: pointer to the enum state |
217 | * @sect_type: section type to enumerate |
218 | * |
219 | * This function will enumerate all the sections of a particular type in the |
220 | * ice segment. The first call is made with the ice_seg parameter non-NULL; |
221 | * on subsequent calls, ice_seg is set to NULL which continues the enumeration. |
222 | * When the function returns a NULL pointer, then the end of the matching |
223 | * sections has been reached. |
224 | */ |
225 | void *ice_pkg_enum_section(struct ice_seg *ice_seg, struct ice_pkg_enum *state, |
226 | u32 sect_type) |
227 | { |
228 | u16 offset, size; |
229 | |
230 | if (ice_seg) |
231 | state->type = sect_type; |
232 | |
233 | if (!ice_pkg_advance_sect(ice_seg, state)) |
234 | return NULL; |
235 | |
236 | /* scan for next matching section */ |
237 | while (state->buf->section_entry[state->sect_idx].type != |
238 | cpu_to_le32(state->type)) |
239 | if (!ice_pkg_advance_sect(NULL, state)) |
240 | return NULL; |
241 | |
242 | /* validate section */ |
243 | offset = le16_to_cpu(state->buf->section_entry[state->sect_idx].offset); |
244 | if (offset < ICE_MIN_S_OFF || offset > ICE_MAX_S_OFF) |
245 | return NULL; |
246 | |
247 | size = le16_to_cpu(state->buf->section_entry[state->sect_idx].size); |
248 | if (size < ICE_MIN_S_SZ || size > ICE_MAX_S_SZ) |
249 | return NULL; |
250 | |
251 | /* make sure the section fits in the buffer */ |
252 | if (offset + size > ICE_PKG_BUF_SIZE) |
253 | return NULL; |
254 | |
255 | state->sect_type = |
256 | le32_to_cpu(state->buf->section_entry[state->sect_idx].type); |
257 | |
258 | /* calc pointer to this section */ |
259 | state->sect = |
260 | ((u8 *)state->buf) + |
261 | le16_to_cpu(state->buf->section_entry[state->sect_idx].offset); |
262 | |
263 | return state->sect; |
264 | } |
265 | |
266 | /** |
267 | * ice_pkg_enum_entry |
268 | * @ice_seg: pointer to the ice segment (or NULL on subsequent calls) |
269 | * @state: pointer to the enum state |
270 | * @sect_type: section type to enumerate |
271 | * @offset: pointer to variable that receives the offset in the table (optional) |
272 | * @handler: function that handles access to the entries into the section type |
273 | * |
274 | * This function will enumerate all the entries in particular section type in |
275 | * the ice segment. The first call is made with the ice_seg parameter non-NULL; |
276 | * on subsequent calls, ice_seg is set to NULL which continues the enumeration. |
277 | * When the function returns a NULL pointer, then the end of the entries has |
278 | * been reached. |
279 | * |
280 | * Since each section may have a different header and entry size, the handler |
281 | * function is needed to determine the number and location entries in each |
282 | * section. |
283 | * |
284 | * The offset parameter is optional, but should be used for sections that |
285 | * contain an offset for each section table. For such cases, the section handler |
286 | * function must return the appropriate offset + index to give the absolution |
287 | * offset for each entry. For example, if the base for a section's header |
288 | * indicates a base offset of 10, and the index for the entry is 2, then |
289 | * section handler function should set the offset to 10 + 2 = 12. |
290 | */ |
291 | static void *ice_pkg_enum_entry(struct ice_seg *ice_seg, |
292 | struct ice_pkg_enum *state, u32 sect_type, |
293 | u32 *offset, |
294 | void *(*handler)(u32 sect_type, void *section, |
295 | u32 index, u32 *offset)) |
296 | { |
297 | void *entry; |
298 | |
299 | if (ice_seg) { |
300 | if (!handler) |
301 | return NULL; |
302 | |
303 | if (!ice_pkg_enum_section(ice_seg, state, sect_type)) |
304 | return NULL; |
305 | |
306 | state->entry_idx = 0; |
307 | state->handler = handler; |
308 | } else { |
309 | state->entry_idx++; |
310 | } |
311 | |
312 | if (!state->handler) |
313 | return NULL; |
314 | |
315 | /* get entry */ |
316 | entry = state->handler(state->sect_type, state->sect, state->entry_idx, |
317 | offset); |
318 | if (!entry) { |
319 | /* end of a section, look for another section of this type */ |
320 | if (!ice_pkg_enum_section(NULL, state, sect_type: 0)) |
321 | return NULL; |
322 | |
323 | state->entry_idx = 0; |
324 | entry = state->handler(state->sect_type, state->sect, |
325 | state->entry_idx, offset); |
326 | } |
327 | |
328 | return entry; |
329 | } |
330 | |
331 | /** |
332 | * ice_sw_fv_handler |
333 | * @sect_type: section type |
334 | * @section: pointer to section |
335 | * @index: index of the field vector entry to be returned |
336 | * @offset: ptr to variable that receives the offset in the field vector table |
337 | * |
338 | * This is a callback function that can be passed to ice_pkg_enum_entry. |
339 | * This function treats the given section as of type ice_sw_fv_section and |
340 | * enumerates offset field. "offset" is an index into the field vector table. |
341 | */ |
342 | static void *ice_sw_fv_handler(u32 sect_type, void *section, u32 index, |
343 | u32 *offset) |
344 | { |
345 | struct ice_sw_fv_section *fv_section = section; |
346 | |
347 | if (!section || sect_type != ICE_SID_FLD_VEC_SW) |
348 | return NULL; |
349 | if (index >= le16_to_cpu(fv_section->count)) |
350 | return NULL; |
351 | if (offset) |
352 | /* "index" passed in to this function is relative to a given |
353 | * 4k block. To get to the true index into the field vector |
354 | * table need to add the relative index to the base_offset |
355 | * field of this section |
356 | */ |
357 | *offset = le16_to_cpu(fv_section->base_offset) + index; |
358 | return fv_section->fv + index; |
359 | } |
360 | |
361 | /** |
362 | * ice_get_prof_index_max - get the max profile index for used profile |
363 | * @hw: pointer to the HW struct |
364 | * |
365 | * Calling this function will get the max profile index for used profile |
366 | * and store the index number in struct ice_switch_info *switch_info |
367 | * in HW for following use. |
368 | */ |
369 | static int ice_get_prof_index_max(struct ice_hw *hw) |
370 | { |
371 | u16 prof_index = 0, j, max_prof_index = 0; |
372 | struct ice_pkg_enum state; |
373 | struct ice_seg *ice_seg; |
374 | bool flag = false; |
375 | struct ice_fv *fv; |
376 | u32 offset; |
377 | |
378 | memset(&state, 0, sizeof(state)); |
379 | |
380 | if (!hw->seg) |
381 | return -EINVAL; |
382 | |
383 | ice_seg = hw->seg; |
384 | |
385 | do { |
386 | fv = ice_pkg_enum_entry(ice_seg, state: &state, ICE_SID_FLD_VEC_SW, |
387 | offset: &offset, handler: ice_sw_fv_handler); |
388 | if (!fv) |
389 | break; |
390 | ice_seg = NULL; |
391 | |
392 | /* in the profile that not be used, the prot_id is set to 0xff |
393 | * and the off is set to 0x1ff for all the field vectors. |
394 | */ |
395 | for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++) |
396 | if (fv->ew[j].prot_id != ICE_PROT_INVALID || |
397 | fv->ew[j].off != ICE_FV_OFFSET_INVAL) |
398 | flag = true; |
399 | if (flag && prof_index > max_prof_index) |
400 | max_prof_index = prof_index; |
401 | |
402 | prof_index++; |
403 | flag = false; |
404 | } while (fv); |
405 | |
406 | hw->switch_info->max_used_prof_index = max_prof_index; |
407 | |
408 | return 0; |
409 | } |
410 | |
411 | /** |
412 | * ice_get_ddp_pkg_state - get DDP pkg state after download |
413 | * @hw: pointer to the HW struct |
414 | * @already_loaded: indicates if pkg was already loaded onto the device |
415 | */ |
416 | static enum ice_ddp_state ice_get_ddp_pkg_state(struct ice_hw *hw, |
417 | bool already_loaded) |
418 | { |
419 | if (hw->pkg_ver.major == hw->active_pkg_ver.major && |
420 | hw->pkg_ver.minor == hw->active_pkg_ver.minor && |
421 | hw->pkg_ver.update == hw->active_pkg_ver.update && |
422 | hw->pkg_ver.draft == hw->active_pkg_ver.draft && |
423 | !memcmp(p: hw->pkg_name, q: hw->active_pkg_name, size: sizeof(hw->pkg_name))) { |
424 | if (already_loaded) |
425 | return ICE_DDP_PKG_SAME_VERSION_ALREADY_LOADED; |
426 | else |
427 | return ICE_DDP_PKG_SUCCESS; |
428 | } else if (hw->active_pkg_ver.major != ICE_PKG_SUPP_VER_MAJ || |
429 | hw->active_pkg_ver.minor != ICE_PKG_SUPP_VER_MNR) { |
430 | return ICE_DDP_PKG_ALREADY_LOADED_NOT_SUPPORTED; |
431 | } else if (hw->active_pkg_ver.major == ICE_PKG_SUPP_VER_MAJ && |
432 | hw->active_pkg_ver.minor == ICE_PKG_SUPP_VER_MNR) { |
433 | return ICE_DDP_PKG_COMPATIBLE_ALREADY_LOADED; |
434 | } else { |
435 | return ICE_DDP_PKG_ERR; |
436 | } |
437 | } |
438 | |
439 | /** |
440 | * ice_init_pkg_regs - initialize additional package registers |
441 | * @hw: pointer to the hardware structure |
442 | */ |
443 | static void ice_init_pkg_regs(struct ice_hw *hw) |
444 | { |
445 | #define ICE_SW_BLK_INP_MASK_L 0xFFFFFFFF |
446 | #define ICE_SW_BLK_INP_MASK_H 0x0000FFFF |
447 | #define ICE_SW_BLK_IDX 0 |
448 | |
449 | /* setup Switch block input mask, which is 48-bits in two parts */ |
450 | wr32(hw, GL_PREEXT_L2_PMASK0(ICE_SW_BLK_IDX), ICE_SW_BLK_INP_MASK_L); |
451 | wr32(hw, GL_PREEXT_L2_PMASK1(ICE_SW_BLK_IDX), ICE_SW_BLK_INP_MASK_H); |
452 | } |
453 | |
454 | /** |
455 | * ice_marker_ptype_tcam_handler |
456 | * @sect_type: section type |
457 | * @section: pointer to section |
458 | * @index: index of the Marker PType TCAM entry to be returned |
459 | * @offset: pointer to receive absolute offset, always 0 for ptype TCAM sections |
460 | * |
461 | * This is a callback function that can be passed to ice_pkg_enum_entry. |
462 | * Handles enumeration of individual Marker PType TCAM entries. |
463 | */ |
464 | static void *ice_marker_ptype_tcam_handler(u32 sect_type, void *section, |
465 | u32 index, u32 *offset) |
466 | { |
467 | struct ice_marker_ptype_tcam_section *marker_ptype; |
468 | |
469 | if (sect_type != ICE_SID_RXPARSER_MARKER_PTYPE) |
470 | return NULL; |
471 | |
472 | if (index > ICE_MAX_MARKER_PTYPE_TCAMS_IN_BUF) |
473 | return NULL; |
474 | |
475 | if (offset) |
476 | *offset = 0; |
477 | |
478 | marker_ptype = section; |
479 | if (index >= le16_to_cpu(marker_ptype->count)) |
480 | return NULL; |
481 | |
482 | return marker_ptype->tcam + index; |
483 | } |
484 | |
485 | /** |
486 | * ice_add_dvm_hint |
487 | * @hw: pointer to the HW structure |
488 | * @val: value of the boost entry |
489 | * @enable: true if entry needs to be enabled, or false if needs to be disabled |
490 | */ |
491 | static void ice_add_dvm_hint(struct ice_hw *hw, u16 val, bool enable) |
492 | { |
493 | if (hw->dvm_upd.count < ICE_DVM_MAX_ENTRIES) { |
494 | hw->dvm_upd.tbl[hw->dvm_upd.count].boost_addr = val; |
495 | hw->dvm_upd.tbl[hw->dvm_upd.count].enable = enable; |
496 | hw->dvm_upd.count++; |
497 | } |
498 | } |
499 | |
500 | /** |
501 | * ice_add_tunnel_hint |
502 | * @hw: pointer to the HW structure |
503 | * @label_name: label text |
504 | * @val: value of the tunnel port boost entry |
505 | */ |
506 | static void ice_add_tunnel_hint(struct ice_hw *hw, char *label_name, u16 val) |
507 | { |
508 | if (hw->tnl.count < ICE_TUNNEL_MAX_ENTRIES) { |
509 | u16 i; |
510 | |
511 | for (i = 0; tnls[i].type != TNL_LAST; i++) { |
512 | size_t len = strlen(tnls[i].label_prefix); |
513 | |
514 | /* Look for matching label start, before continuing */ |
515 | if (strncmp(label_name, tnls[i].label_prefix, len)) |
516 | continue; |
517 | |
518 | /* Make sure this label matches our PF. Note that the PF |
519 | * character ('0' - '7') will be located where our |
520 | * prefix string's null terminator is located. |
521 | */ |
522 | if ((label_name[len] - '0') == hw->pf_id) { |
523 | hw->tnl.tbl[hw->tnl.count].type = tnls[i].type; |
524 | hw->tnl.tbl[hw->tnl.count].valid = false; |
525 | hw->tnl.tbl[hw->tnl.count].boost_addr = val; |
526 | hw->tnl.tbl[hw->tnl.count].port = 0; |
527 | hw->tnl.count++; |
528 | break; |
529 | } |
530 | } |
531 | } |
532 | } |
533 | |
534 | /** |
535 | * ice_label_enum_handler |
536 | * @sect_type: section type |
537 | * @section: pointer to section |
538 | * @index: index of the label entry to be returned |
539 | * @offset: pointer to receive absolute offset, always zero for label sections |
540 | * |
541 | * This is a callback function that can be passed to ice_pkg_enum_entry. |
542 | * Handles enumeration of individual label entries. |
543 | */ |
544 | static void *ice_label_enum_handler(u32 __always_unused sect_type, |
545 | void *section, u32 index, u32 *offset) |
546 | { |
547 | struct ice_label_section *labels; |
548 | |
549 | if (!section) |
550 | return NULL; |
551 | |
552 | if (index > ICE_MAX_LABELS_IN_BUF) |
553 | return NULL; |
554 | |
555 | if (offset) |
556 | *offset = 0; |
557 | |
558 | labels = section; |
559 | if (index >= le16_to_cpu(labels->count)) |
560 | return NULL; |
561 | |
562 | return labels->label + index; |
563 | } |
564 | |
565 | /** |
566 | * ice_enum_labels |
567 | * @ice_seg: pointer to the ice segment (NULL on subsequent calls) |
568 | * @type: the section type that will contain the label (0 on subsequent calls) |
569 | * @state: ice_pkg_enum structure that will hold the state of the enumeration |
570 | * @value: pointer to a value that will return the label's value if found |
571 | * |
572 | * Enumerates a list of labels in the package. The caller will call |
573 | * ice_enum_labels(ice_seg, type, ...) to start the enumeration, then call |
574 | * ice_enum_labels(NULL, 0, ...) to continue. When the function returns a NULL |
575 | * the end of the list has been reached. |
576 | */ |
577 | static char *ice_enum_labels(struct ice_seg *ice_seg, u32 type, |
578 | struct ice_pkg_enum *state, u16 *value) |
579 | { |
580 | struct ice_label *label; |
581 | |
582 | /* Check for valid label section on first call */ |
583 | if (type && !(type >= ICE_SID_LBL_FIRST && type <= ICE_SID_LBL_LAST)) |
584 | return NULL; |
585 | |
586 | label = ice_pkg_enum_entry(ice_seg, state, sect_type: type, NULL, |
587 | handler: ice_label_enum_handler); |
588 | if (!label) |
589 | return NULL; |
590 | |
591 | *value = le16_to_cpu(label->value); |
592 | return label->name; |
593 | } |
594 | |
595 | /** |
596 | * ice_boost_tcam_handler |
597 | * @sect_type: section type |
598 | * @section: pointer to section |
599 | * @index: index of the boost TCAM entry to be returned |
600 | * @offset: pointer to receive absolute offset, always 0 for boost TCAM sections |
601 | * |
602 | * This is a callback function that can be passed to ice_pkg_enum_entry. |
603 | * Handles enumeration of individual boost TCAM entries. |
604 | */ |
605 | static void *ice_boost_tcam_handler(u32 sect_type, void *section, u32 index, |
606 | u32 *offset) |
607 | { |
608 | struct ice_boost_tcam_section *boost; |
609 | |
610 | if (!section) |
611 | return NULL; |
612 | |
613 | if (sect_type != ICE_SID_RXPARSER_BOOST_TCAM) |
614 | return NULL; |
615 | |
616 | if (index > ICE_MAX_BST_TCAMS_IN_BUF) |
617 | return NULL; |
618 | |
619 | if (offset) |
620 | *offset = 0; |
621 | |
622 | boost = section; |
623 | if (index >= le16_to_cpu(boost->count)) |
624 | return NULL; |
625 | |
626 | return boost->tcam + index; |
627 | } |
628 | |
629 | /** |
630 | * ice_find_boost_entry |
631 | * @ice_seg: pointer to the ice segment (non-NULL) |
632 | * @addr: Boost TCAM address of entry to search for |
633 | * @entry: returns pointer to the entry |
634 | * |
635 | * Finds a particular Boost TCAM entry and returns a pointer to that entry |
636 | * if it is found. The ice_seg parameter must not be NULL since the first call |
637 | * to ice_pkg_enum_entry requires a pointer to an actual ice_segment structure. |
638 | */ |
639 | static int ice_find_boost_entry(struct ice_seg *ice_seg, u16 addr, |
640 | struct ice_boost_tcam_entry **entry) |
641 | { |
642 | struct ice_boost_tcam_entry *tcam; |
643 | struct ice_pkg_enum state; |
644 | |
645 | memset(&state, 0, sizeof(state)); |
646 | |
647 | if (!ice_seg) |
648 | return -EINVAL; |
649 | |
650 | do { |
651 | tcam = ice_pkg_enum_entry(ice_seg, state: &state, |
652 | ICE_SID_RXPARSER_BOOST_TCAM, NULL, |
653 | handler: ice_boost_tcam_handler); |
654 | if (tcam && le16_to_cpu(tcam->addr) == addr) { |
655 | *entry = tcam; |
656 | return 0; |
657 | } |
658 | |
659 | ice_seg = NULL; |
660 | } while (tcam); |
661 | |
662 | *entry = NULL; |
663 | return -EIO; |
664 | } |
665 | |
666 | /** |
667 | * ice_is_init_pkg_successful - check if DDP init was successful |
668 | * @state: state of the DDP pkg after download |
669 | */ |
670 | bool ice_is_init_pkg_successful(enum ice_ddp_state state) |
671 | { |
672 | switch (state) { |
673 | case ICE_DDP_PKG_SUCCESS: |
674 | case ICE_DDP_PKG_SAME_VERSION_ALREADY_LOADED: |
675 | case ICE_DDP_PKG_COMPATIBLE_ALREADY_LOADED: |
676 | return true; |
677 | default: |
678 | return false; |
679 | } |
680 | } |
681 | |
682 | /** |
683 | * ice_pkg_buf_alloc |
684 | * @hw: pointer to the HW structure |
685 | * |
686 | * Allocates a package buffer and returns a pointer to the buffer header. |
687 | * Note: all package contents must be in Little Endian form. |
688 | */ |
689 | struct ice_buf_build *ice_pkg_buf_alloc(struct ice_hw *hw) |
690 | { |
691 | struct ice_buf_build *bld; |
692 | struct ice_buf_hdr *buf; |
693 | |
694 | bld = devm_kzalloc(dev: ice_hw_to_dev(hw), size: sizeof(*bld), GFP_KERNEL); |
695 | if (!bld) |
696 | return NULL; |
697 | |
698 | buf = (struct ice_buf_hdr *)bld; |
699 | buf->data_end = |
700 | cpu_to_le16(offsetof(struct ice_buf_hdr, section_entry)); |
701 | return bld; |
702 | } |
703 | |
704 | static bool ice_is_gtp_u_profile(u16 prof_idx) |
705 | { |
706 | return (prof_idx >= ICE_PROFID_IPV6_GTPU_TEID && |
707 | prof_idx <= ICE_PROFID_IPV6_GTPU_IPV6_TCP_INNER) || |
708 | prof_idx == ICE_PROFID_IPV4_GTPU_TEID; |
709 | } |
710 | |
711 | static bool ice_is_gtp_c_profile(u16 prof_idx) |
712 | { |
713 | switch (prof_idx) { |
714 | case ICE_PROFID_IPV4_GTPC_TEID: |
715 | case ICE_PROFID_IPV4_GTPC_NO_TEID: |
716 | case ICE_PROFID_IPV6_GTPC_TEID: |
717 | case ICE_PROFID_IPV6_GTPC_NO_TEID: |
718 | return true; |
719 | default: |
720 | return false; |
721 | } |
722 | } |
723 | |
724 | /** |
725 | * ice_get_sw_prof_type - determine switch profile type |
726 | * @hw: pointer to the HW structure |
727 | * @fv: pointer to the switch field vector |
728 | * @prof_idx: profile index to check |
729 | */ |
730 | static enum ice_prof_type ice_get_sw_prof_type(struct ice_hw *hw, |
731 | struct ice_fv *fv, u32 prof_idx) |
732 | { |
733 | u16 i; |
734 | |
735 | if (ice_is_gtp_c_profile(prof_idx)) |
736 | return ICE_PROF_TUN_GTPC; |
737 | |
738 | if (ice_is_gtp_u_profile(prof_idx)) |
739 | return ICE_PROF_TUN_GTPU; |
740 | |
741 | for (i = 0; i < hw->blk[ICE_BLK_SW].es.fvw; i++) { |
742 | /* UDP tunnel will have UDP_OF protocol ID and VNI offset */ |
743 | if (fv->ew[i].prot_id == (u8)ICE_PROT_UDP_OF && |
744 | fv->ew[i].off == ICE_VNI_OFFSET) |
745 | return ICE_PROF_TUN_UDP; |
746 | |
747 | /* GRE tunnel will have GRE protocol */ |
748 | if (fv->ew[i].prot_id == (u8)ICE_PROT_GRE_OF) |
749 | return ICE_PROF_TUN_GRE; |
750 | } |
751 | |
752 | return ICE_PROF_NON_TUN; |
753 | } |
754 | |
755 | /** |
756 | * ice_get_sw_fv_bitmap - Get switch field vector bitmap based on profile type |
757 | * @hw: pointer to hardware structure |
758 | * @req_profs: type of profiles requested |
759 | * @bm: pointer to memory for returning the bitmap of field vectors |
760 | */ |
761 | void ice_get_sw_fv_bitmap(struct ice_hw *hw, enum ice_prof_type req_profs, |
762 | unsigned long *bm) |
763 | { |
764 | struct ice_pkg_enum state; |
765 | struct ice_seg *ice_seg; |
766 | struct ice_fv *fv; |
767 | |
768 | if (req_profs == ICE_PROF_ALL) { |
769 | bitmap_set(map: bm, start: 0, ICE_MAX_NUM_PROFILES); |
770 | return; |
771 | } |
772 | |
773 | memset(&state, 0, sizeof(state)); |
774 | bitmap_zero(dst: bm, ICE_MAX_NUM_PROFILES); |
775 | ice_seg = hw->seg; |
776 | do { |
777 | enum ice_prof_type prof_type; |
778 | u32 offset; |
779 | |
780 | fv = ice_pkg_enum_entry(ice_seg, state: &state, ICE_SID_FLD_VEC_SW, |
781 | offset: &offset, handler: ice_sw_fv_handler); |
782 | ice_seg = NULL; |
783 | |
784 | if (fv) { |
785 | /* Determine field vector type */ |
786 | prof_type = ice_get_sw_prof_type(hw, fv, prof_idx: offset); |
787 | |
788 | if (req_profs & prof_type) |
789 | set_bit(nr: (u16)offset, addr: bm); |
790 | } |
791 | } while (fv); |
792 | } |
793 | |
794 | /** |
795 | * ice_get_sw_fv_list |
796 | * @hw: pointer to the HW structure |
797 | * @lkups: list of protocol types |
798 | * @bm: bitmap of field vectors to consider |
799 | * @fv_list: Head of a list |
800 | * |
801 | * Finds all the field vector entries from switch block that contain |
802 | * a given protocol ID and offset and returns a list of structures of type |
803 | * "ice_sw_fv_list_entry". Every structure in the list has a field vector |
804 | * definition and profile ID information |
805 | * NOTE: The caller of the function is responsible for freeing the memory |
806 | * allocated for every list entry. |
807 | */ |
808 | int ice_get_sw_fv_list(struct ice_hw *hw, struct ice_prot_lkup_ext *lkups, |
809 | unsigned long *bm, struct list_head *fv_list) |
810 | { |
811 | struct ice_sw_fv_list_entry *fvl; |
812 | struct ice_sw_fv_list_entry *tmp; |
813 | struct ice_pkg_enum state; |
814 | struct ice_seg *ice_seg; |
815 | struct ice_fv *fv; |
816 | u32 offset; |
817 | |
818 | memset(&state, 0, sizeof(state)); |
819 | |
820 | if (!lkups->n_val_words || !hw->seg) |
821 | return -EINVAL; |
822 | |
823 | ice_seg = hw->seg; |
824 | do { |
825 | u16 i; |
826 | |
827 | fv = ice_pkg_enum_entry(ice_seg, state: &state, ICE_SID_FLD_VEC_SW, |
828 | offset: &offset, handler: ice_sw_fv_handler); |
829 | if (!fv) |
830 | break; |
831 | ice_seg = NULL; |
832 | |
833 | /* If field vector is not in the bitmap list, then skip this |
834 | * profile. |
835 | */ |
836 | if (!test_bit((u16)offset, bm)) |
837 | continue; |
838 | |
839 | for (i = 0; i < lkups->n_val_words; i++) { |
840 | int j; |
841 | |
842 | for (j = 0; j < hw->blk[ICE_BLK_SW].es.fvw; j++) |
843 | if (fv->ew[j].prot_id == |
844 | lkups->fv_words[i].prot_id && |
845 | fv->ew[j].off == lkups->fv_words[i].off) |
846 | break; |
847 | if (j >= hw->blk[ICE_BLK_SW].es.fvw) |
848 | break; |
849 | if (i + 1 == lkups->n_val_words) { |
850 | fvl = devm_kzalloc(dev: ice_hw_to_dev(hw), |
851 | size: sizeof(*fvl), GFP_KERNEL); |
852 | if (!fvl) |
853 | goto err; |
854 | fvl->fv_ptr = fv; |
855 | fvl->profile_id = offset; |
856 | list_add(new: &fvl->list_entry, head: fv_list); |
857 | break; |
858 | } |
859 | } |
860 | } while (fv); |
861 | if (list_empty(head: fv_list)) { |
862 | dev_warn(ice_hw_to_dev(hw), |
863 | "Required profiles not found in currently loaded DDP package" ); |
864 | return -EIO; |
865 | } |
866 | |
867 | return 0; |
868 | |
869 | err: |
870 | list_for_each_entry_safe(fvl, tmp, fv_list, list_entry) { |
871 | list_del(entry: &fvl->list_entry); |
872 | devm_kfree(dev: ice_hw_to_dev(hw), p: fvl); |
873 | } |
874 | |
875 | return -ENOMEM; |
876 | } |
877 | |
878 | /** |
879 | * ice_init_prof_result_bm - Initialize the profile result index bitmap |
880 | * @hw: pointer to hardware structure |
881 | */ |
882 | void ice_init_prof_result_bm(struct ice_hw *hw) |
883 | { |
884 | struct ice_pkg_enum state; |
885 | struct ice_seg *ice_seg; |
886 | struct ice_fv *fv; |
887 | |
888 | memset(&state, 0, sizeof(state)); |
889 | |
890 | if (!hw->seg) |
891 | return; |
892 | |
893 | ice_seg = hw->seg; |
894 | do { |
895 | u32 off; |
896 | u16 i; |
897 | |
898 | fv = ice_pkg_enum_entry(ice_seg, state: &state, ICE_SID_FLD_VEC_SW, |
899 | offset: &off, handler: ice_sw_fv_handler); |
900 | ice_seg = NULL; |
901 | if (!fv) |
902 | break; |
903 | |
904 | bitmap_zero(dst: hw->switch_info->prof_res_bm[off], |
905 | ICE_MAX_FV_WORDS); |
906 | |
907 | /* Determine empty field vector indices, these can be |
908 | * used for recipe results. Skip index 0, since it is |
909 | * always used for Switch ID. |
910 | */ |
911 | for (i = 1; i < ICE_MAX_FV_WORDS; i++) |
912 | if (fv->ew[i].prot_id == ICE_PROT_INVALID && |
913 | fv->ew[i].off == ICE_FV_OFFSET_INVAL) |
914 | set_bit(nr: i, addr: hw->switch_info->prof_res_bm[off]); |
915 | } while (fv); |
916 | } |
917 | |
918 | /** |
919 | * ice_pkg_buf_free |
920 | * @hw: pointer to the HW structure |
921 | * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc()) |
922 | * |
923 | * Frees a package buffer |
924 | */ |
925 | void ice_pkg_buf_free(struct ice_hw *hw, struct ice_buf_build *bld) |
926 | { |
927 | devm_kfree(dev: ice_hw_to_dev(hw), p: bld); |
928 | } |
929 | |
930 | /** |
931 | * ice_pkg_buf_reserve_section |
932 | * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc()) |
933 | * @count: the number of sections to reserve |
934 | * |
935 | * Reserves one or more section table entries in a package buffer. This routine |
936 | * can be called multiple times as long as they are made before calling |
937 | * ice_pkg_buf_alloc_section(). Once ice_pkg_buf_alloc_section() |
938 | * is called once, the number of sections that can be allocated will not be able |
939 | * to be increased; not using all reserved sections is fine, but this will |
940 | * result in some wasted space in the buffer. |
941 | * Note: all package contents must be in Little Endian form. |
942 | */ |
943 | int ice_pkg_buf_reserve_section(struct ice_buf_build *bld, u16 count) |
944 | { |
945 | struct ice_buf_hdr *buf; |
946 | u16 section_count; |
947 | u16 data_end; |
948 | |
949 | if (!bld) |
950 | return -EINVAL; |
951 | |
952 | buf = (struct ice_buf_hdr *)&bld->buf; |
953 | |
954 | /* already an active section, can't increase table size */ |
955 | section_count = le16_to_cpu(buf->section_count); |
956 | if (section_count > 0) |
957 | return -EIO; |
958 | |
959 | if (bld->reserved_section_table_entries + count > ICE_MAX_S_COUNT) |
960 | return -EIO; |
961 | bld->reserved_section_table_entries += count; |
962 | |
963 | data_end = le16_to_cpu(buf->data_end) + |
964 | flex_array_size(buf, section_entry, count); |
965 | buf->data_end = cpu_to_le16(data_end); |
966 | |
967 | return 0; |
968 | } |
969 | |
970 | /** |
971 | * ice_pkg_buf_alloc_section |
972 | * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc()) |
973 | * @type: the section type value |
974 | * @size: the size of the section to reserve (in bytes) |
975 | * |
976 | * Reserves memory in the buffer for a section's content and updates the |
977 | * buffers' status accordingly. This routine returns a pointer to the first |
978 | * byte of the section start within the buffer, which is used to fill in the |
979 | * section contents. |
980 | * Note: all package contents must be in Little Endian form. |
981 | */ |
982 | void *ice_pkg_buf_alloc_section(struct ice_buf_build *bld, u32 type, u16 size) |
983 | { |
984 | struct ice_buf_hdr *buf; |
985 | u16 sect_count; |
986 | u16 data_end; |
987 | |
988 | if (!bld || !type || !size) |
989 | return NULL; |
990 | |
991 | buf = (struct ice_buf_hdr *)&bld->buf; |
992 | |
993 | /* check for enough space left in buffer */ |
994 | data_end = le16_to_cpu(buf->data_end); |
995 | |
996 | /* section start must align on 4 byte boundary */ |
997 | data_end = ALIGN(data_end, 4); |
998 | |
999 | if ((data_end + size) > ICE_MAX_S_DATA_END) |
1000 | return NULL; |
1001 | |
1002 | /* check for more available section table entries */ |
1003 | sect_count = le16_to_cpu(buf->section_count); |
1004 | if (sect_count < bld->reserved_section_table_entries) { |
1005 | void *section_ptr = ((u8 *)buf) + data_end; |
1006 | |
1007 | buf->section_entry[sect_count].offset = cpu_to_le16(data_end); |
1008 | buf->section_entry[sect_count].size = cpu_to_le16(size); |
1009 | buf->section_entry[sect_count].type = cpu_to_le32(type); |
1010 | |
1011 | data_end += size; |
1012 | buf->data_end = cpu_to_le16(data_end); |
1013 | |
1014 | buf->section_count = cpu_to_le16(sect_count + 1); |
1015 | return section_ptr; |
1016 | } |
1017 | |
1018 | /* no free section table entries */ |
1019 | return NULL; |
1020 | } |
1021 | |
1022 | /** |
1023 | * ice_pkg_buf_alloc_single_section |
1024 | * @hw: pointer to the HW structure |
1025 | * @type: the section type value |
1026 | * @size: the size of the section to reserve (in bytes) |
1027 | * @section: returns pointer to the section |
1028 | * |
1029 | * Allocates a package buffer with a single section. |
1030 | * Note: all package contents must be in Little Endian form. |
1031 | */ |
1032 | struct ice_buf_build *ice_pkg_buf_alloc_single_section(struct ice_hw *hw, |
1033 | u32 type, u16 size, |
1034 | void **section) |
1035 | { |
1036 | struct ice_buf_build *buf; |
1037 | |
1038 | if (!section) |
1039 | return NULL; |
1040 | |
1041 | buf = ice_pkg_buf_alloc(hw); |
1042 | if (!buf) |
1043 | return NULL; |
1044 | |
1045 | if (ice_pkg_buf_reserve_section(bld: buf, count: 1)) |
1046 | goto ice_pkg_buf_alloc_single_section_err; |
1047 | |
1048 | *section = ice_pkg_buf_alloc_section(bld: buf, type, size); |
1049 | if (!*section) |
1050 | goto ice_pkg_buf_alloc_single_section_err; |
1051 | |
1052 | return buf; |
1053 | |
1054 | ice_pkg_buf_alloc_single_section_err: |
1055 | ice_pkg_buf_free(hw, bld: buf); |
1056 | return NULL; |
1057 | } |
1058 | |
1059 | /** |
1060 | * ice_pkg_buf_get_active_sections |
1061 | * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc()) |
1062 | * |
1063 | * Returns the number of active sections. Before using the package buffer |
1064 | * in an update package command, the caller should make sure that there is at |
1065 | * least one active section - otherwise, the buffer is not legal and should |
1066 | * not be used. |
1067 | * Note: all package contents must be in Little Endian form. |
1068 | */ |
1069 | u16 ice_pkg_buf_get_active_sections(struct ice_buf_build *bld) |
1070 | { |
1071 | struct ice_buf_hdr *buf; |
1072 | |
1073 | if (!bld) |
1074 | return 0; |
1075 | |
1076 | buf = (struct ice_buf_hdr *)&bld->buf; |
1077 | return le16_to_cpu(buf->section_count); |
1078 | } |
1079 | |
1080 | /** |
1081 | * ice_pkg_buf |
1082 | * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc()) |
1083 | * |
1084 | * Return a pointer to the buffer's header |
1085 | */ |
1086 | struct ice_buf *ice_pkg_buf(struct ice_buf_build *bld) |
1087 | { |
1088 | if (!bld) |
1089 | return NULL; |
1090 | |
1091 | return &bld->buf; |
1092 | } |
1093 | |
1094 | static enum ice_ddp_state ice_map_aq_err_to_ddp_state(enum ice_aq_err aq_err) |
1095 | { |
1096 | switch (aq_err) { |
1097 | case ICE_AQ_RC_ENOSEC: |
1098 | case ICE_AQ_RC_EBADSIG: |
1099 | return ICE_DDP_PKG_FILE_SIGNATURE_INVALID; |
1100 | case ICE_AQ_RC_ESVN: |
1101 | return ICE_DDP_PKG_FILE_REVISION_TOO_LOW; |
1102 | case ICE_AQ_RC_EBADMAN: |
1103 | case ICE_AQ_RC_EBADBUF: |
1104 | return ICE_DDP_PKG_LOAD_ERROR; |
1105 | default: |
1106 | return ICE_DDP_PKG_ERR; |
1107 | } |
1108 | } |
1109 | |
1110 | /** |
1111 | * ice_acquire_global_cfg_lock |
1112 | * @hw: pointer to the HW structure |
1113 | * @access: access type (read or write) |
1114 | * |
1115 | * This function will request ownership of the global config lock for reading |
1116 | * or writing of the package. When attempting to obtain write access, the |
1117 | * caller must check for the following two return values: |
1118 | * |
1119 | * 0 - Means the caller has acquired the global config lock |
1120 | * and can perform writing of the package. |
1121 | * -EALREADY - Indicates another driver has already written the |
1122 | * package or has found that no update was necessary; in |
1123 | * this case, the caller can just skip performing any |
1124 | * update of the package. |
1125 | */ |
1126 | static int ice_acquire_global_cfg_lock(struct ice_hw *hw, |
1127 | enum ice_aq_res_access_type access) |
1128 | { |
1129 | int status; |
1130 | |
1131 | status = ice_acquire_res(hw, res: ICE_GLOBAL_CFG_LOCK_RES_ID, access, |
1132 | ICE_GLOBAL_CFG_LOCK_TIMEOUT); |
1133 | |
1134 | if (!status) |
1135 | mutex_lock(&ice_global_cfg_lock_sw); |
1136 | else if (status == -EALREADY) |
1137 | ice_debug(hw, ICE_DBG_PKG, |
1138 | "Global config lock: No work to do\n" ); |
1139 | |
1140 | return status; |
1141 | } |
1142 | |
1143 | /** |
1144 | * ice_release_global_cfg_lock |
1145 | * @hw: pointer to the HW structure |
1146 | * |
1147 | * This function will release the global config lock. |
1148 | */ |
1149 | static void ice_release_global_cfg_lock(struct ice_hw *hw) |
1150 | { |
1151 | mutex_unlock(lock: &ice_global_cfg_lock_sw); |
1152 | ice_release_res(hw, res: ICE_GLOBAL_CFG_LOCK_RES_ID); |
1153 | } |
1154 | |
1155 | /** |
1156 | * ice_aq_download_pkg |
1157 | * @hw: pointer to the hardware structure |
1158 | * @pkg_buf: the package buffer to transfer |
1159 | * @buf_size: the size of the package buffer |
1160 | * @last_buf: last buffer indicator |
1161 | * @error_offset: returns error offset |
1162 | * @error_info: returns error information |
1163 | * @cd: pointer to command details structure or NULL |
1164 | * |
1165 | * Download Package (0x0C40) |
1166 | */ |
1167 | static int |
1168 | ice_aq_download_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, |
1169 | u16 buf_size, bool last_buf, u32 *error_offset, |
1170 | u32 *error_info, struct ice_sq_cd *cd) |
1171 | { |
1172 | struct ice_aqc_download_pkg *cmd; |
1173 | struct ice_aq_desc desc; |
1174 | int status; |
1175 | |
1176 | if (error_offset) |
1177 | *error_offset = 0; |
1178 | if (error_info) |
1179 | *error_info = 0; |
1180 | |
1181 | cmd = &desc.params.download_pkg; |
1182 | ice_fill_dflt_direct_cmd_desc(desc: &desc, opcode: ice_aqc_opc_download_pkg); |
1183 | desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); |
1184 | |
1185 | if (last_buf) |
1186 | cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF; |
1187 | |
1188 | status = ice_aq_send_cmd(hw, desc: &desc, buf: pkg_buf, buf_size, cd); |
1189 | if (status == -EIO) { |
1190 | /* Read error from buffer only when the FW returned an error */ |
1191 | struct ice_aqc_download_pkg_resp *resp; |
1192 | |
1193 | resp = (struct ice_aqc_download_pkg_resp *)pkg_buf; |
1194 | if (error_offset) |
1195 | *error_offset = le32_to_cpu(resp->error_offset); |
1196 | if (error_info) |
1197 | *error_info = le32_to_cpu(resp->error_info); |
1198 | } |
1199 | |
1200 | return status; |
1201 | } |
1202 | |
1203 | /** |
1204 | * ice_get_pkg_seg_by_idx |
1205 | * @pkg_hdr: pointer to the package header to be searched |
1206 | * @idx: index of segment |
1207 | */ |
1208 | static struct ice_generic_seg_hdr * |
1209 | ice_get_pkg_seg_by_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx) |
1210 | { |
1211 | if (idx < le32_to_cpu(pkg_hdr->seg_count)) |
1212 | return (struct ice_generic_seg_hdr *) |
1213 | ((u8 *)pkg_hdr + |
1214 | le32_to_cpu(pkg_hdr->seg_offset[idx])); |
1215 | |
1216 | return NULL; |
1217 | } |
1218 | |
1219 | /** |
1220 | * ice_is_signing_seg_at_idx - determine if segment is a signing segment |
1221 | * @pkg_hdr: pointer to package header |
1222 | * @idx: segment index |
1223 | */ |
1224 | static bool ice_is_signing_seg_at_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx) |
1225 | { |
1226 | struct ice_generic_seg_hdr *seg; |
1227 | |
1228 | seg = ice_get_pkg_seg_by_idx(pkg_hdr, idx); |
1229 | if (!seg) |
1230 | return false; |
1231 | |
1232 | return le32_to_cpu(seg->seg_type) == SEGMENT_TYPE_SIGNING; |
1233 | } |
1234 | |
1235 | /** |
1236 | * ice_is_signing_seg_type_at_idx |
1237 | * @pkg_hdr: pointer to package header |
1238 | * @idx: segment index |
1239 | * @seg_id: segment id that is expected |
1240 | * @sign_type: signing type |
1241 | * |
1242 | * Determine if a segment is a signing segment of the correct type |
1243 | */ |
1244 | static bool |
1245 | ice_is_signing_seg_type_at_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx, |
1246 | u32 seg_id, u32 sign_type) |
1247 | { |
1248 | struct ice_sign_seg *seg; |
1249 | |
1250 | if (!ice_is_signing_seg_at_idx(pkg_hdr, idx)) |
1251 | return false; |
1252 | |
1253 | seg = (struct ice_sign_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx); |
1254 | |
1255 | if (seg && le32_to_cpu(seg->seg_id) == seg_id && |
1256 | le32_to_cpu(seg->sign_type) == sign_type) |
1257 | return true; |
1258 | |
1259 | return false; |
1260 | } |
1261 | |
1262 | /** |
1263 | * ice_is_buffer_metadata - determine if package buffer is a metadata buffer |
1264 | * @buf: pointer to buffer header |
1265 | */ |
1266 | static bool ice_is_buffer_metadata(struct ice_buf_hdr *buf) |
1267 | { |
1268 | if (le32_to_cpu(buf->section_entry[0].type) & ICE_METADATA_BUF) |
1269 | return true; |
1270 | |
1271 | return false; |
1272 | } |
1273 | |
1274 | /** |
1275 | * ice_is_last_download_buffer |
1276 | * @buf: pointer to current buffer header |
1277 | * @idx: index of the buffer in the current sequence |
1278 | * @count: the buffer count in the current sequence |
1279 | * |
1280 | * Note: this routine should only be called if the buffer is not the last buffer |
1281 | */ |
1282 | static bool |
1283 | ice_is_last_download_buffer(struct ice_buf_hdr *buf, u32 idx, u32 count) |
1284 | { |
1285 | struct ice_buf *next_buf; |
1286 | |
1287 | if ((idx + 1) == count) |
1288 | return true; |
1289 | |
1290 | /* A set metadata flag in the next buffer will signal that the current |
1291 | * buffer will be the last buffer downloaded |
1292 | */ |
1293 | next_buf = ((struct ice_buf *)buf) + 1; |
1294 | |
1295 | return ice_is_buffer_metadata(buf: (struct ice_buf_hdr *)next_buf); |
1296 | } |
1297 | |
1298 | /** |
1299 | * ice_dwnld_cfg_bufs_no_lock |
1300 | * @hw: pointer to the hardware structure |
1301 | * @bufs: pointer to an array of buffers |
1302 | * @start: buffer index of first buffer to download |
1303 | * @count: the number of buffers to download |
1304 | * @indicate_last: if true, then set last buffer flag on last buffer download |
1305 | * |
1306 | * Downloads package configuration buffers to the firmware. Metadata buffers |
1307 | * are skipped, and the first metadata buffer found indicates that the rest |
1308 | * of the buffers are all metadata buffers. |
1309 | */ |
1310 | static enum ice_ddp_state |
1311 | ice_dwnld_cfg_bufs_no_lock(struct ice_hw *hw, struct ice_buf *bufs, u32 start, |
1312 | u32 count, bool indicate_last) |
1313 | { |
1314 | enum ice_ddp_state state = ICE_DDP_PKG_SUCCESS; |
1315 | struct ice_buf_hdr *bh; |
1316 | enum ice_aq_err err; |
1317 | u32 offset, info, i; |
1318 | |
1319 | if (!bufs || !count) |
1320 | return ICE_DDP_PKG_ERR; |
1321 | |
1322 | /* If the first buffer's first section has its metadata bit set |
1323 | * then there are no buffers to be downloaded, and the operation is |
1324 | * considered a success. |
1325 | */ |
1326 | bh = (struct ice_buf_hdr *)(bufs + start); |
1327 | if (le32_to_cpu(bh->section_entry[0].type) & ICE_METADATA_BUF) |
1328 | return ICE_DDP_PKG_SUCCESS; |
1329 | |
1330 | for (i = 0; i < count; i++) { |
1331 | bool last = false; |
1332 | int status; |
1333 | |
1334 | bh = (struct ice_buf_hdr *)(bufs + start + i); |
1335 | |
1336 | if (indicate_last) |
1337 | last = ice_is_last_download_buffer(buf: bh, idx: i, count); |
1338 | |
1339 | status = ice_aq_download_pkg(hw, pkg_buf: bh, ICE_PKG_BUF_SIZE, last_buf: last, |
1340 | error_offset: &offset, error_info: &info, NULL); |
1341 | |
1342 | /* Save AQ status from download package */ |
1343 | if (status) { |
1344 | ice_debug(hw, ICE_DBG_PKG, "Pkg download failed: err %d off %d inf %d\n" , |
1345 | status, offset, info); |
1346 | err = hw->adminq.sq_last_status; |
1347 | state = ice_map_aq_err_to_ddp_state(aq_err: err); |
1348 | break; |
1349 | } |
1350 | |
1351 | if (last) |
1352 | break; |
1353 | } |
1354 | |
1355 | return state; |
1356 | } |
1357 | |
1358 | /** |
1359 | * ice_download_pkg_sig_seg - download a signature segment |
1360 | * @hw: pointer to the hardware structure |
1361 | * @seg: pointer to signature segment |
1362 | */ |
1363 | static enum ice_ddp_state |
1364 | ice_download_pkg_sig_seg(struct ice_hw *hw, struct ice_sign_seg *seg) |
1365 | { |
1366 | return ice_dwnld_cfg_bufs_no_lock(hw, bufs: seg->buf_tbl.buf_array, start: 0, |
1367 | le32_to_cpu(seg->buf_tbl.buf_count), |
1368 | indicate_last: false); |
1369 | } |
1370 | |
1371 | /** |
1372 | * ice_download_pkg_config_seg - download a config segment |
1373 | * @hw: pointer to the hardware structure |
1374 | * @pkg_hdr: pointer to package header |
1375 | * @idx: segment index |
1376 | * @start: starting buffer |
1377 | * @count: buffer count |
1378 | * |
1379 | * Note: idx must reference a ICE segment |
1380 | */ |
1381 | static enum ice_ddp_state |
1382 | ice_download_pkg_config_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr, |
1383 | u32 idx, u32 start, u32 count) |
1384 | { |
1385 | struct ice_buf_table *bufs; |
1386 | struct ice_seg *seg; |
1387 | u32 buf_count; |
1388 | |
1389 | seg = (struct ice_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx); |
1390 | if (!seg) |
1391 | return ICE_DDP_PKG_ERR; |
1392 | |
1393 | bufs = ice_find_buf_table(ice_seg: seg); |
1394 | buf_count = le32_to_cpu(bufs->buf_count); |
1395 | |
1396 | if (start >= buf_count || start + count > buf_count) |
1397 | return ICE_DDP_PKG_ERR; |
1398 | |
1399 | return ice_dwnld_cfg_bufs_no_lock(hw, bufs: bufs->buf_array, start, count, |
1400 | indicate_last: true); |
1401 | } |
1402 | |
1403 | /** |
1404 | * ice_dwnld_sign_and_cfg_segs - download a signing segment and config segment |
1405 | * @hw: pointer to the hardware structure |
1406 | * @pkg_hdr: pointer to package header |
1407 | * @idx: segment index (must be a signature segment) |
1408 | * |
1409 | * Note: idx must reference a signature segment |
1410 | */ |
1411 | static enum ice_ddp_state |
1412 | ice_dwnld_sign_and_cfg_segs(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr, |
1413 | u32 idx) |
1414 | { |
1415 | enum ice_ddp_state state; |
1416 | struct ice_sign_seg *seg; |
1417 | u32 conf_idx; |
1418 | u32 start; |
1419 | u32 count; |
1420 | |
1421 | seg = (struct ice_sign_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx); |
1422 | if (!seg) { |
1423 | state = ICE_DDP_PKG_ERR; |
1424 | goto exit; |
1425 | } |
1426 | |
1427 | conf_idx = le32_to_cpu(seg->signed_seg_idx); |
1428 | start = le32_to_cpu(seg->signed_buf_start); |
1429 | count = le32_to_cpu(seg->signed_buf_count); |
1430 | |
1431 | state = ice_download_pkg_sig_seg(hw, seg); |
1432 | if (state) |
1433 | goto exit; |
1434 | |
1435 | state = ice_download_pkg_config_seg(hw, pkg_hdr, idx: conf_idx, start, |
1436 | count); |
1437 | |
1438 | exit: |
1439 | return state; |
1440 | } |
1441 | |
1442 | /** |
1443 | * ice_match_signing_seg - determine if a matching signing segment exists |
1444 | * @pkg_hdr: pointer to package header |
1445 | * @seg_id: segment id that is expected |
1446 | * @sign_type: signing type |
1447 | */ |
1448 | static bool |
1449 | ice_match_signing_seg(struct ice_pkg_hdr *pkg_hdr, u32 seg_id, u32 sign_type) |
1450 | { |
1451 | u32 i; |
1452 | |
1453 | for (i = 0; i < le32_to_cpu(pkg_hdr->seg_count); i++) { |
1454 | if (ice_is_signing_seg_type_at_idx(pkg_hdr, idx: i, seg_id, |
1455 | sign_type)) |
1456 | return true; |
1457 | } |
1458 | |
1459 | return false; |
1460 | } |
1461 | |
1462 | /** |
1463 | * ice_post_dwnld_pkg_actions - perform post download package actions |
1464 | * @hw: pointer to the hardware structure |
1465 | */ |
1466 | static enum ice_ddp_state |
1467 | ice_post_dwnld_pkg_actions(struct ice_hw *hw) |
1468 | { |
1469 | int status; |
1470 | |
1471 | status = ice_set_vlan_mode(hw); |
1472 | if (status) { |
1473 | ice_debug(hw, ICE_DBG_PKG, "Failed to set VLAN mode: err %d\n" , |
1474 | status); |
1475 | return ICE_DDP_PKG_ERR; |
1476 | } |
1477 | |
1478 | return ICE_DDP_PKG_SUCCESS; |
1479 | } |
1480 | |
1481 | /** |
1482 | * ice_download_pkg |
1483 | * @hw: pointer to the hardware structure |
1484 | * @pkg_hdr: pointer to package header |
1485 | * |
1486 | * Handles the download of a complete package. |
1487 | */ |
1488 | static enum ice_ddp_state |
1489 | ice_download_pkg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr) |
1490 | { |
1491 | enum ice_aq_err aq_err = hw->adminq.sq_last_status; |
1492 | enum ice_ddp_state state = ICE_DDP_PKG_ERR; |
1493 | int status; |
1494 | u32 i; |
1495 | |
1496 | ice_debug(hw, ICE_DBG_INIT, "Segment ID %d\n" , hw->pkg_seg_id); |
1497 | ice_debug(hw, ICE_DBG_INIT, "Signature type %d\n" , hw->pkg_sign_type); |
1498 | |
1499 | status = ice_acquire_global_cfg_lock(hw, access: ICE_RES_WRITE); |
1500 | if (status) { |
1501 | if (status == -EALREADY) |
1502 | state = ICE_DDP_PKG_ALREADY_LOADED; |
1503 | else |
1504 | state = ice_map_aq_err_to_ddp_state(aq_err); |
1505 | return state; |
1506 | } |
1507 | |
1508 | for (i = 0; i < le32_to_cpu(pkg_hdr->seg_count); i++) { |
1509 | if (!ice_is_signing_seg_type_at_idx(pkg_hdr, idx: i, seg_id: hw->pkg_seg_id, |
1510 | sign_type: hw->pkg_sign_type)) |
1511 | continue; |
1512 | |
1513 | state = ice_dwnld_sign_and_cfg_segs(hw, pkg_hdr, idx: i); |
1514 | if (state) |
1515 | break; |
1516 | } |
1517 | |
1518 | if (!state) |
1519 | state = ice_post_dwnld_pkg_actions(hw); |
1520 | |
1521 | ice_release_global_cfg_lock(hw); |
1522 | ice_post_pkg_dwnld_vlan_mode_cfg(hw); |
1523 | |
1524 | return state; |
1525 | } |
1526 | |
1527 | /** |
1528 | * ice_aq_get_pkg_info_list |
1529 | * @hw: pointer to the hardware structure |
1530 | * @pkg_info: the buffer which will receive the information list |
1531 | * @buf_size: the size of the pkg_info information buffer |
1532 | * @cd: pointer to command details structure or NULL |
1533 | * |
1534 | * Get Package Info List (0x0C43) |
1535 | */ |
1536 | static int ice_aq_get_pkg_info_list(struct ice_hw *hw, |
1537 | struct ice_aqc_get_pkg_info_resp *pkg_info, |
1538 | u16 buf_size, struct ice_sq_cd *cd) |
1539 | { |
1540 | struct ice_aq_desc desc; |
1541 | |
1542 | ice_fill_dflt_direct_cmd_desc(desc: &desc, opcode: ice_aqc_opc_get_pkg_info_list); |
1543 | |
1544 | return ice_aq_send_cmd(hw, desc: &desc, buf: pkg_info, buf_size, cd); |
1545 | } |
1546 | |
1547 | /** |
1548 | * ice_aq_update_pkg |
1549 | * @hw: pointer to the hardware structure |
1550 | * @pkg_buf: the package cmd buffer |
1551 | * @buf_size: the size of the package cmd buffer |
1552 | * @last_buf: last buffer indicator |
1553 | * @error_offset: returns error offset |
1554 | * @error_info: returns error information |
1555 | * @cd: pointer to command details structure or NULL |
1556 | * |
1557 | * Update Package (0x0C42) |
1558 | */ |
1559 | static int ice_aq_update_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, |
1560 | u16 buf_size, bool last_buf, u32 *error_offset, |
1561 | u32 *error_info, struct ice_sq_cd *cd) |
1562 | { |
1563 | struct ice_aqc_download_pkg *cmd; |
1564 | struct ice_aq_desc desc; |
1565 | int status; |
1566 | |
1567 | if (error_offset) |
1568 | *error_offset = 0; |
1569 | if (error_info) |
1570 | *error_info = 0; |
1571 | |
1572 | cmd = &desc.params.download_pkg; |
1573 | ice_fill_dflt_direct_cmd_desc(desc: &desc, opcode: ice_aqc_opc_update_pkg); |
1574 | desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); |
1575 | |
1576 | if (last_buf) |
1577 | cmd->flags |= ICE_AQC_DOWNLOAD_PKG_LAST_BUF; |
1578 | |
1579 | status = ice_aq_send_cmd(hw, desc: &desc, buf: pkg_buf, buf_size, cd); |
1580 | if (status == -EIO) { |
1581 | /* Read error from buffer only when the FW returned an error */ |
1582 | struct ice_aqc_download_pkg_resp *resp; |
1583 | |
1584 | resp = (struct ice_aqc_download_pkg_resp *)pkg_buf; |
1585 | if (error_offset) |
1586 | *error_offset = le32_to_cpu(resp->error_offset); |
1587 | if (error_info) |
1588 | *error_info = le32_to_cpu(resp->error_info); |
1589 | } |
1590 | |
1591 | return status; |
1592 | } |
1593 | |
1594 | /** |
1595 | * ice_aq_upload_section |
1596 | * @hw: pointer to the hardware structure |
1597 | * @pkg_buf: the package buffer which will receive the section |
1598 | * @buf_size: the size of the package buffer |
1599 | * @cd: pointer to command details structure or NULL |
1600 | * |
1601 | * Upload Section (0x0C41) |
1602 | */ |
1603 | int ice_aq_upload_section(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, |
1604 | u16 buf_size, struct ice_sq_cd *cd) |
1605 | { |
1606 | struct ice_aq_desc desc; |
1607 | |
1608 | ice_fill_dflt_direct_cmd_desc(desc: &desc, opcode: ice_aqc_opc_upload_section); |
1609 | desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); |
1610 | |
1611 | return ice_aq_send_cmd(hw, desc: &desc, buf: pkg_buf, buf_size, cd); |
1612 | } |
1613 | |
1614 | /** |
1615 | * ice_update_pkg_no_lock |
1616 | * @hw: pointer to the hardware structure |
1617 | * @bufs: pointer to an array of buffers |
1618 | * @count: the number of buffers in the array |
1619 | */ |
1620 | int ice_update_pkg_no_lock(struct ice_hw *hw, struct ice_buf *bufs, u32 count) |
1621 | { |
1622 | int status = 0; |
1623 | u32 i; |
1624 | |
1625 | for (i = 0; i < count; i++) { |
1626 | struct ice_buf_hdr *bh = (struct ice_buf_hdr *)(bufs + i); |
1627 | bool last = ((i + 1) == count); |
1628 | u32 offset, info; |
1629 | |
1630 | status = ice_aq_update_pkg(hw, pkg_buf: bh, le16_to_cpu(bh->data_end), |
1631 | last_buf: last, error_offset: &offset, error_info: &info, NULL); |
1632 | |
1633 | if (status) { |
1634 | ice_debug(hw, ICE_DBG_PKG, |
1635 | "Update pkg failed: err %d off %d inf %d\n" , |
1636 | status, offset, info); |
1637 | break; |
1638 | } |
1639 | } |
1640 | |
1641 | return status; |
1642 | } |
1643 | |
1644 | /** |
1645 | * ice_update_pkg |
1646 | * @hw: pointer to the hardware structure |
1647 | * @bufs: pointer to an array of buffers |
1648 | * @count: the number of buffers in the array |
1649 | * |
1650 | * Obtains change lock and updates package. |
1651 | */ |
1652 | int ice_update_pkg(struct ice_hw *hw, struct ice_buf *bufs, u32 count) |
1653 | { |
1654 | int status; |
1655 | |
1656 | status = ice_acquire_change_lock(hw, access: ICE_RES_WRITE); |
1657 | if (status) |
1658 | return status; |
1659 | |
1660 | status = ice_update_pkg_no_lock(hw, bufs, count); |
1661 | |
1662 | ice_release_change_lock(hw); |
1663 | |
1664 | return status; |
1665 | } |
1666 | |
1667 | /** |
1668 | * ice_find_seg_in_pkg |
1669 | * @hw: pointer to the hardware structure |
1670 | * @seg_type: the segment type to search for (i.e., SEGMENT_TYPE_CPK) |
1671 | * @pkg_hdr: pointer to the package header to be searched |
1672 | * |
1673 | * This function searches a package file for a particular segment type. On |
1674 | * success it returns a pointer to the segment header, otherwise it will |
1675 | * return NULL. |
1676 | */ |
1677 | static struct ice_generic_seg_hdr * |
1678 | ice_find_seg_in_pkg(struct ice_hw *hw, u32 seg_type, |
1679 | struct ice_pkg_hdr *pkg_hdr) |
1680 | { |
1681 | u32 i; |
1682 | |
1683 | ice_debug(hw, ICE_DBG_PKG, "Package format version: %d.%d.%d.%d\n" , |
1684 | pkg_hdr->pkg_format_ver.major, pkg_hdr->pkg_format_ver.minor, |
1685 | pkg_hdr->pkg_format_ver.update, |
1686 | pkg_hdr->pkg_format_ver.draft); |
1687 | |
1688 | /* Search all package segments for the requested segment type */ |
1689 | for (i = 0; i < le32_to_cpu(pkg_hdr->seg_count); i++) { |
1690 | struct ice_generic_seg_hdr *seg; |
1691 | |
1692 | seg = (struct ice_generic_seg_hdr |
1693 | *)((u8 *)pkg_hdr + |
1694 | le32_to_cpu(pkg_hdr->seg_offset[i])); |
1695 | |
1696 | if (le32_to_cpu(seg->seg_type) == seg_type) |
1697 | return seg; |
1698 | } |
1699 | |
1700 | return NULL; |
1701 | } |
1702 | |
1703 | /** |
1704 | * ice_has_signing_seg - determine if package has a signing segment |
1705 | * @hw: pointer to the hardware structure |
1706 | * @pkg_hdr: pointer to the driver's package hdr |
1707 | */ |
1708 | static bool ice_has_signing_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr) |
1709 | { |
1710 | struct ice_generic_seg_hdr *seg_hdr; |
1711 | |
1712 | seg_hdr = (struct ice_generic_seg_hdr *) |
1713 | ice_find_seg_in_pkg(hw, SEGMENT_TYPE_SIGNING, pkg_hdr); |
1714 | |
1715 | return seg_hdr ? true : false; |
1716 | } |
1717 | |
1718 | /** |
1719 | * ice_get_pkg_segment_id - get correct package segment id, based on device |
1720 | * @mac_type: MAC type of the device |
1721 | */ |
1722 | static u32 ice_get_pkg_segment_id(enum ice_mac_type mac_type) |
1723 | { |
1724 | u32 seg_id; |
1725 | |
1726 | switch (mac_type) { |
1727 | case ICE_MAC_E830: |
1728 | seg_id = SEGMENT_TYPE_ICE_E830; |
1729 | break; |
1730 | case ICE_MAC_GENERIC: |
1731 | default: |
1732 | seg_id = SEGMENT_TYPE_ICE_E810; |
1733 | break; |
1734 | } |
1735 | |
1736 | return seg_id; |
1737 | } |
1738 | |
1739 | /** |
1740 | * ice_get_pkg_sign_type - get package segment sign type, based on device |
1741 | * @mac_type: MAC type of the device |
1742 | */ |
1743 | static u32 ice_get_pkg_sign_type(enum ice_mac_type mac_type) |
1744 | { |
1745 | u32 sign_type; |
1746 | |
1747 | switch (mac_type) { |
1748 | case ICE_MAC_E830: |
1749 | sign_type = SEGMENT_SIGN_TYPE_RSA3K_SBB; |
1750 | break; |
1751 | case ICE_MAC_GENERIC: |
1752 | default: |
1753 | sign_type = SEGMENT_SIGN_TYPE_RSA2K; |
1754 | break; |
1755 | } |
1756 | |
1757 | return sign_type; |
1758 | } |
1759 | |
1760 | /** |
1761 | * ice_get_signing_req - get correct package requirements, based on device |
1762 | * @hw: pointer to the hardware structure |
1763 | */ |
1764 | static void ice_get_signing_req(struct ice_hw *hw) |
1765 | { |
1766 | hw->pkg_seg_id = ice_get_pkg_segment_id(mac_type: hw->mac_type); |
1767 | hw->pkg_sign_type = ice_get_pkg_sign_type(mac_type: hw->mac_type); |
1768 | } |
1769 | |
1770 | /** |
1771 | * ice_init_pkg_info |
1772 | * @hw: pointer to the hardware structure |
1773 | * @pkg_hdr: pointer to the driver's package hdr |
1774 | * |
1775 | * Saves off the package details into the HW structure. |
1776 | */ |
1777 | static enum ice_ddp_state ice_init_pkg_info(struct ice_hw *hw, |
1778 | struct ice_pkg_hdr *pkg_hdr) |
1779 | { |
1780 | struct ice_generic_seg_hdr *seg_hdr; |
1781 | |
1782 | if (!pkg_hdr) |
1783 | return ICE_DDP_PKG_ERR; |
1784 | |
1785 | hw->pkg_has_signing_seg = ice_has_signing_seg(hw, pkg_hdr); |
1786 | ice_get_signing_req(hw); |
1787 | |
1788 | ice_debug(hw, ICE_DBG_INIT, "Pkg using segment id: 0x%08X\n" , |
1789 | hw->pkg_seg_id); |
1790 | |
1791 | seg_hdr = (struct ice_generic_seg_hdr *) |
1792 | ice_find_seg_in_pkg(hw, seg_type: hw->pkg_seg_id, pkg_hdr); |
1793 | if (seg_hdr) { |
1794 | struct ice_meta_sect *meta; |
1795 | struct ice_pkg_enum state; |
1796 | |
1797 | memset(&state, 0, sizeof(state)); |
1798 | |
1799 | /* Get package information from the Metadata Section */ |
1800 | meta = ice_pkg_enum_section(ice_seg: (struct ice_seg *)seg_hdr, state: &state, |
1801 | ICE_SID_METADATA); |
1802 | if (!meta) { |
1803 | ice_debug(hw, ICE_DBG_INIT, |
1804 | "Did not find ice metadata section in package\n" ); |
1805 | return ICE_DDP_PKG_INVALID_FILE; |
1806 | } |
1807 | |
1808 | hw->pkg_ver = meta->ver; |
1809 | memcpy(hw->pkg_name, meta->name, sizeof(meta->name)); |
1810 | |
1811 | ice_debug(hw, ICE_DBG_PKG, "Pkg: %d.%d.%d.%d, %s\n" , |
1812 | meta->ver.major, meta->ver.minor, meta->ver.update, |
1813 | meta->ver.draft, meta->name); |
1814 | |
1815 | hw->ice_seg_fmt_ver = seg_hdr->seg_format_ver; |
1816 | memcpy(hw->ice_seg_id, seg_hdr->seg_id, sizeof(hw->ice_seg_id)); |
1817 | |
1818 | ice_debug(hw, ICE_DBG_PKG, "Ice Seg: %d.%d.%d.%d, %s\n" , |
1819 | seg_hdr->seg_format_ver.major, |
1820 | seg_hdr->seg_format_ver.minor, |
1821 | seg_hdr->seg_format_ver.update, |
1822 | seg_hdr->seg_format_ver.draft, seg_hdr->seg_id); |
1823 | } else { |
1824 | ice_debug(hw, ICE_DBG_INIT, |
1825 | "Did not find ice segment in driver package\n" ); |
1826 | return ICE_DDP_PKG_INVALID_FILE; |
1827 | } |
1828 | |
1829 | return ICE_DDP_PKG_SUCCESS; |
1830 | } |
1831 | |
1832 | /** |
1833 | * ice_get_pkg_info |
1834 | * @hw: pointer to the hardware structure |
1835 | * |
1836 | * Store details of the package currently loaded in HW into the HW structure. |
1837 | */ |
1838 | static enum ice_ddp_state ice_get_pkg_info(struct ice_hw *hw) |
1839 | { |
1840 | DEFINE_FLEX(struct ice_aqc_get_pkg_info_resp, pkg_info, pkg_info, |
1841 | ICE_PKG_CNT); |
1842 | u16 size = __struct_size(pkg_info); |
1843 | u32 i; |
1844 | |
1845 | if (ice_aq_get_pkg_info_list(hw, pkg_info, buf_size: size, NULL)) |
1846 | return ICE_DDP_PKG_ERR; |
1847 | |
1848 | for (i = 0; i < le32_to_cpu(pkg_info->count); i++) { |
1849 | #define ICE_PKG_FLAG_COUNT 4 |
1850 | char flags[ICE_PKG_FLAG_COUNT + 1] = { 0 }; |
1851 | u8 place = 0; |
1852 | |
1853 | if (pkg_info->pkg_info[i].is_active) { |
1854 | flags[place++] = 'A'; |
1855 | hw->active_pkg_ver = pkg_info->pkg_info[i].ver; |
1856 | hw->active_track_id = |
1857 | le32_to_cpu(pkg_info->pkg_info[i].track_id); |
1858 | memcpy(hw->active_pkg_name, pkg_info->pkg_info[i].name, |
1859 | sizeof(pkg_info->pkg_info[i].name)); |
1860 | hw->active_pkg_in_nvm = pkg_info->pkg_info[i].is_in_nvm; |
1861 | } |
1862 | if (pkg_info->pkg_info[i].is_active_at_boot) |
1863 | flags[place++] = 'B'; |
1864 | if (pkg_info->pkg_info[i].is_modified) |
1865 | flags[place++] = 'M'; |
1866 | if (pkg_info->pkg_info[i].is_in_nvm) |
1867 | flags[place++] = 'N'; |
1868 | |
1869 | ice_debug(hw, ICE_DBG_PKG, "Pkg[%d]: %d.%d.%d.%d,%s,%s\n" , i, |
1870 | pkg_info->pkg_info[i].ver.major, |
1871 | pkg_info->pkg_info[i].ver.minor, |
1872 | pkg_info->pkg_info[i].ver.update, |
1873 | pkg_info->pkg_info[i].ver.draft, |
1874 | pkg_info->pkg_info[i].name, flags); |
1875 | } |
1876 | |
1877 | return ICE_DDP_PKG_SUCCESS; |
1878 | } |
1879 | |
1880 | /** |
1881 | * ice_chk_pkg_compat |
1882 | * @hw: pointer to the hardware structure |
1883 | * @ospkg: pointer to the package hdr |
1884 | * @seg: pointer to the package segment hdr |
1885 | * |
1886 | * This function checks the package version compatibility with driver and NVM |
1887 | */ |
1888 | static enum ice_ddp_state ice_chk_pkg_compat(struct ice_hw *hw, |
1889 | struct ice_pkg_hdr *ospkg, |
1890 | struct ice_seg **seg) |
1891 | { |
1892 | DEFINE_FLEX(struct ice_aqc_get_pkg_info_resp, pkg, pkg_info, |
1893 | ICE_PKG_CNT); |
1894 | u16 size = __struct_size(pkg); |
1895 | enum ice_ddp_state state; |
1896 | u32 i; |
1897 | |
1898 | /* Check package version compatibility */ |
1899 | state = ice_chk_pkg_version(pkg_ver: &hw->pkg_ver); |
1900 | if (state) { |
1901 | ice_debug(hw, ICE_DBG_INIT, "Package version check failed.\n" ); |
1902 | return state; |
1903 | } |
1904 | |
1905 | /* find ICE segment in given package */ |
1906 | *seg = (struct ice_seg *)ice_find_seg_in_pkg(hw, seg_type: hw->pkg_seg_id, |
1907 | pkg_hdr: ospkg); |
1908 | if (!*seg) { |
1909 | ice_debug(hw, ICE_DBG_INIT, "no ice segment in package.\n" ); |
1910 | return ICE_DDP_PKG_INVALID_FILE; |
1911 | } |
1912 | |
1913 | /* Check if FW is compatible with the OS package */ |
1914 | if (ice_aq_get_pkg_info_list(hw, pkg_info: pkg, buf_size: size, NULL)) |
1915 | return ICE_DDP_PKG_LOAD_ERROR; |
1916 | |
1917 | for (i = 0; i < le32_to_cpu(pkg->count); i++) { |
1918 | /* loop till we find the NVM package */ |
1919 | if (!pkg->pkg_info[i].is_in_nvm) |
1920 | continue; |
1921 | if ((*seg)->hdr.seg_format_ver.major != |
1922 | pkg->pkg_info[i].ver.major || |
1923 | (*seg)->hdr.seg_format_ver.minor > |
1924 | pkg->pkg_info[i].ver.minor) { |
1925 | state = ICE_DDP_PKG_FW_MISMATCH; |
1926 | ice_debug(hw, ICE_DBG_INIT, |
1927 | "OS package is not compatible with NVM.\n" ); |
1928 | } |
1929 | /* done processing NVM package so break */ |
1930 | break; |
1931 | } |
1932 | |
1933 | return state; |
1934 | } |
1935 | |
1936 | /** |
1937 | * ice_init_pkg_hints |
1938 | * @hw: pointer to the HW structure |
1939 | * @ice_seg: pointer to the segment of the package scan (non-NULL) |
1940 | * |
1941 | * This function will scan the package and save off relevant information |
1942 | * (hints or metadata) for driver use. The ice_seg parameter must not be NULL |
1943 | * since the first call to ice_enum_labels requires a pointer to an actual |
1944 | * ice_seg structure. |
1945 | */ |
1946 | static void ice_init_pkg_hints(struct ice_hw *hw, struct ice_seg *ice_seg) |
1947 | { |
1948 | struct ice_pkg_enum state; |
1949 | char *label_name; |
1950 | u16 val; |
1951 | int i; |
1952 | |
1953 | memset(&hw->tnl, 0, sizeof(hw->tnl)); |
1954 | memset(&state, 0, sizeof(state)); |
1955 | |
1956 | if (!ice_seg) |
1957 | return; |
1958 | |
1959 | label_name = ice_enum_labels(ice_seg, ICE_SID_LBL_RXPARSER_TMEM, state: &state, |
1960 | value: &val); |
1961 | |
1962 | while (label_name) { |
1963 | if (!strncmp(label_name, ICE_TNL_PRE, strlen(ICE_TNL_PRE))) |
1964 | /* check for a tunnel entry */ |
1965 | ice_add_tunnel_hint(hw, label_name, val); |
1966 | |
1967 | /* check for a dvm mode entry */ |
1968 | else if (!strncmp(label_name, ICE_DVM_PRE, strlen(ICE_DVM_PRE))) |
1969 | ice_add_dvm_hint(hw, val, enable: true); |
1970 | |
1971 | /* check for a svm mode entry */ |
1972 | else if (!strncmp(label_name, ICE_SVM_PRE, strlen(ICE_SVM_PRE))) |
1973 | ice_add_dvm_hint(hw, val, enable: false); |
1974 | |
1975 | label_name = ice_enum_labels(NULL, type: 0, state: &state, value: &val); |
1976 | } |
1977 | |
1978 | /* Cache the appropriate boost TCAM entry pointers for tunnels */ |
1979 | for (i = 0; i < hw->tnl.count; i++) { |
1980 | ice_find_boost_entry(ice_seg, addr: hw->tnl.tbl[i].boost_addr, |
1981 | entry: &hw->tnl.tbl[i].boost_entry); |
1982 | if (hw->tnl.tbl[i].boost_entry) { |
1983 | hw->tnl.tbl[i].valid = true; |
1984 | if (hw->tnl.tbl[i].type < __TNL_TYPE_CNT) |
1985 | hw->tnl.valid_count[hw->tnl.tbl[i].type]++; |
1986 | } |
1987 | } |
1988 | |
1989 | /* Cache the appropriate boost TCAM entry pointers for DVM and SVM */ |
1990 | for (i = 0; i < hw->dvm_upd.count; i++) |
1991 | ice_find_boost_entry(ice_seg, addr: hw->dvm_upd.tbl[i].boost_addr, |
1992 | entry: &hw->dvm_upd.tbl[i].boost_entry); |
1993 | } |
1994 | |
1995 | /** |
1996 | * ice_fill_hw_ptype - fill the enabled PTYPE bit information |
1997 | * @hw: pointer to the HW structure |
1998 | */ |
1999 | static void ice_fill_hw_ptype(struct ice_hw *hw) |
2000 | { |
2001 | struct ice_marker_ptype_tcam_entry *tcam; |
2002 | struct ice_seg *seg = hw->seg; |
2003 | struct ice_pkg_enum state; |
2004 | |
2005 | bitmap_zero(dst: hw->hw_ptype, ICE_FLOW_PTYPE_MAX); |
2006 | if (!seg) |
2007 | return; |
2008 | |
2009 | memset(&state, 0, sizeof(state)); |
2010 | |
2011 | do { |
2012 | tcam = ice_pkg_enum_entry(ice_seg: seg, state: &state, |
2013 | ICE_SID_RXPARSER_MARKER_PTYPE, NULL, |
2014 | handler: ice_marker_ptype_tcam_handler); |
2015 | if (tcam && |
2016 | le16_to_cpu(tcam->addr) < ICE_MARKER_PTYPE_TCAM_ADDR_MAX && |
2017 | le16_to_cpu(tcam->ptype) < ICE_FLOW_PTYPE_MAX) |
2018 | set_bit(le16_to_cpu(tcam->ptype), addr: hw->hw_ptype); |
2019 | |
2020 | seg = NULL; |
2021 | } while (tcam); |
2022 | } |
2023 | |
2024 | /** |
2025 | * ice_init_pkg - initialize/download package |
2026 | * @hw: pointer to the hardware structure |
2027 | * @buf: pointer to the package buffer |
2028 | * @len: size of the package buffer |
2029 | * |
2030 | * This function initializes a package. The package contains HW tables |
2031 | * required to do packet processing. First, the function extracts package |
2032 | * information such as version. Then it finds the ice configuration segment |
2033 | * within the package; this function then saves a copy of the segment pointer |
2034 | * within the supplied package buffer. Next, the function will cache any hints |
2035 | * from the package, followed by downloading the package itself. Note, that if |
2036 | * a previous PF driver has already downloaded the package successfully, then |
2037 | * the current driver will not have to download the package again. |
2038 | * |
2039 | * The local package contents will be used to query default behavior and to |
2040 | * update specific sections of the HW's version of the package (e.g. to update |
2041 | * the parse graph to understand new protocols). |
2042 | * |
2043 | * This function stores a pointer to the package buffer memory, and it is |
2044 | * expected that the supplied buffer will not be freed immediately. If the |
2045 | * package buffer needs to be freed, such as when read from a file, use |
2046 | * ice_copy_and_init_pkg() instead of directly calling ice_init_pkg() in this |
2047 | * case. |
2048 | */ |
2049 | enum ice_ddp_state ice_init_pkg(struct ice_hw *hw, u8 *buf, u32 len) |
2050 | { |
2051 | bool already_loaded = false; |
2052 | enum ice_ddp_state state; |
2053 | struct ice_pkg_hdr *pkg; |
2054 | struct ice_seg *seg; |
2055 | |
2056 | if (!buf || !len) |
2057 | return ICE_DDP_PKG_ERR; |
2058 | |
2059 | pkg = (struct ice_pkg_hdr *)buf; |
2060 | state = ice_verify_pkg(pkg, len); |
2061 | if (state) { |
2062 | ice_debug(hw, ICE_DBG_INIT, "failed to verify pkg (err: %d)\n" , |
2063 | state); |
2064 | return state; |
2065 | } |
2066 | |
2067 | /* initialize package info */ |
2068 | state = ice_init_pkg_info(hw, pkg_hdr: pkg); |
2069 | if (state) |
2070 | return state; |
2071 | |
2072 | /* must be a matching segment */ |
2073 | if (hw->pkg_has_signing_seg && |
2074 | !ice_match_signing_seg(pkg_hdr: pkg, seg_id: hw->pkg_seg_id, sign_type: hw->pkg_sign_type)) |
2075 | return ICE_DDP_PKG_ERR; |
2076 | |
2077 | /* before downloading the package, check package version for |
2078 | * compatibility with driver |
2079 | */ |
2080 | state = ice_chk_pkg_compat(hw, ospkg: pkg, seg: &seg); |
2081 | if (state) |
2082 | return state; |
2083 | |
2084 | /* initialize package hints and then download package */ |
2085 | ice_init_pkg_hints(hw, ice_seg: seg); |
2086 | state = ice_download_pkg(hw, pkg_hdr: pkg); |
2087 | if (state == ICE_DDP_PKG_ALREADY_LOADED) { |
2088 | ice_debug(hw, ICE_DBG_INIT, |
2089 | "package previously loaded - no work.\n" ); |
2090 | already_loaded = true; |
2091 | } |
2092 | |
2093 | /* Get information on the package currently loaded in HW, then make sure |
2094 | * the driver is compatible with this version. |
2095 | */ |
2096 | if (!state || state == ICE_DDP_PKG_ALREADY_LOADED) { |
2097 | state = ice_get_pkg_info(hw); |
2098 | if (!state) |
2099 | state = ice_get_ddp_pkg_state(hw, already_loaded); |
2100 | } |
2101 | |
2102 | if (ice_is_init_pkg_successful(state)) { |
2103 | hw->seg = seg; |
2104 | /* on successful package download update other required |
2105 | * registers to support the package and fill HW tables |
2106 | * with package content. |
2107 | */ |
2108 | ice_init_pkg_regs(hw); |
2109 | ice_fill_blk_tbls(hw); |
2110 | ice_fill_hw_ptype(hw); |
2111 | ice_get_prof_index_max(hw); |
2112 | } else { |
2113 | ice_debug(hw, ICE_DBG_INIT, "package load failed, %d\n" , state); |
2114 | } |
2115 | |
2116 | return state; |
2117 | } |
2118 | |
2119 | /** |
2120 | * ice_copy_and_init_pkg - initialize/download a copy of the package |
2121 | * @hw: pointer to the hardware structure |
2122 | * @buf: pointer to the package buffer |
2123 | * @len: size of the package buffer |
2124 | * |
2125 | * This function copies the package buffer, and then calls ice_init_pkg() to |
2126 | * initialize the copied package contents. |
2127 | * |
2128 | * The copying is necessary if the package buffer supplied is constant, or if |
2129 | * the memory may disappear shortly after calling this function. |
2130 | * |
2131 | * If the package buffer resides in the data segment and can be modified, the |
2132 | * caller is free to use ice_init_pkg() instead of ice_copy_and_init_pkg(). |
2133 | * |
2134 | * However, if the package buffer needs to be copied first, such as when being |
2135 | * read from a file, the caller should use ice_copy_and_init_pkg(). |
2136 | * |
2137 | * This function will first copy the package buffer, before calling |
2138 | * ice_init_pkg(). The caller is free to immediately destroy the original |
2139 | * package buffer, as the new copy will be managed by this function and |
2140 | * related routines. |
2141 | */ |
2142 | enum ice_ddp_state ice_copy_and_init_pkg(struct ice_hw *hw, const u8 *buf, |
2143 | u32 len) |
2144 | { |
2145 | enum ice_ddp_state state; |
2146 | u8 *buf_copy; |
2147 | |
2148 | if (!buf || !len) |
2149 | return ICE_DDP_PKG_ERR; |
2150 | |
2151 | buf_copy = devm_kmemdup(dev: ice_hw_to_dev(hw), src: buf, len, GFP_KERNEL); |
2152 | |
2153 | state = ice_init_pkg(hw, buf: buf_copy, len); |
2154 | if (!ice_is_init_pkg_successful(state)) { |
2155 | /* Free the copy, since we failed to initialize the package */ |
2156 | devm_kfree(dev: ice_hw_to_dev(hw), p: buf_copy); |
2157 | } else { |
2158 | /* Track the copied pkg so we can free it later */ |
2159 | hw->pkg_copy = buf_copy; |
2160 | hw->pkg_size = len; |
2161 | } |
2162 | |
2163 | return state; |
2164 | } |
2165 | |