hw/core/qdev-properties: Extract system-mode specific properties
[qemu/ar7.git] / hw / core / qdev-properties-system.c
blob49bdd125814f9d30248015a3bbc54eb7631ad315
1 /*
2 * qdev property parsing
3 * (parts specific for qemu-system-*)
5 * This file is based on code from hw/qdev-properties.c from
6 * commit 074a86fccd185616469dfcdc0e157f438aebba18,
7 * Copyright (c) Gerd Hoffmann <kraxel@redhat.com> and other contributors.
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
13 #include "qemu/osdep.h"
14 #include "hw/qdev-properties.h"
15 #include "qapi/error.h"
16 #include "qapi/visitor.h"
17 #include "qapi/qapi-types-block.h"
18 #include "qapi/qapi-types-machine.h"
19 #include "qapi/qapi-types-migration.h"
20 #include "qapi/qmp/qerror.h"
21 #include "qemu/ctype.h"
22 #include "qemu/cutils.h"
23 #include "qemu/units.h"
24 #include "qemu/error-report.h"
25 #include "qdev-prop-internal.h"
27 #include "audio/audio.h"
28 #include "chardev/char-fe.h"
29 #include "sysemu/block-backend.h"
30 #include "sysemu/blockdev.h"
31 #include "net/net.h"
32 #include "hw/pci/pci.h"
34 static bool check_prop_still_unset(DeviceState *dev, const char *name,
35 const void *old_val, const char *new_val,
36 Error **errp)
38 const GlobalProperty *prop = qdev_find_global_prop(dev, name);
40 if (!old_val) {
41 return true;
44 if (prop) {
45 error_setg(errp, "-global %s.%s=... conflicts with %s=%s",
46 prop->driver, prop->property, name, new_val);
47 } else {
48 /* Error message is vague, but a better one would be hard */
49 error_setg(errp, "%s=%s conflicts, and override is not implemented",
50 name, new_val);
52 return false;
56 /* --- drive --- */
58 static void get_drive(Object *obj, Visitor *v, const char *name, void *opaque,
59 Error **errp)
61 DeviceState *dev = DEVICE(obj);
62 Property *prop = opaque;
63 void **ptr = qdev_get_prop_ptr(dev, prop);
64 const char *value;
65 char *p;
67 if (*ptr) {
68 value = blk_name(*ptr);
69 if (!*value) {
70 BlockDriverState *bs = blk_bs(*ptr);
71 if (bs) {
72 value = bdrv_get_node_name(bs);
75 } else {
76 value = "";
79 p = g_strdup(value);
80 visit_type_str(v, name, &p, errp);
81 g_free(p);
84 static void set_drive_helper(Object *obj, Visitor *v, const char *name,
85 void *opaque, bool iothread, Error **errp)
87 DeviceState *dev = DEVICE(obj);
88 Property *prop = opaque;
89 void **ptr = qdev_get_prop_ptr(dev, prop);
90 char *str;
91 BlockBackend *blk;
92 bool blk_created = false;
93 int ret;
95 if (dev->realized) {
96 qdev_prop_set_after_realize(dev, name, errp);
97 return;
100 if (!visit_type_str(v, name, &str, errp)) {
101 return;
105 * TODO Should this really be an error? If no, the old value
106 * needs to be released before we store the new one.
108 if (!check_prop_still_unset(dev, name, *ptr, str, errp)) {
109 return;
112 if (!*str) {
113 g_free(str);
114 *ptr = NULL;
115 return;
118 blk = blk_by_name(str);
119 if (!blk) {
120 BlockDriverState *bs = bdrv_lookup_bs(NULL, str, NULL);
121 if (bs) {
123 * If the device supports iothreads, it will make sure to move the
124 * block node to the right AioContext if necessary (or fail if this
125 * isn't possible because of other users). Devices that are not
126 * aware of iothreads require their BlockBackends to be in the main
127 * AioContext.
129 AioContext *ctx = iothread ? bdrv_get_aio_context(bs) :
130 qemu_get_aio_context();
131 blk = blk_new(ctx, 0, BLK_PERM_ALL);
132 blk_created = true;
134 ret = blk_insert_bs(blk, bs, errp);
135 if (ret < 0) {
136 goto fail;
140 if (!blk) {
141 error_setg(errp, "Property '%s.%s' can't find value '%s'",
142 object_get_typename(OBJECT(dev)), prop->name, str);
143 goto fail;
145 if (blk_attach_dev(blk, dev) < 0) {
146 DriveInfo *dinfo = blk_legacy_dinfo(blk);
148 if (dinfo && dinfo->type != IF_NONE) {
149 error_setg(errp, "Drive '%s' is already in use because "
150 "it has been automatically connected to another "
151 "device (did you need 'if=none' in the drive options?)",
152 str);
153 } else {
154 error_setg(errp, "Drive '%s' is already in use by another device",
155 str);
157 goto fail;
160 *ptr = blk;
162 fail:
163 if (blk_created) {
164 /* If we need to keep a reference, blk_attach_dev() took it */
165 blk_unref(blk);
168 g_free(str);
171 static void set_drive(Object *obj, Visitor *v, const char *name, void *opaque,
172 Error **errp)
174 set_drive_helper(obj, v, name, opaque, false, errp);
177 static void set_drive_iothread(Object *obj, Visitor *v, const char *name,
178 void *opaque, Error **errp)
180 set_drive_helper(obj, v, name, opaque, true, errp);
183 static void release_drive(Object *obj, const char *name, void *opaque)
185 DeviceState *dev = DEVICE(obj);
186 Property *prop = opaque;
187 BlockBackend **ptr = qdev_get_prop_ptr(dev, prop);
189 if (*ptr) {
190 AioContext *ctx = blk_get_aio_context(*ptr);
192 aio_context_acquire(ctx);
193 blockdev_auto_del(*ptr);
194 blk_detach_dev(*ptr, dev);
195 aio_context_release(ctx);
199 const PropertyInfo qdev_prop_drive = {
200 .name = "str",
201 .description = "Node name or ID of a block device to use as a backend",
202 .get = get_drive,
203 .set = set_drive,
204 .release = release_drive,
207 const PropertyInfo qdev_prop_drive_iothread = {
208 .name = "str",
209 .description = "Node name or ID of a block device to use as a backend",
210 .get = get_drive,
211 .set = set_drive_iothread,
212 .release = release_drive,
215 /* --- character device --- */
217 static void get_chr(Object *obj, Visitor *v, const char *name, void *opaque,
218 Error **errp)
220 DeviceState *dev = DEVICE(obj);
221 CharBackend *be = qdev_get_prop_ptr(dev, opaque);
222 char *p;
224 p = g_strdup(be->chr && be->chr->label ? be->chr->label : "");
225 visit_type_str(v, name, &p, errp);
226 g_free(p);
229 static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
230 Error **errp)
232 DeviceState *dev = DEVICE(obj);
233 Property *prop = opaque;
234 CharBackend *be = qdev_get_prop_ptr(dev, prop);
235 Chardev *s;
236 char *str;
238 if (dev->realized) {
239 qdev_prop_set_after_realize(dev, name, errp);
240 return;
243 if (!visit_type_str(v, name, &str, errp)) {
244 return;
248 * TODO Should this really be an error? If no, the old value
249 * needs to be released before we store the new one.
251 if (!check_prop_still_unset(dev, name, be->chr, str, errp)) {
252 return;
255 if (!*str) {
256 g_free(str);
257 be->chr = NULL;
258 return;
261 s = qemu_chr_find(str);
262 if (s == NULL) {
263 error_setg(errp, "Property '%s.%s' can't find value '%s'",
264 object_get_typename(obj), prop->name, str);
265 } else if (!qemu_chr_fe_init(be, s, errp)) {
266 error_prepend(errp, "Property '%s.%s' can't take value '%s': ",
267 object_get_typename(obj), prop->name, str);
269 g_free(str);
272 static void release_chr(Object *obj, const char *name, void *opaque)
274 DeviceState *dev = DEVICE(obj);
275 Property *prop = opaque;
276 CharBackend *be = qdev_get_prop_ptr(dev, prop);
278 qemu_chr_fe_deinit(be, false);
281 const PropertyInfo qdev_prop_chr = {
282 .name = "str",
283 .description = "ID of a chardev to use as a backend",
284 .get = get_chr,
285 .set = set_chr,
286 .release = release_chr,
289 /* --- mac address --- */
292 * accepted syntax versions:
293 * 01:02:03:04:05:06
294 * 01-02-03-04-05-06
296 static void get_mac(Object *obj, Visitor *v, const char *name, void *opaque,
297 Error **errp)
299 DeviceState *dev = DEVICE(obj);
300 Property *prop = opaque;
301 MACAddr *mac = qdev_get_prop_ptr(dev, prop);
302 char buffer[2 * 6 + 5 + 1];
303 char *p = buffer;
305 snprintf(buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x",
306 mac->a[0], mac->a[1], mac->a[2],
307 mac->a[3], mac->a[4], mac->a[5]);
309 visit_type_str(v, name, &p, errp);
312 static void set_mac(Object *obj, Visitor *v, const char *name, void *opaque,
313 Error **errp)
315 DeviceState *dev = DEVICE(obj);
316 Property *prop = opaque;
317 MACAddr *mac = qdev_get_prop_ptr(dev, prop);
318 int i, pos;
319 char *str;
320 const char *p;
322 if (dev->realized) {
323 qdev_prop_set_after_realize(dev, name, errp);
324 return;
327 if (!visit_type_str(v, name, &str, errp)) {
328 return;
331 for (i = 0, pos = 0; i < 6; i++, pos += 3) {
332 long val;
334 if (!qemu_isxdigit(str[pos])) {
335 goto inval;
337 if (!qemu_isxdigit(str[pos + 1])) {
338 goto inval;
340 if (i == 5) {
341 if (str[pos + 2] != '\0') {
342 goto inval;
344 } else {
345 if (str[pos + 2] != ':' && str[pos + 2] != '-') {
346 goto inval;
349 if (qemu_strtol(str + pos, &p, 16, &val) < 0 || val > 0xff) {
350 goto inval;
352 mac->a[i] = val;
354 g_free(str);
355 return;
357 inval:
358 error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
359 g_free(str);
362 const PropertyInfo qdev_prop_macaddr = {
363 .name = "str",
364 .description = "Ethernet 6-byte MAC Address, example: 52:54:00:12:34:56",
365 .get = get_mac,
366 .set = set_mac,
369 void qdev_prop_set_macaddr(DeviceState *dev, const char *name,
370 const uint8_t *value)
372 char str[2 * 6 + 5 + 1];
373 snprintf(str, sizeof(str), "%02x:%02x:%02x:%02x:%02x:%02x",
374 value[0], value[1], value[2], value[3], value[4], value[5]);
376 object_property_set_str(OBJECT(dev), name, str, &error_abort);
379 /* --- netdev device --- */
380 static void get_netdev(Object *obj, Visitor *v, const char *name,
381 void *opaque, Error **errp)
383 DeviceState *dev = DEVICE(obj);
384 Property *prop = opaque;
385 NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop);
386 char *p = g_strdup(peers_ptr->ncs[0] ? peers_ptr->ncs[0]->name : "");
388 visit_type_str(v, name, &p, errp);
389 g_free(p);
392 static void set_netdev(Object *obj, Visitor *v, const char *name,
393 void *opaque, Error **errp)
395 DeviceState *dev = DEVICE(obj);
396 Property *prop = opaque;
397 NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop);
398 NetClientState **ncs = peers_ptr->ncs;
399 NetClientState *peers[MAX_QUEUE_NUM];
400 int queues, err = 0, i = 0;
401 char *str;
403 if (dev->realized) {
404 qdev_prop_set_after_realize(dev, name, errp);
405 return;
408 if (!visit_type_str(v, name, &str, errp)) {
409 return;
412 queues = qemu_find_net_clients_except(str, peers,
413 NET_CLIENT_DRIVER_NIC,
414 MAX_QUEUE_NUM);
415 if (queues == 0) {
416 err = -ENOENT;
417 goto out;
420 if (queues > MAX_QUEUE_NUM) {
421 error_setg(errp, "queues of backend '%s'(%d) exceeds QEMU limitation(%d)",
422 str, queues, MAX_QUEUE_NUM);
423 goto out;
426 for (i = 0; i < queues; i++) {
427 if (peers[i]->peer) {
428 err = -EEXIST;
429 goto out;
433 * TODO Should this really be an error? If no, the old value
434 * needs to be released before we store the new one.
436 if (!check_prop_still_unset(dev, name, ncs[i], str, errp)) {
437 goto out;
440 ncs[i] = peers[i];
441 ncs[i]->queue_index = i;
444 peers_ptr->queues = queues;
446 out:
447 error_set_from_qdev_prop_error(errp, err, dev, prop, str);
448 g_free(str);
451 const PropertyInfo qdev_prop_netdev = {
452 .name = "str",
453 .description = "ID of a netdev to use as a backend",
454 .get = get_netdev,
455 .set = set_netdev,
459 /* --- audiodev --- */
460 static void get_audiodev(Object *obj, Visitor *v, const char* name,
461 void *opaque, Error **errp)
463 DeviceState *dev = DEVICE(obj);
464 Property *prop = opaque;
465 QEMUSoundCard *card = qdev_get_prop_ptr(dev, prop);
466 char *p = g_strdup(audio_get_id(card));
468 visit_type_str(v, name, &p, errp);
469 g_free(p);
472 static void set_audiodev(Object *obj, Visitor *v, const char* name,
473 void *opaque, Error **errp)
475 DeviceState *dev = DEVICE(obj);
476 Property *prop = opaque;
477 QEMUSoundCard *card = qdev_get_prop_ptr(dev, prop);
478 AudioState *state;
479 int err = 0;
480 char *str;
482 if (dev->realized) {
483 qdev_prop_set_after_realize(dev, name, errp);
484 return;
487 if (!visit_type_str(v, name, &str, errp)) {
488 return;
491 state = audio_state_by_name(str);
493 if (!state) {
494 err = -ENOENT;
495 goto out;
497 card->state = state;
499 out:
500 error_set_from_qdev_prop_error(errp, err, dev, prop, str);
501 g_free(str);
504 const PropertyInfo qdev_prop_audiodev = {
505 .name = "str",
506 .description = "ID of an audiodev to use as a backend",
507 /* release done on shutdown */
508 .get = get_audiodev,
509 .set = set_audiodev,
512 bool qdev_prop_set_drive_err(DeviceState *dev, const char *name,
513 BlockBackend *value, Error **errp)
515 const char *ref = "";
517 if (value) {
518 ref = blk_name(value);
519 if (!*ref) {
520 const BlockDriverState *bs = blk_bs(value);
521 if (bs) {
522 ref = bdrv_get_node_name(bs);
527 return object_property_set_str(OBJECT(dev), name, ref, errp);
530 void qdev_prop_set_drive(DeviceState *dev, const char *name,
531 BlockBackend *value)
533 qdev_prop_set_drive_err(dev, name, value, &error_abort);
536 void qdev_prop_set_chr(DeviceState *dev, const char *name,
537 Chardev *value)
539 assert(!value || value->label);
540 object_property_set_str(OBJECT(dev), name, value ? value->label : "",
541 &error_abort);
544 void qdev_prop_set_netdev(DeviceState *dev, const char *name,
545 NetClientState *value)
547 assert(!value || value->name);
548 object_property_set_str(OBJECT(dev), name, value ? value->name : "",
549 &error_abort);
552 void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
554 qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
555 if (nd->netdev) {
556 qdev_prop_set_netdev(dev, "netdev", nd->netdev);
558 if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
559 object_property_find(OBJECT(dev), "vectors")) {
560 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
562 nd->instantiated = 1;
565 /* --- lost tick policy --- */
567 QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int));
569 const PropertyInfo qdev_prop_losttickpolicy = {
570 .name = "LostTickPolicy",
571 .enum_table = &LostTickPolicy_lookup,
572 .get = qdev_propinfo_get_enum,
573 .set = qdev_propinfo_set_enum,
574 .set_default_value = qdev_propinfo_set_default_value_enum,
577 /* --- blocksize --- */
579 /* lower limit is sector size */
580 #define MIN_BLOCK_SIZE 512
581 #define MIN_BLOCK_SIZE_STR "512 B"
583 * upper limit is arbitrary, 2 MiB looks sufficient for all sensible uses, and
584 * matches qcow2 cluster size limit
586 #define MAX_BLOCK_SIZE (2 * MiB)
587 #define MAX_BLOCK_SIZE_STR "2 MiB"
589 static void set_blocksize(Object *obj, Visitor *v, const char *name,
590 void *opaque, Error **errp)
592 DeviceState *dev = DEVICE(obj);
593 Property *prop = opaque;
594 uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
595 uint64_t value;
597 if (dev->realized) {
598 qdev_prop_set_after_realize(dev, name, errp);
599 return;
602 if (!visit_type_size(v, name, &value, errp)) {
603 return;
605 /* value of 0 means "unset" */
606 if (value && (value < MIN_BLOCK_SIZE || value > MAX_BLOCK_SIZE)) {
607 error_setg(errp,
608 "Property %s.%s doesn't take value %" PRIu64
609 " (minimum: " MIN_BLOCK_SIZE_STR
610 ", maximum: " MAX_BLOCK_SIZE_STR ")",
611 dev->id ? : "", name, value);
612 return;
615 /* We rely on power-of-2 blocksizes for bitmasks */
616 if ((value & (value - 1)) != 0) {
617 error_setg(errp,
618 "Property %s.%s doesn't take value '%" PRId64 "', "
619 "it's not a power of 2", dev->id ?: "", name, (int64_t)value);
620 return;
623 *ptr = value;
626 const PropertyInfo qdev_prop_blocksize = {
627 .name = "size",
628 .description = "A power of two between " MIN_BLOCK_SIZE_STR
629 " and " MAX_BLOCK_SIZE_STR,
630 .get = qdev_propinfo_get_size32,
631 .set = set_blocksize,
632 .set_default_value = qdev_propinfo_set_default_value_uint,
635 /* --- Block device error handling policy --- */
637 QEMU_BUILD_BUG_ON(sizeof(BlockdevOnError) != sizeof(int));
639 const PropertyInfo qdev_prop_blockdev_on_error = {
640 .name = "BlockdevOnError",
641 .description = "Error handling policy, "
642 "report/ignore/enospc/stop/auto",
643 .enum_table = &BlockdevOnError_lookup,
644 .get = qdev_propinfo_get_enum,
645 .set = qdev_propinfo_set_enum,
646 .set_default_value = qdev_propinfo_set_default_value_enum,
649 /* --- BIOS CHS translation */
651 QEMU_BUILD_BUG_ON(sizeof(BiosAtaTranslation) != sizeof(int));
653 const PropertyInfo qdev_prop_bios_chs_trans = {
654 .name = "BiosAtaTranslation",
655 .description = "Logical CHS translation algorithm, "
656 "auto/none/lba/large/rechs",
657 .enum_table = &BiosAtaTranslation_lookup,
658 .get = qdev_propinfo_get_enum,
659 .set = qdev_propinfo_set_enum,
660 .set_default_value = qdev_propinfo_set_default_value_enum,
663 /* --- FDC default drive types */
665 const PropertyInfo qdev_prop_fdc_drive_type = {
666 .name = "FdcDriveType",
667 .description = "FDC drive type, "
668 "144/288/120/none/auto",
669 .enum_table = &FloppyDriveType_lookup,
670 .get = qdev_propinfo_get_enum,
671 .set = qdev_propinfo_set_enum,
672 .set_default_value = qdev_propinfo_set_default_value_enum,
675 /* --- MultiFDCompression --- */
677 const PropertyInfo qdev_prop_multifd_compression = {
678 .name = "MultiFDCompression",
679 .description = "multifd_compression values, "
680 "none/zlib/zstd",
681 .enum_table = &MultiFDCompression_lookup,
682 .get = qdev_propinfo_get_enum,
683 .set = qdev_propinfo_set_enum,
684 .set_default_value = qdev_propinfo_set_default_value_enum,
687 /* --- Reserved Region --- */
690 * Accepted syntax:
691 * <low address>:<high address>:<type>
692 * where low/high addresses are uint64_t in hexadecimal
693 * and type is a non-negative decimal integer
695 static void get_reserved_region(Object *obj, Visitor *v, const char *name,
696 void *opaque, Error **errp)
698 DeviceState *dev = DEVICE(obj);
699 Property *prop = opaque;
700 ReservedRegion *rr = qdev_get_prop_ptr(dev, prop);
701 char buffer[64];
702 char *p = buffer;
703 int rc;
705 rc = snprintf(buffer, sizeof(buffer), "0x%"PRIx64":0x%"PRIx64":%u",
706 rr->low, rr->high, rr->type);
707 assert(rc < sizeof(buffer));
709 visit_type_str(v, name, &p, errp);
712 static void set_reserved_region(Object *obj, Visitor *v, const char *name,
713 void *opaque, Error **errp)
715 DeviceState *dev = DEVICE(obj);
716 Property *prop = opaque;
717 ReservedRegion *rr = qdev_get_prop_ptr(dev, prop);
718 Error *local_err = NULL;
719 const char *endptr;
720 char *str;
721 int ret;
723 if (dev->realized) {
724 qdev_prop_set_after_realize(dev, name, errp);
725 return;
728 visit_type_str(v, name, &str, &local_err);
729 if (local_err) {
730 error_propagate(errp, local_err);
731 return;
734 ret = qemu_strtou64(str, &endptr, 16, &rr->low);
735 if (ret) {
736 error_setg(errp, "start address of '%s'"
737 " must be a hexadecimal integer", name);
738 goto out;
740 if (*endptr != ':') {
741 goto separator_error;
744 ret = qemu_strtou64(endptr + 1, &endptr, 16, &rr->high);
745 if (ret) {
746 error_setg(errp, "end address of '%s'"
747 " must be a hexadecimal integer", name);
748 goto out;
750 if (*endptr != ':') {
751 goto separator_error;
754 ret = qemu_strtoui(endptr + 1, &endptr, 10, &rr->type);
755 if (ret) {
756 error_setg(errp, "type of '%s'"
757 " must be a non-negative decimal integer", name);
759 goto out;
761 separator_error:
762 error_setg(errp, "reserved region fields must be separated with ':'");
763 out:
764 g_free(str);
765 return;
768 const PropertyInfo qdev_prop_reserved_region = {
769 .name = "reserved_region",
770 .description = "Reserved Region, example: 0xFEE00000:0xFEEFFFFF:0",
771 .get = get_reserved_region,
772 .set = set_reserved_region,
775 /* --- pci address --- */
778 * bus-local address, i.e. "$slot" or "$slot.$fn"
780 static void set_pci_devfn(Object *obj, Visitor *v, const char *name,
781 void *opaque, Error **errp)
783 DeviceState *dev = DEVICE(obj);
784 Property *prop = opaque;
785 int32_t value, *ptr = qdev_get_prop_ptr(dev, prop);
786 unsigned int slot, fn, n;
787 char *str;
789 if (dev->realized) {
790 qdev_prop_set_after_realize(dev, name, errp);
791 return;
794 if (!visit_type_str(v, name, &str, NULL)) {
795 if (!visit_type_int32(v, name, &value, errp)) {
796 return;
798 if (value < -1 || value > 255) {
799 error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
800 name ? name : "null", "pci_devfn");
801 return;
803 *ptr = value;
804 return;
807 if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
808 fn = 0;
809 if (sscanf(str, "%x%n", &slot, &n) != 1) {
810 goto invalid;
813 if (str[n] != '\0' || fn > 7 || slot > 31) {
814 goto invalid;
816 *ptr = slot << 3 | fn;
817 g_free(str);
818 return;
820 invalid:
821 error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
822 g_free(str);
825 static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest,
826 size_t len)
828 int32_t *ptr = qdev_get_prop_ptr(dev, prop);
830 if (*ptr == -1) {
831 return snprintf(dest, len, "<unset>");
832 } else {
833 return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7);
837 const PropertyInfo qdev_prop_pci_devfn = {
838 .name = "int32",
839 .description = "Slot and optional function number, example: 06.0 or 06",
840 .print = print_pci_devfn,
841 .get = qdev_propinfo_get_int32,
842 .set = set_pci_devfn,
843 .set_default_value = qdev_propinfo_set_default_value_int,
846 /* --- pci host address --- */
848 static void get_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
849 void *opaque, Error **errp)
851 DeviceState *dev = DEVICE(obj);
852 Property *prop = opaque;
853 PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop);
854 char buffer[] = "ffff:ff:ff.f";
855 char *p = buffer;
856 int rc = 0;
859 * Catch "invalid" device reference from vfio-pci and allow the
860 * default buffer representing the non-existent device to be used.
862 if (~addr->domain || ~addr->bus || ~addr->slot || ~addr->function) {
863 rc = snprintf(buffer, sizeof(buffer), "%04x:%02x:%02x.%0d",
864 addr->domain, addr->bus, addr->slot, addr->function);
865 assert(rc == sizeof(buffer) - 1);
868 visit_type_str(v, name, &p, errp);
872 * Parse [<domain>:]<bus>:<slot>.<func>
873 * if <domain> is not supplied, it's assumed to be 0.
875 static void set_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
876 void *opaque, Error **errp)
878 DeviceState *dev = DEVICE(obj);
879 Property *prop = opaque;
880 PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop);
881 char *str, *p;
882 const char *e;
883 unsigned long val;
884 unsigned long dom = 0, bus = 0;
885 unsigned int slot = 0, func = 0;
887 if (dev->realized) {
888 qdev_prop_set_after_realize(dev, name, errp);
889 return;
892 if (!visit_type_str(v, name, &str, errp)) {
893 return;
896 p = str;
897 if (qemu_strtoul(p, &e, 16, &val) < 0 || val > 0xffff || e == p) {
898 goto inval;
900 if (*e != ':') {
901 goto inval;
903 bus = val;
905 p = (char *)e + 1;
906 if (qemu_strtoul(p, &e, 16, &val) < 0 || val > 0x1f || e == p) {
907 goto inval;
909 if (*e == ':') {
910 dom = bus;
911 bus = val;
912 p = (char *)e + 1;
913 if (qemu_strtoul(p, &e, 16, &val) < 0 || val > 0x1f || e == p) {
914 goto inval;
917 slot = val;
919 if (*e != '.') {
920 goto inval;
922 p = (char *)e + 1;
923 if (qemu_strtoul(p, &e, 10, &val) < 0 || val > 7 || e == p) {
924 goto inval;
926 func = val;
928 if (bus > 0xff) {
929 goto inval;
932 if (*e) {
933 goto inval;
936 addr->domain = dom;
937 addr->bus = bus;
938 addr->slot = slot;
939 addr->function = func;
941 g_free(str);
942 return;
944 inval:
945 error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
946 g_free(str);
949 const PropertyInfo qdev_prop_pci_host_devaddr = {
950 .name = "str",
951 .description = "Address (bus/device/function) of "
952 "the host device, example: 04:10.0",
953 .get = get_pci_host_devaddr,
954 .set = set_pci_host_devaddr,
957 /* --- OffAutoPCIBAR off/auto/bar0/bar1/bar2/bar3/bar4/bar5 --- */
959 const PropertyInfo qdev_prop_off_auto_pcibar = {
960 .name = "OffAutoPCIBAR",
961 .description = "off/auto/bar0/bar1/bar2/bar3/bar4/bar5",
962 .enum_table = &OffAutoPCIBAR_lookup,
963 .get = qdev_propinfo_get_enum,
964 .set = qdev_propinfo_set_enum,
965 .set_default_value = qdev_propinfo_set_default_value_enum,
968 /* --- PCIELinkSpeed 2_5/5/8/16 -- */
970 static void get_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
971 void *opaque, Error **errp)
973 DeviceState *dev = DEVICE(obj);
974 Property *prop = opaque;
975 PCIExpLinkSpeed *p = qdev_get_prop_ptr(dev, prop);
976 int speed;
978 switch (*p) {
979 case QEMU_PCI_EXP_LNK_2_5GT:
980 speed = PCIE_LINK_SPEED_2_5;
981 break;
982 case QEMU_PCI_EXP_LNK_5GT:
983 speed = PCIE_LINK_SPEED_5;
984 break;
985 case QEMU_PCI_EXP_LNK_8GT:
986 speed = PCIE_LINK_SPEED_8;
987 break;
988 case QEMU_PCI_EXP_LNK_16GT:
989 speed = PCIE_LINK_SPEED_16;
990 break;
991 default:
992 /* Unreachable */
993 abort();
996 visit_type_enum(v, prop->name, &speed, prop->info->enum_table, errp);
999 static void set_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
1000 void *opaque, Error **errp)
1002 DeviceState *dev = DEVICE(obj);
1003 Property *prop = opaque;
1004 PCIExpLinkSpeed *p = qdev_get_prop_ptr(dev, prop);
1005 int speed;
1007 if (dev->realized) {
1008 qdev_prop_set_after_realize(dev, name, errp);
1009 return;
1012 if (!visit_type_enum(v, prop->name, &speed, prop->info->enum_table,
1013 errp)) {
1014 return;
1017 switch (speed) {
1018 case PCIE_LINK_SPEED_2_5:
1019 *p = QEMU_PCI_EXP_LNK_2_5GT;
1020 break;
1021 case PCIE_LINK_SPEED_5:
1022 *p = QEMU_PCI_EXP_LNK_5GT;
1023 break;
1024 case PCIE_LINK_SPEED_8:
1025 *p = QEMU_PCI_EXP_LNK_8GT;
1026 break;
1027 case PCIE_LINK_SPEED_16:
1028 *p = QEMU_PCI_EXP_LNK_16GT;
1029 break;
1030 default:
1031 /* Unreachable */
1032 abort();
1036 const PropertyInfo qdev_prop_pcie_link_speed = {
1037 .name = "PCIELinkSpeed",
1038 .description = "2_5/5/8/16",
1039 .enum_table = &PCIELinkSpeed_lookup,
1040 .get = get_prop_pcielinkspeed,
1041 .set = set_prop_pcielinkspeed,
1042 .set_default_value = qdev_propinfo_set_default_value_enum,
1045 /* --- PCIELinkWidth 1/2/4/8/12/16/32 -- */
1047 static void get_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
1048 void *opaque, Error **errp)
1050 DeviceState *dev = DEVICE(obj);
1051 Property *prop = opaque;
1052 PCIExpLinkWidth *p = qdev_get_prop_ptr(dev, prop);
1053 int width;
1055 switch (*p) {
1056 case QEMU_PCI_EXP_LNK_X1:
1057 width = PCIE_LINK_WIDTH_1;
1058 break;
1059 case QEMU_PCI_EXP_LNK_X2:
1060 width = PCIE_LINK_WIDTH_2;
1061 break;
1062 case QEMU_PCI_EXP_LNK_X4:
1063 width = PCIE_LINK_WIDTH_4;
1064 break;
1065 case QEMU_PCI_EXP_LNK_X8:
1066 width = PCIE_LINK_WIDTH_8;
1067 break;
1068 case QEMU_PCI_EXP_LNK_X12:
1069 width = PCIE_LINK_WIDTH_12;
1070 break;
1071 case QEMU_PCI_EXP_LNK_X16:
1072 width = PCIE_LINK_WIDTH_16;
1073 break;
1074 case QEMU_PCI_EXP_LNK_X32:
1075 width = PCIE_LINK_WIDTH_32;
1076 break;
1077 default:
1078 /* Unreachable */
1079 abort();
1082 visit_type_enum(v, prop->name, &width, prop->info->enum_table, errp);
1085 static void set_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
1086 void *opaque, Error **errp)
1088 DeviceState *dev = DEVICE(obj);
1089 Property *prop = opaque;
1090 PCIExpLinkWidth *p = qdev_get_prop_ptr(dev, prop);
1091 int width;
1093 if (dev->realized) {
1094 qdev_prop_set_after_realize(dev, name, errp);
1095 return;
1098 if (!visit_type_enum(v, prop->name, &width, prop->info->enum_table,
1099 errp)) {
1100 return;
1103 switch (width) {
1104 case PCIE_LINK_WIDTH_1:
1105 *p = QEMU_PCI_EXP_LNK_X1;
1106 break;
1107 case PCIE_LINK_WIDTH_2:
1108 *p = QEMU_PCI_EXP_LNK_X2;
1109 break;
1110 case PCIE_LINK_WIDTH_4:
1111 *p = QEMU_PCI_EXP_LNK_X4;
1112 break;
1113 case PCIE_LINK_WIDTH_8:
1114 *p = QEMU_PCI_EXP_LNK_X8;
1115 break;
1116 case PCIE_LINK_WIDTH_12:
1117 *p = QEMU_PCI_EXP_LNK_X12;
1118 break;
1119 case PCIE_LINK_WIDTH_16:
1120 *p = QEMU_PCI_EXP_LNK_X16;
1121 break;
1122 case PCIE_LINK_WIDTH_32:
1123 *p = QEMU_PCI_EXP_LNK_X32;
1124 break;
1125 default:
1126 /* Unreachable */
1127 abort();
1131 const PropertyInfo qdev_prop_pcie_link_width = {
1132 .name = "PCIELinkWidth",
1133 .description = "1/2/4/8/12/16/32",
1134 .enum_table = &PCIELinkWidth_lookup,
1135 .get = get_prop_pcielinkwidth,
1136 .set = set_prop_pcielinkwidth,
1137 .set_default_value = qdev_propinfo_set_default_value_enum,