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>
This commit is contained in:
parent
c1755b14fa
commit
06e686eaab
@ -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,
|
||||
};
|
||||
|
@ -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)) {
|
||||
error_setg(errp, "Device %x.%x.%04x already exists",
|
||||
cssid, ssid, devno);
|
||||
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);
|
||||
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",
|
||||
dev->bus_id.cssid, dev->bus_id.ssid,
|
||||
dev->bus_id.devid);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1516,7 +1501,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 +1530,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 +1559,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 +1588,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 +1617,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 +1647,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 +1685,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 +1841,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,
|
||||
|
@ -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;
|
||||
|
@ -151,5 +151,22 @@ int css_do_rsch(SubchDev *sch);
|
||||
int css_do_rchp(uint8_t cssid, uint8_t chpid);
|
||||
bool css_present(uint8_t cssid);
|
||||
#endif
|
||||
/*
|
||||
* Identify a device within the channel subsystem.
|
||||
* Note that this can be used to identify either the subchannel or
|
||||
* the attached I/O device, as there's always one I/O device per
|
||||
* subchannel.
|
||||
*/
|
||||
typedef struct CssDevId {
|
||||
uint8_t cssid;
|
||||
uint8_t ssid;
|
||||
uint16_t devid;
|
||||
bool valid;
|
||||
} CssDevId;
|
||||
|
||||
extern PropertyInfo css_devid_propinfo;
|
||||
|
||||
#define DEFINE_PROP_CSS_DEV_ID(_n, _s, _f) \
|
||||
DEFINE_PROP(_n, _s, _f, css_devid_propinfo, CssDevId)
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user