Switchtec Userspace PROJECT_NUMBER = 4.2
Loading...
Searching...
No Matches
fw.c
Go to the documentation of this file.
1/*
2 * Microsemi Switchtec(tm) PCIe Management Library
3 * Copyright (c) 2017, Microsemi Corporation
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
22 *
23 */
24
29
30#define SWITCHTEC_LIB_CORE
31
32#include "switchtec_priv.h"
33#include "switchtec/switchtec.h"
34#include "switchtec/errors.h"
35#include "switchtec/endian.h"
36#include "switchtec/utils.h"
37#include "switchtec/mfg.h"
38
39#include <unistd.h>
40
41#include <errno.h>
42#include <stdio.h>
43#include <string.h>
44
55
57 char magic[4];
58 uint32_t image_len;
59 uint32_t load_addr;
60 uint32_t version;
61 uint32_t rsvd;
62 uint32_t header_crc;
63 uint32_t image_crc;
64};
65
66enum switchtec_fw_part_type_gen4 {
67 SWITCHTEC_FW_IMG_TYPE_MAP_GEN4 = 0x0,
68 SWITCHTEC_FW_IMG_TYPE_KEYMAN_GEN4 = 0x1,
69 SWITCHTEC_FW_IMG_TYPE_BL2_GEN4 = 0x2,
70 SWITCHTEC_FW_IMG_TYPE_CFG_GEN4 = 0x3,
71 SWITCHTEC_FW_IMG_TYPE_IMG_GEN4 = 0x4,
72 SWITCHTEC_FW_IMG_TYPE_NVLOG_GEN4 = 0x5,
73 SWITCHTEC_FW_IMG_TYPE_SEEPROM_GEN4 = 0xFE,
74 SWITCHTEC_FW_IMG_TYPE_UNKNOWN_GEN4,
75};
76
77enum switchtec_fw_part_type_gen5 {
78 SWITCHTEC_FW_IMG_TYPE_MAP_GEN5 = 0x0,
79 SWITCHTEC_FW_IMG_TYPE_KEYMAN_GEN5 = 0x1,
80 SWITCHTEC_FW_IMG_TYPE_RIOT_GEN5 = 0x2,
81 SWITCHTEC_FW_IMG_TYPE_BL2_GEN5 = 0x3,
82 SWITCHTEC_FW_IMG_TYPE_CFG_GEN5 = 0x4,
83 SWITCHTEC_FW_IMG_TYPE_IMG_GEN5 = 0x5,
84 SWITCHTEC_FW_IMG_TYPE_NVLOG_GEN5 = 0x6,
85 SWITCHTEC_FW_IMG_TYPE_SEEPROM_GEN5 = 0xFE,
86 SWITCHTEC_FW_IMG_TYPE_UNKNOWN_GEN5,
87};
88
90 char magic[4];
91 char sub_magic[4];
92 uint32_t hdr_version;
93 uint32_t secure_version;
94 uint32_t header_len;
95 uint32_t metadata_len;
96 uint32_t image_len;
97 uint32_t type;
98 uint8_t fw_id;
99 uint8_t rsvd[3];
100 uint32_t version;
101 uint32_t sequence;
102 uint32_t reserved1;
103 uint8_t date_str[8];
104 uint8_t time_str[8];
105 uint8_t img_str[16];
106 uint8_t rsvd1[4];
107 uint32_t image_crc;
108 uint8_t public_key_modulus[512];
109 uint8_t public_key_exponent[4];
110 uint8_t uart_port;
111 uint8_t uart_rate;
112 uint8_t bist_enable;
113 uint8_t bist_gpio_pin_cfg;
114 uint8_t bist_gpio_level_cfg;
115 uint8_t rsvd2[3];
116 uint32_t xml_version;
117 uint32_t relocatable_img_len;
118 uint32_t link_addr;
119 uint32_t header_crc;
120};
121
123 char magic[4];
124 char sub_magic[4];
125 uint32_t hdr_version;
126 uint32_t secure_version;
127 uint32_t header_len;
128 uint32_t metadata_len;
129 uint32_t image_len;
130 uint32_t type;
131 uint8_t fw_id;
132 uint8_t rsvd[3];
133 uint32_t version;
134 uint32_t sequence;
135 uint32_t reserved1;
136 uint8_t date_str[8];
137 uint8_t time_str[8];
138 uint8_t img_str[16];
139 uint8_t rsvd1[4];
140 uint32_t image_crc;
141 uint8_t public_key_modulus[512];
142 uint8_t public_key_exponent[4];
143 uint8_t uart_port;
144 uint8_t uart_rate;
145 uint8_t bist_enable;
146 uint8_t bist_gpio_pin_cfg;
147 uint8_t bist_gpio_level_cfg;
148 uint8_t rollback_enable;
149 uint8_t rsvd2[2];
150 uint32_t xml_version;
151 uint32_t relocatable_img_len;
152 uint32_t link_addr;
153 uint32_t header_crc;
154};
155
157 char magic[4];
158 uint32_t image_len;
159 uint32_t type;
160 uint32_t load_addr;
161 uint32_t version;
162 uint32_t rsvd[9];
163 uint32_t header_crc;
164 uint32_t image_crc;
165};
166
167static uint32_t get_fw_tx_id(struct switchtec_dev *dev)
168{
169 if (switchtec_is_gen5(dev))
170 return MRPC_FW_TX_GEN5;
171 else
172 return MRPC_FW_TX;
173}
174
175static int switchtec_fw_dlstatus(struct switchtec_dev *dev,
176 enum switchtec_fw_dlstatus *status,
177 enum mrpc_bg_status *bgstatus)
178{
179 uint32_t cmd = MRPC_FWDNLD;
180 uint32_t subcmd = MRPC_FWDNLD_GET_STATUS;
181 struct {
182 uint8_t dlstatus;
183 uint8_t bgstatus;
184 uint16_t reserved;
185 } result;
186 int ret;
187
188 if (switchtec_boot_phase(dev) != SWITCHTEC_BOOT_PHASE_FW)
189 cmd = get_fw_tx_id(dev);
190
191 ret = switchtec_cmd(dev, cmd, &subcmd, sizeof(subcmd),
192 &result, sizeof(result));
193
194 if (ret)
195 return ret;
196
197 if (status != NULL)
198 *status = result.dlstatus;
199
200 if (bgstatus != NULL)
201 *bgstatus = result.bgstatus;
202
203 return 0;
204}
205
206static int switchtec_fw_wait(struct switchtec_dev *dev,
207 enum switchtec_fw_dlstatus *status)
208{
209 enum mrpc_bg_status bgstatus;
210 int ret;
211
212 do {
213 // Delay slightly to avoid interrupting the firmware too much
214 usleep(5000);
215
216 ret = switchtec_fw_dlstatus(dev, status, &bgstatus);
217 if (ret < 0)
218 return ret;
219
220 if (bgstatus == MRPC_BG_STAT_OFFSET)
221 return SWITCHTEC_DLSTAT_ERROR_OFFSET;
222
223 if (bgstatus == MRPC_BG_STAT_ERROR) {
224 if (*status != SWITCHTEC_DLSTAT_INPROGRESS &&
225 *status != SWITCHTEC_DLSTAT_COMPLETES &&
226 *status != SWITCHTEC_DLSTAT_SUCCESS_FIRM_ACT &&
227 *status != SWITCHTEC_DLSTAT_SUCCESS_DATA_ACT)
228 return *status;
229 else
230 return SWITCHTEC_DLSTAT_ERROR_PROGRAM;
231 }
232
233 } while (bgstatus == MRPC_BG_STAT_INPROGRESS);
234
235 return 0;
236}
237
238static int set_redundant(struct switchtec_dev *dev, int type, int set)
239{
240 int ret;
241 char *part_types[] = {
242 "KEYMAN",
243 "RIOT",
244 "BL2",
245 "CFG",
246 "MAIN-FW"
247 };
248
249 struct {
250 uint8_t subcmd;
251 uint8_t part_type;
252 uint8_t redundant_val;
253 uint8_t reserved;
254 } cmd;
255
256 cmd.subcmd = MRPC_FWDNLD_SET_RDNDNT;
257 cmd.redundant_val = set;
258 cmd.part_type = type;
259
260 printf("%s redundant flag \t(%s)\n", set ? "Checking" : "Un-checking",
261 part_types[type-1]);
262 ret = switchtec_cmd(dev, MRPC_FWDNLD, &cmd, sizeof(cmd), NULL, 0);
263 if (ret) {
264 fprintf(stderr, "Error: setting redudant flag \t(%s)\n",
265 part_types[type-1]);
266 return 1;
267 }
268 else {
269 printf("Success: set redundant flag \t(%s)\n",
270 part_types[type-1]);
271 }
272 return 0;
273}
274
281int switchtec_fw_set_redundant_flag (struct switchtec_dev *dev, int keyman,
282 int riot, int bl2, int cfg, int fw,
283 int set)
284{
285 int ret = 0;
286 if(keyman)
287 ret += set_redundant(dev, SWITCHTEC_PART_TYPE_KEYMAN, set);
288 if (riot)
289 ret += set_redundant(dev, SWITCHTEC_PART_TYPE_RC, set);
290 if (bl2)
291 ret += set_redundant(dev, SWITCHTEC_PART_TYPE_BL2, set);
292 if (cfg)
293 ret += set_redundant(dev, SWITCHTEC_PART_TYPE_CFG, set);
294 if (fw)
295 ret += set_redundant(dev, SWITCHTEC_PART_TYPE_FW, set);
296
297 return ret;
298}
299
310int switchtec_fw_toggle_active_partition(struct switchtec_dev *dev,
311 int toggle_bl2, int toggle_key,
312 int toggle_fw, int toggle_cfg,
313 int toggle_riotcore)
314{
315 uint32_t cmd_id;
316 size_t cmd_size;
317 struct {
318 uint8_t subcmd;
319 uint8_t toggle_fw;
320 uint8_t toggle_cfg;
321 uint8_t toggle_bl2;
322 uint8_t toggle_key;
323 uint8_t toggle_riotcore;
324 } cmd;
325
326 if (switchtec_boot_phase(dev) == SWITCHTEC_BOOT_PHASE_BL2) {
327 cmd_id = get_fw_tx_id(dev);
328 cmd.subcmd = MRPC_FW_TX_TOGGLE;
329 } else {
330 cmd_id = MRPC_FWDNLD;
331 cmd.subcmd = MRPC_FWDNLD_TOGGLE;
332 }
333
334 cmd.toggle_bl2 = !!toggle_bl2;
335 cmd.toggle_key = !!toggle_key;
336 cmd.toggle_fw = !!toggle_fw;
337 cmd.toggle_cfg = !!toggle_cfg;
338 if (switchtec_is_gen5(dev)) {
339 cmd.toggle_riotcore = !!toggle_riotcore;
340 cmd_size = sizeof(cmd);
341 } else {
342 cmd_size = sizeof(cmd) - 1;
343 }
344
345 return switchtec_cmd(dev, cmd_id, &cmd, cmd_size,
346 NULL, 0);
347}
348
349struct cmd_fwdl {
351 uint8_t subcmd;
352 uint8_t dont_activate;
353 uint8_t reserved[2];
354 uint32_t offset;
355 uint32_t img_length;
356 uint32_t blk_length;
357 } hdr;
358 uint8_t data[MRPC_MAX_DATA_LEN - sizeof(struct cmd_fwdl_hdr)];
359};
360
372int switchtec_fw_write_fd(struct switchtec_dev *dev, int img_fd,
373 int dont_activate, int force,
374 void (*progress_callback)(int cur, int tot))
375{
376 enum switchtec_fw_dlstatus status;
377 enum mrpc_bg_status bgstatus;
378 ssize_t image_size, offset = 0;
379 int ret;
380 struct cmd_fwdl cmd = {};
381 uint32_t cmd_id = MRPC_FWDNLD;
382
383 if (switchtec_boot_phase(dev) != SWITCHTEC_BOOT_PHASE_FW)
384 cmd_id = get_fw_tx_id(dev);
385
386 image_size = lseek(img_fd, 0, SEEK_END);
387 if (image_size < 0)
388 return -errno;
389 lseek(img_fd, 0, SEEK_SET);
390
391 switchtec_fw_dlstatus(dev, &status, &bgstatus);
392
393 if (!force && status == SWITCHTEC_DLSTAT_INPROGRESS) {
394 errno = EBUSY;
395 return -EBUSY;
396 }
397
398 if (bgstatus == MRPC_BG_STAT_INPROGRESS) {
399 errno = EBUSY;
400 return -EBUSY;
401 }
402
403 if (switchtec_boot_phase(dev) == SWITCHTEC_BOOT_PHASE_BL2)
404 cmd.hdr.subcmd = MRPC_FW_TX_FLASH;
405 else
406 cmd.hdr.subcmd = MRPC_FWDNLD_DOWNLOAD;
407
408 cmd.hdr.dont_activate = !!dont_activate;
409 cmd.hdr.img_length = htole32(image_size);
410
411 while (offset < image_size) {
412 ssize_t blklen = read(img_fd, &cmd.data,
413 sizeof(cmd.data));
414
415 if (blklen == -EAGAIN || blklen == -EWOULDBLOCK)
416 continue;
417
418 if (blklen < 0)
419 return -errno;
420
421 if (blklen == 0)
422 break;
423
424 cmd.hdr.offset = htole32(offset);
425 cmd.hdr.blk_length = htole32(blklen);
426
427 ret = switchtec_cmd(dev, cmd_id, &cmd, sizeof(cmd),
428 NULL, 0);
429
430 if (ret)
431 return ret;
432
433 ret = switchtec_fw_wait(dev, &status);
434 if (ret != 0)
435 return ret;
436
437 offset += le32toh(cmd.hdr.blk_length);
438
439 if (progress_callback)
440 progress_callback(offset, image_size);
441
442 }
443
444 if (status == SWITCHTEC_DLSTAT_COMPLETES)
445 return 0;
446
447 if (status == SWITCHTEC_DLSTAT_SUCCESS_FIRM_ACT)
448 return 0;
449
450 if (status == SWITCHTEC_DLSTAT_SUCCESS_DATA_ACT)
451 return 0;
452
453 if (status == 0)
454 return SWITCHTEC_DLSTAT_HARDWARE_ERR;
455
456 return status;
457}
458
465{
466 uint8_t major = (version >> 24) & 0xff;
467
468 switch (major) {
469 case 1:
470 case 2: return SWITCHTEC_GEN3;
471 case 3:
472 case 4:
473 case 5: return SWITCHTEC_GEN4;
474 case 6:
475 case 7:
476 case 8: return SWITCHTEC_GEN5;
477 default: return SWITCHTEC_GEN_UNKNOWN;
478 }
479}
480
492int switchtec_fw_write_file(struct switchtec_dev *dev, FILE *fimg,
493 int dont_activate, int force,
494 void (*progress_callback)(int cur, int tot))
495{
496 enum switchtec_fw_dlstatus status;
497 enum mrpc_bg_status bgstatus;
498 ssize_t image_size, offset = 0;
499 int ret;
500 struct cmd_fwdl cmd = {};
501 uint32_t cmd_id = MRPC_FWDNLD;
502
503 if (switchtec_boot_phase(dev) != SWITCHTEC_BOOT_PHASE_FW)
504 cmd_id = get_fw_tx_id(dev);
505
506 ret = fseek(fimg, 0, SEEK_END);
507 if (ret)
508 return -errno;
509 image_size = ftell(fimg);
510 if (image_size < 0)
511 return -errno;
512 ret = fseek(fimg, 0, SEEK_SET);
513 if (ret)
514 return -errno;
515
516 switchtec_fw_dlstatus(dev, &status, &bgstatus);
517
518 if (!force && status == SWITCHTEC_DLSTAT_INPROGRESS) {
519 errno = EBUSY;
520 return -EBUSY;
521 }
522
523 if (bgstatus == MRPC_BG_STAT_INPROGRESS) {
524 errno = EBUSY;
525 return -EBUSY;
526 }
527
528 if (switchtec_boot_phase(dev) == SWITCHTEC_BOOT_PHASE_BL2)
529 cmd.hdr.subcmd = MRPC_FW_TX_FLASH;
530 else
531 cmd.hdr.subcmd = MRPC_FWDNLD_DOWNLOAD;
532
533 cmd.hdr.dont_activate = !!dont_activate;
534 cmd.hdr.img_length = htole32(image_size);
535
536 while (offset < image_size) {
537 ssize_t blklen = fread(&cmd.data, 1, sizeof(cmd.data), fimg);
538
539 if (blklen == 0) {
540 ret = ferror(fimg);
541 if (ret)
542 return ret;
543 break;
544 }
545
546 cmd.hdr.offset = htole32(offset);
547 cmd.hdr.blk_length = htole32(blklen);
548
549 ret = switchtec_cmd(dev, cmd_id, &cmd, sizeof(cmd),
550 NULL, 0);
551
552 if (ret)
553 return ret;
554
555 ret = switchtec_fw_wait(dev, &status);
556 if (ret != 0)
557 return ret;
558
559 offset += le32toh(cmd.hdr.blk_length);
560
561 if (progress_callback)
562 progress_callback(offset, image_size);
563 }
564
565 if (status == SWITCHTEC_DLSTAT_COMPLETES)
566 return 0;
567
568 if (status == SWITCHTEC_DLSTAT_SUCCESS_FIRM_ACT)
569 return 0;
570
571 if (status == SWITCHTEC_DLSTAT_SUCCESS_DATA_ACT)
572 return 0;
573
574 if (status == 0)
575 return SWITCHTEC_DLSTAT_HARDWARE_ERR;
576
577 return status;
578}
579
588void switchtec_fw_perror(const char *s, int ret)
589{
590 const char *msg;
591
592 if (ret <= 0) {
593 perror(s);
594 return;
595 }
596
597 switch(ret) {
598 case SWITCHTEC_DLSTAT_HEADER_INCORRECT:
599 msg = "Header incorrect"; break;
600 case SWITCHTEC_DLSTAT_OFFSET_INCORRECT:
601 msg = "Offset incorrect"; break;
602 case SWITCHTEC_DLSTAT_CRC_INCORRECT:
603 msg = "CRC incorrect"; break;
604 case SWITCHTEC_DLSTAT_LENGTH_INCORRECT:
605 msg = "Length incorrect"; break;
606 case SWITCHTEC_DLSTAT_HARDWARE_ERR:
607 msg = "Hardware Error"; break;
608 case SWITCHTEC_DLSTAT_PACKAGE_TOO_SMALL:
609 msg = "Package length less than 32 bytes"; break;
610 case SWITCHTEC_DLSTAT_SIG_MEM_ALLOC:
611 msg = "Signature memory allocation failed"; break;
612 case SWITCHTEC_DLSTAT_SEEPROM:
613 msg = "SEEPROM download failed"; break;
614 case SWITCHTEC_DLSTAT_READONLY_PARTITION:
615 msg = "Programming a read-only partition"; break;
616 case SWITCHTEC_DLSTAT_DOWNLOAD_TIMEOUT:
617 msg = "Download Timeout"; break;
618 case SWITCHTEC_DLSTAT_SEEPROM_TWI_NOT_ENABLED:
619 msg = "SEEPROM or related TWI bus isn't enabled"; break;
620 case SWITCHTEC_DLSTAT_PROGRAM_RUNNING:
621 msg = "Programming a running partition"; break;
622 case SWITCHTEC_DLSTAT_NOT_ALLOWED:
623 msg = "Programming not allowed over this interface"; break;
624 case SWITCHTEC_DLSTAT_XML_MISMATCH_ACT:
625 msg = "Activation failed due to XML version mismatch"; break;
626 case SWITCHTEC_DLSTAT_UNKNOWN_ACT:
627 msg = "Activation failed due to unknown error"; break;
628 case SWITCHTEC_DLSTAT_ERROR_OFFSET:
629 msg = "Data offset error during programming"; break;
630 case SWITCHTEC_DLSTAT_ERROR_PROGRAM:
631 msg = "Failed to program to flash"; break;
632
633 case SWITCHTEC_DLSTAT_NO_FILE:
634 msg = "No Image Transferred"; break;
635 default:
636 fprintf(stderr, "%s: Unknown Error (0x%x)\n", s, ret);
637 return;
638 }
639
640 fprintf(stderr, "%s: %s\n", s, msg);
641}
642
643static enum switchtec_fw_type
644switchtec_fw_id_to_type_gen3(const struct switchtec_fw_image_info *info)
645{
646 switch ((unsigned long)info->part_id) {
647 case SWITCHTEC_FW_PART_ID_G3_BOOT: return SWITCHTEC_FW_TYPE_BOOT;
648 case SWITCHTEC_FW_PART_ID_G3_MAP0: return SWITCHTEC_FW_TYPE_MAP;
649 case SWITCHTEC_FW_PART_ID_G3_MAP1: return SWITCHTEC_FW_TYPE_MAP;
650 case SWITCHTEC_FW_PART_ID_G3_IMG0: return SWITCHTEC_FW_TYPE_IMG;
651 case SWITCHTEC_FW_PART_ID_G3_IMG1: return SWITCHTEC_FW_TYPE_IMG;
652 case SWITCHTEC_FW_PART_ID_G3_DAT0: return SWITCHTEC_FW_TYPE_CFG;
653 case SWITCHTEC_FW_PART_ID_G3_DAT1: return SWITCHTEC_FW_TYPE_CFG;
654 case SWITCHTEC_FW_PART_ID_G3_NVLOG: return SWITCHTEC_FW_TYPE_NVLOG;
655 case SWITCHTEC_FW_PART_ID_G3_SEEPROM: return SWITCHTEC_FW_TYPE_SEEPROM;
656
657 //Legacy
658 case 0xa8000000: return SWITCHTEC_FW_TYPE_BOOT;
659 case 0xa8020000: return SWITCHTEC_FW_TYPE_MAP;
660 case 0xa8060000: return SWITCHTEC_FW_TYPE_IMG;
661 case 0xa8210000: return SWITCHTEC_FW_TYPE_CFG;
662
663 default: return SWITCHTEC_FW_TYPE_UNKNOWN;
664 }
665}
666
667static enum switchtec_fw_type
668switchtec_fw_id_to_type_gen4(const struct switchtec_fw_image_info *info)
669{
670 switch (info->part_id) {
671 case SWITCHTEC_FW_PART_ID_G4_MAP0: return SWITCHTEC_FW_TYPE_MAP;
672 case SWITCHTEC_FW_PART_ID_G4_MAP1: return SWITCHTEC_FW_TYPE_MAP;
673 case SWITCHTEC_FW_PART_ID_G4_KEY0: return SWITCHTEC_FW_TYPE_KEY;
674 case SWITCHTEC_FW_PART_ID_G4_KEY1: return SWITCHTEC_FW_TYPE_KEY;
675 case SWITCHTEC_FW_PART_ID_G4_BL20: return SWITCHTEC_FW_TYPE_BL2;
676 case SWITCHTEC_FW_PART_ID_G4_BL21: return SWITCHTEC_FW_TYPE_BL2;
677 case SWITCHTEC_FW_PART_ID_G4_CFG0: return SWITCHTEC_FW_TYPE_CFG;
678 case SWITCHTEC_FW_PART_ID_G4_CFG1: return SWITCHTEC_FW_TYPE_CFG;
679 case SWITCHTEC_FW_PART_ID_G4_IMG0: return SWITCHTEC_FW_TYPE_IMG;
680 case SWITCHTEC_FW_PART_ID_G4_IMG1: return SWITCHTEC_FW_TYPE_IMG;
681 case SWITCHTEC_FW_PART_ID_G4_NVLOG: return SWITCHTEC_FW_TYPE_NVLOG;
682 case SWITCHTEC_FW_PART_ID_G4_SEEPROM: return SWITCHTEC_FW_TYPE_SEEPROM;
683 default: return SWITCHTEC_FW_TYPE_UNKNOWN;
684 }
685}
686
687static enum switchtec_fw_type
688switchtec_fw_id_to_type_gen5(const struct switchtec_fw_image_info *info)
689{
690 switch (info->part_id) {
691 case SWITCHTEC_FW_PART_ID_G5_MAP0: return SWITCHTEC_FW_TYPE_MAP;
692 case SWITCHTEC_FW_PART_ID_G5_MAP1: return SWITCHTEC_FW_TYPE_MAP;
693 case SWITCHTEC_FW_PART_ID_G5_KEY0: return SWITCHTEC_FW_TYPE_KEY;
694 case SWITCHTEC_FW_PART_ID_G5_KEY1: return SWITCHTEC_FW_TYPE_KEY;
695 case SWITCHTEC_FW_PART_ID_G5_RIOT0: return SWITCHTEC_FW_TYPE_RIOT;
696 case SWITCHTEC_FW_PART_ID_G5_RIOT1: return SWITCHTEC_FW_TYPE_RIOT;
697 case SWITCHTEC_FW_PART_ID_G5_BL20: return SWITCHTEC_FW_TYPE_BL2;
698 case SWITCHTEC_FW_PART_ID_G5_BL21: return SWITCHTEC_FW_TYPE_BL2;
699 case SWITCHTEC_FW_PART_ID_G5_CFG0: return SWITCHTEC_FW_TYPE_CFG;
700 case SWITCHTEC_FW_PART_ID_G5_CFG1: return SWITCHTEC_FW_TYPE_CFG;
701 case SWITCHTEC_FW_PART_ID_G5_IMG0: return SWITCHTEC_FW_TYPE_IMG;
702 case SWITCHTEC_FW_PART_ID_G5_IMG1: return SWITCHTEC_FW_TYPE_IMG;
703 case SWITCHTEC_FW_PART_ID_G5_NVLOG: return SWITCHTEC_FW_TYPE_NVLOG;
704 case SWITCHTEC_FW_PART_ID_G5_SEEPROM: return SWITCHTEC_FW_TYPE_SEEPROM;
705 default: return SWITCHTEC_FW_TYPE_UNKNOWN;
706 }
707}
708
709static enum switchtec_fw_type
710switchtec_fw_id_to_type(const struct switchtec_fw_image_info *info)
711{
712 switch (info->gen) {
713 case SWITCHTEC_GEN3: return switchtec_fw_id_to_type_gen3(info);
714 case SWITCHTEC_GEN4: return switchtec_fw_id_to_type_gen4(info);
715 case SWITCHTEC_GEN5: return switchtec_fw_id_to_type_gen5(info);
716 default: return SWITCHTEC_FW_TYPE_UNKNOWN;
717 }
718}
719
720static int switchtec_fw_file_info_gen3(int fd,
721 struct switchtec_fw_image_info *info)
722{
723 struct switchtec_fw_image_header_gen3 hdr = {};
724 int ret;
725
726 ret = read(fd, &hdr, sizeof(hdr));
727 lseek(fd, 0, SEEK_SET);
728
729 if (ret != sizeof(hdr))
730 goto invalid_file;
731
732 if (strcmp(hdr.magic, "PMC") != 0)
733 goto invalid_file;
734
735 if (info == NULL)
736 return 0;
737
738 info->gen = SWITCHTEC_GEN3;
739 info->part_id = hdr.type;
740 info->image_crc = le32toh(hdr.image_crc);
741 version_to_string(hdr.version, info->version, sizeof(info->version));
742 info->image_len = le32toh(hdr.image_len);
743
744 info->type = switchtec_fw_id_to_type(info);
745
746 info->secure_version = 0;
747 info->signed_image = 0;
748
749 return 0;
750
751invalid_file:
752 errno = ENOEXEC;
753 return -errno;
754}
755
756static enum switchtec_fw_image_part_id_gen4 hdr_type2_id_gen4(uint32_t type)
757{
758 switch (type) {
759 case SWITCHTEC_FW_IMG_TYPE_MAP_GEN4:
760 return SWITCHTEC_FW_PART_ID_G4_MAP0;
761
762 case SWITCHTEC_FW_IMG_TYPE_KEYMAN_GEN4:
763 return SWITCHTEC_FW_PART_ID_G4_KEY0;
764
765 case SWITCHTEC_FW_IMG_TYPE_BL2_GEN4:
766 return SWITCHTEC_FW_PART_ID_G4_BL20;
767
768 case SWITCHTEC_FW_IMG_TYPE_CFG_GEN4:
769 return SWITCHTEC_FW_PART_ID_G4_CFG0;
770
771 case SWITCHTEC_FW_IMG_TYPE_IMG_GEN4:
772 return SWITCHTEC_FW_PART_ID_G4_IMG0;
773
774 case SWITCHTEC_FW_IMG_TYPE_NVLOG_GEN4:
775 return SWITCHTEC_FW_PART_ID_G4_NVLOG;
776
777 case SWITCHTEC_FW_IMG_TYPE_SEEPROM_GEN4:
778 return SWITCHTEC_FW_PART_ID_G4_SEEPROM;
779
780 default:
781 return -1;
782 }
783}
784
785static enum switchtec_fw_image_part_id_gen5 hdr_type2_id_gen5(uint32_t type)
786{
787 switch (type) {
788 case SWITCHTEC_FW_IMG_TYPE_MAP_GEN5:
789 return SWITCHTEC_FW_PART_ID_G5_MAP0;
790
791 case SWITCHTEC_FW_IMG_TYPE_KEYMAN_GEN5:
792 return SWITCHTEC_FW_PART_ID_G5_KEY0;
793
794 case SWITCHTEC_FW_IMG_TYPE_RIOT_GEN5:
795 return SWITCHTEC_FW_PART_ID_G5_RIOT0;
796
797 case SWITCHTEC_FW_IMG_TYPE_BL2_GEN5:
798 return SWITCHTEC_FW_PART_ID_G5_BL20;
799
800 case SWITCHTEC_FW_IMG_TYPE_CFG_GEN5:
801 return SWITCHTEC_FW_PART_ID_G5_CFG0;
802
803 case SWITCHTEC_FW_IMG_TYPE_IMG_GEN5:
804 return SWITCHTEC_FW_PART_ID_G5_IMG0;
805
806 case SWITCHTEC_FW_IMG_TYPE_NVLOG_GEN5:
807 return SWITCHTEC_FW_PART_ID_G5_NVLOG;
808
809 case SWITCHTEC_FW_IMG_TYPE_SEEPROM_GEN5:
810 return SWITCHTEC_FW_PART_ID_G5_SEEPROM;
811
812 default:
813 return -1;
814 }
815}
816
817static int switchtec_fw_file_info_gen45(int fd,
818 struct switchtec_fw_image_info *info)
819{
820 int ret;
821 struct switchtec_fw_metadata_gen4 hdr = {};
822 uint8_t exp_zero[4] = {};
823 uint32_t version;
824 int part_id;
825
826 ret = read(fd, &hdr, sizeof(hdr));
827 lseek(fd, 0, SEEK_SET);
828
829 if (ret != sizeof(hdr))
830 goto invalid_file;
831
832 if (strncmp(hdr.magic, "MSCC", sizeof(hdr.magic)))
833 goto invalid_file;
834
835 if (strncmp(hdr.sub_magic, "_MD ", sizeof(hdr.sub_magic)))
836 goto invalid_file;
837
838 if (!info)
839 return 0;
840
841 /* Non-zero 'fw-id' field means the image is for Gen5 or later */
842 if (hdr.fw_id)
843 part_id = hdr_type2_id_gen5(le32toh(hdr.type));
844 else
845 part_id = hdr_type2_id_gen4(le32toh(hdr.type));
846
847 if (part_id < 0)
848 goto invalid_file;
849
850 info->part_id = part_id;
851
852 info->image_crc = le32toh(hdr.image_crc);
853 version = le32toh(hdr.version);
854 version_to_string(version, info->version, sizeof(info->version));
855 info->image_len = le32toh(hdr.image_len);
856 info->gen = switchtec_fw_version_to_gen(version);
857
858 info->type = switchtec_fw_id_to_type(info);
859
860 info->secure_version = le32toh(hdr.secure_version);
861 info->signed_image = !!memcmp(hdr.public_key_exponent, exp_zero, 4);
862
863 return 0;
864
865invalid_file:
866 errno = ENOEXEC;
867 return -errno;
868}
869
877{
878 char magic[4];
879 int ret;
880
881 ret = read(fd, &magic, sizeof(magic));
882 lseek(fd, 0, SEEK_SET);
883
884 if (ret != sizeof(magic)) {
885 errno = ENOEXEC;
886 return -1;
887 }
888
889 if (!strncmp(magic, "PMC", sizeof(magic))) {
890 return switchtec_fw_file_info_gen3(fd, info);
891 } else if (!strncmp(magic, "MSCC", sizeof(magic))) {
892 return switchtec_fw_file_info_gen45(fd, info);
893 } else {
894 errno = ENOEXEC;
895 return -1;
896 }
897
898 return 0;
899}
900
909int switchtec_fw_file_secure_version_newer(struct switchtec_dev *dev,
910 int img_fd)
911{
912 int ret;
913 struct switchtec_fw_image_info info;
914 struct switchtec_sn_ver_info sn_info = {};
915
916 if (switchtec_is_gen3(dev))
917 return 0;
918
919 ret = switchtec_fw_file_info(img_fd, &info);
920 if (ret)
921 return 0;
922
923 if (!info.signed_image)
924 return 0;
925
926 ret = switchtec_sn_ver_get(dev, &sn_info);
927 if (ret) {
928 sn_info.ver_bl2 = 0xffffffff;
929 sn_info.ver_main = 0xffffffff;
930 sn_info.ver_km = 0xffffffff;
931 }
932
933 switch (info.type) {
934 case SWITCHTEC_FW_TYPE_BL2:
935 if (info.secure_version > sn_info.ver_bl2)
936 return 1;
937
938 break;
939 case SWITCHTEC_FW_TYPE_IMG:
940 if (info.secure_version > sn_info.ver_main)
941 return 1;
942
943 break;
944 case SWITCHTEC_FW_TYPE_KEY:
945 if (info.secure_version > sn_info.ver_km)
946 return 1;
947
948 break;
949 default:
950 break;
951 }
952
953 return 0;
954}
955
962{
963 switch (info->type) {
964 case SWITCHTEC_FW_TYPE_BOOT: return "BOOT";
965 case SWITCHTEC_FW_TYPE_MAP: return "MAP";
966 case SWITCHTEC_FW_TYPE_IMG: return "IMG";
967 case SWITCHTEC_FW_TYPE_CFG: return "CFG";
968 case SWITCHTEC_FW_TYPE_KEY: return "KEY";
969 case SWITCHTEC_FW_TYPE_RIOT: return "RIOT";
970 case SWITCHTEC_FW_TYPE_BL2: return "BL2";
971 case SWITCHTEC_FW_TYPE_NVLOG: return "NVLOG";
972 case SWITCHTEC_FW_TYPE_SEEPROM: return "SEEPROM";
973 default: return "UNKNOWN";
974 }
975}
976
977static int switchtec_fw_map_get_active(struct switchtec_dev *dev,
978 struct switchtec_fw_image_info *info)
979{
980 uint32_t map0_update_index;
981 uint32_t map1_update_index;
982 int ret;
983
984 ret = switchtec_fw_read(dev, SWITCHTEC_FLASH_MAP0_PART_START,
985 sizeof(uint32_t), &map0_update_index);
986 if (ret < 0)
987 return ret;
988
989 ret = switchtec_fw_read(dev, SWITCHTEC_FLASH_MAP1_PART_START,
990 sizeof(uint32_t), &map1_update_index);
991 if (ret < 0)
992 return ret;
993
994 info->active = 0;
995 if (map0_update_index > map1_update_index) {
996 if (info->part_addr == SWITCHTEC_FLASH_MAP0_PART_START)
997 info->active = 1;
998 } else {
999 if (info->part_addr == SWITCHTEC_FLASH_MAP1_PART_START)
1000 info->active = 1;
1001 }
1002
1003 return 0;
1004}
1005
1006static int switchtec_fw_info_metadata_gen3(struct switchtec_dev *dev,
1007 struct switchtec_fw_image_info *inf)
1008{
1009 struct switchtec_fw_footer_gen3 *metadata;
1010 unsigned long addr;
1011 int ret = 0;
1012
1013 if (inf->part_id == SWITCHTEC_FW_PART_ID_G3_NVLOG)
1014 return 1;
1015
1016 metadata = malloc(sizeof(*metadata));
1017 if (!metadata)
1018 return -1;
1019
1020 addr = inf->part_addr + inf->part_len - sizeof(*metadata);
1021
1022 ret = switchtec_fw_read(dev, addr, sizeof(*metadata), metadata);
1023 if (ret < 0)
1024 goto err_out;
1025
1026 if (strncmp(metadata->magic, "PMC", sizeof(metadata->magic)))
1027 goto err_out;
1028
1029 version_to_string(metadata->version, inf->version,
1030 sizeof(inf->version));
1031 inf->part_body_offset = 0;
1032 inf->image_crc = metadata->image_crc;
1033 inf->image_len = metadata->image_len;
1034 inf->metadata = metadata;
1035
1036 return 0;
1037
1038err_out:
1039 free(metadata);
1040 return 1;
1041}
1042
1043static int switchtec_fw_part_info_gen3(struct switchtec_dev *dev,
1044 struct switchtec_fw_image_info *inf)
1045{
1046 int ret = 0;
1047
1048 inf->read_only = switchtec_fw_is_boot_ro(dev);
1049
1050 switch (inf->part_id) {
1051 case SWITCHTEC_FW_PART_ID_G3_BOOT:
1052 inf->part_addr = SWITCHTEC_FLASH_BOOT_PART_START;
1053 inf->part_len = SWITCHTEC_FLASH_PART_LEN;
1054 inf->active = true;
1055 break;
1056 case SWITCHTEC_FW_PART_ID_G3_MAP0:
1057 inf->part_addr = SWITCHTEC_FLASH_MAP0_PART_START;
1058 inf->part_len = SWITCHTEC_FLASH_PART_LEN;
1059 ret = switchtec_fw_map_get_active(dev, inf);
1060 break;
1061 case SWITCHTEC_FW_PART_ID_G3_MAP1:
1062 inf->part_addr = SWITCHTEC_FLASH_MAP1_PART_START;
1063 inf->part_len = SWITCHTEC_FLASH_PART_LEN;
1064 ret = switchtec_fw_map_get_active(dev, inf);
1065 break;
1066 default:
1067 ret = switchtec_flash_part(dev, inf, inf->part_id);
1068 inf->read_only = false;
1069 }
1070
1071 if (ret)
1072 return ret;
1073
1074 inf->valid = true;
1075
1076 if (inf->part_id == SWITCHTEC_FW_PART_ID_G3_NVLOG)
1077 return 1;
1078
1079 return switchtec_fw_info_metadata_gen3(dev, inf);
1080}
1081
1082static int switchtec_fw_info_metadata_gen4(struct switchtec_dev *dev,
1083 struct switchtec_fw_image_info *inf)
1084{
1085 struct switchtec_fw_metadata_gen4 *metadata;
1086 struct {
1087 uint8_t subcmd;
1088 uint8_t part_id;
1089 } subcmd = {
1090 .subcmd = MRPC_PART_INFO_GET_METADATA,
1091 .part_id = inf->part_id,
1092 };
1093 int ret;
1094
1095 if (inf->part_id == SWITCHTEC_FW_PART_ID_G4_NVLOG)
1096 return 1;
1097 if (inf->part_id == SWITCHTEC_FW_PART_ID_G4_SEEPROM)
1098 subcmd.subcmd = MRPC_PART_INFO_GET_SEEPROM;
1099
1100 metadata = malloc(sizeof(*metadata));
1101 if (!metadata)
1102 return -1;
1103
1104 ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd, sizeof(subcmd),
1105 metadata, sizeof(*metadata));
1106 if (ret)
1107 goto err_out;
1108
1109 if (strncmp(metadata->magic, "MSCC", sizeof(metadata->magic)))
1110 goto err_out;
1111
1112 if (strncmp(metadata->sub_magic, "_MD ", sizeof(metadata->sub_magic)))
1113 goto err_out;
1114
1115 version_to_string(le32toh(metadata->version), inf->version,
1116 sizeof(inf->version));
1117 inf->part_body_offset = le32toh(metadata->header_len);
1118 inf->image_crc = le32toh(metadata->image_crc);
1119 inf->image_len = le32toh(metadata->image_len);
1120 inf->metadata = metadata;
1121
1122 return 0;
1123
1124err_out:
1125 free(metadata);
1126 return -1;
1127}
1128
1129static int switchtec_fw_info_metadata_gen5(struct switchtec_dev *dev,
1130 struct switchtec_fw_image_info *inf)
1131{
1132 struct switchtec_fw_metadata_gen5 *metadata;
1133 struct {
1134 uint8_t subcmd;
1135 uint8_t part_id;
1136 } subcmd = {
1137 .subcmd = MRPC_PART_INFO_GET_METADATA_GEN5,
1138 .part_id = inf->part_id,
1139 };
1140 int ret;
1141
1142 if (inf->part_id == SWITCHTEC_FW_PART_ID_G5_NVLOG)
1143 return 1;
1144 if (inf->part_id == SWITCHTEC_FW_PART_ID_G5_SEEPROM)
1145 subcmd.subcmd = MRPC_PART_INFO_GET_SEEPROM;
1146
1147 metadata = malloc(sizeof(*metadata));
1148 if (!metadata)
1149 return -1;
1150
1151 ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd, sizeof(subcmd),
1152 metadata, sizeof(*metadata));
1153 if (ret)
1154 goto err_out;
1155
1156 if (strncmp(metadata->magic, "MSCC", sizeof(metadata->magic)))
1157 goto err_out;
1158
1159 if (strncmp(metadata->sub_magic, "_MD ", sizeof(metadata->sub_magic)))
1160 goto err_out;
1161
1162 version_to_string(le32toh(metadata->version), inf->version,
1163 sizeof(inf->version));
1164 inf->part_body_offset = le32toh(metadata->header_len);
1165 inf->image_crc = le32toh(metadata->image_crc);
1166 inf->image_len = le32toh(metadata->image_len);
1167 inf->metadata = metadata;
1168
1169 return 0;
1170
1171err_out:
1172 free(metadata);
1173 return -1;
1174}
1175
1177 uint32_t firmware_version;
1178 uint32_t flash_size;
1179 uint16_t device_id;
1180 uint8_t ecc_enable;
1181 uint8_t rsvd1;
1182 uint8_t running_bl2_flag;
1183 uint8_t running_cfg_flag;
1184 uint8_t running_img_flag;
1185 uint8_t running_key_flag;
1186 uint32_t rsvd2[12];
1188 uint32_t image_crc;
1189 uint32_t image_len;
1190 uint16_t image_version;
1191 uint8_t valid;
1192 uint8_t active;
1193 uint32_t part_start;
1194 uint32_t part_end;
1195 uint32_t part_offset;
1196 uint32_t part_size_dw;
1197 uint8_t read_only;
1198 uint8_t is_using;
1199 uint8_t rsvd[2];
1200 } map0, map1, keyman0, keyman1, bl20, bl21, cfg0, cfg1,
1201 img0, img1, nvlog, vendor[8];
1202};
1203
1205 uint32_t firmware_version;
1206 uint32_t flash_size;
1207 uint16_t device_id;
1208 uint8_t ecc_enable;
1209 uint8_t rsvd1;
1210 uint8_t running_riot_flag;
1211 uint8_t running_bl2_flag;
1212 uint8_t running_cfg_flag;
1213 uint8_t running_img_flag;
1214 uint8_t running_key_flag;
1215 uint8_t rsvd2[3];
1216 uint8_t key_redundant_flag;
1217 uint8_t riot_redundant_flag;
1218 uint8_t bl2_redundant_flag;
1219 uint8_t cfg_redundant_flag;
1220 uint8_t img_redundant_flag;
1221 uint8_t rsvd3[3];
1222 uint32_t rsvd4[9];
1223 struct switchtec_flash_part_info_gen4 map0, map1, keyman0, keyman1,
1224 riot0, riot1, bl20, bl21,
1225 cfg0, cfg1, img0, img1, nvlog,
1226 vendor[8];
1227};
1228
1229static int switchtec_fw_part_info_gen4(struct switchtec_dev *dev,
1230 struct switchtec_fw_image_info *inf,
1231 struct switchtec_flash_info_gen4 *all)
1232{
1233 struct switchtec_flash_part_info_gen4 *part_info;
1234 int ret;
1235
1236 switch(inf->part_id) {
1237 case SWITCHTEC_FW_PART_ID_G4_MAP0:
1238 part_info = &all->map0;
1239 break;
1240 case SWITCHTEC_FW_PART_ID_G4_MAP1:
1241 part_info = &all->map1;
1242 break;
1243 case SWITCHTEC_FW_PART_ID_G4_KEY0:
1244 part_info = &all->keyman0;
1245 break;
1246 case SWITCHTEC_FW_PART_ID_G4_KEY1:
1247 part_info = &all->keyman1;
1248 break;
1249 case SWITCHTEC_FW_PART_ID_G4_BL20:
1250 part_info = &all->bl20;
1251 break;
1252 case SWITCHTEC_FW_PART_ID_G4_BL21:
1253 part_info = &all->bl21;
1254 break;
1255 case SWITCHTEC_FW_PART_ID_G4_IMG0:
1256 part_info = &all->img0;
1257 break;
1258 case SWITCHTEC_FW_PART_ID_G4_IMG1:
1259 part_info = &all->img1;
1260 break;
1261 case SWITCHTEC_FW_PART_ID_G4_CFG0:
1262 part_info = &all->cfg0;
1263 break;
1264 case SWITCHTEC_FW_PART_ID_G4_CFG1:
1265 part_info = &all->cfg1;
1266 break;
1267 case SWITCHTEC_FW_PART_ID_G4_NVLOG:
1268 part_info = &all->nvlog;
1269 break;
1270 case SWITCHTEC_FW_PART_ID_G4_SEEPROM:
1271 if (switchtec_gen(dev) < SWITCHTEC_GEN5)
1272 return 0;
1273
1274 inf->active = true;
1275 /* length is not applicable for SEEPROM image */
1276 inf->part_len = 0xffffffff;
1277
1278 ret = switchtec_fw_info_metadata_gen4(dev, inf);
1279 if (!ret) {
1280 inf->running = true;
1281 inf->valid = true;
1282 }
1283
1284 return 0;
1285 default:
1286 errno = EINVAL;
1287 return -1;
1288 }
1289
1290 inf->part_addr = le32toh(part_info->part_start);
1291 inf->part_len = le32toh(part_info->part_size_dw) * 4;
1292 inf->active = part_info->active;
1293 inf->running = part_info->is_using;
1294 inf->read_only = part_info->read_only;
1295 inf->valid = part_info->valid;
1296 if (!inf->valid)
1297 return 0;
1298
1299 return switchtec_fw_info_metadata_gen4(dev, inf);
1300}
1301
1302static int switchtec_fw_part_info_gen5(struct switchtec_dev *dev,
1303 struct switchtec_fw_image_info *inf,
1304 struct switchtec_flash_info_gen5 *all)
1305{
1306 struct switchtec_flash_part_info_gen4 *part_info;
1307 int ret;
1308
1309 switch(inf->part_id) {
1310 case SWITCHTEC_FW_PART_ID_G5_MAP0:
1311 part_info = &all->map0;
1312 break;
1313 case SWITCHTEC_FW_PART_ID_G5_MAP1:
1314 part_info = &all->map1;
1315 break;
1316 case SWITCHTEC_FW_PART_ID_G5_RIOT0:
1317 inf->redundant = all->riot_redundant_flag;
1318 part_info = &all->riot0;
1319 break;
1320 case SWITCHTEC_FW_PART_ID_G5_RIOT1:
1321 inf->redundant = all->riot_redundant_flag;
1322 part_info = &all->riot1;
1323 break;
1324 case SWITCHTEC_FW_PART_ID_G5_KEY0:
1325 inf->redundant = all->key_redundant_flag;
1326 part_info = &all->keyman0;
1327 break;
1328 case SWITCHTEC_FW_PART_ID_G5_KEY1:
1329 inf->redundant = all->key_redundant_flag;
1330 part_info = &all->keyman1;
1331 break;
1332 case SWITCHTEC_FW_PART_ID_G5_BL20:
1333 inf->redundant = all->bl2_redundant_flag;
1334 part_info = &all->bl20;
1335 break;
1336 case SWITCHTEC_FW_PART_ID_G5_BL21:
1337 inf->redundant = all->bl2_redundant_flag;
1338 part_info = &all->bl21;
1339 break;
1340 case SWITCHTEC_FW_PART_ID_G5_IMG0:
1341 inf->redundant = all->img_redundant_flag;
1342 part_info = &all->img0;
1343 break;
1344 case SWITCHTEC_FW_PART_ID_G5_IMG1:
1345 inf->redundant = all->img_redundant_flag;
1346 part_info = &all->img1;
1347 break;
1348 case SWITCHTEC_FW_PART_ID_G5_CFG0:
1349 inf->redundant = all->cfg_redundant_flag;
1350 part_info = &all->cfg0;
1351 break;
1352 case SWITCHTEC_FW_PART_ID_G5_CFG1:
1353 inf->redundant = all->cfg_redundant_flag;
1354 part_info = &all->cfg1;
1355 break;
1356 case SWITCHTEC_FW_PART_ID_G5_NVLOG:
1357 part_info = &all->nvlog;
1358 break;
1359 case SWITCHTEC_FW_PART_ID_G5_SEEPROM:
1360 inf->active = true;
1361 /* length is not applicable for SEEPROM image */
1362 inf->part_len = 0xffffffff;
1363
1364 ret = switchtec_fw_info_metadata_gen5(dev, inf);
1365 if (!ret) {
1366 inf->running = true;
1367 inf->valid = true;
1368 }
1369
1370 return 0;
1371 default:
1372 errno = EINVAL;
1373 return -1;
1374 }
1375
1376 inf->part_addr = le32toh(part_info->part_start);
1377 inf->part_len = le32toh(part_info->part_size_dw) * 4;
1378 inf->active = part_info->active;
1379 inf->running = part_info->is_using;
1380 inf->read_only = part_info->read_only;
1381 inf->valid = part_info->valid;
1382 if (!inf->valid)
1383 return 0;
1384
1385 return switchtec_fw_info_metadata_gen5(dev, inf);
1386}
1387
1397static int switchtec_fw_part_info(struct switchtec_dev *dev, int nr_info,
1398 struct switchtec_fw_image_info *info)
1399{
1400 int ret;
1401 int i;
1402 uint8_t subcmd = MRPC_PART_INFO_GET_ALL_INFO;
1403 struct switchtec_flash_info_gen4 all_info_gen4;
1404 struct switchtec_flash_info_gen5 all_info_gen5;
1405
1406 if (info == NULL || nr_info == 0)
1407 return -EINVAL;
1408
1409 if (dev->gen == SWITCHTEC_GEN4) {
1410 ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd,
1411 sizeof(subcmd), &all_info_gen4,
1412 sizeof(all_info_gen4));
1413 if (ret)
1414 return ret;
1415 all_info_gen4.firmware_version =
1416 le32toh(all_info_gen4.firmware_version);
1417 all_info_gen4.flash_size = le32toh(all_info_gen4.flash_size);
1418 all_info_gen4.device_id = le16toh(all_info_gen4.device_id);
1419 } else if (dev->gen == SWITCHTEC_GEN5) {
1420 subcmd = MRPC_PART_INFO_GET_ALL_INFO_GEN5;
1421 ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd,
1422 sizeof(subcmd), &all_info_gen5,
1423 sizeof(all_info_gen5));
1424 if (ret)
1425 return ret;
1426 all_info_gen5.firmware_version =
1427 le32toh(all_info_gen5.firmware_version);
1428 all_info_gen5.flash_size = le32toh(all_info_gen5.flash_size);
1429 all_info_gen5.device_id = le16toh(all_info_gen5.device_id);
1430 }
1431
1432 for (i = 0; i < nr_info; i++) {
1433 struct switchtec_fw_image_info *inf = &info[i];
1434 ret = 0;
1435
1436 inf->gen = dev->gen;
1437 inf->type = switchtec_fw_id_to_type(inf);
1438 inf->active = false;
1439 inf->running = false;
1440 inf->valid = false;
1441
1442 switch (info->gen) {
1443 case SWITCHTEC_GEN3:
1444 ret = switchtec_fw_part_info_gen3(dev, inf);
1445 break;
1446 case SWITCHTEC_GEN4:
1447 ret = switchtec_fw_part_info_gen4(dev, inf,
1448 &all_info_gen4);
1449 break;
1450 case SWITCHTEC_GEN5:
1451 ret = switchtec_fw_part_info_gen5(dev, inf,
1452 &all_info_gen5);
1453 break;
1454 default:
1455 errno = EINVAL;
1456 return -1;
1457 }
1458
1459 if (ret < 0)
1460 return ret;
1461
1462 if (ret) {
1463 inf->version[0] = 0;
1464 inf->image_crc = 0xFFFFFFFF;
1465 inf->metadata = NULL;
1466 }
1467 }
1468
1469 return nr_info;
1470}
1471
1472int switchtec_get_device_id_bl2(struct switchtec_dev *dev,
1473 unsigned short *device_id)
1474{
1475 int ret;
1476 uint8_t subcmd = MRPC_PART_INFO_GET_ALL_INFO;
1477 struct switchtec_flash_info_gen4 all_info;
1478 struct switchtec_flash_info_gen5 all_info_gen5;
1479
1480 if (dev->gen != SWITCHTEC_GEN_UNKNOWN)
1481 return -EINVAL;
1482
1483 ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd,
1484 sizeof(subcmd), &all_info,
1485 sizeof(all_info));
1486 if (!ret) {
1487 *device_id = le16toh(all_info.device_id);
1488 } else if (ret == ERR_SUBCMD_INVALID) {
1489 subcmd = MRPC_PART_INFO_GET_ALL_INFO_GEN5;
1490 ret = switchtec_cmd(dev, MRPC_PART_INFO, &subcmd,
1491 sizeof(subcmd), &all_info_gen5,
1492 sizeof(all_info_gen5));
1493 if (!ret)
1494 *device_id = le16toh(all_info_gen5.device_id);
1495 }
1496
1497 return ret;
1498}
1499
1500static long multicfg_subcmd(struct switchtec_dev *dev, uint32_t subcmd,
1501 uint8_t index)
1502{
1503 int ret;
1504 uint32_t result;
1505
1506 subcmd |= index << 8;
1507 subcmd = htole32(subcmd);
1508
1509 ret = switchtec_cmd(dev, MRPC_MULTI_CFG, &subcmd, sizeof(subcmd),
1510 &result, sizeof(result));
1511 if (ret)
1512 return -1;
1513
1514 return result;
1515}
1516
1517static int get_multicfg(struct switchtec_dev *dev,
1518 struct switchtec_fw_image_info *info,
1519 int *nr_mult)
1520{
1521 int ret;
1522 int i;
1523
1524 ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_SUPPORTED, 0);
1525 if (ret < 0)
1526 return ret;
1527
1528 if (!ret) {
1529 *nr_mult = 0;
1530 return 0;
1531 }
1532
1533 ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_COUNT, 0);
1534 if (ret < 0)
1535 return ret;
1536
1537 if (*nr_mult > ret)
1538 *nr_mult = ret;
1539
1540 for (i = 0; i < *nr_mult; i++) {
1541 info[i].part_addr = multicfg_subcmd(dev,
1542 MRPC_MULTI_CFG_START_ADDR,
1543 i);
1544 info[i].part_len = multicfg_subcmd(dev,
1545 MRPC_MULTI_CFG_LENGTH, i);
1546 strcpy(info[i].version, "");
1547 info[i].image_crc = 0;
1548 info[i].active = 0;
1549 }
1550
1551 ret = multicfg_subcmd(dev, MRPC_MULTI_CFG_ACTIVE, 0);
1552 if (ret < 0)
1553 return ret;
1554
1555 if (ret < *nr_mult)
1556 info[ret].active = 1;
1557
1558 return 0;
1559}
1560
1561static const enum switchtec_fw_image_part_id_gen3
1562switchtec_fw_partitions_gen3[] = {
1563 SWITCHTEC_FW_PART_ID_G3_BOOT,
1564 SWITCHTEC_FW_PART_ID_G3_MAP0,
1565 SWITCHTEC_FW_PART_ID_G3_MAP1,
1566 SWITCHTEC_FW_PART_ID_G3_IMG0,
1567 SWITCHTEC_FW_PART_ID_G3_DAT0,
1568 SWITCHTEC_FW_PART_ID_G3_DAT1,
1569 SWITCHTEC_FW_PART_ID_G3_NVLOG,
1570 SWITCHTEC_FW_PART_ID_G3_IMG1,
1571};
1572
1573static const enum switchtec_fw_image_part_id_gen4
1574switchtec_fw_partitions_gen4[] = {
1575 SWITCHTEC_FW_PART_ID_G4_MAP0,
1576 SWITCHTEC_FW_PART_ID_G4_MAP1,
1577 SWITCHTEC_FW_PART_ID_G4_KEY0,
1578 SWITCHTEC_FW_PART_ID_G4_KEY1,
1579 SWITCHTEC_FW_PART_ID_G4_BL20,
1580 SWITCHTEC_FW_PART_ID_G4_BL21,
1581 SWITCHTEC_FW_PART_ID_G4_CFG0,
1582 SWITCHTEC_FW_PART_ID_G4_CFG1,
1583 SWITCHTEC_FW_PART_ID_G4_IMG0,
1584 SWITCHTEC_FW_PART_ID_G4_IMG1,
1585 SWITCHTEC_FW_PART_ID_G4_NVLOG,
1586 SWITCHTEC_FW_PART_ID_G4_SEEPROM,
1587};
1588
1589static const enum switchtec_fw_image_part_id_gen5
1590switchtec_fw_partitions_gen5[] = {
1591 SWITCHTEC_FW_PART_ID_G5_MAP0,
1592 SWITCHTEC_FW_PART_ID_G5_MAP1,
1593 SWITCHTEC_FW_PART_ID_G5_KEY0,
1594 SWITCHTEC_FW_PART_ID_G5_KEY1,
1595 SWITCHTEC_FW_PART_ID_G5_RIOT0,
1596 SWITCHTEC_FW_PART_ID_G5_RIOT1,
1597 SWITCHTEC_FW_PART_ID_G5_BL20,
1598 SWITCHTEC_FW_PART_ID_G5_BL21,
1599 SWITCHTEC_FW_PART_ID_G5_CFG0,
1600 SWITCHTEC_FW_PART_ID_G5_CFG1,
1601 SWITCHTEC_FW_PART_ID_G5_IMG0,
1602 SWITCHTEC_FW_PART_ID_G5_IMG1,
1603 SWITCHTEC_FW_PART_ID_G5_NVLOG,
1604 SWITCHTEC_FW_PART_ID_G5_SEEPROM,
1605};
1606
1607static struct switchtec_fw_part_type *
1608switchtec_fw_type_ptr(struct switchtec_fw_part_summary *summary,
1609 struct switchtec_fw_image_info *info)
1610{
1611 switch (info->type) {
1612 case SWITCHTEC_FW_TYPE_BOOT: return &summary->boot;
1613 case SWITCHTEC_FW_TYPE_MAP: return &summary->map;
1614 case SWITCHTEC_FW_TYPE_IMG: return &summary->img;
1615 case SWITCHTEC_FW_TYPE_CFG: return &summary->cfg;
1616 case SWITCHTEC_FW_TYPE_NVLOG: return &summary->nvlog;
1617 case SWITCHTEC_FW_TYPE_SEEPROM: return &summary->seeprom;
1618 case SWITCHTEC_FW_TYPE_KEY: return &summary->key;
1619 case SWITCHTEC_FW_TYPE_BL2: return &summary->bl2;
1620 case SWITCHTEC_FW_TYPE_RIOT: return &summary->riot;
1621 default: return NULL;
1622 }
1623}
1624
1634switchtec_fw_part_summary(struct switchtec_dev *dev)
1635{
1636 struct switchtec_fw_part_summary *summary;
1637 struct switchtec_fw_image_info **infp;
1638 struct switchtec_fw_part_type *type;
1639 int nr_info, nr_mcfg = 16;
1640 size_t st_sz;
1641 int ret, i;
1642
1643 switch (dev->gen) {
1644 case SWITCHTEC_GEN3:
1645 nr_info = ARRAY_SIZE(switchtec_fw_partitions_gen3);
1646 break;
1647 case SWITCHTEC_GEN4:
1648 nr_info = ARRAY_SIZE(switchtec_fw_partitions_gen4);
1649 break;
1650 case SWITCHTEC_GEN5:
1651 nr_info = ARRAY_SIZE(switchtec_fw_partitions_gen5);
1652 break;
1653 default:
1654 errno = EINVAL;
1655 return NULL;
1656 }
1657
1658 st_sz = sizeof(*summary) + sizeof(*summary->all) * (nr_info + nr_mcfg);
1659
1660 summary = malloc(st_sz);
1661 if (!summary)
1662 return NULL;
1663
1664 memset(summary, 0, st_sz);
1665 summary->nr_info = nr_info;
1666
1667 switch (dev->gen) {
1668 case SWITCHTEC_GEN3:
1669 for (i = 0; i < nr_info; i++)
1670 summary->all[i].part_id =
1671 switchtec_fw_partitions_gen3[i];
1672 break;
1673 case SWITCHTEC_GEN4:
1674 for (i = 0; i < nr_info; i++)
1675 summary->all[i].part_id =
1676 switchtec_fw_partitions_gen4[i];
1677 break;
1678 case SWITCHTEC_GEN5:
1679 for (i = 0; i < nr_info; i++)
1680 summary->all[i].part_id =
1681 switchtec_fw_partitions_gen5[i];
1682 break;
1683 default:
1684 errno = EINVAL;
1685 free(summary);
1686 return NULL;
1687 }
1688
1689 ret = switchtec_fw_part_info(dev, nr_info, summary->all);
1690 if (ret != nr_info) {
1691 free(summary);
1692 return NULL;
1693 }
1694
1695 ret = get_multicfg(dev, &summary->all[nr_info], &nr_mcfg);
1696 if (ret) {
1697 nr_mcfg = 0;
1698 errno = 0;
1699 }
1700
1701 for (i = 0; i < nr_info; i++) {
1702 type = switchtec_fw_type_ptr(summary, &summary->all[i]);
1703 if (type == NULL) {
1704 free(summary);
1705 return NULL;
1706 }
1707 if (summary->all[i].active)
1708 type->active = &summary->all[i];
1709 else
1710 type->inactive = &summary->all[i];
1711 }
1712
1713 infp = &summary->mult_cfg;
1714 for (; i < nr_info + nr_mcfg; i++) {
1715 *infp = &summary->all[i];
1716 infp = &summary->all[i].next;
1717 }
1718
1719 return summary;
1720}
1721
1727{
1728 int i;
1729
1730 for (i = 0; i < summary->nr_info; i++)
1731 free(summary->all[i].metadata);
1732
1733 free(summary);
1734}
1735
1744int switchtec_fw_read(struct switchtec_dev *dev, unsigned long addr,
1745 size_t len, void *buf)
1746{
1747 int ret;
1748 struct {
1749 uint32_t addr;
1750 uint32_t length;
1751 } cmd;
1752 unsigned char *cbuf = buf;
1753 size_t read = 0;
1754
1755 while(len) {
1756 size_t chunk_len = len;
1757 if (chunk_len > MRPC_MAX_DATA_LEN-8)
1758 chunk_len = MRPC_MAX_DATA_LEN-8;
1759
1760 cmd.addr = htole32(addr);
1761 cmd.length = htole32(chunk_len);
1762
1763 ret = switchtec_cmd(dev, MRPC_RD_FLASH, &cmd, sizeof(cmd),
1764 cbuf, chunk_len);
1765 if (ret)
1766 return -1;
1767
1768 addr += chunk_len;
1769 len -= chunk_len;
1770 read += chunk_len;
1771 cbuf += chunk_len;
1772 }
1773
1774 return read;
1775}
1776
1788int switchtec_fw_read_fd(struct switchtec_dev *dev, int fd,
1789 unsigned long addr, size_t len,
1790 void (*progress_callback)(int cur, int tot))
1791{
1792 int ret;
1793 unsigned char buf[(MRPC_MAX_DATA_LEN-8)*4];
1794 size_t read = 0;
1795 size_t total_len = len;
1796 size_t total_wrote;
1797 ssize_t wrote;
1798
1799 while(len) {
1800 size_t chunk_len = len;
1801 if (chunk_len > sizeof(buf))
1802 chunk_len = sizeof(buf);
1803
1804 ret = switchtec_fw_read(dev, addr, chunk_len, buf);
1805 if (ret < 0)
1806 return ret;
1807
1808 total_wrote = 0;
1809 while (total_wrote < ret) {
1810 wrote = write(fd, &buf[total_wrote],
1811 ret - total_wrote);
1812 if (wrote < 0)
1813 return -1;
1814 total_wrote += wrote;
1815 }
1816
1817 read += ret;
1818 addr += ret;
1819 len -= ret;
1820
1821 if (progress_callback)
1822 progress_callback(read, total_len);
1823 }
1824
1825 return read;
1826}
1827
1837int switchtec_fw_body_read_fd(struct switchtec_dev *dev, int fd,
1838 struct switchtec_fw_image_info *info,
1839 void (*progress_callback)(int cur, int tot))
1840{
1841 return switchtec_fw_read_fd(dev, fd,
1842 info->part_addr + info->part_body_offset,
1843 info->image_len, progress_callback);
1844}
1845
1846static int switchtec_fw_img_write_hdr_gen3(int fd,
1847 struct switchtec_fw_image_info *info)
1848{
1849 struct switchtec_fw_footer_gen3 *ftr = info->metadata;
1850 struct switchtec_fw_image_header_gen3 hdr = {};
1851
1852 memcpy(hdr.magic, ftr->magic, sizeof(hdr.magic));
1853 hdr.image_len = ftr->image_len;
1854 hdr.type = info->part_id;
1855 hdr.load_addr = ftr->load_addr;
1856 hdr.version = ftr->version;
1857 hdr.header_crc = ftr->header_crc;
1858 hdr.image_crc = ftr->image_crc;
1859
1860 if (hdr.type == SWITCHTEC_FW_PART_ID_G3_MAP1)
1861 hdr.type = SWITCHTEC_FW_PART_ID_G3_MAP0;
1862 else if (hdr.type == SWITCHTEC_FW_PART_ID_G3_IMG1)
1863 hdr.type = SWITCHTEC_FW_PART_ID_G3_IMG0;
1864 else if (hdr.type == SWITCHTEC_FW_PART_ID_G3_DAT1)
1865 hdr.type = SWITCHTEC_FW_PART_ID_G3_DAT0;
1866
1867 return write(fd, &hdr, sizeof(hdr));
1868}
1869
1870static int switchtec_fw_img_write_hdr_gen4(int fd,
1871 struct switchtec_fw_image_info *info)
1872{
1873 int ret;
1874 struct switchtec_fw_metadata_gen4 *hdr = info->metadata;
1875
1876 ret = write(fd, hdr, sizeof(*hdr));
1877 if (ret < 0)
1878 return ret;
1879
1880 return lseek(fd, info->part_body_offset, SEEK_SET);
1881}
1882
1897{
1898 switch (info->gen) {
1899 case SWITCHTEC_GEN3: return switchtec_fw_img_write_hdr_gen3(fd, info);
1900 case SWITCHTEC_GEN4:
1901 case SWITCHTEC_GEN5: return switchtec_fw_img_write_hdr_gen4(fd, info);
1902 default:
1903 errno = EINVAL;
1904 return -1;
1905 }
1906}
1907
1909 uint8_t subcmd;
1910 uint8_t set_get;
1911 uint8_t status;
1912 uint8_t reserved;
1913};
1914
1921int switchtec_fw_is_boot_ro(struct switchtec_dev *dev)
1922{
1923 struct switchtec_boot_ro subcmd = {
1924 .subcmd = MRPC_FWDNLD_BOOT_RO,
1925 .set_get = 0,
1926 };
1927
1928 struct {
1929 uint8_t status;
1930 uint8_t reserved[3];
1931 } result;
1932
1933 int ret;
1934
1935 if (!switchtec_is_gen3(dev)) {
1936 errno = ENOTSUP;
1937 return -1;
1938 }
1939
1940 ret = switchtec_cmd(dev, MRPC_FWDNLD, &subcmd, sizeof(subcmd),
1941 &result, sizeof(result));
1942
1943 if (ret == ERR_SUBCMD_INVALID) {
1944 errno = 0;
1945 return 0;
1946 }
1947
1948 if (ret)
1949 return ret;
1950
1951 return result.status;
1952}
1953
1960int switchtec_fw_set_boot_ro(struct switchtec_dev *dev,
1961 enum switchtec_fw_ro ro)
1962{
1963 struct switchtec_boot_ro subcmd = {
1964 .subcmd = MRPC_FWDNLD_BOOT_RO,
1965 .set_get = 1,
1966 .status = ro,
1967 };
1968
1969 if (!switchtec_is_gen3(dev)) {
1970 errno = ENOTSUP;
1971 return -1;
1972 }
1973
1974 return switchtec_cmd(dev, MRPC_FWDNLD, &subcmd, sizeof(subcmd),
1975 NULL, 0);
1976}
1977
int switchtec_cmd(struct switchtec_dev *dev, uint32_t cmd, const void *payload, size_t payload_len, void *resp, size_t resp_len)
Execute an MRPC command.
Definition platform.c:178
enum switchtec_gen switchtec_fw_version_to_gen(unsigned int version)
Extract generation information from FW version number.
Definition fw.c:464
int switchtec_fw_img_write_hdr(int fd, struct switchtec_fw_image_info *info)
Write the header for a Switchtec firmware image file.
Definition fw.c:1896
int switchtec_fw_read(struct switchtec_dev *dev, unsigned long addr, size_t len, void *buf)
Read a Switchtec device's flash data.
Definition fw.c:1744
int switchtec_fw_body_read_fd(struct switchtec_dev *dev, int fd, struct switchtec_fw_image_info *info, void(*progress_callback)(int cur, int tot))
Read a Switchtec device's flash image body into a file.
Definition fw.c:1837
int switchtec_fw_file_secure_version_newer(struct switchtec_dev *dev, int img_fd)
Check if the secure version of an image file is newer than that of the image on device.
Definition fw.c:909
int switchtec_fw_read_fd(struct switchtec_dev *dev, int fd, unsigned long addr, size_t len, void(*progress_callback)(int cur, int tot))
Read a Switchtec device's flash data into a file.
Definition fw.c:1788
int switchtec_fw_is_boot_ro(struct switchtec_dev *dev)
Check if the boot partition is marked as read-only.
Definition fw.c:1921
int switchtec_fw_file_info(int fd, struct switchtec_fw_image_info *info)
Retrieve information about a firmware image file.
Definition fw.c:876
int switchtec_fw_write_fd(struct switchtec_dev *dev, int img_fd, int dont_activate, int force, void(*progress_callback)(int cur, int tot))
Write a firmware file to the switchtec device.
Definition fw.c:372
void switchtec_fw_perror(const char *s, int ret)
Print an error string to stdout.
Definition fw.c:588
static int switchtec_fw_part_info(struct switchtec_dev *dev, int nr_info, struct switchtec_fw_image_info *info)
Return firmware information structures for a number of firmware partitions.
Definition fw.c:1397
int switchtec_fw_set_boot_ro(struct switchtec_dev *dev, enum switchtec_fw_ro ro)
Set or clear a boot partition's read-only flag.
Definition fw.c:1960
void switchtec_fw_part_summary_free(struct switchtec_fw_part_summary *summary)
Free a firmware part summary data structure.
Definition fw.c:1726
int switchtec_fw_set_redundant_flag(struct switchtec_dev *dev, int keyman, int riot, int bl2, int cfg, int fw, int set)
Set the redundant image flag for the specified image types.
Definition fw.c:281
int switchtec_fw_toggle_active_partition(struct switchtec_dev *dev, int toggle_bl2, int toggle_key, int toggle_fw, int toggle_cfg, int toggle_riotcore)
Toggle the active firmware partition for the main or configuration images.
Definition fw.c:310
const char * switchtec_fw_image_type(const struct switchtec_fw_image_info *info)
Return a string describing the type of a firmware image.
Definition fw.c:961
int switchtec_fw_write_file(struct switchtec_dev *dev, FILE *fimg, int dont_activate, int force, void(*progress_callback)(int cur, int tot))
Write a firmware file to the switchtec device.
Definition fw.c:492
struct switchtec_fw_part_summary * switchtec_fw_part_summary(struct switchtec_dev *dev)
Return firmware summary information structure for the flash partitfons in the device.
Definition fw.c:1634
int switchtec_flash_part(struct switchtec_dev *dev, struct switchtec_fw_image_info *info, enum switchtec_fw_image_part_id_gen3 part)
Retrieve information about a flash partition.
Definition platform.c:297
int switchtec_sn_ver_get(struct switchtec_dev *dev, struct switchtec_sn_ver_info *info)
Get serial number and security version.
Definition mfg.c:1737
Definition fw.c:349
Information about a firmware image or partition.
Definition switchtec.h:270
enum switchtec_gen gen
Image generation.
Definition switchtec.h:271
size_t part_body_offset
Partition image body offset.
Definition switchtec.h:277
unsigned long image_crc
CRC checksum of the image.
Definition switchtec.h:279
char version[32]
Firmware/Config version.
Definition switchtec.h:274
size_t image_len
Length of the image.
Definition switchtec.h:278
unsigned long part_id
Image partition ID.
Definition switchtec.h:272
size_t part_addr
Address of the partition.
Definition switchtec.h:275
size_t part_len
Length of the partition.
Definition switchtec.h:276
enum switchtec_fw_type type
Image partition type.
Definition switchtec.h:273
Main Switchtec header.
switchtec_fw_ro
Flag which indicates if a partition is read-only or not.
Definition switchtec.h:981
switchtec_gen
The PCIe generations.
Definition switchtec.h:91
switchtec_boot_phase
Device boot phase.
Definition switchtec.h:111
static int switchtec_is_gen5(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 5 device.
Definition switchtec.h:477
switchtec_fw_dlstatus
Firmware update status.
Definition switchtec.h:950
static int switchtec_is_gen3(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 3 device.
Definition switchtec.h:461