[PATCH v2 0/7] syscore: Pass context data to callbacks

Thierry Reding posted 7 patches 2 months, 3 weeks ago
arch/arm/mach-exynos/mcpm-exynos.c        |  4 +-
arch/arm/mach-exynos/suspend.c            | 14 +++---
arch/arm/mach-pxa/irq.c                   |  4 +-
arch/arm/mach-pxa/mfp-pxa2xx.c            |  4 +-
arch/arm/mach-pxa/mfp-pxa3xx.c            |  4 +-
arch/arm/mach-pxa/smemc.c                 |  4 +-
arch/arm/mach-s3c/irq-pm-s3c64xx.c        |  4 +-
arch/arm/mach-s5pv210/pm.c                |  2 +-
arch/arm/mach-versatile/integrator_ap.c   |  4 +-
arch/arm/mm/cache-b15-rac.c               |  4 +-
arch/loongarch/kernel/smp.c               |  4 +-
arch/mips/alchemy/common/dbdma.c          |  4 +-
arch/mips/alchemy/common/irq.c            |  8 ++--
arch/mips/alchemy/common/usb.c            |  4 +-
arch/mips/pci/pci-alchemy.c               | 28 ++++++------
arch/powerpc/platforms/cell/spu_base.c    |  2 +-
arch/powerpc/platforms/powermac/pic.c     |  4 +-
arch/powerpc/sysdev/fsl_lbc.c             |  4 +-
arch/powerpc/sysdev/fsl_pci.c             |  4 +-
arch/powerpc/sysdev/ipic.c                |  4 +-
arch/powerpc/sysdev/mpic.c                |  4 +-
arch/powerpc/sysdev/mpic_timer.c          |  2 +-
arch/sh/mm/pmb.c                          |  2 +-
arch/x86/events/amd/ibs.c                 |  4 +-
arch/x86/hyperv/hv_init.c                 |  4 +-
arch/x86/kernel/amd_gart_64.c             |  2 +-
arch/x86/kernel/apic/apic.c               |  4 +-
arch/x86/kernel/apic/io_apic.c            |  9 +++-
arch/x86/kernel/cpu/aperfmperf.c          |  6 +--
arch/x86/kernel/cpu/intel_epb.c           |  8 ++--
arch/x86/kernel/cpu/mce/core.c            |  6 +--
arch/x86/kernel/cpu/microcode/core.c      |  7 ++-
arch/x86/kernel/cpu/mtrr/legacy.c         |  4 +-
arch/x86/kernel/cpu/umwait.c              |  2 +-
arch/x86/kernel/i8237.c                   |  2 +-
arch/x86/kernel/i8259.c                   |  6 +--
arch/x86/kernel/kvm.c                     |  4 +-
drivers/acpi/pci_link.c                   |  2 +-
drivers/acpi/sleep.c                      |  4 +-
drivers/base/firmware_loader/main.c       |  2 +-
drivers/base/syscore.c                    |  8 ++--
drivers/bus/mvebu-mbus.c                  | 24 +++++-----
drivers/clk/at91/pmc.c                    |  4 +-
drivers/clk/imx/clk-vf610.c               |  4 +-
drivers/clk/ingenic/pm.c                  |  4 +-
drivers/clk/ingenic/tcu.c                 | 54 +++++++++++------------
drivers/clk/mvebu/common.c                | 25 +++++++----
drivers/clk/rockchip/clk-rk3288.c         |  4 +-
drivers/clk/samsung/clk-s5pv210-audss.c   |  4 +-
drivers/clk/samsung/clk.c                 |  4 +-
drivers/clk/tegra/clk-tegra210.c          |  4 +-
drivers/clocksource/timer-armada-370-xp.c |  4 +-
drivers/cpuidle/cpuidle-psci.c            |  4 +-
drivers/gpio/gpio-mxc.c                   |  4 +-
drivers/gpio/gpio-pxa.c                   |  4 +-
drivers/gpio/gpio-sa1100.c                |  4 +-
drivers/hv/vmbus_drv.c                    |  4 +-
drivers/iommu/amd/init.c                  |  4 +-
drivers/iommu/intel/iommu.c               |  4 +-
drivers/irqchip/exynos-combiner.c         |  6 ++-
drivers/irqchip/irq-armada-370-xp.c       |  4 +-
drivers/irqchip/irq-bcm7038-l1.c          |  4 +-
drivers/irqchip/irq-gic-v3-its.c          |  4 +-
drivers/irqchip/irq-i8259.c               |  4 +-
drivers/irqchip/irq-imx-gpcv2.c           | 33 ++++++--------
drivers/irqchip/irq-loongson-eiointc.c    |  4 +-
drivers/irqchip/irq-loongson-htpic.c      |  2 +-
drivers/irqchip/irq-loongson-htvec.c      |  4 +-
drivers/irqchip/irq-loongson-pch-lpc.c    |  4 +-
drivers/irqchip/irq-loongson-pch-pic.c    |  4 +-
drivers/irqchip/irq-mchp-eic.c            |  4 +-
drivers/irqchip/irq-mst-intc.c            |  4 +-
drivers/irqchip/irq-mtk-cirq.c            |  4 +-
drivers/irqchip/irq-renesas-rzg2l.c       |  4 +-
drivers/irqchip/irq-sa11x0.c              |  4 +-
drivers/irqchip/irq-sifive-plic.c         |  4 +-
drivers/irqchip/irq-sun6i-r.c             | 10 ++---
drivers/irqchip/irq-tegra.c               |  4 +-
drivers/irqchip/irq-vic.c                 |  4 +-
drivers/leds/trigger/ledtrig-cpu.c        |  6 +--
drivers/macintosh/via-pmu.c               |  4 +-
drivers/power/reset/sc27xx-poweroff.c     |  2 +-
drivers/sh/clk/core.c                     |  2 +-
drivers/sh/intc/core.c                    |  4 +-
drivers/soc/bcm/brcmstb/biuctrl.c         |  4 +-
drivers/soc/tegra/pmc.c                   |  7 ++-
drivers/thermal/intel/intel_hfi.c         |  4 +-
drivers/xen/xen-acpi-processor.c          |  2 +-
include/linux/syscore_ops.h               |  6 +--
kernel/cpu_pm.c                           |  4 +-
kernel/irq/generic-chip.c                 |  6 +--
kernel/irq/pm.c                           |  3 +-
kernel/printk/printk.c                    |  3 +-
kernel/time/sched_clock.c                 | 14 +++++-
kernel/time/timekeeping.c                 | 14 +++++-
virt/kvm/kvm_main.c                       |  6 +--
96 files changed, 306 insertions(+), 269 deletions(-)
[PATCH v2 0/7] syscore: Pass context data to callbacks
Posted by Thierry Reding 2 months, 3 weeks ago
From: Thierry Reding <treding@nvidia.com>

