diff options
Diffstat (limited to 'drivers/vme/bridges/vme_tsi148.c')
-rw-r--r-- | drivers/vme/bridges/vme_tsi148.c | 85 |
1 files changed, 83 insertions, 2 deletions
diff --git a/drivers/vme/bridges/vme_tsi148.c b/drivers/vme/bridges/vme_tsi148.c index f6385f7a66d9..880d9242e349 100644 --- a/drivers/vme/bridges/vme_tsi148.c +++ b/drivers/vme/bridges/vme_tsi148.c | |||
@@ -1263,12 +1263,55 @@ static ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf, | |||
1263 | u32 aspace, cycle, dwidth; | 1263 | u32 aspace, cycle, dwidth; |
1264 | struct vme_bus_error *vme_err = NULL; | 1264 | struct vme_bus_error *vme_err = NULL; |
1265 | struct vme_bridge *tsi148_bridge; | 1265 | struct vme_bridge *tsi148_bridge; |
1266 | void *addr = image->kern_base + offset; | ||
1267 | unsigned int done = 0; | ||
1268 | unsigned int count32; | ||
1266 | 1269 | ||
1267 | tsi148_bridge = image->parent; | 1270 | tsi148_bridge = image->parent; |
1268 | 1271 | ||
1269 | spin_lock(&image->lock); | 1272 | spin_lock(&image->lock); |
1270 | 1273 | ||
1271 | memcpy_fromio(buf, image->kern_base + offset, (unsigned int)count); | 1274 | /* The following code handles VME address alignment. We cannot use |
1275 | * memcpy_xxx directly here because it may cut small data transfers in | ||
1276 | * to 8-bit cycles, thus making D16 cycle impossible. | ||
1277 | * On the other hand, the bridge itself assures that the maximum data | ||
1278 | * cycle configured for the transfer is used and splits it | ||
1279 | * automatically for non-aligned addresses, so we don't want the | ||
1280 | * overhead of needlessly forcing small transfers for the entire cycle. | ||
1281 | */ | ||
1282 | if ((uintptr_t)addr & 0x1) { | ||
1283 | *(u8 *)buf = ioread8(addr); | ||
1284 | done += 1; | ||
1285 | if (done == count) | ||
1286 | goto out; | ||
1287 | } | ||
1288 | if ((uintptr_t)addr & 0x2) { | ||
1289 | if ((count - done) < 2) { | ||
1290 | *(u8 *)(buf + done) = ioread8(addr + done); | ||
1291 | done += 1; | ||
1292 | goto out; | ||
1293 | } else { | ||
1294 | *(u16 *)(buf + done) = ioread16(addr + done); | ||
1295 | done += 2; | ||
1296 | } | ||
1297 | } | ||
1298 | |||
1299 | count32 = (count - done) & ~0x3; | ||
1300 | if (count32 > 0) { | ||
1301 | memcpy_fromio(buf + done, addr + done, count32); | ||
1302 | done += count32; | ||
1303 | } | ||
1304 | |||
1305 | if ((count - done) & 0x2) { | ||
1306 | *(u16 *)(buf + done) = ioread16(addr + done); | ||
1307 | done += 2; | ||
1308 | } | ||
1309 | if ((count - done) & 0x1) { | ||
1310 | *(u8 *)(buf + done) = ioread8(addr + done); | ||
1311 | done += 1; | ||
1312 | } | ||
1313 | |||
1314 | out: | ||
1272 | retval = count; | 1315 | retval = count; |
1273 | 1316 | ||
1274 | if (!err_chk) | 1317 | if (!err_chk) |
@@ -1301,6 +1344,9 @@ static ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf, | |||
1301 | int retval = 0, enabled; | 1344 | int retval = 0, enabled; |
1302 | unsigned long long vme_base, size; | 1345 | unsigned long long vme_base, size; |
1303 | u32 aspace, cycle, dwidth; | 1346 | u32 aspace, cycle, dwidth; |
1347 | void *addr = image->kern_base + offset; | ||
1348 | unsigned int done = 0; | ||
1349 | unsigned int count32; | ||
1304 | 1350 | ||
1305 | struct vme_bus_error *vme_err = NULL; | 1351 | struct vme_bus_error *vme_err = NULL; |
1306 | struct vme_bridge *tsi148_bridge; | 1352 | struct vme_bridge *tsi148_bridge; |
@@ -1312,7 +1358,42 @@ static ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf, | |||
1312 | 1358 | ||
1313 | spin_lock(&image->lock); | 1359 | spin_lock(&image->lock); |
1314 | 1360 | ||
1315 | memcpy_toio(image->kern_base + offset, buf, (unsigned int)count); | 1361 | /* Here we apply for the same strategy we do in master_read |
1362 | * function in order to assure D16 cycle when required. | ||
1363 | */ | ||
1364 | if ((uintptr_t)addr & 0x1) { | ||
1365 | iowrite8(*(u8 *)buf, addr); | ||
1366 | done += 1; | ||
1367 | if (done == count) | ||
1368 | goto out; | ||
1369 | } | ||
1370 | if ((uintptr_t)addr & 0x2) { | ||
1371 | if ((count - done) < 2) { | ||
1372 | iowrite8(*(u8 *)(buf + done), addr + done); | ||
1373 | done += 1; | ||
1374 | goto out; | ||
1375 | } else { | ||
1376 | iowrite16(*(u16 *)(buf + done), addr + done); | ||
1377 | done += 2; | ||
1378 | } | ||
1379 | } | ||
1380 | |||
1381 | count32 = (count - done) & ~0x3; | ||
1382 | if (count32 > 0) { | ||
1383 | memcpy_toio(addr + done, buf + done, count32); | ||
1384 | done += count32; | ||
1385 | } | ||
1386 | |||
1387 | if ((count - done) & 0x2) { | ||
1388 | iowrite16(*(u16 *)(buf + done), addr + done); | ||
1389 | done += 2; | ||
1390 | } | ||
1391 | if ((count - done) & 0x1) { | ||
1392 | iowrite8(*(u8 *)(buf + done), addr + done); | ||
1393 | done += 1; | ||
1394 | } | ||
1395 | |||
1396 | out: | ||
1316 | retval = count; | 1397 | retval = count; |
1317 | 1398 | ||
1318 | /* | 1399 | /* |