qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v6 0/3] Red Hat PCI bridge resource reserve capability
@ 2017-08-13 16:03 Aleksandr Bezzubikov
  2017-08-13 16:03 ` [Qemu-devel] [PATCH v6 1/3] pci: refactor pci_find_capapibilty to get bdf as the first argument instead of the whole pci_device Aleksandr Bezzubikov
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Aleksandr Bezzubikov @ 2017-08-13 16:03 UTC (permalink / raw)
  To: seabios
  Cc: marcel, mst, kevin, kraxel, lersek, qemu-devel,
	Aleksandr Bezzubikov

Now PCI bridges get a bus range number on a system init,
basing on currently plugged devices. That's why when one wants to hotplug another bridge,
it needs his child bus, which the parent is unable to provide (speaking about virtual device).
The suggested workaround is to have vendor-specific capability in Red Hat PCI bridges
that contains number of additional bus to reserve (as well as IO/MEM/PREF space limit hints) 
on BIOS PCI init.
So this capability is intended only for pure QEMU->SeaBIOS usage.

Considering all aforesaid, this series is directly connected with
QEMU series "Generic PCIE-PCI Bridge".

Although the new PCI capability is supposed to contain various limits along with
bus number to reserve, now only its full layout is proposed. And
only bus_reserve field is used in QEMU and BIOS. Limits usage
is still a subject for implementation as now
the main goal of this series to provide necessary support from the 
firmware side to PCIE-PCI bridge hotplug. 

Changes v5->v6:
1. Remove unnecessary indents and line breaks (addresses Marcel's comments)
2. Count IO/MEM/PREF region size as a maximum of necessary size and one provide in
	RESOURCE_RESERVE capability (addresses Marcel's comment).
3. Make the cap debug message more detailed (addresses Marcel's comment).
4. Change pref_32 and pref_64 cap fields comment.

Changes v4->v5:
1. Rename capability-related #defines
2. Move capability IO/MEM/PREF fields values usage to the regions creation stage (addresses Marcel's comment)
3. The capability layout change: separate pref_mem into pref_mem_32 and pref_mem_64 fields (QEMU side has the same changes) (addresses Laszlo's comment)
4. Extract the capability lookup and check to the separate function (addresses Marcel's comment)
	- despite of Marcel's comment do not extract field check for -1 since it increases code length
	  and doesn't look nice because of different field types 
5. Fix the capability's comment (addresses Marcel's comment)
6. Fix the 3rd patch message

Changes v3->v4:
1. Use all QEMU PCI capability fields - addresses Michael's comment
2. Changes of the capability layout (QEMU side has the same changes):
	- change reservation fields types: bus_res - uint32_t, others - uint64_t
	- interpret -1 value as 'ignore'

Changes v2->v3:
1. Merge commit 2 (Red Hat vendor ID) into commit 4 - addresses Marcel's comment,
	and add Generic PCIE Root Port device ID - addresses Michael's comment.
2. Changes of the capability layout  (QEMU side has the same changes):
	- add 'type' field to distinguish multiple 
		RedHat-specific capabilities - addresses Michael's comment
	- do not mimiс PCI Config space register layout, but use mutually exclusive differently
		sized fields for IO and prefetchable memory limits - addresses Laszlo's comment
	- use defines instead of structure and offsetof - addresses Michael's comment
3. Interpret 'bus_reserve' field as a minimum necessary
	 range to reserve - addresses Gerd's comment
4. pci_find_capability moved to pci.c - addresses Kevin's comment
5. Move capability layout header to src/fw/dev-pci.h - addresses Kevin's comment
6. Add the capability documentation - addresses Michael's comment
7. Add capability length and bus_reserve field sanity checks - addresses Michael's comment

Changes v1->v2:
1. New #define for Red Hat vendor added (addresses Konrad's comment).
2. Refactored pci_find_capability function (addresses Marcel's comment).
3. Capability reworked:
	- data type added;
	- reserve space in a structure for IO, memory and 
	  prefetchable memory limits.

Aleksandr Bezzubikov (3):
  pci: refactor pci_find_capapibilty to get bdf as the first argument
    instead of the whole pci_device
  pci: add QEMU-specific PCI capability structure
  pci: enable RedHat PCI bridges to reserve additional resource on PCI
    init

 src/fw/dev-pci.h    |  53 +++++++++++++++++++++++++++
 src/fw/pciinit.c    | 101 +++++++++++++++++++++++++++++++++++++++++++++++++---
 src/hw/pci.c        |  25 +++++++++++++
 src/hw/pci.h        |   1 +
 src/hw/pci_ids.h    |   3 ++
 src/hw/pcidevice.c  |  24 -------------
 src/hw/pcidevice.h  |   1 -
 src/hw/virtio-pci.c |   6 ++--
 8 files changed, 181 insertions(+), 33 deletions(-)
 create mode 100644 src/fw/dev-pci.h

-- 
2.7.4

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

* [Qemu-devel] [PATCH v6 1/3] pci: refactor pci_find_capapibilty to get bdf as the first argument instead of the whole pci_device
  2017-08-13 16:03 [Qemu-devel] [PATCH v6 0/3] Red Hat PCI bridge resource reserve capability Aleksandr Bezzubikov
@ 2017-08-13 16:03 ` Aleksandr Bezzubikov
  2017-08-13 16:03 ` [Qemu-devel] [PATCH v6 2/3] pci: add QEMU-specific PCI capability structure Aleksandr Bezzubikov
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 7+ messages in thread
From: Aleksandr Bezzubikov @ 2017-08-13 16:03 UTC (permalink / raw)
  To: seabios
  Cc: marcel, mst, kevin, kraxel, lersek, qemu-devel,
	Aleksandr Bezzubikov

Refactor pci_find_capability function to get bdf instead of
a whole pci_device* as the only necessary field for this function
is still bdf.

Signed-off-by: Aleksandr Bezzubikov <zuban32s@gmail.com>
Reviewed-by: Marcel Apfelbaum <marcel@redhat.com>
---
 src/fw/pciinit.c    |  4 ++--
 src/hw/pci.c        | 25 +++++++++++++++++++++++++
 src/hw/pci.h        |  1 +
 src/hw/pcidevice.c  | 24 ------------------------
 src/hw/pcidevice.h  |  1 -
 src/hw/virtio-pci.c |  6 +++---
 6 files changed, 31 insertions(+), 30 deletions(-)

diff --git a/src/fw/pciinit.c b/src/fw/pciinit.c
index 08221e6..864954f 100644
--- a/src/fw/pciinit.c
+++ b/src/fw/pciinit.c
@@ -762,7 +762,7 @@ static int pci_bus_hotplug_support(struct pci_bus *bus, u8 pcie_cap)
         return downstream_port && slot_implemented;
     }
 
-    shpc_cap = pci_find_capability(bus->bus_dev, PCI_CAP_ID_SHPC, 0);
+    shpc_cap = pci_find_capability(bus->bus_dev->bdf, PCI_CAP_ID_SHPC, 0);
     return !!shpc_cap;
 }
 
@@ -844,7 +844,7 @@ static int pci_bios_check_devices(struct pci_bus *busses)
              */
             parent = &busses[0];
         int type;
-        u8 pcie_cap = pci_find_capability(s->bus_dev, PCI_CAP_ID_EXP, 0);
+        u8 pcie_cap = pci_find_capability(s->bus_dev->bdf, PCI_CAP_ID_EXP, 0);
         int hotplug_support = pci_bus_hotplug_support(s, pcie_cap);
         for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) {
             u64 align = (type == PCI_REGION_TYPE_IO) ?
diff --git a/src/hw/pci.c b/src/hw/pci.c
index 8e3d617..50d9d2d 100644
--- a/src/hw/pci.c
+++ b/src/hw/pci.c
@@ -58,6 +58,30 @@ pci_config_maskw(u16 bdf, u32 addr, u16 off, u16 on)
     pci_config_writew(bdf, addr, val);
 }
 
+u8 pci_find_capability(u16 bdf, u8 cap_id, u8 cap)
+{
+    int i;
+    u16 status = pci_config_readw(bdf, PCI_STATUS);
+
+    if (!(status & PCI_STATUS_CAP_LIST))
+        return 0;
+
+    if (cap == 0) {
+        /* find first */
+        cap = pci_config_readb(bdf, PCI_CAPABILITY_LIST);
+    } else {
+        /* find next */
+        cap = pci_config_readb(bdf, cap + PCI_CAP_LIST_NEXT);
+    }
+    for (i = 0; cap && i <= 0xff; i++) {
+        if (pci_config_readb(bdf, cap + PCI_CAP_LIST_ID) == cap_id)
+            return cap;
+        cap = pci_config_readb(bdf, cap + PCI_CAP_LIST_NEXT);
+    }
+
+    return 0;
+}
+
 // Helper function for foreachbdf() macro - return next device
 int
 pci_next(int bdf, int bus)
@@ -107,3 +131,4 @@ pci_reboot(void)
     outb(v|6, PORT_PCI_REBOOT); /* Actually do the reset */
     udelay(50);
 }
+
diff --git a/src/hw/pci.h b/src/hw/pci.h
index ee6e196..2e30e28 100644
--- a/src/hw/pci.h
+++ b/src/hw/pci.h
@@ -39,6 +39,7 @@ u32 pci_config_readl(u16 bdf, u32 addr);
 u16 pci_config_readw(u16 bdf, u32 addr);
 u8 pci_config_readb(u16 bdf, u32 addr);
 void pci_config_maskw(u16 bdf, u32 addr, u16 off, u16 on);
+u8 pci_find_capability(u16 bdf, u8 cap_id, u8 cap);
 int pci_next(int bdf, int bus);
 int pci_probe_host(void);
 void pci_reboot(void);
diff --git a/src/hw/pcidevice.c b/src/hw/pcidevice.c
index cfebf66..8853cf7 100644
--- a/src/hw/pcidevice.c
+++ b/src/hw/pcidevice.c
@@ -134,30 +134,6 @@ pci_find_init_device(const struct pci_device_id *ids, void *arg)
     return NULL;
 }
 
-u8 pci_find_capability(struct pci_device *pci, u8 cap_id, u8 cap)
-{
-    int i;
-    u16 status = pci_config_readw(pci->bdf, PCI_STATUS);
-
-    if (!(status & PCI_STATUS_CAP_LIST))
-        return 0;
-
-    if (cap == 0) {
-        /* find first */
-        cap = pci_config_readb(pci->bdf, PCI_CAPABILITY_LIST);
-    } else {
-        /* find next */
-        cap = pci_config_readb(pci->bdf, cap + PCI_CAP_LIST_NEXT);
-    }
-    for (i = 0; cap && i <= 0xff; i++) {
-        if (pci_config_readb(pci->bdf, cap + PCI_CAP_LIST_ID) == cap_id)
-            return cap;
-        cap = pci_config_readb(pci->bdf, cap + PCI_CAP_LIST_NEXT);
-    }
-
-    return 0;
-}
-
 // Enable PCI bus-mastering (ie, DMA) support on a pci device
 void
 pci_enable_busmaster(struct pci_device *pci)
diff --git a/src/hw/pcidevice.h b/src/hw/pcidevice.h
index 354b549..225d545 100644
--- a/src/hw/pcidevice.h
+++ b/src/hw/pcidevice.h
@@ -69,7 +69,6 @@ int pci_init_device(const struct pci_device_id *ids
                     , struct pci_device *pci, void *arg);
 struct pci_device *pci_find_init_device(const struct pci_device_id *ids
                                         , void *arg);
-u8 pci_find_capability(struct pci_device *pci, u8 cap_id, u8 cap);
 void pci_enable_busmaster(struct pci_device *pci);
 u16 pci_enable_iobar(struct pci_device *pci, u32 addr);
 void *pci_enable_membar(struct pci_device *pci, u32 addr);
diff --git a/src/hw/virtio-pci.c b/src/hw/virtio-pci.c
index e5c2c33..96f9c6b 100644
--- a/src/hw/virtio-pci.c
+++ b/src/hw/virtio-pci.c
@@ -19,7 +19,7 @@
 #include "malloc.h" // free
 #include "output.h" // dprintf
 #include "pci.h" // pci_config_readl
-#include "pcidevice.h" // pci_find_capability
+#include "pcidevice.h" // struct pci_device
 #include "pci_regs.h" // PCI_BASE_ADDRESS_0
 #include "string.h" // memset
 #include "virtio-pci.h"
@@ -381,7 +381,7 @@ fail:
 
 void vp_init_simple(struct vp_device *vp, struct pci_device *pci)
 {
-    u8 cap = pci_find_capability(pci, PCI_CAP_ID_VNDR, 0);
+    u8 cap = pci_find_capability(pci->bdf, PCI_CAP_ID_VNDR, 0);
     struct vp_cap *vp_cap;
     const char *mode;
     u32 offset, base, mul;
@@ -479,7 +479,7 @@ void vp_init_simple(struct vp_device *vp, struct pci_device *pci)
                     vp_cap->cap, type, vp_cap->bar, addr, offset, mode);
         }
 
-        cap = pci_find_capability(pci, PCI_CAP_ID_VNDR, cap);
+        cap = pci_find_capability(pci->bdf, PCI_CAP_ID_VNDR, cap);
     }
 
     if (vp->common.cap && vp->notify.cap && vp->isr.cap && vp->device.cap) {
-- 
2.7.4

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

* [Qemu-devel] [PATCH v6 2/3] pci: add QEMU-specific PCI capability structure
  2017-08-13 16:03 [Qemu-devel] [PATCH v6 0/3] Red Hat PCI bridge resource reserve capability Aleksandr Bezzubikov
  2017-08-13 16:03 ` [Qemu-devel] [PATCH v6 1/3] pci: refactor pci_find_capapibilty to get bdf as the first argument instead of the whole pci_device Aleksandr Bezzubikov
