diff options
-rw-r--r-- | sys/dev/pci/if_vic.c | 173 |
1 files changed, 112 insertions, 61 deletions
diff --git a/sys/dev/pci/if_vic.c b/sys/dev/pci/if_vic.c index 91bf199fde5..ddc0807e619 100644 --- a/sys/dev/pci/if_vic.c +++ b/sys/dev/pci/if_vic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_vic.c,v 1.22 2006/11/02 02:17:22 brad Exp $ */ +/* $OpenBSD: if_vic.c,v 1.23 2006/11/02 04:32:59 dlg Exp $ */ /* * Copyright (c) 2006 Reyk Floeter <reyk@openbsd.org> @@ -141,6 +141,7 @@ int vic_map_pci(struct vic_softc *, struct pci_attach_args *); int vic_query(struct vic_softc *); int vic_alloc_data(struct vic_softc *); int vic_init_data(struct vic_softc *sc); +int vic_uninit_data(struct vic_softc *sc); u_int32_t vic_read(struct vic_softc *, bus_size_t); void vic_write(struct vic_softc *, bus_size_t, u_int32_t); @@ -209,11 +210,6 @@ vic_attach(struct device *parent, struct device *self, void *aux) return; } - if (vic_init_data(sc) != 0) { - /* error printed by vic_alloc */ - return; - } - bcopy(sc->sc_lladdr, sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN); ifp = &sc->sc_ac.ac_if; @@ -335,6 +331,11 @@ vic_query(struct vic_softc *sc) int vic_alloc_data(struct vic_softc *sc) { + u_int8_t *kva; + u_int offset; + struct vic_rxdesc *rxd; + int i; + sc->sc_rxbuf = malloc(sizeof(struct vic_rxbuf) * sc->sc_nrxbuf, M_NOWAIT, M_DEVBUF); if (sc->sc_rxbuf == NULL) { @@ -357,6 +358,46 @@ vic_alloc_data(struct vic_softc *sc) printf("%s: unable to allocate dma region\n", DEVNAME(sc)); goto freetx; } + kva = VIC_DMA_KVA(sc); + + /* set up basic vic data */ + sc->sc_data = VIC_DMA_KVA(sc); + + sc->sc_data->vd_magic = VIC_MAGIC; + sc->sc_data->vd_length = sc->sc_dma_size; + + offset = sizeof(struct vic_data); + + /* set up the rx ring */ + sc->sc_rxq = (struct vic_rxdesc *)&kva[offset]; + + sc->sc_data->vd_rx_offset = offset; + sc->sc_data->vd_rx_length = sc->sc_nrxbuf; + + offset += sizeof(struct vic_rxdesc) * sc->sc_nrxbuf; + + /* set up the dummy rx ring 2 with an unusable entry */ + sc->sc_rxq2 = (struct vic_rxdesc *)&kva[offset]; + + sc->sc_data->vd_rx_offset2 = offset; + sc->sc_data->vd_rx_length2 = VIC_QUEUE2_SIZE; + + for (i = 0; i < VIC_QUEUE2_SIZE; i++) { + rxd = &sc->sc_rxq2[i]; + + rxd->rx_physaddr = 0; + rxd->rx_buflength = 0; + rxd->rx_length = 0; + rxd->rx_owner = VIC_OWNER_DRIVER; + + offset += sizeof(struct vic_rxdesc); + } + + /* set up the tx ring */ + sc->sc_txq = (struct vic_txdesc *)&kva[offset]; + + sc->sc_data->vd_tx_offset = offset; + sc->sc_data->vd_tx_length = sc->sc_ntxbuf; return (0); freetx: @@ -370,29 +411,12 @@ err: int vic_init_data(struct vic_softc *sc) { - u_int8_t *kva = VIC_DMA_KVA(sc); - u_int offset; - struct vic_rxbuf *rxb; struct vic_rxdesc *rxd; struct vic_txbuf *txb; int i; - /* set up basic vic data */ - sc->sc_data = VIC_DMA_KVA(sc); - - sc->sc_data->vd_magic = VIC_MAGIC; - sc->sc_data->vd_length = sc->sc_dma_size; - - offset = sizeof(struct vic_data); - - /* set up the rx ring */ - sc->sc_rxq = (struct vic_rxdesc *)&kva[offset]; - - sc->sc_data->vd_rx_offset = offset; - sc->sc_data->vd_rx_length = sc->sc_nrxbuf; - for (i = 0; i < sc->sc_nrxbuf; i++) { rxb = &sc->sc_rxbuf[i]; rxd = &sc->sc_rxq[i]; @@ -418,33 +442,8 @@ vic_init_data(struct vic_softc *sc) rxd->rx_buflength = rxb->rxb_m->m_pkthdr.len; /* XXX? */ rxd->rx_length = 0; rxd->rx_owner = VIC_OWNER_NIC; - - offset += sizeof(struct vic_rxdesc); - } - - /* set up the dummy rx ring 2 with an unusable entry */ - sc->sc_rxq2 = (struct vic_rxdesc *)&kva[offset]; - - sc->sc_data->vd_rx_offset2 = offset; - sc->sc_data->vd_rx_length2 = VIC_QUEUE2_SIZE; - - for (i = 0; i < VIC_QUEUE2_SIZE; i++) { - rxd = &sc->sc_rxq2[i]; - - rxd->rx_physaddr = 0; - rxd->rx_buflength = 0; - rxd->rx_length = 0; - rxd->rx_owner = VIC_OWNER_DRIVER; - - offset += sizeof(struct vic_rxdesc); } - /* set up the tx ring */ - sc->sc_txq = (struct vic_txdesc *)&kva[offset]; - - sc->sc_data->vd_tx_offset = offset; - sc->sc_data->vd_tx_length = sc->sc_ntxbuf; - for (i = 0; i < sc->sc_ntxbuf; i++) { txb = &sc->sc_txbuf[i]; if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, VIC_SG_MAX, @@ -477,6 +476,35 @@ freerxbs: return (1); } +int +vic_uninit_data(struct vic_softc *sc) +{ + struct vic_rxbuf *rxb; + struct vic_rxdesc *rxd; + struct vic_txbuf *txb; + + int i; + + for (i = 0; i < sc->sc_nrxbuf; i++) { + rxb = &sc->sc_rxbuf[i]; + rxd = &sc->sc_rxq[i]; + + bus_dmamap_sync(sc->sc_dmat, rxb->rxb_dmamap, 0, + rxb->rxb_m->m_pkthdr.len, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->sc_dmat, rxb->rxb_dmamap); + bus_dmamap_destroy(sc->sc_dmat, rxb->rxb_dmamap); + + m_freem(rxb->rxb_m); + rxb->rxb_m = NULL; + } + + for (i = 0; i < sc->sc_ntxbuf; i++) { + txb = &sc->sc_txbuf[i]; + bus_dmamap_destroy(sc->sc_dmat, txb->txb_dmamap); + } + + return (0); +} void vic_link_state(struct vic_softc *sc) { @@ -523,6 +551,9 @@ vic_rx_proc(struct vic_softc *sc) struct mbuf *m; int len, idx; + if ((ifp->if_flags & IFF_RUNNING) == 0) + return; + bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_map, 0, sc->sc_dma_size, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); @@ -719,6 +750,9 @@ vic_start(struct ifnet *ifp) int i, idx; int tx = 0; + if (!(ifp->if_flags & IFF_RUNNING)) + return; + if (ifp->if_flags & IFF_OACTIVE) return; @@ -954,21 +988,32 @@ vic_init(struct ifnet *ifp) struct vic_softc *sc = (struct vic_softc *)ifp->if_softc; int s; + if (vic_init_data(sc) != 0) + return; + + sc->sc_data->vd_tx_curidx = 0; + sc->sc_data->vd_tx_nextidx = 0; + sc->sc_data->vd_tx_stopped = sc->sc_data->vd_tx_queued = 0; + + sc->sc_data->vd_rx_nextidx = 0; + sc->sc_data->vd_rx_nextidx2 = 0; + + sc->sc_data->vd_rx_saved_nextidx = 0; + sc->sc_data->vd_rx_saved_nextidx2 = 0; + sc->sc_data->vd_tx_saved_nextidx = 0; + bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_map, 0, sc->sc_dma_size, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); s = splnet(); - vic_write(sc, VIC_DATA_ADDR, VIC_DMA_DVA(sc)); - vic_write(sc, VIC_DATA_LENGTH, sc->sc_dma_size); if (ifp->if_flags & IFF_PROMISC) vic_iff(sc, VIC_CMD_IFF_PROMISC); else vic_iff(sc, VIC_CMD_IFF_BROADCAST | VIC_CMD_IFF_MULTICAST); - sc->sc_data->vd_tx_curidx = 0; - sc->sc_data->vd_tx_nextidx = 0; - sc->sc_data->vd_tx_stopped = sc->sc_data->vd_tx_queued = 0; + vic_write(sc, VIC_DATA_ADDR, VIC_DMA_DVA(sc)); + vic_write(sc, VIC_DATA_LENGTH, sc->sc_dma_size); ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; @@ -981,27 +1026,33 @@ vic_init(struct ifnet *ifp) void vic_stop(struct ifnet *ifp) { -#if 0 struct vic_softc *sc = (struct vic_softc *)ifp->if_softc; int s; s = splnet(); - sc->sc_txtimeout = 0; ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); -#ifdef notyet + bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_map, 0, sc->sc_dma_size, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + + /* XXX wait for tx to complete */ + while (sc->sc_txpending > 0) { + splx(s); + delay(1000); + s = splnet(); + } + + sc->sc_data->vd_tx_stopped = 1; + vic_write(sc, VIC_CMD, VIC_CMD_INTR_DISABLE); -#endif - vic_write(sc, VIC_DATA_ADDR, 0); vic_iff(sc, 0); + vic_write(sc, VIC_DATA_ADDR, 0); - sc->sc_data->vd_tx_stopped = 1; - timeout_del(&sc->sc_timer); + vic_uninit_data(sc); splx(s); -#endif } struct mbuf * |