diff mbox

[18/21] pci: Use the new pci_can_add_device() to enforce devfn_min/max

Message ID 1491396106-26376-19-git-send-email-clg@kaod.org
State New
Headers show

Commit Message

Cédric Le Goater April 5, 2017, 12:41 p.m. UTC
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>

This adds a devfn_max field to PCIBus and adds a pci_can_add_device()
function which, if no "addr" (aka devfn) is specified, will tell whether
there is any slot free between devfn_min and devfn_max.

When devfn_max is 0 (default), it will be ignored (no constraints).

This will be used by some PCI root complex implementations that support
only one direct child to avoid having qemu put dumb devices at different
slot numbers.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
[clg: updated for qemu-2.9 ]
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 hw/pci/pci.c             | 22 ++++++++++++++++++++++
 include/hw/pci/pci_bus.h |  1 +
 2 files changed, 23 insertions(+)

Comments

David Gibson April 10, 2017, 5:41 a.m. UTC | #1
On Wed, Apr 05, 2017 at 02:41:43PM +0200, Cédric Le Goater wrote:
> From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> 
> This adds a devfn_max field to PCIBus and adds a pci_can_add_device()
> function which, if no "addr" (aka devfn) is specified, will tell whether
> there is any slot free between devfn_min and devfn_max.
> 
> When devfn_max is 0 (default), it will be ignored (no constraints).
> 
> This will be used by some PCI root complex implementations that support
> only one direct child to avoid having qemu put dumb devices at different
> slot numbers.
> 
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> [clg: updated for qemu-2.9 ]
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
>  hw/pci/pci.c             | 22 ++++++++++++++++++++++
>  include/hw/pci/pci_bus.h |  1 +
>  2 files changed, 23 insertions(+)
> 
> diff --git a/hw/pci/pci.c b/hw/pci/pci.c
> index 259483b1c01a..817ad14ed987 100644
> --- a/hw/pci/pci.c
> +++ b/hw/pci/pci.c
> @@ -143,6 +143,27 @@ static uint16_t pcibus_numa_node(PCIBus *bus)
>      return NUMA_NODE_UNASSIGNED;
>  }
>  
> +static bool pci_can_add_device(BusState *bus, QemuOpts *opts)
> +{
> +    unsigned int devfn, max;
> +    PCIBus *pbus = PCI_BUS(bus);
> +
> +    /* If address is specified, say yes and let it fail if that doesn't work */
> +    if (qemu_opt_get(opts, "addr") != NULL) {

Ah, so these are options for the device to add, not for the bus.  I'm
not entirely sure that device options are standardized enough to do
this safely.

Could you use an initialized, but not realized, device pointer instead?


> +        return true;
> +    }
> +    max = ARRAY_SIZE(pbus->devices);
> +    if (pbus->devfn_max && pbus->devfn_max < max) {
> +        max = pbus->devfn_max;
> +    }
> +    for (devfn = pbus->devfn_min ; devfn < max; devfn += PCI_FUNC_MAX) {
> +        if (!pbus->devices[devfn]) {
> +            break;
> +        }
> +    }
> +    return devfn < max;
> +}
> +
>  static void pci_bus_class_init(ObjectClass *klass, void *data)
>  {
>      BusClass *k = BUS_CLASS(klass);
> @@ -154,6 +175,7 @@ static void pci_bus_class_init(ObjectClass *klass, void *data)
>      k->realize = pci_bus_realize;
>      k->unrealize = pci_bus_unrealize;
>      k->reset = pcibus_reset;
> +    k->can_add_device = pci_can_add_device;
>  
>      pbc->is_root = pcibus_is_root;
>      pbc->bus_num = pcibus_num;
> diff --git a/include/hw/pci/pci_bus.h b/include/hw/pci/pci_bus.h
> index 5484a9b5c573..05c9dd22a8fa 100644
> --- a/include/hw/pci/pci_bus.h
> +++ b/include/hw/pci/pci_bus.h
> @@ -23,6 +23,7 @@ struct PCIBus {
>      PCIIOMMUFunc iommu_fn;
>      void *iommu_opaque;
>      uint8_t devfn_min;
> +    uint8_t devfn_max;
>      pci_set_irq_fn set_irq;
>      pci_map_irq_fn map_irq;
>      pci_route_irq_fn route_intx_to_irq;
Michael S. Tsirkin April 10, 2017, 7:48 p.m. UTC | #2
On Wed, Apr 05, 2017 at 02:41:43PM +0200, Cédric Le Goater wrote:
> From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> 
> This adds a devfn_max field to PCIBus and adds a pci_can_add_device()
> function which, if no "addr" (aka devfn) is specified, will tell whether
> there is any slot free between devfn_min and devfn_max.
> 
> When devfn_max is 0 (default), it will be ignored (no constraints).
> 
> This will be used by some PCI root complex implementations that support
> only one direct child to avoid having qemu put dumb devices at different
> slot numbers.
> 
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> [clg: updated for qemu-2.9 ]
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
>  hw/pci/pci.c             | 22 ++++++++++++++++++++++
>  include/hw/pci/pci_bus.h |  1 +
>  2 files changed, 23 insertions(+)
> 
> diff --git a/hw/pci/pci.c b/hw/pci/pci.c
> index 259483b1c01a..817ad14ed987 100644
> --- a/hw/pci/pci.c
> +++ b/hw/pci/pci.c
> @@ -143,6 +143,27 @@ static uint16_t pcibus_numa_node(PCIBus *bus)
>      return NUMA_NODE_UNASSIGNED;
>  }
>  
> +static bool pci_can_add_device(BusState *bus, QemuOpts *opts)
> +{
> +    unsigned int devfn, max;
> +    PCIBus *pbus = PCI_BUS(bus);
> +
> +    /* If address is specified, say yes and let it fail if that doesn't work */
> +    if (qemu_opt_get(opts, "addr") != NULL) {
> +        return true;
> +    }
> +    max = ARRAY_SIZE(pbus->devices);
> +    if (pbus->devfn_max && pbus->devfn_max < max) {
> +        max = pbus->devfn_max;
> +    }
> +    for (devfn = pbus->devfn_min ; devfn < max; devfn += PCI_FUNC_MAX) {
> +        if (!pbus->devices[devfn]) {
> +            break;
> +        }
> +    }
> +    return devfn < max;
> +}
> +

This doesn't do the right thing for AER I think.


>  static void pci_bus_class_init(ObjectClass *klass, void *data)
>  {
>      BusClass *k = BUS_CLASS(klass);
> @@ -154,6 +175,7 @@ static void pci_bus_class_init(ObjectClass *klass, void *data)
>      k->realize = pci_bus_realize;
>      k->unrealize = pci_bus_unrealize;
>      k->reset = pcibus_reset;
> +    k->can_add_device = pci_can_add_device;
>  
>      pbc->is_root = pcibus_is_root;
>      pbc->bus_num = pcibus_num;
> diff --git a/include/hw/pci/pci_bus.h b/include/hw/pci/pci_bus.h
> index 5484a9b5c573..05c9dd22a8fa 100644
> --- a/include/hw/pci/pci_bus.h
> +++ b/include/hw/pci/pci_bus.h
> @@ -23,6 +23,7 @@ struct PCIBus {
>      PCIIOMMUFunc iommu_fn;
>      void *iommu_opaque;
>      uint8_t devfn_min;
> +    uint8_t devfn_max;
>      pci_set_irq_fn set_irq;
>      pci_map_irq_fn map_irq;
>      pci_route_irq_fn route_intx_to_irq;
> -- 
> 2.7.4
>
diff mbox

Patch

diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 259483b1c01a..817ad14ed987 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -143,6 +143,27 @@  static uint16_t pcibus_numa_node(PCIBus *bus)
     return NUMA_NODE_UNASSIGNED;
 }
 
+static bool pci_can_add_device(BusState *bus, QemuOpts *opts)
+{
+    unsigned int devfn, max;
+    PCIBus *pbus = PCI_BUS(bus);
+
+    /* If address is specified, say yes and let it fail if that doesn't work */
+    if (qemu_opt_get(opts, "addr") != NULL) {
+        return true;
+    }
+    max = ARRAY_SIZE(pbus->devices);
+    if (pbus->devfn_max && pbus->devfn_max < max) {
+        max = pbus->devfn_max;
+    }
+    for (devfn = pbus->devfn_min ; devfn < max; devfn += PCI_FUNC_MAX) {
+        if (!pbus->devices[devfn]) {
+            break;
+        }
+    }
+    return devfn < max;
+}
+
 static void pci_bus_class_init(ObjectClass *klass, void *data)
 {
     BusClass *k = BUS_CLASS(klass);
@@ -154,6 +175,7 @@  static void pci_bus_class_init(ObjectClass *klass, void *data)
     k->realize = pci_bus_realize;
     k->unrealize = pci_bus_unrealize;
     k->reset = pcibus_reset;
+    k->can_add_device = pci_can_add_device;
 
     pbc->is_root = pcibus_is_root;
     pbc->bus_num = pcibus_num;
diff --git a/include/hw/pci/pci_bus.h b/include/hw/pci/pci_bus.h
index 5484a9b5c573..05c9dd22a8fa 100644
--- a/include/hw/pci/pci_bus.h
+++ b/include/hw/pci/pci_bus.h
@@ -23,6 +23,7 @@  struct PCIBus {
     PCIIOMMUFunc iommu_fn;
     void *iommu_opaque;
     uint8_t devfn_min;
+    uint8_t devfn_max;
     pci_set_irq_fn set_irq;
     pci_map_irq_fn map_irq;
     pci_route_irq_fn route_intx_to_irq;