Hi,

Something that's been bugging me over the years is how some drivers have
had to adopt file-scoped variables to pass data into something like the
syscore operations. This is often harmless, but usually leads to drivers
not being able to deal with multiple instances, or additional frameworks
or data structures needing to be created to handle multiple instances.

This series proposes to "objectify" struct syscore_ops by passing a
pointer to struct syscore_ops to the syscore callbacks. Implementations
of these callbacks can then make use of container_of() to get access to
contextual data that struct syscore_ops was embedded in. This elegantly
avoids the need for file-scoped, singleton variables, by tying syscore
to individual instances.

Patch 1 contains the bulk of these changes. It's fairly intrusive
because it does the conversion of the function signature all in one
patch. An alternative would've been to introduce new callbacks such that
these changes could be staged in. However, the amount of changes here
are not quite numerous enough to justify that, in my opinion, and
syscore isn't very frequently used, so the risk of another user getting
added while this is merged is rather small. All in all I think merging
this in one go is the simplest way.

Patches 2-7 are conversions of some existing drivers to take advantage
of this new parameter and tie the code to per-instance data.

Given that the recipient list for this is huge, I'm limiting this to
Greg (because it's at the core a... core change) and a set of larger
lists for architectures and subsystems that are impacted.

Changes in v2:
- kerneldoc fixes

Thanks,
Thierry

Thierry Reding (7):
  syscore: Pass context data to callbacks
  MIPS: Embed syscore_ops in PCI context
  bus: mvebu-mbus: Embed syscore_ops in mbus context
  clk: ingenic: tcu: Embed syscore_ops in TCU context
  clk: mvebu: Embed syscore_ops in clock context
  irqchip/irq-imx-gpcv2: Embed syscore_ops in chip context
  soc/tegra: pmc: Derive PMC context from syscore ops

 arch/arm/mach-exynos/mcpm-exynos.c        |  4 +-
 arch/arm/mach-exynos/suspend.c            | 14 +++---
 arch/arm/mach-pxa/irq.c                   |  4 +-
 arch/arm/mach-pxa/mfp-pxa2xx.c            |  4 +-
 arch/arm/mach-pxa/mfp-pxa3xx.c            |  4 +-
 arch/arm/mach-pxa/smemc.c                 |  4 +-
 arch/arm/mach-s3c/irq-pm-s3c64xx.c        |  4 +-
 arch/arm/mach-s5pv210/pm.c                |  2 +-
 arch/arm/mach-versatile/integrator_ap.c   |  4 +-
 arch/arm/mm/cache-b15-rac.c               |  4 +-
 arch/loongarch/kernel/smp.c               |  4 +-
 arch/mips/alchemy/common/dbdma.c          |  4 +-
 arch/mips/alchemy/common/irq.c            |  8 ++--
 arch/mips/alchemy/common/usb.c            |  4 +-
 arch/mips/pci/pci-alchemy.c               | 28 ++++++------
 arch/powerpc/platforms/cell/spu_base.c    |  2 +-
 arch/powerpc/platforms/powermac/pic.c     |  4 +-
 arch/powerpc/sysdev/fsl_lbc.c             |  4 +-
 arch/powerpc/sysdev/fsl_pci.c             |  4 +-
 arch/powerpc/sysdev/ipic.c                |  4 +-
 arch/powerpc/sysdev/mpic.c                |  4 +-
 arch/powerpc/sysdev/mpic_timer.c          |  2 +-
 arch/sh/mm/pmb.c                          |  2 +-
 arch/x86/events/amd/ibs.c                 |  4 +-
 arch/x86/hyperv/hv_init.c                 |  4 +-
 arch/x86/kernel/amd_gart_64.c             |  2 +-
 arch/x86/kernel/apic/apic.c               |  4 +-
 arch/x86/kernel/apic/io_apic.c            |  9 +++-
 arch/x86/kernel/cpu/aperfmperf.c          |  6 +--
 arch/x86/kernel/cpu/intel_epb.c           |  8 ++--
 arch/x86/kernel/cpu/mce/core.c            |  6 +--
 arch/x86/kernel/cpu/microcode/core.c      |  7 ++-
 arch/x86/kernel/cpu/mtrr/legacy.c         |  4 +-
 arch/x86/kernel/cpu/umwait.c              |  2 +-
 arch/x86/kernel/i8237.c                   |  2 +-
 arch/x86/kernel/i8259.c                   |  6 +--
 arch/x86/kernel/kvm.c                     |  4 +-
 drivers/acpi/pci_link.c                   |  2 +-
 drivers/acpi/sleep.c                      |  4 +-
 drivers/base/firmware_loader/main.c       |  2 +-
 drivers/base/syscore.c                    |  8 ++--
 drivers/bus/mvebu-mbus.c                  | 24 +++++-----
 drivers/clk/at91/pmc.c                    |  4 +-
 drivers/clk/imx/clk-vf610.c               |  4 +-
 drivers/clk/ingenic/pm.c                  |  4 +-
 drivers/clk/ingenic/tcu.c                 | 54 +++++++++++------------
 drivers/clk/mvebu/common.c                | 25 +++++++----
 drivers/clk/rockchip/clk-rk3288.c         |  4 +-
 drivers/clk/samsung/clk-s5pv210-audss.c   |  4 +-
 drivers/clk/samsung/clk.c                 |  4 +-
 drivers/clk/tegra/clk-tegra210.c          |  4 +-
 drivers/clocksource/timer-armada-370-xp.c |  4 +-
 drivers/cpuidle/cpuidle-psci.c            |  4 +-
 drivers/gpio/gpio-mxc.c                   |  4 +-
 drivers/gpio/gpio-pxa.c                   |  4 +-
 drivers/gpio/gpio-sa1100.c                |  4 +-
 drivers/hv/vmbus_drv.c                    |  4 +-
 drivers/iommu/amd/init.c                  |  4 +-
 drivers/iommu/intel/iommu.c               |  4 +-
 drivers/irqchip/exynos-combiner.c         |  6 ++-
 drivers/irqchip/irq-armada-370-xp.c       |  4 +-
 drivers/irqchip/irq-bcm7038-l1.c          |  4 +-
 drivers/irqchip/irq-gic-v3-its.c          |  4 +-
 drivers/irqchip/irq-i8259.c               |  4 +-
 drivers/irqchip/irq-imx-gpcv2.c           | 33 ++++++--------
 drivers/irqchip/irq-loongson-eiointc.c    |  4 +-
 drivers/irqchip/irq-loongson-htpic.c      |  2 +-
 drivers/irqchip/irq-loongson-htvec.c      |  4 +-
 drivers/irqchip/irq-loongson-pch-lpc.c    |  4 +-
 drivers/irqchip/irq-loongson-pch-pic.c    |  4 +-
 drivers/irqchip/irq-mchp-eic.c            |  4 +-
 drivers/irqchip/irq-mst-intc.c            |  4 +-
 drivers/irqchip/irq-mtk-cirq.c            |  4 +-
 drivers/irqchip/irq-renesas-rzg2l.c       |  4 +-
 drivers/irqchip/irq-sa11x0.c              |  4 +-
 drivers/irqchip/irq-sifive-plic.c         |  4 +-
 drivers/irqchip/irq-sun6i-r.c             | 10 ++---
 drivers/irqchip/irq-tegra.c               |  4 +-
 drivers/irqchip/irq-vic.c                 |  4 +-
 drivers/leds/trigger/ledtrig-cpu.c        |  6 +--
 drivers/macintosh/via-pmu.c               |  4 +-
 drivers/power/reset/sc27xx-poweroff.c     |  2 +-
 drivers/sh/clk/core.c                     |  2 +-
 drivers/sh/intc/core.c                    |  4 +-
 drivers/soc/bcm/brcmstb/biuctrl.c         |  4 +-
 drivers/soc/tegra/pmc.c                   |  7 ++-
 drivers/thermal/intel/intel_hfi.c         |  4 +-
 drivers/xen/xen-acpi-processor.c          |  2 +-
 include/linux/syscore_ops.h               |  6 +--
 kernel/cpu_pm.c                           |  4 +-
 kernel/irq/generic-chip.c                 |  6 +--
 kernel/irq/pm.c                           |  3 +-
 kernel/printk/printk.c                    |  3 +-
 kernel/time/sched_clock.c                 | 14 +++++-
 kernel/time/timekeeping.c                 | 14 +++++-
 virt/kvm/kvm_main.c                       |  6 +--
 96 files changed, 306 insertions(+), 269 deletions(-)

-- 
2.50.0
Re: [PATCH v2 0/7] syscore: Pass context data to callbacks
Posted by Greg Kroah-Hartman 2 months, 3 weeks ago
On Thu, Jul 17, 2025 at 12:32:34PM +0200, Thierry Reding wrote:
> From: Thierry Reding <treding@nvidia.com>
> 
> Hi,
> 
> Something that's been bugging me over the years is how some drivers have
> had to adopt file-scoped variables to pass data into something like the
> syscore operations. This is often harmless, but usually leads to drivers
> not being able to deal with multiple instances, or additional frameworks
> or data structures needing to be created to handle multiple instances.
> 
> This series proposes to "objectify" struct syscore_ops by passing a
> pointer to struct syscore_ops to the syscore callbacks. Implementations
> of these callbacks can then make use of container_of() to get access to
> contextual data that struct syscore_ops was embedded in. This elegantly
> avoids the need for file-scoped, singleton variables, by tying syscore
> to individual instances.
> 
> Patch 1 contains the bulk of these changes. It's fairly intrusive
> because it does the conversion of the function signature all in one
> patch. An alternative would've been to introduce new callbacks such that
> these changes could be staged in. However, the amount of changes here
> are not quite numerous enough to justify that, in my opinion, and
> syscore isn't very frequently used, so the risk of another user getting
> added while this is merged is rather small. All in all I think merging
> this in one go is the simplest way.

All at once is good, I like the idea, but:

> Patches 2-7 are conversions of some existing drivers to take advantage
> of this new parameter and tie the code to per-instance data.

That's great, but none of these conversions actually get rid of the
global structure, so what actually was helped here other than the churn
of this "potentially" allowing the global data variables from being
removed in the future?

So how does this actually help?

Also, small nit, make the function pointers const please :)

