in bridges/vme_ca91cx42.c [849:906]
static ssize_t ca91cx42_master_read(struct vme_master_resource *image,
void *buf, size_t count, loff_t offset)
{
ssize_t retval;
void __iomem *addr = image->kern_base + offset;
unsigned int done = 0;
unsigned int count32;
if (count == 0)
return 0;
spin_lock(&image->lock);
/* The following code handles VME address alignment. We cannot use
* memcpy_xxx here because it may cut data transfers in to 8-bit
* cycles when D16 or D32 cycles are required on the VME bus.
* On the other hand, the bridge itself assures that the maximum data
* cycle configured for the transfer is used and splits it
* automatically for non-aligned addresses, so we don't want the
* overhead of needlessly forcing small transfers for the entire cycle.
*/
if ((uintptr_t)addr & 0x1) {
*(u8 *)buf = ioread8(addr);
done += 1;
if (done == count)
goto out;
}
if ((uintptr_t)(addr + done) & 0x2) {
if ((count - done) < 2) {
*(u8 *)(buf + done) = ioread8(addr + done);
done += 1;
goto out;
} else {
*(u16 *)(buf + done) = ioread16(addr + done);
done += 2;
}
}
count32 = (count - done) & ~0x3;
while (done < count32) {
*(u32 *)(buf + done) = ioread32(addr + done);
done += 4;
}
if ((count - done) & 0x2) {
*(u16 *)(buf + done) = ioread16(addr + done);
done += 2;
}
if ((count - done) & 0x1) {
*(u8 *)(buf + done) = ioread8(addr + done);
done += 1;
}
out:
retval = count;
spin_unlock(&image->lock);
return retval;
}