summaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorDong Jia Shi <bjsdjshi@linux.vnet.ibm.com>2017-03-17 04:17:42 +0100
committerCornelia Huck <cornelia.huck@de.ibm.com>2017-03-31 12:55:12 +0200
commitd686f21ace295f224eb2320bf1a8a20835de8494 (patch)
treed61b4653106e6a39dc1e6c90b6f507ac73a5390b /drivers/s390
parent25627ba3899e71fc205e172b676b207ee0ac1e6a (diff)
downloadlinux-d686f21ace295f224eb2320bf1a8a20835de8494.tar.gz
linux-d686f21ace295f224eb2320bf1a8a20835de8494.tar.bz2
linux-d686f21ace295f224eb2320bf1a8a20835de8494.zip
vfio: ccw: introduce support for ccw0
Although Linux does not use format-0 channel command words (CCW0) these are a non-optional part of the platform spec, and for the sake of platform compliance, and possibly some non-Linux guests, we have to support CCW0. Making the kernel execute a format 0 channel program is too much hassle because we would need to allocate and use memory which can be addressed by 24 bit physical addresses (because of CCW0.cda). So we implement CCW0 support by translating the channel program into an equivalent CCW1 program instead. Based upon an orginal patch by Kai Yue Wang. Signed-off-by: Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com> Message-Id: <20170317031743.40128-16-bjsdjshi@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/cio/vfio_ccw_cp.c32
1 files changed, 29 insertions, 3 deletions
diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c
index 16bbb54ee532..ba6ac83a6c25 100644
--- a/drivers/s390/cio/vfio_ccw_cp.c
+++ b/drivers/s390/cio/vfio_ccw_cp.c
@@ -247,7 +247,34 @@ static long copy_ccw_from_iova(struct channel_program *cp,
struct ccw1 *to, u64 iova,
unsigned long len)
{
- return copy_from_iova(cp->mdev, to, iova, len * sizeof(struct ccw1));
+ struct ccw0 ccw0;
+ struct ccw1 *pccw1;
+ int ret;
+ int i;
+
+ ret = copy_from_iova(cp->mdev, to, iova, len * sizeof(struct ccw1));
+ if (ret)
+ return ret;
+
+ if (!cp->orb.cmd.fmt) {
+ pccw1 = to;
+ for (i = 0; i < len; i++) {
+ ccw0 = *(struct ccw0 *)pccw1;
+ if ((pccw1->cmd_code & 0x0f) == CCW_CMD_TIC) {
+ pccw1->cmd_code = CCW_CMD_TIC;
+ pccw1->flags = 0;
+ pccw1->count = 0;
+ } else {
+ pccw1->cmd_code = ccw0.cmd_code;
+ pccw1->flags = ccw0.flags;
+ pccw1->count = ccw0.count;
+ }
+ pccw1->cda = ccw0.cda;
+ pccw1++;
+ }
+ }
+
+ return ret;
}
/*
@@ -616,9 +643,8 @@ int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb)
* Only support prefetch enable mode now.
* Only support 64bit addressing idal.
* Only support 4k IDAW.
- * Only support ccw1.
*/
- if (!orb->cmd.pfch || !orb->cmd.c64 || orb->cmd.i2k || !orb->cmd.fmt)
+ if (!orb->cmd.pfch || !orb->cmd.c64 || orb->cmd.i2k)
return -EOPNOTSUPP;
INIT_LIST_HEAD(&cp->ccwchain_list);