thanks,

greg k-h
Re: [PATCH v2 0/7] syscore: Pass context data to callbacks
Posted by Thierry Reding 2 months, 2 weeks ago
On Thu, Jul 17, 2025 at 02:11:41PM +0200, Greg Kroah-Hartman wrote:
> On Thu, Jul 17, 2025 at 12:32:34PM +0200, Thierry Reding wrote:
> > From: Thierry Reding <treding@nvidia.com>
> > 
> > Hi,
> > 
> > Something that's been bugging me over the years is how some drivers have
> > had to adopt file-scoped variables to pass data into something like the
> > syscore operations. This is often harmless, but usually leads to drivers
> > not being able to deal with multiple instances, or additional frameworks
> > or data structures needing to be created to handle multiple instances.
> > 
> > This series proposes to "objectify" struct syscore_ops by passing a
> > pointer to struct syscore_ops to the syscore callbacks. Implementations
> > of these callbacks can then make use of container_of() to get access to
> > contextual data that struct syscore_ops was embedded in. This elegantly
> > avoids the need for file-scoped, singleton variables, by tying syscore
> > to individual instances.
> > 
> > Patch 1 contains the bulk of these changes. It's fairly intrusive
> > because it does the conversion of the function signature all in one
> > patch. An alternative would've been to introduce new callbacks such that
> > these changes could be staged in. However, the amount of changes here
> > are not quite numerous enough to justify that, in my opinion, and
> > syscore isn't very frequently used, so the risk of another user getting
> > added while this is merged is rather small. All in all I think merging
> > this in one go is the simplest way.
> 
> All at once is good, I like the idea, but:
> 
> > Patches 2-7 are conversions of some existing drivers to take advantage
> > of this new parameter and tie the code to per-instance data.
> 
> That's great, but none of these conversions actually get rid of the
> global structure, so what actually was helped here other than the churn
> of this "potentially" allowing the global data variables from being
> removed in the future?
> 
> So how does this actually help?

