aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/net/iflib.c82
1 files changed, 58 insertions, 24 deletions
diff --git a/sys/net/iflib.c b/sys/net/iflib.c
index ea2c5789a7b5..0d4124599419 100644
--- a/sys/net/iflib.c
+++ b/sys/net/iflib.c
@@ -1005,6 +1005,8 @@ iflib_netmap_txsync(struct netmap_kring *kring, int flags)
nm_i = kring->nr_hwcur;
if (nm_i != head) { /* we have new packets to send */
+ uint32_t pkt_len = 0, seg_idx = 0;
+ int nic_i_start = -1, flags = 0;
pkt_info_zero(&pi);
pi.ipi_segs = txq->ift_segs;
pi.ipi_qsidx = kring->ring_id;
@@ -1019,22 +1021,40 @@ iflib_netmap_txsync(struct netmap_kring *kring, int flags)
u_int len = slot->len;
uint64_t paddr;
void *addr = PNMB(na, slot, &paddr);
- int flags = (slot->flags & NS_REPORT ||
+
+ flags |= (slot->flags & NS_REPORT ||
nic_i == 0 || nic_i == report_frequency) ?
IPI_TX_INTR : 0;
- /* device-specific */
- pi.ipi_len = len;
- pi.ipi_segs[0].ds_addr = paddr;
- pi.ipi_segs[0].ds_len = len;
- pi.ipi_nsegs = 1;
- pi.ipi_ndescs = 0;
- pi.ipi_pidx = nic_i;
- pi.ipi_flags = flags;
+ /*
+ * If this is the first packet fragment, save the
+ * index of the first NIC slot for later.
+ */
+ if (nic_i_start < 0)
+ nic_i_start = nic_i;
+
+ pi.ipi_segs[seg_idx].ds_addr = paddr;
+ pi.ipi_segs[seg_idx].ds_len = len;
+ if (len) {
+ pkt_len += len;
+ seg_idx++;
+ }
- /* Fill the slot in the NIC ring. */
- ctx->isc_txd_encap(ctx->ifc_softc, &pi);
- DBG_COUNTER_INC(tx_encap);
+ if (!(slot->flags & NS_MOREFRAG)) {
+ pi.ipi_len = pkt_len;
+ pi.ipi_nsegs = seg_idx;
+ pi.ipi_pidx = nic_i_start;
+ pi.ipi_ndescs = 0;
+ pi.ipi_flags = flags;
+
+ /* Prepare the NIC TX ring. */
+ ctx->isc_txd_encap(ctx->ifc_softc, &pi);
+ DBG_COUNTER_INC(tx_encap);
+
+ /* Reinit per-packet info for the next one. */
+ flags = seg_idx = pkt_len = 0;
+ nic_i_start = -1;
+ }
/* prefetch for next round */
__builtin_prefetch(&ring->slot[nm_i + 1]);
@@ -1053,7 +1073,7 @@ iflib_netmap_txsync(struct netmap_kring *kring, int flags)
txq->ift_sds.ifsd_map[nic_i],
BUS_DMASYNC_PREWRITE);
- slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED);
+ slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED | NS_MOREFRAG);
nm_i = nm_next(nm_i, lim);
nic_i = nm_next(nic_i, lim);
}
@@ -1116,6 +1136,7 @@ iflib_netmap_rxsync(struct netmap_kring *kring, int flags)
u_int n;
u_int const lim = kring->nkr_num_slots - 1;
int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR;
+ int i = 0;
if_ctx_t ctx = ifp->if_softc;
if_shared_ctx_t sctx = ctx->ifc_sctx;
@@ -1177,17 +1198,30 @@ iflib_netmap_rxsync(struct netmap_kring *kring, int flags)
ri.iri_cidx = *cidxp;
error = ctx->isc_rxd_pkt_get(ctx->ifc_softc, &ri);
- ring->slot[nm_i].len = error ? 0 : ri.iri_len - crclen;
- ring->slot[nm_i].flags = 0;
- if (have_rxcq) {
- *cidxp = ri.iri_cidx;
- while (*cidxp >= scctx->isc_nrxd[0])
- *cidxp -= scctx->isc_nrxd[0];
+ for (i = 0; i < ri.iri_nfrags; i++) {
+ if (error) {
+ ring->slot[nm_i].len = 0;
+ ring->slot[nm_i].flags = 0;
+ } else {
+ ring->slot[nm_i].len = ri.iri_frags[i].irf_len;
+ if (i == (ri.iri_nfrags - 1)) {
+ ring->slot[nm_i].len -= crclen;
+ ring->slot[nm_i].flags = 0;
+ } else
+ ring->slot[nm_i].flags = NS_MOREFRAG;
+ }
+
+ if (have_rxcq) {
+ *cidxp = ri.iri_cidx;
+ while (*cidxp >= scctx->isc_nrxd[0])
+ *cidxp -= scctx->isc_nrxd[0];
+ }
+
+ bus_dmamap_sync(fl->ifl_buf_tag,
+ fl->ifl_sds.ifsd_map[nic_i], BUS_DMASYNC_POSTREAD);
+ nm_i = nm_next(nm_i, lim);
+ fl->ifl_cidx = nic_i = nm_next(nic_i, lim);
}
- bus_dmamap_sync(fl->ifl_buf_tag,
- fl->ifl_sds.ifsd_map[nic_i], BUS_DMASYNC_POSTREAD);
- nm_i = nm_next(nm_i, lim);
- fl->ifl_cidx = nic_i = nm_next(nic_i, lim);
}
if (n) { /* update the state variables */
if (netmap_no_pendintr && !force_update) {
@@ -1234,7 +1268,7 @@ iflib_netmap_attach(if_ctx_t ctx)
bzero(&na, sizeof(na));
na.ifp = ctx->ifc_ifp;
- na.na_flags = NAF_BDG_MAYSLEEP;
+ na.na_flags = NAF_BDG_MAYSLEEP | NAF_MOREFRAG;
MPASS(ctx->ifc_softc_ctx.isc_ntxqsets);
MPASS(ctx->ifc_softc_ctx.isc_nrxqsets);