qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 00/17] pci: Abort if pci_add_capability fails
@ 2022-10-28 12:26 Akihiko Odaki
  2022-10-28 12:26 ` [PATCH v5 01/17] hw/vfio/pci: Ensure MSI and MSI-X do not overlap Akihiko Odaki
                   ` (16 more replies)
  0 siblings, 17 replies; 24+ messages in thread
From: Akihiko Odaki @ 2022-10-28 12:26 UTC (permalink / raw)
  Cc: Alex Williamson, qemu-devel, qemu-block, qemu-arm,
	Michael S . Tsirkin, Marcel Apfelbaum, Gerd Hoffmann,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost, John Snow,
	Dmitry Fleytman, Jason Wang, Stefan Weil, Keith Busch,
	Klaus Jensen, Peter Maydell, Andrey Smirnov, Paul Burton,
	Aleksandar Rikalo, Yan Vugenfirer, Yuri Benditovich,
	Akihiko Odaki

pci_add_capability appears most PCI devices. Its error handling required
lots of code, and led to inconsistent behaviors such as:
- passing error_abort
- passing error_fatal
- asserting the returned value
- propagating the error to the caller
- skipping the rest of the function
- just ignoring

The code generating errors in pci_add_capability had a comment which
says:
> Verify that capabilities don't overlap.  Note: device assignment
> depends on this check to verify that the device is not broken.
> Should never trigger for emulated devices, but it's helpful for
> debugging these.

Indeed vfio has some code that passes capability offsets and sizes from
a physical device, but it explicitly pays attention so that the
capabilities never overlap. Therefore, we can always assert that
capabilities never overlap when pci_add_capability is called, resolving
these inconsistencies.

v5:
- Fix capability ID specification in vfio_msi_early_setup (Alex Williamson)
- Use range_covers_byte() (Alex Williamson)
- warn_report() in case of MSI/MSI-X capability overlap (Alex Williamson)

v4:
- Fix typos in messages (Markus Armbruster)
- hw/vfio/pci: Ensure MSI and MSI-X do not overlap (Alex Williamson)

v3:
- Correct patch split between virtio-pci and pci (Markus Armbruster)
- Add messages for individual patches (Markus Armbruster)
- Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

Akihiko Odaki (17):
  hw/vfio/pci: Ensure MSI and MSI-X do not overlap
  pci: Allow to omit errp for pci_add_capability
  hw/i386/amd_iommu: Omit errp for pci_add_capability
  ahci: Omit errp for pci_add_capability
  e1000e: Omit errp for pci_add_capability
  eepro100: Omit errp for pci_add_capability
  hw/nvme: Omit errp for pci_add_capability
  msi: Omit errp for pci_add_capability
  hw/pci/pci_bridge: Omit errp for pci_add_capability
  pcie: Omit errp for pci_add_capability
  pci/shpc: Omit errp for pci_add_capability
  msix: Omit errp for pci_add_capability
  pci/slotid: Omit errp for pci_add_capability
  hw/pci-bridge/pcie_pci_bridge: Omit errp for pci_add_capability
  hw/vfio/pci: Omit errp for pci_add_capability
  virtio-pci: Omit errp for pci_add_capability
  pci: Remove legacy errp from pci_add_capability

 docs/pcie_sriov.txt                |  4 +-
 hw/display/bochs-display.c         |  4 +-
 hw/i386/amd_iommu.c                | 21 ++------
 hw/ide/ich.c                       |  8 +---
 hw/net/e1000e.c                    | 22 ++-------
 hw/net/eepro100.c                  |  7 +--
 hw/nvme/ctrl.c                     | 14 +-----
 hw/pci-bridge/cxl_downstream.c     |  9 +---
 hw/pci-bridge/cxl_upstream.c       |  8 +---
 hw/pci-bridge/i82801b11.c          | 14 +-----
 hw/pci-bridge/pci_bridge_dev.c     |  2 +-
 hw/pci-bridge/pcie_pci_bridge.c    | 19 ++------
 hw/pci-bridge/pcie_root_port.c     | 16 +------
 hw/pci-bridge/xio3130_downstream.c | 15 ++----
 hw/pci-bridge/xio3130_upstream.c   | 15 ++----
 hw/pci-host/designware.c           |  3 +-
 hw/pci-host/xilinx-pcie.c          |  4 +-
 hw/pci/msi.c                       |  9 +---
 hw/pci/msix.c                      |  8 +---
 hw/pci/pci.c                       | 29 +++--------
 hw/pci/pci_bridge.c                | 21 +++-----
 hw/pci/pcie.c                      | 52 ++++++--------------
 hw/pci/shpc.c                      | 23 +++------
 hw/pci/slotid_cap.c                |  8 +---
 hw/usb/hcd-xhci-pci.c              |  3 +-
 hw/vfio/pci-quirks.c               | 15 ++----
 hw/vfio/pci.c                      | 77 ++++++++++++++++++++++--------
 hw/vfio/pci.h                      |  3 ++
 hw/virtio/virtio-pci.c             | 12 ++---
 include/hw/pci/pci.h               |  5 +-
 include/hw/pci/pci_bridge.h        |  5 +-
 include/hw/pci/pcie.h              | 11 ++---
 include/hw/pci/shpc.h              |  3 +-
 include/hw/virtio/virtio-pci.h     |  2 +-
 34 files changed, 155 insertions(+), 316 deletions(-)

-- 
2.37.3



^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v5 01/17] hw/vfio/pci: Ensure MSI and MSI-X do not overlap
  2022-10-28 12:26 [PATCH v5 00/17] pci: Abort if pci_add_capability fails Akihiko Odaki
@ 2022-10-28 12:26 ` Akihiko Odaki
  2022-10-28 14:16   ` Alex Williamson
  2022-10-28 12:26 ` [PATCH v5 02/17] pci: Allow to omit errp for pci_add_capability Akihiko Odaki
                   ` (15 subsequent siblings)
  16 siblings, 1 reply; 24+ messages in thread
From: Akihiko Odaki @ 2022-10-28 12:26 UTC (permalink / raw)
  Cc: Alex Williamson, qemu-devel, qemu-block, qemu-arm,
	Michael S . Tsirkin, Marcel Apfelbaum, Gerd Hoffmann,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost, John Snow,
	Dmitry Fleytman, Jason Wang, Stefan Weil, Keith Busch,
	Klaus Jensen, Peter Maydell, Andrey Smirnov, Paul Burton,
	Aleksandar Rikalo, Yan Vugenfirer, Yuri Benditovich,
	Akihiko Odaki

vfio_add_std_cap() is designed to ensure that capabilities do not
overlap, but it failed to do so for MSI and MSI-X capabilities.

Ensure MSI and MSI-X capabilities do not overlap with others by omitting
other overlapping capabilities.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/vfio/pci.c | 63 +++++++++++++++++++++++++++++++++++++++++++--------
 hw/vfio/pci.h |  3 +++
 2 files changed, 56 insertions(+), 10 deletions(-)

diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 939dcc3d4a..36c8f3dc85 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -1278,23 +1278,42 @@ static void vfio_disable_interrupts(VFIOPCIDevice *vdev)
     }
 }
 
-static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
+static void vfio_msi_early_setup(VFIOPCIDevice *vdev, Error **errp)
 {
     uint16_t ctrl;
-    bool msi_64bit, msi_maskbit;
-    int ret, entries;
-    Error *err = NULL;
+    uint8_t pos;
+
+    pos = pci_find_capability(&vdev->pdev, PCI_CAP_ID_MSI);
+    if (!pos) {
+        return;
+    }
 
     if (pread(vdev->vbasedev.fd, &ctrl, sizeof(ctrl),
               vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) {
         error_setg_errno(errp, errno, "failed reading MSI PCI_CAP_FLAGS");
-        return -errno;
+        return;
     }
-    ctrl = le16_to_cpu(ctrl);
+    vdev->msi_pos = pos;
+    vdev->msi_ctrl = le16_to_cpu(ctrl);
 
-    msi_64bit = !!(ctrl & PCI_MSI_FLAGS_64BIT);
-    msi_maskbit = !!(ctrl & PCI_MSI_FLAGS_MASKBIT);
-    entries = 1 << ((ctrl & PCI_MSI_FLAGS_QMASK) >> 1);
+    vdev->msi_cap_size = 0xa;
+    if ((vdev->msi_ctrl & PCI_MSI_FLAGS_MASKBIT)) {
+        vdev->msi_cap_size += 0xa;
+    }
+    if ((vdev->msi_ctrl & PCI_MSI_FLAGS_64BIT)) {
+        vdev->msi_cap_size += 0x4;
+    }
+}
+
+static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
+{
+    bool msi_64bit, msi_maskbit;
+    int ret, entries;
+    Error *err = NULL;
+
+    msi_64bit = !!(vdev->msi_ctrl & PCI_MSI_FLAGS_64BIT);
+    msi_maskbit = !!(vdev->msi_ctrl & PCI_MSI_FLAGS_MASKBIT);
+    entries = 1 << ((vdev->msi_ctrl & PCI_MSI_FLAGS_QMASK) >> 1);
 
     trace_vfio_msi_setup(vdev->vbasedev.name, pos);
 
@@ -1306,7 +1325,6 @@ static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
         error_propagate_prepend(errp, err, "msi_init failed: ");
         return ret;
     }
-    vdev->msi_cap_size = 0xa + (msi_maskbit ? 0xa : 0) + (msi_64bit ? 0x4 : 0);
 
     return 0;
 }
@@ -1524,6 +1542,7 @@ static void vfio_msix_early_setup(VFIOPCIDevice *vdev, Error **errp)
     pba = le32_to_cpu(pba);
 
     msix = g_malloc0(sizeof(*msix));
+    msix->pos = pos;
     msix->table_bar = table & PCI_MSIX_FLAGS_BIRMASK;
     msix->table_offset = table & ~PCI_MSIX_FLAGS_BIRMASK;
     msix->pba_bar = pba & PCI_MSIX_FLAGS_BIRMASK;
@@ -2025,6 +2044,24 @@ static int vfio_add_std_cap(VFIOPCIDevice *vdev, uint8_t pos, Error **errp)
         }
     }
 
+    if (cap_id != PCI_CAP_ID_MSI &&
+        range_covers_byte(vdev->msi_pos, vdev->msi_cap_size, pos)) {
+        warn_report(VFIO_MSG_PREFIX
+                    "A capability overlaps with MSI, ignoring (%" PRIu8 " @ %" PRIu8 " in [%" PRIu8 ", %" PRIu8 "))",
+                    vdev->vbasedev.name, cap_id, pos,
+                    vdev->msi_pos, vdev->msi_pos + vdev->msi_cap_size);
+        return 0;
+    }
+
+    if (cap_id != PCI_CAP_ID_MSIX && vdev->msix &&
+        range_covers_byte(vdev->msix->pos, MSIX_CAP_LENGTH, pos)) {
+        warn_report(VFIO_MSG_PREFIX
+                    "A capability overlaps with MSI-X, ignoring (%" PRIu8 " @ %" PRIu8 " in [%" PRIu8 ", %" PRIu8 "))",
+                    vdev->vbasedev.name, cap_id, pos,
+                    vdev->msix->pos, vdev->msix->pos + MSIX_CAP_LENGTH);
+        return 0;
+    }
+
     /* Scale down size, esp in case virt caps were added above */
     size = MIN(size, vfio_std_cap_max_size(pdev, pos));
 
@@ -3037,6 +3074,12 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
 
     vfio_bars_prepare(vdev);
 
