summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2010-02-21 14:48:43 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2010-02-21 14:48:43 +0000
commit71847f867f487600a9727c329298f88db3b353bf (patch)
tree76a3196ad7c2be7276f16f1622bdf8eef8d9bd85
parenta155ac59cca3f7ea994c687509692dea2c600043 (diff)
Make sure we only request our peer to start processing descriptors if it
isn't currently doing so. Fixes hangs on large data transfers.
-rw-r--r--sys/arch/sparc64/dev/vnet.c44
1 files changed, 30 insertions, 14 deletions
diff --git a/sys/arch/sparc64/dev/vnet.c b/sys/arch/sparc64/dev/vnet.c
index f9f11b66fcd..f20f5a5b676 100644
--- a/sys/arch/sparc64/dev/vnet.c
+++ b/sys/arch/sparc64/dev/vnet.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vnet.c,v 1.23 2010/02/21 12:01:42 kettenis Exp $ */
+/* $OpenBSD: vnet.c,v 1.24 2010/02/21 14:48:42 kettenis Exp $ */
/*
* Copyright (c) 2009 Mark Kettenis
*
@@ -165,6 +165,8 @@ struct vnet_softc {
int sc_tx_prod;
int sc_tx_cons;
+ uint8_t sc_peer_state;
+
struct ldc_map *sc_lm;
struct vnet_dring *sc_vd;
struct vnet_soft_desc *sc_vsd;
@@ -211,6 +213,7 @@ void vnet_send_ver_info(struct vnet_softc *, uint16_t, uint16_t);
void vnet_send_attr_info(struct vnet_softc *);
void vnet_send_dring_reg(struct vnet_softc *);
void vio_send_rdx(struct vnet_softc *);
+void vnet_send_dring_data(struct vnet_softc *, uint32_t);
void vnet_start(struct ifnet *);
void vnet_start_desc(struct ifnet *);
@@ -851,6 +854,8 @@ vnet_rx_vio_dring_data(struct vnet_softc *sc, struct vio_msg_tag *tag)
struct ldc_map *map = sc->sc_lm;
int cons;
+ sc->sc_peer_state = dm->proc_state;
+
cons = sc->sc_tx_cons;
while (sc->sc_vd->vd_desc[cons].hdr.dstate == VIO_DESC_DONE) {
map->lm_slot[sc->sc_vsd[cons].vsd_map_idx].entry = 0;
@@ -864,6 +869,9 @@ vnet_rx_vio_dring_data(struct vnet_softc *sc, struct vio_msg_tag *tag)
}
sc->sc_tx_cons = cons;
+ if (sc->sc_tx_cnt > 0 && sc->sc_peer_state != VIO_DP_ACTIVE)
+ vnet_send_dring_data(sc, sc->sc_tx_cons);
+
if (sc->sc_tx_cnt < sc->sc_vd->vd_nentries)
ifp->if_flags &= ~IFF_OACTIVE;
if (sc->sc_tx_cnt == 0)
@@ -1009,12 +1017,30 @@ vio_send_rdx(struct vnet_softc *sc)
}
void
+vnet_send_dring_data(struct vnet_softc *sc, uint32_t start_idx)
+{
+ struct vio_dring_msg dm;
+
+ bzero(&dm, sizeof(dm));
+ dm.tag.type = VIO_TYPE_DATA;
+ dm.tag.stype = VIO_SUBTYPE_INFO;
+ dm.tag.stype_env = VIO_DRING_DATA;
+ dm.tag.sid = sc->sc_local_sid;
+ dm.seq_no = sc->sc_seq_no++;
+ dm.dring_ident = sc->sc_dring_ident;
+ dm.start_idx = start_idx;
+ dm.end_idx = -1;
+ vio_sendmsg(sc, &dm, sizeof(dm));
+
+ sc->sc_peer_state = VIO_DP_ACTIVE;
+}
+
+void
vnet_start(struct ifnet *ifp)
{
struct vnet_softc *sc = ifp->if_softc;
struct ldc_conn *lc = &sc->sc_lc;
struct ldc_map *map = sc->sc_lm;
- struct vio_dring_msg dm;
struct mbuf *m;
paddr_t pa;
caddr_t buf;
@@ -1111,18 +1137,8 @@ vnet_start(struct ifnet *ifp)
m_freem(m);
}
- if (desc != sc->sc_tx_prod) {
- bzero(&dm, sizeof(dm));
- dm.tag.type = VIO_TYPE_DATA;
- dm.tag.stype = VIO_SUBTYPE_INFO;
- dm.tag.stype_env = VIO_DRING_DATA;
- dm.tag.sid = sc->sc_local_sid;
- dm.seq_no = sc->sc_seq_no++;
- dm.dring_ident = sc->sc_dring_ident;
- dm.start_idx = sc->sc_tx_prod;
- dm.end_idx = -1;
- vio_sendmsg(sc, &dm, sizeof(dm));
-
+ if (sc->sc_tx_cnt > 0 && sc->sc_peer_state != VIO_DP_ACTIVE) {
+ vnet_send_dring_data(sc, sc->sc_tx_prod);
ifp->if_timer = 5;
}