aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/intc/s390_flic.c8
-rw-r--r--hw/intc/s390_flic_kvm.c26
-rw-r--r--hw/s390x/css.c124
-rw-r--r--hw/s390x/s390-virtio-ccw.c2
-rw-r--r--hw/s390x/virtio-ccw.c80
-rw-r--r--hw/s390x/virtio-ccw.h2
6 files changed, 190 insertions, 52 deletions
diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c
index bc75fa7d95..6ab29efc65 100644
--- a/hw/intc/s390_flic.c
+++ b/hw/intc/s390_flic.c
@@ -67,6 +67,13 @@ static void qemu_s390_release_adapter_routes(S390FLICState *fs,
{
}
+static int qemu_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id,
+ uint16_t subchannel_nr)
+{
+ /* Fixme TCG */
+ return -ENOSYS;
+}
+
static void qemu_s390_flic_class_init(ObjectClass *oc, void *data)
{
S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
@@ -75,6 +82,7 @@ static void qemu_s390_flic_class_init(ObjectClass *oc, void *data)
fsc->io_adapter_map = qemu_s390_io_adapter_map;
fsc->add_adapter_routes = qemu_s390_add_adapter_routes;
fsc->release_adapter_routes = qemu_s390_release_adapter_routes;
+ fsc->clear_io_irq = qemu_s390_clear_io_flic;
}
static const TypeInfo qemu_s390_flic_info = {
diff --git a/hw/intc/s390_flic_kvm.c b/hw/intc/s390_flic_kvm.c
index eed6325cde..680857f0c7 100644
--- a/hw/intc/s390_flic_kvm.c
+++ b/hw/intc/s390_flic_kvm.c
@@ -30,6 +30,7 @@ typedef struct KVMS390FLICState {
S390FLICState parent_obj;
uint32_t fd;
+ bool clear_io_supported;
} KVMS390FLICState;
DeviceState *s390_flic_kvm_create(void)
@@ -130,6 +131,24 @@ int kvm_s390_inject_flic(struct kvm_s390_irq *irq)
return flic_enqueue_irqs(irq, sizeof(*irq), flic);
}
+static int kvm_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id,
+ uint16_t subchannel_nr)
+{
+ KVMS390FLICState *flic = KVM_S390_FLIC(fs);
+ int rc;
+ uint32_t sid = subchannel_id << 16 | subchannel_nr;
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_FLIC_CLEAR_IO_IRQ,
+ .addr = (uint64_t) &sid,
+ .attr = sizeof(sid),
+ };
+ if (unlikely(!flic->clear_io_supported)) {
+ return -ENOSYS;
+ }
+ rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
+ return rc ? -errno : 0;
+}
+
/**
* __get_all_irqs - store all pending irqs in buffer
* @flic: pointer to flic device state
@@ -358,6 +377,7 @@ static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
{
KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
struct kvm_create_device cd = {0};
+ struct kvm_device_attr test_attr = {0};
int ret;
flic_state->fd = -1;
@@ -374,6 +394,11 @@ static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
}
flic_state->fd = cd.fd;
+ /* Check clear_io_irq support */
+ test_attr.group = KVM_DEV_FLIC_CLEAR_IO_IRQ;
+ flic_state->clear_io_supported = !ioctl(flic_state->fd,
+ KVM_HAS_DEVICE_ATTR, test_attr);
+
/* Register savevm handler for floating interrupts */
register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save,
kvm_flic_load, (void *) flic_state);
@@ -420,6 +445,7 @@ static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
fsc->io_adapter_map = kvm_s390_io_adapter_map;
fsc->add_adapter_routes = kvm_s390_add_adapter_routes;
fsc->release_adapter_routes = kvm_s390_release_adapter_routes;
+ fsc->clear_io_irq = kvm_s390_clear_io_flic;
}
static const TypeInfo kvm_s390_flic_info = {
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index 1675a19ac2..76668814da 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -10,6 +10,8 @@
*/
#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qapi/visitor.h"
#include <hw/qdev.h>
#include "qemu/bitops.h"
#include "exec/address-spaces.h"
@@ -192,12 +194,46 @@ out:
return ret;
}
-uint16_t css_build_subchannel_id(SubchDev *sch)
+static void css_clear_io_interrupt(uint16_t subchannel_id,
+ uint16_t subchannel_nr)
+{
+ Error *err = NULL;
+ static bool no_clear_irq;
+ S390FLICState *fs = s390_get_flic();
+ S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
+ int r;
+
+ if (unlikely(no_clear_irq)) {
+ return;
+ }
+ r = fsc->clear_io_irq(fs, subchannel_id, subchannel_nr);
+ switch (r) {
+ case 0:
+ break;
+ case -ENOSYS:
+ no_clear_irq = true;
+ /*
+ * Ignore unavailability, as the user can't do anything
+ * about it anyway.
+ */
+ break;
+ default:
+ error_setg_errno(&err, -r, "unexpected error condition");
+ error_propagate(&error_abort, err);
+ }
+}
+
+static inline uint16_t css_do_build_subchannel_id(uint8_t cssid, uint8_t ssid)
{
if (channel_subsys.max_cssid > 0) {
- return (sch->cssid << 8) | (1 << 3) | (sch->ssid << 1) | 1;
+ return (cssid << 8) | (1 << 3) | (ssid << 1) | 1;
}
- return (sch->ssid << 1) | 1;
+ return (ssid << 1) | 1;
+}
+
+uint16_t css_build_subchannel_id(SubchDev *sch)
+{
+ return css_do_build_subchannel_id(sch->cssid, sch->ssid);
}
static void css_inject_io_interrupt(SubchDev *sch)
@@ -1429,6 +1465,8 @@ void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid,
css_queue_crw(CRW_RSC_SUBCH, CRW_ERC_IPI, 0,
(guest_cssid << 8) | (ssid << 4));
}
+ /* RW_ERC_IPI --> clear pending interrupts */
+ css_clear_io_interrupt(css_do_build_subchannel_id(cssid, ssid), schid);
}
void css_generate_chp_crws(uint8_t cssid, uint8_t chpid)
@@ -1644,3 +1682,83 @@ void css_reset(void)
channel_subsys.max_cssid = 0;
channel_subsys.max_ssid = 0;
}
+
+static void get_css_devid(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ CssDevId *dev_id = qdev_get_prop_ptr(dev, prop);
+ char buffer[] = "xx.x.xxxx";
+ char *p = buffer;
+ int r;
+
+ if (dev_id->valid) {
+
+ r = snprintf(buffer, sizeof(buffer), "%02x.%1x.%04x", dev_id->cssid,
+ dev_id->ssid, dev_id->devid);
+ assert(r == sizeof(buffer) - 1);
+
+ /* drop leading zero */
+ if (dev_id->cssid <= 0xf) {
+ p++;
+ }
+ } else {
+ snprintf(buffer, sizeof(buffer), "<unset>");
+ }
+
+ visit_type_str(v, name, &p, errp);
+}
+
+/*
+ * parse <cssid>.<ssid>.<devid> and assert valid range for cssid/ssid
+ */
+static void set_css_devid(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ CssDevId *dev_id = qdev_get_prop_ptr(dev, prop);
+ Error *local_err = NULL;
+ char *str;
+ int num, n1, n2;
+ unsigned int cssid, ssid, devid;
+
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
+ return;
+ }
+
+ visit_type_str(v, name, &str, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ num = sscanf(str, "%2x.%1x%n.%4x%n", &cssid, &ssid, &n1, &devid, &n2);
+ if (num != 3 || (n2 - n1) != 5 || strlen(str) != n2) {
+ error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
+ goto out;
+ }
+ if ((cssid > MAX_CSSID) || (ssid > MAX_SSID)) {
+ error_setg(errp, "Invalid cssid or ssid: cssid %x, ssid %x",
+ cssid, ssid);
+ goto out;
+ }
+
+ dev_id->cssid = cssid;
+ dev_id->ssid = ssid;
+ dev_id->devid = devid;
+ dev_id->valid = true;
+
+out:
+ g_free(str);
+}
+
+PropertyInfo css_devid_propinfo = {
+ .name = "str",
+ .description = "Identifier of an I/O device in the channel "
+ "subsystem, example: fe.1.23ab",
+ .get = get_css_devid,
+ .set = set_css_devid,
+};
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 95ff5e35ae..e257ca5ab0 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -204,7 +204,7 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
mc->no_parallel = 1;
mc->no_sdcard = 1;
mc->use_sclp = 1;
- mc->max_cpus = 255;
+ mc->max_cpus = 248;
mc->get_hotplug_handler = s390_get_hotplug_handler;
hc->plug = s390_machine_device_plug;
nc->nmi_monitor_handler = s390_nmi;
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index 2b68e5e87d..2192be8774 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -737,14 +737,9 @@ static void virtio_sch_disable_cb(SubchDev *sch)
static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
{
- unsigned int cssid = 0;
- unsigned int ssid = 0;
unsigned int schid;
- unsigned int devno;
- bool have_devno = false;
bool found = false;
SubchDev *sch;
- int num;
Error *err = NULL;
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_GET_CLASS(dev);
@@ -763,54 +758,44 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
* Use a device number if provided. Otherwise, fall back to subchannel
* number.
*/
- if (dev->bus_id) {
- num = sscanf(dev->bus_id, "%x.%x.%04x", &cssid, &ssid, &devno);
- if (num == 3) {
- if ((cssid > MAX_CSSID) || (ssid > MAX_SSID)) {
- error_setg(errp, "Invalid cssid or ssid: cssid %x, ssid %x",
- cssid, ssid);
- goto out_err;
- }
- /* Enforce use of virtual cssid. */
- if (cssid != VIRTUAL_CSSID) {
- error_setg(errp, "cssid %x not valid for virtio devices",
- cssid);
- goto out_err;
- }
- if (css_devno_used(cssid, ssid, devno)) {
+ if (dev->bus_id.valid) {
+ /* Enforce use of virtual cssid. */
+ if (dev->bus_id.cssid != VIRTUAL_CSSID) {
+ error_setg(errp, "cssid %x not valid for virtio devices",
+ dev->bus_id.cssid);
+ goto out_err;
+ }
+ if (css_devno_used(dev->bus_id.cssid, dev->bus_id.ssid,
+ dev->bus_id.devid)) {
error_setg(errp, "Device %x.%x.%04x already exists",
- cssid, ssid, devno);
+ dev->bus_id.cssid, dev->bus_id.ssid,
+ dev->bus_id.devid);
goto out_err;
- }
- sch->cssid = cssid;
- sch->ssid = ssid;
- sch->devno = devno;
- have_devno = true;
- } else {
- error_setg(errp, "Malformed devno parameter '%s'", dev->bus_id);
- goto out_err;
}
- }
+ sch->cssid = dev->bus_id.cssid;
+ sch->ssid = dev->bus_id.ssid;
+ sch->devno = dev->bus_id.devid;
- /* Find the next free id. */
- if (have_devno) {
+ /* Find the next free id. */
for (schid = 0; schid <= MAX_SCHID; schid++) {
- if (!css_find_subch(1, cssid, ssid, schid)) {
+ if (!css_find_subch(1, sch->cssid, sch->ssid, schid)) {
sch->schid = schid;
- css_subch_assign(cssid, ssid, schid, devno, sch);
+ css_subch_assign(sch->cssid, sch->ssid, sch->schid,
+ sch->devno, sch);
found = true;
break;
}
}
if (!found) {
error_setg(errp, "No free subchannel found for %x.%x.%04x",
- cssid, ssid, devno);
+ sch->cssid, sch->ssid, sch->devno);
goto out_err;
}
- trace_virtio_ccw_new_device(cssid, ssid, schid, devno,
- "user-configured");
+ trace_virtio_ccw_new_device(sch->cssid, sch->ssid, sch->schid,
+ sch->devno, "user-configured");
} else {
- cssid = VIRTUAL_CSSID;
+ unsigned int cssid = VIRTUAL_CSSID, ssid, devno;
+
for (ssid = 0; ssid <= MAX_SSID; ssid++) {
for (schid = 0; schid <= MAX_SCHID; schid++) {
if (!css_find_subch(1, cssid, ssid, schid)) {
@@ -868,7 +853,7 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
}
if (err) {
error_propagate(errp, err);
- css_subch_assign(cssid, ssid, schid, devno, NULL);
+ css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
goto out_err;
}
@@ -1106,6 +1091,7 @@ static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc,
ind_old = *ind_addr;
ind_new = ind_old | to_be_set;
} while (atomic_cmpxchg(ind_addr, ind_old, ind_new) != ind_old);
+ trace_virtio_ccw_set_ind(ind_loc, ind_old, ind_new);
cpu_physical_memory_unmap(ind_addr, len, 1, len);
return ind_old;
@@ -1516,7 +1502,7 @@ static void virtio_ccw_device_unplugged(DeviceState *d)
/**************** Virtio-ccw Bus Device Descriptions *******************/
static Property virtio_ccw_net_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
+ DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1545,7 +1531,7 @@ static const TypeInfo virtio_ccw_net = {
};
static Property virtio_ccw_blk_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
+ DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1574,7 +1560,7 @@ static const TypeInfo virtio_ccw_blk = {
};
static Property virtio_ccw_serial_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
+ DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1603,7 +1589,7 @@ static const TypeInfo virtio_ccw_serial = {
};
static Property virtio_ccw_balloon_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
+ DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1632,7 +1618,7 @@ static const TypeInfo virtio_ccw_balloon = {
};
static Property virtio_ccw_scsi_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
+ DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1662,7 +1648,7 @@ static const TypeInfo virtio_ccw_scsi = {
#ifdef CONFIG_VHOST_SCSI
static Property vhost_ccw_scsi_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
+ DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
VIRTIO_CCW_MAX_REV),
DEFINE_PROP_END_OF_LIST(),
@@ -1700,7 +1686,7 @@ static void virtio_ccw_rng_instance_init(Object *obj)
}
static Property virtio_ccw_rng_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
+ DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1856,7 +1842,7 @@ static const TypeInfo virtio_ccw_bus_info = {
#ifdef CONFIG_VIRTFS
static Property virtio_ccw_9p_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
+ DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h
index 86b9edb18f..0bfb5d93c6 100644
--- a/hw/s390x/virtio-ccw.h
+++ b/hw/s390x/virtio-ccw.h
@@ -80,7 +80,7 @@ typedef struct VirtIOCCWDeviceClass {
struct VirtioCcwDevice {
DeviceState parent_obj;
SubchDev *sch;
- char *bus_id;
+ CssDevId bus_id;
int revision;
uint32_t max_rev;
VirtioBusState bus;