summaryrefslogtreecommitdiff
path: root/drivers/s390/cio
diff options
context:
space:
mode:
authorEric Farman <farman@linux.ibm.com>2022-10-31 21:48:29 +0300
committerHeiko Carstens <hca@linux.ibm.com>2023-01-09 16:34:09 +0300
commit1b676fe3d9d3f262bc26bb18dc1b1ac66c83c2a0 (patch)
treeff5c77c813087140f92d4e27a11ac608e7659084 /drivers/s390/cio
parent61f3a16b9d5cd9361a317ee7870083c1bc171188 (diff)
downloadlinux-1b676fe3d9d3f262bc26bb18dc1b1ac66c83c2a0.tar.xz
vfio/ccw: handle a guest Format-1 IDAL
There are two scenarios that need to be addressed here. First, an ORB that does NOT have the Format-2 IDAL bit set could have both a direct-addressed CCW and an indirect-data-address CCW chained together. This means that the IDA CCW will contain a Format-1 IDAL, and can be easily converted to a 2K Format-2 IDAL. But it also means that the direct-addressed CCW needs to be converted to the same 2K Format-2 IDAL for consistency with the ORB settings. Secondly, a Format-1 IDAL is comprised of 31-bit addresses. Thus, we need to cast this IDAL to a pointer of ints while populating the list of addresses that are sent to vfio. Since the result of both of these is the use of the 2K IDAL variants, and the output of vfio-ccw is always a Format-2 IDAL (in order to use 64-bit addresses), make sure that the correct control bit gets set in the ORB when these scenarios occur. 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/cio')
-rw-r--r--drivers/s390/cio/vfio_ccw_cp.c19
1 files changed, 16 insertions, 3 deletions
diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c
index 525277750041..a7415d440a81 100644
--- a/drivers/s390/cio/vfio_ccw_cp.c
+++ b/drivers/s390/cio/vfio_ccw_cp.c
@@ -222,6 +222,8 @@ static void convert_ccw0_to_ccw1(struct ccw1 *source, unsigned long len)
}
}
+#define idal_is_2k(_cp) (!(_cp)->orb.cmd.c64 || (_cp)->orb.cmd.i2k)
+
/*
* Helpers to operate ccwchain.
*/
@@ -504,8 +506,9 @@ static unsigned long *get_guest_idal(struct ccw1 *ccw,
struct vfio_device *vdev =
&container_of(cp, struct vfio_ccw_private, cp)->vdev;
unsigned long *idaws;
+ unsigned int *idaws_f1;
int idal_len = idaw_nr * sizeof(*idaws);
- int idaw_size = PAGE_SIZE;
+ int idaw_size = idal_is_2k(cp) ? PAGE_SIZE / 2 : PAGE_SIZE;
int idaw_mask = ~(idaw_size - 1);
int i, ret;
@@ -527,8 +530,10 @@ static unsigned long *get_guest_idal(struct ccw1 *ccw,
for (i = 1; i < idaw_nr; i++)
idaws[i] = (idaws[i - 1] + idaw_size) & idaw_mask;
} else {
- kfree(idaws);
- return ERR_PTR(-EOPNOTSUPP);
+ idaws_f1 = (unsigned int *)idaws;
+ idaws_f1[0] = ccw->cda;
+ for (i = 1; i < idaw_nr; i++)
+ idaws_f1[i] = (idaws_f1[i - 1] + idaw_size) & idaw_mask;
}
}
@@ -598,6 +603,7 @@ static int ccwchain_fetch_ccw(struct ccw1 *ccw,
struct vfio_device *vdev =
&container_of(cp, struct vfio_ccw_private, cp)->vdev;
unsigned long *idaws;
+ unsigned int *idaws_f1;
int ret;
int idaw_nr;
int i;
@@ -628,9 +634,12 @@ static int ccwchain_fetch_ccw(struct ccw1 *ccw,
* Copy guest IDAWs into page_array, in case the memory they
* occupy is not contiguous.
*/
+ idaws_f1 = (unsigned int *)idaws;
for (i = 0; i < idaw_nr; i++) {
if (cp->orb.cmd.c64)
pa->pa_iova[i] = idaws[i];
+ else
+ pa->pa_iova[i] = idaws_f1[i];
}
if (ccw_does_data_transfer(ccw)) {
@@ -851,7 +860,11 @@ union orb *cp_get_orb(struct channel_program *cp, struct subchannel *sch)
/*
* Everything built by vfio-ccw is a Format-2 IDAL.
+ * If the input was a Format-1 IDAL, indicate that
+ * 2K Format-2 IDAWs were created here.
*/
+ if (!orb->cmd.c64)
+ orb->cmd.i2k = 1;
orb->cmd.c64 = 1;
if (orb->cmd.lpm == 0)