summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/pci/if_myx.c122
1 files changed, 73 insertions, 49 deletions
diff --git a/sys/dev/pci/if_myx.c b/sys/dev/pci/if_myx.c
index cbc0ffeab1a..b7210a57d15 100644
--- a/sys/dev/pci/if_myx.c
+++ b/sys/dev/pci/if_myx.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_myx.c,v 1.54 2014/01/31 00:52:20 dlg Exp $ */
+/* $OpenBSD: if_myx.c,v 1.55 2014/02/05 08:17:30 dlg Exp $ */
/*
* Copyright (c) 2007 Reyk Floeter <reyk@openbsd.org>
@@ -99,6 +99,12 @@ struct myx_ring_lock {
u_int mrl_running;
};
+enum myx_state {
+ MYX_S_OFF = 0,
+ MYX_S_RUNNING,
+ MYX_S_DOWN
+};
+
struct myx_softc {
struct device sc_dev;
struct arpcom sc_ac;
@@ -154,6 +160,7 @@ struct myx_softc {
struct ifmedia sc_media;
+ volatile enum myx_state sc_state;
volatile u_int8_t sc_linkdown;
};
@@ -1196,6 +1203,10 @@ myx_up(struct myx_softc *sc)
goto free_rxbig;
}
+ mtx_enter(&sc->sc_sts_mtx);
+ sc->sc_state = MYX_S_RUNNING;
+ mtx_leave(&sc->sc_sts_mtx);
+
if (myx_cmd(sc, MYXCMD_SET_IFUP, &mc, NULL) != 0) {
printf("%s: failed to start the device\n", DEVNAME(sc));
goto free_rxbig;
@@ -1203,8 +1214,8 @@ myx_up(struct myx_softc *sc)
CLR(ifp->if_flags, IFF_OACTIVE);
SET(ifp->if_flags, IFF_RUNNING);
-
myx_iff(sc);
+ myx_start(ifp);
return;
@@ -1326,36 +1337,30 @@ void
myx_down(struct myx_softc *sc)
{
struct ifnet *ifp = &sc->sc_ac.ac_if;
+ volatile struct myx_status *sts = sc->sc_sts;
bus_dmamap_t map = sc->sc_sts_dma.mxm_map;
struct myx_buf *mb;
struct myx_cmd mc;
int s;
myx_sts_enter(sc);
- sc->sc_linkdown = sc->sc_sts->ms_linkdown;
- myx_sts_leave(sc);
+ sc->sc_linkdown = sts->ms_linkdown;
+ sc->sc_state = MYX_S_DOWN;
memset(&mc, 0, sizeof(mc));
(void)myx_cmd(sc, MYXCMD_SET_IFDOWN, &mc, NULL);
- myx_sts_enter(sc);
- /* we play with the guts of sc_sts by hand here */
- while (sc->sc_linkdown == sc->sc_sts->ms_linkdown) {
- bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
- BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
-
- msleep(sc->sc_sts, &sc->sc_sts_mtx, 0, "myxdown", 0);
-
- bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
- BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
- }
+ bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+ while (sc->sc_state != MYX_S_OFF)
+ msleep(sts, &sc->sc_sts_mtx, 0, "myxdown", 0);
+ bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
mtx_leave(&sc->sc_sts_mtx);
timeout_del(&sc->sc_refill);
s = splnet();
- CLR(ifp->if_flags, IFF_RUNNING);
-
if (ifp->if_link_state != LINK_STATE_UNKNOWN) {
ifp->if_link_state = LINK_STATE_UNKNOWN;
ifp->if_baudrate = 0;
@@ -1611,59 +1616,60 @@ myx_intr(void *arg)
struct myx_softc *sc = (struct myx_softc *)arg;
struct ifnet *ifp = &sc->sc_ac.ac_if;
volatile struct myx_status *sts = sc->sc_sts;
- u_int32_t data, link;
+ enum myx_state state = MYX_S_RUNNING;
+ bus_dmamap_t map = sc->sc_sts_dma.mxm_map;
+ u_int32_t data, link = 0xffffffff;
int refill = 0;
u_int8_t valid = 0;
- u_int if_flags;
int i;
- if_flags = ifp->if_flags;
- if (!ISSET(if_flags, IFF_RUNNING))
+ mtx_enter(&sc->sc_sts_mtx);
+ if (sc->sc_state == MYX_S_OFF) {
+ mtx_leave(&sc->sc_sts_mtx);
return (0);
+ }
+
+ bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
- myx_sts_enter(sc);
valid = sts->ms_isvalid;
if (valid == 0x0) {
myx_sts_leave(sc);
return (0);
}
- sts->ms_isvalid = 0;
if (sc->sc_intx) {
data = htobe32(0);
bus_space_write_raw_region_4(sc->sc_memt, sc->sc_memh,
sc->sc_irqdeassertoff, &data, sizeof(data));
}
-
- if (!ISSET(if_flags, IFF_UP) &&
- sc->sc_linkdown != sts->ms_linkdown) {
- /* myx_down is waiting for us */
- wakeup_one(sc->sc_sts);
- }
-
- link = sts->ms_statusupdated ? sts->ms_linkstate : 0xffffffff;
+ sts->ms_isvalid = 0;
do {
- data = betoh32(sts->ms_txdonecnt);
- myx_sts_leave(sc);
+ data = sts->ms_txdonecnt;
- if (data != sc->sc_tx_count)
- myx_txeof(sc, data);
+ bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE |
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+ } while (sts->ms_isvalid);
- refill |= myx_rxeof(sc);
+ if (sts->ms_statusupdated) {
+ link = sts->ms_linkstate;
- myx_sts_enter(sc);
- } while (sts->ms_isvalid);
+ if (sc->sc_state == MYX_S_DOWN &&
+ sc->sc_linkdown != sts->ms_linkdown)
+ state = MYX_S_DOWN;
+ }
myx_sts_leave(sc);
- if (link != 0xffffffff) {
- KERNEL_LOCK();
- myx_link_state(sc, link);
- KERNEL_UNLOCK();
- }
+ data = betoh32(data);
+ if (data != sc->sc_tx_count)
+ myx_txeof(sc, data);
data = htobe32(3);
if (valid & 0x1) {
+ refill |= myx_rxeof(sc);
+
bus_space_write_raw_region_4(sc->sc_memt, sc->sc_memh,
sc->sc_irqclaimoff, &data, sizeof(data));
}
@@ -1672,12 +1678,25 @@ myx_intr(void *arg)
bus_space_barrier(sc->sc_memt, sc->sc_memh,
sc->sc_irqclaimoff, sizeof(data) * 2, BUS_SPACE_BARRIER_WRITE);
- if (ISSET(if_flags, IFF_OACTIVE)) {
- KERNEL_LOCK();
+ if (state == MYX_S_DOWN) {
+ /* myx_down is waiting for us */
+ mtx_enter(&sc->sc_sts_mtx);
+ sc->sc_state = MYX_S_OFF;
+ wakeup(sts);
+ mtx_leave(&sc->sc_sts_mtx);
+
+ return (1);
+ }
+
+ KERNEL_LOCK();
+ if (link != 0xffffffff)
+ myx_link_state(sc, link);
+
+ if (ISSET(ifp->if_flags, IFF_OACTIVE)) {
CLR(ifp->if_flags, IFF_OACTIVE);
myx_start(ifp);
- KERNEL_UNLOCK();
}
+ KERNEL_UNLOCK();
for (i = 0; i < 2; i++) {
if (ISSET(refill, 1 << i)) {
@@ -1710,6 +1729,7 @@ myx_txeof(struct myx_softc *sc, u_int32_t done_count)
struct myx_buf *mb;
struct mbuf *m;
bus_dmamap_t map;
+ u_int free = 0;
do {
mb = myx_buf_get(&sc->sc_tx_buf_list);
@@ -1721,9 +1741,7 @@ myx_txeof(struct myx_softc *sc, u_int32_t done_count)
m = mb->mb_m;
map = mb->mb_map;
- sc->sc_tx_free += map->dm_nsegs;
- if (map->dm_mapsize < 60)
- sc->sc_tx_free += 1;
+ free += map->dm_nsegs + (map->dm_mapsize < 60 ? 1 : 0);
bus_dmamap_sync(sc->sc_dmat, map, 0,
map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
@@ -1736,6 +1754,12 @@ myx_txeof(struct myx_softc *sc, u_int32_t done_count)
myx_buf_put(&sc->sc_tx_buf_free, mb);
} while (++sc->sc_tx_count != done_count);
+
+ if (free) {
+ KERNEL_LOCK();
+ sc->sc_tx_free += free;
+ KERNEL_UNLOCK();
+ }
}
int