Several s390x patches including:
- missing virtio-1 related code for virtio-ccw - bugfixes in ipl device, gdb, virtio-ccw - bugfix in s390-ccw bios + rebuild - introduce versioned machines for s390-ccw-virtio -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJVlUUuAAoJEN7Pa5PG8C+vLQgP/0HMDJCbUtmH7L47jRKAnoAQ RsXqmdnIqMaMAuf9PJwVy6Gx/akvo2qR3cu9J3H19uBhZvXj4WyfBZkeSBO/uqfn r23f3EEGmeym0uHaC3Xi8j0MGUJbu+K41mXwA5/pZXwEe//EsvV1uFoo7Euff2/u 2cuGLdte6E9iJg2n/sbRoZuODOoEKQv1xyc7Z7uB1AnLiiUwwPcw2h2Q57rVNuhM 8J8fc9kFRGIjmh/vXYT0nLImboyVdIz2whYT/AXm+Q0gDBf4vGUo0pLjN0I/DMSe 6lxBBVNA+4qFF3EFkbQU32gc/HnIzqKhtLno9l6+wDjETEsCKabESRRnmRrlPWYw hJsJf/DxoObob7z7tEvA0EKFR+cDVxyv0u68aha7AykY7CrMiZy7QS18BsSTp6gX OP0u1JQU9v+hOq1X4LGOoHuJMT9f83UDsjHoXYHPRxlNVf9YHznrexRBJXVp2Nkr 1yRusXrazBajdyJ0Mp1CXIaOfICBOLSIpJpExteqBZcRJBSBd4usCBCO+EbdDAHc rr/DmhpFNqyvlFysg4ILQ5ua0yyqV3ViRpHK+CNODi11ZzkZ7B6ROrdBeRzYNgz8 sYMd0leFHWHCzfRYf/P6GipdeCr9fUw5GCGpm5KGQ+q9kejFj1WipFtesLcZPeiZ jopOuL787iuRxl/SvIj8 =kh9m -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20150702-v3' into staging Several s390x patches including: - missing virtio-1 related code for virtio-ccw - bugfixes in ipl device, gdb, virtio-ccw - bugfix in s390-ccw bios + rebuild - introduce versioned machines for s390-ccw-virtio # gpg: Signature made Thu Jul 2 15:05:34 2015 BST using RSA key ID C6F02FAF # gpg: Good signature from "Cornelia Huck <huckc@linux.vnet.ibm.com>" # gpg: aka "Cornelia Huck <cornelia.huck@de.ibm.com>" * remotes/cohuck/tags/s390x-20150702-v3: s390x/migration: Introduce 2.4 machine s390x/gdb: synchronize cpu state after modifying acrs s390x/ipl: Fix boot if no bootindex was specified virtio-ccw: migrate ->revision s390x/virtio-ccw: support virtio-1 set_vq format s390x/virtio-ccw: add virtio set-revision call s390x/css: Add a callback for when subchannel gets disabled s390-ccw.img: update s390-ccw.img: Consume service interrupts css: mss/mcss-e vs. migration virtio-ccw: complete handling of guest-initiated resets Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
5317b0f6d4
@ -588,6 +588,7 @@ int css_do_msch(SubchDev *sch, const SCHIB *orig_schib)
|
|||||||
{
|
{
|
||||||
SCSW *s = &sch->curr_status.scsw;
|
SCSW *s = &sch->curr_status.scsw;
|
||||||
PMCW *p = &sch->curr_status.pmcw;
|
PMCW *p = &sch->curr_status.pmcw;
|
||||||
|
uint16_t oldflags;
|
||||||
int ret;
|
int ret;
|
||||||
SCHIB schib;
|
SCHIB schib;
|
||||||
|
|
||||||
@ -610,6 +611,7 @@ int css_do_msch(SubchDev *sch, const SCHIB *orig_schib)
|
|||||||
copy_schib_from_guest(&schib, orig_schib);
|
copy_schib_from_guest(&schib, orig_schib);
|
||||||
/* Only update the program-modifiable fields. */
|
/* Only update the program-modifiable fields. */
|
||||||
p->intparm = schib.pmcw.intparm;
|
p->intparm = schib.pmcw.intparm;
|
||||||
|
oldflags = p->flags;
|
||||||
p->flags &= ~(PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA |
|
p->flags &= ~(PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA |
|
||||||
PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME |
|
PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME |
|
||||||
PMCW_FLAGS_MASK_MP);
|
PMCW_FLAGS_MASK_MP);
|
||||||
@ -625,6 +627,12 @@ int css_do_msch(SubchDev *sch, const SCHIB *orig_schib)
|
|||||||
(PMCW_CHARS_MASK_MBFC | PMCW_CHARS_MASK_CSENSE);
|
(PMCW_CHARS_MASK_MBFC | PMCW_CHARS_MASK_CSENSE);
|
||||||
sch->curr_status.mba = schib.mba;
|
sch->curr_status.mba = schib.mba;
|
||||||
|
|
||||||
|
/* Has the channel been disabled? */
|
||||||
|
if (sch->disable_cb && (oldflags & PMCW_FLAGS_MASK_ENA) != 0
|
||||||
|
&& (p->flags & PMCW_FLAGS_MASK_ENA) == 0) {
|
||||||
|
sch->disable_cb(sch);
|
||||||
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@ -1464,6 +1472,21 @@ int subch_device_load(SubchDev *s, QEMUFile *f)
|
|||||||
}
|
}
|
||||||
s->ccw_fmt_1 = qemu_get_byte(f);
|
s->ccw_fmt_1 = qemu_get_byte(f);
|
||||||
s->ccw_no_data_cnt = qemu_get_byte(f);
|
s->ccw_no_data_cnt = qemu_get_byte(f);
|
||||||
|
/*
|
||||||
|
* Hack alert. We don't migrate the channel subsystem status (no
|
||||||
|
* device!), but we need to find out if the guest enabled mss/mcss-e.
|
||||||
|
* If the subchannel is enabled, it certainly was able to access it,
|
||||||
|
* so adjust the max_ssid/max_cssid values for relevant ssid/cssid
|
||||||
|
* values. This is not watertight, but better than nothing.
|
||||||
|
*/
|
||||||
|
if (s->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ENA) {
|
||||||
|
if (s->ssid) {
|
||||||
|
channel_subsys->max_ssid = MAX_SSID;
|
||||||
|
}
|
||||||
|
if (s->cssid != channel_subsys->default_cssid) {
|
||||||
|
channel_subsys->max_cssid = MAX_CSSID;
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1483,6 +1506,10 @@ void css_reset_sch(SubchDev *sch)
|
|||||||
{
|
{
|
||||||
PMCW *p = &sch->curr_status.pmcw;
|
PMCW *p = &sch->curr_status.pmcw;
|
||||||
|
|
||||||
|
if ((p->flags & PMCW_FLAGS_MASK_ENA) != 0 && sch->disable_cb) {
|
||||||
|
sch->disable_cb(sch);
|
||||||
|
}
|
||||||
|
|
||||||
p->intparm = 0;
|
p->intparm = 0;
|
||||||
p->flags &= ~(PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA |
|
p->flags &= ~(PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA |
|
||||||
PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME |
|
PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME |
|
||||||
|
@ -81,6 +81,7 @@ struct SubchDev {
|
|||||||
uint8_t ccw_no_data_cnt;
|
uint8_t ccw_no_data_cnt;
|
||||||
/* transport-provided data: */
|
/* transport-provided data: */
|
||||||
int (*ccw_cb) (SubchDev *, CCW1);
|
int (*ccw_cb) (SubchDev *, CCW1);
|
||||||
|
void (*disable_cb)(SubchDev *);
|
||||||
SenseId id;
|
SenseId id;
|
||||||
void *driver_data;
|
void *driver_data;
|
||||||
};
|
};
|
||||||
|
@ -218,7 +218,7 @@ static Property s390_ipl_properties[] = {
|
|||||||
* - -1 if no valid boot device was found
|
* - -1 if no valid boot device was found
|
||||||
* - ccw id of the boot device otherwise
|
* - ccw id of the boot device otherwise
|
||||||
*/
|
*/
|
||||||
static uint32_t s390_update_iplstate(CPUS390XState *env, S390IPLState *ipl)
|
static uint64_t s390_update_iplstate(CPUS390XState *env, S390IPLState *ipl)
|
||||||
{
|
{
|
||||||
DeviceState *dev_st;
|
DeviceState *dev_st;
|
||||||
|
|
||||||
@ -248,7 +248,7 @@ static uint32_t s390_update_iplstate(CPUS390XState *env, S390IPLState *ipl)
|
|||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
out:
|
out:
|
||||||
return ipl->cssid << 24 | ipl->ssid << 16 | ipl->devno;
|
return (uint32_t) (ipl->cssid << 24 | ipl->ssid << 16 | ipl->devno);
|
||||||
}
|
}
|
||||||
|
|
||||||
int s390_ipl_update_diag308(IplParameterBlock *iplb)
|
int s390_ipl_update_diag308(IplParameterBlock *iplb)
|
||||||
|
@ -204,9 +204,6 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
|
|||||||
MachineClass *mc = MACHINE_CLASS(oc);
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
NMIClass *nc = NMI_CLASS(oc);
|
NMIClass *nc = NMI_CLASS(oc);
|
||||||
|
|
||||||
mc->name = "s390-ccw-virtio";
|
|
||||||
mc->alias = "s390-ccw";
|
|
||||||
mc->desc = "VirtIO-ccw based S390 machine";
|
|
||||||
mc->init = ccw_init;
|
mc->init = ccw_init;
|
||||||
mc->block_default_type = IF_VIRTIO;
|
mc->block_default_type = IF_VIRTIO;
|
||||||
mc->no_cdrom = 1;
|
mc->no_cdrom = 1;
|
||||||
@ -216,7 +213,6 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
|
|||||||
mc->no_sdcard = 1;
|
mc->no_sdcard = 1;
|
||||||
mc->use_sclp = 1;
|
mc->use_sclp = 1;
|
||||||
mc->max_cpus = 255;
|
mc->max_cpus = 255;
|
||||||
mc->is_default = 1;
|
|
||||||
nc->nmi_monitor_handler = s390_nmi;
|
nc->nmi_monitor_handler = s390_nmi;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,6 +268,7 @@ static inline void s390_machine_initfn(Object *obj)
|
|||||||
static const TypeInfo ccw_machine_info = {
|
static const TypeInfo ccw_machine_info = {
|
||||||
.name = TYPE_S390_CCW_MACHINE,
|
.name = TYPE_S390_CCW_MACHINE,
|
||||||
.parent = TYPE_MACHINE,
|
.parent = TYPE_MACHINE,
|
||||||
|
.abstract = true,
|
||||||
.instance_size = sizeof(S390CcwMachineState),
|
.instance_size = sizeof(S390CcwMachineState),
|
||||||
.instance_init = s390_machine_initfn,
|
.instance_init = s390_machine_initfn,
|
||||||
.class_init = ccw_machine_class_init,
|
.class_init = ccw_machine_class_init,
|
||||||
@ -281,9 +278,26 @@ static const TypeInfo ccw_machine_info = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void ccw_machine_2_4_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
|
|
||||||
|
mc->name = "s390-ccw-virtio-2.4";
|
||||||
|
mc->alias = "s390-ccw-virtio";
|
||||||
|
mc->desc = "VirtIO-ccw based S390 machine v2.4";
|
||||||
|
mc->is_default = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo ccw_machine_2_4_info = {
|
||||||
|
.name = TYPE_S390_CCW_MACHINE "2.4",
|
||||||
|
.parent = TYPE_S390_CCW_MACHINE,
|
||||||
|
.class_init = ccw_machine_2_4_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
static void ccw_machine_register_types(void)
|
static void ccw_machine_register_types(void)
|
||||||
{
|
{
|
||||||
type_register_static(&ccw_machine_info);
|
type_register_static(&ccw_machine_info);
|
||||||
|
type_register_static(&ccw_machine_2_4_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(ccw_machine_register_types)
|
type_init(ccw_machine_register_types)
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "hw/sysbus.h"
|
#include "hw/sysbus.h"
|
||||||
#include "qemu/bitops.h"
|
#include "qemu/bitops.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
|
#include "hw/virtio/virtio-access.h"
|
||||||
#include "hw/virtio/virtio-bus.h"
|
#include "hw/virtio/virtio-bus.h"
|
||||||
#include "hw/s390x/adapter.h"
|
#include "hw/s390x/adapter.h"
|
||||||
#include "hw/s390x/s390_flic.h"
|
#include "hw/s390x/s390_flic.h"
|
||||||
@ -237,11 +238,20 @@ VirtualCssBus *virtual_css_bus_init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Communication blocks used by several channel commands. */
|
/* Communication blocks used by several channel commands. */
|
||||||
typedef struct VqInfoBlock {
|
typedef struct VqInfoBlockLegacy {
|
||||||
uint64_t queue;
|
uint64_t queue;
|
||||||
uint32_t align;
|
uint32_t align;
|
||||||
uint16_t index;
|
uint16_t index;
|
||||||
uint16_t num;
|
uint16_t num;
|
||||||
|
} QEMU_PACKED VqInfoBlockLegacy;
|
||||||
|
|
||||||
|
typedef struct VqInfoBlock {
|
||||||
|
uint64_t desc;
|
||||||
|
uint32_t res0;
|
||||||
|
uint16_t index;
|
||||||
|
uint16_t num;
|
||||||
|
uint64_t avail;
|
||||||
|
uint64_t used;
|
||||||
} QEMU_PACKED VqInfoBlock;
|
} QEMU_PACKED VqInfoBlock;
|
||||||
|
|
||||||
typedef struct VqConfigBlock {
|
typedef struct VqConfigBlock {
|
||||||
@ -261,18 +271,27 @@ typedef struct VirtioThinintInfo {
|
|||||||
uint8_t isc;
|
uint8_t isc;
|
||||||
} QEMU_PACKED VirtioThinintInfo;
|
} QEMU_PACKED VirtioThinintInfo;
|
||||||
|
|
||||||
|
typedef struct VirtioRevInfo {
|
||||||
|
uint16_t revision;
|
||||||
|
uint16_t length;
|
||||||
|
uint8_t data[0];
|
||||||
|
} QEMU_PACKED VirtioRevInfo;
|
||||||
|
|
||||||
/* Specify where the virtqueues for the subchannel are in guest memory. */
|
/* Specify where the virtqueues for the subchannel are in guest memory. */
|
||||||
static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align,
|
static int virtio_ccw_set_vqs(SubchDev *sch, VqInfoBlock *info,
|
||||||
uint16_t index, uint16_t num)
|
VqInfoBlockLegacy *linfo)
|
||||||
{
|
{
|
||||||
VirtIODevice *vdev = virtio_ccw_get_vdev(sch);
|
VirtIODevice *vdev = virtio_ccw_get_vdev(sch);
|
||||||
|
uint16_t index = info ? info->index : linfo->index;
|
||||||
|
uint16_t num = info ? info->num : linfo->num;
|
||||||
|
uint64_t desc = info ? info->desc : linfo->queue;
|
||||||
|
|
||||||
if (index >= VIRTIO_CCW_QUEUE_MAX) {
|
if (index >= VIRTIO_CCW_QUEUE_MAX) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Current code in virtio.c relies on 4K alignment. */
|
/* Current code in virtio.c relies on 4K alignment. */
|
||||||
if (addr && (align != 4096)) {
|
if (linfo && desc && (linfo->align != 4096)) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,8 +299,12 @@ static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtio_queue_set_addr(vdev, index, addr);
|
if (info) {
|
||||||
if (!addr) {
|
virtio_queue_set_rings(vdev, index, desc, info->avail, info->used);
|
||||||
|
} else {
|
||||||
|
virtio_queue_set_addr(vdev, index, desc);
|
||||||
|
}
|
||||||
|
if (!desc) {
|
||||||
virtio_queue_set_vector(vdev, index, VIRTIO_NO_VECTOR);
|
virtio_queue_set_vector(vdev, index, VIRTIO_NO_VECTOR);
|
||||||
} else {
|
} else {
|
||||||
/* Fail if we don't have a big enough queue. */
|
/* Fail if we don't have a big enough queue. */
|
||||||
@ -296,10 +319,98 @@ static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
static void virtio_ccw_reset_virtio(VirtioCcwDevice *dev, VirtIODevice *vdev)
|
||||||
|
{
|
||||||
|
virtio_ccw_stop_ioeventfd(dev);
|
||||||
|
virtio_reset(vdev);
|
||||||
|
if (dev->indicators) {
|
||||||
|
release_indicator(&dev->routes.adapter, dev->indicators);
|
||||||
|
dev->indicators = NULL;
|
||||||
|
}
|
||||||
|
if (dev->indicators2) {
|
||||||
|
release_indicator(&dev->routes.adapter, dev->indicators2);
|
||||||
|
dev->indicators2 = NULL;
|
||||||
|
}
|
||||||
|
if (dev->summary_indicator) {
|
||||||
|
release_indicator(&dev->routes.adapter, dev->summary_indicator);
|
||||||
|
dev->summary_indicator = NULL;
|
||||||
|
}
|
||||||
|
dev->sch->thinint_active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int virtio_ccw_handle_set_vq(SubchDev *sch, CCW1 ccw, bool check_len,
|
||||||
|
bool is_legacy)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
VqInfoBlock info;
|
VqInfoBlock info;
|
||||||
|
VqInfoBlockLegacy linfo;
|
||||||
|
size_t info_len = is_legacy ? sizeof(linfo) : sizeof(info);
|
||||||
|
|
||||||
|
if (check_len) {
|
||||||
|
if (ccw.count != info_len) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
} else if (ccw.count < info_len) {
|
||||||
|
/* Can't execute command. */
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (!ccw.cda) {
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
if (is_legacy) {
|
||||||
|
linfo.queue = address_space_ldq_be(&address_space_memory, ccw.cda,
|
||||||
|
MEMTXATTRS_UNSPECIFIED, NULL);
|
||||||
|
linfo.align = address_space_ldl_be(&address_space_memory,
|
||||||
|
ccw.cda + sizeof(linfo.queue),
|
||||||
|
MEMTXATTRS_UNSPECIFIED,
|
||||||
|
NULL);
|
||||||
|
linfo.index = address_space_lduw_be(&address_space_memory,
|
||||||
|
ccw.cda + sizeof(linfo.queue)
|
||||||
|
+ sizeof(linfo.align),
|
||||||
|
MEMTXATTRS_UNSPECIFIED,
|
||||||
|
NULL);
|
||||||
|
linfo.num = address_space_lduw_be(&address_space_memory,
|
||||||
|
ccw.cda + sizeof(linfo.queue)
|
||||||
|
+ sizeof(linfo.align)
|
||||||
|
+ sizeof(linfo.index),
|
||||||
|
MEMTXATTRS_UNSPECIFIED,
|
||||||
|
NULL);
|
||||||
|
ret = virtio_ccw_set_vqs(sch, NULL, &linfo);
|
||||||
|
} else {
|
||||||
|
info.desc = address_space_ldq_be(&address_space_memory, ccw.cda,
|
||||||
|
MEMTXATTRS_UNSPECIFIED, NULL);
|
||||||
|
info.index = address_space_lduw_be(&address_space_memory,
|
||||||
|
ccw.cda + sizeof(info.desc)
|
||||||
|
+ sizeof(info.res0),
|
||||||
|
MEMTXATTRS_UNSPECIFIED, NULL);
|
||||||
|
info.num = address_space_lduw_be(&address_space_memory,
|
||||||
|
ccw.cda + sizeof(info.desc)
|
||||||
|
+ sizeof(info.res0)
|
||||||
|
+ sizeof(info.index),
|
||||||
|
MEMTXATTRS_UNSPECIFIED, NULL);
|
||||||
|
info.avail = address_space_ldq_be(&address_space_memory,
|
||||||
|
ccw.cda + sizeof(info.desc)
|
||||||
|
+ sizeof(info.res0)
|
||||||
|
+ sizeof(info.index)
|
||||||
|
+ sizeof(info.num),
|
||||||
|
MEMTXATTRS_UNSPECIFIED, NULL);
|
||||||
|
info.used = address_space_ldq_be(&address_space_memory,
|
||||||
|
ccw.cda + sizeof(info.desc)
|
||||||
|
+ sizeof(info.res0)
|
||||||
|
+ sizeof(info.index)
|
||||||
|
+ sizeof(info.num)
|
||||||
|
+ sizeof(info.avail),
|
||||||
|
MEMTXATTRS_UNSPECIFIED, NULL);
|
||||||
|
ret = virtio_ccw_set_vqs(sch, &info, NULL);
|
||||||
|
}
|
||||||
|
sch->curr_status.scsw.count = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
VirtioRevInfo revinfo;
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
VirtioFeatDesc features;
|
VirtioFeatDesc features;
|
||||||
void *config;
|
void *config;
|
||||||
@ -323,44 +434,10 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
|||||||
/* Look at the command. */
|
/* Look at the command. */
|
||||||
switch (ccw.cmd_code) {
|
switch (ccw.cmd_code) {
|
||||||
case CCW_CMD_SET_VQ:
|
case CCW_CMD_SET_VQ:
|
||||||
if (check_len) {
|
ret = virtio_ccw_handle_set_vq(sch, ccw, check_len, dev->revision < 1);
|
||||||
if (ccw.count != sizeof(info)) {
|
|
||||||
ret = -EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (ccw.count < sizeof(info)) {
|
|
||||||
/* Can't execute command. */
|
|
||||||
ret = -EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!ccw.cda) {
|
|
||||||
ret = -EFAULT;
|
|
||||||
} else {
|
|
||||||
info.queue = address_space_ldq(&address_space_memory, ccw.cda,
|
|
||||||
MEMTXATTRS_UNSPECIFIED, NULL);
|
|
||||||
info.align = address_space_ldl(&address_space_memory,
|
|
||||||
ccw.cda + sizeof(info.queue),
|
|
||||||
MEMTXATTRS_UNSPECIFIED,
|
|
||||||
NULL);
|
|
||||||
info.index = address_space_lduw(&address_space_memory,
|
|
||||||
ccw.cda + sizeof(info.queue)
|
|
||||||
+ sizeof(info.align),
|
|
||||||
MEMTXATTRS_UNSPECIFIED,
|
|
||||||
NULL);
|
|
||||||
info.num = address_space_lduw(&address_space_memory,
|
|
||||||
ccw.cda + sizeof(info.queue)
|
|
||||||
+ sizeof(info.align)
|
|
||||||
+ sizeof(info.index),
|
|
||||||
MEMTXATTRS_UNSPECIFIED,
|
|
||||||
NULL);
|
|
||||||
ret = virtio_ccw_set_vqs(sch, info.queue, info.align, info.index,
|
|
||||||
info.num);
|
|
||||||
sch->curr_status.scsw.count = 0;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case CCW_CMD_VDEV_RESET:
|
case CCW_CMD_VDEV_RESET:
|
||||||
virtio_ccw_stop_ioeventfd(dev);
|
virtio_ccw_reset_virtio(dev, vdev);
|
||||||
virtio_reset(vdev);
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
case CCW_CMD_READ_FEAT:
|
case CCW_CMD_READ_FEAT:
|
||||||
@ -383,7 +460,16 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
|||||||
MEMTXATTRS_UNSPECIFIED,
|
MEMTXATTRS_UNSPECIFIED,
|
||||||
NULL);
|
NULL);
|
||||||
if (features.index == 0) {
|
if (features.index == 0) {
|
||||||
features.features = vdev->host_features;
|
features.features = (uint32_t)vdev->host_features;
|
||||||
|
} else if (features.index == 1) {
|
||||||
|
features.features = (uint32_t)(vdev->host_features >> 32);
|
||||||
|
/*
|
||||||
|
* Don't offer version 1 to the guest if it did not
|
||||||
|
* negotiate at least revision 1.
|
||||||
|
*/
|
||||||
|
if (dev->revision <= 0) {
|
||||||
|
features.features &= ~(1 << (VIRTIO_F_VERSION_1 - 32));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Return zeroes if the guest supports more feature bits. */
|
/* Return zeroes if the guest supports more feature bits. */
|
||||||
features.features = 0;
|
features.features = 0;
|
||||||
@ -419,7 +505,20 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
|||||||
MEMTXATTRS_UNSPECIFIED,
|
MEMTXATTRS_UNSPECIFIED,
|
||||||
NULL);
|
NULL);
|
||||||
if (features.index == 0) {
|
if (features.index == 0) {
|
||||||
virtio_set_features(vdev, features.features);
|
virtio_set_features(vdev,
|
||||||
|
(vdev->guest_features & 0xffffffff00000000ULL) |
|
||||||
|
features.features);
|
||||||
|
} else if (features.index == 1) {
|
||||||
|
/*
|
||||||
|
* The guest should not set version 1 if it didn't
|
||||||
|
* negotiate a revision >= 1.
|
||||||
|
*/
|
||||||
|
if (dev->revision <= 0) {
|
||||||
|
features.features &= ~(1 << (VIRTIO_F_VERSION_1 - 32));
|
||||||
|
}
|
||||||
|
virtio_set_features(vdev,
|
||||||
|
(vdev->guest_features & 0x00000000ffffffffULL) |
|
||||||
|
((uint64_t)features.features << 32));
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* If the guest supports more feature bits, assert that it
|
* If the guest supports more feature bits, assert that it
|
||||||
@ -500,7 +599,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
|||||||
}
|
}
|
||||||
if (virtio_set_status(vdev, status) == 0) {
|
if (virtio_set_status(vdev, status) == 0) {
|
||||||
if (vdev->status == 0) {
|
if (vdev->status == 0) {
|
||||||
virtio_reset(vdev);
|
virtio_ccw_reset_virtio(dev, vdev);
|
||||||
}
|
}
|
||||||
if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
|
if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
|
||||||
virtio_ccw_start_ioeventfd(dev);
|
virtio_ccw_start_ioeventfd(dev);
|
||||||
@ -640,6 +739,40 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case CCW_CMD_SET_VIRTIO_REV:
|
||||||
|
len = sizeof(revinfo);
|
||||||
|
if (ccw.count < len) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!ccw.cda) {
|
||||||
|
ret = -EFAULT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
revinfo.revision =
|
||||||
|
address_space_lduw_be(&address_space_memory, ccw.cda,
|
||||||
|
MEMTXATTRS_UNSPECIFIED, NULL);
|
||||||
|
revinfo.length =
|
||||||
|
address_space_lduw_be(&address_space_memory,
|
||||||
|
ccw.cda + sizeof(revinfo.revision),
|
||||||
|
MEMTXATTRS_UNSPECIFIED, NULL);
|
||||||
|
if (ccw.count < len + revinfo.length ||
|
||||||
|
(check_len && ccw.count > len + revinfo.length)) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Once we start to support revisions with additional data, we'll
|
||||||
|
* need to fetch it here. Nothing to do for now, though.
|
||||||
|
*/
|
||||||
|
if (dev->revision >= 0 ||
|
||||||
|
revinfo.revision > virtio_ccw_rev_max(vdev)) {
|
||||||
|
ret = -ENOSYS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
dev->revision = revinfo.revision;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -ENOSYS;
|
ret = -ENOSYS;
|
||||||
break;
|
break;
|
||||||
@ -647,6 +780,13 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void virtio_sch_disable_cb(SubchDev *sch)
|
||||||
|
{
|
||||||
|
VirtioCcwDevice *dev = sch->driver_data;
|
||||||
|
|
||||||
|
dev->revision = -1;
|
||||||
|
}
|
||||||
|
|
||||||
static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
|
static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
|
||||||
{
|
{
|
||||||
unsigned int cssid = 0;
|
unsigned int cssid = 0;
|
||||||
@ -766,12 +906,15 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
|
|||||||
css_sch_build_virtual_schib(sch, 0, VIRTIO_CCW_CHPID_TYPE);
|
css_sch_build_virtual_schib(sch, 0, VIRTIO_CCW_CHPID_TYPE);
|
||||||
|
|
||||||
sch->ccw_cb = virtio_ccw_cb;
|
sch->ccw_cb = virtio_ccw_cb;
|
||||||
|
sch->disable_cb = virtio_sch_disable_cb;
|
||||||
|
|
||||||
/* Build senseid data. */
|
/* Build senseid data. */
|
||||||
memset(&sch->id, 0, sizeof(SenseId));
|
memset(&sch->id, 0, sizeof(SenseId));
|
||||||
sch->id.reserved = 0xff;
|
sch->id.reserved = 0xff;
|
||||||
sch->id.cu_type = VIRTIO_CCW_CU_TYPE;
|
sch->id.cu_type = VIRTIO_CCW_CU_TYPE;
|
||||||
|
|
||||||
|
dev->revision = -1;
|
||||||
|
|
||||||
if (k->realize) {
|
if (k->realize) {
|
||||||
k->realize(dev, &err);
|
k->realize(dev, &err);
|
||||||
}
|
}
|
||||||
@ -1081,21 +1224,8 @@ static void virtio_ccw_reset(DeviceState *d)
|
|||||||
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
|
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
|
||||||
VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
|
VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
|
||||||
|
|
||||||
virtio_ccw_stop_ioeventfd(dev);
|
virtio_ccw_reset_virtio(dev, vdev);
|
||||||
virtio_reset(vdev);
|
|
||||||
css_reset_sch(dev->sch);
|
css_reset_sch(dev->sch);
|
||||||
if (dev->indicators) {
|
|
||||||
release_indicator(&dev->routes.adapter, dev->indicators);
|
|
||||||
dev->indicators = NULL;
|
|
||||||
}
|
|
||||||
if (dev->indicators2) {
|
|
||||||
release_indicator(&dev->routes.adapter, dev->indicators2);
|
|
||||||
dev->indicators2 = NULL;
|
|
||||||
}
|
|
||||||
if (dev->summary_indicator) {
|
|
||||||
release_indicator(&dev->routes.adapter, dev->summary_indicator);
|
|
||||||
dev->summary_indicator = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtio_ccw_vmstate_change(DeviceState *d, bool running)
|
static void virtio_ccw_vmstate_change(DeviceState *d, bool running)
|
||||||
@ -1342,6 +1472,7 @@ static void virtio_ccw_save_config(DeviceState *d, QEMUFile *f)
|
|||||||
qemu_put_be16(f, vdev->config_vector);
|
qemu_put_be16(f, vdev->config_vector);
|
||||||
qemu_put_be64(f, dev->routes.adapter.ind_offset);
|
qemu_put_be64(f, dev->routes.adapter.ind_offset);
|
||||||
qemu_put_byte(f, dev->thinint_isc);
|
qemu_put_byte(f, dev->thinint_isc);
|
||||||
|
qemu_put_be32(f, dev->revision);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f)
|
static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f)
|
||||||
@ -1382,6 +1513,7 @@ static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f)
|
|||||||
dev->thinint_isc, true, false,
|
dev->thinint_isc, true, false,
|
||||||
&dev->routes.adapter.adapter_id);
|
&dev->routes.adapter.adapter_id);
|
||||||
}
|
}
|
||||||
|
dev->revision = qemu_get_be32(f);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
#define CCW_CMD_SET_CONF_IND 0x53
|
#define CCW_CMD_SET_CONF_IND 0x53
|
||||||
#define CCW_CMD_READ_VQ_CONF 0x32
|
#define CCW_CMD_READ_VQ_CONF 0x32
|
||||||
#define CCW_CMD_SET_IND_ADAPTER 0x73
|
#define CCW_CMD_SET_IND_ADAPTER 0x73
|
||||||
|
#define CCW_CMD_SET_VIRTIO_REV 0x83
|
||||||
|
|
||||||
#define TYPE_VIRTIO_CCW_DEVICE "virtio-ccw-device"
|
#define TYPE_VIRTIO_CCW_DEVICE "virtio-ccw-device"
|
||||||
#define VIRTIO_CCW_DEVICE(obj) \
|
#define VIRTIO_CCW_DEVICE(obj) \
|
||||||
@ -86,6 +87,7 @@ struct VirtioCcwDevice {
|
|||||||
DeviceState parent_obj;
|
DeviceState parent_obj;
|
||||||
SubchDev *sch;
|
SubchDev *sch;
|
||||||
char *bus_id;
|
char *bus_id;
|
||||||
|
int revision;
|
||||||
VirtioBusState bus;
|
VirtioBusState bus;
|
||||||
bool ioeventfd_started;
|
bool ioeventfd_started;
|
||||||
bool ioeventfd_disabled;
|
bool ioeventfd_disabled;
|
||||||
@ -99,6 +101,12 @@ struct VirtioCcwDevice {
|
|||||||
uint64_t ind_bit;
|
uint64_t ind_bit;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* The maximum virtio revision we support. */
|
||||||
|
static inline int virtio_ccw_rev_max(VirtIODevice *vdev)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* virtual css bus type */
|
/* virtual css bus type */
|
||||||
typedef struct VirtualCssBus {
|
typedef struct VirtualCssBus {
|
||||||
BusState parent_obj;
|
BusState parent_obj;
|
||||||
|
Binary file not shown.
@ -47,6 +47,7 @@ typedef unsigned long long __u64;
|
|||||||
|
|
||||||
/* start.s */
|
/* start.s */
|
||||||
void disabled_wait(void);
|
void disabled_wait(void);
|
||||||
|
void consume_sclp_int(void);
|
||||||
|
|
||||||
/* main.c */
|
/* main.c */
|
||||||
void virtio_panic(const char *string);
|
void virtio_panic(const char *string);
|
||||||
|
@ -24,6 +24,7 @@ static int sclp_service_call(unsigned int command, void *sccb)
|
|||||||
" srl %0,28"
|
" srl %0,28"
|
||||||
: "=&d" (cc) : "d" (command), "a" (__pa(sccb))
|
: "=&d" (cc) : "d" (command), "a" (__pa(sccb))
|
||||||
: "cc", "memory");
|
: "cc", "memory");
|
||||||
|
consume_sclp_int();
|
||||||
if (cc == 3)
|
if (cc == 3)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
if (cc == 2)
|
if (cc == 2)
|
||||||
|
@ -28,6 +28,38 @@ disabled_wait:
|
|||||||
larl %r1,disabled_wait_psw
|
larl %r1,disabled_wait_psw
|
||||||
lpswe 0(%r1)
|
lpswe 0(%r1)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* void consume_sclp_int(void)
|
||||||
|
*
|
||||||
|
* eats one sclp interrupt
|
||||||
|
*/
|
||||||
|
.globl consume_sclp_int
|
||||||
|
consume_sclp_int:
|
||||||
|
/* enable service interrupts in cr0 */
|
||||||
|
stctg 0,0,0(15)
|
||||||
|
oi 6(15), 0x2
|
||||||
|
lctlg 0,0,0(15)
|
||||||
|
/* prepare external call handler */
|
||||||
|
larl %r1, external_new_code
|
||||||
|
stg %r1, 0x1b8
|
||||||
|
larl %r1, external_new_mask
|
||||||
|
mvc 0x1b0(8),0(%r1)
|
||||||
|
/* load enabled wait PSW */
|
||||||
|
larl %r1, enabled_wait_psw
|
||||||
|
lpswe 0(%r1)
|
||||||
|
|
||||||
|
external_new_code:
|
||||||
|
/* disable service interrupts in cr0 */
|
||||||
|
stctg 0,0,0(15)
|
||||||
|
ni 6(15), 0xfd
|
||||||
|
lctlg 0,0,0(15)
|
||||||
|
br 14
|
||||||
|
|
||||||
.align 8
|
.align 8
|
||||||
disabled_wait_psw:
|
disabled_wait_psw:
|
||||||
.quad 0x0002000180000000,0x0000000000000000
|
.quad 0x0002000180000000,0x0000000000000000
|
||||||
|
enabled_wait_psw:
|
||||||
|
.quad 0x0302000180000000,0x0000000000000000
|
||||||
|
external_new_mask:
|
||||||
|
.quad 0x0000000180000000
|
||||||
|
@ -92,6 +92,7 @@ static int cpu_write_ac_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
|
|||||||
switch (n) {
|
switch (n) {
|
||||||
case S390_A0_REGNUM ... S390_A15_REGNUM:
|
case S390_A0_REGNUM ... S390_A15_REGNUM:
|
||||||
env->aregs[n] = ldl_p(mem_buf);
|
env->aregs[n] = ldl_p(mem_buf);
|
||||||
|
cpu_synchronize_post_init(ENV_GET_CPU(env));
|
||||||
return 4;
|
return 4;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user