summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2019-10-26 23:40:30 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2019-10-26 23:40:30 +0000
commit5bf68ca5b136300ba765cab751964b68d6e18b70 (patch)
tree8959804586aafe462cae7db6a277ecbb63a9bf93 /sys
parentd1e7983d035ff489de69556cd484fe089acf7e4b (diff)
make vmx transmit (vmxnet3_start) mpsafe.
to make mpsafetey a bit easier to figure out i disabled checksum and vlan offload. i'll put them back in soon though.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pci/if_vmx.c247
-rw-r--r--sys/dev/pci/if_vmxreg.h6
2 files changed, 104 insertions, 149 deletions
diff --git a/sys/dev/pci/if_vmx.c b/sys/dev/pci/if_vmx.c
index a9693f0e5aa..1e03126f879 100644
--- a/sys/dev/pci/if_vmx.c
+++ b/sys/dev/pci/if_vmx.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_vmx.c,v 1.51 2019/10/26 23:01:33 dlg Exp $ */
+/* $OpenBSD: if_vmx.c,v 1.52 2019/10/26 23:40:29 dlg Exp $ */
/*
* Copyright (c) 2013 Tsubai Masanari
@@ -53,16 +53,18 @@
#define VMXNET3_DRIVER_VERSION 0x00010000
+#define VMX_TX_GEN htole32(VMXNET3_TX_GEN_M << VMXNET3_TX_GEN_S)
+#define VMX_TXC_GEN htole32(VMXNET3_TXC_GEN_M << VMXNET3_TXC_GEN_S)
+
struct vmxnet3_softc;
struct vmxnet3_txring {
struct mbuf *m[NTXDESC];
bus_dmamap_t dmap[NTXDESC];
struct vmxnet3_txdesc *txd;
+ u_int32_t gen;
u_int prod;
u_int cons;
- u_int free;
- u_int8_t gen;
};
struct vmxnet3_rxring {
@@ -84,7 +86,7 @@ struct vmxnet3_comp_ring {
struct vmxnet3_rxcompdesc *rxcd;
};
u_int next;
- u_int8_t gen;
+ u_int32_t gen;
};
struct vmxnet3_txqueue {
@@ -172,7 +174,7 @@ void vmxnet3_stop(struct ifnet *);
void vmxnet3_reset(struct vmxnet3_softc *);
int vmxnet3_init(struct vmxnet3_softc *);
int vmxnet3_ioctl(struct ifnet *, u_long, caddr_t);
-void vmxnet3_start(struct ifnet *);
+void vmxnet3_start(struct ifqueue *);
int vmxnet3_load_mbuf(struct vmxnet3_softc *, struct vmxnet3_txring *,
struct mbuf **);
void vmxnet3_watchdog(struct ifnet *);
@@ -289,15 +291,18 @@ vmxnet3_attach(struct device *parent, struct device *self, void *aux)
strlcpy(ifp->if_xname, self->dv_xname, IFNAMSIZ);
ifp->if_softc = sc;
ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX;
+ ifp->if_xflags = IFXF_MPSAFE;
ifp->if_ioctl = vmxnet3_ioctl;
- ifp->if_start = vmxnet3_start;
+ ifp->if_qstart = vmxnet3_start;
ifp->if_watchdog = vmxnet3_watchdog;
ifp->if_hardmtu = VMXNET3_MAX_MTU;
ifp->if_capabilities = IFCAP_VLAN_MTU;
+#if 0
if (sc->sc_ds->upt_features & UPT1_F_CSUM)
ifp->if_capabilities |= IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4;
if (sc->sc_ds->upt_features & UPT1_F_VLAN)
ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
+#endif
IFQ_SET_MAXLEN(&ifp->if_snd, NTXDESC);
@@ -415,7 +420,7 @@ vmxnet3_alloc_txring(struct vmxnet3_softc *sc, int queue)
for (idx = 0; idx < NTXDESC; idx++) {
if (bus_dmamap_create(sc->sc_dmat, JUMBO_LEN, NTXSEGS,
- JUMBO_LEN, 0, BUS_DMA_NOWAIT, &ring->dmap[idx]))
+ VMXNET3_TX_LEN_M + 1, 0, BUS_DMA_NOWAIT, &ring->dmap[idx]))
return -1;
}
@@ -494,10 +499,9 @@ vmxnet3_txinit(struct vmxnet3_softc *sc, struct vmxnet3_txqueue *tq)
struct vmxnet3_comp_ring *comp_ring = &tq->comp_ring;
ring->cons = ring->prod = 0;
- ring->free = NTXDESC;
- ring->gen = 1;
+ ring->gen = VMX_TX_GEN;
comp_ring->next = 0;
- comp_ring->gen = 1;
+ comp_ring->gen = VMX_TXC_GEN;
bzero(ring->txd, NTXDESC * sizeof ring->txd[0]);
bzero(comp_ring->txcd, NTXCOMPDESC * sizeof comp_ring->txcd[0]);
}
@@ -718,28 +722,31 @@ vmxnet3_evintr(struct vmxnet3_softc *sc)
void
vmxnet3_txintr(struct vmxnet3_softc *sc, struct vmxnet3_txqueue *tq)
{
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
struct vmxnet3_txring *ring = &tq->cmd_ring;
struct vmxnet3_comp_ring *comp_ring = &tq->comp_ring;
struct vmxnet3_txcompdesc *txcd;
- struct ifnet *ifp = &sc->sc_arpcom.ac_if;
bus_dmamap_t map;
struct mbuf *m;
- u_int cons;
- u_int free = 0;
+ u_int cons, next;
+ uint32_t rgen;
cons = ring->cons;
+ if (cons == ring->prod)
+ return;
- for (;;) {
- txcd = &comp_ring->txcd[comp_ring->next];
+ next = comp_ring->next;
+ rgen = comp_ring->gen;
- if (letoh32((txcd->txc_word3 >> VMXNET3_TXC_GEN_S) &
- VMXNET3_TXC_GEN_M) != comp_ring->gen)
+ /* postread */
+ for (;;) {
+ txcd = &comp_ring->txcd[next];
+ if ((txcd->txc_word3 & VMX_TXC_GEN) != rgen)
break;
- comp_ring->next++;
- if (comp_ring->next == NTXCOMPDESC) {
- comp_ring->next = 0;
- comp_ring->gen ^= 1;
+ if (++next == NTXCOMPDESC) {
+ next = 0;
+ rgen ^= VMX_TXC_GEN;
}
m = ring->m[cons];
@@ -748,26 +755,22 @@ vmxnet3_txintr(struct vmxnet3_softc *sc, struct vmxnet3_txqueue *tq)
KASSERT(m != NULL);
map = ring->dmap[cons];
- free += map->dm_nsegs;
bus_dmamap_unload(sc->sc_dmat, map);
m_freem(m);
- cons = (letoh32((txcd->txc_word0 >>
- VMXNET3_TXC_EOPIDX_S) & VMXNET3_TXC_EOPIDX_M) + 1)
- % NTXDESC;
+ cons = (letoh32(txcd->txc_word0) >> VMXNET3_TXC_EOPIDX_S) &
+ VMXNET3_TXC_EOPIDX_M;
+ cons++;
+ cons %= NTXDESC;
}
+ /* preread */
+ comp_ring->next = next;
+ comp_ring->gen = rgen;
ring->cons = cons;
- if (atomic_add_int_nv(&ring->free, free) == NTXDESC)
- ifp->if_timer = 0;
-
- if (ifq_is_oactive(&ifp->if_snd)) {
- KERNEL_LOCK();
- ifq_clr_oactive(&ifp->if_snd);
- vmxnet3_start(ifp);
- KERNEL_UNLOCK();
- }
+ if (ifq_is_oactive(&ifp->if_snd))
+ ifq_restart(&ifp->if_snd);
}
void
@@ -1113,38 +1116,64 @@ vmxnet3_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
return error;
}
+static inline int
+vmx_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m)
+{
+ int error;
+
+ error = bus_dmamap_load_mbuf(dmat, map, m,
+ BUS_DMA_STREAMING | BUS_DMA_NOWAIT);
+ if (error != EFBIG)
+ return (error);
+
+ error = m_defrag(m, M_DONTWAIT);
+ if (error != 0)
+ return (error);
+
+ return (bus_dmamap_load_mbuf(dmat, map, m,
+ BUS_DMA_STREAMING | BUS_DMA_NOWAIT));
+}
+
void
-vmxnet3_start(struct ifnet *ifp)
+vmxnet3_start(struct ifqueue *ifq)
{
+ struct ifnet *ifp = ifq->ifq_if;
struct vmxnet3_softc *sc = ifp->if_softc;
struct vmxnet3_txqueue *tq = sc->sc_txq;
struct vmxnet3_txring *ring = &tq->cmd_ring;
- struct vmxnet3_txdesc *txd;
+ struct vmxnet3_txdesc *txd, *sop;
+ bus_dmamap_t map;
+ unsigned int prod, free, i;
+ unsigned int post = 0;
+ uint32_t rgen, gen;
+
struct mbuf *m;
- u_int free, used;
- int n;
- if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
- return;
+ free = ring->cons;
+ prod = ring->prod;
+ if (free <= prod)
+ free += NTXDESC;
+ free -= prod;
- free = ring->free;
- used = 0;
+ sop = &ring->txd[prod];
+ rgen = ring->gen;
+ gen = rgen ^ VMX_TX_GEN;
for (;;) {
- if (used + NTXSEGS > free) {
- ifq_set_oactive(&ifp->if_snd);
+ if (free <= NTXSEGS) {
+ ifq_set_oactive(ifq);
break;
}
- IFQ_DEQUEUE(&ifp->if_snd, m);
+ m = ifq_dequeue(ifq);
if (m == NULL)
break;
- txd = &ring->txd[ring->prod];
+ map = ring->dmap[prod];
- n = vmxnet3_load_mbuf(sc, ring, &m);
- if (n == -1) {
- ifp->if_oerrors++;
+ if (vmx_load_mbuf(sc->sc_dmat, map, m) != 0) {
+ ifq->ifq_errors++;
+ m_freem(m);
continue;
}
@@ -1153,115 +1182,41 @@ vmxnet3_start(struct ifnet *ifp)
bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT);
#endif
- /* Change the ownership by flipping the "generation" bit */
- txd->tx_word2 ^= htole32(VMXNET3_TX_GEN_M << VMXNET3_TX_GEN_S);
+ ring->m[prod] = m;
- used += n;
- }
+ bus_dmamap_sync(sc->sc_dmat, map, 0,
+ map->dm_mapsize, BUS_DMASYNC_PREWRITE);
- if (used > 0) {
- ifp->if_timer = 5;
- atomic_sub_int(&ring->free, used);
- WRITE_BAR0(sc, VMXNET3_BAR0_TXH(0), ring->prod);
- }
-}
-
-int
-vmxnet3_load_mbuf(struct vmxnet3_softc *sc, struct vmxnet3_txring *ring,
- struct mbuf **mp)
-{
- struct vmxnet3_txdesc *txd, *sop;
- struct mbuf *n, *m = *mp;
- bus_dmamap_t map;
- u_int hlen = ETHER_HDR_LEN, csum_off;
- u_int prod;
- int gen, i;
-
- prod = ring->prod;
- map = ring->dmap[prod];
-#if 0
- if (m->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT) {
- printf("%s: IP checksum offloading is not supported\n",
- sc->sc_dev.dv_xname);
- return -1;
- }
-#endif
- if (m->m_pkthdr.csum_flags & (M_TCP_CSUM_OUT|M_UDP_CSUM_OUT)) {
- struct ip *ip;
- int offp;
-
- if (m->m_pkthdr.csum_flags & M_TCP_CSUM_OUT)
- csum_off = offsetof(struct tcphdr, th_sum);
- else
- csum_off = offsetof(struct udphdr, uh_sum);
-
- n = m_pulldown(m, hlen, sizeof(*ip), &offp);
- if (n == NULL)
- return (-1);
+ for (i = 0; i < map->dm_nsegs; i++) {
+ txd = &ring->txd[prod];
+ txd->tx_addr = htole64(map->dm_segs[i].ds_addr);
+ txd->tx_word2 = htole32(map->dm_segs[i].ds_len <<
+ VMXNET3_TX_LEN_S) | gen;
+ txd->tx_word3 = 0;
- ip = (struct ip *)(n->m_data + offp);
- hlen += ip->ip_hl << 2;
-
- *mp = m_pullup(m, hlen + csum_off + 2);
- if (*mp == NULL)
- return (-1);
- m = *mp;
- }
-
- switch (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT)) {
- case 0:
- break;
- case EFBIG:
- if (m_defrag(m, M_DONTWAIT) == 0 &&
- bus_dmamap_load_mbuf(sc->sc_dmat, map, m,
- BUS_DMA_NOWAIT) == 0)
- break;
-
- /* FALLTHROUGH */
- default:
- m_freem(m);
- return -1;
- }
-
- ring->m[prod] = m;
+ if (++prod == NTXDESC) {
+ prod = 0;
+ rgen ^= VMX_TX_GEN;
+ }
- sop = &ring->txd[prod];
- gen = ring->gen ^ 1; /* owned by cpu (yet) */
-
- for (i = 0; i < map->dm_nsegs; i++) {
- txd = &ring->txd[prod];
- txd->tx_addr = htole64(map->dm_segs[i].ds_addr);
- txd->tx_word2 = htole32(((map->dm_segs[i].ds_len &
- VMXNET3_TX_LEN_M) << VMXNET3_TX_LEN_S) |
- ((gen & VMXNET3_TX_GEN_M) << VMXNET3_TX_GEN_S));
- txd->tx_word3 = 0;
-
- if (++prod == NTXDESC) {
- prod = 0;
- ring->gen ^= 1;
+ gen = rgen;
}
+ txd->tx_word3 = htole32(VMXNET3_TX_EOP | VMXNET3_TX_COMPREQ);
- gen = ring->gen;
+ free -= i;
+ post = 1;
}
- txd->tx_word3 |= htole32(VMXNET3_TX_EOP | VMXNET3_TX_COMPREQ);
- if (m->m_flags & M_VLANTAG) {
- sop->tx_word3 |= htole32(VMXNET3_TX_VTAG_MODE);
- sop->tx_word3 |= htole32((m->m_pkthdr.ether_vtag &
- VMXNET3_TX_VLANTAG_M) << VMXNET3_TX_VLANTAG_S);
- }
- if (m->m_pkthdr.csum_flags & (M_TCP_CSUM_OUT|M_UDP_CSUM_OUT)) {
- sop->tx_word2 |= htole32(((hlen + csum_off) &
- VMXNET3_TX_OP_M) << VMXNET3_TX_OP_S);
- sop->tx_word3 |= htole32(((hlen & VMXNET3_TX_HLEN_M) <<
- VMXNET3_TX_HLEN_S) | (VMXNET3_OM_CSUM << VMXNET3_TX_OM_S));
- }
+ if (!post)
+ return;
- /* dmamap_sync map */
+ /* Change the ownership by flipping the "generation" bit */
+ sop->tx_word2 ^= VMX_TX_GEN;
ring->prod = prod;
+ ring->gen = rgen;
- return (map->dm_nsegs);
+ WRITE_BAR0(sc, VMXNET3_BAR0_TXH(0), prod);
}
void
diff --git a/sys/dev/pci/if_vmxreg.h b/sys/dev/pci/if_vmxreg.h
index ca5debdb6b0..9125fbcc44c 100644
--- a/sys/dev/pci/if_vmxreg.h
+++ b/sys/dev/pci/if_vmxreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_vmxreg.h,v 1.4 2019/08/06 10:15:27 dlg Exp $ */
+/* $OpenBSD: if_vmxreg.h,v 1.5 2019/10/26 23:40:29 dlg Exp $ */
/*
* Copyright (c) 2013 Tsubai Masanari
@@ -98,7 +98,7 @@ struct vmxnet3_txdesc {
u_int32_t tx_word2;
#define VMXNET3_TX_LEN_M 0x00003fff
#define VMXNET3_TX_LEN_S 0
-#define VMXNET3_TX_GEN_M 0x00000001 /* generation */
+#define VMXNET3_TX_GEN_M 0x00000001U /* generation */
#define VMXNET3_TX_GEN_S 14
#define VMXNET3_TX_RES0 0x00008000
#define VMXNET3_TX_DTYPE_M 0x00000001 /* descriptor type */
@@ -139,7 +139,7 @@ struct vmxnet3_txcompdesc {
#define VMXNET3_TXC_RES2_M 0x00ffffff
#define VMXNET3_TXC_TYPE_M 0x0000007f
#define VMXNET3_TXC_TYPE_S 24
-#define VMXNET3_TXC_GEN_M 0x00000001
+#define VMXNET3_TXC_GEN_M 0x00000001U
#define VMXNET3_TXC_GEN_S 31
} __packed;