@ 2017-08-13 16:03 ` Aleksandr Bezzubikov
  2017-08-16  9:54   ` Marcel Apfelbaum
  2017-08-13 16:03 ` [Qemu-devel] [PATCH v6 3/3] pci: enable RedHat PCI bridges to reserve additional resource on PCI init Aleksandr Bezzubikov
  2017-08-16 10:36 ` [Qemu-devel] [PATCH v6 0/3] Red Hat PCI bridge resource reserve capability Marcel Apfelbaum
  3 siblings, 1 reply; 7+ messages in thread
From: Aleksandr Bezzubikov @ 2017-08-13 16:03 UTC (permalink / raw)
  To: seabios
  Cc: marcel, mst, kevin, kraxel, lersek, qemu-devel,
	Aleksandr Bezzubikov

On PCI init PCI bridge devices may need some
extra info about bus number to reserve, IO, memory and
prefetchable memory limits. QEMU can provide this
with special vendor-specific PCI capability.

This capability is intended to be used only
for Red Hat PCI bridges, i.e. QEMU cooperation.

Signed-off-by: Aleksandr Bezzubikov <zuban32s@gmail.com>
---
 src/fw/dev-pci.h | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100644 src/fw/dev-pci.h

diff --git a/src/fw/dev-pci.h b/src/fw/dev-pci.h
new file mode 100644
index 0000000..0dc5556
--- /dev/null
+++ b/src/fw/dev-pci.h
@@ -0,0 +1,53 @@
+#ifndef _PCI_CAP_H
+#define _PCI_CAP_H
+
+#include "types.h"
+
+/*
+ *
+ * QEMU-specific vendor(Red Hat)-specific capability.
+ * It's intended to provide some hints for firmware to init PCI devices.
+ *
+ * Its structure is shown below:
+ *
+ * Header:
+ *
+ * u8 id;       Standard PCI Capability Header field
+ * u8 next;     Standard PCI Capability Header field
+ * u8 len;      Standard PCI Capability Header field
+ * u8 type;     Red Hat vendor-specific capability type
+ * Data:
+ *
+ * u32 bus_res;     minimum bus number to reserve;
+ *                  this is necessary for PCI Express Root Ports
+ *                  to support PCI bridges hotplug
+ * u64 io;          IO space to reserve
+ * u32 mem;         non-prefetchable memory to reserve
+ *
+ * At most of the following two fields may be set to a value
+ * different from 0xFF...F:
+ * u32 prefetchable_mem_32;     prefetchable memory to reserve (32-bit MMIO)
+ * u64 prefetchable_mem_64;     prefetchable memory to reserve (64-bit MMIO)
+ *
+ * If any field value in Data section is 0xFF...F,
+ * it means that such kind of reservation is not needed and must be ignored.
+ *
+*/
+
+/* Offset of vendor-specific capability type field */
+#define PCI_CAP_REDHAT_TYPE_OFFSET  3
+
+/* List of valid Red Hat vendor-specific capability types */
+#define REDHAT_CAP_RESOURCE_RESERVE 1
+
+
+/* Offsets of RESOURCE_RESERVE capability fields */
+#define RES_RESERVE_BUS_RES        4
+#define RES_RESERVE_IO             8
+#define RES_RESERVE_MEM            16
+#define RES_RESERVE_PREF_MEM_32    20
+#define RES_RESERVE_PREF_MEM_64    24
+#define RES_RESERVE_CAP_SIZE       32
+
+#endif /* _PCI_CAP_H */
+
-- 
2.7.4

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

