From nobody Fri Dec 19 12:14:46 2025 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 586472F1FE9; Fri, 10 Oct 2025 14:42:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760107383; cv=none; b=qyigwk94fWi3bJ7TaW64uiO0b0Pp1s1Cg1GsSaQN8GPhrYmKl8Ry6M5rYEQvaJiwrb0Mlrhn60Blo09eXSwRkqB8318DV/rHy56OlxSNvE66L+6nCM4dW+HXYhTE1zNAbOqFTq6+7clz9p57CmLwzF+9yCTF55yKXmQp+5znYjo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760107383; c=relaxed/simple; bh=CoNAQv21FfT9IE9DUrO8U1Q2zCeNLD9qeUhzpmJH2Xs=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=Kq0PCCAl6LnbgKfh0x4pGThe1oTU/sbliLboetgn4MXz6JJHPJk5ahuoMnByj7aWY5YhmTnBUgY6QY7j9h3EiEIQK43lBrWzpx8FiWlqzdR/OkYg6KzPe8iXAerB9Kh/fFgb0zcgSj8cowhUYuXP2TyV7m5/cqfEAbVG8kaW2lI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=pass smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=c4vZ5bvy; arc=none smtp.client-ip=198.175.65.18 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="c4vZ5bvy" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1760107382; x=1791643382; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=CoNAQv21FfT9IE9DUrO8U1Q2zCeNLD9qeUhzpmJH2Xs=; b=c4vZ5bvyPGl3geZ5o1HBY36VlmuNxmzSacO6adUGDJKRgY02EhEDeOc3 huQurmS9eLjkyZLANN/HjWebYPti1O1zFaN1QOq/ane/iqVoH65iXseVb fRuIBLhsUWWOQQdYaOZksf3ODLmQ6W3yvXHj9EpGRNC5yLtp7IIzqPDsJ 3AmrU2PVZ6m5a3DWiEt+OUklFh6huQlM5knkQLkKdiFrLkbRCjT0K6Ah1 /4+PzXFmeK2zF1fcMtBbHXO3wTPn9LR0wAYkFKgYubVNR0tiA1yb7sq7i m4h8vl4sna0ZlEGiz4rXVZ3ARreWYIyTFaG3+I7GCrzSl84EzWm6bERrS Q==; X-CSE-ConnectionGUID: Ou1AyywFQf2k3R1tB+z8Jg== X-CSE-MsgGUID: 3BQxd5z1Q1CHuBlrB5wB9w== X-IronPort-AV: E=McAfee;i="6800,10657,11578"; a="62370393" X-IronPort-AV: E=Sophos;i="6.19,219,1754982000"; d="scan'208";a="62370393" Received: from orviesa009.jf.intel.com ([10.64.159.149]) by orvoesa110.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Oct 2025 07:42:56 -0700 X-CSE-ConnectionGUID: xid9jkCqStKfNqhz/r/DTA== X-CSE-MsgGUID: xj8Bvk5SSvWKZLIwHTVzKg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.19,219,1754982000"; d="scan'208";a="180573825" Received: from ijarvine-mobl1.ger.corp.intel.com (HELO localhost) ([10.245.245.127]) by orviesa009-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Oct 2025 07:42:49 -0700 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= To: linux-pci@vger.kernel.org, Bjorn Helgaas , Geert Uytterhoeven , Kai-Heng Feng , Rob Herring , linux-kernel@vger.kernel.org Cc: Andy Shevchenko , =?UTF-8?q?Krzysztof=20Wilczy=C5=84ski?= , Linux-Renesas , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Subject: [PATCH 1/3] PCI: Refactor host bridge window coalescing loop to use prev Date: Fri, 10 Oct 2025 17:42:29 +0300 Message-Id: <20251010144231.15773-2-ilpo.jarvinen@linux.intel.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20251010144231.15773-1-ilpo.jarvinen@linux.intel.com> References: <20251010144231.15773-1-ilpo.jarvinen@linux.intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable pci_register_host_bridge() has loop for coalescing host bridge windows that are contiguous. It loops through all but the last entry and if necessary, coalesces the current entry with the next. The resource coalescing modifies the resources in place which can cause issues if other parts of the kernel hold a pointer to the same resource. This problem was demonstrated to happen when trying to address an issue with the host bridge window setup on R-Car M2-W (see the link below). An upcoming change will perform a safe merge of the resources within a new function in resource.c. That results in removing both old resource entries from the resources list and despite using resource_list_for_each_entry_safe(), the loop will no longer hold valid pointer to any resources list as the next entry is removed from the list. Alter the loop to look back instead of ahead. That is, change next to prev. When merging previous with the current resource, the next resource remains valid so resource_list_for_each_entry_safe() is able to continue iterating the list. Link: https://lore.kernel.org/linux-pci/CAMuHMdVgCHU80mRm1Vwo6GFgNAtQcf50yH= Bz_oAk4TrtjcMpYg@mail.gmail.com/ Signed-off-by: Ilpo J=C3=A4rvinen --- drivers/pci/probe.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index f41128f91ca7..04523dea7d96 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -952,11 +952,11 @@ static bool pci_preserve_config(struct pci_host_bridg= e *host_bridge) static int pci_register_host_bridge(struct pci_host_bridge *bridge) { struct device *parent =3D bridge->dev.parent; - struct resource_entry *window, *next, *n; + struct resource_entry *window, *prev, *n; struct pci_bus *bus, *b; - resource_size_t offset, next_offset; + resource_size_t offset, prev_offset; LIST_HEAD(resources); - struct resource *res, *next_res; + struct resource *res, *prev_res; bool bus_registered =3D false; char addr[64], *fmt; const char *name; @@ -1049,21 +1049,21 @@ static int pci_register_host_bridge(struct pci_host= _bridge *bridge) =20 /* Coalesce contiguous windows */ resource_list_for_each_entry_safe(window, n, &resources) { - if (list_is_last(&window->node, &resources)) - break; + if (list_is_first(&window->node, &resources)) + continue; =20 - next =3D list_next_entry(window, node); + prev =3D list_prev_entry(window, node); offset =3D window->offset; res =3D window->res; - next_offset =3D next->offset; - next_res =3D next->res; + prev_offset =3D prev->offset; + prev_res =3D prev->res; =20 - if (res->flags !=3D next_res->flags || offset !=3D next_offset) + if (prev_res->flags !=3D res->flags || prev_offset !=3D offset) continue; =20 - if (res->end + 1 =3D=3D next_res->start) { - next_res->start =3D res->start; - res->flags =3D res->start =3D res->end =3D 0; + if (prev_res->end + 1 =3D=3D res->start) { + res->start =3D prev_res->start; + prev_res->flags =3D prev_res->start =3D prev_res->end =3D 0; } } =20 --=20 2.39.5 From nobody Fri Dec 19 12:14:46 2025 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 933BA2F746E; Fri, 10 Oct 2025 14:43:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760107387; cv=none; b=KwqI8192A9ZQRj8tbbDc4TMkVYr22KcmXpHQELHHY3Gtnm/o3kj4jG3WGiwccArCfv9CoDTeP61mYU8+fYWld9WefJtjsQrUW6alolk+QLTLZFLX+XTzMPueIM7VCaioNAW+2LIbpGNnTkjcGioNG1QS6Xl1gGR6mQkH6hvYpF4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760107387; c=relaxed/simple; bh=Ps0eFgpKDQwj5gTo/VReISXpz7hf3pTeaFFQ3wYZhls=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=GWIL1Qa8ZlnoX2m+gGzRRtDnYWvgwYW16lDawSEX+oB5+AIQA1MxAsg0hgEdwFJXhH8oIDbNR1FMSlzYRDACAJhlL9guNMKjpnpayVDSqhdKlT9oVUkEwg95nVybGCMRulqvpcgobrMEHHEkDhQ8QExoab3/B0ZLXJN4gA9z+FY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=pass smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=SCa2/y6C; arc=none smtp.client-ip=198.175.65.18 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="SCa2/y6C" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1760107386; x=1791643386; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Ps0eFgpKDQwj5gTo/VReISXpz7hf3pTeaFFQ3wYZhls=; b=SCa2/y6CyDSH0x7ZTcTVVhusFwxLfQR8n/gSRCeYkKntiFXvpBK5FeFb 64GryA86hJGzRVLbwoRi0YG4tzQAVG+qPgGvVklNENYyoCjPy2+H6vrmT jE3q1ctBMrimTzbvN9UousKaGjgHeNeBfLqF1gkqB9tIuF5mDmiXbJNbt yX6Nxrg41Lq0TBYDDgHfwjswMJwozBv40xZmKt9y//n1aajt7o6SaZzOg G21I5goaOqAm/cC2nu/FLDLGdfkeyBesJytvMlK4CpLXWcaPVezkd1AFH 2e+bE7q70va0Oux+khwt+e7rPUiFV848ETAAOJn3obCIWQaqEOsygEDgl w==; X-CSE-ConnectionGUID: p/SK3P0JTGm8Bha/ip3Eag== X-CSE-MsgGUID: j0KGA7BqRX65GDZbogyj9A== X-IronPort-AV: E=McAfee;i="6800,10657,11578"; a="62370423" X-IronPort-AV: E=Sophos;i="6.19,219,1754982000"; d="scan'208";a="62370423" Received: from orviesa009.jf.intel.com ([10.64.159.149]) by orvoesa110.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Oct 2025 07:43:05 -0700 X-CSE-ConnectionGUID: c2y819vBRTm5pmzRWCIXQg== X-CSE-MsgGUID: 7aZHqcs2SiyzZ2O2ZSco6g== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.19,219,1754982000"; d="scan'208";a="180573932" Received: from ijarvine-mobl1.ger.corp.intel.com (HELO localhost) ([10.245.245.127]) by orviesa009-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Oct 2025 07:42:59 -0700 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= To: linux-pci@vger.kernel.org, Bjorn Helgaas , Geert Uytterhoeven , Kai-Heng Feng , Rob Herring , linux-kernel@vger.kernel.org Cc: Andy Shevchenko , =?UTF-8?q?Krzysztof=20Wilczy=C5=84ski?= , Linux-Renesas , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Subject: [PATCH 2/3] PCI: Do not coalesce host bridge resource structs in place Date: Fri, 10 Oct 2025 17:42:30 +0300 Message-Id: <20251010144231.15773-3-ilpo.jarvinen@linux.intel.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20251010144231.15773-1-ilpo.jarvinen@linux.intel.com> References: <20251010144231.15773-1-ilpo.jarvinen@linux.intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable The resource coalescing for host bridge windows in pci_register_host_bridge() can alter the underlying struct resource which is inherently dangerous as this code has no knowledge of who else holds a pointer the same resource. Merge the struct resource inside a newly added resource_list_merge_entries() which uses the internal __res member of the struct resource_entry to store the merged resource, thus preserving the original resource structs. Link: https://lore.kernel.org/linux-pci/CAMuHMdUjhq2ZLFyMYv9KYRW8brsvXMH5xb= 5NW8shsHJmx7w2QQ@mail.gmail.com/ Signed-off-by: Ilpo J=C3=A4rvinen --- drivers/pci/probe.c | 8 +-- include/linux/resource_ext.h | 3 + kernel/resource.c | 135 ++++++++++++++++++++++++++++++++++- 3 files changed, 140 insertions(+), 6 deletions(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 04523dea7d96..053bffc17146 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1061,10 +1061,10 @@ static int pci_register_host_bridge(struct pci_host= _bridge *bridge) if (prev_res->flags !=3D res->flags || prev_offset !=3D offset) continue; =20 - if (prev_res->end + 1 =3D=3D res->start) { - res->start =3D prev_res->start; - prev_res->flags =3D prev_res->start =3D prev_res->end =3D 0; - } + if (prev_res->end + 1 !=3D res->start) + continue; + + resource_list_merge_entries(prev, window); } =20 /* Add initial resources to the bus */ diff --git a/include/linux/resource_ext.h b/include/linux/resource_ext.h index ff0339df56af..4d6f2a926e6d 100644 --- a/include/linux/resource_ext.h +++ b/include/linux/resource_ext.h @@ -60,6 +60,9 @@ resource_list_destroy_entry(struct resource_entry *entry) resource_list_free_entry(entry); } =20 +struct resource_entry *resource_list_merge_entries(struct resource_entry *= entry, + struct resource_entry *next); + #define resource_list_for_each_entry(entry, list) \ list_for_each_entry((entry), (list), node) =20 diff --git a/kernel/resource.c b/kernel/resource.c index f9bb5481501a..c6e1872abb78 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -10,6 +10,7 @@ =20 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt =20 +#include #include #include #include @@ -206,6 +207,13 @@ static struct resource * __request_resource(struct res= ource *root, struct resour } } =20 +static void resource_clear_tree_links(struct resource *res) +{ + res->parent =3D NULL; + res->child =3D NULL; + res->sibling =3D NULL; +} + static int __release_resource(struct resource *old, bool release_child) { struct resource *tmp, **p, *chd; @@ -265,6 +273,101 @@ void release_child_resources(struct resource *r) write_unlock(&resource_lock); } =20 +/** + * resource_mergeable - Test if resources are contiguous and can be merged + * @r1: first resource + * @r2: second resource + * + * Tests @r1 is followed by @r2 contiguously and share the metadata. + * + * Return: %true if resources are mergeable non-destructively. + */ +static bool resource_mergeable(struct resource *r1, struct resource *r2) +{ + if ((r1->flags !=3D r2->flags) || + (r1->desc !=3D r2->desc) || + (r1->parent !=3D r2->parent) || + (r1->end + 1 !=3D r2->start)) + return false; + + if (r1->name =3D=3D r2->name) + return true; + + if (r1->name && r2->name && !strcmp(r1->name, r2->name)) + return true; + + return false; +} + +static int resource_coalesce(struct resource *res, struct resource *next_r= es, + struct resource *new_res) +{ + struct resource *parent, *tmp; + struct resource **p, **c; + + if (!resource_mergeable(res, next_res)) + return -EINVAL; + + guard(write_lock)(&resource_lock); + parent =3D res->parent; + + if (parent !=3D next_res->parent) + return -EINVAL; + + if (parent && res->sibling !=3D next_res) + return -EINVAL; + + new_res->start =3D res->start; + new_res->end =3D next_res->end; + new_res->name =3D res->name; + new_res->flags =3D res->flags; + new_res->desc =3D res->desc; + + if (!parent) + return 0; + + /* prepare for step 2), find res & next_res from child/sibling chain. */ + p =3D &parent->child; + while (1) { + tmp =3D *p; + if (tmp =3D=3D res) + break; + + /* No res in child/sibling, the resource tree is corrupted! */ + if (WARN_ON_ONCE(!tmp)) + return -EINVAL; + + p =3D &tmp->sibling; + } + + /* 1) set the parent */ + new_res->parent =3D parent; + + /* 2) inject into parent's child/sibling chain */ + *p =3D new_res; + new_res->sibling =3D next_res->sibling; + + /* 3) move children over and switch them to the new parent. */ + c =3D &new_res->child; + *c =3D res->child; + while (*c) { + tmp =3D *c; + tmp->parent =3D new_res; + c =3D &tmp->sibling; + } + *c =3D next_res->child; + while (*c) { + tmp =3D *c; + tmp->parent =3D new_res; + c =3D &tmp->sibling; + } + + resource_clear_tree_links(res); + resource_clear_tree_links(next_res); + + return 0; +} + /** * request_resource_conflict - request and reserve an I/O or memory resour= ce * @root: root resource descriptor @@ -1503,8 +1606,7 @@ static bool system_ram_resources_mergeable(struct res= ource *r1, struct resource *r2) { /* We assume either r1 or r2 is IORESOURCE_SYSRAM_MERGEABLE. */ - return r1->flags =3D=3D r2->flags && r1->end + 1 =3D=3D r2->start && - r1->name =3D=3D r2->name && r1->desc =3D=3D r2->desc && + return resource_mergeable(r1, r2) && !r1->child && !r2->child; } =20 @@ -1860,6 +1962,35 @@ void resource_list_free(struct list_head *head) } EXPORT_SYMBOL(resource_list_free); =20 +struct resource_entry *resource_list_merge_entries(struct resource_entry *= entry, + struct resource_entry *next) +{ + struct resource *res =3D entry->res, *next_res =3D next->res, *new_res; + int ret; + + if ((entry->offset !=3D next->offset) || + !resource_mergeable(res, next_res)) + return ERR_PTR(-EINVAL); + + /* Use the internal __res to not mutate the input resources. */ + struct resource_entry __free(kfree) *new =3D resource_list_create_entry(N= ULL, 0); + if (!new) + return ERR_PTR(-ENOMEM); + + new->offset =3D next->offset; + new_res =3D new->res; + + ret =3D resource_coalesce(res, next_res, new_res); + if (ret) + return ERR_PTR(ret); + + resource_list_add_tail(new, &entry->node); + resource_list_destroy_entry(entry); + resource_list_destroy_entry(next); + + return no_free_ptr(new); +} + #ifdef CONFIG_GET_FREE_REGION #define GFR_DESCENDING (1UL << 0) #define GFR_REQUEST_REGION (1UL << 1) --=20 2.39.5 From nobody Fri Dec 19 12:14:46 2025 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 761E72F6560; Fri, 10 Oct 2025 14:43:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760107394; cv=none; b=QPWrXKbTnEWteqYCYOOfcJdY0e72aBfKmRPmoua0FzSIVJxFBL9DkENoO1eAUCrtIpBeEjXKRq7l4skEQThItuZxdL+CvNnJra1njFfB/Ai7R32Wjm4b47VOp0c2GoZlJFfxIgSUkK4b2PFK0pUShJxGdLt3EPihrlH+9Xyt2ZU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760107394; c=relaxed/simple; bh=c553U0H/z/bCC1272Ow+lGztpoU5p2QncIMSPsjy4ZE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=hPQxJBMVFAypIEYMTLUnlO3pZQHZD3nepCmrumfDznNg4koFJP8S1eKGlBmyVhcLROU2Jcv6aOug9GmSobMx12OYd3k5eQY0y7t4F605e5QjDTsTJf7RdmuNa7H0zF3DthLztIfnghRQL+p5HqpVbPxvkqSJ/20PUZsDAkPkG6Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=pass smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=oIN/0eVm; arc=none smtp.client-ip=198.175.65.18 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="oIN/0eVm" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1760107393; x=1791643393; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=c553U0H/z/bCC1272Ow+lGztpoU5p2QncIMSPsjy4ZE=; b=oIN/0eVmqYUOLflRWIjAMJ8Xcb60US8agfZHbIgBnGWbRMS6gUtLQxph sNuibTz+RBb6ubboWvbze6L43SgS/R/yzNa85SGMWI1PtCNCnhiM+6jvd jkQ2KIZgkNPSUmKZFOB7GSARY3QfSVSUjXTHQNwacU/z0I274/lNwah5P lW/OyvClZpkQ/YlqEZOXMDb5NA9qKSTD1RdjtvVk20ltolRexZDW4D7SI 2toV4JFjHFUNtmzq93NP7dj6jC3epCY0UdE42+10FBwfwqVdbIY/zvoBc KlCtcOQDE8zqlOW2ahegICMtb656ALa4+Rx3v1KVmEOum/CzrKJK5BRKT A==; X-CSE-ConnectionGUID: PLGsdZ4YQEeF/x+IyCMpZw== X-CSE-MsgGUID: YDtS+YD2Rq+7haJ50pNS/Q== X-IronPort-AV: E=McAfee;i="6800,10657,11578"; a="62370447" X-IronPort-AV: E=Sophos;i="6.19,219,1754982000"; d="scan'208";a="62370447" Received: from orviesa009.jf.intel.com ([10.64.159.149]) by orvoesa110.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Oct 2025 07:43:12 -0700 X-CSE-ConnectionGUID: tGwq278OQfq3lgEiZFUNig== X-CSE-MsgGUID: wgBjgDyXQpSXs5xcsVyFtg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.19,219,1754982000"; d="scan'208";a="180574092" Received: from ijarvine-mobl1.ger.corp.intel.com (HELO localhost) ([10.245.245.127]) by orviesa009-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Oct 2025 07:43:08 -0700 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= To: linux-pci@vger.kernel.org, Bjorn Helgaas , Geert Uytterhoeven , Kai-Heng Feng , Rob Herring , linux-kernel@vger.kernel.org Cc: Andy Shevchenko , =?UTF-8?q?Krzysztof=20Wilczy=C5=84ski?= , Linux-Renesas , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Subject: [PATCH 3/3] resource, kunit: add test case for resource_coalesce() Date: Fri, 10 Oct 2025 17:42:31 +0300 Message-Id: <20251010144231.15773-4-ilpo.jarvinen@linux.intel.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20251010144231.15773-1-ilpo.jarvinen@linux.intel.com> References: <20251010144231.15773-1-ilpo.jarvinen@linux.intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Add a test case for resource_coalesce() which has both parent and children resources to adjust. Add framework to build resource trees in a human-readable way and to verify them which could be used to kunit test also other resource tree manipulation functions. Signed-off-by: Ilpo J=C3=A4rvinen --- include/linux/ioport.h | 5 ++ kernel/resource.c | 8 ++- kernel/resource_kunit.c | 121 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+), 2 deletions(-) diff --git a/include/linux/ioport.h b/include/linux/ioport.h index e8b2d6aa4013..56f4d1cfde29 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -426,5 +426,10 @@ static inline void irqresource_disabled(struct resourc= e *res, u32 irq) =20 extern struct address_space *iomem_get_mapping(void); =20 +#if IS_ENABLED(CONFIG_KUNIT) +int resource_coalesce(struct resource *res, struct resource *next_res, + struct resource *new_res); +#endif + #endif /* __ASSEMBLY__ */ #endif /* _LINUX_IOPORT_H */ diff --git a/kernel/resource.c b/kernel/resource.c index c6e1872abb78..f7e7b49dc9a4 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -10,6 +10,8 @@ =20 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt =20 +#include + #include #include #include @@ -299,8 +301,9 @@ static bool resource_mergeable(struct resource *r1, str= uct resource *r2) return false; } =20 -static int resource_coalesce(struct resource *res, struct resource *next_r= es, - struct resource *new_res) +VISIBLE_IF_KUNIT int resource_coalesce(struct resource *res, + struct resource *next_res, + struct resource *new_res) { struct resource *parent, *tmp; struct resource **p, **c; @@ -367,6 +370,7 @@ static int resource_coalesce(struct resource *res, stru= ct resource *next_res, =20 return 0; } +EXPORT_SYMBOL_IF_KUNIT(resource_coalesce); =20 /** * request_resource_conflict - request and reserve an I/O or memory resour= ce diff --git a/kernel/resource_kunit.c b/kernel/resource_kunit.c index b8ef75b99eb2..3b5d09bb612a 100644 --- a/kernel/resource_kunit.c +++ b/kernel/resource_kunit.c @@ -4,6 +4,8 @@ */ =20 #include + +#include #include #include #include @@ -20,6 +22,16 @@ #define R3_END 0x789a #define R4_START 0x2000 #define R4_END 0x7000 +#define R4A_START 0x2000 +#define R4A_END 0x3000 +#define R4B_START 0x3001 +#define R4B_END 0x4000 +#define R5_START 0x7001 +#define R5_END 0x8000 +#define R5A_START 0x7001 +#define R5A_END 0x7800 +#define R5B_START 0x7801 +#define R5B_END 0x7c00 =20 static struct resource r0 =3D { .start =3D R0_START, .end =3D R0_END }; static struct resource r1 =3D { .start =3D R1_START, .end =3D R1_END }; @@ -34,6 +46,11 @@ struct result { bool ret; }; =20 +struct resource_tree_def { + struct resource r; + unsigned int parent, child, sibling; +}; + static struct result results_for_union[] =3D { { .r1 =3D &r1, .r2 =3D &r0, .r.start =3D R0_START, .r.end =3D R0_END, .ret= =3D true, @@ -139,6 +156,107 @@ static void resource_test_intersection(struct kunit *= test) } while (++i < ARRAY_SIZE(results_for_intersection)); } =20 +static struct resource *copy_resource_tree(struct kunit *test, + struct resource_tree_def *def, + size_t len, size_t extra) +{ + struct resource *tree; + unsigned int i; + + tree =3D kunit_kcalloc(test, len + extra, sizeof(*tree), GFP_KERNEL); + KUNIT_EXPECT_NOT_NULL(test, tree); + + for (i =3D 0; i < len; i++) { + tree[i] =3D def[i].r; + + if (def[i].parent) + tree[i].parent =3D &tree[def[i].parent]; + if (def[i].child) + tree[i].child =3D &tree[def[i].child]; + if (def[i].sibling) + tree[i].sibling =3D &tree[def[i].sibling]; + } + + return tree; +} + +static void resource_do_test_tree(struct kunit *test, struct resource *tre= e, + struct resource_tree_def *exp_tree, + size_t len) +{ + unsigned int link, i; + + for (i =3D 0; i < len; i++) { + KUNIT_EXPECT_EQ_MSG(test, tree[i].start, exp_tree[i].r.start, + "Start elements for resource %u are not equal", i); + KUNIT_EXPECT_EQ_MSG(test, tree[i].end, exp_tree[i].r.end, + "End elements for resource %u are not equal", i); + + link =3D tree[i].parent ? tree[i].parent - &tree[0] : 0; + KUNIT_EXPECT_EQ_MSG(test, link, exp_tree[i].parent, + "Parent link for resource %u is not equal", i); + + link =3D tree[i].child ? tree[i].child - &tree[0] : 0; + KUNIT_EXPECT_EQ_MSG(test, link, exp_tree[i].child, + "Child link for resource %u is not equal", i); + + link =3D tree[i].sibling ? tree[i].sibling - &tree[0] : 0; + KUNIT_EXPECT_EQ_MSG(test, link, exp_tree[i].sibling, + "Sibling link for resource %u is not equal", i); + } +} + +struct resource_tree_def resource_test_tree[8] =3D { + /* [0] is empty intentionally. */ + [1] =3D { .r.start =3D R0_START, .r.end =3D R0_END, .child =3D 2 }, + [2] =3D { .r.start =3D R4_START, .r.end =3D R4_END, .parent =3D 1, .sibli= ng =3D 3, .child =3D 4 }, + [3] =3D { .r.start =3D R5_START, .r.end =3D R5_END, .parent =3D 1, .child= =3D 6 }, + [4] =3D { .r.start =3D R4A_START, .r.end =3D R4A_END, .parent =3D 2, .sib= ling =3D 5 }, + [5] =3D { .r.start =3D R4B_START, .r.end =3D R4B_END, .parent =3D 2 }, + [6] =3D { .r.start =3D R5A_START, .r.end =3D R5A_END, .parent =3D 3, .sib= ling =3D 7 }, + [7] =3D { .r.start =3D R5B_START, .r.end =3D R5B_END, .parent =3D 3 }, +}; + +struct resource_tree_def result_for_coalesce_2_and_3[9] =3D { + /* [0] is empty intentionally. */ + [1] =3D { .r.start =3D R0_START, .r.end =3D R0_END, .child =3D 8 }, + [2] =3D { .r.start =3D R4_START, .r.end =3D R4_END }, + [3] =3D { .r.start =3D R5_START, .r.end =3D R5_END }, + [4] =3D { .r.start =3D R4A_START, .r.end =3D R4A_END, .parent =3D 8, .sib= ling =3D 5 }, + [5] =3D { .r.start =3D R4B_START, .r.end =3D R4B_END, .parent =3D 8, .sib= ling =3D 6 }, + [6] =3D { .r.start =3D R5A_START, .r.end =3D R5A_END, .parent =3D 8, .sib= ling =3D 7 }, + [7] =3D { .r.start =3D R5B_START, .r.end =3D R5B_END, .parent =3D 8 }, + [8] =3D { .r.start =3D R4_START, .r.end =3D R5_END, .parent =3D 1, .child= =3D 4 }, +}; + +static void resource_test_tree_test_harness(struct kunit *test) +{ + struct resource *tree; + + tree =3D copy_resource_tree(test, resource_test_tree, + ARRAY_SIZE(resource_test_tree), 0); + + /* Sanity-check test harness with identity check */ + resource_do_test_tree(test, tree, resource_test_tree, + ARRAY_SIZE(resource_test_tree)); +} + +static void resource_test_coalesce(struct kunit *test) +{ + struct resource *tree, *result; + int ret; + + tree =3D copy_resource_tree(test, resource_test_tree, + ARRAY_SIZE(resource_test_tree), 1); + + result =3D &tree[ARRAY_SIZE(resource_test_tree)]; + + ret =3D resource_coalesce(&tree[2], &tree[3], result); + KUNIT_EXPECT_EQ(test, ret, 0); + resource_do_test_tree(test, tree, result_for_coalesce_2_and_3, + ARRAY_SIZE(result_for_coalesce_2_and_3)); +} + /* * The test resource tree for region_intersects() test: * @@ -292,6 +410,8 @@ static void resource_test_region_intersects(struct kuni= t *test) static struct kunit_case resource_test_cases[] =3D { KUNIT_CASE(resource_test_union), KUNIT_CASE(resource_test_intersection), + KUNIT_CASE(resource_test_tree_test_harness), + KUNIT_CASE(resource_test_coalesce), KUNIT_CASE(resource_test_region_intersects), {} }; @@ -304,3 +424,4 @@ kunit_test_suite(resource_test_suite); =20 MODULE_DESCRIPTION("I/O Port & Memory Resource manager unit tests"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); --=20 2.39.5