Thanks for pointing this out and letting me look at it again. Most of
these actually do get rid of the global data variables. The MIPS patch
doesn't because I forgot, but the __alchemy_pci_ctx is no longer used
after the patch (except where it's initialized to the ctx variable, but
that's no longer needed now). I've updated that patch.

The Ingenic TCU patch gets rid of it, and so do the clk/mvebu and
irq-imx-gpcv2 patches. The two exceptions where it wasn't possible to
get rid of the global data variables are mvebu-mbus and Tegra PMC, in
both cases because there is other functionality that relies on the
global variable. The bits that make it very difficult to remove these
entirely is that they export functions that are called without context
from other parts of code.

I have a fairly large series on top of this that converts the Tegra PMC
driver to move away from this as much as possible. It's not possible to
do on 32-bit ARM because there is some low-level CPU code that needs to
call into this function. However, the goal is to at least make the PMC
driver data completely instance-specific on 64-bit ARM so that we can
support multiple instances eventually.

Maybe something similar could be done for mvebu-bus, but I'm not sure
it's worth it. Typically for these cases you need some form of context
in order to replace the global data. On Tegra we do have that in many
cases (via DT phandle references), but I'm not familiar enough with
mvebu to know if something similar exists.

My goal with this series is to get this a bit more established so that
people don't use the lack of context in syscore as an excuse for not
properly encapsulating things. These usually tend to go hand in hand,
where people end up using a global data variable for syscore and since
they can't get around that one, they keep using it for a bunch of other
shortcuts.

> Also, small nit, make the function pointers const please :)

