From nobody Sat Jun 13 17:07:41 2026 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 6676637188B; Wed, 6 May 2026 07:11:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778051507; cv=none; b=EH+8y62F8YJHSxPuTpVIyGEfL43589AeB05R0R6SKtaKz4yw5XmmI+tmtjCGiHwkyFGOZnlhjCn6BpeXyh1BQML+TxqHzEFvesfHoyOviuYjYLXCrJI3gXSC8QDX698WOdiA8bG0BEc2JkSDt2ZeYdKjRO2nBY7+keX/HVYGq9Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778051507; c=relaxed/simple; bh=HYvmWZaiN+vSqr3j4xh9IKCNnojZ1zmK/tKLnuM56Sk=; h=Date:From:To:Subject:Cc:In-Reply-To:References:MIME-Version: Message-ID:Content-Type; b=ALYBE+hWCejUZA6FdtD5WGT9wU9bjnGgn3ObRpgdF6blCR9RtroL8Nql/7mY5WzgiS+HTe8YKoe2uEkKazKKozGiX/TuQ+I9+0tjHI0zYUgqlZB2vkJcEXShuTYGE0llA3MiQGGeqZWl232Bgz9q4iWClasypAI/YOGv7gMUDK8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=xxZSijUU; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=+hAwAd8x; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="xxZSijUU"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="+hAwAd8x" Date: Wed, 06 May 2026 07:11:42 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1778051503; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=dyuyrzXG+7TCKTKMbwaVDUbWmRVYcnTlGawkihK0Gvw=; b=xxZSijUUrCxZxWCnj9rXP51fHimf38X3qwxH41LZgeRC5FECP/QFK8rWPQZ2ZSUzckFAKX YJiNHrSmp2QWDOYdiXLGcKvXnd84lCfqayNQXKKpny0+37YO6m8hfs1Uvhb3r+eLcC8APZ xCflfMwhJ3edn91H6r/bUF1hL3kmK2FDm04tpFBwqpD0jWPkdjkxWh1d3UBJOVkMrfBTwy En3134Mj5mxEziw4rsRV4NrhmQuPI3UIwjZGyI1ZvBOdmHi6NBSs0/Zn+wSpxfgLa3/jhg H0tXaFCP8m7Te3jXTMuLWYid3TMjEyYgUctULvxG+lF1L8ei5ypYNRGDMMAYmg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1778051503; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=dyuyrzXG+7TCKTKMbwaVDUbWmRVYcnTlGawkihK0Gvw=; b=+hAwAd8xe1Jhg0ODV5EjuUSbrJphfNnaDBg5Ak2QmZyr5Sj5Jv0FPw+h1oC0osSOICd/0T tW5ZwMMbOy55auBw== From: "tip-bot2 for Frederic Weisbecker" Sender: tip-bot2@linutronix.de Reply-to: linux-kernel@vger.kernel.org To: linux-tip-commits@vger.kernel.org Subject: [tip: timers/core] timers/migration: Abstract out hierarchy to prepare for CPU capacity awareness Cc: Frederic Weisbecker , Thomas Gleixner , x86@kernel.org, linux-kernel@vger.kernel.org In-Reply-To: <20260423165354.95152-3-frederic@kernel.org> References: <20260423165354.95152-3-frederic@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-ID: <177805150209.424702.7584089444435960226.tip-bot2@tip-bot2> Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails Precedence: bulk Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable The following commit has been merged into the timers/core branch of tip: Commit-ID: ff65875f80d1a662d2d39e3e36345a0918766b3c Gitweb: https://git.kernel.org/tip/ff65875f80d1a662d2d39e3e36345a091= 8766b3c Author: Frederic Weisbecker AuthorDate: Thu, 23 Apr 2026 18:53:50 +02:00 Committer: Thomas Gleixner CommitterDate: Wed, 06 May 2026 08:33:06 +02:00 timers/migration: Abstract out hierarchy to prepare for CPU capacity awaren= ess In order to prepare for separating out CPUs from different capacities in distinct hierarchies, create a hierarchy structure that group setup must rely upon. Signed-off-by: Frederic Weisbecker Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20260423165354.95152-3-frederic@kernel.org --- kernel/time/timer_migration.c | 100 +++++++++++++++++++-------------- kernel/time/timer_migration.h | 10 +++- 2 files changed, 69 insertions(+), 41 deletions(-) diff --git a/kernel/time/timer_migration.c b/kernel/time/timer_migration.c index 1d0d3a4..a8ec85f 100644 --- a/kernel/time/timer_migration.c +++ b/kernel/time/timer_migration.c @@ -102,7 +102,7 @@ * active CPU/group information atomic_try_cmpxchg() is used instead and o= nly * the per CPU tmigr_cpu->lock is held. * - * During the setup of groups tmigr_level_list is required. It is protecte= d by + * During the setup of groups, hier->level_list is required. It is protect= ed by * @tmigr_mutex. * * When @timer_base->lock as well as tmigr related locks are required, the= lock @@ -416,13 +416,12 @@ */ =20 static DEFINE_MUTEX(tmigr_mutex); -static struct list_head *tmigr_level_list __read_mostly; + +static struct tmigr_hierarchy *hierarchy; =20 static unsigned int tmigr_hierarchy_levels __read_mostly; static unsigned int tmigr_crossnode_level __read_mostly; =20 -static struct tmigr_group *tmigr_root; - static DEFINE_PER_CPU(struct tmigr_cpu, tmigr_cpu); =20 /* @@ -1653,14 +1652,14 @@ static void tmigr_init_group(struct tmigr_group *gr= oup, unsigned int lvl, group->groupevt.ignore =3D true; } =20 -static struct tmigr_group *tmigr_get_group(int node, unsigned int lvl) +static struct tmigr_group *tmigr_get_group(struct tmigr_hierarchy *hier, i= nt node, unsigned int lvl) { struct tmigr_group *tmp, *group =3D NULL; =20 lockdep_assert_held(&tmigr_mutex); =20 /* Try to attach to an existing group first */ - list_for_each_entry(tmp, &tmigr_level_list[lvl], list) { + list_for_each_entry(tmp, &hier->level_list[lvl], list) { /* * If @lvl is below the cross NUMA node level, check whether * this group belongs to the same NUMA node. @@ -1694,14 +1693,14 @@ static struct tmigr_group *tmigr_get_group(int node= , unsigned int lvl) tmigr_init_group(group, lvl, node); =20 /* Setup successful. Add it to the hierarchy */ - list_add(&group->list, &tmigr_level_list[lvl]); + list_add(&group->list, &hier->level_list[lvl]); trace_tmigr_group_set(group); return group; } =20 -static bool tmigr_init_root(struct tmigr_group *group, bool activate) +static bool tmigr_init_root(struct tmigr_hierarchy *hier, struct tmigr_gro= up *group, bool activate) { - if (!group->parent && group !=3D tmigr_root) { + if (!group->parent && group !=3D hier->root) { /* * This is the new top-level, prepare its groupmask in advance * to avoid accidents where yet another new top-level is @@ -1717,11 +1716,10 @@ static bool tmigr_init_root(struct tmigr_group *gro= up, bool activate) =20 } =20 -static void tmigr_connect_child_parent(struct tmigr_group *child, - struct tmigr_group *parent, - bool activate) +static void tmigr_connect_child_parent(struct tmigr_hierarchy *hier, struc= t tmigr_group *child, + struct tmigr_group *parent, bool activate) { - if (tmigr_init_root(parent, activate)) { + if (tmigr_init_root(hier, parent, activate)) { /* * The previous top level had prepared its groupmask already, * simply account it in advance as the first child. If some groups @@ -1757,10 +1755,10 @@ static void tmigr_connect_child_parent(struct tmigr= _group *child, trace_tmigr_connect_child_parent(child); } =20 -static int tmigr_setup_groups(unsigned int cpu, unsigned int node, - struct tmigr_group *start, bool activate) +static int tmigr_setup_groups(struct tmigr_hierarchy *hier, unsigned int c= pu, + unsigned int node, struct tmigr_group *start, bool activate) { - struct tmigr_group *group, *child, **stack; + struct tmigr_group *root =3D hier->root, *group, *child, **stack; int i, top =3D 0, err =3D 0, start_lvl =3D 0; bool root_mismatch =3D false; =20 @@ -1773,11 +1771,11 @@ static int tmigr_setup_groups(unsigned int cpu, uns= igned int node, start_lvl =3D start->level + 1; } =20 - if (tmigr_root) - root_mismatch =3D tmigr_root->numa_node !=3D node; + if (root) + root_mismatch =3D root->numa_node !=3D node; =20 for (i =3D start_lvl; i < tmigr_hierarchy_levels; i++) { - group =3D tmigr_get_group(node, i); + group =3D tmigr_get_group(hier, node, i); if (IS_ERR(group)) { err =3D PTR_ERR(group); i--; @@ -1799,7 +1797,7 @@ static int tmigr_setup_groups(unsigned int cpu, unsig= ned int node, if (group->parent) break; if ((!root_mismatch || i >=3D tmigr_crossnode_level) && - list_is_singular(&tmigr_level_list[i])) + list_is_singular(&hier->level_list[i])) break; } =20 @@ -1827,7 +1825,7 @@ static int tmigr_setup_groups(unsigned int cpu, unsig= ned int node, tmc->tmgroup =3D group; tmc->groupmask =3D BIT(group->num_children++); =20 - tmigr_init_root(group, activate); + tmigr_init_root(hier, group, activate); =20 trace_tmigr_connect_cpu_parent(tmc); =20 @@ -1835,7 +1833,7 @@ static int tmigr_setup_groups(unsigned int cpu, unsig= ned int node, continue; } else { child =3D stack[i - 1]; - tmigr_connect_child_parent(child, group, activate); + tmigr_connect_child_parent(hier, child, group, activate); } } =20 @@ -1894,15 +1892,14 @@ static int tmigr_setup_groups(unsigned int cpu, uns= igned int node, } =20 /* Root update */ - if (list_is_singular(&tmigr_level_list[top])) { - group =3D list_first_entry(&tmigr_level_list[top], - typeof(*group), list); + if (list_is_singular(&hier->level_list[top])) { + group =3D list_first_entry(&hier->level_list[top], typeof(*group), list); WARN_ON_ONCE(group->parent); - if (tmigr_root) { + if (root) { /* Old root should be the same or below */ - WARN_ON_ONCE(tmigr_root->level > top); + WARN_ON_ONCE(root->level > top); } - tmigr_root =3D group; + hier->root =3D group; } out: kfree(stack); @@ -1910,18 +1907,47 @@ out: return err; } =20 +static struct tmigr_hierarchy *tmigr_get_hierarchy(void) +{ + if (hierarchy) + return hierarchy; + + hierarchy =3D kzalloc(sizeof(*hierarchy), GFP_KERNEL); + if (!hierarchy) + return ERR_PTR(-ENOMEM); + + hierarchy->level_list =3D kzalloc_objs(struct list_head, tmigr_hierarchy_= levels); + if (!hierarchy->level_list) { + kfree(hierarchy); + hierarchy =3D NULL; + return ERR_PTR(-ENOMEM); + } + + for (int i =3D 0; i < tmigr_hierarchy_levels; i++) + INIT_LIST_HEAD(&hierarchy->level_list[i]); + + return hierarchy; +} + static int tmigr_add_cpu(unsigned int cpu) { - struct tmigr_group *old_root =3D tmigr_root; + struct tmigr_hierarchy *hier; + struct tmigr_group *old_root; int node =3D cpu_to_node(cpu); int ret; =20 guard(mutex)(&tmigr_mutex); =20 - ret =3D tmigr_setup_groups(cpu, node, NULL, false); + hier =3D tmigr_get_hierarchy(); + if (IS_ERR(hier)) + return PTR_ERR(hier); + + old_root =3D hier->root; + + ret =3D tmigr_setup_groups(hier, cpu, node, NULL, false); =20 /* Root has changed? Connect the old one to the new */ - if (ret >=3D 0 && old_root && old_root !=3D tmigr_root) { + if (ret >=3D 0 && old_root && old_root !=3D hier->root) { /* * The target CPU must never do the prepare work, except * on early boot when the boot CPU is the target. Otherwise @@ -1935,7 +1961,7 @@ static int tmigr_add_cpu(unsigned int cpu) * otherwise the old root may not be active as expected. */ WARN_ON_ONCE(!per_cpu_ptr(&tmigr_cpu, raw_smp_processor_id())->available= ); - ret =3D tmigr_setup_groups(-1, old_root->numa_node, old_root, true); + ret =3D tmigr_setup_groups(hier, -1, old_root->numa_node, old_root, true= ); } =20 return ret; @@ -1970,7 +1996,7 @@ static int tmigr_cpu_prepare(unsigned int cpu) =20 static int __init tmigr_init(void) { - unsigned int cpulvl, nodelvl, cpus_per_node, i; + unsigned int cpulvl, nodelvl, cpus_per_node; unsigned int nnodes =3D num_possible_nodes(); unsigned int ncpus =3D num_possible_cpus(); int ret =3D -ENOMEM; @@ -2017,14 +2043,6 @@ static int __init tmigr_init(void) */ tmigr_crossnode_level =3D cpulvl; =20 - tmigr_level_list =3D kzalloc_objs(struct list_head, - tmigr_hierarchy_levels); - if (!tmigr_level_list) - goto err; - - for (i =3D 0; i < tmigr_hierarchy_levels; i++) - INIT_LIST_HEAD(&tmigr_level_list[i]); - pr_info("Timer migration: %d hierarchy levels; %d children per group;" " %d crossnode level\n", tmigr_hierarchy_levels, TMIGR_CHILDREN_PER_GROUP, diff --git a/kernel/time/timer_migration.h b/kernel/time/timer_migration.h index 70879cd..77df422 100644 --- a/kernel/time/timer_migration.h +++ b/kernel/time/timer_migration.h @@ -6,6 +6,16 @@ #define TMIGR_CHILDREN_PER_GROUP 8 =20 /** + * struct tmigr_hierarchy - a hierarchy associated to a given CPU capacity. + * @level_list: Per level lists of tmigr groups + * @root: The current root of the hierarchy + */ +struct tmigr_hierarchy { + struct list_head *level_list; + struct tmigr_group *root; +}; + +/** * struct tmigr_event - a timer event associated to a CPU * @nextevt: The node to enqueue an event in the parent group queue * @cpu: The CPU to which this event belongs