QEMU-Arm Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Tushar Dave <tdave@nvidia.com>
To: qemu-devel@nongnu.org
Cc: alwilliamson@nvidia.com, jgg@nvidia.com, skolothumtho@nvidia.com,
	qemu-arm@nongnu.org, peter.maydell@linaro.org, mst@redhat.com,
	marcel.apfelbaum@gmail.com, devel@edk2.groups.io
Subject: [RFC PATCH v2 1/5] hw/pci: add fixed-bar and pci-bars properties
Date: Wed, 26 Aug 2026 19:40:20 -0500	[thread overview]
Message-ID: <20260827004024.598351-2-tdave@nvidia.com> (raw)
In-Reply-To: <20260827004024.598351-1-tdave@nvidia.com>

Introduce two PCI properties used to configure fixed BAR placement.

The fixed-bar property is added to pcie-root-port. It identifies a
root port whose subordinate PCI hierarchy participates in fixed BAR
placement.

The pci-bars property is added to PCI devices and accepts explicit
BAR addresses in the form:

    pci-bars=barN@<addr>[,barM@<addr>]...

The parser validates the property syntax and stores the user-provided
addresses on the PCIDevice for later use.

These properties are generic and can be used with both emulated and
VFIO-backed PCI devices.

Signed-off-by: Tushar Dave <tdave@nvidia.com>
---
 hw/pci-bridge/pcie_root_port.c |   1 +
 hw/pci/pci.c                   | 129 +++++++++++++++++++++++++++++++++
 include/hw/pci/pci_device.h    |  10 +++
 include/hw/pci/pcie_port.h     |   1 +
 4 files changed, 141 insertions(+)

diff --git a/hw/pci-bridge/pcie_root_port.c b/hw/pci-bridge/pcie_root_port.c
index 7c3e78010b..cea39b92ca 100644
--- a/hw/pci-bridge/pcie_root_port.c
+++ b/hw/pci-bridge/pcie_root_port.c
@@ -151,6 +151,7 @@ static void rp_exit(PCIDevice *d)
 static const Property rp_props[] = {
     DEFINE_PROP_BIT(COMPAT_PROP_PCP, PCIDevice, cap_present,
                     QEMU_PCIE_SLTCAP_PCP_BITNR, true),
+    DEFINE_PROP_BOOL("fixed-bar", PCIESlot, fixed_bar, false),
 };
 
 static void rp_instance_post_init(Object *obj)
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index d3191609e2..1a326f6f91 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -50,6 +50,7 @@
 #include "hw/core/boards.h"
 #include "hw/nvram/fw_cfg.h"
 #include "qapi/error.h"
+#include "qapi/util.h"
 #include "qemu/cutils.h"
 #include "pci-internal.h"
 
@@ -88,6 +89,7 @@ static const Property pci_props[] = {
     DEFINE_PROP_STRING("romfile", PCIDevice, romfile),
     DEFINE_PROP_UINT32("romsize", PCIDevice, romsize, UINT32_MAX),
     DEFINE_PROP_INT32("rombar",  PCIDevice, rom_bar, -1),
+    DEFINE_PROP_STRING("pci-bars", PCIDevice, pci_bars),
     DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present,
                     QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false),
     DEFINE_PROP_BIT("x-pcie-lnksta-dllla", PCIDevice, cap_present,
@@ -225,6 +227,125 @@ static void pci_bus_unrealize(BusState *qbus)
     vmstate_unregister(NULL, &vmstate_pcibus, bus);
 }
 
