diff options
author | Marcus Glocker <mglocker@cvs.openbsd.org> | 2007-09-18 17:35:39 +0000 |
---|---|---|
committer | Marcus Glocker <mglocker@cvs.openbsd.org> | 2007-09-18 17:35:39 +0000 |
commit | 940e6e683bf6b568cdc59ead07f17a888923326f (patch) | |
tree | c04ffbd01bdbb0032a89be9d7f67538fe289c8ac /sys/dev/ic | |
parent | b75ed7b61135edc8df08131746f3c7d40757c4c7 (diff) |
Drag back the original DragonFlyBSD firmware loading routines, so we can
load the same firmware revision as they do. Our previously used firmware
images seem to contain the wrong revision. You need to bump your firmware
package to version 1.2.
Other than expected, loading the right firmware revision still doesn't fix
a fatal chip error at initialization time.
Diffstat (limited to 'sys/dev/ic')
-rw-r--r-- | sys/dev/ic/bwi.c | 411 | ||||
-rw-r--r-- | sys/dev/ic/bwivar.h | 38 |
2 files changed, 291 insertions, 158 deletions
diff --git a/sys/dev/ic/bwi.c b/sys/dev/ic/bwi.c index ac95dea2feb..fac9585d162 100644 --- a/sys/dev/ic/bwi.c +++ b/sys/dev/ic/bwi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bwi.c,v 1.38 2007/09/17 20:43:18 mglocker Exp $ */ +/* $OpenBSD: bwi.c,v 1.39 2007/09/18 17:35:38 mglocker Exp $ */ /* * Copyright (c) 2007 The DragonFly Project. All rights reserved. @@ -144,10 +144,14 @@ void bwi_mac_init_tpctl_11bg(struct bwi_mac *); void bwi_mac_detach(struct bwi_mac *); int bwi_get_firmware(const char *, const uint8_t *, size_t, size_t *, size_t *); +int bwi_fwimage_is_valid(struct bwi_softc *, uint8_t *, + size_t fw_len, char *, uint8_t); +int bwi_mac_fw_alloc(struct bwi_mac *); +void bwi_mac_fw_free(struct bwi_mac *); int bwi_mac_fw_load(struct bwi_mac *); int bwi_mac_gpio_init(struct bwi_mac *); int bwi_mac_gpio_fini(struct bwi_mac *); -int bwi_mac_fw_load_iv(struct bwi_mac *, uint8_t *, int); +int bwi_mac_fw_load_iv(struct bwi_mac *, uint8_t *, size_t); int bwi_mac_fw_init(struct bwi_mac *); void bwi_mac_opmode_init(struct bwi_mac *); void bwi_mac_hostflags_init(struct bwi_mac *); @@ -1007,6 +1011,10 @@ bwi_mac_init(struct bwi_mac *mac) /* * Load and initialize firmwares */ + error = bwi_mac_fw_alloc(mac); + if (error) + return (error); + error = bwi_mac_fw_load(mac); if (error) return (error); @@ -1498,7 +1506,7 @@ bwi_mac_init_tpctl_11bg(struct bwi_mac *mac) void bwi_mac_detach(struct bwi_mac *mac) { - + bwi_mac_fw_free(mac); } int @@ -1536,57 +1544,195 @@ bwi_get_firmware(const char *name, const uint8_t *ucode, size_t size_ucode, } int -bwi_mac_fw_load(struct bwi_mac *mac) +bwi_fwimage_is_valid(struct bwi_softc *sc, uint8_t *fw, size_t fw_len, + char *fw_name, uint8_t fw_type) +{ + const struct bwi_fwhdr *hdr; + + if (fw_len < sizeof(*hdr)) { + printf("invalid firmware (%s): invalid size %u\n", + fw_name, fw_len); + return (1); + } + + hdr = (const struct bwi_fwhdr *)fw; + + if (fw_type != BWI_FW_T_IV) { + /* + * Don't verify IV's size, it has different meaning + */ + if (betoh32(hdr->fw_size) != fw_len - sizeof(*hdr)) { + printf("invalid firmware (%s): size mismatch, " + "fw %u, real %u\n", + fw_name, betoh32(hdr->fw_size), + fw_len - sizeof(*hdr)); + return (1); + } + } + + if (hdr->fw_type != fw_type) { + printf("invalid firmware (%s): type mismatch, " + "fw \'%c\', target \'%c\'\n", + fw_name, hdr->fw_type, fw_type); + return (1); + } + + if (hdr->fw_gen != BWI_FW_GEN_1) { + printf("invalid firmware (%s): wrong generation, " + "fw %d, target %d\n", + fw_name, hdr->fw_gen, BWI_FW_GEN_1); + return (1); + } + + return (0); +} + +int +bwi_mac_fw_alloc(struct bwi_mac *mac) { struct bwi_softc *sc = mac->mac_sc; - char *name = "bwi-airforce"; - char filename[64]; - uint8_t *ucode; - uint16_t fw_rev; - uint32_t *fw; - size_t size_ucode, size_fw, size_pcm, off_fw, off_pcm; - int fw_len, i, error = 0; + char fwname[64]; + int idx, error; + + if (mac->mac_ucode == NULL) { + snprintf(fwname, sizeof(fwname), "ucode%d.fw", + mac->mac_rev >= 5 ? 5 : mac->mac_rev); + + error = loadfirmware(fwname, &mac->mac_ucode, + &mac->mac_ucode_size); + if (error != 0) { + printf("%s: error %d, could not read firmware %s!\n", + sc->sc_dev.dv_xname, error, fwname); + return (ENOMEM); + } + DPRINTF(1, "%s: loaded firmware file %s\n", + sc->sc_dev.dv_xname, fwname); - /* - * Load FW file - */ - if ((error = loadfirmware(name, &ucode, &size_ucode)) != 0) { - printf("%s: error %d, could not read firmware %s!\n", - sc->sc_dev.dv_xname, error, name); - return (EIO); + if (bwi_fwimage_is_valid(sc, mac->mac_ucode, + mac->mac_ucode_size, fwname, BWI_FW_T_UCODE)) + return (EINVAL); } - DPRINTF(1, "%s: successfully read %s\n", sc->sc_dev.dv_xname, name); - /* - * Get FW file offset - */ - snprintf(filename, sizeof(filename), "bwi_microcode%d.fw", - mac->mac_rev >= 5 ? 5 : mac->mac_rev); - if (bwi_get_firmware(filename, ucode, size_ucode, &size_fw, &off_fw)) { - printf("%s: get offset for firmware file %s failed!\n", - sc->sc_dev.dv_xname, filename); - error = ENOMEM; - goto out; - } + if (mac->mac_pcm == NULL) { + snprintf(fwname, sizeof(fwname), "pcm%d.fw", + mac->mac_rev < 5 ? 4 : 5); - /* - * Get PCM file offset - */ - snprintf(filename, sizeof(filename), "bwi_pcm%d.fw", - mac->mac_rev < 5 ? 4 : 5); - if (bwi_get_firmware(filename, ucode, size_ucode, &size_pcm, - &off_pcm)) { - printf("%s: get offset for firmware file %s failed!\n", - sc->sc_dev.dv_xname, filename); - error = ENOMEM; - goto out; + error = loadfirmware(fwname, &mac->mac_pcm, + &mac->mac_pcm_size); + if (error != 0) { + printf("%s: error %d, could not read firmware %s!\n", + sc->sc_dev.dv_xname, error, fwname); + return (ENOMEM); + } + DPRINTF(1, "%s: loaded firmware file %s\n", + sc->sc_dev.dv_xname, fwname); + + if (bwi_fwimage_is_valid(sc, mac->mac_pcm, + mac->mac_pcm_size, fwname, BWI_FW_T_PCM)) + return (EINVAL); + } + + if (mac->mac_iv == NULL) { + /* TODO: 11A */ + if (mac->mac_rev == 2 || mac->mac_rev == 4) { + idx = 2; + } else if (mac->mac_rev >= 5 && mac->mac_rev <= 10) { + idx = 5; + } else { + DPRINTF(1, "%s: no suitable IV for MAC rev %d\n", + sc->sc_dev.dv_xname, mac->mac_rev); + return (ENODEV); + } + + snprintf(fwname, sizeof(fwname), "b0g0initvals%d.fw", idx); + + error = loadfirmware(fwname, &mac->mac_iv, + &mac->mac_iv_size); + if (error != 0) { + printf("%s: error %d, could not read firmware %s!\n", + sc->sc_dev.dv_xname, error, fwname); + return (ENOMEM); + } + DPRINTF(1, "%s: loaded firmware file %s\n", + sc->sc_dev.dv_xname, fwname); + + if (bwi_fwimage_is_valid(sc, mac->mac_iv, + mac->mac_iv_size, fwname, BWI_FW_T_IV)) + return (EINVAL); + } + + if (mac->mac_iv_ext == NULL) { + /* TODO: 11A */ + if (mac->mac_rev == 2 || mac->mac_rev == 4 || + mac->mac_rev >= 11) { + /* No extended IV */ + goto back; + } else if (mac->mac_rev >= 5 && mac->mac_rev <= 10) { + idx = 5; + } else { + printf("%s: no suitable ExtIV for MAC rev %d\n", + sc->sc_dev.dv_xname, mac->mac_rev); + return (ENODEV); + } + + snprintf(fwname, sizeof(fwname), "b0g0bsinitvals%d.fw", idx); + + error = loadfirmware(fwname, &mac->mac_iv_ext, + &mac->mac_iv_ext_size); + if (error != 0) { + printf("%s: error %d, could not read firmware %s!\n", + sc->sc_dev.dv_xname, error, fwname); + return (ENOMEM); + } + DPRINTF(1, "%s: loaded firmware file %s\n", + sc->sc_dev.dv_xname, fwname); + + if (bwi_fwimage_is_valid(sc, mac->mac_iv_ext, + mac->mac_iv_ext_size, fwname, BWI_FW_T_IV)) + return (EINVAL); + } + +back: + return (0); +} + +void +bwi_mac_fw_free(struct bwi_mac *mac) +{ + if (mac->mac_ucode != NULL) { + free(mac->mac_ucode, M_DEVBUF); + mac->mac_ucode = NULL; } + if (mac->mac_pcm != NULL) { + free(mac->mac_pcm, M_DEVBUF); + mac->mac_pcm = NULL; + } + + if (mac->mac_iv != NULL) { + free(mac->mac_iv, M_DEVBUF); + mac->mac_iv = NULL; + } + + if (mac->mac_iv_ext != NULL) { + free(mac->mac_iv_ext, M_DEVBUF); + mac->mac_iv_ext = NULL; + } +} + +int +bwi_mac_fw_load(struct bwi_mac *mac) +{ + struct bwi_softc *sc = mac->mac_sc; + uint16_t fw_rev; + const uint32_t *fw; + int fw_len, i, error = 0; + /* * Load FW image */ - fw = (uint32_t *)(ucode + off_fw); - fw_len = size_fw / sizeof(uint32_t); + fw = (const uint32_t *)(mac->mac_ucode + BWI_FWHDR_SZ); + fw_len = (mac->mac_ucode_size - BWI_FWHDR_SZ) / sizeof(uint32_t); CSR_WRITE_4(sc, BWI_MOBJ_CTRL, BWI_MOBJ_CTRL_VAL(BWI_FW_UCODE_MOBJ | BWI_WR_MOBJ_AUTOINC, 0)); @@ -1598,8 +1744,8 @@ bwi_mac_fw_load(struct bwi_mac *mac) /* * Load PCM image */ - fw = (uint32_t *)(ucode + off_pcm); - fw_len = size_pcm / sizeof(uint32_t); + fw = (const uint32_t *)(mac->mac_pcm + BWI_FWHDR_SZ); + fw_len = (mac->mac_pcm_size - BWI_FWHDR_SZ) / sizeof(uint32_t); CSR_WRITE_4(sc, BWI_MOBJ_CTRL, BWI_MOBJ_CTRL_VAL(BWI_FW_PCM_MOBJ, 0x01ea)); @@ -1650,7 +1796,6 @@ bwi_mac_fw_load(struct bwi_mac *mac) MOBJ_READ_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_FWPATCHLV)); out: - free(ucode, M_DEVBUF); return (error); } @@ -1707,138 +1852,104 @@ bwi_mac_gpio_fini(struct bwi_mac *mac) } int -bwi_mac_fw_load_iv(struct bwi_mac *mac, uint8_t *fw_image, int fw_len) +bwi_mac_fw_load_iv(struct bwi_mac *mac, uint8_t *fw, size_t fw_len) { struct bwi_softc *sc = mac->mac_sc; + const struct bwi_fwhdr *hdr; const struct bwi_fw_iv *iv; - uint16_t offset, size; - uint32_t val; - int iv_len, i, error = 0; + int n, i, iv_img_size; /* Get the number of IVs in the IV image */ - iv_len = fw_len / sizeof(struct bwi_fw_iv); - DPRINTF(1, "%s: IV count %d\n", sc->sc_dev.dv_xname, iv_len); + hdr = (const struct bwi_fwhdr *)fw; + n = betoh32(hdr->fw_iv_cnt); + DPRINTF(1, "%s: IV count %d\n", sc->sc_dev.dv_xname, n); + + /* Calculate the IV image size, for later sanity check */ + iv_img_size = fw_len - sizeof(*hdr); /* Locate the first IV */ - iv = (const struct bwi_fw_iv *)fw_image; + iv = (const struct bwi_fw_iv *)(fw + sizeof(*hdr)); + + for (i = 0; i < n; ++i) { + uint16_t iv_ofs, ofs; + int sz = 0; + + if (iv_img_size < sizeof(iv->iv_ofs)) { + printf("%s: invalid IV image, ofs\n", + sc->sc_dev.dv_xname); + return (EINVAL); + } + iv_img_size -= sizeof(iv->iv_ofs); + sz += sizeof(iv->iv_ofs); - for (i = 0; i < iv_len; i++, iv++) { - offset = betoh16(iv->offset); - size = betoh16(iv->size); - val = betoh32(iv->val); + iv_ofs = betoh16(iv->iv_ofs); - if (offset >= 0x1000) { - error = ENODEV; - goto error; + ofs = __SHIFTOUT(iv_ofs, BWI_FW_IV_OFS_MASK); + if (ofs >= 0x1000) { + printf("%s: invalid ofs (0x%04x) for %dth iv\n", + sc->sc_dev.dv_xname, ofs, i); + return (EINVAL); } - if (size == sizeof(uint16_t)) { - if (val & 0xffff0000) { - error = ENODEV; - goto error; + if (iv_ofs & BWI_FW_IV_IS_32BIT) { + uint32_t val32; + + if (iv_img_size < sizeof(iv->iv_val.val32)) { + printf("%s: invalid IV image, val32\n", + sc->sc_dev.dv_xname); + return (EINVAL); } - CSR_WRITE_2(sc, offset, (uint16_t)val); - } else if (size == sizeof(uint32_t)) - CSR_WRITE_4(sc, offset, val); - else { - error = ENODEV; - goto error; + iv_img_size -= sizeof(iv->iv_val.val32); + sz += sizeof(iv->iv_val.val32); + + val32 = betoh32(iv->iv_val.val32); + CSR_WRITE_4(sc, ofs, val32); + } else { + uint16_t val16; + + if (iv_img_size < sizeof(iv->iv_val.val16)) { + printf("%s: invalid IV image, val16\n", + sc->sc_dev.dv_xname); + return (EINVAL); + } + iv_img_size -= sizeof(iv->iv_val.val16); + sz += sizeof(iv->iv_val.val16); + + val16 = betoh16(iv->iv_val.val16); + CSR_WRITE_2(sc, ofs, val16); } + + iv = (const struct bwi_fw_iv *)((const uint8_t *)iv + sz); } - return (error); + if (iv_img_size != 0) { + printf("%s: invalid IV image, size left %d\n", + sc->sc_dev.dv_xname, iv_img_size); + return (EINVAL); + } -error: - printf("%s: bad IV format!\n", sc->sc_dev.dv_xname); - return (error); + return (0); } int bwi_mac_fw_init(struct bwi_mac *mac) { struct bwi_softc *sc = mac->mac_sc; - char *name = "bwi-airforce"; - char fwname[64]; - uint8_t *ucode; - size_t size_ucode, size_iv, off_iv; - int idx, error = 0; - - /* - * Load FW file - */ - if ((error = loadfirmware(name, &ucode, &size_ucode)) != 0) { - printf("%s: error %d, could not read firmware %s!\n", - sc->sc_dev.dv_xname, error, name); - return (EIO); - } - DPRINTF(1, "%s: successfully read %s\n", sc->sc_dev.dv_xname, name); - - /* - * Load IV - * - * TODO: 11A - */ - if (mac->mac_rev == 2 || mac->mac_rev == 4) - idx = 2; - else if (mac->mac_rev >= 5 && mac->mac_rev <= 10) - idx = 5; - else { - printf("%s: no suitable IV for MAC rev %d\n", - sc->sc_dev.dv_xname, mac->mac_rev); - error = ENODEV; - goto out; - } - snprintf(fwname, sizeof(fwname), "bwi_initval%02d.fw", idx); - - DPRINTF(1, "%s: IV image is %s\n", sc->sc_dev.dv_xname, fwname); - - if (bwi_get_firmware(fwname, ucode, size_ucode, &size_iv, &off_iv)) { - printf("%s: IV image %s not found!\n", - sc->sc_dev.dv_xname, fwname); - error = ENOMEM; - goto out; - } + int error; - error = bwi_mac_fw_load_iv(mac, (ucode + off_iv), size_iv); + error = bwi_mac_fw_load_iv(mac, mac->mac_iv, mac->mac_iv_size); if (error) { - printf("%s: load IV failed!\n", sc->sc_dev.dv_xname); - goto out; - } - - /* - * Load extended IV - * - * TODO: 11A - */ - if (mac->mac_rev == 2 || mac->mac_rev == 4 || mac->mac_rev >= 11) - /* No extended IV */ - goto out; - else if (mac->mac_rev >= 5 && mac->mac_rev <= 10) - idx = 5; - else { - printf("%s: no suitable extended IV for MAC rev %d\n", - sc->sc_dev.dv_xname, mac->mac_rev); - error = ENODEV; - goto out; + printf("%s: load IV failed\n", sc->sc_dev.dv_xname); + return (error); } - snprintf(fwname, sizeof(fwname), "bwi_initval%02d.fw", idx); - - DPRINTF(1, "%s: extended IV image is %s\n", - sc->sc_dev.dv_xname, fwname); - if (bwi_get_firmware(fwname, ucode, size_ucode, &size_iv, &off_iv)) { - printf("%s: extended IV image %s not found!\n", - sc->sc_dev.dv_xname, fwname); - error = ENOMEM; - goto out; + if (mac->mac_iv_ext != NULL) { + error = bwi_mac_fw_load_iv(mac, mac->mac_iv_ext, + mac->mac_iv_ext_size); + if (error) + printf("%s: load ExtIV failed\n", sc->sc_dev.dv_xname); } - error = bwi_mac_fw_load_iv(mac, (ucode + off_iv), size_iv); - if (error) - printf("%s: load extended IV failed!\n", sc->sc_dev.dv_xname); - -out: - free(ucode, M_DEVBUF); return (error); } diff --git a/sys/dev/ic/bwivar.h b/sys/dev/ic/bwivar.h index 1ad1dcd826d..18d055de580 100644 --- a/sys/dev/ic/bwivar.h +++ b/sys/dev/ic/bwivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bwivar.h,v 1.10 2007/09/16 19:02:37 mglocker Exp $ */ +/* $OpenBSD: bwivar.h,v 1.11 2007/09/18 17:35:38 mglocker Exp $ */ /* * Copyright (c) 2007 The DragonFly Project. All rights reserved. @@ -221,9 +221,25 @@ struct bwi_txstats_data { int stats_idx; }; +struct bwi_fwhdr { + /* Big endian */ + uint8_t fw_type; /* BWI_FW_T_ */ + uint8_t fw_gen; /* BWI_FW_GEN */ + uint8_t fw_pad[2]; + uint32_t fw_size; +#define fw_iv_cnt fw_size +} __packed; + +#define BWI_FWHDR_SZ sizeof(struct bwi_fwhdr) #define BWI_FW_VERSION3 3 #define BWI_FW_VERSION4 4 #define BWI_FW_VERSION3_REVMAX 0x128 +#define BWI_FW_T_UCODE 'u' +#define BWI_FW_T_PCM 'p' +#define BWI_FW_T_IV 'i' +#define BWI_FW_GEN_1 1 +#define BWI_FW_IV_OFS_MASK __BITS(14, 0) +#define BWI_FW_IV_IS_32BIT __BIT(15) struct fwheader { char filename[64]; @@ -233,9 +249,11 @@ struct fwheader { struct bwi_fw_iv { /* Big endian */ - uint16_t offset; - uint16_t size; - uint32_t val; + uint16_t iv_ofs; + union { + uint32_t val32; + uint16_t val16; + } iv_val; } __packed; enum bwi_clock_mode { @@ -377,10 +395,14 @@ struct bwi_mac { struct bwi_tpctl mac_tpctl; /* TX power control */ uint32_t mac_flags; /* BWI_MAC_F_ */ - struct fw_image *mac_ucode; - struct fw_image *mac_pcm; - struct fw_image *mac_iv; - struct fw_image *mac_iv_ext; + uint8_t *mac_ucode; + size_t mac_ucode_size; + uint8_t *mac_pcm; + size_t mac_pcm_size; + uint8_t *mac_iv; + size_t mac_iv_size; + uint8_t *mac_iv_ext; + size_t mac_iv_ext_size; }; #define BWI_MAC_F_BSWAP 0x1 |