+    vfio_msi_early_setup(vdev, &err);
+    if (err) {
+        error_propagate(errp, err);
+        goto error;
+    }
+
     vfio_msix_early_setup(vdev, &err);
     if (err) {
         error_propagate(errp, err);
diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h
index 7c236a52f4..9ae0278058 100644
--- a/hw/vfio/pci.h
+++ b/hw/vfio/pci.h
@@ -107,6 +107,7 @@ enum {
 
 /* Cache of MSI-X setup */
 typedef struct VFIOMSIXInfo {
+    uint8_t pos;
     uint8_t table_bar;
     uint8_t pba_bar;
     uint16_t entries;
@@ -128,6 +129,8 @@ struct VFIOPCIDevice {
     unsigned int rom_size;
     off_t rom_offset; /* Offset of ROM region within device fd */
     void *rom;
+    uint8_t msi_pos;
+    uint16_t msi_ctrl;
     int msi_cap_size;
     VFIOMSIVector *msi_vectors;
     VFIOMSIXInfo *msix;
-- 
2.37.3



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v5 02/17] pci: Allow to omit errp for pci_add_capability
  2022-10-28 12:26 [PATCH v5 00/17] pci: Abort if pci_add_capability fails Akihiko Odaki
  2022-10-28 12:26 ` [PATCH v5 01/17] hw/vfio/pci: Ensure MSI and MSI-X do not overlap Akihiko Odaki
@ 2022-10-28 12:26 ` Akihiko Odaki
  2022-10-28 22:35   ` Philippe Mathieu-Daudé
  2022-10-28 12:26 ` [PATCH v5 03/17] hw/i386/amd_iommu: Omit " Akihiko Odaki
                   ` (14 subsequent siblings)
  16 siblings, 1 reply; 24+ messages in thread
From: Akihiko Odaki @ 2022-10-28 12:26 UTC (permalink / raw)
  Cc: Alex Williamson, qemu-devel, qemu-block, qemu-arm,
	Michael S . Tsirkin, Marcel Apfelbaum, Gerd Hoffmann,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost, John Snow,
	Dmitry Fleytman, Jason Wang, Stefan Weil, Keith Busch,
	Klaus Jensen, Peter Maydell, Andrey Smirnov, Paul Burton,
	Aleksandar Rikalo, Yan Vugenfirer, Yuri Benditovich,
	Akihiko Odaki

pci_add_capability appears most PCI devices. Its error handling required
lots of code, and led to inconsistent behaviors such as:
- passing error_abort
- passing error_fatal
- asserting the returned value
- propagating the error to the caller
- skipping the rest of the function
- just ignoring

The code generating errors in pci_add_capability had a comment which
says:
> Verify that capabilities don't overlap.  Note: device assignment
> depends on this check to verify that the device is not broken.
> Should never trigger for emulated devices, but it's helpful for
> debugging these.

Indeed vfio has some code that passes capability offsets and sizes from
a physical device, but it explicitly pays attention so that the
capabilities never overlap. Therefore, we can always assert that
capabilities never overlap when pci_add_capability is called, resolving
these inconsistencies.

Such an implementation of pci_add_capability will not have errp
parameter. However, there are so many callers of pci_add_capability
that it does not make sense to amend all of them at once to match
with the new signature. Instead, this change will allow callers of
pci_add_capability to omit errp as the first step.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/pci/pci.c         |  8 ++++----
 include/hw/pci/pci.h | 13 ++++++++++---
 2 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 2f450f6a72..8ee2171011 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -2513,14 +2513,14 @@ static void pci_del_option_rom(PCIDevice *pdev)
 }
 
 /*
- * On success, pci_add_capability() returns a positive value
+ * On success, pci_add_capability_legacy() returns a positive value
  * that the offset of the pci capability.
  * On failure, it sets an error and returns a negative error
  * code.
  */
-int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
-                       uint8_t offset, uint8_t size,
-                       Error **errp)
+int pci_add_capability_legacy(PCIDevice *pdev, uint8_t cap_id,
+                              uint8_t offset, uint8_t size,
+                              Error **errp)
 {
     uint8_t *config;
     int i, overlapping_cap;
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index b54b6ef88f..51fd106f16 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -2,6 +2,7 @@
 #define QEMU_PCI_H
 
 #include "exec/memory.h"
+#include "qapi/error.h"
 #include "sysemu/dma.h"
 
 /* PCI includes legacy ISA access.  */
@@ -390,9 +391,15 @@ void pci_register_vga(PCIDevice *pci_dev, MemoryRegion *mem,
 void pci_unregister_vga(PCIDevice *pci_dev);
 pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num);
 
-int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
-                       uint8_t offset, uint8_t size,
-                       Error **errp);
+int pci_add_capability_legacy(PCIDevice *pdev, uint8_t cap_id,
+                              uint8_t offset, uint8_t size,
+                              Error **errp);
+
+#define PCI_ADD_CAPABILITY_VA(pdev, cap_id, offset, size, errp, ...) \
+    pci_add_capability_legacy(pdev, cap_id, offset, size, errp)
+
+#define pci_add_capability(...) \
+    PCI_ADD_CAPABILITY_VA(__VA_ARGS__, &error_abort)
 
 void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
 
-- 
2.37.3



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v5 03/17] hw/i386/amd_iommu: Omit errp for pci_add_capability
  2022-10-28 12:26 [PATCH v5 00/17] pci: Abort if pci_add_capability fails Akihiko Odaki
  2022-10-28 12:26 ` [PATCH v5 01/17] hw/vfio/pci: Ensure MSI and MSI-X do not overlap Akihiko Odaki
  2022-10-28 12:26 ` [PATCH v5 02/17] pci: Allow to omit errp for pci_add_capability Akihiko Odaki
@ 2022-10-28 12:26 ` Akihiko Odaki
  2022-10-28 12:26 ` [PATCH v5 04/17] ahci: " Akihiko Odaki
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2022-10-28 12:26 UTC (permalink / raw)
  Cc: Alex Williamson, qemu-devel, qemu-block, qemu-arm,
	Michael S . Tsirkin, Marcel Apfelbaum, Gerd Hoffmann,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost, John Snow,
	Dmitry Fleytman, Jason Wang, Stefan Weil, Keith Busch,
	Klaus Jensen, Peter Maydell, Andrey Smirnov, Paul Burton,
	Aleksandar Rikalo, Yan Vugenfirer, Yuri Benditovich,
	Akihiko Odaki

Omitting errp for pci_add_capability() causes it to abort if
capabilities overlap. This behavior is appropriate here because all of
the capabilities set in this device are defined in the program and
their overlap should not happen unless there is a programming error.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/i386/amd_iommu.c | 21 ++++-----------------
 1 file changed, 4 insertions(+), 17 deletions(-)

diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
index 725f69095b..8a88cbea0a 100644
--- a/hw/i386/amd_iommu.c
+++ b/hw/i386/amd_iommu.c
@@ -1539,7 +1539,6 @@ static void amdvi_sysbus_reset(DeviceState *dev)
 
 static void amdvi_sysbus_realize(DeviceState *dev, Error **errp)
 {
-    int ret = 0;
     AMDVIState *s = AMD_IOMMU_DEVICE(dev);
     MachineState *ms = MACHINE(qdev_get_machine());
     PCMachineState *pcms = PC_MACHINE(ms);
@@ -1553,23 +1552,11 @@ static void amdvi_sysbus_realize(DeviceState *dev, Error **errp)
     if (!qdev_realize(DEVICE(&s->pci), &bus->qbus, errp)) {
         return;
     }
-    ret = pci_add_capability(&s->pci.dev, AMDVI_CAPAB_ID_SEC, 0,
-                                         AMDVI_CAPAB_SIZE, errp);
-    if (ret < 0) {
-        return;
-    }
-    s->capab_offset = ret;
+    s->capab_offset = pci_add_capability(&s->pci.dev, AMDVI_CAPAB_ID_SEC, 0,
+                                         AMDVI_CAPAB_SIZE);
 
-    ret = pci_add_capability(&s->pci.dev, PCI_CAP_ID_MSI, 0,
-                             AMDVI_CAPAB_REG_SIZE, errp);
-    if (ret < 0) {
-        return;
-    }
-    ret = pci_add_capability(&s->pci.dev, PCI_CAP_ID_HT, 0,
-                             AMDVI_CAPAB_REG_SIZE, errp);
-    if (ret < 0) {
-        return;
-    }
+    pci_add_capability(&s->pci.dev, PCI_CAP_ID_MSI, 0, AMDVI_CAPAB_REG_SIZE);
+    pci_add_capability(&s->pci.dev, PCI_CAP_ID_HT, 0, AMDVI_CAPAB_REG_SIZE);
 
     /* Pseudo address space under root PCI bus. */
     x86ms->ioapic_as = amdvi_host_dma_iommu(bus, s, AMDVI_IOAPIC_SB_DEVID);
-- 
2.37.3



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v5 04/17] ahci: Omit errp for pci_add_capability
  2022-10-28 12:26 [PATCH v5 00/17] pci: Abort if pci_add_capability fails Akihiko Odaki
                   ` (2 preceding siblings ...)
  2022-10-28 12:26 ` [PATCH v5 03/17] hw/i386/amd_iommu: Omit " Akihiko Odaki
@ 2022-10-28 12:26 ` Akihiko Odaki
  2022-10-28 12:26 ` [PATCH v5 05/17] e1000e: " Akihiko Odaki
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2022-10-28 12:26 UTC (permalink / raw)
  Cc: Alex Williamson, qemu-devel, qemu-block, qemu-arm,
	Michael S . Tsirkin, Marcel Apfelbaum, Gerd Hoffmann,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost, John Snow,
	Dmitry Fleytman, Jason Wang, Stefan Weil, Keith Busch,
	Klaus Jensen, Peter Maydell, Andrey Smirnov, Paul Burton,
	Aleksandar Rikalo, Yan Vugenfirer, Yuri Benditovich,
	Akihiko Odaki

Omitting errp for pci_add_capability() causes it to abort if
capabilities overlap. This behavior is appropriate here because all of
the capabilities set in this device are defined in the program and
their overlap should not happen unless there is a programming error.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/ide/ich.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 1007a51fcb..3b478b01f8 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -106,7 +106,7 @@ static void pci_ich9_ahci_init(Object *obj)
 static void pci_ich9_ahci_realize(PCIDevice *dev, Error **errp)
 {
     struct AHCIPCIState *d;
-    int sata_cap_offset;
+    uint8_t sata_cap_offset;
     uint8_t *sata_cap;
     d = ICH9_AHCI(dev);
     int ret;
@@ -130,11 +130,7 @@ static void pci_ich9_ahci_realize(PCIDevice *dev, Error **errp)
                      &d->ahci.mem);
 
     sata_cap_offset = pci_add_capability(dev, PCI_CAP_ID_SATA,
-                                          ICH9_SATA_CAP_OFFSET, SATA_CAP_SIZE,
-                                          errp);
-    if (sata_cap_offset < 0) {
-        return;
-    }
+                                          ICH9_SATA_CAP_OFFSET, SATA_CAP_SIZE);
 
     sata_cap = dev->config + sata_cap_offset;
     pci_set_word(sata_cap + SATA_CAP_REV, 0x10);
-- 
2.37.3



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v5 05/17] e1000e: Omit errp for pci_add_capability
  2022-10-28 12:26 [PATCH v5 00/17] pci: Abort if pci_add_capability fails Akihiko Odaki
                   ` (3 preceding siblings ...)
  2022-10-28 12:26 ` [PATCH v5 04/17] ahci: " Akihiko Odaki
@ 2022-10-28 12:26 ` Akihiko Odaki
  2022-10-28 12:26 ` [PATCH v5 06/17] eepro100: " Akihiko Odaki
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2022-10-28 12:26 UTC (permalink / raw)
  Cc: Alex Williamson, qemu-devel, qemu-block, qemu-arm,
	Michael S . Tsirkin, Marcel Apfelbaum, Gerd Hoffmann,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost, John Snow,
	Dmitry Fleytman, Jason Wang, Stefan Weil, Keith Busch,
	Klaus Jensen, Peter Maydell, Andrey Smirnov, Paul Burton,
	Aleksandar Rikalo, Yan Vugenfirer, Yuri Benditovich,
	Akihiko Odaki

Omitting errp for pci_add_capability() causes it to abort if
capabilities overlap. This behavior is appropriate here because all of
the capabilities set in this device are defined in the program and
their overlap should not happen unless there is a programming error.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/net/e1000e.c | 18 +++---------------
 1 file changed, 3 insertions(+), 15 deletions(-)

diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c
index ac96f7665a..e433b8f9a5 100644
--- a/hw/net/e1000e.c
+++ b/hw/net/e1000e.c
@@ -377,17 +377,10 @@ e1000e_gen_dsn(uint8_t *mac)
            (uint64_t)(mac[0])  << 56;
 }
 
-static int
+static void
 e1000e_add_pm_capability(PCIDevice *pdev, uint8_t offset, uint16_t pmc)
 {
-    Error *local_err = NULL;
-    int ret = pci_add_capability(pdev, PCI_CAP_ID_PM, offset,
-                                 PCI_PM_SIZEOF, &local_err);
-
-    if (local_err) {
-        error_report_err(local_err);
-        return ret;
-    }
+    pci_add_capability(pdev, PCI_CAP_ID_PM, offset, PCI_PM_SIZEOF);
 
     pci_set_word(pdev->config + offset + PCI_PM_PMC,
                  PCI_PM_CAP_VER_1_1 |
@@ -400,8 +393,6 @@ e1000e_add_pm_capability(PCIDevice *pdev, uint8_t offset, uint16_t pmc)
 
     pci_set_word(pdev->w1cmask + offset + PCI_PM_CTRL,
                  PCI_PM_CTRL_PME_STATUS);
-
-    return ret;
 }
 
 static void e1000e_write_config(PCIDevice *pci_dev, uint32_t address,
@@ -480,10 +471,7 @@ static void e1000e_pci_realize(PCIDevice *pci_dev, Error **errp)
         trace_e1000e_msi_init_fail(ret);
     }
 
-    if (e1000e_add_pm_capability(pci_dev, e1000e_pmrb_offset,
-                                  PCI_PM_CAP_DSI) < 0) {
-        hw_error("Failed to initialize PM capability");
-    }
+    e1000e_add_pm_capability(pci_dev, e1000e_pmrb_offset, PCI_PM_CAP_DSI);
 
     if (pcie_aer_init(pci_dev, PCI_ERR_VER, e1000e_aer_offset,
                       PCI_ERR_SIZEOF, NULL) < 0) {
-- 
2.37.3



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v5 06/17] eepro100: Omit errp for pci_add_capability
  2022-10-28 12:26 [PATCH v5 00/17] pci: Abort if pci_add_capability fails Akihiko Odaki
                   ` (4 preceding siblings ...)
  2022-10-28 12:26 ` [PATCH v5 05/17] e1000e: " Akihiko Odaki
@ 2022-10-28 12:26 ` Akihiko Odaki
  2022-10-28 12:26 ` [PATCH v5 07/17] hw/nvme: " Akihiko Odaki
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2022-10-28 12:26 UTC (permalink / raw)
  Cc: Alex Williamson, qemu-devel, qemu-block, qemu-arm,
	Michael S . Tsirkin, Marcel Apfelbaum, Gerd Hoffmann,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost, John Snow,
	Dmitry Fleytman, Jason Wang, Stefan Weil, Keith Busch,
	Klaus Jensen, Peter Maydell, Andrey Smirnov, Paul Burton,
	Aleksandar Rikalo, Yan Vugenfirer, Yuri Benditovich,
	Akihiko Odaki

Omitting errp for pci_add_capability() causes it to abort if
capabilities overlap. This behavior is appropriate here because all of
the capabilities set in this device are defined in the program and
their overlap should not happen unless there is a programming error.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/net/eepro100.c | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c
index 679f52f80f..bf2ecdded9 100644
--- a/hw/net/eepro100.c
+++ b/hw/net/eepro100.c
@@ -549,12 +549,7 @@ static void e100_pci_reset(EEPRO100State *s, Error **errp)
     if (info->power_management) {
         /* Power Management Capabilities */
         int cfg_offset = 0xdc;
-        int r = pci_add_capability(&s->dev, PCI_CAP_ID_PM,
-                                   cfg_offset, PCI_PM_SIZEOF,
-                                   errp);
-        if (r < 0) {
-            return;
-        }
+        pci_add_capability(&s->dev, PCI_CAP_ID_PM, cfg_offset, PCI_PM_SIZEOF);
 
         pci_set_word(pci_conf + cfg_offset + PCI_PM_PMC, 0x7e21);
 #if 0 /* TODO: replace dummy code for power management emulation. */
-- 
2.37.3



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v5 07/17] hw/nvme: Omit errp for pci_add_capability
  2022-10-28 12:26 [PATCH v5 00/17] pci: Abort if pci_add_capability fails Akihiko Odaki
                   ` (5 preceding siblings ...)
  2022-10-28 12:26 ` [PATCH v5 06/17] eepro100: " Akihiko Odaki
@ 2022-10-28 12:26 ` Akihiko Odaki
  2022-10-28 12:26 ` [PATCH v5 08/17] msi: " Akihiko Odaki
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2022-10-28 12:26 UTC (permalink / raw)
  Cc: Alex Williamson, qemu-devel, qemu-block, qemu-arm,
	Michael S . Tsirkin, Marcel Apfelbaum, Gerd Hoffmann,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost, John Snow,
	Dmitry Fleytman, Jason Wang, Stefan Weil, Keith Busch,
	Klaus Jensen, Peter Maydell, Andrey Smirnov, Paul Burton,
	Aleksandar Rikalo, Yan Vugenfirer, Yuri Benditovich,
	Akihiko Odaki

Omitting errp for pci_add_capability() causes it to abort if
capabilities overlap. This behavior is appropriate here because all of
the capabilities set in this device are defined in the program and
their overlap should not happen unless there is a programming error.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/nvme/ctrl.c | 14 ++------------
 1 file changed, 2 insertions(+), 12 deletions(-)

diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index 87aeba0564..ff4e2beea6 100644
--- a/hw/nvme/ctrl.c
+++ b/hw/nvme/ctrl.c
@@ -7325,17 +7325,9 @@ static void nvme_init_sriov(NvmeCtrl *n, PCIDevice *pci_dev, uint16_t offset)
                               PCI_BASE_ADDRESS_MEM_TYPE_64, bar_size);
 }
 
-static int nvme_add_pm_capability(PCIDevice *pci_dev, uint8_t offset)
+static void nvme_add_pm_capability(PCIDevice *pci_dev, uint8_t offset)
 {
-    Error *err = NULL;
-    int ret;
-
-    ret = pci_add_capability(pci_dev, PCI_CAP_ID_PM, offset,
-                             PCI_PM_SIZEOF, &err);
-    if (err) {
-        error_report_err(err);
-        return ret;
-    }
+    pci_add_capability(pci_dev, PCI_CAP_ID_PM, offset, PCI_PM_SIZEOF);
 
     pci_set_word(pci_dev->config + offset + PCI_PM_PMC,
                  PCI_PM_CAP_VER_1_2);
@@ -7343,8 +7335,6 @@ static int nvme_add_pm_capability(PCIDevice *pci_dev, uint8_t offset)
                  PCI_PM_CTRL_NO_SOFT_RESET);
     pci_set_word(pci_dev->wmask + offset + PCI_PM_CTRL,
                  PCI_PM_CTRL_STATE_MASK);
-
-    return 0;
 }
 
 static int nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp)
-- 
2.37.3



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v5 08/17] msi: Omit errp for pci_add_capability
  2022-10-28 12:26 [PATCH v5 00/17] pci: Abort if pci_add_capability fails Akihiko Odaki
                   ` (6 preceding siblings ...)
  2022-10-28 12:26 ` [PATCH v5 07/17] hw/nvme: " Akihiko Odaki
@ 2022-10-28 12:26 ` Akihiko Odaki
  2022-10-28 12:26 ` [PATCH v5 09/17] hw/pci/pci_bridge: " Akihiko Odaki
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2022-10-28 12:26 UTC (permalink / raw)
  Cc: Alex Williamson, qemu-devel, qemu-block, qemu-arm,
	Michael S . Tsirkin, Marcel Apfelbaum, Gerd Hoffmann,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost, John Snow,
	Dmitry Fleytman, Jason Wang, Stefan Weil, Keith Busch,
	Klaus Jensen, Peter Maydell, Andrey Smirnov, Paul Burton,
	Aleksandar Rikalo, Yan Vugenfirer, Yuri Benditovich,
	Akihiko Odaki

Omitting errp for pci_add_capability() causes it to abort if
capabilities overlap. A caller of msi_init(), which calls
pci_add_capability() in turn, is expected to ensure that will not
happen.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/pci/msi.c | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/hw/pci/msi.c b/hw/pci/msi.c
index 058d1d1ef1..5283a08b5a 100644
--- a/hw/pci/msi.c
+++ b/hw/pci/msi.c
@@ -194,7 +194,6 @@ int msi_init(struct PCIDevice *dev, uint8_t offset,
     unsigned int vectors_order;
     uint16_t flags;
     uint8_t cap_size;
-    int config_offset;
 
     if (!msi_nonbroken) {
         error_setg(errp, "MSI is not supported by interrupt controller");
@@ -221,13 +220,7 @@ int msi_init(struct PCIDevice *dev, uint8_t offset,
     }
 
     cap_size = msi_cap_sizeof(flags);
-    config_offset = pci_add_capability(dev, PCI_CAP_ID_MSI, offset,
-                                        cap_size, errp);
-    if (config_offset < 0) {
-        return config_offset;
-    }
-
-    dev->msi_cap = config_offset;
+    dev->msi_cap = pci_add_capability(dev, PCI_CAP_ID_MSI, offset, cap_size);
     dev->cap_present |= QEMU_PCI_CAP_MSI;
 
     pci_set_word(dev->config + msi_flags_off(dev), flags);
-- 
2.37.3



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v5 09/17] hw/pci/pci_bridge: Omit errp for pci_add_capability
  2022-10-28 12:26 [PATCH v5 00/17] pci: Abort if pci_add_capability fails Akihiko Odaki
                   ` (7 preceding siblings ...)
  2022-10-28 12:26 ` [PATCH v5 08/17] msi: " Akihiko Odaki
@ 2022-10-28 12:26 ` Akihiko Odaki
  2022-10-28 12:26 ` [PATCH v5 10/17] pcie: " Akihiko Odaki
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2022-10-28 12:26 UTC (permalink / raw)
  Cc: Alex Williamson, qemu-devel, qemu-block, qemu-arm,
	Michael S . Tsirkin, Marcel Apfelbaum, Gerd Hoffmann,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost, John Snow,
	Dmitry Fleytman, Jason Wang, Stefan Weil, Keith Busch,
	Klaus Jensen, Peter Maydell, Andrey Smirnov, Paul Burton,
	Aleksandar Rikalo, Yan Vugenfirer, Yuri Benditovich,
	Akihiko Odaki

Omitting errp for pci_add_capability() causes it to abort if
capabilities overlap. A caller of pci_bridge_ssvid_init(), which calls
pci_add_capability() in turn, is expected to ensure that will not
happen.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/pci-bridge/i82801b11.c          | 14 ++------------
 hw/pci-bridge/pcie_root_port.c     |  7 +------
 hw/pci-bridge/xio3130_downstream.c |  8 ++------
 hw/pci-bridge/xio3130_upstream.c   |  8 ++------
 hw/pci/pci_bridge.c                | 21 ++++++---------------
 include/hw/pci/pci_bridge.h        |  5 ++---
 6 files changed, 15 insertions(+), 48 deletions(-)

diff --git a/hw/pci-bridge/i82801b11.c b/hw/pci-bridge/i82801b11.c
index f28181e210..f45dcdbacc 100644
--- a/hw/pci-bridge/i82801b11.c
+++ b/hw/pci-bridge/i82801b11.c
@@ -61,21 +61,11 @@ typedef struct I82801b11Bridge {
 
 static void i82801b11_bridge_realize(PCIDevice *d, Error **errp)
 {
-    int rc;
-
     pci_bridge_initfn(d, TYPE_PCI_BUS);
 
-    rc = pci_bridge_ssvid_init(d, I82801ba_SSVID_OFFSET,
-                               I82801ba_SSVID_SVID, I82801ba_SSVID_SSID,
-                               errp);
-    if (rc < 0) {
-        goto err_bridge;
-    }
+    pci_bridge_ssvid_init(d, I82801ba_SSVID_OFFSET,
+                          I82801ba_SSVID_SVID, I82801ba_SSVID_SSID);
     pci_config_set_prog_interface(d->config, PCI_CLASS_BRIDGE_PCI_INF_SUB);
-    return;
-
-err_bridge:
-    pci_bridge_exitfn(d);
 }
 
 static const VMStateDescription i82801b11_bridge_dev_vmstate = {
diff --git a/hw/pci-bridge/pcie_root_port.c b/hw/pci-bridge/pcie_root_port.c
index 460e48269d..a9d8c2adb4 100644
--- a/hw/pci-bridge/pcie_root_port.c
+++ b/hw/pci-bridge/pcie_root_port.c
@@ -74,12 +74,7 @@ static void rp_realize(PCIDevice *d, Error **errp)
     }
     pcie_port_init_reg(d);
 
-    rc = pci_bridge_ssvid_init(d, rpc->ssvid_offset, dc->vendor_id,
-                               rpc->ssid, errp);
-    if (rc < 0) {
-        error_append_hint(errp, "Can't init SSV ID, error %d\n", rc);
-        goto err_bridge;
-    }
+    pci_bridge_ssvid_init(d, rpc->ssvid_offset, dc->vendor_id, rpc->ssid);
 
     if (rpc->interrupts_init) {
         rc = rpc->interrupts_init(d, errp);
diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c
index 05e2b06c0c..eea3d3a2df 100644
--- a/hw/pci-bridge/xio3130_downstream.c
+++ b/hw/pci-bridge/xio3130_downstream.c
@@ -81,12 +81,8 @@ static void xio3130_downstream_realize(PCIDevice *d, Error **errp)
         goto err_bridge;
     }
 
-    rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET,
-                               XIO3130_SSVID_SVID, XIO3130_SSVID_SSID,
-                               errp);
-    if (rc < 0) {
-        goto err_msi;
-    }
+    pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET,
+                          XIO3130_SSVID_SVID, XIO3130_SSVID_SSID);
 
     rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_DOWNSTREAM,
                        p->port, errp);
diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c
index 5ff46ef050..d954906d79 100644
--- a/hw/pci-bridge/xio3130_upstream.c
+++ b/hw/pci-bridge/xio3130_upstream.c
@@ -71,12 +71,8 @@ static void xio3130_upstream_realize(PCIDevice *d, Error **errp)
         goto err_bridge;
     }
 
-    rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET,
-                               XIO3130_SSVID_SVID, XIO3130_SSVID_SSID,
-                               errp);
-    if (rc < 0) {
-        goto err_msi;
-    }
+    pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET,
+                          XIO3130_SSVID_SVID, XIO3130_SSVID_SSID);
 
     rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_UPSTREAM,
                        p->port, errp);
diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c
index da34c8ebcd..30032fed64 100644
--- a/hw/pci/pci_bridge.c
+++ b/hw/pci/pci_bridge.c
@@ -42,21 +42,15 @@
 #define PCI_SSVID_SVID          4
 #define PCI_SSVID_SSID          6
 
-int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset,
-                          uint16_t svid, uint16_t ssid,
-                          Error **errp)
+void pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset,
+                           uint16_t svid, uint16_t ssid)
 {
-    int pos;
+    uint8_t pos;
 
-    pos = pci_add_capability(dev, PCI_CAP_ID_SSVID, offset,
-                             PCI_SSVID_SIZEOF, errp);
-    if (pos < 0) {
-        return pos;
-    }
+    pos = pci_add_capability(dev, PCI_CAP_ID_SSVID, offset, PCI_SSVID_SIZEOF);
 
     pci_set_word(dev->config + pos + PCI_SSVID_SVID, svid);
     pci_set_word(dev->config + pos + PCI_SSVID_SSID, ssid);
-    return pos;
 }
 
 /* Accessor function to get parent bridge device from pci bus. */
@@ -455,11 +449,8 @@ int pci_bridge_qemu_reserve_cap_init(PCIDevice *dev, int cap_offset,
             .mem_pref_64 = cpu_to_le64(res_reserve.mem_pref_64)
     };
 
-    int offset = pci_add_capability(dev, PCI_CAP_ID_VNDR,
-                                    cap_offset, cap_len, errp);
-    if (offset < 0) {
-        return offset;
-    }
+    uint8_t offset = pci_add_capability(dev, PCI_CAP_ID_VNDR,
+                                        cap_offset, cap_len);
 
     memcpy(dev->config + offset + PCI_CAP_FLAGS,
            (char *)&cap + PCI_CAP_FLAGS,
diff --git a/include/hw/pci/pci_bridge.h b/include/hw/pci/pci_bridge.h
index ba4bafac7c..e499482972 100644
--- a/include/hw/pci/pci_bridge.h
+++ b/include/hw/pci/pci_bridge.h
@@ -101,9 +101,8 @@ typedef struct PXBDev PXBDev;
 DECLARE_INSTANCE_CHECKER(PXBDev, PXB_CXL_DEV,
                          TYPE_PXB_CXL_DEVICE)
 
-int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset,
-                          uint16_t svid, uint16_t ssid,
-                          Error **errp);
+void pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset,
+                           uint16_t svid, uint16_t ssid);
 
 PCIDevice *pci_bridge_get_device(PCIBus *bus);
 PCIBus *pci_bridge_get_sec_bus(PCIBridge *br);
-- 
2.37.3



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v5 10/17] pcie: Omit errp for pci_add_capability
  2022-10-28 12:26 [PATCH v5 00/17] pci: Abort if pci_add_capability fails Akihiko Odaki
                   ` (8 preceding siblings ...)
  2022-10-28 12:26 ` [PATCH v5 09/17] hw/pci/pci_bridge: " Akihiko Odaki
@ 2022-10-28 12:26 ` Akihiko Odaki
  2022-10-28 12:26 ` [PATCH v5 11/17] pci/shpc: " Akihiko Odaki
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2022-10-28 12:26 UTC (permalink / raw)
  Cc: Alex Williamson, qemu-devel, qemu-block, qemu-arm,
	Michael S . Tsirkin, Marcel Apfelbaum, Gerd Hoffmann,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost, John Snow,
	Dmitry Fleytman, Jason Wang, Stefan Weil, Keith Busch,
	Klaus Jensen, Peter Maydell, Andrey Smirnov, Paul Burton,
	Aleksandar Rikalo, Yan Vugenfirer, Yuri Benditovich,
	Akihiko Odaki, Jonathan Cameron

Omitting errp for pci_add_capability() causes it to abort if
capabilities overlap. A caller of a PCIe function which calls
pci_add_capability() in turn is expected to ensure that will not
happen.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> (for CXL parts)
---
 docs/pcie_sriov.txt                |  4 +--
 hw/display/bochs-display.c         |  4 +--
 hw/net/e1000e.c                    |  4 +--
 hw/pci-bridge/cxl_downstream.c     |  9 ++----
 hw/pci-bridge/cxl_upstream.c       |  8 ++---
 hw/pci-bridge/pcie_pci_bridge.c    |  6 +---
 hw/pci-bridge/pcie_root_port.c     |  9 +-----
 hw/pci-bridge/xio3130_downstream.c |  7 +---
 hw/pci-bridge/xio3130_upstream.c   |  7 +---
 hw/pci-host/designware.c           |  3 +-
 hw/pci-host/xilinx-pcie.c          |  4 +--
 hw/pci/pcie.c                      | 52 ++++++++----------------------
 hw/usb/hcd-xhci-pci.c              |  3 +-
 hw/virtio/virtio-pci.c             |  3 +-
 include/hw/pci/pcie.h              | 11 +++----
 15 files changed, 35 insertions(+), 99 deletions(-)

diff --git a/docs/pcie_sriov.txt b/docs/pcie_sriov.txt
index 11158dbf88..728a73ba7b 100644
--- a/docs/pcie_sriov.txt
+++ b/docs/pcie_sriov.txt
@@ -49,7 +49,7 @@ setting up a BAR for a VF.
    pci_your_pf_dev_realize( ... )
    {
       ...
-      int ret = pcie_endpoint_cap_init(d, 0x70);
+      pcie_endpoint_cap_init(d, 0x70);
       ...
       pcie_ari_init(d, 0x100, 1);
       ...
@@ -79,7 +79,7 @@ setting up a BAR for a VF.
    pci_your_vf_dev_realize( ... )
    {
       ...
-      int ret = pcie_endpoint_cap_init(d, 0x60);
+      pcie_endpoint_cap_init(d, 0x60);
       ...
       pcie_ari_init(d, 0x100, 1);
       ...
diff --git a/hw/display/bochs-display.c b/hw/display/bochs-display.c
index 8ed734b195..111cabcfb3 100644
--- a/hw/display/bochs-display.c
+++ b/hw/display/bochs-display.c
@@ -265,7 +265,6 @@ static void bochs_display_realize(PCIDevice *dev, Error **errp)
 {
     BochsDisplayState *s = BOCHS_DISPLAY(dev);
     Object *obj = OBJECT(dev);
-    int ret;
 
     if (s->vgamem < 4 * MiB) {
         error_setg(errp, "bochs-display: video memory too small");
@@ -302,8 +301,7 @@ static void bochs_display_realize(PCIDevice *dev, Error **errp)
     }
 
     if (pci_bus_is_express(pci_get_bus(dev))) {
-        ret = pcie_endpoint_cap_init(dev, 0x80);
-        assert(ret > 0);
+        pcie_endpoint_cap_init(dev, 0x80);
     } else {
         dev->cap_present &= ~QEMU_PCI_CAP_EXPRESS;
     }
diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c
index e433b8f9a5..aea4305c43 100644
--- a/hw/net/e1000e.c
+++ b/hw/net/e1000e.c
@@ -462,9 +462,7 @@ static void e1000e_pci_realize(PCIDevice *pci_dev, Error **errp)
 
     e1000e_init_msix(s);
 
-    if (pcie_endpoint_cap_v1_init(pci_dev, e1000e_pcie_offset) < 0) {
-        hw_error("Failed to initialize PCIe capability");
-    }
+    pcie_endpoint_cap_v1_init(pci_dev, e1000e_pcie_offset);
 
     ret = msi_init(PCI_DEVICE(s), 0xD0, 1, true, false, NULL);
     if (ret) {
diff --git a/hw/pci-bridge/cxl_downstream.c b/hw/pci-bridge/cxl_downstream.c
index a361e519d0..1980dd9c6c 100644
--- a/hw/pci-bridge/cxl_downstream.c
+++ b/hw/pci-bridge/cxl_downstream.c
@@ -155,12 +155,8 @@ static void cxl_dsp_realize(PCIDevice *d, Error **errp)
         goto err_bridge;
     }
 
-    rc = pcie_cap_init(d, CXL_DOWNSTREAM_PORT_EXP_OFFSET,
-                       PCI_EXP_TYPE_DOWNSTREAM, p->port,
-                       errp);
-    if (rc < 0) {
-        goto err_msi;
-    }
+    pcie_cap_init(d, CXL_DOWNSTREAM_PORT_EXP_OFFSET,
+                  PCI_EXP_TYPE_DOWNSTREAM, p->port);
 
     pcie_cap_flr_init(d);
     pcie_cap_deverr_init(d);
@@ -195,7 +191,6 @@ static void cxl_dsp_realize(PCIDevice *d, Error **errp)
     pcie_chassis_del_slot(s);
  err_pcie_cap:
     pcie_cap_exit(d);
- err_msi:
     msi_uninit(d);
  err_bridge:
     pci_bridge_exitfn(d);
diff --git a/hw/pci-bridge/cxl_upstream.c b/hw/pci-bridge/cxl_upstream.c
index a83a3e81e4..26f27ba681 100644
--- a/hw/pci-bridge/cxl_upstream.c
+++ b/hw/pci-bridge/cxl_upstream.c
@@ -138,11 +138,8 @@ static void cxl_usp_realize(PCIDevice *d, Error **errp)
         goto err_bridge;
     }
 
-    rc = pcie_cap_init(d, CXL_UPSTREAM_PORT_PCIE_CAP_OFFSET,
-                       PCI_EXP_TYPE_UPSTREAM, p->port, errp);
-    if (rc < 0) {
-        goto err_msi;
-    }
+    pcie_cap_init(d, CXL_UPSTREAM_PORT_PCIE_CAP_OFFSET,
+                  PCI_EXP_TYPE_UPSTREAM, p->port);
 
     pcie_cap_flr_init(d);
     pcie_cap_deverr_init(d);
@@ -165,7 +162,6 @@ static void cxl_usp_realize(PCIDevice *d, Error **errp)
 
 err_cap:
     pcie_cap_exit(d);
-err_msi:
     msi_uninit(d);
 err_bridge:
     pci_bridge_exitfn(d);
diff --git a/hw/pci-bridge/pcie_pci_bridge.c b/hw/pci-bridge/pcie_pci_bridge.c
index 1cd917a459..df5dfdd139 100644
--- a/hw/pci-bridge/pcie_pci_bridge.c
+++ b/hw/pci-bridge/pcie_pci_bridge.c
@@ -47,10 +47,7 @@ static void pcie_pci_bridge_realize(PCIDevice *d, Error **errp)
         goto error;
     }
 
-    rc = pcie_cap_init(d, 0, PCI_EXP_TYPE_PCI_BRIDGE, 0, errp);
-    if (rc < 0) {
-        goto cap_error;
-    }
+    pcie_cap_init(d, 0, PCI_EXP_TYPE_PCI_BRIDGE, 0);
 
     pos = pci_add_capability(d, PCI_CAP_ID_PM, 0, PCI_PM_SIZEOF, errp);
     if (pos < 0) {
@@ -90,7 +87,6 @@ msi_error:
 aer_error:
 pm_error:
     pcie_cap_exit(d);
-cap_error:
     shpc_cleanup(d, &pcie_br->shpc_bar);
 error:
     pci_bridge_exitfn(d);
diff --git a/hw/pci-bridge/pcie_root_port.c b/hw/pci-bridge/pcie_root_port.c
index a9d8c2adb4..92cebc7cce 100644
--- a/hw/pci-bridge/pcie_root_port.c
+++ b/hw/pci-bridge/pcie_root_port.c
@@ -83,13 +83,7 @@ static void rp_realize(PCIDevice *d, Error **errp)
         }
     }
 
-    rc = pcie_cap_init(d, rpc->exp_offset, PCI_EXP_TYPE_ROOT_PORT,
-                       p->port, errp);
-    if (rc < 0) {
-        error_append_hint(errp, "Can't add Root Port capability, "
-                          "error %d\n", rc);
-        goto err_int;
-    }
+    pcie_cap_init(d, rpc->exp_offset, PCI_EXP_TYPE_ROOT_PORT, p->port);
 
     pcie_cap_arifwd_init(d);
     pcie_cap_deverr_init(d);
@@ -120,7 +114,6 @@ err:
     pcie_chassis_del_slot(s);
 err_pcie_cap:
     pcie_cap_exit(d);
-err_int:
     if (rpc->interrupts_uninit) {
         rpc->interrupts_uninit(d);
     }
diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c
index eea3d3a2df..37307c8c23 100644
--- a/hw/pci-bridge/xio3130_downstream.c
+++ b/hw/pci-bridge/xio3130_downstream.c
@@ -84,11 +84,7 @@ static void xio3130_downstream_realize(PCIDevice *d, Error **errp)
     pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET,
                           XIO3130_SSVID_SVID, XIO3130_SSVID_SSID);
 
-    rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_DOWNSTREAM,
-                       p->port, errp);
-    if (rc < 0) {
-        goto err_msi;
-    }
+    pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_DOWNSTREAM, p->port);
     pcie_cap_flr_init(d);
     pcie_cap_deverr_init(d);
     pcie_cap_slot_init(d, s);
@@ -113,7 +109,6 @@ err:
     pcie_chassis_del_slot(s);
 err_pcie_cap:
     pcie_cap_exit(d);
-err_msi:
     msi_uninit(d);
 err_bridge:
     pci_bridge_exitfn(d);
diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c
index d954906d79..546224d97c 100644
--- a/hw/pci-bridge/xio3130_upstream.c
+++ b/hw/pci-bridge/xio3130_upstream.c
@@ -74,11 +74,7 @@ static void xio3130_upstream_realize(PCIDevice *d, Error **errp)
     pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET,
                           XIO3130_SSVID_SVID, XIO3130_SSVID_SSID);
 
-    rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_UPSTREAM,
-                       p->port, errp);
-    if (rc < 0) {
-        goto err_msi;
-    }
+    pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_UPSTREAM, p->port);
     pcie_cap_flr_init(d);
     pcie_cap_deverr_init(d);
 
@@ -92,7 +88,6 @@ static void xio3130_upstream_realize(PCIDevice *d, Error **errp)
 
 err:
     pcie_cap_exit(d);
-err_msi:
     msi_uninit(d);
 err_bridge:
     pci_bridge_exitfn(d);
diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c
index bde3a343a2..3e4972ad76 100644
--- a/hw/pci-host/designware.c
+++ b/hw/pci-host/designware.c
@@ -414,8 +414,7 @@ static void designware_pcie_root_realize(PCIDevice *dev, Error **errp)
 
     pcie_port_init_reg(dev);
 
-    pcie_cap_init(dev, 0x70, PCI_EXP_TYPE_ROOT_PORT,
-                  0, &error_fatal);
+    pcie_cap_init(dev, 0x70, PCI_EXP_TYPE_ROOT_PORT, 0);
 
     msi_nonbroken = true;
     msi_init(dev, 0x50, 32, true, true, &error_fatal);
diff --git a/hw/pci-host/xilinx-pcie.c b/hw/pci-host/xilinx-pcie.c
index 38d5901a45..49f0ac5e35 100644
--- a/hw/pci-host/xilinx-pcie.c
+++ b/hw/pci-host/xilinx-pcie.c
@@ -282,9 +282,7 @@ static void xilinx_pcie_root_realize(PCIDevice *pci_dev, Error **errp)
 
     pci_bridge_initfn(pci_dev, TYPE_PCI_BUS);
 
-    if (pcie_endpoint_cap_v1_init(pci_dev, 0x80) < 0) {
-        error_setg(errp, "Failed to initialize PCIe capability");
-    }
+    pcie_endpoint_cap_v1_init(pci_dev, 0x80);
 }
 
 static void xilinx_pcie_root_class_init(ObjectClass *klass, void *data)
diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
index 68a62da0b5..923ad29c52 100644
--- a/hw/pci/pcie.c
+++ b/hw/pci/pcie.c
@@ -151,21 +151,15 @@ static void pcie_cap_fill_slot_lnk(PCIDevice *dev)
     }
 }
 
-int pcie_cap_init(PCIDevice *dev, uint8_t offset,
-                  uint8_t type, uint8_t port,
-                  Error **errp)
+void pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port)
 {
     /* PCIe cap v2 init */
-    int pos;
+    uint8_t pos;
     uint8_t *exp_cap;
 
     assert(pci_is_express(dev));
 
-    pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset,
-                             PCI_EXP_VER2_SIZEOF, errp);
-    if (pos < 0) {
-        return pos;
-    }
+    pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset, PCI_EXP_VER2_SIZEOF);
     dev->exp.exp_cap = pos;
     exp_cap = dev->config + pos;
 
@@ -185,38 +179,26 @@ int pcie_cap_init(PCIDevice *dev, uint8_t offset,
         /* read-only to behave like a 'NULL' Extended Capability Header */
         pci_set_long(dev->wmask + PCI_CONFIG_SPACE_SIZE, 0);
     }
-
-    return pos;
 }
 
-int pcie_cap_v1_init(PCIDevice *dev, uint8_t offset, uint8_t type,
-                     uint8_t port)
+void pcie_cap_v1_init(PCIDevice *dev, uint8_t offset, uint8_t type,
+                      uint8_t port)
 {
     /* PCIe cap v1 init */
-    int pos;
-    Error *local_err = NULL;
+    uint8_t pos;
 
     assert(pci_is_express(dev));
 
-    pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset,
-                             PCI_EXP_VER1_SIZEOF, &local_err);
-    if (pos < 0) {
-        error_report_err(local_err);
-        return pos;
-    }
+    pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset, PCI_EXP_VER1_SIZEOF);
     dev->exp.exp_cap = pos;
 
     pcie_cap_v1_fill(dev, port, type, PCI_EXP_FLAGS_VER1);
-
-    return pos;
 }
 
-static int
+static void
 pcie_endpoint_cap_common_init(PCIDevice *dev, uint8_t offset, uint8_t cap_size)
 {
     uint8_t type = PCI_EXP_TYPE_ENDPOINT;
-    Error *local_err = NULL;
-    int ret;
 
     /*
      * Windows guests will report Code 10, device cannot start, if
@@ -229,26 +211,20 @@ pcie_endpoint_cap_common_init(PCIDevice *dev, uint8_t offset, uint8_t cap_size)
     }
 
     if (cap_size == PCI_EXP_VER1_SIZEOF) {
-        return pcie_cap_v1_init(dev, offset, type, 0);
+        pcie_cap_v1_init(dev, offset, type, 0);
     } else {
-        ret = pcie_cap_init(dev, offset, type, 0, &local_err);
-
-        if (ret < 0) {
-            error_report_err(local_err);
-        }
-
-        return ret;
+        pcie_cap_init(dev, offset, type, 0);
     }
 }
 
-int pcie_endpoint_cap_init(PCIDevice *dev, uint8_t offset)
+void pcie_endpoint_cap_init(PCIDevice *dev, uint8_t offset)
 {
-    return pcie_endpoint_cap_common_init(dev, offset, PCI_EXP_VER2_SIZEOF);
+    pcie_endpoint_cap_common_init(dev, offset, PCI_EXP_VER2_SIZEOF);
 }
 
-int pcie_endpoint_cap_v1_init(PCIDevice *dev, uint8_t offset)
+void pcie_endpoint_cap_v1_init(PCIDevice *dev, uint8_t offset)
 {
-    return pcie_endpoint_cap_common_init(dev, offset, PCI_EXP_VER1_SIZEOF);
+    pcie_endpoint_cap_common_init(dev, offset, PCI_EXP_VER1_SIZEOF);
 }
 
 void pcie_cap_exit(PCIDevice *dev)
diff --git a/hw/usb/hcd-xhci-pci.c b/hw/usb/hcd-xhci-pci.c
index e934b1a5b1..0eba2b36ae 100644
--- a/hw/usb/hcd-xhci-pci.c
+++ b/hw/usb/hcd-xhci-pci.c
@@ -150,8 +150,7 @@ static void usb_xhci_pci_realize(struct PCIDevice *dev, Error **errp)
 
     if (pci_bus_is_express(pci_get_bus(dev)) ||
         xhci_get_flag(&s->xhci, XHCI_FLAG_FORCE_PCIE_ENDCAP)) {
-        ret = pcie_endpoint_cap_init(dev, 0xa0);
-        assert(ret > 0);
+        pcie_endpoint_cap_init(dev, 0xa0);
     }
 
     if (s->msix != ON_OFF_AUTO_OFF) {
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 45327f0b31..c37bdc77ea 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1862,8 +1862,7 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
         int pos;
         uint16_t last_pcie_cap_offset = PCI_CONFIG_SPACE_SIZE;
 
-        pos = pcie_endpoint_cap_init(pci_dev, 0);
-        assert(pos > 0);
+        pcie_endpoint_cap_init(pci_dev, 0);
 
         pos = pci_add_capability(pci_dev, PCI_CAP_ID_PM, 0,
                                  PCI_PM_SIZEOF, errp);
diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h
index 798a262a0a..7a35851ae8 100644
--- a/include/hw/pci/pcie.h
+++ b/include/hw/pci/pcie.h
@@ -92,13 +92,12 @@ struct PCIExpressDevice {
 #define COMPAT_PROP_PCP "power_controller_present"
 
 /* PCI express capability helper functions */
-int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type,
-                  uint8_t port, Error **errp);
-int pcie_cap_v1_init(PCIDevice *dev, uint8_t offset,
-                     uint8_t type, uint8_t port);
-int pcie_endpoint_cap_init(PCIDevice *dev, uint8_t offset);
+void pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port);
+void pcie_cap_v1_init(PCIDevice *dev, uint8_t offset,
+                      uint8_t type, uint8_t port);
+void pcie_endpoint_cap_init(PCIDevice *dev, uint8_t offset);
 void pcie_cap_exit(PCIDevice *dev);
-int pcie_endpoint_cap_v1_init(PCIDevice *dev, uint8_t offset);
+void pcie_endpoint_cap_v1_init(PCIDevice *dev, uint8_t offset);
 void pcie_cap_v1_exit(PCIDevice *dev);
 uint8_t pcie_cap_get_type(const PCIDevice *dev);
 void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector);
-- 
2.37.3



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v5 11/17] pci/shpc: Omit errp for pci_add_capability
  2022-10-28 12:26 [PATCH v5 00/17] pci: Abort if pci_add_capability fails Akihiko Odaki
                   ` (9 preceding siblings ...)
  2022-10-28 12:26 ` [PATCH v5 10/17] pcie: " Akihiko Odaki
@ 2022-10-28 12:26 ` Akihiko Odaki
  2022-10-28 12:26 ` [PATCH v5 12/17] msix: " Akihiko Odaki
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2022-10-28 12:26 UTC (permalink / raw)
  Cc: Alex Williamson, qemu-devel, qemu-block, qemu-arm,
	Michael S . Tsirkin, Marcel Apfelbaum, Gerd Hoffmann,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost, John Snow,
	Dmitry Fleytman, Jason Wang, Stefan Weil, Keith Busch,
	Klaus Jensen, Peter Maydell, Andrey Smirnov, Paul Burton,
	Aleksandar Rikalo, Yan Vugenfirer, Yuri Benditovich,
	Akihiko Odaki

Omitting errp for pci_add_capability() causes it to abort if
capabilities overlap. A caller of shpc_init(), which calls
pci_add_capability() in turn, is expected to ensure that will not
happen.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/pci-bridge/pci_bridge_dev.c  |  2 +-
 hw/pci-bridge/pcie_pci_bridge.c |  2 +-
 hw/pci/shpc.c                   | 23 ++++++-----------------
 include/hw/pci/shpc.h           |  3 +--
 4 files changed, 9 insertions(+), 21 deletions(-)

diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c
index 657a06ddbe..4b6d1876eb 100644
--- a/hw/pci-bridge/pci_bridge_dev.c
+++ b/hw/pci-bridge/pci_bridge_dev.c
@@ -66,7 +66,7 @@ static void pci_bridge_dev_realize(PCIDevice *dev, Error **errp)
         dev->config[PCI_INTERRUPT_PIN] = 0x1;
         memory_region_init(&bridge_dev->bar, OBJECT(dev), "shpc-bar",
                            shpc_bar_size(dev));
-        err = shpc_init(dev, &br->sec_bus, &bridge_dev->bar, 0, errp);
+        err = shpc_init(dev, &br->sec_bus, &bridge_dev->bar, 0);
         if (err) {
             goto shpc_error;
         }
diff --git a/hw/pci-bridge/pcie_pci_bridge.c b/hw/pci-bridge/pcie_pci_bridge.c
index df5dfdd139..99778e3e24 100644
--- a/hw/pci-bridge/pcie_pci_bridge.c
+++ b/hw/pci-bridge/pcie_pci_bridge.c
@@ -42,7 +42,7 @@ static void pcie_pci_bridge_realize(PCIDevice *d, Error **errp)
     d->config[PCI_INTERRUPT_PIN] = 0x1;
     memory_region_init(&pcie_br->shpc_bar, OBJECT(d), "shpc-bar",
                        shpc_bar_size(d));
-    rc = shpc_init(d, &br->sec_bus, &pcie_br->shpc_bar, 0, errp);
+    rc = shpc_init(d, &br->sec_bus, &pcie_br->shpc_bar, 0);
     if (rc) {
         goto error;
     }
diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c
index e71f3a7483..5b3228c793 100644
--- a/hw/pci/shpc.c
+++ b/hw/pci/shpc.c
@@ -440,16 +440,11 @@ static void shpc_cap_update_dword(PCIDevice *d)
 }
 
 /* Add SHPC capability to the config space for the device. */
-static int shpc_cap_add_config(PCIDevice *d, Error **errp)
+static void shpc_cap_add_config(PCIDevice *d)
 {
     uint8_t *config;
-    int config_offset;
-    config_offset = pci_add_capability(d, PCI_CAP_ID_SHPC,
-                                       0, SHPC_CAP_LENGTH,
-                                       errp);
-    if (config_offset < 0) {
-        return config_offset;
-    }
+    uint8_t config_offset;
+    config_offset = pci_add_capability(d, PCI_CAP_ID_SHPC, 0, SHPC_CAP_LENGTH);
     config = d->config + config_offset;
 
     pci_set_byte(config + SHPC_CAP_DWORD_SELECT, 0);
@@ -459,7 +454,6 @@ static int shpc_cap_add_config(PCIDevice *d, Error **errp)
     /* Make dword select and data writable. */
     pci_set_byte(d->wmask + config_offset + SHPC_CAP_DWORD_SELECT, 0xff);
     pci_set_long(d->wmask + config_offset + SHPC_CAP_DWORD_DATA, 0xffffffff);
-    return 0;
 }
 
 static uint64_t shpc_mmio_read(void *opaque, hwaddr addr,
@@ -584,18 +578,13 @@ void shpc_device_unplug_request_cb(HotplugHandler *hotplug_dev,
 }
 
 /* Initialize the SHPC structure in bridge's BAR. */
-int shpc_init(PCIDevice *d, PCIBus *sec_bus, MemoryRegion *bar,
-              unsigned offset, Error **errp)
+int shpc_init(PCIDevice *d, PCIBus *sec_bus, MemoryRegion *bar, unsigned offset)
 {
-    int i, ret;
+    int i;
     int nslots = SHPC_MAX_SLOTS; /* TODO: qdev property? */
     SHPCDevice *shpc = d->shpc = g_malloc0(sizeof(*d->shpc));
     shpc->sec_bus = sec_bus;
-    ret = shpc_cap_add_config(d, errp);
-    if (ret) {
-        g_free(d->shpc);
-        return ret;
-    }
+    shpc_cap_add_config(d);
     if (nslots < SHPC_MIN_SLOTS) {
         return 0;
     }
diff --git a/include/hw/pci/shpc.h b/include/hw/pci/shpc.h
index d5683b7399..18ab16ec9f 100644
--- a/include/hw/pci/shpc.h
+++ b/include/hw/pci/shpc.h
@@ -38,8 +38,7 @@ struct SHPCDevice {
 
 void shpc_reset(PCIDevice *d);
 int shpc_bar_size(PCIDevice *dev);
-int shpc_init(PCIDevice *dev, PCIBus *sec_bus, MemoryRegion *bar,
-              unsigned off, Error **errp);
+int shpc_init(PCIDevice *dev, PCIBus *sec_bus, MemoryRegion *bar, unsigned off);
 void shpc_cleanup(PCIDevice *dev, MemoryRegion *bar);
 void shpc_free(PCIDevice *dev);
 void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int len);
-- 
2.37.3



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v5 12/17] msix: Omit errp for pci_add_capability
  2022-10-28 12:26 [PATCH v5 00/17] pci: Abort if pci_add_capability fails Akihiko Odaki
                   ` (10 preceding siblings ...)
  2022-10-28 12:26 ` [PATCH v5 11/17] pci/shpc: " Akihiko Odaki
@ 2022-10-28 12:26 ` Akihiko Odaki
  2022-10-28 12:26 ` [PATCH v5 13/17] pci/slotid: " Akihiko Odaki
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2022-10-28 12:26 UTC (permalink / raw)
  Cc: Alex Williamson, qemu-devel, qemu-block, qemu-arm,
	Michael S . Tsirkin, Marcel Apfelbaum, Gerd Hoffmann,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost, John Snow,
	Dmitry Fleytman, Jason Wang, Stefan Weil, Keith Busch,
	Klaus Jensen, Peter Maydell, Andrey Smirnov, Paul Burton,
	Aleksandar Rikalo, Yan Vugenfirer, Yuri Benditovich,
	Akihiko Odaki

Omitting errp for pci_add_capability() causes it to abort if
capabilities overlap. A caller of msix_init(), which calls
pci_add_capability() in turn, is expected to ensure that will not
happen.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/pci/msix.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/hw/pci/msix.c b/hw/pci/msix.c
index 1e381a9813..28af83403b 100644
--- a/hw/pci/msix.c
+++ b/hw/pci/msix.c
@@ -311,7 +311,7 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
               uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos,
               Error **errp)
 {
-    int cap;
+    uint8_t cap;
     unsigned table_size, pba_size;
     uint8_t *config;
 
@@ -340,11 +340,7 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
         return -EINVAL;
     }
 
-    cap = pci_add_capability(dev, PCI_CAP_ID_MSIX,
-                              cap_pos, MSIX_CAP_LENGTH, errp);
-    if (cap < 0) {
-        return cap;
-    }
+    cap = pci_add_capability(dev, PCI_CAP_ID_MSIX, cap_pos, MSIX_CAP_LENGTH);
 
     dev->msix_cap = cap;
     dev->cap_present |= QEMU_PCI_CAP_MSIX;
-- 
2.37.3



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v5 13/17] pci/slotid: Omit errp for pci_add_capability
  2022-10-28 12:26 [PATCH v5 00/17] pci: Abort if pci_add_capability fails Akihiko Odaki
                   ` (11 preceding siblings ...)
  2022-10-28 12:26 ` [PATCH v5 12/17] msix: " Akihiko Odaki
@ 2022-10-28 12:26 ` Akihiko Odaki
  2022-10-28 12:26 ` [PATCH v5 14/17] hw/pci-bridge/pcie_pci_bridge: " Akihiko Odaki
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2022-10-28 12:26 UTC (permalink / raw)
  Cc: Alex Williamson, qemu-devel, qemu-block, qemu-arm,
	Michael S . Tsirkin, Marcel Apfelbaum, Gerd Hoffmann,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost, John Snow,
	Dmitry Fleytman, Jason Wang, Stefan Weil, Keith Busch,
	Klaus Jensen, Peter Maydell, Andrey Smirnov, Paul Burton,
	Aleksandar Rikalo, Yan Vugenfirer, Yuri Benditovich,
	Akihiko Odaki

Omitting errp for pci_add_capability() causes it to abort if
capabilities overlap. A caller of slotid_cap_init(), which calls
pci_add_capability() in turn, is expected to ensure that will not
happen.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/pci/slotid_cap.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/hw/pci/slotid_cap.c b/hw/pci/slotid_cap.c
index 36d021b4a6..5da8c82133 100644
--- a/hw/pci/slotid_cap.c
+++ b/hw/pci/slotid_cap.c
@@ -12,7 +12,7 @@ int slotid_cap_init(PCIDevice *d, int nslots,
                     unsigned offset,
                     Error **errp)
 {
-    int cap;
+    uint8_t cap;
 
     if (!chassis) {
         error_setg(errp, "Bridge chassis not specified. Each bridge is required"
@@ -24,11 +24,7 @@ int slotid_cap_init(PCIDevice *d, int nslots,
         return -EINVAL;
     }
 
-    cap = pci_add_capability(d, PCI_CAP_ID_SLOTID, offset,
-                             SLOTID_CAP_LENGTH, errp);
-    if (cap < 0) {
-        return cap;
-    }
+    cap = pci_add_capability(d, PCI_CAP_ID_SLOTID, offset, SLOTID_CAP_LENGTH);
     /* We make each chassis unique, this way each bridge is First in Chassis */
     d->config[cap + PCI_SID_ESR] = PCI_SID_ESR_FIC |
         (nslots << SLOTID_NSLOTS_SHIFT);
-- 
2.37.3



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v5 14/17] hw/pci-bridge/pcie_pci_bridge: Omit errp for pci_add_capability
  2022-10-28 12:26 [PATCH v5 00/17] pci: Abort if pci_add_capability fails Akihiko Odaki
                   ` (12 preceding siblings ...)
  2022-10-28 12:26 ` [PATCH v5 13/17] pci/slotid: " Akihiko Odaki
@ 2022-10-28 12:26 ` Akihiko Odaki
  2022-10-28 12:26 ` [PATCH v5 15/17] hw/vfio/pci: " Akihiko Odaki
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2022-10-28 12:26 UTC (permalink / raw)
  Cc: Alex Williamson, qemu-devel, qemu-block, qemu-arm,
	Michael S . Tsirkin, Marcel Apfelbaum, Gerd Hoffmann,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost, John Snow,
	Dmitry Fleytman, Jason Wang, Stefan Weil, Keith Busch,
	Klaus Jensen, Peter Maydell, Andrey Smirnov, Paul Burton,
	Aleksandar Rikalo, Yan Vugenfirer, Yuri Benditovich,
	Akihiko Odaki

Omitting errp for pci_add_capability() causes it to abort if
capabilities overlap. This behavior is appropriate heare because all of
the capabilities set in this device are defined in the program and
their overlap should not happen unless there is a programming error.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/pci-bridge/pcie_pci_bridge.c | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/hw/pci-bridge/pcie_pci_bridge.c b/hw/pci-bridge/pcie_pci_bridge.c
index 99778e3e24..1b839465e7 100644
--- a/hw/pci-bridge/pcie_pci_bridge.c
+++ b/hw/pci-bridge/pcie_pci_bridge.c
@@ -35,7 +35,7 @@ static void pcie_pci_bridge_realize(PCIDevice *d, Error **errp)
 {
     PCIBridge *br = PCI_BRIDGE(d);
     PCIEPCIBridge *pcie_br = PCIE_PCI_BRIDGE_DEV(d);
-    int rc, pos;
+    int rc;
 
     pci_bridge_initfn(d, TYPE_PCI_BUS);
 
@@ -49,12 +49,8 @@ static void pcie_pci_bridge_realize(PCIDevice *d, Error **errp)
 
     pcie_cap_init(d, 0, PCI_EXP_TYPE_PCI_BRIDGE, 0);
 
-    pos = pci_add_capability(d, PCI_CAP_ID_PM, 0, PCI_PM_SIZEOF, errp);
-    if (pos < 0) {
-        goto pm_error;
-    }
-    d->exp.pm_cap = pos;
-    pci_set_word(d->config + pos + PCI_PM_PMC, 0x3);
+    d->exp.pm_cap = pci_add_capability(d, PCI_CAP_ID_PM, 0, PCI_PM_SIZEOF);
+    pci_set_word(d->config + d->exp.pm_cap + PCI_PM_PMC, 0x3);
 
     pcie_cap_arifwd_init(d);
     pcie_cap_deverr_init(d);
@@ -85,7 +81,6 @@ static void pcie_pci_bridge_realize(PCIDevice *d, Error **errp)
 msi_error:
     pcie_aer_exit(d);
 aer_error:
-pm_error:
     pcie_cap_exit(d);
     shpc_cleanup(d, &pcie_br->shpc_bar);
 error:
-- 
2.37.3



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v5 15/17] hw/vfio/pci: Omit errp for pci_add_capability
  2022-10-28 12:26 [PATCH v5 00/17] pci: Abort if pci_add_capability fails Akihiko Odaki
                   ` (13 preceding siblings ...)
  2022-10-28 12:26 ` [PATCH v5 14/17] hw/pci-bridge/pcie_pci_bridge: " Akihiko Odaki
@ 2022-10-28 12:26 ` Akihiko Odaki
  2022-10-28 12:26 ` [PATCH v5 16/17] virtio-pci: " Akihiko Odaki
  2022-10-28 12:26 ` [PATCH v5 17/17] pci: Remove legacy errp from pci_add_capability Akihiko Odaki
  16 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2022-10-28 12:26 UTC (permalink / raw)
  Cc: Alex Williamson, qemu-devel, qemu-block, qemu-arm,
	Michael S . Tsirkin, Marcel Apfelbaum, Gerd Hoffmann,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost, John Snow,
	Dmitry Fleytman, Jason Wang, Stefan Weil, Keith Busch,
	Klaus Jensen, Peter Maydell, Andrey Smirnov, Paul Burton,
	Aleksandar Rikalo, Yan Vugenfirer, Yuri Benditovich,
	Akihiko Odaki

The code generating errors in pci_add_capability has a comment which
says:
> Verify that capabilities don't overlap.  Note: device assignment
> depends on this check to verify that the device is not broken.
> Should never trigger for emulated devices, but it's helpful for
> debugging these.

Indeed vfio has some code that passes capability offsets and sizes from
a physical device, but it explicitly pays attention so that the
capabilities never overlap. Therefore, in pci_add_capability(), we can
always assert that capabilities never overlap, and that is what happens
when omitting errp.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/vfio/pci-quirks.c | 15 +++------------
 hw/vfio/pci.c        | 14 +++++---------
 2 files changed, 8 insertions(+), 21 deletions(-)

diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c
index f0147a050a..e94fd273ea 100644
--- a/hw/vfio/pci-quirks.c
+++ b/hw/vfio/pci-quirks.c
@@ -1530,7 +1530,7 @@ const PropertyInfo qdev_prop_nv_gpudirect_clique = {
 static int vfio_add_nv_gpudirect_cap(VFIOPCIDevice *vdev, Error **errp)
 {
     PCIDevice *pdev = &vdev->pdev;
-    int ret, pos = 0xC8;
+    int pos = 0xC8;
 
     if (vdev->nv_gpudirect_clique == 0xFF) {
         return 0;
@@ -1547,11 +1547,7 @@ static int vfio_add_nv_gpudirect_cap(VFIOPCIDevice *vdev, Error **errp)
         return -EINVAL;
     }
 
-    ret = pci_add_capability(pdev, PCI_CAP_ID_VNDR, pos, 8, errp);
-    if (ret < 0) {
-        error_prepend(errp, "Failed to add NVIDIA GPUDirect cap: ");
-        return ret;
-    }
+    pci_add_capability(pdev, PCI_CAP_ID_VNDR, pos, 8);
 
     memset(vdev->emulated_config_bits + pos, 0xFF, 8);
     pos += PCI_CAP_FLAGS;
@@ -1718,12 +1714,7 @@ static int vfio_add_vmd_shadow_cap(VFIOPCIDevice *vdev, Error **errp)
         return -EFAULT;
     }
 
-    ret = pci_add_capability(&vdev->pdev, PCI_CAP_ID_VNDR, pos,
-                             VMD_SHADOW_CAP_LEN, errp);
-    if (ret < 0) {
-        error_prepend(errp, "Failed to add VMD MEMBAR Shadow cap: ");
-        return ret;
-    }
+    pci_add_capability(&vdev->pdev, PCI_CAP_ID_VNDR, pos, VMD_SHADOW_CAP_LEN);
 
     memset(vdev->emulated_config_bits + pos, 0xFF, VMD_SHADOW_CAP_LEN);
     pos += PCI_CAP_FLAGS;
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 36c8f3dc85..d043289f78 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -1845,7 +1845,7 @@ static void vfio_add_emulated_long(VFIOPCIDevice *vdev, int pos,
     vfio_set_long_bits(vdev->emulated_config_bits + pos, mask, mask);
 }
 
-static int vfio_setup_pcie_cap(VFIOPCIDevice *vdev, int pos, uint8_t size,
+static int vfio_setup_pcie_cap(VFIOPCIDevice *vdev, uint8_t pos, uint8_t size,
                                Error **errp)
 {
     uint16_t flags;
@@ -1962,11 +1962,7 @@ static int vfio_setup_pcie_cap(VFIOPCIDevice *vdev, int pos, uint8_t size,
                                1, PCI_EXP_FLAGS_VERS);
     }
 
-    pos = pci_add_capability(&vdev->pdev, PCI_CAP_ID_EXP, pos, size,
-                             errp);
-    if (pos < 0) {
-        return pos;
-    }
+    pos = pci_add_capability(&vdev->pdev, PCI_CAP_ID_EXP, pos, size);
 
     vdev->pdev.exp.exp_cap = pos;
 
@@ -2082,14 +2078,14 @@ static int vfio_add_std_cap(VFIOPCIDevice *vdev, uint8_t pos, Error **errp)
     case PCI_CAP_ID_PM:
         vfio_check_pm_reset(vdev, pos);
         vdev->pm_cap = pos;
-        ret = pci_add_capability(pdev, cap_id, pos, size, errp);
+        pci_add_capability(pdev, cap_id, pos, size);
         break;
     case PCI_CAP_ID_AF:
         vfio_check_af_flr(vdev, pos);
-        ret = pci_add_capability(pdev, cap_id, pos, size, errp);
+        pci_add_capability(pdev, cap_id, pos, size);
         break;
     default:
-        ret = pci_add_capability(pdev, cap_id, pos, size, errp);
+        pci_add_capability(pdev, cap_id, pos, size);
         break;
     }
 
-- 
2.37.3



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v5 16/17] virtio-pci: Omit errp for pci_add_capability
  2022-10-28 12:26 [PATCH v5 00/17] pci: Abort if pci_add_capability fails Akihiko Odaki
                   ` (14 preceding siblings ...)
  2022-10-28 12:26 ` [PATCH v5 15/17] hw/vfio/pci: " Akihiko Odaki
@ 2022-10-28 12:26 ` Akihiko Odaki
  2022-10-28 12:26 ` [PATCH v5 17/17] pci: Remove legacy errp from pci_add_capability Akihiko Odaki
  16 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2022-10-28 12:26 UTC (permalink / raw)
  Cc: Alex Williamson, qemu-devel, qemu-block, qemu-arm,
	Michael S . Tsirkin, Marcel Apfelbaum, Gerd Hoffmann,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost, John Snow,
	Dmitry Fleytman, Jason Wang, Stefan Weil, Keith Busch,
	Klaus Jensen, Peter Maydell, Andrey Smirnov, Paul Burton,
	Aleksandar Rikalo, Yan Vugenfirer, Yuri Benditovich,
	Akihiko Odaki

Omitting errp for pci_add_capability() causes it to abort if
capabilities overlap. This behavior is appropriate here because all of
the capabilities set in this device are defined in the program and
their overlap should not happen unless there is a programming error.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/virtio/virtio-pci.c         | 9 ++-------
 include/hw/virtio/virtio-pci.h | 2 +-
 2 files changed, 3 insertions(+), 8 deletions(-)

diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index c37bdc77ea..b393ff01be 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1154,8 +1154,7 @@ static int virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy,
     PCIDevice *dev = &proxy->pci_dev;
     int offset;
 
-    offset = pci_add_capability(dev, PCI_CAP_ID_VNDR, 0,
-                                cap->cap_len, &error_abort);
+    offset = pci_add_capability(dev, PCI_CAP_ID_VNDR, 0, cap->cap_len);
 
     assert(cap->cap_len >= sizeof *cap);
     memcpy(dev->config + offset + PCI_CAP_FLAGS, &cap->cap_len,
@@ -1864,11 +1863,7 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
 
         pcie_endpoint_cap_init(pci_dev, 0);
 
-        pos = pci_add_capability(pci_dev, PCI_CAP_ID_PM, 0,
-                                 PCI_PM_SIZEOF, errp);
-        if (pos < 0) {
-            return;
-        }
+        pos = pci_add_capability(pci_dev, PCI_CAP_ID_PM, 0, PCI_PM_SIZEOF);
 
         pci_dev->exp.pm_cap = pos;
 
diff --git a/include/hw/virtio/virtio-pci.h b/include/hw/virtio/virtio-pci.h
index 2446dcd9ae..9f3736723c 100644
--- a/include/hw/virtio/virtio-pci.h
+++ b/include/hw/virtio/virtio-pci.h
@@ -141,7 +141,7 @@ struct VirtIOPCIProxy {
     uint32_t msix_bar_idx;
     uint32_t modern_io_bar_idx;
     uint32_t modern_mem_bar_idx;
-    int config_cap;
+    uint8_t config_cap;
     uint32_t flags;
     bool disable_modern;
     bool ignore_backend_features;
-- 
2.37.3



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v5 17/17] pci: Remove legacy errp from pci_add_capability
  2022-10-28 12:26 [PATCH v5 00/17] pci: Abort if pci_add_capability fails Akihiko Odaki
                   ` (15 preceding siblings ...)
  2022-10-28 12:26 ` [PATCH v5 16/17] virtio-pci: " Akihiko Odaki
@ 2022-10-28 12:26 ` Akihiko Odaki
  16 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2022-10-28 12:26 UTC (permalink / raw)
  Cc: Alex Williamson, qemu-devel, qemu-block, qemu-arm,
	Michael S . Tsirkin, Marcel Apfelbaum, Gerd Hoffmann,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost, John Snow,
	Dmitry Fleytman, Jason Wang, Stefan Weil, Keith Busch,
	Klaus Jensen, Peter Maydell, Andrey Smirnov, Paul Burton,
	Aleksandar Rikalo, Yan Vugenfirer, Yuri Benditovich,
	Akihiko Odaki

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/pci/pci.c         | 29 +++++++----------------------
 include/hw/pci/pci.h | 12 ++----------
 2 files changed, 9 insertions(+), 32 deletions(-)

diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 8ee2171011..8ff71e4553 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -2513,38 +2513,23 @@ static void pci_del_option_rom(PCIDevice *pdev)
 }
 
 /*
- * On success, pci_add_capability_legacy() returns a positive value
- * that the offset of the pci capability.
- * On failure, it sets an error and returns a negative error
- * code.
+ * pci_add_capability() returns a positive value that the offset of the pci
+ * capability.
  */
-int pci_add_capability_legacy(PCIDevice *pdev, uint8_t cap_id,
-                              uint8_t offset, uint8_t size,
-                              Error **errp)
+uint8_t pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
+                           uint8_t offset, uint8_t size)
 {
     uint8_t *config;
-    int i, overlapping_cap;
+    int i;
 
     if (!offset) {
         offset = pci_find_space(pdev, size);
         /* out of PCI config space is programming error */
         assert(offset);
     } else {
-        /* Verify that capabilities don't overlap.  Note: device assignment
-         * depends on this check to verify that the device is not broken.
-         * Should never trigger for emulated devices, but it's helpful
-         * for debugging these. */
+        /* Verify that capabilities don't overlap. */
         for (i = offset; i < offset + size; i++) {
-            overlapping_cap = pci_find_capability_at_offset(pdev, i);
-            if (overlapping_cap) {
-                error_setg(errp, "%s:%02x:%02x.%x "
-                           "Attempt to add PCI capability %x at offset "
-                           "%x overlaps existing capability %x at offset %x",
-                           pci_root_bus_path(pdev), pci_dev_bus_num(pdev),
-                           PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
-                           cap_id, offset, overlapping_cap, i);
-                return -EINVAL;
-            }
+            assert(!pci_find_capability_at_offset(pdev, i));
         }
     }
 
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index 51fd106f16..2a5d4b329f 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -2,7 +2,6 @@
 #define QEMU_PCI_H
 
 #include "exec/memory.h"
-#include "qapi/error.h"
 #include "sysemu/dma.h"
 
 /* PCI includes legacy ISA access.  */
@@ -391,15 +390,8 @@ void pci_register_vga(PCIDevice *pci_dev, MemoryRegion *mem,
 void pci_unregister_vga(PCIDevice *pci_dev);
 pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num);
 
-int pci_add_capability_legacy(PCIDevice *pdev, uint8_t cap_id,
-                              uint8_t offset, uint8_t size,
-                              Error **errp);
-
-#define PCI_ADD_CAPABILITY_VA(pdev, cap_id, offset, size, errp, ...) \
-    pci_add_capability_legacy(pdev, cap_id, offset, size, errp)
-
-#define pci_add_capability(...) \
-    PCI_ADD_CAPABILITY_VA(__VA_ARGS__, &error_abort)
+uint8_t pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
+                           uint8_t offset, uint8_t size);
 
 void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
 
-- 
2.37.3



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [PATCH v5 01/17] hw/vfio/pci: Ensure MSI and MSI-X do not overlap
  2022-10-28 12:26 ` [PATCH v5 01/17] hw/vfio/pci: Ensure MSI and MSI-X do not overlap Akihiko Odaki
@ 2022-10-28 14:16   ` Alex Williamson
  2022-10-28 16:12     ` Akihiko Odaki
  0 siblings, 1 reply; 24+ messages in thread
From: Alex Williamson @ 2022-10-28 14:16 UTC (permalink / raw)
  To: Akihiko Odaki
  Cc: qemu-devel, qemu-block, qemu-arm, Michael S . Tsirkin,
	Marcel Apfelbaum, Gerd Hoffmann, Paolo Bonzini, Richard Henderson,
	Eduardo Habkost, John Snow, Dmitry Fleytman, Jason Wang,
	Stefan Weil, Keith Busch, Klaus Jensen, Peter Maydell,
	Andrey Smirnov, Paul Burton, Aleksandar Rikalo, Yan Vugenfirer,
	Yuri Benditovich

On Fri, 28 Oct 2022 21:26:13 +0900
Akihiko Odaki <akihiko.odaki@daynix.com> wrote:

> vfio_add_std_cap() is designed to ensure that capabilities do not
> overlap, but it failed to do so for MSI and MSI-X capabilities.
> 
> Ensure MSI and MSI-X capabilities do not overlap with others by omitting
> other overlapping capabilities.
> 
> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
> ---
>  hw/vfio/pci.c | 63 +++++++++++++++++++++++++++++++++++++++++++--------
>  hw/vfio/pci.h |  3 +++
>  2 files changed, 56 insertions(+), 10 deletions(-)
> 
> diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
> index 939dcc3d4a..36c8f3dc85 100644
> --- a/hw/vfio/pci.c
> +++ b/hw/vfio/pci.c
> @@ -1278,23 +1278,42 @@ static void vfio_disable_interrupts(VFIOPCIDevice *vdev)
>      }
>  }
>  
> -static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
> +static void vfio_msi_early_setup(VFIOPCIDevice *vdev, Error **errp)
>  {
>      uint16_t ctrl;
> -    bool msi_64bit, msi_maskbit;
> -    int ret, entries;
> -    Error *err = NULL;
> +    uint8_t pos;
> +
> +    pos = pci_find_capability(&vdev->pdev, PCI_CAP_ID_MSI);
> +    if (!pos) {
> +        return;
> +    }
>  
>      if (pread(vdev->vbasedev.fd, &ctrl, sizeof(ctrl),
>                vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) {
>          error_setg_errno(errp, errno, "failed reading MSI PCI_CAP_FLAGS");
> -        return -errno;
> +        return;
>      }
> -    ctrl = le16_to_cpu(ctrl);
> +    vdev->msi_pos = pos;
> +    vdev->msi_ctrl = le16_to_cpu(ctrl);
>  
> -    msi_64bit = !!(ctrl & PCI_MSI_FLAGS_64BIT);
> -    msi_maskbit = !!(ctrl & PCI_MSI_FLAGS_MASKBIT);
> -    entries = 1 << ((ctrl & PCI_MSI_FLAGS_QMASK) >> 1);
> +    vdev->msi_cap_size = 0xa;
> +    if ((vdev->msi_ctrl & PCI_MSI_FLAGS_MASKBIT)) {
> +        vdev->msi_cap_size += 0xa;
> +    }
> +    if ((vdev->msi_ctrl & PCI_MSI_FLAGS_64BIT)) {
> +        vdev->msi_cap_size += 0x4;
> +    }
> +}
> +
> +static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
> +{
> +    bool msi_64bit, msi_maskbit;
> +    int ret, entries;
> +    Error *err = NULL;
> +
> +    msi_64bit = !!(vdev->msi_ctrl & PCI_MSI_FLAGS_64BIT);
> +    msi_maskbit = !!(vdev->msi_ctrl & PCI_MSI_FLAGS_MASKBIT);
> +    entries = 1 << ((vdev->msi_ctrl & PCI_MSI_FLAGS_QMASK) >> 1);
>  
>      trace_vfio_msi_setup(vdev->vbasedev.name, pos);
>  
> @@ -1306,7 +1325,6 @@ static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
>          error_propagate_prepend(errp, err, "msi_init failed: ");
>          return ret;
>      }
> -    vdev->msi_cap_size = 0xa + (msi_maskbit ? 0xa : 0) + (msi_64bit ? 0x4 : 0);
>  
>      return 0;
>  }
> @@ -1524,6 +1542,7 @@ static void vfio_msix_early_setup(VFIOPCIDevice *vdev, Error **errp)
>      pba = le32_to_cpu(pba);
>  
>      msix = g_malloc0(sizeof(*msix));
> +    msix->pos = pos;
>      msix->table_bar = table & PCI_MSIX_FLAGS_BIRMASK;
>      msix->table_offset = table & ~PCI_MSIX_FLAGS_BIRMASK;
>      msix->pba_bar = pba & PCI_MSIX_FLAGS_BIRMASK;
> @@ -2025,6 +2044,24 @@ static int vfio_add_std_cap(VFIOPCIDevice *vdev, uint8_t pos, Error **errp)
>          }
>      }
>  
> +    if (cap_id != PCI_CAP_ID_MSI &&
> +        range_covers_byte(vdev->msi_pos, vdev->msi_cap_size, pos)) {
> +        warn_report(VFIO_MSG_PREFIX
> +                    "A capability overlaps with MSI, ignoring (%" PRIu8 " @ %" PRIu8 " in [%" PRIu8 ", %" PRIu8 "))",
> +                    vdev->vbasedev.name, cap_id, pos,
> +                    vdev->msi_pos, vdev->msi_pos + vdev->msi_cap_size);
> +        return 0;
> +    }
> +
> +    if (cap_id != PCI_CAP_ID_MSIX && vdev->msix &&
> +        range_covers_byte(vdev->msix->pos, MSIX_CAP_LENGTH, pos)) {
> +        warn_report(VFIO_MSG_PREFIX
> +                    "A capability overlaps with MSI-X, ignoring (%" PRIu8 " @ %" PRIu8 " in [%" PRIu8 ", %" PRIu8 "))",
> +                    vdev->vbasedev.name, cap_id, pos,
> +                    vdev->msix->pos, vdev->msix->pos + MSIX_CAP_LENGTH);
> +        return 0;
> +    }