I originally tried that. Unfortunately, the struct syscore_ops contains
a struct list_head to add it to the global list of structures. I suppose
I could move the function pointers into a different structure and make
pointers to that const, something like this:

	struct syscore;

	struct syscore_ops {
		int (*suspend)(struct syscore *syscore);
		void (*resume)(struct syscore *syscore);
		void (*shutdown)(struct syscore *syscore);
	};

	struct syscore {
		const struct syscore_ops *ops;
		struct list_head node;
	};

Is that what you had in mind?

Thanks,
Thierry
Re: [PATCH v2 0/7] syscore: Pass context data to callbacks
Posted by Greg Kroah-Hartman 2 months, 2 weeks ago
On Fri, Jul 18, 2025 at 03:49:37PM +0200, Thierry Reding wrote:
> On Thu, Jul 17, 2025 at 02:11:41PM +0200, Greg Kroah-Hartman wrote:
> > On Thu, Jul 17, 2025 at 12:32:34PM +0200, Thierry Reding wrote:
> > > From: Thierry Reding <treding@nvidia.com>
> > > 
> > > Hi,
> > > 
> > > Something that's been bugging me over the years is how some drivers have
> > > had to adopt file-scoped variables to pass data into something like the
> > > syscore operations. This is often harmless, but usually leads to drivers
> > > not being able to deal with multiple instances, or additional frameworks
> > > or data structures needing to be created to handle multiple instances.
> > > 
> > > This series proposes to "objectify" struct syscore_ops by passing a
> > > pointer to struct syscore_ops to the syscore callbacks. Implementations
> > > of these callbacks can then make use of container_of() to get access to
> > > contextual data that struct syscore_ops was embedded in. This elegantly
> > > avoids the need for file-scoped, singleton variables, by tying syscore
> > > to individual instances.
> > > 
> > > Patch 1 contains the bulk of these changes. It's fairly intrusive
> > > because it does the conversion of the function signature all in one
> > > patch. An alternative would've been to introduce new callbacks such that
> > > these changes could be staged in. However, the amount of changes here
> > > are not quite numerous enough to justify that, in my opinion, and
> > > syscore isn't very frequently used, so the risk of another user getting
> > > added while this is merged is rather small. All in all I think merging
> > > this in one go is the simplest way.
> > 
> > All at once is good, I like the idea, but:
> > 
> > > Patches 2-7 are conversions of some existing drivers to take advantage
> > > of this new parameter and tie the code to per-instance data.
> > 
> > That's great, but none of these conversions actually get rid of the
> > global structure, so what actually was helped here other than the churn
> > of this "potentially" allowing the global data variables from being
> > removed in the future?
> > 
> > So how does this actually help?
> 
> Thanks for pointing this out and letting me look at it again. Most of
> these actually do get rid of the global data variables. The MIPS patch
> doesn't because I forgot, but the __alchemy_pci_ctx is no longer used
> after the patch (except where it's initialized to the ctx variable, but
> that's no longer needed now). I've updated that patch.
> 
> The Ingenic TCU patch gets rid of it, and so do the clk/mvebu and
> irq-imx-gpcv2 patches. The two exceptions where it wasn't possible to
> get rid of the global data variables are mvebu-mbus and Tegra PMC, in
> both cases because there is other functionality that relies on the
> global variable. The bits that make it very difficult to remove these
> entirely is that they export functions that are called without context
> from other parts of code.

Ah, I must have looked at the wrong examples in the patch series, sorry.

> I have a fairly large series on top of this that converts the Tegra PMC
> driver to move away from this as much as possible. It's not possible to
> do on 32-bit ARM because there is some low-level CPU code that needs to
> call into this function. However, the goal is to at least make the PMC
> driver data completely instance-specific on 64-bit ARM so that we can
> support multiple instances eventually.
> 
> Maybe something similar could be done for mvebu-bus, but I'm not sure
> it's worth it. Typically for these cases you need some form of context
> in order to replace the global data. On Tegra we do have that in many
> cases (via DT phandle references), but I'm not familiar enough with
> mvebu to know if something similar exists.
> 
> My goal with this series is to get this a bit more established so that
> people don't use the lack of context in syscore as an excuse for not
> properly encapsulating things. These usually tend to go hand in hand,
> where people end up using a global data variable for syscore and since
> they can't get around that one, they keep using it for a bunch of other
> shortcuts.

I agree, I overall like this change, just expected to see more global
structures being able to be removed.

> > Also, small nit, make the function pointers const please :)
> 
> I originally tried that. Unfortunately, the struct syscore_ops contains
> a struct list_head to add it to the global list of structures. I suppose
> I could move the function pointers into a different structure and make
> pointers to that const, something like this:
> 
> 	struct syscore;
> 
> 	struct syscore_ops {
> 		int (*suspend)(struct syscore *syscore);
> 		void (*resume)(struct syscore *syscore);
> 		void (*shutdown)(struct syscore *syscore);
> 	};
> 
> 	struct syscore {
> 		const struct syscore_ops *ops;
> 		struct list_head node;
> 	};
> 
> Is that what you had in mind?

