vmx(4): Add TCP/UDP Checksum Offloading for IPv4/6
authorjan <jan@openbsd.org>
Thu, 15 Feb 2024 13:24:45 +0000 (13:24 +0000)
committerjan <jan@openbsd.org>
Thu, 15 Feb 2024 13:24:45 +0000 (13:24 +0000)
ok jmatthew@, bluhm@

sys/dev/pci/if_vmx.c

index 4a9c762..7a3c772 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_vmx.c,v 1.80 2024/02/09 15:22:41 jan Exp $ */
+/*     $OpenBSD: if_vmx.c,v 1.81 2024/02/15 13:24:45 jan Exp $ */
 
 /*
  * Copyright (c) 2013 Tsubai Masanari
@@ -400,10 +400,12 @@ vmxnet3_attach(struct device *parent, struct device *self, void *aux)
        ifp->if_watchdog = vmxnet3_watchdog;
        ifp->if_hardmtu = VMXNET3_MAX_MTU;
        ifp->if_capabilities = IFCAP_VLAN_MTU;
-#if 0
-       if (sc->sc_ds->upt_features & UPT1_F_CSUM)
+
+       if (sc->sc_ds->upt_features & UPT1_F_CSUM) {
                ifp->if_capabilities |= IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4;
-#endif
+               ifp->if_capabilities |= IFCAP_CSUM_TCPv6 | IFCAP_CSUM_UDPv6;
+       }
+
 #if NVLAN > 0
        if (sc->sc_ds->upt_features & UPT1_F_VLAN)
                ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
@@ -1397,6 +1399,55 @@ vmx_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m)
            BUS_DMA_STREAMING | BUS_DMA_NOWAIT));
 }
 
+void
+vmxnet3_tx_offload(struct vmxnet3_txdesc *sop, struct mbuf *m)
+{
+       struct ether_extracted ext;
+       uint32_t offset = 0;
+       uint32_t hdrlen;
+
+       /*
+        * VLAN Offload
+        */
+
+#if NVLAN > 0
+       if (ISSET(m->m_flags, M_VLANTAG)) {
+               sop->tx_word3 |= htole32(VMXNET3_TX_VTAG_MODE);
+               sop->tx_word3 |= htole32((m->m_pkthdr.ether_vtag &
+                   VMXNET3_TX_VLANTAG_M) << VMXNET3_TX_VLANTAG_S);
+       }
+#endif
+
+       /*
+        * Checksum Offload
+        */
+
+       if (!ISSET(m->m_pkthdr.csum_flags, M_TCP_CSUM_OUT) &&
+           !ISSET(m->m_pkthdr.csum_flags, M_UDP_CSUM_OUT))
+               return;
+
+       ether_extract_headers(m, &ext);
+
+       hdrlen = sizeof(*ext.eh);
+       if (ext.evh)
+               hdrlen = sizeof(*ext.evh);
+
+       if (ext.ip4 || ext.ip6)
+               hdrlen += ext.iphlen;
+
+       if (ext.tcp)
+               offset = hdrlen + offsetof(struct tcphdr, th_sum);
+       else if (ext.udp)
+               offset = hdrlen + offsetof(struct udphdr, uh_sum);
+
+       hdrlen &= VMXNET3_TX_HLEN_M;
+       offset &= VMXNET3_TX_OP_M;
+
+       sop->tx_word3 |= htole32(VMXNET3_OM_CSUM << VMXNET3_TX_OM_S);
+       sop->tx_word3 |= htole32(hdrlen << VMXNET3_TX_HLEN_S);
+       sop->tx_word2 |= htole32(offset << VMXNET3_TX_OP_S);
+}
+
 void
 vmxnet3_start(struct ifqueue *ifq)
 {
@@ -1469,13 +1520,7 @@ vmxnet3_start(struct ifqueue *ifq)
                }
                txd->tx_word3 = htole32(VMXNET3_TX_EOP | VMXNET3_TX_COMPREQ);
 
-#if NVLAN > 0
-               if (ISSET(m->m_flags, M_VLANTAG)) {
-                       sop->tx_word3 |= htole32(VMXNET3_TX_VTAG_MODE);
-                       sop->tx_word3 |= htole32((m->m_pkthdr.ether_vtag &
-                           VMXNET3_TX_VLANTAG_M) << VMXNET3_TX_VLANTAG_S);
-               }
-#endif
+               vmxnet3_tx_offload(sop, m);
 
                ring->prod = prod;
                /* Change the ownership by flipping the "generation" bit */