From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=209.85.210.49 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793913859; b=0T+rwOX7AEGCR3MRE7WT2BBTALCETYIlTKBPQ4osqf6O8ON5mYN8M6ZUJUnB7ekC9FjK 6yBqrPKvxLmwMLTH9obOQPUSlO7hgpz5bY3TeaQ7em5mNvRBvw0JwgEj+cZF0xzQmK2xt jQmRrV2OzcLKckKXMHViiL750+imuRo8T0C5/2tMpXfV6lsl9u6stu7v50l06gXpiI0in X/5bZthaooINUGNx8hNDNUq8bxl7z+uw1vjY0r9XCY34VM8xKa8Hr4nrcTXQYWxZhiPpi /8vt7yiut/K1tTEpaDuwt3zVZodO0qJUGqyFGpLy0AAaDapxA54Y8S8d9WBnOjyurng== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793913859; h=DMARC-Filter:Received:DKIM-Signature:X-Google-DKIM-Signature: X-Forwarded-Encrypted:X-Gm-Message-State:X-Gm-Gg:X-Received:Received: From:To:Cc:Subject:Date:Message-ID:X-Mailer:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding; bh=647ljXCJztGicp7YV3FS/mcGU5fzbToeSjHEko7ri7o=; b=0y3m8nOilFevd3z6yEWX0T+RR1w4+32ZHmupTRBEIc7J2xkc41Qap7qxhCLYwZ+r4JP/ +4I0RpAxaThPGtt9tQaGkduLwAWsNFAD3pw7dzSeNl7i2Y7TSzHitU4QAQUMmJKPH163O LDldbOG68PnmkMomJhSo98hWHNZmxt+HWMvJmtIaDCo0+lHBZAnCny0T7muKT4z4pa6FT Rpn9mCbPZVoGY/RcuRjLqh2iFktW+Uh4Le8stRoYZye4GJ/9vbd74LFBbiYV2/DfxGvJV NoOL9sxObO5WPPSHtlGub/4QKEwdRgYwM7X/zpqXjy3JNF1AhWlkM9VGdyAl3fWNn1g== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass header.from=riscstar.com; spf=pass smtp.mailfrom=riscstar.com; dkim=pass header.d=riscstar.com header.i=@riscstar.com header.a=rsa-sha256 header.s=google header.b=3tixUHaC; arc=none smtp.remote-ip=209.85.210.49 Received: from mail-ot1-f49.google.com (mail-ot1-f49.google.com [209.85.210.49]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 229BF606D814 for ; Thu, 5 Nov 2026 21:24:18 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org 229BF606D814 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=riscstar.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=riscstar.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key, unprotected) header.d=riscstar.com header.i=@riscstar.com header.a=rsa-sha256 header.s=google header.b=3tixUHaC Received: by mail-ot1-f49.google.com with SMTP id 46e09a7af769-854b6e2e41fso20001a34.3 for ; Thu, 05 Nov 2026 13:24:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=riscstar.com; s=google; t=1793913858; x=1794518658; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=647ljXCJztGicp7YV3FS/mcGU5fzbToeSjHEko7ri7o=; b=3tixUHaCUkrk9WS78wwur2uKuD+nh8UofCPfmONePQb1e545u7gspVfjUByNQsDtcs 5P9/y5AtsfVxU19INadG09sT5oSuMRFFc6pnECgDuV6SRMyGnudpVhLdf5YW1VR7qqSW Slej3GUUy5vbd+z52OIUdYqVPcfzdWQtRpJ7jv6XnQxQZNxbjwSxg7UFDugz0eQY612d SDpe3QwRW7bFxMBxGUuG9Hoa2ZDj4AnQCERnj3nGSKrAxbgtPXGf0z3OM6nTBnDwHeeB bn9PqfCikqyhAeqw2Xo/ZQGCgIxyxgIf30VThPjyzecZ2sYtEdNIj/eeSCoMHCqZYGGU 4E+w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793913858; x=1794518658; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=647ljXCJztGicp7YV3FS/mcGU5fzbToeSjHEko7ri7o=; b=bnG/AsIiZ0bmr9Y2My64daWzfQXeZKXEjdgGG/yeoXM9nm270K/kIDapsuszhbYTjW 8R/5CEsdCTDRbUz0h/39a30kk+fk1yjeeSGDFrwkffDzWDkK6C0KZnjRGVHwR3jNr2wI y8+wBvX6xhO4bR2HuLlkD/bsggaXykcJJX8TWu/Dhzn5Cvl0WhUn4uYU5c+fRE0cX8nC AH1OSPCzwpnD5iNye/uWPHE2pcIteGDCFz+nWtzhNtRYjyXNDVNd7QcnKackqbGpmkeF vom0UeyWqeOkzP9tDuZBfaIj9XE+a7i/+aGfcD/bcpVvRy9D/GISlvpaAW9JR6JeKISg Z6HA== X-Forwarded-Encrypted: i=1; AKwUvBwovh8B9YJLyrxSI23VZ4b97OLkR5Xt9pTM2SskfssZve/hnXbe9on3hk1FEkadll27UWOs8OdpWegU@vger.kernel.org X-Gm-Message-State: APuU4Z/wgLEIVBk/oZWqWV3DPfw9uhU8JFqLjOpX6Xs7oWgtFBj1Pe1D otHl6vECk3ZzoVWJgM7Od/ujPnC1NwWNmuGHB9ufsPXpVweovmIw9KRfIa8XorbgGfU= X-Gm-Gg: AYBFou3vX0d5oXLc4k8mGCMGyoq4VNw/ktG/qVfVRN1DvhPrynCNHxyj5zWzLMeOUP7 TqKSJcsnVsyl0XvC4uRBbeB3ITS8YvDOEaoQaOzFvEfMKoH2rqON+PmClxIcwgX3GjEfFqba15/ c1vfYyCps9wOA1EGwAciiO6LMhhlUbO4tC+pbzCOLCquAIz4EsvXIA+/s2f1SFInheB39Gmp3iM Hpx10UfNiWkyDfwIf+f7Hg0RzNHppRbxcvzrhy0HmMdxxaSKwAUxRdo7ADfJCJtcBh9mx/StE+Q mp5Wyr6kUJzT/G4/886u0W3dB3KpRytELARlVwdLyKYJtta06ynvc7qOTR1xuIZ2zjzNi5xxoQ9 0DvFDyrYuROFPb/G1ErJe+J1cFHWXlKN6vnWCPB4xR6+gj4nG/FjdHMov6ITeaKnHRBz02UJpy+ Mr5yPeeRGsUYVy/vIuvTTUHkqDdnwycQnGdUQ2WJA6h5E91XYJpnbNmC0jo3ISCxaX0LZ1FtbyG /3M8PsvENgE9MBxC/F5KsO8Tl4cZXWdhqKIE7LQ/U0q8HRVN2KbFiLu8gd/2G091aOZY0N2ImVv lgE1d9cEJighgEbk/2kPGqW5yyLdNJBAYhjlFpY0w9VkXq2xFIEmVYI= X-Received: by 2002:a05:6808:4f6c:b0:4f5:e13:95e2 with SMTP id 5614622812f47-567e0f327abmr531990b6e.9.1793913857962; Thu, 05 Nov 2026 13:24:17 -0800 (PST) Received: from zippy.localdomain ([73.62.185.64]) by smtp.gmail.com with ESMTPSA id 5614622812f47-567a9ef58b1sm5349897b6e.3.2026.11.05.13.24.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 05 Nov 2026 13:24:17 -0800 (PST) From: Alex Elder To: bhelgaas@google.com, robh@google.com, krzk+dt@kernel.org, conor+dt@kernel.org Cc: daniel@riscstar.com, mohd.anwar@oss.qualcomm.com, lorenzo.bianconi@oss.qualcomm.com, linux-pci@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Andrea della Porta Subject: [PATCH v4 2/2] PCI: of: introduce of_pci_update_endpoint_node_ranges() Date: Thu, 5 Nov 2026 15:24:12 -0600 Message-ID: <20261105212412.591931-3-elder@riscstar.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20261105212412.591931-1-elder@riscstar.com> References: <20261105212412.591931-1-elder@riscstar.com> X-Mailing-List: devicetree@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Commit 407d1a51921e9 ("PCI: Create device tree node for bridge") introduced the PCI_DYNAMIC_OF_NODES Kconfig option, which creates a devicetree node for a PCI bridge as part of pci_bus_add_device(). Its successor commit ae9813db1dc5a ("PCI: Add quirks to generate device tree node for Xilinx Alveo U50") shows how to use a PCI final fixup quirk to also create a devicetree node for a non-bridge PCI device. In both cases, of_pci_make_dev_node() uses an OF changeset to dynamically create a node populated with appropriate properties and apply it to the live devicetree. The dynamic devicetree node for a PCI device will include a "ranges" property, and a new type of 3-cell address is introduced for use within an endpoint. The endpoint's ranges property will contain a range entry for each of the endpoint's BARs. The "child address" portion of each range will use the BAR number in the "flags" (first) cell in the address. This allows addresses within the endpoint to be expressed relative to whatever address gets assigned to each BAR. Unfortunately, if a PCI endpoint device had a devicetree node set up statically, its "ranges" property (if present) will be static, and it cannot contain the addresses assigned to the endpoint's BARs during enumeration. This means that the "BAR number" based addressing scheme doesn't work for PCI endpoints whose devicetree nodes are created statically. To remedy this, modify of_pci_make_dev_node() to dynamically create a "ranges" property even if the device already has a devicetree node--just as is done when the endpoint has none. A few conditions: - A PCI bridge node's ranges property is never updated - If a PCI endpoint node defines a ranges property with a non-empty value (i.e., it's not just "ranges;"), that ranges property is preserved Otherwise a new ranges property is created using assigned addresses, and it replaces (or adds) that property to the PCI endpoint node. As a result, "BAR number" addresses work correctly even when the endpoint's devicetree node is created statically. This has been verified by Andrea della Porta (with both static and dynamic ranges properties) on the Raspberry Pi 5 RP1. Tested-by: Andrea della Porta Signed-off-by: Alex Elder --- drivers/pci/of.c | 97 +++++++++++++++++++++++++++++++++++---- drivers/pci/of_property.c | 2 +- drivers/pci/pci.h | 1 + 3 files changed, 91 insertions(+), 9 deletions(-) diff --git a/drivers/pci/of.c b/drivers/pci/of.c index 5a040ed836744..fa9e9377c3eb9 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -17,6 +17,9 @@ #include #include #include + +#include + #include "pci.h" #ifdef CONFIG_PCI @@ -742,20 +745,98 @@ void of_pci_remove_node(struct pci_dev *pdev) of_node_put(np); } +/* Returns true if the ranges property was added or updated successfully */ +static bool of_pci_update_endpoint_node_ranges(struct pci_dev *pdev) +{ + struct device_node *np = pci_device_to_OF_node(pdev); + struct property *prop; + u32 *value; + u32 size; + + prop = kzalloc_obj(*prop); + if (!prop) + return false; + + value = of_pci_build_prop_ranges(pdev, &size); + if (!value) { + kfree(prop); + return false; + } + + prop->name = "ranges"; + prop->length = size * sizeof(u32); + prop->value = value; + + /* The property value needs to be in big-endian byte order */ + while (size--) + cpu_to_be32s(value++); + + /* of_update_property() consumes the allocated property */ + of_update_property(np, prop); + + return true; +} + +/* + * Create a devicetree node for a PCI device. If the device is a bridge + * and it already has a devicetree node, there's nothing further to do. + * If it is a bridge without an existing devicetree node, one is created + * dynamically. + * + * This function can also be called (via PCI quirk) for a PCI endpoint + * (function) that implements a PCI endpoint bus. As with a PCI bridge, + * if the endpoint has no existing devicetree node, one is created + * dynamically. The node will include a ranges property that maps + * BAR-relative addresses in the child to the PCI address ranges + * assigned to the PCI endpoint BARs. + * + * If an endpoint already has a devicetree node, and it includes a + * "pci-ep-bus" sub-node, its ranges property must still be dynamically + * populated so that it can take into account the BAR ranges assigned + * during PCI enumeration. + */ void of_pci_make_dev_node(struct pci_dev *pdev) { - struct device_node *ppnode, *np = NULL; + struct device_node *np = pci_device_to_OF_node(pdev); + struct device *dev = &pdev->dev; + struct device_node *ppnode; + struct of_changeset *cset; const char *pci_type; - struct of_changeset *cset; const char *name; int ret; - /* - * If there is already a device tree node linked to this device, - * return immediately. - */ - if (pci_device_to_OF_node(pdev)) + /* See if the PCI device already has a devicetree node */ + if (np) { + struct device_node *child; + unsigned int rlen = 0; + + /* Nothing further needed for a bridge */ + if (pci_is_bridge(pdev)) + return; + + /* + * A ranges property is only needed if the endpoint's + * devicetree node includes a "pci-ep-bus" sub-node. + */ + child = of_get_child_by_name(np, "pci-ep-bus"); + if (!child) + return; + of_node_put(child); + + /* If the ranges property is non-empty, just keep it.*/ + if (of_get_property(np, "ranges", &rlen) && rlen) + return; + + /* + * Otherwise create a ranges property, defining an entry for + * each BAR, and map BAR offsets to the PCI bus address based + * on the BAR's assigned range. + */ + if (!of_pci_update_endpoint_node_ranges(pdev)) + dev_err(dev, "failed to update ranges property\n"); + return; + } /* Check if there is device tree node for parent device */ if (!pdev->bus->self) @@ -794,7 +875,7 @@ void of_pci_make_dev_node(struct pci_dev *pdev) np->data = cset; - ret = device_add_of_node(&pdev->dev, np); + ret = device_add_of_node(dev, np); if (ret) goto out_revert_cset; diff --git a/drivers/pci/of_property.c b/drivers/pci/of_property.c index b202f45b3660b..44e169f4fbf4d 100644 --- a/drivers/pci/of_property.c +++ b/drivers/pci/of_property.c @@ -122,7 +122,7 @@ static int of_pci_prop_bus_range(struct pci_dev *pdev, * * Caller is responsible for ensuring the returned pointer gets freed. */ -static u32 *of_pci_build_prop_ranges(struct pci_dev *pdev, u32 *count) +u32 *of_pci_build_prop_ranges(struct pci_dev *pdev, u32 *count) { bool bridge_device = pci_is_bridge(pdev); struct of_pci_range_entry *entries; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index e93f602b9ca48..af21a46cfdb3c 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -1324,6 +1324,7 @@ struct of_changeset; #ifdef CONFIG_PCI_DYNAMIC_OF_NODES void of_pci_make_dev_node(struct pci_dev *pdev); void of_pci_remove_node(struct pci_dev *pdev); +u32 *of_pci_build_prop_ranges(struct pci_dev *pdev, u32 *count); int of_pci_add_properties(struct pci_dev *pdev, struct of_changeset *ocs, struct device_node *np); void of_pci_make_host_bridge_node(struct pci_host_bridge *bridge); -- 2.53.0