On Sat, Apr 19, 2014 at 09:30:27PM +0200, Christian Weisgerber wrote:
> This removes a RX offload hack similar to the one just deleted from
> sk(4).  These chips can only add 16-bit words starting from some
> offset, and so the driver gives them the likely start of the TCP/UDP
> payload and then tries to compensate and... ugh.
> 
> Affected drivers:
> * gem(4)
> * hme(4)
> * another hme(4) driver for sparc
> 
> I've successfully tested gem(4) on a Blade 100.  I don't have any
> hme(4) hardware.
> 

Running with this on my sparc64 with:
hme0 at pci1 dev 1 function 1 "Sun HME" rev 0x01: ivec 0x7e1, address 
08:00:20:c2:d2:0a
luphy0 at hme0 phy 0: LU6612 10/100 PHY, rev. 1

Seems to work (at least SSH and other TCP services still work).

-- 
:wq Claudio

> ok?
> 
> Index: dev/ic/gem.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/ic/gem.c,v
> retrieving revision 1.102
> diff -u -p -r1.102 gem.c
> --- dev/ic/gem.c      14 Mar 2014 11:04:24 -0000      1.102
> +++ dev/ic/gem.c      19 Apr 2014 19:00:01 -0000
> @@ -120,7 +120,6 @@ int               gem_eint(struct gem_softc *, u_int)
>  int          gem_rint(struct gem_softc *);
>  int          gem_tint(struct gem_softc *, u_int32_t);
>  int          gem_pint(struct gem_softc *);
> -void         gem_rxcksum(struct mbuf *, u_int64_t);
>  
>  #ifdef GEM_DEBUG
>  #define      DPRINTF(sc, x)  if ((sc)->sc_arpcom.ac_if.if_flags & IFF_DEBUG) 
> \
> @@ -811,9 +810,6 @@ gem_init(struct ifnet *ifp)
>  
>       /* Encode Receive Descriptor ring size: four possible values */
>       v = gem_ringsize(GEM_NRXDESC /*XXX*/);
> -     /* RX TCP/UDP checksum offset */
> -     v |= ((ETHER_HDR_LEN + sizeof(struct ip)) <<
> -         GEM_RX_CONFIG_CXM_START_SHFT);
>       /* Enable DMA */
>       bus_space_write_4(t, h, GEM_RX_CONFIG, 
>               v|(GEM_THRSH_1024<<GEM_RX_CONFIG_FIFO_THRS_SHIFT)|
> @@ -948,95 +944,6 @@ gem_init_regs(struct gem_softc *sc)
>  }
>  
>  /*
> - * RX TCP/UDP checksum
> - */
> -void
> -gem_rxcksum(struct mbuf *m, u_int64_t rxstat)
> -{
> -     struct ether_header *eh;
> -     struct ip *ip;
> -     struct udphdr *uh;
> -     int32_t hlen, len, pktlen;
> -     u_int16_t cksum, *opts;
> -     u_int32_t temp32;
> -     union pseudoh {
> -             struct hdr {
> -                     u_int16_t len;
> -                     u_int8_t ttl;
> -                     u_int8_t proto;
> -                     u_int32_t src;
> -                     u_int32_t dst;
> -             } h;
> -             u_int16_t w[6];
> -     } ph;
> -
> -     pktlen = m->m_pkthdr.len;
> -     if (pktlen < sizeof(struct ether_header))
> -             return;
> -     eh = mtod(m, struct ether_header *);
> -     if (eh->ether_type != htons(ETHERTYPE_IP))
> -             return;
> -     ip = (struct ip *)(eh + 1);
> -     if (ip->ip_v != IPVERSION)
> -             return;
> -
> -     hlen = ip->ip_hl << 2;
> -     pktlen -= sizeof(struct ether_header);
> -     if (hlen < sizeof(struct ip))
> -             return;
> -     if (ntohs(ip->ip_len) < hlen)
> -             return;
> -     if (ntohs(ip->ip_len) != pktlen) 
> -             return;
> -     if (ip->ip_off & htons(IP_MF | IP_OFFMASK))
> -             return; /* can't handle fragmented packet */
> -
> -     switch (ip->ip_p) {
> -     case IPPROTO_TCP:
> -             if (pktlen < (hlen + sizeof(struct tcphdr)))
> -                     return;
> -             break;
> -     case IPPROTO_UDP:
> -             if (pktlen < (hlen + sizeof(struct udphdr)))
> -                     return;
> -             uh = (struct udphdr *)((caddr_t)ip + hlen);
> -             if (uh->uh_sum == 0)
> -                     return; /* no checksum */
> -             break;
> -     default:
> -             return;
> -     }
> -
> -     cksum = htons(~(rxstat & GEM_RD_CHECKSUM));
> -     /* cksum fixup for IP options */
> -     len = hlen - sizeof(struct ip);
> -     if (len > 0) {
> -             opts = (u_int16_t *)(ip + 1);
> -             for (; len > 0; len -= sizeof(u_int16_t), opts++) {
> -                     temp32 = cksum - *opts;
> -                     temp32 = (temp32 >> 16) + (temp32 & 65535);
> -                     cksum = temp32 & 65535;
> -             }
> -     }
> -
> -     ph.h.len = htons(ntohs(ip->ip_len) - hlen);
> -     ph.h.ttl = 0;
> -     ph.h.proto = ip->ip_p;
> -     ph.h.src = ip->ip_src.s_addr;
> -     ph.h.dst = ip->ip_dst.s_addr;
> -     temp32 = cksum;
> -     opts = &ph.w[0];
> -     temp32 += opts[0] + opts[1] + opts[2] + opts[3] + opts[4] + opts[5];
> -     temp32 = (temp32 >> 16) + (temp32 & 65535);
> -     temp32 += (temp32 >> 16);
> -     cksum = ~temp32;
> -     if (cksum == 0) {
> -             m->m_pkthdr.csum_flags |=
> -                     M_TCP_CSUM_IN_OK | M_UDP_CSUM_IN_OK;
> -     }
> -}
> -
> -/*
>   * Receive interrupt.
>   */
>  int
> @@ -1100,8 +1007,6 @@ gem_rint(struct gem_softc *sc)
>               ifp->if_ipackets++;
>               m->m_pkthdr.rcvif = ifp;
>               m->m_pkthdr.len = m->m_len = len;
> -
> -             gem_rxcksum(m, rxstat); 
>  
>  #if NBPFILTER > 0
>               if (ifp->if_bpf)
> Index: dev/ic/hme.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/ic/hme.c,v
> retrieving revision 1.63
> diff -u -p -r1.63 hme.c
> --- dev/ic/hme.c      7 Aug 2013 01:06:29 -0000       1.63
> +++ dev/ic/hme.c      19 Apr 2014 19:12:29 -0000
> @@ -105,8 +105,6 @@ void              hme_mediastatus(struct ifnet *, st
>  int          hme_eint(struct hme_softc *, u_int);
>  int          hme_rint(struct hme_softc *);
>  int          hme_tint(struct hme_softc *);
> -/* TCP/UDP checksum offload support */
> -void                 hme_rxcksum(struct mbuf *, u_int32_t);
>  
>  void
>  hme_config(sc)
> @@ -516,7 +514,7 @@ hme_init(sc)
>       bus_space_handle_t erx = sc->sc_erx;
>       bus_space_handle_t mac = sc->sc_mac;
>       u_int8_t *ea;
> -     u_int32_t v, n;
> +     u_int32_t v;
>  
>       /*
>        * Initialization sequence. The numbered steps below correspond
> @@ -625,10 +623,6 @@ hme_init(sc)
>  #endif
>       /* Enable DMA */
>       v |= HME_ERX_CFG_DMAENABLE | (HME_RX_OFFSET << 3);
> -     /* RX TCP/UDP cksum offset */
> -     n = (ETHER_HDR_LEN + sizeof(struct ip)) / 2;
> -     n = (n << HME_ERX_CFG_CSUM_SHIFT) & HME_ERX_CFG_CSUMSTART;
> -     v |= n;
>       bus_space_write_4(t, erx, HME_ERXI_CFG, v);
>  
>       /* step 11. XIF Configuration */
> @@ -831,101 +825,6 @@ hme_tint(sc)
>  }
>  
>  /*
> - * XXX layering violation
> - *
> - * If we can have additional csum data member in 'struct pkthdr' for
> - * these incomplete checksum offload capable hardware, things would be
> - * much simpler. That member variable will carry partial checksum
> - * data and it may be evaluated in TCP/UDP input handler after
> - * computing pseudo header checksumming.
> - */
> -void
> -hme_rxcksum(struct mbuf *m, u_int32_t flags)
> -{
> -     struct ether_header *eh;
> -     struct ip *ip;
> -     struct udphdr *uh;
> -     int32_t hlen, len, pktlen;
> -     u_int16_t cksum, *opts;
> -     u_int32_t temp32;
> -     union pseudoh {
> -             struct hdr {
> -                     u_int16_t len;
> -                     u_int8_t ttl;
> -                     u_int8_t proto;
> -                     u_int32_t src;
> -                     u_int32_t dst;
> -             } h;
> -             u_int16_t w[6];
> -     } ph;
> -
> -     pktlen = m->m_pkthdr.len;
> -     if (pktlen < sizeof(struct ether_header))
> -             return;
> -     eh = mtod(m, struct ether_header *);
> -     if (eh->ether_type != htons(ETHERTYPE_IP))
> -             return;
> -     ip = (struct ip *)(eh + 1);
> -     if (ip->ip_v != IPVERSION)
> -             return;
> -
> -     hlen = ip->ip_hl << 2;
> -     pktlen -= sizeof(struct ether_header);
> -     if (hlen < sizeof(struct ip))
> -             return;
> -     if (ntohs(ip->ip_len) < hlen)
> -             return;
> -     if (ntohs(ip->ip_len) != pktlen) 
> -             return;
> -     if (ip->ip_off & htons(IP_MF | IP_OFFMASK))
> -             return; /* can't handle fragmented packet */
> -
> -     switch (ip->ip_p) {
> -     case IPPROTO_TCP:
> -             if (pktlen < (hlen + sizeof(struct tcphdr)))
> -                     return;
> -             break;
> -     case IPPROTO_UDP:
> -             if (pktlen < (hlen + sizeof(struct udphdr)))
> -                     return;
> -             uh = (struct udphdr *)((caddr_t)ip + hlen);
> -             if (uh->uh_sum == 0)
> -                     return; /* no checksum */
> -             break;
> -     default:
> -             return;
> -     }
> -
> -     cksum = htons(~(flags & HME_XD_RXCKSUM));
> -     /* cksum fixup for IP options */
> -     len = hlen - sizeof(struct ip);
> -     if (len > 0) {
> -             opts = (u_int16_t *)(ip + 1);
> -             for (; len > 0; len -= sizeof(u_int16_t), opts++) {
> -                     temp32 = cksum - *opts;
> -                     temp32 = (temp32 >> 16) + (temp32 & 65535);
> -                     cksum = temp32 & 65535;
> -             }
> -     }
> -     /* cksum fixup for pseudo-header, replace with in_cksum_phdr()? */
> -     ph.h.len = htons(ntohs(ip->ip_len) - hlen);
> -     ph.h.ttl = 0;
> -     ph.h.proto = ip->ip_p;
> -     ph.h.src = ip->ip_src.s_addr;
> -     ph.h.dst = ip->ip_dst.s_addr;
> -     temp32 = cksum;
> -     opts = &ph.w[0];
> -     temp32 += opts[0] + opts[1] + opts[2] + opts[3] + opts[4] + opts[5];
> -     temp32 = (temp32 >> 16) + (temp32 & 65535);
> -     temp32 += (temp32 >> 16);
> -     cksum = ~temp32;
> -     if (cksum == 0) {
> -             m->m_pkthdr.csum_flags |=
> -                     M_TCP_CSUM_IN_OK | M_UDP_CSUM_IN_OK;
> -     }
> -}
> -
> -/*
>   * Receive interrupt.
>   */
>  int
> @@ -975,7 +874,6 @@ hme_rint(sc)
>               m->m_pkthdr.len = m->m_len = len;
>  
>               ifp->if_ipackets++;
> -             hme_rxcksum(m, flags);
>  
>  #if NBPFILTER > 0
>               if (ifp->if_bpf)
> Index: arch/sparc/dev/hme.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/sparc/dev/hme.c,v
> retrieving revision 1.64
> diff -u -p -r1.64 hme.c
> --- arch/sparc/dev/hme.c      5 Sep 2013 20:55:58 -0000       1.64
> +++ arch/sparc/dev/hme.c      19 Apr 2014 19:15:08 -0000
> @@ -103,9 +103,6 @@ int       hme_tint(struct hme_softc *);
>  int  hme_mint(struct hme_softc *, u_int32_t);
>  int  hme_eint(struct hme_softc *, u_int32_t);
>  
> -/* TCP/UDP checksum offload support */
> -void hme_rxcksum(struct mbuf *, u_int32_t);
> -
>  void hme_reset_rx(struct hme_softc *);
>  void hme_reset_tx(struct hme_softc *);
>  
> @@ -494,7 +491,7 @@ void
>  hmeinit(sc)
>       struct hme_softc *sc;
>  {
> -     u_int32_t c, n;
> +     u_int32_t c;
>       struct ifnet *ifp = &sc->sc_arpcom.ac_if;
>       struct hme_tcvr *tcvr = sc->sc_tcvr;
>       struct hme_cr *cr = sc->sc_cr;
> @@ -553,10 +550,6 @@ hmeinit(sc)
>       txr->cfg |= TXR_CFG_DMAENABLE;
>  
>       c = RXR_CFG_DMAENABLE | (HME_RX_OFFSET << 3);
> -     /* RX TCP/UDP cksum offset */
> -     n = (ETHER_HDR_LEN + sizeof(struct ip)) / 2;
> -     n = (n << RXR_CFG_CSUM_SHIFT) & RXR_CFG_CSUMSTART;
> -     c |= n;
>  #if HME_RX_RING_SIZE == 32
>       c |= RXR_CFG_RINGSIZE32;
>  #elif HME_RX_RING_SIZE == 64
> @@ -709,101 +702,6 @@ hme_tint(sc)
>       return (1);
>  }
>  
> -/*
> - * XXX layering violation
> - *
> - * If we can have additional csum data member in 'struct pkthdr' for
> - * these incomplete checksum offload capable hardware, things would be
> - * much simpler. That member variable will carry partial checksum
> - * data and it may be evaluated in TCP/UDP input handler after
> - * computing pseudo header checksumming.
> - */
> -void
> -hme_rxcksum(struct mbuf *m, u_int32_t flags)
> -{
> -     struct ether_header *eh;
> -     struct ip *ip;
> -     struct udphdr *uh;
> -     int32_t hlen, len, pktlen;
> -     u_int16_t cksum, *opts;
> -     u_int32_t temp32;
> -     union pseudoh {
> -             struct hdr {
> -                     u_int16_t len;
> -                     u_int8_t ttl;
> -                     u_int8_t proto;
> -                     u_int32_t src;
> -                     u_int32_t dst;
> -             } h;
> -             u_int16_t w[6];
> -     } ph;
> -
> -     pktlen = m->m_pkthdr.len;
> -     if (pktlen < sizeof(struct ether_header))
> -             return;
> -     eh = mtod(m, struct ether_header *);
> -     if (eh->ether_type != htons(ETHERTYPE_IP))
> -             return;
> -     ip = (struct ip *)(eh + 1);
> -     if (ip->ip_v != IPVERSION)
> -             return;
> -
> -     hlen = ip->ip_hl << 2;
> -     pktlen -= sizeof(struct ether_header);
> -     if (hlen < sizeof(struct ip))
> -             return;
> -     if (ntohs(ip->ip_len) < hlen)
> -             return;
> -     if (ntohs(ip->ip_len) != pktlen) 
> -             return;
> -     if (ip->ip_off & htons(IP_MF | IP_OFFMASK))
> -             return; /* can't handle fragmented packet */
> -
> -     switch (ip->ip_p) {
> -     case IPPROTO_TCP:
> -             if (pktlen < (hlen + sizeof(struct tcphdr)))
> -                     return;
> -             break;
> -     case IPPROTO_UDP:
> -             if (pktlen < (hlen + sizeof(struct udphdr)))
> -                     return;
> -             uh = (struct udphdr *)((caddr_t)ip + hlen);
> -             if (uh->uh_sum == 0)
> -                     return; /* no checksum */
> -             break;
> -     default:
> -             return;
> -     }
> -
> -     cksum = htons(~(flags & HME_RXD_CSUM));
> -     /* cksum fixup for IP options */
> -     len = hlen - sizeof(struct ip);
> -     if (len > 0) {
> -             opts = (u_int16_t *)(ip + 1);
> -             for (; len > 0; len -= sizeof(u_int16_t), opts++) {
> -                     temp32 = cksum - *opts;
> -                     temp32 = (temp32 >> 16) + (temp32 & 65535);
> -                     cksum = temp32 & 65535;
> -             }
> -     }
> -     /* cksum fixup for pseudo-header, replace with in_cksum_phdr()? */
> -     ph.h.len = htons(ntohs(ip->ip_len) - hlen);
> -     ph.h.ttl = 0;
> -     ph.h.proto = ip->ip_p;
> -     ph.h.src = ip->ip_src.s_addr;
> -     ph.h.dst = ip->ip_dst.s_addr;
> -     temp32 = cksum;
> -     opts = &ph.w[0];
> -     temp32 += opts[0] + opts[1] + opts[2] + opts[3] + opts[4] + opts[5];
> -     temp32 = (temp32 >> 16) + (temp32 & 65535);
> -     temp32 += (temp32 >> 16);
> -     cksum = ~temp32;
> -     if (cksum == 0) {
> -             m->m_pkthdr.csum_flags |=
> -                     M_TCP_CSUM_IN_OK | M_UDP_CSUM_IN_OK;
> -     }
> -}
> -
>  int
>  hme_rint(sc)
>       struct hme_softc *sc;
> @@ -944,7 +842,6 @@ hme_read(sc, idx, len, flags)
>       }
>  
>       ifp->if_ipackets++;
> -     hme_rxcksum(m, flags);
>  
>  #if NBPFILTER > 0
>       /*
> -- 
> Christian "naddy" Weisgerber                          na...@mips.inka.de
> 

Reply via email to