diff options
author | gallatin <gallatin@FreeBSD.org> | 2006-07-17 22:17:05 +0000 |
---|---|---|
committer | gallatin <gallatin@FreeBSD.org> | 2006-07-17 22:17:05 +0000 |
commit | 3780baa5cb60344516a547bf4b9dd46e27511834 (patch) | |
tree | d6c41f802acc3a4e868bb6042736ce3b5cfbbecf /sys/dev | |
parent | 34956b2cd0b05cebd806944640c67a45f98d014c (diff) | |
download | FreeBSD-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.c | 108 |
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; |