Capabilities are not a single byte, the fact that it doesn't start
within the MSI or MSI-X capability is not a sufficient test.  We're
also choosing to prioritize MSI and MSI-X capabilities by protecting
that range rather than the existing behavior where we'd drop those
capabilities if they overlap with another capability that has already
been placed.  There are merits to both approaches, but I don't see any
justification here to change the current behavior.

Isn't the most similar behavior to existing to pass the available size
to vfio_msi[x]_setup() and return an errno if the size would be
exceeded?  Something like below (untested, and requires exporting
msi_cap_sizeof()).  Thanks,

Alex

diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 939dcc3d4a9e..485f9bc5102d 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -1278,11 +1278,13 @@ static void vfio_disable_interrupts(VFIOPCIDevice *vdev)
     }
 }
 
-static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
+static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos,
+                          uint8_t size, Error **errp)
 {
     uint16_t ctrl;
     bool msi_64bit, msi_maskbit;
     int ret, entries;
+    uint8_t msi_cap_size;
     Error *err = NULL;
 
     if (pread(vdev->vbasedev.fd, &ctrl, sizeof(ctrl),
@@ -1295,6 +1297,10 @@ static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
     msi_64bit = !!(ctrl & PCI_MSI_FLAGS_64BIT);
     msi_maskbit = !!(ctrl & PCI_MSI_FLAGS_MASKBIT);
     entries = 1 << ((ctrl & PCI_MSI_FLAGS_QMASK) >> 1);
+    msi_cap_size = msi_cap_sizeof(ctrl);
+
+    if (msi_cap_size > size)
+	    return -ENOSPC;
 
     trace_vfio_msi_setup(vdev->vbasedev.name, pos);
 
@@ -1306,7 +1312,7 @@ static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
         error_propagate_prepend(errp, err, "msi_init failed: ");
         return ret;
     }
-    vdev->msi_cap_size = 0xa + (msi_maskbit ? 0xa : 0) + (msi_64bit ? 0x4 : 0);
+    vdev->msi_cap_size = msi_cap_size;
 
     return 0;
 }
@@ -1570,11 +1576,15 @@ static void vfio_msix_early_setup(VFIOPCIDevice *vdev, Error **errp)
     vfio_pci_relocate_msix(vdev, errp);
 }
 
