summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2007-04-30 21:22:57 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2007-04-30 21:22:57 +0000
commit007c6a5784d0e02da828d0a265692bc4dd94b284 (patch)
tree44b04bb5b0d39c377f9425997c3b6c2fc373283f
parent9fbaf12fca8954c2600f43198734144f9d6f2940 (diff)
initial code for firmware loading and initialization. it is used by
the reset function and will be used later to load an alternative/updated firmware image and bootloader from disk if the images from the flash are not supported by the driver.
-rw-r--r--sys/dev/pci/if_nx.c258
-rw-r--r--sys/dev/pci/if_nxreg.h65
2 files changed, 285 insertions, 38 deletions
diff --git a/sys/dev/pci/if_nx.c b/sys/dev/pci/if_nx.c
index 7087b540611..7c430beb479 100644
--- a/sys/dev/pci/if_nx.c
+++ b/sys/dev/pci/if_nx.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_nx.c,v 1.25 2007/04/30 13:26:19 reyk Exp $ */
+/* $OpenBSD: if_nx.c,v 1.26 2007/04/30 21:22:56 reyk Exp $ */
/*
* Copyright (c) 2007 Reyk Floeter <reyk@openbsd.org>
@@ -81,6 +81,18 @@ int nx_debug = 0;
#define DPRINTF(_lvl, arg...)
#endif
+#ifdef notyet
+/*
+ * The NetXen firmware and bootloader is about 800k big, don't even try
+ * to load the alternative version from disk with small kernels used by
+ * the install media. The driver can still try to use the primary firmware
+ * and bootloader found in the controller's flash memory.
+ */
+#ifndef SMALL_KERNEL
+#define NXB_LOADFIRMWARE
+#endif
+#endif
+
struct nx_softc;
struct nxb_port {
@@ -108,12 +120,17 @@ struct nxb_softc {
pci_intr_handle_t sc_ih;
- int sc_window;
- int sc_state;
- struct nxb_info sc_nxbinfo;
- u_int32_t sc_fwmajor;
- u_int32_t sc_fwminor;
- u_int32_t sc_fwbuild;
+ u_int sc_flags;
+#define NXFLAG_FWINVALID (1<<0) /* update firmware from disk */
+
+ struct nxb_info sc_nxbinfo; /* Information from flash */
+ struct nxb_imageinfo sc_nxbimage; /* Image info from flash */
+
+ int sc_window; /* SW memory window */
+ int sc_state; /* Firmware state */
+ u_int32_t sc_fwmajor; /* Load image major rev */
+ u_int32_t sc_fwminor; /* Load image minor rev */
+ u_int32_t sc_fwbuild; /* Load image build rev */
u_int32_t sc_nrxbuf;
u_int32_t sc_ntxbuf;
@@ -138,7 +155,13 @@ struct nx_softc {
int nxb_match(struct device *, void *, void *);
void nxb_attach(struct device *, struct device *, void *);
int nxb_query(struct nxb_softc *sc);
+int nxb_booted(struct nxb_softc *sc);
void nxb_mountroot(void *);
+int nxb_loadfirmware(struct nxb_softc *, struct nxb_firmware_header *,
+ u_int8_t **, size_t *);
+int nxb_reloadfirmware(struct nxb_softc *, struct nxb_firmware_header *,
+ u_int8_t **, size_t *);
+void nxb_reset(struct nxb_softc *);
u_int32_t nxb_read(struct nxb_softc *, bus_size_t);
void nxb_write(struct nxb_softc *, bus_size_t, u_int32_t);
@@ -457,16 +480,19 @@ nxb_query(struct nxb_softc *sc)
/* Make sure that the serial number is a NUL-terminated string */
nu->nu_serial_num[31] = '\0';
+ /* Copy flash image information */
+ bcopy(&nu->nu_image, &sc->sc_nxbimage, sizeof(sc->sc_nxbimage));
+
#ifdef NX_DEBUG
#define _NXBUSER(_e) do { \
if (nx_debug & NXDBG_FLASH) \
printf("%s: %s: 0x%08x (%u)\n", \
sc->sc_dev.dv_xname, #_e, nu->_e, nu->_e); \
} while (0)
- _NXBUSER(nu_bootloader_ver);
- _NXBUSER(nu_bootloader_size);
- _NXBUSER(nu_image_ver);
- _NXBUSER(nu_image_size);
+ _NXBUSER(nu_image.nim_bootld_ver);
+ _NXBUSER(nu_image.nim_bootld_size);
+ _NXBUSER(nu_image.nim_image_ver);
+ _NXBUSER(nu_image.nim_image_size);
_NXBUSER(nu_primary);
_NXBUSER(nu_secondary);
_NXBUSER(nu_subsys_id);
@@ -495,6 +521,18 @@ nxb_query(struct nxb_softc *sc)
return (0);
}
+int
+nxb_booted(struct nxb_softc *sc)
+{
+ if (nxb_wait(sc, NXSW_CMDPEG_STATE,
+ NXSW_CMDPEG_INIT_DONE, NXSW_CMDPEG_STATE_M, 1, 2000000) != 0) {
+ printf("%s: bootstrap failed, code 0x%x\n",
+ sc->sc_dev.dv_xname, nxb_read(sc, NXSW_CMDPEG_STATE));
+ return (-1);
+ }
+ return (0);
+}
+
void
nxb_mountroot(void *arg)
{
@@ -505,13 +543,8 @@ nxb_mountroot(void *arg)
/*
* Poll the status of the running firmware.
*/
- if (nxb_wait(sc, NXSW_CMDPEG_STATE,
- NXSW_CMDPEG_INIT_DONE, NXSW_CMDPEG_STATE_M, 1, 2000000) != 0) {
- printf("%s: bootstrap failed, code 0x%x\n",
- sc->sc_dev.dv_xname,
- nxb_read(sc, NXSW_CMDPEG_STATE));
+ if (nxb_booted(sc) != 0)
return;
- }
/*
* Get and validate the loaded firmware version
@@ -523,15 +556,13 @@ nxb_mountroot(void *arg)
sc->sc_fwmajor, sc->sc_fwminor, sc->sc_fwbuild);
if (sc->sc_fwmajor != NX_FIRMWARE_MAJOR ||
sc->sc_fwminor != NX_FIRMWARE_MINOR) {
- /*
- * XXX The driver should load an alternative firmware image
- * XXX from disk if the firmware image in the flash is not
- * XXX supported by the driver.
- */
printf(", requires %u.%u.xx (%u.%u.%u)\n",
NX_FIRMWARE_MAJOR, NX_FIRMWARE_MINOR,
NX_FIRMWARE_MAJOR, NX_FIRMWARE_MINOR,
NX_FIRMWARE_BUILD);
+
+ sc->sc_flags |= NXFLAG_FWINVALID;
+ nxb_reset(sc);
return;
}
printf("\n");
@@ -540,6 +571,189 @@ nxb_mountroot(void *arg)
sc->sc_state = NX_S_READY;
}
+int
+nxb_loadfirmware(struct nxb_softc *sc, struct nxb_firmware_header *fh,
+ u_int8_t **fw, size_t *fwlen)
+{
+#ifdef NXB_LOADFIRMWARE
+ u_int8_t *mem;
+ size_t memlen;
+
+ /*
+ * Load a supported bootloader and firmware image from disk
+ */
+ if (loadfirmware("nxb", &mem, &memlen) != 0)
+ return (-1);
+
+ if ((memlen) < sizeof(*fh))
+ goto fail;
+ bcopy(mem, fh, sizeof(*fh));
+ if (ntohl(fh->fw_hdrver) != NX_FIRMWARE_HDRVER)
+ goto fail;
+
+ *fw = mem;
+ *fwlen = memlen;
+
+ return (0);
+ fail:
+ free(mem, M_DEVBUF);
+#endif
+ return (-1);
+}
+
+int
+nxb_reloadfirmware(struct nxb_softc *sc, struct nxb_firmware_header *fh,
+ u_int8_t **fw, size_t *fwlen)
+{
+ u_int8_t *mem;
+ size_t memlen;
+ u_int32_t addr, *data;
+ u_int i;
+
+ /*
+ * Load the images from flash, setup a fake firmware header
+ */
+ memlen = sc->sc_nxbimage.nim_bootld_size + sizeof(*fh);
+ mem = (u_int8_t *)malloc(memlen, M_DEVBUF, M_NOWAIT);
+ if (mem == NULL)
+ return (-1);
+
+ fh->fw_hdrver = htonl(NX_FIRMWARE_HDRVER);
+ fh->fw_image_ver = htonl(sc->sc_nxbimage.nim_image_ver);
+ fh->fw_image_size = 0; /* Reload firmware image from flash */
+ fh->fw_bootld_ver = htonl(sc->sc_nxbimage.nim_bootld_ver);
+ fh->fw_bootld_size = htonl(sc->sc_nxbimage.nim_bootld_size);
+ bcopy(fh, mem, sizeof(*fh));
+
+ addr = NXFLASHMAP_BOOTLOADER;
+ data = (u_int32_t *)(mem + sizeof(*fh));
+ for (i = 0; i < (sc->sc_nxbimage.nim_bootld_size / 4); i++) {
+ if (nxb_read_rom(sc, addr, data) != 0)
+ goto fail;
+ addr += sizeof(u_int32_t);
+ data++;
+ }
+
+ *fw = mem;
+ *fwlen = memlen;
+
+ return (0);
+ fail:
+ free(mem, M_DEVBUF);
+ return (-1);
+}
+
+void
+nxb_reset(struct nxb_softc *sc)
+{
+ struct nxb_firmware_header fh;
+ u_int8_t *fw = NULL;
+ size_t fwlen = 0;
+ int bootsz, imagesz;
+ u_int i;
+ u_int32_t *data, addr, val;
+ bus_size_t reg;
+
+ bzero(&fh, sizeof(fh));
+ if (sc->sc_flags & NXFLAG_FWINVALID) {
+ if (nxb_loadfirmware(sc, &fh, &fw, &fwlen) != 0) {
+ printf("%s: failed to load firmware from disk\n",
+ sc->sc_dev.dv_xname);
+ goto fail;
+ }
+ } else {
+ if (nxb_reloadfirmware(sc, &fh, &fw, &fwlen) != 0) {
+ printf("%s: failed to reload firmware from flash\n",
+ sc->sc_dev.dv_xname);
+ goto fail;
+ }
+ }
+
+ /*
+ * Validate the information found in the extra header
+ */
+ val = ntohl(fh.fw_image_ver);
+ sc->sc_fwmajor = (val & NXB_IMAGE_MAJOR_M) >> NXB_IMAGE_MAJOR_S;
+ sc->sc_fwminor = (val & NXB_IMAGE_MINOR_M) >> NXB_IMAGE_MINOR_S;
+ sc->sc_fwbuild = (val & NXB_IMAGE_BUILD_M) >> NXB_IMAGE_BUILD_S;
+ if (sc->sc_flags & NXFLAG_FWINVALID)
+ printf("%s: using firmware %u.%u.%u\n", sc->sc_dev.dv_xname,
+ sc->sc_fwmajor, sc->sc_fwminor, sc->sc_fwbuild);
+ if (sc->sc_fwmajor != NX_FIRMWARE_MAJOR ||
+ sc->sc_fwminor != NX_FIRMWARE_MINOR) {
+ printf("%s: unsupported firmware version\n",
+ sc->sc_dev.dv_xname);
+ goto fail;
+ }
+
+ bootsz = ntohl(fh.fw_bootld_size);
+ imagesz = ntohl(fh.fw_image_size);
+ if ((imagesz + bootsz) != (fwlen - sizeof(fh)) ||
+ (imagesz % 4) || (bootsz % 4)) {
+ printf("%s: invalid firmware image\n", sc->sc_dev.dv_xname);
+ goto fail;
+ }
+
+ /*
+ * Initialize the SW registers
+ */
+ addr = NXFLASHMAP_CRBINIT_0;
+ if (nxb_read_rom(sc, addr, &val) != 0)
+ goto fail1;
+
+ /* XXX */
+ DPRINTF(NXDBG_FLASH, "%s(%s): ncrb 0x%08x\n",
+ sc->sc_dev.dv_xname, __func__, val);
+
+ /*
+ * Load the images into RAM
+ */
+
+ /* Reset casper boot chip */
+ nxb_write(sc, NXROMUSB_GLB_CAS_RESET, NXROMUSB_GLB_CAS_RESET_ENABLE);
+
+ reg = NXFLASHMAP_BOOTLOADER;
+ data = (u_int32_t *)(fw + sizeof(fh));
+ for (i = 0; i < (bootsz / 4); i++) {
+ nxb_write(sc, reg, *data);
+ addr += sizeof(u_int32_t);
+ data++;
+ }
+ if (imagesz) {
+ reg = NXFLASHMAP_FIRMWARE_0;
+ for (i = 0; i < (imagesz / 4); i++) {
+ nxb_write(sc, reg, *data);
+ addr += sizeof(u_int32_t);
+ data++;
+ }
+ /* tell the bootloader to load the firmware image from RAM */
+ nxb_write(sc, NXSW_BOOTLD_CONFIG, NXSW_BOOTLD_CONFIG_RAM);
+ }
+
+ /* Power on the clocks and unreset the casper boot chip */
+ nxb_write(sc, NXROMUSB_GLB_CHIPCLKCONTROL,
+ NXROMUSB_GLB_CHIPCLKCONTROL_ON);
+ nxb_write(sc, NXROMUSB_GLB_CAS_RESET, NXROMUSB_GLB_CAS_RESET_DISABLE);
+
+ /*
+ * bootstrap the newly loaded firmware and wait for completion
+ */
+ nxb_write(sc, NXROMUSB_GLB_PEGTUNE, NXROMUSB_GLB_PEGTUNE_DONE);
+ if (nxb_booted(sc) != 0)
+ goto fail;
+
+ /* Firmware is ready for operation, allow interrupts etc. */
+ sc->sc_state = NX_S_READY;
+ goto done;
+ fail1:
+ printf("%s: failed to reset firmware\n", sc->sc_dev.dv_xname);
+ fail:
+ sc->sc_state = NX_S_FAIL;
+ done:
+ if (fw != NULL)
+ free(fw, M_DEVBUF);
+}
+
u_int32_t
nxb_read(struct nxb_softc *sc, bus_size_t reg)
{
diff --git a/sys/dev/pci/if_nxreg.h b/sys/dev/pci/if_nxreg.h
index cb3c39284b0..b293b2248be 100644
--- a/sys/dev/pci/if_nxreg.h
+++ b/sys/dev/pci/if_nxreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_nxreg.h,v 1.12 2007/04/30 10:55:08 reyk Exp $ */
+/* $OpenBSD: if_nxreg.h,v 1.13 2007/04/30 21:22:56 reyk Exp $ */
/*
* Copyright (c) 2007 Reyk Floeter <reyk@openbsd.org>
@@ -41,6 +41,7 @@
/* Used to indicate various states of the NIC and its firmware */
enum nx_state {
+ NX_S_FAIL = -1, /* Failed to initialize the device */
NX_S_OFFLINE = 0, /* Firmware is not active yet */
NX_S_BOOTING = 1, /* Chipset is booting the firmware */
NX_S_READY = 3 /* Device has been initialized and is ready */
@@ -134,6 +135,8 @@ struct nx_statusdesc {
#define NXPCIMEM_SIZE_128MB 0x08000000 /* 128MB size */
#define NXPCIMEM_SIZE_32MB 0x02000000 /* 32MB size */
+#define NXPCIMAP_DDR_NET 0x00000000
+#define NXPCIMAP_DDR_MD 0x02000000
#define NXPCIMAP_DIRECT_CRB 0x04400000
#define NXPCIMAP_CRB 0x06000000
@@ -279,6 +282,11 @@ struct nx_statusdesc {
#define NXSW_PHY_LOCK_ID NXSW(0x2120) /* Used for locking the PHY */
#define NXSW_PHY_LOCK_DRV 0x44524956 /* Driver PHY lock ID */
+/* Boot loader configuration */
+#define NXSW_BOOTLD_CONFIG NXSW(0x01fc)
+#define NXSW_BOOTLD_CONFIG_ROM 0x00000000 /* Load firmware from flasg */
+#define NXSW_BOOTLD_CONFIG_RAM 0x12345678 /* Load firmware from memory */
+
/* Version registers of the loaded firmware */
#define NXSW_FW_VERSION_MAJOR NXSW(0x2150) /* Major f/w version */
#define NXSW_FW_VERSION_MINOR NXSW(0x2154) /* Minor f/w version */
@@ -360,13 +368,18 @@ struct nx_statusdesc {
/* Casper Reset Register */
#define NXROMUSB_GLB_CAS_RESET NXROMUSB(0x00000038)
-#define NXRUMUSB_GLB_CAS_RESET_ENABLE (1<<0) /* Enable Casper reset */
+#define NXROMUSB_GLB_CAS_RESET_ENABLE (1<<0) /* Enable Casper reset */
+#define NXROMUSB_GLB_CAS_RESET_DISABLE 0
#define NXROMUSB_GLB_CAS_RESET_DEF 0 /* Disabled */
/* Reset register */
#define NXROMUSB_GLB_PEGTUNE NXROMUSB(0x0000005c)
#define NXROMUSB_GLB_PEGTUNE_DONE (1<<0)
+/* Chip clock control register */
+#define NXROMUSB_GLB_CHIPCLKCONTROL NXROMUSB(0x000000a8)
+#define NXROMUSB_GLB_CHIPCLKCONTROL_ON 0x00003fff
+
/* ROM Register */
#define NXROMUSB_ROM_CONTROL NXROMUSB(0x00010000)
#define NXROMUSB_ROM_OPCODE NXROMUSB(0x00010004)
@@ -402,12 +415,11 @@ enum nxb_board_types {
NXB_BOARDTYPE_P2SB31_10GCX4 = 15
};
-#define NXB_VERSION 0x00000001 /* board information version */
-#define NXB_MAGIC 0x12345678 /* magic value */
#define NXB_MAX_PORTS NX_MAX_PORTS /* max supported ports */
struct nxb_info {
u_int32_t ni_hdrver; /* Board info version */
+#define NXB_VERSION 0x00000001 /* board information version */
u_int32_t ni_board_mfg;
u_int32_t ni_board_type;
@@ -473,6 +485,7 @@ struct nxb_info {
u_int32_t ni_lladdr3_high;
u_int32_t ni_magic;
+#define NXB_MAGIC 0x12345678 /* magic value */
u_int32_t ni_mnrd_imm;
u_int32_t ni_mndll_override;
@@ -480,23 +493,43 @@ struct nxb_info {
#define NXB_MAX_PORT_LLADDRS 32
-struct nxb_userinfo {
- u_int8_t nu_flash_md5[1024];
+struct nxb_imageinfo {
+ u_int32_t nim_bootld_ver;
+ u_int32_t nim_bootld_size;
+ u_int32_t nim_image_ver;
+#define NXB_IMAGE_MAJOR_S 0
+#define NXB_IMAGE_MAJOR_M 0x000000ff
+#define NXB_IMAGE_MINOR_S 8
+#define NXB_IMAGE_MINOR_M 0x0000ff00
+#define NXB_IMAGE_BUILD_S 16
+#define NXB_IMAGE_BUILD_M 0xffff0000
+ u_int32_t nim_image_size;
+} __packed;
- u_int32_t nu_bootloader_ver;
- u_int32_t nu_bootloader_size;
+struct nxb_userinfo {
+ u_int8_t nu_flash_md5[1024];
- u_int32_t nu_image_ver;
- u_int32_t nu_image_size;
+ struct nxb_imageinfo nu_image;
- u_int32_t nu_primary;
- u_int32_t nu_secondary;
- u_int64_t nu_lladdr[NXB_MAX_PORTS * NXB_MAX_PORT_LLADDRS];
- u_int32_t nu_subsys_id;
- u_int8_t nu_serial_num[32];
- u_int32_t nu_bios_ver;
+ u_int32_t nu_primary;
+ u_int32_t nu_secondary;
+ u_int64_t nu_lladdr[NXB_MAX_PORTS * NXB_MAX_PORT_LLADDRS];
+ u_int32_t nu_subsys_id;
+ u_int8_t nu_serial_num[32];
+ u_int32_t nu_bios_ver;
/* Followed by user-specific data */
} __packed;
+/* Appended to the on-disk firmware image, values in network byte order */
+struct nxb_firmware_header {
+ u_int32_t fw_hdrver;
+#define NX_FIRMWARE_HDRVER 0 /* version of the firmware header */
+ struct nxb_imageinfo fw_image;
+#define fw_image_ver fw_image.nim_image_ver
+#define fw_image_size fw_image.nim_image_size
+#define fw_bootld_ver fw_image.nim_bootld_ver
+#define fw_bootld_size fw_image.nim_bootld_size
+} __packed;
+
#endif /* _NX_REG_H */