2018-01-11 03:05:09

by Dong Jia Shi

[permalink] [raw]
Subject: [RFC PATCH 0/5] vfio/ccw: basic channel path event handling

Hi Folks,

This is the QEMU couterpart for the "basic channel path event handling" series.
For more information, please refer to the kernel counterpart.

Dong Jia Shi (5):
vfio: linux-headers update for vfio-ccw
vfio/ccw: get schib region info
vfio/ccw: get irq info and set up handler for chp irq
vfio/ccw: update subchanel information block lazily
vfio/ccw: build schib with real schib information

hw/s390x/css.c | 97 ++++----------------
hw/s390x/s390-ccw.c | 32 +++++--
hw/vfio/ccw.c | 199 ++++++++++++++++++++++++++++++++++-------
include/hw/s390x/css.h | 3 +-
include/hw/s390x/s390-ccw.h | 4 +-
linux-headers/linux/vfio.h | 2 +
linux-headers/linux/vfio_ccw.h | 6 ++
target/s390x/ioinst.c | 3 +-
8 files changed, 224 insertions(+), 122 deletions(-)

--
2.13.5


2018-01-11 03:05:15

by Dong Jia Shi

[permalink] [raw]
Subject: [RFC PATCH 1/5] vfio: linux-headers update for vfio-ccw

This is a placeholder for a linux-headers update.

Signed-off-by: Dong Jia Shi <[email protected]>
---
linux-headers/linux/vfio.h | 2 ++
linux-headers/linux/vfio_ccw.h | 6 ++++++
2 files changed, 8 insertions(+)

diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h
index 4312e961ff..24d85be022 100644
--- a/linux-headers/linux/vfio.h
+++ b/linux-headers/linux/vfio.h
@@ -457,11 +457,13 @@ enum {

enum {
VFIO_CCW_CONFIG_REGION_INDEX,
+ VFIO_CCW_SCHIB_REGION_INDEX,
VFIO_CCW_NUM_REGIONS
};

enum {
VFIO_CCW_IO_IRQ_INDEX,
+ VFIO_CCW_CHP_IRQ_INDEX,
VFIO_CCW_NUM_IRQS
};

diff --git a/linux-headers/linux/vfio_ccw.h b/linux-headers/linux/vfio_ccw.h
index 5bf96c3812..4944dd946e 100644
--- a/linux-headers/linux/vfio_ccw.h
+++ b/linux-headers/linux/vfio_ccw.h
@@ -22,4 +22,10 @@ struct ccw_io_region {
__u32 ret_code;
} __attribute__((packed));

+struct ccw_schib_region {
+ __u8 cc;
+#define SCHIB_AREA_SIZE 52
+ __u8 schib_area[SCHIB_AREA_SIZE];
+} __attribute__((packed));
+
#endif
--
2.13.5

2018-01-11 03:05:27

by Dong Jia Shi

[permalink] [raw]
Subject: [RFC PATCH 4/5] vfio/ccw: update subchanel information block lazily

We want to sync up channel path related information between the
physical device and the virtual device. Thus here we read out
subchannel information block from the schib region, and update
the virtual sbuchannel information block.

Since the kernel side will signal userland once it has channel
path information update, we only do update if we were signaled.

We sets scsw.pno and pmcw.pnom to indicate path related event
for a guest. This is a bit lazy, but it works.

Signed-off-by: Dong Jia Shi <[email protected]>
---
hw/s390x/css.c | 14 +++++++++--
hw/s390x/s390-ccw.c | 12 +++++++++
hw/vfio/ccw.c | 59 ++++++++++++++++++++++++++++++++++++++++++++-
include/hw/s390x/css.h | 3 ++-
include/hw/s390x/s390-ccw.h | 1 +
target/s390x/ioinst.c | 3 +--
6 files changed, 86 insertions(+), 6 deletions(-)

diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index 1c526fd7e2..c1ec83f08f 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -1297,11 +1297,16 @@ static void copy_schib_to_guest(SCHIB *dest, const SCHIB *src)
}
}