-static int vfio_msix_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
+static int vfio_msix_setup(VFIOPCIDevice *vdev, int pos,
+                           uint8_t size, Error **errp)
 {
     int ret;
     Error *err = NULL;
 
+    if (MSIX_CAP_LENGTH > size)
+	    return -ENOSPC;
+
     vdev->msix->pending = g_new0(unsigned long,
                                  BITS_TO_LONGS(vdev->msix->entries));
     ret = msix_init(&vdev->pdev, vdev->msix->entries,
@@ -2033,14 +2043,14 @@ static int vfio_add_std_cap(VFIOPCIDevice *vdev, uint8_t pos, Error **errp)
 
     switch (cap_id) {
     case PCI_CAP_ID_MSI:
-        ret = vfio_msi_setup(vdev, pos, errp);
+        ret = vfio_msi_setup(vdev, pos, size, errp);
         break;
     case PCI_CAP_ID_EXP:
         vfio_check_pcie_flr(vdev, pos);
         ret = vfio_setup_pcie_cap(vdev, pos, size, errp);
         break;
     case PCI_CAP_ID_MSIX:
-        ret = vfio_msix_setup(vdev, pos, errp);
+        ret = vfio_msix_setup(vdev, pos, size, errp);
         break;
     case PCI_CAP_ID_PM:
         vfio_check_pm_reset(vdev, pos);



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [PATCH v5 01/17] hw/vfio/pci: Ensure MSI and MSI-X do not overlap
  2022-10-28 14:16   ` Alex Williamson
@ 2022-10-28 16:12     ` Akihiko Odaki
  2022-10-28 19:23       ` Alex Williamson
  0 siblings, 1 reply; 24+ messages in thread
From: Akihiko Odaki @ 2022-10-28 16:12 UTC (permalink / raw)
  To: Alex Williamson
  Cc: qemu-devel, qemu-block, qemu-arm, Michael S . Tsirkin,
	Marcel Apfelbaum, Gerd Hoffmann, Paolo Bonzini, Richard Henderson,
	Eduardo Habkost, John Snow, Dmitry Fleytman, Jason Wang,
	Stefan Weil, Keith Busch, Klaus Jensen, Peter Maydell,
	Andrey Smirnov, Paul Burton, Aleksandar Rikalo, Yan Vugenfirer,
	Yuri Benditovich

On 2022/10/28 23:16, Alex Williamson wrote:
> On Fri, 28 Oct 2022 21:26:13 +0900
> Akihiko Odaki <akihiko.odaki@daynix.com> wrote:
> 
>> vfio_add_std_cap() is designed to ensure that capabilities do not
>> overlap, but it failed to do so for MSI and MSI-X capabilities.
>>
>> Ensure MSI and MSI-X capabilities do not overlap with others by omitting
>> other overlapping capabilities.
>>
>> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
>> ---
>>   hw/vfio/pci.c | 63 +++++++++++++++++++++++++++++++++++++++++++--------
>>   hw/vfio/pci.h |  3 +++
>>   2 files changed, 56 insertions(+), 10 deletions(-)
>>
>> diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
>> index 939dcc3d4a..36c8f3dc85 100644
>> --- a/hw/vfio/pci.c
>> +++ b/hw/vfio/pci.c
>> @@ -1278,23 +1278,42 @@ static void vfio_disable_interrupts(VFIOPCIDevice *vdev)
>>       }
>>   }
>>   
>> -static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
>> +static void vfio_msi_early_setup(VFIOPCIDevice *vdev, Error **errp)
>>   {
>>       uint16_t ctrl;
>> -    bool msi_64bit, msi_maskbit;
>> -    int ret, entries;
>> -    Error *err = NULL;
>> +    uint8_t pos;
>> +
>> +    pos = pci_find_capability(&vdev->pdev, PCI_CAP_ID_MSI);
>> +    if (!pos) {
>> +        return;
>> +    }
>>   
>>       if (pread(vdev->vbasedev.fd, &ctrl, sizeof(ctrl),
>>                 vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) {
>>           error_setg_errno(errp, errno, "failed reading MSI PCI_CAP_FLAGS");
>> -        return -errno;
>> +        return;
>>       }
>> -    ctrl = le16_to_cpu(ctrl);
>> +    vdev->msi_pos = pos;
>> +    vdev->msi_ctrl = le16_to_cpu(ctrl);
>>   
>> -    msi_64bit = !!(ctrl & PCI_MSI_FLAGS_64BIT);
>> -    msi_maskbit = !!(ctrl & PCI_MSI_FLAGS_MASKBIT);
>> -    entries = 1 << ((ctrl & PCI_MSI_FLAGS_QMASK) >> 1);
>> +    vdev->msi_cap_size = 0xa;
>> +    if ((vdev->msi_ctrl & PCI_MSI_FLAGS_MASKBIT)) {
>> +        vdev->msi_cap_size += 0xa;
>> +    }
>> +    if ((vdev->msi_ctrl & PCI_MSI_FLAGS_64BIT)) {
>> +        vdev->msi_cap_size += 0x4;
>> +    }
>> +}
>> +
>> +static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
>> +{
>> +    bool msi_64bit, msi_maskbit;
>> +    int ret, entries;
>> +    Error *err = NULL;
>> +
>> +    msi_64bit = !!(vdev->msi_ctrl & PCI_MSI_FLAGS_64BIT);
>> +    msi_maskbit = !!(vdev->msi_ctrl & PCI_MSI_FLAGS_MASKBIT);
>> +    entries = 1 << ((vdev->msi_ctrl & PCI_MSI_FLAGS_QMASK) >> 1);
>>   
>>       trace_vfio_msi_setup(vdev->vbasedev.name, pos);
>>   
>> @@ -1306,7 +1325,6 @@ static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
>>           error_propagate_prepend(errp, err, "msi_init failed: ");
>>           return ret;
>>       }
>> -    vdev->msi_cap_size = 0xa + (msi_maskbit ? 0xa : 0) + (msi_64bit ? 0x4 : 0);
>>   
>>       return 0;
>>   }
>> @@ -1524,6 +1542,7 @@ static void vfio_msix_early_setup(VFIOPCIDevice *vdev, Error **errp)
>>       pba = le32_to_cpu(pba);
>>   
>>       msix = g_malloc0(sizeof(*msix));
>> +    msix->pos = pos;
>>       msix->table_bar = table & PCI_MSIX_FLAGS_BIRMASK;
>>       msix->table_offset = table & ~PCI_MSIX_FLAGS_BIRMASK;
>>       msix->pba_bar = pba & PCI_MSIX_FLAGS_BIRMASK;
>> @@ -2025,6 +2044,24 @@ static int vfio_add_std_cap(VFIOPCIDevice *vdev, uint8_t pos, Error **errp)
>>           }
>>       }
>>   
>> +    if (cap_id != PCI_CAP_ID_MSI &&
>> +        range_covers_byte(vdev->msi_pos, vdev->msi_cap_size, pos)) {
>> +        warn_report(VFIO_MSG_PREFIX
>> +                    "A capability overlaps with MSI, ignoring (%" PRIu8 " @ %" PRIu8 " in [%" PRIu8 ", %" PRIu8 "))",
>> +                    vdev->vbasedev.name, cap_id, pos,
>> +                    vdev->msi_pos, vdev->msi_pos + vdev->msi_cap_size);
>> +        return 0;
>> +    }
>> +
>> +    if (cap_id != PCI_CAP_ID_MSIX && vdev->msix &&
>> +        range_covers_byte(vdev->msix->pos, MSIX_CAP_LENGTH, pos)) {
>> +        warn_report(VFIO_MSG_PREFIX
>> +                    "A capability overlaps with MSI-X, ignoring (%" PRIu8 " @ %" PRIu8 " in [%" PRIu8 ", %" PRIu8 "))",
>> +                    vdev->vbasedev.name, cap_id, pos,
>> +                    vdev->msix->pos, vdev->msix->pos + MSIX_CAP_LENGTH);
>> +        return 0;
>> +    }
> 
> Capabilities are not a single byte, the fact that it doesn't start
> within the MSI or MSI-X capability is not a sufficient test.  We're
> also choosing to prioritize MSI and MSI-X capabilities by protecting
> that range rather than the existing behavior where we'd drop those
> capabilities if they overlap with another capability that has already
> been placed.  There are merits to both approaches, but I don't see any
> justification here to change the current behavior.
> 
> Isn't the most similar behavior to existing to pass the available size
> to vfio_msi[x]_setup() and return an errno if the size would be
> exceeded?  Something like below (untested, and requires exporting
> msi_cap_sizeof()).  Thanks,

It only tests the beginning of the capability currently being added 
because its end is determined by vfio_std_cap_max_size() so that the 
overlap does not happen.

A comment in vfio_add_std_cap() says:
 >     /*
 >      * If it becomes important to configure capabilities to their actual
 >      * size, use this as the default when it's something we don't 
recognize.
 >      * Since QEMU doesn't actually handle many of the config accesses,
 >      * exact size doesn't seem worthwhile.
 >      */

My understanding of the problem is that while clipping is performed when 
overlapping two capabilities other than MSI and MSI-X according to the 
comment, the clipping does not happen when one of the overlapping 
capability is MSI or MSI-X.

According to that, the correct way to fix is to perform clipping also in 
such a case. As QEMU actually handles the config acccesses for MSI and 
MSI-X, MSI and MSI-X are always priotized over the other capabilities.

Regards,
Akihiko Odaki

> 
> Alex
> 
> diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
> index 939dcc3d4a9e..485f9bc5102d 100644
> --- a/hw/vfio/pci.c
> +++ b/hw/vfio/pci.c
> @@ -1278,11 +1278,13 @@ static void vfio_disable_interrupts(VFIOPCIDevice *vdev)
>       }
>   }
>   
> -static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
> +static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos,
> +                          uint8_t size, Error **errp)
>   {
>       uint16_t ctrl;
>       bool msi_64bit, msi_maskbit;
>       int ret, entries;
> +    uint8_t msi_cap_size;
>       Error *err = NULL;
>   
>       if (pread(vdev->vbasedev.fd, &ctrl, sizeof(ctrl),
> @@ -1295,6 +1297,10 @@ static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
>       msi_64bit = !!(ctrl & PCI_MSI_FLAGS_64BIT);
>       msi_maskbit = !!(ctrl & PCI_MSI_FLAGS_MASKBIT);
>       entries = 1 << ((ctrl & PCI_MSI_FLAGS_QMASK) >> 1);
> +    msi_cap_size = msi_cap_sizeof(ctrl);
> +
> +    if (msi_cap_size > size)
> +	    return -ENOSPC;
>   
>       trace_vfio_msi_setup(vdev->vbasedev.name, pos);
>   
> @@ -1306,7 +1312,7 @@ static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
>           error_propagate_prepend(errp, err, "msi_init failed: ");
>           return ret;
>       }
> -    vdev->msi_cap_size = 0xa + (msi_maskbit ? 0xa : 0) + (msi_64bit ? 0x4 : 0);
> +    vdev->msi_cap_size = msi_cap_size;
>   
>       return 0;
>   }
> @@ -1570,11 +1576,15 @@ static void vfio_msix_early_setup(VFIOPCIDevice *vdev, Error **errp)
>       vfio_pci_relocate_msix(vdev, errp);
>   }
>   
> -static int vfio_msix_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
> +static int vfio_msix_setup(VFIOPCIDevice *vdev, int pos,
> +                           uint8_t size, Error **errp)
>   {
>       int ret;
>       Error *err = NULL;
>   
> +    if (MSIX_CAP_LENGTH > size)
> +	    return -ENOSPC;
> +
>       vdev->msix->pending = g_new0(unsigned long,
>                                    BITS_TO_LONGS(vdev->msix->entries));
>       ret = msix_init(&vdev->pdev, vdev->msix->entries,
> @@ -2033,14 +2043,14 @@ static int vfio_add_std_cap(VFIOPCIDevice *vdev, uint8_t pos, Error **errp)
>   
>       switch (cap_id) {
>       case PCI_CAP_ID_MSI:
> -        ret = vfio_msi_setup(vdev, pos, errp);
> +        ret = vfio_msi_setup(vdev, pos, size, errp);
>           break;
>       case PCI_CAP_ID_EXP:
>           vfio_check_pcie_flr(vdev, pos);
>           ret = vfio_setup_pcie_cap(vdev, pos, size, errp);
>           break;
>       case PCI_CAP_ID_MSIX:
> -        ret = vfio_msix_setup(vdev, pos, errp);
> +        ret = vfio_msix_setup(vdev, pos, size, errp);
>           break;
>       case PCI_CAP_ID_PM:
>           vfio_check_pm_reset(vdev, pos);
> 


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v5 01/17] hw/vfio/pci: Ensure MSI and MSI-X do not overlap
  2022-10-28 16:12     ` Akihiko Odaki
@ 2022-10-28 19:23       ` Alex Williamson
  2022-10-31 12:37         ` Akihiko Odaki
  0 siblings, 1 reply; 24+ messages in thread
From: Alex Williamson @ 2022-10-28 19:23 UTC (permalink / raw)
  To: Akihiko Odaki
  Cc: qemu-devel, qemu-block, qemu-arm, Michael S . Tsirkin,
	Marcel Apfelbaum, Gerd Hoffmann, Paolo Bonzini, Richard Henderson,
	Eduardo Habkost, John Snow, Dmitry Fleytman, Jason Wang,
	Stefan Weil, Keith Busch, Klaus Jensen, Peter Maydell,
	Andrey Smirnov, Paul Burton, Aleksandar Rikalo, Yan Vugenfirer,
	Yuri Benditovich

On Sat, 29 Oct 2022 01:12:11 +0900
Akihiko Odaki <akihiko.odaki@daynix.com> wrote:

> On 2022/10/28 23:16, Alex Williamson wrote:
> > On Fri, 28 Oct 2022 21:26:13 +0900
> > Akihiko Odaki <akihiko.odaki@daynix.com> wrote:
> >   
> >> vfio_add_std_cap() is designed to ensure that capabilities do not
> >> overlap, but it failed to do so for MSI and MSI-X capabilities.
> >>
> >> Ensure MSI and MSI-X capabilities do not overlap with others by omitting
> >> other overlapping capabilities.
> >>
> >> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
> >> ---
> >>   hw/vfio/pci.c | 63 +++++++++++++++++++++++++++++++++++++++++++--------
> >>   hw/vfio/pci.h |  3 +++
> >>   2 files changed, 56 insertions(+), 10 deletions(-)
> >>
> >> diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
> >> index 939dcc3d4a..36c8f3dc85 100644
> >> --- a/hw/vfio/pci.c
> >> +++ b/hw/vfio/pci.c
> >> @@ -1278,23 +1278,42 @@ static void vfio_disable_interrupts(VFIOPCIDevice *vdev)
> >>       }
> >>   }
> >>   
> >> -static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
> >> +static void vfio_msi_early_setup(VFIOPCIDevice *vdev, Error **errp)
> >>   {
> >>       uint16_t ctrl;
> >> -    bool msi_64bit, msi_maskbit;
> >> -    int ret, entries;
> >> -    Error *err = NULL;
> >> +    uint8_t pos;
> >> +
> >> +    pos = pci_find_capability(&vdev->pdev, PCI_CAP_ID_MSI);
> >> +    if (!pos) {
> >> +        return;
> >> +    }
> >>   
> >>       if (pread(vdev->vbasedev.fd, &ctrl, sizeof(ctrl),
> >>                 vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) {
> >>           error_setg_errno(errp, errno, "failed reading MSI PCI_CAP_FLAGS");
> >> -        return -errno;
> >> +        return;
> >>       }
> >> -    ctrl = le16_to_cpu(ctrl);
> >> +    vdev->msi_pos = pos;
> >> +    vdev->msi_ctrl = le16_to_cpu(ctrl);
> >>   
> >> -    msi_64bit = !!(ctrl & PCI_MSI_FLAGS_64BIT);
> >> -    msi_maskbit = !!(ctrl & PCI_MSI_FLAGS_MASKBIT);
> >> -    entries = 1 << ((ctrl & PCI_MSI_FLAGS_QMASK) >> 1);
> >> +    vdev->msi_cap_size = 0xa;
> >> +    if ((vdev->msi_ctrl & PCI_MSI_FLAGS_MASKBIT)) {
> >> +        vdev->msi_cap_size += 0xa;
> >> +    }
> >> +    if ((vdev->msi_ctrl & PCI_MSI_FLAGS_64BIT)) {
> >> +        vdev->msi_cap_size += 0x4;
> >> +    }
> >> +}
> >> +
> >> +static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
> >> +{
> >> +    bool msi_64bit, msi_maskbit;
> >> +    int ret, entries;
> >> +    Error *err = NULL;
> >> +
> >> +    msi_64bit = !!(vdev->msi_ctrl & PCI_MSI_FLAGS_64BIT);
> >> +    msi_maskbit = !!(vdev->msi_ctrl & PCI_MSI_FLAGS_MASKBIT);
> >> +    entries = 1 << ((vdev->msi_ctrl & PCI_MSI_FLAGS_QMASK) >> 1);
> >>   
> >>       trace_vfio_msi_setup(vdev->vbasedev.name, pos);
> >>   
> >> @@ -1306,7 +1325,6 @@ static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
> >>           error_propagate_prepend(errp, err, "msi_init failed: ");
> >>           return ret;
> >>       }
> >> -    vdev->msi_cap_size = 0xa + (msi_maskbit ? 0xa : 0) + (msi_64bit ? 0x4 : 0);
> >>   
> >>       return 0;
> >>   }
> >> @@ -1524,6 +1542,7 @@ static void vfio_msix_early_setup(VFIOPCIDevice *vdev, Error **errp)
> >>       pba = le32_to_cpu(pba);
> >>   
> >>       msix = g_malloc0(sizeof(*msix));
> >> +    msix->pos = pos;
> >>       msix->table_bar = table & PCI_MSIX_FLAGS_BIRMASK;
> >>       msix->table_offset = table & ~PCI_MSIX_FLAGS_BIRMASK;
> >>       msix->pba_bar = pba & PCI_MSIX_FLAGS_BIRMASK;
> >> @@ -2025,6 +2044,24 @@ static int vfio_add_std_cap(VFIOPCIDevice *vdev, uint8_t pos, Error **errp)
> >>           }
> >>       }
> >>   
> >> +    if (cap_id != PCI_CAP_ID_MSI &&
> >> +        range_covers_byte(vdev->msi_pos, vdev->msi_cap_size, pos)) {
> >> +        warn_report(VFIO_MSG_PREFIX
> >> +                    "A capability overlaps with MSI, ignoring (%" PRIu8 " @ %" PRIu8 " in [%" PRIu8 ", %" PRIu8 "))",
> >> +                    vdev->vbasedev.name, cap_id, pos,
> >> +                    vdev->msi_pos, vdev->msi_pos + vdev->msi_cap_size);
> >> +        return 0;
> >> +    }
> >> +
> >> +    if (cap_id != PCI_CAP_ID_MSIX && vdev->msix &&
> >> +        range_covers_byte(vdev->msix->pos, MSIX_CAP_LENGTH, pos)) {
> >> +        warn_report(VFIO_MSG_PREFIX
> >> +                    "A capability overlaps with MSI-X, ignoring (%" PRIu8 " @ %" PRIu8 " in [%" PRIu8 ", %" PRIu8 "))",
> >> +                    vdev->vbasedev.name, cap_id, pos,
> >> +                    vdev->msix->pos, vdev->msix->pos + MSIX_CAP_LENGTH);
> >> +        return 0;
> >> +    }  
> > 
> > Capabilities are not a single byte, the fact that it doesn't start
> > within the MSI or MSI-X capability is not a sufficient test.  We're
> > also choosing to prioritize MSI and MSI-X capabilities by protecting
> > that range rather than the existing behavior where we'd drop those
> > capabilities if they overlap with another capability that has already
> > been placed.  There are merits to both approaches, but I don't see any
> > justification here to change the current behavior.
> > 
> > Isn't the most similar behavior to existing to pass the available size
> > to vfio_msi[x]_setup() and return an errno if the size would be
> > exceeded?  Something like below (untested, and requires exporting
> > msi_cap_sizeof()).  Thanks,  
> 
> It only tests the beginning of the capability currently being added 
> because its end is determined by vfio_std_cap_max_size() so that the 
> overlap does not happen.
> 
> A comment in vfio_add_std_cap() says:
>  >     /*
>  >      * If it becomes important to configure capabilities to their actual
>  >      * size, use this as the default when it's something we don't   
> recognize.
>  >      * Since QEMU doesn't actually handle many of the config accesses,
>  >      * exact size doesn't seem worthwhile.
>  >      */  
> 
> My understanding of the problem is that while clipping is performed when 
> overlapping two capabilities other than MSI and MSI-X according to the 
> comment, the clipping does not happen when one of the overlapping 
> capability is MSI or MSI-X.
> 
> According to that, the correct way to fix is to perform clipping also in 
> such a case. As QEMU actually handles the config acccesses for MSI and 
> MSI-X, MSI and MSI-X are always priotized over the other capabilities.