* [Qemu-devel] [PATCH v6 3/3] pci: enable RedHat PCI bridges to reserve additional resource on PCI init
  2017-08-13 16:03 [Qemu-devel] [PATCH v6 0/3] Red Hat PCI bridge resource reserve capability Aleksandr Bezzubikov
  2017-08-13 16:03 ` [Qemu-devel] [PATCH v6 1/3] pci: refactor pci_find_capapibilty to get bdf as the first argument instead of the whole pci_device Aleksandr Bezzubikov
  2017-08-13 16:03 ` [Qemu-devel] [PATCH v6 2/3] pci: add QEMU-specific PCI capability structure Aleksandr Bezzubikov
@ 2017-08-13 16:03 ` Aleksandr Bezzubikov
  2017-08-16 10:34   ` Marcel Apfelbaum
  2017-08-16 10:36 ` [Qemu-devel] [PATCH v6 0/3] Red Hat PCI bridge resource reserve capability Marcel Apfelbaum
  3 siblings, 1 reply; 7+ messages in thread
From: Aleksandr Bezzubikov @ 2017-08-13 16:03 UTC (permalink / raw)
  To: seabios
  Cc: marcel, mst, kevin, kraxel, lersek, qemu-devel,
	Aleksandr Bezzubikov

In case of Red Hat Generic PCIE Root Port reserve additional buses
and/or IO/MEM/PREF space, which values are provided in a vendor-specific capability.

Signed-off-by: Aleksandr Bezzubikov <zuban32s@gmail.com>
---
 src/fw/pciinit.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
 src/hw/pci_ids.h |  3 ++
 2 files changed, 98 insertions(+), 4 deletions(-)

diff --git a/src/fw/pciinit.c b/src/fw/pciinit.c
index 864954f..620b187 100644
--- a/src/fw/pciinit.c
+++ b/src/fw/pciinit.c
@@ -15,6 +15,7 @@
 #include "hw/pcidevice.h" // pci_probe_devices
 #include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL
 #include "hw/pci_regs.h" // PCI_COMMAND
+#include "fw/dev-pci.h" // REDHAT_CAP_RESOURCE_RESERVE
 #include "list.h" // struct hlist_node
 #include "malloc.h" // free
 #include "output.h" // dprintf
@@ -522,6 +523,32 @@ static void pci_bios_init_platform(void)
     }
 }
 
+static u8 pci_find_resource_reserve_capability(u16 bdf)
+{
+    if (pci_config_readw(bdf, PCI_VENDOR_ID) == PCI_VENDOR_ID_REDHAT &&
+        pci_config_readw(bdf, PCI_DEVICE_ID) ==
+                PCI_DEVICE_ID_REDHAT_ROOT_PORT) {
+        u8 cap = 0;
+        do {
+            cap = pci_find_capability(bdf, PCI_CAP_ID_VNDR, cap);
+        } while (cap &&
+                 pci_config_readb(bdf, cap + PCI_CAP_REDHAT_TYPE_OFFSET) !=
+                        REDHAT_CAP_RESOURCE_RESERVE);
+        if (cap) {
+            u8 cap_len = pci_config_readb(bdf, cap + PCI_CAP_FLAGS);
+            if (cap_len < RES_RESERVE_CAP_SIZE) {
+                dprintf(1, "PCI: QEMU resource reserve cap length %d is invalid\n",
+                        cap_len);
+            }
+        } else {
+            dprintf(1, "PCI: invalid QEMU resource reserve cap offset\n");
+        }
+        return cap;
+    } else {
+        dprintf(1, "PCI: QEMU resource reserve cap not found\n");
+        return 0;
+    }
+}
 
 /****************************************************************
  * Bus initialization
@@ -578,9 +605,28 @@ pci_bios_init_bus_rec(int bus, u8 *pci_bus)
         pci_bios_init_bus_rec(secbus, pci_bus);
 
         if (subbus != *pci_bus) {
+            u8 res_bus = 0;
+            u8 cap = pci_find_resource_reserve_capability(bdf);
+
+            if (cap) {
+                u32 tmp_res_bus = pci_config_readl(bdf,
+                        cap + RES_RESERVE_BUS_RES);
+                if (tmp_res_bus != (u32)-1) {
+                    res_bus = tmp_res_bus & 0xFF;
+                    if ((u8)(res_bus + secbus) < secbus ||
+                            (u8)(res_bus + secbus) < res_bus) {
+                        dprintf(1, "PCI: bus_reserve value %d is invalid\n",
+                                res_bus);
+                        res_bus = 0;
+                    }
+                }
+                res_bus = (*pci_bus > secbus + res_bus) ? *pci_bus
+                        : secbus + res_bus;
+            }
             dprintf(1, "PCI: subordinate bus = 0x%x -> 0x%x\n",
-                    subbus, *pci_bus);
-            subbus = *pci_bus;
+                    subbus, res_bus);
+            subbus = res_bus;
+            *pci_bus = res_bus;
         } else {
             dprintf(1, "PCI: subordinate bus = 0x%x\n", subbus);
         }
@@ -844,20 +890,65 @@ static int pci_bios_check_devices(struct pci_bus *busses)
              */
             parent = &busses[0];
         int type;
-        u8 pcie_cap = pci_find_capability(s->bus_dev->bdf, PCI_CAP_ID_EXP, 0);
+        u16 bdf = s->bus_dev->bdf;
+        u8 pcie_cap = pci_find_capability(bdf, PCI_CAP_ID_EXP, 0);
+        u8 qemu_cap = pci_find_resource_reserve_capability(bdf);
+
         int hotplug_support = pci_bus_hotplug_support(s, pcie_cap);
         for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) {
             u64 align = (type == PCI_REGION_TYPE_IO) ?
                 PCI_BRIDGE_IO_MIN : PCI_BRIDGE_MEM_MIN;
             if (!pci_bridge_has_region(s->bus_dev, type))
                 continue;
+            u64 size = 0;
+            if (qemu_cap) {
+                u32 tmp_size;
+                u64 tmp_size_64;
+                switch(type) {
+                case PCI_REGION_TYPE_IO:
+                    tmp_size_64 = (pci_config_readl(bdf, qemu_cap + RES_RESERVE_IO) |
+                            (u64)pci_config_readl(bdf, qemu_cap + RES_RESERVE_IO + 4) << 32);
+                    if (tmp_size_64 != (u64)-1) {
+                        size = tmp_size_64;
+                    }
+                    break;
+                case PCI_REGION_TYPE_MEM:
+                    tmp_size = pci_config_readl(bdf, qemu_cap + RES_RESERVE_MEM);
+                    if (tmp_size != (u32)-1) {
+                        size = tmp_size;
+                    }
+                    break;
+                case PCI_REGION_TYPE_PREFMEM:
+                    tmp_size = pci_config_readl(bdf, qemu_cap + RES_RESERVE_PREF_MEM_32);
+                    tmp_size_64 = (pci_config_readl(bdf, qemu_cap + RES_RESERVE_PREF_MEM_64) |
+                            (u64)pci_config_readl(bdf, qemu_cap + RES_RESERVE_PREF_MEM_64 + 4) << 32);
+                    if (tmp_size != (u32)-1 && tmp_size_64 == (u64)-1) {
+                        size = tmp_size;
+                    } else if (tmp_size == (u32)-1 && tmp_size_64 != (u64)-1) {
+                        size = tmp_size_64;
+                    } else if (tmp_size != (u32)-1 && tmp_size_64 != (u64)-1) {
+                        dprintf(1, "PCI: resource reserve cap PREF32 and PREF64"
+                                " conflict\n");
+                    }
+                    break;
+                default:
+                    break;
+                }
+            }
             if (pci_region_align(&s->r[type]) > align)
                  align = pci_region_align(&s->r[type]);
             u64 sum = pci_region_sum(&s->r[type]);
             int resource_optional = pcie_cap && (type == PCI_REGION_TYPE_IO);
             if (!sum && hotplug_support && !resource_optional)
                 sum = align; /* reserve min size for hot-plug */
-            u64 size = ALIGN(sum, align);
+            if (size > sum) {
+                dprintf(1, "PCI: QEMU resource reserve cap: "
+                        "size %08llx type %s\n",
+                        size, region_type_name[type]);
+            } else {
+                size = sum;
+            }
+            size = ALIGN(size, align);
             int is64 = pci_bios_bridge_region_is64(&s->r[type],
                                             s->bus_dev, type);
             // entry->bar is -1 if the entry represents a bridge region
diff --git a/src/hw/pci_ids.h b/src/hw/pci_ids.h
index 4ac73b4..38fa2ca 100644
--- a/src/hw/pci_ids.h
+++ b/src/hw/pci_ids.h
@@ -2263,6 +2263,9 @@
 #define PCI_DEVICE_ID_KORENIX_JETCARDF0	0x1600
 #define PCI_DEVICE_ID_KORENIX_JETCARDF1	0x16ff
 
+#define PCI_VENDOR_ID_REDHAT		0x1b36
+#define PCI_DEVICE_ID_REDHAT_ROOT_PORT	0x000C
+
 #define PCI_VENDOR_ID_TEKRAM		0x1de1
 #define PCI_DEVICE_ID_TEKRAM_DC290	0xdc29
 
-- 
2.7.4

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

* Re: [Qemu-devel] [PATCH v6 2/3] pci: add QEMU-specific PCI capability structure
  2017-08-13 16:03 ` [Qemu-devel] [PATCH v6 2/3] pci: add QEMU-specific PCI capability structure Aleksandr Bezzubikov
