From d1103dfaefaef202555fc23d831a9bcf8a697989 Mon Sep 17 00:00:00 2001 From: degroote Date: Wed, 18 Jul 2007 18:49:16 +0000 Subject: [PATCH] change firmware loading code to adopt the new 2.14.4 firmware layout (from OpenBSD). While here, remove some dead code I added when I ported the code from OpenBSD. IMPORTANT : You must download the 2.14.4 firmware or update your sysutils/wpi-firmware2 to the last revision (2.14.4) or the driver will stop working. --- sys/dev/pci/if_wpi.c | 204 +++++++++++++++++++--------------------- sys/dev/pci/if_wpireg.h | 24 ++--- 2 files changed, 111 insertions(+), 117 deletions(-) diff --git a/sys/dev/pci/if_wpi.c b/sys/dev/pci/if_wpi.c index 1ae874f8a808..1690ed11de10 100644 --- a/sys/dev/pci/if_wpi.c +++ b/sys/dev/pci/if_wpi.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_wpi.c,v 1.16 2007/07/11 17:51:07 degroote Exp $ */ +/* $NetBSD: if_wpi.c,v 1.17 2007/07/18 18:49:16 degroote Exp $ */ /*- * Copyright (c) 2006, 2007 @@ -18,7 +18,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: if_wpi.c,v 1.16 2007/07/11 17:51:07 degroote Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_wpi.c,v 1.17 2007/07/18 18:49:16 degroote Exp $"); /* * Driver for Intel PRO/Wireless 3945ABG 802.11 network adapters. @@ -121,9 +121,10 @@ static void wpi_mem_lock(struct wpi_softc *); static void wpi_mem_unlock(struct wpi_softc *); static uint32_t wpi_mem_read(struct wpi_softc *, uint16_t); static void wpi_mem_write(struct wpi_softc *, uint16_t, uint32_t); +static void wpi_mem_write_region_4(struct wpi_softc *, uint16_t, + const uint32_t *, int); static int wpi_read_prom_data(struct wpi_softc *, uint32_t, void *, int); -static int wpi_load_segment(struct wpi_softc *, uint32_t, const uint8_t *, - int); +static int wpi_load_microcode(struct wpi_softc *, const uint8_t *, int); static int wpi_load_firmware(struct wpi_softc *); static void wpi_calib_timeout(void *); static void wpi_iter_func(void *, struct ieee80211_node *); @@ -1036,6 +1037,15 @@ wpi_mem_write(struct wpi_softc *sc, uint16_t addr, uint32_t data) WPI_WRITE(sc, WPI_WRITE_MEM_DATA, data); } +static void +wpi_mem_write_region_4(struct wpi_softc *sc, uint16_t addr, + const uint32_t *data, int wlen) +{ + for (; wlen > 0; wlen--, data++, addr += 4) + wpi_mem_write(sc, addr, *data); +} + + /* * Read `len' bytes from the EEPROM. We access the EEPROM through the MAC * instead of using the traditional bit-bang method. @@ -1071,55 +1081,47 @@ wpi_read_prom_data(struct wpi_softc *sc, uint32_t addr, void *data, int len) return 0; } -static int -wpi_load_segment(struct wpi_softc *sc, uint32_t target, const uint8_t *data, - int len) +/* + * The firmware boot code is small and is intended to be copied directly into + * the NIC internal memory. + */ +int +wpi_load_microcode(struct wpi_softc *sc, const uint8_t *ucode, int size) { - struct wpi_dma_info *dma = &sc->fw_dma; - struct wpi_tx_desc desc; - int ntries, error = 0; + int ntries; - DPRINTFN(2, ("loading firmware segment target=%x len=%d\n", target, - len)); + size /= sizeof (uint32_t); - /* copy data to pre-allocated DMA-safe memory */ - memcpy(dma->vaddr, data, len); - bus_dmamap_sync(dma->tag, dma->map, 0, len, BUS_DMASYNC_PREWRITE); + wpi_mem_lock(sc); - /* setup Tx descriptor */ - memset(&desc, 0, sizeof desc); - desc.flags = htole32(WPI_PAD32(len) << 28 | 1 << 24); - desc.segs[0].addr = htole32(dma->paddr); - desc.segs[0].len = htole32(len); + /* copy microcode image into NIC memory */ + wpi_mem_write_region_4(sc, WPI_MEM_UCODE_BASE, + (const uint32_t *)ucode, size); - /* tell adapter where to copy data in its internal memory */ - WPI_WRITE(sc, WPI_FW_TARGET, target); + wpi_mem_write(sc, WPI_MEM_UCODE_SRC, 0); + wpi_mem_write(sc, WPI_MEM_UCODE_DST, WPI_FW_TEXT); + wpi_mem_write(sc, WPI_MEM_UCODE_SIZE, size); - WPI_WRITE(sc, WPI_TX_CONFIG(6), 0); + /* run microcode */ + wpi_mem_write(sc, WPI_MEM_UCODE_CTL, WPI_UC_RUN); - /* copy Tx descriptor into NIC memory */ - WPI_WRITE_REGION_4(sc, WPI_TX_DESC(6), (uint32_t *)&desc, - sizeof desc / sizeof (uint32_t)); - - WPI_WRITE(sc, WPI_TX_CREDIT(6), 0xfffff); - WPI_WRITE(sc, WPI_TX_STATE(6), 0x4001); - WPI_WRITE(sc, WPI_TX_CONFIG(6), 0x80000001); - - /* wait while the adapter transfers the block */ - for (ntries = 0; ntries < 100; ntries++) { - if (WPI_READ(sc, WPI_TX_STATUS) & WPI_TX_IDLE(6)) + /* wait for transfer to complete */ + for (ntries = 0; ntries < 1000; ntries++) { + if (!(wpi_mem_read(sc, WPI_MEM_UCODE_CTL) & WPI_UC_RUN)) break; - DELAY(1000); + DELAY(10); } - if (ntries == 100) { - aprint_error("%s: timeout transferring firmware segment\n", + if (ntries == 1000) { + wpi_mem_unlock(sc); + printf("%s: could not load boot firmware\n", sc->sc_dev.dv_xname); - error = ETIMEDOUT; + return ETIMEDOUT; } + wpi_mem_write(sc, WPI_MEM_UCODE_CTL, WPI_UC_ENABLE); - WPI_WRITE(sc, WPI_TX_CREDIT(6), 0); + wpi_mem_unlock(sc); - return error; + return 0; } static int @@ -1127,12 +1129,13 @@ wpi_load_firmware(struct wpi_softc *sc) { struct wpi_dma_info *dma = &sc->fw_dma; struct wpi_firmware_hdr hdr; - const uint8_t *boot_text, *boot_data, *main_text, *main_data; - uint32_t main_textsz, main_datasz, boot_textsz, boot_datasz; + const uint8_t *init_text, *init_data, *main_text, *main_data; + const uint8_t *boot_text; + uint32_t init_textsz, init_datasz, main_textsz, main_datasz; + uint32_t boot_textsz; firmware_handle_t fw; u_char *dfw; size_t size; - uint32_t tmp; int error; /* load firmware image from disk */ @@ -1161,38 +1164,25 @@ wpi_load_firmware(struct wpi_softc *sc) main_textsz = le32toh(hdr.main_textsz); main_datasz = le32toh(hdr.main_datasz); + init_textsz = le32toh(hdr.init_textsz); + init_datasz = le32toh(hdr.init_datasz); boot_textsz = le32toh(hdr.boot_textsz); - boot_datasz = le32toh(hdr.boot_datasz); - /* sanity-check firmware header */ - if (main_textsz > WPI_FW_MAIN_TEXT_MAXSZ) { - aprint_error("%s: main .text segment too large: %u bytes\n", - sc->sc_dev.dv_xname, main_textsz); - error = EINVAL; - goto fail2; - } - if (main_datasz > WPI_FW_MAIN_DATA_MAXSZ) { - aprint_error("%s: main .data segment too large: %u bytes\n", - sc->sc_dev.dv_xname, main_datasz); - error = EINVAL; - goto fail2; - } - if (boot_textsz > WPI_FW_BOOT_TEXT_MAXSZ) { - aprint_error("%s: boot .text segment too large: %u bytes\n", - sc->sc_dev.dv_xname, boot_textsz); - error = EINVAL; - goto fail2; - } - if (boot_datasz > WPI_FW_BOOT_DATA_MAXSZ) { - aprint_error("%s: boot .data segment too large: %u bytes\n", - sc->sc_dev.dv_xname, boot_datasz); + /* sanity-check firmware segments sizes */ + if (main_textsz > WPI_FW_MAIN_TEXT_MAXSZ || + main_datasz > WPI_FW_MAIN_DATA_MAXSZ || + init_textsz > WPI_FW_INIT_TEXT_MAXSZ || + init_datasz > WPI_FW_INIT_DATA_MAXSZ || + boot_textsz > WPI_FW_BOOT_TEXT_MAXSZ || + (boot_textsz & 3) != 0) { + printf("%s: invalid firmware header\n", sc->sc_dev.dv_xname); error = EINVAL; goto fail2; } /* check that all firmware segments are present */ if (size < sizeof (struct wpi_firmware_hdr) + main_textsz + - main_datasz + boot_textsz + boot_datasz) { + main_datasz + init_textsz + init_datasz + boot_textsz) { aprint_error("%s: firmware file too short: %zu bytes\n", sc->sc_dev.dv_xname, size); error = EINVAL; @@ -1216,43 +1206,32 @@ wpi_load_firmware(struct wpi_softc *sc) /* get pointers to firmware segments */ main_text = dfw + sizeof (struct wpi_firmware_hdr); main_data = main_text + main_textsz; - boot_text = main_data + main_datasz; - boot_data = boot_text + boot_textsz; + init_text = main_data + main_datasz; + init_data = init_text + init_textsz; + boot_text = init_data + init_datasz; - /* load firmware boot .data segment into NIC */ - error = wpi_load_segment(sc, WPI_FW_DATA, boot_data, boot_datasz); - if (error != 0) { - aprint_error("%s: could not load firmware boot .data segment\n", - sc->sc_dev.dv_xname); - goto fail3; - } + /* copy initialization images into pre-allocated DMA-safe memory */ + memcpy(dma->vaddr, init_data, init_datasz); + memcpy((char*)dma->vaddr + WPI_FW_INIT_DATA_MAXSZ, init_text, init_textsz); - /* load firmware boot .text segment into NIC */ - error = wpi_load_segment(sc, WPI_FW_TEXT, boot_text, boot_textsz); - if (error != 0) { - aprint_error("%s: could not load firmware boot .text segment\n", - sc->sc_dev.dv_xname); - goto fail3; - } - - /* copy firmware runtime into pre-allocated DMA-safe memory */ - memcpy(dma->vaddr, main_text, main_textsz); - memcpy((uint8_t*)dma->vaddr + main_textsz, main_data, main_datasz); - bus_dmamap_sync(dma->tag, dma->map, 0, main_textsz + main_datasz, - BUS_DMASYNC_PREWRITE); - - /* tell adapter where to find firmware runtime */ + /* tell adapter where to find initialization images */ wpi_mem_lock(sc); - wpi_mem_write(sc, WPI_MEM_MAIN_TEXT_BASE, dma->paddr); - wpi_mem_write(sc, WPI_MEM_MAIN_TEXT_SIZE, main_textsz); - wpi_mem_write(sc, WPI_MEM_MAIN_DATA_BASE, dma->paddr + main_textsz); - wpi_mem_write(sc, WPI_MEM_MAIN_DATA_SIZE, main_datasz); + wpi_mem_write(sc, WPI_MEM_DATA_BASE, dma->paddr); + wpi_mem_write(sc, WPI_MEM_DATA_SIZE, init_datasz); + wpi_mem_write(sc, WPI_MEM_TEXT_BASE, + dma->paddr + WPI_FW_INIT_DATA_MAXSZ); + wpi_mem_write(sc, WPI_MEM_TEXT_SIZE, init_textsz); wpi_mem_unlock(sc); + /* load firmware boot code */ + if ((error = wpi_load_microcode(sc, boot_text, boot_textsz)) != 0) { + printf("%s: could not load boot firmware\n", + sc->sc_dev.dv_xname); + goto fail3; + } + /* now press "execute" ;-) */ - tmp = WPI_READ(sc, WPI_RESET); - tmp &= ~(WPI_MASTER_DISABLED | WPI_STOP_MASTER | WPI_NEVO_RESET); - WPI_WRITE(sc, WPI_RESET, tmp); + WPI_WRITE(sc, WPI_RESET, 0); /* ..and wait at most one second for adapter to initialize */ if ((error = tsleep(sc, PCATCH, "wpiinit", hz)) != 0) { @@ -1261,6 +1240,27 @@ wpi_load_firmware(struct wpi_softc *sc) sc->sc_dev.dv_xname); } + /* copy runtime images into pre-allocated DMA-safe memory */ + memcpy(dma->vaddr, main_data, main_datasz); + memcpy((char*)dma->vaddr + WPI_FW_MAIN_DATA_MAXSZ, main_text, main_textsz); + + /* tell adapter where to find runtime images */ + wpi_mem_lock(sc); + wpi_mem_write(sc, WPI_MEM_DATA_BASE, dma->paddr); + wpi_mem_write(sc, WPI_MEM_DATA_SIZE, main_datasz); + wpi_mem_write(sc, WPI_MEM_TEXT_BASE, + dma->paddr + WPI_FW_MAIN_DATA_MAXSZ); + wpi_mem_write(sc, WPI_MEM_TEXT_SIZE, WPI_FW_UPDATED | main_textsz); + wpi_mem_unlock(sc); + + /* wait at most one second for second alive notification */ + if ((error = tsleep(sc, PCATCH, "wpiinit", hz)) != 0) { + /* this isn't what was supposed to happen.. */ + printf("%s: timeout waiting for adapter to initialize\n", + sc->sc_dev.dv_xname); + } + + fail3: firmware_free(dfw,size); fail2: firmware_close(fw); fail1: return error; @@ -2696,17 +2696,9 @@ wpi_scan(struct wpi_softc *sc, uint16_t flags) frm = (uint8_t *)(wh + 1); -#ifdef old_code - /* add essid IE */ - *frm++ = IEEE80211_ELEMID_SSID; - *frm++ = ic->ic_des_esslen; - memcpy(frm, ic->ic_des_essid, ic->ic_des_esslen); - frm += ic->ic_des_esslen; -#else /* add empty essid IE (firmware generates it for directed scans) */ *frm++ = IEEE80211_ELEMID_SSID; *frm++ = 0; -#endif mode = ieee80211_chan2mode(ic, ic->ic_ibss_chan); rs = &ic->ic_sup_rates[mode]; diff --git a/sys/dev/pci/if_wpireg.h b/sys/dev/pci/if_wpireg.h index 7bb6c54e963c..2a5aaf30391e 100644 --- a/sys/dev/pci/if_wpireg.h +++ b/sys/dev/pci/if_wpireg.h @@ -1,4 +1,4 @@ -/* $NetBSD: if_wpireg.h,v 1.4 2007/07/09 19:38:52 degroote Exp $ */ +/* $NetBSD: if_wpireg.h,v 1.5 2007/07/18 18:49:17 degroote Exp $ */ /*- * Copyright (c) 2006 @@ -52,7 +52,6 @@ #define WPI_TEMPERATURE 0x060 #define WPI_CHICKEN 0x100 #define WPI_PLL_CTL 0x20c -#define WPI_FW_TARGET 0x410 #define WPI_WRITE_MEM_ADDR 0x444 #define WPI_READ_MEM_ADDR 0x448 #define WPI_WRITE_MEM_DATA 0x44c @@ -96,10 +95,10 @@ #define WPI_MEM_UCODE_BASE 0x3800 -#define WPI_MEM_MAIN_TEXT_BASE 0x3490 -#define WPI_MEM_MAIN_TEXT_SIZE 0x3494 -#define WPI_MEM_MAIN_DATA_BASE 0x3498 -#define WPI_MEM_MAIN_DATA_SIZE 0x349c +#define WPI_MEM_TEXT_BASE 0x3490 +#define WPI_MEM_TEXT_SIZE 0x3494 +#define WPI_MEM_DATA_BASE 0x3498 +#define WPI_MEM_DATA_SIZE 0x349c /* possible flags for register WPI_HWCONFIG */ #define WPI_HW_ALM_MB (1 << 8) @@ -111,9 +110,8 @@ /* possible flags for registers WPI_READ_MEM_ADDR/WPI_WRITE_MEM_ADDR */ #define WPI_MEM_4 ((sizeof (uint32_t) - 1) << 24) -/* possible values for WPI_FW_TARGET */ +/* possible values for WPI_MEM_UCODE_DST */ #define WPI_FW_TEXT 0x00000000 -#define WPI_FW_DATA 0x00800000 /* possible flags for WPI_GPIO_STATUS */ #define WPI_POWERED (1 << 9) @@ -146,7 +144,8 @@ #define WPI_RX_IDLE (1 << 24) /* possible flags for register WPI_UC_CTL */ -#define WPI_UC_RUN (1 << 30) +#define WPI_UC_ENABLE (1 << 30) +#define WPI_UC_RUN (1 << 31) /* possible flags for register WPI_INTR_CSR */ #define WPI_ALIVE_INTR (1 << 0) @@ -588,15 +587,18 @@ struct wpi_firmware_hdr { uint32_t version; uint32_t main_textsz; uint32_t main_datasz; + uint32_t init_textsz; + uint32_t init_datasz; uint32_t boot_textsz; - uint32_t boot_datasz; } __attribute__((__packed__)); #define WPI_FW_MAIN_TEXT_MAXSZ (80 * 1024) #define WPI_FW_MAIN_DATA_MAXSZ (32 * 1024) +#define WPI_FW_INIT_TEXT_MAXSZ (80 * 1024) +#define WPI_FW_INIT_DATA_MAXSZ (32 * 1024) #define WPI_FW_BOOT_TEXT_MAXSZ (80 * 1024) -#define WPI_FW_BOOT_DATA_MAXSZ (32 * 1024) +#define WPI_FW_UPDATED (1 << 31) /* + * Offsets into EEPROM. + */