Here's a scenario, a vendor ships a device with an MSI capability where
the MSI control register reports per vector masking, but the packing of
the capabilities is such that the next capability doesn't allow for the
mask and pending bits registers.  Currently, depending on the order we
add them, pci_add_capability() will fail for either the MSI capability
or the encroaching capability.  This failure will propagate back to
vfio_realize and we'll fail to instantiate the device.  To make this
scenario even a bit more pathological, let's assume the encroaching
capability is MSI-X.

As proposed here, we'd drop the MSI-X capability because it's starting
position lies within our expectation of the extent of the MSI
capability, and we'd allow the device to initialize with only MSI.
Was that intentional?  Was that a good choice?  What if the driver
only supports MSI-X?  We've subtly, perhaps unintentionally, changed
the policy based on some notion of prioritizing certain capabilities
over others.

The intent of vfio_std_cap_max_size() is not to intentionally
clip ranges, it's only meant to simplify defining the extent of a
capability to be bounded by the nearest capability after it in config
space.

Currently we rely on a combination of our own range management and the
overlap detection in pci_add_capability() to generate a device
instantiation failure.  If it's deemed worthwhile to remove the latter,
and that is the extent of the focus of this series, let's not go
dabbling into defining new priority schemes for capabilities and
defining certain overlap scenarios as arbitrarily continue'able.
Thanks,

