[openfabrics-ewg] 1.0 branch update owners
Johannes Erdfelt
johannes at erdfelt.com
Mon May 1 17:15:07 PDT 2006
On Thu, Apr 27, 2006, Tziporet Koren <tziporet at mellanox.co.il> wrote:
> Please do it on Monday so it can be in RC4
Here's the patch for tvflash. It's a somewhat large patch because of all
of the changes that have happened since the original version was dropped
into subversion.
Changelog:
- Add two new operations, modify Topspin/Cisco boot options, print GUIDs
- Add support for Tiger, Cheetah, Lion Mini and Lion Cub Rev C
- Rewrite support for adding new boards
- Add support for SPI flash chips
- Add support to program through PCI config space
I don't have an account in the OF Subversion. Can I work with someone to
get this checked in?
JE
Index: src/firmware.h
===================================================================
--- src/firmware.h (revision 6845)
+++ src/firmware.h (working copy)
@@ -28,8 +28,10 @@
enum operation {
OP_NONE,
OP_IDENTIFY,
+ OP_PRINT_GUIDS,
OP_DOWNLOAD,
- OP_UPLOAD,
+ OP_UPLOAD,
+ OP_MODIFY_OPTIONS,
};
enum identify_mode {
@@ -38,33 +40,8 @@
IDENTIFY_HARDWARE_LABEL,
};
-enum board_type {
- BOARD_JAGUAR,
- BOARD_COUGAR,
- BOARD_COUGARCUB,
- BOARD_LIONCUB,
-};
+#define TV_FLASH_DEFAULT_SECTOR_SIZE 0x010000 /* 64K */
-#define BOARD_JAGUAR_A0_STR "HCA.Jaguar.A0"
-#define BOARD_JAGUAR_A1_STR "HCA.Jaguar.A1"
-#define BOARD_COUGAR_A1_STR "HCA.Cougar.A1"
-#define BOARD_COUGARCUB_A1_STR "HCA.CougarCub.A1"
-#define BOARD_LIONCUB_A0_STR "HCA.LionCub.A0"
-
-#define COUGARCUB_VPD_STR "Cougar cub"
-
-struct tvdevice {
- struct tvdevice *next;
-
- struct pci_dev *pdev;
-
- int num;
-
- int can_map;
- int vpd;
- unsigned char vpd_data[256];
-};
-
struct topspin_vsd {
uint32_t flags;
/*
@@ -82,11 +59,13 @@
#define VSD_FLAG_BOOT_ENABLE_PORT_1 0x00010000
#define VSD_FLAG_BOOT_ENABLE_PORT_2 0x00020000
#define VSD_FLAG_BOOT_ENABLE_SCAN 0x00040000
+#define VSD_FLAG_BOOT_WAIT_ON_ERROR 0x00080000
+#define VSD_FLAG_BOOT_TRY_FOREVER 0x00100000
#define VSD_FLAG_BOOT_TYPE 0x00C00000
#define VSD_FLAG_BOOT_TYPE_WELL_KNOWN 0x00000000
#define VSD_FLAG_BOOT_TYPE_SAVED 0x00400000
- /* 0x00800000 */
+#define VSD_FLAG_BOOT_TYPE_PXE 0x00800000
#define VSD_FLAG_BOOT_TYPE_DISABLE 0x00C00000
uint64_t createtime;
@@ -97,22 +76,25 @@
uint16_t micro_ver; /* 0 */
int8_t revision_ver; /* 7 (highbit set for rc) */
uint8_t old_build_num; /* Old build number */
+ /* FIXME: This is in little endian when it should be big endian */
uint16_t build_num; /* For Topspin use (eg 345) */
- uint8_t hw_label[64]; /* Text label unique to this hardware */
+ char hw_label[64]; /* Text label unique to this hardware */
- uint8_t build_rev[16]; /* For Topspin use (eg 2.0.0) */
+ char build_rev[16]; /* For Topspin use (eg 2.0.0) */
- uint8_t unused[0xc3 - 0x70]; /* Program as 0 */
+ uint8_t unused[0xc2 - 0x70]; /* Program as 0 */
- uint8_t boot_ioc_num; /* Saved IOC num */
- uint32_t boot_service_name[2];/* Saved service name */
- uint8_t boot_dgid[16]; /* Saved destination GID */
- uint8_t boot_port; /* Port number to use (0 == any) */
-#define BOOT_VERSION 1
- uint8_t boot_version; /* Version of boot firmware options */
+#define BOOT_PXE_SECS_DEFAULT 20
+ uint8_t boot_pxe_secs; /* Number of secs to wait for DHCP (0 = inf) */
+ uint8_t boot_ioc_num; /* Saved IOC num */
+ uint8_t boot_service_name[8]; /* Saved service name */
+ uint8_t boot_dgid[16]; /* Saved destination GID */
+ uint8_t boot_port; /* Port number to use (0 == any) */
+#define BOOT_VERSION 2
+ uint8_t boot_version; /* Version of boot firmware options */
- uint16_t signature2; /* 0x05ad */
+ uint16_t signature2;
} __attribute__((packed));
union vsd {
@@ -128,29 +110,198 @@
} data;
};
-struct image {
+struct failsafe {
unsigned char valid;
- uint32_t addr;
- uint32_t size;
+ struct image {
+ unsigned char valid;
- union vsd vsd;
+ uint32_t addr;
+ uint32_t size;
+
+ union vsd vsd;
+ } images[2];
};
-struct failsafe {
- unsigned char valid;
- unsigned int sector_sz;
+enum method {
+ METHOD_MMAP,
+ METHOD_PCI_CFG,
+};
- struct image images[2];
+struct pciid;
+
+enum flash_command_set {
+ CS_UNKNOWN = 0,
+ CS_INTEL = 1,
+ CS_AMD = 2,
+ CS_SPI = 3,
};
-#define GUID_LEN 8
+#define GPIO_DAT 0xF0080
+#define GPIO_DIR 0xF0088
+#define GPIO_POL 0xF0090
+#define GPIO_MOD 0xF0098
+#define GPIO_LOCK 0xF00EC
-#define TV_FLASH_SIZE 0x400000 /* 4M */
-#define TV_FLASH_BANK_SIZE 0x080000 /* 512K */
-#define TV_FLASH_BANK_MASK (TV_FLASH_BANK_SIZE - 1)
-#define TV_FLASH_DEFAULT_SECTOR_SIZE 0x010000 /* 64K */
+#define GPIO_DATACLEAR 0xF00F4
+#define GPIO_DATASET 0xF00DC
+struct tvdevice {
+ struct tvdevice *next;
+
+ struct pci_dev *pdev;
+ struct pciid *pciid;
+ struct board *board;
+ unsigned char revision;
+
+ unsigned char num;
+ unsigned char flags;
+
+ enum method method;
+ uint8_t *bar0;
+
+ unsigned char flash_bank;
+ struct failsafe failsafe;
+
+ unsigned flash_size;
+
+ enum flash_command_set flash_command_set;
+ unsigned char flash_bank_shift;
+ unsigned int flash_bank_mask;
+ unsigned int flash_sector_sz;
+
+ unsigned int gpio_data[2], gpio_direction[2];
+ unsigned int gpio_polarity[2], gpio_output_mode[2];
+
+ unsigned char vpd_present;
+
+ /* This is just so we can force alignment for this data */
+ union {
+ unsigned char vpd_char[256];
+ unsigned int vpd_int[256/4];
+ } vpd;
+};
+
+enum hca_chip {
+ CHIP_TAVOR,
+ CHIP_ARBEL,
+ CHIP_SINAI,
+};
+
+/* Board identification */
+struct board {
+ char *name;
+ enum hca_chip chip;
+ char *fwlabel;
+ int num_ports;
+};
+
+/* Tavor */
+struct board jaguar = { "Jaguar", CHIP_TAVOR, "HCA.Jaguar", 2 };
+struct board cougar = { "Cougar", CHIP_TAVOR, "HCA.Cougar", 2 };
+struct board cougarcub = { "Cougar Cub", CHIP_TAVOR, "HCA.CougarCub", 2 };
+/* Arbel */
+struct board lioncub = { "Lion Cub", CHIP_ARBEL, "HCA.LionCub", 2 };
+struct board lioncub_revc = { "Lion Cub", CHIP_ARBEL, "HCA.LionCub.RevC", 2 };
+struct board glacier = { "DLGL", CHIP_ARBEL, "HCA.DLGL", 2 };
+struct board bc2 = { "BC2 HSDC", CHIP_ARBEL, "HCA.HSDC", 2 };
+struct board lionmini = { "Lion Mini", CHIP_ARBEL, "HCA.LionMini", 2 };
+struct board genarbel = { "Generic Arbel", CHIP_ARBEL, NULL, 2 };
+/* Sinai */
+struct board tiger = { "Tiger", CHIP_SINAI, "HCA.Tiger", 1 };
+struct board cheetah = { "Cheetah", CHIP_SINAI, "HCA.Cheetah", 1 };
+struct board gensinai = { "Generic Sinai", CHIP_SINAI, NULL, 1 };
+
+/* Map VPD string to board */
+struct board_vpd {
+ char *str;
+
+ struct board *board;
+};
+
+struct board_vpd board_vpds[] = {
+ { "Cougar cub", &cougarcub },
+ { "Lion cub", &lioncub },
+ { "Lion mini", &lionmini },
+ { "DLGL", &glacier },
+ { "Tiger", &tiger },
+ { "Cheetah", &cheetah },
+ { "BC2 HSDC", &bc2 },
+};
+
+/* Map PCI id to chip and function to identify board */
+#define PCI_VENDOR_MELLANOX 0x15b3
+#define PCI_VENDOR_TOPSPIN 0x1867
+
+#define PCI_DEVICE_MELLANOX_MT23108 0x5a44
+#define PCI_DEVICE_MELLANOX_MT23108_PCICONF 0x5a45
+#define PCI_DEVICE_MELLANOX_MT23108_PCIBRIDGE 0x5a46
+#define PCI_DEVICE_MELLANOX_MT25208 0x6282
+#define PCI_DEVICE_MELLANOX_MT25208_COMPAT 0x6278
+#define PCI_DEVICE_MELLANOX_MT25208_PCICONF 0x6279
+#define PCI_DEVICE_MELLANOX_MT25204 0x6274
+#define PCI_DEVICE_MELLANOX_MT25204_PCICONF 0x6275
+
+struct pciid {
+ uint16_t vendor;
+ uint16_t device;
+ unsigned int flags;
+
+ struct board *(*identify)(struct tvdevice *);
+};
+
+static struct board *tavor_identify(struct tvdevice *);
+static struct board *arbel_identify(struct tvdevice *);
+static struct board *sinai_identify(struct tvdevice *);
+
+#define FLAG_RECOVERY 1
+#define FLAG_TAVOR_COMPAT 2
+
+struct pciid pciids[] = {
+ /* Tavor, only one has VPD */
+ { PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT23108,
+ 0, tavor_identify },
+ { PCI_VENDOR_TOPSPIN, PCI_DEVICE_MELLANOX_MT23108,
+ 0, tavor_identify },
+ { PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT23108_PCICONF,
+ FLAG_RECOVERY, tavor_identify },
+ { PCI_VENDOR_TOPSPIN, PCI_DEVICE_MELLANOX_MT23108_PCICONF,
+ FLAG_RECOVERY, tavor_identify },
+
+ /* Arbel, all have VPDs */
+ { PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT25208,
+ 0, arbel_identify },
+ { PCI_VENDOR_TOPSPIN, PCI_DEVICE_MELLANOX_MT25208,
+ 0, arbel_identify },
+ { PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT25208_COMPAT,
+ FLAG_TAVOR_COMPAT, arbel_identify },
+ { PCI_VENDOR_TOPSPIN, PCI_DEVICE_MELLANOX_MT25208_COMPAT,
+ FLAG_TAVOR_COMPAT, arbel_identify },
+ { PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT25208_PCICONF,
+ FLAG_RECOVERY, arbel_identify },
+ { PCI_VENDOR_TOPSPIN, PCI_DEVICE_MELLANOX_MT25208_PCICONF,
+ FLAG_RECOVERY, arbel_identify },
+
+ /* Sinai, all have VPDs */
+ { PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT25204,
+ 0, sinai_identify },
+ { PCI_VENDOR_TOPSPIN, PCI_DEVICE_MELLANOX_MT25204,
+ 0, sinai_identify },
+ { PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT25204_PCICONF,
+ FLAG_RECOVERY, sinai_identify },
+ { PCI_VENDOR_TOPSPIN, PCI_DEVICE_MELLANOX_MT25204_PCICONF,
+ FLAG_RECOVERY, sinai_identify },
+ /* Some old Tiger and Cheetah boards use PCI device id 0x538x (24204) */
+ { PCI_VENDOR_MELLANOX, 0x5e8c,
+ 0, sinai_identify },
+ { PCI_VENDOR_MELLANOX, 0x5e8d,
+ FLAG_RECOVERY, sinai_identify },
+};
+
+#define GUID_LEN 8
+
#define TV_FLASH_GUID_OFF 0x24
+#define MAX_STR 0xB0
+
#endif
Index: src/tvflash.c
===================================================================
--- src/tvflash.c (revision 6845)
+++ src/tvflash.c (working copy)
@@ -24,16 +24,17 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
-#include <sys/mman.h>
#include <unistd.h>
#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
#include <termios.h>
#include <fcntl.h>
#include <pci/pci.h>
+#include <sys/utsname.h>
#include <limits.h>
#include <ctype.h>
#include <time.h>
@@ -41,35 +42,18 @@
#include "firmware.h"
-struct tvdevice *tvdevices = NULL;
-
+/* Global variables */
+struct tvdevice *tvdevices = NULL, *tvdevices_tail = NULL;
+unsigned char force = 0, verbose = 1, use_config_space = 0;
char *argv0;
+unsigned short cols;
-unsigned char force = 0, verbose = 1, config = 0;
+/* Local prototypes */
+static void usage(void);
/* Topspin OID */
static const uint8_t default_oid[] = { 0x00, 0x05, 0xad, 0x00 };
-#define PCI_VENDOR_MELLANOX 0x15b3
-#define PCI_VENDOR_TOPSPIN 0x1867
-#define PCI_DEVICE_MELLANOX_MT23108 0x5a44
-#define PCI_DEVICE_MELLANOX_MT23108_PCICONF 0x5a45
-#define PCI_DEVICE_MELLANOX_MT23108_PCIBRIDGE 0x5a46
-#define PCI_DEVICE_MELLANOX_MT25208_COMPAT 0x6278
-#define PCI_DEVICE_MELLANOX_MT25208 0x6282
-#define PCI_DEVICE_MELLANOX_MT25208_PCICONF 0x6279
-
-#define MAX_STR 0xB0
-
-unsigned short cols;
-
-unsigned char flash_bank;
-struct failsafe failsafe;
-unsigned int gpio_data[2], gpio_direction[2], gpio_polarity[2],
- gpio_output_mode[2];
-struct pci_dev *cur_hca;
-uint8_t *bar0;
-
/*
* Simple utility functions
*/
@@ -85,21 +69,19 @@
word = (image[4 * j] << 24) | (image[4 * j + 1] << 16) |
(image[4 * j + 2] << 8) | image[4 * j + 3];
for (i = 0; i < 32; i++) {
- if (crc & 0x8000) {
+ if (crc & 0x8000)
crc = (((crc << 1) | (word >> 31)) ^ 0x100b) & 0xffff;
- } else {
+ else
crc = ((crc << 1) | (word >> 31)) & 0xffff;
- }
word = word << 1;
}
}
for (i = 0; i < 16; i++) {
- if (crc & 0x8000) {
+ if (crc & 0x8000)
crc = ((crc << 1) ^ 0x100b) & 0xffff;
- } else {
+ else
crc = (crc << 1) & 0xffff;
- }
}
crc = crc ^ 0xffff;
@@ -107,11 +89,43 @@
return (crc & 0xffff);
}
-static int parse_guid(unsigned char *arg, unsigned char *new_guid)
+/*
+ * We need some LE to host macros and those vary depending on the architecture
+ * and there are no standardized ones. So we mix the ntoh* and hton* functions
+ * with an unconditional swab* to get the desired behavior. Not the most
+ * efficient, but it works and is portable.
+ */
+static uint16_t le16_to_cpu(uint16_t x)
{
+ uint16_t i = htons(x);
+
+ return ((i >> 8) & 0xff) | ((i & 0xff) << 8);
+}
+
+#if 0
+static uint16_t cpu_to_le16(uint16_t x)
+{
+ uint16_t i = ntohs(x);
+
+ return ((i >> 8) & 0xff) | ((i & 0xff) << 8);
+}
+#endif
+
+static uint32_t swab32(uint32_t x)
+{
+ return ((x >> 24) | ((x >> 8) & 0xff00) | ((x & 0xff00) << 8) | (x << 24));
+}
+
+#define be16_to_cpu ntohs
+#define cpu_to_be16 htons
+#define be32_to_cpu ntohl
+#define cpu_to_be32 htonl
+
+static int parse_hex_str(char *arg, unsigned char *hexstr, int octets)
+{
if (strchr(arg, ':') != NULL) {
- unsigned char *p;
- int octet = 7, octetspercolon;
+ char *p;
+ int octetspercolon;
/* Determine the format of the GUID. Is it single or double octet? */
p = strrchr(arg, ':');
@@ -120,14 +134,14 @@
else if (*(p + 1) && *(p + 2) && !*(p + 3))
octetspercolon = 1;
else {
- fprintf(stderr, "Unknown GUID format\n");
- return 1;
+ fprintf(stderr, "Unknown hex string format\n");
+ return -1;
}
/*
- * We don't require a full GUID here. If the user doesn't specify
- * a full GUID, we'll put in the default OID and 0 pad the rest
- * and use as much of a GUID the user gives.
+ * We don't require a full GUID here. If the user doesn't
+ * specify a full GUID, we'll put the Topspin OID and 0 pad
+ * the rest and use as much of a GUID the user gives
*/
do {
unsigned char value, hex;
@@ -141,7 +155,7 @@
if (octetspercolon == 2) {
/* There should be no more characters after this */
if (*(p + 4) != 0)
- return 1;
+ return -1;
hex = toupper(*(p + 2));
if (hex >= '0' && hex <= '9')
@@ -149,7 +163,7 @@
else if (hex >= 'A' && hex <= 'F')
value = (hex - 'A' + 10) << 4;
else
- return 1;
+ return -1;
hex = toupper(*(p + 3));
if (hex >= '0' && hex <= '9')
@@ -157,13 +171,13 @@
else if (hex >= 'A' && hex <= 'F')
value |= hex - 'A' + 10;
else
- return 1;
+ return -1;
- new_guid[octet--] = value;
+ hexstr[--octets] = value;
} else {
/* There should be no more characters after this */
if (*(p + 2) != 0)
- return 1;
+ return -1;
}
hex = toupper(*p);
@@ -172,7 +186,7 @@
else if (hex >= 'A' && hex <= 'F')
value = (hex - 'A' + 10) << 4;
else
- return 1;
+ return -1;
hex = toupper(*(p + 1));
if (hex >= '0' && hex <= '9')
@@ -180,37 +194,215 @@
else if (hex >= 'A' && hex <= 'F')
value |= hex - 'A' + 10;
else
- return 1;
+ return -1;
- new_guid[octet--] = value;
- } while (p > arg && octet >= 0);
+ hexstr[--octets] = value;
+ } while (p > arg && octets > 0);
- if (octet < 0 && p > arg)
- /* Still data left */
+ /* Data left over */
+ if (p > arg)
return 1;
+ } else {
+ unsigned long low_guid = strtol(arg, NULL, 16);
- if (octet > 0 && octet < 3) {
- fprintf(stderr, "GUID is not 8 octets, but longer than 4 maximum to automatically generate\n");
+ /* FIXME: Check the result of strtol, or do something more intelligent */
+
+ hexstr[octets - 4] = (low_guid >> 24) & 0xff;
+ hexstr[octets - 3] = (low_guid >> 16) & 0xff;
+ hexstr[octets - 2] = (low_guid >> 8) & 0xff;
+ hexstr[octets - 1] = low_guid & 0xff;
+
+ octets -= 4;
+ }
+
+ return octets;
+}
+
+static int parse_guid(char *arg, unsigned char *new_guid)
+{
+ int octets;
+
+ octets = parse_hex_str(arg, new_guid, GUID_LEN);
+
+ if (octets < 0)
+ return 1;
+
+ if (octets > 0 && octets < 3) {
+ fprintf(stderr, "GUID is not 8 octets, but longer than 4 maximum to automatically generate\n");
+ return 1;
+ }
+
+ if (octets >= 3) {
+ memcpy(new_guid, default_oid, 4);
+
+ if (octets > 3)
+ /* Zero out the non specified portions */
+ memset(new_guid + 3, 0, octets - 3);
+ }
+
+ return 0;
+}
+
+static int parse_change_options(struct topspin_vsd *vsd, char *cmd)
+{
+ char *p = cmd, *end = strchr(cmd, 0);
+
+ while (p && p < end) {
+ char *pc, *pe;
+
+ pc = strchr(p, ',');
+ if (pc) {
+ *pc = 0;
+ pc++;
+ }
+
+ pe = strchr(p, '=');
+ if (!pe) {
+ fprintf(stderr, "Missing = in token '%s'\n", p);
return 1;
}
- if (octet >= 3) {
- memcpy(new_guid, default_oid, 4);
+ *pe = 0;
+ pe++;
- if (octet > 3)
- /* Zero out the non specified portions */
- memset(new_guid + 3, 0, octet - 3);
+ if (strcasecmp(p, "auto_upgrade") == 0) {
+ if (strcasecmp(pe, "yes") == 0 ||
+ strcasecmp(pe, "on") == 0 ||
+ strcasecmp(pe, "1") == 0)
+ vsd->flags |= cpu_to_be32(VSD_FLAG_AUTOUPGRADE);
+ else if (strcasecmp(pe, "no") == 0 ||
+ strcasecmp(pe, "off") == 0 ||
+ strcasecmp(pe, "0") == 0)
+ vsd->flags &= ~cpu_to_be32(VSD_FLAG_AUTOUPGRADE);
+ else {
+ fprintf(stderr, "Unknown boolean value '%s'\n", pe);
+ return 1;
+ }
+ } else if (strcasecmp(p, "boot_enable_port_1") == 0) {
+ if (strcasecmp(pe, "yes") == 0 ||
+ strcasecmp(pe, "on") == 0 ||
+ strcasecmp(pe, "1") == 0)
+ vsd->flags |= cpu_to_be32(VSD_FLAG_BOOT_ENABLE_PORT_1);
+ else if (strcasecmp(pe, "no") == 0 ||
+ strcasecmp(pe, "off") == 0 ||
+ strcasecmp(pe, "0") == 0)
+ vsd->flags &= ~cpu_to_be32(VSD_FLAG_BOOT_ENABLE_PORT_1);
+ else {
+ fprintf(stderr, "Unknown boolean value '%s'\n", pe);
+ return 1;
+ }
+ } else if (strcasecmp(p, "boot_enable_port_2") == 0) {
+ if (strcasecmp(pe, "yes") == 0 ||
+ strcasecmp(pe, "on") == 0 ||
+ strcasecmp(pe, "1") == 0)
+ vsd->flags |= cpu_to_be32(VSD_FLAG_BOOT_ENABLE_PORT_2);
+ else if (strcasecmp(pe, "no") == 0 ||
+ strcasecmp(pe, "off") == 0 ||
+ strcasecmp(pe, "0") == 0)
+ vsd->flags &= ~cpu_to_be32(VSD_FLAG_BOOT_ENABLE_PORT_2);
+ else {
+ fprintf(stderr, "Unknown boolean value '%s'\n", pe);
+ return 1;
+ }
+ } else if (strcasecmp(p, "boot_service_scan") == 0) {
+ if (strcasecmp(pe, "yes") == 0 ||
+ strcasecmp(pe, "on") == 0 ||
+ strcasecmp(pe, "1") == 0)
+ vsd->flags |= cpu_to_be32(VSD_FLAG_BOOT_ENABLE_SCAN);
+ else if (strcasecmp(pe, "no") == 0 ||
+ strcasecmp(pe, "off") == 0 ||
+ strcasecmp(pe, "0") == 0)
+ vsd->flags &= ~cpu_to_be32(VSD_FLAG_BOOT_ENABLE_SCAN);
+ else {
+ fprintf(stderr, "Unknown boolean value '%s'\n", pe);
+ return 1;
+ }
+ } else if (strcasecmp(p, "boot_wait_on_error") == 0) {
+ if (strcasecmp(pe, "yes") == 0 ||
+ strcasecmp(pe, "on") == 0 ||
+ strcasecmp(pe, "1") == 0)
+ vsd->flags |= cpu_to_be32(VSD_FLAG_BOOT_WAIT_ON_ERROR);
+ else if (strcasecmp(pe, "no") == 0 ||
+ strcasecmp(pe, "off") == 0 ||
+ strcasecmp(pe, "0") == 0)
+ vsd->flags &= ~cpu_to_be32(VSD_FLAG_BOOT_WAIT_ON_ERROR);
+ else {
+ fprintf(stderr, "Unknown boolean value '%s'\n", pe);
+ return 1;
+ }
+ } else if (strcasecmp(p, "boot_try_forever") == 0) {
+ if (strcasecmp(pe, "yes") == 0 ||
+ strcasecmp(pe, "on") == 0 ||
+ strcasecmp(pe, "1") == 0)
+ vsd->flags |= cpu_to_be32(VSD_FLAG_BOOT_TRY_FOREVER);
+ else if (strcasecmp(pe, "no") == 0 ||
+ strcasecmp(pe, "off") == 0 ||
+ strcasecmp(pe, "0") == 0)
+ vsd->flags &= ~cpu_to_be32(VSD_FLAG_BOOT_TRY_FOREVER);
+ else {
+ fprintf(stderr, "Unknown boolean value '%s'\n", pe);
+ return 1;
+ }
+ } else if (strcasecmp(p, "boot_type") == 0) {
+ vsd->flags &= ~cpu_to_be32(VSD_FLAG_BOOT_TYPE);
+ if (strcasecmp(pe, "well_known") == 0)
+ vsd->flags |= cpu_to_be32(VSD_FLAG_BOOT_TYPE_WELL_KNOWN);
+ else if (strcasecmp(pe, "saved") == 0)
+ vsd->flags |= cpu_to_be32(VSD_FLAG_BOOT_TYPE_SAVED);
+ else if (strcasecmp(pe, "pxe") == 0)
+ vsd->flags |= cpu_to_be32(VSD_FLAG_BOOT_TYPE_PXE);
+ else if (strcasecmp(pe, "disable") == 0)
+ vsd->flags |= cpu_to_be32(VSD_FLAG_BOOT_TYPE_DISABLE);
+ else {
+ fprintf(stderr, "Unknown boot type '%s'\n", pe);
+ return 1;
+ }
+ } else if (strcasecmp(p, "boot_saved_port") == 0) {
+ unsigned long port;
+
+ port = strtoul(pe, NULL, 10);
+ if (port > 2) {
+ fprintf(stderr, "Invalid port number '%s'\n", pe);
+ return 1;
+ }
+
+ vsd->boot_port = port;
+ } else if (strcasecmp(p, "boot_saved_ioc_num") == 0) {
+ unsigned long ioc;
+
+ ioc = strtoul(pe, NULL, 10);
+ if (ioc == ULONG_MAX) {
+ fprintf(stderr, "Invalid ioc number '%s'\n", pe);
+ return 1;
+ }
+
+ vsd->boot_ioc_num = ioc;
+ } else if (strcasecmp(p, "boot_saved_dgid") == 0) {
+ if (parse_hex_str(pe, vsd->boot_dgid, 16) < 0) {
+ fprintf(stderr, "Couldn't parse dgid\n");
+ return 1;
+ }
+ } else if (strcasecmp(p, "boot_saved_service_name") == 0) {
+ if (parse_hex_str(pe, vsd->boot_service_name, 8) < 0) {
+ fprintf(stderr, "Couldn't parse service name\n");
+ return 1;
+ }
+ } else if (strcasecmp(p, "boot_pxe_secs") == 0) {
+ unsigned long secs;
+
+ secs = strtoul(pe, NULL, 10);
+ if (secs > 250) {
+ fprintf(stderr, "Invalid number of seconds '%s'\n", pe);
+ return 1;
+ }
+
+ vsd->boot_pxe_secs = secs;
+ } else {
+ fprintf(stderr, "Unknown option '%s'\n", p);
+ return 1;
}
- } else {
- unsigned long low_guid = strtol(arg, NULL, 16);
- /* FIXME: Check the result of strtol, or do something more intelligent */
-
- memcpy(new_guid, default_oid, 4);
- new_guid[4] = (low_guid >> 24) & 0xff;
- new_guid[5] = (low_guid >> 16) & 0xff;
- new_guid[6] = (low_guid >> 8) & 0xff;
- new_guid[7] = low_guid & 0xff;
+ p = pc;
}
return 0;
@@ -220,6 +412,7 @@
{
int i, carry = 1;
+ /* FIXME: Do we really want to try to increment the vendor oid too? */
for (i = 7; i >= 0; i--) {
if (carry && guid[i] == 0xFF) {
new_guid[i] = 0;
@@ -231,66 +424,89 @@
}
}
-static int update_status(char *string, int pos, int max, int curbar)
+unsigned int status_curpos, status_relpos, status_maxpos;
+unsigned int status_curbar;
+unsigned char status_prev;
+
+static void status_start(unsigned int max)
{
+ status_curpos = 0;
+ status_relpos = 0;
+ status_maxpos = max;
+
+ status_curbar = 0;
+ status_prev = 0;
+
+ if (verbose)
+ printf("Flashing - ");
+}
+
+static void status_update(unsigned char status, unsigned int curpos)
+{
unsigned int bar;
- if (cols) {
- bar = (pos * (cols - 14)) / max;
- if (bar != curbar) {
- int i;
+ if (!verbose)
+ return;
- printf("%-10s [", string);
- for (i = 0; i < bar; i++)
- printf("=");
+ curpos += status_relpos;
- printf("%*s]\r", (cols - 14) - bar, "");
- fflush(stdout);
- curbar = bar;
- }
- } else {
- /* Fall back to something simpler */
- bar = (pos * 100) / max;
- if (bar != curbar) {
- printf("%-10s %3d%%\r", string, bar);
- fflush(stdout);
- curbar = bar;
- }
+ bar = (curpos * (cols - 12)) / status_maxpos;
+ status_curpos = curpos;
+
+ /* Force a character to be printed during a status change */
+ if (status != status_prev && status_curbar >= bar)
+ bar = status_curbar + 1;
+
+ if (status_curbar < bar) {
+ for (; status_curbar < bar; status_curbar++)
+ printf("%c", status);
+
+ fflush(stdout);
}
- return curbar;
+ status_prev = status;
}
+static void status_mark(void)
+{
+ status_relpos = status_curpos;
+}
+
+static void status_stop(void)
+{
+ if (verbose)
+ printf("\n");
+}
+
/*
* HCA card management
*/
+static int vpd_read(struct tvdevice *tvdev);
+
static int scan_devices(struct pci_access *pacc)
{
struct pci_dev *pdev;
struct tvdevice *tvdev;
- int count = 0, pci_count = 0, pciconf_count = 0;
- int i;
+ int pci_count = 0, pciconf_count = 0;
+ unsigned short kernel;
+ struct utsname utsname;
-#define HCA_PCI_DEV(v, d, c) .vendor = v, .device = d, .can_map = c
+ /*
+ * libpci, depending on the kernel it's running under, will create the
+ * PCI device list in the correct order, or backwards. As a result, we
+ * need to create our list appropriately too so the order of the HCAs
+ * matches what the kernel sees the HCA list (ie ib0 is HCA #0, etc)
+ */
+ if (uname(&utsname) < 0) {
+ fprintf(stderr, "couldn't get uname information, assuming 2.4 kernel\n");
+ kernel = 0x0204;
+ } else {
+ unsigned int major, minor;
- static const struct {
- uint16_t vendor;
- uint16_t device;
- int can_map;
- } hca_dev_table[] = {
- { HCA_PCI_DEV(PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT23108, 1) },
- { HCA_PCI_DEV(PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT25208_COMPAT, 1) },
- { HCA_PCI_DEV(PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT25208, 1) },
- { HCA_PCI_DEV(PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT23108_PCICONF, 0) },
- { HCA_PCI_DEV(PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT25208_PCICONF, 0) },
- { HCA_PCI_DEV(PCI_VENDOR_TOPSPIN, PCI_DEVICE_MELLANOX_MT23108, 1) },
- { HCA_PCI_DEV(PCI_VENDOR_TOPSPIN, PCI_DEVICE_MELLANOX_MT25208_COMPAT, 1) },
- { HCA_PCI_DEV(PCI_VENDOR_TOPSPIN, PCI_DEVICE_MELLANOX_MT25208, 1) },
- { HCA_PCI_DEV(PCI_VENDOR_TOPSPIN, PCI_DEVICE_MELLANOX_MT23108_PCICONF, 0) },
- { HCA_PCI_DEV(PCI_VENDOR_TOPSPIN, PCI_DEVICE_MELLANOX_MT25208_PCICONF, 0) },
- { 0 }
- };
+ sscanf(utsname.release, "%d.%d", &major, &minor);
+ kernel = ((major & 0xff) << 8) | (minor & 0xff);
+ }
/*
* Example of how various configurations appear on the PCI bus.
@@ -316,48 +532,58 @@
* 03:01:0 5a45 00a1 (PCI conf)
*/
for (pdev = pacc->devices; pdev; pdev = pdev->next) {
+ int i;
+
pci_fill_info(pdev, PCI_FILL_IDENT);
- for (i = 0; hca_dev_table[i].vendor; ++i) {
- if (hca_dev_table[i].vendor == pdev->vendor_id &&
- hca_dev_table[i].device == pdev->device_id)
- break;
- }
+ for (i = 0; i < sizeof(pciids) / sizeof(pciids[0]); i++) {
+ if (pciids[i].vendor != pdev->vendor_id ||
+ pciids[i].device != pdev->device_id)
+ continue;
- if (!hca_dev_table[i].vendor)
- continue;
+ tvdev = malloc(sizeof(*tvdev));
+ if (!tvdev) {
+ fprintf(stderr, "couldn't allocate %d bytes for device struct\n", (int) sizeof *tvdev);
+ return -1;
+ }
+ memset(tvdev, 0, sizeof(*tvdev));
+ tvdev->pdev = pdev;
+ tvdev->pciid = &pciids[i];
+ tvdev->flags = pciids[i].flags;
- /*
- * MT23108 based boards can appear in one of two ways:
- * - Normal mode (flash jumper removed) will result in the PCI bridge
- * and MT23108 PCI devices appearing.
- * - Recovery mode (flash jumper shorted) will result in only the PCI
- * conf device appearing.
- *
- * We can use any of these devices, so we store a pointer if we find
- * the bridge of conf device. If we hit another one or we find a
- * MT23108 device, we load the appropriate modules and start the
- * device (if on the switch).
- */
+ vpd_read(tvdev);
- tvdev = calloc(sizeof *tvdev, 1);
- if (!tvdev) {
- fprintf(stderr, "couldn't allocate %d bytes for device struct\n",
- (int) sizeof *tvdev);
- return -1;
+ tvdev->revision = pci_read_word(pdev, PCI_CLASS_REVISION) & 0xff;
+
+ /* According to the documentation, a revision of 0x00 is an A0 */
+ if (tvdev->revision == 0x00)
+ tvdev->revision = 0xA0;
+ else if (tvdev->revision == 0x01)
+ tvdev->revision = 0xA1;
+
+ if (kernel <= 0x0204) {
+ tvdev->next = tvdevices;
+ if (!tvdevices_tail)
+ tvdevices_tail = tvdev;
+ tvdevices = tvdev;
+ } else {
+ if (tvdevices_tail)
+ tvdevices_tail->next = tvdev;
+ else /* first device we found */
+ tvdevices = tvdev;
+ tvdevices_tail = tvdev;
+ }
}
- tvdev->pdev = pdev;
- tvdev->can_map = hca_dev_table[i].can_map;
- if (tvdev->can_map)
+ }
+
+ for (tvdev = tvdevices; tvdev; tvdev = tvdev->next) {
+ if (tvdev->flags & FLAG_RECOVERY)
+ tvdev->num = pciconf_count++;
+ else
tvdev->num = pci_count++;
- else
- tvdev->num = pciconf_count++;
- tvdev->next = tvdevices;
- tvdevices = tvdev;
- count++;
}
- return count;
+ return pci_count + pciconf_count;
}
static struct tvdevice *find_device(int hca)
@@ -378,8 +604,8 @@
* VPD code
*/
-static int READ_VPD(struct pci_dev *pdev, unsigned int vpd_off, unsigned int addr,
- unsigned int *data)
+static int read_vpd_data(struct pci_dev *pdev, unsigned int vpd_off,
+ unsigned int addr, unsigned int *data)
{
int i;
unsigned int val;
@@ -398,20 +624,19 @@
}
gettimeofday(&tcur, NULL);
elapsed = ((tcur.tv_sec - tstart.tv_sec) * 1000L) +
- ((tcur.tv_usec - tstart.tv_usec) / 1000L);
+ ((tcur.tv_usec - tstart.tv_usec) / 1000L);
} while (elapsed < 100);
if (verbose > 1)
- fprintf(stderr, "READ_VPD: timed out at off %x\n", addr);
+ fprintf(stderr, "read_vpd_data: timed out at off %x\n", addr);
return 1;
}
static int vpd_exists(struct pci_dev *pdev, int *vpd_off)
{
- int cap_ptr;
- int cap_id;
- int val;
+ int cap_ptr, cap_id;
+ int val;
cap_ptr = pci_read_long(pdev, PCI_CAPABILITY_LIST) & 0xff;
while (cap_ptr != 0) {
@@ -427,23 +652,27 @@
return 0;
}
-static int vpd_read(struct tvdevice *tvdev, struct pci_dev *pdev)
+static int vpd_read(struct tvdevice *tvdev)
{
int vpd_off;
- tvdev->vpd = 0;
+ tvdev->vpd_present = 0;
- if (vpd_exists(pdev, &vpd_off)) {
+ if (vpd_exists(tvdev->pdev, &vpd_off)) {
unsigned int *ptr;
- int i;
+ int i, swap_endian = 0;
- ptr = (unsigned int *)tvdev->vpd_data;
+ ptr = tvdev->vpd.vpd_int;
- if (READ_VPD(pdev, vpd_off, 0, ptr++) != 0)
+ if (read_vpd_data(tvdev->pdev, vpd_off, 0, ptr++) != 0)
return 0;
+ /* Check to see if we got the endianess swapped on us */
+ if (tvdev->vpd.vpd_char[0] != 0x82 && tvdev->vpd.vpd_char[3] == 0x82)
+ swap_endian = 1;
+
for (i = 1; i < 64; i++) {
- if (READ_VPD(pdev, vpd_off, (i * 4), ptr++) != 0) {
+ if (read_vpd_data(tvdev->pdev, vpd_off, (i * 4), ptr++) != 0) {
if (i < 32)
return 0;
else
@@ -451,339 +680,552 @@
}
}
- tvdev->vpd = 1;
+ tvdev->vpd_present = 1;
+
+ if (swap_endian) {
+ ptr = tvdev->vpd.vpd_int;
+ for (i = 0; i < 64; i++) {
+ *ptr = swab32(*ptr);
+ ptr++;
+ }
+ }
}
- return tvdev->vpd;
+ return tvdev->vpd_present;
}
-static int open_hca(struct tvdevice *tvdev)
+/*
+ * Read/Write from the configuration space
+ */
+static unsigned int read_cfg(struct tvdevice *tvdev, unsigned int addr)
{
- cur_hca = tvdev->pdev;
+ unsigned int val;
- if (!config && tvdev->can_map) {
- int fd = open("/dev/mem", O_RDWR, O_SYNC);
- if (fd < 0) {
- perror("open /dev/mem");
- return errno;
+ switch (tvdev->method) {
+ case METHOD_MMAP:
+ val = ntohl(*(uint32_t *)(tvdev->bar0 + addr));
+ break;
+ case METHOD_PCI_CFG:
+ if (!pci_write_long(tvdev->pdev, 22 * 4, addr)) {
+ fprintf(stderr, "read_cfg: pci_write_long failed\n");
+ exit(1);
}
- bar0 = mmap(NULL,
- 1 << 20,
- PROT_READ | PROT_WRITE,
- MAP_SHARED,
- fd,
- tvdev->pdev->base_addr[0] & ~0xfUL);
- close(fd);
- if (bar0 == MAP_FAILED) {
- perror("mmap");
- return errno;
- }
- } else
- bar0 = NULL;
- return 0;
+ val = pci_read_long(tvdev->pdev, 23 * 4);
+ break;
+ default:
+ abort();
+ }
+
+ return val;
}
-static void close_hca(void)
+static void write_cfg(struct tvdevice *tvdev, unsigned int addr,
+ unsigned int data)
{
- if (bar0)
- munmap(bar0, 1 << 20);
+ switch (tvdev->method) {
+ case METHOD_MMAP:
+ *(uint32_t *)(tvdev->bar0 + addr) = htonl(data);
+ break;
+ case METHOD_PCI_CFG:
+ if (!pci_write_long(tvdev->pdev, 22 * 4, addr) ||
+ !pci_write_long(tvdev->pdev, 23 * 4, data)) {
+ fprintf(stderr, "write_cfg: pci_write_long failed\n");
+ exit(1);
+ }
+ break;
+ default:
+ abort();
+ }
}
-/* InfiniHost Read from Internal Configuration Space */
-static uint32_t READ_CFG(unsigned int addr)
-{
- if (bar0)
- return ntohl(*(uint32_t *) (bar0 + addr));
+#define NUM_SPIS 4
- if (!pci_write_long(cur_hca, 22 * 4, addr)) {
- fprintf(stderr, "READ_CFG failed\n");
- exit(1);
- }
+#define FLASH_GW 0xF0400
+#define FLASH_ADDR 0xF0404
+#define FLASH_DATA 0xF0408
+#define FLASH_CS 0xF0418
- return pci_read_long(cur_hca, 23 * 4);
-} /* READ_CFG */
+#define READ_OP (1 << 0)
-/* InfiniHost Write to the Internal Configuration Space */
-static void WRITE_CFG(unsigned int addr, unsigned int data)
+#define SPI_NO_DATA (1 << 4)
+#define SPI_NO_ADDR (1 << 5)
+#define SPI_SPECIAL (1 << 6)
+#define BUSY (1 << 30)
+
+#define WIP (1 << 24)
+#define WEL (1 << 25)
+
+#define FC_SE 0xD8
+#define FC_PP 0x02
+#define FC_RDSR 0x05
+#define FC_WREN 0x06
+
+#define WAIT_INTERVAL 10
+
+static void flash_set_bank(struct tvdevice *tvdev, unsigned int addr)
{
- if (bar0)
- *(uint32_t *) (bar0 + addr) = htonl(data);
- else if (!pci_write_long(cur_hca, 22 * 4, addr) ||
- !pci_write_long(cur_hca, 23 * 4, data)) {
- fprintf(stderr, "WRITE_CFG failed\n");
- exit(1);
+ unsigned char bank = addr >> tvdev->flash_bank_shift;
+
+ if (bank == tvdev->flash_bank)
+ return;
+
+ switch (tvdev->flash_command_set) {
+ case CS_SPI:
+ write_cfg(tvdev, FLASH_CS, bank << 30);
+ break;
+ default:
+ /* Set the appropriate data bits */
+ write_cfg(tvdev, GPIO_DAT + 4, (read_cfg(tvdev, GPIO_DAT + 4) & ~(0x07 << 4)) | (bank << 4));
+ break;
}
-} /* WRITE_CFG */
-static void flash_set_bank(unsigned char bank)
-{
- /* Set the appropriate data bits */
- WRITE_CFG(0xF0080 + 0x04,
- (READ_CFG(0xF0080 + 0x04) & ~(0x07 << 4)) | (bank << 4));
-
- flash_bank = bank;
+ tvdev->flash_bank = bank;
}
/* read a dword from the flash, address must be 4 bytes aligned */
-static unsigned int flash_read(unsigned int addr)
+static unsigned int flash_read(struct tvdevice *tvdev, unsigned int addr)
{
- unsigned int cmd;
+ unsigned int cmd, status;
- if ((addr >> 19) != flash_bank)
- flash_set_bank(addr >> 19);
+ flash_set_bank(tvdev, addr);
- WRITE_CFG(0xF01A4, (addr & (TV_FLASH_BANK_MASK & ~3)) | (1 << 29));
- do {
- cmd = READ_CFG(0xF01A4);
- } while (cmd & 0xE0000000);
+ switch (tvdev->flash_command_set) {
+ case CS_SPI:
+ write_cfg(tvdev, FLASH_ADDR, (addr & tvdev->flash_bank_mask));
+ write_cfg(tvdev, FLASH_GW, READ_OP | BUSY | (2 << 8));
- return READ_CFG(0xF01A8);
+ do {
+ status = read_cfg(tvdev, FLASH_GW);
+ } while (status & BUSY);
+
+ return read_cfg(tvdev, FLASH_DATA);
+ default:
+ write_cfg(tvdev, 0xF01A4, (addr & (tvdev->flash_bank_mask & ~3)) | (1 << 29));
+ do {
+ cmd = read_cfg(tvdev, 0xF01A4);
+ } while (cmd & 0xE0000000);
+
+ return read_cfg(tvdev, 0xF01A8);
+ }
}
/* read a byte from the flash */
-static unsigned char flash_byte_read(unsigned int addr)
+static unsigned char flash_byte_read(struct tvdevice *tvdev, unsigned int addr)
{
unsigned int data;
- data = flash_read(addr & ~3);
+ data = flash_read(tvdev, addr & ~3);
return ((data >> ((3 - (addr & 3)) * 8)) & 0xFF);
}
/* writes a command to the flash */
-static void flash_write_cmd(unsigned int addr, unsigned char data)
+static void flash_write_cmd(struct tvdevice *tvdev, unsigned int addr,
+ unsigned char data)
{
unsigned int cmd;
- WRITE_CFG(0xF01A8, data << 24);
- WRITE_CFG(0xF01A4, (addr & TV_FLASH_BANK_MASK) | (2 << 29));
+ write_cfg(tvdev, 0xF01A8, data << 24);
+ write_cfg(tvdev, 0xF01A4, (addr & tvdev->flash_bank_mask) | (2 << 29));
do {
- cmd = READ_CFG(0xF01A4);
+ cmd = read_cfg(tvdev, 0xF01A4);
} while (cmd & 0xE0000000);
}
-static void flash_chip_reset(void)
+static void flash_chip_reset(struct tvdevice *tvdev)
{
- /* Issue Flash Reset Command*/
- flash_write_cmd(0x0, 0xf0);
+ /* Issue Flash Reset Command */
+ switch (tvdev->flash_command_set) {
+ case CS_INTEL:
+ flash_write_cmd(tvdev, 0x555, 0xFF);
+ break;
+ case CS_AMD:
+ flash_write_cmd(tvdev, 0x555, 0xF0);
+ break;
+ default:
+ break;
+ }
}
-#define WAIT_INTERVAL 10
+static void spi_wait_wip(struct tvdevice *tvdev)
+{
+ unsigned int status;
+ unsigned int count = 0;
-static void flash_erase_sector(unsigned int addr)
+ do {
+ status = read_cfg(tvdev, FLASH_GW);
+ } while (status & BUSY);
+
+ do {
+ if (++count > 5000)
+ usleep(WAIT_INTERVAL);
+
+ write_cfg(tvdev, FLASH_ADDR, FC_RDSR << 24);
+ write_cfg(tvdev, FLASH_GW, READ_OP | SPI_NO_ADDR | SPI_SPECIAL | BUSY);
+
+ do {
+ status = read_cfg(tvdev, FLASH_GW);
+ } while (status & BUSY);
+
+ status = read_cfg(tvdev, FLASH_DATA);
+ } while (status & WIP);
+}
+
+static void flash_erase_sector(struct tvdevice *tvdev, unsigned int addr)
{
- unsigned int stat;
+ unsigned int status;
- if ((addr >> 19) != flash_bank)
- flash_set_bank(addr >> 19);
+ flash_set_bank(tvdev, addr);
- /* Issue Flash Sector Erase Command*/
- flash_write_cmd(0x555, 0xAA);
- flash_write_cmd(0x2AA, 0x55);
- flash_write_cmd(0x555, 0x80);
- flash_write_cmd(0x555, 0xAA);
- flash_write_cmd(0x2AA, 0x55);
- flash_write_cmd(addr & TV_FLASH_BANK_MASK, 0x30);
+ /* Issue Flash Sector Erase Command */
+ switch (tvdev->flash_command_set) {
+ case CS_SPI:
+ /* Issue Write Enable */
+ write_cfg(tvdev, FLASH_ADDR, FC_WREN << 24);
+ write_cfg(tvdev, FLASH_GW, SPI_NO_ADDR | SPI_NO_DATA | SPI_SPECIAL | BUSY);
- /* Wait for sector erase completion */
- do {
- stat = flash_read(addr);
- usleep(WAIT_INTERVAL);
- } while (stat != 0xFFFFFFFF);
+ do {
+ status = read_cfg(tvdev, FLASH_GW);
+ } while (status & BUSY);
+
+ /* Issue Sector Erase */
+ write_cfg(tvdev, FLASH_ADDR, (FC_SE << 24) | (addr & tvdev->flash_bank_mask));
+ write_cfg(tvdev, FLASH_GW, SPI_NO_DATA | SPI_SPECIAL | BUSY);
+
+ /* Wait for sector erase completion */
+ spi_wait_wip(tvdev);
+ break;
+ case CS_INTEL:
+ flash_write_cmd(tvdev, addr & tvdev->flash_bank_mask, 0x20); /* Erase */
+ flash_write_cmd(tvdev, addr & tvdev->flash_bank_mask, 0xD0); /* Confirm */
+
+ /* Wait for sector erase completion */
+ do {
+ usleep(WAIT_INTERVAL);
+ status = flash_read(tvdev, addr);
+ } while (!(status & 0x80));
+ break;
+ case CS_AMD:
+ flash_write_cmd(tvdev, 0x555, 0xAA);
+ flash_write_cmd(tvdev, 0x2AA, 0x55);
+ flash_write_cmd(tvdev, 0x555, 0x80);
+ flash_write_cmd(tvdev, 0x555, 0xAA);
+ flash_write_cmd(tvdev, 0x2AA, 0x55);
+ flash_write_cmd(tvdev, addr & tvdev->flash_bank_mask, 0x30);
+
+ /* Wait for sector erase completion */
+ do {
+ usleep(WAIT_INTERVAL);
+ status = flash_read(tvdev, addr);
+ } while (status != 0xFFFFFFFF);
+ break;
+ default:
+ break;
+ }
+
+ flash_chip_reset(tvdev);
}
-static void flash_write_byte(unsigned int addr, unsigned char data)
+static int log2up(unsigned long in)
{
- unsigned int stat;
+ unsigned int i;
- if ((addr >> 19) != flash_bank)
- flash_set_bank(addr >> 19);
+ for (i = 0; i < 32; i++) {
+ if (in <= (unsigned long)(1 << i))
+ break;
+ }
- /* Issue Byte Program Command */
- flash_write_cmd(0x555, 0xAA);
- flash_write_cmd(0x2AA, 0x55);
- flash_write_cmd(0x555, 0xA0);
- flash_write_cmd(addr & TV_FLASH_BANK_MASK, data);
+ return i;
+}
- /* Wait for the Byte Program to Complete (Verify Byte Program) */
+static void flash_spi_write_block(struct tvdevice *tvdev, unsigned int addr,
+ unsigned char *sector, unsigned int len)
+{
+ unsigned int i, status;
+
+ /* Enable write */
+ write_cfg(tvdev, FLASH_ADDR, FC_WREN << 24);
+ write_cfg(tvdev, FLASH_GW, SPI_NO_ADDR | SPI_NO_DATA | SPI_SPECIAL | BUSY);
+
do {
- stat = flash_read(addr & ~3);
- } while (data != ((stat >> ((3 - (addr & 3)) * 8)) & 0xFF));
-} /* flash_write_byte */
+ status = read_cfg(tvdev, FLASH_GW);
+ } while (status & BUSY);
-static void mtflash_init(void)
+ write_cfg(tvdev, FLASH_ADDR, (FC_PP << 24) | (addr & tvdev->flash_bank_mask));
+
+ for (i = 0; i < len; i += 4) {
+ uint32_t dword = *((uint32_t *)(sector + i));
+
+ write_cfg(tvdev, FLASH_DATA + i, be32_to_cpu(dword));
+ }
+
+ write_cfg(tvdev, FLASH_GW, SPI_SPECIAL | BUSY | (log2up(len) << 8));
+
+ /* Wait for erase to complete */
+ spi_wait_wip(tvdev);
+}
+
+static void flash_write_byte(struct tvdevice *tvdev, unsigned int addr,
+ unsigned char data)
{
- READ_CFG (0xF0150);
- WRITE_CFG(0xF0150, 1 << 30);
+ unsigned int status;
+
+ switch (tvdev->flash_command_set) {
+ case CS_INTEL:
+ flash_write_cmd(tvdev, addr & tvdev->flash_bank_mask, 0x40);
+ flash_write_cmd(tvdev, addr & tvdev->flash_bank_mask, data);
+
+ /* Wait for the Byte Program to Complete (Verify Byte Program) */
+ do {
+ status = flash_read(tvdev, addr & ~3);
+ } while (!(status & 0x80));
+ break;
+ case CS_AMD:
+ /* Issue Byte Program Command */
+ flash_write_cmd(tvdev, 0x555, 0xAA);
+ flash_write_cmd(tvdev, 0x2AA, 0x55);
+ flash_write_cmd(tvdev, 0x555, 0xA0);
+ flash_write_cmd(tvdev, addr & tvdev->flash_bank_mask, data);
+
+ /* Wait for the Byte Program to Complete (Verify Byte Program) */
+ do {
+ status = flash_read(tvdev, addr & ~3);
+ } while (data != ((status >> ((3 - (addr & 3)) * 8)) & 0xFF));
+ break;
+ default:
+ /* Not possible, but compiler complains */
+ break;
+ }
}
-static void grab_gpio(void)
+static void grab_gpio(struct tvdevice *tvdev)
{
/* Grab the semaphore first */
- while (READ_CFG(0xF03FC) == 1)
+ while (read_cfg(tvdev, 0xF03FC) == 1)
;
- WRITE_CFG(0xF03FC, 1);
+ write_cfg(tvdev, 0xF03FC, 1);
/* Now copy out the values */
- gpio_data[0] = READ_CFG(0xF0080) & 0xFF;
- gpio_data[1] = READ_CFG(0xF0084);
+ tvdev->gpio_data[0] = read_cfg(tvdev, GPIO_DAT) & 0xFF;
+ tvdev->gpio_data[1] = read_cfg(tvdev, GPIO_DAT + 4);
- gpio_direction[0] = READ_CFG(0xF0088) & 0xFF;
- gpio_direction[1] = READ_CFG(0xF008C);
+ tvdev->gpio_direction[0] = read_cfg(tvdev, GPIO_DIR) & 0xFF;
+ tvdev->gpio_direction[1] = read_cfg(tvdev, GPIO_DIR + 4);
- gpio_polarity[0] = READ_CFG(0xF0090) & 0xFF;
- gpio_polarity[1] = READ_CFG(0xF0094);
+ tvdev->gpio_polarity[0] = read_cfg(tvdev, GPIO_POL) & 0xFF;
+ tvdev->gpio_polarity[1] = read_cfg(tvdev, GPIO_POL + 4);
- gpio_output_mode[0] = READ_CFG(0xF0098) & 0xFF;
- gpio_output_mode[1] = READ_CFG(0xF009C);
+ tvdev->gpio_output_mode[0] = read_cfg(tvdev, GPIO_MOD) & 0xFF;
+ tvdev->gpio_output_mode[1] = read_cfg(tvdev, GPIO_MOD + 4);
+}
- /* Set the direction of the flash pins to output */
- WRITE_CFG(0xF0080 + 0x0C, READ_CFG(0xF0080 + 0x0C) | (0x07 << 4));
+static void release_gpio(struct tvdevice *tvdev)
+{
+ if (tvdev->board->chip == CHIP_SINAI) {
+ flash_set_bank(tvdev, 0);
- /* Clear the data for the flash pins to start at bank 0 */
- WRITE_CFG(0xF0080 + 0x54, 0x07 << 4);
+ /* Unlock GPIO */
+ write_cfg(tvdev, GPIO_LOCK, 0xAAAA);
+ }
- /* Clear the polarity for the flash pins */
- WRITE_CFG(0xF0080 + 0x14, READ_CFG(0xF0080 + 0x14) & ~(0x07 << 4));
-
- /* Clear the output mode for the flash pins */
- WRITE_CFG(0xF0080 + 0x1C, READ_CFG(0xF0080 + 0x1C) & ~(0x07 << 4));
-
- flash_bank = 0;
-}
-
-static void release_gpio(void)
-{
/* Write back the saved values */
- WRITE_CFG(0xF0080, (READ_CFG(0xF0080) & ~0xFF) | gpio_data[0]);
- WRITE_CFG(0xF0084, gpio_data[1]);
+ write_cfg(tvdev, GPIO_DAT, (read_cfg(tvdev, GPIO_DAT) & ~0xFF) | tvdev->gpio_data[0]);
+ write_cfg(tvdev, GPIO_DAT + 4, tvdev->gpio_data[1]);
- WRITE_CFG(0xF0088, (READ_CFG(0xF0088) & ~0xFF) | gpio_direction[0]);
- WRITE_CFG(0xF008C, gpio_direction[1]);
+ write_cfg(tvdev, GPIO_DIR, (read_cfg(tvdev, GPIO_DIR) & ~0xFF) | tvdev->gpio_direction[0]);
+ write_cfg(tvdev, GPIO_DIR + 4, tvdev->gpio_direction[1]);
- WRITE_CFG(0xF0090, (READ_CFG(0xF0090) & ~0xFF) | gpio_polarity[0]);
- WRITE_CFG(0xF0094, gpio_polarity[1]);
+ write_cfg(tvdev, GPIO_POL, (read_cfg(tvdev, GPIO_POL) & ~0xFF) | tvdev->gpio_polarity[0]);
+ write_cfg(tvdev, GPIO_POL + 4, tvdev->gpio_polarity[1]);
- WRITE_CFG(0xF0098, (READ_CFG(0xF0098) & ~0xFF) | gpio_output_mode[0]);
- WRITE_CFG(0xF009C, gpio_output_mode[1]);
+ write_cfg(tvdev, GPIO_MOD, (read_cfg(tvdev, GPIO_MOD) & ~0xFF) | tvdev->gpio_output_mode[0]);
+ write_cfg(tvdev, GPIO_MOD + 4, tvdev->gpio_output_mode[1]);
/* Release the semaphore */
- WRITE_CFG(0xF03FC, 0);
+ write_cfg(tvdev, 0xF03FC, 0);
}
-static int identify_board(struct tvdevice *tvdev)
+static struct board *vpd_identify(struct tvdevice *tvdev)
{
- unsigned char cougar;
+ char str[MAX_STR];
+ int i;
- /* Check the PCI device id first */
- if (tvdev->pdev->device_id == PCI_DEVICE_MELLANOX_MT25208 ||
- tvdev->pdev->device_id == PCI_DEVICE_MELLANOX_MT25208_COMPAT ||
- tvdev->pdev->device_id == PCI_DEVICE_MELLANOX_MT25208_PCICONF)
- return BOARD_LIONCUB;
+ if (tvdev->vpd_present) {
+ if (tvdev->vpd.vpd_char[0] == 0x82) {
+ unsigned short len16;
+ char *p = (char *)&tvdev->vpd.vpd_char[3];
- /* Set pin 12 to input and check the value */
- WRITE_CFG(0xF0080 + 0x0C, READ_CFG(0xF0080 + 0x0C) & ~(1 << 12));
+ memcpy(&len16, tvdev->vpd.vpd_char + 1, sizeof(len16));
+ len16 = le16_to_cpu(len16);
- usleep(10);
+ /* Skip leading whitespace */
+ for (; len16 > 0 && isspace(*p); len16--, p++)
+ ;
- cougar = !!(READ_CFG(0xF0080 + 0x04) & (1 << 12));
- if (!cougar)
- return BOARD_JAGUAR;
+ /* Make sure we don't copy too much */
+ if (len16 > sizeof(str))
+ len16 = sizeof(str);
- if (tvdev->vpd) {
- unsigned char str[MAX_STR];
- unsigned short len16;
+ memcpy(str, p, len16);
+ str[len16] = 0;
- if (tvdev->vpd_data[0] == 0x82) {
- len16 = *(unsigned short *)&tvdev->vpd_data[1];
- memcpy(str, &tvdev->vpd_data[3], len16);
- str[len16] = 0;
- if (strncasecmp(str, COUGARCUB_VPD_STR,
- strlen(COUGARCUB_VPD_STR)) == 0)
- return BOARD_COUGARCUB;
+ /* Strip off any trailing whitespace */
+ for (len16--; len16 > 0 && isspace(str[len16]); len16--)
+ str[len16] = 0;
} else
fprintf(stderr, " \nError. String Tag not present (found tag %02x instead)\n",
- tvdev->vpd_data[0]);
+ tvdev->vpd.vpd_char[0]);
+ } else
+ str[0] = 0;
+
+ for (i = 0; i < sizeof(board_vpds) / sizeof(board_vpds[0]); i++) {
+ if (strcasecmp(str, board_vpds[i].str) == 0)
+ return board_vpds[i].board;
}
- return BOARD_COUGAR;
+ return NULL;
}
-/*
- * Mid level flash functions (firmware image)
- */
+static struct board *arbel_identify(struct tvdevice *tvdev)
+{
+ struct board *board;
-static void fixup_topspin_vsd(struct topspin_vsd *vsd, int do_boot)
+ board = vpd_identify(tvdev);
+ if (board)
+ return board;
+
+ return &genarbel;
+}
+
+static struct board *sinai_identify(struct tvdevice *tvdev)
{
- if (!(vsd->flags & htonl(VSD_FLAG_ALIGN_FIXED))) {
+ struct board *board;
+
+ board = vpd_identify(tvdev);
+ if (board)
+ return board;
+
+ return &gensinai;
+}
+
+static struct board *tavor_identify(struct tvdevice *tvdev)
+{
+ struct board *board;
+
+ /* Detect the difference between a Jaguar and Cougar via the GPIO pins */
+
+ /* Set GPIO pin 12 to input and check the value */
+ write_cfg(tvdev, GPIO_DIR + 4, read_cfg(tvdev, GPIO_DIR + 4) & ~(1 << 12));
+
+ usleep(10);
+
+ /* Check if board is a Jaguar by looking at GPIO pin 12 */
+ if (!(read_cfg(tvdev, GPIO_DAT + 4) & (1 << 12)))
+ return &jaguar;
+
+ /* Check the rest by VPD */
+ board = vpd_identify(tvdev);
+ if (board)
+ return board;
+
+ /*
+ * FIXME: We shouldn't assume Cougar if the VPD is corrupt. The very
+ * fact that there is a VPD probably means it's not a Cougar board.
+ * It's only a Cougar if there is no VPD at all.
+ */
+
+ return &cougar;
+}
+
+static void fixup_topspin_vsd(struct topspin_vsd *vsd)
+{
+ if (!(vsd->flags & cpu_to_be32(VSD_FLAG_ALIGN_FIXED))) {
/*
- * Some images have the hw_label field misaligned by
- * one byte. If this is an old image (the flag isn't
- * set), then move it back one character
+ * Some images have the hw_label field misaligned by one byte.
+ * If this is an old image (the flag isn't set), then move
+ * it back one character
*/
- memmove(vsd->hw_label, vsd->hw_label + 1, sizeof(vsd->hw_label) - 1);
- vsd->flags |= htonl(VSD_FLAG_ALIGN_FIXED);
+ memmove(vsd->hw_label,
+ vsd->hw_label + 1,
+ sizeof(vsd->hw_label) - 1);
+ vsd->flags |= cpu_to_be32(VSD_FLAG_ALIGN_FIXED);
}
- if (!(vsd->flags & htonl(VSD_FLAG_NEW_BUILD_NUM))) {
+ if (!(vsd->flags & cpu_to_be32(VSD_FLAG_NEW_BUILD_NUM))) {
/*
- * Some images have the hw_label field misaligned by
- * one byte. If this is an old image (the flag isn't
- * set), then move it back one character
+ * build_num used to be an 8 bit field, but our build numbers
+ * quickly outgrew that limitation, so expand to 16 bits and
+ * a new location
*/
vsd->build_num = vsd->old_build_num;
- vsd->flags |= htonl(VSD_FLAG_NEW_BUILD_NUM);
+ vsd->flags |= cpu_to_be32(VSD_FLAG_NEW_BUILD_NUM);
}
- if (!do_boot)
- return;
-
- if ((vsd->flags & htonl(VSD_FLAG_BOOT_OPTIONS)) &&
- vsd->boot_version < BOOT_VERSION) {
+ if ((vsd->flags & cpu_to_be32(VSD_FLAG_BOOT_OPTIONS)) &&
+ ((vsd->boot_version < 1) || (vsd->boot_version > BOOT_VERSION))) {
/* Invalid, reset to defaults */
vsd->boot_version = BOOT_VERSION;
vsd->boot_port = 0;
vsd->boot_ioc_num = 0;
- memset(vsd->boot_dgid, 0,
- sizeof(vsd->boot_dgid));
- vsd->boot_service_name[0] = 0;
- vsd->boot_service_name[1] = 0;
+ memset(vsd->boot_dgid, 0, sizeof(vsd->boot_dgid));
+ memset(vsd->boot_service_name, 0, sizeof(vsd->boot_service_name));
+ vsd->boot_pxe_secs = BOOT_PXE_SECS_DEFAULT;
- vsd->flags &= ~htonl(VSD_FLAG_BOOT_OPTIONS_MASK);
- vsd->flags |=
- htonl(VSD_FLAG_BOOT_ENABLE_PORT_1 |
- VSD_FLAG_BOOT_ENABLE_PORT_2 |
- VSD_FLAG_BOOT_ENABLE_SCAN |
- VSD_FLAG_BOOT_TYPE_WELL_KNOWN |
- VSD_FLAG_BOOT_GID_BIG);
+ vsd->flags &= ~cpu_to_be32(VSD_FLAG_BOOT_OPTIONS_MASK);
+ vsd->flags |= cpu_to_be32(VSD_FLAG_BOOT_ENABLE_PORT_1 |
+ VSD_FLAG_BOOT_ENABLE_PORT_2 |
+ VSD_FLAG_BOOT_ENABLE_SCAN |
+ VSD_FLAG_BOOT_TYPE_WELL_KNOWN |
+ VSD_FLAG_BOOT_GID_BIG);
}
- if (!(vsd->flags & htonl(VSD_FLAG_BOOT_GID_BIG))) {
+ if (!(vsd->flags & cpu_to_be32(VSD_FLAG_BOOT_GID_BIG))) {
uint8_t dword[4];
int i;
for (i = 0; i < sizeof(vsd->boot_dgid); i += 4) {
- memcpy(dword,&vsd->boot_dgid[i], 4);
+ memcpy(dword, &vsd->boot_dgid[i], 4);
vsd->boot_dgid[i + 0] = dword[3];
vsd->boot_dgid[i + 1] = dword[2];
vsd->boot_dgid[i + 2] = dword[1];
vsd->boot_dgid[i + 3] = dword[0];
}
-
- vsd->flags |= htonl(VSD_FLAG_BOOT_GID_BIG);
+
+ vsd->flags |= cpu_to_be32(VSD_FLAG_BOOT_GID_BIG);
}
+
+ if (vsd->boot_version < 2) {
+ uint8_t dword[4];
+ int i;
+
+ vsd->boot_version = BOOT_VERSION;
+ vsd->boot_pxe_secs = BOOT_PXE_SECS_DEFAULT;
+
+ for (i = 0; i < sizeof(vsd->boot_service_name); i += 4) {
+ memcpy(dword, &vsd->boot_service_name[i], 4);
+ vsd->boot_service_name[i + 0] = dword[3];
+ vsd->boot_service_name[i + 1] = dword[2];
+ vsd->boot_service_name[i + 2] = dword[1];
+ vsd->boot_service_name[i + 3] = dword[0];
+ }
+ }
}
+/*
+ * Mid level flash functions (firmware image)
+ */
+
static int flash_image_read_from_file(char *fname,
- unsigned char **isbuf, unsigned int *isbufsz,
- unsigned char **psbuf, unsigned int *psbufsz,
- unsigned char **ibuf, unsigned int *ibufsz)
+ unsigned char **isbuf, unsigned int *isbufsz,
+ unsigned char **psbuf, unsigned int *psbufsz,
+ unsigned char **ibuf, unsigned int *ibufsz)
{
+ unsigned int sector_sz = 0;
+ uint32_t signature;
+ unsigned char *buf;
+ struct stat imgstat;
FILE *fimg;
- struct stat imgstat;
- char *buf;
- unsigned int sector_sz;
/* Open and read image files */
fimg = fopen(fname, "r");
@@ -810,19 +1252,43 @@
}
fclose(fimg);
- /* See if we find a sector size first */
- sector_sz = ntohs(*(uint16_t *)(buf + 0x32));
+ /* Check the signature on the IS */
+ signature = be32_to_cpu(*(uint32_t *)(buf + 0x24));
+ if (signature == 0x5a445a44) {
+ unsigned int is_sz;
- /*
- * Do some sanity checking of the result. Anything less than 4KB or more
- * than 1MB is suspicious and thrown out
- */
- if (sector_sz < 12 || sector_sz > 20)
- sector_sz = TV_FLASH_DEFAULT_SECTOR_SIZE;
- else
- sector_sz = 1 << sector_sz;
+ is_sz = be32_to_cpu(*(uint32_t *)(buf + 0x2c));
- if (ntohl(*(uint32_t *)(buf + sector_sz + 8)) == 0x5a445a44) {
+ if (is_sz > 4 && is_sz < 1048576) {
+ uint16_t crc, img_crc;
+
+ /* is_sz is a count of dwords */
+ is_sz = is_sz * 4;
+ img_crc = be32_to_cpu(*(uint32_t *)(buf + 0x28 + is_sz + 12));
+
+ /* Verify the CRC of the IS */
+ crc = flash_crc16(buf + 0x28, is_sz + 16 - 4);
+ if (crc == img_crc) {
+ unsigned int sector_sz_ptr, log2_sector_sz;
+
+ /* Then grab the sector size */
+ sector_sz_ptr = be16_to_cpu(*(uint16_t *)(buf + 0x16));
+ log2_sector_sz = be16_to_cpu(*(uint16_t *)(buf + sector_sz_ptr + 0x32));
+
+ /*
+ * Do some sanity checking of the result.
+ * Anything less than 4KB or more than
+ * 1MB is suspicious and thrown out
+ */
+ if (log2_sector_sz >= 12 && log2_sector_sz <= 20)
+ sector_sz = 1 << log2_sector_sz;
+ }
+ }
+ }
+
+ /* Check for PPS */
+ if (sector_sz &&
+ be32_to_cpu(*(uint32_t *)(buf + sector_sz + 8)) == 0x5a445a44) {
union vsd *vsd;
/* Failsafe firmware image */
@@ -830,14 +1296,14 @@
*isbufsz = sector_sz;
*psbuf = buf + sector_sz;
*psbufsz = sector_sz;
- *ibuf = buf + ntohl(*(uint32_t *)(buf + sector_sz + 0));
- *ibufsz = ntohl(*(uint32_t *)(buf + sector_sz + 4));
+ *ibuf = buf + be32_to_cpu(*(uint32_t *)(buf + sector_sz + 0));
+ *ibufsz = be32_to_cpu(*(uint32_t *)(buf + sector_sz + 4));
/* Perform some image fixups */
vsd = (union vsd *)(buf + sector_sz + 0x20);
-
- if (ntohs(vsd->data.signature) == VSD_SIGNATURE_TOPSPIN)
- fixup_topspin_vsd(&vsd->data.vendor.topspin, 0);
+ if (be16_to_cpu(vsd->data.signature) == VSD_SIGNATURE_TOPSPIN &&
+ be16_to_cpu(vsd->data.vendor.topspin.signature2) == VSD_SIGNATURE_TOPSPIN)
+ fixup_topspin_vsd(&vsd->data.vendor.topspin);
} else {
/* Non failsafe firmware image */
*isbuf = *psbuf = NULL;
@@ -849,143 +1315,180 @@
return 0;
}
-static int validate_image(struct image *image, unsigned char *psbuf)
+static int validate_xps(struct image *image, unsigned char *psbuf)
{
- image->valid = (ntohl(*(uint32_t *)(psbuf + 0x8)) == 0x5a445a44);
+ /* Check for signature */
+ image->valid = (be32_to_cpu(*(uint32_t *)(psbuf + 0x8)) == 0x5a445a44);
if (image->valid) {
- image->addr = ntohl(*(uint32_t *)(psbuf + 0x0));
- image->size = ntohl(*(uint32_t *)(psbuf + 0x4));
- image->valid = flash_crc16(psbuf, 0x104) == ntohs(*(uint16_t *)(psbuf + 0x106));
+ image->addr = be32_to_cpu(*(uint32_t *)(psbuf + 0x0));
+ image->size = be32_to_cpu(*(uint32_t *)(psbuf + 0x4));
+ /* Check CRC for xPS */
+ image->valid = (flash_crc16(psbuf, 0x104) == be16_to_cpu(*(uint16_t *)(psbuf + 0x106)));
- memcpy(image->vsd.raw, psbuf + 0x20, sizeof image->vsd.raw);
+ memcpy(image->vsd.raw, psbuf + 0x20, sizeof(image->vsd.raw));
- if (htons(image->vsd.data.signature) == VSD_SIGNATURE_TOPSPIN)
- fixup_topspin_vsd(&image->vsd.data.vendor.topspin, 1);
+ if (be16_to_cpu(image->vsd.data.signature) == VSD_SIGNATURE_TOPSPIN &&
+ be16_to_cpu(image->vsd.data.vendor.topspin.signature2) == VSD_SIGNATURE_TOPSPIN)
+ fixup_topspin_vsd(&image->vsd.data.vendor.topspin);
}
return image->valid;
}
-static int flash_check_failsafe(void)
+static int flash_check_failsafe(struct tvdevice *tvdev)
{
- unsigned short sector_sz_ptr;
- unsigned short sector_sz;
- char *psbuf;
+ unsigned int sector_sz = 0;
+ struct failsafe *failsafe = &tvdev->failsafe;
+ uint32_t signature;
+ unsigned char *psbuf;
int i;
- /* Grab the sector size first */
- sector_sz_ptr = (flash_byte_read(0x16) << 8) | flash_byte_read(0x17);
- sector_sz = (flash_byte_read(0x32 + sector_sz_ptr) << 8) |
- flash_byte_read(0x33 + sector_sz_ptr);
+ /* Check the signature on the IS */
+ signature = flash_read(tvdev, 0x24);
+ if (signature == 0x5a445a44) {
+ unsigned char *is;
+ unsigned int is_sz;
- /*
- * Do some sanity checking of the result. Anything less than 4KB or more
- * than 1MB is suspicious and thrown out
- */
- if (sector_sz < 12 || sector_sz > 20) {
- failsafe.sector_sz = TV_FLASH_DEFAULT_SECTOR_SIZE;
- failsafe.valid = 0;
- return 0;
+ is_sz = flash_read(tvdev, 0x2c);
+ if (is_sz > 4 && is_sz < 1048576) {
+ uint16_t crc, img_crc;
+
+ /* is_sz is a count of dwords */
+ is_sz = is_sz * 4;
+ is = malloc(is_sz + 16);
+ if (!is) {
+ fprintf(stderr, "couldn't allocate %d bytes for sector buffer\n",
+ is_sz);
+ exit(1);
+ }
+
+ for (i = 0; i < is_sz + 16; i += 4)
+ *(uint32_t *)(is + i) = be32_to_cpu(flash_read(tvdev, 0x28 + i));
+
+ img_crc = flash_read(tvdev, 0x28 + is_sz + 12);
+
+ /* Verify the CRC of the IS */
+ crc = flash_crc16(is, is_sz + 16 - 4);
+ if (crc == img_crc) {
+ unsigned int sector_sz_ptr, log2_sector_sz;
+
+ /* Then grab the sector size */
+ sector_sz_ptr = flash_read(tvdev, 0x14) & 0xffff;
+ log2_sector_sz = flash_read(tvdev, sector_sz_ptr + 0x30) & 0xffff;
+
+ /*
+ * Do some sanity checking of the result.
+ * Anything less than 4KB or more than
+ * 1MB is suspicious and thrown out
+ */
+ if (log2_sector_sz >= 12 && log2_sector_sz <= 20)
+ sector_sz = 1 << log2_sector_sz;
+ }
+
+ free(is);
+ }
}
- failsafe.sector_sz = 1 << sector_sz;
+ if (!sector_sz)
+ return 0;
- psbuf = malloc(failsafe.sector_sz);
+ psbuf = malloc(sector_sz);
if (!psbuf) {
fprintf(stderr, "couldn't allocate temp buffer for PPS/SPS (size = %d)\n",
- failsafe.sector_sz);
+ sector_sz);
exit(1);
}
/* Check both PPS and SPS for valid signatures */
/* Read out the PPS */
- for (i = 0; i < failsafe.sector_sz; i += 4)
- *(uint32_t *)(psbuf + i) = ntohl(flash_read(failsafe.sector_sz + i));
+ for (i = 0; i < sector_sz; i += 4)
+ *(uint32_t *)(psbuf + i) = be32_to_cpu(flash_read(tvdev, sector_sz + i));
- validate_image(&failsafe.images[0], psbuf);
+ validate_xps(&failsafe->images[0], psbuf);
/* Read out the SPS */
- for (i = 0; i < failsafe.sector_sz; i += 4)
- *(uint32_t *)(psbuf + i) = ntohl(flash_read(failsafe.sector_sz * 2 + i));
+ for (i = 0; i < sector_sz; i += 4)
+ *(uint32_t *)(psbuf + i) = be32_to_cpu(flash_read(tvdev, sector_sz * 2 + i));
- validate_image(&failsafe.images[1], psbuf);
+ validate_xps(&failsafe->images[1], psbuf);
/*
* Last sanity check. We can't say that the IS is programmed correctly
* if we don't see a valid PPS or SPS.
*/
- failsafe.valid = (failsafe.images[0].valid || failsafe.images[1].valid);
+ failsafe->valid = (failsafe->images[0].valid || failsafe->images[1].valid);
free(psbuf);
- return failsafe.valid;
+ return failsafe->valid;
}
/* GUID section structure */
struct guid_section {
- uint8_t gs_fw_reserved_1[16];
- uint8_t gs_node_guid [GUID_LEN];
- uint8_t gs_port1_guid [GUID_LEN];
- uint8_t gs_port2_guid [GUID_LEN];
- uint8_t gs_sysimg_guid[8];
- uint8_t gs_fw_reserved_2[2];
+ uint8_t gs_fw_reserved_1[16];
+ uint8_t gs_node_guid [GUID_LEN];
+ uint8_t gs_port1_guid [GUID_LEN];
+ uint8_t gs_port2_guid [GUID_LEN];
+ uint8_t gs_sysimg_guid[8];
+ uint8_t gs_fw_reserved_2[2];
uint16_t gs_crc16;
};
/* Get the GUIDs currently programmed in the flash */
-static int flash_get_curr_guids(unsigned char *guid_node, unsigned char *guid_port1,
- unsigned char *guid_port2)
+static int flash_get_curr_guids(struct tvdevice *tvdev, unsigned char *guid_node,
+ unsigned char *guid_port1, unsigned char *guid_port2)
{
unsigned int imageaddr = 0;
unsigned char *up;
unsigned int paddr;
int bcnt;
- if (failsafe.valid) {
- if (failsafe.images[0].valid)
- imageaddr = failsafe.images[0].addr;
+ if (tvdev->failsafe.valid) {
+ if (tvdev->failsafe.images[0].valid)
+ imageaddr = tvdev->failsafe.images[0].addr;
else
- imageaddr = failsafe.images[1].addr;
+ imageaddr = tvdev->failsafe.images[1].addr;
} else
imageaddr = 0;
- paddr = flash_read(imageaddr + TV_FLASH_GUID_OFF) + imageaddr;
- if (paddr > TV_FLASH_SIZE) {
+ paddr = flash_read(tvdev, imageaddr + TV_FLASH_GUID_OFF) + imageaddr;
+ if (paddr > tvdev->flash_size) {
fprintf(stderr, "GUID offset (0x%X) is larger than flash size (0x%X)!\n",
- paddr, TV_FLASH_SIZE);
+ paddr, tvdev->flash_size);
return 1;
}
/* Read the Node GUID */
up = guid_node;
for (bcnt = 0; bcnt < GUID_LEN; bcnt++)
- *up++ = flash_byte_read(paddr++);
+ *up++ = flash_byte_read(tvdev, paddr++);
/* Read the Port1 GUID */
up = guid_port1;
for (bcnt = 0; bcnt < GUID_LEN; bcnt++)
- *up++ = flash_byte_read(paddr++);
+ *up++ = flash_byte_read(tvdev, paddr++);
/* Read the Port2 GUID */
up = guid_port2;
for (bcnt = 0; bcnt < GUID_LEN; bcnt++)
- *up++ = flash_byte_read(paddr++);
+ *up++ = flash_byte_read(tvdev, paddr++);
return 0;
}
/* GUID update */
-static int flash_guids_update(unsigned char *ibuf, unsigned int ibufsz,
- unsigned char *guid_node, unsigned char *guid_port1,
- unsigned char *guid_port2)
+static int flash_guids_update(struct tvdevice *tvdev,
+ unsigned char *ibuf, unsigned int ibufsz,
+ unsigned char *guid_node, unsigned char *guid_port1,
+ unsigned char *guid_port2)
{
unsigned int paddr;
struct guid_section *gsp;
uint16_t new_crc;
/* Endianess problems suck */
- paddr = ntohl(*(uint32_t *)(ibuf + TV_FLASH_GUID_OFF));
+ paddr = be32_to_cpu(*(uint32_t *)(ibuf + TV_FLASH_GUID_OFF));
if (paddr > ibufsz) {
fprintf(stderr, "GUID pointer (0x%X) is larger than image size (0x%X)!\n",
paddr, ibufsz);
@@ -995,17 +1498,19 @@
/* Blend in the new GUIDs */
memcpy(&ibuf[paddr], guid_node, GUID_LEN);
memcpy(&ibuf[paddr + GUID_LEN], guid_port1, GUID_LEN);
- memcpy(&ibuf[paddr + GUID_LEN * 2], guid_port2, GUID_LEN);
+ if (tvdev->board->num_ports > 1)
+ memcpy(&ibuf[paddr + GUID_LEN * 2], guid_port2, GUID_LEN);
printf("New Node GUID = %02x%02x%02x%02x%02x%02x%02x%02x\n",
- guid_node[0], guid_node[1], guid_node[2], guid_node[3],
- guid_node[4], guid_node[5], guid_node[6], guid_node[7]);
+ guid_node[0], guid_node[1], guid_node[2], guid_node[3],
+ guid_node[4], guid_node[5], guid_node[6], guid_node[7]);
printf("New Port1 GUID = %02x%02x%02x%02x%02x%02x%02x%02x\n",
- guid_port1[0], guid_port1[1], guid_port1[2], guid_port1[3],
- guid_port1[4], guid_port1[5], guid_port1[6], guid_port1[7]);
- printf("New Port2 GUID = %02x%02x%02x%02x%02x%02x%02x%02x\n",
- guid_port2[0], guid_port2[1], guid_port2[2], guid_port2[3],
- guid_port2[4], guid_port2[5], guid_port2[6], guid_port2[7]);
+ guid_port1[0], guid_port1[1], guid_port1[2], guid_port1[3],
+ guid_port1[4], guid_port1[5], guid_port1[6], guid_port1[7]);
+ if (tvdev->board->num_ports > 1)
+ printf("New Port2 GUID = %02x%02x%02x%02x%02x%02x%02x%02x\n",
+ guid_port2[0], guid_port2[1], guid_port2[2], guid_port2[3],
+ guid_port2[4], guid_port2[5], guid_port2[6], guid_port2[7]);
/* Get pointer to the GUID section in the image buffer */
gsp = (struct guid_section *)(ibuf + paddr - sizeof(gsp->gs_fw_reserved_1));
@@ -1013,7 +1518,7 @@
/* Recalculate GUID section CRC-16 - FW_Reserver_2 and CRC itself excluded */
new_crc = flash_crc16((uint8_t *)gsp, (uint32_t)&((struct guid_section *)0)->gs_fw_reserved_2);
- gsp->gs_crc16 = htons(new_crc);
+ gsp->gs_crc16 = cpu_to_be16(new_crc);
return 0;
}
@@ -1023,26 +1528,26 @@
*/
/* Identify */
-static int create_ver_str(union vsd *vsd, unsigned char *buf, unsigned int buflen)
+static int create_ver_str(union vsd *vsd, char *buf, unsigned int buflen)
{
if (vsd->data.vendor.topspin.revision_ver) {
if (vsd->data.vendor.topspin.revision_ver & 0x80)
- snprintf(buf, buflen, "%d.%02d.%04d-rc%d",
- vsd->data.vendor.topspin.major_ver,
- vsd->data.vendor.topspin.minor_ver,
- ntohs(vsd->data.vendor.topspin.micro_ver),
- vsd->data.vendor.topspin.revision_ver & ~(-1 << 7));
+ snprintf(buf, buflen, "%d.%d.%03d-rc%d",
+ vsd->data.vendor.topspin.major_ver,
+ vsd->data.vendor.topspin.minor_ver,
+ be16_to_cpu(vsd->data.vendor.topspin.micro_ver),
+ vsd->data.vendor.topspin.revision_ver & ~(-1 << 7));
else
- snprintf(buf, buflen, "%d.%02d.%04d_%d",
- vsd->data.vendor.topspin.major_ver,
- vsd->data.vendor.topspin.minor_ver,
- ntohs(vsd->data.vendor.topspin.micro_ver),
- vsd->data.vendor.topspin.revision_ver);
+ snprintf(buf, buflen, "%d.%d.%03d_%d",
+ vsd->data.vendor.topspin.major_ver,
+ vsd->data.vendor.topspin.minor_ver,
+ be16_to_cpu(vsd->data.vendor.topspin.micro_ver),
+ vsd->data.vendor.topspin.revision_ver);
} else
- snprintf(buf, buflen, "%d.%02d.%04d",
- vsd->data.vendor.topspin.major_ver,
- vsd->data.vendor.topspin.minor_ver,
- ntohs(vsd->data.vendor.topspin.micro_ver));
+ snprintf(buf, buflen, "%d.%d.%03d",
+ vsd->data.vendor.topspin.major_ver,
+ vsd->data.vendor.topspin.minor_ver,
+ be16_to_cpu(vsd->data.vendor.topspin.micro_ver));
return strlen(buf);
}
@@ -1051,242 +1556,423 @@
{
char str[MAX_STR];
unsigned short i = 0, rlen;
- unsigned char *ptr = tvdev->vpd_data;
- unsigned short len16 = 0;
+ unsigned char *ptr = tvdev->vpd.vpd_char;
+ unsigned short len16;
unsigned char len8 = 0, cksum = 0;
int len = 0;
int pn = 0, ec = 0, sn = 0, fp = 0, dc = 0, rv = 0;
- printf("\n Vital Product Data");
+ printf("\n Vital Product Data\n");
/* First field is string tag */
if (ptr[0] != 0x82) {
- fprintf(stderr, " \nError. String Tag not present (found tag %02x instead)\n",
+ fprintf(stderr, " Error. String Tag not present (found tag %02x instead)\n",
ptr[0]);
return;
}
/* print out String Tag */
- len16 = *(unsigned short *)&ptr[1];
+ memcpy(&len16, ptr + 1, sizeof(len16));
+ len16 = le16_to_cpu(len16);
memcpy(str, &ptr[3], len16);
str[len16] = 0;
- printf("\n Product Name: %s", str);
+ printf(" Product Name: %s\n", str);
/* string len + 2 bytes of length field + 1 byte of tag */
ptr = &ptr[len16 + 3];
/* check for Read only tag */
if (ptr[0] != 0x90) {
- fprintf(stderr, "\n Error. R Tag not present\n");
+ fprintf(stderr, " Error. R Tag not present\n");
return;
}
- rlen = *(unsigned short *)&ptr[1]; /* Read only resource len */
+ memcpy(&rlen, ptr + 1, sizeof(rlen)); /* Read only resource len */
+ rlen = le16_to_cpu(rlen);
/* parse and print out each field, till we hit end tag */
- ptr += 3; /* 1 byte rtag + 2 bytes length field */
+ ptr += 3; /* 1 byte rtag + 2 bytes length field */
while (i < rlen) {
if ((ptr[0] == 'P') && (ptr[1] == 'N')) {
len8 = ptr[2];
memcpy(str, &ptr[3], len8);
str[len8] = 0;
- printf("\n P/N: %s", str);
+ printf(" P/N: %s\n", str);
pn = 1;
} else if ((ptr[0] == 'E') && (ptr[1] == 'C')) {
len8 = ptr[2];
memcpy(str, &ptr[3], len8);
str[len8] = 0;
- printf("\n E/C: %s", str);
+ printf(" E/C: %s\n", str);
ec = 1;
} else if ((ptr[0] == 'S') && (ptr[1] == 'N')) {
len8 = ptr[2];
memcpy(str, &ptr[3], len8);
str[len8] = 0;
- printf("\n S/N: %s", str);
+ printf(" S/N: %s\n", str);
sn = 1;
} else if ((ptr[0] == 'V') && (ptr[1] == '0')) {
len8 = ptr[2];
memcpy(str, &ptr[3], len8);
str[len8] = 0;
- printf("\n Freq/Power: %s", str);
+ printf(" Freq/Power: %s\n", str);
fp = 1;
} else if ((ptr[0] == 'V') && (ptr[1] == '2')) {
len8 = ptr[2];
memcpy(str, &ptr[3], len8);
str[len8] = 0;
- printf("\n Date Code: %s", str);
+ printf(" Date Code: %s\n", str);
dc = 1;
} else if ((ptr[0] == 'R') && (ptr[1] == 'V')) {
- len = &ptr[2] - tvdev->vpd_data + 1;
+ len = &ptr[2] - tvdev->vpd.vpd_char + 1;
while (len >= 0) {
- cksum += tvdev->vpd_data[len];
+ cksum += tvdev->vpd.vpd_char[len];
len--;
}
if (cksum == 0)
- printf("\n Checksum: Ok");
+ printf(" Checksum: Ok\n");
else
- printf("\n Checksum: Incorrect");
+ printf(" Checksum: Incorrect\n");
rv = 1;
} else if (ptr[0] == 0x78) /* End Tag */
- break;
+ break;
i += (len8 + 3);
ptr += (len8 + 3);
}
if (!pn)
- printf("\n P/N: N/A");
+ printf(" P/N: N/A\n");
if (!ec)
- printf("\n E/C: N/A");
+ printf(" E/C: N/A\n");
if (!sn)
- printf("\n S/N: N/A");
+ printf(" S/N: N/A\n");
if (!dc)
- printf("\n Date Code: N/A");
+ printf(" Date Code: N/A\n");
if (!fp)
- printf("\n Freq/Power: N/A");
+ printf(" Freq/Power: N/A\n");
if (!rv)
- printf("\n Checksum: N/A");
- printf("\n");
+ printf(" Checksum: N/A\n");
}
-static int identify_hca(int num, struct tvdevice *tvdev,
- enum identify_mode identify_mode)
+static int open_device(struct tvdevice *tvdev)
{
- unsigned char revision;
- int err;
+#if defined(__PPC64__)
+ unsigned short command;
- err = open_hca(tvdev);
- if (err)
- return err;
+ /* Enable memory regions if it's disabled */
+ command = pci_read_word(tvdev->pdev, 0x04);
+ if (!(command & 0x02))
+ pci_write_word(tvdev->pdev, 0x04, command | 0x02);
+#endif
- mtflash_init();
- flash_chip_reset();
- grab_gpio();
+ if (!use_config_space && !(tvdev->flags & FLAG_RECOVERY)) {
+ int fd;
- flash_check_failsafe();
+ fd = open("/dev/mem", O_RDWR, O_SYNC);
+ if (fd >= 0) {
+ tvdev->bar0 = mmap(NULL, 1 << 20, PROT_READ | PROT_WRITE, MAP_SHARED,
+ fd, tvdev->pdev->base_addr[0] & PCI_ADDR_MEM_MASK);
+ close(fd);
+ if (tvdev->bar0 == MAP_FAILED)
+ tvdev->bar0 = NULL;
+ } else
+ tvdev->bar0 = NULL;
+ } else
+ tvdev->bar0 = NULL;
- vpd_read(tvdev, tvdev->pdev);
+ if (tvdev->bar0) {
+ tvdev->method = METHOD_MMAP;
+ return 0;
+ }
- revision = pci_read_word(tvdev->pdev, PCI_CLASS_REVISION) & 0xff;
+#if 0
+ /* FIXME: Test that we can do this first */
+ tvdev->method = METHOD_PCI_CFG;
- /* According to the documentation, a revision of 0x00 is an A0 */
- if (revision == 0x00)
- revision = 0xA0;
+ return 0;
+#else
+ return 1;
+#endif
+}
- switch (identify_mode) {
- case IDENTIFY_EXTENDED:
- switch (tvdev->pdev->device_id) {
- case PCI_DEVICE_MELLANOX_MT23108_PCICONF:
- case PCI_DEVICE_MELLANOX_MT23108_PCIBRIDGE:
- printf("HCA #%d: Found MT23108 (recovery mode)", num);
+static void identify_flash_device(struct tvdevice *tvdev)
+{
+ char cfiq[1024], str[4];
+ int i, width = 0;
+
+ switch (tvdev->board->chip) {
+ case CHIP_SINAI:
+ /* SPI device */
+ tvdev->flash_size = 0x200000; /* 2MB */
+ tvdev->flash_bank_shift = 20;
+ tvdev->flash_command_set = CS_SPI;
+ tvdev->flash_sector_sz = 0x10000; /* 64KB */
+ break;
+ default:
+ tvdev->flash_size = 0x400000; /* 4MB */
+ tvdev->flash_bank_shift = 19;
+ tvdev->flash_bank_mask = (1 << tvdev->flash_bank_shift) - 1;
+
+ /* Parallel flash chip */
+
+ /* Get CFI info for flash device */
+ flash_write_cmd(tvdev, 0x55, 0xFF); /* Reset */
+ flash_write_cmd(tvdev, 0x55, 0x98); /* CFI Query */
+
+ str[0] = flash_byte_read(tvdev, 0x10);
+ str[1] = flash_byte_read(tvdev, 0x11);
+ str[2] = flash_byte_read(tvdev, 0x12);
+ str[3] = 0;
+
+ if (strcmp(str, "QRY") == 0)
+ width = 1;
+ else {
+ str[0] = flash_byte_read(tvdev, 0x20);
+ str[1] = flash_byte_read(tvdev, 0x22);
+ str[2] = flash_byte_read(tvdev, 0x24);
+ str[3] = 0;
+
+ if (strcmp(str, "QRY") == 0)
+ width = 2;
+ }
+
+ if (!width) {
+ fprintf(stderr, "CFI query failed. Unknown flash device.\n");
+ exit(1);
+ }
+
+ for (i = 0; i < sizeof(cfiq); i++)
+ cfiq[i] = flash_byte_read(tvdev, i * width);
+
+ tvdev->flash_command_set = cfiq[0x13];
+
+ /*
+ * FIXME: This is a hack for now. We should really get this
+ * from the CFI query. Careful, MX chips have buggy
+ * information.
+ */
+ switch (tvdev->flash_command_set) {
+ case CS_INTEL:
+ tvdev->flash_sector_sz = 0x20000; /* 128KB */
break;
- case PCI_DEVICE_MELLANOX_MT25208_PCICONF:
- printf("HCA #%d: Found MT25208 (recovery mode)", num);
+ case CS_AMD:
+ tvdev->flash_sector_sz = 0x10000; /* 64KB */
break;
- case PCI_DEVICE_MELLANOX_MT23108:
- printf("HCA #%d: Found MT23108", num);
- break;
- case PCI_DEVICE_MELLANOX_MT25208:
- printf("HCA #%d: Found MT25208", num);
- break;
- case PCI_DEVICE_MELLANOX_MT25208_COMPAT:
- printf("HCA #%d: Found MT25208 (MT23108 mode)", num);
- break;
+ default:
+ printf("Unknown flash command set.\n");
+ exit(1);
}
- switch (identify_board(tvdev)) {
- case BOARD_JAGUAR:
- printf(", Jaguar");
+ break;
+ }
+
+ tvdev->flash_bank_mask = (1 << tvdev->flash_bank_shift) - 1;
+
+ flash_chip_reset(tvdev);
+
+ tvdev->flash_bank = -1;
+ flash_set_bank(tvdev, 0);
+}
+
+static int open_hca(struct tvdevice *tvdev)
+{
+ int ret;
+
+ ret = open_device(tvdev);
+ if (ret)
+ return ret;
+
+ read_cfg(tvdev, 0xF0150);
+ write_cfg(tvdev, 0xF0150, 1 << 30);
+
+ grab_gpio(tvdev);
+
+ tvdev->board = tvdev->pciid->identify(tvdev);
+ if (!tvdev->board) {
+ fprintf(stderr, "unable to identify board\n");
+ return 1;
+ }
+
+ identify_flash_device(tvdev);
+
+ if (tvdev->flash_command_set == CS_UNKNOWN) {
+ printf("Unknown flash device, cannot continue\n");
+ return 1;
+ }
+
+ /* RevC LionCub boards use Intel flash chips and use a different firmware */
+ if (tvdev->board == &lioncub && tvdev->flash_command_set == CS_INTEL)
+ tvdev->board = &lioncub_revc;
+
+ switch (tvdev->board->chip) {
+ case CHIP_SINAI:
+ /* SPI flash */
+
+ /* Unlock GPIO */
+ write_cfg(tvdev, GPIO_LOCK, 0xAAAA);
+
+#define SPI_ENABLE ((1 << (NUM_SPIS - 1)) - 1)
+ write_cfg(tvdev, GPIO_DIR + 4, SPI_ENABLE << 5);
+ write_cfg(tvdev, GPIO_POL + 4, (SPI_ENABLE ^ 0x07) << 5);
+ write_cfg(tvdev, GPIO_MOD + 4, (SPI_ENABLE ^ 0x07) << 5);
+ break;
+ default:
+ /* Parallel flash */
+
+ /* Set the direction of the flash pins to output */
+ write_cfg(tvdev, GPIO_DIR + 4, read_cfg(tvdev, GPIO_DIR + 4) | (0x07 << 4));
+
+ /* Clear the data for the flash pins to start at bank 0 */
+ write_cfg(tvdev, 0xF0080 + 0x54, 0x07 << 4);
+
+ /* Clear the polarity for the flash pins */
+ write_cfg(tvdev, GPIO_POL + 4, read_cfg(tvdev, GPIO_POL + 4) & ~(0x07 << 4));
+
+ /* Clear the output mode for the flash pins */
+ write_cfg(tvdev, GPIO_MOD + 4, read_cfg(tvdev, GPIO_MOD + 4) & ~(0x07 << 4));
+ break;
+ }
+
+ return 0;
+}
+
+static void close_hca(struct tvdevice *tvdev)
+{
+ release_gpio(tvdev);
+
+ if (tvdev->bar0)
+ munmap(tvdev->bar0, 1 << 20);
+}
+
+static int identify_hca(int num, struct tvdevice *tvdev,
+ enum identify_mode identify_mode, int *unreliable)
+{
+ if (open_hca(tvdev)) {
+ fprintf(stderr, "couldn't open hca %d\n", num);
+ return 1;
+ }
+
+ flash_check_failsafe(tvdev);
+
+ switch (identify_mode) {
+ case IDENTIFY_EXTENDED:
+ printf("HCA #%d: ", num);
+ switch (tvdev->board->chip) {
+ case CHIP_TAVOR:
+ printf("MT23108");
break;
- case BOARD_COUGAR:
- printf(", Cougar");
+ case CHIP_ARBEL:
+ printf("MT25208");
+ if (tvdev->flags & FLAG_TAVOR_COMPAT)
+ printf(" Tavor Compat");
break;
- case BOARD_COUGARCUB:
- printf(", Cougar Cub");
+ case CHIP_SINAI:
+ printf("MT25204");
break;
- case BOARD_LIONCUB:
- printf(", Lion Cub");
+ default:
+ printf("Unknown");
break;
}
- printf(", revision %02X", revision);
+ if (tvdev->flags & FLAG_RECOVERY)
+ printf(" (recovery mode)");
- if (failsafe.valid && failsafe.images[0].valid &&
- (failsafe.images[0].vsd.data.vendor.topspin.flags &
- htonl(VSD_FLAG_AUTOUPGRADE)))
- printf(" (firmware autoupgrade)");
+ printf(", %s", tvdev->board->name);
- printf("\n");
+ if (tvdev->flags & FLAG_RECOVERY) {
+ printf("(*)");
+ *unreliable = 1;
+ }
- if (failsafe.valid) {
- if (failsafe.images[0].valid) {
- if (ntohs(failsafe.images[0].vsd.data.signature) == 0x05ad &&
- ntohs(failsafe.images[0].vsd.data.vendor.topspin.signature2) == 0x05ad) {
- unsigned char ver_str[40];
+ printf(", revision %02X\n", tvdev->revision);
- create_ver_str(&failsafe.images[0].vsd, ver_str, sizeof(ver_str));
- if (failsafe.images[0].vsd.data.vendor.topspin.build_rev[0])
+ if (tvdev->failsafe.valid) {
+ union vsd *vsd;
+
+ if (tvdev->failsafe.images[0].valid) {
+ vsd = &tvdev->failsafe.images[0].vsd;
+ if (be16_to_cpu(vsd->data.signature) == VSD_SIGNATURE_TOPSPIN &&
+ be16_to_cpu(vsd->data.vendor.topspin.signature2) == VSD_SIGNATURE_TOPSPIN) {
+ char ver_str[40];
+
+ create_ver_str(vsd, ver_str, sizeof(ver_str));
+ if (vsd->data.vendor.topspin.build_rev[0])
printf(" Primary image is v%s build %s.%d, with label '%s'\n",
- ver_str,
- failsafe.images[0].vsd.data.vendor.topspin.build_rev,
- failsafe.images[0].vsd.data.vendor.topspin.build_num,
- failsafe.images[0].vsd.data.vendor.topspin.hw_label);
+ ver_str,
+ vsd->data.vendor.topspin.build_rev,
+ le16_to_cpu(tvdev->failsafe.images[0].vsd.data.vendor.topspin.build_num),
+ vsd->data.vendor.topspin.hw_label);
else
printf(" Primary image is v%s, with label '%s'\n",
- ver_str,
- failsafe.images[0].vsd.data.vendor.topspin.hw_label);
+ ver_str,
+ vsd->data.vendor.topspin.hw_label);
} else
printf(" Primary image is valid, unknown source\n");
+
+ if (verbose > 1)
+ printf(" 0x%08x bytes @ 0x%08x\n",
+ tvdev->failsafe.images[0].size,
+ tvdev->failsafe.images[0].addr);
} else
printf(" Primary image is NOT valid\n");
- if (failsafe.images[1].valid) {
- if (ntohs(failsafe.images[1].vsd.data.signature) == 0x05ad &&
- ntohs(failsafe.images[1].vsd.data.vendor.topspin.signature2) == 0x05ad) {
- unsigned char ver_str[40];
+ if (tvdev->failsafe.images[1].valid) {
+ vsd = &tvdev->failsafe.images[1].vsd;
+ if (be16_to_cpu(vsd->data.signature) == VSD_SIGNATURE_TOPSPIN &&
+ be16_to_cpu(vsd->data.vendor.topspin.signature2) == VSD_SIGNATURE_TOPSPIN) {
+ char ver_str[40];
- create_ver_str(&failsafe.images[1].vsd, ver_str, sizeof(ver_str));
- if (failsafe.images[1].vsd.data.vendor.topspin.build_rev[0])
+ create_ver_str(vsd, ver_str, sizeof(ver_str));
+ if (vsd->data.vendor.topspin.build_rev[0])
printf(" Secondary image is v%s build %s.%d, with label '%s'\n",
- ver_str,
- failsafe.images[1].vsd.data.vendor.topspin.build_rev,
- failsafe.images[1].vsd.data.vendor.topspin.build_num,
- failsafe.images[1].vsd.data.vendor.topspin.hw_label);
+ ver_str,
+ vsd->data.vendor.topspin.build_rev,
+ le16_to_cpu(vsd->data.vendor.topspin.build_num),
+ vsd->data.vendor.topspin.hw_label);
else
printf(" Secondary image is v%s, with label '%s'\n",
- ver_str,
- failsafe.images[1].vsd.data.vendor.topspin.hw_label);
+ ver_str,
+ vsd->data.vendor.topspin.hw_label);
} else
printf(" Secondary image is valid, unknown source\n");
+
+ if (verbose > 1)
+ printf(" 0x%08x bytes @ 0x%08x\n",
+ tvdev->failsafe.images[1].size,
+ tvdev->failsafe.images[1].addr);
} else
printf(" Secondary image is NOT valid\n");
} else
printf(" Firmware is NOT installed in failsafe mode\n");
/* If vpd is present, read it and print it */
- if (tvdev->vpd)
+ if (tvdev->vpd_present)
print_vpd_info(tvdev);
break;
case IDENTIFY_PRIMARY_FIRMWARE_LABEL:
- if (failsafe.valid) {
- if (failsafe.images[0].valid) {
- if (ntohs(failsafe.images[0].vsd.data.signature) == 0x05ad &&
- ntohs(failsafe.images[0].vsd.data.vendor.topspin.signature2) == 0x05ad) {
+ if (tvdev->failsafe.valid) {
+ union vsd *vsd;
+
+ if (tvdev->failsafe.images[0].valid) {
+ vsd = &tvdev->failsafe.images[0].vsd;
+ if (be16_to_cpu(vsd->data.signature) == VSD_SIGNATURE_TOPSPIN &&
+ be16_to_cpu(vsd->data.vendor.topspin.signature2) == VSD_SIGNATURE_TOPSPIN) {
unsigned int build_major = 0, build_minor = 0, build_micro = 0;
- sscanf(failsafe.images[0].vsd.data.vendor.topspin.build_rev, "%u.%u.%u",
- &build_major, &build_minor, &build_micro);
+ sscanf(vsd->data.vendor.topspin.build_rev, "%u.%u.%u",
+ &build_major, &build_minor, &build_micro);
printf("%s:%d:%d:%d:%d:%d:%d:%d:%d:%d\n",
- failsafe.images[0].vsd.data.vendor.topspin.hw_label,
- (failsafe.images[0].vsd.data.vendor.topspin.flags & htonl(VSD_FLAG_AUTOUPGRADE)) ? 1 : 0,
- failsafe.images[0].vsd.data.vendor.topspin.major_ver,
- failsafe.images[0].vsd.data.vendor.topspin.minor_ver,
- ntohs(failsafe.images[0].vsd.data.vendor.topspin.micro_ver),
- failsafe.images[0].vsd.data.vendor.topspin.revision_ver,
- build_major, build_minor, build_micro,
- failsafe.images[0].vsd.data.vendor.topspin.build_num);
+ vsd->data.vendor.topspin.hw_label,
+ (vsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_AUTOUPGRADE)) ? 1 : 0,
+ vsd->data.vendor.topspin.major_ver,
+ vsd->data.vendor.topspin.minor_ver,
+ be16_to_cpu(vsd->data.vendor.topspin.micro_ver),
+ vsd->data.vendor.topspin.revision_ver,
+ build_major, build_minor, build_micro,
+ le16_to_cpu(vsd->data.vendor.topspin.build_num));
} else
printf("Unknown\n");
} else
@@ -1297,26 +1983,15 @@
break;
case IDENTIFY_HARDWARE_LABEL:
/* Print out what we think the firmware label should be */
- switch (identify_board(tvdev)) {
- case BOARD_JAGUAR:
- printf("HCA.Jaguar.%02X\n", revision);
- break;
- case BOARD_COUGAR:
- printf("HCA.Cougar.%02X\n", revision);
- break;
- case BOARD_COUGARCUB:
- printf("HCA.CougarCub.%02X\n", revision);
- break;
- case BOARD_LIONCUB:
- printf("HCA.LionCub.%02X\n", revision);
- break;
- }
-
+ if (tvdev->board->fwlabel)
+ printf("%s.%02X",
+ tvdev->board->fwlabel, tvdev->revision);
+ else
+ printf("Unknown.%02X", tvdev->revision);
break;
}
- release_gpio();
- close_hca();
+ close_hca(tvdev);
return 0;
}
@@ -1324,28 +1999,29 @@
static int identify_hcas(int hca, enum identify_mode identify_mode)
{
struct tvdevice *tvdev;
- int count = 0;
- int ret;
+ int ret = 0, count = 0, unreliable = 0;
if (hca >= 0) {
tvdev = find_device(hca);
if (!tvdev) {
- fprintf(stderr, "couldn't find HCA #%d on the PCI bus\n", hca);
+ fprintf(stderr, "couldn't find HCA #%d on the PCI bus\n",
+ hca);
return 1;
}
- ret = identify_hca(hca, tvdev, identify_mode);
- if (ret)
- return ret;
+ ret = identify_hca(hca, tvdev, identify_mode, &unreliable);
} else {
for (tvdev = tvdevices; tvdev; tvdev = tvdev->next) {
- ret = identify_hca(count++, tvdev, identify_mode);
+ ret = identify_hca(count++, tvdev, identify_mode, &unreliable);
if (ret)
- return ret;
+ break;
}
}
- return 0;
+ if (unreliable)
+ printf("\n(*) Unreliable in recovery mode\n");
+
+ return ret;
}
static int identify_firmware(char *ifname, enum identify_mode identify_mode)
@@ -1355,8 +2031,8 @@
union vsd *vsd = NULL;
/* Read the flash image into the memory */
- if (flash_image_read_from_file(ifname, &isbuf, &isbufsz, &psbuf, &psbufsz,
- &ibuf, &ibufsz))
+ if (flash_image_read_from_file(ifname, &isbuf, &isbufsz, &psbuf,
+ &psbufsz, &ibuf, &ibufsz))
return 1;
vsd = (union vsd *)(psbuf + 0x20);
@@ -1365,25 +2041,26 @@
case IDENTIFY_EXTENDED:
printf("Firmware image %s", ifname);
- if (psbuf && vsd->data.vendor.topspin.flags & htonl(VSD_FLAG_AUTOUPGRADE))
+ if (psbuf && vsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_AUTOUPGRADE))
printf(" (firmware autoupgrade)");
printf("\n");
if (psbuf) {
- if (ntohs(vsd->data.signature) == 0x05ad &&
- ntohs(vsd->data.vendor.topspin.signature2) == 0x05ad) {
- unsigned char ver_str[40];
+ if (be16_to_cpu(vsd->data.signature) == VSD_SIGNATURE_TOPSPIN &&
+ be16_to_cpu(vsd->data.vendor.topspin.signature2) == VSD_SIGNATURE_TOPSPIN) {
+ char ver_str[40];
create_ver_str(vsd, ver_str, sizeof(ver_str));
if (vsd->data.vendor.topspin.build_rev[0])
printf(" Image is v%s build %s.%d, with label '%s'\n",
- ver_str, vsd->data.vendor.topspin.build_rev,
- vsd->data.vendor.topspin.build_num, vsd->data.vendor.topspin.hw_label);
+ ver_str, vsd->data.vendor.topspin.build_rev,
+ le16_to_cpu(vsd->data.vendor.topspin.build_num),
+ vsd->data.vendor.topspin.hw_label);
else
printf(" Image is v%s, with label '%s'\n",
- ver_str,
- vsd->data.vendor.topspin.hw_label);
+ ver_str,
+ vsd->data.vendor.topspin.hw_label);
} else
printf(" Image is valid, unknown source\n");
} else
@@ -1392,22 +2069,22 @@
break;
case IDENTIFY_PRIMARY_FIRMWARE_LABEL:
if (psbuf) {
- if (ntohs(vsd->data.signature) == 0x05ad &&
- ntohs(vsd->data.vendor.topspin.signature2) == 0x05ad) {
+ if (be16_to_cpu(vsd->data.signature) == VSD_SIGNATURE_TOPSPIN &&
+ be16_to_cpu(vsd->data.vendor.topspin.signature2) == VSD_SIGNATURE_TOPSPIN) {
unsigned int build_major = 0, build_minor = 0, build_micro = 0;
sscanf(vsd->data.vendor.topspin.build_rev, "%u.%u.%u",
- &build_major, &build_minor, &build_micro);
+ &build_major, &build_minor, &build_micro);
printf("%s:%d:%d:%d:%d:%d:%d:%d:%d:%d\n",
- vsd->data.vendor.topspin.hw_label,
- (vsd->data.vendor.topspin.flags & htonl(VSD_FLAG_AUTOUPGRADE)) ? 1 : 0,
- vsd->data.vendor.topspin.major_ver,
- vsd->data.vendor.topspin.minor_ver,
- ntohs(vsd->data.vendor.topspin.micro_ver),
- vsd->data.vendor.topspin.revision_ver,
- build_major, build_minor, build_micro,
- vsd->data.vendor.topspin.build_num);
+ vsd->data.vendor.topspin.hw_label,
+ (vsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_AUTOUPGRADE)) ? 1 : 0,
+ vsd->data.vendor.topspin.major_ver,
+ vsd->data.vendor.topspin.minor_ver,
+ be16_to_cpu(vsd->data.vendor.topspin.micro_ver),
+ vsd->data.vendor.topspin.revision_ver,
+ build_major, build_minor, build_micro,
+ le16_to_cpu(vsd->data.vendor.topspin.build_num));
} else
printf("Unknown\n");
} else
@@ -1423,17 +2100,76 @@
return 0;
}
+static int print_hca_guids(int num, struct tvdevice *tvdev)
+{
+ unsigned char guid_node[GUID_LEN];
+ unsigned char guid_port1[GUID_LEN];
+ unsigned char guid_port2[GUID_LEN];
+
+ if (open_hca(tvdev)) {
+ fprintf(stderr, "couldn't open hca %d\n", num);
+ return 1;
+ }
+
+ flash_check_failsafe(tvdev);
+
+ if (flash_get_curr_guids(tvdev, guid_node, guid_port1, guid_port2)) {
+ fprintf(stderr, "Cannot determine previous GUID. Corrupted flash?\n");
+ return 1;
+ }
+
+ printf("HCA #%d\n", num);
+ printf("Node GUID = %02x%02x%02x%02x%02x%02x%02x%02x\n",
+ guid_node[0], guid_node[1], guid_node[2], guid_node[3],
+ guid_node[4], guid_node[5], guid_node[6], guid_node[7]);
+ printf("Port1 GUID = %02x%02x%02x%02x%02x%02x%02x%02x\n",
+ guid_port1[0], guid_port1[1], guid_port1[2], guid_port1[3],
+ guid_port1[4], guid_port1[5], guid_port1[6], guid_port1[7]);
+ if (tvdev->board->num_ports > 1)
+ printf("Port2 GUID = %02x%02x%02x%02x%02x%02x%02x%02x\n",
+ guid_port2[0], guid_port2[1], guid_port2[2], guid_port2[3],
+ guid_port2[4], guid_port2[5], guid_port2[6], guid_port2[7]);
+
+ close_hca(tvdev);
+
+ return 0;
+}
+
+static int print_guids(int hca)
+{
+ struct tvdevice *tvdev;
+ int ret = 0, count = 0;
+
+ if (hca >= 0) {
+ tvdev = find_device(hca);
+ if (!tvdev) {
+ fprintf(stderr, "couldn't find HCA #%d on the PCI bus\n", hca);
+ return 1;
+ }
+
+ ret = print_hca_guids(hca, tvdev);
+ } else {
+ for (tvdev = tvdevices; tvdev; tvdev = tvdev->next) {
+ ret = print_hca_guids(count++, tvdev);
+ if (ret)
+ break;
+ }
+ }
+
+ return ret;
+}
+
/* Download (from HCA to host) */
-static int flash_image_write_to_file(char *fname)
+static int flash_image_write_to_file(struct tvdevice *tvdev, char *fname)
{
char *buffer;
int i, fd;
unsigned int offset;
- buffer = malloc(failsafe.sector_sz);
+ buffer = malloc(tvdev->flash_sector_sz);
if (!buffer) {
fprintf(stderr, "couldn't allocated %d bytes of memory for buffer\n",
- failsafe.sector_sz);
+ tvdev->flash_sector_sz);
return 1;
}
@@ -1448,11 +2184,11 @@
}
offset = 0;
- while (offset < TV_FLASH_SIZE) {
- for (i = 0; i < failsafe.sector_sz; i += 4) {
+ while (offset < tvdev->flash_size) {
+ for (i = 0; i < tvdev->flash_sector_sz; i += 4) {
unsigned int data;
- data = flash_read(offset + i);
+ data = flash_read(tvdev, offset + i);
buffer[i + 0] = (data >> 24) & 0xff;
buffer[i + 1] = (data >> 16) & 0xff;
@@ -1460,9 +2196,9 @@
buffer[i + 3] = data & 0xff;
}
- write(fd, buffer, failsafe.sector_sz);
+ write(fd, buffer, tvdev->flash_sector_sz);
- offset += failsafe.sector_sz;
+ offset += tvdev->flash_sector_sz;
}
close(fd);
@@ -1481,317 +2217,213 @@
return 1;
}
- ret = open_hca(tvdev);
+ if (open_hca(tvdev)) {
+ fprintf(stderr, "couldn't open hca %d\n", hca);
+ return 1;
+ }
- mtflash_init();
- grab_gpio();
+ flash_check_failsafe(tvdev);
- flash_check_failsafe();
+ ret = flash_image_write_to_file(tvdev, ofname);
- ret = flash_image_write_to_file(ofname);
+ close_hca(tvdev);
- release_gpio();
- close_hca();
-
return ret;
}
-/* Upload (from host to HCA) */
-static void flash_move_pps_to_sps(void)
+static void flash_write_block(struct tvdevice *tvdev, unsigned char status,
+ unsigned int addr, unsigned char *buffer, unsigned int buflen)
{
- unsigned int addr, curbar = -1;
+ unsigned int pos = 0, bufsz = buflen;
- flash_chip_reset();
-
- if (verbose)
- curbar = update_status("Failsafe", 0, failsafe.sector_sz, curbar);
-
- flash_erase_sector(failsafe.sector_sz * 2);
-
- for (addr = 0; addr < failsafe.sector_sz; addr += 4) {
- uint32_t data;
+ while (bufsz > 0) {
+ unsigned int len = 16;
int i;
- if (verbose)
- curbar = update_status("Failsafe", addr, failsafe.sector_sz, curbar);
+ flash_set_bank(tvdev, addr);
- data = flash_read(failsafe.sector_sz + addr);
- for (i = 0; i < 4; i++)
- flash_write_byte(failsafe.sector_sz * 2 + addr + i,
- ((data >> ((3 - i) * 8)) & 0xFF));
- }
+ if (len > bufsz)
+ bufsz = len;
- flash_chip_reset();
+ switch (tvdev->flash_command_set) {
+ case CS_SPI:
+ flash_spi_write_block(tvdev, addr, buffer + pos, len);
+ break;
+ default:
+ for (i = 0; i < len; i++)
+ flash_write_byte(tvdev, addr + i, buffer[pos + i]);
+ break;
+ }
+ addr += len;
+ pos += len;
+ bufsz -= len;
- if (verbose) {
- update_status("Failsafe", failsafe.sector_sz, failsafe.sector_sz, curbar);
- printf("\n");
+ if (status)
+ status_update(status, pos);
}
}
-static void flash_write_invariant_sector(unsigned char *isbuf, unsigned int isbufsz)
+/* Upload (from host to HCA) */
+static int flash_compare_invariant_sector(struct tvdevice *tvdev, unsigned char *isbuf,
+ unsigned int isbufsz)
{
- unsigned int addr, curbar = -1;
+ unsigned int addr, data;
- flash_chip_reset();
+ flash_chip_reset(tvdev);
- if (verbose)
- curbar = update_status("Failsafe", 0, isbufsz, curbar);
+ for (addr = 0; addr < isbufsz; addr += 4) {
+ int i;
- flash_erase_sector(0);
-
- for (addr = 0; addr < isbufsz; addr++) {
- if (verbose)
- curbar = update_status("Failsafe", addr, isbufsz, curbar);
-
- flash_write_byte(addr, isbuf[addr]);
+ data = flash_read(tvdev, addr);
+ for (i = 0; i < 4; i++) {
+ if (isbuf[addr + i] != ((data >> ((3 - i) * 8)) & 0xFF))
+ return 1;
+ }
}
- flash_chip_reset();
-
- if (verbose) {
- update_status("Failsafe", isbufsz, isbufsz, curbar);
- printf("\n");
- }
+ return 0;
}
-static void flash_erase_failsafe_sectors(unsigned int psbufoff, unsigned int psbufsz,
- unsigned int ibufoff, unsigned int ibufsz)
+static void flash_move_pps_to_sps(struct tvdevice *tvdev)
{
- unsigned int addr, curbar = -1, totalsz = psbufsz + ibufsz;
+ unsigned int addr;
+ unsigned char *sector;
- flash_chip_reset();
+ flash_chip_reset(tvdev);
- for (addr = 0; addr < psbufsz; addr += failsafe.sector_sz) {
- if (verbose)
- curbar = update_status("Erasing", addr, totalsz, curbar);
-
- flash_erase_sector(psbufoff + addr);
+ sector = malloc(tvdev->flash_sector_sz);
+ if (!sector) {
+ fprintf(stderr, "Unable to allocate %d bytes of memory for buffer\n",
+ tvdev->flash_sector_sz);
+ exit(1);
}
- for (addr = 0; addr < ibufsz; addr += failsafe.sector_sz) {
- if (verbose)
- curbar = update_status("Erasing", psbufsz + addr, totalsz, curbar);
+ for (addr = 0; addr < tvdev->flash_sector_sz; addr += 4) {
+ uint32_t data;
+ int i;
- flash_erase_sector(ibufoff + addr);
+ data = flash_read(tvdev, tvdev->flash_sector_sz + addr);
+ for (i = 0; i < 4; i++)
+ sector[addr + i] = ((data >> ((3 - i) * 8)) & 0xFF);
}
- flash_chip_reset();
+ /* Erase the SPS sector */
+ status_update('E', 0);
+ flash_erase_sector(tvdev, tvdev->flash_sector_sz * 2);
- if (verbose) {
- update_status("Erasing", totalsz, totalsz, curbar);
- printf("\n");
- }
-}
+ /* Write the old PPS as the SPS */
+ flash_write_block(tvdev, 'F', tvdev->flash_sector_sz * 2, sector, tvdev->flash_sector_sz);
+ status_mark();
-static void flash_write_failsafe_image(unsigned int psbufoff, unsigned char *psbuf,
- unsigned int psbufsz, unsigned int ibufoff,
- unsigned char *ibuf, unsigned int ibufsz)
-{
- unsigned int addr, curbar = -1, totalsz = psbufsz + ibufsz;
+ flash_chip_reset(tvdev);
- flash_chip_reset();
-
- /* Set the image offset and size */
- *(uint32_t *)(psbuf + 0x0) = htonl(ibufoff);
- *(uint32_t *)(psbuf + 0x4) = htonl(ibufsz);
-
- /* Set CRC and Signature to something invalid for now */
- *(uint32_t *)(psbuf + 0x8) = 0xFFFFFFFF;
- *(uint16_t *)(psbuf + 0x106) = 0xFFFF;
-
- for (addr = 0; addr < psbufsz; addr++) {
- if (verbose)
- curbar = update_status("Writing", addr, totalsz, curbar);
-
- flash_write_byte(psbufoff + addr, psbuf[addr]);
- }
-
- for (addr = 0; addr < ibufsz; addr++) {
- if (verbose)
- curbar = update_status("Writing", psbufsz + addr, totalsz, curbar);
-
- flash_write_byte(ibufoff + addr, ibuf[addr]);
- }
-
- flash_chip_reset();
-
- if (verbose) {
- update_status("Writing", totalsz, totalsz, curbar);
- printf("\n");
- }
+ free(sector);
}
-static int flash_verify_failsafe_image(unsigned int psbufoff, unsigned char *psbuf,
- unsigned int psbufsz, unsigned int ibufoff,
- unsigned char *ibuf, unsigned int ibufsz)
+static void flash_write_invariant_sector(struct tvdevice *tvdev, unsigned char *isbuf,
+ unsigned int isbufsz)
{
- unsigned int addr, data, curbar = -1, totalsz = psbufsz + ibufsz;
+ flash_chip_reset(tvdev);
- flash_chip_reset();
+ status_update('E', 0);
+ flash_erase_sector(tvdev, 0);
+ flash_write_block(tvdev, 'I', 0, isbuf, isbufsz);
+ status_mark();
- for (addr = 0; addr < ibufsz; addr += 4) {
- int i;
-
- if (verbose)
- curbar = update_status("Verifying", addr, totalsz, curbar);
-
- data = flash_read(ibufoff + addr);
-
- for (i = 0; i < 4; i++) {
- if (ibuf[addr + i] != ((data >> ((3 - i) * 8)) & 0xFF)) {
- if (verbose)
- printf("\n");
-
- return 1;
- }
- }
- }
-
- for (addr = 0; addr < psbufsz; addr += 4) {
- int i;
-
- if (verbose)
- curbar = update_status("Verifying", ibufsz + addr, totalsz, curbar);
-
- data = flash_read(psbufoff + addr);
-
- for (i = 0; i < 4; i++) {
- if (psbuf[addr + i] != ((data >> ((3 - i) * 8)) & 0xFF)) {
- if (verbose)
- printf("\n");
-
- return 1;
- }
- }
- }
-
- if (verbose) {
- update_status("Verifying", totalsz, totalsz, curbar);
- printf("\n");
- }
-
- return 0;
+ flash_chip_reset(tvdev);
}
-static void flash_finish_failsafe(unsigned int psbufoff, unsigned char *psbuf,
- unsigned int psbufsz)
+static void flash_write_pps(struct tvdevice *tvdev, unsigned int psbufoff,
+ unsigned char *psbuf, unsigned int psbufsz, unsigned int ibufoff,
+ unsigned int ibufsz)
{
- int i;
+ /* Set the image offset and size */
+ *(uint32_t *)(psbuf + 0x0) = cpu_to_be32(ibufoff);
+ *(uint32_t *)(psbuf + 0x4) = cpu_to_be32(ibufsz);
- /* Set CRC and Signature to something invalid for now */
- *(uint32_t *)(psbuf + 0x8) = htonl(0x5a445a44);
- *(uint16_t *)(psbuf + 0x106) = htons(flash_crc16(psbuf, 0x104));
+ /* Set signature and CRC to all-ones for now */
+ *(uint32_t *)(psbuf + 0x8) = 0xFFFFFFFF;
+ *(uint16_t *)(psbuf + 0x106) = 0xFFFF;
- /* Write the CRC */
- for (i = 0; i < sizeof(uint16_t); i++)
- flash_write_byte(psbufoff + 0x106 + i, psbuf[0x106 + i]);
+ /* Erase then write the PPS */
+ flash_chip_reset(tvdev);
- /* Write the signature */
- for (i = 0; i < sizeof(uint32_t); i++)
- flash_write_byte(psbufoff + 0x8 + i, psbuf[0x8 + i]);
+ status_update('E', 0);
+ flash_erase_sector(tvdev, psbufoff);
+ flash_write_block(tvdev, 'P', psbufoff, psbuf, psbufsz);
+ status_mark();
+
+ flash_chip_reset(tvdev);
}
-static void flash_erase_sectors(unsigned int ibufsz)
+static void flash_finish_failsafe(struct tvdevice *tvdev, unsigned int psbufoff,
+ unsigned char *psbuf, unsigned int psbufsz)
{
- unsigned int addr, curbar = -1;
+ /* Set signature and CRC to something valid */
+ *(uint32_t *)(psbuf + 0x8) = cpu_to_be32(0x5a445a44);
+ *(uint16_t *)(psbuf + 0x106) = cpu_to_be16(flash_crc16(psbuf, 0x104));
- flash_chip_reset();
+ /* Write CRC and signature */
+ flash_chip_reset(tvdev);
- for (addr = 0; addr < ibufsz; addr += failsafe.sector_sz) {
- if (verbose)
- curbar = update_status("Erasing", addr, ibufsz, curbar);
+ flash_write_block(tvdev, 0, psbufoff + 0x106, psbuf + 0x106, sizeof(uint16_t));
+ flash_write_block(tvdev, 0, psbufoff + 0x8, psbuf + 0x8, sizeof(uint32_t));
- flash_erase_sector(addr);
- }
-
- flash_chip_reset();
-
- if (verbose) {
- update_status("Erasing", ibufsz, ibufsz, curbar);
- printf("\n");
- }
+ flash_chip_reset(tvdev);
}
-static void flash_write_image(unsigned char *ibuf, unsigned int ibufsz)
+static void flash_write_image(struct tvdevice *tvdev, unsigned int ibufoff,
+ unsigned char *ibuf, unsigned int ibufsz)
{
- unsigned int addr, curbar = -1;
+ unsigned int addr;
- flash_chip_reset();
+ /* Erase then write the firmware image */
+ for (addr = 0; addr < ibufsz; addr += tvdev->flash_sector_sz) {
+ unsigned int len = tvdev->flash_sector_sz;
- for (addr = 0; addr < ibufsz; addr++) {
- if (verbose)
- curbar = update_status("Writing", addr, ibufsz, curbar);
+ if (len > ibufsz - addr)
+ len = ibufsz - addr;
- flash_write_byte(addr, ibuf[addr]);
+ status_update('E', 0);
+ flash_erase_sector(tvdev, ibufoff + addr);
+ flash_write_block(tvdev, 'W', ibufoff + addr, ibuf + addr, len);
+ status_mark();
}
- flash_chip_reset();
-
- if (verbose) {
- update_status("Writing", ibufsz, ibufsz, curbar);
- printf("\n");
- }
+ flash_chip_reset(tvdev);
}
-static int flash_verify_image(unsigned char *ibuf, unsigned int ibufsz)
+static unsigned int flash_verify_image(struct tvdevice *tvdev, unsigned int off,
+ unsigned char *buf, unsigned int bufsz)
{
- unsigned int addr, data, curbar = -1;
+ unsigned int addr, data;
- flash_chip_reset();
+ flash_chip_reset(tvdev);
- for (addr = 0; addr < ibufsz; addr += 4) {
+ for (addr = 0; addr < bufsz; addr += 4) {
int i;
- if (verbose)
- curbar = update_status("Verifying", addr, ibufsz, curbar);
+ status_update('V', addr);
- data = flash_read(addr);
-
+ data = flash_read(tvdev, off + addr);
for (i = 0; i < 4; i++) {
- if (ibuf[addr + i] != ((data >> ((3 - i) * 8)) & 0xFF)) {
- if (verbose)
- printf("\n");
-
- return 1;
- }
+ if (buf[addr + i] != ((data >> ((3 - i) * 8)) & 0xFF))
+ return addr + i;
}
}
+ status_mark();
- if (verbose) {
- update_status("Verifying", ibufsz, ibufsz, curbar);
- printf("\n");
- }
-
- return 0;
+ return addr;
}
-static void usage(void)
+static int upload_firmware(int hca, char *ifname, char *guid, char *change_option_cmd)
{
- fprintf(stderr, "Usage: %s [OPTION]...\n", argv0);
- fprintf(stderr, " -q\t\tProduce less output (quieter)\n");
- fprintf(stderr, " -v\t\tProduce more output (verbose)\n");
- fprintf(stderr, " -f\t\tForce operation (use cautiously)\n\n");
- fprintf(stderr, " -c\t\tAlways use PCI config space\n\n");
- fprintf(stderr, " -h <num>\tSelect HCA to use for operation (default: 0)\n");
- fprintf(stderr, "One operation mode must be specified:\n");
- fprintf(stderr, " -i\t\tIdentify HCAs\n");
- fprintf(stderr, " -s <filename>\n\t\tSave firmware programmed on flash device to local file\n");
- fprintf(stderr, " [-d] <filename> [<Node GUID>]\n\t\tDownload firmware to flash device from local file\n\n");
- fprintf(stderr, "When specifying a GUID, use only the lower 24 bits in hexadecimal format.\n");
-
- exit(1);
-}
-
-static int upload_firmware(int hca, char *ifname, char *guid, int autoupgrade)
-{
struct tvdevice *tvdev;
unsigned char *isbuf, *psbuf, *ibuf;
- unsigned int isbufsz, psbufsz, ibufsz;
+ unsigned int isbufsz, psbufsz, ibufsz, addr, status_count;
unsigned char new_guid_node[GUID_LEN], new_guid_port1[GUID_LEN],
- new_guid_port2[GUID_LEN];
- int sector = 0;
- int ret;
+ new_guid_port2[GUID_LEN];
+ int ret = 1, sector = 0, program_is = 0;
tvdev = find_device(hca);
if (!tvdev) {
@@ -1799,16 +2431,13 @@
return 1;
}
- ret = open_hca(tvdev);
- if (ret)
- return ret;
+ if (open_hca(tvdev)) {
+ fprintf(stderr, "couldn't open hca %d\n", hca);
+ return 1;
+ }
- mtflash_init();
- flash_chip_reset();
- grab_gpio();
+ flash_check_failsafe(tvdev);
- flash_check_failsafe();
-
if (guid) {
/* GUIDs given to us on command line */
if (parse_guid(guid, new_guid_node)) {
@@ -1817,40 +2446,46 @@
}
inc_guid(new_guid_node, new_guid_port1);
- inc_guid(new_guid_port1, new_guid_port2);
+ if (tvdev->board->num_ports > 1)
+ inc_guid(new_guid_port1, new_guid_port2);
} else {
/* Preserve the current GUIDs */
- if (flash_get_curr_guids(new_guid_node, new_guid_port1, new_guid_port2)) {
+ if (flash_get_curr_guids(tvdev, new_guid_node, new_guid_port1,
+ new_guid_port2)) {
fprintf(stderr, "Cannot determine previous GUID. Corrupted flash?\n");
fprintf(stderr, "GUID must be specified on command line.\n\n");
usage();
}
/*
- * Now we check the GUIDs to make sure they are valid or could possibly
- * cause some confusion (the default Mellanox GUID)
+ * Now we check the GUIDs to make sure they are valid or
+ * could possibly cause some confusion (the default Mellanox
+ * GUID)
*/
- if ((memcmp(new_guid_node, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0) ||
- (memcmp(new_guid_port1, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0) ||
- (memcmp(new_guid_port2, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0)) {
+ if (memcmp(new_guid_node, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0 ||
+ memcmp(new_guid_port1, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0 ||
+ (tvdev->board->num_ports > 1 &&
+ memcmp(new_guid_port2, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0)) {
fprintf(stderr, "GUIDs read from flash are all zeros. Corrupted flash?\n");
fprintf(stderr, "GUID must be specified on command line.\n\n");
usage();
}
- if ((memcmp(new_guid_node, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0) ||
- (memcmp(new_guid_port1, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0) ||
- (memcmp(new_guid_port2, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0)) {
+ if (memcmp(new_guid_node, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0 ||
+ memcmp(new_guid_port1, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0 ||
+ (tvdev->board->num_ports > 1 &&
+ memcmp(new_guid_port2, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0)) {
fprintf(stderr, "GUIDs read from flash are all ones. Device access error?\n");
fprintf(stderr, "GUID must be specified on command line.\n\n");
usage();
}
- if (((memcmp(new_guid_node, "\x00\x02\xc9\x00\x01\x00\xd0\x50", 8) == 0) ||
- (memcmp(new_guid_port1, "\x00\x02\xc9\x00\x01\x00\xd0\x51", 8) == 0) ||
- (memcmp(new_guid_port2, "\x00\x02\xc9\x00\x01\x00\xd0\x52", 8) == 0)) &&
+ if ((memcmp(new_guid_node, "\x00\x02\xc9\x00\x01\x00\xd0\x50", 8) == 0 ||
+ memcmp(new_guid_port1, "\x00\x02\xc9\x00\x01\x00\xd0\x51", 8) == 0 ||
+ (tvdev->board->num_ports > 1 &&
+ memcmp(new_guid_port2, "\x00\x02\xc9\x00\x01\x00\xd0\x52", 8) == 0)) &&
!force) {
- fprintf(stderr, "GUIDs read from flash are vendor default GUIDs. It is not reccomended\n");
+ fprintf(stderr, "GUIDs read from flash are vendor default GUIDs. It is not recommended\n");
fprintf(stderr, "that these GUIDs be used because of a high chance of GUID conflict.\n");
fprintf(stderr, "Please specify new GUID on command line, or use -f option.\n");
usage();
@@ -1858,8 +2493,8 @@
}
/* Read the flash image into the memory */
- if (flash_image_read_from_file(ifname, &isbuf, &isbufsz, &psbuf, &psbufsz,
- &ibuf, &ibufsz))
+ if (flash_image_read_from_file(ifname, &isbuf, &isbufsz, &psbuf,
+ &psbufsz, &ibuf, &ibufsz))
return 1;
if (psbuf) {
@@ -1867,118 +2502,111 @@
vsd = (union vsd *)(psbuf + 0x20);
- if (ntohs(vsd->data.signature) == 0x05ad &&
- ntohs(vsd->data.vendor.topspin.signature2) == 0x05ad) {
+ if (be16_to_cpu(vsd->data.signature) == VSD_SIGNATURE_TOPSPIN &&
+ be16_to_cpu(vsd->data.vendor.topspin.signature2) == VSD_SIGNATURE_TOPSPIN) {
+ union vsd *fvsd = &tvdev->failsafe.images[0].vsd;
+
/* Update the time the image was flashed */
- vsd->data.vendor.topspin.flashtime = htonl(time(NULL));
+ vsd->data.vendor.topspin.flashtime = cpu_to_be32(time(NULL));
- /* Set any flags */
- if (autoupgrade)
- vsd->data.vendor.topspin.flags |= htonl(VSD_FLAG_AUTOUPGRADE);
- else
- vsd->data.vendor.topspin.flags &= ~htonl(VSD_FLAG_AUTOUPGRADE);
+ /* Set default value, we'll overwrite this if we need to */
+ vsd->data.vendor.topspin.flags |= cpu_to_be32(VSD_FLAG_AUTOUPGRADE);
/* Copy over boot ROM options from old VSD */
- vsd->data.vendor.topspin.flags &= ~htonl(VSD_FLAG_BOOT_OPTIONS);
- vsd->data.vendor.topspin.flags |= (failsafe.images[0].vsd.data.vendor.topspin.flags & htonl(VSD_FLAG_BOOT_OPTIONS));
+ vsd->data.vendor.topspin.flags &= ~cpu_to_be32(VSD_FLAG_BOOT_OPTIONS);
+ vsd->data.vendor.topspin.flags |= (fvsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_BOOT_OPTIONS));
- if (vsd->data.vendor.topspin.flags & htonl(VSD_FLAG_BOOT_OPTIONS)) {
- vsd->data.vendor.topspin.flags &= ~htonl(VSD_FLAG_BOOT_OPTIONS_MASK);
- vsd->data.vendor.topspin.flags |= (failsafe.images[0].vsd.data.vendor.topspin.flags & htonl(VSD_FLAG_BOOT_OPTIONS_MASK));
+ if (vsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_BOOT_OPTIONS)) {
+ vsd->data.vendor.topspin.flags &= ~cpu_to_be32(VSD_FLAG_BOOT_OPTIONS_MASK);
+ vsd->data.vendor.topspin.flags |= (fvsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_BOOT_OPTIONS_MASK));
- vsd->data.vendor.topspin.boot_version = failsafe.images[0].vsd.data.vendor.topspin.boot_version;
- vsd->data.vendor.topspin.boot_port = failsafe.images[0].vsd.data.vendor.topspin.boot_port;
- vsd->data.vendor.topspin.boot_ioc_num = failsafe.images[0].vsd.data.vendor.topspin.boot_ioc_num;
- memcpy(vsd->data.vendor.topspin.boot_dgid, failsafe.images[0].vsd.data.vendor.topspin.boot_dgid,
- sizeof(vsd->data.vendor.topspin.boot_dgid));
- vsd->data.vendor.topspin.boot_service_name[0] = failsafe.images[0].vsd.data.vendor.topspin.boot_service_name[0];
- vsd->data.vendor.topspin.boot_service_name[1] = failsafe.images[0].vsd.data.vendor.topspin.boot_service_name[1];
+ vsd->data.vendor.topspin.boot_version = fvsd->data.vendor.topspin.boot_version;
+ vsd->data.vendor.topspin.boot_port = fvsd->data.vendor.topspin.boot_port;
+ vsd->data.vendor.topspin.boot_ioc_num = fvsd->data.vendor.topspin.boot_ioc_num;
+ memcpy(vsd->data.vendor.topspin.boot_dgid,
+ fvsd->data.vendor.topspin.boot_dgid,
+ sizeof(vsd->data.vendor.topspin.boot_dgid));
+ memcpy(vsd->data.vendor.topspin.boot_service_name,
+ fvsd->data.vendor.topspin.boot_service_name,
+ sizeof(vsd->data.vendor.topspin.boot_service_name));
+ vsd->data.vendor.topspin.boot_pxe_secs = fvsd->data.vendor.topspin.boot_pxe_secs;
} else {
/* Set some sensible defaults */
- vsd->data.vendor.topspin.flags |= htonl(VSD_FLAG_BOOT_OPTIONS |
- VSD_FLAG_BOOT_ENABLE_PORT_1 |
- VSD_FLAG_BOOT_ENABLE_PORT_2 |
- VSD_FLAG_BOOT_ENABLE_SCAN |
- VSD_FLAG_BOOT_TYPE_WELL_KNOWN);
+ vsd->data.vendor.topspin.flags |= cpu_to_be32(VSD_FLAG_BOOT_OPTIONS |
+ VSD_FLAG_BOOT_ENABLE_PORT_1 |
+ VSD_FLAG_BOOT_ENABLE_PORT_2 |
+ VSD_FLAG_BOOT_ENABLE_SCAN |
+ VSD_FLAG_BOOT_TYPE_WELL_KNOWN);
vsd->data.vendor.topspin.boot_version = BOOT_VERSION;
+ vsd->data.vendor.topspin.boot_pxe_secs = BOOT_PXE_SECS_DEFAULT;
}
+ if (change_option_cmd &&
+ parse_change_options(&vsd->data.vendor.topspin, change_option_cmd))
+ return 1;
+
/* Calculate the VSD checksum */
vsd->data.checksum = 0;
- vsd->data.checksum = htons(flash_crc16(vsd->raw, sizeof(vsd->raw)));
+ vsd->data.checksum = cpu_to_be16(flash_crc16(vsd->raw, sizeof(vsd->raw)));
}
- /* Calculate the PPS checksum */
- *(uint16_t *)(psbuf + 0x106) = htons(flash_crc16(psbuf, 0x104));
+ /* PPS checksum will be updated as a final step */
- if (ntohs(vsd->data.signature) == 0x05ad &&
- ntohs(vsd->data.vendor.topspin.signature2) == 0x05ad &&
+ if (be16_to_cpu(vsd->data.signature) == VSD_SIGNATURE_TOPSPIN &&
+ be16_to_cpu(vsd->data.vendor.topspin.signature2) == VSD_SIGNATURE_TOPSPIN &&
!force) {
- unsigned char revision;
- char *incompatible = NULL;
- int board;
+ if (tvdev->board->fwlabel) {
+ char hwlabel[64];
- vpd_read(tvdev, tvdev->pdev);
+ /*
+ * Check to make sure this file is correct for
+ * the hardware. We check only as far as the
+ * hwlabel since boot firmware will have extra
+ * information appended to the label.
+ */
+ snprintf(hwlabel, sizeof(hwlabel), "%s.%02X",
+ tvdev->board->fwlabel, tvdev->revision);
+ if (strncasecmp(vsd->data.vendor.topspin.hw_label, hwlabel, strlen(hwlabel)) != 0) {
+ fprintf(stderr, "Firmware image specified has hardware label '%s', but hardware\n",
+ vsd->data.vendor.topspin.hw_label);
+ fprintf(stderr, "is of type '%s'. Please confirm you are using the correct\n",
+ hwlabel);
+ fprintf(stderr, "firmware or use the force option (-f).\n");
+ return 1;
+ }
+ } else {
+ if (tvdev->flags & FLAG_RECOVERY) {
+ fprintf(stderr, "WARNING: Unable to verify firmware image is appropriate for hardware when\n");
+ fprintf(stderr, "hardware is in flash recovery mode.\n");
+ } else
+ fprintf(stderr, "WARNING: Unable to verify firmware image is appropriate for unknown hardware.\n");
- revision = pci_read_word(tvdev->pdev, PCI_CLASS_REVISION) & 0xff;
-
- /* According to the documentation, a revision of 0x00 is an A0 */
- if (revision == 0x00)
- revision = 0xA0;
-
- board = identify_board(tvdev);
-
- /* Check to make sure this file is correct for the hardware */
- if (board == BOARD_JAGUAR && revision == 0xA0 &&
- strncmp(vsd->data.vendor.topspin.hw_label,
- BOARD_JAGUAR_A0_STR, strlen(BOARD_JAGUAR_A1_STR)) != 0)
- incompatible = BOARD_JAGUAR_A0_STR;
- else if (board == BOARD_JAGUAR && revision == 0xA1 &&
- strncmp(vsd->data.vendor.topspin.hw_label,
- BOARD_JAGUAR_A1_STR, strlen(BOARD_JAGUAR_A1_STR)) != 0)
- incompatible = BOARD_JAGUAR_A1_STR;
- else if (board == BOARD_COUGAR && revision == 0xA1 &&
- strncmp(vsd->data.vendor.topspin.hw_label,
- BOARD_COUGAR_A1_STR, strlen(BOARD_COUGAR_A1_STR)) != 0)
- incompatible = BOARD_COUGAR_A1_STR;
- else if (board == BOARD_COUGARCUB && revision == 0xA1 &&
- strncmp(vsd->data.vendor.topspin.hw_label,
- BOARD_COUGARCUB_A1_STR, strlen(BOARD_COUGARCUB_A1_STR)) != 0)
- incompatible = BOARD_COUGARCUB_A1_STR;
- else if (board == BOARD_LIONCUB && revision == 0xA0 &&
- strncmp(vsd->data.vendor.topspin.hw_label,
- BOARD_LIONCUB_A0_STR, strlen(BOARD_LIONCUB_A0_STR)) != 0)
- incompatible = BOARD_LIONCUB_A0_STR;
-
- if (incompatible) {
- fprintf(stderr, "Firmware image specified has hardware label '%s', but hardware\n", vsd->data.vendor.topspin.hw_label);
- fprintf(stderr, "is of type '%s'. Please confirm you are using the correct\n", incompatible);
- fprintf(stderr, "firmware or use the force option (-f).\n");
- return 1;
+ fprintf(stderr, "Will upload flash image in 20 seconds or hit Ctrl-C to exit.\n");
+ sleep(20);
}
}
- if (failsafe.valid) {
+ if (tvdev->failsafe.valid) {
/* We'll always use the space opposite of the PPS */
- if (failsafe.images[0].addr + failsafe.images[0].size < TV_FLASH_SIZE / 2)
- sector = (TV_FLASH_SIZE / 2) / failsafe.sector_sz;
- else if (failsafe.images[0].addr >= failsafe.sector_sz * 3 + ibufsz)
+ if (tvdev->failsafe.images[0].addr + tvdev->failsafe.images[0].size < tvdev->flash_size / 2)
+ sector = (tvdev->flash_size / 2) / tvdev->flash_sector_sz;
+ else if (tvdev->failsafe.images[0].addr >= tvdev->flash_sector_sz * 3 + ibufsz)
sector = 3;
else {
- fprintf(stderr, "Unable to fit new image (size 0x%x) on flash in Failsafe mode\n", ibufsz);
+ fprintf(stderr, "Unable to fit new image (size 0x%x) on flash in Failsafe mode\n",
+ ibufsz);
exit(1);
}
- } else {
+ } else
/* No Invariant Sector yet (will be programmed below) */
sector = 3;
- }
- } else if (ibufsz > TV_FLASH_SIZE) {
+ } else if (ibufsz > tvdev->flash_size) {
fprintf(stderr, "Image size is larger than size of flash (0x%X)\n",
- TV_FLASH_SIZE);
+ tvdev->flash_size);
return 1;
}
- if (failsafe.valid && !psbuf) {
+ if (tvdev->failsafe.valid && !psbuf) {
if (!force) {
/* Flash is in Failsafe mode, but image doesn't have Failsafe information */
printf("Flash is in failsafe mode, but image is not a failsafe firmware image.\n");
@@ -1992,59 +2620,292 @@
}
}
- if (flash_guids_update(ibuf, ibufsz, new_guid_node, new_guid_port1, new_guid_port2))
+ if (flash_guids_update(tvdev, ibuf, ibufsz, new_guid_node,
+ new_guid_port1, new_guid_port2))
return 1;
- printf("Programming HCA Microcode... Flash Image Size = %d\n", ibufsz);
+ /* Compare the currently programmed IS with the IS from the file */
+ if (isbuf) {
+ if (force > 1) {
+ /* User specified -ff, always upgrade IS */
+ if (tvdev->failsafe.valid) {
+ /* But warn if the firmware is already in failsafe mode, just in case */
+ printf("WARNING: Flash reprogramming won't be failsafe, continuing in 10 seconds\n");
+ sleep(10);
+ }
- if (!failsafe.valid && isbuf)
+ program_is = 1;
+ } else if (flash_compare_invariant_sector(tvdev, isbuf, isbufsz) != 0) {
+ /* IS is out-of-date, so we need to upgrade it */
+ printf("WARNING: Out-of-date Invariant sector found. Flash reprogramming won't be\n");
+ printf("failsafe, continuing in 10 seconds\n");
+ sleep(10);
+ program_is = 1;
+ } else if (!tvdev->failsafe.valid)
+ /* Not in failsafe, so it's safe to silently program the IS */
+ program_is = 1;
+ }
+
+ printf("Programming HCA firmware... Flash Image Size = %d\n", ibufsz);
+
+ if (psbuf) {
+ status_count = psbufsz + ibufsz + psbufsz + ibufsz;
+ if (tvdev->failsafe.images[0].valid)
+ status_count += tvdev->flash_sector_sz;
+ } else
+ status_count = ibufsz + ibufsz;
+
+ if (program_is) {
/* Program the Invariant Sector first */
- flash_write_invariant_sector(isbuf, isbufsz);
+ status_start(status_count + isbufsz + isbufsz);
+ flash_write_invariant_sector(tvdev, isbuf, isbufsz);
+ addr = flash_verify_image(tvdev, 0, isbuf, isbufsz);
+ if (addr < isbufsz) {
+ status_stop();
+ printf("Flash verify of IS FAILED @ %d (%d total)\n",
+ addr, isbufsz);
+ ret = 1;
+ goto verify_failed;
+ }
+ } else
+ status_start(status_count);
+
if (psbuf) {
- if (failsafe.images[0].valid)
- /* Move the PPS to the SPS */
- flash_move_pps_to_sps();
+ if (tvdev->failsafe.images[0].valid)
+ flash_move_pps_to_sps(tvdev);
- /* Erase all of the sectors we'll be writing into */
- flash_erase_failsafe_sectors(failsafe.sector_sz, psbufsz,
- sector * failsafe.sector_sz, ibufsz);
- /* Write the PPS and the image */
- flash_write_failsafe_image(failsafe.sector_sz, psbuf, psbufsz,
- sector * failsafe.sector_sz, ibuf, ibufsz);
- /* Verify the PPS and the image */
- if (flash_verify_failsafe_image(failsafe.sector_sz, psbuf, psbufsz,
- sector * failsafe.sector_sz, ibuf, ibufsz))
+ /* Write the PPS and image */
+ flash_write_pps(tvdev, tvdev->flash_sector_sz, psbuf, psbufsz,
+ sector * tvdev->flash_sector_sz, ibufsz);
+ flash_write_image(tvdev, sector * tvdev->flash_sector_sz, ibuf, ibufsz);
+
+ /* Verify the PPS and image */
+ addr = flash_verify_image(tvdev, tvdev->flash_sector_sz, psbuf, psbufsz);
+ if (addr < psbufsz) {
+ status_stop();
+ printf("Flash verify of PPS FAILED @ %d (%d total)\n",
+ addr, psbufsz);
+ ret = 1;
goto verify_failed;
+ }
+ addr = flash_verify_image(tvdev, sector * tvdev->flash_sector_sz, ibuf, ibufsz);
+ if (addr < ibufsz) {
+ status_stop();
+ printf("Flash verify of image FAILED @ %d (%d total)\n",
+ addr, ibufsz);
+ ret = 1;
+ goto verify_failed;
+ }
+
/* Finish writing the PPS */
- flash_finish_failsafe(failsafe.sector_sz, psbuf, psbufsz);
+ flash_finish_failsafe(tvdev, tvdev->flash_sector_sz, psbuf, psbufsz);
} else {
- flash_erase_sectors(ibufsz);
- flash_write_image(ibuf, ibufsz);
- if (flash_verify_image(ibuf, ibufsz))
+ flash_write_image(tvdev, 0, ibuf, ibufsz);
+ addr = flash_verify_image(tvdev, 0, ibuf, ibufsz);
+ if (addr < ibufsz) {
+ status_stop();
+ printf("Flash verify of image FAILED @ %d (%d total)\n",
+ addr, ibufsz);
+ ret = 1;
goto verify_failed;
+ }
}
+ status_stop();
+
+ ret = 0;
+
printf("Flash verify passed!\n");
- release_gpio();
- close_hca();
+verify_failed:
+ close_hca(tvdev);
+ return ret;
+}
+
+static int modify_options(int hca, char *change_option_cmd)
+{
+ struct tvdevice *tvdev;
+ union vsd *vsd;
+ unsigned char *psbuf;
+ int i;
+
+ tvdev = find_device(hca);
+ if (!tvdev) {
+ fprintf(stderr, "couldn't find HCA #%d on the PCI bus\n", hca);
+ return 1;
+ }
+
+ if (open_hca(tvdev)) {
+ fprintf(stderr, "couldn't open hca %d\n", hca);
+ return 1;
+ }
+
+ flash_check_failsafe(tvdev);
+
+ psbuf = malloc(tvdev->flash_sector_sz);
+ if (!psbuf) {
+ fprintf(stderr, "couldn't allocate temp buffer for PPS/SPS (size = %d)\n",
+ tvdev->flash_sector_sz);
+ exit(1);
+ }
+
+ for (i = 0; i < tvdev->flash_sector_sz; i += 4)
+ *(uint32_t *)(psbuf + i) = be32_to_cpu(flash_read(tvdev, tvdev->flash_sector_sz + i));
+
+ vsd = (union vsd *)(psbuf + 0x20);
+
+ if (be16_to_cpu(vsd->data.signature) != VSD_SIGNATURE_TOPSPIN ||
+ be16_to_cpu(vsd->data.vendor.topspin.signature2) != VSD_SIGNATURE_TOPSPIN) {
+ /* Not out VSD format, so nothing to print */
+ printf("error: VSD not in Topspin format\n");
+ return 1;
+ }
+
+ fixup_topspin_vsd(&vsd->data.vendor.topspin);
+
+ if (change_option_cmd[0] == 0) {
+ if (vsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_AUTOUPGRADE))
+ printf(" auto_upgrade=yes\n");
+ else
+ printf(" auto_upgrade=no\n");
+
+ if (vsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_BOOT_ENABLE_PORT_1))
+ printf(" boot_enable_port_1=yes\n");
+ else
+ printf(" boot_enable_port_1=no\n");
+
+ if (vsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_BOOT_ENABLE_PORT_2))
+ printf(" boot_enable_port_2=yes\n");
+ else
+ printf(" boot_enable_port_2=no\n");
+
+ if (!(vsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_BOOT_ENABLE_SCAN)))
+ printf(" boot_service_scan=no\n");
+
+ if (vsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_BOOT_WAIT_ON_ERROR))
+ printf(" boot_wait_on_error=yes\n");
+ else
+ printf(" boot_wait_on_error=no\n");
+
+ if (vsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_BOOT_TRY_FOREVER))
+ printf(" boot_try_forever=yes\n");
+ else
+ printf(" boot_try_forever=no\n");
+
+ switch (be32_to_cpu(vsd->data.vendor.topspin.flags) & VSD_FLAG_BOOT_TYPE) {
+ case VSD_FLAG_BOOT_TYPE_WELL_KNOWN:
+ printf(" boot_type=well_known\n");
+ break;
+ case VSD_FLAG_BOOT_TYPE_SAVED:
+ printf(" boot_type=saved\n");
+ break;
+ case VSD_FLAG_BOOT_TYPE_PXE:
+ printf(" boot_type=pxe\n");
+ break;
+ case VSD_FLAG_BOOT_TYPE_DISABLE:
+ printf(" boot_type=disable\n");
+ break;
+ default:
+ printf(" boot_type=unknown\n");
+ break;
+ }
+
+ printf(" boot_saved_port=%d\n", vsd->data.vendor.topspin.boot_port);
+ printf(" boot_saved_ioc_num=%d\n", vsd->data.vendor.topspin.boot_ioc_num);
+ printf(" boot_saved_dgid=%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
+ vsd->data.vendor.topspin.boot_dgid[0], vsd->data.vendor.topspin.boot_dgid[1],
+ vsd->data.vendor.topspin.boot_dgid[2], vsd->data.vendor.topspin.boot_dgid[3],
+ vsd->data.vendor.topspin.boot_dgid[4], vsd->data.vendor.topspin.boot_dgid[5],
+ vsd->data.vendor.topspin.boot_dgid[6], vsd->data.vendor.topspin.boot_dgid[7],
+ vsd->data.vendor.topspin.boot_dgid[8], vsd->data.vendor.topspin.boot_dgid[9],
+ vsd->data.vendor.topspin.boot_dgid[10], vsd->data.vendor.topspin.boot_dgid[11],
+ vsd->data.vendor.topspin.boot_dgid[12], vsd->data.vendor.topspin.boot_dgid[13],
+ vsd->data.vendor.topspin.boot_dgid[14], vsd->data.vendor.topspin.boot_dgid[15]);
+ printf(" boot_saved_service_name=%02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
+ vsd->data.vendor.topspin.boot_service_name[0],
+ vsd->data.vendor.topspin.boot_service_name[1],
+ vsd->data.vendor.topspin.boot_service_name[2],
+ vsd->data.vendor.topspin.boot_service_name[3],
+ vsd->data.vendor.topspin.boot_service_name[4],
+ vsd->data.vendor.topspin.boot_service_name[5],
+ vsd->data.vendor.topspin.boot_service_name[6],
+ vsd->data.vendor.topspin.boot_service_name[7]);
+ printf(" boot_pxe_secs=%d\n", vsd->data.vendor.topspin.boot_pxe_secs);
+ } else {
+ if (parse_change_options(&vsd->data.vendor.topspin, change_option_cmd))
+ return 1;
+
+ /* Calculate the VSD checksum */
+ vsd->data.checksum = 0;
+ vsd->data.checksum = cpu_to_be16(flash_crc16(vsd->raw, sizeof(vsd->raw)));
+
+ /* Set signature and CRC to all-ones for now */
+ *(uint32_t *)(psbuf + 0x8) = 0xFFFFFFFF;
+ *(uint16_t *)(psbuf + 0x106) = 0xFFFF;
+
+ flash_chip_reset(tvdev);
+
+ status_start(tvdev->flash_sector_sz);
+
+ status_update('E', 0);
+ flash_erase_sector(tvdev, tvdev->flash_sector_sz);
+ flash_write_block(tvdev, 'F', tvdev->flash_sector_sz, psbuf, tvdev->flash_sector_sz);
+ status_mark();
+
+ flash_chip_reset(tvdev);
+
+ flash_finish_failsafe(tvdev, tvdev->flash_sector_sz, psbuf, tvdev->flash_sector_sz);
+
+ status_stop();
+ }
+
+ free(psbuf);
+
+ close_hca(tvdev);
+
return 0;
+}
-verify_failed:
- printf("Flash verify failed!\n");
+static void usage(void)
+{
+ fprintf(stderr, "Usage: %s [OPTION]...\n", argv0);
+ fprintf(stderr, " -q\t\tProduce less output (quieter)\n");
+ fprintf(stderr, " -v\t\tProduce more output (verbose)\n");
+ fprintf(stderr, " -f\t\tForce operation (use cautiously)\n");
+ fprintf(stderr, " -p\t\tUser PCI config space access instead of memory mapping\n");
+ fprintf(stderr, " -h <num>\tSelect HCA to use for operation (default: 0)\n");
+ fprintf(stderr, " -o [<cmd>]\tChange options command (no command shows current values)\n");
+ fprintf(stderr, " The following commands and values are accepted:\n");
+ fprintf(stderr, " auto_upgrade [yes|no]\n");
+ fprintf(stderr, " boot_enable_port1 [yes|no]\n");
+ fprintf(stderr, " boot_enable_port2 [yes|no]\n");
+ fprintf(stderr, " boot_wait_on_error [yes|no]\n");
+ fprintf(stderr, " boot_try_forever [yes|no]\n");
+ fprintf(stderr, " boot_type [well_known|saved|pxe|disable]\n");
+ fprintf(stderr, " boot_saved_port [0|1|2]\n");
+ fprintf(stderr, " boot_saved_ioc_num ##\n");
+ fprintf(stderr, " boot_saved_dgid ####:####:####:####:####:####:####:####\n");
+ fprintf(stderr, " boot_saved_service_name ####:####:####:####\n");
+ fprintf(stderr, " boot_pxe_secs ##\n");
+ fprintf(stderr, " -u\t\tDisable autoupgrade of firmware (-o auto_upgrade=no)\n\n");
- release_gpio();
- close_hca();
+ fprintf(stderr, "One operation mode must be specified:\n");
+ fprintf(stderr, " -i\t\tIdentify HCAs\n");
+ fprintf(stderr, " -g\t\tPrint GUIDs programmed into firmware\n");
+ fprintf(stderr, " -s <filename>\n\t\tSave firmware programmed on flash device to local file\n");
+ fprintf(stderr, " [-d] <filename> [<Node GUID>]\n\t\tDownload firmware to flash device from local file\n\n");
- return 1;
+ fprintf(stderr, "When specifying a GUID, use only the lower 24 bits in hexadecimal format.\n");
+
+ exit(1);
}
int main(int argc, char *argv[])
{
- char *filename = NULL, *guid = NULL;
+ char *filename = NULL, *guid = NULL, *change_option_cmd = NULL;
struct winsize winsize;
struct pci_access *pacc;
enum operation operation = OP_NONE;
@@ -2057,13 +2918,14 @@
if (sizeof(vsd.data) != sizeof(vsd.raw)) {
extern void __sizeof_vsd_data_doesnt_equal_sizeof_vsd_raw();
+
__sizeof_vsd_data_doesnt_equal_sizeof_vsd_raw();
}
}
/* Figure out the size of the window, but fall back if we can't */
if (ioctl(0, TIOCGWINSZ, &winsize) < 0)
- cols = 0;
+ cols = 80;
else
cols = winsize.ws_col;
@@ -2072,7 +2934,7 @@
while (1) {
int c;
- c = getopt(argc, argv, "qvfcuh:i::s:d:");
+ c = getopt(argc, argv, "qvfupgh:i::s:d:o::");
if (c == -1)
break;
@@ -2084,14 +2946,14 @@
verbose++;
break;
case 'f':
- force = 1;
+ force++;
break;
- case 'c':
- config = 1;
- break;
case 'u':
autoupgrade = 0;
break;
+ case 'p':
+ use_config_space = 1;
+ break;
case 'h': {
char *p;
@@ -2103,7 +2965,7 @@
hca = (unsigned int)ret;
break;
- }
+ }
case 'i':
if (operation != OP_NONE) {
fprintf(stderr, "multiple operations specified on command line\n");
@@ -2119,12 +2981,21 @@
else if (strcasecmp(optarg, "hwlabel") == 0)
identify_mode = IDENTIFY_HARDWARE_LABEL;
else {
- fprintf(stderr, "unknown identify mode '%s'\n", optarg);
+ fprintf(stderr, "unknown identify mode '%s'\n",
+ optarg);
usage();
}
} else
identify_mode = IDENTIFY_EXTENDED;
break;
+ case 'g':
+ if (operation != OP_NONE) {
+ fprintf(stderr, "multiple operations specified on command line\n");
+ usage();
+ }
+
+ operation = OP_PRINT_GUIDS;
+ break;
case 's':
if (operation != OP_NONE) {
fprintf(stderr, "multiple operations specified on command line\n");
@@ -2135,7 +3006,7 @@
filename = optarg;
break;
case 'd':
- if (operation != OP_NONE) {
+ if (operation != OP_NONE && operation != OP_MODIFY_OPTIONS) {
fprintf(stderr, "multiple operations specified on command line\n");
usage();
}
@@ -2143,24 +3014,41 @@
operation = OP_UPLOAD; /* Download firmware to HCA */
filename = optarg;
break;
+ case 'o':
+ if (operation != OP_NONE && operation != OP_UPLOAD) {
+ fprintf(stderr, "multiple operations specified on command line\n");
+ usage();
+ }
+
+ if (optarg)
+ change_option_cmd = optarg;
+ else
+ change_option_cmd = "";
+
+ /* operation will be set below */
+ break;
}
}
if (operation == OP_NONE) {
- /* Default to OP_UPLOAD, but we need a filename argument */
- if (optind >= argc)
- usage();
+ if (change_option_cmd) {
+ operation = OP_MODIFY_OPTIONS;
+ } else {
+ /* Default to OP_UPLOAD, but we need a filename argument */
+ if (optind >= argc)
+ usage();
- operation = OP_UPLOAD; /* Download firmware to HCA */
- filename = argv[optind++];
+ operation = OP_UPLOAD; /* Download firmware to HCA */
+ filename = argv[optind++];
+ }
}
/* The upload operation can take an optional GUID argument too */
- if (optind < argc && (operation == OP_UPLOAD))
+ if (optind < argc && operation == OP_UPLOAD)
guid = argv[optind++];
/* Identify operation can take an optional filename argument here */
- if (optind < argc && (operation == OP_IDENTIFY)) {
+ if (optind < argc && operation == OP_IDENTIFY) {
filename = argv[optind++];
if (filename && identify_mode == IDENTIFY_HARDWARE_LABEL) {
fprintf(stderr, "cannot print hardware label for firmware image file\n");
@@ -2168,25 +3056,59 @@
}
}
+ /* Change option command can take an optional filename argument here */
+ if (optind < argc && change_option_cmd && change_option_cmd[0] == 0)
+ change_option_cmd = argv[optind++];
+
+ /* Set change_option_cmd correctly */
+ if (!autoupgrade) {
+ if (change_option_cmd && change_option_cmd[0] != 0) {
+ size_t len = strlen(change_option_cmd) + strlen("auto_upgrade=off") + 1;
+ char *p;
+
+ p = malloc(len);
+ if (!p) {
+ fprintf(stderr, "Unable to allocate %Zd bytes for change_option_cmd\n",
+ len);
+ exit(1);
+ }
+
+ snprintf(p, len - 1, "%s,auto_upgrade=off",
+ change_option_cmd);
+ change_option_cmd = p;
+ } else
+ change_option_cmd = "auto_upgrade=off";
+ }
+
pacc = pci_alloc();
pci_init(pacc);
pci_scan_bus(pacc);
- scan_devices(pacc);
-
switch (operation) {
case OP_IDENTIFY:
if (filename)
ret = identify_firmware(filename, identify_mode);
- else
+ else {
+ scan_devices(pacc);
ret = identify_hcas(hca, identify_mode);
+ }
break;
+ case OP_PRINT_GUIDS:
+ scan_devices(pacc);
+ ret = print_guids(hca);
+ break;
case OP_DOWNLOAD:
+ scan_devices(pacc);
ret = download_firmware(hca >= 0 ? hca : 0, filename);
break;
case OP_UPLOAD:
- ret = upload_firmware(hca >= 0 ? hca : 0, filename, guid, autoupgrade);
+ scan_devices(pacc);
+ ret = upload_firmware(hca >= 0 ? hca : 0, filename, guid, change_option_cmd);
break;
+ case OP_MODIFY_OPTIONS:
+ scan_devices(pacc);
+ ret = modify_options(hca >= 0 ? hca : 0, change_option_cmd);
+ break;
default:
fprintf(stderr, "ERROR: Invalid operation %d\n", operation);
ret = 1;
More information about the ewg
mailing list