@ 2017-08-16  9:54   ` Marcel Apfelbaum
  0 siblings, 0 replies; 7+ messages in thread
From: Marcel Apfelbaum @ 2017-08-16  9:54 UTC (permalink / raw)
  To: Aleksandr Bezzubikov, seabios; +Cc: mst, kevin, kraxel, lersek, qemu-devel

On 13/08/2017 19:03, Aleksandr Bezzubikov wrote:
> On PCI init PCI bridge devices may need some
> extra info about bus number to reserve, IO, memory and
> prefetchable memory limits. QEMU can provide this
> with special vendor-specific PCI capability.
> 
> This capability is intended to be used only
> for Red Hat PCI bridges, i.e. QEMU cooperation.
> 


Reviewed-by: Marcel Apfelbaum <marcel@redhat.com>

Thanks,
Marcel

> Signed-off-by: Aleksandr Bezzubikov <zuban32s@gmail.com>
> ---
>   src/fw/dev-pci.h | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 53 insertions(+)
>   create mode 100644 src/fw/dev-pci.h
> 
> diff --git a/src/fw/dev-pci.h b/src/fw/dev-pci.h
> new file mode 100644
> index 0000000..0dc5556
> --- /dev/null
> +++ b/src/fw/dev-pci.h
> @@ -0,0 +1,53 @@
> +#ifndef _PCI_CAP_H
> +#define _PCI_CAP_H
> +
> +#include "types.h"
> +
> +/*
> + *
> + * QEMU-specific vendor(Red Hat)-specific capability.
> + * It's intended to provide some hints for firmware to init PCI devices.
> + *
> + * Its structure is shown below:
> + *
> + * Header:
> + *
> + * u8 id;       Standard PCI Capability Header field
> + * u8 next;     Standard PCI Capability Header field
> + * u8 len;      Standard PCI Capability Header field
> + * u8 type;     Red Hat vendor-specific capability type
> + * Data:
> + *
> + * u32 bus_res;     minimum bus number to reserve;
> + *                  this is necessary for PCI Express Root Ports
> + *                  to support PCI bridges hotplug
> + * u64 io;          IO space to reserve
> + * u32 mem;         non-prefetchable memory to reserve
> + *
> + * At most of the following two fields may be set to a value
> + * different from 0xFF...F:
> + * u32 prefetchable_mem_32;     prefetchable memory to reserve (32-bit MMIO)
> + * u64 prefetchable_mem_64;     prefetchable memory to reserve (64-bit MMIO)
> + *
> + * If any field value in Data section is 0xFF...F,
> + * it means that such kind of reservation is not needed and must be ignored.
> + *
> +*/
> +
> +/* Offset of vendor-specific capability type field */
> +#define PCI_CAP_REDHAT_TYPE_OFFSET  3
> +
> +/* List of valid Red Hat vendor-specific capability types */
> +#define REDHAT_CAP_RESOURCE_RESERVE 1
> +
> +
> +/* Offsets of RESOURCE_RESERVE capability fields */
> +#define RES_RESERVE_BUS_RES        4
> +#define RES_RESERVE_IO             8
> +#define RES_RESERVE_MEM            16
> +#define RES_RESERVE_PREF_MEM_32    20
> +#define RES_RESERVE_PREF_MEM_64    24
> +#define RES_RESERVE_CAP_SIZE       32
> +
> +#endif /* _PCI_CAP_H */
> +
> 

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

* Re: [Qemu-devel] [PATCH v6 3/3] pci: enable RedHat PCI bridges to reserve additional resource on PCI init
  2017-08-13 16:03 ` [Qemu-devel] [PATCH v6 3/3] pci: enable RedHat PCI bridges to reserve additional resource on PCI init Aleksandr Bezzubikov