Alex



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v5 02/17] pci: Allow to omit errp for pci_add_capability
  2022-10-28 12:26 ` [PATCH v5 02/17] pci: Allow to omit errp for pci_add_capability Akihiko Odaki
@ 2022-10-28 22:35   ` Philippe Mathieu-Daudé
  2022-10-31 12:39     ` Akihiko Odaki
  0 siblings, 1 reply; 24+ messages in thread
From: Philippe Mathieu-Daudé @ 2022-10-28 22:35 UTC (permalink / raw)
  To: Akihiko Odaki
  Cc: Alex Williamson, qemu-devel, qemu-block, qemu-arm,
	Michael S . Tsirkin, Marcel Apfelbaum, Gerd Hoffmann,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost, John Snow,
	Dmitry Fleytman, Jason Wang, Stefan Weil, Keith Busch,
	Klaus Jensen, Peter Maydell, Andrey Smirnov, Paul Burton,
	Aleksandar Rikalo, Yan Vugenfirer, Yuri Benditovich

On 28/10/22 14:26, Akihiko Odaki wrote:
> pci_add_capability appears most PCI devices. Its error handling required
> lots of code, and led to inconsistent behaviors such as:
> - passing error_abort
> - passing error_fatal
> - asserting the returned value
> - propagating the error to the caller
> - skipping the rest of the function
> - just ignoring
> 
> The code generating errors in pci_add_capability had a comment which
> says:
>> Verify that capabilities don't overlap.  Note: device assignment
>> depends on this check to verify that the device is not broken.
>> Should never trigger for emulated devices, but it's helpful for
>> debugging these.
> 
> Indeed vfio has some code that passes capability offsets and sizes from
> a physical device, but it explicitly pays attention so that the
> capabilities never overlap. Therefore, we can always assert that
> capabilities never overlap when pci_add_capability is called, resolving
> these inconsistencies.
> 
> Such an implementation of pci_add_capability will not have errp
> parameter. However, there are so many callers of pci_add_capability
> that it does not make sense to amend all of them at once to match
> with the new signature. Instead, this change will allow callers of
> pci_add_capability to omit errp as the first step.
> 
> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
> ---
>   hw/pci/pci.c         |  8 ++++----
>   include/hw/pci/pci.h | 13 ++++++++++---
>   2 files changed, 14 insertions(+), 7 deletions(-)

> diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
> index b54b6ef88f..51fd106f16 100644
> --- a/include/hw/pci/pci.h
> +++ b/include/hw/pci/pci.h
> @@ -2,6 +2,7 @@
>   #define QEMU_PCI_H
>   
>   #include "exec/memory.h"
> +#include "qapi/error.h"
>   #include "sysemu/dma.h"
>   
>   /* PCI includes legacy ISA access.  */
> @@ -390,9 +391,15 @@ void pci_register_vga(PCIDevice *pci_dev, MemoryRegion *mem,
>   void pci_unregister_vga(PCIDevice *pci_dev);
>   pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num);
>   
> -int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
> -                       uint8_t offset, uint8_t size,
> -                       Error **errp);
> +int pci_add_capability_legacy(PCIDevice *pdev, uint8_t cap_id,
> +                              uint8_t offset, uint8_t size,
> +                              Error **errp);
> +
> +#define PCI_ADD_CAPABILITY_VA(pdev, cap_id, offset, size, errp, ...) \
> +    pci_add_capability_legacy(pdev, cap_id, offset, size, errp)
> +
> +#define pci_add_capability(...) \
> +    PCI_ADD_CAPABILITY_VA(__VA_ARGS__, &error_abort)
Do we really need PCI_ADD_CAPABILITY_VA?

   #define pci_add_capability(...) \
        pci_add_capability_legacy(__VA_ARGS__, &error_abort)



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v5 01/17] hw/vfio/pci: Ensure MSI and MSI-X do not overlap
  2022-10-28 19:23       ` Alex Williamson
