Index | Thread | Search

From:
Stefan Sperling <stsp@stsp.name>
Subject:
dwqe Rx IP header checksum offload
To:
tech@openbsd.org
Date:
Mon, 8 Apr 2024 17:20:51 +0200

Download raw body.

Thread
The patch below enables IP header checksum offload in Rx for dwqe(4).

In my test setup the happy path works with offloading as expected but
I did not yet manage to successfully trigger an Rx interrupt in dwqe(4)
with a packet that has a bad IP header checksum.
This setup is remote and there is a switch in-between the interfaces
I use for testing. I am not sure if the bad packet even makes it onto
the wire where dwqe is listening.
If someone has the means to test bad IP checksums easily I would
appreciate help and/or hints.

I am not sure which of (RDES1_IP_HDR_ERROR | RDES1_IP_CSUM_ERROR) will
be set in the error case, so for now I am checking both bits.

I am also unsure whether RDES1_IPV4_HDR will be set for packets with
an invalid checksum. Fall back on software verification if it is not set,
which is not ideal but at least shouldn't break anything.

diff 10b37c3828744df12271d36aa2bfdb7e386d157f refs/heads/dwqe
commit - 10b37c3828744df12271d36aa2bfdb7e386d157f
commit + 3bdb4dc7959d23f2a15f8d74f1cb32e01418d52d
blob - dfc822b6576d4301e06ee6612dfae3fa1f19f721
blob + 90e9eefe4fecfab38fdbf63501495e3e3e7c1aef
--- sys/dev/ic/dwqe.c
+++ sys/dev/ic/dwqe.c
@@ -641,6 +641,12 @@ dwqe_tx_proc(struct dwqe_softc *sc)
 	}
 }
 
+int
+dwqe_have_rx_csum_offload(struct dwqe_softc *sc)
+{
+	return (sc->sc_hw_feature[0] & GMAC_MAC_HW_FEATURE0_RXCOESEL);
+}
+
 void
 dwqe_rx_proc(struct dwqe_softc *sc)
 {
@@ -689,6 +695,17 @@ dwqe_rx_proc(struct dwqe_softc *sc)
 
 			m->m_pkthdr.len = m->m_len = len;
 
+			if (dwqe_have_rx_csum_offload(sc) &&
+			    (rxd->sd_tdes1 & RDES1_IPV4_HDR)) {
+				uint16_t flag;
+				if (rxd->sd_tdes1 &
+				    (RDES1_IP_HDR_ERROR | RDES1_IP_CSUM_ERROR))
+					flag = M_IPV4_CSUM_IN_BAD;
+				else 
+					flag = M_IPV4_CSUM_IN_OK;
+				m->m_pkthdr.csum_flags |= flag;
+			}
+
 			ml_enqueue(&ml, m);
 		}
 
@@ -864,6 +881,12 @@ dwqe_up(struct dwqe_softc *sc)
 
 	if (!sc->sc_fixed_link)
 		timeout_add_sec(&sc->sc_phy_tick, 1);
+
+	if (dwqe_have_rx_csum_offload(sc)) {
+		reg = dwqe_read(sc, GMAC_MAC_CONF);
+		reg |= GMAC_MAC_CONF_IPC;
+		dwqe_write(sc, GMAC_MAC_CONF, reg);
+	}
 }
 
 void
blob - bc6de32a5a5e80968082f683f9536d64b944b518
blob + 5f9a22678eee28f56ecbb5b20d763c29eb4de5d7
--- sys/dev/ic/dwqereg.h
+++ sys/dev/ic/dwqereg.h
@@ -17,6 +17,7 @@
  */
 
 #define GMAC_MAC_CONF		0x0000
+#define  GMAC_MAC_CONF_IPC		(1 << 27)
 #define  GMAC_MAC_CONF_CST		(1 << 21)
 #define  GMAC_MAC_CONF_ACS		(1 << 20)
 #define  GMAC_MAC_CONF_BE		(1 << 18)
@@ -61,6 +62,8 @@
 #define GMAC_VERSION		0x0110
 #define  GMAC_VERSION_SNPS_MASK		0xff
 #define GMAC_MAC_HW_FEATURE(x)	(0x011c + (x) * 0x4)
+#define  GMAC_MAC_HW_FEATURE0_TXCOESEL	(1 << 14)
+#define  GMAC_MAC_HW_FEATURE0_RXCOESEL	(1 << 16)
 #define  GMAC_MAC_HW_FEATURE1_TXFIFOSIZE(x) (((x) >> 6) & 0x1f)
 #define  GMAC_MAC_HW_FEATURE1_RXFIFOSIZE(x) (((x) >> 0) & 0x1f)
 #define GMAC_MAC_MDIO_ADDR	0x0200
@@ -234,6 +237,12 @@ struct dwqe_desc {
 #define TDES3_OWN		(1U << 31)
 
 /* Rx bits */
+#define RDES1_IP_PAYLOAD_TYPE	0x7
+#define RDES1_IP_HDR_ERROR	(1 << 3)
+#define RDES1_IPV4_HDR		(1 << 4)
+#define RDES1_IPV6_HDR		(1 << 5)
+#define RDES1_IP_CSUM_BYPASS	(1 << 6)
+#define RDES1_IP_CSUM_ERROR	(1 << 7)
 #define RDES3_ES		(1 << 15)
 #define RDES3_DE		(1 << 19)
 #define RDES3_RE		(1 << 20)