summaryrefslogtreecommitdiff
path: root/drivers/s390
diff options
context:
space:
mode:
authorEric Farman <farman@linux.ibm.com>2022-10-20 19:00:14 +0200
committerHeiko Carstens <hca@linux.ibm.com>2023-01-09 14:34:08 +0100
commit667e5dbabf2bb790640525cff7d563cf88eb3e61 (patch)
treeb76ac80096f6a6e6443a0cf8caad010f9fa8457d /drivers/s390
parentb21f9cb1124e9fee33dd3c07108aabde060b6ef8 (diff)
vfio/ccw: read only one Format-1 IDAW
The intention is to read the first IDAW to determine the starting location of an I/O operation, knowing that the second and any/all subsequent IDAWs will be aligned per architecture. But, this read receives 64-bits of data, which is the size of a Format-2 IDAW. In the event that Format-1 IDAWs are presented, adjust the size of the read to 32-bits. The data will end up occupying the upper word of the target iova variable, so shift it down to the lower word for use as an address. (By definition, this IDAW format uses a 31-bit address, so the "sign" bit will always be off and there is no concern about sign extension.) Signed-off-by: Eric Farman <farman@linux.ibm.com> Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/cio/vfio_ccw_cp.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c
index 9d74e0b74da7..fbb46bec3174 100644
--- a/drivers/s390/cio/vfio_ccw_cp.c
+++ b/drivers/s390/cio/vfio_ccw_cp.c
@@ -509,6 +509,7 @@ static int ccw_count_idaws(struct ccw1 *ccw,
struct vfio_device *vdev =
&container_of(cp, struct vfio_ccw_private, cp)->vdev;
u64 iova;
+ int size = cp->orb.cmd.c64 ? sizeof(u64) : sizeof(u32);
int ret;
int bytes = 1;
@@ -516,11 +517,18 @@ static int ccw_count_idaws(struct ccw1 *ccw,
bytes = ccw->count;
if (ccw_is_idal(ccw)) {
- /* Read first IDAW to see if it's 4K-aligned or not. */
- /* All subsequent IDAws will be 4K-aligned. */
- ret = vfio_dma_rw(vdev, ccw->cda, &iova, sizeof(iova), false);
+ /* Read first IDAW to check its starting address. */
+ /* All subsequent IDAWs will be 2K- or 4K-aligned. */
+ ret = vfio_dma_rw(vdev, ccw->cda, &iova, size, false);
if (ret)
return ret;
+
+ /*
+ * Format-1 IDAWs only occupy the first 32 bits,
+ * and bit 0 is always off.
+ */
+ if (!cp->orb.cmd.c64)
+ iova = iova >> 32;
} else {
iova = ccw->cda;
}