eth_copy_and_sum() and its progeny. Part 1: Stepping into it In the current git tree a test build of ppc32 allmodconfig had suddenly grown a bunch of warnings about undefined symbol - eth_io_copy_and_sum(). A quick grep had shown that no such function is defined anywhere in include/asm-powerpc, indeed. However, a slightly longer grep had shown that it never had been there in the first place; the change that had triggered that fun consisted of removal of #include from asm-powerpc/io.h. We used to do it in 32bit case. Now we don't. So we have a function present in some, but not all asm-*/io.h. What does it do, anyway? We do have some legacy helpers in there, so it might be one of those. Looking at the instances shows quite a mess: i386, cris, ppc, x86_64: a wrapper for eth_copy_and_sum() arm: wrapper for eth_copy_and_sum() of a slightly different kind. alpha, mips, parisc: memcpy_fromio(), ignoring the last argument (whatever it might be) and having variations on the same comment. everything else: nada. Wrappers for eth_copy_and_sum() and comments around them are suggestive - it looks like we go that way if iomem is accessible somewhere by normal memory access and in that case we just do to a chunk of iomem whatever eth_copy_and_sum() would do. The other group is also interesting - it's clearly derived from the same ancestor and shares the same comment: /* * XXX - We don't have csum_partial_copy_fromio() yet, so we cheat here and * just copy it. The net code will then do the checksum later. Presently * only used by some shared memory 8390 Ethernet cards anyway. */ OK, so it looks like we have "copy from iomem and optionally find a checksum and do something with it; not doing it at all is not fatal". So what do we do to that checksum if we do calculate it? Time to take a look at eth_copy_and_sum(): static inline void eth_copy_and_sum (struct sk_buff *dest, unsigned char *src, i nt len, int base) { memcpy (dest->data, src, len); } ... whiskey tango foxtrot, over. Maybe it's a stub for some configs and the real variant lives somewhere else? Nope, that sucker is unconditional and no other instance exists anywhere in the tree. In other words, that "optionally" is "never". Just what the hell is going on there? Part 2: Where's that shovel? Out of these two, eth_copy_and_sum() is slightly older - 1.3.7 vs 1.3.31 resp. Moreover, the quick look shows that eth_io_copy_and_sum() had always been either memcpy_fromio() or a wrapper for eth_copy_and_sum(). So the first target is eth_copy_and_sum() history. At its first appearance (1.3.7) it lived in net/ethernet/eth.c and back then the name made sense, indeed. Originally it was "if payload is not an IP, memcpy() to skb->data, otherwise copy and calculate checksum of embedded IP packet as we go; store checksum in skb->csum and set skb->ip_summed". As the matter of fact, the first sighting of ->ip_summed is 1.3.7; we are at the very beginning of the machinery for offloading checksum calculation to drivers. In 1.3.65 we see the first serious change: checksum work is made conditional on !CONFIG_IP_ROUTER. In 2.1.23 the simple case is taken to inlined version in etherdevice.h In 2.3.41-pre2 everything except the simple case is taken out and shot, unconditionally. In 2.4.0-test7-pre7 the last vestiges of that sucker are gone (not even #if 0). At the same time CONFIG_IP_ROUTER is gone too and we reach the recent situation. More than 6 years ago. Now, eth_copy_and_sum() copies from normal memory. Of course, sometimes we want to copy from iomem. So a new helper (eth_io_copy_and_sum()) had been introduced in 1.3.31. From the very beginning "just memcpy_fromio() and let the upper layers checksum later" had been an acceptable variant. Not many drivers used it, actually - especially back when it did some checksum work. Note that even if architecture allows access to iomem as to normal memory (e.g. i386), device itself might impose additional restrictions (e.g. "aligned 32bit accesses only"). And that was a killer, since we had no way to be sure that csum_partial_copy() would honour those restrictions. These days we have it only in 3c503, as3200, e2100, es3210, wd and smc variants. The history is also messy. Originally it was done for i386 and alpha, essentially in the current forms, then it kept propagating in very odd ways long past the point when all variants had been equivalent to memcpy_fromio(). The latest such event is in 2.6.10-bk3 (for ppc). Part 4: now what? * eth_copy_and_sum() has misguiding name and signature. In fact it's not obvious that we want to keep it - open-coded memcpy() would be both shorter and less confusing. * eth_io_copy_and_sum() must die; all users can and should switch to memcpy_fromio(), especially since most of them have it used on a codepath nearby (when packet is wrapped around the end of ring buffer). * that should've been done a _long_ time ago, right when eth_copy_and_sum() had become memcpy(). * architecture-dependent stuff should be consistent and regulary checked for actually being architecture-dependent...