I missed the list_head, so yes, this would be better, but don't pass
back the syscore structure, how about just a void * instead, making the
whole container_of() stuff go away?

thanks,

greg k-h
Re: [PATCH v2 0/7] syscore: Pass context data to callbacks
Posted by Thierry Reding 2 months, 2 weeks ago
On Sat, Jul 19, 2025 at 08:52:41AM +0200, Greg Kroah-Hartman wrote:
> On Fri, Jul 18, 2025 at 03:49:37PM +0200, Thierry Reding wrote:
> > On Thu, Jul 17, 2025 at 02:11:41PM +0200, Greg Kroah-Hartman wrote:
> > > On Thu, Jul 17, 2025 at 12:32:34PM +0200, Thierry Reding wrote:
[...]
> > 	struct syscore;
> > 
> > 	struct syscore_ops {
> > 		int (*suspend)(struct syscore *syscore);
> > 		void (*resume)(struct syscore *syscore);
> > 		void (*shutdown)(struct syscore *syscore);
> > 	};
> > 
> > 	struct syscore {
> > 		const struct syscore_ops *ops;
> > 		struct list_head node;
> > 	};
> > 
> > Is that what you had in mind?
> 
> I missed the list_head, so yes, this would be better, but don't pass
> back the syscore structure, how about just a void * instead, making the
> whole container_of() stuff go away?

Yeah, that's a possibility. I personally don't like passing the void *
around because it's easier to make mistakes that way. I also find it
unintuitive because it doesn't immediately show you what the functions
expect.

My understanding is that the container_of() should get optimized away
most of the time, so there aren't any obvious downsides that I can see.

But I don't feel very strongly, so if you have a strong preference for
void pointers, I can do that.

