From patchwork Wed Jun 12 05:49:21 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Gibson X-Patchwork-Id: 1114303 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=gibson.dropbear.id.au Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=gibson.dropbear.id.au header.i=@gibson.dropbear.id.au header.b="R0nKqTgh"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45NxCx0Sdzz9s9y for ; Wed, 12 Jun 2019 16:04:38 +1000 (AEST) Received: from localhost ([::1]:56884 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hawN8-0008VH-Tg for incoming@patchwork.ozlabs.org; Wed, 12 Jun 2019 02:04:34 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58575) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1haw8o-0004Zp-P7 for qemu-devel@nongnu.org; Wed, 12 Jun 2019 01:49:48 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1haw8k-00072p-LQ for qemu-devel@nongnu.org; Wed, 12 Jun 2019 01:49:46 -0400 Received: from ozlabs.org ([203.11.71.1]:54437) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1haw8k-00070v-0m; Wed, 12 Jun 2019 01:49:42 -0400 Received: by ozlabs.org (Postfix, from userid 1007) id 45NwtR0HDnz9sND; Wed, 12 Jun 2019 15:49:34 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gibson.dropbear.id.au; s=201602; t=1560318575; bh=5mQj3sa0x70jnY5xmg5WskDu7xryaD4fDO6cG7edD8s=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=R0nKqTghPz6JQ8Eq2AKLQ8le+MAwhe+WZLTva9eRdKB0Envz/NRr6f0W6POMwaYmf DWoviui49qKpDFOvToSMqj41PItnsJUdJLozQlGBBuhaAaXE8xWIC1dP0cl3+GTxrz nGtI0maUxYwHD9JMBqJ319OrLjYTtnSrttgcTjKg= From: David Gibson To: peter.maydell@linaro.org Date: Wed, 12 Jun 2019 15:49:21 +1000 Message-Id: <20190612054929.21136-6-david@gibson.dropbear.id.au> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190612054929.21136-1-david@gibson.dropbear.id.au> References: <20190612054929.21136-1-david@gibson.dropbear.id.au> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 203.11.71.1 Subject: [Qemu-devel] [PULL 05/13] spapr: Clean up dt creation for PCI buses X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: lvivier@redhat.com, "Michael S . Tsirkin" , aik@ozlabs.ru, qemu-devel@nongnu.org, groug@kaod.org, qemu-ppc@nongnu.org, clg@kaod.org, David Gibson Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" 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 Acked-by: Michael S. Tsirkin --- 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 8e10fc6857..dc5e46e6d4 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; +} + /* 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, gchar *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. */ @@ -2057,44 +2109,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) { @@ -2132,8 +2146,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) }; @@ -2180,8 +2194,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; @@ -2194,8 +2206,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))); @@ -2260,13 +2270,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 < 0) { + 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);