On 23/05/2019 15:29, David Gibson wrote:
> Device nodes for PCI bridges (both host and P2P) describe both the bridge
> device itself and the bus hanging off it, handling of this is a bit of a
> mess.
> 
> spapr_dt_pci_device() has a few things it only adds for non-bridges, but
> always adds #address-cells and #size-cells which should only appear for
> bridges.  But the walking down the subordinate PCI bus is done in one of
> its callers spapr_populate_pci_devices_dt().  The PHB dt creation in
> spapr_populate_pci_dt() open codes some similar logic to the bridge case.
> 
> This patch consolidates things in a bunch of ways:
>  * Bus specific dt info is now created in spapr_dt_pci_bus() used for both
>    P2P bridges and the host bridge.  This includes walking subordinate
>    devices
>  * spapr_dt_pci_device() now calls spapr_dt_pci_bus() when called on a
>    P2P bridge
>  * We do detection of bridges with the is_bridge field of the device class,
>    rather than checking PCI config space directly, for consistency with
>    qemu's core PCI code.
>  * Several things are renamed for brevity and clarity
> 
> Signed-off-by: David Gibson <da...@gibson.dropbear.id.au>
> ---
>  hw/ppc/spapr.c              |   7 +-
>  hw/ppc/spapr_pci.c          | 140 +++++++++++++++++++-----------------
>  include/hw/pci-host/spapr.h |   4 +-
>  3 files changed, 79 insertions(+), 72 deletions(-)
> 
> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> index e2b33e5890..44573adce7 100644
> --- a/hw/ppc/spapr.c
> +++ b/hw/ppc/spapr.c
> @@ -1309,8 +1309,7 @@ static void *spapr_build_fdt(SpaprMachineState *spapr)
>      }
>  
>      QLIST_FOREACH(phb, &spapr->phbs, list) {
> -        ret = spapr_populate_pci_dt(phb, PHANDLE_INTC, fdt,
> -                                    spapr->irq->nr_msis, NULL);
> +        ret = spapr_dt_phb(phb, PHANDLE_INTC, fdt, spapr->irq->nr_msis, 
> NULL);
>          if (ret < 0) {
>              error_report("couldn't setup PCI devices in fdt");
>              exit(1);
> @@ -3917,8 +3916,8 @@ int spapr_phb_dt_populate(SpaprDrc *drc, 
> SpaprMachineState *spapr,
>          return -1;
>      }
>  
> -    if (spapr_populate_pci_dt(sphb, intc_phandle, fdt, spapr->irq->nr_msis,
> -                              fdt_start_offset)) {
> +    if (spapr_dt_phb(sphb, intc_phandle, fdt, spapr->irq->nr_msis,
> +                     fdt_start_offset)) {
>          error_setg(errp, "unable to create FDT node for PHB %d", 
> sphb->index);
>          return -1;
>      }
> diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
> index 4075b433fd..c166df4145 100644
> --- a/hw/ppc/spapr_pci.c
> +++ b/hw/ppc/spapr_pci.c
> @@ -1219,6 +1219,60 @@ static const char *dt_name_from_class(uint8_t class, 
> uint8_t subclass,
>  static uint32_t spapr_phb_get_pci_drc_index(SpaprPhbState *phb,
>                                              PCIDevice *pdev);
>  
> +typedef struct PciWalkFdt {
> +    void *fdt;
> +    int offset;
> +    SpaprPhbState *sphb;
> +    int err;
> +} PciWalkFdt;
> +
> +static int spapr_dt_pci_device(SpaprPhbState *sphb, PCIDevice *dev,
> +                               void *fdt, int parent_offset);
> +
> +static void spapr_dt_pci_device_cb(PCIBus *bus, PCIDevice *pdev,
> +                                   void *opaque)
> +{
> +    PciWalkFdt *p = opaque;
> +    int err;
> +
> +    if (p->err) {
> +        /* Something's already broken, don't keep going */
> +        return;
> +    }
> +
> +    err = spapr_dt_pci_device(p->sphb, pdev, p->fdt, p->offset);
> +    if (err < 0) {
> +        p->err = err;
> +    }
> +}
> +
> +/* Augment PCI device node with bridge specific information */
> +static int spapr_dt_pci_bus(SpaprPhbState *sphb, PCIBus *bus,
> +                               void *fdt, int offset)
> +{
> +    PciWalkFdt cbinfo = {
> +        .fdt = fdt,
> +        .offset = offset,
> +        .sphb = sphb,
> +        .err = 0,
> +    };
> +
> +    _FDT(fdt_setprop_cell(fdt, offset, "#address-cells",
> +                          RESOURCE_CELLS_ADDRESS));
> +    _FDT(fdt_setprop_cell(fdt, offset, "#size-cells",
> +                          RESOURCE_CELLS_SIZE));
> +
> +    if (bus) {
> +        pci_for_each_device_reverse(bus, pci_bus_num(bus),
> +                                    spapr_dt_pci_device_cb, &cbinfo);
> +        if (cbinfo.err) {
> +            return cbinfo.err;
> +        }
> +    }
> +
> +    return offset;


This spapr_dt_pci_bus() returns 0 or an offset or an error.

But:
spapr_dt_phb() returns 0 or error; and so does spapr_dt_drc().

Not extremely consistent.

It looks like spapr_dt_pci_bus() does not need to return @offset as it
does not change it and the caller - spapr_dt_pci_device() - can have 1
"return offset" in the end.



> +}
> +
>  /* create OF node for pci device and required OF DT properties */
>  static int spapr_dt_pci_device(SpaprPhbState *sphb, PCIDevice *dev,
>                                 void *fdt, int parent_offset)
> @@ -1228,10 +1282,9 @@ static int spapr_dt_pci_device(SpaprPhbState *sphb, 
> PCIDevice *dev,
>      char *nodename;
>      int slot = PCI_SLOT(dev->devfn);
>      int func = PCI_FUNC(dev->devfn);
> +    PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
>      ResourceProps rp;
>      uint32_t drc_index = spapr_phb_get_pci_drc_index(sphb, dev);
> -    uint32_t header_type = pci_default_read_config(dev, PCI_HEADER_TYPE, 1);
> -    bool is_bridge = (header_type == PCI_HEADER_TYPE_BRIDGE);
>      uint32_t vendor_id = pci_default_read_config(dev, PCI_VENDOR_ID, 2);
>      uint32_t device_id = pci_default_read_config(dev, PCI_DEVICE_ID, 2);
>      uint32_t revision_id = pci_default_read_config(dev, PCI_REVISION_ID, 1);
> @@ -1268,13 +1321,6 @@ static int spapr_dt_pci_device(SpaprPhbState *sphb, 
> PCIDevice *dev,
>          _FDT(fdt_setprop_cell(fdt, offset, "interrupts", irq_pin));
>      }
>  
> -    if (!is_bridge) {
> -        uint32_t min_grant = pci_default_read_config(dev, PCI_MIN_GNT, 1);
> -        uint32_t max_latency = pci_default_read_config(dev, PCI_MAX_LAT, 1);
> -        _FDT(fdt_setprop_cell(fdt, offset, "min-grant", min_grant));
> -        _FDT(fdt_setprop_cell(fdt, offset, "max-latency", max_latency));
> -    }
> -
>      if (subsystem_id) {
>          _FDT(fdt_setprop_cell(fdt, offset, "subsystem-id", subsystem_id));
>      }
> @@ -1309,11 +1355,6 @@ static int spapr_dt_pci_device(SpaprPhbState *sphb, 
> PCIDevice *dev,
>          _FDT(fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index));
>      }
>  
> -    _FDT(fdt_setprop_cell(fdt, offset, "#address-cells",
> -                          RESOURCE_CELLS_ADDRESS));
> -    _FDT(fdt_setprop_cell(fdt, offset, "#size-cells",
> -                          RESOURCE_CELLS_SIZE));
> -
>      if (msi_present(dev)) {
>          uint32_t max_msi = msi_nr_vectors_allocated(dev);
>          if (max_msi) {
> @@ -1338,7 +1379,18 @@ static int spapr_dt_pci_device(SpaprPhbState *sphb, 
> PCIDevice *dev,
>  
>      spapr_phb_nvgpu_populate_pcidev_dt(dev, fdt, offset, sphb);
>  
> -    return offset;
> +    if (!pc->is_bridge) {
> +        /* Properties only for non-bridges */
> +        uint32_t min_grant = pci_default_read_config(dev, PCI_MIN_GNT, 1);
> +        uint32_t max_latency = pci_default_read_config(dev, PCI_MAX_LAT, 1);
> +        _FDT(fdt_setprop_cell(fdt, offset, "min-grant", min_grant));
> +        _FDT(fdt_setprop_cell(fdt, offset, "max-latency", max_latency));
> +        return offset;
> +    } else {
> +        PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(dev));
> +
> +        return spapr_dt_pci_bus(sphb, sec_bus, fdt, offset);
> +    }
>  }
>  
>  /* Callback to be called during DRC release. */
> @@ -2063,44 +2115,6 @@ static const TypeInfo spapr_phb_info = {
>      }
>  };
>  
> -typedef struct SpaprFdt {
> -    void *fdt;
> -    int node_off;
> -    SpaprPhbState *sphb;
> -} SpaprFdt;
> -
> -static void spapr_populate_pci_devices_dt(PCIBus *bus, PCIDevice *pdev,
> -                                          void *opaque)
> -{
> -    PCIBus *sec_bus;
> -    SpaprFdt *p = opaque;
> -    int offset;
> -    SpaprFdt s_fdt;
> -
> -    offset = spapr_dt_pci_device(p->sphb, pdev, p->fdt, p->node_off);
> -    if (!offset) {
> -        error_report("Failed to create pci child device tree node");
> -        return;
> -    }
> -
> -    if ((pci_default_read_config(pdev, PCI_HEADER_TYPE, 1) !=
> -         PCI_HEADER_TYPE_BRIDGE)) {
> -        return;
> -    }
> -
> -    sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev));
> -    if (!sec_bus) {
> -        return;
> -    }
> -
> -    s_fdt.fdt = p->fdt;
> -    s_fdt.node_off = offset;
> -    s_fdt.sphb = p->sphb;
> -    pci_for_each_device_reverse(sec_bus, pci_bus_num(sec_bus),
> -                                spapr_populate_pci_devices_dt,
> -                                &s_fdt);
> -}
> -
>  static void spapr_phb_pci_enumerate_bridge(PCIBus *bus, PCIDevice *pdev,
>                                             void *opaque)
>  {
> @@ -2138,8 +2152,8 @@ static void spapr_phb_pci_enumerate(SpaprPhbState *phb)
>  
>  }
>  
> -int spapr_populate_pci_dt(SpaprPhbState *phb, uint32_t intc_phandle, void 
> *fdt,
> -                          uint32_t nr_msis, int *node_offset)
> +int spapr_dt_phb(SpaprPhbState *phb, uint32_t intc_phandle, void *fdt,
> +                 uint32_t nr_msis, int *node_offset)
>  {
>      int bus_off, i, j, ret;
>      uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) };
> @@ -2186,8 +2200,6 @@ int spapr_populate_pci_dt(SpaprPhbState *phb, uint32_t 
> intc_phandle, void *fdt,
>                                  cpu_to_be32(0x0),
>                                  cpu_to_be32(phb->numa_node)};
>      SpaprTceTable *tcet;
> -    PCIBus *bus = PCI_HOST_BRIDGE(phb)->bus;
> -    SpaprFdt s_fdt;
>      SpaprDrc *drc;
>      Error *errp = NULL;
>  
> @@ -2200,8 +2212,6 @@ int spapr_populate_pci_dt(SpaprPhbState *phb, uint32_t 
> intc_phandle, void *fdt,
>      /* Write PHB properties */
>      _FDT(fdt_setprop_string(fdt, bus_off, "device_type", "pci"));
>      _FDT(fdt_setprop_string(fdt, bus_off, "compatible", "IBM,Logical_PHB"));
> -    _FDT(fdt_setprop_cell(fdt, bus_off, "#address-cells", 0x3));
> -    _FDT(fdt_setprop_cell(fdt, bus_off, "#size-cells", 0x2));
>      _FDT(fdt_setprop_cell(fdt, bus_off, "#interrupt-cells", 0x1));
>      _FDT(fdt_setprop(fdt, bus_off, "used-by-rtas", NULL, 0));
>      _FDT(fdt_setprop(fdt, bus_off, "bus-range", &bus_range, 
> sizeof(bus_range)));
> @@ -2266,13 +2276,11 @@ int spapr_populate_pci_dt(SpaprPhbState *phb, 
> uint32_t intc_phandle, void *fdt,
>      spapr_phb_pci_enumerate(phb);
>      _FDT(fdt_setprop_cell(fdt, bus_off, "qemu,phb-enumerated", 0x1));
>  
> -    /* Populate tree nodes with PCI devices attached */
> -    s_fdt.fdt = fdt;
> -    s_fdt.node_off = bus_off;
> -    s_fdt.sphb = phb;
> -    pci_for_each_device_reverse(bus, pci_bus_num(bus),
> -                                spapr_populate_pci_devices_dt,
> -                                &s_fdt);
> +    /* Walk the bridge and subordinate buses */
> +    ret = spapr_dt_pci_bus(phb, PCI_HOST_BRIDGE(phb)->bus, fdt, bus_off);
> +    if (ret) {


if (ret < 0)

otherwise it returns prematurely and NVLink stuff does not make it to
the FDT.


Otherwise the whole patchset is a good cleanup and seems working fine.


> +        return ret;
> +    }
>  
>      ret = spapr_drc_populate_dt(fdt, bus_off, OBJECT(phb),
>                                  SPAPR_DR_CONNECTOR_TYPE_PCI);
> diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h
> index 53519c835e..1b61162f91 100644
> --- a/include/hw/pci-host/spapr.h
> +++ b/include/hw/pci-host/spapr.h
> @@ -131,8 +131,8 @@ static inline qemu_irq spapr_phb_lsi_qirq(struct 
> SpaprPhbState *phb, int pin)
>      return spapr_qirq(spapr, phb->lsi_table[pin].irq);
>  }
>  
> -int spapr_populate_pci_dt(SpaprPhbState *phb, uint32_t intc_phandle, void 
> *fdt,
> -                          uint32_t nr_msis, int *node_offset);
> +int spapr_dt_phb(SpaprPhbState *phb, uint32_t intc_phandle, void *fdt,
> +                 uint32_t nr_msis, int *node_offset);
>  
>  void spapr_pci_rtas_init(void);
>  
> 

-- 
Alexey

Reply via email to