Changeset View
Standalone View
sys/dev/e1000/em_txrx.c
Show First 20 Lines • Show All 135 Lines • ▼ Show 20 Lines | |||||||||||
**********************************************************************/ | **********************************************************************/ | ||||||||||
static int | static int | ||||||||||
em_tso_setup(struct e1000_softc *sc, if_pkt_info_t pi, uint32_t *txd_upper, | em_tso_setup(struct e1000_softc *sc, if_pkt_info_t pi, uint32_t *txd_upper, | ||||||||||
uint32_t *txd_lower) | uint32_t *txd_lower) | ||||||||||
{ | { | ||||||||||
if_softc_ctx_t scctx = sc->shared; | if_softc_ctx_t scctx = sc->shared; | ||||||||||
struct em_tx_queue *que = &sc->tx_queues[pi->ipi_qsidx]; | struct em_tx_queue *que = &sc->tx_queues[pi->ipi_qsidx]; | ||||||||||
struct tx_ring *txr = &que->txr; | struct tx_ring *txr = &que->txr; | ||||||||||
struct e1000_hw *hw = &sc->hw; | |||||||||||
struct e1000_context_desc *TXD; | struct e1000_context_desc *TXD; | ||||||||||
int cur, hdr_len; | int cur, hdr_len; | ||||||||||
uint32_t cmd_type_len; | |||||||||||
hdr_len = pi->ipi_ehdrlen + pi->ipi_ip_hlen + pi->ipi_tcp_hlen; | hdr_len = pi->ipi_ehdrlen + pi->ipi_ip_hlen + pi->ipi_tcp_hlen; | ||||||||||
*txd_lower = (E1000_TXD_CMD_DEXT | /* Extended descr type */ | *txd_lower = (E1000_TXD_CMD_DEXT | /* Extended descr type */ | ||||||||||
E1000_TXD_DTYP_D | /* Data descr type */ | E1000_TXD_DTYP_D | /* Data descr type */ | ||||||||||
E1000_TXD_CMD_TSE); /* Do TSE on this packet */ | E1000_TXD_CMD_TSE); /* Do TSE on this packet */ | ||||||||||
/* IP and/or TCP header checksum calculation and insertion. */ | /* IP and/or TCP header checksum calculation and insertion. */ | ||||||||||
*txd_upper = (E1000_TXD_POPTS_IXSM | E1000_TXD_POPTS_TXSM) << 8; | *txd_upper = (E1000_TXD_POPTS_IXSM | E1000_TXD_POPTS_TXSM) << 8; | ||||||||||
Show All 24 Lines | em_tso_setup(struct e1000_softc *sc, if_pkt_info_t pi, uint32_t *txd_upper, | ||||||||||
/* | /* | ||||||||||
* Payload size per packet w/o any headers. | * Payload size per packet w/o any headers. | ||||||||||
* Length of all headers up to payload. | * Length of all headers up to payload. | ||||||||||
*/ | */ | ||||||||||
TXD->tcp_seg_setup.fields.mss = htole16(pi->ipi_tso_segsz); | TXD->tcp_seg_setup.fields.mss = htole16(pi->ipi_tso_segsz); | ||||||||||
TXD->tcp_seg_setup.fields.hdr_len = hdr_len; | TXD->tcp_seg_setup.fields.hdr_len = hdr_len; | ||||||||||
TXD->cmd_and_length = htole32(sc->txd_cmd | | /* | ||||||||||
* 8254x SDM4.0 page 45, and PCIe GbE SDM2.5 page 63 | |||||||||||
* - Set up basic TUCMDs | |||||||||||
* - Enable IP bit on 82544 | |||||||||||
* - For others IP bit on indicates IPv4, while off indicates IPv6 | |||||||||||
*/ | |||||||||||
cmd_type_len = sc->txd_cmd | | |||||||||||
E1000_TXD_CMD_DEXT | /* Extended descr */ | E1000_TXD_CMD_DEXT | /* Extended descr */ | ||||||||||
E1000_TXD_CMD_TSE | /* TSE context */ | E1000_TXD_CMD_TSE | /* TSE context */ | ||||||||||
E1000_TXD_CMD_IP | /* Do IP csum */ | E1000_TXD_CMD_TCP; /* Do TCP checksum */ | ||||||||||
E1000_TXD_CMD_TCP | /* Do TCP checksum */ | if (hw->mac.type == e1000_82544) | ||||||||||
cmd_type_len |= E1000_TXD_CMD_IP; | |||||||||||
else if (pi->ipi_etype == ETHERTYPE_IP) | |||||||||||
cmd_type_len |= E1000_TXD_CMD_IP; | |||||||||||
TXD->cmd_and_length = htole32(cmd_type_len | | |||||||||||
(pi->ipi_len - hdr_len)); /* Total len */ | (pi->ipi_len - hdr_len)); /* Total len */ | ||||||||||
markjUnsubmitted Not Done Inline Actions
markj: | |||||||||||
txr->tx_tso = true; | txr->tx_tso = true; | ||||||||||
if (++cur == scctx->isc_ntxd[0]) { | if (++cur == scctx->isc_ntxd[0]) { | ||||||||||
cur = 0; | cur = 0; | ||||||||||
} | } | ||||||||||
DPRINTF(iflib_get_dev(sc->ctx), "%s: pidx: %d cur: %d\n", __FUNCTION__, | DPRINTF(iflib_get_dev(sc->ctx), "%s: pidx: %d cur: %d\n", __FUNCTION__, | ||||||||||
pi->ipi_pidx, cur); | pi->ipi_pidx, cur); | ||||||||||
return (cur); | return (cur); | ||||||||||
▲ Show 20 Lines • Show All 144 Lines • ▼ Show 20 Lines | em_isc_txd_encap(void *arg, if_pkt_info_t pi) | ||||||||||
/* Do hardware assists */ | /* Do hardware assists */ | ||||||||||
if (do_tso) { | if (do_tso) { | ||||||||||
i = em_tso_setup(sc, pi, &txd_upper, &txd_lower); | i = em_tso_setup(sc, pi, &txd_upper, &txd_lower); | ||||||||||
tso_desc = true; | tso_desc = true; | ||||||||||
} else if (csum_flags & EM_CSUM_OFFLOAD) { | } else if (csum_flags & EM_CSUM_OFFLOAD) { | ||||||||||
i = em_transmit_checksum_setup(sc, pi, &txd_upper, &txd_lower); | i = em_transmit_checksum_setup(sc, pi, &txd_upper, &txd_lower); | ||||||||||
} | } | ||||||||||
if (pi->ipi_mflags & M_VLANTAG) { | if (pi->ipi_mflags & M_VLANTAG) { | ||||||||||
Not Done Inline ActionsWhy is this change needed? markj: Why is this change needed? | |||||||||||
Not Done Inline ActionsIt's insufficient as is, we need to properly handle legacy, context and data descriptors for lem/em and I haven't wrapped my brain around it yet to make the encap code look and work nice. The primary issue is we are supposed to put the vlan tag and mark the VLE bit in the last data descriptor following a context descriptor. The lem versus em datasheet is confusing, it says put the tag and VLE in the first data descriptor if using the context/data descriptors for hwcsum non-TSE (aka non-TSO), and last if TSE (TSO) so I'm still trying to understand it. kbowling: It's insufficient as is, we need to properly handle legacy, context and data descriptors for… | |||||||||||
/* Set the vlan id. */ | /* Set the vlan id. */ | ||||||||||
txd_upper |= htole16(pi->ipi_vtag) << 16; | txd_upper |= htole16(pi->ipi_vtag) << 16; | ||||||||||
/* Tell hardware to add tag */ | /* Tell hardware to add tag */ | ||||||||||
txd_lower |= htole32(E1000_TXD_CMD_VLE); | txd_lower |= htole32(E1000_TXD_CMD_VLE); | ||||||||||
} | } | ||||||||||
DPRINTF(iflib_get_dev(sc->ctx), | DPRINTF(iflib_get_dev(sc->ctx), | ||||||||||
"encap: set up tx: nsegs=%d first=%d i=%d\n", nsegs, first, i); | "encap: set up tx: nsegs=%d first=%d i=%d\n", nsegs, first, i); | ||||||||||
▲ Show 20 Lines • Show All 236 Lines • ▼ Show 20 Lines | em_isc_rxd_available(void *arg, uint16_t rxqid, qidx_t idx, qidx_t budget) | ||||||||||
struct em_rx_queue *que = &sc->rx_queues[rxqid]; | struct em_rx_queue *que = &sc->rx_queues[rxqid]; | ||||||||||
struct rx_ring *rxr = &que->rxr; | struct rx_ring *rxr = &que->rxr; | ||||||||||
union e1000_rx_desc_extended *rxd; | union e1000_rx_desc_extended *rxd; | ||||||||||
uint32_t staterr = 0; | uint32_t staterr = 0; | ||||||||||
int cnt, i; | int cnt, i; | ||||||||||
for (cnt = 0, i = idx; cnt < scctx->isc_nrxd[0] && cnt <= budget;) { | for (cnt = 0, i = idx; cnt < scctx->isc_nrxd[0] && cnt <= budget;) { | ||||||||||
rxd = &rxr->rx_base[i]; | rxd = &rxr->rx_base[i]; | ||||||||||
staterr = le32toh(rxd->wb.upper.status_error); | staterr = le32toh(rxd->wb.upper.status_error); | ||||||||||
Done Inline ActionsI would have gone for the ifp too, but the "iflib way" is to avoid accessing this directly when possible. Can you get what you need from scctx->isc_capenable ? gallatin: I would have gone for the ifp too, but the "iflib way" is to avoid accessing this directly when… | |||||||||||
if ((staterr & E1000_RXD_STAT_DD) == 0) | if ((staterr & E1000_RXD_STAT_DD) == 0) | ||||||||||
break; | break; | ||||||||||
if (++i == scctx->isc_nrxd[0]) | if (++i == scctx->isc_nrxd[0]) | ||||||||||
i = 0; | i = 0; | ||||||||||
if (staterr & E1000_RXD_STAT_EOP) | if (staterr & E1000_RXD_STAT_EOP) | ||||||||||
cnt++; | cnt++; | ||||||||||
} | } | ||||||||||
Show All 24 Lines | do { | ||||||||||
/* Error Checking then decrement count */ | /* Error Checking then decrement count */ | ||||||||||
MPASS ((status & E1000_RXD_STAT_DD) != 0); | MPASS ((status & E1000_RXD_STAT_DD) != 0); | ||||||||||
len = le16toh(rxd->length); | len = le16toh(rxd->length); | ||||||||||
ri->iri_len += len; | ri->iri_len += len; | ||||||||||
eop = (status & E1000_RXD_STAT_EOP) != 0; | eop = (status & E1000_RXD_STAT_EOP) != 0; | ||||||||||
/* Make sure bad packets are discarded */ | /* Make sure bad packets are discarded */ | ||||||||||
Not Done Inline ActionsWhy fetch it from each descriptor? markj: Why fetch it from each descriptor? | |||||||||||
Not Done Inline ActionsI had the same concern, trying to unify the igb and ixgbe txrx so I will prep an update for those to move it outside the loop. kbowling: I had the same concern, trying to unify the igb and ixgbe txrx so I will prep an update for… | |||||||||||
if (errors & E1000_RXD_ERR_FRAME_ERR_MASK) { | if (errors & E1000_RXD_ERR_FRAME_ERR_MASK) { | ||||||||||
sc->dropped_pkts++; | sc->dropped_pkts++; | ||||||||||
/* XXX fixup if common */ | /* XXX fixup if common */ | ||||||||||
Done Inline ActionsI believe iflib ensures that this field is zeroed. Otherwise, note that we assume ri->iri_flags is zeroed when ORing M_VLANTAG below. markj: I believe iflib ensures that this field is zeroed. Otherwise, note that we assume `ri… | |||||||||||
return (EBADMSG); | return (EBADMSG); | ||||||||||
} | } | ||||||||||
ri->iri_frags[i].irf_flid = 0; | ri->iri_frags[i].irf_flid = 0; | ||||||||||
ri->iri_frags[i].irf_idx = cidx; | ri->iri_frags[i].irf_idx = cidx; | ||||||||||
ri->iri_frags[i].irf_len = len; | ri->iri_frags[i].irf_len = len; | ||||||||||
/* Zero out the receive descriptors status. */ | /* Zero out the receive descriptors status. */ | ||||||||||
rxd->status = 0; | rxd->status = 0; | ||||||||||
if (++cidx == scctx->isc_nrxd[0]) | if (++cidx == scctx->isc_nrxd[0]) | ||||||||||
cidx = 0; | cidx = 0; | ||||||||||
i++; | i++; | ||||||||||
} while (!eop); | } while (!eop); | ||||||||||
/* XXX add a faster way to look this up */ | /* XXX add a faster way to look this up */ | ||||||||||
if (sc->hw.mac.type >= e1000_82543) | if (sc->hw.mac.type >= e1000_82543) | ||||||||||
em_receive_checksum(status, errors, ri); | em_receive_checksum(status, errors, ri); | ||||||||||
if (status & E1000_RXD_STAT_VP) { | if (status & E1000_RXD_STAT_VP) { | ||||||||||
ri->iri_vtag = le16toh(rxd->special); | ri->iri_vtag = le16toh(rxd->special); | ||||||||||
ri->iri_flags |= M_VLANTAG; | ri->iri_flags |= M_VLANTAG; | ||||||||||
Not Done Inline Actions
markj: | |||||||||||
} | } | ||||||||||
ri->iri_nfrags = i; | ri->iri_nfrags = i; | ||||||||||
return (0); | return (0); | ||||||||||
} | } | ||||||||||
static int | static int | ||||||||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | em_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri) | ||||||||||
if (scctx->isc_capenable & IFCAP_RXCSUM) | if (scctx->isc_capenable & IFCAP_RXCSUM) | ||||||||||
em_receive_checksum(staterr, staterr >> 24, ri); | em_receive_checksum(staterr, staterr >> 24, ri); | ||||||||||
if (staterr & E1000_RXD_STAT_VP) { | if (staterr & E1000_RXD_STAT_VP) { | ||||||||||
ri->iri_vtag = le16toh(rxd->wb.upper.vlan); | ri->iri_vtag = le16toh(rxd->wb.upper.vlan); | ||||||||||
ri->iri_flags |= M_VLANTAG; | ri->iri_flags |= M_VLANTAG; | ||||||||||
} | } | ||||||||||
ri->iri_flowid = le32toh(rxd->wb.lower.hi_dword.rss); | ri->iri_flowid = le32toh(rxd->wb.lower.hi_dword.rss); | ||||||||||
Not Done Inline Actions
markj: | |||||||||||
ri->iri_rsstype = em_determine_rsstype(pkt_info); | ri->iri_rsstype = em_determine_rsstype(pkt_info); | ||||||||||
ri->iri_nfrags = i; | ri->iri_nfrags = i; | ||||||||||
return (0); | return (0); | ||||||||||
} | } | ||||||||||
/********************************************************************* | /********************************************************************* | ||||||||||
* | * | ||||||||||
* Verify that the hardware indicated that the checksum is valid. | * Verify that the hardware indicated that the checksum is valid. | ||||||||||
* Inform the stack about the status of checksum so that stack | * Inform the stack about the status of checksum so that stack | ||||||||||
* doesn't spend time verifying the checksum. | * doesn't spend time verifying the checksum. | ||||||||||
Done Inline ActionsI'd expect this to be rare too? markj: I'd expect this to be rare too? | |||||||||||
* | * | ||||||||||
*********************************************************************/ | *********************************************************************/ | ||||||||||
static void | static void | ||||||||||
em_receive_checksum(uint16_t status, uint8_t errors, if_rxd_info_t ri) | em_receive_checksum(uint16_t status, uint8_t errors, if_rxd_info_t ri) | ||||||||||
{ | { | ||||||||||
if (__predict_false(status & E1000_RXD_STAT_IXSM)) | if (__predict_false(status & E1000_RXD_STAT_IXSM)) | ||||||||||
return; | return; | ||||||||||
Show All 32 Lines | case E1000_RXDADV_RSSTYPE_IPV6_EX: | ||||||||||
return M_HASHTYPE_RSS_IPV6_EX; | return M_HASHTYPE_RSS_IPV6_EX; | ||||||||||
case E1000_RXDADV_RSSTYPE_IPV6: | case E1000_RXDADV_RSSTYPE_IPV6: | ||||||||||
return M_HASHTYPE_RSS_IPV6; | return M_HASHTYPE_RSS_IPV6; | ||||||||||
case E1000_RXDADV_RSSTYPE_IPV6_TCP_EX: | case E1000_RXDADV_RSSTYPE_IPV6_TCP_EX: | ||||||||||
return M_HASHTYPE_RSS_TCP_IPV6_EX; | return M_HASHTYPE_RSS_TCP_IPV6_EX; | ||||||||||
default: | default: | ||||||||||
return M_HASHTYPE_OPAQUE; | return M_HASHTYPE_OPAQUE; | ||||||||||
} | } | ||||||||||
} | } | ||||||||||
Not Done Inline Actionscase should be on the same indentation level as switch. markj: `case` should be on the same indentation level as `switch`. | |||||||||||
Not Done Inline ActionsThe indentation was right before. markj: The indentation was right before. |