@ 2017-08-16 10:34   ` Marcel Apfelbaum
  0 siblings, 0 replies; 7+ messages in thread
From: Marcel Apfelbaum @ 2017-08-16 10:34 UTC (permalink / raw)
  To: Aleksandr Bezzubikov, seabios; +Cc: mst, kevin, kraxel, lersek, qemu-devel

On 13/08/2017 19:03, Aleksandr Bezzubikov wrote:
> In case of Red Hat Generic PCIE Root Port reserve additional buses
> and/or IO/MEM/PREF space, which values are provided in a vendor-specific capability.
> 
> Signed-off-by: Aleksandr Bezzubikov <zuban32s@gmail.com>
> ---
>   src/fw/pciinit.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
>   src/hw/pci_ids.h |  3 ++
>   2 files changed, 98 insertions(+), 4 deletions(-)
> 
> diff --git a/src/fw/pciinit.c b/src/fw/pciinit.c
> index 864954f..620b187 100644
> --- a/src/fw/pciinit.c
> +++ b/src/fw/pciinit.c
> @@ -15,6 +15,7 @@
>   #include "hw/pcidevice.h" // pci_probe_devices
>   #include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL
>   #include "hw/pci_regs.h" // PCI_COMMAND
> +#include "fw/dev-pci.h" // REDHAT_CAP_RESOURCE_RESERVE
>   #include "list.h" // struct hlist_node
>   #include "malloc.h" // free
>   #include "output.h" // dprintf
> @@ -522,6 +523,32 @@ static void pci_bios_init_platform(void)
>       }
>   }
>   
> +static u8 pci_find_resource_reserve_capability(u16 bdf)
> +{
> +    if (pci_config_readw(bdf, PCI_VENDOR_ID) == PCI_VENDOR_ID_REDHAT &&
> +        pci_config_readw(bdf, PCI_DEVICE_ID) ==
> +                PCI_DEVICE_ID_REDHAT_ROOT_PORT) {
> +        u8 cap = 0;
> +        do {
> +            cap = pci_find_capability(bdf, PCI_CAP_ID_VNDR, cap);
> +        } while (cap &&
> +                 pci_config_readb(bdf, cap + PCI_CAP_REDHAT_TYPE_OFFSET) !=
> +                        REDHAT_CAP_RESOURCE_RESERVE);
> +        if (cap) {
> +            u8 cap_len = pci_config_readb(bdf, cap + PCI_CAP_FLAGS);
> +            if (cap_len < RES_RESERVE_CAP_SIZE) {
> +                dprintf(1, "PCI: QEMU resource reserve cap length %d is invalid\n",
> +                        cap_len);
> +            }
> +        } else {
> +            dprintf(1, "PCI: invalid QEMU resource reserve cap offset\n");
> +        }
> +        return cap;
> +    } else {
> +        dprintf(1, "PCI: QEMU resource reserve cap not found\n");
> +        return 0;
> +    }
> +}
>   
>   /****************************************************************
>    * Bus initialization
> @@ -578,9 +605,28 @@ pci_bios_init_bus_rec(int bus, u8 *pci_bus)
>           pci_bios_init_bus_rec(secbus, pci_bus);
>   
>           if (subbus != *pci_bus) {
> +            u8 res_bus = 0;
> +            u8 cap = pci_find_resource_reserve_capability(bdf);
> +
> +            if (cap) {
> +                u32 tmp_res_bus = pci_config_readl(bdf,
> +                        cap + RES_RESERVE_BUS_RES);
> +                if (tmp_res_bus != (u32)-1) {
> +                    res_bus = tmp_res_bus & 0xFF;
> +                    if ((u8)(res_bus + secbus) < secbus ||
> +                            (u8)(res_bus + secbus) < res_bus) {
> +                        dprintf(1, "PCI: bus_reserve value %d is invalid\n",
> +                                res_bus);
> +                        res_bus = 0;
> +                    }
> +                }
> +                res_bus = (*pci_bus > secbus + res_bus) ? *pci_bus
> +                        : secbus + res_bus;
> +            }
>               dprintf(1, "PCI: subordinate bus = 0x%x -> 0x%x\n",
> -                    subbus, *pci_bus);
> -            subbus = *pci_bus;
> +                    subbus, res_bus);
> +            subbus = res_bus;
> +            *pci_bus = res_bus;
>           } else {
>               dprintf(1, "PCI: subordinate bus = 0x%x\n", subbus);
>           }
> @@ -844,20 +890,65 @@ static int pci_bios_check_devices(struct pci_bus *busses)
>                */
>               parent = &busses[0];
>           int type;
> -        u8 pcie_cap = pci_find_capability(s->bus_dev->bdf, PCI_CAP_ID_EXP, 0);
> +        u16 bdf = s->bus_dev->bdf;
> +        u8 pcie_cap = pci_find_capability(bdf, PCI_CAP_ID_EXP, 0);
> +        u8 qemu_cap = pci_find_resource_reserve_capability(bdf);
> +
>           int hotplug_support = pci_bus_hotplug_support(s, pcie_cap);
>           for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) {
>               u64 align = (type == PCI_REGION_TYPE_IO) ?
>                   PCI_BRIDGE_IO_MIN : PCI_BRIDGE_MEM_MIN;
>               if (!pci_bridge_has_region(s->bus_dev, type))
>                   continue;
> +            u64 size = 0;
> +            if (qemu_cap) {
> +                u32 tmp_size;
> +                u64 tmp_size_64;
> +                switch(type) {
> +                case PCI_REGION_TYPE_IO:
> +                    tmp_size_64 = (pci_config_readl(bdf, qemu_cap + RES_RESERVE_IO) |
> +                            (u64)pci_config_readl(bdf, qemu_cap + RES_RESERVE_IO + 4) << 32);
> +                    if (tmp_size_64 != (u64)-1) {
> +                        size = tmp_size_64;
> +                    }
> +                    break;
> +                case PCI_REGION_TYPE_MEM:
> +                    tmp_size = pci_config_readl(bdf, qemu_cap + RES_RESERVE_MEM);
> +                    if (tmp_size != (u32)-1) {
> +                        size = tmp_size;
> +                    }
> +                    break;
> +                case PCI_REGION_TYPE_PREFMEM:
> +                    tmp_size = pci_config_readl(bdf, qemu_cap + RES_RESERVE_PREF_MEM_32);
> +                    tmp_size_64 = (pci_config_readl(bdf, qemu_cap + RES_RESERVE_PREF_MEM_64) |
> +                            (u64)pci_config_readl(bdf, qemu_cap + RES_RESERVE_PREF_MEM_64 + 4) << 32);
> +                    if (tmp_size != (u32)-1 && tmp_size_64 == (u64)-1) {
> +                        size = tmp_size;
> +                    } else if (tmp_size == (u32)-1 && tmp_size_64 != (u64)-1) {
> +                        size = tmp_size_64;
> +                    } else if (tmp_size != (u32)-1 && tmp_size_64 != (u64)-1) {
> +                        dprintf(1, "PCI: resource reserve cap PREF32 and PREF64"
> +                                " conflict\n");
> +                    }
> +                    break;
> +                default:
> +                    break;
> +                }
> +            }
>               if (pci_region_align(&s->r[type]) > align)
>                    align = pci_region_align(&s->r[type]);
>               u64 sum = pci_region_sum(&s->r[type]);
>               int resource_optional = pcie_cap && (type == PCI_REGION_TYPE_IO);
>               if (!sum && hotplug_support && !resource_optional)
>                   sum = align; /* reserve min size for hot-plug */
> -            u64 size = ALIGN(sum, align);
> +            if (size > sum) {
> +                dprintf(1, "PCI: QEMU resource reserve cap: "
> +                        "size %08llx type %s\n",
> +                        size, region_type_name[type]);
> +            } else {
> +                size = sum;
> +            }
> +            size = ALIGN(size, align);
>               int is64 = pci_bios_bridge_region_is64(&s->r[type],
>                                               s->bus_dev, type);
>               // entry->bar is -1 if the entry represents a bridge region
> diff --git a/src/hw/pci_ids.h b/src/hw/pci_ids.h
> index 4ac73b4..38fa2ca 100644
> --- a/src/hw/pci_ids.h
> +++ b/src/hw/pci_ids.h
> @@ -2263,6 +2263,9 @@
>   #define PCI_DEVICE_ID_KORENIX_JETCARDF0	0x1600
>   #define PCI_DEVICE_ID_KORENIX_JETCARDF1	0x16ff
>   
> +#define PCI_VENDOR_ID_REDHAT		0x1b36
> +#define PCI_DEVICE_ID_REDHAT_ROOT_PORT	0x000C
> +
>   #define PCI_VENDOR_ID_TEKRAM		0x1de1
>   #define PCI_DEVICE_ID_TEKRAM_DC290	0xdc29
>   
> 

Hi Aleksandr,

Reviewed-by: Marcel Apfelbaum <marcel@redhat.com>

Thanks,
Marcel

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

* Re: [Qemu-devel] [PATCH v6 0/3] Red Hat PCI bridge resource reserve capability
  2017-08-13 16:03 [Qemu-devel] [PATCH v6 0/3] Red Hat PCI bridge resource reserve capability Aleksandr Bezzubikov
                   ` (2 preceding siblings ...)
  2017-08-13 16:03 ` [Qemu-devel] [PATCH v6 3/3] pci: enable RedHat PCI bridges to reserve additional resource on PCI init Aleksandr Bezzubikov
@ 2017-08-16 10:36 ` Marcel Apfelbaum
  3 siblings, 0 replies; 7+ messages in thread