+#define PCI_BARS_SYNTAX "expected barN@<addr>[,barM@<addr>]*; "
+
+static int pci_parse_bar_token(const char *tok, Error **errp)
+{
+    int v = qapi_enum_parse(&OffAutoPCIBAR_lookup, tok, -1, errp);
+
+    if (v < 0) {
+        return -1;
+    }
+    if (v < OFF_AUTO_PCIBAR_BAR0) {
+        error_setg(errp, "pci-bars: " PCI_BARS_SYNTAX
+                   "invalid BAR '%s', expected bar0..bar5", tok);
+        return -1;
+    }
+    return v - OFF_AUTO_PCIBAR_BAR0;
+}
+
+/*
+ * Parse pci-bars=barN@<addr>[,barM@<addr>]*
+ * Stores parsed addresses into pci_dev->fixed_bar_addrs[].
+ * BAR existence is checked here against io_regions[], which is already
+ * populated by the device's own realize() at this point. Alignment and
+ * MMIO-window placement checks are deferred to blob-write time, when
+ * the full fixed-bar topology is available.
+ */
+static void pci_parse_pci_bars(PCIDevice *pci_dev, Error **errp)
+{
+    Error *local_err = NULL;
+    char **entries = NULL;
+    char **parts = NULL;
+    const char *endp;
+    char **e;
+    uint64_t bar_addr;
+    PCIIORegion *r;
+    int index;
+    int i, ret;
+
+    if (!pci_dev->pci_bars || !*pci_dev->pci_bars) {
+        return;
+    }
+    if (DEVICE(pci_dev)->hotplugged) {
+        error_setg(&local_err,
+                   "pci-bars is not supported on hot-plugged devices");
+        goto out;
+    }
+
+    entries = g_strsplit(pci_dev->pci_bars, ",", -1);
+    for (e = entries; e && *e; e++) {
+        const char *entry = g_strstrip(*e);
+        if (*entry == '\0') {
+            error_setg(&local_err,
+                       "pci-bars: " PCI_BARS_SYNTAX "empty field in list");
+            goto out;
+        }
+
+        parts = g_strsplit(entry, "@", 2);
+        if (!parts[0] || !parts[1]) {
+            error_setg(&local_err,
+                       "pci-bars: " PCI_BARS_SYNTAX "missing '@' in '%s'",
+                       entry);
+            goto out;
+        }
+
+        index = pci_parse_bar_token(parts[0], &local_err);
+        if (index < 0) {
+            goto out;
+        }
+
+        r = &pci_dev->io_regions[index];
+        if (!r->size) {
+            error_setg(&local_err, "pci-bars: bar%d does not exist on %s",
+                       index, pci_dev->name);
+            goto out;
+        }
+        if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
+            error_setg(&local_err, "pci-bars: bar%d on %s is an I/O BAR, "
+                       "not a memory BAR", index, pci_dev->name);
+            goto out;
+        }
+
+        ret = qemu_strtou64(parts[1], &endp, 0, &bar_addr);
+        if (ret) {
+            error_setg(&local_err,
+                       "pci-bars: " PCI_BARS_SYNTAX
+                       "unparseable address in '%s'", entry);
+            goto out;
+        }
+        if (*endp != '\0') {
+            error_setg(&local_err,
+                       "pci-bars: " PCI_BARS_SYNTAX
+                       "trailing data after address in '%s'", entry);
+            goto out;
+        }
+        g_clear_pointer(&parts, g_strfreev);
+
+        if (!pci_dev->fixed_bar_addrs) {
+            pci_dev->fixed_bar_addrs = g_new(pcibus_t, PCI_NUM_REGIONS - 1);
+            for (i = 0; i < PCI_NUM_REGIONS - 1; i++) {
+                pci_dev->fixed_bar_addrs[i] = PCI_BAR_UNMAPPED;
+            }
+        }
+        if (pci_dev->fixed_bar_addrs[index] != PCI_BAR_UNMAPPED) {
+            error_setg(&local_err,
+                       "pci-bars: bar%d specified more than once",
+                       index);
+            goto out;
+        }
+        pci_dev->fixed_bar_addrs[index] = (pcibus_t)bar_addr;
+    }
+
+out:
+    g_clear_pointer(&parts, g_strfreev);
+    g_strfreev(entries);
+    if (local_err) {
+        g_clear_pointer(&pci_dev->fixed_bar_addrs, g_free);
+        error_propagate(errp, local_err);
+    }
+}
+
 static int pcibus_num(PCIBus *bus)
 {
     if (pci_bus_is_root(bus)) {
@@ -1479,6 +1600,7 @@ static void pci_qdev_unrealize(DeviceState *dev)
     pci_unregister_io_regions(pci_dev);
     pci_del_option_rom(pci_dev);
     pcie_sriov_unregister_device(pci_dev);
+    g_clear_pointer(&pci_dev->fixed_bar_addrs, g_free);
 
     if (pc->exit) {
         pc->exit(pci_dev);
@@ -2376,6 +2498,13 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp)
         is_default_rom = true;
     }
 
+    pci_parse_pci_bars(pci_dev, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        pci_qdev_unrealize(DEVICE(pci_dev));
+        return;
+    }
+
     pci_add_option_rom(pci_dev, is_default_rom, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
diff --git a/include/hw/pci/pci_device.h b/include/hw/pci/pci_device.h
index 5cac6e1688..0bdc7ebce3 100644
--- a/include/hw/pci/pci_device.h
+++ b/include/hw/pci/pci_device.h
@@ -187,6 +187,16 @@ struct PCIDevice {
     uint32_t max_bounce_buffer_size;
 
     char *sriov_pf;
+
+    /*
+     * pci-bars property holds user-supplied fixed BAR addresses.
+     * pci_bars is the raw property string (barN@<addr>,...).
+     * fixed_bar_addrs is the parsed array (PCI_NUM_REGIONS-1 entries);
+     * each slot is PCI_BAR_UNMAPPED or the address for that BAR.
+     * NULL when the property is not set.
+     */
+    char      *pci_bars;
+    pcibus_t  *fixed_bar_addrs;
 };
 
 static inline int pci_intx(PCIDevice *pci_dev)
diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h
index b28af067a6..ef66c9768b 100644
--- a/include/hw/pci/pcie_port.h
+++ b/include/hw/pci/pcie_port.h
@@ -65,6 +65,7 @@ struct PCIESlot {
 
     /* broken ACPI hotplug compat knob to preserve 6.1 ABI intact */
     bool        hide_native_hotplug_cap;
+    bool        fixed_bar;
 
     QLIST_ENTRY(PCIESlot) next;
 };
-- 
2.34.1



  reply	other threads:[~2026-08-27  0:42 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-27  0:40 [RFC PATCH v2 0/5] hw/pci, hw/arm/virt: fixed PCI BAR placement Tushar Dave
2026-08-27  0:40 ` Tushar Dave [this message]
2026-08-27  0:40 ` [RFC PATCH v2 2/5] pci: add validation for fixed BAR configuration Tushar Dave
2026-08-27  0:40 ` [RFC PATCH v2 3/5] pci: add fixed BAR fw_cfg blob export Tushar Dave
2026-08-27  0:40 ` [RFC PATCH v2 4/5] hw/arm/virt: export fixed BAR metadata via fw_cfg Tushar Dave
2026-08-27  0:40 ` [RFC PATCH v2 5/5] hw/arm/virt: add highmem-mmio-base property Tushar Dave
2026-08-27  7:18 ` [RFC PATCH v2 0/5] hw/pci, hw/arm/virt: fixed PCI BAR placement Gerd Hoffmann
2026-08-27 13:47   ` Alex Williamson
2026-08-27 14:38     ` [edk2-devel] " Ard Biesheuvel
2026-08-28 15:49       ` Tushar Dave
2026-08-31 13:42         ` Gerd Hoffmann
2026-09-01 21:58           ` Tushar Dave
2026-08-31 13:24     ` Gerd Hoffmann
2026-09-01 22:27       ` Tushar Dave
2026-09-02  6:15         ` Gerd Hoffmann
2026-09-02 15:24           ` Alex Williamson
2026-09-03  9:34             ` Gerd Hoffmann
2026-09-02 16:30           ` Tushar Dave
2026-09-03  9:47             ` Gerd Hoffmann
2026-09-04 13:46               ` Tushar Dave

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260827004024.598351-2-tdave@nvidia.com \
    --to=tdave@nvidia.com \
    --cc=alwilliamson@nvidia.com \
    --cc=devel@edk2.groups.io \
    --cc=jgg@nvidia.com \
    --cc=marcel.apfelbaum@gmail.com \
    --cc=mst@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=skolothumtho@nvidia.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox