Linux Power Management development
 help / color / mirror / Atom feed
* Re: [PATCH 2/2] arm64: dts: qcom: lemans-evk: Describe the PCIe M.2 Key E connector
From: Wei Deng @ 2026-06-22  6:02 UTC (permalink / raw)
  To: konrad.dybcio
  Cc: andersson, robh, krzk+dt, conor+dt, mani, brgl, linux-arm-msm,
	devicetree, linux-kernel, linux-pci, linux-pm, quic_chezhou,
	cheng.jiang, shuai.zhang, jinwang.li, xiuzhuo.shang, mengshi.wu
In-Reply-To: <580db7de-321d-4f4e-99f9-3c9a1cc5a3f9@oss.qualcomm.com>

Hi Konrad,

On Thu, Jun 18, 2026 at 11:49:05AM +0200, Konrad Dybcio wrote:
> On 6/8/26 11:17 AM, Wei Deng wrote:
> > The lemans EVK has the PCIe M.2 Mechanical Key E connector to connect
> > wireless connectivity cards over PCIe and UART interfaces. Hence,
> > describe the connector node and link it with the PCIe 0 Root Port and
> > UART17 nodes through graph port/endpoint.
> >
> > Also add 'compatible = "pciclass,0604"' to the pcieport0 node in
> > lemans.dtsi to allow the PCI subsystem to associate the DT node with
> > the PCI-to-PCI bridge device.
>
> Ideally this would be a separate change
>
> Also, b4 can't grab this patch since there's something wrong with the
> threading (multiple series in a single thread) - please switch to using
> b4 for submissions yourself to avoid such mistakes.
>
> https://b4.docs.kernel.org/en/latest/
>
> Konrad

Thanks for the review. Agreed. Posting shortly.

--
Best Regards,
Wei Deng

^ permalink raw reply

* RE: [PATCH 1/8] PCI: imx6: Add skip_pwrctrl_off flag support
From: Sherry Sun @ 2026-06-22  5:52 UTC (permalink / raw)
  To: Frank Li (OSS), Sherry Sun (OSS)
  Cc: robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
	Frank Li, s.hauer@pengutronix.de, kernel@pengutronix.de,
	festevam@gmail.com, Amitkumar Karwar, Neeraj Sanjay Kale,
	marcel@holtmann.org, luiz.dentz@gmail.com, Hongxing Zhu,
	l.stach@pengutronix.de, lpieralisi@kernel.org,
	kwilczynski@kernel.org, mani@kernel.org, bhelgaas@google.com,
	brgl@kernel.org, imx@lists.linux.dev, linux-pci@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-bluetooth@vger.kernel.org,
	linux-pm@vger.kernel.org
In-Reply-To: <ajQ64ZswbmTceIGO@SMW015318>

> On Thu, Jun 18, 2026 at 06:10:40PM +0800, Sherry Sun (OSS) wrote:
> > From: Sherry Sun <sherry.sun@nxp.com>
> >
> > Use dw_pcie::skip_pwrctrl_off to avoid powering off devices during
> > suspend to preserve wakeup capability of the devices and also not to
> > power on the devices in the init path.
> > This allows controller power-off to be skipped when some devices(e.g.
> > M.2 cards key E without auxiliary power) required to support PCIe L2
> > link state and wake-up mechanisms.
> >
> > Signed-off-by: Sherry Sun <sherry.sun@nxp.com>
> > ---
> >  drivers/pci/controller/dwc/pci-imx6.c | 36
> > +++++++++++++++++----------
> >  1 file changed, 23 insertions(+), 13 deletions(-)
> >
> > diff --git a/drivers/pci/controller/dwc/pci-imx6.c
> > b/drivers/pci/controller/dwc/pci-imx6.c
> > index 0fa716d1ed75..ff5a9565dbbf 100644
> > --- a/drivers/pci/controller/dwc/pci-imx6.c
> > +++ b/drivers/pci/controller/dwc/pci-imx6.c
> > @@ -1382,16 +1382,20 @@ static int imx_pcie_host_init(struct dw_pcie_rp
> *pp)
> >  		}
> >  	}
> >
> > -	ret = pci_pwrctrl_create_devices(dev);
> > -	if (ret) {
> > -		dev_err(dev, "failed to create pwrctrl devices\n");
> > -		goto err_reg_disable;
> > +	if (!pci->suspended) {
> > +		ret = pci_pwrctrl_create_devices(dev);
> > +		if (ret) {
> > +			dev_err(dev, "failed to create pwrctrl devices\n");
> > +			goto err_reg_disable;
> > +		}
> 
> supposed create_devices only do once.
> 
> pci_pwrctrl_power_on_devices() controller on and off for difference case.
> 

Hi  Frank,
Yes, pci_pwrctrl_create_devices() is currently only called once
during imx_pcie_probe.
pci_pwrctrl_power_on_devices() is called during imx_pcie_probe
and during suspend/resume (depending on skip_pwrctrl_off flag).

Best Regards
Sherry
> >  	}
> >
> > -	ret = pci_pwrctrl_power_on_devices(dev);
> > -	if (ret) {
> > -		dev_err(dev, "failed to power on pwrctrl devices\n");
> > -		goto err_pwrctrl_destroy;
> > +	if (!pp->skip_pwrctrl_off) {
> > +		ret = pci_pwrctrl_power_on_devices(dev);
> > +		if (ret) {
> > +			dev_err(dev, "failed to power on pwrctrl devices\n");
> > +			goto err_pwrctrl_destroy;
> > +		}
> >  	}
> >
> >  	ret = imx_pcie_clk_enable(imx_pcie); @@ -1460,9 +1464,10 @@
> static
> > int imx_pcie_host_init(struct dw_pcie_rp *pp)
> >  err_clk_disable:
> >  	imx_pcie_clk_disable(imx_pcie);
> >  err_pwrctrl_power_off:
> > -	pci_pwrctrl_power_off_devices(dev);
> > +	if (!pp->skip_pwrctrl_off)
> > +		pci_pwrctrl_power_off_devices(dev);
> >  err_pwrctrl_destroy:
> > -	if (ret != -EPROBE_DEFER)
> > +	if (ret != -EPROBE_DEFER && !pci->suspended)
> >  		pci_pwrctrl_destroy_devices(dev);
> >  err_reg_disable:
> >  	if (imx_pcie->vpcie)
> > @@ -1482,7 +1487,8 @@ static void imx_pcie_host_exit(struct dw_pcie_rp
> *pp)
> >  	}
> >  	imx_pcie_clk_disable(imx_pcie);
> >
> > -	pci_pwrctrl_power_off_devices(pci->dev);
> > +	if (!pci->pp.skip_pwrctrl_off)
> > +		pci_pwrctrl_power_off_devices(pci->dev);
> >  	if (imx_pcie->vpcie)
> >  		regulator_disable(imx_pcie->vpcie);
> >  }
> > @@ -1990,12 +1996,16 @@ static int imx_pcie_probe(struct
> > platform_device *pdev)  static void imx_pcie_shutdown(struct
> > platform_device *pdev)  {
> >  	struct imx_pcie *imx_pcie = platform_get_drvdata(pdev);
> > +	struct dw_pcie *pci = imx_pcie->pci;
> > +	struct dw_pcie_rp *pp = &pci->pp;
> >
> >  	/* bring down link, so bootloader gets clean state in case of reboot */
> >  	imx_pcie_assert_core_reset(imx_pcie);
> >  	imx_pcie_assert_perst(imx_pcie, true);
> > -	pci_pwrctrl_power_off_devices(&pdev->dev);
> > -	pci_pwrctrl_destroy_devices(&pdev->dev);
> > +	if (!pp->skip_pwrctrl_off)
> > +		pci_pwrctrl_power_off_devices(&pdev->dev);
> > +	if (!pci->suspended)
> > +		pci_pwrctrl_destroy_devices(&pdev->dev);
> >  }
> >
> >  static const struct imx_pcie_drvdata drvdata[] = {
> > --
> > 2.50.1
> >
> >

^ permalink raw reply

* Re: [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state
From: Alexei Starovoitov @ 2026-06-22  5:28 UTC (permalink / raw)
  To: Kaitao Cheng
  Cc: Andrew Morton, David Hildenbrand, Jens Axboe, Tejun Heo,
	Alexander Viro, Christian Brauner, Alexei Starovoitov,
	Daniel Borkmann, Andrii Nakryiko, Johannes Weiner, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim,
	Thomas Gleixner, Juri Lelli, Vincent Guittot, Paul Moore,
	Andy Shevchenko, Paul E. McKenney, Shakeel Butt,
	Christian König, David Howells, Simona Vetter, Randy Dunlap,
	Luca Ceresoli, Philipp Stanner, linux-block, LKML,
	open list:CONTROL GROUP (CGROUP), linux-ntfs-dev, Linux-Fsdevel,
	io-uring, audit, bpf, Network Development, dri-devel,
	linux-perf-use., linux-trace-kernel, kexec, live-patching,
	linux-modules, Linux Crypto Mailing List, Linux Power Management,
	rcu, sched-ext, linux-mm, virtualization, damon,
	clang-built-linux, chengkaitao
In-Reply-To: <20260622040533.29824-1-kaitao.cheng@linux.dev>

On Sun, Jun 21, 2026 at 9:06 PM Kaitao Cheng <kaitao.cheng@linux.dev> wrote:
>
> From: chengkaitao <chengkaitao@kylinos.cn>
>
> The list_for_each*_safe() helpers are used when the loop body may remove
> the current entry.  Their current interface, however, forces every caller
> to define a temporary cursor outside the macro and pass it in, even when
> the caller never uses that cursor directly.  For most call sites this
> extra cursor is just boilerplate required by the macro implementation.
>
> This is awkward because the saved next pointer is an internal detail of
> the iteration.  Callers that only remove or move the current entry do not
> need to spell it out.
>
> The _safe() suffix has also caused confusion.  Christian Koenig pointed
> out that the name is easy to read as a thread-safe variant, especially
> for beginners, even though it only means that the iterator keeps enough
> state to tolerate removal of the current entry.  He suggested _mutable()
> as a clearer description of what the loop permits.
>
> Add *_mutable() iterator variants for list, hlist and llist.  The new
> helpers are variadic and support both forms.  In the common case, the
> caller omits the temporary cursor and the macro creates a unique internal
> cursor with typeof(pos) and __UNIQUE_ID().  If a loop really needs an
> explicit temporary cursor, the caller can still pass it and the helper
> keeps the existing *_safe() behaviour.
>
> For example, a call site may use the shorter form:
>
>   list_for_each_entry_mutable(pos, head, member)
>
> or keep the explicit temporary cursor form:
>
>   list_for_each_entry_mutable(pos, tmp, head, member)
>
> The existing *_safe() helpers remain available for compatibility.  This
> series only converts users in mm, block, kernel, init and io_uring.  If
> this approach looks acceptable, the remaining users can be converted in
> follow-up series.
>
> Changes in v3 (Christian König, Andy Shevchenko):
> - Convert safe list walks to mutable iterators
>
> Changes in v2 (Muchun Song, Andy Shevchenko):
> - Drop the list_for_each_entry_mutable*() helpers from v1 and make the
>   cursor change directly in the existing list_for_each_entry*() helpers.
> - Open-code special list walks that rely on updating the loop cursor in
>   the body, preserving their existing traversal semantics.
>
> Link to v2:
> https://lore.kernel.org/all/20260609061347.93688-1-kaitao.cheng@linux.dev/
>
> Link to v1:
> https://lore.kernel.org/all/20260529082149.76764-1-kaitao.cheng@linux.dev/
>
> Kaitao Cheng (7):
>   list: Add mutable iterator variants
>   llist: Add mutable iterator variants
>   mm: Use mutable list iterators
>   block: Use mutable list iterators
>   kernel: Use mutable list iterators
>   initramfs: Use mutable list iterator
>   io_uring: Use mutable list iterators
>
>  block/bfq-iosched.c                 |  17 +-
>  block/blk-cgroup.c                  |  12 +-
>  block/blk-flush.c                   |   4 +-
>  block/blk-iocost.c                  |  18 +-
>  block/blk-mq.c                      |   8 +-
>  block/blk-throttle.c                |   4 +-
>  block/kyber-iosched.c               |   4 +-
>  block/partitions/ldm.c              |   8 +-
>  block/sed-opal.c                    |   4 +-
>  include/linux/list.h                | 269 ++++++++++++++++++++++++----
>  include/linux/llist.h               |  81 +++++++--
>  init/initramfs.c                    |   5 +-
>  io_uring/cancel.c                   |   6 +-
>  io_uring/poll.c                     |   3 +-
>  io_uring/rw.c                       |   4 +-
>  io_uring/timeout.c                  |   8 +-
>  io_uring/uring_cmd.c                |   3 +-
>  kernel/audit_tree.c                 |   4 +-
>  kernel/audit_watch.c                |  16 +-
>  kernel/auditfilter.c                |   4 +-
>  kernel/auditsc.c                    |   4 +-
>  kernel/bpf/arena.c                  |  10 +-
>  kernel/bpf/arraymap.c               |   8 +-
>  kernel/bpf/bpf_local_storage.c      |   3 +-
>  kernel/bpf/bpf_lru_list.c           |  25 ++-
>  kernel/bpf/btf.c                    |  18 +-
>  kernel/bpf/cgroup.c                 |   7 +-
>  kernel/bpf/cpumap.c                 |   4 +-
>  kernel/bpf/devmap.c                 |  10 +-
>  kernel/bpf/helpers.c                |   8 +-
>  kernel/bpf/local_storage.c          |   4 +-
>  kernel/bpf/memalloc.c               |  16 +-
>  kernel/bpf/offload.c                |   8 +-
>  kernel/bpf/states.c                 |   4 +-
>  kernel/bpf/stream.c                 |   4 +-
>  kernel/bpf/verifier.c               |   6 +-
>  kernel/cgroup/cgroup-v1.c           |   4 +-
>  kernel/cgroup/cgroup.c              |  54 +++---
>  kernel/cgroup/dmem.c                |  12 +-
>  kernel/cgroup/rdma.c                |   8 +-
>  kernel/events/core.c                |  44 +++--
>  kernel/events/uprobes.c             |  12 +-
>  kernel/exit.c                       |   8 +-
>  kernel/fail_function.c              |   4 +-
>  kernel/gcov/clang.c                 |   4 +-
>  kernel/irq_work.c                   |   4 +-
>  kernel/kexec_core.c                 |   4 +-
>  kernel/kprobes.c                    |  16 +-
>  kernel/livepatch/core.c             |   4 +-
>  kernel/livepatch/core.h             |   4 +-
>  kernel/liveupdate/kho_block.c       |   4 +-
>  kernel/liveupdate/luo_flb.c         |   4 +-
>  kernel/locking/rwsem.c              |   2 +-
>  kernel/locking/test-ww_mutex.c      |   2 +-
>  kernel/module/main.c                |  11 +-
>  kernel/padata.c                     |   4 +-
>  kernel/power/snapshot.c             |   8 +-
>  kernel/power/wakelock.c             |   4 +-
>  kernel/printk/printk.c              |  11 +-
>  kernel/ptrace.c                     |   4 +-
>  kernel/rcu/rcutorture.c             |   3 +-
>  kernel/rcu/tasks.h                  |   9 +-
>  kernel/rcu/tree.c                   |   6 +-
>  kernel/resource.c                   |   4 +-
>  kernel/sched/core.c                 |   4 +-
>  kernel/sched/ext.c                  |  22 +--
>  kernel/sched/fair.c                 |  28 +--
>  kernel/sched/topology.c             |   4 +-
>  kernel/sched/wait.c                 |   4 +-
>  kernel/seccomp.c                    |   4 +-
>  kernel/signal.c                     |  11 +-
>  kernel/smp.c                        |   4 +-
>  kernel/taskstats.c                  |   8 +-
>  kernel/time/clockevents.c           |   6 +-
>  kernel/time/clocksource.c           |   4 +-
>  kernel/time/posix-cpu-timers.c      |   4 +-
>  kernel/time/posix-timers.c          |   3 +-
>  kernel/torture.c                    |   3 +-
>  kernel/trace/bpf_trace.c            |   4 +-
>  kernel/trace/ftrace.c               |  49 +++--
>  kernel/trace/ring_buffer.c          |  25 ++-
>  kernel/trace/trace.c                |  12 +-
>  kernel/trace/trace_dynevent.c       |   6 +-
>  kernel/trace/trace_dynevent.h       |   5 +-
>  kernel/trace/trace_events.c         |  35 ++--
>  kernel/trace/trace_events_filter.c  |   4 +-
>  kernel/trace/trace_events_hist.c    |   8 +-
>  kernel/trace/trace_events_trigger.c |  17 +-
>  kernel/trace/trace_events_user.c    |  16 +-
>  kernel/trace/trace_stat.c           |   4 +-
>  kernel/user-return-notifier.c       |   3 +-
>  kernel/workqueue.c                  |  16 +-
>  mm/backing-dev.c                    |   8 +-
>  mm/balloon.c                        |   8 +-
>  mm/cma.c                            |   4 +-
>  mm/compaction.c                     |   4 +-
>  mm/damon/core.c                     |   4 +-
>  mm/damon/sysfs-schemes.c            |   4 +-
>  mm/dmapool.c                        |   4 +-
>  mm/huge_memory.c                    |   8 +-
>  mm/hugetlb.c                        |  56 +++---
>  mm/hugetlb_vmemmap.c                |  16 +-
>  mm/khugepaged.c                     |  14 +-
>  mm/kmemleak.c                       |   7 +-
>  mm/ksm.c                            |  25 +--
>  mm/list_lru.c                       |   4 +-
>  mm/memcontrol-v1.c                  |   8 +-
>  mm/memory-failure.c                 |  12 +-
>  mm/memory-tiers.c                   |   4 +-
>  mm/migrate.c                        |  23 ++-
>  mm/mmu_notifier.c                   |   9 +-
>  mm/page_alloc.c                     |   8 +-
>  mm/page_reporting.c                 |   2 +-
>  mm/percpu.c                         |  11 +-
>  mm/pgtable-generic.c                |   4 +-
>  mm/rmap.c                           |  10 +-
>  mm/shmem.c                          |   9 +-
>  mm/slab_common.c                    |  14 +-
>  mm/slub.c                           |  33 ++--
>  mm/swapfile.c                       |   4 +-
>  mm/userfaultfd.c                    |  12 +-
>  mm/vmalloc.c                        |  24 +--
>  mm/vmscan.c                         |   7 +-
>  mm/zsmalloc.c                       |   4 +-
>  124 files changed, 875 insertions(+), 681 deletions(-)

Not sure what you were thinking, but this diff stat
is not landable.

pw-bot: cr

^ permalink raw reply

* Re: [PATCH v3 5/7] kernel: Use mutable list iterators
From: bot+bpf-ci @ 2026-06-22  5:22 UTC (permalink / raw)
  To: kaitao.cheng, paul, eparis, ast, daniel, andrii, eddyz87, memxor,
	davem, kuba, hawk, john.fastabend, tj, hannes, mkoutny, dev,
	mripard, natalie.vock, peterz, mingo, acme, namhyung, mhiramat,
	oleg, oberpar, akpm, baoquan.he, rppt, pasha.tatashin, pratyush,
	naveen, jpoimboe, jikos, mbenes, pmladek, will, boqun, mcgrof,
	petr.pavlu, da.gomez, samitolvanen, steffen.klassert,
	daniel.m.jordan, rafael, dave, paulmck, josh, frederic,
	neeraj.upadhyay, joelagnelf, urezki, juri.lelli, vincent.guittot,
	kees, bsingharora, anna-maria, tglx, jstultz, kpsingh,
	mattbobrowski, nathan, martin.lau, song, mark.rutland,
	mathieu.desnoyers, dietmar.eggemann, void, rostedt
  Cc: audit, linux-kernel, bpf, netdev, cgroups, dri-devel,
	linux-perf-users, linux-trace-kernel, kexec, live-patching,
	linux-modules, linux-crypto, linux-pm, rcu, sched-ext, llvm,
	chengkaitao, ast, andrii, daniel, martin.lau, eddyz87,
	yonghong.song, clm, ihor.solodrai
In-Reply-To: <20260622042811.31684-1-kaitao.cheng@linux.dev>

[-- Attachment #1: Type: text/plain, Size: 1983 bytes --]

> diff --git a/kernel/trace/trace_dynevent.c b/kernel/trace/trace_dynevent.c
> index c4dfbc293bae..9e076106bee7 100644
> --- a/kernel/trace/trace_dynevent.c
> +++ b/kernel/trace/trace_dynevent.c

[ ... ]

> @@ -100,7 +100,7 @@ int dyn_event_release(const char *raw_command, struct dyn_event_operations *type
>  		return -EINVAL;
>
>  	mutex_lock(&event_mutex);
> -	for_each_dyn_event_safe(pos, n) {
> +	for_each_dyn_event_safe(pos) {
>  		if (type && type != pos->ops)
>  			continue;
>  		if (!pos->ops->match(system, event,

Does this leave the variable n unused? Looking at the function
declaration around line 74, it still has:

	struct dyn_event *pos, *n;

but after this change n is no longer passed to for_each_dyn_event_safe().
The macro now hides the temporary cursor internally, so n appears to be
dead code. This would trigger -Wunused-variable warnings and break builds
with CONFIG_WERROR=y.

For comparison, the sibling change at line 219 (dyn_events_release_all)
correctly removed the *tmp variable from its declaration.

> diff --git a/kernel/trace/trace_dynevent.h b/kernel/trace/trace_dynevent.h
> index beee3f8d7544..a4dc0812284f 100644
> --- a/kernel/trace/trace_dynevent.h
> +++ b/kernel/trace/trace_dynevent.h
> @@ -115,10 +115,9 @@ int dyn_event_create(const char *raw_command, struct dyn_event_operations *type)
>  /*
>   * for_each_dyn_event	-	iterate over the dyn_event list safely
>   * @pos:	the struct dyn_event * to use as a loop cursor
> - * @n:		the struct dyn_event * to use as temporary storage
>   */
> -#define for_each_dyn_event_safe(pos, n)	\
> -	list_for_each_entry_safe(pos, n, &dyn_event_list, list)
> +#define for_each_dyn_event_safe(pos)	\
> +	list_for_each_entry_mutable(pos, &dyn_event_list, list)


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/27930295027

^ permalink raw reply

* [PATCH v3 5/7] kernel: Use mutable list iterators
From: Kaitao Cheng @ 2026-06-22  4:28 UTC (permalink / raw)
  To: Paul Moore, Eric Paris, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
	David S. Miller, Jakub Kicinski, Jesper Dangaard Brouer,
	John Fastabend, Tejun Heo, Johannes Weiner, Michal Koutný,
	Maarten Lankhorst, Maxime Ripard, Natalie Vock, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim,
	Masami Hiramatsu, Oleg Nesterov, Peter Oberparleiter,
	Andrew Morton, Baoquan He, Mike Rapoport, Pasha Tatashin,
	Pratyush Yadav, Naveen N Rao, Josh Poimboeuf, Jiri Kosina,
	Miroslav Benes, Petr Mladek, Will Deacon, Boqun Feng,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Steffen Klassert, Daniel Jordan, Rafael J. Wysocki,
	Davidlohr Bueso, Paul E. McKenney, Josh Triplett,
	Frederic Weisbecker, Neeraj Upadhyay, Joel Fernandes,
	Uladzislau Rezki, Juri Lelli, Vincent Guittot, Kees Cook,
	Balbir Singh, Anna-Maria Behnsen, Thomas Gleixner, John Stultz,
	KP Singh, Matt Bobrowski, Nathan Chancellor, Martin KaFai Lau,
	Song Liu, Mark Rutland, Mathieu Desnoyers, Dietmar Eggemann,
	David Vernet, Steven Rostedt
  Cc: audit, linux-kernel, bpf, netdev, cgroups, dri-devel,
	linux-perf-users, linux-trace-kernel, kexec, live-patching,
	linux-modules, linux-crypto, linux-pm, rcu, sched-ext, llvm,
	Kaitao Cheng
In-Reply-To: <20260622040533.29824-1-kaitao.cheng@linux.dev>

From: Kaitao Cheng <chengkaitao@kylinos.cn>

The safe list iteration helpers require callers to provide a temporary
cursor even when the cursor is only used internally by the loop. This
leaves many functions with otherwise unused variables whose only purpose
is to satisfy the old iterator interface.

Use the mutable list iteration helpers for those cases. The mutable
helpers keep the same removal-safe traversal semantics, while allowing
the temporary cursor to be internal to the macro when the caller does
not need to observe it.

Convert list, hlist and llist users under kernel/ where the temporary
cursor is not used outside the iteration. Keep the explicit cursor form
where the next entry is still needed by the surrounding code.

No functional change intended.

Signed-off-by: Kaitao Cheng <chengkaitao@kylinos.cn>
---
 kernel/audit_tree.c                 |  4 +--
 kernel/audit_watch.c                | 16 ++++-----
 kernel/auditfilter.c                |  4 +--
 kernel/auditsc.c                    |  4 +--
 kernel/bpf/arena.c                  | 10 +++---
 kernel/bpf/arraymap.c               |  8 ++---
 kernel/bpf/bpf_local_storage.c      |  3 +-
 kernel/bpf/bpf_lru_list.c           | 25 ++++++-------
 kernel/bpf/btf.c                    | 18 +++++-----
 kernel/bpf/cgroup.c                 |  7 ++--
 kernel/bpf/cpumap.c                 |  4 +--
 kernel/bpf/devmap.c                 | 10 +++---
 kernel/bpf/helpers.c                |  8 ++---
 kernel/bpf/local_storage.c          |  4 +--
 kernel/bpf/memalloc.c               | 16 ++++-----
 kernel/bpf/offload.c                |  8 ++---
 kernel/bpf/states.c                 |  4 +--
 kernel/bpf/stream.c                 |  4 +--
 kernel/bpf/verifier.c               |  6 ++--
 kernel/cgroup/cgroup-v1.c           |  4 +--
 kernel/cgroup/cgroup.c              | 54 ++++++++++++++---------------
 kernel/cgroup/dmem.c                | 12 +++----
 kernel/cgroup/rdma.c                |  8 ++---
 kernel/events/core.c                | 44 +++++++++++------------
 kernel/events/uprobes.c             | 12 +++----
 kernel/exit.c                       |  8 ++---
 kernel/fail_function.c              |  4 +--
 kernel/gcov/clang.c                 |  4 +--
 kernel/irq_work.c                   |  4 +--
 kernel/kexec_core.c                 |  4 +--
 kernel/kprobes.c                    | 16 ++++-----
 kernel/livepatch/core.c             |  4 +--
 kernel/livepatch/core.h             |  4 +--
 kernel/liveupdate/kho_block.c       |  4 +--
 kernel/liveupdate/luo_flb.c         |  4 +--
 kernel/locking/rwsem.c              |  2 +-
 kernel/locking/test-ww_mutex.c      |  2 +-
 kernel/module/main.c                | 11 +++---
 kernel/padata.c                     |  4 +--
 kernel/power/snapshot.c             |  8 ++---
 kernel/power/wakelock.c             |  4 +--
 kernel/printk/printk.c              | 11 +++---
 kernel/ptrace.c                     |  4 +--
 kernel/rcu/rcutorture.c             |  3 +-
 kernel/rcu/tasks.h                  |  9 +++--
 kernel/rcu/tree.c                   |  6 ++--
 kernel/resource.c                   |  4 +--
 kernel/sched/core.c                 |  4 +--
 kernel/sched/ext.c                  | 22 ++++++------
 kernel/sched/fair.c                 | 28 +++++++--------
 kernel/sched/topology.c             |  4 +--
 kernel/sched/wait.c                 |  4 +--
 kernel/seccomp.c                    |  4 +--
 kernel/signal.c                     | 11 +++---
 kernel/smp.c                        |  4 +--
 kernel/taskstats.c                  |  8 ++---
 kernel/time/clockevents.c           |  6 ++--
 kernel/time/clocksource.c           |  4 +--
 kernel/time/posix-cpu-timers.c      |  4 +--
 kernel/time/posix-timers.c          |  3 +-
 kernel/torture.c                    |  3 +-
 kernel/trace/bpf_trace.c            |  4 +--
 kernel/trace/ftrace.c               | 49 +++++++++++---------------
 kernel/trace/ring_buffer.c          | 25 +++++++------
 kernel/trace/trace.c                | 12 +++----
 kernel/trace/trace_dynevent.c       |  6 ++--
 kernel/trace/trace_dynevent.h       |  5 ++-
 kernel/trace/trace_events.c         | 35 +++++++++----------
 kernel/trace/trace_events_filter.c  |  4 +--
 kernel/trace/trace_events_hist.c    |  8 ++---
 kernel/trace/trace_events_trigger.c | 17 ++++-----
 kernel/trace/trace_events_user.c    | 16 ++++-----
 kernel/trace/trace_stat.c           |  4 +--
 kernel/user-return-notifier.c       |  3 +-
 kernel/workqueue.c                  | 16 ++++-----
 75 files changed, 353 insertions(+), 381 deletions(-)

diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
index 1ed19b775912..9652b0595ad4 100644
--- a/kernel/audit_tree.c
+++ b/kernel/audit_tree.c
@@ -543,10 +543,10 @@ static void audit_tree_log_remove_rule(struct audit_context *context,
 
 static void kill_rules(struct audit_context *context, struct audit_tree *tree)
 {
-	struct audit_krule *rule, *next;
+	struct audit_krule *rule;
 	struct audit_entry *entry;
 
-	list_for_each_entry_safe(rule, next, &tree->rules, rlist) {
+	list_for_each_entry_mutable(rule, &tree->rules, rlist) {
 		entry = container_of(rule, struct audit_entry, rule);
 
 		list_del_init(&rule->rlist);
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index 06dd0ebe73e2..f56812c8186f 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -247,14 +247,14 @@ static void audit_update_watch(struct audit_parent *parent,
 			       u64 ino, unsigned int invalidating,
 			       struct audit_watch_ctx *ctx)
 {
-	struct audit_watch *owatch, *nwatch, *nextw;
-	struct audit_krule *r, *nextr;
+	struct audit_watch *owatch, *nwatch;
+	struct audit_krule *r;
 	struct audit_entry *oentry, *nentry;
 
 	mutex_lock(&audit_filter_mutex);
 	/* Run all of the watches on this parent looking for the one that
 	 * matches the given dname */
-	list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
+	list_for_each_entry_mutable(owatch, &parent->watches, wlist) {
 		if (audit_compare_dname_path(dname, owatch->path,
 					     AUDIT_NAME_FULL))
 			continue;
@@ -275,7 +275,7 @@ static void audit_update_watch(struct audit_parent *parent,
 		nwatch->dev = dev;
 		nwatch->ino = ino;
 
-		list_for_each_entry_safe(r, nextr, &owatch->rules, rlist) {
+		list_for_each_entry_mutable(r, &owatch->rules, rlist) {
 
 			oentry = container_of(r, struct audit_entry, rule);
 			list_del(&oentry->rule.rlist);
@@ -322,13 +322,13 @@ static void audit_update_watch(struct audit_parent *parent,
 /* Remove all watches & rules associated with a parent that is going away. */
 static void audit_remove_parent_watches(struct audit_parent *parent)
 {
-	struct audit_watch *w, *nextw;
-	struct audit_krule *r, *nextr;
+	struct audit_watch *w;
+	struct audit_krule *r;
 	struct audit_entry *e;
 
 	mutex_lock(&audit_filter_mutex);
-	list_for_each_entry_safe(w, nextw, &parent->watches, wlist) {
-		list_for_each_entry_safe(r, nextr, &w->rules, rlist) {
+	list_for_each_entry_mutable(w, &parent->watches, wlist) {
+		list_for_each_entry_mutable(r, &w->rules, rlist) {
 			e = container_of(r, struct audit_entry, rule);
 			audit_watch_log_rule_change(r, w, "remove_rule");
 			if (e->rule.exe)
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 4401119b5275..6a4936870903 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -1445,14 +1445,14 @@ static int update_lsm_rule(struct audit_krule *r)
  * updated rule. */
 int audit_update_lsm_rules(void)
 {
-	struct audit_krule *r, *n;
+	struct audit_krule *r;
 	int i, err = 0;
 
 	/* audit_filter_mutex synchronizes the writers */
 	mutex_lock(&audit_filter_mutex);
 
 	for (i = 0; i < AUDIT_NR_FILTERS; i++) {
-		list_for_each_entry_safe(r, n, &audit_rules_list[i], list) {
+		list_for_each_entry_mutable(r, &audit_rules_list[i], list) {
 			int res = update_lsm_rule(r);
 			if (!err)
 				err = res;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 6610e667c728..df9c6c9e9e49 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -929,9 +929,9 @@ static inline void audit_free_module(struct audit_context *context)
 }
 static inline void audit_free_names(struct audit_context *context)
 {
-	struct audit_names *n, *next;
+	struct audit_names *n;
 
-	list_for_each_entry_safe(n, next, &context->names_list, list) {
+	list_for_each_entry_mutable(n, &context->names_list, list) {
 		list_del(&n->list);
 		if (n->name)
 			putname(n->name);
diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c
index 80b7b8a69446..597c3cd428eb 100644
--- a/kernel/bpf/arena.c
+++ b/kernel/bpf/arena.c
@@ -842,7 +842,7 @@ static void arena_free_pages(struct bpf_arena *arena, long uaddr, long page_cnt,
 	long kaddr, pgoff;
 	struct page *page;
 	struct llist_head free_pages;
-	struct llist_node *pos, *t;
+	struct llist_node *pos;
 	struct arena_free_span *s;
 	struct clear_range_data cdata;
 	unsigned long flags;
@@ -889,7 +889,7 @@ static void arena_free_pages(struct bpf_arena *arena, long uaddr, long page_cnt,
 		/* bulk zap if multiple pages being freed */
 		zap_pages(arena, full_uaddr, page_cnt);
 
-	llist_for_each_safe(pos, t, __llist_del_all(&free_pages)) {
+	llist_for_each_mutable(pos, __llist_del_all(&free_pages)) {
 		page = llist_entry(pos, struct page, pcp_llist);
 		if (page_cnt == 1 && page_ref_count(page) > 1) /* maybe mapped by user space */
 			/* Optimization for the common case of page_cnt==1:
@@ -963,7 +963,7 @@ static void arena_free_worker(struct work_struct *work)
 {
 	struct bpf_arena *arena = container_of(work, struct bpf_arena, free_work);
 	struct mem_cgroup *new_memcg, *old_memcg;
-	struct llist_node *list, *pos, *t;
+	struct llist_node *list, *pos;
 	struct arena_free_span *s;
 	u64 arena_vm_start, user_vm_start;
 	struct llist_head free_pages;
@@ -1002,7 +1002,7 @@ static void arena_free_worker(struct work_struct *work)
 	raw_res_spin_unlock_irqrestore(&arena->spinlock, flags);
 
 	/* Iterate the list again without holding spinlock to do the tlb flush and zap_pages */
-	llist_for_each_safe(pos, t, list) {
+	llist_for_each_mutable(pos, list) {
 		s = llist_entry(pos, struct arena_free_span, node);
 		page_cnt = s->page_cnt;
 		full_uaddr = clear_lo32(user_vm_start) + s->uaddr;
@@ -1018,7 +1018,7 @@ static void arena_free_worker(struct work_struct *work)
 	}
 
 	/* free all pages collected by apply_to_existing_page_range() in the first loop */
-	llist_for_each_safe(pos, t, __llist_del_all(&free_pages)) {
+	llist_for_each_mutable(pos, __llist_del_all(&free_pages)) {
 		page = llist_entry(pos, struct page, pcp_llist);
 		__free_page(page);
 	}
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index 248b4818178c..1150179a90f7 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -1083,12 +1083,12 @@ static int prog_array_map_poke_track(struct bpf_map *map,
 static void prog_array_map_poke_untrack(struct bpf_map *map,
 					struct bpf_prog_aux *prog_aux)
 {
-	struct prog_poke_elem *elem, *tmp;
+	struct prog_poke_elem *elem;
 	struct bpf_array_aux *aux;
 
 	aux = container_of(map, struct bpf_array, map)->aux;
 	mutex_lock(&aux->poke_mutex);
-	list_for_each_entry_safe(elem, tmp, &aux->poke_progs, list) {
+	list_for_each_entry_mutable(elem, &aux->poke_progs, list) {
 		if (elem->aux == prog_aux) {
 			list_del_init(&elem->list);
 			kfree(elem);
@@ -1196,11 +1196,11 @@ static struct bpf_map *prog_array_map_alloc(union bpf_attr *attr)
 
 static void prog_array_map_free(struct bpf_map *map)
 {
-	struct prog_poke_elem *elem, *tmp;
+	struct prog_poke_elem *elem;
 	struct bpf_array_aux *aux;
 
 	aux = container_of(map, struct bpf_array, map)->aux;
-	list_for_each_entry_safe(elem, tmp, &aux->poke_progs, list) {
+	list_for_each_entry_mutable(elem, &aux->poke_progs, list) {
 		list_del_init(&elem->list);
 		kfree(elem);
 	}
diff --git a/kernel/bpf/bpf_local_storage.c b/kernel/bpf/bpf_local_storage.c
index 6fc6a4b672b5..5f01ba032b12 100644
--- a/kernel/bpf/bpf_local_storage.c
+++ b/kernel/bpf/bpf_local_storage.c
@@ -161,14 +161,13 @@ void bpf_selem_free(struct bpf_local_storage_elem *selem,
 static void bpf_selem_free_list(struct hlist_head *list, bool reuse_now)
 {
 	struct bpf_local_storage_elem *selem;
-	struct hlist_node *n;
 
 	/* The "_safe" iteration is needed.
 	 * The loop is not removing the selem from the list
 	 * but bpf_selem_free will use the selem->rcu_head
 	 * which is union-ized with the selem->free_node.
 	 */
-	hlist_for_each_entry_safe(selem, n, list, free_node)
+	hlist_for_each_entry_mutable(selem, list, free_node)
 		bpf_selem_free(selem, reuse_now);
 }
 
diff --git a/kernel/bpf/bpf_lru_list.c b/kernel/bpf/bpf_lru_list.c
index 5ed7cb4b98c0..4b7306ade684 100644
--- a/kernel/bpf/bpf_lru_list.c
+++ b/kernel/bpf/bpf_lru_list.c
@@ -126,11 +126,11 @@ static void __bpf_lru_list_rotate_active(struct bpf_lru *lru,
 					 struct bpf_lru_list *l)
 {
 	struct list_head *active = &l->lists[BPF_LRU_LIST_T_ACTIVE];
-	struct bpf_lru_node *node, *tmp_node, *first_node;
+	struct bpf_lru_node *node, *first_node;
 	unsigned int i = 0;
 
 	first_node = list_first_entry(active, struct bpf_lru_node, list);
-	list_for_each_entry_safe_reverse(node, tmp_node, active, list) {
+	list_for_each_entry_mutable_reverse(node, active, list) {
 		if (bpf_lru_node_is_ref(node))
 			__bpf_lru_node_move(l, node, BPF_LRU_LIST_T_ACTIVE);
 		else
@@ -196,11 +196,11 @@ __bpf_lru_list_shrink_inactive(struct bpf_lru *lru,
 			       enum bpf_lru_list_type tgt_free_type)
 {
 	struct list_head *inactive = &l->lists[BPF_LRU_LIST_T_INACTIVE];
-	struct bpf_lru_node *node, *tmp_node;
+	struct bpf_lru_node *node;
 	unsigned int nshrinked = 0;
 	unsigned int i = 0;
 
-	list_for_each_entry_safe_reverse(node, tmp_node, inactive, list) {
+	list_for_each_entry_mutable_reverse(node, inactive, list) {
 		if (bpf_lru_node_is_ref(node) &&
 		    !READ_ONCE(node->pending_free)) {
 			__bpf_lru_node_move(l, node, BPF_LRU_LIST_T_ACTIVE);
@@ -247,7 +247,7 @@ static unsigned int __bpf_lru_list_shrink(struct bpf_lru *lru,
 					  enum bpf_lru_list_type tgt_free_type)
 
 {
-	struct bpf_lru_node *node, *tmp_node;
+	struct bpf_lru_node *node;
 	struct list_head *force_shrink_list;
 	unsigned int nshrinked;
 
@@ -262,8 +262,7 @@ static unsigned int __bpf_lru_list_shrink(struct bpf_lru *lru,
 	else
 		force_shrink_list = &l->lists[BPF_LRU_LIST_T_ACTIVE];
 
-	list_for_each_entry_safe_reverse(node, tmp_node, force_shrink_list,
-					 list) {
+	list_for_each_entry_mutable_reverse(node, force_shrink_list, list) {
 		if (READ_ONCE(node->pending_free) ||
 		    lru->del_from_htab(lru->del_arg, node)) {
 			__bpf_lru_node_move_to_free(l, node, free_list,
@@ -279,10 +278,9 @@ static unsigned int __bpf_lru_list_shrink(struct bpf_lru *lru,
 static void __local_list_flush(struct bpf_lru_list *l,
 			       struct bpf_lru_locallist *loc_l)
 {
-	struct bpf_lru_node *node, *tmp_node;
+	struct bpf_lru_node *node;
 
-	list_for_each_entry_safe_reverse(node, tmp_node,
-					 &loc_l->pending_list, list) {
+	list_for_each_entry_mutable_reverse(node, &loc_l->pending_list, list) {
 		if (READ_ONCE(node->pending_free))
 			__bpf_lru_node_move_in(l, node, BPF_LRU_LIST_T_FREE);
 		else if (bpf_lru_node_is_ref(node))
@@ -313,7 +311,7 @@ static void bpf_lru_list_pop_free_to_local(struct bpf_lru *lru,
 					   struct bpf_lru_locallist *loc_l)
 {
 	struct bpf_lru_list *l = &lru->common_lru.lru_list;
-	struct bpf_lru_node *node, *tmp_node;
+	struct bpf_lru_node *node;
 	unsigned int nfree = 0;
 	LIST_HEAD(tmp_free);
 
@@ -324,8 +322,7 @@ static void bpf_lru_list_pop_free_to_local(struct bpf_lru *lru,
 
 	__bpf_lru_list_rotate(lru, l);
 
-	list_for_each_entry_safe(node, tmp_node, &l->lists[BPF_LRU_LIST_T_FREE],
-				 list) {
+	list_for_each_entry_mutable(node, &l->lists[BPF_LRU_LIST_T_FREE], list) {
 		__bpf_lru_node_move_to_free(l, node, &tmp_free,
 					    BPF_LRU_LOCAL_LIST_T_FREE);
 		if (++nfree == lru->target_free)
@@ -343,7 +340,7 @@ static void bpf_lru_list_pop_free_to_local(struct bpf_lru *lru,
 	 * Transfer the harvested nodes from the temporary list_head into
 	 * the lockless per-CPU free llist.
 	 */
-	list_for_each_entry_safe(node, tmp_node, &tmp_free, list) {
+	list_for_each_entry_mutable(node, &tmp_free, list) {
 		list_del(&node->list);
 		llist_add(&node->llist, &loc_l->free_llist);
 	}
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 15ae7c43f594..983928bd774b 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -8439,7 +8439,7 @@ static void purge_cand_cache(struct btf *btf);
 static int btf_module_notify(struct notifier_block *nb, unsigned long op,
 			     void *module)
 {
-	struct btf_module *btf_mod, *tmp;
+	struct btf_module *btf_mod;
 	struct module *mod = module;
 	struct btf *btf;
 	int err = 0;
@@ -8512,7 +8512,7 @@ static int btf_module_notify(struct notifier_block *nb, unsigned long op,
 		break;
 	case MODULE_STATE_LIVE:
 		mutex_lock(&btf_module_mutex);
-		list_for_each_entry_safe(btf_mod, tmp, &btf_modules, list) {
+		list_for_each_entry_mutable(btf_mod, &btf_modules, list) {
 			if (btf_mod->module != module)
 				continue;
 
@@ -8523,7 +8523,7 @@ static int btf_module_notify(struct notifier_block *nb, unsigned long op,
 		break;
 	case MODULE_STATE_GOING:
 		mutex_lock(&btf_module_mutex);
-		list_for_each_entry_safe(btf_mod, tmp, &btf_modules, list) {
+		list_for_each_entry_mutable(btf_mod, &btf_modules, list) {
 			if (btf_mod->module != module)
 				continue;
 
@@ -8567,10 +8567,10 @@ struct module *btf_try_get_module(const struct btf *btf)
 {
 	struct module *res = NULL;
 #ifdef CONFIG_DEBUG_INFO_BTF_MODULES
-	struct btf_module *btf_mod, *tmp;
+	struct btf_module *btf_mod;
 
 	mutex_lock(&btf_module_mutex);
-	list_for_each_entry_safe(btf_mod, tmp, &btf_modules, list) {
+	list_for_each_entry_mutable(btf_mod, &btf_modules, list) {
 		if (btf_mod->btf != btf)
 			continue;
 
@@ -8596,7 +8596,7 @@ struct module *btf_try_get_module(const struct btf *btf)
 static struct btf *btf_get_module_btf(const struct module *module)
 {
 #ifdef CONFIG_DEBUG_INFO_BTF_MODULES
-	struct btf_module *btf_mod, *tmp;
+	struct btf_module *btf_mod;
 #endif
 	struct btf *btf = NULL;
 
@@ -8609,7 +8609,7 @@ static struct btf *btf_get_module_btf(const struct module *module)
 
 #ifdef CONFIG_DEBUG_INFO_BTF_MODULES
 	mutex_lock(&btf_module_mutex);
-	list_for_each_entry_safe(btf_mod, tmp, &btf_modules, list) {
+	list_for_each_entry_mutable(btf_mod, &btf_modules, list) {
 		if (btf_mod->module != module)
 			continue;
 
@@ -8773,7 +8773,7 @@ static int btf_check_iter_kfuncs(struct btf *btf, const char *func_name,
 static int btf_check_kfunc_name(struct btf *btf, const char *func_name, u32 kind)
 {
 #ifdef CONFIG_DEBUG_INFO_BTF_MODULES
-	struct btf_module *btf_mod, *tmp;
+	struct btf_module *btf_mod;
 #endif
 	s32 id;
 
@@ -8789,7 +8789,7 @@ static int btf_check_kfunc_name(struct btf *btf, const char *func_name, u32 kind
 
 #ifdef CONFIG_DEBUG_INFO_BTF_MODULES
 	guard(mutex)(&btf_module_mutex);
-	list_for_each_entry_safe(btf_mod, tmp, &btf_modules, list) {
+	list_for_each_entry_mutable(btf_mod, &btf_modules, list) {
 		if (btf_mod->btf == btf)
 			continue;
 		id = btf_find_by_name_kind(btf_mod->btf, func_name, kind);
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
index 83ce66296ac1..a3bd18ab9246 100644
--- a/kernel/bpf/cgroup.c
+++ b/kernel/bpf/cgroup.c
@@ -328,7 +328,7 @@ static void cgroup_bpf_release(struct work_struct *work)
 					       bpf.release_work);
 	struct bpf_prog_array *old_array;
 	struct list_head *storages = &cgrp->bpf.storages;
-	struct bpf_cgroup_storage *storage, *stmp;
+	struct bpf_cgroup_storage *storage;
 
 	unsigned int atype;
 
@@ -337,9 +337,8 @@ static void cgroup_bpf_release(struct work_struct *work)
 	for (atype = 0; atype < ARRAY_SIZE(cgrp->bpf.progs); atype++) {
 		struct hlist_head *progs = &cgrp->bpf.progs[atype];
 		struct bpf_prog_list *pl;
-		struct hlist_node *pltmp;
 
-		hlist_for_each_entry_safe(pl, pltmp, progs, node) {
+		hlist_for_each_entry_mutable(pl, progs, node) {
 			hlist_del(&pl->node);
 			if (pl->prog) {
 				if (pl->prog->expected_attach_type == BPF_LSM_CGROUP)
@@ -360,7 +359,7 @@ static void cgroup_bpf_release(struct work_struct *work)
 		bpf_prog_array_free(old_array);
 	}
 
-	list_for_each_entry_safe(storage, stmp, storages, list_cg) {
+	list_for_each_entry_mutable(storage, storages, list_cg) {
 		bpf_cgroup_storage_unlink(storage);
 		bpf_cgroup_storage_free(storage);
 	}
diff --git a/kernel/bpf/cpumap.c b/kernel/bpf/cpumap.c
index 5e59ab896f05..fa3a1b3559e2 100644
--- a/kernel/bpf/cpumap.c
+++ b/kernel/bpf/cpumap.c
@@ -821,9 +821,9 @@ int cpu_map_generic_redirect(struct bpf_cpu_map_entry *rcpu,
 
 void __cpu_map_flush(struct list_head *flush_list)
 {
-	struct xdp_bulk_queue *bq, *tmp;
+	struct xdp_bulk_queue *bq;
 
-	list_for_each_entry_safe(bq, tmp, flush_list, flush_node) {
+	list_for_each_entry_mutable(bq, flush_list, flush_node) {
 		local_lock_nested_bh(&bq->obj->bulkq->bq_lock);
 		bq_flush_to_queue(bq);
 		local_unlock_nested_bh(&bq->obj->bulkq->bq_lock);
diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
index dc7b859e8bbf..d85e4f955061 100644
--- a/kernel/bpf/devmap.c
+++ b/kernel/bpf/devmap.c
@@ -219,11 +219,10 @@ static void dev_map_free(struct bpf_map *map)
 		for (i = 0; i < dtab->n_buckets; i++) {
 			struct bpf_dtab_netdev *dev;
 			struct hlist_head *head;
-			struct hlist_node *next;
 
 			head = dev_map_index_hash(dtab, i);
 
-			hlist_for_each_entry_safe(dev, next, head, index_hlist) {
+			hlist_for_each_entry_mutable(dev, head, index_hlist) {
 				hlist_del_rcu(&dev->index_hlist);
 				if (dev->xdp_prog)
 					bpf_prog_put(dev->xdp_prog);
@@ -426,9 +425,9 @@ static void bq_xmit_all(struct xdp_dev_bulk_queue *bq, u32 flags)
  */
 void __dev_flush(struct list_head *flush_list)
 {
-	struct xdp_dev_bulk_queue *bq, *tmp;
+	struct xdp_dev_bulk_queue *bq;
 
-	list_for_each_entry_safe(bq, tmp, flush_list, flush_node) {
+	list_for_each_entry_mutable(bq, flush_list, flush_node) {
 		local_lock_nested_bh(&bq->dev->xdp_bulkq->bq_lock);
 		bq_xmit_all(bq, XDP_XMIT_FLUSH);
 		bq->dev_rx = NULL;
@@ -1124,11 +1123,10 @@ static void dev_map_hash_remove_netdev(struct bpf_dtab *dtab,
 	for (i = 0; i < dtab->n_buckets; i++) {
 		struct bpf_dtab_netdev *dev;
 		struct hlist_head *head;
-		struct hlist_node *next;
 
 		head = dev_map_index_hash(dtab, i);
 
-		hlist_for_each_entry_safe(dev, next, head, index_hlist) {
+		hlist_for_each_entry_mutable(dev, head, index_hlist) {
 			if (netdev != dev->dev)
 				continue;
 
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index c18f1e16edee..cfaf97dd970a 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -1662,7 +1662,7 @@ static void bpf_async_process_op(struct bpf_async_cb *cb, u32 op,
 static void bpf_async_irq_worker(struct irq_work *work)
 {
 	struct bpf_async_cb *cb = container_of(work, struct bpf_async_cb, worker);
-	struct llist_node *pos, *n, *list;
+	struct llist_node *pos, *list;
 
 	list = llist_del_all(&cb->async_cmds);
 	if (!list)
@@ -1670,7 +1670,7 @@ static void bpf_async_irq_worker(struct irq_work *work)
 
 	list = llist_reverse_order(list);
 	this_cpu_write(async_cb_running, cb);
-	llist_for_each_safe(pos, n, list) {
+	llist_for_each_mutable(pos, list) {
 		struct bpf_async_cmd *cmd;
 
 		cmd = container_of(pos, struct bpf_async_cmd, node);
@@ -2247,7 +2247,7 @@ EXPORT_SYMBOL_GPL(bpf_base_func_proto);
 void bpf_list_head_free(const struct btf_field *field, void *list_head,
 			struct bpf_spin_lock *spin_lock)
 {
-	struct list_head *head = list_head, drain, *pos, *n;
+	struct list_head *head = list_head, drain, *pos;
 
 	BUILD_BUG_ON(sizeof(struct list_head) > sizeof(struct bpf_list_head));
 	BUILD_BUG_ON(__alignof__(struct list_head) > __alignof__(struct bpf_list_head));
@@ -2262,7 +2262,7 @@ void bpf_list_head_free(const struct btf_field *field, void *list_head,
 	__bpf_spin_lock_irqsave(spin_lock);
 	if (!head->next || list_empty(head))
 		goto unlock;
-	list_for_each_safe(pos, n, head) {
+	list_for_each_mutable(pos, head) {
 		struct bpf_list_node_kern *node;
 
 		node = container_of(pos, struct bpf_list_node_kern, list_head);
diff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c
index 23267213a17f..2595c5a4d171 100644
--- a/kernel/bpf/local_storage.c
+++ b/kernel/bpf/local_storage.c
@@ -342,11 +342,11 @@ static void cgroup_storage_map_free(struct bpf_map *_map)
 {
 	struct bpf_cgroup_storage_map *map = map_to_storage(_map);
 	struct list_head *storages = &map->list;
-	struct bpf_cgroup_storage *storage, *stmp;
+	struct bpf_cgroup_storage *storage;
 
 	cgroup_lock();
 
-	list_for_each_entry_safe(storage, stmp, storages, list_map) {
+	list_for_each_entry_mutable(storage, storages, list_map) {
 		bpf_cgroup_storage_unlink(storage);
 		bpf_cgroup_storage_free(storage);
 	}
diff --git a/kernel/bpf/memalloc.c b/kernel/bpf/memalloc.c
index e9662db7198f..09adb1d0e101 100644
--- a/kernel/bpf/memalloc.c
+++ b/kernel/bpf/memalloc.c
@@ -264,10 +264,10 @@ static void free_one(void *obj, bool percpu)
 
 static int free_all(struct bpf_mem_cache *c, struct llist_node *llnode, bool percpu)
 {
-	struct llist_node *pos, *t;
+	struct llist_node *pos;
 	int cnt = 0;
 
-	llist_for_each_safe(pos, t, llnode) {
+	llist_for_each_mutable(pos, llnode) {
 		if (c->dtor)
 			c->dtor((void *)pos + LLIST_NODE_SZ, c->dtor_ctx);
 		free_one(pos, percpu);
@@ -296,7 +296,7 @@ static void enque_to_free(struct bpf_mem_cache *c, void *obj)
 
 static void do_call_rcu_ttrace(struct bpf_mem_cache *c)
 {
-	struct llist_node *llnode, *t;
+	struct llist_node *llnode;
 
 	if (atomic_xchg(&c->call_rcu_ttrace_in_progress, 1)) {
 		if (unlikely(READ_ONCE(c->draining))) {
@@ -307,7 +307,7 @@ static void do_call_rcu_ttrace(struct bpf_mem_cache *c)
 	}
 
 	WARN_ON_ONCE(!llist_empty(&c->waiting_for_gp_ttrace));
-	llist_for_each_safe(llnode, t, llist_del_all(&c->free_by_rcu_ttrace))
+	llist_for_each_mutable(llnode, llist_del_all(&c->free_by_rcu_ttrace))
 		llist_add(llnode, &c->waiting_for_gp_ttrace);
 
 	if (unlikely(READ_ONCE(c->draining))) {
@@ -326,7 +326,7 @@ static void do_call_rcu_ttrace(struct bpf_mem_cache *c)
 static void free_bulk(struct bpf_mem_cache *c)
 {
 	struct bpf_mem_cache *tgt = c->tgt;
-	struct llist_node *llnode, *t;
+	struct llist_node *llnode;
 	unsigned long flags;
 	int cnt;
 
@@ -346,7 +346,7 @@ static void free_bulk(struct bpf_mem_cache *c)
 	} while (cnt > (c->high_watermark + c->low_watermark) / 2);
 
 	/* and drain free_llist_extra */
-	llist_for_each_safe(llnode, t, llist_del_all(&c->free_llist_extra))
+	llist_for_each_mutable(llnode, llist_del_all(&c->free_llist_extra))
 		enque_to_free(tgt, llnode);
 	do_call_rcu_ttrace(tgt);
 }
@@ -374,13 +374,13 @@ static void __free_by_rcu(struct rcu_head *head)
 
 static void check_free_by_rcu(struct bpf_mem_cache *c)
 {
-	struct llist_node *llnode, *t;
+	struct llist_node *llnode;
 	unsigned long flags;
 
 	/* drain free_llist_extra_rcu */
 	if (unlikely(!llist_empty(&c->free_llist_extra_rcu))) {
 		inc_active(c, &flags);
-		llist_for_each_safe(llnode, t, llist_del_all(&c->free_llist_extra_rcu))
+		llist_for_each_mutable(llnode, llist_del_all(&c->free_llist_extra_rcu))
 			if (__llist_add(llnode, &c->free_by_rcu))
 				c->free_by_rcu_tail = llnode;
 		dec_active(c, &flags);
diff --git a/kernel/bpf/offload.c b/kernel/bpf/offload.c
index 0d6f5569588c..32a21613fe79 100644
--- a/kernel/bpf/offload.c
+++ b/kernel/bpf/offload.c
@@ -137,8 +137,8 @@ static void __bpf_offload_dev_netdev_unregister(struct bpf_offload_dev *offdev,
 						struct net_device *netdev)
 {
 	struct bpf_offload_netdev *ondev, *altdev = NULL;
-	struct bpf_offloaded_map *offmap, *mtmp;
-	struct bpf_prog_offload *offload, *ptmp;
+	struct bpf_offloaded_map *offmap;
+	struct bpf_prog_offload *offload;
 
 	ASSERT_RTNL();
 
@@ -165,9 +165,9 @@ static void __bpf_offload_dev_netdev_unregister(struct bpf_offload_dev *offdev,
 			offmap->netdev = altdev->netdev;
 		list_splice_init(&ondev->maps, &altdev->maps);
 	} else {
-		list_for_each_entry_safe(offload, ptmp, &ondev->progs, offloads)
+		list_for_each_entry_mutable(offload, &ondev->progs, offloads)
 			__bpf_prog_offload_destroy(offload->prog);
-		list_for_each_entry_safe(offmap, mtmp, &ondev->maps, offloads)
+		list_for_each_entry_mutable(offmap, &ondev->maps, offloads)
 			__bpf_map_offload_destroy(offmap);
 	}
 
diff --git a/kernel/bpf/states.c b/kernel/bpf/states.c
index 32f346ce3ffc..ec7942049c06 100644
--- a/kernel/bpf/states.c
+++ b/kernel/bpf/states.c
@@ -1241,7 +1241,7 @@ int bpf_is_state_visited(struct bpf_verifier_env *env, int insn_idx)
 	struct bpf_verifier_state *cur = env->cur_state, *new;
 	bool force_new_state, add_new_state, loop;
 	int n, err, states_cnt = 0;
-	struct list_head *pos, *tmp, *head;
+	struct list_head *pos, *head;
 
 	force_new_state = env->test_state_freq || bpf_is_force_checkpoint(env, insn_idx) ||
 			  /* Avoid accumulating infinitely long jmp history */
@@ -1267,7 +1267,7 @@ int bpf_is_state_visited(struct bpf_verifier_env *env, int insn_idx)
 
 	loop = false;
 	head = bpf_explored_state(env, insn_idx);
-	list_for_each_safe(pos, tmp, head) {
+	list_for_each_mutable(pos, head) {
 		sl = container_of(pos, struct bpf_verifier_state_list, node);
 		states_cnt++;
 		if (sl->state.insn_idx != insn_idx)
diff --git a/kernel/bpf/stream.c b/kernel/bpf/stream.c
index be9ce98e9469..3d722cfd1d07 100644
--- a/kernel/bpf/stream.c
+++ b/kernel/bpf/stream.c
@@ -96,9 +96,9 @@ static void bpf_stream_free_elem(struct bpf_stream_elem *elem)
 
 static void bpf_stream_free_list(struct llist_node *list)
 {
-	struct bpf_stream_elem *elem, *tmp;
+	struct bpf_stream_elem *elem;
 
-	llist_for_each_entry_safe(elem, tmp, list, node)
+	llist_for_each_entry_mutable(elem, list, node)
 		bpf_stream_free_elem(elem);
 }
 
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 2abc79dbf281..7cd5d10b390a 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -18285,7 +18285,7 @@ static void sanitize_dead_code(struct bpf_verifier_env *env)
 static void free_states(struct bpf_verifier_env *env)
 {
 	struct bpf_verifier_state_list *sl;
-	struct list_head *head, *pos, *tmp;
+	struct list_head *head, *pos;
 	struct bpf_scc_info *info;
 	int i, j;
 
@@ -18293,7 +18293,7 @@ static void free_states(struct bpf_verifier_env *env)
 	env->cur_state = NULL;
 	while (!pop_stack(env, NULL, NULL, false));
 
-	list_for_each_safe(pos, tmp, &env->free_list) {
+	list_for_each_mutable(pos, &env->free_list) {
 		sl = container_of(pos, struct bpf_verifier_state_list, node);
 		bpf_free_verifier_state(&sl->state, false);
 		kfree(sl);
@@ -18316,7 +18316,7 @@ static void free_states(struct bpf_verifier_env *env)
 	for (i = 0; i < state_htab_size(env); i++) {
 		head = &env->explored_states[i];
 
-		list_for_each_safe(pos, tmp, head) {
+		list_for_each_mutable(pos, head) {
 			sl = container_of(pos, struct bpf_verifier_state_list, node);
 			bpf_free_verifier_state(&sl->state, false);
 			kfree(sl);
diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c
index a4337c9b5287..1c777b28861f 100644
--- a/kernel/cgroup/cgroup-v1.c
+++ b/kernel/cgroup/cgroup-v1.c
@@ -205,10 +205,10 @@ struct cgroup_pidlist {
  */
 void cgroup1_pidlist_destroy_all(struct cgroup *cgrp)
 {
-	struct cgroup_pidlist *l, *tmp_l;
+	struct cgroup_pidlist *l;
 
 	mutex_lock(&cgrp->pidlist_mutex);
-	list_for_each_entry_safe(l, tmp_l, &cgrp->pidlists, links)
+	list_for_each_entry_mutable(l, &cgrp->pidlists, links)
 		mod_delayed_work(cgroup_pidlist_destroy_wq, &l->destroy_dwork, 0);
 	mutex_unlock(&cgrp->pidlist_mutex);
 
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 38f8d9df8fbc..2b619c1553ee 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -872,9 +872,9 @@ static void css_set_update_populated(struct css_set *cset, bool populated)
 static void css_set_skip_task_iters(struct css_set *cset,
 				    struct task_struct *task)
 {
-	struct css_task_iter *it, *pos;
+	struct css_task_iter *it;
 
-	list_for_each_entry_safe(it, pos, &cset->task_iters, iters_node)
+	list_for_each_entry_mutable(it, &cset->task_iters, iters_node)
 		css_task_iter_skip(it, task);
 }
 
@@ -951,7 +951,7 @@ static unsigned long css_set_hash(struct cgroup_subsys_state **css)
 
 void put_css_set_locked(struct css_set *cset)
 {
-	struct cgrp_cset_link *link, *tmp_link;
+	struct cgrp_cset_link *link;
 	struct cgroup_subsys *ss;
 	int ssid;
 
@@ -970,7 +970,7 @@ void put_css_set_locked(struct css_set *cset)
 	hash_del(&cset->hlist);
 	css_set_count--;
 
-	list_for_each_entry_safe(link, tmp_link, &cset->cgrp_links, cgrp_link) {
+	list_for_each_entry_mutable(link, &cset->cgrp_links, cgrp_link) {
 		list_del(&link->cset_link);
 		list_del(&link->cgrp_link);
 		if (cgroup_parent(link->cgrp))
@@ -1129,9 +1129,9 @@ static struct css_set *find_existing_css_set(struct css_set *old_cset,
 
 static void free_cgrp_cset_links(struct list_head *links_to_free)
 {
-	struct cgrp_cset_link *link, *tmp_link;
+	struct cgrp_cset_link *link;
 
-	list_for_each_entry_safe(link, tmp_link, links_to_free, cset_link) {
+	list_for_each_entry_mutable(link, links_to_free, cset_link) {
 		list_del(&link->cset_link);
 		kfree(link);
 	}
@@ -1372,7 +1372,7 @@ void cgroup_free_root(struct cgroup_root *root)
 static void cgroup_destroy_root(struct cgroup_root *root)
 {
 	struct cgroup *cgrp = &root->cgrp;
-	struct cgrp_cset_link *link, *tmp_link;
+	struct cgrp_cset_link *link;
 	int ret;
 
 	trace_cgroup_destroy_root(root);
@@ -1395,7 +1395,7 @@ static void cgroup_destroy_root(struct cgroup_root *root)
 	 */
 	spin_lock_irq(&css_set_lock);
 
-	list_for_each_entry_safe(link, tmp_link, &cgrp->cset_links, cset_link) {
+	list_for_each_entry_mutable(link, &cgrp->cset_links, cset_link) {
 		list_del(&link->cset_link);
 		list_del(&link->cgrp_link);
 		kfree(link);
@@ -1887,7 +1887,7 @@ int rebind_subsystems(struct cgroup_root *dst_root, u32 ss_mask)
 		struct cgroup_root *src_root = ss->root;
 		struct cgroup *scgrp = &src_root->cgrp;
 		struct cgroup_subsys_state *css = cgroup_css(scgrp, ss);
-		struct css_set *cset, *cset_pos;
+		struct css_set *cset;
 		struct css_task_iter *it;
 
 		WARN_ON(!css || cgroup_css(dcgrp, ss));
@@ -1912,8 +1912,8 @@ int rebind_subsystems(struct cgroup_root *dst_root, u32 ss_mask)
 		spin_lock_irq(&css_set_lock);
 		css->cgroup = dcgrp;
 		WARN_ON(!list_empty(&dcgrp->e_csets[ss->id]));
-		list_for_each_entry_safe(cset, cset_pos, &scgrp->e_csets[ss->id],
-					 e_cset_node[ss->id]) {
+		list_for_each_entry_mutable(cset, &scgrp->e_csets[ss->id],
+					    e_cset_node[ss->id]) {
 			list_move_tail(&cset->e_cset_node[ss->id],
 				       &dcgrp->e_csets[ss->id]);
 			/*
@@ -2689,8 +2689,8 @@ static int cgroup_migrate_execute(struct cgroup_mgctx *mgctx)
 {
 	struct cgroup_taskset *tset = &mgctx->tset;
 	struct cgroup_subsys *ss;
-	struct task_struct *task, *tmp_task;
-	struct css_set *cset, *tmp_cset;
+	struct task_struct *task;
+	struct css_set *cset;
 	int ssid, failed_ssid, ret;
 
 	/* check that we can legitimately attach to the cgroup */
@@ -2714,7 +2714,7 @@ static int cgroup_migrate_execute(struct cgroup_mgctx *mgctx)
 	 */
 	spin_lock_irq(&css_set_lock);
 	list_for_each_entry(cset, &tset->src_csets, mg_node) {
-		list_for_each_entry_safe(task, tmp_task, &cset->mg_tasks, cg_list) {
+		list_for_each_entry_mutable(task, &cset->mg_tasks, cg_list) {
 			struct css_set *from_cset = task_css_set(task);
 			struct css_set *to_cset = cset->mg_dst_cset;
 
@@ -2767,7 +2767,7 @@ static int cgroup_migrate_execute(struct cgroup_mgctx *mgctx)
 out_release_tset:
 	spin_lock_irq(&css_set_lock);
 	list_splice_init(&tset->dst_csets, &tset->src_csets);
-	list_for_each_entry_safe(cset, tmp_cset, &tset->src_csets, mg_node) {
+	list_for_each_entry_mutable(cset, &tset->src_csets, mg_node) {
 		list_splice_tail_init(&cset->mg_tasks, &cset->tasks);
 		list_del_init(&cset->mg_node);
 	}
@@ -2825,14 +2825,14 @@ int cgroup_migrate_vet_dst(struct cgroup *dst_cgrp)
  */
 void cgroup_migrate_finish(struct cgroup_mgctx *mgctx)
 {
-	struct css_set *cset, *tmp_cset;
+	struct css_set *cset;
 
 	lockdep_assert_held(&cgroup_mutex);
 
 	spin_lock_irq(&css_set_lock);
 
-	list_for_each_entry_safe(cset, tmp_cset, &mgctx->preloaded_src_csets,
-				 mg_src_preload_node) {
+	list_for_each_entry_mutable(cset, &mgctx->preloaded_src_csets,
+				    mg_src_preload_node) {
 		cset->mg_src_cgrp = NULL;
 		cset->mg_dst_cgrp = NULL;
 		cset->mg_dst_cset = NULL;
@@ -2840,8 +2840,8 @@ void cgroup_migrate_finish(struct cgroup_mgctx *mgctx)
 		put_css_set_locked(cset);
 	}
 
-	list_for_each_entry_safe(cset, tmp_cset, &mgctx->preloaded_dst_csets,
-				 mg_dst_preload_node) {
+	list_for_each_entry_mutable(cset, &mgctx->preloaded_dst_csets,
+				    mg_dst_preload_node) {
 		cset->mg_src_cgrp = NULL;
 		cset->mg_dst_cgrp = NULL;
 		cset->mg_dst_cset = NULL;
@@ -2917,13 +2917,13 @@ void cgroup_migrate_add_src(struct css_set *src_cset,
  */
 int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx)
 {
-	struct css_set *src_cset, *tmp_cset;
+	struct css_set *src_cset;
 
 	lockdep_assert_held(&cgroup_mutex);
 
 	/* look up the dst cset for each src cset and link it to src */
-	list_for_each_entry_safe(src_cset, tmp_cset, &mgctx->preloaded_src_csets,
-				 mg_src_preload_node) {
+	list_for_each_entry_mutable(src_cset, &mgctx->preloaded_src_csets,
+				    mg_src_preload_node) {
 		struct css_set *dst_cset;
 		struct cgroup_subsys *ss;
 		int ssid;
@@ -3225,10 +3225,10 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp)
 	spin_lock_irq(&css_set_lock);
 	list_for_each_entry(src_cset, &mgctx.preloaded_src_csets,
 			    mg_src_preload_node) {
-		struct task_struct *task, *ntask;
+		struct task_struct *task;
 
 		/* all tasks in src_csets need to be migrated */
-		list_for_each_entry_safe(task, ntask, &src_cset->tasks, cg_list)
+		list_for_each_entry_mutable(task, &src_cset->tasks, cg_list)
 			cgroup_migrate_add_task(task, &mgctx);
 	}
 	spin_unlock_irq(&css_set_lock);
@@ -7106,10 +7106,10 @@ static DEFINE_PER_CPU(struct irq_work, cgrp_dead_tasks_iwork);
 static void cgrp_dead_tasks_iwork_fn(struct irq_work *iwork)
 {
 	struct llist_node *lnode;
-	struct task_struct *task, *next;
+	struct task_struct *task;
 
 	lnode = llist_del_all(this_cpu_ptr(&cgrp_dead_tasks));
-	llist_for_each_entry_safe(task, next, lnode, cg_dead_lnode) {
+	llist_for_each_entry_mutable(task, lnode, cg_dead_lnode) {
 		do_cgroup_task_dead(task);
 		put_task_struct(task);
 	}
diff --git a/kernel/cgroup/dmem.c b/kernel/cgroup/dmem.c
index 4753a67d0f0f..1daa8fb49fbe 100644
--- a/kernel/cgroup/dmem.c
+++ b/kernel/cgroup/dmem.c
@@ -203,10 +203,10 @@ static void dmemcs_offline(struct cgroup_subsys_state *css)
 static void dmemcs_free(struct cgroup_subsys_state *css)
 {
 	struct dmemcg_state *dmemcs = css_to_dmemcs(css);
-	struct dmem_cgroup_pool_state *pool, *next;
+	struct dmem_cgroup_pool_state *pool;
 
 	spin_lock(&dmemcg_lock);
-	list_for_each_entry_safe(pool, next, &dmemcs->pools, css_node) {
+	list_for_each_entry_mutable(pool, &dmemcs->pools, css_node) {
 		/*
 		 *The pool is dead and all references are 0,
 		 * no need for RCU protection with list_del_rcu or freeing.
@@ -444,9 +444,9 @@ get_cg_pool_locked(struct dmemcg_state *dmemcs, struct dmem_cgroup_region *regio
 static void dmemcg_free_rcu(struct rcu_head *rcu)
 {
 	struct dmem_cgroup_region *region = container_of(rcu, typeof(*region), rcu);
-	struct dmem_cgroup_pool_state *pool, *next;
+	struct dmem_cgroup_pool_state *pool;
 
-	list_for_each_entry_safe(pool, next, &region->pools, region_node)
+	list_for_each_entry_mutable(pool, &region->pools, region_node)
 		free_cg_pool(pool);
 	kfree(region->name);
 	kfree(region);
@@ -467,7 +467,7 @@ static void dmemcg_free_region(struct kref *ref)
  */
 void dmem_cgroup_unregister_region(struct dmem_cgroup_region *region)
 {
-	struct dmem_cgroup_pool_state *pool, *next;
+	struct dmem_cgroup_pool_state *pool;
 
 	if (!region)
 		return;
@@ -477,7 +477,7 @@ void dmem_cgroup_unregister_region(struct dmem_cgroup_region *region)
 	/* Remove from global region list */
 	list_del_rcu(&region->region_node);
 
-	list_for_each_entry_safe(pool, next, &region->pools, region_node) {
+	list_for_each_entry_mutable(pool, &region->pools, region_node) {
 		list_del_rcu(&pool->css_node);
 		list_del(&pool->region_node);
 		dmemcg_pool_put(pool);
diff --git a/kernel/cgroup/rdma.c b/kernel/cgroup/rdma.c
index 5e82a03b3270..5527375c16e1 100644
--- a/kernel/cgroup/rdma.c
+++ b/kernel/cgroup/rdma.c
@@ -444,7 +444,7 @@ EXPORT_SYMBOL(rdmacg_register_device);
  */
 void rdmacg_unregister_device(struct rdmacg_device *device)
 {
-	struct rdmacg_resource_pool *rpool, *tmp;
+	struct rdmacg_resource_pool *rpool;
 
 	/*
 	 * Synchronize with any active resource settings,
@@ -457,7 +457,7 @@ void rdmacg_unregister_device(struct rdmacg_device *device)
 	 * Now that this device is off the cgroup list, its safe to free
 	 * all the rpool resources.
 	 */
-	list_for_each_entry_safe(rpool, tmp, &device->rpools, dev_node)
+	list_for_each_entry_mutable(rpool, &device->rpools, dev_node)
 		free_cg_rpool_locked(rpool);
 
 	mutex_unlock(&rdmacg_mutex);
@@ -747,11 +747,11 @@ rdmacg_css_alloc(struct cgroup_subsys_state *parent)
 static void rdmacg_css_free(struct cgroup_subsys_state *css)
 {
 	struct rdma_cgroup *cg = css_rdmacg(css);
-	struct rdmacg_resource_pool *rpool, *tmp;
+	struct rdmacg_resource_pool *rpool;
 
 	/* Clean up rpools kept alive by non-zero peak values */
 	mutex_lock(&rdmacg_mutex);
-	list_for_each_entry_safe(rpool, tmp, &cg->rpools, cg_node)
+	list_for_each_entry_mutable(rpool, &cg->rpools, cg_node)
 		free_cg_rpool_locked(rpool);
 	mutex_unlock(&rdmacg_mutex);
 
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 00e6dcb931d9..dd93436f8f2d 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -2346,7 +2346,7 @@ static inline struct list_head *get_event_list(struct perf_event *event)
 static void perf_group_detach(struct perf_event *event)
 {
 	struct perf_event *leader = event->group_leader;
-	struct perf_event *sibling, *tmp;
+	struct perf_event *sibling;
 	struct perf_event_context *ctx = event->ctx;
 
 	lockdep_assert_held(&ctx->lock);
@@ -2376,7 +2376,7 @@ static void perf_group_detach(struct perf_event *event)
 	 * upgrade the siblings to singleton events by adding them
 	 * to whatever list we are on.
 	 */
-	list_for_each_entry_safe(sibling, tmp, &event->sibling_list, sibling_list) {
+	list_for_each_entry_mutable(sibling, &event->sibling_list, sibling_list) {
 
 		/*
 		 * Events that have PERF_EV_CAP_SIBLING require being part of
@@ -2405,8 +2405,8 @@ static void perf_group_detach(struct perf_event *event)
 	}
 
 out:
-	for_each_sibling_event(tmp, leader)
-		perf_event__header_size(tmp);
+	for_each_sibling_event(sibling, leader)
+		perf_event__header_size(sibling);
 
 	perf_event__header_size(leader);
 }
@@ -3528,7 +3528,7 @@ static void __pmu_ctx_sched_out(struct perf_event_pmu_context *pmu_ctx,
 				enum event_type_t event_type)
 {
 	struct perf_event_context *ctx = pmu_ctx->ctx;
-	struct perf_event *event, *tmp;
+	struct perf_event *event;
 	struct pmu *pmu = pmu_ctx->pmu;
 
 	if (ctx->task && !(ctx->is_active & EVENT_ALL)) {
@@ -3543,16 +3543,14 @@ static void __pmu_ctx_sched_out(struct perf_event_pmu_context *pmu_ctx,
 
 	perf_pmu_disable(pmu);
 	if (event_type & EVENT_PINNED) {
-		list_for_each_entry_safe(event, tmp,
-					 &pmu_ctx->pinned_active,
-					 active_list)
+		list_for_each_entry_mutable(event, &pmu_ctx->pinned_active,
+					    active_list)
 			group_sched_out(event, ctx);
 	}
 
 	if (event_type & EVENT_FLEXIBLE) {
-		list_for_each_entry_safe(event, tmp,
-					 &pmu_ctx->flexible_active,
-					 active_list)
+		list_for_each_entry_mutable(event, &pmu_ctx->flexible_active,
+					    active_list)
 			group_sched_out(event, ctx);
 		/*
 		 * Since we cleared EVENT_FLEXIBLE, also clear
@@ -4738,7 +4736,7 @@ static void perf_event_exit_event(struct perf_event *event,
 static void perf_event_remove_on_exec(struct perf_event_context *ctx)
 {
 	struct perf_event_context *clone_ctx = NULL;
-	struct perf_event *event, *next;
+	struct perf_event *event;
 	unsigned long flags;
 	bool modified = false;
 
@@ -4747,7 +4745,7 @@ static void perf_event_remove_on_exec(struct perf_event_context *ctx)
 	if (WARN_ON_ONCE(ctx->task != current))
 		goto unlock;
 
-	list_for_each_entry_safe(event, next, &ctx->event_list, event_entry) {
+	list_for_each_entry_mutable(event, &ctx->event_list, event_entry) {
 		if (!event->attr.remove_on_exec)
 			continue;
 
@@ -11833,9 +11831,9 @@ perf_addr_filter_new(struct perf_event *event, struct list_head *filters)
 
 static void free_filters_list(struct list_head *filters)
 {
-	struct perf_addr_filter *filter, *iter;
+	struct perf_addr_filter *filter;
 
-	list_for_each_entry_safe(filter, iter, filters, entry) {
+	list_for_each_entry_mutable(filter, filters, entry) {
 		path_put(&filter->path);
 		list_del(&filter->entry);
 		kfree(filter);
@@ -14436,7 +14434,7 @@ static void __perf_pmu_install_event(struct pmu *pmu,
 static void __perf_pmu_install(struct perf_event_context *ctx,
 			       int cpu, struct pmu *pmu, struct list_head *events)
 {
-	struct perf_event *event, *tmp;
+	struct perf_event *event;
 
 	/*
 	 * Re-instate events in 2 passes.
@@ -14446,7 +14444,7 @@ static void __perf_pmu_install(struct perf_event_context *ctx,
 	 * leader will enable its siblings, even if those are still on the old
 	 * context.
 	 */
-	list_for_each_entry_safe(event, tmp, events, migrate_entry) {
+	list_for_each_entry_mutable(event, events, migrate_entry) {
 		if (event->group_leader == event)
 			continue;
 
@@ -14458,7 +14456,7 @@ static void __perf_pmu_install(struct perf_event_context *ctx,
 	 * Once all the siblings are setup properly, install the group leaders
 	 * to make it go.
 	 */
-	list_for_each_entry_safe(event, tmp, events, migrate_entry) {
+	list_for_each_entry_mutable(event, events, migrate_entry) {
 		list_del(&event->migrate_entry);
 		__perf_pmu_install_event(pmu, ctx, cpu, event);
 	}
@@ -14592,7 +14590,7 @@ perf_event_exit_event(struct perf_event *event,
 static void perf_event_exit_task_context(struct task_struct *task, bool exit)
 {
 	struct perf_event_context *ctx, *clone_ctx = NULL;
-	struct perf_event *child_event, *next;
+	struct perf_event *child_event;
 
 	ctx = perf_pin_task_context(task);
 	if (!ctx)
@@ -14642,7 +14640,7 @@ static void perf_event_exit_task_context(struct task_struct *task, bool exit)
 	if (exit)
 		perf_event_task(task, ctx, 0);
 
-	list_for_each_entry_safe(child_event, next, &ctx->event_list, event_entry)
+	list_for_each_entry_mutable(child_event, &ctx->event_list, event_entry)
 		perf_event_exit_event(child_event, ctx, exit ? task : NULL, false);
 
 	mutex_unlock(&ctx->mutex);
@@ -14675,13 +14673,13 @@ static void perf_event_exit_task_context(struct task_struct *task, bool exit)
  */
 void perf_event_exit_task(struct task_struct *task)
 {
-	struct perf_event *event, *tmp;
+	struct perf_event *event;
 
 	WARN_ON_ONCE(task != current);
 
 	mutex_lock(&task->perf_event_mutex);
-	list_for_each_entry_safe(event, tmp, &task->perf_event_list,
-				 owner_entry) {
+	list_for_each_entry_mutable(event, &task->perf_event_list,
+				    owner_entry) {
 		list_del_init(&event->owner_entry);
 
 		/*
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 4084e926e284..61aa48e3b5a6 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -258,13 +258,13 @@ static void delayed_uprobe_delete(struct delayed_uprobe *du)
 
 static void delayed_uprobe_remove(struct uprobe *uprobe, struct mm_struct *mm)
 {
-	struct list_head *pos, *q;
+	struct list_head *pos;
 	struct delayed_uprobe *du;
 
 	if (!uprobe && !mm)
 		return;
 
-	list_for_each_safe(pos, q, &delayed_uprobe_list) {
+	list_for_each_mutable(pos, &delayed_uprobe_list) {
 		du = list_entry(pos, struct delayed_uprobe, list);
 
 		if (uprobe && du->uprobe != uprobe)
@@ -1562,13 +1562,13 @@ static void build_probe_list(struct inode *inode,
 /* @vma contains reference counter, not the probed instruction. */
 static int delayed_ref_ctr_inc(struct vm_area_struct *vma)
 {
-	struct list_head *pos, *q;
+	struct list_head *pos;
 	struct delayed_uprobe *du;
 	unsigned long vaddr;
 	int ret = 0, err = 0;
 
 	mutex_lock(&delayed_uprobe_lock);
-	list_for_each_safe(pos, q, &delayed_uprobe_list) {
+	list_for_each_mutable(pos, &delayed_uprobe_list) {
 		du = list_entry(pos, struct delayed_uprobe, list);
 
 		if (du->mm != vma->vm_mm ||
@@ -1597,7 +1597,7 @@ static int delayed_ref_ctr_inc(struct vm_area_struct *vma)
 int uprobe_mmap(struct vm_area_struct *vma)
 {
 	struct list_head tmp_list;
-	struct uprobe *uprobe, *u;
+	struct uprobe *uprobe;
 	struct inode *inode;
 
 	if (no_uprobe_events())
@@ -1622,7 +1622,7 @@ int uprobe_mmap(struct vm_area_struct *vma)
 	 * removed. But in this case filter_chain() must return false, all
 	 * consumers have gone away.
 	 */
-	list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) {
+	list_for_each_entry_mutable(uprobe, &tmp_list, pending_list) {
 		if (!fatal_signal_pending(current) &&
 		    filter_chain(uprobe, vma->vm_mm)) {
 			unsigned long vaddr = offset_to_vaddr(vma, uprobe->offset);
diff --git a/kernel/exit.c b/kernel/exit.c
index 1056422bc101..62ef6553253a 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -630,7 +630,7 @@ static struct task_struct *find_child_reaper(struct task_struct *father,
 {
 	struct pid_namespace *pid_ns = task_active_pid_ns(father);
 	struct task_struct *reaper = pid_ns->child_reaper;
-	struct task_struct *p, *n;
+	struct task_struct *p;
 
 	if (likely(reaper != father))
 		return reaper;
@@ -644,7 +644,7 @@ static struct task_struct *find_child_reaper(struct task_struct *father,
 
 	write_unlock_irq(&tasklist_lock);
 
-	list_for_each_entry_safe(p, n, dead, ptrace_entry) {
+	list_for_each_entry_mutable(p, dead, ptrace_entry) {
 		list_del_init(&p->ptrace_entry);
 		release_task(p);
 	}
@@ -766,7 +766,7 @@ static void forget_original_parent(struct task_struct *father,
 static void exit_notify(struct task_struct *tsk, int group_dead)
 {
 	bool autoreap;
-	struct task_struct *p, *n;
+	struct task_struct *p;
 	LIST_HEAD(dead);
 
 	write_lock_irq(&tasklist_lock);
@@ -800,7 +800,7 @@ static void exit_notify(struct task_struct *tsk, int group_dead)
 		wake_up_process(tsk->signal->group_exec_task);
 	write_unlock_irq(&tasklist_lock);
 
-	list_for_each_entry_safe(p, n, &dead, ptrace_entry) {
+	list_for_each_entry_mutable(p, &dead, ptrace_entry) {
 		list_del_init(&p->ptrace_entry);
 		release_task(p);
 	}
diff --git a/kernel/fail_function.c b/kernel/fail_function.c
index 2eaf55005f49..357c810c4908 100644
--- a/kernel/fail_function.c
+++ b/kernel/fail_function.c
@@ -226,9 +226,9 @@ static void fei_attr_remove(struct fei_attr *attr)
 
 static void fei_attr_remove_all(void)
 {
-	struct fei_attr *attr, *n;
+	struct fei_attr *attr;
 
-	list_for_each_entry_safe(attr, n, &fei_attr_list, list) {
+	list_for_each_entry_mutable(attr, &fei_attr_list, list) {
 		fei_attr_remove(attr);
 	}
 }
diff --git a/kernel/gcov/clang.c b/kernel/gcov/clang.c
index fd98ced0e51d..e9a86a04d793 100644
--- a/kernel/gcov/clang.c
+++ b/kernel/gcov/clang.c
@@ -347,9 +347,9 @@ struct gcov_info *gcov_info_dup(struct gcov_info *info)
  */
 void gcov_info_free(struct gcov_info *info)
 {
-	struct gcov_fn_info *fn, *tmp;
+	struct gcov_fn_info *fn;
 
-	list_for_each_entry_safe(fn, tmp, &info->functions, head) {
+	list_for_each_entry_mutable(fn, &info->functions, head) {
 		kvfree(fn->counters);
 		list_del(&fn->head);
 		kfree(fn);
diff --git a/kernel/irq_work.c b/kernel/irq_work.c
index f7e2dc2c30c6..ce454e12cd86 100644
--- a/kernel/irq_work.c
+++ b/kernel/irq_work.c
@@ -234,7 +234,7 @@ void irq_work_single(void *arg)
 
 static void irq_work_run_list(struct llist_head *list)
 {
-	struct irq_work *work, *tmp;
+	struct irq_work *work;
 	struct llist_node *llnode;
 
 	/*
@@ -248,7 +248,7 @@ static void irq_work_run_list(struct llist_head *list)
 		return;
 
 	llnode = llist_del_all(list);
-	llist_for_each_entry_safe(work, tmp, llnode, node.llist)
+	llist_for_each_entry_mutable(work, llnode, node.llist)
 		irq_work_single(work);
 }
 
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index dc770b9a6d05..d50d15d4709f 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -318,9 +318,9 @@ static void kimage_free_pages(struct page *page)
 
 void kimage_free_page_list(struct list_head *list)
 {
-	struct page *page, *next;
+	struct page *page;
 
-	list_for_each_entry_safe(page, next, list, lru) {
+	list_for_each_entry_mutable(page, list, lru) {
 		list_del(&page->lru);
 		kimage_free_pages(page);
 	}
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index bfc89083daa9..8e8fd6833d1c 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -228,12 +228,12 @@ static bool collect_one_slot(struct kprobe_insn_page *kip, int idx)
 
 static int collect_garbage_slots(struct kprobe_insn_cache *c)
 {
-	struct kprobe_insn_page *kip, *next;
+	struct kprobe_insn_page *kip;
 
 	/* Ensure no-one is interrupted on the garbages */
 	synchronize_rcu();
 
-	list_for_each_entry_safe(kip, next, &c->pages, list) {
+	list_for_each_entry_mutable(kip, &c->pages, list) {
 		int i;
 
 		if (kip->ngarbage == 0)
@@ -563,7 +563,7 @@ static void do_optimize_kprobes(void)
  */
 static void do_unoptimize_kprobes(void)
 {
-	struct optimized_kprobe *op, *tmp;
+	struct optimized_kprobe *op;
 
 	lockdep_assert_held(&text_mutex);
 	/* See comment in do_optimize_kprobes() */
@@ -573,7 +573,7 @@ static void do_unoptimize_kprobes(void)
 		arch_unoptimize_kprobes(&unoptimizing_list, &freeing_list);
 
 	/* Loop on 'freeing_list' for disarming and removing from kprobe hash list */
-	list_for_each_entry_safe(op, tmp, &freeing_list, list) {
+	list_for_each_entry_mutable(op, &freeing_list, list) {
 		/* Switching from detour code to origin */
 		op->kp.flags &= ~KPROBE_FLAG_OPTIMIZED;
 		/* Disarm probes if marked disabled and not gone */
@@ -594,9 +594,9 @@ static void do_unoptimize_kprobes(void)
 /* Reclaim all kprobes on the 'freeing_list' */
 static void do_free_cleaned_kprobes(void)
 {
-	struct optimized_kprobe *op, *tmp;
+	struct optimized_kprobe *op;
 
-	list_for_each_entry_safe(op, tmp, &freeing_list, list) {
+	list_for_each_entry_mutable(op, &freeing_list, list) {
 		list_del_init(&op->list);
 		if (WARN_ON_ONCE(!kprobe_unused(&op->kp))) {
 			/*
@@ -2598,9 +2598,9 @@ static int __init populate_kprobe_blacklist(unsigned long *start,
 /* Remove all symbols in given area from kprobe blacklist */
 static void kprobe_remove_area_blacklist(unsigned long start, unsigned long end)
 {
-	struct kprobe_blacklist_entry *ent, *n;
+	struct kprobe_blacklist_entry *ent;
 
-	list_for_each_entry_safe(ent, n, &kprobe_blacklist, list) {
+	list_for_each_entry_mutable(ent, &kprobe_blacklist, list) {
 		if (ent->start_addr < start || ent->start_addr >= end)
 			continue;
 		list_del(&ent->list);
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 28d15ba58a26..6e433519bfff 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -788,9 +788,9 @@ void klp_free_patch_async(struct klp_patch *patch)
 
 void klp_free_replaced_patches_async(struct klp_patch *new_patch)
 {
-	struct klp_patch *old_patch, *tmp_patch;
+	struct klp_patch *old_patch;
 
-	klp_for_each_patch_safe(old_patch, tmp_patch) {
+	klp_for_each_patch_safe(old_patch) {
 		if (old_patch == new_patch)
 			return;
 		klp_free_patch_async(old_patch);
diff --git a/kernel/livepatch/core.h b/kernel/livepatch/core.h
index 38209c7361b6..274c8108062f 100644
--- a/kernel/livepatch/core.h
+++ b/kernel/livepatch/core.h
@@ -7,8 +7,8 @@
 extern struct mutex klp_mutex;
 extern struct list_head klp_patches;
 
-#define klp_for_each_patch_safe(patch, tmp_patch)		\
-	list_for_each_entry_safe(patch, tmp_patch, &klp_patches, list)
+#define klp_for_each_patch_safe(patch)		\
+	list_for_each_entry_mutable(patch, &klp_patches, list)
 
 #define klp_for_each_patch(patch)	\
 	list_for_each_entry(patch, &klp_patches, list)
diff --git a/kernel/liveupdate/kho_block.c b/kernel/liveupdate/kho_block.c
index 0d2a342ef422..40e42a47751c 100644
--- a/kernel/liveupdate/kho_block.c
+++ b/kernel/liveupdate/kho_block.c
@@ -298,9 +298,9 @@ int kho_block_set_restore(struct kho_block_set *bs, u64 head_pa)
  */
 void kho_block_set_destroy(struct kho_block_set *bs)
 {
-	struct kho_block *block, *tmp;
+	struct kho_block *block;
 
-	list_for_each_entry_safe(block, tmp, &bs->blocks, list) {
+	list_for_each_entry_mutable(block, &bs->blocks, list) {
 		list_del(&block->list);
 		kho_block_free_ser(bs, block->ser);
 		kfree(block);
diff --git a/kernel/liveupdate/luo_flb.c b/kernel/liveupdate/luo_flb.c
index 5c27134ce7ba..cf5d577e25e4 100644
--- a/kernel/liveupdate/luo_flb.c
+++ b/kernel/liveupdate/luo_flb.c
@@ -359,13 +359,13 @@ static void luo_flb_unregister_one(struct liveupdate_file_handler *fh,
 void luo_flb_unregister_all(struct liveupdate_file_handler *fh)
 {
 	struct list_head *flb_list = &ACCESS_PRIVATE(fh, flb_list);
-	struct luo_flb_link *iter, *tmp;
+	struct luo_flb_link *iter;
 
 	if (!liveupdate_enabled())
 		return;
 
 	lockdep_assert_held_write(&luo_register_rwlock);
-	list_for_each_entry_safe(iter, tmp, flb_list, list)
+	list_for_each_entry_mutable(iter, flb_list, list)
 		luo_flb_unregister_one(fh, iter->flb);
 }
 
diff --git a/kernel/locking/rwsem.c b/kernel/locking/rwsem.c
index b9c180ac1eee..8db6caf31e41 100644
--- a/kernel/locking/rwsem.c
+++ b/kernel/locking/rwsem.c
@@ -567,7 +567,7 @@ static void rwsem_mark_wake(struct rw_semaphore *sem,
 		atomic_long_add(adjustment, &sem->count);
 
 	/* 2nd pass */
-	list_for_each_entry_safe(waiter, next, &wlist, list) {
+	list_for_each_entry_mutable(waiter, &wlist, list) {
 		struct task_struct *tsk;
 
 		tsk = waiter->task;
diff --git a/kernel/locking/test-ww_mutex.c b/kernel/locking/test-ww_mutex.c
index 838d631544ed..f290061a8b48 100644
--- a/kernel/locking/test-ww_mutex.c
+++ b/kernel/locking/test-ww_mutex.c
@@ -546,7 +546,7 @@ static void stress_reorder_work(struct work_struct *work)
 	} while (!time_after(jiffies, stress->timeout));
 
 out:
-	list_for_each_entry_safe(ll, ln, &locks, link)
+	list_for_each_entry_mutable(ll, &locks, link)
 		kfree(ll);
 	kfree(order);
 }
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 46dd8d25a605..471448804053 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -725,10 +725,10 @@ static int ref_module(struct module *a, struct module *b)
 /* Clear the unload stuff of the module. */
 static void module_unload_free(struct module *mod)
 {
-	struct module_use *use, *tmp;
+	struct module_use *use;
 
 	mutex_lock(&module_mutex);
-	list_for_each_entry_safe(use, tmp, &mod->target_list, target_list) {
+	list_for_each_entry_mutable(use, &mod->target_list, target_list) {
 		struct module *i = use->target;
 		pr_debug("%s unusing %s\n", mod->name, i->name);
 		module_put(i);
@@ -3041,14 +3041,14 @@ struct mod_initfree {
 
 static void do_free_init(struct work_struct *w)
 {
-	struct llist_node *pos, *n, *list;
+	struct llist_node *pos, *list;
 	struct mod_initfree *initfree;
 
 	list = llist_del_all(&init_free_list);
 
 	synchronize_rcu();
 
-	llist_for_each_safe(pos, n, list) {
+	llist_for_each_mutable(pos, list) {
 		initfree = container_of(pos, struct mod_initfree, node);
 		execmem_free(initfree->init_text);
 		execmem_free(initfree->init_data);
@@ -3701,11 +3701,10 @@ static int idempotent_complete(struct idempotent *u, int ret)
 	const void *cookie = u->cookie;
 	int hash = hash_ptr(cookie, IDEM_HASH_BITS);
 	struct hlist_head *head = idem_hash + hash;
-	struct hlist_node *next;
 	struct idempotent *pos;
 
 	spin_lock(&idem_lock);
-	hlist_for_each_entry_safe(pos, next, head, entry) {
+	hlist_for_each_entry_mutable(pos, head, entry) {
 		if (pos->cookie != cookie)
 			continue;
 		hlist_del_init(&pos->entry);
diff --git a/kernel/padata.c b/kernel/padata.c
index 0d3ea1b68b1f..270f7b0eca0a 100644
--- a/kernel/padata.c
+++ b/kernel/padata.c
@@ -134,13 +134,13 @@ static void padata_work_free(struct padata_work *pw)
 
 static void __init padata_works_free(struct list_head *works)
 {
-	struct padata_work *cur, *next;
+	struct padata_work *cur;
 
 	if (list_empty(works))
 		return;
 
 	spin_lock_bh(&padata_works_lock);
-	list_for_each_entry_safe(cur, next, works, pw_list) {
+	list_for_each_entry_mutable(cur, works, pw_list) {
 		list_del(&cur->pw_list);
 		padata_work_free(cur);
 	}
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index d933b5b2c05d..c4802f2a2e35 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -610,9 +610,9 @@ struct mem_extent {
  */
 static void free_mem_extents(struct list_head *list)
 {
-	struct mem_extent *ext, *aux;
+	struct mem_extent *ext;
 
-	list_for_each_entry_safe(ext, aux, list, hook) {
+	list_for_each_entry_mutable(ext, list, hook) {
 		list_del(&ext->hook);
 		kfree(ext);
 	}
@@ -633,7 +633,7 @@ static int create_mem_extents(struct list_head *list, gfp_t gfp_mask)
 
 	for_each_populated_zone(zone) {
 		unsigned long zone_start, zone_end;
-		struct mem_extent *ext, *cur, *aux;
+		struct mem_extent *ext, *cur;
 
 		zone_start = zone->zone_start_pfn;
 		zone_end = zone_end_pfn(zone);
@@ -665,7 +665,7 @@ static int create_mem_extents(struct list_head *list, gfp_t gfp_mask)
 
 		/* More merging may be possible */
 		cur = ext;
-		list_for_each_entry_safe_continue(cur, aux, list, hook) {
+		list_for_each_entry_mutable_continue(cur, list, hook) {
 			if (zone_end < cur->start)
 				break;
 			if (zone_end < cur->end)
diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c
index fd763da06a87..c8718aacfa5a 100644
--- a/kernel/power/wakelock.c
+++ b/kernel/power/wakelock.c
@@ -102,13 +102,13 @@ static inline void wakelocks_lru_most_recent(struct wakelock *wl)
 
 static void __wakelocks_gc(struct work_struct *work)
 {
-	struct wakelock *wl, *aux;
+	struct wakelock *wl;
 	ktime_t now;
 
 	mutex_lock(&wakelocks_lock);
 
 	now = ktime_get();
-	list_for_each_entry_safe_reverse(wl, aux, &wakelocks_lru_list, lru) {
+	list_for_each_entry_mutable_reverse(wl, &wakelocks_lru_list, lru) {
 		u64 idle_time_ns;
 		bool active;
 
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 2fe9a963c823..3f524c6bdf6e 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3787,7 +3787,6 @@ static struct syscore printk_syscore = {
  */
 static void printk_kthreads_check_locked(void)
 {
-	struct hlist_node *tmp;
 	struct console *con;
 
 	lockdep_assert_console_list_lock_held();
@@ -3805,7 +3804,7 @@ static void printk_kthreads_check_locked(void)
 			 * are any nbcon consoles, they will set up their own
 			 * kthread.
 			 */
-			hlist_for_each_entry_safe(con, tmp, &console_list, node) {
+			hlist_for_each_entry_mutable(con, &console_list, node) {
 				if (con->flags & CON_NBCON)
 					continue;
 
@@ -3833,7 +3832,7 @@ static void printk_kthreads_check_locked(void)
 	if (printk_kthreads_running)
 		return;
 
-	hlist_for_each_entry_safe(con, tmp, &console_list, node) {
+	hlist_for_each_entry_mutable(con, &console_list, node) {
 		if (!(con->flags & CON_NBCON))
 			continue;
 
@@ -4209,9 +4208,8 @@ void register_console(struct console *newcon)
 	if (bootcon_registered &&
 	    ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV) &&
 	    !keep_bootcon) {
-		struct hlist_node *tmp;
 
-		hlist_for_each_entry_safe(con, tmp, &console_list, node) {
+		hlist_for_each_entry_mutable(con, &console_list, node) {
 			if (con->flags & CON_BOOT)
 				unregister_console_locked(con);
 		}
@@ -4426,12 +4424,11 @@ void __init console_init(void)
  */
 static int __init printk_late_init(void)
 {
-	struct hlist_node *tmp;
 	struct console *con;
 	int ret;
 
 	console_list_lock();
-	hlist_for_each_entry_safe(con, tmp, &console_list, node) {
+	hlist_for_each_entry_mutable(con, &console_list, node) {
 		if (!(con->flags & CON_BOOT))
 			continue;
 
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index d041645d9d17..8032b653af83 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -619,9 +619,9 @@ static int ptrace_detach(struct task_struct *child, unsigned int data)
  */
 void exit_ptrace(struct task_struct *tracer, struct list_head *dead)
 {
-	struct task_struct *p, *n;
+	struct task_struct *p;
 
-	list_for_each_entry_safe(p, n, &tracer->ptraced, ptrace_entry) {
+	list_for_each_entry_mutable(p, &tracer->ptraced, ptrace_entry) {
 		if (unlikely(p->ptrace & PT_EXITKILL))
 			send_sig_info(SIGKILL, SEND_SIG_PRIV, p);
 
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index 882a158ada7b..9eb0007411a9 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -537,11 +537,10 @@ static void
 rcu_torture_pipe_update(struct rcu_torture *old_rp)
 {
 	struct rcu_torture *rp;
-	struct rcu_torture *rp1;
 
 	if (old_rp)
 		list_add(&old_rp->rtort_free, &rcu_torture_removed);
-	list_for_each_entry_safe(rp, rp1, &rcu_torture_removed, rtort_free) {
+	list_for_each_entry_mutable(rp, &rcu_torture_removed, rtort_free) {
 		if (rcu_torture_pipe_update_one(rp)) {
 			list_del(&rp->rtort_free);
 			rcu_torture_free(rp);
diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h
index f4da5fad70f5..e79380d93c85 100644
--- a/kernel/rcu/tasks.h
+++ b/kernel/rcu/tasks.h
@@ -1052,12 +1052,11 @@ static void rcu_tasks_postscan(struct list_head *hop)
 	for_each_possible_cpu(cpu) {
 		unsigned long j = jiffies + 1;
 		struct rcu_tasks_percpu *rtpcp = per_cpu_ptr(rcu_tasks.rtpcpu, cpu);
-		struct task_struct *t;
-		struct task_struct *t1;
+		struct task_struct *t, *t1;
 		struct list_head tmp;
 
 		raw_spin_lock_irq_rcu_node(rtpcp);
-		list_for_each_entry_safe(t, t1, &rtpcp->rtp_exit_list, rcu_tasks_exit_list) {
+		list_for_each_entry_mutable(t, t1, &rtpcp->rtp_exit_list, rcu_tasks_exit_list) {
 			if (list_empty(&t->rcu_tasks_holdout_list))
 				rcu_tasks_pertask(t, hop);
 
@@ -1120,9 +1119,9 @@ static void check_holdout_task(struct task_struct *t,
 static void check_all_holdout_tasks(struct list_head *hop,
 				    bool needreport, bool *firstreport)
 {
-	struct task_struct *t, *t1;
+	struct task_struct *t;
 
-	list_for_each_entry_safe(t, t1, hop, rcu_tasks_holdout_list) {
+	list_for_each_entry_mutable(t, hop, rcu_tasks_holdout_list) {
 		check_holdout_task(t, needreport, firstreport);
 		cond_resched();
 	}
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index 03a43d3d2616..7c7792d62ac5 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -1664,7 +1664,7 @@ static void rcu_sr_normal_complete(struct llist_node *node)
 
 static void rcu_sr_normal_gp_cleanup_work(struct work_struct *work)
 {
-	struct llist_node *done, *rcu, *next, *head;
+	struct llist_node *done, *rcu, *head;
 
 	/*
 	 * This work execution can potentially execute
@@ -1694,7 +1694,7 @@ static void rcu_sr_normal_gp_cleanup_work(struct work_struct *work)
 	 * nodes is removed, in next round of cleanup
 	 * work execution.
 	 */
-	llist_for_each_safe(rcu, next, head) {
+	llist_for_each_mutable(rcu, head) {
 		if (!rcu_sr_is_wait_head(rcu)) {
 			rcu_sr_normal_complete(rcu);
 			continue;
@@ -1726,7 +1726,7 @@ static void rcu_sr_normal_gp_cleanup(void)
 	/*
 	 * Process (a) and (d) cases. See an illustration.
 	 */
-	llist_for_each_safe(rcu, next, wait_tail->next) {
+	llist_for_each_mutable(rcu, next, wait_tail->next) {
 		if (rcu_sr_is_wait_head(rcu))
 			break;
 
diff --git a/kernel/resource.c b/kernel/resource.c
index e60539a55541..19b89b09e291 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -1951,9 +1951,9 @@ EXPORT_SYMBOL(resource_list_create_entry);
 
 void resource_list_free(struct list_head *head)
 {
-	struct resource_entry *entry, *tmp;
+	struct resource_entry *entry;
 
-	list_for_each_entry_safe(entry, tmp, head, node)
+	list_for_each_entry_mutable(entry, head, node)
 		resource_list_destroy_entry(entry);
 }
 EXPORT_SYMBOL(resource_list_free);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index e97e98c33be5..873e26f2a032 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -3892,7 +3892,7 @@ void sched_ttwu_pending(void *arg)
 {
 	struct llist_node *llist = arg;
 	struct rq *rq = this_rq();
-	struct task_struct *p, *t;
+	struct task_struct *p;
 	struct rq_flags rf;
 
 	if (!llist)
@@ -3901,7 +3901,7 @@ void sched_ttwu_pending(void *arg)
 	rq_lock_irqsave(rq, &rf);
 	update_rq_clock(rq);
 
-	llist_for_each_entry_safe(p, t, llist, wake_entry.llist) {
+	llist_for_each_entry_mutable(p, llist, wake_entry.llist) {
 		if (WARN_ON_ONCE(p->on_cpu))
 			smp_cond_load_acquire(&p->on_cpu, !VAL);
 
diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 0db6fa2daea3..2119f2629fd1 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -4121,7 +4121,7 @@ static void process_ddsp_deferred_locals(struct rq *rq)
 	 * Now that @rq can be unlocked, execute the deferred enqueueing of
 	 * tasks directly dispatched to the local DSQs of other CPUs. See
 	 * direct_dispatch(). Keep popping from the head instead of using
-	 * list_for_each_entry_safe() as dispatch_local_dsq() may unlock @rq
+	 * list_for_each_entry_mutable() as dispatch_local_dsq() may unlock @rq
 	 * temporarily.
 	 */
 	while ((p = list_first_entry_or_null(&rq->scx.ddsp_deferred_locals,
@@ -4186,7 +4186,7 @@ static u32 reenq_local(struct scx_sched *sch, struct rq *rq, u64 reenq_flags)
 {
 	LIST_HEAD(tasks);
 	u32 nr_enqueued = 0;
-	struct task_struct *p, *n;
+	struct task_struct *p;
 
 	lockdep_assert_rq_held(rq);
 
@@ -4200,8 +4200,8 @@ static u32 reenq_local(struct scx_sched *sch, struct rq *rq, u64 reenq_flags)
 	 * @rq->scx.local_dsq. Move all candidate tasks off to a private list
 	 * first to avoid processing the same tasks repeatedly.
 	 */
-	list_for_each_entry_safe(p, n, &rq->scx.local_dsq.list,
-				 scx.dsq_list.node) {
+	list_for_each_entry_mutable(p, &rq->scx.local_dsq.list,
+				    scx.dsq_list.node) {
 		struct scx_sched *task_sch = scx_task_sched(p);
 		u32 reason;
 
@@ -4234,7 +4234,7 @@ static u32 reenq_local(struct scx_sched *sch, struct rq *rq, u64 reenq_flags)
 		list_add_tail(&p->scx.dsq_list.node, &tasks);
 	}
 
-	list_for_each_entry_safe(p, n, &tasks, scx.dsq_list.node) {
+	list_for_each_entry_mutable(p, &tasks, scx.dsq_list.node) {
 		list_del_init(&p->scx.dsq_list.node);
 
 		do_enqueue_task(rq, p, SCX_ENQ_REENQ, -1);
@@ -4786,9 +4786,9 @@ static void free_dsq_rcufn(struct rcu_head *rcu)
 static void free_dsq_irq_workfn(struct irq_work *irq_work)
 {
 	struct llist_node *to_free = llist_del_all(&dsqs_to_free);
-	struct scx_dispatch_q *dsq, *tmp_dsq;
+	struct scx_dispatch_q *dsq;
 
-	llist_for_each_entry_safe(dsq, tmp_dsq, to_free, free_node)
+	llist_for_each_entry_mutable(dsq, to_free, free_node)
 		call_rcu(&dsq->rcu, free_dsq_rcufn);
 }
 
@@ -5684,7 +5684,7 @@ static void scx_bypass(struct scx_sched *sch, bool bypass)
 	 */
 	for_each_possible_cpu(cpu) {
 		struct rq *rq = cpu_rq(cpu);
-		struct task_struct *p, *n;
+		struct task_struct *p;
 
 		raw_spin_rq_lock(rq);
 		raw_spin_lock(&scx_sched_lock);
@@ -5711,14 +5711,14 @@ static void scx_bypass(struct scx_sched *sch, bool bypass)
 		}
 
 		/*
-		 * The use of list_for_each_entry_safe_reverse() is required
+		 * The use of list_for_each_entry_mutable_reverse() is required
 		 * because each task is going to be removed from and added back
 		 * to the runnable_list during iteration. Because they're added
 		 * to the tail of the list, safe reverse iteration can still
 		 * visit all nodes.
 		 */
-		list_for_each_entry_safe_reverse(p, n, &rq->scx.runnable_list,
-						 scx.runnable_node) {
+		list_for_each_entry_mutable_reverse(p, &rq->scx.runnable_list,
+						    scx.runnable_node) {
 			if (!scx_is_descendant(scx_task_sched(p), sch))
 				continue;
 
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index d78467ec6ee1..0f21a168fd9a 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -408,9 +408,9 @@ static inline void assert_list_leaf_cfs_rq(struct rq *rq)
 }
 
 /* Iterate through all leaf cfs_rq's on a runqueue */
-#define for_each_leaf_cfs_rq_safe(rq, cfs_rq, pos)			\
-	list_for_each_entry_safe(cfs_rq, pos, &rq->leaf_cfs_rq_list,	\
-				 leaf_cfs_rq_list)
+#define for_each_leaf_cfs_rq_safe(rq, cfs_rq)			\
+	list_for_each_entry_mutable(cfs_rq, &(rq)->leaf_cfs_rq_list,	\
+				    leaf_cfs_rq_list)
 
 /* Do the two (enqueued) entities belong to the same group ? */
 static inline struct cfs_rq *
@@ -494,8 +494,8 @@ static inline void assert_list_leaf_cfs_rq(struct rq *rq)
 {
 }
 
-#define for_each_leaf_cfs_rq_safe(rq, cfs_rq, pos)	\
-		for (cfs_rq = &rq->cfs, pos = NULL; cfs_rq; cfs_rq = pos)
+#define for_each_leaf_cfs_rq_safe(rq, cfs_rq)	\
+		for (cfs_rq = &(rq)->cfs; cfs_rq; cfs_rq = NULL)
 
 static inline struct sched_entity *parent_entity(struct sched_entity *se)
 {
@@ -6724,7 +6724,7 @@ static int tg_unthrottle_up(struct task_group *tg, void *data)
 {
 	struct rq *rq = data;
 	struct cfs_rq *cfs_rq = tg_cfs_rq(tg, cpu_of(rq));
-	struct task_struct *p, *tmp;
+	struct task_struct *p;
 	LIST_HEAD(throttled_tasks);
 
 	/*
@@ -6765,7 +6765,7 @@ static int tg_unthrottle_up(struct task_group *tg, void *data)
 	list_splice_init(&cfs_rq->throttled_limbo_list, &throttled_tasks);
 
 	/* Re-enqueue the tasks that have been throttled at this level. */
-	list_for_each_entry_safe(p, tmp, &throttled_tasks, throttle_node) {
+	list_for_each_entry_mutable(p, &throttled_tasks, throttle_node) {
 		/*
 		 * Back to being throttled! Break out and put the remaining
 		 * tasks back onto the limbo_list to prevent running them
@@ -6966,7 +6966,7 @@ void unthrottle_cfs_rq(struct cfs_rq *cfs_rq)
 
 static void __cfsb_csd_unthrottle(void *arg)
 {
-	struct cfs_rq *cursor, *tmp;
+	struct cfs_rq *cursor;
 	struct rq *rq = arg;
 
 	guard(rq_lock)(rq);
@@ -6988,8 +6988,8 @@ static void __cfsb_csd_unthrottle(void *arg)
 	 */
 	guard(rcu)();
 
-	list_for_each_entry_safe(cursor, tmp, &rq->cfsb_csd_list,
-				 throttled_csd_list) {
+	list_for_each_entry_mutable(cursor, &rq->cfsb_csd_list,
+				    throttled_csd_list) {
 		list_del_init(&cursor->throttled_csd_list);
 
 		if (cfs_rq_throttled(cursor))
@@ -11118,14 +11118,14 @@ static bool __update_blocked_others(struct rq *rq, bool *done)
 
 static bool __update_blocked_fair(struct rq *rq, bool *done)
 {
-	struct cfs_rq *cfs_rq, *pos;
+	struct cfs_rq *cfs_rq;
 	bool decayed = false;
 
 	/*
 	 * Iterates the task_group tree in a bottom up fashion, see
 	 * list_add_leaf_cfs_rq() for details.
 	 */
-	for_each_leaf_cfs_rq_safe(rq, cfs_rq, pos) {
+	for_each_leaf_cfs_rq_safe(rq, cfs_rq) {
 		struct sched_entity *se;
 
 		if (update_cfs_rq_load_avg(cfs_rq_clock_pelt(cfs_rq), cfs_rq)) {
@@ -15401,10 +15401,10 @@ DEFINE_SCHED_CLASS(fair) = {
 
 void print_cfs_stats(struct seq_file *m, int cpu)
 {
-	struct cfs_rq *cfs_rq, *pos;
+	struct cfs_rq *cfs_rq;
 
 	rcu_read_lock();
-	for_each_leaf_cfs_rq_safe(cpu_rq(cpu), cfs_rq, pos)
+	for_each_leaf_cfs_rq_safe(cpu_rq(cpu), cfs_rq)
 		print_cfs_rq(m, cpu, cfs_rq);
 	rcu_read_unlock();
 }
diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c
index 622e2e01974c..062887738bff 100644
--- a/kernel/sched/topology.c
+++ b/kernel/sched/topology.c
@@ -1753,7 +1753,7 @@ static inline void asym_cpu_capacity_update_data(int cpu)
  */
 static void asym_cpu_capacity_scan(void)
 {
-	struct asym_cap_data *entry, *next;
+	struct asym_cap_data *entry;
 	int cpu;
 
 	list_for_each_entry(entry, &asym_cap_list, link)
@@ -1762,7 +1762,7 @@ static void asym_cpu_capacity_scan(void)
 	for_each_cpu_and(cpu, cpu_possible_mask, housekeeping_cpumask(HK_TYPE_DOMAIN))
 		asym_cpu_capacity_update_data(cpu);
 
-	list_for_each_entry_safe(entry, next, &asym_cap_list, link) {
+	list_for_each_entry_mutable(entry, &asym_cap_list, link) {
 		if (cpumask_empty(cpu_capacity_span(entry))) {
 			list_del_rcu(&entry->link);
 			call_rcu(&entry->rcu, free_asym_cap_entry);
diff --git a/kernel/sched/wait.c b/kernel/sched/wait.c
index 20f27e2cf7ae..3411f9ac2073 100644
--- a/kernel/sched/wait.c
+++ b/kernel/sched/wait.c
@@ -92,7 +92,7 @@ EXPORT_SYMBOL(remove_wait_queue);
 static int __wake_up_common(struct wait_queue_head *wq_head, unsigned int mode,
 			int nr_exclusive, int wake_flags, void *key)
 {
-	wait_queue_entry_t *curr, *next;
+	wait_queue_entry_t *curr;
 
 	lockdep_assert_held(&wq_head->lock);
 
@@ -101,7 +101,7 @@ static int __wake_up_common(struct wait_queue_head *wq_head, unsigned int mode,
 	if (&curr->entry == &wq_head->head)
 		return nr_exclusive;
 
-	list_for_each_entry_safe_from(curr, next, &wq_head->head, entry) {
+	list_for_each_entry_mutable_from(curr, &wq_head->head, entry) {
 		unsigned flags = curr->flags;
 		int ret;
 
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 066909393c38..7212e47703f9 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -1168,7 +1168,7 @@ static int seccomp_do_user_notification(int this_syscall,
 	u32 flags = 0;
 	long ret = 0;
 	struct seccomp_knotif n = {};
-	struct seccomp_kaddfd *addfd, *tmp;
+	struct seccomp_kaddfd *addfd;
 
 	mutex_lock(&match->notify_lock);
 	err = -ENOSYS;
@@ -1225,7 +1225,7 @@ static int seccomp_do_user_notification(int this_syscall,
 
 interrupted:
 	/* If there were any pending addfd calls, clear them out */
-	list_for_each_entry_safe(addfd, tmp, &n.addfd, list) {
+	list_for_each_entry_mutable(addfd, &n.addfd, list) {
 		/* The process went away before we got a chance to handle it */
 		addfd->ret = -ESRCH;
 		list_del_init(&addfd->list);
diff --git a/kernel/signal.c b/kernel/signal.c
index 9c2b32c4d755..072231bebf52 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -748,7 +748,7 @@ static void sigqueue_free_ignored(struct task_struct *tsk, struct sigqueue *q)
 /* Remove signals in mask from the pending set and queue. */
 static void flush_sigqueue_mask(struct task_struct *p, sigset_t *mask, struct sigpending *s)
 {
-	struct sigqueue *q, *n;
+	struct sigqueue *q;
 	sigset_t m;
 
 	lockdep_assert_held(&p->sighand->siglock);
@@ -758,7 +758,7 @@ static void flush_sigqueue_mask(struct task_struct *p, sigset_t *mask, struct si
 		return;
 
 	sigandnsets(&s->signal, &s->signal, mask);
-	list_for_each_entry_safe(q, n, &s->list, list) {
+	list_for_each_entry_mutable(q, &s->list, list) {
 		if (sigismember(mask, q->info.si_signo)) {
 			list_del_init(&q->list);
 			sigqueue_free_ignored(p, q);
@@ -1899,12 +1899,12 @@ EXPORT_SYMBOL(kill_pid);
 static void __flush_itimer_signals(struct sigpending *pending)
 {
 	sigset_t signal, retain;
-	struct sigqueue *q, *n;
+	struct sigqueue *q;
 
 	signal = pending->signal;
 	sigemptyset(&retain);
 
-	list_for_each_entry_safe(q, n, &pending->list, list) {
+	list_for_each_entry_mutable(q, &pending->list, list) {
 		int sig = q->info.si_signo;
 
 		if (likely(q->info.si_code != SI_TIMER)) {
@@ -2101,7 +2101,6 @@ static inline void posixtimer_sig_ignore(struct task_struct *tsk, struct sigqueu
 static void posixtimer_sig_unignore(struct task_struct *tsk, int sig)
 {
 	struct hlist_head *head = &tsk->signal->ignored_posix_timers;
-	struct hlist_node *tmp;
 	struct k_itimer *tmr;
 
 	if (likely(hlist_empty(head)))
@@ -2114,7 +2113,7 @@ static void posixtimer_sig_unignore(struct task_struct *tsk, int sig)
 	 * rearmed or not. This cannot be decided here w/o dropping sighand
 	 * lock and creating a loop retry horror show.
 	 */
-	hlist_for_each_entry_safe(tmr, tmp , head, ignored_list) {
+	hlist_for_each_entry_mutable(tmr, head, ignored_list) {
 		struct task_struct *target;
 
 		/*
diff --git a/kernel/smp.c b/kernel/smp.c
index a0bb56bd8dda..305187e50b58 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -544,7 +544,7 @@ static void __flush_smp_call_function_queue(bool warn_cpu_offline)
 	 * First; run all SYNC callbacks, people are waiting for us.
 	 */
 	prev = NULL;
-	llist_for_each_entry_safe(csd, csd_next, entry, node.llist) {
+	llist_for_each_entry_mutable(csd, csd_next, entry, node.llist) {
 		/* Do we wait until *after* callback? */
 		if (CSD_TYPE(csd) == CSD_TYPE_SYNC) {
 			smp_call_func_t func = csd->func;
@@ -572,7 +572,7 @@ static void __flush_smp_call_function_queue(bool warn_cpu_offline)
 	 * Second; run all !SYNC callbacks.
 	 */
 	prev = NULL;
-	llist_for_each_entry_safe(csd, csd_next, entry, node.llist) {
+	llist_for_each_entry_mutable(csd, csd_next, entry, node.llist) {
 		int type = CSD_TYPE(csd);
 
 		if (type != CSD_TYPE_TTWU) {
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index 2cd0172d0516..08932d4776d1 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -111,7 +111,7 @@ static void send_cpu_listeners(struct sk_buff *skb,
 					struct listener_list *listeners)
 {
 	struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
-	struct listener *s, *tmp;
+	struct listener *s;
 	struct sk_buff *skb_next, *skb_cur = skb;
 	void *reply = genlmsg_data(genlhdr);
 	int delcount = 0;
@@ -145,7 +145,7 @@ static void send_cpu_listeners(struct sk_buff *skb,
 
 	/* Delete invalidated entries */
 	down_write(&listeners->sem);
-	list_for_each_entry_safe(s, tmp, &listeners->list, list) {
+	list_for_each_entry_mutable(s, &listeners->list, list) {
 		if (!s->valid) {
 			list_del(&s->list);
 			kfree(s);
@@ -299,7 +299,7 @@ static void fill_tgid_exit(struct task_struct *tsk)
 static int add_del_listener(pid_t pid, const struct cpumask *mask, int isadd)
 {
 	struct listener_list *listeners;
-	struct listener *s, *tmp, *s2;
+	struct listener *s, *s2;
 	unsigned int cpu;
 	int ret = 0;
 
@@ -343,7 +343,7 @@ static int add_del_listener(pid_t pid, const struct cpumask *mask, int isadd)
 	for_each_cpu(cpu, mask) {
 		listeners = &per_cpu(listener_array, cpu);
 		down_write(&listeners->sem);
-		list_for_each_entry_safe(s, tmp, &listeners->list, list) {
+		list_for_each_entry_mutable(s, &listeners->list, list) {
 			if (s->pid == pid) {
 				list_del(&s->list);
 				kfree(s);
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
index 0014d163f989..a13eeab8d83f 100644
--- a/kernel/time/clockevents.c
+++ b/kernel/time/clockevents.c
@@ -678,7 +678,7 @@ void clockevents_resume(void)
  */
 void tick_offline_cpu(unsigned int cpu)
 {
-	struct clock_event_device *dev, *tmp;
+	struct clock_event_device *dev;
 
 	raw_spin_lock(&clockevents_lock);
 
@@ -689,13 +689,13 @@ void tick_offline_cpu(unsigned int cpu)
 	 * Unregister the clock event devices which were
 	 * released above.
 	 */
-	list_for_each_entry_safe(dev, tmp, &clockevents_released, list)
+	list_for_each_entry_mutable(dev, &clockevents_released, list)
 		list_del(&dev->list);
 
 	/*
 	 * Now check whether the CPU has left unused per cpu devices
 	 */
-	list_for_each_entry_safe(dev, tmp, &clockevent_devices, list) {
+	list_for_each_entry_mutable(dev, &clockevent_devices, list) {
 		if (cpumask_test_cpu(cpu, dev->cpumask) &&
 		    cpumask_weight(dev->cpumask) == 1 &&
 		    !tick_is_broadcast_device(dev)) {
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index e48c4d379a7c..ac857d7ce4bb 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -776,12 +776,12 @@ static void clocksource_dequeue_watchdog(struct clocksource *cs)
 
 static int __clocksource_watchdog_kthread(void)
 {
-	struct clocksource *cs, *tmp;
+	struct clocksource *cs;
 	unsigned long flags;
 	int select = 0;
 
 	spin_lock_irqsave(&watchdog_lock, flags);
-	list_for_each_entry_safe(cs, tmp, &watchdog_list, wd_list) {
+	list_for_each_entry_mutable(cs, &watchdog_list, wd_list) {
 		if (cs->flags & CLOCK_SOURCE_UNSTABLE) {
 			list_del_init(&cs->wd_list);
 			clocksource_change_rating(cs, 0);
diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c
index 5e633d8750d1..1f2c5533d598 100644
--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -1296,7 +1296,7 @@ static inline bool posix_cpu_timers_enable_work(struct task_struct *tsk,
 
 static void handle_posix_cpu_timers(struct task_struct *tsk)
 {
-	struct k_itimer *timer, *next;
+	struct k_itimer *timer;
 	unsigned long flags, start;
 	LIST_HEAD(firing);
 
@@ -1369,7 +1369,7 @@ static void handle_posix_cpu_timers(struct task_struct *tsk)
 	 * each timer's lock before clearing its firing flag, so no
 	 * timer call will interfere.
 	 */
-	list_for_each_entry_safe(timer, next, &firing, it.cpu.elist) {
+	list_for_each_entry_mutable(timer, &firing, it.cpu.elist) {
 		bool cpu_firing;
 
 		/*
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
index 436ba794cc0b..d89307c4adb0 100644
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -1085,7 +1085,6 @@ SYSCALL_DEFINE1(timer_delete, timer_t, timer_id)
 void exit_itimers(struct task_struct *tsk)
 {
 	struct hlist_head timers;
-	struct hlist_node *next;
 	struct k_itimer *timer;
 
 	/* Clear restore mode for exec() */
@@ -1099,7 +1098,7 @@ void exit_itimers(struct task_struct *tsk)
 		hlist_move_list(&tsk->signal->posix_timers, &timers);
 
 	/* The timers are not longer accessible via tsk::signal */
-	hlist_for_each_entry_safe(timer, next, &timers, list) {
+	hlist_for_each_entry_mutable(timer, &timers, list) {
 		scoped_guard (spinlock_irq, &timer->it_lock)
 			posix_timer_delete(timer);
 		posix_timer_unhash_and_free(timer);
diff --git a/kernel/torture.c b/kernel/torture.c
index 77cb3589b19f..047dcde729dd 100644
--- a/kernel/torture.c
+++ b/kernel/torture.c
@@ -510,10 +510,9 @@ EXPORT_SYMBOL_GPL(torture_shuffle_task_register);
 static void torture_shuffle_task_unregister_all(void)
 {
 	struct shuffle_task *stp;
-	struct shuffle_task *p;
 
 	mutex_lock(&shuffle_task_mutex);
-	list_for_each_entry_safe(stp, p, &shuffle_task_list, st_l) {
+	list_for_each_entry_mutable(stp, &shuffle_task_list, st_l) {
 		list_del(&stp->st_l);
 		kfree(stp);
 	}
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 82f8feea6931..7f6d8b287adb 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -2276,7 +2276,7 @@ subsys_initcall(send_signal_irq_work_init);
 static int bpf_event_notify(struct notifier_block *nb, unsigned long op,
 			    void *module)
 {
-	struct bpf_trace_module *btm, *tmp;
+	struct bpf_trace_module *btm;
 	struct module *mod = module;
 	int ret = 0;
 
@@ -2297,7 +2297,7 @@ static int bpf_event_notify(struct notifier_block *nb, unsigned long op,
 		}
 		break;
 	case MODULE_STATE_GOING:
-		list_for_each_entry_safe(btm, tmp, &bpf_trace_modules, list) {
+		list_for_each_entry_mutable(btm, &bpf_trace_modules, list) {
 			if (btm->module == module) {
 				list_del(&btm->list);
 				kfree(btm);
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index f93e34dd2328..422665c687ff 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1252,7 +1252,6 @@ void ftrace_hash_remove(struct ftrace_hash *hash)
 {
 	struct ftrace_func_entry *entry;
 	struct hlist_head *hhd;
-	struct hlist_node *tn;
 	int size;
 	int i;
 
@@ -1261,7 +1260,7 @@ void ftrace_hash_remove(struct ftrace_hash *hash)
 	size = 1 << hash->size_bits;
 	for (i = 0; i < size; i++) {
 		hhd = &hash->buckets[i];
-		hlist_for_each_entry_safe(entry, tn, hhd, hlist)
+		hlist_for_each_entry_mutable(entry, hhd, hlist)
 			remove_hash_entry(hash, entry);
 	}
 	FTRACE_WARN_ON(hash->count);
@@ -1270,7 +1269,6 @@ void ftrace_hash_remove(struct ftrace_hash *hash)
 static void ftrace_hash_clear(struct ftrace_hash *hash)
 {
 	struct hlist_head *hhd;
-	struct hlist_node *tn;
 	struct ftrace_func_entry *entry;
 	int size = 1 << hash->size_bits;
 	int i;
@@ -1280,7 +1278,7 @@ static void ftrace_hash_clear(struct ftrace_hash *hash)
 
 	for (i = 0; i < size; i++) {
 		hhd = &hash->buckets[i];
-		hlist_for_each_entry_safe(entry, tn, hhd, hlist)
+		hlist_for_each_entry_mutable(entry, hhd, hlist)
 			free_hash_entry(hash, entry);
 	}
 	FTRACE_WARN_ON(hash->count);
@@ -1296,14 +1294,14 @@ static void free_ftrace_mod(struct ftrace_mod_load *ftrace_mod)
 
 static void clear_ftrace_mod_list(struct list_head *head)
 {
-	struct ftrace_mod_load *p, *n;
+	struct ftrace_mod_load *p;
 
 	/* stack tracer isn't supported yet */
 	if (!head)
 		return;
 
 	mutex_lock(&ftrace_lock);
-	list_for_each_entry_safe(p, n, head, list)
+	list_for_each_entry_mutable(p, head, list)
 		free_ftrace_mod(p);
 	mutex_unlock(&ftrace_lock);
 }
@@ -1451,7 +1449,6 @@ static struct ftrace_hash *__move_hash(struct ftrace_hash *src, int size)
 	struct ftrace_func_entry *entry;
 	struct ftrace_hash *new_hash;
 	struct hlist_head *hhd;
-	struct hlist_node *tn;
 	int bits = 0;
 	int i;
 
@@ -1474,7 +1471,7 @@ static struct ftrace_hash *__move_hash(struct ftrace_hash *src, int size)
 	size = 1 << src->size_bits;
 	for (i = 0; i < size; i++) {
 		hhd = &src->buckets[i];
-		hlist_for_each_entry_safe(entry, tn, hhd, hlist) {
+		hlist_for_each_entry_mutable(entry, hhd, hlist) {
 			remove_hash_entry(src, entry);
 			add_ftrace_hash_entry(new_hash, entry);
 		}
@@ -3327,7 +3324,6 @@ static int append_hash(struct ftrace_hash **hash, struct ftrace_hash *new_hash,
 static void remove_hash(struct ftrace_hash *hash, struct ftrace_hash *notrace_hash)
 {
 	struct ftrace_func_entry *entry;
-	struct hlist_node *tmp;
 	int size;
 	int i;
 
@@ -3337,7 +3333,7 @@ static void remove_hash(struct ftrace_hash *hash, struct ftrace_hash *notrace_ha
 
 	size = 1 << hash->size_bits;
 	for (i = 0; i < size; i++) {
-		hlist_for_each_entry_safe(entry, tmp, &hash->buckets[i], hlist) {
+		hlist_for_each_entry_mutable(entry, &hash->buckets[i], hlist) {
 			if (!__ftrace_lookup_ip(notrace_hash, entry->ip))
 				continue;
 			remove_hash_entry(hash, entry);
@@ -5084,7 +5080,7 @@ static int ftrace_hash_move_and_update_ops(struct ftrace_ops *ops,
 static int cache_mod(struct trace_array *tr,
 		     const char *func, char *module, int enable)
 {
-	struct ftrace_mod_load *ftrace_mod, *n;
+	struct ftrace_mod_load *ftrace_mod;
 	struct list_head *head = enable ? &tr->mod_trace : &tr->mod_notrace;
 
 	guard(mutex)(&ftrace_lock);
@@ -5096,7 +5092,7 @@ static int cache_mod(struct trace_array *tr,
 		func++;
 
 		/* Look to remove this hash */
-		list_for_each_entry_safe(ftrace_mod, n, head, list) {
+		list_for_each_entry_mutable(ftrace_mod, head, list) {
 			if (strcmp(ftrace_mod->module, module) != 0)
 				continue;
 
@@ -5124,7 +5120,7 @@ static int cache_mod(struct trace_array *tr,
 static void process_mod_list(struct list_head *head, struct ftrace_ops *ops,
 			     char *mod, bool enable)
 {
-	struct ftrace_mod_load *ftrace_mod, *n;
+	struct ftrace_mod_load *ftrace_mod;
 	struct ftrace_hash **orig_hash, *new_hash;
 	LIST_HEAD(process_mods);
 	char *func;
@@ -5143,7 +5139,7 @@ static void process_mod_list(struct list_head *head, struct ftrace_ops *ops,
 
 	mutex_lock(&ftrace_lock);
 
-	list_for_each_entry_safe(ftrace_mod, n, head, list) {
+	list_for_each_entry_mutable(ftrace_mod, head, list) {
 
 		if (strcmp(ftrace_mod->module, mod) != 0)
 			continue;
@@ -5165,7 +5161,7 @@ static void process_mod_list(struct list_head *head, struct ftrace_ops *ops,
 
 	mutex_unlock(&ftrace_lock);
 
-	list_for_each_entry_safe(ftrace_mod, n, &process_mods, list) {
+	list_for_each_entry_mutable(ftrace_mod, &process_mods, list) {
 
 		func = ftrace_mod->func;
 
@@ -5616,7 +5612,6 @@ unregister_ftrace_function_probe_func(char *glob, struct trace_array *tr,
 	struct ftrace_hash **orig_hash;
 	struct ftrace_hash *old_hash;
 	struct ftrace_hash *hash = NULL;
-	struct hlist_node *tmp;
 	struct hlist_head hhd;
 	char str[KSYM_SYMBOL_LEN];
 	int count = 0;
@@ -5677,7 +5672,7 @@ unregister_ftrace_function_probe_func(char *glob, struct trace_array *tr,
 
 	size = 1 << hash->size_bits;
 	for (i = 0; i < size; i++) {
-		hlist_for_each_entry_safe(entry, tmp, &hash->buckets[i], hlist) {
+		hlist_for_each_entry_mutable(entry, &hash->buckets[i], hlist) {
 
 			if (func_g.search) {
 				kallsyms_lookup(entry->ip, NULL, NULL,
@@ -5715,7 +5710,7 @@ unregister_ftrace_function_probe_func(char *glob, struct trace_array *tr,
 				       &old_hash_ops);
 	synchronize_rcu();
 
-	hlist_for_each_entry_safe(entry, tmp, &hhd, hlist) {
+	hlist_for_each_entry_mutable(entry, &hhd, hlist) {
 		hlist_del(&entry->hlist);
 		if (probe_ops->free)
 			probe_ops->free(probe_ops, tr, entry->ip, probe->data);
@@ -5738,9 +5733,9 @@ unregister_ftrace_function_probe_func(char *glob, struct trace_array *tr,
 
 void clear_ftrace_function_probes(struct trace_array *tr)
 {
-	struct ftrace_func_probe *probe, *n;
+	struct ftrace_func_probe *probe;
 
-	list_for_each_entry_safe(probe, n, &tr->func_probes, list)
+	list_for_each_entry_mutable(probe, &tr->func_probes, list)
 		unregister_ftrace_function_probe_func(NULL, tr, probe->probe_ops);
 }
 
@@ -5771,11 +5766,11 @@ __init int register_ftrace_command(struct ftrace_func_command *cmd)
  */
 __init int unregister_ftrace_command(struct ftrace_func_command *cmd)
 {
-	struct ftrace_func_command *p, *n;
+	struct ftrace_func_command *p;
 
 	guard(mutex)(&ftrace_cmd_mutex);
 
-	list_for_each_entry_safe(p, n, &ftrace_commands, list) {
+	list_for_each_entry_mutable(p, &ftrace_commands, list) {
 		if (strcmp(cmd->name, p->name) == 0) {
 			list_del_init(&p->list);
 			return 0;
@@ -7876,10 +7871,9 @@ static void ftrace_free_mod_map(struct rcu_head *rcu)
 {
 	struct ftrace_mod_map *mod_map = container_of(rcu, struct ftrace_mod_map, rcu);
 	struct ftrace_mod_func *mod_func;
-	struct ftrace_mod_func *n;
 
 	/* All the contents of mod_map are now not visible to readers */
-	list_for_each_entry_safe(mod_func, n, &mod_map->funcs, list) {
+	list_for_each_entry_mutable(mod_func, &mod_map->funcs, list) {
 		kfree(mod_func->name);
 		list_del(&mod_func->list);
 		kfree(mod_func);
@@ -7891,7 +7885,6 @@ static void ftrace_free_mod_map(struct rcu_head *rcu)
 void ftrace_release_mod(struct module *mod)
 {
 	struct ftrace_mod_map *mod_map;
-	struct ftrace_mod_map *n;
 	struct dyn_ftrace *rec;
 	struct ftrace_page **last_pg;
 	struct ftrace_page *tmp_page = NULL;
@@ -7903,7 +7896,7 @@ void ftrace_release_mod(struct module *mod)
 	 * To avoid the UAF problem after the module is unloaded, the
 	 * 'mod_map' resource needs to be released unconditionally.
 	 */
-	list_for_each_entry_safe(mod_map, n, &ftrace_mod_maps, list) {
+	list_for_each_entry_mutable(mod_map, &ftrace_mod_maps, list) {
 		if (mod_map->mod == mod) {
 			list_del_rcu(&mod_map->list);
 			call_rcu(&mod_map->rcu, ftrace_free_mod_map);
@@ -8290,7 +8283,7 @@ void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr)
 	struct dyn_ftrace *rec;
 	struct dyn_ftrace key;
 	struct ftrace_mod_map *mod_map = NULL;
-	struct ftrace_init_func *func, *func_next;
+	struct ftrace_init_func *func;
 	LIST_HEAD(clear_hash);
 
 	key.ip = start;
@@ -8341,7 +8334,7 @@ void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr)
 	}
 	mutex_unlock(&ftrace_lock);
 
-	list_for_each_entry_safe(func, func_next, &clear_hash, list) {
+	list_for_each_entry_mutable(func, &clear_hash, list) {
 		clear_func_from_hashes(func);
 		kfree(func);
 	}
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 56a328e94395..24b2deb1f7a6 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -2362,7 +2362,7 @@ static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
 {
 	struct trace_buffer *buffer = cpu_buffer->buffer;
 	struct ring_buffer_cpu_meta *meta = NULL;
-	struct buffer_page *bpage, *tmp;
+	struct buffer_page *bpage;
 	bool user_thread = current->mm != NULL;
 	struct ring_buffer_desc *desc = NULL;
 	long i;
@@ -2450,7 +2450,7 @@ static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
 	return 0;
 
 free_pages:
-	list_for_each_entry_safe(bpage, tmp, pages, list) {
+	list_for_each_entry_mutable(bpage, pages, list) {
 		list_del_init(&bpage->list);
 		free_buffer_page(bpage);
 	}
@@ -2609,7 +2609,7 @@ rb_allocate_cpu_buffer(struct trace_buffer *buffer, long nr_pages, int cpu)
 static void rb_free_cpu_buffer(struct ring_buffer_per_cpu *cpu_buffer)
 {
 	struct list_head *head = cpu_buffer->pages;
-	struct buffer_page *bpage, *tmp;
+	struct buffer_page *bpage;
 
 	irq_work_sync(&cpu_buffer->irq_work.work);
 
@@ -2621,7 +2621,7 @@ static void rb_free_cpu_buffer(struct ring_buffer_per_cpu *cpu_buffer)
 	if (head) {
 		rb_head_page_deactivate(cpu_buffer);
 
-		list_for_each_entry_safe(bpage, tmp, head, list) {
+		list_for_each_entry_mutable(bpage, head, list) {
 			list_del_init(&bpage->list);
 			free_buffer_page(bpage);
 		}
@@ -3163,9 +3163,9 @@ rb_insert_pages(struct ring_buffer_per_cpu *cpu_buffer)
 
 	/* free pages if they weren't inserted */
 	if (!success) {
-		struct buffer_page *bpage, *tmp;
-		list_for_each_entry_safe(bpage, tmp, &cpu_buffer->new_pages,
-					 list) {
+		struct buffer_page *bpage;
+
+		list_for_each_entry_mutable(bpage, &cpu_buffer->new_pages, list) {
 			list_del_init(&bpage->list);
 			free_buffer_page(bpage);
 		}
@@ -3395,7 +3395,7 @@ int ring_buffer_resize(struct trace_buffer *buffer, unsigned long size,
 
  out_err:
 	for_each_buffer_cpu(buffer, cpu) {
-		struct buffer_page *bpage, *tmp;
+		struct buffer_page *bpage;
 
 		cpu_buffer = buffer->buffers[cpu];
 		cpu_buffer->nr_pages_to_update = 0;
@@ -3403,8 +3403,7 @@ int ring_buffer_resize(struct trace_buffer *buffer, unsigned long size,
 		if (list_empty(&cpu_buffer->new_pages))
 			continue;
 
-		list_for_each_entry_safe(bpage, tmp, &cpu_buffer->new_pages,
-					list) {
+		list_for_each_entry_mutable(bpage, &cpu_buffer->new_pages, list) {
 			list_del_init(&bpage->list);
 			free_buffer_page(bpage);
 
@@ -7316,7 +7315,7 @@ EXPORT_SYMBOL_GPL(ring_buffer_subbuf_order_get);
 int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
 {
 	struct ring_buffer_per_cpu *cpu_buffer;
-	struct buffer_page *bpage, *tmp;
+	struct buffer_page *bpage;
 	int old_order, old_size;
 	int nr_pages;
 	int psize;
@@ -7436,7 +7435,7 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
 		raw_spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
 
 		/* Free old sub buffers */
-		list_for_each_entry_safe(bpage, tmp, &old_pages, list) {
+		list_for_each_entry_mutable(bpage, &old_pages, list) {
 			list_del_init(&bpage->list);
 			free_buffer_page(bpage);
 		}
@@ -7461,7 +7460,7 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
 		if (!cpu_buffer->nr_pages_to_update)
 			continue;
 
-		list_for_each_entry_safe(bpage, tmp, &cpu_buffer->new_pages, list) {
+		list_for_each_entry_mutable(bpage, &cpu_buffer->new_pages, list) {
 			list_del_init(&bpage->list);
 			free_buffer_page(bpage);
 		}
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 1146b83b711a..f1049850e986 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -1380,7 +1380,7 @@ static int do_run_tracer_selftest(struct tracer *type)
 
 static __init int init_trace_selftests(void)
 {
-	struct trace_selftests *p, *n;
+	struct trace_selftests *p;
 	struct tracer *t, **last;
 	int ret;
 
@@ -1394,7 +1394,7 @@ static __init int init_trace_selftests(void)
 	pr_info("Running postponed tracer tests:\n");
 
 	tracing_selftest_running = true;
-	list_for_each_entry_safe(p, n, &postponed_selftests, list) {
+	list_for_each_entry_mutable(p, &postponed_selftests, list) {
 		/* This loop can take minutes when sanitizers are enabled, so
 		 * lets make sure we allow RCU processing.
 		 */
@@ -1434,11 +1434,11 @@ static void __init apply_trace_boot_options(void);
 
 static void free_tracers(struct trace_array *tr)
 {
-	struct tracers *t, *n;
+	struct tracers *t;
 
 	lockdep_assert_held(&trace_types_lock);
 
-	list_for_each_entry_safe(t, n, &tr->tracers, list) {
+	list_for_each_entry_mutable(t, &tr->tracers, list) {
 		list_del(&t->list);
 		kfree(t->flags);
 		kfree(t);
@@ -6906,11 +6906,11 @@ void tracing_log_err(struct trace_array *tr,
 
 static void clear_tracing_err_log(struct trace_array *tr)
 {
-	struct tracing_log_err *err, *next;
+	struct tracing_log_err *err;
 
 	guard(mutex)(&tracing_err_log_lock);
 
-	list_for_each_entry_safe(err, next, &tr->err_log, list) {
+	list_for_each_entry_mutable(err, &tr->err_log, list) {
 		list_del(&err->list);
 		free_tracing_log_err(err);
 	}
diff --git a/kernel/trace/trace_dynevent.c b/kernel/trace/trace_dynevent.c
index c4dfbc293bae..9e076106bee7 100644
--- a/kernel/trace/trace_dynevent.c
+++ b/kernel/trace/trace_dynevent.c
@@ -100,7 +100,7 @@ int dyn_event_release(const char *raw_command, struct dyn_event_operations *type
 		return -EINVAL;
 
 	mutex_lock(&event_mutex);
-	for_each_dyn_event_safe(pos, n) {
+	for_each_dyn_event_safe(pos) {
 		if (type && type != pos->ops)
 			continue;
 		if (!pos->ops->match(system, event,
@@ -207,7 +207,7 @@ static const struct seq_operations dyn_event_seq_op = {
  */
 int dyn_events_release_all(struct dyn_event_operations *type)
 {
-	struct dyn_event *ev, *tmp;
+	struct dyn_event *ev;
 	int ret = 0;
 
 	mutex_lock(&event_mutex);
@@ -219,7 +219,7 @@ int dyn_events_release_all(struct dyn_event_operations *type)
 			goto out;
 		}
 	}
-	for_each_dyn_event_safe(ev, tmp) {
+	for_each_dyn_event_safe(ev) {
 		if (type && ev->ops != type)
 			continue;
 		ret = ev->ops->free(ev);
diff --git a/kernel/trace/trace_dynevent.h b/kernel/trace/trace_dynevent.h
index beee3f8d7544..a4dc0812284f 100644
--- a/kernel/trace/trace_dynevent.h
+++ b/kernel/trace/trace_dynevent.h
@@ -115,10 +115,9 @@ int dyn_event_create(const char *raw_command, struct dyn_event_operations *type)
 /*
  * for_each_dyn_event	-	iterate over the dyn_event list safely
  * @pos:	the struct dyn_event * to use as a loop cursor
- * @n:		the struct dyn_event * to use as temporary storage
  */
-#define for_each_dyn_event_safe(pos, n)	\
-	list_for_each_entry_safe(pos, n, &dyn_event_list, list)
+#define for_each_dyn_event_safe(pos)	\
+	list_for_each_entry_mutable(pos, &dyn_event_list, list)
 
 extern void dynevent_cmd_init(struct dynevent_cmd *cmd, char *buf, int maxlen,
 			      enum dynevent_type type,
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index c46e623e7e0d..a34fb3e688d5 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -75,8 +75,7 @@ static int system_refcount_dec(struct event_subsystem *system)
 
 #define do_for_each_event_file_safe(tr, file)			\
 	list_for_each_entry(tr, &ftrace_trace_arrays, list) {	\
-		struct trace_event_file *___n;				\
-		list_for_each_entry_safe(file, ___n, &tr->events, list)
+		list_for_each_entry_mutable(file, &tr->events, list)
 
 #define while_for_each_event_file()		\
 	}
@@ -219,11 +218,11 @@ static int trace_define_common_fields(void)
 
 static void trace_destroy_fields(struct trace_event_call *call)
 {
-	struct ftrace_event_field *field, *next;
+	struct ftrace_event_field *field;
 	struct list_head *head;
 
 	head = trace_get_fields(call);
-	list_for_each_entry_safe(field, next, head, link) {
+	list_for_each_entry_mutable(field, head, link) {
 		list_del(&field->link);
 		kmem_cache_free(field_cachep, field);
 	}
@@ -928,9 +927,9 @@ static void free_event_mod(struct event_mod_load *event_mod)
 
 static void clear_mod_events(struct trace_array *tr)
 {
-	struct event_mod_load *event_mod, *n;
+	struct event_mod_load *event_mod;
 
-	list_for_each_entry_safe(event_mod, n, &tr->mod_events, list) {
+	list_for_each_entry_mutable(event_mod, &tr->mod_events, list) {
 		free_event_mod(event_mod);
 	}
 }
@@ -938,10 +937,10 @@ static void clear_mod_events(struct trace_array *tr)
 static int remove_cache_mod(struct trace_array *tr, const char *mod,
 			    const char *match, const char *system, const char *event)
 {
-	struct event_mod_load *event_mod, *n;
+	struct event_mod_load *event_mod;
 	int ret = -EINVAL;
 
-	list_for_each_entry_safe(event_mod, n, &tr->mod_events, list) {
+	list_for_each_entry_mutable(event_mod, &tr->mod_events, list) {
 		if (strcmp(event_mod->module, mod) != 0)
 			continue;
 
@@ -3557,7 +3556,7 @@ static void update_event_fields(struct trace_event_call *call,
 /* Update all events for replacing eval and sanitizing */
 void trace_event_update_all(struct trace_eval_map **map, int len)
 {
-	struct trace_event_call *call, *p;
+	struct trace_event_call *call;
 	const char *last_system = NULL;
 	bool first = false;
 	bool updated;
@@ -3565,7 +3564,7 @@ void trace_event_update_all(struct trace_eval_map **map, int len)
 	int i;
 
 	down_write(&trace_event_sem);
-	list_for_each_entry_safe(call, p, &ftrace_events, list) {
+	list_for_each_entry_mutable(call, &ftrace_events, list) {
 		/* events are usually grouped together with systems */
 		if (!last_system || call->class->system != last_system) {
 			first = true;
@@ -3892,9 +3891,9 @@ EXPORT_SYMBOL_GPL(trace_remove_event_call);
 #ifdef CONFIG_MODULES
 static void update_mod_cache(struct trace_array *tr, struct module *mod)
 {
-	struct event_mod_load *event_mod, *n;
+	struct event_mod_load *event_mod;
 
-	list_for_each_entry_safe(event_mod, n, &tr->mod_events, list) {
+	list_for_each_entry_mutable(event_mod, &tr->mod_events, list) {
 		if (strcmp(event_mod->module, mod->name) != 0)
 			continue;
 
@@ -3940,18 +3939,18 @@ static void trace_module_add_events(struct module *mod)
 
 static void trace_module_remove_events(struct module *mod)
 {
-	struct trace_event_call *call, *p;
-	struct module_string *modstr, *m;
+	struct trace_event_call *call;
+	struct module_string *modstr;
 
 	down_write(&trace_event_sem);
-	list_for_each_entry_safe(call, p, &ftrace_events, list) {
+	list_for_each_entry_mutable(call, &ftrace_events, list) {
 		if ((call->flags & TRACE_EVENT_FL_DYNAMIC) || !call->module)
 			continue;
 		if (call->module == mod)
 			__trace_remove_event_call(call);
 	}
 	/* Check for any strings allocated for this module */
-	list_for_each_entry_safe(modstr, m, &module_strings, next) {
+	list_for_each_entry_mutable(modstr, &module_strings, next) {
 		if (modstr->module != mod)
 			continue;
 		list_del(&modstr->next);
@@ -4483,9 +4482,9 @@ void __trace_early_add_events(struct trace_array *tr)
 static void
 __trace_remove_event_dirs(struct trace_array *tr)
 {
-	struct trace_event_file *file, *next;
+	struct trace_event_file *file;
 
-	list_for_each_entry_safe(file, next, &tr->events, list)
+	list_for_each_entry_mutable(file, &tr->events, list)
 		remove_event_file_dir(file);
 }
 
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 609325f57942..d82128084a87 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -1352,9 +1352,9 @@ struct filter_head {
 
 static void free_filter_list(struct filter_head *filter_list)
 {
-	struct filter_list *filter_item, *tmp;
+	struct filter_list *filter_item;
 
-	list_for_each_entry_safe(filter_item, tmp, &filter_list->list, list) {
+	list_for_each_entry_mutable(filter_item, &filter_list->list, list) {
 		__free_filter(filter_item->filter);
 		list_del(&filter_item->list);
 		kfree(filter_item);
diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
index 82ce492ab268..ff6016acab20 100644
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -6765,7 +6765,7 @@ static bool hist_file_check_refs(struct trace_event_file *file)
 
 static void hist_unreg_all(struct trace_event_file *file)
 {
-	struct event_trigger_data *test, *n;
+	struct event_trigger_data *test;
 	struct hist_trigger_data *hist_data;
 	struct synth_event *se;
 	const char *se_name;
@@ -6775,7 +6775,7 @@ static void hist_unreg_all(struct trace_event_file *file)
 	if (hist_file_check_refs(file))
 		return;
 
-	list_for_each_entry_safe(test, n, &file->triggers, list) {
+	list_for_each_entry_mutable(test, &file->triggers, list) {
 		if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
 			hist_data = test->private_data;
 			list_del_rcu(&test->list);
@@ -7002,9 +7002,9 @@ hist_enable_trigger(struct event_trigger_data *data,
 
 static void hist_enable_unreg_all(struct trace_event_file *file)
 {
-	struct event_trigger_data *test, *n;
+	struct event_trigger_data *test;
 
-	list_for_each_entry_safe(test, n, &file->triggers, list) {
+	list_for_each_entry_mutable(test, &file->triggers, list) {
 		if (test->cmd_ops->trigger_type == ETT_HIST_ENABLE) {
 			list_del_rcu(&test->list);
 			update_cond_flag(file);
diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c
index 655db2e82513..8654cd83f64d 100644
--- a/kernel/trace/trace_events_trigger.c
+++ b/kernel/trace/trace_events_trigger.c
@@ -40,7 +40,7 @@ static void trigger_create_kthread_locked(void)
 
 static void trigger_data_free_queued_locked(void)
 {
-	struct event_trigger_data *data, *tmp;
+	struct event_trigger_data *data;
 	struct llist_node *llnodes;
 
 	lockdep_assert_held(&trigger_data_kthread_mutex);
@@ -51,14 +51,14 @@ static void trigger_data_free_queued_locked(void)
 
 	tracepoint_synchronize_unregister();
 
-	llist_for_each_entry_safe(data, tmp, llnodes, llist)
+	llist_for_each_entry_mutable(data, llnodes, llist)
 		kfree(data);
 }
 
 /* Bulk garbage collection of event_trigger_data elements */
 static int trigger_kthread_fn(void *ignore)
 {
-	struct event_trigger_data *data, *tmp;
+	struct event_trigger_data *data;
 	struct llist_node *llnodes;
 
 	/* Once this task starts, it lives forever */
@@ -74,7 +74,7 @@ static int trigger_kthread_fn(void *ignore)
 		/* make sure current triggers exit before free */
 		tracepoint_synchronize_unregister();
 
-		llist_for_each_entry_safe(data, tmp, llnodes, llist)
+		llist_for_each_entry_mutable(data, llnodes, llist)
 			kfree(data);
 	}
 
@@ -477,11 +477,11 @@ __init int register_event_command(struct event_command *cmd)
  */
 __init int unregister_event_command(struct event_command *cmd)
 {
-	struct event_command *p, *n;
+	struct event_command *p;
 
 	guard(mutex)(&trigger_cmd_mutex);
 
-	list_for_each_entry_safe(p, n, &trigger_commands, list) {
+	list_for_each_entry_mutable(p, &trigger_commands, list) {
 		if (strcmp(cmd->name, p->name) == 0) {
 			list_del_init(&p->list);
 			return 0;
@@ -632,8 +632,9 @@ clear_event_triggers(struct trace_array *tr)
 	struct trace_event_file *file;
 
 	list_for_each_entry(file, &tr->events, list) {
-		struct event_trigger_data *data, *n;
-		list_for_each_entry_safe(data, n, &file->triggers, list) {
+		struct event_trigger_data *data;
+
+		list_for_each_entry_mutable(data, &file->triggers, list) {
 			trace_event_trigger_enable_disable(file, 0);
 			list_del_rcu(&data->list);
 			if (data->cmd_ops->free)
diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c
index c4ba484f7b38..090d645eebf0 100644
--- a/kernel/trace/trace_events_user.c
+++ b/kernel/trace/trace_events_user.c
@@ -761,9 +761,9 @@ static struct user_event_mm *current_user_event_mm(void)
 
 static void user_event_mm_destroy(struct user_event_mm *mm)
 {
-	struct user_event_enabler *enabler, *next;
+	struct user_event_enabler *enabler;
 
-	list_for_each_entry_safe(enabler, next, &mm->enablers, mm_enablers_link)
+	list_for_each_entry_mutable(enabler, &mm->enablers, mm_enablers_link)
 		user_event_enabler_destroy(enabler, false);
 
 	mmdrop(mm->mm);
@@ -1085,10 +1085,10 @@ static int user_field_size(const char *type)
 
 static void user_event_destroy_validators(struct user_event *user)
 {
-	struct user_event_validator *validator, *next;
+	struct user_event_validator *validator;
 	struct list_head *head = &user->validators;
 
-	list_for_each_entry_safe(validator, next, head, user_event_link) {
+	list_for_each_entry_mutable(validator, head, user_event_link) {
 		list_del(&validator->user_event_link);
 		kfree(validator);
 	}
@@ -1096,10 +1096,10 @@ static void user_event_destroy_validators(struct user_event *user)
 
 static void user_event_destroy_fields(struct user_event *user)
 {
-	struct ftrace_event_field *field, *next;
+	struct ftrace_event_field *field;
 	struct list_head *head = &user->fields;
 
-	list_for_each_entry_safe(field, next, head, link) {
+	list_for_each_entry_mutable(field, head, link) {
 		list_del(&field->link);
 		kfree(field);
 	}
@@ -2611,7 +2611,7 @@ static long user_events_ioctl_unreg(unsigned long uarg)
 {
 	struct user_unreg __user *ureg = (struct user_unreg __user *)uarg;
 	struct user_event_mm *mm = current->user_event_mm;
-	struct user_event_enabler *enabler, *next;
+	struct user_event_enabler *enabler;
 	struct user_unreg reg;
 	unsigned long flags;
 	long ret;
@@ -2636,7 +2636,7 @@ static long user_events_ioctl_unreg(unsigned long uarg)
 	 */
 	mutex_lock(&event_mutex);
 
-	list_for_each_entry_safe(enabler, next, &mm->enablers, mm_enablers_link) {
+	list_for_each_entry_mutable(enabler, &mm->enablers, mm_enablers_link) {
 		if (enabler->addr == reg.disable_addr &&
 		    ENABLE_BIT(enabler) == reg.disable_bit) {
 			set_bit(ENABLE_VAL_FREEING_BIT, ENABLE_BITOPS(enabler));
diff --git a/kernel/trace/trace_stat.c b/kernel/trace/trace_stat.c
index 856ece13b7dc..3240b1ff7418 100644
--- a/kernel/trace/trace_stat.c
+++ b/kernel/trace/trace_stat.c
@@ -344,10 +344,10 @@ int register_stat_tracer(struct tracer_stat *trace)
 
 void unregister_stat_tracer(struct tracer_stat *trace)
 {
-	struct stat_session *node, *tmp;
+	struct stat_session *node;
 
 	mutex_lock(&all_stat_sessions_mutex);
-	list_for_each_entry_safe(node, tmp, &all_stat_sessions, session_list) {
+	list_for_each_entry_mutable(node, &all_stat_sessions, session_list) {
 		if (node->ts == trace) {
 			list_del(&node->session_list);
 			destroy_session(node);
diff --git a/kernel/user-return-notifier.c b/kernel/user-return-notifier.c
index 870ecd7c63ed..9f1dcd72b756 100644
--- a/kernel/user-return-notifier.c
+++ b/kernel/user-return-notifier.c
@@ -35,11 +35,10 @@ EXPORT_SYMBOL_GPL(user_return_notifier_unregister);
 void fire_user_return_notifiers(void)
 {
 	struct user_return_notifier *urn;
-	struct hlist_node *tmp2;
 	struct hlist_head *head;
 
 	head = &get_cpu_var(return_notifier_list);
-	hlist_for_each_entry_safe(urn, tmp2, head, link)
+	hlist_for_each_entry_mutable(urn, head, link)
 		urn->on_user_return(urn);
 	put_cpu_var(return_notifier_list);
 }
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 78f25afb4a9d..8fbdf1664c38 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -1167,7 +1167,7 @@ static void move_linked_works(struct work_struct *work, struct list_head *head,
 	 * Linked worklist will always end before the end of the list,
 	 * use NULL for list head.
 	 */
-	list_for_each_entry_safe_from(work, n, NULL, entry) {
+	list_for_each_entry_mutable_from(work, n, NULL, entry) {
 		list_move_tail(&work->entry, head);
 		if (!(*work_data_bits(work) & WORK_STRUCT_LINKED))
 			break;
@@ -1193,7 +1193,7 @@ static void move_linked_works(struct work_struct *work, struct list_head *head,
  *
  * If @nextp is not NULL, it's updated to point to the next work of the last
  * scheduled work. This allows assign_work() to be nested inside
- * list_for_each_entry_safe().
+ * list_for_each_entry_mutable().
  *
  * Returns %true if @work was successfully assigned to @worker. %false if @work
  * was punted to another worker already executing it.
@@ -2912,9 +2912,9 @@ static void detach_dying_workers(struct list_head *cull_list)
 
 static void reap_dying_workers(struct list_head *cull_list)
 {
-	struct worker *worker, *tmp;
+	struct worker *worker;
 
-	list_for_each_entry_safe(worker, tmp, cull_list, entry) {
+	list_for_each_entry_mutable(worker, cull_list, entry) {
 		list_del_init(&worker->entry);
 		kthread_stop_put(worker->task);
 		kfree(worker);
@@ -3550,7 +3550,7 @@ static bool assign_rescuer_work(struct pool_workqueue *pwq, struct worker *rescu
 		work = list_next_entry(cursor, entry);
 
 	/* find the next work item to rescue */
-	list_for_each_entry_safe_from(work, n, &pool->worklist, entry) {
+	list_for_each_entry_mutable_from(work, n, &pool->worklist, entry) {
 		if (get_work_pwq(work) == pwq && assign_work(work, rescuer, &n)) {
 			pwq->stats[PWQ_STAT_RESCUED]++;
 			/* put the cursor for next search */
@@ -4157,7 +4157,7 @@ void __flush_workqueue(struct workqueue_struct *wq)
 		struct wq_flusher *next, *tmp;
 
 		/* complete all the flushers sharing the current flush color */
-		list_for_each_entry_safe(next, tmp, &wq->flusher_queue, list) {
+		list_for_each_entry_mutable(next, &wq->flusher_queue, list) {
 			if (next->flush_color != wq->flush_color)
 				break;
 			list_del_init(&next->list);
@@ -7080,7 +7080,7 @@ static int workqueue_apply_unbound_cpumask(const cpumask_var_t unbound_cpumask)
 	LIST_HEAD(ctxs);
 	int ret = 0;
 	struct workqueue_struct *wq;
-	struct apply_wqattrs_ctx *ctx, *n;
+	struct apply_wqattrs_ctx *ctx;
 
 	lockdep_assert_held(&wq_pool_mutex);
 
@@ -7097,7 +7097,7 @@ static int workqueue_apply_unbound_cpumask(const cpumask_var_t unbound_cpumask)
 		list_add_tail(&ctx->list, &ctxs);
 	}
 
-	list_for_each_entry_safe(ctx, n, &ctxs, list) {
+	list_for_each_entry_mutable(ctx, &ctxs, list) {
 		if (!ret)
 			apply_wqattrs_commit(ctx);
 		apply_wqattrs_cleanup(ctx);
-- 
2.43.0


^ permalink raw reply related

* [PATCH v3 2/7] llist: Add mutable iterator variants
From: Kaitao Cheng @ 2026-06-22  4:05 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Jens Axboe, Tejun Heo,
	Alexander Viro, Christian Brauner, Alexei Starovoitov,
	Daniel Borkmann, Andrii Nakryiko, Johannes Weiner, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim,
	Thomas Gleixner, Juri Lelli, Vincent Guittot, Paul Moore,
	Andy Shevchenko, Paul E. McKenney, Shakeel Butt,
	Christian König
  Cc: David Howells, Simona Vetter, Randy Dunlap, Luca Ceresoli,
	Philipp Stanner, linux-block, linux-kernel, cgroups,
	linux-ntfs-dev, linux-fsdevel, io-uring, audit, bpf, netdev,
	dri-devel, linux-perf-users, linux-trace-kernel, kexec,
	live-patching, linux-modules, linux-crypto, linux-pm, rcu,
	sched-ext, linux-mm, virtualization, damon, llvm, Kaitao Cheng
In-Reply-To: <20260622040533.29824-1-kaitao.cheng@linux.dev>

From: Kaitao Cheng <chengkaitao@kylinos.cn>

llist_for_each_safe() and llist_for_each_entry_safe() require callers to
provide a temporary cursor even when the cursor is only needed by the
iterator itself.  This makes call sites noisier than necessary for the
common case where the loop body may remove the current entry but does
not otherwise inspect the saved next pointer.

Add llist_for_each_mutable() and llist_for_each_entry_mutable() variants
that support both forms.  Callers may omit the temporary cursor and let
the helper create an internal unique cursor, or keep passing an explicit
cursor when the loop needs to inspect or reset it.

Keep the existing safe helpers as compatibility wrappers so current users
continue to build unchanged while new code can use the shorter mutable
form.

Signed-off-by: Kaitao Cheng <chengkaitao@kylinos.cn>
---
 include/linux/llist.h | 81 ++++++++++++++++++++++++++++++++++---------
 1 file changed, 65 insertions(+), 16 deletions(-)

diff --git a/include/linux/llist.h b/include/linux/llist.h
index 8846b7709669..1c6f12411d5e 100644
--- a/include/linux/llist.h
+++ b/include/linux/llist.h
@@ -49,6 +49,7 @@
  */
 
 #include <linux/atomic.h>
+#include <linux/args.h>
 #include <linux/container_of.h>
 #include <linux/stddef.h>
 #include <linux/types.h>
@@ -143,12 +144,33 @@ static inline bool llist_on_list(const struct llist_node *node)
 #define llist_for_each(pos, node)			\
 	for ((pos) = (node); pos; (pos) = (pos)->next)
 
+/*
+ * llist_for_each_safe is an old interface, use llist_for_each_mutable instead.
+ */
+#define llist_for_each_safe(pos, n, node)			\
+	for ((pos) = (node); (pos) && ((n) = (pos)->next, true); (pos) = (n))
+
+#define __llist_for_each_mutable_internal(pos, tmp, node)		\
+	for (typeof(pos) tmp = ((pos) = (node)) ? (pos)->next : NULL;	\
+	     (pos);							\
+	     (pos) = tmp, tmp = (pos) ? (pos)->next : NULL)
+
+#define __llist_for_each_mutable1(pos, node)				\
+	__llist_for_each_mutable_internal(pos, __UNIQUE_ID(next), node)
+
+#define __llist_for_each_mutable2(pos, next, node)			\
+	llist_for_each_safe(pos, next, node)
+
 /**
- * llist_for_each_safe - iterate over some deleted entries of a lock-less list
- *			 safe against removal of list entry
+ * llist_for_each_mutable - iterate over some deleted entries of a lock-less list
+ *			    safe against removal of list entry
  * @pos:	the &struct llist_node to use as a loop cursor
- * @n:		another &struct llist_node to use as temporary storage
- * @node:	the first entry of deleted list entries
+ * @...:	either (node) or (next, node)
+ *
+ * next:	another &struct llist_node to use as optional temporary storage.
+ *		The temporary cursor is internal unless explicitly supplied by
+ *		the caller.
+ * node:	the first entry of deleted list entries
  *
  * In general, some entries of the lock-less list can be traversed
  * safely only after being deleted from list, so start with an entry
@@ -159,8 +181,9 @@ static inline bool llist_on_list(const struct llist_node *node)
  * you want to traverse from the oldest to the newest, you must
  * reverse the order by yourself before traversing.
  */
-#define llist_for_each_safe(pos, n, node)			\
-	for ((pos) = (node); (pos) && ((n) = (pos)->next, true); (pos) = (n))
+#define llist_for_each_mutable(pos, ...)				\
+	CONCATENATE(__llist_for_each_mutable, COUNT_ARGS(__VA_ARGS__))	\
+		(pos, __VA_ARGS__)
 
 /**
  * llist_for_each_entry - iterate over some deleted entries of lock-less list of given type
@@ -182,13 +205,41 @@ static inline bool llist_on_list(const struct llist_node *node)
 	     member_address_is_nonnull(pos, member);			\
 	     (pos) = llist_entry((pos)->member.next, typeof(*(pos)), member))
 
+/*
+ * llist_for_each_entry_safe is an old interface, use llist_for_each_entry_mutable instead.
+ */
+#define llist_for_each_entry_safe(pos, n, node, member)			       \
+	for (pos = llist_entry((node), typeof(*pos), member);		       \
+	     member_address_is_nonnull(pos, member) &&			       \
+	        (n = llist_entry(pos->member.next, typeof(*n), member), true); \
+	     pos = n)
+
+#define __llist_for_each_entry_mutable_internal(pos, tmp, node, member)	\
+	for (typeof(pos) tmp = ((pos) = llist_entry((node), typeof(*pos), member), \
+		member_address_is_nonnull(pos, member) ?			\
+		llist_entry((pos)->member.next, typeof(*pos), member) : NULL);	\
+	     member_address_is_nonnull(pos, member);				\
+	     (pos) = tmp, tmp = member_address_is_nonnull(pos, member) ?	\
+		llist_entry((pos)->member.next, typeof(*pos), member) : NULL)
+
+#define __llist_for_each_entry_mutable2(pos, node, member)			\
+	__llist_for_each_entry_mutable_internal(pos, __UNIQUE_ID(next), node, member)
+
+#define __llist_for_each_entry_mutable3(pos, next, node, member)		\
+	llist_for_each_entry_safe(pos, next, node, member)
+
 /**
- * llist_for_each_entry_safe - iterate over some deleted entries of lock-less list of given type
- *			       safe against removal of list entry
+ * llist_for_each_entry_mutable - iterate over some deleted entries of
+ *				  lock-less list of given type safe against
+ *				  removal of list entry
  * @pos:	the type * to use as a loop cursor.
- * @n:		another type * to use as temporary storage
- * @node:	the first entry of deleted list entries.
- * @member:	the name of the llist_node with the struct.
+ * @...:	either (node, member) or (next, node, member)
+ *
+ * next:	another type * to use as optional temporary storage. The
+ *		temporary cursor is internal unless explicitly supplied by the
+ *		caller.
+ * node:	the first entry of deleted list entries.
+ * member:	the name of the llist_node with the struct.
  *
  * In general, some entries of the lock-less list can be traversed
  * safely only after being removed from list, so start with an entry
@@ -199,11 +250,9 @@ static inline bool llist_on_list(const struct llist_node *node)
  * you want to traverse from the oldest to the newest, you must
  * reverse the order by yourself before traversing.
  */
-#define llist_for_each_entry_safe(pos, n, node, member)			       \
-	for (pos = llist_entry((node), typeof(*pos), member);		       \
-	     member_address_is_nonnull(pos, member) &&			       \
-	        (n = llist_entry(pos->member.next, typeof(*n), member), true); \
-	     pos = n)
+#define llist_for_each_entry_mutable(pos, ...)				\
+	CONCATENATE(__llist_for_each_entry_mutable,			\
+		COUNT_ARGS(__VA_ARGS__))(pos, __VA_ARGS__)
 
 /**
  * llist_empty - tests whether a lock-less list is empty
-- 
2.43.0


^ permalink raw reply related

* [PATCH v3 1/7] list: Add mutable iterator variants
From: Kaitao Cheng @ 2026-06-22  4:05 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Jens Axboe, Tejun Heo,
	Alexander Viro, Christian Brauner, Alexei Starovoitov,
	Daniel Borkmann, Andrii Nakryiko, Johannes Weiner, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim,
	Thomas Gleixner, Juri Lelli, Vincent Guittot, Paul Moore,
	Andy Shevchenko, Paul E. McKenney, Shakeel Butt,
	Christian König
  Cc: David Howells, Simona Vetter, Randy Dunlap, Luca Ceresoli,
	Philipp Stanner, linux-block, linux-kernel, cgroups,
	linux-ntfs-dev, linux-fsdevel, io-uring, audit, bpf, netdev,
	dri-devel, linux-perf-users, linux-trace-kernel, kexec,
	live-patching, linux-modules, linux-crypto, linux-pm, rcu,
	sched-ext, linux-mm, virtualization, damon, llvm, Kaitao Cheng
In-Reply-To: <20260622040533.29824-1-kaitao.cheng@linux.dev>

From: Kaitao Cheng <chengkaitao@kylinos.cn>

The list_for_each*_safe() helpers are used when the loop body may
remove the current entry.  Their API exposes the temporary cursor at
every call site, even though most users only need it for the iterator
implementation and never reference it in the loop body.

Add *_mutable() variants for list and hlist iteration.  The new helpers
support both forms: callers may keep passing an explicit temporary cursor
when they need to inspect or reset it, or omit it and let the helper use
a unique internal cursor.

This makes call sites that only mutate the list through the current entry
less noisy, while keeping the existing *_safe() helpers available for
compatibility.

Signed-off-by: Kaitao Cheng <chengkaitao@kylinos.cn>
---
 include/linux/list.h | 269 +++++++++++++++++++++++++++++++++++++------
 1 file changed, 231 insertions(+), 38 deletions(-)

diff --git a/include/linux/list.h b/include/linux/list.h
index 09d979976b3b..1081def7cea9 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -7,6 +7,7 @@
 #include <linux/stddef.h>
 #include <linux/poison.h>
 #include <linux/const.h>
+#include <linux/args.h>
 
 #include <asm/barrier.h>
 
@@ -763,28 +764,72 @@ static inline void list_splice_tail_init(struct list_head *list,
 #define list_for_each_prev(pos, head) \
 	for (pos = (head)->prev; !list_is_head(pos, (head)); pos = pos->prev)
 
-/**
- * list_for_each_safe - iterate over a list safe against removal of list entry
- * @pos:	the &struct list_head to use as a loop cursor.
- * @n:		another &struct list_head to use as temporary storage
- * @head:	the head for your list.
+/*
+ * list_for_each_safe is an old interface, use list_for_each_mutable instead.
  */
 #define list_for_each_safe(pos, n, head) \
 	for (pos = (head)->next, n = pos->next; \
 	     !list_is_head(pos, (head)); \
 	     pos = n, n = pos->next)
 
+#define __list_for_each_mutable_internal(pos, tmp, head)		\
+	for (typeof(pos) tmp = (pos = (head)->next)->next;		\
+	     !list_is_head(pos, (head));				\
+	     pos = tmp, tmp = pos->next)
+
+#define __list_for_each_mutable1(pos, head)				\
+	__list_for_each_mutable_internal(pos, __UNIQUE_ID(next), head)
+
+#define __list_for_each_mutable2(pos, next, head)			\
+	list_for_each_safe(pos, next, head)
+
 /**
- * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
+ * list_for_each_mutable - iterate over a list safe against entry removal
  * @pos:	the &struct list_head to use as a loop cursor.
- * @n:		another &struct list_head to use as temporary storage
- * @head:	the head for your list.
+ * @...:	either (head) or (next, head)
+ *
+ * next:	another &struct list_head to use as optional temporary storage.
+ *		The temporary cursor is internal unless explicitly supplied by
+ *		the caller.
+ * head:	the head for your list.
+ */
+#define list_for_each_mutable(pos, ...)					\
+	CONCATENATE(__list_for_each_mutable, COUNT_ARGS(__VA_ARGS__))	\
+		(pos, __VA_ARGS__)
+
+/*
+ * list_for_each_prev_safe is an old interface, use list_for_each_prev_mutable instead.
  */
 #define list_for_each_prev_safe(pos, n, head) \
 	for (pos = (head)->prev, n = pos->prev; \
 	     !list_is_head(pos, (head)); \
 	     pos = n, n = pos->prev)
 
+#define __list_for_each_prev_mutable_internal(pos, tmp, head)		\
+	for (typeof(pos) tmp = (pos = (head)->prev)->prev;		\
+	     !list_is_head(pos, (head));				\
+	     pos = tmp, tmp = pos->prev)
+
+#define __list_for_each_prev_mutable1(pos, head)			\
+	__list_for_each_prev_mutable_internal(pos, __UNIQUE_ID(prev), head)
+
+#define __list_for_each_prev_mutable2(pos, prev, head)			\
+	list_for_each_prev_safe(pos, prev, head)
+
+/**
+ * list_for_each_prev_mutable - iterate over a list backwards safe against entry removal
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @...:	either (head) or (prev, head)
+ *
+ * prev:	another &struct list_head to use as optional temporary storage.
+ *		The temporary cursor is internal unless explicitly supplied by
+ *		the caller.
+ * head:	the head for your list.
+ */
+#define list_for_each_prev_mutable(pos, ...)				\
+	CONCATENATE(__list_for_each_prev_mutable, COUNT_ARGS(__VA_ARGS__)) \
+		(pos, __VA_ARGS__)
+
 /**
  * list_count_nodes - count nodes in the list
  * @head:	the head for your list.
@@ -895,12 +940,8 @@ static inline size_t list_count_nodes(struct list_head *head)
 	for (; !list_entry_is_head(pos, head, member);			\
 	     pos = list_prev_entry(pos, member))
 
-/**
- * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @pos:	the type * to use as a loop cursor.
- * @n:		another type * to use as temporary storage
- * @head:	the head for your list.
- * @member:	the name of the list_head within the struct.
+/*
+ * list_for_each_entry_safe is an old interface, use list_for_each_entry_mutable instead.
  */
 #define list_for_each_entry_safe(pos, n, head, member)			\
 	for (pos = list_first_entry(head, typeof(*pos), member),	\
@@ -908,15 +949,36 @@ static inline size_t list_count_nodes(struct list_head *head)
 	     !list_entry_is_head(pos, head, member); 			\
 	     pos = n, n = list_next_entry(n, member))
 
+#define __list_for_each_entry_mutable_internal(pos, tmp, head, member)	\
+	for (typeof(pos) tmp = list_next_entry(pos =			\
+		list_first_entry(head, typeof(*pos), member), member);	\
+	     !list_entry_is_head(pos, head, member);			\
+	     pos = tmp, tmp = list_next_entry(tmp, member))
+
+#define __list_for_each_entry_mutable2(pos, head, member)		\
+	__list_for_each_entry_mutable_internal(pos, __UNIQUE_ID(next), head, member)
+
+#define __list_for_each_entry_mutable3(pos, next, head, member)		\
+	list_for_each_entry_safe(pos, next, head, member)
+
 /**
- * list_for_each_entry_safe_continue - continue list iteration safe against removal
+ * list_for_each_entry_mutable - iterate over a list safe against entry removal
  * @pos:	the type * to use as a loop cursor.
- * @n:		another type * to use as temporary storage
- * @head:	the head for your list.
- * @member:	the name of the list_head within the struct.
+ * @...:	either (head, member) or (next, head, member)
  *
- * Iterate over list of given type, continuing after current point,
- * safe against removal of list entry.
+ * next:	another type * to use as optional temporary storage. The
+ *		temporary cursor is internal unless explicitly supplied by the
+ *		caller.
+ * head:	the head for your list.
+ * member:	the name of the list_head within the struct.
+ */
+#define list_for_each_entry_mutable(pos, ...)				\
+	CONCATENATE(__list_for_each_entry_mutable, COUNT_ARGS(__VA_ARGS__)) \
+		(pos, __VA_ARGS__)
+
+/*
+ * list_for_each_entry_safe_continue is an old interface,
+ * use list_for_each_entry_mutable_continue instead.
  */
 #define list_for_each_entry_safe_continue(pos, n, head, member) 		\
 	for (pos = list_next_entry(pos, member), 				\
@@ -924,30 +986,79 @@ static inline size_t list_count_nodes(struct list_head *head)
 	     !list_entry_is_head(pos, head, member);				\
 	     pos = n, n = list_next_entry(n, member))
 
+#define __list_for_each_entry_mutable_continue_internal(pos, tmp, head, member) \
+	for (typeof(pos) tmp = list_next_entry(pos =			\
+		list_next_entry(pos, member), member);			\
+	     !list_entry_is_head(pos, head, member);			\
+	     pos = tmp, tmp = list_next_entry(tmp, member))
+
+#define __list_for_each_entry_mutable_continue2(pos, head, member)	\
+	__list_for_each_entry_mutable_continue_internal(pos,		\
+		__UNIQUE_ID(next), head, member)
+
+#define __list_for_each_entry_mutable_continue3(pos, next, head, member) \
+	list_for_each_entry_safe_continue(pos, next, head, member)
+
 /**
- * list_for_each_entry_safe_from - iterate over list from current point safe against removal
+ * list_for_each_entry_mutable_continue - continue list iteration safe against removal
  * @pos:	the type * to use as a loop cursor.
- * @n:		another type * to use as temporary storage
- * @head:	the head for your list.
- * @member:	the name of the list_head within the struct.
+ * @...:	either (head, member) or (next, head, member)
  *
- * Iterate over list of given type from current point, safe against
- * removal of list entry.
+ * next:	another type * to use as optional temporary storage. The
+ *		temporary cursor is internal unless explicitly supplied by the
+ *		caller.
+ * head:	the head for your list.
+ * member:	the name of the list_head within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of list entry.
+ */
+#define list_for_each_entry_mutable_continue(pos, ...)			\
+	CONCATENATE(__list_for_each_entry_mutable_continue,		\
+		COUNT_ARGS(__VA_ARGS__))(pos, __VA_ARGS__)
+
+/*
+ * list_for_each_entry_safe_from is an old interface,
+ * use list_for_each_entry_mutable_from instead.
  */
 #define list_for_each_entry_safe_from(pos, n, head, member) 			\
 	for (n = list_next_entry(pos, member);					\
 	     !list_entry_is_head(pos, head, member);				\
 	     pos = n, n = list_next_entry(n, member))
 
+#define __list_for_each_entry_mutable_from_internal(pos, tmp, head, member) \
+	for (typeof(pos) tmp = list_next_entry(pos, member);		\
+	     !list_entry_is_head(pos, head, member);			\
+	     pos = tmp, tmp = list_next_entry(tmp, member))
+
+#define __list_for_each_entry_mutable_from2(pos, head, member)		\
+	__list_for_each_entry_mutable_from_internal(pos,		\
+		__UNIQUE_ID(next), head, member)
+
+#define __list_for_each_entry_mutable_from3(pos, next, head, member)	\
+	list_for_each_entry_safe_from(pos, next, head, member)
+
 /**
- * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
+ * list_for_each_entry_mutable_from - iterate over list from current point safe against removal
  * @pos:	the type * to use as a loop cursor.
- * @n:		another type * to use as temporary storage
- * @head:	the head for your list.
- * @member:	the name of the list_head within the struct.
+ * @...:	either (head, member) or (next, head, member)
  *
- * Iterate backwards over list of given type, safe against removal
- * of list entry.
+ * next:	another type * to use as optional temporary storage. The
+ *		temporary cursor is internal unless explicitly supplied by the
+ *		caller.
+ * head:	the head for your list.
+ * member:	the name of the list_head within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of list entry.
+ */
+#define list_for_each_entry_mutable_from(pos, ...)			\
+	CONCATENATE(__list_for_each_entry_mutable_from,			\
+		COUNT_ARGS(__VA_ARGS__))(pos, __VA_ARGS__)
+
+/*
+ * list_for_each_entry_safe_reverse is an old interface,
+ * use list_for_each_entry_mutable_reverse instead.
  */
 #define list_for_each_entry_safe_reverse(pos, n, head, member)		\
 	for (pos = list_last_entry(head, typeof(*pos), member),		\
@@ -955,6 +1066,37 @@ static inline size_t list_count_nodes(struct list_head *head)
 	     !list_entry_is_head(pos, head, member); 			\
 	     pos = n, n = list_prev_entry(n, member))
 
+#define __list_for_each_entry_mutable_reverse_internal(pos, tmp, head, member) \
+	for (typeof(pos) tmp = list_prev_entry(pos =			\
+		list_last_entry(head, typeof(*pos), member), member);	\
+	     !list_entry_is_head(pos, head, member);			\
+	     pos = tmp, tmp = list_prev_entry(tmp, member))
+
+#define __list_for_each_entry_mutable_reverse2(pos, head, member)	\
+	__list_for_each_entry_mutable_reverse_internal(pos,		\
+		__UNIQUE_ID(prev), head, member)
+
+#define __list_for_each_entry_mutable_reverse3(pos, prev, head, member)	\
+	list_for_each_entry_safe_reverse(pos, prev, head, member)
+
+/**
+ * list_for_each_entry_mutable_reverse - iterate backwards over list safe against removal
+ * @pos:	the type * to use as a loop cursor.
+ * @...:	either (head, member) or (prev, head, member)
+ *
+ * prev:	another type * to use as optional temporary storage. The
+ *		temporary cursor is internal unless explicitly supplied by the
+ *		caller.
+ * head:	the head for your list.
+ * member:	the name of the list_head within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
+ */
+#define list_for_each_entry_mutable_reverse(pos, ...)			\
+	CONCATENATE(__list_for_each_entry_mutable_reverse,		\
+		COUNT_ARGS(__VA_ARGS__))(pos, __VA_ARGS__)
+
 /**
  * list_safe_reset_next - reset a stale list_for_each_entry_safe loop
  * @pos:	the loop cursor used in the list_for_each_entry_safe loop
@@ -1189,6 +1331,31 @@ static inline void hlist_splice_init(struct hlist_head *from,
 	for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
 	     pos = n)
 
+#define __hlist_for_each_mutable_internal(pos, tmp, head)		\
+	for (typeof(pos) tmp = (pos = (head)->first) ? pos->next : NULL; \
+	     pos;							\
+	     pos = tmp, tmp = pos ? pos->next : NULL)
+
+#define __hlist_for_each_mutable1(pos, head)				\
+	__hlist_for_each_mutable_internal(pos, __UNIQUE_ID(next), head)
+
+#define __hlist_for_each_mutable2(pos, next, head)			\
+	hlist_for_each_safe(pos, next, head)
+
+/**
+ * hlist_for_each_mutable - iterate over a hlist safe against entry removal
+ * @pos:	the &struct hlist_node to use as a loop cursor.
+ * @...:	either (head) or (next, head)
+ *
+ * next:	another &struct hlist_node to use as optional temporary storage.
+ *		The temporary cursor is internal unless explicitly supplied by
+ *		the caller.
+ * head:	the head for your hlist.
+ */
+#define hlist_for_each_mutable(pos, ...)				\
+	CONCATENATE(__hlist_for_each_mutable, COUNT_ARGS(__VA_ARGS__))	\
+		(pos, __VA_ARGS__)
+
 #define hlist_entry_safe(ptr, type, member) \
 	({ typeof(ptr) ____ptr = (ptr); \
 	   ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
@@ -1224,18 +1391,44 @@ static inline void hlist_splice_init(struct hlist_head *from,
 	for (; pos;							\
 	     pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
 
-/**
- * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @pos:	the type * to use as a loop cursor.
- * @n:		a &struct hlist_node to use as temporary storage
- * @head:	the head for your list.
- * @member:	the name of the hlist_node within the struct.
+/*
+ * hlist_for_each_entry_safe is an old interface, use hlist_for_each_entry_mutable instead.
  */
 #define hlist_for_each_entry_safe(pos, n, head, member) 		\
 	for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\
 	     pos && ({ n = pos->member.next; 1; });			\
 	     pos = hlist_entry_safe(n, typeof(*pos), member))
 
+#define __hlist_for_each_entry_mutable_internal(pos, tmp, head, member)	\
+	for (struct hlist_node *tmp = (pos =				\
+		hlist_entry_safe((head)->first, typeof(*pos), member)) ? \
+		pos->member.next : NULL;				\
+	     pos;							\
+	     pos = hlist_entry_safe((tmp), typeof(*pos), member),	\
+		tmp = pos ? pos->member.next : NULL)
+
+#define __hlist_for_each_entry_mutable2(pos, head, member)		\
+	__hlist_for_each_entry_mutable_internal(pos,			\
+		__UNIQUE_ID(next), head, member)
+
+#define __hlist_for_each_entry_mutable3(pos, next, head, member)	\
+	hlist_for_each_entry_safe(pos, next, head, member)
+
+/**
+ * hlist_for_each_entry_mutable - iterate over hlist safe against entry removal
+ * @pos:	the type * to use as a loop cursor.
+ * @...:	either (head, member) or (next, head, member)
+ *
+ * next:	a &struct hlist_node to use as optional temporary storage. The
+ *		temporary cursor is internal unless explicitly supplied by the
+ *		caller.
+ * head:	the head for your hlist.
+ * member:	the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_mutable(pos, ...)				\
+	CONCATENATE(__hlist_for_each_entry_mutable,			\
+		COUNT_ARGS(__VA_ARGS__))(pos, __VA_ARGS__)
+
 /**
  * hlist_count_nodes - count nodes in the hlist
  * @head:	the head for your hlist.
-- 
2.43.0


^ permalink raw reply related

* [PATCH v3 0/7] Prepare mutable list iterators to cache cursor state
From: Kaitao Cheng @ 2026-06-22  4:05 UTC (permalink / raw)
  To: Andrew Morton, David Hildenbrand, Jens Axboe, Tejun Heo,
	Alexander Viro, Christian Brauner, Alexei Starovoitov,
	Daniel Borkmann, Andrii Nakryiko, Johannes Weiner, Peter Zijlstra,
	Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim,
	Thomas Gleixner, Juri Lelli, Vincent Guittot, Paul Moore,
	Andy Shevchenko, Paul E. McKenney, Shakeel Butt,
	Christian König
  Cc: David Howells, Simona Vetter, Randy Dunlap, Luca Ceresoli,
	Philipp Stanner, linux-block, linux-kernel, cgroups,
	linux-ntfs-dev, linux-fsdevel, io-uring, audit, bpf, netdev,
	dri-devel, linux-perf-users, linux-trace-kernel, kexec,
	live-patching, linux-modules, linux-crypto, linux-pm, rcu,
	sched-ext, linux-mm, virtualization, damon, llvm, chengkaitao

From: chengkaitao <chengkaitao@kylinos.cn>

The list_for_each*_safe() helpers are used when the loop body may remove
the current entry.  Their current interface, however, forces every caller
to define a temporary cursor outside the macro and pass it in, even when
the caller never uses that cursor directly.  For most call sites this
extra cursor is just boilerplate required by the macro implementation.

This is awkward because the saved next pointer is an internal detail of
the iteration.  Callers that only remove or move the current entry do not
need to spell it out.

The _safe() suffix has also caused confusion.  Christian Koenig pointed
out that the name is easy to read as a thread-safe variant, especially
for beginners, even though it only means that the iterator keeps enough
state to tolerate removal of the current entry.  He suggested _mutable()
as a clearer description of what the loop permits.

Add *_mutable() iterator variants for list, hlist and llist.  The new
helpers are variadic and support both forms.  In the common case, the
caller omits the temporary cursor and the macro creates a unique internal
cursor with typeof(pos) and __UNIQUE_ID().  If a loop really needs an
explicit temporary cursor, the caller can still pass it and the helper
keeps the existing *_safe() behaviour.

For example, a call site may use the shorter form:

  list_for_each_entry_mutable(pos, head, member)

or keep the explicit temporary cursor form:

  list_for_each_entry_mutable(pos, tmp, head, member)

The existing *_safe() helpers remain available for compatibility.  This
series only converts users in mm, block, kernel, init and io_uring.  If
this approach looks acceptable, the remaining users can be converted in
follow-up series.

Changes in v3 (Christian König, Andy Shevchenko):
- Convert safe list walks to mutable iterators

Changes in v2 (Muchun Song, Andy Shevchenko):
- Drop the list_for_each_entry_mutable*() helpers from v1 and make the
  cursor change directly in the existing list_for_each_entry*() helpers.
- Open-code special list walks that rely on updating the loop cursor in
  the body, preserving their existing traversal semantics.

Link to v2:
https://lore.kernel.org/all/20260609061347.93688-1-kaitao.cheng@linux.dev/

Link to v1:
https://lore.kernel.org/all/20260529082149.76764-1-kaitao.cheng@linux.dev/

Kaitao Cheng (7):
  list: Add mutable iterator variants
  llist: Add mutable iterator variants
  mm: Use mutable list iterators
  block: Use mutable list iterators
  kernel: Use mutable list iterators
  initramfs: Use mutable list iterator
  io_uring: Use mutable list iterators

 block/bfq-iosched.c                 |  17 +-
 block/blk-cgroup.c                  |  12 +-
 block/blk-flush.c                   |   4 +-
 block/blk-iocost.c                  |  18 +-
 block/blk-mq.c                      |   8 +-
 block/blk-throttle.c                |   4 +-
 block/kyber-iosched.c               |   4 +-
 block/partitions/ldm.c              |   8 +-
 block/sed-opal.c                    |   4 +-
 include/linux/list.h                | 269 ++++++++++++++++++++++++----
 include/linux/llist.h               |  81 +++++++--
 init/initramfs.c                    |   5 +-
 io_uring/cancel.c                   |   6 +-
 io_uring/poll.c                     |   3 +-
 io_uring/rw.c                       |   4 +-
 io_uring/timeout.c                  |   8 +-
 io_uring/uring_cmd.c                |   3 +-
 kernel/audit_tree.c                 |   4 +-
 kernel/audit_watch.c                |  16 +-
 kernel/auditfilter.c                |   4 +-
 kernel/auditsc.c                    |   4 +-
 kernel/bpf/arena.c                  |  10 +-
 kernel/bpf/arraymap.c               |   8 +-
 kernel/bpf/bpf_local_storage.c      |   3 +-
 kernel/bpf/bpf_lru_list.c           |  25 ++-
 kernel/bpf/btf.c                    |  18 +-
 kernel/bpf/cgroup.c                 |   7 +-
 kernel/bpf/cpumap.c                 |   4 +-
 kernel/bpf/devmap.c                 |  10 +-
 kernel/bpf/helpers.c                |   8 +-
 kernel/bpf/local_storage.c          |   4 +-
 kernel/bpf/memalloc.c               |  16 +-
 kernel/bpf/offload.c                |   8 +-
 kernel/bpf/states.c                 |   4 +-
 kernel/bpf/stream.c                 |   4 +-
 kernel/bpf/verifier.c               |   6 +-
 kernel/cgroup/cgroup-v1.c           |   4 +-
 kernel/cgroup/cgroup.c              |  54 +++---
 kernel/cgroup/dmem.c                |  12 +-
 kernel/cgroup/rdma.c                |   8 +-
 kernel/events/core.c                |  44 +++--
 kernel/events/uprobes.c             |  12 +-
 kernel/exit.c                       |   8 +-
 kernel/fail_function.c              |   4 +-
 kernel/gcov/clang.c                 |   4 +-
 kernel/irq_work.c                   |   4 +-
 kernel/kexec_core.c                 |   4 +-
 kernel/kprobes.c                    |  16 +-
 kernel/livepatch/core.c             |   4 +-
 kernel/livepatch/core.h             |   4 +-
 kernel/liveupdate/kho_block.c       |   4 +-
 kernel/liveupdate/luo_flb.c         |   4 +-
 kernel/locking/rwsem.c              |   2 +-
 kernel/locking/test-ww_mutex.c      |   2 +-
 kernel/module/main.c                |  11 +-
 kernel/padata.c                     |   4 +-
 kernel/power/snapshot.c             |   8 +-
 kernel/power/wakelock.c             |   4 +-
 kernel/printk/printk.c              |  11 +-
 kernel/ptrace.c                     |   4 +-
 kernel/rcu/rcutorture.c             |   3 +-
 kernel/rcu/tasks.h                  |   9 +-
 kernel/rcu/tree.c                   |   6 +-
 kernel/resource.c                   |   4 +-
 kernel/sched/core.c                 |   4 +-
 kernel/sched/ext.c                  |  22 +--
 kernel/sched/fair.c                 |  28 +--
 kernel/sched/topology.c             |   4 +-
 kernel/sched/wait.c                 |   4 +-
 kernel/seccomp.c                    |   4 +-
 kernel/signal.c                     |  11 +-
 kernel/smp.c                        |   4 +-
 kernel/taskstats.c                  |   8 +-
 kernel/time/clockevents.c           |   6 +-
 kernel/time/clocksource.c           |   4 +-
 kernel/time/posix-cpu-timers.c      |   4 +-
 kernel/time/posix-timers.c          |   3 +-
 kernel/torture.c                    |   3 +-
 kernel/trace/bpf_trace.c            |   4 +-
 kernel/trace/ftrace.c               |  49 +++--
 kernel/trace/ring_buffer.c          |  25 ++-
 kernel/trace/trace.c                |  12 +-
 kernel/trace/trace_dynevent.c       |   6 +-
 kernel/trace/trace_dynevent.h       |   5 +-
 kernel/trace/trace_events.c         |  35 ++--
 kernel/trace/trace_events_filter.c  |   4 +-
 kernel/trace/trace_events_hist.c    |   8 +-
 kernel/trace/trace_events_trigger.c |  17 +-
 kernel/trace/trace_events_user.c    |  16 +-
 kernel/trace/trace_stat.c           |   4 +-
 kernel/user-return-notifier.c       |   3 +-
 kernel/workqueue.c                  |  16 +-
 mm/backing-dev.c                    |   8 +-
 mm/balloon.c                        |   8 +-
 mm/cma.c                            |   4 +-
 mm/compaction.c                     |   4 +-
 mm/damon/core.c                     |   4 +-
 mm/damon/sysfs-schemes.c            |   4 +-
 mm/dmapool.c                        |   4 +-
 mm/huge_memory.c                    |   8 +-
 mm/hugetlb.c                        |  56 +++---
 mm/hugetlb_vmemmap.c                |  16 +-
 mm/khugepaged.c                     |  14 +-
 mm/kmemleak.c                       |   7 +-
 mm/ksm.c                            |  25 +--
 mm/list_lru.c                       |   4 +-
 mm/memcontrol-v1.c                  |   8 +-
 mm/memory-failure.c                 |  12 +-
 mm/memory-tiers.c                   |   4 +-
 mm/migrate.c                        |  23 ++-
 mm/mmu_notifier.c                   |   9 +-
 mm/page_alloc.c                     |   8 +-
 mm/page_reporting.c                 |   2 +-
 mm/percpu.c                         |  11 +-
 mm/pgtable-generic.c                |   4 +-
 mm/rmap.c                           |  10 +-
 mm/shmem.c                          |   9 +-
 mm/slab_common.c                    |  14 +-
 mm/slub.c                           |  33 ++--
 mm/swapfile.c                       |   4 +-
 mm/userfaultfd.c                    |  12 +-
 mm/vmalloc.c                        |  24 +--
 mm/vmscan.c                         |   7 +-
 mm/zsmalloc.c                       |   4 +-
 124 files changed, 875 insertions(+), 681 deletions(-)

-- 
2.43.0


^ permalink raw reply

* RE: [PATCH 3/8] Bluetooth: btnxpuart: Add M.2 Bluetooth device support using pwrseq
From: Sherry Sun @ 2026-06-22  3:51 UTC (permalink / raw)
  To: Frank Li (OSS), Sherry Sun (OSS)
  Cc: robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
	Frank Li, s.hauer@pengutronix.de, kernel@pengutronix.de,
	festevam@gmail.com, Amitkumar Karwar, Neeraj Sanjay Kale,
	marcel@holtmann.org, luiz.dentz@gmail.com, Hongxing Zhu,
	l.stach@pengutronix.de, lpieralisi@kernel.org,
	kwilczynski@kernel.org, mani@kernel.org, bhelgaas@google.com,
	brgl@kernel.org, imx@lists.linux.dev, linux-pci@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-bluetooth@vger.kernel.org,
	linux-pm@vger.kernel.org
In-Reply-To: <ajQ4oBUNGOrhcPX5@SMW015318>

> On Thu, Jun 18, 2026 at 06:10:42PM +0800, Sherry Sun (OSS) wrote:
> > From: Sherry Sun <sherry.sun@nxp.com>
> >
> > Power supply to the M.2 Bluetooth device attached to the host using
> > M.2 connector is controlled using the 'uart' pwrseq device. So add
> > support for getting the pwrseq device if the OF graph link is present.
> > Once obtained, the existing pwrseq APIs can be used to control the
> > power supplies of the
> > M.2 card.
> >
> > Signed-off-by: Sherry Sun <sherry.sun@nxp.com>
> > ---
> >  drivers/bluetooth/btnxpuart.c | 33 ++++++++++++++++++++++++++++++---
> >  1 file changed, 30 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/bluetooth/btnxpuart.c
> > b/drivers/bluetooth/btnxpuart.c index e7036a48ce48..1aa8972f0dab
> > 100644
> > --- a/drivers/bluetooth/btnxpuart.c
> > +++ b/drivers/bluetooth/btnxpuart.c
> > @@ -9,6 +9,8 @@
> >
> >  #include <linux/serdev.h>
> >  #include <linux/of.h>
> > +#include <linux/of_graph.h>
> > +#include <linux/pwrseq/consumer.h>
> >  #include <linux/skbuff.h>
> >  #include <linux/unaligned.h>
> >  #include <linux/firmware.h>
> > @@ -211,6 +213,7 @@ struct btnxpuart_dev {
> >
> >  	struct ps_data psdata;
> >  	struct btnxpuart_data *nxp_data;
> > +	struct pwrseq_desc *pwrseq;
> >  	struct reset_control *pdn;
> >  	struct hci_uart hu;
> >  };
> > @@ -1866,11 +1869,27 @@ static int nxp_serdev_probe(struct
> serdev_device *serdev)
> >  		return err;
> >  	}
> >
> > +	if (of_graph_is_present(dev_of_node(&serdev->ctrl->dev))) {
> > +		struct pwrseq_desc *pwrseq;
> > +
> > +		pwrseq = devm_pwrseq_get(&serdev->ctrl->dev, "uart");
> > +		if (IS_ERR(pwrseq))
> > +			return PTR_ERR(pwrseq);
> > +
> > +		nxpdev->pwrseq = pwrseq;
> > +		err = pwrseq_power_on(pwrseq);
> > +		if (err) {
> > +			dev_err(&serdev->dev, "Failed to power on
> pwrseq\n");
> > +			return err;
> > +		}
> 
> Can you provide helper function like devm clk get and enabled?
> like devm_pwrsq_get_on()
> 
> So simple below error handle.

Ok, will try.

Best Regards
Sherry

> 
> > +	}
> > +
> >  	/* Initialize and register HCI device */
> >  	hdev = hci_alloc_dev();
> >  	if (!hdev) {
> >  		dev_err(&serdev->dev, "Can't allocate HCI device\n");
> > -		return -ENOMEM;
> > +		err = -ENOMEM;
> > +		goto err_pwrseq_power_off;
> >  	}
> >
> >  	reset_control_deassert(nxpdev->pdn);
> > @@ -1903,11 +1922,14 @@ static int nxp_serdev_probe(struct
> > serdev_device *serdev)
> >
> >  	if (hci_register_dev(hdev) < 0) {
> >  		dev_err(&serdev->dev, "Can't register HCI device\n");
> > +		err = -ENODEV;
> >  		goto probe_fail;
> >  	}
> >
> > -	if (ps_setup(hdev))
> > +	if (ps_setup(hdev)) {
> > +		err = -ENODEV;
> >  		goto probe_fail;
> > +	}
> >
> >  	hci_devcd_register(hdev, nxp_coredump, nxp_coredump_hdr,
> >  			   nxp_coredump_notify);
> > @@ -1917,7 +1939,10 @@ static int nxp_serdev_probe(struct
> > serdev_device *serdev)
> >  probe_fail:
> >  	reset_control_assert(nxpdev->pdn);
> >  	hci_free_dev(hdev);
> > -	return -ENODEV;
> > +err_pwrseq_power_off:
> > +	if (nxpdev->pwrseq)
> > +		pwrseq_power_off(nxpdev->pwrseq);
> > +	return err;
> >  }
> >
> >  static void nxp_serdev_remove(struct serdev_device *serdev) @@
> > -1944,6 +1969,8 @@ static void nxp_serdev_remove(struct serdev_device
> *serdev)
> >  	ps_cleanup(nxpdev);
> >  	hci_unregister_dev(hdev);
> >  	reset_control_assert(nxpdev->pdn);
> > +	if (nxpdev->pwrseq)
> > +		pwrseq_power_off(nxpdev->pwrseq);
> >  	hci_free_dev(hdev);
> >  }
> >
> > --
> > 2.50.1
> >
> >

^ permalink raw reply

* RE: [PATCH 0/8] Add PCIe M.2 Key E connector support for NXP i.MX boards
From: Sherry Sun @ 2026-06-22  3:18 UTC (permalink / raw)
  To: Bartosz Golaszewski, Sherry Sun (OSS)
  Cc: imx@lists.linux.dev, linux-pci@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-bluetooth@vger.kernel.org,
	linux-pm@vger.kernel.org, robh@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, Frank Li, s.hauer@pengutronix.de,
	kernel@pengutronix.de, festevam@gmail.com, Amitkumar Karwar,
	Neeraj Sanjay Kale, marcel@holtmann.org, luiz.dentz@gmail.com,
	Hongxing Zhu, l.stach@pengutronix.de, lpieralisi@kernel.org,
	kwilczynski@kernel.org, mani@kernel.org, bhelgaas@google.com
In-Reply-To: <CAMRc=MfsNa4itdpyGtR16wMb+wMkJwg+9=QJF2-oOoVVfFCF3g@mail.gmail.com>

> On Thu, 18 Jun 2026 12:10:39 +0200, "Sherry Sun (OSS)"
> <sherry.sun@oss.nxp.com> said:
> > From: Sherry Sun <sherry.sun@nxp.com>
> >
> > This series adds support for NXP Wi-Fi/BT combo chips (88W9098, AW693)
> > inserted into PCIe M.2 Key E connectors on several i.MX EVK/MEK boards.
> >
> > For M.2 cards that rely on PCIe L2 link state and wake-up mechanisms,
> > the card must remain powered during suspend. Patch 1 uses the existing
> > dw_pcie_rp::skip_pwrctrl_off flag to skip power-off during suspend and
> > skip power-on during the init path.
> >
> > Alsp the btnxpuart driver is extended to obtain a pwrseq descriptor
> > via the OF graph on the UART controller device in patch 2.
> >
> > Sherry Sun (8):
> >   PCI: imx6: Add skip_pwrctrl_off flag support
> >   power: sequencing: pcie-m2: Add PCI ID for NXP 88W9098 and AW693
> >     Bluetooth
> 
> Can this be applied independently without build-time issues?

Hi Bart,

Yes, this patch can be applied independently, I was able to successfully
build it based on the following base-commit:
3ce97bd3c4f18608335e709c24d6a40e7036cab8.

However, please note that it may conflict with the following patch when
applied: https://lore.kernel.org/all/20260617143055.820096-1-wei.deng@oss.qualcomm.com/.

Best Regards
Sherry

> 
> >   Bluetooth: btnxpuart: Add M.2 Bluetooth device support using pwrseq
> >   arm64: dts: imx8mq-evk: Describe the PCIe M.2 Key E connector
> >   arm64: dts: imx95-19x19-evk: Describe the PCIe M.2 Key E connector
> >   arm64: dts: imx8dxl-evk: Describe the PCIe M.2 Key E connector
> >   arm64: dts: imx8qm-mek: Describe the PCIe M.2 Key E connector
> >   arm64: dts: imx8qxp-mek: Describe the PCIe M.2 Key E connector
> >
> >  arch/arm64/boot/dts/freescale/imx8dxl-evk.dts | 56 +++++++++++++-----
> > arch/arm64/boot/dts/freescale/imx8mq-evk.dts  | 44 ++++++++++++--
> > arch/arm64/boot/dts/freescale/imx8qm-mek.dts  | 58 ++++++++++++++-----
> > arch/arm64/boot/dts/freescale/imx8qxp-mek.dts | 54 ++++++++++++-----
> >  .../boot/dts/freescale/imx95-19x19-evk.dts    | 55 +++++++++++++-----
> >  drivers/bluetooth/btnxpuart.c                 | 33 ++++++++++-
> >  drivers/pci/controller/dwc/pci-imx6.c         | 36 +++++++-----
> >  drivers/power/sequencing/pwrseq-pcie-m2.c     |  4 ++
> >  8 files changed, 264 insertions(+), 76 deletions(-)
> >
> > --
> > 2.50.1
> >
> >

^ permalink raw reply

* Re: [PATCH] cpufreq: schedutil: Fix uncleared need_freq_update on the adjust_perf path
From: Zhongqiu Han @ 2026-06-22  2:34 UTC (permalink / raw)
  To: Christian Loehle, Hongyan Xia, rafael@kernel.org,
	viresh.kumar@linaro.org, mingo@redhat.com, peterz@infradead.org,
	juri.lelli@redhat.com, vincent.guittot@linaro.org,
	dietmar.eggemann@arm.com, rostedt@goodmis.org, bsegall@google.com,
	mgorman@suse.de, vschneid@redhat.com, kprateek.nayak@amd.com
  Cc: linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org,
	stable@vger.kernel.org, zhongqiu.han
In-Reply-To: <0767a224-d988-46d9-a535-2b490d990287@arm.com>

On 6/17/2026 3:27 PM, Christian Loehle wrote:
> On 6/17/26 05:06, Hongyan Xia wrote:
>> On 6/16/2026 11:47 PM, Zhongqiu Han wrote:
>>> The need_freq_update flag makes sugov_should_update_freq() return true
>>> regardless of the rate_limit_us throttling, and is cleared in
>>> sugov_update_next_freq(). sugov_update_single_freq() and
>>> sugov_update_shared() go through that helper, so the flag does not
>>> persist there.
>>>
>>> However, sugov_update_single_perf() (used by drivers implementing the
>>> ->adjust_perf() callback, e.g. intel_pstate or amd-pstate in passive mode)
>>> calls cpufreq_driver_adjust_perf() directly and never goes through
>>> sugov_update_next_freq(), so the need_freq_update flag is not cleared in
>>> that path.
>>>
>>> Before commit 75da043d8f88 ("cpufreq/sched: Set need_freq_update in
>>> ignore_dl_rate_limit()"), this was effectively harmless because
>>> sugov_should_update_freq() still honoured the rate limit even when
>>> need_freq_update was set. After that change, the flag forces
>>> sugov_should_update_freq() to always return true, so once set, it stays
>>> effective indefinitely on the adjust_perf path.
>>>
>>> As a result, cpufreq_driver_adjust_perf() gets called on every scheduler
>>> utilization update (with the runqueue lock held) rather than being
>>> throttled by rate_limit_us, even if the driver itself may skip redundant
>>> hardware updates.
>>>
>>> Clear need_freq_update at the end of the adjust_perf path as well.
>>>
>>> Fixes: 75da043d8f88 ("cpufreq/sched: Set need_freq_update in ignore_dl_rate_limit()")
>>> Cc: stable@vger.kernel.org
>>> Signed-off-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
>>> ---
>>>    kernel/sched/cpufreq_schedutil.c | 1 +
>>>    1 file changed, 1 insertion(+)
>>>
>>> diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
>>> index ae9fd211cec1..a4e689eefdfb 100644
>>> --- a/kernel/sched/cpufreq_schedutil.c
>>> +++ b/kernel/sched/cpufreq_schedutil.c
>>> @@ -486,6 +486,7 @@ static void sugov_update_single_perf(struct update_util_data *hook, u64 time,
>>>    	cpufreq_driver_adjust_perf(sg_policy->policy, sg_cpu->bw_min,
>>>    				   sg_cpu->util, max_cap);
>>>    
>>> +	sg_policy->need_freq_update = false;
>>>    	sg_policy->last_freq_update_time = time;
>>
>> Nice catch. Thanks.
>>
>> It does seem to me that setting last_freq_update_time should then assert
>> !need_freq_update, otherwise it doesn't make sense, but that's a
>> different topic.
> +1, feel free to submit that too.

Thanks Hongyan and Christian for the review and suggestions. I'll look
into it.

> 
> For $SUBJECT:
> Reviewed-by: Christian Loehle <christian.loehle@arm.com>


-- 
Thx and BRs,
Zhongqiu Han

^ permalink raw reply

* RE: [PATCH v2 0/6] cpufreq: intel_pstate: Set cpuinfo_min_freq to a lower value with HWP enabled plus cleanups
From: Doug Smythies @ 2026-06-21 23:34 UTC (permalink / raw)
  To: 'Rafael J. Wysocki', 'Linux PM'
  Cc: 'LKML', 'Srinivas Pandruvada'
In-Reply-To: <6005456.DvuYhMxLoT@rafael.j.wysocki>

On 2026.06.19 10:32 Rafael wrote:

> This is in v2 because technically it is an update of
>
> https://lore.kernel.org/linux-pm/2381464.iZASKD2KPV@rafael.j.wysocki/
>
> but it contains new patches.
>
> This series updates the intel_pstate driver to set cpuinfo_min_freq to a lower
> value when HWP is enabled to support systems in which CPUs can actually run
> at performance levels below the current minimum level.
>
> It also carries out some code cleanups, mostly related to HWP, either in
> preparation for the functional changes or top of them.
>
> Thanks!

Hi Rafael,

Is there a way to test this? I have tried everything I can think of and have
been unable to get the processor frequency below the old minimum of 800 MHz.
No matter what I do, I always see greater or equal to 8 for each CPU in the
IA32_PERF_STATUS register, or by looking at non stale entries in:

grep . /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq

Example:
doug@s19:~$ grep . /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq:100000
/sys/devices/system/cpu/cpu10/cpufreq/scaling_cur_freq:100000
/sys/devices/system/cpu/cpu11/cpufreq/scaling_cur_freq:100000
/sys/devices/system/cpu/cpu1/cpufreq/scaling_cur_freq:800013
/sys/devices/system/cpu/cpu2/cpufreq/scaling_cur_freq:800014
/sys/devices/system/cpu/cpu3/cpufreq/scaling_cur_freq:799996
/sys/devices/system/cpu/cpu4/cpufreq/scaling_cur_freq:800023
/sys/devices/system/cpu/cpu5/cpufreq/scaling_cur_freq:800053
/sys/devices/system/cpu/cpu6/cpufreq/scaling_cur_freq:100000
/sys/devices/system/cpu/cpu7/cpufreq/scaling_cur_freq:100000
/sys/devices/system/cpu/cpu8/cpufreq/scaling_cur_freq:100000
/sys/devices/system/cpu/cpu9/cpufreq/scaling_cur_freq:100000

Readers note:
Stale entries are just "scaling_min_freq".
Non-stale entries tend to be not nice round numbers.

For me this patch set introduces confusion between min and max
frequency settings and what I actually get. I can set " scaling_min_freq"
to 100 MHz and "scaling_max_freq" to 100MHz, but never get them.
Before this patch set, I always got what I asked for.

Other details:
Processor: Intel(R) Core(TM) i5-10600K CPU @ 4.10GHz
MSR_PLATFORM_INFO (0x0ce) 808083af1012900
Other stuff from my msr0decoder program:
doug@s19:~$ sudo c/msr-decoder
How many CPUs?: 12
8.) 0x198: IA32_PERF_STATUS     : CPU 11-0 :   8 :   8 :   8 :   8 :   8 :   8 :   8 :   8 :   8 :   8 :   8 :   8 :
B.) 0x770: IA32_PM_ENABLE: 1 : HWP enable
1.) 0x19C: IA32_THERM_STATUS: 88470000
2.) 0x1AA: MSR_MISC_PWR_MGMT: 401CC0 EIST enabled Coordination enabled OOB Bit 8 reset OOB Bit 18 reset
3.) 0x1B1: IA32_PACKAGE_THERM_STATUS: 88450000
4.) 0x64F: MSR_CORE_PERF_LIMIT_REASONS: 200000 RATLL
A.) 0x1FC: MSR_POWER_CTL: 3C005D : C1E disable : EEO disable : RHO disable
5.) 0x771: IA32_HWP_CAPABILITIES (performance): 10B2930 : high 48 : guaranteed 41 : efficient 11 : lowest 1
6.) 0x774: IA32_HWP_REQUEST:    CPU 11-0 :
    raw: 80010101 : 80010101 : 80010101 : 80010101 : 80010101 : 80010101 : 80010101 : 80010101 : 80010101 : 80010101 : 80010101 : 80010101 :
    min:        1 :        1 :        1 :        1 :        1 :        1 :        1 :        1 :        1 :        1 :        1 :        1 :
    max:        1 :        1 :        1 :        1 :        1 :        1 :        1 :        1 :        1 :        1 :        1 :        1 :
    des:        1 :        1 :        1 :        1 :        1 :        1 :        1 :        1 :        1 :        1 :        1 :        1 :
    epp:      128 :      128 :      128 :      128 :      128 :      128 :      128 :      128 :      128 :      128 :      128 :      128 :
    act:        0 :        0 :        0 :        0 :        0 :        0 :        0 :        0 :        0 :        0 :        0 :        0 :
7.) 0x777: IA32_HWP_STATUS: 0 : high 0 : guaranteed 0 : efficient 0 : lowest 0

The driver was intel_cpufreq, governor conservative (but I tried them all). I also tried epp = 255 so as to slow down the processor response time.

... Doug


^ permalink raw reply

* Re: [PATCH v2 0/6] cpufreq: intel_pstate: Set cpuinfo_min_freq to a lower value with HWP enabled plus cleanups
From: srinivas pandruvada @ 2026-06-21 21:50 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM; +Cc: LKML
In-Reply-To: <6005456.DvuYhMxLoT@rafael.j.wysocki>

On Fri, 2026-06-19 at 19:31 +0200, Rafael J. Wysocki wrote:
> Hi,
> 
> This is in v2 because technically it is an update of
> 
> https://lore.kernel.org/linux-pm/2381464.iZASKD2KPV@rafael.j.wysocki/
> 
> but it contains new patches.
> 
> This series updates the intel_pstate driver to set cpuinfo_min_freq
> to a lower
> value when HWP is enabled to support systems in which CPUs can
> actually run
> at performance levels below the current minimum level.
> 

Is this intentional?

HWP_CAP: 0x10f163e
MSR 0xce(platform_info: 0x804043df8811b00

cpu0/cpufreq/cpuinfo_min_freq
100000

cpu0/cpufreq/scaling_min_freq
400000

Thanks,
Srinivas

> It also carries out some code cleanups, mostly related to HWP, either
> in
> preparation for the functional changes or top of them.
> 
> Thanks!
> 
> 
> 

^ permalink raw reply

* Re: [PATCH v1] cpufreq: intel_pstate: Skip HWP_CAP reads in Broadwell mode
From: srinivas pandruvada @ 2026-06-21 21:38 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM; +Cc: Chen Yu, LKML
In-Reply-To: <12920597.O9o76ZdvQC@rafael.j.wysocki>

On Fri, 2026-06-19 at 21:24 +0200, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> 
> When running in the Broadwell HWP mode, the turbo, max and min
> P-state values are retrieved from MSR_PLATFORM_INFO, so reading
> MSR_HWP_CAPABILITIES in that mode in order to update those values
> is pointless.  Moreover, using the MSR_HWP_CAPABILITIES value for
> updating them in the Broadwell mode may be harmful, so avoid doing
> that altogether.
> 
> Fixes: de5bcf404ace ("cpufreq: intel_pstate: Clean up frequency
> computations")


Can't apply this patch on the latest Linux master even after applying
prior 6 patches.
What is this based on?

Thanks,
Srinivas

> Link:
> https://sashiko.dev/#/patchset/6005456.DvuYhMxLoT%40rafael.j.wysocki
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> Cc: All applicable <stable@vger.kernel.org>
> ---
>  drivers/cpufreq/intel_pstate.c |    3 +++
>  1 file changed, 3 insertions(+)
> 
> --- a/drivers/cpufreq/intel_pstate.c
> +++ b/drivers/cpufreq/intel_pstate.c
> @@ -1197,6 +1197,9 @@ static void intel_pstate_get_hwp_cap(str
>  {
>  	int scaling = cpu->pstate.scaling;
>  
> +	if (hwp_mode_bdw)
> +		return;
> +
>  	__intel_pstate_get_hwp_cap(cpu);
>  
>  	cpu->pstate.max_freq = cpu->pstate.max_pstate * scaling;
> 
> 
> 

^ permalink raw reply

* Re: [PATCH] pmdomain: bcm: bcm2835-power: Raise ASB poll timeout to 100us
From: Florian Fainelli @ 2026-06-21 20:13 UTC (permalink / raw)
  To: Maíra Canal, Stefan Wahren, Ulf Hansson,
	Broadcom internal kernel review list, Ray Jui, Scott Branden
  Cc: linux-pm, linux-rpi-kernel, linux-arm-kernel, kernel-dev
In-Reply-To: <4af63689-e08c-406e-9ec3-f56dcbfb6f91@igalia.com>



On 6/19/2026 2:57 PM, Maíra Canal wrote:
> Hi,
> 
> On 31/05/26 09:18, Maíra Canal wrote:
>> Hi Stefan,
>>
>> On 31/05/26 07:41, Stefan Wahren wrote:
>>> Hi Maíra,
>>>
>>> Am 30.05.26 um 22:46 schrieb Maíra Canal:
>>>> Commit 18605b1b936b ("pmdomain: bcm: bcm2835-power: Increase ASB 
>>>> control
>>>> timeout") raised the ASB handshake polling budget from 1us to 5us.
>>>> Surveying the pmdomain subsystem, 5us is still one of the smallest 
>>>> polling
>>>> budgets by a wide margin. Comparable handshakes in other drivers use:
>>>>
>>>>    - 100us : starfive jh71xx-pmu, apple pmgr-pwrstate
>>>>    - 1ms   : renesas rcar-sysc, rmobile-sysc (power-on)
>>>>    - 10ms  : renesas rcar-gen4-sysc, sunxi sun55i-pck600
>>>>    - 1s    : mediatek mtk-pm-domains, mtk-scpsys
>>>>
>>>> Raise the BCM2835 timeout to 100us, matching analogous drivers. 
>>>> 100us is
>>>> still negligible relative to a power-domain transition and gives the 
>>>> V3D
>>>> master ASB substantially more headroom to drain under heavy workloads,
>>>> assuring us that the timeout is enough for any scenario.
>>> tbh I'm not convinced by this explanation. Starting with a timeout 
>>> comparison across different pmdomain driver looks strange to me.
>>>
>>> My expectation that the reason for such a patch is that there is some 
>>> kind of scenario to trigger unexpected timeouts.
>>> If this is the case, please provide more information about the 
>>> scenario (specific platform, scenario, link to the bug report).
>>
>> The context: I was debugging this issue [1] and initially I had the
>> intuition that it could be related to a timeout in the ASB polling loop.
>> As I don't have access to the BCM2835 SoC datasheet (the public one
>> doesn't have PM information), I started to check other driver's
>> handshake timeout to see if ours was comparable to similar drivers. As
>> you can see, our timeout is much smaller.
>>
>> In the end, issue [1] wasn't related to the pmdomain driver, so I don't
>> have a specific scenario to trigger this issue. Even though, I sent this
>> patch considering the comparison to other drivers with the goal to be
>> conservative and use a larger timeout that could accommodate an extreme
>> scenario. However, if you believe it's unreasonable, I'm okay dropping
>> this patch.
>>
>> Ideally, it would be great to have information from Broadcom on what's
>> the largest possible time required to perform a power transition. Maybe
>> Florian could help us with that?
>>
> 
> Gentle ping, any ideas about this?

I think it's reasonable in the sense that if there is a lot of traffic 
posted on the AXI asynchronous bridge it will take longer for the 
acknowledgement to come, I asked the designers whether 100us is 
reasonable or not and will get back to you as soon as I get an answer.
-- 
Florian


^ permalink raw reply

* Re: [PATCH v2] cpufreq: intel_pstate: Adjust the .adjust_perf() driver callback
From: Mario Limonciello @ 2026-06-21 19:07 UTC (permalink / raw)
  To: Zhongqiu Han, Rafael J. Wysocki, Linux PM
  Cc: LKML, Viresh Kumar, Srinivas Pandruvada, Christian Loehle,
	Peter Zijlstra, Vincent Guittot
In-Reply-To: <56a6b35a-407f-4529-b655-27d6cde5e595@oss.qualcomm.com>

On 6/19/26 08:43, Zhongqiu Han wrote:
> On 6/19/2026 10:52 PM, Rafael J. Wysocki wrote:
>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>
>> In some cases, the processor may not actually stick to the "desired"
>> performance level programmed through the driver's .adjust_perf()
>> callback and may go above it, which may not be desirable (for instance,
>> there may be a UCLAMP_MAX limit set for the task currently running on
>> the given CPU which should be respected).
>>
>> Address that by adjusting the .adjust_perf() callback to take an
>> additional argument, max_perf, representing the maximum allowed
>> performance level of the CPU and update the intel_pstate driver to
>> take that argument into account as appropriate.
>>
>> Accordingly, adjust cpufreq_driver_adjust_perf() and the other existing
>> user of .adjust_perf(), which is the amd-pstate driver (but the behavior
>> of that driver is not changed).
>>
>> While at it, also update the cpufreq_driver_adjust_perf()
>> documentation to reflect this change and some previous code
>> changes that have not been taken into account in it.
>>
>> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>> Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
> 
> Looks good to me. Thanks
> 
> Reviewed-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>

Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
> 
>> ---
>>
>> This is an update of
>>
>> https://lore.kernel.org/linux-pm/14060154.uLZWGnKmhe@rafael.j.wysocki/
>>
>> sent mainly because the v1 did not update the Rust bindings by
>> omission.  It also fixes a few typos present in the v1.
>>
>> Thanks!
>>
>> ---
>>   drivers/cpufreq/amd-pstate.c     |    1 +
>>   drivers/cpufreq/cpufreq.c        |   14 +++++++++-----
>>   drivers/cpufreq/intel_pstate.c   |    9 ++++++++-
>>   include/linux/cpufreq.h          |    2 ++
>>   kernel/sched/cpufreq_schedutil.c |    4 +++-
>>   rust/kernel/cpufreq.rs           |    6 ++++--
>>   6 files changed, 27 insertions(+), 9 deletions(-)
>>
>> --- a/drivers/cpufreq/amd-pstate.c
>> +++ b/drivers/cpufreq/amd-pstate.c
>> @@ -781,6 +781,7 @@ static unsigned int amd_pstate_fast_swit
>>   static void amd_pstate_adjust_perf(struct cpufreq_policy *policy,
>>                      unsigned long _min_perf,
>>                      unsigned long target_perf,
>> +                   unsigned long _max_perf,
>>                      unsigned long capacity)
>>   {
>>       u8 max_perf, min_perf, des_perf, cap_perf;
>> --- a/drivers/cpufreq/cpufreq.c
>> +++ b/drivers/cpufreq/cpufreq.c
>> @@ -2252,14 +2252,17 @@ EXPORT_SYMBOL_GPL(cpufreq_driver_fast_sw
>>    * @policy: cpufreq policy object of the target CPU.
>>    * @min_perf: Minimum (required) performance level (units of 
>> @capacity).
>>    * @target_perf: Target (desired) performance level (units of 
>> @capacity).
>> + * @max_perf: Maximum (allowed) performance level (units of @capacity).
>>    * @capacity: Capacity of the target CPU.
>>    *
>> - * Carry out a fast performance level switch of @cpu without sleeping.
>> + * Carry out a fast performance level adjustment for the CPU 
>> represented by
>> + * @policy without sleeping.
>>    *
>>    * The driver's ->adjust_perf() callback invoked by this function 
>> must be
>> - * suitable for being called from within RCU-sched read-side critical 
>> sections
>> - * and it is expected to select a suitable performance level equal to 
>> or above
>> - * @min_perf and preferably equal to or below @target_perf.
>> + * suitable for calling from within RCU-sched read-side critical 
>> sections and
>> + * it is expected to program the processor to select suitable 
>> performance
>> + * levels between @min_perf and @max_perf inclusive and preferably 
>> close to
>> + * @target_perf going forward for the CPU represented by @policy.
>>    *
>>    * This function must not be called if policy->fast_switch_enabled 
>> is unset.
>>    *
>> @@ -2271,9 +2274,10 @@ EXPORT_SYMBOL_GPL(cpufreq_driver_fast_sw
>>   void cpufreq_driver_adjust_perf(struct cpufreq_policy *policy,
>>                    unsigned long min_perf,
>>                    unsigned long target_perf,
>> +                 unsigned long max_perf,
>>                    unsigned long capacity)
>>   {
>> -    cpufreq_driver->adjust_perf(policy, min_perf, target_perf, 
>> capacity);
>> +    cpufreq_driver->adjust_perf(policy, min_perf, target_perf, 
>> max_perf, capacity);
>>   }
>>   /**
>> --- a/drivers/cpufreq/intel_pstate.c
>> +++ b/drivers/cpufreq/intel_pstate.c
>> @@ -3241,6 +3241,7 @@ static unsigned int intel_cpufreq_fast_s
>>   static void intel_cpufreq_adjust_perf(struct cpufreq_policy *policy,
>>                         unsigned long min_perf,
>>                         unsigned long target_perf,
>> +                      unsigned long max_perf,
>>                         unsigned long capacity)
>>   {
>>       struct cpudata *cpu = all_cpu_data[policy->cpu];
>> @@ -3271,7 +3272,13 @@ static void intel_cpufreq_adjust_perf(st
>>       if (min_pstate > cpu->max_perf_ratio)
>>           min_pstate = cpu->max_perf_ratio;
>> -    max_pstate = min(cap_pstate, cpu->max_perf_ratio);
>> +    max_pstate = cap_pstate;
>> +    if (max_perf < capacity)
>> +        max_pstate = DIV_ROUND_UP(cap_pstate * max_perf, capacity);
>> +
>> +    if (max_pstate > cpu->max_perf_ratio)
>> +        max_pstate = cpu->max_perf_ratio;
>> +
>>       if (max_pstate < min_pstate)
>>           max_pstate = min_pstate;
>> --- a/include/linux/cpufreq.h
>> +++ b/include/linux/cpufreq.h
>> @@ -379,6 +379,7 @@ struct cpufreq_driver {
>>       void        (*adjust_perf)(struct cpufreq_policy *policy,
>>                          unsigned long min_perf,
>>                          unsigned long target_perf,
>> +                       unsigned long max_perf,
>>                          unsigned long capacity);
>>       /*
>> @@ -624,6 +625,7 @@ unsigned int cpufreq_driver_fast_switch(
>>   void cpufreq_driver_adjust_perf(struct cpufreq_policy *policy,
>>                   unsigned long min_perf,
>>                   unsigned long target_perf,
>> +                unsigned long max_perf,
>>                   unsigned long capacity);
>>   bool cpufreq_driver_has_adjust_perf(void);
>>   int cpufreq_driver_target(struct cpufreq_policy *policy,
>> --- a/kernel/sched/cpufreq_schedutil.c
>> +++ b/kernel/sched/cpufreq_schedutil.c
>> @@ -50,6 +50,7 @@ struct sugov_cpu {
>>       unsigned long        util;
>>       unsigned long        bw_min;
>> +    unsigned long        bw_max;
>>       /* The field below is for single-CPU policies only: */
>>   #ifdef CONFIG_NO_HZ_COMMON
>> @@ -232,6 +233,7 @@ static void sugov_get_util(struct sugov_
>>       util = effective_cpu_util(sg_cpu->cpu, util, &min, &max);
>>       util = max(util, boost);
>>       sg_cpu->bw_min = min;
>> +    sg_cpu->bw_max = max;
>>       sg_cpu->util = sugov_effective_cpu_perf(sg_cpu->cpu, util, min, 
>> max);
>>   }
>> @@ -484,7 +486,7 @@ static void sugov_update_single_perf(str
>>           sg_cpu->util = prev_util;
>>       cpufreq_driver_adjust_perf(sg_policy->policy, sg_cpu->bw_min,
>> -                   sg_cpu->util, max_cap);
>> +                   sg_cpu->util, sg_cpu->bw_max, max_cap);
>>       sg_policy->last_freq_update_time = time;
>>   }
>> --- a/rust/kernel/cpufreq.rs
>> +++ b/rust/kernel/cpufreq.rs
>> @@ -792,7 +792,8 @@ pub trait Driver {
>>       }
>>       /// Driver's `adjust_perf` callback.
>> -    fn adjust_perf(_policy: &mut Policy, _min_perf: usize, 
>> _target_perf: usize, _capacity: usize) {
>> +    fn adjust_perf(_policy: &mut Policy, _min_perf: usize, 
>> _target_perf: usize,
>> +                   _max_perf: usize, _capacity: usize) {
>>           build_error!(VTABLE_DEFAULT_ERROR)
>>       }
>> @@ -1262,12 +1263,13 @@ impl<T: Driver> Registration<T> {
>>           ptr: *mut bindings::cpufreq_policy,
>>           min_perf: c_ulong,
>>           target_perf: c_ulong,
>> +        max_perf: c_ulong,
>>           capacity: c_ulong,
>>       ) {
>>           // SAFETY: The `ptr` is guaranteed to be valid by the 
>> contract with the C code for the
>>           // lifetime of `policy`.
>>           let policy = unsafe { Policy::from_raw_mut(ptr) };
>> -        T::adjust_perf(policy, min_perf, target_perf, capacity);
>> +        T::adjust_perf(policy, min_perf, target_perf, max_perf, 
>> capacity);
>>       }
>>       /// Driver's `get_intermediate` callback.
>>
>>
>>
> 
> 



^ permalink raw reply

* [PATCH] power: supply: sbs-battery: Add PbAc, NiZn, RAM, and ZnAr support
From: Boris Shtrasman @ 2026-06-21 14:59 UTC (permalink / raw)
  To: Sebastian Reichel; +Cc: linux-pm, linux-kernel, Boris Shtrasman

Add support for PbAc, NiZn, RAM, and ZnAr chemistries as defined in the
Smart Battery Data Specification v1.1 (Section 5.1.30 DeviceChemistry).

Currently, the sbs-battery driver only handles LION, LiP, NiCd and NiMH.
The Smart Battery specification defines 8 possible values:
 - Lead Acid (PbAc)
 - Lithium Ion (LION)
 - Nickel Cadmium (NiCd)
 - Nickel Metal Hydride (NiMH)
 - Nickel Zinc (NiZn)
 - Rechargeable Alkaline-Manganese (RAM)
 - Zinc Air (ZnAr)
 - Lithium Polymer (LiP)

Map the missing specification values to their respective core kernel
POWER_SUPPLY_TECHNOLOGY definitions.

Link: https://sbs-forum.org/specs/sbdat110.pdf
Signed-off-by: Boris Shtrasman <borissh1983@gmail.com>
---
 drivers/power/supply/sbs-battery.c | 8 ++++++++
 include/linux/power_supply.h       | 4 ++++
 2 files changed, 12 insertions(+)

diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
index 43c48196c167..42a941e99155 100644
--- a/drivers/power/supply/sbs-battery.c
+++ b/drivers/power/supply/sbs-battery.c
@@ -860,6 +860,14 @@ static int sbs_get_chemistry(struct sbs_info *chip,
 		chip->technology = POWER_SUPPLY_TECHNOLOGY_NiCd;
 	else if (!strncasecmp(chemistry, "NiMH", 4))
 		chip->technology = POWER_SUPPLY_TECHNOLOGY_NiMH;
+	else if (!strncasecmp(chemistry, "PbAc", 4))
+		chip->technology = POWER_SUPPLY_TECHNOLOGY_PbAc;
+	else if (!strncasecmp(chemistry, "NiZn", 4))
+		chip->technology = POWER_SUPPLY_TECHNOLOGY_NiZn;
+	else if (!strncasecmp(chemistry, "RAM", 3))
+		chip->technology = POWER_SUPPLY_TECHNOLOGY_RAM;
+	else if (!strncasecmp(chemistry, "ZnAr", 4))
+		chip->technology = POWER_SUPPLY_TECHNOLOGY_ZnAr;
 	else
 		chip->technology = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
 
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 7a5e4c3242a0..034800cd21da 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -83,6 +83,10 @@ enum {
 	POWER_SUPPLY_TECHNOLOGY_LiFe,
 	POWER_SUPPLY_TECHNOLOGY_NiCd,
 	POWER_SUPPLY_TECHNOLOGY_LiMn,
+	POWER_SUPPLY_TECHNOLOGY_PbAc,
+	POWER_SUPPLY_TECHNOLOGY_NiZn,
+	POWER_SUPPLY_TECHNOLOGY_RAM,
+	POWER_SUPPLY_TECHNOLOGY_ZnAr,
 };
 
 enum {
-- 
2.47.3


^ permalink raw reply related

* Re: [PATCH v1] power: supply: surface_{battery,charger}: Consistently define ssam_device_ids using named initializers
From: Maximilian Luz @ 2026-06-21 13:32 UTC (permalink / raw)
  To: Uwe Kleine-König (The Capable Hub), Sebastian Reichel
  Cc: linux-pm, platform-driver-x86, linux-kernel
In-Reply-To: <bc8eff03b2f36c82af5a75fc7114c277228921db.1781526433.git.u.kleine-koenig@baylibre.com>

Am 15.06.2026 um 14:51 schrieb Uwe Kleine-König (The Capable Hub):
> The .driver_data member of the the two struct ssam_device_id arrays were
> initialized by list expressions. This isn't easily readable if you don't
> work with the Surface System Aggregator core regularily. Using named
> initializers is more explicit and thus easier to parse and also more
> robust to changes of the struct definition. This robustness is relevant
> for a planned change to struct ssam_device_id replacing .driver_data
> by an anonymous union.
> 
> While touching these arrays, also drop the comma after the list
> terminators.
> 
> This change doesn't introduce changes to the compiled ssam_device_id
> arrays.
> 
> Signed-off-by: Uwe Kleine-König (The Capable Hub) <u.kleine-koenig@baylibre.com>
> ---
> Hello,
> 
> the mentioned change to ssam_device_id is similar to
> https://lore.kernel.org/all/cover.1779878004.git.u.kleine-koenig@baylibre.com/.
> 
> That allows to get rid of the casts in these two drivers and thus
> benefits a bit more of the (admittedly weak) type safety of C.

As in the prior patch: I assume that will be a separate change or am I missing something in this patch?

> But IMHO the improved readability alone also justifies this change.
> 
> Best regards
> Uwe

Looks good to me.

Reviewed-by: Maximilian Luz <luzmaximilian@gmail.com>

> 
>   drivers/power/supply/surface_battery.c | 11 ++++++++---
>   drivers/power/supply/surface_charger.c |  7 +++++--
>   2 files changed, 13 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/power/supply/surface_battery.c b/drivers/power/supply/surface_battery.c
> index c759add4df49..1273b6082311 100644
> --- a/drivers/power/supply/surface_battery.c
> +++ b/drivers/power/supply/surface_battery.c
> @@ -852,9 +852,14 @@ static const struct spwr_psy_properties spwr_psy_props_bat2_sb3 = {
>   };
>   
>   static const struct ssam_device_id surface_battery_match[] = {
> -	{ SSAM_SDEV(BAT, SAM, 0x01, 0x00), (unsigned long)&spwr_psy_props_bat1     },
> -	{ SSAM_SDEV(BAT, KIP, 0x01, 0x00), (unsigned long)&spwr_psy_props_bat2_sb3 },
> -	{ },
> +	{
> +		SSAM_SDEV(BAT, SAM, 0x01, 0x00),
> +		.driver_data = (unsigned long)&spwr_psy_props_bat1,
> +	}, {
> +		SSAM_SDEV(BAT, KIP, 0x01, 0x00),
> +		.driver_data = (unsigned long)&spwr_psy_props_bat2_sb3,
> +	},
> +	{ }
>   };
>   MODULE_DEVICE_TABLE(ssam, surface_battery_match);
>   
> diff --git a/drivers/power/supply/surface_charger.c b/drivers/power/supply/surface_charger.c
> index 90b823848c99..d4bba6b41794 100644
> --- a/drivers/power/supply/surface_charger.c
> +++ b/drivers/power/supply/surface_charger.c
> @@ -260,8 +260,11 @@ static const struct spwr_psy_properties spwr_psy_props_adp1 = {
>   };
>   
>   static const struct ssam_device_id surface_ac_match[] = {
> -	{ SSAM_SDEV(BAT, SAM, 0x01, 0x01), (unsigned long)&spwr_psy_props_adp1 },
> -	{ },
> +	{
> +		SSAM_SDEV(BAT, SAM, 0x01, 0x01),
> +		.driver_data = (unsigned long)&spwr_psy_props_adp1,
> +	},
> +	{ }
>   };
>   MODULE_DEVICE_TABLE(ssam, surface_ac_match);
>   
> 
> base-commit: c425609d6ac4012c8bbf01ec2e10e801b1923a7b


^ permalink raw reply

* [PATCH v9 9/9] arm64: dts: mediatek: Add MediaTek MT6392 PMIC dtsi
From: Luca Leonardo Scorcia @ 2026-06-21  8:13 UTC (permalink / raw)
  To: linux-mediatek
  Cc: Val Packett, Luca Leonardo Scorcia, Dmitry Torokhov, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Sen Chu, Sean Wang,
	Macpaul Lin, Lee Jones, Matthias Brugger,
	AngeloGioacchino Del Regno, Liam Girdwood, Mark Brown,
	Linus Walleij, Julien Massot, Louis-Alexis Eyraud, Fabien Parent,
	Akari Tsuyukusa, Chen Zhong, linux-input, devicetree,
	linux-kernel, linux-pm, linux-arm-kernel, linux-gpio
In-Reply-To: <20260621081634.467858-1-l.scorcia@gmail.com>

From: Val Packett <val@packett.cool>

Add the dtsi to be included by all boards using the MT6392 PMIC,
providing support for regulator, keys, pinctrl and RTC.

Import the new file in the shared device tree for the Pumpkin boards.

Signed-off-by: Val Packett <val@packett.cool>
Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
---
 arch/arm64/boot/dts/mediatek/mt6392.dtsi      | 145 ++++++++++++++++++
 .../boot/dts/mediatek/pumpkin-common.dtsi     |   7 +
 2 files changed, 152 insertions(+)
 create mode 100644 arch/arm64/boot/dts/mediatek/mt6392.dtsi

diff --git a/arch/arm64/boot/dts/mediatek/mt6392.dtsi b/arch/arm64/boot/dts/mediatek/mt6392.dtsi
new file mode 100644
index 000000000000..69d63c153d9e
--- /dev/null
+++ b/arch/arm64/boot/dts/mediatek/mt6392.dtsi
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ * Copyright (c) 2024 Val Packett <val@packett.cool>
+ * Copyright (c) 2026 Luca Leonardo Scorcia <l.scorcia@gmail.com>
+ */
+
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/regulator/mediatek,mt6392-regulator.h>
+
+&pwrap {
+	pmic: pmic {
+		compatible = "mediatek,mt6392", "mediatek,mt6323";
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		mt6392keys: keys {
+			compatible = "mediatek,mt6392-keys";
+
+			key-power {
+				linux,keycodes = <KEY_POWER>;
+				wakeup-source;
+			};
+
+			key-home {
+				linux,keycodes = <KEY_HOME>;
+				wakeup-source;
+			};
+		};
+
+		mt6392pio: pinctrl {
+			compatible = "mediatek,mt6392-pinctrl";
+
+			gpio-controller;
+			#gpio-cells = <2>;
+		};
+
+		mt6392regulators: regulators {
+			compatible = "mediatek,mt6392-regulator";
+
+			/* Fixed supply defined in the data sheet */
+			avddldo-supply = <&mt6392_vsys_reg>;
+
+			mt6392_vcore_reg: vcore {
+				regulator-allowed-modes = <MT6392_REGULATOR_MODE_NORMAL
+							   MT6392_BUCK_MODE_FORCE_PWM>;
+			};
+			mt6392_vproc_reg: vproc {
+				regulator-allowed-modes = <MT6392_REGULATOR_MODE_NORMAL
+							   MT6392_BUCK_MODE_FORCE_PWM>;
+			};
+			mt6392_vsys_reg: vsys {
+				regulator-allowed-modes = <MT6392_REGULATOR_MODE_NORMAL
+							   MT6392_BUCK_MODE_FORCE_PWM>;
+			};
+			mt6392_vaud28_reg: vaud28 {
+				regulator-allowed-modes = <MT6392_REGULATOR_MODE_NORMAL
+							   MT6392_LDO_MODE_LP>;
+			};
+			mt6392_vxo22_reg: vxo22 {
+				regulator-allowed-modes = <MT6392_REGULATOR_MODE_NORMAL
+							   MT6392_LDO_MODE_LP>;
+			};
+			mt6392_vaud22_reg: vaud22 {
+				regulator-allowed-modes = <MT6392_REGULATOR_MODE_NORMAL
+							   MT6392_LDO_MODE_LP>;
+			};
+			mt6392_vadc18_reg: vadc18 {
+				regulator-allowed-modes = <MT6392_REGULATOR_MODE_NORMAL
+							   MT6392_LDO_MODE_LP>;
+			};
+			mt6392_vcama_reg: vcama { };
+			mt6392_vcn35_reg: vcn35 {
+				regulator-allowed-modes = <MT6392_REGULATOR_MODE_NORMAL
+							   MT6392_LDO_MODE_LP>;
+			};
+			mt6392_vio28_reg: vio28 {
+				regulator-allowed-modes = <MT6392_REGULATOR_MODE_NORMAL
+							   MT6392_LDO_MODE_LP>;
+			};
+			mt6392_vusb_reg: vusb {
+				regulator-allowed-modes = <MT6392_REGULATOR_MODE_NORMAL
+							   MT6392_LDO_MODE_LP>;
+			};
+			mt6392_vmc_reg: vmc {
+				regulator-allowed-modes = <MT6392_REGULATOR_MODE_NORMAL
+							   MT6392_LDO_MODE_LP>;
+			};
+			mt6392_vmch_reg: vmch {
+				regulator-allowed-modes = <MT6392_REGULATOR_MODE_NORMAL
+							   MT6392_LDO_MODE_LP>;
+			};
+			mt6392_vemc3v3_reg: vemc3v3 {
+				regulator-allowed-modes = <MT6392_REGULATOR_MODE_NORMAL
+							   MT6392_LDO_MODE_LP>;
+			};
+			mt6392_vcamaf_reg: vcamaf {
+				regulator-allowed-modes = <MT6392_REGULATOR_MODE_NORMAL
+							   MT6392_LDO_MODE_LP>;
+			};
+			mt6392_vgp1_reg: vgp1 {
+				regulator-allowed-modes = <MT6392_REGULATOR_MODE_NORMAL
+							   MT6392_LDO_MODE_LP>;
+			};
+			mt6392_vgp2_reg: vgp2 {
+				regulator-allowed-modes = <MT6392_REGULATOR_MODE_NORMAL
+							   MT6392_LDO_MODE_LP>;
+			};
+			mt6392_vefuse_reg: vefuse {
+				regulator-allowed-modes = <MT6392_REGULATOR_MODE_NORMAL
+							   MT6392_LDO_MODE_LP>;
+			};
+			mt6392_vm25_reg: vm25 {
+				regulator-allowed-modes = <MT6392_REGULATOR_MODE_NORMAL
+							   MT6392_LDO_MODE_LP>;
+			};
+			mt6392_vdig18_reg: vdig18 { };
+			mt6392_vm_reg: vm {
+				regulator-allowed-modes = <MT6392_REGULATOR_MODE_NORMAL
+							   MT6392_LDO_MODE_LP>;
+			};
+			mt6392_vio18_reg: vio18 {
+				regulator-allowed-modes = <MT6392_REGULATOR_MODE_NORMAL
+							   MT6392_LDO_MODE_LP>;
+			};
+			mt6392_vcn18_reg: vcn18 {
+				regulator-allowed-modes = <MT6392_REGULATOR_MODE_NORMAL
+							   MT6392_LDO_MODE_LP>;
+			};
+			mt6392_vcamd_reg: vcamd {
+				regulator-allowed-modes = <MT6392_REGULATOR_MODE_NORMAL
+							   MT6392_LDO_MODE_LP>;
+			};
+			mt6392_vcamio_reg: vcamio {
+				regulator-allowed-modes = <MT6392_REGULATOR_MODE_NORMAL
+							   MT6392_LDO_MODE_LP>;
+			};
+			mt6392_vrtc_reg: vrtc { };
+		};
+
+		mt6392rtc: rtc {
+			compatible = "mediatek,mt6392-rtc", "mediatek,mt6323-rtc";
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi b/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi
index 805fb82138a8..b19d5792bd89 100644
--- a/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi
+++ b/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi
@@ -6,6 +6,8 @@
 
 #include <dt-bindings/gpio/gpio.h>
 
+#include "mt6392.dtsi"
+
 / {
 	aliases {
 		serial0 = &uart0;
@@ -160,6 +162,11 @@ &i2c2 {
 	status = "okay";
 };
 
+&pmic {
+	interrupt-parent = <&pio>;
+	interrupts = <28 IRQ_TYPE_LEVEL_HIGH>;
+};
+
 &uart0 {
 	status = "okay";
 };
-- 
2.43.0


^ permalink raw reply related

* [PATCH v9 8/9] regulator: Add MediaTek MT6392 regulator
From: Luca Leonardo Scorcia @ 2026-06-21  8:13 UTC (permalink / raw)
  To: linux-mediatek
  Cc: Fabien Parent, Val Packett, Luca Leonardo Scorcia,
	Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Sen Chu, Sean Wang, Macpaul Lin, Lee Jones, Matthias Brugger,
	AngeloGioacchino Del Regno, Liam Girdwood, Mark Brown,
	Linus Walleij, Louis-Alexis Eyraud, Julien Massot,
	Akari Tsuyukusa, Chen Zhong, linux-input, devicetree,
	linux-kernel, linux-pm, linux-arm-kernel, linux-gpio
In-Reply-To: <20260621081634.467858-1-l.scorcia@gmail.com>

From: Fabien Parent <parent.f@gmail.com>

The MT6392 is a regulator found on boards based on the MediaTek
MT8167, MT8516, and probably other SoCs. It is a so called PMIC and
connects as a slave to a SoC using SPI, wrapped inside PWRAP.

Signed-off-by: Fabien Parent <parent.f@gmail.com>
Co-developed-by: Val Packett <val@packett.cool>
Signed-off-by: Val Packett <val@packett.cool>
Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
---
 drivers/regulator/Kconfig                  |   9 +
 drivers/regulator/Makefile                 |   1 +
 drivers/regulator/mt6392-regulator.c       | 764 +++++++++++++++++++++
 include/linux/regulator/mt6392-regulator.h |  42 ++
 4 files changed, 816 insertions(+)
 create mode 100644 drivers/regulator/mt6392-regulator.c
 create mode 100644 include/linux/regulator/mt6392-regulator.h

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index a54a549196fe..ae375b9e6391 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -1001,6 +1001,15 @@ config REGULATOR_MT6380
 	  This driver supports the control of different power rails of device
 	  through regulator interface.
 
+config REGULATOR_MT6392
+	tristate "MediaTek MT6392 PMIC"
+	depends on MFD_MT6397
+	help
+	  Say y here to select this option to enable the power regulator of
+	  MediaTek MT6392 PMIC.
+	  This driver supports the control of different power rails of device
+	  through regulator interface.
+
 config REGULATOR_MT6397
 	tristate "MediaTek MT6397 PMIC"
 	depends on MFD_MT6397
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 134eee274dbf..a8e795a1eda1 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -118,6 +118,7 @@ obj-$(CONFIG_REGULATOR_MT6360) += mt6360-regulator.o
 obj-$(CONFIG_REGULATOR_MT6363) += mt6363-regulator.o
 obj-$(CONFIG_REGULATOR_MT6370) += mt6370-regulator.o
 obj-$(CONFIG_REGULATOR_MT6380)	+= mt6380-regulator.o
+obj-$(CONFIG_REGULATOR_MT6392)	+= mt6392-regulator.o
 obj-$(CONFIG_REGULATOR_MT6397)	+= mt6397-regulator.o
 obj-$(CONFIG_REGULATOR_MTK_DVFSRC) += mtk-dvfsrc-regulator.o
 obj-$(CONFIG_REGULATOR_QCOM_LABIBB) += qcom-labibb-regulator.o
diff --git a/drivers/regulator/mt6392-regulator.c b/drivers/regulator/mt6392-regulator.c
new file mode 100644
index 000000000000..93fe887709c3
--- /dev/null
+++ b/drivers/regulator/mt6392-regulator.c
@@ -0,0 +1,764 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ * Copyright (c) 2020 BayLibre, SAS.
+ * Author: Chen Zhong <chen.zhong@mediatek.com>
+ * Author: Fabien Parent <fparent@baylibre.com>
+ * Author: Luca Leonardo Scorcia <l.scorcia@gmail.com>
+ *
+ * The data sheet for MT6392 regulators is spotty to say the least,
+ * many important registers/fields are missing and the ones that aren't
+ * lack crucial information. Some useful details have been retrieved from
+ * Android sources.
+ * The driver code is mostly based on the MT6397 one.
+ */
+
+#include <linux/module.h>
+#include <linux/linear_range.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/mt6397/core.h>
+#include <linux/mfd/mt6392/registers.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6392-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+/*
+ * Buck mode constants which may be used in devicetree properties (eg.
+ * regulator-initial-mode, regulator-allowed-modes).
+ * See the manufacturer's datasheet for more information on these modes.
+ */
+#define MT6392_REGULATOR_MODE_NORMAL	0
+#define MT6392_BUCK_MODE_FORCE_PWM	1
+
+/*
+ * LDO mode constants which may be used in devicetree properties (eg.
+ * regulator-initial-mode, regulator-allowed-modes).
+ * See the manufacturer's datasheet for more information on these modes.
+ */
+#define MT6392_LDO_MODE_LP		2
+
+/**
+ * MT6392 regulators' information
+ *
+ * @desc: standard fields of regulator description.
+ * @qi_status_reg: Register to query enable signal status of regulators
+ * @qi_status_mask: Mask to query enable signal status of regulators (RO)
+ * @vselctrl_reg: Vsel control mode selector register
+ * @vselctrl_mask: Vsel control mode selector mask (RO)
+ * @vsel_reg_mode_reg: Vsel register when Vsel control mode selector = 0 (Register mode)
+ * @vsel_reg_mode_mask: Vsel register mask in Register mode (RW)
+ * @vsel_normal_mode_reg: Vsel register when Vsel control mode selector = 1 (Normal mode)
+ * @vsel_normal_mode_mask: Vsel register mask in Register mode (RW)
+ * @pwm_modeset_reg: Register to control buck mode (Auto/Force PWM)
+ * @pwm_modeset_mask: Mask to control buck mode (RW)
+ * @lp_modeget_reg: Register to get LDO low-power mode
+ * @lp_modeget_mask: Mask to get LDO low-power mode (RO)
+ * @lp_modeset_reg: Register to control LDO low-power mode
+ * @lp_modeset_mask: Mask to control LDO low-power mode (WO)
+ */
+struct mt6392_regulator_info {
+	struct regulator_desc desc;
+	u32 qi_status_reg;
+	u32 qi_status_mask;
+	u32 vselctrl_reg;
+	u32 vselctrl_mask;
+	u32 vsel_reg_mode_reg;
+	u32 vsel_reg_mode_mask;
+	u32 vsel_normal_mode_reg;
+	u32 vsel_normal_mode_mask;
+	u32 pwm_modeset_reg;
+	u32 pwm_modeset_mask;
+	u32 lp_modeget_reg;
+	u32 lp_modeget_mask;
+	u32 lp_modeset_reg;
+	u32 lp_modeset_mask;
+};
+
+#define MT6392_BUCK(match, vreg, supply, min, max, step, volt_ranges,	\
+	_qi_status_reg, _qi_status_mask, _enable_reg, _enable_mask,	\
+	_vselctrl_reg, _vselctrl_mask,					\
+	_vsel_reg_mode_reg, _vsel_reg_mode_mask,			\
+	_vsel_normal_mode_reg, _vsel_normal_mode_mask,			\
+	_pwm_modeset_reg, _pwm_modeset_mask, _ramp_delay)		\
+[MT6392_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.supply_name = supply,					\
+		.of_match = of_match_ptr(match),			\
+		.regulators_node = of_match_ptr("regulators"),		\
+		.ops = &mt6392_volt_range_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6392_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = ((max) - (min)) / (step) + 1,		\
+		.linear_ranges = volt_ranges,				\
+		.n_linear_ranges = ARRAY_SIZE(volt_ranges),		\
+		.enable_reg = _enable_reg,				\
+		.enable_mask = _enable_mask,				\
+		.of_map_mode = mt6392_map_mode,				\
+		.ramp_delay = _ramp_delay,				\
+	},								\
+	.qi_status_reg = _qi_status_reg,				\
+	.qi_status_mask = _qi_status_mask,				\
+	.vselctrl_reg = _vselctrl_reg,					\
+	.vselctrl_mask = _vselctrl_mask,				\
+	.vsel_reg_mode_reg = _vsel_reg_mode_reg,			\
+	.vsel_reg_mode_mask = _vsel_reg_mode_mask,			\
+	.vsel_normal_mode_reg = _vsel_normal_mode_reg,			\
+	.vsel_normal_mode_mask = _vsel_normal_mode_mask,		\
+	.pwm_modeset_reg = _pwm_modeset_reg,				\
+	.pwm_modeset_mask = _pwm_modeset_mask,				\
+}
+
+#define MT6392_LDO(match, vreg, supply, ldo_volt_table,			\
+	_qi_status_reg, _qi_status_mask,				\
+	_enable_reg, _enable_mask,					\
+	_vsel_reg, _vsel_mask,						\
+	_lp_modeget_reg, _lp_modeget_mask,				\
+	_lp_modeset_reg, _lp_modeset_mask,				\
+	_enable_time)							\
+[MT6392_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.supply_name = supply,					\
+		.of_match = of_match_ptr(match),			\
+		.regulators_node = of_match_ptr("regulators"),		\
+		.ops = &mt6392_volt_table_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6392_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = ARRAY_SIZE(ldo_volt_table),		\
+		.volt_table = ldo_volt_table,				\
+		.vsel_reg = _vsel_reg,					\
+		.vsel_mask = _vsel_mask,				\
+		.enable_reg = _enable_reg,				\
+		.enable_mask = _enable_mask,				\
+		.enable_time = _enable_time,				\
+		.of_map_mode = mt6392_map_mode,				\
+	},								\
+	.qi_status_reg = _qi_status_reg,				\
+	.qi_status_mask = _qi_status_mask,				\
+	.lp_modeget_reg = _lp_modeget_reg,				\
+	.lp_modeget_mask = _lp_modeget_mask,				\
+	.lp_modeset_reg = _lp_modeset_reg,				\
+	.lp_modeset_mask = _lp_modeset_mask,				\
+}
+
+#define MT6392_LDO_LINEAR(match, vreg, supply, min, max, step,		\
+	volt_ranges,							\
+	_qi_status_reg, _qi_status_mask,				\
+	_enable_reg, _enable_mask,					\
+	_vsel_reg, _vsel_mask,						\
+	_lp_modeget_reg, _lp_modeget_mask,				\
+	_lp_modeset_reg, _lp_modeset_mask,				\
+	_enable_time)							\
+[MT6392_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.supply_name = supply,					\
+		.of_match = of_match_ptr(match),			\
+		.regulators_node = of_match_ptr("regulators"),		\
+		.ops = &mt6392_volt_ldo_range_ops,			\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6392_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = ((max) - (min)) / (step) + 1,		\
+		.linear_ranges = volt_ranges,				\
+		.n_linear_ranges = ARRAY_SIZE(volt_ranges),		\
+		.vsel_reg = _vsel_reg,					\
+		.vsel_mask = _vsel_mask,				\
+		.enable_reg = _enable_reg,				\
+		.enable_mask = _enable_mask,				\
+		.enable_time = _enable_time,				\
+		.of_map_mode = mt6392_map_mode,				\
+	},								\
+	.qi_status_reg = _qi_status_reg,				\
+	.qi_status_mask = _qi_status_mask,				\
+	.lp_modeget_reg = _lp_modeget_reg,				\
+	.lp_modeget_mask = _lp_modeget_mask,				\
+	.lp_modeset_reg = _lp_modeset_reg,				\
+	.lp_modeset_mask = _lp_modeset_mask,				\
+}
+
+#define MT6392_REG_FIXED(match, vreg, supply, volt,			\
+	_qi_status_reg, _qi_status_mask,				\
+	_enable_reg, _enable_mask,					\
+	_lp_modeget_reg, _lp_modeget_mask,				\
+	_lp_modeset_reg, _lp_modeset_mask,				\
+	_enable_time)							\
+[MT6392_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.supply_name = supply,					\
+		.of_match = of_match_ptr(match),			\
+		.regulators_node = of_match_ptr("regulators"),		\
+		.ops = &mt6392_volt_fixed_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6392_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = 1,					\
+		.min_uV = volt,						\
+		.enable_reg = _enable_reg,				\
+		.enable_mask = _enable_mask,				\
+		.enable_time = _enable_time,				\
+		.of_map_mode = mt6392_map_mode,				\
+	},								\
+	.qi_status_reg = _qi_status_reg,				\
+	.qi_status_mask = _qi_status_mask,				\
+	.lp_modeget_reg = _lp_modeget_reg,				\
+	.lp_modeget_mask = _lp_modeget_mask,				\
+	.lp_modeset_reg = _lp_modeset_reg,				\
+	.lp_modeset_mask = _lp_modeset_mask,				\
+}
+
+#define MT6392_REG_FIXED_NO_MODE(match, vreg, supply, volt,		\
+	_qi_status_reg, _qi_status_mask,				\
+	_enable_reg, _enable_mask, _enable_time)			\
+[MT6392_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.supply_name = supply,					\
+		.of_match = of_match_ptr(match),			\
+		.regulators_node = of_match_ptr("regulators"),		\
+		.ops = &mt6392_volt_fixed_no_mode_ops,			\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6392_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = 1,					\
+		.min_uV = volt,						\
+		.enable_reg = _enable_reg,				\
+		.enable_mask = _enable_mask,				\
+		.enable_time = _enable_time,				\
+	},								\
+	.qi_status_reg = _qi_status_reg,				\
+	.qi_status_mask = _qi_status_mask,				\
+}
+
+#define MT6392_REG(match, vreg, supply, volt)				\
+[MT6392_ID_##vreg] = {							\
+	.desc = {							\
+		.name = #vreg,						\
+		.supply_name = supply,					\
+		.of_match = of_match_ptr(match),			\
+		.regulators_node = of_match_ptr("regulators"),		\
+		.ops = &mt6392_volt_no_ops,				\
+		.type = REGULATOR_VOLTAGE,				\
+		.id = MT6392_ID_##vreg,					\
+		.owner = THIS_MODULE,					\
+		.n_voltages = 1,					\
+		.min_uV = volt,						\
+	},								\
+}
+
+static const struct linear_range buck_volt_range1[] = {
+	REGULATOR_LINEAR_RANGE(700000, 0, 0x7f, 6250),
+};
+
+static const struct linear_range buck_volt_range2[] = {
+	REGULATOR_LINEAR_RANGE(1400000, 0, 0x7f, 12500),
+};
+
+static const u32 ldo_volt_table1[] = {
+	1800000, 1900000, 2000000, 2200000,
+};
+
+static const struct linear_range ldo_volt_range2[] = {
+	REGULATOR_LINEAR_RANGE(3300000, 0, 3, 100000),
+};
+
+static const u32 ldo_volt_table3[] = {
+	1800000, 3300000,
+};
+
+static const u32 ldo_volt_table4[] = {
+	3000000, 3300000,
+};
+
+static const u32 ldo_volt_table5[] = {
+	1200000, 1300000, 1500000, 1800000, 2000000, 2800000, 3000000, 3300000,
+};
+
+static const u32 ldo_volt_table6[] = {
+	1240000, 1390000,
+};
+
+static const u32 ldo_volt_table7[] = {
+	1200000, 1300000, 1500000, 1800000,
+};
+
+static const u32 ldo_volt_table8[] = {
+	1800000, 2000000,
+};
+
+static unsigned int mt6392_map_mode(unsigned int mode)
+{
+	switch (mode) {
+	case MT6392_REGULATOR_MODE_NORMAL:
+		return REGULATOR_MODE_NORMAL;
+	case MT6392_BUCK_MODE_FORCE_PWM:
+		return REGULATOR_MODE_FAST;
+	case MT6392_LDO_MODE_LP:
+		return REGULATOR_MODE_STANDBY;
+	default:
+		return REGULATOR_MODE_INVALID;
+	}
+}
+
+static int mt6392_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	int ret, val = 0;
+	struct mt6392_regulator_info *info = rdev_get_drvdata(rdev);
+
+	if (!info->pwm_modeset_mask) {
+		dev_err(&rdev->dev, "regulator %s doesn't support set_mode\n", info->desc.name);
+		return -EINVAL;
+	}
+
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		val = 1;
+		break;
+	case REGULATOR_MODE_NORMAL:
+		val = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	val <<= ffs(info->pwm_modeset_mask) - 1;
+
+	ret = regmap_update_bits(rdev->regmap, info->pwm_modeset_reg,
+				 info->pwm_modeset_mask, val);
+
+	return ret;
+}
+
+static unsigned int mt6392_buck_get_mode(struct regulator_dev *rdev)
+{
+	unsigned int val;
+	unsigned int mode;
+	int ret;
+	struct mt6392_regulator_info *info = rdev_get_drvdata(rdev);
+
+	if (!info->pwm_modeset_mask) {
+		dev_err(&rdev->dev, "regulator %s doesn't support get_mode\n", info->desc.name);
+		return -EINVAL;
+	}
+
+	ret = regmap_read(rdev->regmap, info->pwm_modeset_reg, &val);
+	if (ret < 0)
+		return ret;
+
+	val &= info->pwm_modeset_mask;
+	val >>= ffs(info->pwm_modeset_mask) - 1;
+
+	if (val & 0x1)
+		mode = REGULATOR_MODE_FAST;
+	else
+		mode = REGULATOR_MODE_NORMAL;
+
+	return mode;
+}
+
+static int mt6392_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	int ret, val = 0;
+	struct mt6392_regulator_info *info = rdev_get_drvdata(rdev);
+
+	if (!info->lp_modeset_mask) {
+		dev_err(&rdev->dev, "regulator %s doesn't support set_mode\n",
+			info->desc.name);
+		return -EINVAL;
+	}
+
+	switch (mode) {
+	case REGULATOR_MODE_STANDBY:
+		val = 1;
+		break;
+	case REGULATOR_MODE_NORMAL:
+		val = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	val <<= ffs(info->lp_modeset_mask) - 1;
+
+	ret = regmap_update_bits(rdev->regmap, info->lp_modeset_reg,
+				 info->lp_modeset_mask, val);
+
+	return ret;
+}
+
+static unsigned int mt6392_ldo_get_mode(struct regulator_dev *rdev)
+{
+	unsigned int val;
+	unsigned int mode;
+	int ret;
+	struct mt6392_regulator_info *info = rdev_get_drvdata(rdev);
+
+	if (!info->lp_modeget_mask) {
+		dev_err(&rdev->dev, "regulator %s doesn't support get_mode\n",
+			info->desc.name);
+		return -EINVAL;
+	}
+
+	ret = regmap_read(rdev->regmap, info->lp_modeget_reg, &val);
+	if (ret < 0)
+		return ret;
+
+	val &= info->lp_modeget_mask;
+	val >>= ffs(info->lp_modeget_mask) - 1;
+
+	if (val & 0x1)
+		mode = REGULATOR_MODE_STANDBY;
+	else
+		mode = REGULATOR_MODE_NORMAL;
+
+	return mode;
+}
+
+static int mt6392_get_status(struct regulator_dev *rdev)
+{
+	int ret;
+	u32 regval;
+	struct mt6392_regulator_info *info = rdev_get_drvdata(rdev);
+
+	ret = regmap_read(rdev->regmap, info->qi_status_reg, &regval);
+	if (ret != 0) {
+		dev_err(&rdev->dev, "Failed to read qi_status_reg: %d\n", ret);
+		return ret;
+	}
+
+	return (regval & info->qi_status_mask) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF;
+}
+
+static const struct regulator_ops mt6392_volt_range_ops = {
+	.list_voltage = regulator_list_voltage_linear_range,
+	.map_voltage = regulator_map_voltage_linear_range,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6392_get_status,
+	.set_mode = mt6392_buck_set_mode,
+	.get_mode = mt6392_buck_get_mode,
+};
+
+static const struct regulator_ops mt6392_volt_table_ops = {
+	.list_voltage = regulator_list_voltage_table,
+	.map_voltage = regulator_map_voltage_iterate,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6392_get_status,
+	.set_mode = mt6392_ldo_set_mode,
+	.get_mode = mt6392_ldo_get_mode,
+};
+
+static const struct regulator_ops mt6392_volt_ldo_range_ops = {
+	.list_voltage = regulator_list_voltage_linear_range,
+	.map_voltage = regulator_map_voltage_linear_range,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6392_get_status,
+	.set_mode = mt6392_ldo_set_mode,
+	.get_mode = mt6392_ldo_get_mode,
+};
+
+static const struct regulator_ops mt6392_volt_fixed_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6392_get_status,
+	.set_mode = mt6392_ldo_set_mode,
+	.get_mode = mt6392_ldo_get_mode,
+};
+
+static const struct regulator_ops mt6392_volt_fixed_no_mode_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_status = mt6392_get_status,
+};
+
+static const struct regulator_ops mt6392_volt_no_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+};
+
+/* The array is indexed by id(MT6392_ID_XXX) */
+static struct mt6392_regulator_info mt6392_regulators[] = {
+	MT6392_BUCK("vproc", VPROC, "vproc", 700000, 1493750, 6250,
+		    buck_volt_range1,
+		    MT6392_VPROC_CON7, BIT(13), // Regulator status
+		    MT6392_VPROC_CON7, BIT(0),  // Regulator enable
+		    MT6392_VPROC_CON5, BIT(0),  // Vsel ctrl mode selector,not present in data sheet
+		    MT6392_VPROC_CON9, GENMASK(6, 0),  // Vsel when control mode = register (0)
+		    MT6392_VPROC_CON10, GENMASK(6, 0), // Vsel when control mode = normal (1)
+		    MT6392_VPROC_CON2, BIT(8),  // Auto / Force PWM mode
+		    12500),
+	MT6392_BUCK("vsys", VSYS, "vsys", 1400000, 2987500, 12500,
+		    buck_volt_range2,
+		    MT6392_VSYS_CON7, BIT(13),
+		    MT6392_VSYS_CON7, BIT(0),
+		    MT6392_VSYS_CON5, BIT(0), // Not present in data sheet
+		    MT6392_VSYS_CON9, GENMASK(6, 0),
+		    MT6392_VSYS_CON10, GENMASK(6, 0),
+		    MT6392_VSYS_CON2, BIT(8),
+		    25000),
+	MT6392_BUCK("vcore", VCORE, "vcore", 700000, 1493750, 6250,
+		    buck_volt_range1,
+		    MT6392_VCORE_CON7, BIT(13),
+		    MT6392_VCORE_CON7, BIT(0),
+		    MT6392_VCORE_CON5, BIT(0), // Not present in data sheet
+		    MT6392_VCORE_CON9, GENMASK(6, 0),
+		    MT6392_VCORE_CON10, GENMASK(6, 0),
+		    MT6392_VCORE_CON2, BIT(8),
+		    12500),
+
+	MT6392_REG_FIXED("vxo22", VXO22, "ldo1", 2200000,
+			 MT6392_ANALDO_CON1, BIT(15),
+			 MT6392_ANALDO_CON1, BIT(10), // Not present in data sheet
+			 MT6392_ANALDO_CON1, BIT(7),
+			 MT6392_ANALDO_CON1, BIT(1), // Not present in data sheet
+			 110),
+	MT6392_LDO("vaud22", VAUD22, "ldo1", ldo_volt_table1,
+		   MT6392_ANALDO_CON2, BIT(15),
+		   MT6392_ANALDO_CON2, BIT(14), // Not present in data sheet
+		   MT6392_ANALDO_CON8, GENMASK(6, 5), // Not present in data sheet
+		   MT6392_ANALDO_CON2, BIT(7),
+		   MT6392_ANALDO_CON2, BIT(1),  // Not present in data sheet
+		   264),
+	MT6392_REG_FIXED_NO_MODE("vcama", VCAMA, "ldo1", 2800000,
+				 MT6392_ANALDO_CON4, BIT(15),
+				 MT6392_ANALDO_CON4, BIT(15),
+				 264),
+	MT6392_REG_FIXED("vaud28", VAUD28, "ldo1", 2800000,
+			 MT6392_ANALDO_CON23, BIT(15),
+			 MT6392_ANALDO_CON23, BIT(14), // Not present in data sheet
+			 MT6392_ANALDO_CON23, BIT(7),
+			 MT6392_ANALDO_CON23, BIT(1), // Not present in data sheet
+			 264),
+	MT6392_REG_FIXED("vadc18", VADC18, "ldo1", 1800000,
+			 MT6392_ANALDO_CON25, BIT(15),
+			 MT6392_ANALDO_CON25, BIT(14), // Not present in data sheet
+			 MT6392_ANALDO_CON25, BIT(7),
+			 MT6392_ANALDO_CON25, BIT(1), // Not present in data sheet
+			 264),
+	MT6392_LDO_LINEAR("vcn35", VCN35, "ldo2", 3300000, 3600000, 100000, ldo_volt_range2,
+			  MT6392_ANALDO_CON17, BIT(15), // Not present in data sheet
+			  MT6392_ANALDO_CON21, BIT(12), // Not present in data sheet
+			  MT6392_ANALDO_CON16, GENMASK(4, 3),
+			  MT6392_ANALDO_CON21, BIT(7),
+			  MT6392_ANALDO_CON21, BIT(1), // Not present in data sheet
+			  264),
+	MT6392_REG_FIXED("vio28", VIO28, "ldo2", 2800000,
+			 MT6392_DIGLDO_CON0, BIT(15),
+			 MT6392_DIGLDO_CON0, BIT(14), // Not present in data sheet
+			 MT6392_DIGLDO_CON0, BIT(7),
+			 MT6392_DIGLDO_CON0, BIT(1), // Not present in data sheet
+			 264),
+	MT6392_REG_FIXED("vusb", VUSB, "ldo3", 3300000,
+			 MT6392_DIGLDO_CON2, BIT(15),
+			 MT6392_DIGLDO_CON2, BIT(14), // Not present in data sheet
+			 MT6392_DIGLDO_CON2, BIT(7),
+			 MT6392_DIGLDO_CON2, BIT(1), // Not present in data sheet
+			 264),
+	MT6392_LDO("vmc", VMC, "ldo2", ldo_volt_table3,
+		   MT6392_DIGLDO_CON3, BIT(15),
+		   MT6392_DIGLDO_CON3, BIT(12),
+		   MT6392_DIGLDO_CON24, BIT(4),
+		   MT6392_DIGLDO_CON3, BIT(7),
+		   MT6392_DIGLDO_CON3, BIT(1), // Not present in data sheet
+		   264),
+	MT6392_LDO("vmch", VMCH, "ldo2", ldo_volt_table4,
+		   MT6392_DIGLDO_CON5, BIT(15),
+		   MT6392_DIGLDO_CON5, BIT(14),
+		   MT6392_DIGLDO_CON26, BIT(7),
+		   MT6392_DIGLDO_CON5, BIT(7),
+		   MT6392_DIGLDO_CON5, BIT(1), // Not present in data sheet
+		   264),
+	MT6392_LDO("vemc3v3", VEMC3V3, "ldo3", ldo_volt_table4,
+		   MT6392_DIGLDO_CON6, BIT(15),
+		   MT6392_DIGLDO_CON6, BIT(14), // Not present in data sheet
+		   MT6392_DIGLDO_CON27, BIT(7),
+		   MT6392_DIGLDO_CON6, BIT(7),
+		   MT6392_DIGLDO_CON6, BIT(1), // Not present in data sheet
+		   264),
+	MT6392_LDO("vgp1", VGP1, "ldo3", ldo_volt_table5,
+		   MT6392_DIGLDO_CON7, BIT(15),
+		   MT6392_DIGLDO_CON7, BIT(15),
+		   MT6392_DIGLDO_CON28, GENMASK(7, 5),
+		   MT6392_DIGLDO_CON7, BIT(7),
+		   MT6392_DIGLDO_CON7, BIT(1), // Not present in data sheet
+		   264),
+	MT6392_LDO("vgp2", VGP2, "ldo3", ldo_volt_table5,
+		   MT6392_DIGLDO_CON8, BIT(15),
+		   MT6392_DIGLDO_CON8, BIT(15),
+		   MT6392_DIGLDO_CON29, GENMASK(7, 5),
+		   MT6392_DIGLDO_CON8, BIT(7),
+		   MT6392_DIGLDO_CON8, BIT(1), // Not present in data sheet
+		   264),
+	MT6392_REG_FIXED("vcn18", VCN18, "avddldo", 1800000,
+			 MT6392_DIGLDO_CON11, BIT(15),
+			 MT6392_DIGLDO_CON11, BIT(14), // Not present in data sheet
+			 MT6392_DIGLDO_CON11, BIT(7),
+			 MT6392_DIGLDO_CON11, BIT(1), // Not present in data sheet
+			 264),
+	MT6392_LDO("vcamaf", VCAMAF, "ldo3", ldo_volt_table5,
+		   MT6392_DIGLDO_CON31, BIT(15),
+		   MT6392_DIGLDO_CON31, BIT(15),
+		   MT6392_DIGLDO_CON32, GENMASK(7, 5),
+		   MT6392_DIGLDO_CON31, BIT(7),
+		   MT6392_DIGLDO_CON31, BIT(1), // Not present in data sheet
+		   264),
+	MT6392_LDO("vm", VM, "avddldo", ldo_volt_table6,
+		   MT6392_DIGLDO_CON47, BIT(15),
+		   MT6392_DIGLDO_CON47, BIT(14), // Not present in data sheet
+		   MT6392_DIGLDO_CON48, GENMASK(5, 4), // Not present in data sheet
+		   MT6392_DIGLDO_CON47, BIT(7), // Not present in data sheet
+		   MT6392_DIGLDO_CON47, BIT(1),
+		   264),
+	MT6392_REG_FIXED("vio18", VIO18, "avddldo", 1800000,
+			 MT6392_DIGLDO_CON49, BIT(15),
+			 MT6392_DIGLDO_CON49, BIT(14), // Not present in data sheet
+			 MT6392_DIGLDO_CON49, BIT(7),
+			 MT6392_DIGLDO_CON49, BIT(1), // Not present in data sheet
+			 264),
+	MT6392_LDO("vcamd", VCAMD, "avddldo", ldo_volt_table7,
+		   MT6392_DIGLDO_CON51, BIT(15),
+		   MT6392_DIGLDO_CON51, BIT(14),
+		   MT6392_DIGLDO_CON52, GENMASK(6, 5),
+		   MT6392_DIGLDO_CON51, BIT(7),
+		   MT6392_DIGLDO_CON51, BIT(1),
+		   264),
+	MT6392_REG_FIXED("vcamio", VCAMIO, "avddldo", 1800000,
+			 MT6392_DIGLDO_CON53, BIT(15),
+			 MT6392_DIGLDO_CON53, BIT(14),
+			 MT6392_DIGLDO_CON53, BIT(7),
+			 MT6392_DIGLDO_CON53, BIT(1), // Not present in data sheet
+			 264),
+	MT6392_REG_FIXED("vm25", VM25, "ldo3", 2500000,
+			 MT6392_DIGLDO_CON55, BIT(15),
+			 MT6392_DIGLDO_CON55, BIT(14), // Not present in data sheet
+			 MT6392_DIGLDO_CON55, BIT(7),
+			 MT6392_DIGLDO_CON55, BIT(1), // Not present in data sheet
+			 264),
+	MT6392_LDO("vefuse", VEFUSE, "ldo2", ldo_volt_table8,
+		   MT6392_DIGLDO_CON57, BIT(15),
+		   MT6392_DIGLDO_CON57, BIT(14), // Not present in data sheet
+		   MT6392_DIGLDO_CON58, BIT(5), // Not present in data sheet
+		   MT6392_DIGLDO_CON57, BIT(7),
+		   MT6392_DIGLDO_CON57, BIT(1), // Not present in data sheet
+		   264),
+	MT6392_REG("vdig18", VDIG18, "ldo2", 1800000), // Internal non changeable regulator
+	MT6392_REG_FIXED_NO_MODE("vrtc", VRTC, "ldo1", 2800000,
+				 MT6392_DIGLDO_CON15, BIT(15),
+				 MT6392_DIGLDO_CON15, BIT(8), // Not present in data sheet
+				 264)
+};
+
+// Buck regulators can be in Register mode or Normal mode.
+// Each mode uses a different register to set the desired voltage.
+static int mt6392_set_buck_vsel_reg(struct platform_device *pdev)
+{
+	struct mt6397_chip *mt6392 = dev_get_drvdata(pdev->dev.parent);
+	int i;
+	u32 regval;
+
+	for (i = 0; i < MT6392_MAX_REGULATOR; i++) {
+		if (mt6392_regulators[i].vselctrl_reg) {
+			// Read the vselctrl_reg register
+			if (regmap_read(mt6392->regmap,
+					mt6392_regulators[i].vselctrl_reg,
+					&regval) < 0) {
+				dev_err(&pdev->dev,
+					"Failed to read buck ctrl\n");
+				return -EIO;
+			}
+
+			// vselctrl_reg[vselctrl_mask] defines the mode
+			if (regval & mt6392_regulators[i].vselctrl_mask) {
+				// Regulator in Normal mode
+				mt6392_regulators[i].desc.vsel_reg =
+					mt6392_regulators[i].vsel_normal_mode_reg;
+				mt6392_regulators[i].desc.vsel_mask =
+					mt6392_regulators[i].vsel_normal_mode_mask;
+			} else {
+				// Regulator in Register mode
+				mt6392_regulators[i].desc.vsel_reg =
+					mt6392_regulators[i].vsel_reg_mode_reg;
+				mt6392_regulators[i].desc.vsel_mask =
+					mt6392_regulators[i].vsel_reg_mode_mask;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int mt6392_regulator_probe(struct platform_device *pdev)
+{
+	struct mt6397_chip *mt6392 = dev_get_drvdata(pdev->dev.parent);
+	struct regulator_config config = {};
+	struct regulator_dev *rdev;
+	int i;
+
+	device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
+
+	// Initialize the bucks' vsel_reg and vsel_mask according to current HW state
+	if (mt6392_set_buck_vsel_reg(pdev))
+		return -EIO;
+
+	config.dev = mt6392->dev;
+	config.regmap = mt6392->regmap;
+	for (i = 0; i < MT6392_MAX_REGULATOR; i++) {
+		config.driver_data = &mt6392_regulators[i];
+
+		rdev = devm_regulator_register(&pdev->dev,
+					       &mt6392_regulators[i].desc,
+					       &config);
+		if (IS_ERR(rdev)) {
+			dev_err(&pdev->dev, "failed to register %s\n",
+				mt6392_regulators[i].desc.name);
+			return PTR_ERR(rdev);
+		}
+	}
+
+	return 0;
+}
+
+static const struct platform_device_id mt6392_platform_ids[] = {
+	{ .name = "mt6392-regulator" },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, mt6392_platform_ids);
+
+static struct platform_driver mt6392_regulator_driver = {
+	.driver = {
+		.name = "mt6392-regulator",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+	},
+	.probe = mt6392_regulator_probe,
+	.id_table = mt6392_platform_ids,
+};
+
+module_platform_driver(mt6392_regulator_driver);
+
+MODULE_AUTHOR("Chen Zhong <chen.zhong@mediatek.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6392 PMIC");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/regulator/mt6392-regulator.h b/include/linux/regulator/mt6392-regulator.h
new file mode 100644
index 000000000000..0eccd085b062
--- /dev/null
+++ b/include/linux/regulator/mt6392-regulator.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ * Author: Chen Zhong <chen.zhong@mediatek.com>
+ */
+
+#ifndef __LINUX_REGULATOR_MT6392_H
+#define __LINUX_REGULATOR_MT6392_H
+
+enum {
+	MT6392_ID_VPROC = 0,
+	MT6392_ID_VSYS,
+	MT6392_ID_VCORE,
+	MT6392_ID_VXO22,
+	MT6392_ID_VAUD22,
+	MT6392_ID_VCAMA,
+	MT6392_ID_VAUD28,
+	MT6392_ID_VADC18,
+	MT6392_ID_VCN35,
+	MT6392_ID_VIO28,
+	MT6392_ID_VUSB = 10,
+	MT6392_ID_VMC,
+	MT6392_ID_VMCH,
+	MT6392_ID_VEMC3V3,
+	MT6392_ID_VGP1,
+	MT6392_ID_VGP2,
+	MT6392_ID_VCN18,
+	MT6392_ID_VCAMAF,
+	MT6392_ID_VM,
+	MT6392_ID_VIO18,
+	MT6392_ID_VCAMD,
+	MT6392_ID_VCAMIO,
+	MT6392_ID_VM25,
+	MT6392_ID_VEFUSE,
+	MT6392_ID_VDIG18,
+	MT6392_ID_VRTC,
+	MT6392_ID_RG_MAX,
+};
+
+#define MT6392_MAX_REGULATOR	MT6392_ID_RG_MAX
+
+#endif /* __LINUX_REGULATOR_MT6392_H */
-- 
2.43.0


^ permalink raw reply related

* [PATCH v9 7/9] pinctrl: mediatek: mt6397: Add MediaTek MT6392
From: Luca Leonardo Scorcia @ 2026-06-21  8:13 UTC (permalink / raw)
  To: linux-mediatek
  Cc: Luca Leonardo Scorcia, AngeloGioacchino Del Regno,
	Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Sen Chu, Sean Wang, Macpaul Lin, Lee Jones, Matthias Brugger,
	Liam Girdwood, Mark Brown, Linus Walleij, Louis-Alexis Eyraud,
	Julien Massot, Val Packett, Fabien Parent, Akari Tsuyukusa,
	Chen Zhong, linux-input, devicetree, linux-kernel, linux-pm,
	linux-arm-kernel, linux-gpio
In-Reply-To: <20260621081634.467858-1-l.scorcia@gmail.com>

Add support for the MT6392 pinctrl device, which is very similar to
MT6397 with a handful of different property values and its own pins
definition.

Update the MT6397 driver to retrieve device data from the match table and
use it for driver init.

Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 drivers/pinctrl/mediatek/pinctrl-mt6397.c     | 37 ++++++++++-
 drivers/pinctrl/mediatek/pinctrl-mtk-mt6392.h | 64 +++++++++++++++++++
 2 files changed, 99 insertions(+), 2 deletions(-)
 create mode 100644 drivers/pinctrl/mediatek/pinctrl-mtk-mt6392.h

diff --git a/drivers/pinctrl/mediatek/pinctrl-mt6397.c b/drivers/pinctrl/mediatek/pinctrl-mt6397.c
index 03d0f65d7bcc..8ba02e70595c 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt6397.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt6397.c
@@ -12,10 +12,32 @@
 #include <linux/mfd/mt6397/core.h>
 
 #include "pinctrl-mtk-common.h"
+#include "pinctrl-mtk-mt6392.h"
 #include "pinctrl-mtk-mt6397.h"
 
 #define MT6397_PIN_REG_BASE  0xc000
 
+static const struct mtk_pinctrl_devdata mt6392_pinctrl_data = {
+	.pins = mtk_pins_mt6392,
+	.npins = ARRAY_SIZE(mtk_pins_mt6392),
+	.dir_offset = (MT6397_PIN_REG_BASE + 0x000),
+	.ies_offset = MTK_PINCTRL_NOT_SUPPORT,
+	.smt_offset = MTK_PINCTRL_NOT_SUPPORT,
+	.pullen_offset = (MT6397_PIN_REG_BASE + 0x020),
+	.pullsel_offset = (MT6397_PIN_REG_BASE + 0x040),
+	.dout_offset = (MT6397_PIN_REG_BASE + 0x080),
+	.din_offset = (MT6397_PIN_REG_BASE + 0x0a0),
+	.pinmux_offset = (MT6397_PIN_REG_BASE + 0x0c0),
+	.type1_start = 7,
+	.type1_end = 7,
+	.port_shf = 3,
+	.port_mask = 0x3,
+	.port_align = 2,
+	.mode_mask = 0xf,
+	.mode_per_reg = 5,
+	.mode_shf = 4,
+};
+
 static const struct mtk_pinctrl_devdata mt6397_pinctrl_data = {
 	.pins = mtk_pins_mt6397,
 	.npins = ARRAY_SIZE(mtk_pins_mt6397),
@@ -40,13 +62,24 @@ static const struct mtk_pinctrl_devdata mt6397_pinctrl_data = {
 static int mt6397_pinctrl_probe(struct platform_device *pdev)
 {
 	struct mt6397_chip *mt6397;
+	const struct mtk_pinctrl_devdata *data;
+
+	data = device_get_match_data(&pdev->dev);
+	if (!data)
+		return -ENOENT;
 
 	mt6397 = dev_get_drvdata(pdev->dev.parent);
-	return mtk_pctrl_init(pdev, &mt6397_pinctrl_data, mt6397->regmap);
+	return mtk_pctrl_init(pdev, data, mt6397->regmap);
 }
 
 static const struct of_device_id mt6397_pctrl_match[] = {
-	{ .compatible = "mediatek,mt6397-pinctrl", },
+	{
+		.compatible = "mediatek,mt6392-pinctrl",
+		.data = &mt6392_pinctrl_data
+	}, {
+		.compatible = "mediatek,mt6397-pinctrl",
+		.data = &mt6397_pinctrl_data
+	},
 	{ }
 };
 
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-mt6392.h b/drivers/pinctrl/mediatek/pinctrl-mtk-mt6392.h
new file mode 100644
index 000000000000..e7241af28fdb
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-mt6392.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __PINCTRL_MTK_MT6392_H
+#define __PINCTRL_MTK_MT6392_H
+
+#include <linux/pinctrl/pinctrl.h>
+#include "pinctrl-mtk-common.h"
+
+static const struct mtk_desc_pin mtk_pins_mt6392[] = {
+	MTK_PIN(PINCTRL_PIN(0, "INT"),
+		NULL, "mt6392",
+		MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+		MTK_FUNCTION(0, "GPIO0"),
+		MTK_FUNCTION(1, "INT"),
+		MTK_FUNCTION(5, "TEST_CK2"),
+		MTK_FUNCTION(6, "TEST_IN1"),
+		MTK_FUNCTION(7, "TEST_OUT1")
+	),
+	MTK_PIN(PINCTRL_PIN(1, "SRCLKEN"),
+		NULL, "mt6392",
+		MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+		MTK_FUNCTION(0, "GPIO1"),
+		MTK_FUNCTION(1, "SRCLKEN"),
+		MTK_FUNCTION(5, "TEST_CK0"),
+		MTK_FUNCTION(6, "TEST_IN2"),
+		MTK_FUNCTION(7, "TEST_OUT2")
+	),
+	MTK_PIN(PINCTRL_PIN(2, "RTC_32K1V8"),
+		NULL, "mt6392",
+		MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+		MTK_FUNCTION(0, "GPIO2"),
+		MTK_FUNCTION(1, "RTC_32K1V8"),
+		MTK_FUNCTION(5, "TEST_CK1"),
+		MTK_FUNCTION(6, "TEST_IN3"),
+		MTK_FUNCTION(7, "TEST_OUT3")
+	),
+	MTK_PIN(PINCTRL_PIN(3, "SPI_CLK"),
+		NULL, "mt6392",
+		MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+		MTK_FUNCTION(0, "GPIO3"),
+		MTK_FUNCTION(1, "SPI_CLK")
+	),
+	MTK_PIN(PINCTRL_PIN(4, "SPI_CSN"),
+		NULL, "mt6392",
+		MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+		MTK_FUNCTION(0, "GPIO4"),
+		MTK_FUNCTION(1, "SPI_CSN")
+	),
+	MTK_PIN(PINCTRL_PIN(5, "SPI_MOSI"),
+		NULL, "mt6392",
+		MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+		MTK_FUNCTION(0, "GPIO5"),
+		MTK_FUNCTION(1, "SPI_MOSI")
+	),
+	MTK_PIN(PINCTRL_PIN(6, "SPI_MISO"),
+		NULL, "mt6392",
+		MTK_EINT_FUNCTION(NO_EINT_SUPPORT, NO_EINT_SUPPORT),
+		MTK_FUNCTION(0, "GPIO6"),
+		MTK_FUNCTION(1, "SPI_MISO"),
+		MTK_FUNCTION(6, "TEST_IN4"),
+		MTK_FUNCTION(7, "TEST_OUT4")
+	),
+};
+
+#endif /* __PINCTRL_MTK_MT6392_H */
-- 
2.43.0


^ permalink raw reply related

* [PATCH v9 6/9] input: keyboard: mtk-pmic-keys: Add MT6392 support
From: Luca Leonardo Scorcia @ 2026-06-21  8:13 UTC (permalink / raw)
  To: linux-mediatek
  Cc: Val Packett, Luca Leonardo Scorcia, AngeloGioacchino Del Regno,
	Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Sen Chu, Sean Wang, Macpaul Lin, Lee Jones, Matthias Brugger,
	Liam Girdwood, Mark Brown, Linus Walleij, Louis-Alexis Eyraud,
	Julien Massot, Fabien Parent, Akari Tsuyukusa, Chen Zhong,
	linux-input, devicetree, linux-kernel, linux-pm, linux-arm-kernel,
	linux-gpio
In-Reply-To: <20260621081634.467858-1-l.scorcia@gmail.com>

From: Val Packett <val@packett.cool>

Add support for the MT6392 PMIC to the keys driver.

Signed-off-by: Val Packett <val@packett.cool>
Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/input/keyboard/mtk-pmic-keys.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/drivers/input/keyboard/mtk-pmic-keys.c b/drivers/input/keyboard/mtk-pmic-keys.c
index c78d9f6d97c4..8b4a89fce4fb 100644
--- a/drivers/input/keyboard/mtk-pmic-keys.c
+++ b/drivers/input/keyboard/mtk-pmic-keys.c
@@ -13,6 +13,7 @@
 #include <linux/mfd/mt6357/registers.h>
 #include <linux/mfd/mt6358/registers.h>
 #include <linux/mfd/mt6359/registers.h>
+#include <linux/mfd/mt6392/registers.h>
 #include <linux/mfd/mt6397/core.h>
 #include <linux/mfd/mt6397/registers.h>
 #include <linux/module.h>
@@ -69,6 +70,19 @@ static const struct mtk_pmic_regs mt6397_regs = {
 	.rst_lprst_mask = MTK_PMIC_RST_DU_MASK,
 };
 
+static const struct mtk_pmic_regs mt6392_regs = {
+	.keys_regs[MTK_PMIC_PWRKEY_INDEX] =
+		MTK_PMIC_KEYS_REGS(MT6392_CHRSTATUS, 0x2,
+				   MT6392_INT_MISC_CON, 0x10,
+				   MTK_PMIC_PWRKEY_RST),
+	.keys_regs[MTK_PMIC_HOMEKEY_INDEX] =
+		MTK_PMIC_KEYS_REGS(MT6392_CHRSTATUS, 0x4,
+				   MT6392_INT_MISC_CON, 0x8,
+				   MTK_PMIC_HOMEKEY_RST),
+	.pmic_rst_reg = MT6392_TOP_RST_MISC,
+	.rst_lprst_mask = MTK_PMIC_RST_DU_MASK,
+};
+
 static const struct mtk_pmic_regs mt6323_regs = {
 	.keys_regs[MTK_PMIC_PWRKEY_INDEX] =
 		MTK_PMIC_KEYS_REGS(MT6323_CHRSTATUS,
@@ -301,6 +315,9 @@ static const struct of_device_id of_mtk_pmic_keys_match_tbl[] = {
 	{
 		.compatible = "mediatek,mt6397-keys",
 		.data = &mt6397_regs,
+	}, {
+		.compatible = "mediatek,mt6392-keys",
+		.data = &mt6392_regs,
 	}, {
 		.compatible = "mediatek,mt6323-keys",
 		.data = &mt6323_regs,
-- 
2.43.0


^ permalink raw reply related

* [PATCH v9 5/9] mfd: mt6397: Add support for MT6392 PMIC
From: Luca Leonardo Scorcia @ 2026-06-21  8:13 UTC (permalink / raw)
  To: linux-mediatek
  Cc: Fabien Parent, Val Packett, Luca Leonardo Scorcia,
	AngeloGioacchino Del Regno, Dmitry Torokhov, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Sen Chu, Sean Wang,
	Macpaul Lin, Lee Jones, Matthias Brugger, Liam Girdwood,
	Mark Brown, Linus Walleij, Louis-Alexis Eyraud, Julien Massot,
	Akari Tsuyukusa, Chen Zhong, linux-input, devicetree,
	linux-kernel, linux-pm, linux-arm-kernel, linux-gpio
In-Reply-To: <20260621081634.467858-1-l.scorcia@gmail.com>

From: Fabien Parent <parent.f@gmail.com>

Align the MT6397 PMIC driver to other MFD drivers by passing only an
identifier through mt6397_of_match[*].data and add support for the MT6392
PMIC and its regulator, RTC, keys and pinctrl devices.

The keys device manages two buttons named PWRKEY and FCHR_ENB, the latter
is identified as "Force charging disable" in the data sheet but it also
says "Merge with HOMEKEY", so call it "Home" for consistency.

Signed-off-by: Fabien Parent <parent.f@gmail.com>
Signed-off-by: Val Packett <val@packett.cool>
Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 drivers/mfd/mt6397-core.c            |  98 ++++--
 drivers/mfd/mt6397-irq.c             |   8 +
 include/linux/mfd/mt6392/core.h      |  43 +++
 include/linux/mfd/mt6392/registers.h | 488 +++++++++++++++++++++++++++
 include/linux/mfd/mt6397/core.h      |   1 +
 5 files changed, 612 insertions(+), 26 deletions(-)
 create mode 100644 include/linux/mfd/mt6392/core.h
 create mode 100644 include/linux/mfd/mt6392/registers.h

diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c
index ccd97d66d7f1..f683e878543e 100644
--- a/drivers/mfd/mt6397-core.c
+++ b/drivers/mfd/mt6397-core.c
@@ -18,6 +18,7 @@
 #include <linux/mfd/mt6357/core.h>
 #include <linux/mfd/mt6358/core.h>
 #include <linux/mfd/mt6359/core.h>
+#include <linux/mfd/mt6392/core.h>
 #include <linux/mfd/mt6397/core.h>
 #include <linux/mfd/mt6323/registers.h>
 #include <linux/mfd/mt6328/registers.h>
@@ -25,6 +26,7 @@
 #include <linux/mfd/mt6357/registers.h>
 #include <linux/mfd/mt6358/registers.h>
 #include <linux/mfd/mt6359/registers.h>
+#include <linux/mfd/mt6392/registers.h>
 #include <linux/mfd/mt6397/registers.h>
 
 #define MT6323_RTC_BASE		0x8000
@@ -39,6 +41,9 @@
 #define MT6358_RTC_BASE		0x0588
 #define MT6358_RTC_SIZE		0x3c
 
+#define MT6392_RTC_BASE		0x8000
+#define MT6392_RTC_SIZE		0x3e
+
 #define MT6397_RTC_BASE		0xe000
 #define MT6397_RTC_SIZE		0x3e
 
@@ -65,6 +70,11 @@ static const struct resource mt6358_rtc_resources[] = {
 	DEFINE_RES_IRQ(MT6358_IRQ_RTC),
 };
 
+static const struct resource mt6392_rtc_resources[] = {
+	DEFINE_RES_MEM(MT6392_RTC_BASE, MT6392_RTC_SIZE),
+	DEFINE_RES_IRQ(MT6392_IRQ_RTC),
+};
+
 static const struct resource mt6397_rtc_resources[] = {
 	DEFINE_RES_MEM(MT6397_RTC_BASE, MT6397_RTC_SIZE),
 	DEFINE_RES_IRQ(MT6397_IRQ_RTC),
@@ -114,6 +124,11 @@ static const struct resource mt6331_keys_resources[] = {
 	DEFINE_RES_IRQ_NAMED(MT6331_IRQ_STATUS_HOMEKEY, "homekey"),
 };
 
+static const struct resource mt6392_keys_resources[] = {
+	DEFINE_RES_IRQ_NAMED(MT6392_IRQ_PWRKEY, "powerkey"),
+	DEFINE_RES_IRQ_NAMED(MT6392_IRQ_FCHRKEY, "homekey"),
+};
+
 static const struct resource mt6397_keys_resources[] = {
 	DEFINE_RES_IRQ_NAMED(MT6397_IRQ_PWRKEY, "powerkey"),
 	DEFINE_RES_IRQ_NAMED(MT6397_IRQ_HOMEKEY, "homekey"),
@@ -193,6 +208,16 @@ static const struct mfd_cell mt6359_devs[] = {
 		    "mediatek,mt6359-accdet"),
 };
 
+static const struct mfd_cell mt6392_devs[] = {
+	MFD_CELL_OF("mt6392-keys", mt6392_keys_resources, NULL, 0, 0,
+		    "mediatek,mt6392-keys"),
+	MFD_CELL_OF("mt6392-pinctrl", NULL, NULL, 0, 0,
+		    "mediatek,mt6392-pinctrl"),
+	MFD_CELL_NAME("mt6392-regulator"),
+	MFD_CELL_OF("mt6392-rtc", mt6392_rtc_resources, NULL, 0, 0,
+		    "mediatek,mt6392-rtc"),
+};
+
 static const struct mfd_cell mt6397_devs[] = {
 	MFD_CELL_OF("mt6397-rtc", mt6397_rtc_resources, NULL, 0, 0,
 		    "mediatek,mt6397-rtc"),
@@ -264,6 +289,14 @@ static const struct chip_data mt6359_core = {
 	.irq_init = mt6358_irq_init,
 };
 
+static const struct chip_data mt6392_core = {
+	.cid_addr = MT6392_CID,
+	.cid_shift = 0,
+	.cells = mt6392_devs,
+	.cell_size = ARRAY_SIZE(mt6392_devs),
+	.irq_init = mt6397_irq_init,
+};
+
 static const struct chip_data mt6397_core = {
 	.cid_addr = MT6397_CID,
 	.cid_shift = 0,
@@ -278,6 +311,7 @@ static int mt6397_probe(struct platform_device *pdev)
 	unsigned int id = 0;
 	struct mt6397_chip *pmic;
 	const struct chip_data *pmic_core;
+	int chip_variant;
 
 	pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
 	if (!pmic)
@@ -293,9 +327,36 @@ static int mt6397_probe(struct platform_device *pdev)
 	if (!pmic->regmap)
 		return -ENODEV;
 
-	pmic_core = of_device_get_match_data(&pdev->dev);
-	if (!pmic_core)
+	chip_variant = (unsigned int)(uintptr_t)device_get_match_data(&pdev->dev);
+	switch (chip_variant) {
+	case MT6323_CHIP_ID:
+		pmic_core = &mt6323_core;
+		break;
+	case MT6328_CHIP_ID:
+		pmic_core = &mt6328_core;
+		break;
+	case MT6331_CHIP_ID:
+		pmic_core = &mt6331_mt6332_core;
+		break;
+	case MT6357_CHIP_ID:
+		pmic_core = &mt6357_core;
+		break;
+	case MT6358_CHIP_ID:
+		pmic_core = &mt6358_core;
+		break;
+	case MT6359_CHIP_ID:
+		pmic_core = &mt6359_core;
+		break;
+	case MT6392_CHIP_ID:
+		pmic_core = &mt6392_core;
+		break;
+	case MT6397_CHIP_ID:
+		pmic_core = &mt6397_core;
+		break;
+	default:
+		dev_err(&pdev->dev, "Device not supported\n");
 		return -ENODEV;
+	}
 
 	ret = regmap_read(pmic->regmap, pmic_core->cid_addr, &id);
 	if (ret) {
@@ -327,30 +388,15 @@ static int mt6397_probe(struct platform_device *pdev)
 }
 
 static const struct of_device_id mt6397_of_match[] = {
-	{
-		.compatible = "mediatek,mt6323",
-		.data = &mt6323_core,
-	}, {
-		.compatible = "mediatek,mt6328",
-		.data = &mt6328_core,
-	}, {
-		.compatible = "mediatek,mt6331",
-		.data = &mt6331_mt6332_core,
-	}, {
-		.compatible = "mediatek,mt6357",
-		.data = &mt6357_core,
-	}, {
-		.compatible = "mediatek,mt6358",
-		.data = &mt6358_core,
-	}, {
-		.compatible = "mediatek,mt6359",
-		.data = &mt6359_core,
-	}, {
-		.compatible = "mediatek,mt6397",
-		.data = &mt6397_core,
-	}, {
-		/* sentinel */
-	}
+	{ .compatible = "mediatek,mt6323", .data = (void *)MT6323_CHIP_ID, },
+	{ .compatible = "mediatek,mt6328", .data = (void *)MT6328_CHIP_ID, },
+	{ .compatible = "mediatek,mt6331", .data = (void *)MT6331_CHIP_ID, },
+	{ .compatible = "mediatek,mt6357", .data = (void *)MT6357_CHIP_ID, },
+	{ .compatible = "mediatek,mt6358", .data = (void *)MT6358_CHIP_ID, },
+	{ .compatible = "mediatek,mt6359", .data = (void *)MT6359_CHIP_ID, },
+	{ .compatible = "mediatek,mt6392", .data = (void *)MT6392_CHIP_ID, },
+	{ .compatible = "mediatek,mt6397", .data = (void *)MT6397_CHIP_ID, },
+	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, mt6397_of_match);
 
diff --git a/drivers/mfd/mt6397-irq.c b/drivers/mfd/mt6397-irq.c
index 5d2e5459f744..80ea5b92d232 100644
--- a/drivers/mfd/mt6397-irq.c
+++ b/drivers/mfd/mt6397-irq.c
@@ -15,6 +15,8 @@
 #include <linux/mfd/mt6328/registers.h>
 #include <linux/mfd/mt6331/core.h>
 #include <linux/mfd/mt6331/registers.h>
+#include <linux/mfd/mt6392/core.h>
+#include <linux/mfd/mt6392/registers.h>
 #include <linux/mfd/mt6397/core.h>
 #include <linux/mfd/mt6397/registers.h>
 
@@ -203,6 +205,12 @@ int mt6397_irq_init(struct mt6397_chip *chip)
 		chip->int_status[0] = MT6397_INT_STATUS0;
 		chip->int_status[1] = MT6397_INT_STATUS1;
 		break;
+	case MT6392_CHIP_ID:
+		chip->int_con[0] = MT6392_INT_CON0;
+		chip->int_con[1] = MT6392_INT_CON1;
+		chip->int_status[0] = MT6392_INT_STATUS0;
+		chip->int_status[1] = MT6392_INT_STATUS1;
+		break;
 
 	default:
 		dev_err(chip->dev, "unsupported chip: 0x%x\n", chip->chip_id);
diff --git a/include/linux/mfd/mt6392/core.h b/include/linux/mfd/mt6392/core.h
new file mode 100644
index 000000000000..8777b3abf929
--- /dev/null
+++ b/include/linux/mfd/mt6392/core.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ * Copyright (c) 2026 Luca Leonardo Scorcia <l.scorcia@gmail.com>
+ * Author: Chen Zhong <chen.zhong@mediatek.com>
+ */
+
+#ifndef __MFD_MT6392_CORE_H__
+#define __MFD_MT6392_CORE_H__
+
+enum mt6392_irq_numbers {
+	MT6392_IRQ_SPKL_AB = 0,
+	MT6392_IRQ_SPKL,
+	MT6392_IRQ_BAT_L,
+	MT6392_IRQ_BAT_H,
+	MT6392_IRQ_WATCHDOG,
+	MT6392_IRQ_PWRKEY,
+	MT6392_IRQ_THR_L,
+	MT6392_IRQ_THR_H,
+	MT6392_IRQ_VBATON_UNDET,
+	MT6392_IRQ_BVALID_DET,
+	MT6392_IRQ_CHRDET,
+	MT6392_IRQ_OV,
+	MT6392_IRQ_LDO = 16,
+	MT6392_IRQ_FCHRKEY,
+	MT6392_IRQ_RELEASE_PWRKEY,
+	MT6392_IRQ_RELEASE_FCHRKEY,
+	MT6392_IRQ_RTC,
+	MT6392_IRQ_VPROC,
+	MT6392_IRQ_VSYS,
+	MT6392_IRQ_VCORE,
+	MT6392_IRQ_TYPE_C_CC,
+	MT6392_IRQ_TYPEC_H_MAX,
+	MT6392_IRQ_TYPEC_H_MIN,
+	MT6392_IRQ_TYPEC_L_MAX,
+	MT6392_IRQ_TYPEC_L_MIN,
+	MT6392_IRQ_THR_MAX,
+	MT6392_IRQ_THR_MIN,
+	MT6392_IRQ_NAG_C_DLTV,
+	MT6392_IRQ_NR,
+};
+
+#endif /* __MFD_MT6392_CORE_H__ */
diff --git a/include/linux/mfd/mt6392/registers.h b/include/linux/mfd/mt6392/registers.h
new file mode 100644
index 000000000000..68fe9af448f5
--- /dev/null
+++ b/include/linux/mfd/mt6392/registers.h
@@ -0,0 +1,488 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ * Copyright (c) 2026 Luca Leonardo Scorcia <l.scorcia@gmail.com>
+ * Author: Chen Zhong <chen.zhong@mediatek.com>
+ */
+
+#ifndef __MFD_MT6392_REGISTERS_H__
+#define __MFD_MT6392_REGISTERS_H__
+
+/* PMIC Registers */
+#define MT6392_CHR_CON0                         0x0000
+#define MT6392_CHR_CON1                         0x0002
+#define MT6392_CHR_CON2                         0x0004
+#define MT6392_CHR_CON3                         0x0006
+#define MT6392_CHR_CON4                         0x0008
+#define MT6392_CHR_CON5                         0x000A
+#define MT6392_CHR_CON6                         0x000C
+#define MT6392_CHR_CON7                         0x000E
+#define MT6392_CHR_CON8                         0x0010
+#define MT6392_CHR_CON9                         0x0012
+#define MT6392_CHR_CON10                        0x0014
+#define MT6392_CHR_CON11                        0x0016
+#define MT6392_CHR_CON12                        0x0018
+#define MT6392_CHR_CON13                        0x001A
+#define MT6392_CHR_CON14                        0x001C
+#define MT6392_CHR_CON15                        0x001E
+#define MT6392_CHR_CON16                        0x0020
+#define MT6392_CHR_CON17                        0x0022
+#define MT6392_CHR_CON18                        0x0024
+#define MT6392_CHR_CON19                        0x0026
+#define MT6392_CHR_CON20                        0x0028
+#define MT6392_CHR_CON21                        0x002A
+#define MT6392_CHR_CON22                        0x002C
+#define MT6392_CHR_CON23                        0x002E
+#define MT6392_CHR_CON24                        0x0030
+#define MT6392_CHR_CON25                        0x0032
+#define MT6392_CHR_CON26                        0x0034
+#define MT6392_CHR_CON27                        0x0036
+#define MT6392_CHR_CON28                        0x0038
+#define MT6392_CHR_CON29                        0x003A
+#define MT6392_STRUP_CON0                       0x003C
+#define MT6392_STRUP_CON2                       0x003E
+#define MT6392_STRUP_CON3                       0x0040
+#define MT6392_STRUP_CON4                       0x0042
+#define MT6392_STRUP_CON5                       0x0044
+#define MT6392_STRUP_CON6                       0x0046
+#define MT6392_STRUP_CON7                       0x0048
+#define MT6392_STRUP_CON8                       0x004A
+#define MT6392_STRUP_CON9                       0x004C
+#define MT6392_STRUP_CON10                      0x004E
+#define MT6392_STRUP_CON11                      0x0050
+#define MT6392_SPK_CON0                         0x0052
+#define MT6392_SPK_CON1                         0x0054
+#define MT6392_SPK_CON2                         0x0056
+#define MT6392_SPK_CON6                         0x005E
+#define MT6392_SPK_CON7                         0x0060
+#define MT6392_SPK_CON8                         0x0062
+#define MT6392_SPK_CON9                         0x0064
+#define MT6392_SPK_CON10                        0x0066
+#define MT6392_SPK_CON11                        0x0068
+#define MT6392_SPK_CON12                        0x006A
+#define MT6392_STRUP_CON12                      0x006E
+#define MT6392_STRUP_CON13                      0x0070
+#define MT6392_STRUP_CON14                      0x0072
+#define MT6392_STRUP_CON15                      0x0074
+#define MT6392_STRUP_CON16                      0x0076
+#define MT6392_STRUP_CON17                      0x0078
+#define MT6392_STRUP_CON18                      0x007A
+#define MT6392_STRUP_CON19                      0x007C
+#define MT6392_STRUP_CON20                      0x007E
+#define MT6392_CID                              0x0100
+#define MT6392_TOP_CKPDN0                       0x0102
+#define MT6392_TOP_CKPDN0_SET                   0x0104
+#define MT6392_TOP_CKPDN0_CLR                   0x0106
+#define MT6392_TOP_CKPDN1                       0x0108
+#define MT6392_TOP_CKPDN1_SET                   0x010A
+#define MT6392_TOP_CKPDN1_CLR                   0x010C
+#define MT6392_TOP_CKPDN2                       0x010E
+#define MT6392_TOP_CKPDN2_SET                   0x0110
+#define MT6392_TOP_CKPDN2_CLR                   0x0112
+#define MT6392_TOP_RST_CON                      0x0114
+#define MT6392_TOP_RST_CON_SET                  0x0116
+#define MT6392_TOP_RST_CON_CLR                  0x0118
+#define MT6392_TOP_RST_MISC                     0x011A
+#define MT6392_TOP_RST_MISC_SET                 0x011C
+#define MT6392_TOP_RST_MISC_CLR                 0x011E
+#define MT6392_TOP_CKCON0                       0x0120
+#define MT6392_TOP_CKCON0_SET                   0x0122
+#define MT6392_TOP_CKCON0_CLR                   0x0124
+#define MT6392_TOP_CKCON1                       0x0126
+#define MT6392_TOP_CKCON1_SET                   0x0128
+#define MT6392_TOP_CKCON1_CLR                   0x012A
+#define MT6392_TOP_CKTST0                       0x012C
+#define MT6392_TOP_CKTST1                       0x012E
+#define MT6392_TOP_CKTST2                       0x0130
+#define MT6392_TEST_OUT                         0x0132
+#define MT6392_TEST_CON0                        0x0134
+#define MT6392_TEST_CON1                        0x0136
+#define MT6392_EN_STATUS0                       0x0138
+#define MT6392_EN_STATUS1                       0x013A
+#define MT6392_OCSTATUS0                        0x013C
+#define MT6392_OCSTATUS1                        0x013E
+#define MT6392_PGSTATUS                         0x0140
+#define MT6392_CHRSTATUS                        0x0142
+#define MT6392_TDSEL_CON                        0x0144
+#define MT6392_RDSEL_CON                        0x0146
+#define MT6392_SMT_CON0                         0x0148
+#define MT6392_SMT_CON1                         0x014A
+#define MT6392_DRV_CON0                         0x0152
+#define MT6392_DRV_CON1                         0x0154
+#define MT6392_INT_CON0                         0x0160
+#define MT6392_INT_CON0_SET                     0x0162
+#define MT6392_INT_CON0_CLR                     0x0164
+#define MT6392_INT_CON1                         0x0166
+#define MT6392_INT_CON1_SET                     0x0168
+#define MT6392_INT_CON1_CLR                     0x016A
+#define MT6392_INT_MISC_CON                     0x016C
+#define MT6392_INT_MISC_CON_SET                 0x016E
+#define MT6392_INT_MISC_CON_CLR                 0x0170
+#define MT6392_INT_STATUS0                      0x0172
+#define MT6392_INT_STATUS1                      0x0174
+#define MT6392_OC_GEAR_0                        0x0176
+#define MT6392_OC_GEAR_1                        0x0178
+#define MT6392_OC_GEAR_2                        0x017A
+#define MT6392_OC_CTL_VPROC                     0x017C
+#define MT6392_OC_CTL_VSYS                      0x017E
+#define MT6392_OC_CTL_VCORE                     0x0180
+#define MT6392_FQMTR_CON0                       0x0182
+#define MT6392_FQMTR_CON1                       0x0184
+#define MT6392_FQMTR_CON2                       0x0186
+#define MT6392_RG_SPI_CON                       0x0188
+#define MT6392_DEW_DIO_EN                       0x018A
+#define MT6392_DEW_READ_TEST                    0x018C
+#define MT6392_DEW_WRITE_TEST                   0x018E
+#define MT6392_DEW_CRC_SWRST                    0x0190
+#define MT6392_DEW_CRC_EN                       0x0192
+#define MT6392_DEW_CRC_VAL                      0x0194
+#define MT6392_DEW_DBG_MON_SEL                  0x0196
+#define MT6392_DEW_CIPHER_KEY_SEL               0x0198
+#define MT6392_DEW_CIPHER_IV_SEL                0x019A
+#define MT6392_DEW_CIPHER_EN                    0x019C
+#define MT6392_DEW_CIPHER_RDY                   0x019E
+#define MT6392_DEW_CIPHER_MODE                  0x01A0
+#define MT6392_DEW_CIPHER_SWRST                 0x01A2
+#define MT6392_DEW_RDDMY_NO                     0x01A4
+#define MT6392_DEW_RDATA_DLY_SEL                0x01A6
+#define MT6392_CLK_TRIM_CON0                    0x01A8
+#define MT6392_BUCK_CON0                        0x0200
+#define MT6392_BUCK_CON1                        0x0202
+#define MT6392_BUCK_CON2                        0x0204
+#define MT6392_BUCK_CON3                        0x0206
+#define MT6392_BUCK_CON4                        0x0208
+#define MT6392_BUCK_CON5                        0x020A
+#define MT6392_VPROC_CON0                       0x020C
+#define MT6392_VPROC_CON1                       0x020E
+#define MT6392_VPROC_CON2                       0x0210
+#define MT6392_VPROC_CON3                       0x0212
+#define MT6392_VPROC_CON4                       0x0214
+#define MT6392_VPROC_CON5                       0x0216
+#define MT6392_VPROC_CON7                       0x021A
+#define MT6392_VPROC_CON8                       0x021C
+#define MT6392_VPROC_CON9                       0x021E
+#define MT6392_VPROC_CON10                      0x0220
+#define MT6392_VPROC_CON11                      0x0222
+#define MT6392_VPROC_CON12                      0x0224
+#define MT6392_VPROC_CON13                      0x0226
+#define MT6392_VPROC_CON14                      0x0228
+#define MT6392_VPROC_CON15                      0x022A
+#define MT6392_VPROC_CON18                      0x0230
+#define MT6392_VSYS_CON0                        0x0232
+#define MT6392_VSYS_CON1                        0x0234
+#define MT6392_VSYS_CON2                        0x0236
+#define MT6392_VSYS_CON3                        0x0238
+#define MT6392_VSYS_CON4                        0x023A
+#define MT6392_VSYS_CON5                        0x023C
+#define MT6392_VSYS_CON7                        0x0240
+#define MT6392_VSYS_CON8                        0x0242
+#define MT6392_VSYS_CON9                        0x0244
+#define MT6392_VSYS_CON10                       0x0246
+#define MT6392_VSYS_CON11                       0x0248
+#define MT6392_VSYS_CON12                       0x024A
+#define MT6392_VSYS_CON13                       0x024C
+#define MT6392_VSYS_CON14                       0x024E
+#define MT6392_VSYS_CON15                       0x0250
+#define MT6392_VSYS_CON18                       0x0256
+#define MT6392_BUCK_OC_CON0                     0x0258
+#define MT6392_BUCK_OC_CON1                     0x025A
+#define MT6392_BUCK_OC_CON2                     0x025C
+#define MT6392_BUCK_OC_CON3                     0x025E
+#define MT6392_BUCK_OC_CON4                     0x0260
+#define MT6392_BUCK_OC_VPROC_CON0               0x0262
+#define MT6392_BUCK_OC_VCORE_CON0               0x0264
+#define MT6392_BUCK_OC_VSYS_CON0                0x0266
+#define MT6392_BUCK_ANA_MON_CON0                0x0268
+#define MT6392_BUCK_EFUSE_OC_CON0               0x026A
+#define MT6392_VCORE_CON0                       0x0300
+#define MT6392_VCORE_CON1                       0x0302
+#define MT6392_VCORE_CON2                       0x0304
+#define MT6392_VCORE_CON3                       0x0306
+#define MT6392_VCORE_CON4                       0x0308
+#define MT6392_VCORE_CON5                       0x030A
+#define MT6392_VCORE_CON7                       0x030E
+#define MT6392_VCORE_CON8                       0x0310
+#define MT6392_VCORE_CON9                       0x0312
+#define MT6392_VCORE_CON10                      0x0314
+#define MT6392_VCORE_CON11                      0x0316
+#define MT6392_VCORE_CON12                      0x0318
+#define MT6392_VCORE_CON13                      0x031A
+#define MT6392_VCORE_CON14                      0x031C
+#define MT6392_VCORE_CON15                      0x031E
+#define MT6392_VCORE_CON18                      0x0324
+#define MT6392_BUCK_K_CON0                      0x032A
+#define MT6392_BUCK_K_CON1                      0x032C
+#define MT6392_BUCK_K_CON2                      0x032E
+#define MT6392_ANALDO_CON0                      0x0400
+#define MT6392_ANALDO_CON1                      0x0402
+#define MT6392_ANALDO_CON2                      0x0404
+#define MT6392_ANALDO_CON3                      0x0406
+#define MT6392_ANALDO_CON4                      0x0408
+#define MT6392_ANALDO_CON6                      0x040C
+#define MT6392_ANALDO_CON7                      0x040E
+#define MT6392_ANALDO_CON8                      0x0410
+#define MT6392_ANALDO_CON10                     0x0412
+#define MT6392_ANALDO_CON15                     0x0414
+#define MT6392_ANALDO_CON16                     0x0416
+#define MT6392_ANALDO_CON17                     0x0418
+#define MT6392_ANALDO_CON21                     0x0420
+#define MT6392_ANALDO_CON22                     0x0422
+#define MT6392_ANALDO_CON23                     0x0424
+#define MT6392_ANALDO_CON24                     0x0426
+#define MT6392_ANALDO_CON25                     0x0428
+#define MT6392_ANALDO_CON26                     0x042A
+#define MT6392_ANALDO_CON27                     0x042C
+#define MT6392_ANALDO_CON28                     0x042E
+#define MT6392_ANALDO_CON29                     0x0430
+#define MT6392_DIGLDO_CON0                      0x0500
+#define MT6392_DIGLDO_CON2                      0x0502
+#define MT6392_DIGLDO_CON3                      0x0504
+#define MT6392_DIGLDO_CON5                      0x0506
+#define MT6392_DIGLDO_CON6                      0x0508
+#define MT6392_DIGLDO_CON7                      0x050A
+#define MT6392_DIGLDO_CON8                      0x050C
+#define MT6392_DIGLDO_CON10                     0x0510
+#define MT6392_DIGLDO_CON11                     0x0512
+#define MT6392_DIGLDO_CON12                     0x0514
+#define MT6392_DIGLDO_CON15                     0x051A
+#define MT6392_DIGLDO_CON20                     0x0524
+#define MT6392_DIGLDO_CON21                     0x0526
+#define MT6392_DIGLDO_CON23                     0x0528
+#define MT6392_DIGLDO_CON24                     0x052A
+#define MT6392_DIGLDO_CON26                     0x052C
+#define MT6392_DIGLDO_CON27                     0x052E
+#define MT6392_DIGLDO_CON28                     0x0530
+#define MT6392_DIGLDO_CON29                     0x0532
+#define MT6392_DIGLDO_CON30                     0x0534
+#define MT6392_DIGLDO_CON31                     0x0536
+#define MT6392_DIGLDO_CON32                     0x0538
+#define MT6392_DIGLDO_CON33                     0x053A
+#define MT6392_DIGLDO_CON36                     0x0540
+#define MT6392_DIGLDO_CON41                     0x0546
+#define MT6392_DIGLDO_CON44                     0x054C
+#define MT6392_DIGLDO_CON47                     0x0552
+#define MT6392_DIGLDO_CON48                     0x0554
+#define MT6392_DIGLDO_CON49                     0x0556
+#define MT6392_DIGLDO_CON50                     0x0558
+#define MT6392_DIGLDO_CON51                     0x055A
+#define MT6392_DIGLDO_CON52                     0x055C
+#define MT6392_DIGLDO_CON53                     0x055E
+#define MT6392_DIGLDO_CON54                     0x0560
+#define MT6392_DIGLDO_CON55                     0x0562
+#define MT6392_DIGLDO_CON56                     0x0564
+#define MT6392_DIGLDO_CON57                     0x0566
+#define MT6392_DIGLDO_CON58                     0x0568
+#define MT6392_DIGLDO_CON59                     0x056A
+#define MT6392_DIGLDO_CON60                     0x056C
+#define MT6392_DIGLDO_CON61                     0x056E
+#define MT6392_DIGLDO_CON62                     0x0570
+#define MT6392_DIGLDO_CON63                     0x0572
+#define MT6392_EFUSE_CON0                       0x0600
+#define MT6392_EFUSE_CON1                       0x0602
+#define MT6392_EFUSE_CON2                       0x0604
+#define MT6392_EFUSE_CON3                       0x0606
+#define MT6392_EFUSE_CON4                       0x0608
+#define MT6392_EFUSE_CON5                       0x060A
+#define MT6392_EFUSE_CON6                       0x060C
+#define MT6392_EFUSE_VAL_0_15                   0x060E
+#define MT6392_EFUSE_VAL_16_31                  0x0610
+#define MT6392_EFUSE_VAL_32_47                  0x0612
+#define MT6392_EFUSE_VAL_48_63                  0x0614
+#define MT6392_EFUSE_VAL_64_79                  0x0616
+#define MT6392_EFUSE_VAL_80_95                  0x0618
+#define MT6392_EFUSE_VAL_96_111                 0x061A
+#define MT6392_EFUSE_VAL_112_127                0x061C
+#define MT6392_EFUSE_VAL_128_143                0x061E
+#define MT6392_EFUSE_VAL_144_159                0x0620
+#define MT6392_EFUSE_VAL_160_175                0x0622
+#define MT6392_EFUSE_VAL_176_191                0x0624
+#define MT6392_EFUSE_VAL_192_207                0x0626
+#define MT6392_EFUSE_VAL_208_223                0x0628
+#define MT6392_EFUSE_VAL_224_239                0x062A
+#define MT6392_EFUSE_VAL_240_255                0x062C
+#define MT6392_EFUSE_VAL_256_271                0x062E
+#define MT6392_EFUSE_VAL_272_287                0x0630
+#define MT6392_EFUSE_VAL_288_303                0x0632
+#define MT6392_EFUSE_VAL_304_319                0x0634
+#define MT6392_EFUSE_VAL_320_335                0x0636
+#define MT6392_EFUSE_VAL_336_351                0x0638
+#define MT6392_EFUSE_VAL_352_367                0x063A
+#define MT6392_EFUSE_VAL_368_383                0x063C
+#define MT6392_EFUSE_VAL_384_399                0x063E
+#define MT6392_EFUSE_VAL_400_415                0x0640
+#define MT6392_EFUSE_VAL_416_431                0x0642
+#define MT6392_RTC_MIX_CON0                     0x0644
+#define MT6392_RTC_MIX_CON1                     0x0646
+#define MT6392_EFUSE_VAL_432_447                0x0648
+#define MT6392_EFUSE_VAL_448_463                0x064A
+#define MT6392_EFUSE_VAL_464_479                0x064C
+#define MT6392_EFUSE_VAL_480_495                0x064E
+#define MT6392_EFUSE_VAL_496_511                0x0650
+#define MT6392_EFUSE_DOUT_0_15                  0x0652
+#define MT6392_EFUSE_DOUT_16_31                 0x0654
+#define MT6392_EFUSE_DOUT_32_47                 0x0656
+#define MT6392_EFUSE_DOUT_48_63                 0x0658
+#define MT6392_EFUSE_DOUT_64_79                 0x065A
+#define MT6392_EFUSE_DOUT_80_95                 0x065C
+#define MT6392_EFUSE_DOUT_96_111                0x065E
+#define MT6392_EFUSE_DOUT_112_127               0x0660
+#define MT6392_EFUSE_DOUT_128_143               0x0662
+#define MT6392_EFUSE_DOUT_144_159               0x0664
+#define MT6392_EFUSE_DOUT_160_175               0x0666
+#define MT6392_EFUSE_DOUT_176_191               0x0668
+#define MT6392_EFUSE_DOUT_192_207               0x066A
+#define MT6392_EFUSE_DOUT_208_223               0x066C
+#define MT6392_EFUSE_DOUT_224_239               0x066E
+#define MT6392_EFUSE_DOUT_240_255               0x0670
+#define MT6392_EFUSE_DOUT_256_271               0x0672
+#define MT6392_EFUSE_DOUT_272_287               0x0674
+#define MT6392_EFUSE_DOUT_288_303               0x0676
+#define MT6392_EFUSE_DOUT_304_319               0x0678
+#define MT6392_EFUSE_DOUT_320_335               0x067A
+#define MT6392_EFUSE_DOUT_336_351               0x067C
+#define MT6392_EFUSE_DOUT_352_367               0x067E
+#define MT6392_EFUSE_DOUT_368_383               0x0680
+#define MT6392_EFUSE_DOUT_384_399               0x0682
+#define MT6392_EFUSE_DOUT_400_415               0x0684
+#define MT6392_EFUSE_DOUT_416_431               0x0686
+#define MT6392_EFUSE_DOUT_432_447               0x0688
+#define MT6392_EFUSE_DOUT_448_463               0x068A
+#define MT6392_EFUSE_DOUT_464_479               0x068C
+#define MT6392_EFUSE_DOUT_480_495               0x068E
+#define MT6392_EFUSE_DOUT_496_511               0x0690
+#define MT6392_EFUSE_CON7                       0x0692
+#define MT6392_EFUSE_CON8                       0x0694
+#define MT6392_EFUSE_CON9                       0x0696
+#define MT6392_AUXADC_ADC0                      0x0700
+#define MT6392_AUXADC_ADC1                      0x0702
+#define MT6392_AUXADC_ADC2                      0x0704
+#define MT6392_AUXADC_ADC3                      0x0706
+#define MT6392_AUXADC_ADC4                      0x0708
+#define MT6392_AUXADC_ADC5                      0x070A
+#define MT6392_AUXADC_ADC6                      0x070C
+#define MT6392_AUXADC_ADC7                      0x070E
+#define MT6392_AUXADC_ADC8                      0x0710
+#define MT6392_AUXADC_ADC9                      0x0712
+#define MT6392_AUXADC_ADC10                     0x0714
+#define MT6392_AUXADC_ADC11                     0x0716
+#define MT6392_AUXADC_ADC12                     0x0718
+#define MT6392_AUXADC_ADC13                     0x071A
+#define MT6392_AUXADC_ADC14                     0x071C
+#define MT6392_AUXADC_ADC15                     0x071E
+#define MT6392_AUXADC_ADC16                     0x0720
+#define MT6392_AUXADC_ADC17                     0x0722
+#define MT6392_AUXADC_ADC18                     0x0724
+#define MT6392_AUXADC_ADC19                     0x0726
+#define MT6392_AUXADC_ADC20                     0x0728
+#define MT6392_AUXADC_ADC21                     0x072A
+#define MT6392_AUXADC_ADC22                     0x072C
+#define MT6392_AUXADC_STA0                      0x072E
+#define MT6392_AUXADC_STA1                      0x0730
+#define MT6392_AUXADC_RQST0                     0x0732
+#define MT6392_AUXADC_RQST0_SET                 0x0734
+#define MT6392_AUXADC_RQST0_CLR                 0x0736
+#define MT6392_AUXADC_CON0                      0x0738
+#define MT6392_AUXADC_CON0_SET                  0x073A
+#define MT6392_AUXADC_CON0_CLR                  0x073C
+#define MT6392_AUXADC_CON1                      0x073E
+#define MT6392_AUXADC_CON2                      0x0740
+#define MT6392_AUXADC_CON3                      0x0742
+#define MT6392_AUXADC_CON4                      0x0744
+#define MT6392_AUXADC_CON5                      0x0746
+#define MT6392_AUXADC_CON6                      0x0748
+#define MT6392_AUXADC_CON7                      0x074A
+#define MT6392_AUXADC_CON8                      0x074C
+#define MT6392_AUXADC_CON9                      0x074E
+#define MT6392_AUXADC_CON10                     0x0750
+#define MT6392_AUXADC_CON11                     0x0752
+#define MT6392_AUXADC_CON12                     0x0754
+#define MT6392_AUXADC_CON13                     0x0756
+#define MT6392_AUXADC_CON14                     0x0758
+#define MT6392_AUXADC_CON15                     0x075A
+#define MT6392_AUXADC_CON16                     0x075C
+#define MT6392_AUXADC_AUTORPT0                  0x075E
+#define MT6392_AUXADC_LBAT0                     0x0760
+#define MT6392_AUXADC_LBAT1                     0x0762
+#define MT6392_AUXADC_LBAT2                     0x0764
+#define MT6392_AUXADC_LBAT3                     0x0766
+#define MT6392_AUXADC_LBAT4                     0x0768
+#define MT6392_AUXADC_LBAT5                     0x076A
+#define MT6392_AUXADC_LBAT6                     0x076C
+#define MT6392_AUXADC_THR0                      0x076E
+#define MT6392_AUXADC_THR1                      0x0770
+#define MT6392_AUXADC_THR2                      0x0772
+#define MT6392_AUXADC_THR3                      0x0774
+#define MT6392_AUXADC_THR4                      0x0776
+#define MT6392_AUXADC_THR5                      0x0778
+#define MT6392_AUXADC_THR6                      0x077A
+#define MT6392_AUXADC_EFUSE0                    0x077C
+#define MT6392_AUXADC_EFUSE1                    0x077E
+#define MT6392_AUXADC_EFUSE2                    0x0780
+#define MT6392_AUXADC_EFUSE3                    0x0782
+#define MT6392_AUXADC_EFUSE4                    0x0784
+#define MT6392_AUXADC_EFUSE5                    0x0786
+#define MT6392_AUXADC_NAG_0                     0x0788
+#define MT6392_AUXADC_NAG_1                     0x078A
+#define MT6392_AUXADC_NAG_2                     0x078C
+#define MT6392_AUXADC_NAG_3                     0x078E
+#define MT6392_AUXADC_NAG_4                     0x0790
+#define MT6392_AUXADC_NAG_5                     0x0792
+#define MT6392_AUXADC_NAG_6                     0x0794
+#define MT6392_AUXADC_NAG_7                     0x0796
+#define MT6392_AUXADC_NAG_8                     0x0798
+#define MT6392_AUXADC_TYPEC_H_1                 0x079A
+#define MT6392_AUXADC_TYPEC_H_2                 0x079C
+#define MT6392_AUXADC_TYPEC_H_3                 0x079E
+#define MT6392_AUXADC_TYPEC_H_4                 0x07A0
+#define MT6392_AUXADC_TYPEC_H_5                 0x07A2
+#define MT6392_AUXADC_TYPEC_H_6                 0x07A4
+#define MT6392_AUXADC_TYPEC_H_7                 0x07A6
+#define MT6392_AUXADC_TYPEC_L_1                 0x07A8
+#define MT6392_AUXADC_TYPEC_L_2                 0x07AA
+#define MT6392_AUXADC_TYPEC_L_3                 0x07AC
+#define MT6392_AUXADC_TYPEC_L_4                 0x07AE
+#define MT6392_AUXADC_TYPEC_L_5                 0x07B0
+#define MT6392_AUXADC_TYPEC_L_6                 0x07B2
+#define MT6392_AUXADC_TYPEC_L_7                 0x07B4
+#define MT6392_AUXADC_NAG_9                     0x07B6
+#define MT6392_TYPE_C_PHY_RG_0                  0x0800
+#define MT6392_TYPE_C_PHY_RG_CC_RESERVE_CSR     0x0802
+#define MT6392_TYPE_C_VCMP_CTRL                 0x0804
+#define MT6392_TYPE_C_CTRL                      0x0806
+#define MT6392_TYPE_C_CC_SW_CTRL                0x080a
+#define MT6392_TYPE_C_CC_VOL_PERIODIC_MEAS_VAL  0x080c
+#define MT6392_TYPE_C_CC_VOL_DEBOUNCE_CNT_VAL   0x080e
+#define MT6392_TYPE_C_DRP_SRC_CNT_VAL_0         0x0810
+#define MT6392_TYPE_C_DRP_SNK_CNT_VAL_0         0x0814
+#define MT6392_TYPE_C_DRP_TRY_CNT_VAL_0         0x0818
+#define MT6392_TYPE_C_CC_SRC_DEFAULT_DAC_VAL    0x0820
+#define MT6392_TYPE_C_CC_SRC_15_DAC_VAL         0x0822
+#define MT6392_TYPE_C_CC_SRC_30_DAC_VAL         0x0824
+#define MT6392_TYPE_C_CC_SNK_DAC_VAL_0          0x0828
+#define MT6392_TYPE_C_CC_SNK_DAC_VAL_1          0x082a
+#define MT6392_TYPE_C_INTR_EN_0                 0x0830
+#define MT6392_TYPE_C_INTR_EN_2                 0x0834
+#define MT6392_TYPE_C_INTR_0                    0x0838
+#define MT6392_TYPE_C_INTR_2                    0x083C
+#define MT6392_TYPE_C_CC_STATUS                 0x0840
+#define MT6392_TYPE_C_PWR_STATUS                0x0842
+#define MT6392_TYPE_C_PHY_RG_CC1_RESISTENCE_0   0x0844
+#define MT6392_TYPE_C_PHY_RG_CC1_RESISTENCE_1   0x0846
+#define MT6392_TYPE_C_PHY_RG_CC2_RESISTENCE_0   0x0848
+#define MT6392_TYPE_C_PHY_RG_CC2_RESISTENCE_1   0x084a
+#define MT6392_TYPE_C_CC_SW_FORCE_MODE_ENABLE_0 0x0860
+#define MT6392_TYPE_C_CC_SW_FORCE_MODE_VAL_0    0x0864
+#define MT6392_TYPE_C_CC_SW_FORCE_MODE_VAL_1    0x0866
+#define MT6392_TYPE_C_CC_SW_FORCE_MODE_ENABLE_1 0x0868
+#define MT6392_TYPE_C_CC_SW_FORCE_MODE_VAL_2    0x086c
+#define MT6392_TYPE_C_CC_DAC_CALI_CTRL          0x0870
+#define MT6392_TYPE_C_CC_DAC_CALI_RESULT        0x0872
+#define MT6392_TYPE_C_DEBUG_PORT_SELECT_0       0x0880
+#define MT6392_TYPE_C_DEBUG_PORT_SELECT_1       0x0882
+#define MT6392_TYPE_C_DEBUG_MODE_SELECT         0x0884
+#define MT6392_TYPE_C_DEBUG_OUT_READ_0          0x0888
+#define MT6392_TYPE_C_DEBUG_OUT_READ_1          0x088a
+#define MT6392_TYPE_C_SW_DEBUG_PORT_0           0x088c
+#define MT6392_TYPE_C_SW_DEBUG_PORT_1           0x088e
+
+#endif /* __MFD_MT6392_REGISTERS_H__ */
diff --git a/include/linux/mfd/mt6397/core.h b/include/linux/mfd/mt6397/core.h
index 340fc72e22aa..3729a6856c13 100644
--- a/include/linux/mfd/mt6397/core.h
+++ b/include/linux/mfd/mt6397/core.h
@@ -20,6 +20,7 @@ enum chip_id {
 	MT6359_CHIP_ID = 0x59,
 	MT6366_CHIP_ID = 0x66,
 	MT6391_CHIP_ID = 0x91,
+	MT6392_CHIP_ID = 0x92,
 	MT6397_CHIP_ID = 0x97,
 };
 
-- 
2.43.0


^ permalink raw reply related

* [PATCH v9 4/9] mfd: mt6397: Use MFD_CELL_* to describe sub-devices
From: Luca Leonardo Scorcia @ 2026-06-21  8:13 UTC (permalink / raw)
  To: linux-mediatek
  Cc: Luca Leonardo Scorcia, Dmitry Torokhov, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Sen Chu, Sean Wang,
	Macpaul Lin, Lee Jones, Matthias Brugger,
	AngeloGioacchino Del Regno, Liam Girdwood, Mark Brown,
	Linus Walleij, Val Packett, Julien Massot, Louis-Alexis Eyraud,
	Fabien Parent, Akari Tsuyukusa, Chen Zhong, linux-input,
	devicetree, linux-kernel, linux-pm, linux-arm-kernel, linux-gpio
In-Reply-To: <20260621081634.467858-1-l.scorcia@gmail.com>

Use the MFD_CELL_* macros to describe sub-devices. No functional changes.

Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
---
 drivers/mfd/mt6397-core.c | 197 ++++++++++++--------------------------
 1 file changed, 63 insertions(+), 134 deletions(-)

diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c
index 1bdacda9a933..ccd97d66d7f1 100644
--- a/drivers/mfd/mt6397-core.c
+++ b/drivers/mfd/mt6397-core.c
@@ -124,159 +124,88 @@ static const struct resource mt6323_pwrc_resources[] = {
 };
 
 static const struct mfd_cell mt6323_devs[] = {
-	{
-		.name = "mt6323-rtc",
-		.num_resources = ARRAY_SIZE(mt6323_rtc_resources),
-		.resources = mt6323_rtc_resources,
-		.of_compatible = "mediatek,mt6323-rtc",
-	}, {
-		.name = "mt6323-regulator",
-		.of_compatible = "mediatek,mt6323-regulator"
-	}, {
-		.name = "mt6323-led",
-		.of_compatible = "mediatek,mt6323-led"
-	}, {
-		.name = "mt6323-keys",
-		.num_resources = ARRAY_SIZE(mt6323_keys_resources),
-		.resources = mt6323_keys_resources,
-		.of_compatible = "mediatek,mt6323-keys"
-	}, {
-		.name = "mt6323-pwrc",
-		.num_resources = ARRAY_SIZE(mt6323_pwrc_resources),
-		.resources = mt6323_pwrc_resources,
-		.of_compatible = "mediatek,mt6323-pwrc"
-	},
+	MFD_CELL_OF("mt6323-rtc", mt6323_rtc_resources, NULL, 0, 0,
+		    "mediatek,mt6323-rtc"),
+	MFD_CELL_OF("mt6323-regulator", NULL, NULL, 0, 0,
+		    "mediatek,mt6323-regulator"),
+	MFD_CELL_OF("mt6323-led", NULL, NULL, 0, 0,
+		    "mediatek,mt6323-led"),
+	MFD_CELL_OF("mt6323-keys", mt6323_keys_resources, NULL, 0, 0,
+		    "mediatek,mt6323-keys"),
+	MFD_CELL_OF("mt6323-pwrc", mt6323_pwrc_resources, NULL, 0, 0,
+		    "mediatek,mt6323-pwrc"),
 };
 
 static const struct mfd_cell mt6328_devs[] = {
-	{
-		.name = "mt6328-regulator",
-		.of_compatible = "mediatek,mt6328-regulator"
-	}, {
-		.name = "mt6328-keys",
-		.num_resources = ARRAY_SIZE(mt6328_keys_resources),
-		.resources = mt6328_keys_resources,
-		.of_compatible = "mediatek,mt6328-keys"
-	},
+	MFD_CELL_OF("mt6328-regulator", NULL, NULL, 0, 0,
+		    "mediatek,mt6328-regulator"),
+	MFD_CELL_OF("mt6328-keys", mt6328_keys_resources, NULL, 0, 0,
+		    "mediatek,mt6328-keys"),
 };
 
 static const struct mfd_cell mt6357_devs[] = {
-	{
-		.name = "mt6359-auxadc",
-		.of_compatible = "mediatek,mt6357-auxadc"
-	}, {
-		.name = "mt6357-regulator",
-	}, {
-		.name = "mt6357-rtc",
-		.num_resources = ARRAY_SIZE(mt6357_rtc_resources),
-		.resources = mt6357_rtc_resources,
-		.of_compatible = "mediatek,mt6357-rtc",
-	}, {
-		.name = "mt6357-sound",
-		.of_compatible = "mediatek,mt6357-sound"
-	}, {
-		.name = "mt6357-keys",
-		.num_resources = ARRAY_SIZE(mt6357_keys_resources),
-		.resources = mt6357_keys_resources,
-		.of_compatible = "mediatek,mt6357-keys"
-	},
+	MFD_CELL_OF("mt6359-auxadc", NULL, NULL, 0, 0,
+		    "mediatek,mt6357-auxadc"),
+	MFD_CELL_NAME("mt6357-regulator"),
+	MFD_CELL_OF("mt6357-rtc", mt6357_rtc_resources, NULL, 0, 0,
+		    "mediatek,mt6357-rtc"),
+	MFD_CELL_OF("mt6357-sound", NULL, NULL, 0, 0,
+		    "mediatek,mt6357-sound"),
+	MFD_CELL_OF("mt6357-keys", mt6357_keys_resources, NULL, 0, 0,
+		    "mediatek,mt6357-keys"),
 };
 
 /* MT6331 is always used in combination with MT6332 */
 static const struct mfd_cell mt6331_mt6332_devs[] = {
-	{
-		.name = "mt6331-rtc",
-		.num_resources = ARRAY_SIZE(mt6331_rtc_resources),
-		.resources = mt6331_rtc_resources,
-		.of_compatible = "mediatek,mt6331-rtc",
-	}, {
-		.name = "mt6331-regulator",
-		.of_compatible = "mediatek,mt6331-regulator"
-	}, {
-		.name = "mt6332-regulator",
-		.of_compatible = "mediatek,mt6332-regulator"
-	}, {
-		.name = "mt6331-keys",
-		.num_resources = ARRAY_SIZE(mt6331_keys_resources),
-		.resources = mt6331_keys_resources,
-		.of_compatible = "mediatek,mt6331-keys"
-	},
+	MFD_CELL_OF("mt6331-rtc", mt6331_rtc_resources, NULL, 0, 0,
+		    "mediatek,mt6331-rtc"),
+	MFD_CELL_OF("mt6331-regulator", NULL, NULL, 0, 0,
+		    "mediatek,mt6331-regulator"),
+	MFD_CELL_OF("mt6332-regulator", NULL, NULL, 0, 0,
+		    "mediatek,mt6332-regulator"),
+	MFD_CELL_OF("mt6331-keys", mt6331_keys_resources, NULL, 0, 0,
+		    "mediatek,mt6331-keys"),
 };
 
 static const struct mfd_cell mt6358_devs[] = {
-	{
-		.name = "mt6359-auxadc",
-		.of_compatible = "mediatek,mt6358-auxadc"
-	}, {
-		.name = "mt6358-regulator",
-		.of_compatible = "mediatek,mt6358-regulator"
-	}, {
-		.name = "mt6358-rtc",
-		.num_resources = ARRAY_SIZE(mt6358_rtc_resources),
-		.resources = mt6358_rtc_resources,
-		.of_compatible = "mediatek,mt6358-rtc",
-	}, {
-		.name = "mt6358-sound",
-		.of_compatible = "mediatek,mt6358-sound"
-	}, {
-		.name = "mt6358-keys",
-		.num_resources = ARRAY_SIZE(mt6358_keys_resources),
-		.resources = mt6358_keys_resources,
-		.of_compatible = "mediatek,mt6358-keys"
-	},
+	MFD_CELL_OF("mt6359-auxadc", NULL, NULL, 0, 0,
+		    "mediatek,mt6358-auxadc"),
+	MFD_CELL_OF("mt6358-regulator", NULL, NULL, 0, 0,
+		    "mediatek,mt6358-regulator"),
+	MFD_CELL_OF("mt6358-rtc", mt6358_rtc_resources, NULL, 0, 0,
+		    "mediatek,mt6358-rtc"),
+	MFD_CELL_OF("mt6358-sound", NULL, NULL, 0, 0,
+		    "mediatek,mt6358-sound"),
+	MFD_CELL_OF("mt6358-keys", mt6358_keys_resources, NULL, 0, 0,
+		    "mediatek,mt6358-keys"),
 };
 
 static const struct mfd_cell mt6359_devs[] = {
-	{
-		.name = "mt6359-auxadc",
-		.of_compatible = "mediatek,mt6359-auxadc"
-	},
-	{ .name = "mt6359-regulator", },
-	{
-		.name = "mt6359-rtc",
-		.num_resources = ARRAY_SIZE(mt6358_rtc_resources),
-		.resources = mt6358_rtc_resources,
-		.of_compatible = "mediatek,mt6358-rtc",
-	},
-	{ .name = "mt6359-sound", },
-	{
-		.name = "mt6359-keys",
-		.num_resources = ARRAY_SIZE(mt6359_keys_resources),
-		.resources = mt6359_keys_resources,
-		.of_compatible = "mediatek,mt6359-keys"
-	},
-	{
-		.name = "mt6359-accdet",
-		.of_compatible = "mediatek,mt6359-accdet",
-		.num_resources = ARRAY_SIZE(mt6359_accdet_resources),
-		.resources = mt6359_accdet_resources,
-	},
+	MFD_CELL_OF("mt6359-auxadc", NULL, NULL, 0, 0,
+		    "mediatek,mt6359-auxadc"),
+	MFD_CELL_NAME("mt6359-regulator"),
+	MFD_CELL_OF("mt6359-rtc", mt6358_rtc_resources, NULL, 0, 0,
+		    "mediatek,mt6358-rtc"),
+	MFD_CELL_NAME("mt6359-sound"),
+	MFD_CELL_OF("mt6359-keys", mt6359_keys_resources, NULL, 0, 0,
+		    "mediatek,mt6359-keys"),
+	MFD_CELL_OF("mt6359-accdet", mt6359_accdet_resources, NULL, 0, 0,
+		    "mediatek,mt6359-accdet"),
 };
 
 static const struct mfd_cell mt6397_devs[] = {
-	{
-		.name = "mt6397-rtc",
-		.num_resources = ARRAY_SIZE(mt6397_rtc_resources),
-		.resources = mt6397_rtc_resources,
-		.of_compatible = "mediatek,mt6397-rtc",
-	}, {
-		.name = "mt6397-regulator",
-		.of_compatible = "mediatek,mt6397-regulator",
-	}, {
-		.name = "mt6397-codec",
-		.of_compatible = "mediatek,mt6397-codec",
-	}, {
-		.name = "mt6397-clk",
-		.of_compatible = "mediatek,mt6397-clk",
-	}, {
-		.name = "mt6397-pinctrl",
-		.of_compatible = "mediatek,mt6397-pinctrl",
-	}, {
-		.name = "mt6397-keys",
-		.num_resources = ARRAY_SIZE(mt6397_keys_resources),
-		.resources = mt6397_keys_resources,
-		.of_compatible = "mediatek,mt6397-keys"
-	}
+	MFD_CELL_OF("mt6397-rtc", mt6397_rtc_resources, NULL, 0, 0,
+		    "mediatek,mt6397-rtc"),
+	MFD_CELL_OF("mt6397-regulator", NULL, NULL, 0, 0,
+		    "mediatek,mt6397-regulator"),
+	MFD_CELL_OF("mt6397-codec", NULL, NULL, 0, 0,
+		    "mediatek,mt6397-codec"),
+	MFD_CELL_OF("mt6397-clk", NULL, NULL, 0, 0,
+		    "mediatek,mt6397-clk"),
+	MFD_CELL_OF("mt6397-pinctrl", NULL, NULL, 0, 0,
+		    "mediatek,mt6397-pinctrl"),
+	MFD_CELL_OF("mt6397-keys", mt6397_keys_resources, NULL, 0, 0,
+		    "mediatek,mt6397-keys"),
 };
 
 struct chip_data {
-- 
2.43.0


^ permalink raw reply related

* [PATCH v9 3/9] regulator: dt-bindings: Add MediaTek MT6392 PMIC
From: Luca Leonardo Scorcia @ 2026-06-21  8:13 UTC (permalink / raw)
  To: linux-mediatek
  Cc: Luca Leonardo Scorcia, Dmitry Torokhov, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Sen Chu, Sean Wang,
	Macpaul Lin, Lee Jones, Matthias Brugger,
	AngeloGioacchino Del Regno, Liam Girdwood, Mark Brown,
	Linus Walleij, Julien Massot, Louis-Alexis Eyraud, Val Packett,
	Fabien Parent, Akari Tsuyukusa, Chen Zhong, linux-input,
	devicetree, linux-kernel, linux-pm, linux-arm-kernel, linux-gpio
In-Reply-To: <20260621081634.467858-1-l.scorcia@gmail.com>

Add bindings for the regulators found in the MediaTek MT6392 PMIC,
usually found in board designs using the MediaTek MT8516/MT8167 SoCs.

Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
---
 .../regulator/mediatek,mt6392-regulator.yaml  | 112 ++++++++++++++++++
 .../regulator/mediatek,mt6392-regulator.h     |  23 ++++
 2 files changed, 135 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/regulator/mediatek,mt6392-regulator.yaml
 create mode 100644 include/dt-bindings/regulator/mediatek,mt6392-regulator.h

diff --git a/Documentation/devicetree/bindings/regulator/mediatek,mt6392-regulator.yaml b/Documentation/devicetree/bindings/regulator/mediatek,mt6392-regulator.yaml
new file mode 100644
index 000000000000..d74721d8f2ff
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/mediatek,mt6392-regulator.yaml
@@ -0,0 +1,112 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/mediatek,mt6392-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT6392 regulator
+
+maintainers:
+  - Luca Leonardo Scorcia <l.scorcia@gmail.com>
+
+description:
+  MT6392 is a power management system chip containing three buck converters and
+  23 LDOs. All voltage regulators provided by the PMIC are described as
+  sub-nodes of this node.
+
+properties:
+  compatible:
+    items:
+      - const: mediatek,mt6392-regulator
+
+  vproc-supply:
+    description: Supply for buck regulator vproc
+  vcore-supply:
+    description: Supply for buck regulator vcore
+  vsys-supply:
+    description: Supply for buck regulator vsys
+  avddldo-supply:
+    description:
+      Supply for AVDD LDOs (vm, vio18, vcn18, vcamd, vcamio). According to the data sheet
+      this is an internal supply derived from vsys.
+  ldo1-supply:
+    description: Supply for LDOs group 1 (vaud28, vxo22, vaud22, vadc18, vcama, vrtc)
+  ldo2-supply:
+    description: Supply for LDOs group 2 (vcn35, vio28, vmc, vmch, vefuse, vdig18)
+  ldo3-supply:
+    description: Supply for LDOs group 3 (vusb, vemc3v3, vcamaf, vgp1, vgp2, vm25)
+
+patternProperties:
+  "^v(core|proc|sys)$":
+    description: Buck regulators
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+    properties:
+      regulator-allowed-modes:
+        description:
+          BUCK regulators can set regulator-allowed-modes to values specified in
+          dt-bindings/regulator/mediatek,mt6392-regulator.h
+        items:
+          enum: [0, 1]
+        minItems: 1
+        maxItems: 2
+      regulator-initial-mode:
+        description:
+          BUCK regulators can set regulator-initial-mode to values specified in
+          dt-bindings/regulator/mediatek,mt6392-regulator.h
+        enum: [0, 1]
+
+  "^v(adc18|camio|cn18|io18|xo22|m25|aud28|io28|usb)$":
+    description: LDOs with fixed output and mode setting
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+    properties:
+      regulator-allowed-modes:
+        description:
+          LDO regulators can set regulator-allowed-modes to values specified in
+          dt-bindings/regulator/mediatek,mt6392-regulator.h
+        items:
+          enum: [0, 2]
+        minItems: 1
+        maxItems: 2
+      regulator-initial-mode:
+        description:
+          LDO regulators can set regulator-initial-mode to values specified in
+          dt-bindings/regulator/mediatek,mt6392-regulator.h
+        enum: [0, 2]
+
+  "^v(cama|dig18|rtc)$":
+    description: LDOs with fixed output without mode setting
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+    properties:
+      regulator-allowed-modes: false
+      regulator-initial-mode: false
+
+  "^v(aud22|camaf|camd|cn35|efuse|emc3v3|gp1|gp2|m|mc|mch)$":
+    description: LDOs with adjustable output and mode setting
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+    properties:
+      regulator-allowed-modes:
+        description:
+          LDO regulators can set regulator-allowed-modes to values specified in
+          dt-bindings/regulator/mediatek,mt6392-regulator.h
+        items:
+          enum: [0, 2]
+        minItems: 1
+        maxItems: 2
+      regulator-initial-mode:
+        description:
+          LDO regulators can set regulator-initial-mode to values specified in
+          dt-bindings/regulator/mediatek,mt6392-regulator.h
+        enum: [0, 2]
+
+required:
+  - compatible
+
+additionalProperties: false
diff --git a/include/dt-bindings/regulator/mediatek,mt6392-regulator.h b/include/dt-bindings/regulator/mediatek,mt6392-regulator.h
new file mode 100644
index 000000000000..2e1f41e0ebfe
--- /dev/null
+++ b/include/dt-bindings/regulator/mediatek,mt6392-regulator.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+
+#ifndef _DT_BINDINGS_REGULATOR_MEDIATEK_MT6392_H_
+#define _DT_BINDINGS_REGULATOR_MEDIATEK_MT6392_H_
+
+/*
+ * Buck mode constants which may be used in devicetree properties (eg.
+ * regulator-initial-mode, regulator-allowed-modes).
+ * See the manufacturer's datasheet for more information on these modes.
+ */
+
+#define MT6392_REGULATOR_MODE_NORMAL	0
+#define MT6392_BUCK_MODE_FORCE_PWM	1
+
+/*
+ * LDO mode constants which may be used in devicetree properties (eg.
+ * regulator-initial-mode, regulator-allowed-modes).
+ * See the manufacturer's datasheet for more information on these modes.
+ */
+
+#define MT6392_LDO_MODE_LP		2
+
+#endif
-- 
2.43.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox