summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ic')
-rw-r--r--sys/dev/ic/bwi.c411
-rw-r--r--sys/dev/ic/bwivar.h38
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