From: Marcel Apfelbaum @ 2017-08-16 10:36 UTC (permalink / raw)
  To: Aleksandr Bezzubikov, seabios; +Cc: mst, kevin, kraxel, lersek, qemu-devel

On 13/08/2017 19:03, Aleksandr Bezzubikov wrote:
> Now PCI bridges get a bus range number on a system init,
> basing on currently plugged devices. That's why when one wants to hotplug another bridge,
> it needs his child bus, which the parent is unable to provide (speaking about virtual device).
> The suggested workaround is to have vendor-specific capability in Red Hat PCI bridges
> that contains number of additional bus to reserve (as well as IO/MEM/PREF space limit hints)
> on BIOS PCI init.
> So this capability is intended only for pure QEMU->SeaBIOS usage.
> 
> Considering all aforesaid, this series is directly connected with
> QEMU series "Generic PCIE-PCI Bridge".
> 
> Although the new PCI capability is supposed to contain various limits along with
> bus number to reserve, now only its full layout is proposed. And
> only bus_reserve field is used in QEMU and BIOS. Limits usage
> is still a subject for implementation as now
> the main goal of this series to provide necessary support from the
> firmware side to PCIE-PCI bridge hotplug.
> 
> Changes v5->v6:
> 1. Remove unnecessary indents and line breaks (addresses Marcel's comments)
> 2. Count IO/MEM/PREF region size as a maximum of necessary size and one provide in
> 	RESOURCE_RESERVE capability (addresses Marcel's comment).
> 3. Make the cap debug message more detailed (addresses Marcel's comment).
> 4. Change pref_32 and pref_64 cap fields comment.
> 
> Changes v4->v5:
> 1. Rename capability-related #defines
> 2. Move capability IO/MEM/PREF fields values usage to the regions creation stage (addresses Marcel's comment)
> 3. The capability layout change: separate pref_mem into pref_mem_32 and pref_mem_64 fields (QEMU side has the same changes) (addresses Laszlo's comment)
> 4. Extract the capability lookup and check to the separate function (addresses Marcel's comment)
> 	- despite of Marcel's comment do not extract field check for -1 since it increases code length
> 	  and doesn't look nice because of different field types
> 5. Fix the capability's comment (addresses Marcel's comment)
> 6. Fix the 3rd patch message
> 
> Changes v3->v4:
> 1. Use all QEMU PCI capability fields - addresses Michael's comment
> 2. Changes of the capability layout (QEMU side has the same changes):
> 	- change reservation fields types: bus_res - uint32_t, others - uint64_t
> 	- interpret -1 value as 'ignore'
> 
> Changes v2->v3:
> 1. Merge commit 2 (Red Hat vendor ID) into commit 4 - addresses Marcel's comment,
> 	and add Generic PCIE Root Port device ID - addresses Michael's comment.
> 2. Changes of the capability layout  (QEMU side has the same changes):
> 	- add 'type' field to distinguish multiple
> 		RedHat-specific capabilities - addresses Michael's comment
> 	- do not mimiс PCI Config space register layout, but use mutually exclusive differently
> 		sized fields for IO and prefetchable memory limits - addresses Laszlo's comment
> 	- use defines instead of structure and offsetof - addresses Michael's comment
> 3. Interpret 'bus_reserve' field as a minimum necessary
> 	 range to reserve - addresses Gerd's comment
> 4. pci_find_capability moved to pci.c - addresses Kevin's comment
> 5. Move capability layout header to src/fw/dev-pci.h - addresses Kevin's comment
> 6. Add the capability documentation - addresses Michael's comment
> 7. Add capability length and bus_reserve field sanity checks - addresses Michael's comment
> 
> Changes v1->v2:
> 1. New #define for Red Hat vendor added (addresses Konrad's comment).
> 2. Refactored pci_find_capability function (addresses Marcel's comment).
> 3. Capability reworked:
> 	- data type added;
> 	- reserve space in a structure for IO, memory and
> 	  prefetchable memory limits.
> 
> Aleksandr Bezzubikov (3):
>    pci: refactor pci_find_capapibilty to get bdf as the first argument
>      instead of the whole pci_device
>    pci: add QEMU-specific PCI capability structure
>    pci: enable RedHat PCI bridges to reserve additional resource on PCI
>      init
> 
>   src/fw/dev-pci.h    |  53 +++++++++++++++++++++++++++
>   src/fw/pciinit.c    | 101 +++++++++++++++++++++++++++++++++++++++++++++++++---
>   src/hw/pci.c        |  25 +++++++++++++
>   src/hw/pci.h        |   1 +
>   src/hw/pci_ids.h    |   3 ++
>   src/hw/pcidevice.c  |  24 -------------
>   src/hw/pcidevice.h  |   1 -
>   src/hw/virtio-pci.c |   6 ++--
>   8 files changed, 181 insertions(+), 33 deletions(-)
>   create mode 100644 src/fw/dev-pci.h
> 

Hi,

Series
    Tested-by: Marcel Apfelbaum <marcel@redhat.com>

Tested with Win10 and Fedora guests, verified the bus/io/mem hints
are working correctly.

Thanks,
Marcel

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

end of thread, other threads:[~2017-08-16 10:37 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-08-13 16:03 [Qemu-devel] [PATCH v6 0/3] Red Hat PCI bridge resource reserve capability Aleksandr Bezzubikov
2017-08-13 16:03 ` [Qemu-devel] [PATCH v6 1/3] pci: refactor pci_find_capapibilty to get bdf as the first argument instead of the whole pci_device Aleksandr Bezzubikov
2017-08-13 16:03 ` [Qemu-devel] [PATCH v6 2/3] pci: add QEMU-specific PCI capability structure Aleksandr Bezzubikov
2017-08-16  9:54   ` Marcel Apfelbaum
2017-08-13 16:03 ` [Qemu-devel] [PATCH v6 3/3] pci: enable RedHat PCI bridges to reserve additional resource on PCI init Aleksandr Bezzubikov
2017-08-16 10:34   ` Marcel Apfelbaum
2017-08-16 10:36 ` [Qemu-devel] [PATCH v6 0/3] Red Hat PCI bridge resource reserve capability Marcel Apfelbaum

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).