summaryrefslogtreecommitdiff
path: root/sys/dev/pci/if_vic.c
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2008-11-24 16:13:48 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2008-11-24 16:13:48 +0000
commitada0637547df4a374f7d1f90ba562de57bbf2ec2 (patch)
tree43d58b7357f38a3db44e3cc54012bd3b31e5c0b7 /sys/dev/pci/if_vic.c
parent2f36575b807cf54b4ee51ddafb34e8498f53df97 (diff)
enable the use of the second rx ring. populate it with 4k frames until the
9k backend allocator is available. vic is the first driver to properly support "jumbo" frames. this is the model every other driver should follow.
Diffstat (limited to 'sys/dev/pci/if_vic.c')
-rw-r--r--sys/dev/pci/if_vic.c264
1 files changed, 133 insertions, 131 deletions
diff --git a/sys/dev/pci/if_vic.c b/sys/dev/pci/if_vic.c
index 2f3ccc9e8e0..df25dc0bb53 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.58 2008/11/24 13:10:16 dlg Exp $ */
+/* $OpenBSD: if_vic.c,v 1.59 2008/11/24 16:13:47 dlg Exp $ */
/*
* Copyright (c) 2006 Reyk Floeter <reyk@openbsd.org>
@@ -185,13 +185,15 @@ struct vic_stats {
u_int32_t vs_rx_underrun;
} __packed;
+#define VIC_NRXRINGS 2
+
struct vic_data {
u_int32_t vd_magic;
- u_int32_t vd_rx_length;
- u_int32_t vd_rx_nextidx;
- u_int32_t vd_rx_length2;
- u_int32_t vd_rx_nextidx2;
+ struct {
+ u_int32_t length;
+ u_int32_t nextidx;
+ } vd_rx[VIC_NRXRINGS];
u_int32_t vd_irq;
u_int32_t vd_iff;
@@ -210,13 +212,11 @@ struct vic_data {
u_int32_t vd_reserved2[6];
- u_int32_t vd_rx_saved_nextidx;
- u_int32_t vd_rx_saved_nextidx2;
+ u_int32_t vd_rx_saved_nextidx[VIC_NRXRINGS];
u_int32_t vd_tx_saved_nextidx;
u_int32_t vd_length;
- u_int32_t vd_rx_offset;
- u_int32_t vd_rx_offset2;
+ u_int32_t vd_rx_offset[VIC_NRXRINGS];
u_int32_t vd_tx_offset;
u_int32_t vd_debug;
u_int32_t vd_tx_physaddr;
@@ -290,13 +290,13 @@ struct vic_softc {
struct vic_data *sc_data;
- struct vic_rxbuf *sc_rxbuf;
- struct vic_rxdesc *sc_rxq;
- int sc_rxq_end;
- int sc_rxq_len;
- struct vic_rxdesc *sc_rxq2;
- int sc_rxq_end2;
- int sc_rxq_len2;
+ struct {
+ struct vic_rxbuf *bufs;
+ struct vic_rxdesc *slots;
+ int end;
+ int len;
+ u_int pktlen;
+ } sc_rxq[VIC_NRXRINGS];
struct vic_txbuf *sc_txbuf;
struct vic_txdesc *sc_txq;
@@ -331,8 +331,8 @@ int vic_alloc_dmamem(struct vic_softc *);
void vic_free_dmamem(struct vic_softc *);
void vic_link_state(struct vic_softc *);
-void vic_rx_fill(struct vic_softc *);
-void vic_rx_proc(struct vic_softc *);
+void vic_rx_fill(struct vic_softc *, int);
+void vic_rx_proc(struct vic_softc *, int);
void vic_tx_proc(struct vic_softc *);
void vic_iff(struct vic_softc *);
void vic_getlladdr(struct vic_softc *);
@@ -350,7 +350,7 @@ void vic_tick(void *);
#define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
-struct mbuf *vic_alloc_mbuf(struct vic_softc *, bus_dmamap_t);
+struct mbuf *vic_alloc_mbuf(struct vic_softc *, bus_dmamap_t, u_int);
const struct pci_matchid vic_devices[] = {
{ PCI_VENDOR_VMWARE, PCI_PRODUCT_VMWARE_NET }
@@ -563,13 +563,18 @@ vic_alloc_data(struct vic_softc *sc)
u_int8_t *kva;
u_int offset;
struct vic_rxdesc *rxd;
- int i;
+ int i, q;
- sc->sc_rxbuf = malloc(sizeof(struct vic_rxbuf) * sc->sc_nrxbuf,
- M_DEVBUF, M_NOWAIT);
- if (sc->sc_rxbuf == NULL) {
- printf(": unable to allocate rxbuf\n");
- goto err;
+ sc->sc_rxq[0].pktlen = MCLBYTES;
+ sc->sc_rxq[1].pktlen = 4096; /* XXX VIC_JUMBO_FRAMELEN; */
+
+ for (q = 0; q < VIC_NRXRINGS; q++) {
+ sc->sc_rxq[q].bufs = malloc(sizeof(struct vic_rxbuf) *
+ sc->sc_nrxbuf, M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (sc->sc_rxq[i].bufs == NULL) {
+ printf(": unable to allocate rxbuf for ring %d\n", q);
+ goto freerx;
+ }
}
sc->sc_txbuf = malloc(sizeof(struct vic_txbuf) * sc->sc_ntxbuf,
@@ -598,37 +603,22 @@ vic_alloc_data(struct vic_softc *sc)
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++) {
- rxd = &sc->sc_rxq[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 dummy rx ring 2 with an unusable entry */
- sc->sc_rxq2 = (struct vic_rxdesc *)&kva[offset];
+ for (q = 0; q < VIC_NRXRINGS; q++) {
+ sc->sc_rxq[q].slots = (struct vic_rxdesc *)&kva[offset];
+ sc->sc_data->vd_rx_offset[q] = offset;
+ sc->sc_data->vd_rx[q].length = sc->sc_nrxbuf;
- sc->sc_data->vd_rx_offset2 = offset;
- sc->sc_data->vd_rx_length2 = VIC_QUEUE2_SIZE;
+ for (i = 0; i < sc->sc_nrxbuf; i++) {
+ rxd = &sc->sc_rxq[q].slots[i];
- 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;
+ rxd->rx_physaddr = 0;
+ rxd->rx_buflength = 0;
+ rxd->rx_length = 0;
+ rxd->rx_owner = VIC_OWNER_DRIVER;
- offset += sizeof(struct vic_rxdesc);
+ offset += sizeof(struct vic_rxdesc);
+ }
}
/* set up the tx ring */
@@ -640,23 +630,26 @@ vic_alloc_data(struct vic_softc *sc)
return (0);
freetx:
free(sc->sc_txbuf, M_DEVBUF);
+ q = VIC_NRXRINGS;
freerx:
- free(sc->sc_rxbuf, M_DEVBUF);
-err:
+ while (q--)
+ free(sc->sc_rxq[q].bufs, M_DEVBUF);
+
return (1);
}
void
-vic_rx_fill(struct vic_softc *sc)
+vic_rx_fill(struct vic_softc *sc, int q)
{
struct vic_rxbuf *rxb;
struct vic_rxdesc *rxd;
- while (sc->sc_rxq_len < sc->sc_data->vd_rx_length) {
- rxb = &sc->sc_rxbuf[sc->sc_rxq_end];
- rxd = &sc->sc_rxq[sc->sc_rxq_end];
+ while (sc->sc_rxq[q].len < sc->sc_data->vd_rx[q].length) {
+ rxb = &sc->sc_rxq[q].bufs[sc->sc_rxq[q].end];
+ rxd = &sc->sc_rxq[q].slots[sc->sc_rxq[q].end];
- rxb->rxb_m = vic_alloc_mbuf(sc, rxb->rxb_dmamap);
+ rxb->rxb_m = vic_alloc_mbuf(sc, rxb->rxb_dmamap,
+ sc->sc_rxq[q].pktlen);
if (rxb->rxb_m == NULL)
break;
@@ -668,8 +661,8 @@ vic_rx_fill(struct vic_softc *sc)
rxd->rx_length = 0;
rxd->rx_owner = VIC_OWNER_NIC;
- VIC_INC(sc->sc_rxq_end, sc->sc_data->vd_rx_length);
- sc->sc_rxq_len++;
+ VIC_INC(sc->sc_rxq[q].end, sc->sc_data->vd_rx[q].length);
+ sc->sc_rxq[q].len++;
}
}
@@ -680,35 +673,39 @@ vic_init_data(struct vic_softc *sc)
struct vic_rxdesc *rxd;
struct vic_txbuf *txb;
- int i;
+ int q, i;
- for (i = 0; i < sc->sc_nrxbuf; i++) {
- rxb = &sc->sc_rxbuf[i];
- rxd = &sc->sc_rxq[i];
+ for (q = 0; q < VIC_NRXRINGS; q++) {
+ for (i = 0; i < sc->sc_nrxbuf; i++) {
+ rxb = &sc->sc_rxq[q].bufs[i];
+ rxd = &sc->sc_rxq[q].slots[i];
- if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
- MCLBYTES, 0, BUS_DMA_NOWAIT, &rxb->rxb_dmamap) != 0) {
- printf("%s: unable to create dmamap for rxb %d\n",
- DEVNAME(sc), i);
- goto freerxbs;
+ if (bus_dmamap_create(sc->sc_dmat,
+ sc->sc_rxq[q].pktlen, 1, sc->sc_rxq[q].pktlen, 0,
+ BUS_DMA_NOWAIT, &rxb->rxb_dmamap) != 0) {
+ printf("%s: unable to create dmamap for "
+ "ring %d slot %d\n", DEVNAME(sc), q, i);
+ goto freerxbs;
+ }
+
+ /* scrub the ring */
+ rxd->rx_physaddr = 0;
+ rxd->rx_buflength = 0;
+ rxd->rx_length = 0;
+ rxd->rx_owner = VIC_OWNER_DRIVER;
}
- /* scrub the ring */
- rxd->rx_physaddr = 0;
- rxd->rx_buflength = 0;
- rxd->rx_length = 0;
- rxd->rx_owner = VIC_OWNER_DRIVER;
+ sc->sc_rxq[q].len = 0;
+ sc->sc_rxq[q].end = 0;
+ vic_rx_fill(sc, q);
}
- sc->sc_rxq_len = 0;
- sc->sc_rxq_end = 0;
- vic_rx_fill(sc);
-
for (i = 0; i < sc->sc_ntxbuf; i++) {
txb = &sc->sc_txbuf[i];
- if (bus_dmamap_create(sc->sc_dmat, MCLBYTES,
+ if (bus_dmamap_create(sc->sc_dmat, VIC_JUMBO_FRAMELEN,
(sc->sc_cap & VIC_CMD_HWCAP_SG) ? VIC_SG_MAX : 1,
- MCLBYTES, 0, BUS_DMA_NOWAIT, &txb->txb_dmamap) != 0) {
+ VIC_JUMBO_FRAMELEN, 0, BUS_DMA_NOWAIT,
+ &txb->txb_dmamap) != 0) {
printf("%s: unable to create dmamap for tx %d\n",
DEVNAME(sc), i);
goto freetxbs;
@@ -725,19 +722,23 @@ freetxbs:
}
i = sc->sc_nrxbuf;
+ q = VIC_NRXRINGS;
freerxbs:
- while (i--) {
- rxb = &sc->sc_rxbuf[i];
-
- if (rxb->rxb_m != NULL) {
- 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);
- m_freem(rxb->rxb_m);
- rxb->rxb_m = NULL;
+ do {
+ while (i--) {
+ rxb = &sc->sc_rxq[q].bufs[i];
+
+ if (rxb->rxb_m != NULL) {
+ 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);
+ m_freem(rxb->rxb_m);
+ rxb->rxb_m = NULL;
+ }
+ bus_dmamap_destroy(sc->sc_dmat, rxb->rxb_dmamap);
}
- bus_dmamap_destroy(sc->sc_dmat, rxb->rxb_dmamap);
- }
+ } while (--q);
return (1);
}
@@ -749,20 +750,23 @@ vic_uninit_data(struct vic_softc *sc)
struct vic_rxdesc *rxd;
struct vic_txbuf *txb;
- int i;
+ int i, q;
- for (i = 0; i < sc->sc_nrxbuf; i++) {
- rxb = &sc->sc_rxbuf[i];
- rxd = &sc->sc_rxq[i];
+ for (q = 0; q < VIC_NRXRINGS; q++) {
+ for (i = 0; i < sc->sc_nrxbuf; i++) {
+ rxb = &sc->sc_rxq[q].bufs[i];
+ rxd = &sc->sc_rxq[q].slots[i];
- if (rxb->rxb_m != NULL) {
- 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);
- m_freem(rxb->rxb_m);
- rxb->rxb_m = NULL;
+ if (rxb->rxb_m != NULL) {
+ 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);
+ m_freem(rxb->rxb_m);
+ rxb->rxb_m = NULL;
+ }
+ bus_dmamap_destroy(sc->sc_dmat, rxb->rxb_dmamap);
}
- bus_dmamap_destroy(sc->sc_dmat, rxb->rxb_dmamap);
}
for (i = 0; i < sc->sc_ntxbuf; i++) {
@@ -801,8 +805,10 @@ int
vic_intr(void *arg)
{
struct vic_softc *sc = (struct vic_softc *)arg;
+ int q;
- vic_rx_proc(sc);
+ for (q = 0; q < VIC_NRXRINGS; q++)
+ vic_rx_proc(sc, q);
vic_tx_proc(sc);
vic_write(sc, VIC_CMD, VIC_CMD_INTR_ACK);
@@ -811,7 +817,7 @@ vic_intr(void *arg)
}
void
-vic_rx_proc(struct vic_softc *sc)
+vic_rx_proc(struct vic_softc *sc, int q)
{
struct ifnet *ifp = &sc->sc_ac.ac_if;
struct vic_rxdesc *rxd;
@@ -825,9 +831,9 @@ vic_rx_proc(struct vic_softc *sc)
bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_map, 0, sc->sc_dma_size,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
- while (sc->sc_rxq_len > 0) {
- idx = sc->sc_data->vd_rx_nextidx;
- if (idx >= sc->sc_data->vd_rx_length) {
+ while (sc->sc_rxq[q].len > 0) {
+ idx = sc->sc_data->vd_rx[q].nextidx;
+ if (idx >= sc->sc_data->vd_rx[q].length) {
ifp->if_ierrors++;
if (ifp->if_flags & IFF_DEBUG)
printf("%s: receive index error\n",
@@ -835,11 +841,11 @@ vic_rx_proc(struct vic_softc *sc)
break;
}
- rxd = &sc->sc_rxq[idx];
+ rxd = &sc->sc_rxq[q].slots[idx];
if (rxd->rx_owner != VIC_OWNER_DRIVER)
break;
- rxb = &sc->sc_rxbuf[idx];
+ rxb = &sc->sc_rxq[q].bufs[idx];
if (rxb->rxb_m == NULL) {
ifp->if_ierrors++;
@@ -851,22 +857,17 @@ vic_rx_proc(struct vic_softc *sc)
rxb->rxb_m->m_pkthdr.len, BUS_DMASYNC_POSTREAD);
bus_dmamap_unload(sc->sc_dmat, rxb->rxb_dmamap);
+ m = rxb->rxb_m;
+ rxb->rxb_m = NULL;
len = rxd->rx_length;
+
if (len < VIC_MIN_FRAMELEN) {
- m = rxb->rxb_m;
m_freem(m);
- rxd->rx_owner = VIC_OWNER_DRIVER;
- rxd->rx_length = 0;
-
- rxb->rxb_m = NULL;
-
ifp->if_iqdrops++;
goto nextp;
}
- m = rxb->rxb_m;
- rxb->rxb_m = NULL;
m->m_pkthdr.rcvif = ifp;
m->m_pkthdr.len = m->m_len = len;
@@ -880,11 +881,12 @@ vic_rx_proc(struct vic_softc *sc)
ether_input_mbuf(ifp, m);
nextp:
- sc->sc_rxq_len--;
- VIC_INC(sc->sc_data->vd_rx_nextidx, sc->sc_data->vd_rx_length);
+ sc->sc_rxq[q].len--;
+ VIC_INC(sc->sc_data->vd_rx[q].nextidx,
+ sc->sc_data->vd_rx[q].length);
}
- vic_rx_fill(sc);
+ vic_rx_fill(sc, q);
bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_map, 0, sc->sc_dma_size,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
@@ -1159,7 +1161,7 @@ vic_load_txb(struct vic_softc *sc, struct vic_txbuf *txb, struct mbuf *m)
if (m0 == NULL)
return (ENOBUFS);
if (m->m_pkthdr.len > MHLEN) {
- MCLGET(m0, M_DONTWAIT);
+ MCLGETI(m0, M_DONTWAIT, NULL, m->m_pkthdr.len);
if (!(m0->m_flags & M_EXT)) {
m_freem(m0);
return (ENOBUFS);
@@ -1284,19 +1286,19 @@ void
vic_init(struct ifnet *ifp)
{
struct vic_softc *sc = (struct vic_softc *)ifp->if_softc;
+ int q;
int s;
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;
+ for (q = 0; q < VIC_NRXRINGS; q++) {
+ sc->sc_data->vd_rx[q].nextidx = 0;
+ sc->sc_data->vd_rx_saved_nextidx[q] = 0;
+ }
+
if (vic_init_data(sc) != 0)
return;
@@ -1354,7 +1356,7 @@ vic_stop(struct ifnet *ifp)
}
struct mbuf *
-vic_alloc_mbuf(struct vic_softc *sc, bus_dmamap_t map)
+vic_alloc_mbuf(struct vic_softc *sc, bus_dmamap_t map, u_int pktlen)
{
struct mbuf *m = NULL;
@@ -1362,13 +1364,13 @@ vic_alloc_mbuf(struct vic_softc *sc, bus_dmamap_t map)
if (m == NULL)
return (NULL);
- MCLGETI(m, M_DONTWAIT, &sc->sc_ac.ac_if, MCLBYTES);
+ MCLGETI(m, M_DONTWAIT, &sc->sc_ac.ac_if, pktlen);
if ((m->m_flags & M_EXT) == 0) {
m_freem(m);
return (NULL);
}
m->m_data += ETHER_ALIGN;
- m->m_len = m->m_pkthdr.len = MCLBYTES - ETHER_ALIGN;
+ m->m_len = m->m_pkthdr.len = pktlen - ETHER_ALIGN;
if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT) != 0) {
printf("%s: could not load mbuf DMA map", DEVNAME(sc));