Fixes from Steve Woodford:

- add some missing bus_dmamap_sync operations.
	- don't process other interrupts if we get an error/radio off
	  interrupt.
	- improve command handling - sleep against the descriptor instead
	  of the descriptor set.
This commit is contained in:
skrll 2005-11-26 07:42:10 +00:00
parent ca2b187449
commit 535aed4540
1 changed files with 42 additions and 5 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_iwi.c,v 1.40 2005/11/23 20:35:54 skrll Exp $ */
/* $NetBSD: if_iwi.c,v 1.41 2005/11/26 07:42:10 skrll Exp $ */
/*-
* Copyright (c) 2004, 2005
@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_iwi.c,v 1.40 2005/11/23 20:35:54 skrll Exp $");
__KERNEL_RCSID(0, "$NetBSD: if_iwi.c,v 1.41 2005/11/26 07:42:10 skrll Exp $");
/*-
* Intel(R) PRO/Wireless 2200BG/2225BG/2915ABG driver
@ -123,6 +123,7 @@ static void iwi_fix_channel(struct ieee80211com *, struct mbuf *);
static void iwi_frame_intr(struct iwi_softc *, struct iwi_rx_data *, int,
struct iwi_frame *);
static void iwi_notification_intr(struct iwi_softc *, struct iwi_notif *);
static void iwi_cmd_intr(struct iwi_softc *);
static void iwi_rx_intr(struct iwi_softc *);
static void iwi_tx_intr(struct iwi_softc *, struct iwi_tx_ring *);
static int iwi_intr(void *);
@ -559,6 +560,17 @@ fail: iwi_free_cmd_ring(sc, ring);
static void
iwi_reset_cmd_ring(struct iwi_softc *sc, struct iwi_cmd_ring *ring)
{
int i;
for (i = ring->next; i != ring->cur;) {
bus_dmamap_sync(sc->sc_dmat, sc->cmdq.desc_map,
i * IWI_CMD_DESC_SIZE, IWI_CMD_DESC_SIZE,
BUS_DMASYNC_POSTWRITE);
wakeup(&ring->desc[i]);
i = (i + 1) % ring->count;
}
ring->queued = 0;
ring->cur = ring->next = 0;
}
@ -752,6 +764,9 @@ iwi_alloc_rx_ring(struct iwi_softc *sc, struct iwi_rx_ring *ring,
sc->sc_dev.dv_xname);
goto fail;
}
bus_dmamap_sync(sc->sc_dmat, ring->data[i].map, 0,
ring->data[i].map->dm_mapsize, BUS_DMASYNC_PREREAD);
}
return 0;
@ -1378,6 +1393,23 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif)
}
}
static void
iwi_cmd_intr(struct iwi_softc *sc)
{
uint32_t hw;
hw = CSR_READ_4(sc, IWI_CSR_CMD_RIDX);
for (; sc->cmdq.next != hw;) {
bus_dmamap_sync(sc->sc_dmat, sc->cmdq.desc_map,
sc->cmdq.next * IWI_CMD_DESC_SIZE, IWI_CMD_DESC_SIZE,
BUS_DMASYNC_POSTWRITE);
wakeup(&sc->cmdq.desc[sc->cmdq.next]);
sc->cmdq.next = (sc->cmdq.next + 1) % sc->cmdq.count;
}
}
static void
iwi_rx_intr(struct iwi_softc *sc)
{
@ -1411,6 +1443,9 @@ iwi_rx_intr(struct iwi_softc *sc)
sc->sc_dev.dv_xname, hdr->type);
}
bus_dmamap_sync(sc->sc_dmat, data->map, 0,
data->map->dm_mapsize, BUS_DMASYNC_PREREAD);
DPRINTFN(15, ("rx done idx=%u\n", sc->rxq.cur));
sc->rxq.cur = (sc->rxq.cur + 1) % sc->rxq.count;
@ -1475,6 +1510,7 @@ iwi_intr(void *arg)
iwi_error_log(sc);
sc->sc_ic.ic_ifp->if_flags &= ~IFF_UP;
iwi_stop(&sc->sc_if, 1);
return (1);
}
if (r & IWI_INTR_FW_INITED) {
@ -1486,10 +1522,11 @@ iwi_intr(void *arg)
DPRINTF(("radio transmitter off\n"));
sc->sc_ic.ic_ifp->if_flags &= ~IFF_UP;
iwi_stop(&sc->sc_if, 1);
return (1);
}
if (r & IWI_INTR_CMD_DONE)
wakeup(sc);
iwi_cmd_intr(sc);
if (r & IWI_INTR_TX1_DONE)
iwi_tx_intr(sc, &sc->txq[0]);
@ -1533,7 +1570,7 @@ iwi_cmd(struct iwi_softc *sc, uint8_t type, void *data, uint8_t len,
sc->cmdq.cur = (sc->cmdq.cur + 1) % sc->cmdq.count;
CSR_WRITE_4(sc, IWI_CSR_CMD_WIDX, sc->cmdq.cur);
return async ? 0 : tsleep(sc, 0, "iwicmd", hz);
return async ? 0 : tsleep(desc, 0, "iwicmd", hz);
}
static void
@ -2143,7 +2180,7 @@ iwi_load_firmware(struct iwi_softc *sc, void *fw, int size)
aprint_error("%s: timeout processing cb\n",
sc->sc_dev.dv_xname);
error = EIO;
goto fail2;
goto fail3;
}
/* We're done with command blocks processing */