diff options
author | np <np@FreeBSD.org> | 2012-02-09 23:19:09 +0000 |
---|---|---|
committer | np <np@FreeBSD.org> | 2012-02-09 23:19:09 +0000 |
commit | 1a089455d64a86fb9e288851d23455f9390f4912 (patch) | |
tree | 8b9c34f9877ce253c7165c2f1a2ab31a0d4db85f /sys/dev | |
parent | 41fcde1a4ff1c934853ebacd7ae8dc82dd85b3ce (diff) | |
download | FreeBSD-src-1a089455d64a86fb9e288851d23455f9390f4912.zip FreeBSD-src-1a089455d64a86fb9e288851d23455f9390f4912.tar.gz |
Add IPv6 TSO (including TSO+VLAN) support to cxgb(4).
If an IPv6 packet has extension headers the kernel needs to deal with it
itself. For the rest it can set various CSUM_XXX flags and the driver
will act on them.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/cxgb/cxgb_main.c | 6 | ||||
-rw-r--r-- | sys/dev/cxgb/cxgb_sge.c | 42 |
2 files changed, 34 insertions, 14 deletions
diff --git a/sys/dev/cxgb/cxgb_main.c b/sys/dev/cxgb/cxgb_main.c index 82008e8..fb42004 100644 --- a/sys/dev/cxgb/cxgb_main.c +++ b/sys/dev/cxgb/cxgb_main.c @@ -982,7 +982,7 @@ cxgb_makedev(struct port_info *pi) #define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | \ IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO | \ IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE) -#define CXGB_CAP_ENABLE (CXGB_CAP & ~IFCAP_TSO6) +#define CXGB_CAP_ENABLE CXGB_CAP static int cxgb_port_attach(device_t dev) @@ -2059,8 +2059,8 @@ fail: } if (mask & IFCAP_RXCSUM) ifp->if_capenable ^= IFCAP_RXCSUM; - if (mask & IFCAP_TSO4) { - ifp->if_capenable ^= IFCAP_TSO4; + if (mask & IFCAP_TSO) { + ifp->if_capenable ^= IFCAP_TSO; if (IFCAP_TSO & ifp->if_capenable) { if (IFCAP_TXCSUM & ifp->if_capenable) diff --git a/sys/dev/cxgb/cxgb_sge.c b/sys/dev/cxgb/cxgb_sge.c index 207f4fb..a34dab2 100644 --- a/sys/dev/cxgb/cxgb_sge.c +++ b/sys/dev/cxgb/cxgb_sge.c @@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$"); #include <netinet/in_systm.h> #include <netinet/in.h> #include <netinet/ip.h> +#include <netinet/ip6.h> #include <netinet/tcp.h> #include <dev/pci/pcireg.h> @@ -1492,10 +1493,10 @@ t3_encap(struct sge_qset *qs, struct mbuf **m) check_ring_tx_db(sc, txq, 0); return (0); } else if (tso_info) { - int eth_type; + uint16_t eth_type; struct cpl_tx_pkt_lso *hdr = (struct cpl_tx_pkt_lso *)txd; struct ether_header *eh; - struct ip *ip; + void *l3hdr; struct tcphdr *tcp; txd->flit[2] = 0; @@ -1521,18 +1522,37 @@ t3_encap(struct sge_qset *qs, struct mbuf **m) } eh = mtod(m0, struct ether_header *); - if (eh->ether_type == htons(ETHERTYPE_VLAN)) { - eth_type = CPL_ETH_II_VLAN; - ip = (struct ip *)((struct ether_vlan_header *)eh + 1); + eth_type = eh->ether_type; + if (eth_type == htons(ETHERTYPE_VLAN)) { + struct ether_vlan_header *evh = (void *)eh; + + tso_info |= V_LSO_ETH_TYPE(CPL_ETH_II_VLAN); + l3hdr = evh + 1; + eth_type = evh->evl_proto; } else { - eth_type = CPL_ETH_II; - ip = (struct ip *)(eh + 1); + tso_info |= V_LSO_ETH_TYPE(CPL_ETH_II); + l3hdr = eh + 1; } - tcp = (struct tcphdr *)(ip + 1); - tso_info |= V_LSO_ETH_TYPE(eth_type) | - V_LSO_IPHDR_WORDS(ip->ip_hl) | - V_LSO_TCPHDR_WORDS(tcp->th_off); + if (eth_type == htons(ETHERTYPE_IP)) { + struct ip *ip = l3hdr; + + tso_info |= V_LSO_IPHDR_WORDS(ip->ip_hl); + tcp = (struct tcphdr *)(ip + 1); + } else if (eth_type == htons(ETHERTYPE_IPV6)) { + struct ip6_hdr *ip6 = l3hdr; + + KASSERT(ip6->ip6_nxt == IPPROTO_TCP, + ("%s: CSUM_TSO with ip6_nxt %d", + __func__, ip6->ip6_nxt)); + + tso_info |= F_LSO_IPV6; + tso_info |= V_LSO_IPHDR_WORDS(sizeof(*ip6) >> 2); + tcp = (struct tcphdr *)(ip6 + 1); + } else + panic("%s: CSUM_TSO but neither ip nor ip6", __func__); + + tso_info |= V_LSO_TCPHDR_WORDS(tcp->th_off); hdr->lso_info = htonl(tso_info); if (__predict_false(mlen <= PIO_LEN)) { |