Thierry
Re: [PATCH v2 0/7] syscore: Pass context data to callbacks
Posted by Greg Kroah-Hartman 2 months, 2 weeks ago
On Tue, Jul 22, 2025 at 03:56:40PM +0200, Thierry Reding wrote:
> On Sat, Jul 19, 2025 at 08:52:41AM +0200, Greg Kroah-Hartman wrote:
> > On Fri, Jul 18, 2025 at 03:49:37PM +0200, Thierry Reding wrote:
> > > On Thu, Jul 17, 2025 at 02:11:41PM +0200, Greg Kroah-Hartman wrote:
> > > > On Thu, Jul 17, 2025 at 12:32:34PM +0200, Thierry Reding wrote:
> [...]
> > > 	struct syscore;
> > > 
> > > 	struct syscore_ops {
> > > 		int (*suspend)(struct syscore *syscore);
> > > 		void (*resume)(struct syscore *syscore);
> > > 		void (*shutdown)(struct syscore *syscore);
> > > 	};
> > > 
> > > 	struct syscore {
> > > 		const struct syscore_ops *ops;
> > > 		struct list_head node;
> > > 	};
> > > 
> > > Is that what you had in mind?
> > 
> > I missed the list_head, so yes, this would be better, but don't pass
> > back the syscore structure, how about just a void * instead, making the
> > whole container_of() stuff go away?
> 
> Yeah, that's a possibility. I personally don't like passing the void *
> around because it's easier to make mistakes that way. I also find it
> unintuitive because it doesn't immediately show you what the functions
> expect.
> 
> My understanding is that the container_of() should get optimized away
> most of the time, so there aren't any obvious downsides that I can see.

container_of() is just pointer math, but a cast is even faster :)

> But I don't feel very strongly, so if you have a strong preference for
> void pointers, I can do that.

That's what you really want to have here, it's a syscore data type
thing, that the callback wants to reference.  Just like a irqrequest_t
function passes back a void * that the handler "knows" how to deal with
properly.

thanks,

greg k-h
Re: [PATCH v2 0/7] syscore: Pass context data to callbacks
Posted by Thierry Reding 2 months, 2 weeks ago
On Tue, Jul 22, 2025 at 04:08:09PM +0200, Greg Kroah-Hartman wrote:
> On Tue, Jul 22, 2025 at 03:56:40PM +0200, Thierry Reding wrote:
> > On Sat, Jul 19, 2025 at 08:52:41AM +0200, Greg Kroah-Hartman wrote:
> > > On Fri, Jul 18, 2025 at 03:49:37PM +0200, Thierry Reding wrote:
> > > > On Thu, Jul 17, 2025 at 02:11:41PM +0200, Greg Kroah-Hartman wrote:
> > > > > On Thu, Jul 17, 2025 at 12:32:34PM +0200, Thierry Reding wrote:
> > [...]
> > > > 	struct syscore;
> > > > 
> > > > 	struct syscore_ops {
> > > > 		int (*suspend)(struct syscore *syscore);
> > > > 		void (*resume)(struct syscore *syscore);
> > > > 		void (*shutdown)(struct syscore *syscore);
> > > > 	};
> > > > 
> > > > 	struct syscore {
> > > > 		const struct syscore_ops *ops;
> > > > 		struct list_head node;
> > > > 	};
> > > > 
> > > > Is that what you had in mind?
> > > 
> > > I missed the list_head, so yes, this would be better, but don't pass
> > > back the syscore structure, how about just a void * instead, making the
> > > whole container_of() stuff go away?
> > 
> > Yeah, that's a possibility. I personally don't like passing the void *
> > around because it's easier to make mistakes that way. I also find it
> > unintuitive because it doesn't immediately show you what the functions
> > expect.
> > 
> > My understanding is that the container_of() should get optimized away
> > most of the time, so there aren't any obvious downsides that I can see.
> 
> container_of() is just pointer math, but a cast is even faster :)
> 
> > But I don't feel very strongly, so if you have a strong preference for
> > void pointers, I can do that.
> 
> That's what you really want to have here, it's a syscore data type
> thing, that the callback wants to reference.  Just like a irqrequest_t
> function passes back a void * that the handler "knows" how to deal with
> properly.

IRQ handlers are different, though, because you pass the void * data
when you register the interrupt. That void * then gets stored and passed
to the handler when the interrupt is processed.

We'd have to change it to something like this:

	struct syscore_ops {
		/* parameters now changed to driver-specific data */
		int (*suspend)(void *data);
		void (*resume)(void *data);
		void (*shutdown)(void *data);
	};

	struct syscore {
		const struct syscore_ops *ops;
		struct list_head node;
		/* NEW driver-specific data */
		void *data;
	};

It ends up increasing the syscore structure's size, about 33%, though
given that there aren't a lot of these that's probably negligible.

What I think is a bit more unnatural about it in this case is that we
embed the struct syscore into some driver-private data anyway so that
it becomes per instance, and then we have a circular reference:

	foo->syscore.ops = &foo_syscore_ops;
	foo->syscore.data = foo;

