diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c
index 60c8989..3156e99 100644
--- a/hw/pci-hotplug.c
+++ b/hw/pci-hotplug.c
@@ -41,7 +41,7 @@ static int read_pci_devaddr(Monitor *mon, const char *addrstr,
     if (!strncmp(addrstr, "pci_addr=", 9)) {
         addrstr += 9;
     }
-    if (qemu_parse_pci_devaddr(addrstr, addr, 0)) {
+    if (qemu_parse_pci_devaddr(addrstr, addr, PCI_DEVADDR_WITH_DOM_BUS_OPT)) {
         monitor_printf(mon, "Invalid pci address\n");
         return -1;
     }
diff --git a/hw/pci.c b/hw/pci.c
index 5056fc4..ccbc6aa 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -517,7 +517,8 @@ PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr)
         return pci_find_bus_nr(pci_find_root_bus(0), 0);
     }
 
-    if (qemu_parse_pci_devaddr(devaddr, &addr, 0) < 0) {
+    if (qemu_parse_pci_devaddr(devaddr, &addr,
+                               PCI_DEVADDR_WITH_DOM_BUS_OPT) < 0) {
         return NULL;
     }
 
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 14ea394..32e41f1 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -817,8 +817,11 @@ PropertyInfo qdev_prop_losttickpolicy = {
 /* --- pci address --- */
 
 /*
- * Parse [[<domain>:]<bus>:]<slot>, return -1 on error if !PCI_DEVADDR_WITH_FUNC
- *       [[<domain>:]<bus>:]<slot>.<func>, return -1 on error
+ * Parse
+ *  [[<domain>:]<bus>:]<slot>...       if PCI_DEVADDR_WITH_DOM_BUS_OPT
+ *                  ...<slot>.<func>   if PCI_DEVADDR_WITH_FUNC
+ *                  ...<slot>[.<func>] if PCI_DEVADDR_WITH_FUNC_OPT
+ * return -1 on error
  */
 int qemu_parse_pci_devaddr(const char *addrstr, PCIDeviceAddress *addr,
                            unsigned int flags)
@@ -836,6 +839,9 @@ int qemu_parse_pci_devaddr(const char *addrstr, PCIDeviceAddress *addr,
         return -1;
     }
     if (*e == ':') {
+        if (!(flags & PCI_DEVADDR_WITH_DOM_BUS_OPT)) {
+            return -1;
+        }
         bus = val;
         p = e + 1;
         val = strtoul(p, &e, 16);
@@ -855,16 +861,19 @@ int qemu_parse_pci_devaddr(const char *addrstr, PCIDeviceAddress *addr,
 
     slot = val;
 
-    if (flags & PCI_DEVADDR_WITH_FUNC) {
+    if (flags & (PCI_DEVADDR_WITH_FUNC | PCI_DEVADDR_WITH_FUNC_OPT)) {
         if (*e != '.') {
-            return -1;
-        }
-        p = e + 1;
-        val = strtoul(p, &e, 16);
-        if (e == p) {
-            return -1;
+            if (flags & PCI_DEVADDR_WITH_FUNC) {
+                return -1;
+            }
+        } else {
+            p = e + 1;
+            val = strtoul(p, &e, 16);
+            if (e == p) {
+                return -1;
+            }
+            func = val;
         }
-        func = val;
     }
 
     if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) {
@@ -890,7 +899,7 @@ static void set_pci_devfn(Object *obj, Visitor *v, void *opaque,
     DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
-    unsigned int slot, fn, n;
+    PCIDeviceAddress addr;
     Error *local_err = NULL;
     char *str;
 
@@ -905,21 +914,11 @@ static void set_pci_devfn(Object *obj, Visitor *v, void *opaque,
         return set_int32(obj, v, opaque, name, errp);
     }
 
-    if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
-        fn = 0;
-        if (sscanf(str, "%x%n", &slot, &n) != 1) {
-            goto invalid;
-        }
-    }
-    if (str[n] != '\0' || fn > 7 || slot > 31) {
-        goto invalid;
+    if (qemu_parse_pci_devaddr(str, &addr, PCI_DEVADDR_WITH_FUNC_OPT) < 0) {
+        error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
+    } else {
+        *ptr = addr.slot << 3 | addr.function;
     }
-    *ptr = slot << 3 | fn;
-    g_free(str);
-    return;
-
-invalid:
-    error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
     g_free(str);
 }
 
diff --git a/hw/qdev.h b/hw/qdev.h
index 102550b..15acfca 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -360,7 +360,9 @@ void qdev_set_parent_bus(DeviceState *dev, BusState *bus);
 
 extern int qdev_hotplug;
 
+#define PCI_DEVADDR_WITH_DOM_BUS_OPT    1
 #define PCI_DEVADDR_WITH_FUNC           2
+#define PCI_DEVADDR_WITH_FUNC_OPT       4
 
 int qemu_parse_pci_devaddr(const char *addrstr, PCIDeviceAddress *addr,
                            unsigned int flags);