-int css_do_stsch(SubchDev *sch, SCHIB *schib)
+IOInstEnding css_do_stsch(SubchDev *sch, SCHIB *schib)
{
+ if (sch->update_schib &&
+ (sch->update_schib(sch) != IOINST_CC_EXPECTED)) {
+ return IOINST_CC_NOT_OPERATIONAL;
+ }
+
/* Use current status. */
copy_schib_to_guest(schib, &sch->curr_status);
- return 0;
+ return IOINST_CC_EXPECTED;
}

static void copy_pmcw_from_guest(PMCW *dest, const PMCW *src)
@@ -1586,6 +1591,11 @@ int css_do_tsch_get_irb(SubchDev *sch, IRB *target_irb, int *irb_len)
uint16_t stctl;
IRB irb;

+ if (sch->update_schib &&
+ (sch->update_schib(sch) != IOINST_CC_EXPECTED)) {
+ return IOINST_CC_NOT_OPERATIONAL;
+ }
+
if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
return 3;
}
diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c
index 4a9d4d2534..491697137c 100644
--- a/hw/s390x/s390-ccw.c
+++ b/hw/s390x/s390-ccw.c
@@ -28,6 +28,17 @@ IOInstEnding s390_ccw_cmd_request(SubchDev *sch)
return cdc->handle_request(sch);
}

+static IOInstEnding s390_ccw_update_schib(SubchDev *sch)
+{
+ S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(sch->driver_data);
+
+ if (!cdc->update_schib) {
+ /* g_assert_not_reached()? */
+ return IOINST_CC_NOT_OPERATIONAL;
+ }
+ return cdc->update_schib(sch);
+}
+
static void s390_ccw_get_dev_info(S390CCWDevice *cdev,
char *sysfsdev,
Error **errp)
@@ -83,6 +94,7 @@ static void s390_ccw_realize(S390CCWDevice *cdev, char *sysfsdev, Error **errp)
}
sch->driver_data = cdev;
sch->do_subchannel_work = do_subchannel_work_passthrough;
+ sch->update_schib = s390_ccw_update_schib;

ccw_dev->sch = sch;
ret = css_sch_build_schib(sch, &cdev->hostid);
diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c
index d812cecfe0..0eca3453af 100644
--- a/hw/vfio/ccw.c
+++ b/hw/vfio/ccw.c
@@ -33,6 +33,7 @@ typedef struct VFIOCCWDevice {
struct ccw_io_region *io_region;
EventNotifier io_notifier;

+ bool schib_need_update;
uint64_t schib_region_size;
uint64_t schib_region_offset;
struct ccw_schib_region *schib_region;
@@ -97,6 +98,57 @@ again:
}
}

+static IOInstEnding vfio_ccw_update_schib(SubchDev *sch)
+{
+
+ S390CCWDevice *cdev = sch->driver_data;
+ VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev);
+ struct ccw_schib_region *region = vcdev->schib_region;
+ PMCW *p = &sch->curr_status.pmcw;
+ SCSW *s = &sch->curr_status.scsw;
+ SCHIB *schib;
+ int size;
+ int i;
+
+ /*
+ * If there is no update that interested us since last read,
+ * we do not read then.
+ */
+ if (!vcdev->schib_need_update) {
+ return IOINST_CC_EXPECTED;
+ }
+ vcdev->schib_need_update = false;
+
+ /* Read schib region, and update schib for virtual subchannel. */
+ size = pread(vcdev->vdev.fd, region, vcdev->schib_region_size,
+ vcdev->schib_region_offset);
+ if (size != vcdev->schib_region_size) {
+ return IOINST_CC_NOT_OPERATIONAL;
+ }
+ if (region->cc) {
+ g_assert(region->cc == IOINST_CC_NOT_OPERATIONAL);
+ return region->cc;
+ }
+
+ schib = (SCHIB *)region->schib_area;
+
+ /* Path mask. */
+ p->pim = schib->pmcw.pim;
+ p->pam = schib->pmcw.pam;
+ p->pom = schib->pmcw.pom;
+
+ /* We use PNO and PNOM to indicate path related events. */
+ p->pnom = ~schib->pmcw.pam;
+ s->flags |= SCSW_FLAGS_MASK_PNO;
+
+ /* Chp id. */
+ for (i = 0; i < ARRAY_SIZE(p->chpid); i++) {
+ p->chpid[i] = schib->pmcw.chpid[i];
+ }
+
+ return region->cc;
+}
+
static void vfio_ccw_reset(DeviceState *dev)
{
CcwDevice *ccw_dev = DO_UPCAST(CcwDevice, parent_obj, dev);
@@ -182,7 +234,9 @@ static void vfio_ccw_chp_notifier_handler(void *opaque)
return;
}