Which looks kind of weird. Alternatively I suppose we could completely
rework it and make register_syscore_ops() allocate struct syscore, and
hide the internals from drivers completely:

	err = register_syscore(&foo_syscore_ops, foo);

With that it may be problematic that register_syscore() can now fail.

Thierry
Re: [PATCH v2 0/7] syscore: Pass context data to callbacks
Posted by Rafael J. Wysocki 2 months, 2 weeks ago
On Wed, Jul 23, 2025 at 11:01 AM Thierry Reding
<thierry.reding@gmail.com> wrote:
>
> On Tue, Jul 22, 2025 at 04:08:09PM +0200, Greg Kroah-Hartman wrote:
> > On Tue, Jul 22, 2025 at 03:56:40PM +0200, Thierry Reding wrote:
> > > On Sat, Jul 19, 2025 at 08:52:41AM +0200, Greg Kroah-Hartman wrote:
> > > > On Fri, Jul 18, 2025 at 03:49:37PM +0200, Thierry Reding wrote:
> > > > > On Thu, Jul 17, 2025 at 02:11:41PM +0200, Greg Kroah-Hartman wrote:
> > > > > > On Thu, Jul 17, 2025 at 12:32:34PM +0200, Thierry Reding wrote:
> > > [...]
> > > > >         struct syscore;
> > > > >
> > > > >         struct syscore_ops {
> > > > >                 int (*suspend)(struct syscore *syscore);
> > > > >                 void (*resume)(struct syscore *syscore);
> > > > >                 void (*shutdown)(struct syscore *syscore);
> > > > >         };
> > > > >
> > > > >         struct syscore {
> > > > >                 const struct syscore_ops *ops;
> > > > >                 struct list_head node;
> > > > >         };
> > > > >
> > > > > Is that what you had in mind?
> > > >
> > > > I missed the list_head, so yes, this would be better, but don't pass
> > > > back the syscore structure, how about just a void * instead, making the
> > > > whole container_of() stuff go away?
> > >
> > > Yeah, that's a possibility. I personally don't like passing the void *
> > > around because it's easier to make mistakes that way. I also find it
> > > unintuitive because it doesn't immediately show you what the functions
> > > expect.
> > >
> > > My understanding is that the container_of() should get optimized away
> > > most of the time, so there aren't any obvious downsides that I can see.
> >
> > container_of() is just pointer math, but a cast is even faster :)
> >
> > > But I don't feel very strongly, so if you have a strong preference for
> > > void pointers, I can do that.
> >
> > That's what you really want to have here, it's a syscore data type
> > thing, that the callback wants to reference.  Just like a irqrequest_t
> > function passes back a void * that the handler "knows" how to deal with
> > properly.
>
> IRQ handlers are different, though, because you pass the void * data
> when you register the interrupt. That void * then gets stored and passed
> to the handler when the interrupt is processed.
>
> We'd have to change it to something like this:
>
>         struct syscore_ops {
>                 /* parameters now changed to driver-specific data */
>                 int (*suspend)(void *data);
>                 void (*resume)(void *data);
>                 void (*shutdown)(void *data);
>         };
>
>         struct syscore {
>                 const struct syscore_ops *ops;
>                 struct list_head node;
>                 /* NEW driver-specific data */
>                 void *data;
>         };

I like this more than the original, but I would do

struct syscore_ops_ops {
                 int (*suspend)(void *data);
                 void (*resume)(void *data);
                 void (*shutdown)(void *data);
};

struct syscore_ops {
                 struct list_head node;
                 const struct syscore_ops_ops *ops;
                 void *data;
};

and change register_syscore_ops() to take three arguments, the struct
syscore_ops pointer, the (constified) struct syscore_ops_ops one, and
the (void *) data one.

Note that it is not necessary to change the signature of
unregister_syscore_ops() in this case.

> It ends up increasing the syscore structure's size, about 33%, though
> given that there aren't a lot of these that's probably negligible.

That's not a problem IMV.

> What I think is a bit more unnatural about it in this case is that we
> embed the struct syscore into some driver-private data anyway so that
> it becomes per instance, and then we have a circular reference:
>
>         foo->syscore.ops = &foo_syscore_ops;
>         foo->syscore.data = foo;

That depends because "data" need not be "foo" in all cases, but also
see above.  If the initialization of struct syscore_ops is all done by
register_syscore_ops(), it doesn't look circular any more.

> Which looks kind of weird. Alternatively I suppose we could completely
> rework it and make register_syscore_ops() allocate struct syscore, and
> hide the internals from drivers completely:
>
>         err = register_syscore(&foo_syscore_ops, foo);
>
> With that it may be problematic that register_syscore() can now fail.

Yes, that might be a problem.