Skip to content

Commit

Permalink
vfio-ccw: Introduce a new CRW region
Browse files Browse the repository at this point in the history
This region provides a mechanism to pass a Channel Report Word
that affect vfio-ccw devices, and needs to be passed to the guest
for its awareness and/or processing.

The base driver (see crw_collect_info()) provides space for two
CRWs, as a subchannel event may have two CRWs chained together
(one for the ssid, one for the subchannel).  As vfio-ccw will
deal with everything at the subchannel level, provide space
for a single CRW to be transferred in one shot.

Signed-off-by: Farhan Ali <alifm@linux.ibm.com>
Signed-off-by: Eric Farman <farman@linux.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Message-Id: <20200505122745.53208-7-farman@linux.ibm.com>
[CH: added padding to ccw_crw_region]
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
  • Loading branch information
Farhan Ali authored and cohuck committed Jun 3, 2020
1 parent 4296151 commit d8cac29
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 0 deletions.
20 changes: 20 additions & 0 deletions Documentation/s390/vfio-ccw.rst
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,26 @@ This region is exposed via region type VFIO_REGION_SUBTYPE_CCW_SCHIB.
Reading this region triggers a STORE SUBCHANNEL to be issued to the
associated hardware.

vfio-ccw crw region
---------------------

The vfio-ccw crw region is used to return Channel Report Word (CRW)
data to userspace::

struct ccw_crw_region {
__u32 crw;
__u32 pad;
} __packed;

This region is exposed via region type VFIO_REGION_SUBTYPE_CCW_CRW.

Reading this region returns a CRW if one that is relevant for this
subchannel (e.g. one reporting changes in channel path state) is
pending, or all zeroes if not. If multiple CRWs are pending (including
possibly chained CRWs), reading this region again will return the next
one, until no more CRWs are pending and zeroes are returned. This is
similar to how STORE CHANNEL REPORT WORD works.

vfio-ccw operation details
--------------------------

Expand Down
55 changes: 55 additions & 0 deletions drivers/s390/cio/vfio_ccw_chp.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,58 @@ int vfio_ccw_register_schib_dev_regions(struct vfio_ccw_private *private)
VFIO_REGION_INFO_FLAG_READ,
private->schib_region);
}

static ssize_t vfio_ccw_crw_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_crw_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;

region->crw = 0;

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

static ssize_t vfio_ccw_crw_region_write(struct vfio_ccw_private *private,
const char __user *buf, size_t count,
loff_t *ppos)
{
return -EINVAL;
}

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

}

const struct vfio_ccw_regops vfio_ccw_crw_region_ops = {
.read = vfio_ccw_crw_region_read,
.write = vfio_ccw_crw_region_write,
.release = vfio_ccw_crw_region_release,
};

int vfio_ccw_register_crw_dev_regions(struct vfio_ccw_private *private)
{
return vfio_ccw_register_dev_region(private,
VFIO_REGION_SUBTYPE_CCW_CRW,
&vfio_ccw_crw_region_ops,
sizeof(struct ccw_crw_region),
VFIO_REGION_INFO_FLAG_READ,
private->crw_region);
}
20 changes: 20 additions & 0 deletions drivers/s390/cio/vfio_ccw_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ struct workqueue_struct *vfio_ccw_work_q;
static struct kmem_cache *vfio_ccw_io_region;
static struct kmem_cache *vfio_ccw_cmd_region;
static struct kmem_cache *vfio_ccw_schib_region;
static struct kmem_cache *vfio_ccw_crw_region;

debug_info_t *vfio_ccw_debug_msg_id;
debug_info_t *vfio_ccw_debug_trace_id;
Expand Down Expand Up @@ -120,6 +121,8 @@ static void vfio_ccw_sch_irq(struct subchannel *sch)

