scripts: kernel-doc: allow passing desired Sphinx C domain dialect
[qemu/ar7.git] / hw / core / qdev-properties-system.c
blob9d80a07d26f82edc11cb7cb6782f1943b141e024
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"
33 #include "util/block-helpers.h"
35 static bool check_prop_still_unset(DeviceState *dev, const char *name,
36 const void *old_val, const char *new_val,
37 Error **errp)
39 const GlobalProperty *prop = qdev_find_global_prop(dev, name);
41 if (!old_val) {
42 return true;
45 if (prop) {
46 error_setg(errp, "-global %s.%s=... conflicts with %s=%s",
47 prop->driver, prop->property, name, new_val);
48 } else {
49 /* Error message is vague, but a better one would be hard */
50 error_setg(errp, "%s=%s conflicts, and override is not implemented",
51 name, new_val);
53 return false;
57 /* --- drive --- */
59 static void get_drive(Object *obj, Visitor *v, const char *name, void *opaque,
60 Error **errp)
62 DeviceState *dev = DEVICE(obj);
63 Property *prop = opaque;
64 void **ptr = qdev_get_prop_ptr(dev, prop);
65 const char *value;
66 char *p;
68 if (*ptr) {
69 value = blk_name(*ptr);
70 if (!*value) {
71 BlockDriverState *bs = blk_bs(*ptr);
72 if (bs) {
73 value = bdrv_get_node_name(bs);
76 } else {
77 value = "";
80 p = g_strdup(value);
81 visit_type_str(v, name, &p, errp);
82 g_free(p);
85 static void set_drive_helper(Object *obj, Visitor *v, const char *name,
86 void *opaque, bool iothread, Error **errp)
88 DeviceState *dev = DEVICE(obj);
89 Property *prop = opaque;
90 void **ptr = qdev_get_prop_ptr(dev, prop);
91 char *str;
92 BlockBackend *blk;
93 bool blk_created = false;
94 int ret;
96 if (dev->realized) {
97 qdev_prop_set_after_realize(dev, name, errp);
98 return;
101 if (!visit_type_str(v, name, &str, errp)) {
102 return;
106 * TODO Should this really be an error? If no, the old value
107 * needs to be released before we store the new one.
109 if (!check_prop_still_unset(dev, name, *ptr, str, errp)) {
110 return;
113 if (!*str) {
114 g_free(str);
115 *ptr = NULL;
116 return;
119 blk = blk_by_name(str);
120 if (!blk) {
121 BlockDriverState *bs = bdrv_lookup_bs(NULL, str, NULL);
122 if (bs) {
124 * If the device supports iothreads, it will make sure to move the
125 * block node to the right AioContext if necessary (or fail if this
126 * isn't possible because of other users). Devices that are not
127 * aware of iothreads require their BlockBackends to be in the main
128 * AioContext.
130 AioContext *ctx = iothread ? bdrv_get_aio_context(bs) :
131 qemu_get_aio_context();
132 blk = blk_new(ctx, 0, BLK_PERM_ALL);
133 blk_created = true;
135 ret = blk_insert_bs(blk, bs, errp);
136 if (ret < 0) {
137 goto fail;
141 if (!blk) {
142 error_setg(errp, "Property '%s.%s' can't find value '%s'",
143 object_get_typename(OBJECT(dev)), prop->name, str);
144 goto fail;
146 if (blk_attach_dev(blk, dev) < 0) {
147 DriveInfo *dinfo = blk_legacy_dinfo(blk);
149 if (dinfo && dinfo->type != IF_NONE) {
150 error_setg(errp, "Drive '%s' is already in use because "
151 "it has been automatically connected to another "
152 "device (did you need 'if=none' in the drive options?)",
153 str);
154 } else {
155 error_setg(errp, "Drive '%s' is already in use by another device",
156 str);
158 goto fail;
161 *ptr = blk;
163 fail:
164 if (blk_created) {
165 /* If we need to keep a reference, blk_attach_dev() took it */
166 blk_unref(blk);
169 g_free(str);
172 static void set_drive(Object *obj, Visitor *v, const char *name, void *opaque,
173 Error **errp)
175 set_drive_helper(obj, v, name, opaque, false, errp);
178 static void set_drive_iothread(Object *obj, Visitor *v, const char *name,
179 void *opaque, Error **errp)
181 set_drive_helper(obj, v, name, opaque, true, errp);
184 static void release_drive(Object *obj, const char *name, void *opaque)
186 DeviceState *dev = DEVICE(obj);
187 Property *prop = opaque;
188 BlockBackend **ptr = qdev_get_prop_ptr(dev, prop);
190 if (*ptr) {
191 AioContext *ctx = blk_get_aio_context(*ptr);
193 aio_context_acquire(ctx);
194 blockdev_auto_del(*ptr);
195 blk_detach_dev(*ptr, dev);
196 aio_context_release(ctx);
200 const PropertyInfo qdev_prop_drive = {
201 .name = "str",
202 .description = "Node name or ID of a block device to use as a backend",
203 .get = get_drive,
204 .set = set_drive,
205 .release = release_drive,
208 const PropertyInfo qdev_prop_drive_iothread = {
209 .name = "str",
210 .description = "Node name or ID of a block device to use as a backend",
211 .get = get_drive,
212 .set = set_drive_iothread,
213 .release = release_drive,
216 /* --- character device --- */
218 static void get_chr(Object *obj, Visitor *v, const char *name, void *opaque,
219 Error **errp)
221 DeviceState *dev = DEVICE(obj);
222 CharBackend *be = qdev_get_prop_ptr(dev, opaque);
223 char *p;
225 p = g_strdup(be->chr && be->chr->label ? be->chr->label : "");
226 visit_type_str(v, name, &p, errp);
227 g_free(p);
230 static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
231 Error **errp)
233 DeviceState *dev = DEVICE(obj);
234 Property *prop = opaque;
235 CharBackend *be = qdev_get_prop_ptr(dev, prop);
236 Chardev *s;
237 char *str;
239 if (dev->realized) {
240 qdev_prop_set_after_realize(dev, name, errp);
241 return;
244 if (!visit_type_str(v, name, &str, errp)) {
245 return;
249 * TODO Should this really be an error? If no, the old value
250 * needs to be released before we store the new one.
252 if (!check_prop_still_unset(dev, name, be->chr, str, errp)) {
253 return;
256 if (!*str) {
257 g_free(str);
258 be->chr = NULL;
259 return;
262 s = qemu_chr_find(str);
263 if (s == NULL) {
264 error_setg(errp, "Property '%s.%s' can't find value '%s'",
265 object_get_typename(obj), prop->name, str);
266 } else if (!qemu_chr_fe_init(be, s, errp)) {
267 error_prepend(errp, "Property '%s.%s' can't take value '%s': ",
268 object_get_typename(obj), prop->name, str);
270 g_free(str);
273 static void release_chr(Object *obj, const char *name, void *opaque)
275 DeviceState *dev = DEVICE(obj);
276 Property *prop = opaque;
277 CharBackend *be = qdev_get_prop_ptr(dev, prop);
279 qemu_chr_fe_deinit(be, false);
282 const PropertyInfo qdev_prop_chr = {
283 .name = "str",
284 .description = "ID of a chardev to use as a backend",
285 .get = get_chr,
286 .set = set_chr,
287 .release = release_chr,
290 /* --- mac address --- */
293 * accepted syntax versions:
294 * 01:02:03:04:05:06
295 * 01-02-03-04-05-06
297 static void get_mac(Object *obj, Visitor *v, const char *name, void *opaque,
298 Error **errp)
300 DeviceState *dev = DEVICE(obj);
301 Property *prop = opaque;
302 MACAddr *mac = qdev_get_prop_ptr(dev, prop);
303 char buffer[2 * 6 + 5 + 1];
304 char *p = buffer;
306 snprintf(buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x",
307 mac->a[0], mac->a[1], mac->a[2],
308 mac->a[3], mac->a[4], mac->a[5]);
310 visit_type_str(v, name, &p, errp);
313 static void set_mac(Object *obj, Visitor *v, const char *name, void *opaque,
314 Error **errp)
316 DeviceState *dev = DEVICE(obj);
317 Property *prop = opaque;
318 MACAddr *mac = qdev_get_prop_ptr(dev, prop);
319 int i, pos;
320 char *str;
321 const char *p;
323 if (dev->realized) {
324 qdev_prop_set_after_realize(dev, name, errp);
325 return;
328 if (!visit_type_str(v, name, &str, errp)) {
329 return;
332 for (i = 0, pos = 0; i < 6; i++, pos += 3) {
333 long val;
335 if (!qemu_isxdigit(str[pos])) {
336 goto inval;
338 if (!qemu_isxdigit(str[pos + 1])) {
339 goto inval;
341 if (i == 5) {
342 if (str[pos + 2] != '\0') {
343 goto inval;
345 } else {
346 if (str[pos + 2] != ':' && str[pos + 2] != '-') {
347 goto inval;
350 if (qemu_strtol(str + pos, &p, 16, &val) < 0 || val > 0xff) {
351 goto inval;
353 mac->a[i] = val;
355 g_free(str);
356 return;
358 inval:
359 error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
360 g_free(str);
363 const PropertyInfo qdev_prop_macaddr = {
364 .name = "str",
365 .description = "Ethernet 6-byte MAC Address, example: 52:54:00:12:34:56",
366 .get = get_mac,
367 .set = set_mac,
370 void qdev_prop_set_macaddr(DeviceState *dev, const char *name,
371 const uint8_t *value)
373 char str[2 * 6 + 5 + 1];
374 snprintf(str, sizeof(str), "%02x:%02x:%02x:%02x:%02x:%02x",
375 value[0], value[1], value[2], value[3], value[4], value[5]);
377 object_property_set_str(OBJECT(dev), name, str, &error_abort);
380 /* --- netdev device --- */
381 static void get_netdev(Object *obj, Visitor *v, const char *name,
382 void *opaque, Error **errp)
384 DeviceState *dev = DEVICE(obj);
385 Property *prop = opaque;
386 NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop);
387 char *p = g_strdup(peers_ptr->ncs[0] ? peers_ptr->ncs[0]->name : "");
389 visit_type_str(v, name, &p, errp);
390 g_free(p);
393 static void set_netdev(Object *obj, Visitor *v, const char *name,
394 void *opaque, Error **errp)
396 DeviceState *dev = DEVICE(obj);
397 Property *prop = opaque;
398 NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop);
399 NetClientState **ncs = peers_ptr->ncs;
400 NetClientState *peers[MAX_QUEUE_NUM];
401 int queues, err = 0, i = 0;
402 char *str;
404 if (dev->realized) {
405 qdev_prop_set_after_realize(dev, name, errp);
406 return;
409 if (!visit_type_str(v, name, &str, errp)) {
410 return;
413 queues = qemu_find_net_clients_except(str, peers,
414 NET_CLIENT_DRIVER_NIC,
415 MAX_QUEUE_NUM);
416 if (queues == 0) {
417 err = -ENOENT;
418 goto out;
421 if (queues > MAX_QUEUE_NUM) {
422 error_setg(errp, "queues of backend '%s'(%d) exceeds QEMU limitation(%d)",
423 str, queues, MAX_QUEUE_NUM);
424 goto out;
427 for (i = 0; i < queues; i++) {
428 if (peers[i]->peer) {
429 err = -EEXIST;
430 goto out;
434 * TODO Should this really be an error? If no, the old value
435 * needs to be released before we store the new one.
437 if (!check_prop_still_unset(dev, name, ncs[i], str, errp)) {
438 goto out;
441 ncs[i] = peers[i];
442 ncs[i]->queue_index = i;
445 peers_ptr->queues = queues;
447 out:
448 error_set_from_qdev_prop_error(errp, err, dev, prop, str);
449 g_free(str);
452 const PropertyInfo qdev_prop_netdev = {
453 .name = "str",
454 .description = "ID of a netdev to use as a backend",
455 .get = get_netdev,
456 .set = set_netdev,
460 /* --- audiodev --- */
461 static void get_audiodev(Object *obj, Visitor *v, const char* name,
462 void *opaque, Error **errp)
464 DeviceState *dev = DEVICE(obj);
465 Property *prop = opaque;
466 QEMUSoundCard *card = qdev_get_prop_ptr(dev, prop);
467 char *p = g_strdup(audio_get_id(card));
469 visit_type_str(v, name, &p, errp);
470 g_free(p);
473 static void set_audiodev(Object *obj, Visitor *v, const char* name,
474 void *opaque, Error **errp)
476 DeviceState *dev = DEVICE(obj);
477 Property *prop = opaque;
478 QEMUSoundCard *card = qdev_get_prop_ptr(dev, prop);
479 AudioState *state;
480 int err = 0;
481 char *str;
483 if (dev->realized) {
484 qdev_prop_set_after_realize(dev, name, errp);
485 return;
488 if (!visit_type_str(v, name, &str, errp)) {
489 return;
492 state = audio_state_by_name(str);
494 if (!state) {
495 err = -ENOENT;
496 goto out;
498 card->state = state;
500 out:
501 error_set_from_qdev_prop_error(errp, err, dev, prop, str);
502 g_free(str);
505 const PropertyInfo qdev_prop_audiodev = {
506 .name = "str",
507 .description = "ID of an audiodev to use as a backend",
508 /* release done on shutdown */
509 .get = get_audiodev,
510 .set = set_audiodev,
513 bool qdev_prop_set_drive_err(DeviceState *dev, const char *name,
514 BlockBackend *value, Error **errp)
516 const char *ref = "";
518 if (value) {
519 ref = blk_name(value);
520 if (!*ref) {
521 const BlockDriverState *bs = blk_bs(value);
522 if (bs) {
523 ref = bdrv_get_node_name(bs);
528 return object_property_set_str(OBJECT(dev), name, ref, errp);
531 void qdev_prop_set_drive(DeviceState *dev, const char *name,
532 BlockBackend *value)
534 qdev_prop_set_drive_err(dev, name, value, &error_abort);
537 void qdev_prop_set_chr(DeviceState *dev, const char *name,
538 Chardev *value)
540 assert(!value || value->label);
541 object_property_set_str(OBJECT(dev), name, value ? value->label : "",
542 &error_abort);
545 void qdev_prop_set_netdev(DeviceState *dev, const char *name,
546 NetClientState *value)
548 assert(!value || value->name);
549 object_property_set_str(OBJECT(dev), name, value ? value->name : "",
550 &error_abort);
553 void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
555 qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
556 if (nd->netdev) {
557 qdev_prop_set_netdev(dev, "netdev", nd->netdev);
559 if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
560 object_property_find(OBJECT(dev), "vectors")) {
561 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
563 nd->instantiated = 1;
566 /* --- lost tick policy --- */
568 QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int));
570 const PropertyInfo qdev_prop_losttickpolicy = {
571 .name = "LostTickPolicy",
572 .enum_table = &LostTickPolicy_lookup,
573 .get = qdev_propinfo_get_enum,
574 .set = qdev_propinfo_set_enum,
575 .set_default_value = qdev_propinfo_set_default_value_enum,
578 /* --- blocksize --- */
580 static void set_blocksize(Object *obj, Visitor *v, const char *name,
581 void *opaque, Error **errp)
583 DeviceState *dev = DEVICE(obj);
584 Property *prop = opaque;
585 uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
586 uint64_t value;
587 Error *local_err = NULL;
589 if (dev->realized) {
590 qdev_prop_set_after_realize(dev, name, errp);
591 return;
594 if (!visit_type_size(v, name, &value, errp)) {
595 return;
597 check_block_size(dev->id ? : "", name, value, &local_err);
598 if (local_err) {
599 error_propagate(errp, local_err);
600 return;
602 *ptr = value;
605 const PropertyInfo qdev_prop_blocksize = {
606 .name = "size",
607 .description = "A power of two between " MIN_BLOCK_SIZE_STR
608 " and " MAX_BLOCK_SIZE_STR,
609 .get = qdev_propinfo_get_size32,
610 .set = set_blocksize,
611 .set_default_value = qdev_propinfo_set_default_value_uint,
614 /* --- Block device error handling policy --- */
616 QEMU_BUILD_BUG_ON(sizeof(BlockdevOnError) != sizeof(int));
618 const PropertyInfo qdev_prop_blockdev_on_error = {
619 .name = "BlockdevOnError",
620 .description = "Error handling policy, "
621 "report/ignore/enospc/stop/auto",
622 .enum_table = &BlockdevOnError_lookup,
623 .get = qdev_propinfo_get_enum,
624 .set = qdev_propinfo_set_enum,
625 .set_default_value = qdev_propinfo_set_default_value_enum,
628 /* --- BIOS CHS translation */
630 QEMU_BUILD_BUG_ON(sizeof(BiosAtaTranslation) != sizeof(int));
632 const PropertyInfo qdev_prop_bios_chs_trans = {
633 .name = "BiosAtaTranslation",
634 .description = "Logical CHS translation algorithm, "
635 "auto/none/lba/large/rechs",
636 .enum_table = &BiosAtaTranslation_lookup,
637 .get = qdev_propinfo_get_enum,
638 .set = qdev_propinfo_set_enum,
639 .set_default_value = qdev_propinfo_set_default_value_enum,
642 /* --- FDC default drive types */
644 const PropertyInfo qdev_prop_fdc_drive_type = {
645 .name = "FdcDriveType",
646 .description = "FDC drive type, "
647 "144/288/120/none/auto",
648 .enum_table = &FloppyDriveType_lookup,
649 .get = qdev_propinfo_get_enum,
650 .set = qdev_propinfo_set_enum,
651 .set_default_value = qdev_propinfo_set_default_value_enum,
654 /* --- MultiFDCompression --- */
656 const PropertyInfo qdev_prop_multifd_compression = {
657 .name = "MultiFDCompression",
658 .description = "multifd_compression values, "
659 "none/zlib/zstd",
660 .enum_table = &MultiFDCompression_lookup,
661 .get = qdev_propinfo_get_enum,
662 .set = qdev_propinfo_set_enum,
663 .set_default_value = qdev_propinfo_set_default_value_enum,
666 /* --- Reserved Region --- */
669 * Accepted syntax:
670 * <low address>:<high address>:<type>
671 * where low/high addresses are uint64_t in hexadecimal
672 * and type is a non-negative decimal integer
674 static void get_reserved_region(Object *obj, Visitor *v, const char *name,
675 void *opaque, Error **errp)
677 DeviceState *dev = DEVICE(obj);
678 Property *prop = opaque;
679 ReservedRegion *rr = qdev_get_prop_ptr(dev, prop);
680 char buffer[64];
681 char *p = buffer;
682 int rc;
684 rc = snprintf(buffer, sizeof(buffer), "0x%"PRIx64":0x%"PRIx64":%u",
685 rr->low, rr->high, rr->type);
686 assert(rc < sizeof(buffer));
688 visit_type_str(v, name, &p, errp);
691 static void set_reserved_region(Object *obj, Visitor *v, const char *name,
692 void *opaque, Error **errp)
694 DeviceState *dev = DEVICE(obj);
695 Property *prop = opaque;
696 ReservedRegion *rr = qdev_get_prop_ptr(dev, prop);
697 Error *local_err = NULL;
698 const char *endptr;
699 char *str;
700 int ret;
702 if (dev->realized) {
703 qdev_prop_set_after_realize(dev, name, errp);
704 return;
707 visit_type_str(v, name, &str, &local_err);
708 if (local_err) {
709 error_propagate(errp, local_err);
710 return;
713 ret = qemu_strtou64(str, &endptr, 16, &rr->low);
714 if (ret) {
715 error_setg(errp, "start address of '%s'"
716 " must be a hexadecimal integer", name);
717 goto out;
719 if (*endptr != ':') {
720 goto separator_error;
723 ret = qemu_strtou64(endptr + 1, &endptr, 16, &rr->high);
724 if (ret) {
725 error_setg(errp, "end address of '%s'"
726 " must be a hexadecimal integer", name);
727 goto out;
729 if (*endptr != ':') {
730 goto separator_error;
733 ret = qemu_strtoui(endptr + 1, &endptr, 10, &rr->type);
734 if (ret) {
735 error_setg(errp, "type of '%s'"
736 " must be a non-negative decimal integer", name);
738 goto out;
740 separator_error:
741 error_setg(errp, "reserved region fields must be separated with ':'");
742 out:
743 g_free(str);
744 return;
747 const PropertyInfo qdev_prop_reserved_region = {
748 .name = "reserved_region",
749 .description = "Reserved Region, example: 0xFEE00000:0xFEEFFFFF:0",
750 .get = get_reserved_region,
751 .set = set_reserved_region,
754 /* --- pci address --- */
757 * bus-local address, i.e. "$slot" or "$slot.$fn"
759 static void set_pci_devfn(Object *obj, Visitor *v, const char *name,
760 void *opaque, Error **errp)
762 DeviceState *dev = DEVICE(obj);
763 Property *prop = opaque;
764 int32_t value, *ptr = qdev_get_prop_ptr(dev, prop);
765 unsigned int slot, fn, n;
766 char *str;
768 if (dev->realized) {
769 qdev_prop_set_after_realize(dev, name, errp);
770 return;
773 if (!visit_type_str(v, name, &str, NULL)) {
774 if (!visit_type_int32(v, name, &value, errp)) {
775 return;
777 if (value < -1 || value > 255) {
778 error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
779 name ? name : "null", "pci_devfn");
780 return;
782 *ptr = value;
783 return;
786 if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
787 fn = 0;
788 if (sscanf(str, "%x%n", &slot, &n) != 1) {
789 goto invalid;
792 if (str[n] != '\0' || fn > 7 || slot > 31) {
793 goto invalid;
795 *ptr = slot << 3 | fn;
796 g_free(str);
797 return;
799 invalid:
800 error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
801 g_free(str);
804 static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest,
805 size_t len)
807 int32_t *ptr = qdev_get_prop_ptr(dev, prop);
809 if (*ptr == -1) {
810 return snprintf(dest, len, "<unset>");
811 } else {
812 return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7);
816 const PropertyInfo qdev_prop_pci_devfn = {
817 .name = "int32",
818 .description = "Slot and optional function number, example: 06.0 or 06",
819 .print = print_pci_devfn,
820 .get = qdev_propinfo_get_int32,
821 .set = set_pci_devfn,
822 .set_default_value = qdev_propinfo_set_default_value_int,
825 /* --- pci host address --- */
827 static void get_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
828 void *opaque, Error **errp)
830 DeviceState *dev = DEVICE(obj);
831 Property *prop = opaque;
832 PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop);
833 char buffer[] = "ffff:ff:ff.f";
834 char *p = buffer;
835 int rc = 0;
838 * Catch "invalid" device reference from vfio-pci and allow the
839 * default buffer representing the non-existent device to be used.
841 if (~addr->domain || ~addr->bus || ~addr->slot || ~addr->function) {
842 rc = snprintf(buffer, sizeof(buffer), "%04x:%02x:%02x.%0d",
843 addr->domain, addr->bus, addr->slot, addr->function);
844 assert(rc == sizeof(buffer) - 1);
847 visit_type_str(v, name, &p, errp);
851 * Parse [<domain>:]<bus>:<slot>.<func>
852 * if <domain> is not supplied, it's assumed to be 0.
854 static void set_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
855 void *opaque, Error **errp)
857 DeviceState *dev = DEVICE(obj);
858 Property *prop = opaque;
859 PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop);
860 char *str, *p;
861 char *e;
862 unsigned long val;
863 unsigned long dom = 0, bus = 0;
864 unsigned int slot = 0, func = 0;
866 if (dev->realized) {
867 qdev_prop_set_after_realize(dev, name, errp);
868 return;
871 if (!visit_type_str(v, name, &str, errp)) {
872 return;
875 p = str;
876 val = strtoul(p, &e, 16);
877 if (e == p || *e != ':') {
878 goto inval;
880 bus = val;
882 p = e + 1;
883 val = strtoul(p, &e, 16);
884 if (e == p) {
885 goto inval;
887 if (*e == ':') {
888 dom = bus;
889 bus = val;
890 p = e + 1;
891 val = strtoul(p, &e, 16);
892 if (e == p) {
893 goto inval;
896 slot = val;
898 if (*e != '.') {
899 goto inval;
901 p = e + 1;
902 val = strtoul(p, &e, 10);
903 if (e == p) {
904 goto inval;
906 func = val;
908 if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) {
909 goto inval;
912 if (*e) {
913 goto inval;
916 addr->domain = dom;
917 addr->bus = bus;
918 addr->slot = slot;
919 addr->function = func;
921 g_free(str);
922 return;
924 inval:
925 error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
926 g_free(str);
929 const PropertyInfo qdev_prop_pci_host_devaddr = {
930 .name = "str",
931 .description = "Address (bus/device/function) of "
932 "the host device, example: 04:10.0",
933 .get = get_pci_host_devaddr,
934 .set = set_pci_host_devaddr,
937 /* --- OffAutoPCIBAR off/auto/bar0/bar1/bar2/bar3/bar4/bar5 --- */
939 const PropertyInfo qdev_prop_off_auto_pcibar = {
940 .name = "OffAutoPCIBAR",
941 .description = "off/auto/bar0/bar1/bar2/bar3/bar4/bar5",
942 .enum_table = &OffAutoPCIBAR_lookup,
943 .get = qdev_propinfo_get_enum,
944 .set = qdev_propinfo_set_enum,
945 .set_default_value = qdev_propinfo_set_default_value_enum,
948 /* --- PCIELinkSpeed 2_5/5/8/16 -- */
950 static void get_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
951 void *opaque, Error **errp)
953 DeviceState *dev = DEVICE(obj);
954 Property *prop = opaque;
955 PCIExpLinkSpeed *p = qdev_get_prop_ptr(dev, prop);
956 int speed;
958 switch (*p) {
959 case QEMU_PCI_EXP_LNK_2_5GT:
960 speed = PCIE_LINK_SPEED_2_5;
961 break;
962 case QEMU_PCI_EXP_LNK_5GT:
963 speed = PCIE_LINK_SPEED_5;
964 break;
965 case QEMU_PCI_EXP_LNK_8GT:
966 speed = PCIE_LINK_SPEED_8;
967 break;
968 case QEMU_PCI_EXP_LNK_16GT:
969 speed = PCIE_LINK_SPEED_16;
970 break;
971 default:
972 /* Unreachable */
973 abort();
976 visit_type_enum(v, prop->name, &speed, prop->info->enum_table, errp);
979 static void set_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
980 void *opaque, Error **errp)
982 DeviceState *dev = DEVICE(obj);
983 Property *prop = opaque;
984 PCIExpLinkSpeed *p = qdev_get_prop_ptr(dev, prop);
985 int speed;
987 if (dev->realized) {
988 qdev_prop_set_after_realize(dev, name, errp);
989 return;
992 if (!visit_type_enum(v, prop->name, &speed, prop->info->enum_table,
993 errp)) {
994 return;
997 switch (speed) {
998 case PCIE_LINK_SPEED_2_5:
999 *p = QEMU_PCI_EXP_LNK_2_5GT;
1000 break;
1001 case PCIE_LINK_SPEED_5:
1002 *p = QEMU_PCI_EXP_LNK_5GT;
1003 break;
1004 case PCIE_LINK_SPEED_8:
1005 *p = QEMU_PCI_EXP_LNK_8GT;
1006 break;
1007 case PCIE_LINK_SPEED_16:
1008 *p = QEMU_PCI_EXP_LNK_16GT;
1009 break;
1010 default:
1011 /* Unreachable */
1012 abort();
1016 const PropertyInfo qdev_prop_pcie_link_speed = {
1017 .name = "PCIELinkSpeed",
1018 .description = "2_5/5/8/16",
1019 .enum_table = &PCIELinkSpeed_lookup,
1020 .get = get_prop_pcielinkspeed,
1021 .set = set_prop_pcielinkspeed,
1022 .set_default_value = qdev_propinfo_set_default_value_enum,
1025 /* --- PCIELinkWidth 1/2/4/8/12/16/32 -- */
1027 static void get_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
1028 void *opaque, Error **errp)
1030 DeviceState *dev = DEVICE(obj);
1031 Property *prop = opaque;
1032 PCIExpLinkWidth *p = qdev_get_prop_ptr(dev, prop);
1033 int width;
1035 switch (*p) {
1036 case QEMU_PCI_EXP_LNK_X1:
1037 width = PCIE_LINK_WIDTH_1;
1038 break;
1039 case QEMU_PCI_EXP_LNK_X2:
1040 width = PCIE_LINK_WIDTH_2;
1041 break;
1042 case QEMU_PCI_EXP_LNK_X4:
1043 width = PCIE_LINK_WIDTH_4;
1044 break;
1045 case QEMU_PCI_EXP_LNK_X8:
1046 width = PCIE_LINK_WIDTH_8;
1047 break;
1048 case QEMU_PCI_EXP_LNK_X12:
1049 width = PCIE_LINK_WIDTH_12;
1050 break;
1051 case QEMU_PCI_EXP_LNK_X16:
1052 width = PCIE_LINK_WIDTH_16;
1053 break;
1054 case QEMU_PCI_EXP_LNK_X32:
1055 width = PCIE_LINK_WIDTH_32;
1056 break;
1057 default:
1058 /* Unreachable */
1059 abort();
1062 visit_type_enum(v, prop->name, &width, prop->info->enum_table, errp);
1065 static void set_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
1066 void *opaque, Error **errp)
1068 DeviceState *dev = DEVICE(obj);
1069 Property *prop = opaque;
1070 PCIExpLinkWidth *p = qdev_get_prop_ptr(dev, prop);
1071 int width;
1073 if (dev->realized) {
1074 qdev_prop_set_after_realize(dev, name, errp);
1075 return;
1078 if (!visit_type_enum(v, prop->name, &width, prop->info->enum_table,
1079 errp)) {
1080 return;
1083 switch (width) {
1084 case PCIE_LINK_WIDTH_1:
1085 *p = QEMU_PCI_EXP_LNK_X1;
1086 break;
1087 case PCIE_LINK_WIDTH_2:
1088 *p = QEMU_PCI_EXP_LNK_X2;
1089 break;
1090 case PCIE_LINK_WIDTH_4:
1091 *p = QEMU_PCI_EXP_LNK_X4;
1092 break;
1093 case PCIE_LINK_WIDTH_8:
1094 *p = QEMU_PCI_EXP_LNK_X8;
1095 break;
1096 case PCIE_LINK_WIDTH_12:
1097 *p = QEMU_PCI_EXP_LNK_X12;
1098 break;
1099 case PCIE_LINK_WIDTH_16:
1100 *p = QEMU_PCI_EXP_LNK_X16;
1101 break;
1102 case PCIE_LINK_WIDTH_32:
1103 *p = QEMU_PCI_EXP_LNK_X32;
1104 break;
1105 default:
1106 /* Unreachable */
1107 abort();
1111 const PropertyInfo qdev_prop_pcie_link_width = {
1112 .name = "PCIELinkWidth",
1113 .description = "1/2/4/8/12/16/32",
1114 .enum_table = &PCIELinkWidth_lookup,
1115 .get = get_prop_pcielinkwidth,
1116 .set = set_prop_pcielinkwidth,
1117 .set_default_value = qdev_propinfo_set_default_value_enum,