summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authornp <np@FreeBSD.org>2012-02-09 23:19:09 +0000
committernp <np@FreeBSD.org>2012-02-09 23:19:09 +0000
commit1a089455d64a86fb9e288851d23455f9390f4912 (patch)
tree8b9c34f9877ce253c7165c2f1a2ab31a0d4db85f /sys/dev
parent41fcde1a4ff1c934853ebacd7ae8dc82dd85b3ce (diff)
downloadFreeBSD-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.c6
-rw-r--r--sys/dev/cxgb/cxgb_sge.c42
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)) {
OpenPOWER on IntegriCloud