From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-qk1-f174.google.com (mail-qk1-f174.google.com [209.85.222.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 54AE43BAD9F for ; Thu, 13 Aug 2026 22:07:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.174 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786658848; cv=none; b=B7hidXdOlux9uRcMezL9PLXtams6QHNN8sKIV37L9/vxjo3s5oa7ZXkPHUoSVqEV+xC9/fCczvumup0Uwu3KXCHupcSQ9I70nNg/Dlr7zhxEgDoFH1/QUm/i0L/nwt1RM3qYHH8VJg6zx1sQtDBJcUA3+UpN7SpLX2fhiPx6V6o= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786658848; c=relaxed/simple; bh=eCf4mdXngntMvLx+wFQ8/hDGjbead5uAt7RWmxkIJ0Q=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RQgNu6pVNGnBx1CCbkPXpWrlTsP3i69/3Hi3CezlFwgCjHnkOJRCBCmcCgUmo+u+d5K6TilfgFwyiIiOKVWeHAEyAOKl9yDX8LzQAc9WOly7N62Nzt8WaETlCa3+Vge5hJYnRswrhKpC4Hp38L7H0uN7nwm5/IkJWiEeDfxIMtA= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=riscstar.com; spf=pass smtp.mailfrom=riscstar.com; dkim=pass (2048-bit key) header.d=riscstar-com.20251104.gappssmtp.com header.i=@riscstar-com.20251104.gappssmtp.com header.b=vuJBfkPo; arc=none smtp.client-ip=209.85.222.174 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) header.d=riscstar-com.20251104.gappssmtp.com header.i=@riscstar-com.20251104.gappssmtp.com header.b="vuJBfkPo" Received: by mail-qk1-f174.google.com with SMTP id af79cd13be357-9349ad9c857so40815685a.1 for ; Thu, 13 Aug 2026 15:07:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=riscstar-com.20251104.gappssmtp.com; s=20251104; t=1786658844; x=1787263644; 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=r9KD6iCvTFU5NwlbZkHnKNp8ocE1VNUwFqzlkThaFrQ=; b=vuJBfkPolVgbsAuc1UmPP3i6dzGErdobmtVE/NFEh8fIwTMcVTJ7KhbtnVDGeuU7y5 cfk/z+HmweZssgk7cy7TNyhOYXZHPbq5kIiiICbtTLVP4/t24FFSTmzTsuirHWMHKgij DsB06fHWEdA5f1Q+xI6j07fY7PK/cbfmLZFkey39mShQe6j6nuyWZTXd3LBCCkulU8GV kDsYSgQecScAQrUdPP34zd8qeRatt4AAh5W76K3Qesa6DYkLQgLtThfAMron9cbgl2Gu LRrqExdR+7/ruuhHZ5yiaTbmztCyHMqVcWEWzjtCmqXUmdI1MVvD7xNA3rLoAIwgmg6v HOOQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786658844; x=1787263644; 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=r9KD6iCvTFU5NwlbZkHnKNp8ocE1VNUwFqzlkThaFrQ=; b=Yl5gNPYIIF6j+sJ44EjFbk5WTt6qgt0nVRHJdozL3HDBsQD50BWWdt0q4PWTisD7eA decDvzBoNP8955hHLYI1VS8Xh1lBAUrzac8oY5A+NRmWQdSts8wDVnGon3KrESLcljef oaEYu8T38XDvOAE6wLyaMFB+DI1Nl/XyOGqO0zynVpb24LC76VEmQlbZs3LKdqKvJBft EAgAY3EKK+u7hiyX3aJ24qQq8KszeTaroAY0cQElSiNxnW0BpYyVSIgZ4zP+M08I+r+d qkQstLVnqYkJ+58Wcd5kK4Ngts3SXtGq4ClC1Mg4mwyxkzfj+F1DZRonm92R4kRBolbk i+Hg== X-Forwarded-Encrypted: i=1; AHgh+Rou3ivylkR55ZvooKUGkyYIGDvGN9jGS7sfNDj7DwAu8VQP1mJebU0PAu/5HuDCBhEzskLxpoM/pAUHE1k=@vger.kernel.org X-Gm-Message-State: AOJu0YzAPw8MJZcPQO9opTQlpKfWnqo4O8bWYRkcQpQp2eNtS0wKZsGr TDFScqFOdZTpNhypayPSYxEGqsSPRlCz4aLY9+d0/Y4GldfqKGmhg7Gux0Mj0CsWrzQ= X-Gm-Gg: AR+sD12vlBYyqsCH2c5lF2itPMBI5VjfjxZD98bvJbyfQ+uoXFlc6h9PGKpCXYDVHjP k2ZyF3eLLaKoW2H1m92+K92t83HwzlhPPWeT5vGWfGdknnMeCbgUVGxjJ/QNkNnb6A0GemtK84N QWjpAqkJ9QMuN7fvfmpEaAmn5RiCBpWKrheUkmPHRuFchHVpwTItSTBWYJcmj9eUVrBiWbXzWT7 ZwuhtJWqA9vrz6aBDRGyn3ShjM03WUW6rM2o0CGgVX+vy3fyyW4B3wcX47LwhsCkdscJxsZeU8Z Mg9hnpwrGbFGnejrqejPXKmJGdiUC3rH3EWWsJsPO8p5ifpj2yCdSK0kgKKGHvB2FObMPcVX1bn XV9s9XMNmeeRK6MEv0aGzi5iA3f1ILL7uW2JIvR93mMkDI7yVjJCI1Di8fqrGC03ilYEfm2Rkf4 sI7iQmBEbTWXX7nXNH6pc/4PenvMt4N/ibj0oaVO3nk1TwUgyf7DsrYZNrYlyjzWty X-Received: by 2002:a05:620a:4492:b0:936:583a:dd75 with SMTP id af79cd13be357-936d212c6fdmr99272085a.17.1786658844276; Thu, 13 Aug 2026 15:07:24 -0700 (PDT) Received: from zippy.localdomain ([73.62.185.64]) by smtp.gmail.com with ESMTPSA id af79cd13be357-936ce22e990sm86776985a.38.2026.08.13.15.07.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 13 Aug 2026 15:07:23 -0700 (PDT) From: Alex Elder To: bhelgaas@google.com Cc: lizhi.hou@amd.com, herve.codina@bootlin.com, andrea.porta@suse.com, daniel@riscstar.com, mohdayaa@qti.qualcomm.com, lbiancon@qti.qualcomm.com, mani@kernel.org, robh@kernel.org, linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 2/2] PCI: of: introduce of_pci_update_endpoint_node_ranges() Date: Thu, 13 Aug 2026 17:07:16 -0500 Message-ID: <20260813220717.1394644-3-elder@riscstar.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260813220717.1394644-1-elder@riscstar.com> References: <20260813220717.1394644-1-elder@riscstar.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: 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 just as is done when the endpoint has a null devicetree node pointer. The device node will be updated to add the new "ranges" property (or replace it if one exists). This allows "BAR number" addresses to work correctly even when the endpoint's devicetree node is created statically. Signed-off-by: Alex Elder --- drivers/pci/of.c | 59 ++++++++++++++++++++++++++++++++++----- drivers/pci/of_property.c | 2 +- drivers/pci/pci.h | 1 + 3 files changed, 54 insertions(+), 8 deletions(-) diff --git a/drivers/pci/of.c b/drivers/pci/of.c index 0bbf1a915b7d2..ce14ae01d1f4b 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -663,20 +663,65 @@ 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; +} + void of_pci_make_dev_node(struct pci_dev *pdev) { struct device_node *ppnode, *np = NULL; + struct device *dev = &pdev->dev; + 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)) + /* No need to create a new devicetree node if one already exists */ + if (pci_device_to_OF_node(pdev)) { + if (pci_is_bridge(pdev)) + return; + + /* + * For an endpoint device, we need to add or update its + * devicetree "ranges" property. The new property will + * include an entry for every BAR, mapping BAR offsets + * to the actual assigned PCI bus address space for the + * endpoint. The child space in each range uses the flags + * cell of the child bus address to encode the BAR number. + */ + if (!of_pci_update_endpoint_node_ranges(pdev)) + dev_err(dev, "failed updating ranges property\n"); + return; + } /* Check if there is device tree node for parent device */ if (!pdev->bus->self) @@ -715,7 +760,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 48ce467e7e966..744dee0dd9625 100644 --- a/drivers/pci/of_property.c +++ b/drivers/pci/of_property.c @@ -116,7 +116,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 2e1ccdd6f6418..6ae8adb30fdd0 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -1316,6 +1316,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