aboutsummaryrefslogtreecommitdiff
path: root/hw/s390x/css.c
diff options
context:
space:
mode:
authorCornelia Huck <cornelia.huck@de.ibm.com>2016-04-01 13:42:04 +0200
committerCornelia Huck <cornelia.huck@de.ibm.com>2016-06-14 13:34:50 +0200
commit06e686eaab344b1d38125e49abeb31a416428201 (patch)
tree1e90fe3dfbe9956b46698b8dc4ae56984454785f /hw/s390x/css.c
parentc1755b14fade16f02d3e10a487a03741a2f317ce (diff)
s390x/css: introduce property type for device ids
Let's introduce a CssDevId to handle device ids of the xx.x.xxxx type used for channel devices. This has some benefits: - We can use them in virtio-ccw and split the validity checks for a channel device id in general from the constraint checking within the virtio-ccw scope. - We can reuse the device id type for future non-virtio channel devices. While we're at it, improve the validity checks and disallow e.g. trailing characters. Suggested-by: Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com> Acked-by: David Hildenbrand <dahi@linux.vnet.ibm.com> Reviewed-by: Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Diffstat (limited to 'hw/s390x/css.c')
-rw-r--r--hw/s390x/css.c81
1 files changed, 81 insertions, 0 deletions
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index aceb1c0ee1..76668814da 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -11,6 +11,7 @@
#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"
@@ -1681,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,
+};