@ 2022-10-31 12:37         ` Akihiko Odaki
  0 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2022-10-31 12:37 UTC (permalink / raw)
  To: Alex Williamson
  Cc: qemu-devel, qemu-block, qemu-arm, Michael S . Tsirkin,
	Marcel Apfelbaum, Gerd Hoffmann, Paolo Bonzini, Richard Henderson,
	Eduardo Habkost, John Snow, Dmitry Fleytman, Jason Wang,
	Stefan Weil, Keith Busch, Klaus Jensen, Peter Maydell,
	Andrey Smirnov, Paul Burton, Aleksandar Rikalo, Yan Vugenfirer,
	Yuri Benditovich

On 2022/10/29 4:23, Alex Williamson wrote:
> On Sat, 29 Oct 2022 01:12:11 +0900
> Akihiko Odaki <akihiko.odaki@daynix.com> wrote:
> 
>> On 2022/10/28 23:16, Alex Williamson wrote:
>>> On Fri, 28 Oct 2022 21:26:13 +0900
>>> Akihiko Odaki <akihiko.odaki@daynix.com> wrote:
>>>    
>>>> vfio_add_std_cap() is designed to ensure that capabilities do not
>>>> overlap, but it failed to do so for MSI and MSI-X capabilities.
>>>>
>>>> Ensure MSI and MSI-X capabilities do not overlap with others by omitting
>>>> other overlapping capabilities.
>>>>
>>>> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
>>>> ---
>>>>    hw/vfio/pci.c | 63 +++++++++++++++++++++++++++++++++++++++++++--------
>>>>    hw/vfio/pci.h |  3 +++
>>>>    2 files changed, 56 insertions(+), 10 deletions(-)
>>>>
>>>> diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
>>>> index 939dcc3d4a..36c8f3dc85 100644
>>>> --- a/hw/vfio/pci.c
>>>> +++ b/hw/vfio/pci.c
>>>> @@ -1278,23 +1278,42 @@ static void vfio_disable_interrupts(VFIOPCIDevice *vdev)
>>>>        }
>>>>    }
>>>>    
>>>> -static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
>>>> +static void vfio_msi_early_setup(VFIOPCIDevice *vdev, Error **errp)
>>>>    {
>>>>        uint16_t ctrl;
>>>> -    bool msi_64bit, msi_maskbit;
>>>> -    int ret, entries;
>>>> -    Error *err = NULL;
>>>> +    uint8_t pos;
>>>> +
>>>> +    pos = pci_find_capability(&vdev->pdev, PCI_CAP_ID_MSI);
>>>> +    if (!pos) {
>>>> +        return;
>>>> +    }
>>>>    
>>>>        if (pread(vdev->vbasedev.fd, &ctrl, sizeof(ctrl),
>>>>                  vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) {
>>>>            error_setg_errno(errp, errno, "failed reading MSI PCI_CAP_FLAGS");
>>>> -        return -errno;
>>>> +        return;
>>>>        }
>>>> -    ctrl = le16_to_cpu(ctrl);
>>>> +    vdev->msi_pos = pos;
>>>> +    vdev->msi_ctrl = le16_to_cpu(ctrl);
>>>>    
>>>> -    msi_64bit = !!(ctrl & PCI_MSI_FLAGS_64BIT);
>>>> -    msi_maskbit = !!(ctrl & PCI_MSI_FLAGS_MASKBIT);
>>>> -    entries = 1 << ((ctrl & PCI_MSI_FLAGS_QMASK) >> 1);
>>>> +    vdev->msi_cap_size = 0xa;
>>>> +    if ((vdev->msi_ctrl & PCI_MSI_FLAGS_MASKBIT)) {
>>>> +        vdev->msi_cap_size += 0xa;
>>>> +    }
>>>> +    if ((vdev->msi_ctrl & PCI_MSI_FLAGS_64BIT)) {
>>>> +        vdev->msi_cap_size += 0x4;
>>>> +    }
>>>> +}
>>>> +
>>>> +static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
>>>> +{
>>>> +    bool msi_64bit, msi_maskbit;
>>>> +    int ret, entries;
>>>> +    Error *err = NULL;
>>>> +
>>>> +    msi_64bit = !!(vdev->msi_ctrl & PCI_MSI_FLAGS_64BIT);
>>>> +    msi_maskbit = !!(vdev->msi_ctrl & PCI_MSI_FLAGS_MASKBIT);
>>>> +    entries = 1 << ((vdev->msi_ctrl & PCI_MSI_FLAGS_QMASK) >> 1);
>>>>    
>>>>        trace_vfio_msi_setup(vdev->vbasedev.name, pos);
>>>>    
>>>> @@ -1306,7 +1325,6 @@ static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
>>>>            error_propagate_prepend(errp, err, "msi_init failed: ");
>>>>            return ret;
>>>>        }
>>>> -    vdev->msi_cap_size = 0xa + (msi_maskbit ? 0xa : 0) + (msi_64bit ? 0x4 : 0);
>>>>    
>>>>        return 0;
>>>>    }
>>>> @@ -1524,6 +1542,7 @@ static void vfio_msix_early_setup(VFIOPCIDevice *vdev, Error **errp)
>>>>        pba = le32_to_cpu(pba);
>>>>    
>>>>        msix = g_malloc0(sizeof(*msix));
>>>> +    msix->pos = pos;
>>>>        msix->table_bar = table & PCI_MSIX_FLAGS_BIRMASK;
>>>>        msix->table_offset = table & ~PCI_MSIX_FLAGS_BIRMASK;
>>>>        msix->pba_bar = pba & PCI_MSIX_FLAGS_BIRMASK;
>>>> @@ -2025,6 +2044,24 @@ static int vfio_add_std_cap(VFIOPCIDevice *vdev, uint8_t pos, Error **errp)
>>>>            }
>>>>        }
>>>>    
>>>> +    if (cap_id != PCI_CAP_ID_MSI &&
>>>> +        range_covers_byte(vdev->msi_pos, vdev->msi_cap_size, pos)) {
>>>> +        warn_report(VFIO_MSG_PREFIX
>>>> +                    "A capability overlaps with MSI, ignoring (%" PRIu8 " @ %" PRIu8 " in [%" PRIu8 ", %" PRIu8 "))",
>>>> +                    vdev->vbasedev.name, cap_id, pos,
>>>> +                    vdev->msi_pos, vdev->msi_pos + vdev->msi_cap_size);
>>>> +        return 0;
>>>> +    }
>>>> +
>>>> +    if (cap_id != PCI_CAP_ID_MSIX && vdev->msix &&
>>>> +        range_covers_byte(vdev->msix->pos, MSIX_CAP_LENGTH, pos)) {
>>>> +        warn_report(VFIO_MSG_PREFIX
>>>> +                    "A capability overlaps with MSI-X, ignoring (%" PRIu8 " @ %" PRIu8 " in [%" PRIu8 ", %" PRIu8 "))",
>>>> +                    vdev->vbasedev.name, cap_id, pos,
>>>> +                    vdev->msix->pos, vdev->msix->pos + MSIX_CAP_LENGTH);
>>>> +        return 0;
>>>> +    }
>>>
>>> Capabilities are not a single byte, the fact that it doesn't start
>>> within the MSI or MSI-X capability is not a sufficient test.  We're
>>> also choosing to prioritize MSI and MSI-X capabilities by protecting
>>> that range rather than the existing behavior where we'd drop those
>>> capabilities if they overlap with another capability that has already
>>> been placed.  There are merits to both approaches, but I don't see any
>>> justification here to change the current behavior.
>>>
>>> Isn't the most similar behavior to existing to pass the available size
>>> to vfio_msi[x]_setup() and return an errno if the size would be
>>> exceeded?  Something like below (untested, and requires exporting
>>> msi_cap_sizeof()).  Thanks,
>>
>> It only tests the beginning of the capability currently being added
>> because its end is determined by vfio_std_cap_max_size() so that the
>> overlap does not happen.
>>
>> A comment in vfio_add_std_cap() says:
>>   >     /*
>>   >      * If it becomes important to configure capabilities to their actual
>>   >      * size, use this as the default when it's something we don't
>> recognize.
>>   >      * Since QEMU doesn't actually handle many of the config accesses,
>>   >      * exact size doesn't seem worthwhile.
>>   >      */
>>
>> My understanding of the problem is that while clipping is performed when
>> overlapping two capabilities other than MSI and MSI-X according to the
>> comment, the clipping does not happen when one of the overlapping
>> capability is MSI or MSI-X.
>>
>> According to that, the correct way to fix is to perform clipping also in
>> such a case. As QEMU actually handles the config acccesses for MSI and
>> MSI-X, MSI and MSI-X are always priotized over the other capabilities.
> 
> Here's a scenario, a vendor ships a device with an MSI capability where
> the MSI control register reports per vector masking, but the packing of
> the capabilities is such that the next capability doesn't allow for the
> mask and pending bits registers.  Currently, depending on the order we
> add them, pci_add_capability() will fail for either the MSI capability
> or the encroaching capability.  This failure will propagate back to
> vfio_realize and we'll fail to instantiate the device.  To make this
> scenario even a bit more pathological, let's assume the encroaching
> capability is MSI-X.
> 
> As proposed here, we'd drop the MSI-X capability because it's starting
> position lies within our expectation of the extent of the MSI
> capability, and we'd allow the device to initialize with only MSI.
> Was that intentional?  Was that a good choice?  What if the driver
> only supports MSI-X?  We've subtly, perhaps unintentionally, changed
> the policy based on some notion of prioritizing certain capabilities
> over others.
> 
> The intent of vfio_std_cap_max_size() is not to intentionally
> clip ranges, it's only meant to simplify defining the extent of a
> capability to be bounded by the nearest capability after it in config
> space.
> 
> Currently we rely on a combination of our own range management and the
> overlap detection in pci_add_capability() to generate a device
> instantiation failure.  If it's deemed worthwhile to remove the latter,
> and that is the extent of the focus of this series, let's not go
> dabbling into defining new priority schemes for capabilities and
> defining certain overlap scenarios as arbitrarily continue'able.
> Thanks,
> 
> Alex
> 

You are right. I missed the part that vfio_std_cap_max_size() is not 
intended to clip ranges. That invalidates reasoning to continue when 
MSI/MSI-X capability overlaps with another.

I have sent v6 to make the cases error. Thanks for reviewing and 
pointing this out.

Regards,
Akihiko Odaki


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v5 02/17] pci: Allow to omit errp for pci_add_capability
  2022-10-28 22:35   ` Philippe Mathieu-Daudé
