提交 5317b0f6 编写于 作者: P Peter Maydell

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: NPeter Maydell <peter.maydell@linaro.org>
......@@ -588,6 +588,7 @@ int css_do_msch(SubchDev *sch, const SCHIB *orig_schib)
{
SCSW *s = &sch->curr_status.scsw;
PMCW *p = &sch->curr_status.pmcw;
uint16_t oldflags;
int ret;
SCHIB schib;
......@@ -610,6 +611,7 @@ int css_do_msch(SubchDev *sch, const SCHIB *orig_schib)
copy_schib_from_guest(&schib, orig_schib);
/* Only update the program-modifiable fields. */
p->intparm = schib.pmcw.intparm;
oldflags = p->flags;
p->flags &= ~(PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA |
PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME |
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);
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;
out:
......@@ -1464,6 +1472,21 @@ int subch_device_load(SubchDev *s, QEMUFile *f)
}
s->ccw_fmt_1 = 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;
}
......@@ -1483,6 +1506,10 @@ void css_reset_sch(SubchDev *sch)
{
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->flags &= ~(PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA |
PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME |
......
......@@ -81,6 +81,7 @@ struct SubchDev {
uint8_t ccw_no_data_cnt;
/* transport-provided data: */
int (*ccw_cb) (SubchDev *, CCW1);
void (*disable_cb)(SubchDev *);
SenseId id;
void *driver_data;
};
......
......@@ -218,7 +218,7 @@ static Property s390_ipl_properties[] = {
* - -1 if no valid boot device was found
* - 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;
......@@ -248,7 +248,7 @@ static uint32_t s390_update_iplstate(CPUS390XState *env, S390IPLState *ipl)
return -1;
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)
......
......@@ -204,9 +204,6 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
MachineClass *mc = MACHINE_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->block_default_type = IF_VIRTIO;
mc->no_cdrom = 1;
......@@ -216,7 +213,6 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
mc->no_sdcard = 1;
mc->use_sclp = 1;
mc->max_cpus = 255;
mc->is_default = 1;
nc->nmi_monitor_handler = s390_nmi;
}
......@@ -272,6 +268,7 @@ static inline void s390_machine_initfn(Object *obj)
static const TypeInfo ccw_machine_info = {
.name = TYPE_S390_CCW_MACHINE,
.parent = TYPE_MACHINE,
.abstract = true,
.instance_size = sizeof(S390CcwMachineState),
.instance_init = s390_machine_initfn,
.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)
{
type_register_static(&ccw_machine_info);
type_register_static(&ccw_machine_2_4_info);
}
type_init(ccw_machine_register_types)
......@@ -21,6 +21,7 @@
#include "hw/sysbus.h"
#include "qemu/bitops.h"
#include "qemu/error-report.h"
#include "hw/virtio/virtio-access.h"
#include "hw/virtio/virtio-bus.h"
#include "hw/s390x/adapter.h"
#include "hw/s390x/s390_flic.h"
......@@ -237,11 +238,20 @@ VirtualCssBus *virtual_css_bus_init(void)
}
/* Communication blocks used by several channel commands. */
typedef struct VqInfoBlock {
typedef struct VqInfoBlockLegacy {
uint64_t queue;
uint32_t align;
uint16_t index;
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;
typedef struct VqConfigBlock {
......@@ -261,18 +271,27 @@ typedef struct VirtioThinintInfo {
uint8_t isc;
} 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. */
static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align,
uint16_t index, uint16_t num)
static int virtio_ccw_set_vqs(SubchDev *sch, VqInfoBlock *info,
VqInfoBlockLegacy *linfo)
{
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) {
return -EINVAL;
}
/* Current code in virtio.c relies on 4K alignment. */
if (addr && (align != 4096)) {
if (linfo && desc && (linfo->align != 4096)) {
return -EINVAL;
}
......@@ -280,8 +299,12 @@ static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align,
return -EINVAL;
}
virtio_queue_set_addr(vdev, index, addr);
if (!addr) {
if (info) {
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);
} else {
/* 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;
}
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;
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;
VirtioFeatDesc features;
void *config;
......@@ -323,44 +434,10 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
/* Look at the command. */
switch (ccw.cmd_code) {
case CCW_CMD_SET_VQ:
if (check_len) {
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;
}
ret = virtio_ccw_handle_set_vq(sch, ccw, check_len, dev->revision < 1);
break;
case CCW_CMD_VDEV_RESET:
virtio_ccw_stop_ioeventfd(dev);
virtio_reset(vdev);
virtio_ccw_reset_virtio(dev, vdev);
ret = 0;
break;
case CCW_CMD_READ_FEAT:
......@@ -383,7 +460,16 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
MEMTXATTRS_UNSPECIFIED,
NULL);
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 {
/* Return zeroes if the guest supports more feature bits. */
features.features = 0;
......@@ -419,7 +505,20 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
MEMTXATTRS_UNSPECIFIED,
NULL);
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 {
/*
* 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 (vdev->status == 0) {
virtio_reset(vdev);
virtio_ccw_reset_virtio(dev, vdev);
}
if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
virtio_ccw_start_ioeventfd(dev);
......@@ -640,6 +739,40 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
}
}
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:
ret = -ENOSYS;
break;
......@@ -647,6 +780,13 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
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)
{
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);
sch->ccw_cb = virtio_ccw_cb;
sch->disable_cb = virtio_sch_disable_cb;
/* Build senseid data. */
memset(&sch->id, 0, sizeof(SenseId));
sch->id.reserved = 0xff;
sch->id.cu_type = VIRTIO_CCW_CU_TYPE;
dev->revision = -1;
if (k->realize) {
k->realize(dev, &err);
}
......@@ -1081,21 +1224,8 @@ static void virtio_ccw_reset(DeviceState *d)
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
virtio_ccw_stop_ioeventfd(dev);
virtio_reset(vdev);
virtio_ccw_reset_virtio(dev, vdev);
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)
......@@ -1342,6 +1472,7 @@ static void virtio_ccw_save_config(DeviceState *d, QEMUFile *f)
qemu_put_be16(f, vdev->config_vector);
qemu_put_be64(f, dev->routes.adapter.ind_offset);
qemu_put_byte(f, dev->thinint_isc);
qemu_put_be32(f, dev->revision);
}
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->routes.adapter.adapter_id);
}
dev->revision = qemu_get_be32(f);
return 0;
}
......
......@@ -41,6 +41,7 @@
#define CCW_CMD_SET_CONF_IND 0x53
#define CCW_CMD_READ_VQ_CONF 0x32
#define CCW_CMD_SET_IND_ADAPTER 0x73
#define CCW_CMD_SET_VIRTIO_REV 0x83
#define TYPE_VIRTIO_CCW_DEVICE "virtio-ccw-device"
#define VIRTIO_CCW_DEVICE(obj) \
......@@ -86,6 +87,7 @@ struct VirtioCcwDevice {
DeviceState parent_obj;
SubchDev *sch;
char *bus_id;
int revision;
VirtioBusState bus;
bool ioeventfd_started;
bool ioeventfd_disabled;
......@@ -99,6 +101,12 @@ struct VirtioCcwDevice {
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 */
typedef struct VirtualCssBus {
BusState parent_obj;
......
......@@ -47,6 +47,7 @@ typedef unsigned long long __u64;
/* start.s */
void disabled_wait(void);
void consume_sclp_int(void);
/* main.c */
void virtio_panic(const char *string);
......
......@@ -24,6 +24,7 @@ static int sclp_service_call(unsigned int command, void *sccb)
" srl %0,28"
: "=&d" (cc) : "d" (command), "a" (__pa(sccb))
: "cc", "memory");
consume_sclp_int();
if (cc == 3)
return -EIO;
if (cc == 2)
......
......@@ -28,6 +28,38 @@ disabled_wait:
larl %r1,disabled_wait_psw
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
disabled_wait_psw:
.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) {
case S390_A0_REGNUM ... S390_A15_REGNUM:
env->aregs[n] = ldl_p(mem_buf);
cpu_synchronize_post_init(ENV_GET_CPU(env));
return 4;
default:
return 0;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册