[parisc-linux] memcpy_fromio() seems partially broken [with patch]

Helge Deller deller@gmx.de
Fri, 8 Jun 2001 23:37:31 +0200


Hi,

while I was playing with a few network-cards in the c3k I found a strange 
behaviour when copying unaligned data with memcpy_fromio() off the PCI bus.

Background: 
I wanted to copy data off the network-card (HP J2585A) from an 4-byte aligned 
PCI address to an 2-byte aligned (b/c of skb_reserve(skb, 2)) memory-address 
with memcpy_fromio().
The current code in CVS for memcpy_fromio() copied byteswapped and/or 
completely wrong data for all copied values, while the following 
memcpy_fromio() worked without problems:

/* Copies a block of memory from a device in an efficient manner.
 * Assumes the device can cope with 32-bit transfers.  If it can't,
 * don't use this function.
 */
void memcpy_fromio(const void *dest, unsigned long src, int count)
{
        u32 value;
        if (((unsigned long)dest & 3) != (src & 3))
                goto wordcopy;
        while (src & 3) {
                *(char *)dest = readb(src++);
                ((char *)dest)++;
                count--;
        }
        while (count > 3) {
                *(u32 *)dest = readl(src);
                dest += 4;
                src += 4;
                count -= 4;
        }
        if (!count)
                return;
 wordcopy:
        if (src & 3)
                goto bytecopy;
 wordcopy_loop:
        value = readl(src);
        *((char*)dest) = (char) (value >> 24);  dest++;
        if (--count == 0) return;
        *((char*)dest) = (char) (value >> 16);  dest++;
        if (--count == 0) return;
        *((char*)dest) = (char) (value >> 8);   dest++;
        if (--count == 0) return;
        *((char*)dest) = (char) (value);  dest++;
        if (count) goto wordcopy_loop;
        return;
 
 bytecopy:
        while (count--) {
                *(char *)dest = readb(src++);
                ((char *)dest)++;
        }
}

The previous version copied all data with readb() while this implementation 
tries to access the (pci-)bus most of the time with readl()s. 
I know, this is not the best or cleanest implementation, but I think we need 
to change memcpy_fromio() in such a manner.

What is your thought about it, or any ideas why the previous version sucked ?

Greetings,
Helge