summaryrefslogtreecommitdiff
path: root/sys/dev/pci/if_wpi.c
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2007-07-10 18:29:39 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2007-07-10 18:29:39 +0000
commit9f98df60eea2ecd2a8243b7106fcdee213dbd661 (patch)
tree222447d0a9aa474ba0cae1488028a7dbadba2a15 /sys/dev/pci/if_wpi.c
parent89f1af237ffa6abb21d3a33b8d7c07fbb51436ae (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.c187
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",