Skip to content

Commit

Permalink
VME: Stop using memcpy_[to|from]io() due to unwanted behaviour
Browse files Browse the repository at this point in the history
The ca91cx42 and tsi148 VME bridges use the width of reads and writes on the
PCI bus in part to control the width of the cycles on the VME bus. It is
important that we can control the width of cycles on the VME bus as some VME
hardware requires cycles of a specific width. The memcpy_toio() and
memcpy_fromio() functions do not provide sufficient control, so instead loop
using ioread functions.

Reported-by: Michael Kenney <mfkenney@gmail.com>
Signed-off-by: Martyn Welch <martyn.welch@ge.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
mwelchuk authored and gregkh committed Feb 15, 2014
1 parent f33b215 commit a2a720e
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 24 deletions.
29 changes: 14 additions & 15 deletions drivers/vme/bridges/vme_ca91cx42.c
Original file line number Diff line number Diff line change
Expand Up @@ -869,14 +869,13 @@ static ssize_t ca91cx42_master_read(struct vme_master_resource *image,

spin_lock(&image->lock);

/* The following code handles VME address alignment problem
* in order to assure the maximal data width cycle.
* We cannot use memcpy_xxx directly here because it
* may cut data transfer in 8-bits cycles, thus making
* D16 cycle impossible.
* From the other hand, the bridge itself assures that
* maximal configured data cycle is used and splits it
* automatically for non-aligned addresses.
/* 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);
Expand All @@ -896,9 +895,9 @@ static ssize_t ca91cx42_master_read(struct vme_master_resource *image,
}

count32 = (count - done) & ~0x3;
if (count32 > 0) {
memcpy_fromio(buf + done, addr + done, (unsigned int)count);
done += count32;
while (done < count32) {
*(u32 *)(buf + done) = ioread32(addr + done);
done += 4;
}

if ((count - done) & 0x2) {
Expand Down Expand Up @@ -930,7 +929,7 @@ static ssize_t ca91cx42_master_write(struct vme_master_resource *image,
spin_lock(&image->lock);

/* Here we apply for the same strategy we do in master_read
* function in order to assure D16 cycle when required.
* function in order to assure the correct cycles.
*/
if ((uintptr_t)addr & 0x1) {
iowrite8(*(u8 *)buf, addr);
Expand All @@ -950,9 +949,9 @@ static ssize_t ca91cx42_master_write(struct vme_master_resource *image,
}

count32 = (count - done) & ~0x3;
if (count32 > 0) {
memcpy_toio(addr + done, buf + done, count32);
done += count32;
while (done < count32) {
iowrite32(*(u32 *)(buf + done), addr + done);
done += 4;
}

if ((count - done) & 0x2) {
Expand Down
18 changes: 9 additions & 9 deletions drivers/vme/bridges/vme_tsi148.c
Original file line number Diff line number Diff line change
Expand Up @@ -1276,8 +1276,8 @@ static ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf,
spin_lock(&image->lock);

/* The following code handles VME address alignment. We cannot use
* memcpy_xxx directly here because it may cut small data transfers in
* to 8-bit cycles, thus making D16 cycle impossible.
* 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
Expand All @@ -1301,9 +1301,9 @@ static ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf,
}

count32 = (count - done) & ~0x3;
if (count32 > 0) {
memcpy_fromio(buf + done, addr + done, count32);
done += count32;
while (done < count32) {
*(u32 *)(buf + done) = ioread32(addr + done);
done += 4;
}

if ((count - done) & 0x2) {
Expand Down Expand Up @@ -1363,7 +1363,7 @@ static ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf,
spin_lock(&image->lock);

/* Here we apply for the same strategy we do in master_read
* function in order to assure D16 cycle when required.
* function in order to assure the correct cycles.
*/
if ((uintptr_t)addr & 0x1) {
iowrite8(*(u8 *)buf, addr);
Expand All @@ -1383,9 +1383,9 @@ static ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf,
}

count32 = (count - done) & ~0x3;
if (count32 > 0) {
memcpy_toio(addr + done, buf + done, count32);
done += count32;
while (done < count32) {
iowrite32(*(u32 *)(buf + done), addr + done);
done += 4;
}

if ((count - done) & 0x2) {
Expand Down

0 comments on commit a2a720e

Please sign in to comment.