mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-24 03:59:52 +00:00
vfio-ccw: Add support for the schib region
The schib region can be used to obtain the latest SCHIB from the host passthrough subchannel. Since the guest SCHIB is virtualized, we currently only update the path related information so that the guest is aware of any path related changes when it issues the 'stsch' instruction. 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: <20200505125757.98209-4-farman@linux.ibm.com> Signed-off-by: Cornelia Huck <cohuck@redhat.com>
This commit is contained in:
parent
2a3b9cbaa7
commit
46ea3841ed
@ -1335,11 +1335,20 @@ 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)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For some subchannels, we may want to update parts of
|
||||||
|
* the schib (e.g., update path masks from the host device
|
||||||
|
* for passthrough subchannels).
|
||||||
|
*/
|
||||||
|
ret = s390_ccw_store(sch);
|
||||||
|
|
||||||
/* Use current status. */
|
/* Use current status. */
|
||||||
copy_schib_to_guest(schib, &sch->curr_status);
|
copy_schib_to_guest(schib, &sch->curr_status);
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void copy_pmcw_from_guest(PMCW *dest, const PMCW *src)
|
static void copy_pmcw_from_guest(PMCW *dest, const PMCW *src)
|
||||||
|
@ -51,6 +51,27 @@ int s390_ccw_clear(SubchDev *sch)
|
|||||||
return cdc->handle_clear(sch);
|
return cdc->handle_clear(sch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IOInstEnding s390_ccw_store(SubchDev *sch)
|
||||||
|
{
|
||||||
|
S390CCWDeviceClass *cdc = NULL;
|
||||||
|
int ret = IOINST_CC_EXPECTED;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is called for both virtual and passthrough devices,
|
||||||
|
* but only applies to to the latter. This ugly check makes that
|
||||||
|
* distinction for us.
|
||||||
|
*/
|
||||||
|
if (object_dynamic_cast(OBJECT(sch->driver_data), TYPE_S390_CCW)) {
|
||||||
|
cdc = S390_CCW_DEVICE_GET_CLASS(sch->driver_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cdc && cdc->handle_store) {
|
||||||
|
ret = cdc->handle_store(sch);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void s390_ccw_get_dev_info(S390CCWDevice *cdev,
|
static void s390_ccw_get_dev_info(S390CCWDevice *cdev,
|
||||||
char *sysfsdev,
|
char *sysfsdev,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
|
@ -41,6 +41,9 @@ struct VFIOCCWDevice {
|
|||||||
uint64_t async_cmd_region_size;
|
uint64_t async_cmd_region_size;
|
||||||
uint64_t async_cmd_region_offset;
|
uint64_t async_cmd_region_offset;
|
||||||
struct ccw_cmd_region *async_cmd_region;
|
struct ccw_cmd_region *async_cmd_region;
|
||||||
|
uint64_t schib_region_size;
|
||||||
|
uint64_t schib_region_offset;
|
||||||
|
struct ccw_schib_region *schib_region;
|
||||||
EventNotifier io_notifier;
|
EventNotifier io_notifier;
|
||||||
bool force_orb_pfch;
|
bool force_orb_pfch;
|
||||||
bool warned_orb_pfch;
|
bool warned_orb_pfch;
|
||||||
@ -116,6 +119,51 @@ again:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static IOInstEnding vfio_ccw_handle_store(SubchDev *sch)
|
||||||
|
{
|
||||||
|
S390CCWDevice *cdev = sch->driver_data;
|
||||||
|
VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev);
|
||||||
|
SCHIB *schib = &sch->curr_status;
|
||||||
|
struct ccw_schib_region *region = vcdev->schib_region;
|
||||||
|
SCHIB *s;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* schib region not available so nothing else to do */
|
||||||
|
if (!region) {
|
||||||
|
return IOINST_CC_EXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(region, 0, sizeof(*region));
|
||||||
|
ret = pread(vcdev->vdev.fd, region, vcdev->schib_region_size,
|
||||||
|
vcdev->schib_region_offset);
|
||||||
|
|
||||||
|
if (ret == -1) {
|
||||||
|
/*
|
||||||
|
* Device is probably damaged, but store subchannel does not
|
||||||
|
* have a nonzero cc defined for this scenario. Log an error,
|
||||||
|
* and presume things are otherwise fine.
|
||||||
|
*/
|
||||||
|
error_report("vfio-ccw: store region read failed with errno=%d", errno);
|
||||||
|
return IOINST_CC_EXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Selectively copy path-related bits of the SCHIB,
|
||||||
|
* rather than copying the entire struct.
|
||||||
|
*/
|
||||||
|
s = (SCHIB *)region->schib_area;
|
||||||
|
schib->pmcw.pnom = s->pmcw.pnom;
|
||||||
|
schib->pmcw.lpum = s->pmcw.lpum;
|
||||||
|
schib->pmcw.pam = s->pmcw.pam;
|
||||||
|
schib->pmcw.pom = s->pmcw.pom;
|
||||||
|
|
||||||
|
if (s->scsw.flags & SCSW_FLAGS_MASK_PNO) {
|
||||||
|
schib->scsw.flags |= SCSW_FLAGS_MASK_PNO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return IOINST_CC_EXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
static int vfio_ccw_handle_clear(SubchDev *sch)
|
static int vfio_ccw_handle_clear(SubchDev *sch)
|
||||||
{
|
{
|
||||||
S390CCWDevice *cdev = sch->driver_data;
|
S390CCWDevice *cdev = sch->driver_data;
|
||||||
@ -382,10 +430,23 @@ static void vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp)
|
|||||||
vcdev->async_cmd_region = g_malloc0(info->size);
|
vcdev->async_cmd_region = g_malloc0(info->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = vfio_get_dev_region_info(vdev, VFIO_REGION_TYPE_CCW,
|
||||||
|
VFIO_REGION_SUBTYPE_CCW_SCHIB, &info);
|
||||||
|
if (!ret) {
|
||||||
|
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");
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
vcdev->schib_region_offset = info->offset;
|
||||||
|
vcdev->schib_region = g_malloc(info->size);
|
||||||
|
}
|
||||||
|
|
||||||
g_free(info);
|
g_free(info);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
out_err:
|
out_err:
|
||||||
|
g_free(vcdev->schib_region);
|
||||||
g_free(vcdev->async_cmd_region);
|
g_free(vcdev->async_cmd_region);
|
||||||
g_free(vcdev->io_region);
|
g_free(vcdev->io_region);
|
||||||
g_free(info);
|
g_free(info);
|
||||||
@ -394,6 +455,7 @@ out_err:
|
|||||||
|
|
||||||
static void vfio_ccw_put_region(VFIOCCWDevice *vcdev)
|
static void vfio_ccw_put_region(VFIOCCWDevice *vcdev)
|
||||||
{
|
{
|
||||||
|
g_free(vcdev->schib_region);
|
||||||
g_free(vcdev->async_cmd_region);
|
g_free(vcdev->async_cmd_region);
|
||||||
g_free(vcdev->io_region);
|
g_free(vcdev->io_region);
|
||||||
}
|
}
|
||||||
@ -569,6 +631,7 @@ static void vfio_ccw_class_init(ObjectClass *klass, void *data)
|
|||||||
cdc->handle_request = vfio_ccw_handle_request;
|
cdc->handle_request = vfio_ccw_handle_request;
|
||||||
cdc->handle_halt = vfio_ccw_handle_halt;
|
cdc->handle_halt = vfio_ccw_handle_halt;
|
||||||
cdc->handle_clear = vfio_ccw_handle_clear;
|
cdc->handle_clear = vfio_ccw_handle_clear;
|
||||||
|
cdc->handle_store = vfio_ccw_handle_store;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo vfio_ccw_info = {
|
static const TypeInfo vfio_ccw_info = {
|
||||||
|
@ -218,6 +218,7 @@ IOInstEnding do_subchannel_work_passthrough(SubchDev *sub);
|
|||||||
|
|
||||||
int s390_ccw_halt(SubchDev *sch);
|
int s390_ccw_halt(SubchDev *sch);
|
||||||
int s390_ccw_clear(SubchDev *sch);
|
int s390_ccw_clear(SubchDev *sch);
|
||||||
|
IOInstEnding s390_ccw_store(SubchDev *sch);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CSS_IO_ADAPTER_VIRTIO = 0,
|
CSS_IO_ADAPTER_VIRTIO = 0,
|
||||||
@ -242,7 +243,7 @@ SubchDev *css_find_subch(uint8_t m, uint8_t cssid, uint8_t ssid,
|
|||||||
uint16_t schid);
|
uint16_t schid);
|
||||||
bool css_subch_visible(SubchDev *sch);
|
bool css_subch_visible(SubchDev *sch);
|
||||||
void css_conditional_io_interrupt(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);
|
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_msch(SubchDev *sch, const SCHIB *schib);
|
||||||
IOInstEnding css_do_xsch(SubchDev *sch);
|
IOInstEnding css_do_xsch(SubchDev *sch);
|
||||||
|
@ -37,6 +37,7 @@ typedef struct S390CCWDeviceClass {
|
|||||||
IOInstEnding (*handle_request) (SubchDev *sch);
|
IOInstEnding (*handle_request) (SubchDev *sch);
|
||||||
int (*handle_halt) (SubchDev *sch);
|
int (*handle_halt) (SubchDev *sch);
|
||||||
int (*handle_clear) (SubchDev *sch);
|
int (*handle_clear) (SubchDev *sch);
|
||||||
|
IOInstEnding (*handle_store) (SubchDev *sch);
|
||||||
} S390CCWDeviceClass;
|
} S390CCWDeviceClass;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -292,8 +292,7 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
|
|||||||
sch = css_find_subch(m, cssid, ssid, schid);
|
sch = css_find_subch(m, cssid, ssid, schid);
|
||||||
if (sch) {
|
if (sch) {
|
||||||
if (css_subch_visible(sch)) {
|
if (css_subch_visible(sch)) {
|
||||||
css_do_stsch(sch, &schib);
|
cc = css_do_stsch(sch, &schib);
|
||||||
cc = 0;
|
|
||||||
} else {
|
} else {
|
||||||
/* Indicate no more subchannels in this css/ss */
|
/* Indicate no more subchannels in this css/ss */
|
||||||
cc = 3;
|
cc = 3;
|
||||||
|
Loading…
Reference in New Issue
Block a user