- /* TODO: further process on path informaion. */
+ vcdev->schib_need_update = true;
+
+ /* TODO: Generate channel path crw? */
}

static void vfio_ccw_register_event_notifier(VFIOCCWDevice *vcdev, int irq,
@@ -444,6 +498,8 @@ static void vfio_ccw_realize(DeviceState *dev, Error **errp)
goto out_notifier_err;
}

+ vcdev->schib_need_update = true;
+
return;

out_notifier_err:
@@ -503,6 +559,7 @@ static void vfio_ccw_class_init(ObjectClass *klass, void *data)
dc->reset = vfio_ccw_reset;

cdc->handle_request = vfio_ccw_handle_request;
+ cdc->update_schib = vfio_ccw_update_schib;
}

static const TypeInfo vfio_ccw_info = {
diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h
index 35facb47d2..bcb433af4a 100644
--- a/include/hw/s390x/css.h
+++ b/include/hw/s390x/css.h
@@ -137,6 +137,7 @@ struct SubchDev {
int (*ccw_cb) (SubchDev *, CCW1);
void (*disable_cb)(SubchDev *);
IOInstEnding (*do_subchannel_work) (SubchDev *);
+ IOInstEnding (*update_schib) (SubchDev *);
SenseId id;
void *driver_data;
};
@@ -237,7 +238,7 @@ SubchDev *css_find_subch(uint8_t m, uint8_t cssid, uint8_t ssid,
uint16_t schid);
bool css_subch_visible(SubchDev *sch);
void css_conditional_io_interrupt(SubchDev *sch);
-int css_do_stsch(SubchDev *sch, SCHIB *schib);
+IOInstEnding css_do_stsch(SubchDev *sch, SCHIB *schib);
bool css_schid_final(int m, uint8_t cssid, uint8_t ssid, uint16_t schid);
IOInstEnding css_do_msch(SubchDev *sch, const SCHIB *schib);
IOInstEnding css_do_xsch(SubchDev *sch);
diff --git a/include/hw/s390x/s390-ccw.h b/include/hw/s390x/s390-ccw.h
index 7d15a1a5d4..96e6a00e3e 100644
--- a/include/hw/s390x/s390-ccw.h
+++ b/include/hw/s390x/s390-ccw.h
@@ -34,6 +34,7 @@ typedef struct S390CCWDeviceClass {
void (*realize)(S390CCWDevice *dev, char *sysfsdev, Error **errp);
void (*unrealize)(S390CCWDevice *dev, Error **errp);
IOInstEnding (*handle_request) (SubchDev *sch);
+ IOInstEnding (*update_schib) (SubchDev *);
} S390CCWDeviceClass;

#endif
diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c
index 83c164a168..2c841bb66f 100644
--- a/target/s390x/ioinst.c
+++ b/target/s390x/ioinst.c
@@ -257,8 +257,7 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
sch = css_find_subch(m, cssid, ssid, schid);
if (sch) {
if (css_subch_visible(sch)) {
- css_do_stsch(sch, &schib);
- cc = 0;
+ cc = css_do_stsch(sch, &schib);
} else {
/* Indicate no more subchannels in this css/ss */
cc = 3;
--
2.13.5

2018-01-11 03:05:18

by Dong Jia Shi

[permalink] [raw]
Subject: [RFC PATCH 3/5] vfio/ccw: get irq info and set up handler for chp irq

vfio-ccw now resorts to the eventfd mechanism to communicate
with userland for channel path related event. To get notification
of the channel path event, userland basically needs to:
1. check the chp irq capability via issuing VFIO_DEVICE_GET_IRQ_INFO
ioctl with VFIO_CCW_CHP_IRQ_INDEX.
2. register an event notifier to get an eventfd fd.
3. register the eventfd for chp irq to kernel via
VFIO_DEVICE_SET_IRQS ioctl.

This work introduces vfio_ccw_chp_notifier_handler(), and refactors
vfio_ccw_(un)register_event_notifier() to do the above.

Based on this, future work could read channel path information
out once got the eventfd signal, and do further process.

Signed-off-by: Dong Jia Shi <[email protected]>
---
hw/vfio/ccw.c | 92 +++++++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 70 insertions(+), 22 deletions(-)

diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c
index e673695509..d812cecfe0 100644
--- a/hw/vfio/ccw.c
+++ b/hw/vfio/ccw.c
@@ -36,6 +36,8 @@ typedef struct VFIOCCWDevice {
uint64_t schib_region_size;
uint64_t schib_region_offset;
struct ccw_schib_region *schib_region;
+
+ EventNotifier chp_notifier;
} VFIOCCWDevice;

static void vfio_ccw_compute_needs_reset(VFIODevice *vdev)
@@ -172,33 +174,56 @@ read_err:
css_inject_io_interrupt(sch);
}

-static void vfio_ccw_register_io_notifier(VFIOCCWDevice *vcdev, Error **errp)
+static void vfio_ccw_chp_notifier_handler(void *opaque)
+{
+ VFIOCCWDevice *vcdev = opaque;
+
+ if (!event_notifier_test_and_clear(&vcdev->chp_notifier)) {
+ return;
+ }
+
+ /* TODO: further process on path informaion. */
+}
+
+static void vfio_ccw_register_event_notifier(VFIOCCWDevice *vcdev, int irq,
+ Error **errp)
{
VFIODevice *vdev = &vcdev->vdev;
struct vfio_irq_info *irq_info;
struct vfio_irq_set *irq_set;
size_t argsz;
int32_t *pfd;
-
- if (vdev->num_irqs < VFIO_CCW_IO_IRQ_INDEX + 1) {
- error_setg(errp, "vfio: unexpected number of io irqs %u",
- vdev->num_irqs);
+ EventNotifier *notifier;
+ IOHandler *fd_read;
+
+ switch (irq) {
+ case VFIO_CCW_IO_IRQ_INDEX:
+ notifier = &vcdev->io_notifier;
+ fd_read = vfio_ccw_io_notifier_handler;
+ break;
+ case VFIO_CCW_CHP_IRQ_INDEX:
+ notifier = &vcdev->chp_notifier;
+ fd_read = vfio_ccw_chp_notifier_handler;
+ break;
+ default:
+ error_setg(errp, "vfio: Unsupported device irq(%d) fd: %m", irq);
return;
}

argsz = sizeof(*irq_info);
irq_info = g_malloc0(argsz);
- irq_info->index = VFIO_CCW_IO_IRQ_INDEX;
+ irq_info->index = irq;
irq_info->argsz = argsz;
if (ioctl(vdev->fd, VFIO_DEVICE_GET_IRQ_INFO,
irq_info) < 0 || irq_info->count < 1) {
- error_setg_errno(errp, errno, "vfio: Error getting irq info");
+ error_setg_errno(errp, errno, "vfio: Error getting irq(%d) info", irq);
goto out_free_info;
}

- if (event_notifier_init(&vcdev->io_notifier, 0)) {
+ if (event_notifier_init(notifier, 0)) {
error_setg_errno(errp, errno,
- "vfio: Unable to init event notifier for IO");
+ "vfio: Unable to init event notifier for irq(%d)",
+ irq);
goto out_free_info;
}

@@ -207,17 +232,18 @@ static void vfio_ccw_register_io_notifier(VFIOCCWDevice *vcdev, Error **errp)
irq_set->argsz = argsz;
irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
VFIO_IRQ_SET_ACTION_TRIGGER;
- irq_set->index = VFIO_CCW_IO_IRQ_INDEX;
+ irq_set->index = irq;
irq_set->start = 0;
irq_set->count = 1;
pfd = (int32_t *) &irq_set->data;

- *pfd = event_notifier_get_fd(&vcdev->io_notifier);
- qemu_set_fd_handler(*pfd, vfio_ccw_io_notifier_handler, NULL, vcdev);
+ *pfd = event_notifier_get_fd(notifier);
+ qemu_set_fd_handler(*pfd, fd_read, NULL, vcdev);
if (ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set)) {
- error_setg(errp, "vfio: Failed to set up io notification");
+ error_setg(errp, "vfio: Failed to set up notification for irq(%d)",
+ irq);
qemu_set_fd_handler(*pfd, NULL, NULL, vcdev);
- event_notifier_cleanup(&vcdev->io_notifier);
+ event_notifier_cleanup(notifier);
}

g_free(irq_set);
@@ -226,30 +252,42 @@ out_free_info:
g_free(irq_info);
}

-static void vfio_ccw_unregister_io_notifier(VFIOCCWDevice *vcdev)
+static void vfio_ccw_unregister_event_notifier(VFIOCCWDevice *vcdev, int irq)
{
struct vfio_irq_set *irq_set;
size_t argsz;
int32_t *pfd;
+ EventNotifier *notifier;
+
+ switch (irq) {
+ case VFIO_CCW_IO_IRQ_INDEX:
+ notifier = &vcdev->io_notifier;
+ break;
+ case VFIO_CCW_CHP_IRQ_INDEX:
+ notifier = &vcdev->chp_notifier;
+ break;
+ default:
+ error_report("vfio: Unsupported device irq(%d) fd: %m", irq);
+ return;
+ }

argsz = sizeof(*irq_set) + sizeof(*pfd);
irq_set = g_malloc0(argsz);
irq_set->argsz = argsz;
irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
VFIO_IRQ_SET_ACTION_TRIGGER;
- irq_set->index = VFIO_CCW_IO_IRQ_INDEX;
+ irq_set->index = irq;
irq_set->start = 0;
irq_set->count = 1;
pfd = (int32_t *) &irq_set->data;
*pfd = -1;

if (ioctl(vcdev->vdev.fd, VFIO_DEVICE_SET_IRQS, irq_set)) {
- error_report("vfio: Failed to de-assign device io fd: %m");
+ error_report("vfio: Failed to de-assign device irq(%d) fd: %m", irq);
}

- qemu_set_fd_handler(event_notifier_get_fd(&vcdev->io_notifier),
- NULL, NULL, vcdev);
- event_notifier_cleanup(&vcdev->io_notifier);
+ qemu_set_fd_handler(event_notifier_get_fd(notifier), NULL, NULL, vcdev);
+ event_notifier_cleanup(notifier);

g_free(irq_set);
}
@@ -272,6 +310,11 @@ static void vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp)
return;
}

