diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2007-07-10 18:29:39 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2007-07-10 18:29:39 +0000 |
commit | 9f98df60eea2ecd2a8243b7106fcdee213dbd661 (patch) | |
tree | 222447d0a9aa474ba0cae1488028a7dbadba2a15 /sys/dev/pci/if_wpi.c | |
parent | 89f1af237ffa6abb21d3a33b8d7c07fbb51436ae (diff) |
change firmware loading code to adopt the new 2.14.4 firmware layout.
while i'm here, fix allocation of the Rx ring descriptors so we don't
waste memory.
IMPORTANT: you must upgrade your wpi-firmware package to rev. 2.14.4
or the driver will stop working.
Diffstat (limited to 'sys/dev/pci/if_wpi.c')
-rw-r--r-- | sys/dev/pci/if_wpi.c | 187 |
1 files changed, 93 insertions, 94 deletions
diff --git a/sys/dev/pci/if_wpi.c b/sys/dev/pci/if_wpi.c index cd7958f82cf..17aeb24f0b6 100644 --- a/sys/dev/pci/if_wpi.c +++ b/sys/dev/pci/if_wpi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_wpi.c,v 1.46 2007/07/05 20:29:22 damien Exp $ */ +/* $OpenBSD: if_wpi.c,v 1.47 2007/07/10 18:29:38 damien Exp $ */ /*- * Copyright (c) 2006, 2007 @@ -100,9 +100,10 @@ void wpi_mem_lock(struct wpi_softc *); void wpi_mem_unlock(struct wpi_softc *); uint32_t wpi_mem_read(struct wpi_softc *, uint16_t); void wpi_mem_write(struct wpi_softc *, uint16_t, uint32_t); +void wpi_mem_write_region_4(struct wpi_softc *, uint16_t, + const uint32_t *, int); int wpi_read_prom_data(struct wpi_softc *, uint32_t, void *, int); -int wpi_load_segment(struct wpi_softc *, uint32_t, const uint8_t *, - int); +int wpi_load_microcode(struct wpi_softc *, const uint8_t *, int); int wpi_load_firmware(struct wpi_softc *); void wpi_calib_timeout(void *); void wpi_iter_func(void *, struct ieee80211_node *); @@ -536,8 +537,7 @@ wpi_alloc_rx_ring(struct wpi_softc *sc, struct wpi_rx_ring *ring) ring->cur = 0; error = wpi_dma_contig_alloc(sc->sc_dmat, &ring->desc_dma, - (void **)&ring->desc, - WPI_RX_RING_COUNT * sizeof (struct wpi_rx_desc), + (void **)&ring->desc, WPI_RX_RING_COUNT * sizeof (uint32_t), WPI_RING_DMA_ALIGN, BUS_DMA_NOWAIT); if (error != 0) { printf("%s: could not allocate rx ring DMA memory\n", @@ -917,6 +917,14 @@ wpi_mem_write(struct wpi_softc *sc, uint16_t addr, uint32_t data) WPI_WRITE(sc, WPI_WRITE_MEM_DATA, data); } +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. @@ -952,71 +960,65 @@ wpi_read_prom_data(struct wpi_softc *sc, uint32_t addr, void *data, int len) return 0; } +/* + * The firmware boot code is small and is intended to be copied directly into + * the NIC internal memory. + */ int -wpi_load_segment(struct wpi_softc *sc, uint32_t target, const uint8_t *data, - int len) +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; - - DPRINTFN(2, ("loading firmware segment target=%x len=%d\n", target, - len)); - - /* 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); + int ntries; - /* 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); + size /= sizeof (uint32_t); - /* tell adapter where to copy data in its internal memory */ - WPI_WRITE(sc, WPI_FW_TARGET, target); + wpi_mem_lock(sc); - WPI_WRITE(sc, WPI_TX_CONFIG(6), 0); + /* copy microcode image into NIC memory */ + wpi_mem_write_region_4(sc, WPI_MEM_UCODE_BASE, + (const uint32_t *)ucode, size); - /* copy Tx descriptor into NIC memory */ - WPI_WRITE_REGION_4(sc, WPI_TX_DESC(6), (uint32_t *)&desc, - sizeof desc / sizeof (uint32_t)); + 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_CREDIT(6), 0xfffff); - WPI_WRITE(sc, WPI_TX_STATE(6), 0x4001); - WPI_WRITE(sc, WPI_TX_CONFIG(6), 0x80000001); + /* run microcode */ + wpi_mem_write(sc, WPI_MEM_UCODE_CTL, WPI_UC_RUN); - /* wait while the adapter transfers the segment */ - 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) { - printf("%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; } + int wpi_load_firmware(struct wpi_softc *sc) { struct wpi_dma_info *dma = &sc->fw_dma; const 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; u_char *fw; size_t size; - uint32_t tmp; int error; /* load firmware image from disk */ - if ((error = loadfirmware("wpi-ucode", &fw, &size)) != 0) { + if ((error = loadfirmware("wpi-3945abg", &fw, &size)) != 0) { printf("%s: could not read firmware file\n", sc->sc_dev.dv_xname); goto fail1; @@ -1032,38 +1034,25 @@ wpi_load_firmware(struct wpi_softc *sc) hdr = (const struct wpi_firmware_hdr *)fw; main_textsz = letoh32(hdr->main_textsz); main_datasz = letoh32(hdr->main_datasz); + init_textsz = htole32(hdr->init_textsz); + init_datasz = htole32(hdr->init_datasz); boot_textsz = letoh32(hdr->boot_textsz); - boot_datasz = letoh32(hdr->boot_datasz); - /* sanity-check firmware header */ - if (main_textsz > WPI_FW_MAIN_TEXT_MAXSZ) { - printf("%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) { - printf("%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) { - printf("%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) { - printf("%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) { printf("%s: firmware file too short: %d bytes\n", sc->sc_dev.dv_xname, size); error = EINVAL; @@ -1073,45 +1062,55 @@ wpi_load_firmware(struct wpi_softc *sc) /* get pointers to firmware segments */ main_text = (const uint8_t *)(hdr + 1); 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) { - printf("%s: could not load firmware boot .data segment\n", + /* copy initialization images into pre-allocated DMA-safe memory */ + memcpy(dma->vaddr, init_data, init_datasz); + memcpy(dma->vaddr + WPI_FW_INIT_DATA_MAXSZ, init_text, init_textsz); + + /* tell adapter where to find initialization images */ + wpi_mem_lock(sc); + 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 fail2; } - /* load firmware boot .text segment into NIC */ - error = wpi_load_segment(sc, WPI_FW_TEXT, boot_text, boot_textsz); - if (error != 0) { - printf("%s: could not load firmware boot .text segment\n", + /* now press "execute" ;-) */ + WPI_WRITE(sc, WPI_RESET, 0); + + /* wait at most one second for first 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); goto fail2; } - /* copy firmware runtime into pre-allocated DMA-safe memory */ - memcpy(dma->vaddr, main_text, main_textsz); - memcpy(dma->vaddr + main_textsz, main_data, main_datasz); - bus_dmamap_sync(dma->tag, dma->map, 0, main_textsz + main_datasz, - BUS_DMASYNC_PREWRITE); + /* copy runtime images into pre-allocated DMA-safe memory */ + memcpy(dma->vaddr, main_data, main_datasz); + memcpy(dma->vaddr + WPI_FW_MAIN_DATA_MAXSZ, main_text, main_textsz); - /* tell adapter where to find firmware runtime */ + /* tell adapter where to find runtime 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, 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); - /* 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); - - /* ..and wait at most one second for adapter to initialize */ + /* 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", |