summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorgallatin <gallatin@FreeBSD.org>2006-07-17 22:17:05 +0000
committergallatin <gallatin@FreeBSD.org>2006-07-17 22:17:05 +0000
commit3780baa5cb60344516a547bf4b9dd46e27511834 (patch)
treed6c41f802acc3a4e868bb6042736ce3b5cfbbecf /sys/dev
parent34956b2cd0b05cebd806944640c67a45f98d014c (diff)
downloadFreeBSD-src-3780baa5cb60344516a547bf4b9dd46e27511834.zip
FreeBSD-src-3780baa5cb60344516a547bf4b9dd46e27511834.tar.gz
Firmware loading improvements:
- Copy ethernet firmware down in small chunks so as to avoid bugs in early versions of the bootstrap firmware. - Attempt to "adopt" the running firmware if we cannot load a suitable firmware image via firmware(9). - Separate firmware validation into its own routine, and check the major/minor driver/firmware ABI version.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/mxge/if_mxge.c108
1 files changed, 95 insertions, 13 deletions
diff --git a/sys/dev/mxge/if_mxge.c b/sys/dev/mxge/if_mxge.c
index eb5f89a..2e8a707 100644
--- a/sys/dev/mxge/if_mxge.c
+++ b/sys/dev/mxge/if_mxge.c
@@ -449,6 +449,35 @@ union qualhack
char *rw_char;
};
+static int
+mxge_validate_firmware(mxge_softc_t *sc, const mcp_gen_header_t *hdr)
+{
+ int major, minor;
+
+ if (be32toh(hdr->mcp_type) != MCP_TYPE_ETH) {
+ device_printf(sc->dev, "Bad firmware type: 0x%x\n",
+ be32toh(hdr->mcp_type));
+ return EIO;
+ }
+
+ /* save firmware version for sysctl */
+ strncpy(sc->fw_version, hdr->version, sizeof (sc->fw_version));
+ if (mxge_verbose)
+ device_printf(sc->dev, "firmware id: %s\n", hdr->version);
+
+ sscanf(sc->fw_version, "%d.%d", &major, &minor);
+
+ if (!(major == MXGEFW_VERSION_MAJOR
+ && minor == MXGEFW_VERSION_MINOR)) {
+ device_printf(sc->dev, "Found firmware version %s\n",
+ sc->fw_version);
+ device_printf(sc->dev, "Driver needs %d.%d\n",
+ MXGEFW_VERSION_MAJOR, MXGEFW_VERSION_MINOR);
+ return EINVAL;
+ }
+ return 0;
+
+}
static int
mxge_load_firmware_helper(mxge_softc_t *sc, uint32_t *limit)
@@ -459,6 +488,8 @@ mxge_load_firmware_helper(mxge_softc_t *sc, uint32_t *limit)
const char *fw_data;
union qualhack hack;
int status;
+ unsigned int i;
+ char dummy;
fw = firmware_get(sc->fw_name);
@@ -487,21 +518,21 @@ mxge_load_firmware_helper(mxge_softc_t *sc, uint32_t *limit)
goto abort_with_fw;
}
hdr = (const void*)(fw_data + hdr_offset);
- if (be32toh(hdr->mcp_type) != MCP_TYPE_ETH) {
- device_printf(sc->dev, "Bad firmware type: 0x%x\n",
- be32toh(hdr->mcp_type));
- status = EIO;
- goto abort_with_fw;
- }
- /* save firmware version for sysctl */
- strncpy(sc->fw_version, hdr->version, sizeof (sc->fw_version));
- if (mxge_verbose)
- device_printf(sc->dev, "firmware id: %s\n", hdr->version);
+ status = mxge_validate_firmware(sc, hdr);
+ if (status != 0)
+ goto abort_with_fw;
hack.ro_char = fw_data;
/* Copy the inflated firmware to NIC SRAM. */
- mxge_pio_copy(&sc->sram[MXGE_FW_OFFSET], hack.rw_char, *limit);
+ for (i = 0; i < *limit; i += 256) {
+ mxge_pio_copy(sc->sram + MXGE_FW_OFFSET + i,
+ hack.rw_char + i,
+ min(256U, (unsigned)(*limit - i)));
+ mb();
+ dummy = *sc->sram;
+ mb();
+ }
status = 0;
abort_with_fw:
@@ -621,6 +652,40 @@ mxge_send_cmd(mxge_softc_t *sc, uint32_t cmd, mxge_cmd_t *data)
return EAGAIN;
}
+static int
+mxge_adopt_running_firmware(mxge_softc_t *sc)
+{
+ struct mcp_gen_header *hdr;
+ const size_t bytes = sizeof (struct mcp_gen_header);
+ size_t hdr_offset;
+ int status;
+
+ /* find running firmware header */
+ hdr_offset = htobe32(*(volatile uint32_t *)
+ (sc->sram + MCP_HEADER_PTR_OFFSET));
+
+ if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > sc->sram_size) {
+ device_printf(sc->dev,
+ "Running firmware has bad header offset (%d)\n",
+ (int)hdr_offset);
+ return EIO;
+ }
+
+ /* copy header of running firmware from SRAM to host memory to
+ * validate firmware */
+ hdr = malloc(bytes, M_DEVBUF, M_NOWAIT);
+ if (hdr == NULL) {
+ device_printf(sc->dev, "could not malloc firmware hdr\n");
+ return ENOMEM;
+ }
+ bus_space_read_region_1(rman_get_bustag(sc->mem_res),
+ rman_get_bushandle(sc->mem_res),
+ hdr_offset, (char *)hdr, bytes);
+ status = mxge_validate_firmware(sc, hdr);
+ free(hdr, M_DEVBUF);
+ return status;
+}
+
static int
mxge_load_firmware(mxge_softc_t *sc)
@@ -636,8 +701,25 @@ mxge_load_firmware(mxge_softc_t *sc)
size = sc->sram_size;
status = mxge_load_firmware_helper(sc, &size);
if (status) {
- device_printf(sc->dev, "firmware loading failed\n");
- return status;
+ /* Try to use the currently running firmware, if
+ it is new enough */
+ status = mxge_adopt_running_firmware(sc);
+ if (status) {
+ device_printf(sc->dev,
+ "failed to adopt running firmware\n");
+ return status;
+ }
+ device_printf(sc->dev,
+ "Successfully adopted running firmware\n");
+ if (sc->tx.boundary == 4096) {
+ device_printf(sc->dev,
+ "Using firmware currently running on NIC"
+ ". For optimal\n");
+ device_printf(sc->dev,
+ "performance consider loading optimized "
+ "firmware\n");
+ }
+
}
/* clear confirmation addr */
confirm = (volatile uint32_t *)sc->cmd;
OpenPOWER on IntegriCloud