+ if (vdev->num_irqs < VFIO_CCW_IO_IRQ_INDEX + 1) {
+ error_setg(errp, "vfio: Unexpected number of irqs %u", vdev->num_irqs);
+ return;
+ }
+
/* Get I/O region info. */
ret = vfio_get_region_info(vdev, VFIO_CCW_CONFIG_REGION_INDEX, &info);
if (ret) {
@@ -392,7 +435,11 @@ static void vfio_ccw_realize(DeviceState *dev, Error **errp)
goto out_region_err;
}

- vfio_ccw_register_io_notifier(vcdev, &err);
+ vfio_ccw_register_event_notifier(vcdev, VFIO_CCW_IO_IRQ_INDEX, &err);
+ if (err) {
+ goto out_notifier_err;
+ }
+ vfio_ccw_register_event_notifier(vcdev, VFIO_CCW_CHP_IRQ_INDEX, &err);
if (err) {
goto out_notifier_err;
}
@@ -421,7 +468,8 @@ static void vfio_ccw_unrealize(DeviceState *dev, Error **errp)
S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(cdev);
VFIOGroup *group = vcdev->vdev.group;

- vfio_ccw_unregister_io_notifier(vcdev);
+ vfio_ccw_unregister_event_notifier(vcdev, VFIO_CCW_IO_IRQ_INDEX);
+ vfio_ccw_unregister_event_notifier(vcdev, VFIO_CCW_CHP_IRQ_INDEX);
vfio_ccw_put_region(vcdev);
vfio_put_device(vcdev);
vfio_put_group(group);
--
2.13.5

