@@ -680,6 +680,13 @@ config VFIO_CCW
To compile this driver as a module, choose M here: the
module will be called vfio_ccw.
+config VFIO_CCW_CCW0
+ def_bool n
+ prompt "Support for CCW0 translation"
+ depends on VFIO_CCW
+ help
+ Enable translation for CCW0 programs for VFIO-CCW subchannels.
+
endmenu
menu "Dump support"
@@ -19,6 +19,26 @@
#include "vfio_ccw_cp.h"
+#ifdef CONFIG_VFIO_CCW_CCW0
+/**
+ * struct ccw0 - channel command word
+ * @cmd_code: command code
+ * @cda: data address
+ * @flags: flags, like IDA addressing, etc.
+ * @reserved: will be ignored
+ * @count: byte count
+ *
+ * The format-0 ccw structure.
+ */
+struct ccw0 {
+ __u8 cmd_code;
+ __u32 cda : 24;
+ __u8 flags;
+ __u8 reserved;
+ __u16 count;
+} __packed __aligned(8);
+#endif
+
/*
* Max length for ccw chain.
* XXX: Limit to 256, need to check more?
@@ -247,12 +267,42 @@ static long copy_from_iova(struct device *mdev,
return l;
}
+#ifdef CONFIG_VFIO_CCW_CCW0
+static long copy_ccw_from_iova(struct ccwprogram *cp,
+ struct ccw1 *to, u64 iova,
+ unsigned long len)
+{
+ 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;
+ pccw1->cmd_code = ccw0.cmd_code;
+ pccw1->flags = ccw0.flags;
+ pccw1->count = ccw0.count;
+ pccw1->cda = ccw0.cda;
+ pccw1++;
+ }
+ }
+
+ return ret;
+}
+#else
static long copy_ccw_from_iova(struct ccwprogram *cp,
struct ccw1 *to, u64 iova,
unsigned long len)
{
return copy_from_iova(cp->mdev, to, iova, len * sizeof(struct ccw1));
}
+#endif
/*
* Helpers to operate ccwchain.
@@ -619,10 +669,14 @@ int cp_init(struct ccwprogram *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;
+
+#ifndef CONFIG_VFIO_CCW_CCW0
+ if (!orb->cmd.fmt)
return -EOPNOTSUPP;
+#endif
INIT_LIST_HEAD(&cp->ccwchain_list);
memcpy(&cp->orb, orb, sizeof(*orb));