summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2017-06-08 01:34:01 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2017-06-08 01:34:01 +0000
commit5d0bf25976815db76338471682651eb59e9a2ef9 (patch)
treec437a356db79d4fa3c7b49bd7a30647566081b3e /sys
parent9985d01321b4814174db2a5f3cd3cd1b5b520524 (diff)
make the gem tx path MPSAFE.
this mostly follows the pattern in ifq.h ok jmatthew@
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ic/gem.c105
1 files changed, 57 insertions, 48 deletions
diff --git a/sys/dev/ic/gem.c b/sys/dev/ic/gem.c
index 9c5fd6a8072..c1c34e68b4f 100644
--- a/sys/dev/ic/gem.c
+++ b/sys/dev/ic/gem.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: gem.c,v 1.121 2017/01/22 10:17:38 dlg Exp $ */
+/* $OpenBSD: gem.c,v 1.122 2017/06/08 01:34:00 dlg Exp $ */
/* $NetBSD: gem.c,v 1.1 2001/09/16 00:11:43 eeh Exp $ */
/*
@@ -75,7 +75,7 @@ struct cfdriver gem_cd = {
NULL, "gem", DV_IFNET
};
-void gem_start(struct ifnet *);
+void gem_start(struct ifqueue *);
void gem_stop(struct ifnet *, int);
int gem_ioctl(struct ifnet *, u_long, caddr_t);
void gem_tick(void *);
@@ -217,9 +217,9 @@ gem_config(struct gem_softc *sc)
/* Initialize ifnet structure. */
strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, sizeof ifp->if_xname);
ifp->if_softc = sc;
- ifp->if_flags =
- IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
- ifp->if_start = gem_start;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_xflags = IFXF_MPSAFE;
+ ifp->if_qstart = gem_start;
ifp->if_ioctl = gem_ioctl;
ifp->if_watchdog = gem_watchdog;
IFQ_SET_MAXLEN(&ifp->if_snd, GEM_NTXDESC - 1);
@@ -542,6 +542,7 @@ gem_stop(struct ifnet *ifp, int softonly)
}
intr_barrier(sc->sc_ih);
+ ifq_barrier(&ifp->if_snd);
KASSERT((ifp->if_flags & IFF_RUNNING) == 0);
@@ -1625,12 +1626,12 @@ gem_tint(struct gem_softc *sc, u_int32_t status)
{
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
struct gem_sxd *sd;
- u_int32_t cons, hwcons;
- u_int32_t used, free = 0;
+ u_int32_t cons, prod;
+ int free = 0;
- hwcons = status >> 19;
+ prod = status >> 19;
cons = sc->sc_tx_cons;
- while (cons != hwcons) {
+ while (cons != prod) {
sd = &sc->sc_txd[cons];
if (sd->sd_mbuf != NULL) {
bus_dmamap_sync(sc->sc_dmatag, sd->sd_map, 0,
@@ -1639,25 +1640,23 @@ gem_tint(struct gem_softc *sc, u_int32_t status)
m_freem(sd->sd_mbuf);
sd->sd_mbuf = NULL;
}
- free++;
- if (++cons == GEM_NTXDESC)
- cons = 0;
+
+ free = 1;
+
+ cons++;
+ cons &= GEM_NTXDESC - 1;
}
+ if (free == 0)
+ return (0);
+
sc->sc_tx_cons = cons;
- used = atomic_sub_int_nv(&sc->sc_tx_cnt, free);
- if (used == 0)
+ if (sc->sc_tx_prod == cons)
ifp->if_timer = 0;
- if (ifq_is_oactive(&ifp->if_snd) && (used + GEM_NTXSEGS <
- GEM_NTXDESC - 2)) {
- ifq_clr_oactive(&ifp->if_snd);
-
- KERNEL_LOCK();
- gem_start(ifp);
- KERNEL_UNLOCK();
- }
+ if (ifq_is_oactive(&ifp->if_snd))
+ ifq_restart(&ifp->if_snd);
return (1);
}
@@ -1687,35 +1686,43 @@ gem_load_mbuf(struct gem_softc *sc, struct gem_sxd *sd, struct mbuf *m)
}
void
-gem_start(struct ifnet *ifp)
+gem_start(struct ifqueue *ifq)
{
+ struct ifnet *ifp = ifq->ifq_if;
struct gem_softc *sc = ifp->if_softc;
struct gem_sxd *sd;
struct mbuf *m;
- u_int64_t flags;
+ uint64_t flags, nflags;
bus_dmamap_t map;
- u_int32_t prod, first, last, i;
- unsigned int used, new;
-
- if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
- return;
+ uint32_t prod;
+ uint32_t free, used = 0;
+ uint32_t first, last;
+ int i;
prod = sc->sc_tx_prod;
- used = sc->sc_tx_cnt;
- new = 0;
+
+ /* figure out space */
+ free = sc->sc_tx_cons;
+ if (free <= prod)
+ free += GEM_NTXDESC;
+ free -= prod;
+
+ bus_dmamap_sync(sc->sc_dmatag, sc->sc_cddmamap,
+ 0, sizeof(struct gem_desc) * GEM_NTXDESC,
+ BUS_DMASYNC_PREWRITE);
for (;;) {
- if (used + new + GEM_NTXSEGS > (GEM_NTXDESC - 2)) {
+ if (used + GEM_NTXSEGS + 1 > free) {
ifq_set_oactive(&ifp->if_snd);
break;
}
- IFQ_DEQUEUE(&ifp->if_snd, m);
+ m = ifq_dequeue(ifq);
if (m == NULL)
break;
first = prod;
- sd = &sc->sc_txd[prod];
+ sd = &sc->sc_txd[first];
map = sd->sd_map;
if (gem_load_mbuf(sc, sd, m)) {
@@ -1732,35 +1739,37 @@ gem_start(struct ifnet *ifp)
bus_dmamap_sync(sc->sc_dmatag, map, 0, map->dm_mapsize,
BUS_DMASYNC_PREWRITE);
+ nflags = GEM_TD_START_OF_PACKET;
for (i = 0; i < map->dm_nsegs; i++) {
+ flags = nflags |
+ (map->dm_segs[i].ds_len & GEM_TD_BUFSIZE);
+
GEM_DMA_WRITE(sc, &sc->sc_txdescs[prod].gd_addr,
map->dm_segs[i].ds_addr);
- flags = map->dm_segs[i].ds_len & GEM_TD_BUFSIZE;
- if (i == 0)
- flags |= GEM_TD_START_OF_PACKET;
- if (i == (map->dm_nsegs - 1))
- flags |= GEM_TD_END_OF_PACKET;
GEM_DMA_WRITE(sc, &sc->sc_txdescs[prod].gd_flags,
flags);
- bus_dmamap_sync(sc->sc_dmatag, sc->sc_cddmamap,
- GEM_CDTXOFF(prod), sizeof(struct gem_desc),
- BUS_DMASYNC_PREWRITE);
last = prod;
- if (++prod == GEM_NTXDESC)
- prod = 0;
+ prod++;
+ prod &= GEM_NTXDESC - 1;
+
+ nflags = 0;
}
+ GEM_DMA_WRITE(sc, &sc->sc_txdescs[last].gd_flags,
+ GEM_TD_END_OF_PACKET | flags);
- new += map->dm_nsegs;
+ used += map->dm_nsegs;
sc->sc_txd[last].sd_mbuf = m;
sc->sc_txd[first].sd_map = sc->sc_txd[last].sd_map;
sc->sc_txd[last].sd_map = map;
}
- if (new == 0)
- return;
+ bus_dmamap_sync(sc->sc_dmatag, sc->sc_cddmamap,
+ 0, sizeof(struct gem_desc) * GEM_NTXDESC,
+ BUS_DMASYNC_POSTWRITE);
- atomic_add_int(&sc->sc_tx_cnt, new);
+ if (used == 0)
+ return;
/* Commit. */
sc->sc_tx_prod = prod;