2018-01-11 03:05:57

by Dong Jia Shi

[permalink] [raw]
Subject: [RFC PATCH 5/5] vfio/ccw: build schib with real schib information

The current implementation grabs chpids and path masks from
sysfs to build the schib and chp for the virtual subchannels.

Since now vfio-ccw provides a schib region for store subchannel
information. Let's leverage it to get the chipids and the masks,
and serve the virtual subchannels.

While we are at it, touch one line of the comment around by
adding white space to make it aligned.

Signed-off-by: Dong Jia Shi <[email protected]>
---
hw/s390x/css.c | 83 ++++-----------------------------------------
hw/s390x/s390-ccw.c | 20 +++++++----
hw/vfio/ccw.c | 28 +++++++++------
include/hw/s390x/s390-ccw.h | 3 +-
4 files changed, 39 insertions(+), 95 deletions(-)

diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index c1ec83f08f..b9bc489e55 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -2417,72 +2417,6 @@ SubchDev *css_create_sch(CssDevId bus_id, bool squash_mcss, Error **errp)
return sch;
}

-static int css_sch_get_chpids(SubchDev *sch, CssDevId *dev_id)
-{
- char *fid_path;
- FILE *fd;
- uint32_t chpid[8];
- int i;
- PMCW *p = &sch->curr_status.pmcw;
-
- fid_path = g_strdup_printf("/sys/bus/css/devices/%x.%x.%04x/chpids",
- dev_id->cssid, dev_id->ssid, dev_id->devid);
- fd = fopen(fid_path, "r");
- if (fd == NULL) {
- error_report("%s: open %s failed", __func__, fid_path);
- g_free(fid_path);
- return -EINVAL;
- }
-
- if (fscanf(fd, "%x %x %x %x %x %x %x %x",
- &chpid[0], &chpid[1], &chpid[2], &chpid[3],
- &chpid[4], &chpid[5], &chpid[6], &chpid[7]) != 8) {
- fclose(fd);
- g_free(fid_path);
- return -EINVAL;
- }
-
- for (i = 0; i < ARRAY_SIZE(p->chpid); i++) {
- p->chpid[i] = chpid[i];
- }
-
- fclose(fd);
- g_free(fid_path);
-
- return 0;
-}
-
-static int css_sch_get_path_masks(SubchDev *sch, CssDevId *dev_id)
-{
- char *fid_path;
- FILE *fd;
- uint32_t pim, pam, pom;
- PMCW *p = &sch->curr_status.pmcw;
-
- fid_path = g_strdup_printf("/sys/bus/css/devices/%x.%x.%04x/pimpampom",
- dev_id->cssid, dev_id->ssid, dev_id->devid);
- fd = fopen(fid_path, "r");
- if (fd == NULL) {
- error_report("%s: open %s failed", __func__, fid_path);
- g_free(fid_path);
- return -EINVAL;
- }
-
- if (fscanf(fd, "%x %x %x", &pim, &pam, &pom) != 3) {
- fclose(fd);
- g_free(fid_path);
- return -EINVAL;
- }
-
- p->pim = pim;
- p->pam = pam;
- p->pom = pom;
- fclose(fd);
- g_free(fid_path);
-
- return 0;
-}
-
static int css_sch_get_chpid_type(uint8_t chpid, uint32_t *type,
CssDevId *dev_id)
{
@@ -2529,19 +2463,14 @@ int css_sch_build_schib(SubchDev *sch, CssDevId *dev_id)
/* We are dealing with I/O subchannels only. */
p->devno = sch->devno;

- /* Grab path mask from sysfs. */
- ret = css_sch_get_path_masks(sch, dev_id);
- if (ret) {
- return ret;
- }
-
- /* Grab chpids from sysfs. */
- ret = css_sch_get_chpids(sch, dev_id);
- if (ret) {
- return ret;
+ /* Read schib from the physical device. */
+ /* g_assert(sch->update_schib != NULL) ? */
+ if (sch->update_schib &&
+ (sch->update_schib(sch) != IOINST_CC_EXPECTED)) {
+ return -ENODEV;
}

- /* Build chpid type. */
+ /* Build chpid type. */
for (i = 0; i < ARRAY_SIZE(p->chpid); i++) {
if (p->chpid[i] && !css->chpids[p->chpid[i]].in_use) {
ret = css_sch_get_chpid_type(p->chpid[i], &type, dev_id);
diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c
index 491697137c..f658b87131 100644
--- a/hw/s390x/s390-ccw.c
+++ b/hw/s390x/s390-ccw.c
@@ -72,7 +72,18 @@ static void s390_ccw_get_dev_info(S390CCWDevice *cdev,
cdev->hostid.valid = true;
}

-static void s390_ccw_realize(S390CCWDevice *cdev, char *sysfsdev, Error **errp)
+static void s390_ccw_pre_realize(S390CCWDevice *cdev, char *sysfsdev,
+ Error **errp)
+{
+ Error *err = NULL;
+
+ s390_ccw_get_dev_info(cdev, sysfsdev, &err);
+ if (err) {
+ error_propagate(errp, err);
+ }
+}
+
+static void s390_ccw_realize(S390CCWDevice *cdev, Error **errp)
{
CcwDevice *ccw_dev = CCW_DEVICE(cdev);
CCWDeviceClass *ck = CCW_DEVICE_GET_CLASS(ccw_dev);
@@ -83,11 +94,6 @@ static void s390_ccw_realize(S390CCWDevice *cdev, char *sysfsdev, Error **errp)
int ret;
Error *err = NULL;

- s390_ccw_get_dev_info(cdev, sysfsdev, &err);
- if (err) {
- goto out_err_propagate;
- }
-
sch = css_create_sch(ccw_dev->devno, cbus->squash_mcss, &err);
if (!sch) {
goto out_mdevid_free;
@@ -119,7 +125,6 @@ out_err:
g_free(sch);
out_mdevid_free:
g_free(cdev->mdevid);
-out_err_propagate:
error_propagate(errp, err);
}

@@ -143,6 +148,7 @@ static void s390_ccw_class_init(ObjectClass *klass, void *data)
S390CCWDeviceClass *cdc = S390_CCW_DEVICE_CLASS(klass);

dc->bus_type = TYPE_VIRTUAL_CSS_BUS;
+ cdc->pre_realize = s390_ccw_pre_realize;
cdc->realize = s390_ccw_realize;
cdc->unrealize = s390_ccw_unrealize;
}
diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c
index 0eca3453af..549ef3f8ed 100644
--- a/hw/vfio/ccw.c
+++ b/hw/vfio/ccw.c
@@ -146,6 +146,8 @@ static IOInstEnding vfio_ccw_update_schib(SubchDev *sch)
p->chpid[i] = schib->pmcw.chpid[i];
}

+ /* TODO: add chpid? */
+
return region->cc;
}

@@ -454,9 +456,8 @@ static void vfio_ccw_realize(DeviceState *dev, Error **errp)
S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(cdev);
Error *err = NULL;

- /* Call the class init function for subchannel. */
- if (cdc->realize) {
- cdc->realize(cdev, vcdev->vdev.sysfsdev, &err);
+ if (cdc->pre_realize) {
+ cdc->pre_realize(cdev, vcdev->vdev.sysfsdev, &err);
if (err) {
goto out_err_propagate;
}
@@ -464,7 +465,7 @@ static void vfio_ccw_realize(DeviceState *dev, Error **errp)

group = vfio_ccw_get_group(cdev, &err);
if (!group) {
- goto out_group_err;
+ goto out_err_propagate;
}

vcdev->vdev.ops = &vfio_ccw_ops;
@@ -491,27 +492,34 @@ static void vfio_ccw_realize(DeviceState *dev, Error **errp)

vfio_ccw_register_event_notifier(vcdev, VFIO_CCW_IO_IRQ_INDEX, &err);
if (err) {
- goto out_notifier_err;
+ goto out_io_notifier_err;
}
vfio_ccw_register_event_notifier(vcdev, VFIO_CCW_CHP_IRQ_INDEX, &err);
if (err) {
- goto out_notifier_err;
+ goto out_chp_notifier_err;
}

vcdev->schib_need_update = true;
+ /* Call the class init function for subchannel. */
+ if (cdc->realize) {
+ cdc->realize(cdev, &err);
+ if (err) {
+ goto out_notifier_err;
+ }
+ }

return;

out_notifier_err:
+ vfio_ccw_unregister_event_notifier(vcdev, VFIO_CCW_CHP_IRQ_INDEX);
+out_chp_notifier_err:
+ vfio_ccw_unregister_event_notifier(vcdev, VFIO_CCW_IO_IRQ_INDEX);
+out_io_notifier_err:
vfio_ccw_put_region(vcdev);
out_region_err:
vfio_put_device(vcdev);
out_device_err:
vfio_put_group(group);
-out_group_err:
- if (cdc->unrealize) {
- cdc->unrealize(cdev, NULL);
- }
out_err_propagate:
error_propagate(errp, err);
}
diff --git a/include/hw/s390x/s390-ccw.h b/include/hw/s390x/s390-ccw.h
index 96e6a00e3e..3bbf31dd00 100644
--- a/include/hw/s390x/s390-ccw.h
+++ b/include/hw/s390x/s390-ccw.h
@@ -31,7 +31,8 @@ typedef struct S390CCWDevice {

typedef struct S390CCWDeviceClass {
CCWDeviceClass parent_class;
- void (*realize)(S390CCWDevice *dev, char *sysfsdev, Error **errp);
+ void (*pre_realize)(S390CCWDevice *dev, char *sysfsdev, Error **errp);
+ void (*realize)(S390CCWDevice *dev, Error **errp);
void (*unrealize)(S390CCWDevice *dev, Error **errp);
IOInstEnding (*handle_request) (SubchDev *sch);
IOInstEnding (*update_schib) (SubchDev *);
--
2.13.5

2018-01-11 03:06:36

by Dong Jia Shi

[permalink] [raw]
Subject: [RFC PATCH 2/5] vfio/ccw: get schib region info

vfio-ccw provides an MMIO region for store subchannel
information. We fetch this information via ioctls here,
then we can use it to update schib for virtual subchannels
later on.

While we are at it, also modify the comment and error
message for the config region a bit, to make these unified
with the schib likeness.

Signed-off-by: Dong Jia Shi <[email protected]>
---
hw/vfio/ccw.c | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c
index 16713f2c52..e673695509 100644
--- a/hw/vfio/ccw.c
+++ b/hw/vfio/ccw.c
@@ -32,6 +32,10 @@ typedef struct VFIOCCWDevice {
uint64_t io_region_offset;
struct ccw_io_region *io_region;
EventNotifier io_notifier;
+
+ uint64_t schib_region_size;
+ uint64_t schib_region_offset;
+ struct ccw_schib_region *schib_region;
} VFIOCCWDevice;

static void vfio_ccw_compute_needs_reset(VFIODevice *vdev)
@@ -268,9 +272,10 @@ static void vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp)
return;
}

+ /* Get I/O region info. */
ret = vfio_get_region_info(vdev, VFIO_CCW_CONFIG_REGION_INDEX, &info);
if (ret) {
- error_setg_errno(errp, -ret, "vfio: Error getting config info");
+ error_setg_errno(errp, -ret, "vfio: Error getting config region info");
return;
}

@@ -283,13 +288,30 @@ static void vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp)

vcdev->io_region_offset = info->offset;
vcdev->io_region = g_malloc0(info->size);
+ g_free(info);

+ /* Get SCHIB region info. */
+ ret = vfio_get_region_info(vdev, VFIO_CCW_SCHIB_REGION_INDEX, &info);
+ if (ret) {
+ error_setg_errno(errp, -ret, "vfio: Error getting schib region info");
+ return;
+ }
+
+ vcdev->schib_region_size = info->size;
+ if (sizeof(*vcdev->schib_region) != vcdev->schib_region_size) {
+ error_setg(errp, "vfio: Unexpected size of the schib region");
+ g_free(info);
+ return;
+ }
+ vcdev->schib_region_offset = info->offset;
+ vcdev->schib_region = g_malloc0(info->size);
g_free(info);
}

static void vfio_ccw_put_region(VFIOCCWDevice *vcdev)
{
g_free(vcdev->io_region);
+ g_free(vcdev->schib_region);
}

static void vfio_put_device(VFIOCCWDevice *vcdev)
--
2.13.5