@ 2022-10-31 12:39     ` Akihiko Odaki
  0 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2022-10-31 12:39 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Alex Williamson, qemu-devel, qemu-block, qemu-arm,
	Michael S . Tsirkin, Marcel Apfelbaum, Gerd Hoffmann,
	Paolo Bonzini, Richard Henderson, Eduardo Habkost, John Snow,
	Dmitry Fleytman, Jason Wang, Stefan Weil, Keith Busch,
	Klaus Jensen, Peter Maydell, Andrey Smirnov, Paul Burton,
	Aleksandar Rikalo, Yan Vugenfirer, Yuri Benditovich



On 2022/10/29 7:35, Philippe Mathieu-Daudé wrote:
> On 28/10/22 14:26, Akihiko Odaki wrote:
>> pci_add_capability appears most PCI devices. Its error handling required
>> lots of code, and led to inconsistent behaviors such as:
>> - passing error_abort
>> - passing error_fatal
>> - asserting the returned value
>> - propagating the error to the caller
>> - skipping the rest of the function
>> - just ignoring
>>
>> The code generating errors in pci_add_capability had a comment which
>> says:
>>> Verify that capabilities don't overlap.  Note: device assignment
>>> depends on this check to verify that the device is not broken.
>>> Should never trigger for emulated devices, but it's helpful for
>>> debugging these.
>>
>> Indeed vfio has some code that passes capability offsets and sizes from
>> a physical device, but it explicitly pays attention so that the
>> capabilities never overlap. Therefore, we can always assert that
>> capabilities never overlap when pci_add_capability is called, resolving
>> these inconsistencies.
>>
>> Such an implementation of pci_add_capability will not have errp
>> parameter. However, there are so many callers of pci_add_capability
>> that it does not make sense to amend all of them at once to match
>> with the new signature. Instead, this change will allow callers of
>> pci_add_capability to omit errp as the first step.
>>
>> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
>> ---
>>   hw/pci/pci.c         |  8 ++++----
>>   include/hw/pci/pci.h | 13 ++++++++++---
>>   2 files changed, 14 insertions(+), 7 deletions(-)
> 
>> diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
>> index b54b6ef88f..51fd106f16 100644
>> --- a/include/hw/pci/pci.h
>> +++ b/include/hw/pci/pci.h
>> @@ -2,6 +2,7 @@
>>   #define QEMU_PCI_H
>>   #include "exec/memory.h"
>> +#include "qapi/error.h"
>>   #include "sysemu/dma.h"
>>   /* PCI includes legacy ISA access.  */
>> @@ -390,9 +391,15 @@ void pci_register_vga(PCIDevice *pci_dev, 
>> MemoryRegion *mem,
>>   void pci_unregister_vga(PCIDevice *pci_dev);
>>   pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num);
>> -int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
>> -                       uint8_t offset, uint8_t size,
>> -                       Error **errp);
>> +int pci_add_capability_legacy(PCIDevice *pdev, uint8_t cap_id,
>> +                              uint8_t offset, uint8_t size,
>> +                              Error **errp);
>> +
>> +#define PCI_ADD_CAPABILITY_VA(pdev, cap_id, offset, size, errp, ...) \
>> +    pci_add_capability_legacy(pdev, cap_id, offset, size, errp)
>> +
>> +#define pci_add_capability(...) \
>> +    PCI_ADD_CAPABILITY_VA(__VA_ARGS__, &error_abort)
> Do we really need PCI_ADD_CAPABILITY_VA?
> 
>    #define pci_add_capability(...) \
>         pci_add_capability_legacy(__VA_ARGS__, &error_abort)
> 

When errp is specified by the caller, the last argument, &error_abort 
becomes extra and the compiler complains about that. 
PCI_ADD_CAPABILITY_VA is a temporary dirty hack to ignore the extra 
argument.

Regards,
Akihiko Odaki


^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2022-10-31 12:40 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-10-28 12:26 [PATCH v5 00/17] pci: Abort if pci_add_capability fails Akihiko Odaki
2022-10-28 12:26 ` [PATCH v5 01/17] hw/vfio/pci: Ensure MSI and MSI-X do not overlap Akihiko Odaki
2022-10-28 14:16   ` Alex Williamson
2022-10-28 16:12     ` Akihiko Odaki
2022-10-28 19:23       ` Alex Williamson
2022-10-31 12:37         ` Akihiko Odaki
2022-10-28 12:26 ` [PATCH v5 02/17] pci: Allow to omit errp for pci_add_capability Akihiko Odaki
2022-10-28 22:35   ` Philippe Mathieu-Daudé
2022-10-31 12:39     ` Akihiko Odaki
2022-10-28 12:26 ` [PATCH v5 03/17] hw/i386/amd_iommu: Omit " Akihiko Odaki
2022-10-28 12:26 ` [PATCH v5 04/17] ahci: " Akihiko Odaki
2022-10-28 12:26 ` [PATCH v5 05/17] e1000e: " Akihiko Odaki
2022-10-28 12:26 ` [PATCH v5 06/17] eepro100: " Akihiko Odaki
2022-10-28 12:26 ` [PATCH v5 07/17] hw/nvme: " Akihiko Odaki
2022-10-28 12:26 ` [PATCH v5 08/17] msi: " Akihiko Odaki
2022-10-28 12:26 ` [PATCH v5 09/17] hw/pci/pci_bridge: " Akihiko Odaki
2022-10-28 12:26 ` [PATCH v5 10/17] pcie: " Akihiko Odaki
2022-10-28 12:26 ` [PATCH v5 11/17] pci/shpc: " Akihiko Odaki
2022-10-28 12:26 ` [PATCH v5 12/17] msix: " Akihiko Odaki
2022-10-28 12:26 ` [PATCH v5 13/17] pci/slotid: " Akihiko Odaki
2022-10-28 12:26 ` [PATCH v5 14/17] hw/pci-bridge/pcie_pci_bridge: " Akihiko Odaki
2022-10-28 12:26 ` [PATCH v5 15/17] hw/vfio/pci: " Akihiko Odaki
2022-10-28 12:26 ` [PATCH v5 16/17] virtio-pci: " Akihiko Odaki
2022-10-28 12:26 ` [PATCH v5 17/17] pci: Remove legacy errp from pci_add_capability Akihiko Odaki

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).