static void vfio_ccw_free_regions(struct vfio_ccw_private *private)
{
if (private->crw_region)
kmem_cache_free(vfio_ccw_crw_region, private->crw_region);
if (private->schib_region)
kmem_cache_free(vfio_ccw_schib_region, private->schib_region);
if (private->cmd_region)
Expand Down Expand Up @@ -165,6 +168,12 @@ static int vfio_ccw_sch_probe(struct subchannel *sch)
if (!private->schib_region)
goto out_free;

private->crw_region = kmem_cache_zalloc(vfio_ccw_crw_region,
GFP_KERNEL | GFP_DMA);

if (!private->crw_region)
goto out_free;

private->sch = sch;
dev_set_drvdata(&sch->dev, private);
mutex_init(&private->io_mutex);
Expand Down Expand Up @@ -366,6 +375,7 @@ static void vfio_ccw_debug_exit(void)

static void vfio_ccw_destroy_regions(void)
{
kmem_cache_destroy(vfio_ccw_crw_region);
kmem_cache_destroy(vfio_ccw_schib_region);
kmem_cache_destroy(vfio_ccw_cmd_region);
kmem_cache_destroy(vfio_ccw_io_region);
Expand Down Expand Up @@ -413,6 +423,16 @@ static int __init vfio_ccw_sch_init(void)
goto out_err;
}

vfio_ccw_crw_region = kmem_cache_create_usercopy("vfio_ccw_crw_region",
sizeof(struct ccw_crw_region), 0,
SLAB_ACCOUNT, 0,
sizeof(struct ccw_crw_region), NULL);

if (!vfio_ccw_crw_region) {
ret = -ENOMEM;
goto out_err;
}

isc_register(VFIO_CCW_ISC);
ret = css_driver_register(&vfio_ccw_sch_driver);
if (ret) {
Expand Down
8 changes: 8 additions & 0 deletions drivers/s390/cio/vfio_ccw_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,10 @@ static int vfio_ccw_mdev_open(struct mdev_device *mdev)
if (ret)
goto out_unregister;

ret = vfio_ccw_register_crw_dev_regions(private);
if (ret)
goto out_unregister;

return ret;

out_unregister:
Expand Down Expand Up @@ -389,6 +393,7 @@ static int vfio_ccw_mdev_get_irq_info(struct vfio_irq_info *info)
{
switch (info->index) {
case VFIO_CCW_IO_IRQ_INDEX:
case VFIO_CCW_CRW_IRQ_INDEX:
info->count = 1;
info->flags = VFIO_IRQ_INFO_EVENTFD;
break;
Expand Down Expand Up @@ -416,6 +421,9 @@ static int vfio_ccw_mdev_set_irqs(struct mdev_device *mdev,
case VFIO_CCW_IO_IRQ_INDEX:
ctx = &private->io_trigger;
break;
case VFIO_CCW_CRW_IRQ_INDEX:
ctx = &private->crw_trigger;
break;
default:
return -EINVAL;
}
Expand Down
4 changes: 4 additions & 0 deletions drivers/s390/cio/vfio_ccw_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ void vfio_ccw_unregister_dev_regions(struct vfio_ccw_private *private);

int vfio_ccw_register_async_dev_regions(struct vfio_ccw_private *private);
int vfio_ccw_register_schib_dev_regions(struct vfio_ccw_private *private);
int vfio_ccw_register_crw_dev_regions(struct vfio_ccw_private *private);

/**
* struct vfio_ccw_private
Expand All @@ -71,6 +72,7 @@ int vfio_ccw_register_schib_dev_regions(struct vfio_ccw_private *private);
* @region: additional regions for other subchannel operations
* @cmd_region: MMIO region for asynchronous I/O commands other than START
* @schib_region: MMIO region for SCHIB information
* @crw_region: MMIO region for getting channel report words
* @num_regions: number of additional regions
* @cp: channel program for the current I/O operation
* @irb: irb info received from interrupt
Expand All @@ -90,13 +92,15 @@ struct vfio_ccw_private {
struct vfio_ccw_region *region;
struct ccw_cmd_region *cmd_region;
struct ccw_schib_region *schib_region;
struct ccw_crw_region *crw_region;
int num_regions;

struct channel_program cp;
struct irb irb;
union scsw scsw;

struct eventfd_ctx *io_trigger;
struct eventfd_ctx *crw_trigger;
struct work_struct io_work;
} __aligned(8);

Expand Down
2 changes: 2 additions & 0 deletions include/uapi/linux/vfio.h
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ struct vfio_region_gfx_edid {
/* sub-types for VFIO_REGION_TYPE_CCW */
#define VFIO_REGION_SUBTYPE_CCW_ASYNC_CMD (1)
#define VFIO_REGION_SUBTYPE_CCW_SCHIB (2)
#define VFIO_REGION_SUBTYPE_CCW_CRW (3)

/*
* The MSIX mappable capability informs that MSIX data of a BAR can be mmapped
Expand Down Expand Up @@ -578,6 +579,7 @@ enum {

enum {
VFIO_CCW_IO_IRQ_INDEX,
VFIO_CCW_CRW_IRQ_INDEX,
VFIO_CCW_NUM_IRQS
};

Expand Down
9 changes: 9 additions & 0 deletions include/uapi/linux/vfio_ccw.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,13 @@ struct ccw_schib_region {
__u8 schib_area[SCHIB_AREA_SIZE];
} __packed;

/*
* Used for returning a Channel Report Word to userspace.
* Note: this is controlled by a capability
*/
struct ccw_crw_region {
__u32 crw;
__u32 pad;
} __packed;

#endif

0 comments on commit d8cac29

Please sign in to comment.