mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-06 09:13:55 -06:00
s390x update:
- update Linux headers to 5.8-rc1 (for vfio-ccw path handling) - vfio-ccw: add support for path handling - documentation fix -----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEEw9DWbcNiT/aowBjO3s9rk8bwL68FAl7rieQSHGNvaHVja0By ZWRoYXQuY29tAAoJEN7Pa5PG8C+vOn0P/iOCCMhOTPNEfDF7JandmBV2sp+ZKbVq zrMJzybWSwu1YD8tILUiB/G8K9iVK/dpnccbiH/OfHHnW6x88Q8Ggrs4yxBDggOg 4v/CfoaPR9/0CxhE68OOVz+Wl+6nly1tJu7l8f/8zTkKZhb0WLrn2NypvTIH3n0Q cBMmNCoas15YYkKMCWb68McXWThB3BNAeo0gUZsNH+DayQbHna34zI274xQIXhhM pZynKyxOjYm1BTYqyIEGwXP+IGdJwC1SgknExE93NF/2QW/ZPkrruZuh7BKJQBm1 v2Zix0uR7tuXzuf1DNNLIPm+/sXcVUOq+h/GOtT+HpdrpNixW8qDOuOl9UAAhTSU Gb0EOHbh2X9ypopYswi4nVSuMVQwqXXyWTn/i2XfCQhoIQL/BQ750uacQPaO2W7u zaqEqUdezG6AyYACW2juhqs2jGGOL4/4Vlu7drQFNTm5lAOzfqtE5B7AJ6t71P8k xcKcgEzWL5qTB4kFyFDahKCH2BLluSOa+mshHaZmYZUvSnpFBKWsdEkuPTwXhnl6 FtHjFAfv2a6EsAKsa3rZBR43Kv3pHsSqhdyJczA7AlfL5abUxvU0H86JWVXQEl90 zVbSOqwd3uu2zGUqfVdvCT5+FT3SujpmKujZHXkJuZRcm5AKOXz97aihbJzjoIDf xa3T2/8xWLvJ =qr0y -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20200618' into staging s390x update: - update Linux headers to 5.8-rc1 (for vfio-ccw path handling) - vfio-ccw: add support for path handling - documentation fix # gpg: Signature made Thu 18 Jun 2020 16:36:04 BST # gpg: using RSA key C3D0D66DC3624FF6A8C018CEDECF6B93C6F02FAF # gpg: issuer "cohuck@redhat.com" # gpg: Good signature from "Cornelia Huck <conny@cornelia-huck.de>" [marginal] # gpg: aka "Cornelia Huck <huckc@linux.vnet.ibm.com>" [full] # gpg: aka "Cornelia Huck <cornelia.huck@de.ibm.com>" [full] # gpg: aka "Cornelia Huck <cohuck@kernel.org>" [marginal] # gpg: aka "Cornelia Huck <cohuck@redhat.com>" [marginal] # Primary key fingerprint: C3D0 D66D C362 4FF6 A8C0 18CE DECF 6B93 C6F0 2FAF * remotes/cohuck/tags/s390x-20200618: docs/s390x: fix vfio-ap device_del description vfio-ccw: Add support for the CRW region and IRQ s390x/css: Refactor the css_queue_crw() routine vfio-ccw: Refactor ccw irq handler vfio-ccw: Add support for the schib region vfio-ccw: Refactor cleanup of regions Linux headers: update Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
4d285821c5
32 changed files with 1075 additions and 78 deletions
|
@ -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. */
|
||||
copy_schib_to_guest(schib, &sch->curr_status);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void copy_pmcw_from_guest(PMCW *dest, const PMCW *src)
|
||||
|
@ -2161,30 +2170,23 @@ void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid,
|
|||
}
|
||||
}
|
||||
|
||||
void css_queue_crw(uint8_t rsc, uint8_t erc, int solicited,
|
||||
int chain, uint16_t rsid)
|
||||
void css_crw_add_to_queue(CRW crw)
|
||||
{
|
||||
CrwContainer *crw_cont;
|
||||
|
||||
trace_css_crw(rsc, erc, rsid, chain ? "(chained)" : "");
|
||||
trace_css_crw((crw.flags & CRW_FLAGS_MASK_RSC) >> 8,
|
||||
crw.flags & CRW_FLAGS_MASK_ERC,
|
||||
crw.rsid,
|
||||
(crw.flags & CRW_FLAGS_MASK_C) ? "(chained)" : "");
|
||||
|
||||
/* TODO: Maybe use a static crw pool? */
|
||||
crw_cont = g_try_new0(CrwContainer, 1);
|
||||
if (!crw_cont) {
|
||||
channel_subsys.crws_lost = true;
|
||||
return;
|
||||
}
|
||||
crw_cont->crw.flags = (rsc << 8) | erc;
|
||||
if (solicited) {
|
||||
crw_cont->crw.flags |= CRW_FLAGS_MASK_S;
|
||||
}
|
||||
if (chain) {
|
||||
crw_cont->crw.flags |= CRW_FLAGS_MASK_C;
|
||||
}
|
||||
crw_cont->crw.rsid = rsid;
|
||||
if (channel_subsys.crws_lost) {
|
||||
crw_cont->crw.flags |= CRW_FLAGS_MASK_R;
|
||||
channel_subsys.crws_lost = false;
|
||||
}
|
||||
|
||||
crw_cont->crw = crw;
|
||||
|
||||
QTAILQ_INSERT_TAIL(&channel_subsys.pending_crws, crw_cont, sibling);
|
||||
|
||||
|
@ -2195,6 +2197,27 @@ void css_queue_crw(uint8_t rsc, uint8_t erc, int solicited,
|
|||
}
|
||||
}
|
||||
|
||||
void css_queue_crw(uint8_t rsc, uint8_t erc, int solicited,
|
||||
int chain, uint16_t rsid)
|
||||
{
|
||||
CRW crw;
|
||||
|
||||
crw.flags = (rsc << 8) | erc;
|
||||
if (solicited) {
|
||||
crw.flags |= CRW_FLAGS_MASK_S;
|
||||
}
|
||||
if (chain) {
|
||||
crw.flags |= CRW_FLAGS_MASK_C;
|
||||
}
|
||||
crw.rsid = rsid;
|
||||
if (channel_subsys.crws_lost) {
|
||||
crw.flags |= CRW_FLAGS_MASK_R;
|
||||
channel_subsys.crws_lost = false;
|
||||
}
|
||||
|
||||
css_crw_add_to_queue(crw);
|
||||
}
|
||||
|
||||
void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid,
|
||||
int hotplugged, int add)
|
||||
{
|
||||
|
|
|
@ -51,6 +51,27 @@ int s390_ccw_clear(SubchDev *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,
|
||||
char *sysfsdev,
|
||||
Error **errp)
|
||||
|
|
208
hw/vfio/ccw.c
208
hw/vfio/ccw.c
|
@ -41,7 +41,14 @@ struct VFIOCCWDevice {
|
|||
uint64_t async_cmd_region_size;
|
||||
uint64_t async_cmd_region_offset;
|
||||
struct ccw_cmd_region *async_cmd_region;
|
||||
uint64_t schib_region_size;
|
||||
uint64_t schib_region_offset;
|
||||
struct ccw_schib_region *schib_region;
|
||||
uint64_t crw_region_size;
|
||||
uint64_t crw_region_offset;
|
||||
struct ccw_crw_region *crw_region;
|
||||
EventNotifier io_notifier;
|
||||
EventNotifier crw_notifier;
|
||||
bool force_orb_pfch;
|
||||
bool warned_orb_pfch;
|
||||
};
|
||||
|
@ -116,6 +123,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)
|
||||
{
|
||||
S390CCWDevice *cdev = sch->driver_data;
|
||||
|
@ -206,6 +258,44 @@ static void vfio_ccw_reset(DeviceState *dev)
|
|||
ioctl(vcdev->vdev.fd, VFIO_DEVICE_RESET);
|
||||
}
|
||||
|
||||
static void vfio_ccw_crw_read(VFIOCCWDevice *vcdev)
|
||||
{
|
||||
struct ccw_crw_region *region = vcdev->crw_region;
|
||||
CRW crw;
|
||||
int size;
|
||||
|
||||
/* Keep reading CRWs as long as data is returned */
|
||||
do {
|
||||
memset(region, 0, sizeof(*region));
|
||||
size = pread(vcdev->vdev.fd, region, vcdev->crw_region_size,
|
||||
vcdev->crw_region_offset);
|
||||
|
||||
if (size == -1) {
|
||||
error_report("vfio-ccw: Read crw region failed with errno=%d",
|
||||
errno);
|
||||
break;
|
||||
}
|
||||
|
||||
if (region->crw == 0) {
|
||||
/* No more CRWs to queue */
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(&crw, ®ion->crw, sizeof(CRW));
|
||||
|
||||
css_crw_add_to_queue(crw);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
static void vfio_ccw_crw_notifier_handler(void *opaque)
|
||||
{
|
||||
VFIOCCWDevice *vcdev = opaque;
|
||||
|
||||
while (event_notifier_test_and_clear(&vcdev->crw_notifier)) {
|
||||
vfio_ccw_crw_read(vcdev);
|
||||
}
|
||||
}
|
||||
|
||||
static void vfio_ccw_io_notifier_handler(void *opaque)
|
||||
{
|
||||
VFIOCCWDevice *vcdev = opaque;
|
||||
|
@ -276,22 +366,40 @@ read_err:
|
|||
css_inject_io_interrupt(sch);
|
||||
}
|
||||
|
||||
static void vfio_ccw_register_io_notifier(VFIOCCWDevice *vcdev, Error **errp)
|
||||
static void vfio_ccw_register_irq_notifier(VFIOCCWDevice *vcdev,
|
||||
unsigned int irq,
|
||||
Error **errp)
|
||||
{
|
||||
VFIODevice *vdev = &vcdev->vdev;
|
||||
struct vfio_irq_info *irq_info;
|
||||
size_t argsz;
|
||||
int fd;
|
||||
EventNotifier *notifier;
|
||||
IOHandler *fd_read;
|
||||
|
||||
if (vdev->num_irqs < VFIO_CCW_IO_IRQ_INDEX + 1) {
|
||||
error_setg(errp, "vfio: unexpected number of io irqs %u",
|
||||
switch (irq) {
|
||||
case VFIO_CCW_IO_IRQ_INDEX:
|
||||
notifier = &vcdev->io_notifier;
|
||||
fd_read = vfio_ccw_io_notifier_handler;
|
||||
break;
|
||||
case VFIO_CCW_CRW_IRQ_INDEX:
|
||||
notifier = &vcdev->crw_notifier;
|
||||
fd_read = vfio_ccw_crw_notifier_handler;
|
||||
break;
|
||||
default:
|
||||
error_setg(errp, "vfio: Unsupported device irq(%d)", irq);
|
||||
return;
|
||||
}
|
||||
|
||||
if (vdev->num_irqs < irq + 1) {
|
||||
error_setg(errp, "vfio: unexpected number of irqs %u",
|
||||
vdev->num_irqs);
|
||||
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) {
|
||||
|
@ -299,37 +407,52 @@ static void vfio_ccw_register_io_notifier(VFIOCCWDevice *vcdev, Error **errp)
|
|||
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;
|
||||
}
|
||||
|
||||
fd = event_notifier_get_fd(&vcdev->io_notifier);
|
||||
qemu_set_fd_handler(fd, vfio_ccw_io_notifier_handler, NULL, vcdev);
|
||||
fd = event_notifier_get_fd(notifier);
|
||||
qemu_set_fd_handler(fd, fd_read, NULL, vcdev);
|
||||
|
||||
if (vfio_set_irq_signaling(vdev, VFIO_CCW_IO_IRQ_INDEX, 0,
|
||||
if (vfio_set_irq_signaling(vdev, irq, 0,
|
||||
VFIO_IRQ_SET_ACTION_TRIGGER, fd, errp)) {
|
||||
qemu_set_fd_handler(fd, NULL, NULL, vcdev);
|
||||
event_notifier_cleanup(&vcdev->io_notifier);
|
||||
event_notifier_cleanup(notifier);
|
||||
}
|
||||
|
||||
out_free_info:
|
||||
g_free(irq_info);
|
||||
}
|
||||
|
||||
static void vfio_ccw_unregister_io_notifier(VFIOCCWDevice *vcdev)
|
||||
static void vfio_ccw_unregister_irq_notifier(VFIOCCWDevice *vcdev,
|
||||
unsigned int irq)
|
||||
{
|
||||
Error *err = NULL;
|
||||
EventNotifier *notifier;
|
||||
|
||||
if (vfio_set_irq_signaling(&vcdev->vdev, VFIO_CCW_IO_IRQ_INDEX, 0,
|
||||
switch (irq) {
|
||||
case VFIO_CCW_IO_IRQ_INDEX:
|
||||
notifier = &vcdev->io_notifier;
|
||||
break;
|
||||
case VFIO_CCW_CRW_IRQ_INDEX:
|
||||
notifier = &vcdev->crw_notifier;
|
||||
break;
|
||||
default:
|
||||
error_report("vfio: Unsupported device irq(%d)", irq);
|
||||
return;
|
||||
}
|
||||
|
||||
if (vfio_set_irq_signaling(&vcdev->vdev, irq, 0,
|
||||
VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) {
|
||||
error_reportf_err(err, VFIO_MSG_PREFIX, vcdev->vdev.name);
|
||||
}
|
||||
|
||||
qemu_set_fd_handler(event_notifier_get_fd(&vcdev->io_notifier),
|
||||
qemu_set_fd_handler(event_notifier_get_fd(notifier),
|
||||
NULL, NULL, vcdev);
|
||||
event_notifier_cleanup(&vcdev->io_notifier);
|
||||
event_notifier_cleanup(notifier);
|
||||
}
|
||||
|
||||
static void vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp)
|
||||
|
@ -363,8 +486,7 @@ static void vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp)
|
|||
vcdev->io_region_size = info->size;
|
||||
if (sizeof(*vcdev->io_region) != vcdev->io_region_size) {
|
||||
error_setg(errp, "vfio: Unexpected size of the I/O region");
|
||||
g_free(info);
|
||||
return;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
vcdev->io_region_offset = info->offset;
|
||||
|
@ -377,19 +499,53 @@ static void vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp)
|
|||
vcdev->async_cmd_region_size = info->size;
|
||||
if (sizeof(*vcdev->async_cmd_region) != vcdev->async_cmd_region_size) {
|
||||
error_setg(errp, "vfio: Unexpected size of the async cmd region");
|
||||
g_free(vcdev->io_region);
|
||||
g_free(info);
|
||||
return;
|
||||
goto out_err;
|
||||
}
|
||||
vcdev->async_cmd_region_offset = info->offset;
|
||||
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);
|
||||
}
|
||||
|
||||
ret = vfio_get_dev_region_info(vdev, VFIO_REGION_TYPE_CCW,
|
||||
VFIO_REGION_SUBTYPE_CCW_CRW, &info);
|
||||
|
||||
if (!ret) {
|
||||
vcdev->crw_region_size = info->size;
|
||||
if (sizeof(*vcdev->crw_region) != vcdev->crw_region_size) {
|
||||
error_setg(errp, "vfio: Unexpected size of the CRW region");
|
||||
goto out_err;
|
||||
}
|
||||
vcdev->crw_region_offset = info->offset;
|
||||
vcdev->crw_region = g_malloc(info->size);
|
||||
}
|
||||
|
||||
g_free(info);
|
||||
return;
|
||||
|
||||
out_err:
|
||||
g_free(vcdev->crw_region);
|
||||
g_free(vcdev->schib_region);
|
||||
g_free(vcdev->async_cmd_region);
|
||||
g_free(vcdev->io_region);
|
||||
g_free(info);
|
||||
return;
|
||||
}
|
||||
|
||||
static void vfio_ccw_put_region(VFIOCCWDevice *vcdev)
|
||||
{
|
||||
g_free(vcdev->crw_region);
|
||||
g_free(vcdev->schib_region);
|
||||
g_free(vcdev->async_cmd_region);
|
||||
g_free(vcdev->io_region);
|
||||
}
|
||||
|
@ -499,11 +655,19 @@ static void vfio_ccw_realize(DeviceState *dev, Error **errp)
|
|||
goto out_region_err;
|
||||
}
|
||||
|
||||
vfio_ccw_register_io_notifier(vcdev, &err);
|
||||
vfio_ccw_register_irq_notifier(vcdev, VFIO_CCW_IO_IRQ_INDEX, &err);
|
||||
if (err) {
|
||||
goto out_notifier_err;
|
||||
}
|
||||
|
||||
if (vcdev->crw_region) {
|
||||
vfio_ccw_register_irq_notifier(vcdev, VFIO_CCW_CRW_IRQ_INDEX, &err);
|
||||
if (err) {
|
||||
vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_IO_IRQ_INDEX);
|
||||
goto out_notifier_err;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
out_notifier_err:
|
||||
|
@ -528,7 +692,8 @@ static void vfio_ccw_unrealize(DeviceState *dev)
|
|||
S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(cdev);
|
||||
VFIOGroup *group = vcdev->vdev.group;
|
||||
|
||||
vfio_ccw_unregister_io_notifier(vcdev);
|
||||
vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_CRW_IRQ_INDEX);
|
||||
vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_IO_IRQ_INDEX);
|
||||
vfio_ccw_put_region(vcdev);
|
||||
vfio_ccw_put_device(vcdev);
|
||||
vfio_put_group(group);
|
||||
|
@ -565,6 +730,7 @@ static void vfio_ccw_class_init(ObjectClass *klass, void *data)
|
|||
cdc->handle_request = vfio_ccw_handle_request;
|
||||
cdc->handle_halt = vfio_ccw_handle_halt;
|
||||
cdc->handle_clear = vfio_ccw_handle_clear;
|
||||
cdc->handle_store = vfio_ccw_handle_store;
|
||||
}
|
||||
|
||||
static const TypeInfo vfio_ccw_info = {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue