Commit 5513bc8e authored by Martin Schwidefsky's avatar Martin Schwidefsky
Browse files

Merge tag 'vfio-ccw-20190425' of...

Merge tag 'vfio-ccw-20190425' of https://git.kernel.org/pub/scm/linux/kernel/git/kvms390/vfio-ccw into features

Pull vfio-ccw from Cornelia Huck with the following changes:

 - support for sending halt/clear requests to the device

 - various bug fixes
parents c9f62152 d1ffa760
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -20,5 +20,6 @@ obj-$(CONFIG_CCWGROUP) += ccwgroup.o
qdio-objs := qdio_main.o qdio_thinint.o qdio_debug.o qdio_setup.o
obj-$(CONFIG_QDIO) += qdio.o

vfio_ccw-objs += vfio_ccw_drv.o vfio_ccw_cp.o vfio_ccw_ops.o vfio_ccw_fsm.o
vfio_ccw-objs += vfio_ccw_drv.o vfio_ccw_cp.o vfio_ccw_ops.o vfio_ccw_fsm.o \
	vfio_ccw_async.o
obj-$(CONFIG_VFIO_CCW) += vfio_ccw.o
+1 −0
Original line number Diff line number Diff line
@@ -233,6 +233,7 @@ int hsch(struct subchannel_id schid)

	return ccode;
}
EXPORT_SYMBOL(hsch);

static inline int __xsch(struct subchannel_id schid)
{
+88 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Async I/O region for vfio_ccw
 *
 * Copyright Red Hat, Inc. 2019
 *
 * Author(s): Cornelia Huck <cohuck@redhat.com>
 */

#include <linux/vfio.h>
#include <linux/mdev.h>

#include "vfio_ccw_private.h"

static ssize_t vfio_ccw_async_region_read(struct vfio_ccw_private *private,
					  char __user *buf, size_t count,
					  loff_t *ppos)
{
	unsigned int i = VFIO_CCW_OFFSET_TO_INDEX(*ppos) - VFIO_CCW_NUM_REGIONS;
	loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK;
	struct ccw_cmd_region *region;
	int ret;

	if (pos + count > sizeof(*region))
		return -EINVAL;

	mutex_lock(&private->io_mutex);
	region = private->region[i].data;
	if (copy_to_user(buf, (void *)region + pos, count))
		ret = -EFAULT;
	else
		ret = count;
	mutex_unlock(&private->io_mutex);
	return ret;
}

static ssize_t vfio_ccw_async_region_write(struct vfio_ccw_private *private,
					   const char __user *buf, size_t count,
					   loff_t *ppos)
{
	unsigned int i = VFIO_CCW_OFFSET_TO_INDEX(*ppos) - VFIO_CCW_NUM_REGIONS;
	loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK;
	struct ccw_cmd_region *region;
	int ret;

	if (pos + count > sizeof(*region))
		return -EINVAL;

	if (!mutex_trylock(&private->io_mutex))
		return -EAGAIN;

	region = private->region[i].data;
	if (copy_from_user((void *)region + pos, buf, count)) {
		ret = -EFAULT;
		goto out_unlock;
	}

	vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_ASYNC_REQ);

	ret = region->ret_code ? region->ret_code : count;

out_unlock:
	mutex_unlock(&private->io_mutex);
	return ret;
}

static void vfio_ccw_async_region_release(struct vfio_ccw_private *private,
					  struct vfio_ccw_region *region)
{

}

const struct vfio_ccw_regops vfio_ccw_async_region_ops = {
	.read = vfio_ccw_async_region_read,
	.write = vfio_ccw_async_region_write,
	.release = vfio_ccw_async_region_release,
};

int vfio_ccw_register_async_dev_regions(struct vfio_ccw_private *private)
{
	return vfio_ccw_register_dev_region(private,
					    VFIO_REGION_SUBTYPE_CCW_ASYNC_CMD,
					    &vfio_ccw_async_region_ops,
					    sizeof(struct ccw_cmd_region),
					    VFIO_REGION_INFO_FLAG_READ |
					    VFIO_REGION_INFO_FLAG_WRITE,
					    private->cmd_region);
}
+20 −1
Original line number Diff line number Diff line
@@ -362,6 +362,7 @@ static void cp_unpin_free(struct channel_program *cp)
	struct ccwchain *chain, *temp;
	int i;

	cp->initialized = false;
	list_for_each_entry_safe(chain, temp, &cp->ccwchain_list, next) {
		for (i = 0; i < chain->ch_len; i++) {
			pfn_array_table_unpin_free(chain->ch_pat + i,
@@ -732,6 +733,9 @@ int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb)
	 */
	cp->orb.cmd.c64 = 1;

	if (!ret)
		cp->initialized = true;

	return ret;
}

@@ -746,6 +750,7 @@ int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb)
 */
void cp_free(struct channel_program *cp)
{
	if (cp->initialized)
		cp_unpin_free(cp);
}

@@ -791,6 +796,10 @@ int cp_prefetch(struct channel_program *cp)
	struct ccwchain *chain;
	int len, idx, ret;

	/* this is an error in the caller */
	if (!cp->initialized)
		return -EINVAL;

	list_for_each_entry(chain, &cp->ccwchain_list, next) {
		len = chain->ch_len;
		for (idx = 0; idx < len; idx++) {
@@ -826,6 +835,10 @@ union orb *cp_get_orb(struct channel_program *cp, u32 intparm, u8 lpm)
	struct ccwchain *chain;
	struct ccw1 *cpa;

	/* this is an error in the caller */
	if (!cp->initialized)
		return NULL;

	orb = &cp->orb;

	orb->cmd.intparm = intparm;
@@ -862,6 +875,9 @@ void cp_update_scsw(struct channel_program *cp, union scsw *scsw)
	u32 cpa = scsw->cmd.cpa;
	u32 ccw_head;

	if (!cp->initialized)
		return;

	/*
	 * LATER:
	 * For now, only update the cmd.cpa part. We may need to deal with
@@ -898,6 +914,9 @@ bool cp_iova_pinned(struct channel_program *cp, u64 iova)
	struct ccwchain *chain;
	int i;

	if (!cp->initialized)
		return false;

	list_for_each_entry(chain, &cp->ccwchain_list, next) {
		for (i = 0; i < chain->ch_len; i++)
			if (pfn_array_table_iova_pinned(chain->ch_pat + i,
+2 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
 * @ccwchain_list: list head of ccwchains
 * @orb: orb for the currently processed ssch request
 * @mdev: the mediated device to perform page pinning/unpinning
 * @initialized: whether this instance is actually initialized
 *
 * @ccwchain_list is the head of a ccwchain list, that contents the
 * translated result of the guest channel program that pointed out by
@@ -30,6 +31,7 @@ struct channel_program {
	struct list_head ccwchain_list;
	union orb orb;
	struct device *mdev;
	bool initialized;
};

extern int cp_init(struct channel_program *cp, struct device *mdev,
Loading