summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornp <np@FreeBSD.org>2012-11-29 19:39:27 +0000
committernp <np@FreeBSD.org>2012-11-29 19:39:27 +0000
commitf9f87022c1a8e1d2f0d80afdc321017f553097ae (patch)
tree70565649577f1b2798b01ad36713f13a0f6c6cf1
parentaedb69184652bffb10d55a856fbfa2e5dcb61177 (diff)
downloadFreeBSD-src-f9f87022c1a8e1d2f0d80afdc321017f553097ae.zip
FreeBSD-src-f9f87022c1a8e1d2f0d80afdc321017f553097ae.tar.gz
cxgbe/tom: Handle the case where the chip falls out of DDP mode by
itself. The hole in the receive sequence space corresponds to the number of bytes placed directly up to that point. MFC after: 1 week
-rw-r--r--sys/dev/cxgbe/tom/t4_cpl_io.c28
-rw-r--r--sys/dev/cxgbe/tom/t4_ddp.c36
-rw-r--r--sys/dev/cxgbe/tom/t4_tom.h1
3 files changed, 53 insertions, 12 deletions
diff --git a/sys/dev/cxgbe/tom/t4_cpl_io.c b/sys/dev/cxgbe/tom/t4_cpl_io.c
index 6e56b29..6ae1ec4 100644
--- a/sys/dev/cxgbe/tom/t4_cpl_io.c
+++ b/sys/dev/cxgbe/tom/t4_cpl_io.c
@@ -1113,6 +1113,7 @@ do_rx_data(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
struct socket *so;
struct sockbuf *sb;
int len;
+ uint32_t ddp_placed = 0;
if (__predict_false(toep->flags & TPF_SYNQE)) {
#ifdef INVARIANTS
@@ -1154,13 +1155,8 @@ do_rx_data(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
tp = intotcpcb(inp);
-#ifdef INVARIANTS
- if (__predict_false(tp->rcv_nxt != be32toh(cpl->seq))) {
- log(LOG_ERR,
- "%s: unexpected seq# %x for TID %u, rcv_nxt %x\n",
- __func__, be32toh(cpl->seq), toep->tid, tp->rcv_nxt);
- }
-#endif
+ if (__predict_false(tp->rcv_nxt != be32toh(cpl->seq)))
+ ddp_placed = be32toh(cpl->seq) - tp->rcv_nxt;
tp->rcv_nxt += len;
KASSERT(tp->rcv_wnd >= len, ("%s: negative window size", __func__));
@@ -1207,12 +1203,20 @@ do_rx_data(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
int changed = !(toep->ddp_flags & DDP_ON) ^ cpl->ddp_off;
if (changed) {
- if (__predict_false(!(toep->ddp_flags & DDP_SC_REQ))) {
- /* XXX: handle this if legitimate */
- panic("%s: unexpected DDP state change %d",
- __func__, cpl->ddp_off);
+ if (toep->ddp_flags & DDP_SC_REQ)
+ toep->ddp_flags ^= DDP_ON | DDP_SC_REQ;
+ else {
+ KASSERT(cpl->ddp_off == 1,
+ ("%s: DDP switched on by itself.",
+ __func__));
+
+ /* Fell out of DDP mode */
+ toep->ddp_flags &= ~(DDP_ON | DDP_BUF0_ACTIVE |
+ DDP_BUF1_ACTIVE);
+
+ if (ddp_placed)
+ insert_ddp_data(toep, ddp_placed);
}
- toep->ddp_flags ^= DDP_ON | DDP_SC_REQ;
}
if ((toep->ddp_flags & DDP_OK) == 0 &&
diff --git a/sys/dev/cxgbe/tom/t4_ddp.c b/sys/dev/cxgbe/tom/t4_ddp.c
index 0b43bf2..31eb607 100644
--- a/sys/dev/cxgbe/tom/t4_ddp.c
+++ b/sys/dev/cxgbe/tom/t4_ddp.c
@@ -205,6 +205,42 @@ release_ddp_resources(struct toepcb *toep)
}
}
+/* XXX: handle_ddp_data code duplication */
+void
+insert_ddp_data(struct toepcb *toep, uint32_t n)
+{
+ struct inpcb *inp = toep->inp;
+ struct tcpcb *tp = intotcpcb(inp);
+ struct sockbuf *sb = &inp->inp_socket->so_rcv;
+ struct mbuf *m;
+
+ INP_WLOCK_ASSERT(inp);
+ SOCKBUF_LOCK_ASSERT(sb);
+
+ m = m_get(M_NOWAIT, MT_DATA);
+ if (m == NULL)
+ CXGBE_UNIMPLEMENTED("mbuf alloc failure");
+ m->m_len = n;
+ m->m_flags |= M_DDP; /* Data is already where it should be */
+ m->m_data = "nothing to see here";
+
+ tp->rcv_nxt += n;
+#ifndef USE_DDP_RX_FLOW_CONTROL
+ KASSERT(tp->rcv_wnd >= n, ("%s: negative window size", __func__));
+ tp->rcv_wnd -= n;
+#endif
+
+ KASSERT(toep->sb_cc >= sb->sb_cc,
+ ("%s: sb %p has more data (%d) than last time (%d).",
+ __func__, sb, sb->sb_cc, toep->sb_cc));
+ toep->rx_credits += toep->sb_cc - sb->sb_cc;
+#ifdef USE_DDP_RX_FLOW_CONTROL
+ toep->rx_credits -= n; /* adjust for F_RX_FC_DDP */
+#endif
+ sbappendstream_locked(sb, m);
+ toep->sb_cc = sb->sb_cc;
+}
+
/* SET_TCB_FIELD sent as a ULP command looks like this */
#define LEN__SET_TCB_FIELD_ULP (sizeof(struct ulp_txpkt) + \
sizeof(struct ulptx_idata) + sizeof(struct cpl_set_tcb_field_core))
diff --git a/sys/dev/cxgbe/tom/t4_tom.h b/sys/dev/cxgbe/tom/t4_tom.h
index 0704856..9549b0b 100644
--- a/sys/dev/cxgbe/tom/t4_tom.h
+++ b/sys/dev/cxgbe/tom/t4_tom.h
@@ -273,4 +273,5 @@ int t4_soreceive_ddp(struct socket *, struct sockaddr **, struct uio *,
struct mbuf **, struct mbuf **, int *);
void enable_ddp(struct adapter *, struct toepcb *toep);
void release_ddp_resources(struct toepcb *toep);
+void insert_ddp_data(struct toepcb *, uint32_t);
#endif
OpenPOWER on IntegriCloud