Hi Josh & Frank, A few nits. Overall a nice patch.
One question: Will multicast TFTP still work when this is applied? Josh Boyer wrote: > From: Frank Haverkamp <[EMAIL PROTECTED]> > > http://tools.ietf.org/html/rfc2348 describes the TFTP block size option > which allows larger packtes than the 512 byte default. This reduces the > s/packtes/packets/ > number of TFTP ACKs significantly and improves performance. > > To get the most benefit out of the tftp block size option the support > of defragementation of IP/UDP packet is helpful. The current implemenation > s/defragementation/defragmentation/ s/implemenation/implementation/ > should work even with packets received out of order. To enable the large > packet size the user should set "tftp_block_size" so a value like 16352. > > s/so/to/ > We experimented with different packet sizes and found that more than those > 16KiB do not contribute much to the performance anymore. Therefor I limited > s/Therefor/Therefore/ > the defragmentation buffer to 16KiB no too waste memory. > > so as to not waste memory > Signed-off-by: Frank Haverkamp <[EMAIL PROTECTED]> > Signed-off-by: Josh Boyer <[EMAIL PROTECTED]> > > --- > include/net.h | 17 ++++++ > net/net.c | 156 > ++++++++++++++++++++++++++++++++++++++++++++++++++-------- > net/tftp.c | 22 ++++++++ > net/tftp.h | 10 +++ > 4 files changed, 185 insertions(+), 20 deletions(-) > > --- u-boot.git.orig/include/net.h > +++ u-boot.git/include/net.h > @@ -200,6 +200,13 @@ typedef struct { > ushort udp_xsum; /* Checksum */ > } IP_t; > > +#define IP_OFFS 0x1FFF /* ip offset *= 8 */ > +#define IP_OFFS_SHIFT 3 /* in 8 byte steps */ > +#define IP_FLAGS 0xE000 /* first 3 bits */ > +#define IP_FLAGS_RES 0x8000 /* reserved */ > +#define IP_FLAGS_DFRAG 0x4000 /* don't fragments */ > +#define IP_FLAGS_MFRAG 0x2000 /* more fragments */ > + > Please align these better. After applying, it's: #define IP_OFFS 0x1FFF /* ip offset *= 8 */ #define IP_OFFS_SHIFT 3 /* in 8 byte steps */ #define IP_FLAGS 0xE000 /* first 3 bits */ #define IP_FLAGS_RES 0x8000 /* reserved */ #define IP_FLAGS_DFRAG 0x4000 /* don't fragments */ #define IP_FLAGS_MFRAG 0x2000 /* more fragments */ > #define IP_HDR_SIZE_NO_UDP (sizeof (IP_t) - 8) > #define IP_HDR_SIZE (sizeof (IP_t)) > > @@ -282,6 +289,16 @@ typedef struct icmphdr { > #define PKTSIZE_ALIGN 1536 > /*#define PKTSIZE 608*/ > > + /* > + * IP/UDP Fragmentation support > + * See: http://en.wikipedia.org/wiki/IPv4#Fragmentation_and_reassembly > + * MAX possible UDP packet size is 64 KiB, if there is memory available. > + */ > +#define NET_ETH_MTU 1500 > +#define NET_FRAG_BUF_SIZE (16 * 1024) /* MAX is 64 KiB */ > +#define NET_UDP_FRAG_SIZE (NET_ETH_MTU - IP_HDR_SIZE_NO_UDP) /* 1480 */ > +#define NET_FRAG_BUF_USED (NET_FRAG_BUF_SIZE / NET_UDP_FRAG_SIZE + 1) > + > /* > * Maximum receive ring size; that is, the number of packets > * we can buffer before overflow happens. Basically, this just > --- u-boot.git.orig/net/net.c > +++ u-boot.git/net/net.c > @@ -192,6 +192,15 @@ volatile uchar PktBuf[(PKTBUFSRX+1) * PK > > volatile uchar *NetRxPackets[PKTBUFSRX]; /* Receive packets > */ > > +/* Packet fragmentation support */ > +static uint16_t ip_id = 0; /* sequence number */ > +static uint16_t udp_len = 0; > +static uint16_t udp_src = 0; > +static uint16_t udp_dst = 0; > +static int max_idx = 0; > +static uchar NetFragBuf[NET_FRAG_BUF_SIZE]; > +static char NetFragBufUsed[NET_FRAG_BUF_USED] = { 0, }; > + > static rxhand_f *packetHandler; /* Current RX packet handler > */ > static thand_f *timeHandler; /* Current timeout handler > */ > static ulong timeStart; /* Time base value > */ > @@ -288,6 +297,13 @@ NetLoop(proto_t protocol) > { > bd_t *bd = gd->bd; > > + /* Packet fragmentation support */ > + ip_id = udp_len = udp_src = udp_dst = max_idx = 0; > + memset(NetFragBuf, 0xFF, sizeof(NetFragBuf)); > + memset(NetFragBufUsed, 0, sizeof(NetFragBufUsed)); > + printf("NetFragBuf @ %08x max tftp_block_size=%d udp_frag_size=%d\n", > + NetFragBuf, TFTP_BLOCK_SIZE_MAX, NET_UDP_FRAG_SIZE); > + > #ifdef CONFIG_NET_MULTI > NetRestarted = 0; > NetDevExists = 0; > @@ -1150,6 +1166,39 @@ static void CDPStart(void) > } > #endif > > +#ifdef CONFIG_UDP_CHECKSUM > +/* > + * @sumptr: Points to UDP data > + * @sumlen: Size of UDP data > + * @xsum: UDP checksum across IP source, destination address, protocol and > size > + * > + * Returns 0 when checksum is correct and 1 if it is not > Can you return -1 on failure? Not a big deal, just more conventional. > + */ > +static int udp_checksum(ushort *sumptr, ushort sumlen, ulong xsum) > +{ > + while (sumlen > 1) { > + ushort sumdata; > + > + sumdata = *sumptr++; > + xsum += ntohs(sumdata); > + sumlen -= 2; > + } > + if (sumlen > 0) { > + ushort sumdata; > + > + sumdata = *(unsigned char *) sumptr; > + sumdata = (sumdata << 8) & 0xff00; > + xsum += sumdata; > + } > + while ((xsum >> 16) != 0) { > + xsum = (xsum & 0x0000ffff) + ((xsum >> 16) & 0x0000ffff); > + } > + if ((xsum != 0x00000000) && (xsum != 0x0000ffff)) > + return 1; > + > + return 0; > +} > +#endif /* CONFIG_UDP_CHECKSUM */ > > void > NetReceive(volatile uchar * inpkt, int len) > @@ -1164,6 +1213,7 @@ NetReceive(volatile uchar * inpkt, int l > int iscdp; > #endif > ushort cti = 0, vlanid = VLAN_NONE, myvlanid, mynvlanid; > + uint32_t off; /* ip_off for fragmentation */ > Can you pick a better variable name than 'off'? 'offset' maybe? > > #ifdef ET_DEBUG > printf("packet received\n"); > @@ -1404,9 +1454,11 @@ NetReceive(volatile uchar * inpkt, int l > if ((ip->ip_hl_v & 0xf0) != 0x40) { > return; > } > +#if 0 /* Obsolete after adding the fragmentation support */ > if (ip->ip_off & htons(0x1fff)) { /* Can't deal w/ fragments */ > return; > } > +#endif > Please delete this block if it's now dead code. > /* can't deal with headers > 20 bytes */ > if ((ip->ip_hl_v & 0x0f) > 0x05) { > return; > @@ -1422,6 +1474,88 @@ NetReceive(volatile uchar * inpkt, int l > #endif > return; > } > + > + /* > + * Fragmentation support. We need to check the ip_id > + * and if all fragments were received correctly. > + */ > + off = (ntohs(ip->ip_off) & IP_OFFS) << IP_OFFS_SHIFT; > + if ((off != 0) || (ip->ip_off & htons(IP_FLAGS_MFRAG))) { > + int size, idx, complete; > + char *start; > + > + /* New fragmented packet arrived, clear data. */ > + if (ntohs(ip->ip_id) != ip_id) { > + ip_id = ntohs(ip->ip_id); > + memset(NetFragBufUsed, 0, > sizeof(NetFragBufUsed)); > + udp_len = udp_src = udp_dst = max_idx = 0; > + } > + > + idx = off / NET_UDP_FRAG_SIZE; > + > + /* Packet does not fit into IP/UDP fragmentation buf */ > + if (idx >= NET_FRAG_BUF_USED) { > + return; > + } > + > + NetFragBufUsed[idx] = 1; > + > + /* Copy the UDP hdr with the data for 1st > + fragment, else copy just payload */ > + if (off == 0) { > + udp_len = ntohs(ip->udp_len); > + udp_src = ntohs(ip->udp_src); > + udp_dst = ntohs(ip->udp_dst); > + } > + size = ntohs(ip->ip_len) - IP_HDR_SIZE_NO_UDP; > + start = (char *)ip + IP_HDR_SIZE_NO_UDP; > + memcpy(NetFragBuf + off, start, size); > + > + /* > + * When last fragement has been received we > s/fragement/fragment/ > + * know the number of fragments we expect. If > + * all have arrived we process the packet. > + */ > + if (((off != 0) && !(ip->ip_off & > htons(IP_FLAGS_MFRAG)))) > + max_idx = idx; > + > + if (max_idx == 0) > + return; > + > + complete = 1; > + for (idx = 0; idx < max_idx; idx++) { > + if (NetFragBufUsed[idx] == 0) { > + complete = 0; > + break; > + } > + } > + if (!complete) > + return; > +#ifdef CONFIG_UDP_CHECKSUM > + if (ip->udp_xsum != 0) { > + ulong xsum = ip->ip_p; > + uint16_t *sumptr; > + > + xsum += udp_len; > + xsum += (ntohl(ip->ip_src) >> 16) & 0xffff; > + xsum += (ntohl(ip->ip_src) >> 0) & 0xffff; > + xsum += (ntohl(ip->ip_dst) >> 16) & 0xffff; > + xsum += (ntohl(ip->ip_dst) >> 0) & 0xffff; > + sumptr = (ushort *)NetFragBuf; > + > + if (udp_checksum(sumptr, udp_len, xsum)) { > + putc('U'); > + return; > + } > + } > +#endif /* CONFIG_UDP_CHECKSUM */ > + (*packetHandler)(NetFragBuf + 8, > + udp_dst, > + udp_src, > + udp_len - 8); > Can some of these arguments share lines? > + return; > + } > + > /* > * watch for ICMP host redirects > * > @@ -1502,26 +1636,8 @@ NetReceive(volatile uchar * inpkt, int l > sumlen = ntohs(ip->udp_len); > sumptr = (ushort *) &(ip->udp_src); > > - while (sumlen > 1) { > - ushort sumdata; > - > - sumdata = *sumptr++; > - xsum += ntohs(sumdata); > - sumlen -= 2; > - } > - if (sumlen > 0) { > - ushort sumdata; > - > - sumdata = *(unsigned char *) sumptr; > - sumdata = (sumdata << 8) & 0xff00; > - xsum += sumdata; > - } > - while ((xsum >> 16) != 0) { > - xsum = (xsum & 0x0000ffff) + ((xsum >> 16) & > 0x0000ffff); > - } > - if ((xsum != 0x00000000) && (xsum != 0x0000ffff)) { > - printf(" UDP wrong checksum %08lx %08x\n", > - xsum, ntohs(ip->udp_xsum)); > + if (udp_checksum(sumptr, sumlen, xsum)) { > + putc('U'); > return; > } > } > --- u-boot.git.orig/net/tftp.c > +++ u-boot.git/net/tftp.c > @@ -456,6 +456,7 @@ TftpTimeout (void) > void > TftpStart (void) > { > + char *s, *err; > #ifdef CONFIG_TFTP_PORT > char *ep; /* Environment pointer */ > #endif > @@ -518,6 +519,27 @@ TftpStart (void) > > puts ("Loading: *\b"); > > + /* Get alternate tftp_block_size */ > + if ((s = getenv("tftp_block_size")) != NULL) { > Kind of a long environment variable name. Maybe "tftp_bs"? > + err = NULL; > + > + TftpBlkSizeOption = simple_strtoul(s, &err, 10); > + if (*err) { > + printf("ERR: \"tftp_block_size\" is not a number\n"); > + TftpBlkSizeOption = TFTP_BLOCK_SIZE; > + } > + /* > + * Reject values which require extensive handling. > + * block size of 1428 octets (Ethernet MTU, less > + * the TFTP, UDP and IP header lengths). > + */ > + if (TftpBlkSizeOption > TFTP_BLOCK_SIZE_MAX) { > + printf("ERR: tftp_block_sizes larger than %d not " > + "supported\n", TFTP_BLOCK_SIZE_MAX); > + TftpBlkSizeOption = TFTP_BLOCK_SIZE; > + } > + } > + > NetSetTimeout (TIMEOUT * CFG_HZ, TftpTimeout); > NetSetHandler (TftpHandler); > > --- u-boot.git.orig/net/tftp.h > +++ u-boot.git/net/tftp.h > @@ -8,11 +8,21 @@ > #ifndef __TFTP_H__ > #define __TFTP_H__ > > +#include <net.h> > + > /**********************************************************************/ > /* > * Global functions and variables. > */ > > +/* > + * Maximum TFTP block size bound to max size of fragmented IP/UDP > + * packets minus TFTP and UDP/IP overhead. TFTP overhead is 2 byte > + * opcode and 2 byte block-number. > + */ > +#define TFTP_BLOCK_SIZE_MAX (NET_FRAG_BUF_SIZE - sizeof(IP_t) - 4) > + > + > /* tftp.c */ > extern void TftpStart (void); /* Begin TFTP get */ > > > regards, Ben _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot