From: Sepherosa Ziehau Date: Sat, 9 Mar 2013 09:37:13 +0000 (+0800) Subject: bce: Utilize hardware supplied RSS hash X-Git-Tag: v3.4.0rc~138 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/42ad0e07a760aa29981d4650100f65e770f8f144 bce: Utilize hardware supplied RSS hash The IP fragment detection needs further investigation. Currently we can't tell for 100% sure whether the received packet is an IP fragment or not; we just test the hardware supplied checksum against 0xffff for IP fragment detection. However, it is not a big deal in the current code base, since IP fragments reassemabling is under a token (the IP fragments reassemabing used to be only allowed on netisr0) --- diff --git a/sys/dev/netif/bce/if_bce.c b/sys/dev/netif/bce/if_bce.c index cbeefee27d..fd231aa79b 100644 --- a/sys/dev/netif/bce/if_bce.c +++ b/sys/dev/netif/bce/if_bce.c @@ -414,6 +414,8 @@ static int bce_newbuf_std(struct bce_rx_ring *, uint16_t *, uint16_t, uint32_t *, int); static void bce_setup_rxdesc_std(struct bce_rx_ring *, uint16_t, uint32_t *); +static struct pktinfo *bce_rss_pktinfo(struct pktinfo *, uint32_t, + const struct l2_fhdr *); static void bce_start(struct ifnet *, struct ifaltq_subque *); static int bce_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *); @@ -986,6 +988,8 @@ bce_attach(device_t dev) ifp->if_mtu = ETHERMTU; ifp->if_hwassist = BCE_CSUM_FEATURES | CSUM_TSO; ifp->if_capabilities = BCE_IF_CAPABILITIES; + if (sc->rx_ring_cnt > 1) + ifp->if_capabilities |= IFCAP_RSS; ifp->if_capenable = ifp->if_capabilities; if (sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG) @@ -4346,6 +4350,7 @@ bce_rx_intr(struct bce_rx_ring *rxr, int count, uint16_t hw_cons) /* Scan through the receive chain as long as there is work to do. */ while (sw_cons != hw_cons) { + struct pktinfo pi0, *pi = NULL; struct bce_rx_buf *rx_buf; struct mbuf *m = NULL; struct l2_fhdr *l2fhdr = NULL; @@ -4484,6 +4489,15 @@ bce_rx_intr(struct bce_rx_ring *rxr, int count, uint16_t hw_cons) } } } + if (ifp->if_capenable & IFCAP_RSS) { + pi = bce_rss_pktinfo(&pi0, status, l2fhdr); + if (pi != NULL && + (status & L2_FHDR_STATUS_RSS_HASH)) { + m->m_flags |= M_HASH; + m->m_pkthdr.hash = + toeplitz_hash(l2fhdr->l2_fhdr_hash); + } + } IFNET_STAT_INC(ifp, ipackets, 1); bce_rx_int_next_rx: @@ -4499,7 +4513,7 @@ bce_rx_int_next_rx: m->m_pkthdr.ether_vlantag = l2fhdr->l2_fhdr_vlan_tag; } - ifp->if_input(ifp, m); + ether_input_pkt(ifp, m, pi); #ifdef BCE_RSS_DEBUG rxr->rx_pkts++; #endif @@ -5119,6 +5133,8 @@ bce_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr) else ifp->if_hwassist &= ~CSUM_TSO; } + if (mask & IFCAP_RSS) + ifp->if_capenable ^= IFCAP_RSS; break; default: @@ -7188,3 +7204,37 @@ bce_npoll_coal_change(struct bce_softc *sc) sc->bce_rx_quick_cons_trip_int = old_rx_cons; sc->bce_tx_quick_cons_trip_int = old_tx_cons; } + +static struct pktinfo * +bce_rss_pktinfo(struct pktinfo *pi, uint32_t status, + const struct l2_fhdr *l2fhdr) +{ + /* Check for an IP datagram. */ + if ((status & L2_FHDR_STATUS_IP_DATAGRAM) == 0) + return NULL; + + /* Check if the IP checksum is valid. */ + if (l2fhdr->l2_fhdr_ip_xsum != 0xffff) + return NULL; + + /* Check for a valid TCP/UDP frame. */ + if (status & L2_FHDR_STATUS_TCP_SEGMENT) { + if (status & L2_FHDR_ERRORS_TCP_XSUM) + return NULL; + if (l2fhdr->l2_fhdr_tcp_udp_xsum != 0xffff) + return NULL; + pi->pi_l3proto = IPPROTO_TCP; + } else if (status & L2_FHDR_STATUS_UDP_DATAGRAM) { + if (status & L2_FHDR_ERRORS_UDP_XSUM) + return NULL; + if (l2fhdr->l2_fhdr_tcp_udp_xsum != 0xffff) + return NULL; + pi->pi_l3proto = IPPROTO_UDP; + } else { + return NULL; + } + pi->pi_netisr = NETISR_IP; + pi->pi_flags = 0; + + return pi; +}