From: Stefan Sperling Subject: dwqe Rx IP header checksum offload To: tech@openbsd.org Date: Mon, 8 Apr 2024 17:20:51 +0200 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)