|
Neohapsis is currently accepting applications for employment. For more information, please visit our website www.neohapsis.com or email hr@neohapsis.com |
From: Aaron Campbell (aaron
monkey.org)Date: Tue Jun 11 2002 - 21:23:12 CDT
Here's a patch for hardware TCP/IP checksum offloading for SysKonnect GigE
cards (only receive, for now). Please test and report to me.
Index: share/man/man4/sk.4
===================================================================
RCS file: /cvs/src/share/man/man4/sk.4,v
retrieving revision 1.13
diff -u -r1.13 sk.4
--- share/man/man4/sk.4 5 Oct 2001 14:45:53 -0000 1.13
+++ share/man/man4/sk.4 9 Jun 2002 22:25:21 -0000

-91,6 +91,8 
Using jumbo frames can greatly improve performance for certain tasks,
such as file transfers and data streaming.
.Pp
+Hardware TCP/IP checksum offloading for IPv4 is supported.
+.Pp
The following media types and options (as given to
.Xr ifconfig 8 )
are supported:
Index: sys/dev/pci/if_sk.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_sk.c,v
retrieving revision 1.25
diff -u -r1.25 if_sk.c
--- sys/dev/pci/if_sk.c 8 Jun 2002 23:32:16 -0000 1.25
+++ sys/dev/pci/if_sk.c 9 Jun 2002 22:25:21 -0000

-163,6 +163,8 
void sk_setmulti(struct sk_if_softc *);
void sk_tick(void *);
+int sk_rxcsum(struct mbuf *, u_int16_t, u_int16_t);
+
#define SK_SETBIT(sc, reg, x) \
CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) | x)

-547,6 +549,9 
rd->sk_rx_ring[i].sk_next =
vtophys(&rd->sk_rx_ring[i + 1]);
}
+ rd->sk_rx_ring[i].sk_csum1_start = ETHER_HDR_LEN;
+ rd->sk_rx_ring[i].sk_csum2_start = ETHER_HDR_LEN +
+ sizeof(struct ip);
}
sc_if->sk_cdata.sk_rx_prod = 0;

-1342,8 +1347,10 
struct mbuf *m;
struct ifnet *ifp;
struct sk_chain *cur_rx;
+ struct ether_header *eh;
int total_len = 0;
int i;
+ u_int16_t csum1, csum2;
u_int32_t rxstat;
ifp = &sc_if->arpcom.ac_if;

-1357,6 +1364,8 
m = cur_rx->sk_mbuf;
cur_rx->sk_mbuf = NULL;
total_len = SK_RXBYTES(sc_if->sk_rdata->sk_rx_ring[i].sk_ctl);
+ csum1 = sc_if->sk_rdata->sk_rx_ring[i].sk_csum1;
+ csum2 = sc_if->sk_rdata->sk_rx_ring[i].sk_csum2;
SK_INC(i, SK_RX_RING_CNT);
if (rxstat & XM_RXSTAT_ERRFRAME) {

-1397,8 +1406,13 
if (ifp->if_bpf)
bpf_mtap(ifp->if_bpf, m);
#endif
+ eh = mtod(m, struct ether_header *);
+ m_adj(m, ETHER_HDR_LEN);
+
+ m->m_pkthdr.csum = sk_rxcsum(m, csum1, csum2);
+
/* pass it on. */
- ether_input_mbuf(ifp, m);
+ ether_input(ifp, eh, m);
}
sc_if->sk_cdata.sk_rx_prod = i;

-1487,6 +1501,81 
mii_tick(mii);
mii_pollstat(mii);
timeout_del(&sc_if->sk_tick_ch);
+}
+
+int
+sk_rxcsum(m, csum1, csum2)
+ struct mbuf *m;
+ u_int16_t csum1, csum2;
+{
+ struct ip *ip = mtod(m, struct ip *);
+ u_int16_t fragoff = ntohs(ip->ip_off), iph_csum, ipo_csum, ipd_csum;
+ u_int32_t csum, lenproto;
+ int hlen = ip->ip_hl << 2, sumflags = 0;
+
+ if (ip->ip_v != IPVERSION)
+ return (0);
+
+ if (hlen < sizeof(struct ip))
+ return (0);
+
+ if (hlen > ntohs(ip->ip_len))
+ return (0);
+
+ /*
+ * csum1 = checksum of the data following the Ethernet header.
+ * csum2 = checksum of the data following the IP header (w/o options).
+ *
+ * We compute the IP header checksum by subtracting csum2 from csum1,
+ * then adding the checksum of the IP options.
+ */
+ iph_csum = in_cksum_addword(csum1, (~csum2 & 0xffff));
+ if (hlen > sizeof(struct ip)) {
+ ipo_csum = in4_cksum(m, 0, sizeof(struct ip), hlen -
+ sizeof(struct ip));
+ iph_csum = in_cksum_addword(iph_csum, ipo_csum);
+ ipd_csum = in_cksum_addword(csum2, (~ipo_csum & 0xffff));
+ } else
+ ipd_csum = csum2;
+
+ /*
+ * Check for bad IP checksum.
+ */
+ if (iph_csum != 0xffff) {
+ sumflags |= M_IPV4_CSUM_IN_BAD;
+ return (sumflags);
+ } else
+ sumflags |= M_IPV4_CSUM_IN_OK;
+
+ /*
+ * An IP fragment. Return now.
+ */
+ if ((fragoff & IP_MF) != 0 || ((fragoff & IP_OFFMASK) << 3) != 0)
+ return (sumflags);
+
+ /* XXX - check for no UDP checksum? */
+
+ switch (ip->ip_p) {
+ case IPPROTO_TCP:
+ case IPPROTO_UDP:
+ lenproto = ntohs(ip->ip_len) - hlen + ip->ip_p;
+
+ /* Calculate the pseudo header checksum. */
+ csum = in_cksum_addword(in_cksum_phdr(ip->ip_src.s_addr,
+ ip->ip_dst.s_addr, htonl(lenproto)) + ipd_csum, 0);
+ if (csum != 0xffff) {
+ sumflags |= (ip->ip_p == IPPROTO_TCP) ?
+ M_TCP_CSUM_IN_BAD : M_UDP_CSUM_IN_BAD;
+ } else {
+ sumflags |= (ip->ip_p == IPPROTO_TCP) ?
+ M_TCP_CSUM_IN_OK : M_UDP_CSUM_IN_OK;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return (sumflags);
}
void
Index: sys/dev/pci/if_skreg.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_skreg.h,v
retrieving revision 1.6
diff -u -r1.6 if_skreg.h
--- sys/dev/pci/if_skreg.h 23 Jun 2001 22:03:12 -0000 1.6
+++ sys/dev/pci/if_skreg.h 9 Jun 2002 22:25:22 -0000

-1068,7 +1068,7 
#define SK_RXCTL_OWN 0x80000000
#define SK_RXSTAT \
- (SK_OPCODE_DEFAULT|SK_RXCTL_EOF_INTR|SK_RXCTL_LASTFRAG| \
+ (SK_OPCODE_CSUM|SK_RXCTL_EOF_INTR|SK_RXCTL_LASTFRAG| \
SK_RXCTL_FIRSTFRAG|SK_RXCTL_OWN)
struct sk_tx_desc {
--- Aaron Campbell (aaronmonkey.org || aaron
openbsd.org) http://www.monkey.org/~aaron
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]