diff options
-rw-r--r-- | share/man/man4/wpi.4 | 9 | ||||
-rw-r--r-- | sys/dev/pci/if_wpi.c | 187 | ||||
-rw-r--r-- | sys/dev/pci/if_wpireg.h | 25 |
3 files changed, 112 insertions, 109 deletions
diff --git a/share/man/man4/wpi.4 b/share/man/man4/wpi.4 index fbb61130d21..a4524e691e1 100644 --- a/share/man/man4/wpi.4 +++ b/share/man/man4/wpi.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: wpi.4,v 1.11 2007/06/06 18:17:14 damien Exp $ +.\" $OpenBSD: wpi.4,v 1.12 2007/07/10 18:29:38 damien Exp $ .\" .\" Copyright (c) 2006, 2007 .\" Damien Bergamini <damien.bergamini@free.fr>. All rights reserved. @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd $Mdocdate: June 6 2007 $ +.Dd $Mdocdate: July 10 2007 $ .Os .Dt WPI 4 .Sh NAME @@ -70,6 +70,7 @@ sole mechanism to secure wireless communication. WEP is not enabled by default. .Pp The device has one temperature sensor. +Its value is in the range from 0 (coolest) to 285 (warmest). Sensor data is updated every 500 milliseconds. .Sh CONFIGURATION The @@ -176,7 +177,7 @@ Disable WEP encryption. This is the default mode of operation. .El .Sh FILES -The driver needs at least version 2.14.3 of the following firmware file, +The driver needs at least version 2.14.4 of the following firmware file, which is loaded when an interface is brought up: .Pp .Bl -tag -width Ds -offset indent -compact @@ -196,7 +197,7 @@ A prepackaged version of the firmware, designed to be used with .Xr pkg_add 1 , can be found at: .Pp -.Pa http://damien.bergamini.free.fr/packages/openbsd/wpi-firmware-2.14.3.tgz +.Pa http://damien.bergamini.free.fr/packages/openbsd/wpi-firmware-2.14.4.tgz .Sh EXAMPLES The following .Xr hostname.if 5 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", diff --git a/sys/dev/pci/if_wpireg.h b/sys/dev/pci/if_wpireg.h index 9945d897ff6..110bac8c735 100644 --- a/sys/dev/pci/if_wpireg.h +++ b/sys/dev/pci/if_wpireg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_wpireg.h,v 1.15 2007/06/16 14:15:37 damien Exp $ */ +/* $OpenBSD: if_wpireg.h,v 1.16 2007/07/10 18:29:38 damien Exp $ */ /*- * Copyright (c) 2006, 2007 @@ -49,7 +49,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 @@ -92,10 +91,10 @@ #define WPI_MEM_UCODE_SIZE 0x340c #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 */ @@ -108,9 +107,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) @@ -143,7 +141,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) @@ -571,14 +570,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; } __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. |