LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH 04/11] treewide: Convert struct kernel_param_ops initializers to DEFINE_KERNEL_PARAM_OPS
From: Rafael J. Wysocki @ 2026-05-22 17:01 UTC (permalink / raw)
  To: Kees Cook
  Cc: Luis Chamberlain, Pengpeng Hou, Petr Pavlu, Richard Weinberger,
	Anton Ivanov, Johannes Berg, Rafael J. Wysocki, Len Brown,
	Corey Minyard, Gabriel Somlo, Michael S. Tsirkin, Jani Nikula,
	Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, David Airlie,
	Simona Vetter, Bart Van Assche, Jason Gunthorpe, Leon Romanovsky,
	Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
	Bjorn Helgaas, Hannes Reinecke, James E.J. Bottomley,
	Martin K. Petersen, Daniel Lezcano, Zhang Rui, Lukasz Luba,
	Greg Kroah-Hartman, Jiri Slaby, Alan Stern, Jason Wang, Xuan Zhuo,
	Eugenio Pérez, Jason Baron, Jim Cromie, Tiwei Bie,
	Benjamin Berg, Ilpo Järvinen, David E. Box,
	Maciej W. Rozycki, Srinivas Pandruvada, Peter Zijlstra,
	Heiko Carstens, Vasily Gorbik, Sean Christopherson, Paolo Bonzini,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	H. Peter Anvin, Vinod Koul, Frank Li, Daniel Gomez, Sami Tolvanen,
	Aaron Tomlin, Alexander Potapenko, Marco Elver, Dmitry Vyukov,
	Andrew Morton, John Johansen, Paul Moore, James Morris,
	Serge E. Hallyn, Andy Shevchenko, Georgia Garcia, kvm, dmaengine,
	linux-modules, kasan-dev, linux-mm, apparmor,
	linux-security-module, linux-um, linux-acpi, openipmi-developer,
	qemu-devel, intel-gfx, dri-devel, linux-rdma, linux-media,
	linux-pci, linux-scsi, linux-pm, linuxppc-dev, linux-serial,
	linux-usb, usb-storage, virtualization, linux-kernel, linux-arch,
	netdev, linux-fsdevel, linux-hardening
In-Reply-To: <20260521133326.2465264-4-kees@kernel.org>

On Thu, May 21, 2026 at 3:33 PM Kees Cook <kees@kernel.org> wrote:
>
> Using Coccinelle, rewrite every struct kernel_param_ops initializer that
> sets .get into a DEFINE_KERNEL_PARAM_OPS-family macro invocation,
> for example:
>
> @@
> declarer name DEFINE_KERNEL_PARAM_OPS;
> identifier OPS;
> expression SET, GET;
> @@
> - const struct kernel_param_ops OPS = {
> -       .set = SET,
> -       .get = GET,
> - };
> + DEFINE_KERNEL_PARAM_OPS(OPS, SET, GET);
>
> Using the macro for initialization means future changes can manipulate
> the struct layout and callback prototypes without having to change every
> initializer.
>
> Signed-off-by: Kees Cook <kees@kernel.org>

For ACPI and hibernation:

Acked-by: Rafael J. Wysocki (Intel) <rafael@kernel.org>

> ---
>  mm/kfence/core.c                              |  7 +-
>  arch/powerpc/kvm/book3s_hv.c                  |  5 +-
>  arch/s390/kernel/perf_cpum_sf.c               |  6 +-
>  arch/um/drivers/vfio_kern.c                   |  6 +-
>  arch/um/drivers/virtio_uml.c                  |  6 +-
>  arch/x86/kernel/msr.c                         |  6 +-
>  arch/x86/kvm/mmu/mmu.c                        | 12 +--
>  arch/x86/kvm/svm/avic.c                       |  6 +-
>  arch/x86/kvm/vmx/vmx.c                        |  6 +-
>  arch/x86/platform/uv/uv_nmi.c                 | 12 +--
>  block/disk-events.c                           |  6 +-
>  drivers/acpi/sysfs.c                          | 25 +++----
>  drivers/block/loop.c                          | 12 +--
>  drivers/block/null_blk/main.c                 | 12 +--
>  drivers/block/rnbd/rnbd-srv.c                 |  6 +-
>  drivers/block/ublk_drv.c                      |  7 +-
>  drivers/char/ipmi/ipmi_msghandler.c           |  6 +-
>  drivers/char/ipmi/ipmi_watchdog.c             | 17 ++---
>  drivers/crypto/hisilicon/hpre/hpre_main.c     | 16 +---
>  drivers/crypto/hisilicon/sec2/sec_main.c      | 23 ++----
>  drivers/crypto/hisilicon/zip/zip_crypto.c     |  5 +-
>  drivers/crypto/hisilicon/zip/zip_main.c       | 21 ++----
>  drivers/dma/dmatest.c                         | 20 ++---
>  drivers/edac/i10nm_base.c                     |  6 +-
>  drivers/firmware/efi/efi-pstore.c             |  6 +-
>  drivers/firmware/qcom/qcom_scm.c              |  6 +-
>  drivers/firmware/qemu_fw_cfg.c                |  6 +-
>  drivers/gpu/drm/drm_panic.c                   |  6 +-
>  drivers/gpu/drm/i915/i915_mitigations.c       |  5 +-
>  drivers/gpu/drm/imagination/pvr_fw_trace.c    |  6 +-
>  drivers/hid/hid-cougar.c                      |  6 +-
>  drivers/hid/hid-steam.c                       |  6 +-
>  drivers/infiniband/hw/hfi1/driver.c           |  5 +-
>  drivers/infiniband/ulp/iser/iscsi_iser.c      |  6 +-
>  drivers/infiniband/ulp/isert/ib_isert.c       |  6 +-
>  drivers/infiniband/ulp/srp/ib_srp.c           |  5 +-
>  drivers/input/misc/ati_remote2.c              | 13 ++--
>  drivers/input/mouse/psmouse-base.c            |  6 +-
>  drivers/media/usb/uvc/uvc_driver.c            |  6 +-
>  drivers/misc/lis3lv02d/lis3lv02d.c            |  5 +-
>  drivers/net/wireless/ath/wil6210/main.c       | 10 +--
>  drivers/nvme/host/multipath.c                 | 12 +--
>  drivers/nvme/host/pci.c                       | 18 ++---
>  drivers/nvme/target/rdma.c                    |  5 +-
>  drivers/nvme/target/tcp.c                     |  5 +-
>  drivers/platform/x86/acerhdf.c                |  5 +-
>  drivers/power/supply/bq27xxx_battery.c        |  6 +-
>  drivers/power/supply/test_power.c             | 75 ++++++++-----------
>  drivers/scsi/sg.c                             |  6 +-
>  drivers/target/target_core_user.c             | 13 ++--
>  .../processor_thermal_soc_slider.c            | 12 +--
>  drivers/thermal/intel/intel_powerclamp.c      | 20 +----
>  drivers/tty/hvc/hvc_iucv.c                    |  6 +-
>  drivers/tty/sysrq.c                           |  6 +-
>  drivers/ufs/core/ufs-fault-injection.c        |  5 +-
>  drivers/ufs/core/ufs-mcq.c                    | 18 ++---
>  drivers/ufs/core/ufs-txeq.c                   |  5 +-
>  drivers/ufs/core/ufshcd.c                     | 12 +--
>  drivers/usb/core/quirks.c                     |  6 +-
>  drivers/usb/gadget/legacy/serial.c            |  5 +-
>  drivers/usb/storage/usb.c                     |  5 +-
>  drivers/vhost/scsi.c                          |  7 +-
>  drivers/virt/nitro_enclaves/ne_misc_dev.c     |  6 +-
>  drivers/virtio/virtio_mmio.c                  |  6 +-
>  fs/ceph/super.c                               | 10 +--
>  fs/fuse/dir.c                                 |  5 +-
>  fs/nfs/namespace.c                            |  6 +-
>  fs/nfs/super.c                                |  6 +-
>  fs/ubifs/super.c                              |  6 +-
>  kernel/locking/locktorture.c                  |  6 +-
>  kernel/panic.c                                |  6 +-
>  kernel/params.c                               | 44 +++--------
>  kernel/power/hibernate.c                      |  6 +-
>  kernel/rcu/tree.c                             | 18 ++---
>  kernel/sched/ext.c                            | 11 +--
>  kernel/workqueue.c                            | 12 +--
>  lib/dynamic_debug.c                           |  6 +-
>  lib/test_dynamic_debug.c                      |  6 +-
>  mm/damon/lru_sort.c                           | 19 ++---
>  mm/damon/reclaim.c                            | 19 ++---
>  mm/damon/stat.c                               |  6 +-
>  mm/memory_hotplug.c                           | 12 +--
>  mm/page_reporting.c                           | 11 +--
>  mm/shuffle.c                                  |  6 +-
>  mm/zswap.c                                    | 14 ++--
>  net/batman-adv/bat_algo.c                     |  6 +-
>  net/ceph/ceph_common.c                        |  5 +-
>  net/ipv4/tcp_dctcp.c                          |  6 +-
>  net/sunrpc/auth.c                             |  6 +-
>  net/sunrpc/xprtsock.c                         | 18 ++---
>  samples/damon/mtier.c                         |  6 +-
>  samples/damon/prcl.c                          |  6 +-
>  samples/damon/wsse.c                          |  6 +-
>  security/apparmor/lsm.c                       | 34 +++------
>  sound/hda/controllers/intel.c                 |  5 +-
>  sound/usb/card.c                              |  7 +-
>  96 files changed, 307 insertions(+), 660 deletions(-)
>
> diff --git a/mm/kfence/core.c b/mm/kfence/core.c
> index 655dc5ce3240..e14102c01520 100644
> --- a/mm/kfence/core.c
> +++ b/mm/kfence/core.c
> @@ -92,10 +92,9 @@ static int param_get_sample_interval(char *buffer, const struct kernel_param *kp
>         return param_get_ulong(buffer, kp);
>  }
>
> -static const struct kernel_param_ops sample_interval_param_ops = {
> -       .set = param_set_sample_interval,
> -       .get = param_get_sample_interval,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(sample_interval_param_ops,
> +                              param_set_sample_interval,
> +                              param_get_sample_interval);
>  module_param_cb(sample_interval, &sample_interval_param_ops, &kfence_sample_interval, 0600);
>
>  /* Pool usage% threshold when currently covered allocations are skipped. */
> diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
> index 61dbeea317f3..0c15f0426671 100644
> --- a/arch/powerpc/kvm/book3s_hv.c
> +++ b/arch/powerpc/kvm/book3s_hv.c
> @@ -114,10 +114,7 @@ module_param(one_vm_per_core, bool, S_IRUGO | S_IWUSR);
>  MODULE_PARM_DESC(one_vm_per_core, "Only run vCPUs from the same VM on a core (requires POWER8 or older)");
>
>  #ifdef CONFIG_KVM_XICS
> -static const struct kernel_param_ops module_param_ops = {
> -       .set = param_set_int,
> -       .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(module_param_ops, param_set_int, param_get_int);
>
>  module_param_cb(kvm_irq_bypass, &module_param_ops, &kvm_irq_bypass, 0644);
>  MODULE_PARM_DESC(kvm_irq_bypass, "Bypass passthrough interrupt optimization");
> diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c
> index 7bfeb5208177..76119542562b 100644
> --- a/arch/s390/kernel/perf_cpum_sf.c
> +++ b/arch/s390/kernel/perf_cpum_sf.c
> @@ -2029,10 +2029,8 @@ static int param_set_sfb_size(const char *val, const struct kernel_param *kp)
>  }
>
>  #define param_check_sfb_size(name, p) __param_check(name, p, void)
> -static const struct kernel_param_ops param_ops_sfb_size = {
> -       .set = param_set_sfb_size,
> -       .get = param_get_sfb_size,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_sfb_size, param_set_sfb_size,
> +                              param_get_sfb_size);
>
>  enum {
>         RS_INIT_FAILURE_BSDES   = 2,    /* Bad basic sampling size */
> diff --git a/arch/um/drivers/vfio_kern.c b/arch/um/drivers/vfio_kern.c
> index e6dab473cde4..fb7988dc5482 100644
> --- a/arch/um/drivers/vfio_kern.c
> +++ b/arch/um/drivers/vfio_kern.c
> @@ -628,10 +628,8 @@ static int uml_vfio_cmdline_get(char *buffer, const struct kernel_param *kp)
>         return 0;
>  }
>
> -static const struct kernel_param_ops uml_vfio_cmdline_param_ops = {
> -       .set = uml_vfio_cmdline_set,
> -       .get = uml_vfio_cmdline_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(uml_vfio_cmdline_param_ops, uml_vfio_cmdline_set,
> +                              uml_vfio_cmdline_get);
>
>  device_param_cb(device, &uml_vfio_cmdline_param_ops, NULL, 0400);
>  __uml_help(uml_vfio_cmdline_param_ops,
> diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c
> index 7425a8548141..f9ae745f4586 100644
> --- a/arch/um/drivers/virtio_uml.c
> +++ b/arch/um/drivers/virtio_uml.c
> @@ -1398,10 +1398,8 @@ static int vu_cmdline_get(char *buffer, const struct kernel_param *kp)
>         return strlen(buffer) + 1;
>  }
>
> -static const struct kernel_param_ops vu_cmdline_param_ops = {
> -       .set = vu_cmdline_set,
> -       .get = vu_cmdline_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(vu_cmdline_param_ops, vu_cmdline_set,
> +                              vu_cmdline_get);
>
>  device_param_cb(device, &vu_cmdline_param_ops, NULL, S_IRUSR);
>  __uml_help(vu_cmdline_param_ops,
> diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c
> index 4469c784eaa0..5f4e1814dc4d 100644
> --- a/arch/x86/kernel/msr.c
> +++ b/arch/x86/kernel/msr.c
> @@ -322,10 +322,8 @@ static int get_allow_writes(char *buf, const struct kernel_param *kp)
>         return sprintf(buf, "%s\n", res);
>  }
>
> -static const struct kernel_param_ops allow_writes_ops = {
> -       .set = set_allow_writes,
> -       .get = get_allow_writes
> -};
> +static DEFINE_KERNEL_PARAM_OPS(allow_writes_ops, set_allow_writes,
> +                              get_allow_writes);
>
>  module_param_cb(allow_writes, &allow_writes_ops, NULL, 0600);
>
> diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
> index 24fbc9ea502a..996818ee9b09 100644
> --- a/arch/x86/kvm/mmu/mmu.c
> +++ b/arch/x86/kvm/mmu/mmu.c
> @@ -74,15 +74,11 @@ static int get_nx_huge_pages(char *buffer, const struct kernel_param *kp);
>  static int set_nx_huge_pages(const char *val, const struct kernel_param *kp);
>  static int set_nx_huge_pages_recovery_param(const char *val, const struct kernel_param *kp);
>
> -static const struct kernel_param_ops nx_huge_pages_ops = {
> -       .set = set_nx_huge_pages,
> -       .get = get_nx_huge_pages,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(nx_huge_pages_ops, set_nx_huge_pages,
> +                              get_nx_huge_pages);
>
> -static const struct kernel_param_ops nx_huge_pages_recovery_param_ops = {
> -       .set = set_nx_huge_pages_recovery_param,
> -       .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(nx_huge_pages_recovery_param_ops,
> +                              set_nx_huge_pages_recovery_param, param_get_uint);
>
>  module_param_cb(nx_huge_pages, &nx_huge_pages_ops, &nx_huge_pages, 0644);
>  __MODULE_PARM_TYPE(nx_huge_pages, "bool");
> diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c
> index adf211860949..7907f9addff9 100644
> --- a/arch/x86/kvm/svm/avic.c
> +++ b/arch/x86/kvm/svm/avic.c
> @@ -87,11 +87,7 @@ static int avic_param_get(char *buffer, const struct kernel_param *kp)
>         return param_get_bool(buffer, kp);
>  }
>
> -static const struct kernel_param_ops avic_ops = {
> -       .flags = KERNEL_PARAM_OPS_FL_NOARG,
> -       .set = avic_param_set,
> -       .get = avic_param_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS_NOARG(avic_ops, avic_param_set, avic_param_get);
>
>  /*
>   * Enable / disable AVIC.  In "auto" mode (default behavior), AVIC is enabled
> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> index a29896a9ef14..07f4c7209ac0 100644
> --- a/arch/x86/kvm/vmx/vmx.c
> +++ b/arch/x86/kvm/vmx/vmx.c
> @@ -465,10 +465,8 @@ static int vmentry_l1d_flush_get(char *s, const struct kernel_param *kp)
>  }
>  #endif
>
> -static const struct kernel_param_ops vmentry_l1d_flush_ops = {
> -       .set = vmentry_l1d_flush_set,
> -       .get = vmentry_l1d_flush_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(vmentry_l1d_flush_ops, vmentry_l1d_flush_set,
> +                              vmentry_l1d_flush_get);
>  module_param_cb(vmentry_l1d_flush, &vmentry_l1d_flush_ops, NULL, 0644);
>
>  static __always_inline void vmx_disable_fb_clear(struct vcpu_vmx *vmx)
> diff --git a/arch/x86/platform/uv/uv_nmi.c b/arch/x86/platform/uv/uv_nmi.c
> index 5c50e550ab63..a7ac80b5f8d9 100644
> --- a/arch/x86/platform/uv/uv_nmi.c
> +++ b/arch/x86/platform/uv/uv_nmi.c
> @@ -123,10 +123,8 @@ static int param_set_local64(const char *val, const struct kernel_param *kp)
>         return 0;
>  }
>
> -static const struct kernel_param_ops param_ops_local64 = {
> -       .get = param_get_local64,
> -       .set = param_set_local64,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_local64, param_set_local64,
> +                              param_get_local64);
>  #define param_check_local64(name, p) __param_check(name, p, local64_t)
>
>  static local64_t uv_nmi_count;
> @@ -232,10 +230,8 @@ static int param_set_action(const char *val, const struct kernel_param *kp)
>         return -EINVAL;
>  }
>
> -static const struct kernel_param_ops param_ops_action = {
> -       .get = param_get_action,
> -       .set = param_set_action,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_action, param_set_action,
> +                              param_get_action);
>  #define param_check_action(name, p) __param_check(name, p, enum action_t)
>
>  module_param_named(action, uv_nmi_action, action, 0644);
> diff --git a/block/disk-events.c b/block/disk-events.c
> index 074731ecc3d2..f2d4b48294c6 100644
> --- a/block/disk-events.c
> +++ b/block/disk-events.c
> @@ -416,10 +416,8 @@ static int disk_events_set_dfl_poll_msecs(const char *val,
>         return 0;
>  }
>
> -static const struct kernel_param_ops disk_events_dfl_poll_msecs_param_ops = {
> -       .set    = disk_events_set_dfl_poll_msecs,
> -       .get    = param_get_ulong,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(disk_events_dfl_poll_msecs_param_ops,
> +                              disk_events_set_dfl_poll_msecs, param_get_ulong);
>
>  #undef MODULE_PARAM_PREFIX
>  #define MODULE_PARAM_PREFIX    "block."
> diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
> index a625de3c3c8b..3d32a5280432 100644
> --- a/drivers/acpi/sysfs.c
> +++ b/drivers/acpi/sysfs.c
> @@ -138,15 +138,11 @@ static int param_get_debug_level(char *buffer, const struct kernel_param *kp)
>         return result;
>  }
>
> -static const struct kernel_param_ops param_ops_debug_layer = {
> -       .set = param_set_uint,
> -       .get = param_get_debug_layer,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_debug_layer, param_set_uint,
> +                              param_get_debug_layer);
>
> -static const struct kernel_param_ops param_ops_debug_level = {
> -       .set = param_set_uint,
> -       .get = param_get_debug_level,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_debug_level, param_set_uint,
> +                              param_get_debug_level);
>
>  module_param_cb(debug_layer, &param_ops_debug_layer, &acpi_dbg_layer, 0644);
>  module_param_cb(debug_level, &param_ops_debug_level, &acpi_dbg_level, 0644);
> @@ -201,15 +197,12 @@ static int param_get_trace_method_name(char *buffer, const struct kernel_param *
>         return sysfs_emit(buffer, "%s\n", acpi_gbl_trace_method_name);
>  }
>
> -static const struct kernel_param_ops param_ops_trace_method = {
> -       .set = param_set_trace_method_name,
> -       .get = param_get_trace_method_name,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_trace_method,
> +                              param_set_trace_method_name,
> +                              param_get_trace_method_name);
>
> -static const struct kernel_param_ops param_ops_trace_attrib = {
> -       .set = param_set_uint,
> -       .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_trace_attrib, param_set_uint,
> +                              param_get_uint);
>
>  module_param_cb(trace_method_name, &param_ops_trace_method, &trace_method_name, 0644);
>  module_param_cb(trace_debug_layer, &param_ops_trace_attrib, &acpi_gbl_trace_dbg_layer, 0644);
> diff --git a/drivers/block/loop.c b/drivers/block/loop.c
> index 0000913f7efc..147ad561e584 100644
> --- a/drivers/block/loop.c
> +++ b/drivers/block/loop.c
> @@ -1806,10 +1806,8 @@ static int max_loop_param_set_int(const char *val,
>         return 0;
>  }
>
> -static const struct kernel_param_ops max_loop_param_ops = {
> -       .set = max_loop_param_set_int,
> -       .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(max_loop_param_ops, max_loop_param_set_int,
> +                              param_get_int);
>
>  module_param_cb(max_loop, &max_loop_param_ops, &max_loop, 0444);
>  MODULE_PARM_DESC(max_loop, "Maximum number of loop devices");
> @@ -1836,10 +1834,8 @@ static int loop_set_hw_queue_depth(const char *s, const struct kernel_param *p)
>         return 0;
>  }
>
> -static const struct kernel_param_ops loop_hw_qdepth_param_ops = {
> -       .set    = loop_set_hw_queue_depth,
> -       .get    = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(loop_hw_qdepth_param_ops,
> +                              loop_set_hw_queue_depth, param_get_int);
>
>  device_param_cb(hw_queue_depth, &loop_hw_qdepth_param_ops, &hw_queue_depth, 0444);
>  MODULE_PARM_DESC(hw_queue_depth, "Queue depth for each hardware queue. Default: " __stringify(LOOP_DEFAULT_HW_Q_DEPTH));
> diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c
> index f8c0fd57e041..332ad6ac838a 100644
> --- a/drivers/block/null_blk/main.c
> +++ b/drivers/block/null_blk/main.c
> @@ -149,10 +149,8 @@ static int null_set_queue_mode(const char *str, const struct kernel_param *kp)
>         return null_param_store_val(str, &g_queue_mode, NULL_Q_BIO, NULL_Q_MQ);
>  }
>
> -static const struct kernel_param_ops null_queue_mode_param_ops = {
> -       .set    = null_set_queue_mode,
> -       .get    = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(null_queue_mode_param_ops, null_set_queue_mode,
> +                              param_get_int);
>
>  device_param_cb(queue_mode, &null_queue_mode_param_ops, &g_queue_mode, 0444);
>  MODULE_PARM_DESC(queue_mode, "Block interface to use (0=bio,1=rq,2=multiqueue)");
> @@ -193,10 +191,8 @@ static int null_set_irqmode(const char *str, const struct kernel_param *kp)
>                                         NULL_IRQ_TIMER);
>  }
>
> -static const struct kernel_param_ops null_irqmode_param_ops = {
> -       .set    = null_set_irqmode,
> -       .get    = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(null_irqmode_param_ops, null_set_irqmode,
> +                              param_get_int);
>
>  device_param_cb(irqmode, &null_irqmode_param_ops, &g_irqmode, 0444);
>  MODULE_PARM_DESC(irqmode, "IRQ completion handler. 0-none, 1-softirq, 2-timer");
> diff --git a/drivers/block/rnbd/rnbd-srv.c b/drivers/block/rnbd/rnbd-srv.c
> index 10e8c438bb43..81961f7c883a 100644
> --- a/drivers/block/rnbd/rnbd-srv.c
> +++ b/drivers/block/rnbd/rnbd-srv.c
> @@ -49,10 +49,8 @@ static struct kparam_string dev_search_path_kparam_str = {
>         .string = dev_search_path
>  };
>
> -static const struct kernel_param_ops dev_search_path_ops = {
> -       .set    = dev_search_path_set,
> -       .get    = param_get_string,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(dev_search_path_ops, dev_search_path_set,
> +                              param_get_string);
>
>  module_param_cb(dev_search_path, &dev_search_path_ops,
>                 &dev_search_path_kparam_str, 0444);
> diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
> index 8e5f3738c203..f7bf7ea2d088 100644
> --- a/drivers/block/ublk_drv.c
> +++ b/drivers/block/ublk_drv.c
> @@ -5874,10 +5874,9 @@ static int ublk_get_max_unprivileged_ublks(char *buf,
>         return sysfs_emit(buf, "%u\n", unprivileged_ublks_max);
>  }
>
> -static const struct kernel_param_ops ublk_max_unprivileged_ublks_ops = {
> -       .set = ublk_set_max_unprivileged_ublks,
> -       .get = ublk_get_max_unprivileged_ublks,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(ublk_max_unprivileged_ublks_ops,
> +                              ublk_set_max_unprivileged_ublks,
> +                              ublk_get_max_unprivileged_ublks);
>
>  module_param_cb(ublks_max, &ublk_max_unprivileged_ublks_ops,
>                 &unprivileged_ublks_max, 0644);
> diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
> index 869ac87a4b6a..b5fed11707e8 100644
> --- a/drivers/char/ipmi/ipmi_msghandler.c
> +++ b/drivers/char/ipmi/ipmi_msghandler.c
> @@ -102,10 +102,8 @@ static int panic_op_read_handler(char *buffer, const struct kernel_param *kp)
>         return sprintf(buffer, "%s\n", event_str);
>  }
>
> -static const struct kernel_param_ops panic_op_ops = {
> -       .set = panic_op_write_handler,
> -       .get = panic_op_read_handler
> -};
> +static DEFINE_KERNEL_PARAM_OPS(panic_op_ops, panic_op_write_handler,
> +                              panic_op_read_handler);
>  module_param_cb(panic_op, &panic_op_ops, NULL, 0600);
>  MODULE_PARM_DESC(panic_op, "Sets if the IPMI driver will attempt to store panic information in the event log in the event of a panic.  Set to 'none' for no, 'event' for a single event, or 'string' for a generic event and the panic string in IPMI OEM events.");
>
> diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
> index a013ddbf1466..91a99417d204 100644
> --- a/drivers/char/ipmi/ipmi_watchdog.c
> +++ b/drivers/char/ipmi/ipmi_watchdog.c
> @@ -193,10 +193,8 @@ static int set_param_timeout(const char *val, const struct kernel_param *kp)
>         return rv;
>  }
>
> -static const struct kernel_param_ops param_ops_timeout = {
> -       .set = set_param_timeout,
> -       .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_timeout, set_param_timeout,
> +                              param_get_int);
>  #define param_check_timeout param_check_int
>
>  typedef int (*action_fn)(const char *intval, char *outval);
> @@ -259,17 +257,12 @@ static int set_param_wdog_ifnum(const char *val, const struct kernel_param *kp)
>         return 0;
>  }
>
> -static const struct kernel_param_ops param_ops_wdog_ifnum = {
> -       .set = set_param_wdog_ifnum,
> -       .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_wdog_ifnum, set_param_wdog_ifnum,
> +                              param_get_int);
>
>  #define param_check_wdog_ifnum param_check_int
>
> -static const struct kernel_param_ops param_ops_str = {
> -       .set = set_param_str,
> -       .get = get_param_str,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_str, set_param_str, get_param_str);
>
>  module_param(ifnum_to_use, wdog_ifnum, 0644);
>  MODULE_PARM_DESC(ifnum_to_use, "The interface number to use for the watchdog "
> diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c
> index 357ab5e5887e..1104184c2f63 100644
> --- a/drivers/crypto/hisilicon/hpre/hpre_main.c
> +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c
> @@ -420,10 +420,8 @@ static int hpre_cluster_regs_show(struct seq_file *s, void *unused)
>
>  DEFINE_SHOW_ATTRIBUTE(hpre_cluster_regs);
>
> -static const struct kernel_param_ops hpre_uacce_mode_ops = {
> -       .set = uacce_mode_set,
> -       .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(hpre_uacce_mode_ops, uacce_mode_set,
> +                              param_get_int);
>
>  /*
>   * uacce_mode = 0 means hpre only register to crypto,
> @@ -441,19 +439,13 @@ static int pf_q_num_set(const char *val, const struct kernel_param *kp)
>         return hisi_qm_q_num_set(val, kp, PCI_DEVICE_ID_HUAWEI_HPRE_PF);
>  }
>
> -static const struct kernel_param_ops hpre_pf_q_num_ops = {
> -       .set = pf_q_num_set,
> -       .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(hpre_pf_q_num_ops, pf_q_num_set, param_get_int);
>
>  static u32 pf_q_num = HPRE_PF_DEF_Q_NUM;
>  module_param_cb(pf_q_num, &hpre_pf_q_num_ops, &pf_q_num, 0444);
>  MODULE_PARM_DESC(pf_q_num, "Number of queues in PF of CS(2-1024)");
>
> -static const struct kernel_param_ops vfs_num_ops = {
> -       .set = vfs_num_set,
> -       .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(vfs_num_ops, vfs_num_set, param_get_int);
>
>  static u32 vfs_num;
>  module_param_cb(vfs_num, &vfs_num_ops, &vfs_num, 0444);
> diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c
> index 056bd8f4da5a..3d13f2faa3d0 100644
> --- a/drivers/crypto/hisilicon/sec2/sec_main.c
> +++ b/drivers/crypto/hisilicon/sec2/sec_main.c
> @@ -362,10 +362,8 @@ static int sec_pf_q_num_set(const char *val, const struct kernel_param *kp)
>         return hisi_qm_q_num_set(val, kp, PCI_DEVICE_ID_HUAWEI_SEC_PF);
>  }
>
> -static const struct kernel_param_ops sec_pf_q_num_ops = {
> -       .set = sec_pf_q_num_set,
> -       .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(sec_pf_q_num_ops, sec_pf_q_num_set,
> +                              param_get_int);
>
>  static u32 pf_q_num = SEC_PF_DEF_Q_NUM;
>  module_param_cb(pf_q_num, &sec_pf_q_num_ops, &pf_q_num, 0444);
> @@ -391,18 +389,13 @@ static int sec_ctx_q_num_set(const char *val, const struct kernel_param *kp)
>         return param_set_int(val, kp);
>  }
>
> -static const struct kernel_param_ops sec_ctx_q_num_ops = {
> -       .set = sec_ctx_q_num_set,
> -       .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(sec_ctx_q_num_ops, sec_ctx_q_num_set,
> +                              param_get_int);
>  static u32 ctx_q_num = SEC_CTX_Q_NUM_DEF;
>  module_param_cb(ctx_q_num, &sec_ctx_q_num_ops, &ctx_q_num, 0444);
>  MODULE_PARM_DESC(ctx_q_num, "Queue num in ctx (2 default, 2, 4, ..., 32)");
>
> -static const struct kernel_param_ops vfs_num_ops = {
> -       .set = vfs_num_set,
> -       .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(vfs_num_ops, vfs_num_set, param_get_int);
>
>  static u32 vfs_num;
>  module_param_cb(vfs_num, &vfs_num_ops, &vfs_num, 0444);
> @@ -454,10 +447,8 @@ u64 sec_get_alg_bitmap(struct hisi_qm *qm, u32 high, u32 low)
>         return ((u64)cap_val_h << SEC_ALG_BITMAP_SHIFT) | (u64)cap_val_l;
>  }
>
> -static const struct kernel_param_ops sec_uacce_mode_ops = {
> -       .set = uacce_mode_set,
> -       .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(sec_uacce_mode_ops, uacce_mode_set,
> +                              param_get_int);
>
>  /*
>   * uacce_mode = 0 means sec only register to crypto,
> diff --git a/drivers/crypto/hisilicon/zip/zip_crypto.c b/drivers/crypto/hisilicon/zip/zip_crypto.c
> index 70adde049b53..8f8d57420fb4 100644
> --- a/drivers/crypto/hisilicon/zip/zip_crypto.c
> +++ b/drivers/crypto/hisilicon/zip/zip_crypto.c
> @@ -108,10 +108,7 @@ static int sgl_sge_nr_set(const char *val, const struct kernel_param *kp)
>         return param_set_ushort(val, kp);
>  }
>
> -static const struct kernel_param_ops sgl_sge_nr_ops = {
> -       .set = sgl_sge_nr_set,
> -       .get = param_get_ushort,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(sgl_sge_nr_ops, sgl_sge_nr_set, param_get_ushort);
>
>  static u16 sgl_sge_nr = HZIP_SGL_SGE_NR;
>  module_param_cb(sgl_sge_nr, &sgl_sge_nr_ops, &sgl_sge_nr, 0444);
> diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c
> index 44df9c859bd8..e07d0cf8eca8 100644
> --- a/drivers/crypto/hisilicon/zip/zip_main.c
> +++ b/drivers/crypto/hisilicon/zip/zip_main.c
> @@ -394,10 +394,7 @@ static int perf_mode_set(const char *val, const struct kernel_param *kp)
>         return param_set_int(val, kp);
>  }
>
> -static const struct kernel_param_ops zip_com_perf_ops = {
> -       .set = perf_mode_set,
> -       .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(zip_com_perf_ops, perf_mode_set, param_get_int);
>
>  /*
>   * perf_mode = 0 means enable high compression rate mode,
> @@ -408,10 +405,8 @@ static u32 perf_mode = HZIP_HIGH_COMP_RATE;
>  module_param_cb(perf_mode, &zip_com_perf_ops, &perf_mode, 0444);
>  MODULE_PARM_DESC(perf_mode, "ZIP high perf mode 0(default), 1(enable)");
>
> -static const struct kernel_param_ops zip_uacce_mode_ops = {
> -       .set = uacce_mode_set,
> -       .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(zip_uacce_mode_ops, uacce_mode_set,
> +                              param_get_int);
>
>  /*
>   * uacce_mode = 0 means zip only register to crypto,
> @@ -429,19 +424,13 @@ static int pf_q_num_set(const char *val, const struct kernel_param *kp)
>         return hisi_qm_q_num_set(val, kp, PCI_DEVICE_ID_HUAWEI_ZIP_PF);
>  }
>
> -static const struct kernel_param_ops pf_q_num_ops = {
> -       .set = pf_q_num_set,
> -       .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(pf_q_num_ops, pf_q_num_set, param_get_int);
>
>  static u32 pf_q_num = HZIP_PF_DEF_Q_NUM;
>  module_param_cb(pf_q_num, &pf_q_num_ops, &pf_q_num, 0444);
>  MODULE_PARM_DESC(pf_q_num, "Number of queues in PF(v1 2-4096, v2 2-1024)");
>
> -static const struct kernel_param_ops vfs_num_ops = {
> -       .set = vfs_num_set,
> -       .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(vfs_num_ops, vfs_num_set, param_get_int);
>
>  static u32 vfs_num;
>  module_param_cb(vfs_num, &vfs_num_ops, &vfs_num, 0444);
> diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
> index df38681a1ff4..a7bddadcc52d 100644
> --- a/drivers/dma/dmatest.c
> +++ b/drivers/dma/dmatest.c
> @@ -154,20 +154,15 @@ static struct dmatest_info {
>
>  static int dmatest_run_set(const char *val, const struct kernel_param *kp);
>  static int dmatest_run_get(char *val, const struct kernel_param *kp);
> -static const struct kernel_param_ops run_ops = {
> -       .set = dmatest_run_set,
> -       .get = dmatest_run_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(run_ops, dmatest_run_set, dmatest_run_get);
>  static bool dmatest_run;
>  module_param_cb(run, &run_ops, &dmatest_run, 0644);
>  MODULE_PARM_DESC(run, "Run the test (default: false)");
>
>  static int dmatest_chan_set(const char *val, const struct kernel_param *kp);
>  static int dmatest_chan_get(char *val, const struct kernel_param *kp);
> -static const struct kernel_param_ops multi_chan_ops = {
> -       .set = dmatest_chan_set,
> -       .get = dmatest_chan_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(multi_chan_ops, dmatest_chan_set,
> +                              dmatest_chan_get);
>
>  static char test_channel[20];
>  static struct kparam_string newchan_kps = {
> @@ -178,9 +173,7 @@ module_param_cb(channel, &multi_chan_ops, &newchan_kps, 0644);
>  MODULE_PARM_DESC(channel, "Bus ID of the channel to test (default: any)");
>
>  static int dmatest_test_list_get(char *val, const struct kernel_param *kp);
> -static const struct kernel_param_ops test_list_ops = {
> -       .get = dmatest_test_list_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(test_list_ops, NULL, dmatest_test_list_get);
>  module_param_cb(test_list, &test_list_ops, NULL, 0444);
>  MODULE_PARM_DESC(test_list, "Print current test list");
>
> @@ -292,10 +285,7 @@ static int dmatest_wait_get(char *val, const struct kernel_param *kp)
>         return param_get_bool(val, kp);
>  }
>
> -static const struct kernel_param_ops wait_ops = {
> -       .get = dmatest_wait_get,
> -       .set = param_set_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(wait_ops, param_set_bool, dmatest_wait_get);
>  module_param_cb(wait, &wait_ops, &wait, 0444);
>  MODULE_PARM_DESC(wait, "Wait for tests to complete (default: false)");
>
> diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c
> index 63df35444214..ab05e58faaa8 100644
> --- a/drivers/edac/i10nm_base.c
> +++ b/drivers/edac/i10nm_base.c
> @@ -1284,10 +1284,8 @@ static int set_decoding_via_mca(const char *buf, const struct kernel_param *kp)
>         return ret;
>  }
>
> -static const struct kernel_param_ops decoding_via_mca_param_ops = {
> -       .set = set_decoding_via_mca,
> -       .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(decoding_via_mca_param_ops, set_decoding_via_mca,
> +                              param_get_int);
>
>  module_param_cb(decoding_via_mca, &decoding_via_mca_param_ops, &decoding_via_mca, 0644);
>  MODULE_PARM_DESC(decoding_via_mca, "decoding_via_mca: 0=off(default), 1=enable");
> diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c
> index a253b6144945..fd0f3579fd54 100644
> --- a/drivers/firmware/efi/efi-pstore.c
> +++ b/drivers/firmware/efi/efi-pstore.c
> @@ -43,10 +43,8 @@ static int efi_pstore_disable_set(const char *val, const struct kernel_param *kp
>         return 0;
>  }
>
> -static const struct kernel_param_ops pstore_disable_ops = {
> -       .set    = efi_pstore_disable_set,
> -       .get    = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(pstore_disable_ops, efi_pstore_disable_set,
> +                              param_get_bool);
>
>  module_param_cb(pstore_disable, &pstore_disable_ops, &pstore_disable, 0644);
>  __MODULE_PARM_TYPE(pstore_disable, "bool");
> diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
> index 9b06a69d3a6d..ef57df53e087 100644
> --- a/drivers/firmware/qcom/qcom_scm.c
> +++ b/drivers/firmware/qcom/qcom_scm.c
> @@ -2725,10 +2725,8 @@ static int set_download_mode(const char *val, const struct kernel_param *kp)
>         return 0;
>  }
>
> -static const struct kernel_param_ops download_mode_param_ops = {
> -       .get = get_download_mode,
> -       .set = set_download_mode,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(download_mode_param_ops, set_download_mode,
> +                              get_download_mode);
>
>  module_param_cb(download_mode, &download_mode_param_ops, NULL, 0644);
>  MODULE_PARM_DESC(download_mode, "download mode: off/0/N for no dump mode, full/on/1/Y for full dump mode, mini for minidump mode and full,mini for both full and minidump mode together are acceptable values");
> diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
> index 87a5421bc7d5..c87a5449ba8c 100644
> --- a/drivers/firmware/qemu_fw_cfg.c
> +++ b/drivers/firmware/qemu_fw_cfg.c
> @@ -897,10 +897,8 @@ static int fw_cfg_cmdline_get(char *buf, const struct kernel_param *kp)
>         return 0;
>  }
>
> -static const struct kernel_param_ops fw_cfg_cmdline_param_ops = {
> -       .set = fw_cfg_cmdline_set,
> -       .get = fw_cfg_cmdline_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(fw_cfg_cmdline_param_ops, fw_cfg_cmdline_set,
> +                              fw_cfg_cmdline_get);
>
>  device_param_cb(ioport, &fw_cfg_cmdline_param_ops, NULL, S_IRUSR);
>  device_param_cb(mmio, &fw_cfg_cmdline_param_ops, NULL, S_IRUSR);
> diff --git a/drivers/gpu/drm/drm_panic.c b/drivers/gpu/drm/drm_panic.c
> index d6d3b8d85dea..c35d1adf2ce3 100644
> --- a/drivers/gpu/drm/drm_panic.c
> +++ b/drivers/gpu/drm/drm_panic.c
> @@ -847,10 +847,8 @@ static int drm_panic_type_get(char *buffer, const struct kernel_param *kp)
>                          drm_panic_type_map[drm_panic_type]);
>  }
>
> -static const struct kernel_param_ops drm_panic_ops = {
> -       .set = drm_panic_type_set,
> -       .get = drm_panic_type_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(drm_panic_ops, drm_panic_type_set,
> +                              drm_panic_type_get);
>
>  module_param_cb(panic_screen, &drm_panic_ops, NULL, 0644);
>  MODULE_PARM_DESC(panic_screen,
> diff --git a/drivers/gpu/drm/i915/i915_mitigations.c b/drivers/gpu/drm/i915/i915_mitigations.c
> index def7302ef7fe..6061eae84e9c 100644
> --- a/drivers/gpu/drm/i915/i915_mitigations.c
> +++ b/drivers/gpu/drm/i915/i915_mitigations.c
> @@ -124,10 +124,7 @@ static int mitigations_get(char *buffer, const struct kernel_param *kp)
>         return count;
>  }
>
> -static const struct kernel_param_ops ops = {
> -       .set = mitigations_set,
> -       .get = mitigations_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(ops, mitigations_set, mitigations_get);
>
>  module_param_cb_unsafe(mitigations, &ops, NULL, 0600);
>  MODULE_PARM_DESC(mitigations,
> diff --git a/drivers/gpu/drm/imagination/pvr_fw_trace.c b/drivers/gpu/drm/imagination/pvr_fw_trace.c
> index 6193811ef7be..2df7274e21a8 100644
> --- a/drivers/gpu/drm/imagination/pvr_fw_trace.c
> +++ b/drivers/gpu/drm/imagination/pvr_fw_trace.c
> @@ -71,10 +71,8 @@ pvr_fw_trace_init_mask_set(const char *val, const struct kernel_param *kp)
>         return 0;
>  }
>
> -const struct kernel_param_ops pvr_fw_trace_init_mask_ops = {
> -       .set = pvr_fw_trace_init_mask_set,
> -       .get = param_get_hexint,
> -};
> +DEFINE_KERNEL_PARAM_OPS(pvr_fw_trace_init_mask_ops, pvr_fw_trace_init_mask_set,
> +                       param_get_hexint);
>
>  param_check_hexint(init_fw_trace_mask, &pvr_fw_trace_init_mask);
>  module_param_cb(init_fw_trace_mask, &pvr_fw_trace_init_mask_ops, &pvr_fw_trace_init_mask, 0600);
> diff --git a/drivers/hid/hid-cougar.c b/drivers/hid/hid-cougar.c
> index ad027c45f162..271048bdf7fc 100644
> --- a/drivers/hid/hid-cougar.c
> +++ b/drivers/hid/hid-cougar.c
> @@ -314,10 +314,8 @@ static int cougar_param_set_g6_is_space(const char *val,
>         return 0;
>  }
>
> -static const struct kernel_param_ops cougar_g6_is_space_ops = {
> -       .set    = cougar_param_set_g6_is_space,
> -       .get    = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(cougar_g6_is_space_ops,
> +                              cougar_param_set_g6_is_space, param_get_bool);
>  module_param_cb(g6_is_space, &cougar_g6_is_space_ops, &g6_is_space, 0644);
>
>  static const struct hid_device_id cougar_id_table[] = {
> diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c
> index 197126d6e081..962ed60492ea 100644
> --- a/drivers/hid/hid-steam.c
> +++ b/drivers/hid/hid-steam.c
> @@ -1840,10 +1840,8 @@ static int steam_param_set_lizard_mode(const char *val,
>         return 0;
>  }
>
> -static const struct kernel_param_ops steam_lizard_mode_ops = {
> -       .set    = steam_param_set_lizard_mode,
> -       .get    = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(steam_lizard_mode_ops,
> +                              steam_param_set_lizard_mode, param_get_bool);
>
>  module_param_cb(lizard_mode, &steam_lizard_mode_ops, &lizard_mode, 0644);
>  MODULE_PARM_DESC(lizard_mode,
> diff --git a/drivers/infiniband/hw/hfi1/driver.c b/drivers/infiniband/hw/hfi1/driver.c
> index c7259cc39013..5b9b0b38b419 100644
> --- a/drivers/infiniband/hw/hfi1/driver.c
> +++ b/drivers/infiniband/hw/hfi1/driver.c
> @@ -42,10 +42,7 @@ MODULE_PARM_DESC(cu, "Credit return units");
>  unsigned long hfi1_cap_mask = HFI1_CAP_MASK_DEFAULT;
>  static int hfi1_caps_set(const char *val, const struct kernel_param *kp);
>  static int hfi1_caps_get(char *buffer, const struct kernel_param *kp);
> -static const struct kernel_param_ops cap_ops = {
> -       .set = hfi1_caps_set,
> -       .get = hfi1_caps_get
> -};
> +static DEFINE_KERNEL_PARAM_OPS(cap_ops, hfi1_caps_set, hfi1_caps_get);
>  module_param_cb(cap_mask, &cap_ops, &hfi1_cap_mask, S_IWUSR | S_IRUGO);
>  MODULE_PARM_DESC(cap_mask, "Bit mask of enabled/disabled HW features");
>
> diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
> index 7df441685780..758e527ca7c4 100644
> --- a/drivers/infiniband/ulp/iser/iscsi_iser.c
> +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
> @@ -90,10 +90,8 @@ module_param_named(debug_level, iser_debug_level, int, S_IRUGO | S_IWUSR);
>  MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0 (default:disabled)");
>
>  static int iscsi_iser_set(const char *val, const struct kernel_param *kp);
> -static const struct kernel_param_ops iscsi_iser_size_ops = {
> -       .set = iscsi_iser_set,
> -       .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(iscsi_iser_size_ops, iscsi_iser_set,
> +                              param_get_uint);
>
>  static unsigned int iscsi_max_lun = 512;
>  module_param_cb(max_lun, &iscsi_iser_size_ops, &iscsi_max_lun, S_IRUGO);
> diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
> index 348005e71891..bd91900a0ebf 100644
> --- a/drivers/infiniband/ulp/isert/ib_isert.c
> +++ b/drivers/infiniband/ulp/isert/ib_isert.c
> @@ -30,10 +30,8 @@ MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0 (default:0)");
>
>  static int isert_sg_tablesize_set(const char *val,
>                                   const struct kernel_param *kp);
> -static const struct kernel_param_ops sg_tablesize_ops = {
> -       .set = isert_sg_tablesize_set,
> -       .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(sg_tablesize_ops, isert_sg_tablesize_set,
> +                              param_get_int);
>
>  static int isert_sg_tablesize = ISCSI_ISER_MIN_SG_TABLESIZE;
>  module_param_cb(sg_tablesize, &sg_tablesize_ops, &isert_sg_tablesize, 0644);
> diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
> index b58868e1cf11..a81515f52a4f 100644
> --- a/drivers/infiniband/ulp/srp/ib_srp.c
> +++ b/drivers/infiniband/ulp/srp/ib_srp.c
> @@ -195,10 +195,7 @@ static int srp_tmo_set(const char *val, const struct kernel_param *kp)
>         return res;
>  }
>
> -static const struct kernel_param_ops srp_tmo_ops = {
> -       .get = srp_tmo_get,
> -       .set = srp_tmo_set,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(srp_tmo_ops, srp_tmo_set, srp_tmo_get);
>
>  static inline struct srp_target_port *host_to_target(struct Scsi_Host *host)
>  {
> diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c
> index 8db2dca84975..8b4ef7e163d3 100644
> --- a/drivers/input/misc/ati_remote2.c
> +++ b/drivers/input/misc/ati_remote2.c
> @@ -89,19 +89,16 @@ static int ati_remote2_get_mode_mask(char *buffer,
>
>  static unsigned int channel_mask = ATI_REMOTE2_MAX_CHANNEL_MASK;
>  #define param_check_channel_mask(name, p) __param_check(name, p, unsigned int)
> -static const struct kernel_param_ops param_ops_channel_mask = {
> -       .set = ati_remote2_set_channel_mask,
> -       .get = ati_remote2_get_channel_mask,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_channel_mask,
> +                              ati_remote2_set_channel_mask,
> +                              ati_remote2_get_channel_mask);
>  module_param(channel_mask, channel_mask, 0644);
>  MODULE_PARM_DESC(channel_mask, "Bitmask of channels to accept <15:Channel16>...<1:Channel2><0:Channel1>");
>
>  static unsigned int mode_mask = ATI_REMOTE2_MAX_MODE_MASK;
>  #define param_check_mode_mask(name, p) __param_check(name, p, unsigned int)
> -static const struct kernel_param_ops param_ops_mode_mask = {
> -       .set = ati_remote2_set_mode_mask,
> -       .get = ati_remote2_get_mode_mask,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_mode_mask, ati_remote2_set_mode_mask,
> +                              ati_remote2_get_mode_mask);
>  module_param(mode_mask, mode_mask, 0644);
>  MODULE_PARM_DESC(mode_mask, "Bitmask of modes to accept <4:PC><3:AUX4><2:AUX3><1:AUX2><0:AUX1>");
>
> diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
> index 6ab5f1d96eae..f9ebb1fd0b6f 100644
> --- a/drivers/input/mouse/psmouse-base.c
> +++ b/drivers/input/mouse/psmouse-base.c
> @@ -45,10 +45,8 @@ MODULE_LICENSE("GPL");
>  static unsigned int psmouse_max_proto = PSMOUSE_AUTO;
>  static int psmouse_set_maxproto(const char *val, const struct kernel_param *);
>  static int psmouse_get_maxproto(char *buffer, const struct kernel_param *kp);
> -static const struct kernel_param_ops param_ops_proto_abbrev = {
> -       .set = psmouse_set_maxproto,
> -       .get = psmouse_get_maxproto,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_proto_abbrev, psmouse_set_maxproto,
> +                              psmouse_get_maxproto);
>  #define param_check_proto_abbrev(name, p)      __param_check(name, p, unsigned int)
>  module_param_named(proto, psmouse_max_proto, proto_abbrev, 0644);
>  MODULE_PARM_DESC(proto, "Highest protocol extension to probe (bare, imps, exps, any). Useful for KVM switches.");
> diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
> index 31b4ac3b48c1..2338cab7fef9 100644
> --- a/drivers/media/usb/uvc/uvc_driver.c
> +++ b/drivers/media/usb/uvc/uvc_driver.c
> @@ -2488,10 +2488,8 @@ static int param_set_nodrop(const char *val, const struct kernel_param *kp)
>         return param_set_bool(val, kp);
>  }
>
> -static const struct kernel_param_ops param_ops_nodrop = {
> -       .set = param_set_nodrop,
> -       .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_nodrop, param_set_nodrop,
> +                              param_get_uint);
>
>  param_check_uint(nodrop, &uvc_no_drop_param);
>  module_param_cb(nodrop, &param_ops_nodrop, &uvc_no_drop_param, 0644);
> diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c
> index 21e8ad0a7444..6e40c14be51e 100644
> --- a/drivers/misc/lis3lv02d/lis3lv02d.c
> +++ b/drivers/misc/lis3lv02d/lis3lv02d.c
> @@ -103,10 +103,7 @@ static int param_set_axis(const char *val, const struct kernel_param *kp)
>         return ret;
>  }
>
> -static const struct kernel_param_ops param_ops_axis = {
> -       .set = param_set_axis,
> -       .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_axis, param_set_axis, param_get_int);
>
>  #define param_check_axis(name, p) param_check_int(name, p)
>
> diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
> index d5aec72ecdce..e566d94d5f5c 100644
> --- a/drivers/net/wireless/ath/wil6210/main.c
> +++ b/drivers/net/wireless/ath/wil6210/main.c
> @@ -62,10 +62,7 @@ static int mtu_max_set(const char *val, const struct kernel_param *kp)
>         return ret;
>  }
>
> -static const struct kernel_param_ops mtu_max_ops = {
> -       .set = mtu_max_set,
> -       .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(mtu_max_ops, mtu_max_set, param_get_uint);
>
>  module_param_cb(mtu_max, &mtu_max_ops, &mtu_max, 0444);
>  MODULE_PARM_DESC(mtu_max, " Max MTU value.");
> @@ -91,10 +88,7 @@ static int ring_order_set(const char *val, const struct kernel_param *kp)
>         return 0;
>  }
>
> -static const struct kernel_param_ops ring_order_ops = {
> -       .set = ring_order_set,
> -       .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(ring_order_ops, ring_order_set, param_get_uint);
>
>  module_param_cb(rx_ring_order, &ring_order_ops, &rx_ring_order, 0444);
>  MODULE_PARM_DESC(rx_ring_order, " Rx ring order; size = 1 << order");
> diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
> index 263161cb8ac0..f7362377e427 100644
> --- a/drivers/nvme/host/multipath.c
> +++ b/drivers/nvme/host/multipath.c
> @@ -30,10 +30,8 @@ static int multipath_param_set(const char *val, const struct kernel_param *kp)
>         return 0;
>  }
>
> -static const struct kernel_param_ops multipath_param_ops = {
> -       .set = multipath_param_set,
> -       .get = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(multipath_param_ops, multipath_param_set,
> +                              param_get_bool);
>
>  module_param_cb(multipath, &multipath_param_ops, &multipath, 0444);
>  MODULE_PARM_DESC(multipath,
> @@ -55,10 +53,8 @@ static int multipath_always_on_set(const char *val,
>         return 0;
>  }
>
> -static const struct kernel_param_ops multipath_always_on_ops = {
> -       .set = multipath_always_on_set,
> -       .get = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(multipath_always_on_ops, multipath_always_on_set,
> +                              param_get_bool);
>
>  module_param_cb(multipath_always_on, &multipath_always_on_ops,
>                 &multipath_always_on, 0444);
> diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
> index 9fd04cd7c5cb..c77e9b848d03 100644
> --- a/drivers/nvme/host/pci.c
> +++ b/drivers/nvme/host/pci.c
> @@ -100,10 +100,8 @@ MODULE_PARM_DESC(sgl_threshold,
>  #define NVME_PCI_MIN_QUEUE_SIZE 2
>  #define NVME_PCI_MAX_QUEUE_SIZE 4095
>  static int io_queue_depth_set(const char *val, const struct kernel_param *kp);
> -static const struct kernel_param_ops io_queue_depth_ops = {
> -       .set = io_queue_depth_set,
> -       .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(io_queue_depth_ops, io_queue_depth_set,
> +                              param_get_uint);
>
>  static unsigned int io_queue_depth = 1024;
>  module_param_cb(io_queue_depth, &io_queue_depth_ops, &io_queue_depth, 0644);
> @@ -232,10 +230,8 @@ static int quirks_param_set(const char *value, const struct kernel_param *kp)
>  }
>
>  static char quirks_param[128];
> -static const struct kernel_param_ops quirks_param_ops = {
> -       .set = quirks_param_set,
> -       .get = param_get_string,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(quirks_param_ops, quirks_param_set,
> +                              param_get_string);
>
>  static struct kparam_string quirks_param_string = {
>         .maxlen = sizeof(quirks_param),
> @@ -257,10 +253,8 @@ static int io_queue_count_set(const char *val, const struct kernel_param *kp)
>         return param_set_uint(val, kp);
>  }
>
> -static const struct kernel_param_ops io_queue_count_ops = {
> -       .set = io_queue_count_set,
> -       .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(io_queue_count_ops, io_queue_count_set,
> +                              param_get_uint);
>
>  static unsigned int write_queues;
>  module_param_cb(write_queues, &io_queue_count_ops, &write_queues, 0644);
> diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c
> index e6e2c3f9afdf..dc544813300f 100644
> --- a/drivers/nvme/target/rdma.c
> +++ b/drivers/nvme/target/rdma.c
> @@ -147,10 +147,7 @@ module_param_named(use_srq, nvmet_rdma_use_srq, bool, 0444);
>  MODULE_PARM_DESC(use_srq, "Use shared receive queue.");
>
>  static int srq_size_set(const char *val, const struct kernel_param *kp);
> -static const struct kernel_param_ops srq_size_ops = {
> -       .set = srq_size_set,
> -       .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(srq_size_ops, srq_size_set, param_get_int);
>
>  static int nvmet_rdma_srq_size = 1024;
>  module_param_cb(srq_size, &srq_size_ops, &nvmet_rdma_srq_size, 0644);
> diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
> index 164a564ba3b4..2f336cd7e559 100644
> --- a/drivers/nvme/target/tcp.c
> +++ b/drivers/nvme/target/tcp.c
> @@ -46,10 +46,7 @@ static int set_params(const char *str, const struct kernel_param *kp)
>         return param_store_val(str, kp->arg, 0, INT_MAX);
>  }
>
> -static const struct kernel_param_ops set_param_ops = {
> -       .set    = set_params,
> -       .get    = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(set_param_ops, set_params, param_get_int);
>
>  /* Define the socket priority to use for connections were it is desirable
>   * that the NIC consider performing optimized packet processing or filtering.
> diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
> index 5ce5ad3efe69..bd59c3f3f2c5 100644
> --- a/drivers/platform/x86/acerhdf.c
> +++ b/drivers/platform/x86/acerhdf.c
> @@ -762,10 +762,7 @@ static int interval_set_uint(const char *val, const struct kernel_param *kp)
>         return 0;
>  }
>
> -static const struct kernel_param_ops interval_ops = {
> -       .set = interval_set_uint,
> -       .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(interval_ops, interval_set_uint, param_get_uint);
>
>  module_param_cb(interval, &interval_ops, &interval, 0000);
>  MODULE_PARM_DESC(interval, "Polling interval of temperature check");
> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c
> index 45f0e39b8c2d..09829ee1a49d 100644
> --- a/drivers/power/supply/bq27xxx_battery.c
> +++ b/drivers/power/supply/bq27xxx_battery.c
> @@ -1133,10 +1133,8 @@ static int poll_interval_param_set(const char *val, const struct kernel_param *k
>         return ret;
>  }
>
> -static const struct kernel_param_ops param_ops_poll_interval = {
> -       .get = param_get_uint,
> -       .set = poll_interval_param_set,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_poll_interval, poll_interval_param_set,
> +                              param_get_uint);
>
>  static unsigned int poll_interval = 360;
>  module_param_cb(poll_interval, &param_ops_poll_interval, &poll_interval, 0644);
> diff --git a/drivers/power/supply/test_power.c b/drivers/power/supply/test_power.c
> index 2c0e9ad820c0..0bf2bef3383a 100644
> --- a/drivers/power/supply/test_power.c
> +++ b/drivers/power/supply/test_power.c
> @@ -649,60 +649,47 @@ static int param_set_battery_extension(const char *key,
>
>  #define param_get_battery_extension param_get_bool
>
> -static const struct kernel_param_ops param_ops_ac_online = {
> -       .set = param_set_ac_online,
> -       .get = param_get_ac_online,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_ac_online, param_set_ac_online,
> +                              param_get_ac_online);
>
> -static const struct kernel_param_ops param_ops_usb_online = {
> -       .set = param_set_usb_online,
> -       .get = param_get_usb_online,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_usb_online, param_set_usb_online,
> +                              param_get_usb_online);
>
> -static const struct kernel_param_ops param_ops_battery_status = {
> -       .set = param_set_battery_status,
> -       .get = param_get_battery_status,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_battery_status,
> +                              param_set_battery_status,
> +                              param_get_battery_status);
>
> -static const struct kernel_param_ops param_ops_battery_present = {
> -       .set = param_set_battery_present,
> -       .get = param_get_battery_present,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_battery_present,
> +                              param_set_battery_present,
> +                              param_get_battery_present);
>
> -static const struct kernel_param_ops param_ops_battery_technology = {
> -       .set = param_set_battery_technology,
> -       .get = param_get_battery_technology,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_battery_technology,
> +                              param_set_battery_technology,
> +                              param_get_battery_technology);
>
> -static const struct kernel_param_ops param_ops_battery_health = {
> -       .set = param_set_battery_health,
> -       .get = param_get_battery_health,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_battery_health,
> +                              param_set_battery_health,
> +                              param_get_battery_health);
>
> -static const struct kernel_param_ops param_ops_battery_capacity = {
> -       .set = param_set_battery_capacity,
> -       .get = param_get_battery_capacity,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_battery_capacity,
> +                              param_set_battery_capacity,
> +                              param_get_battery_capacity);
>
> -static const struct kernel_param_ops param_ops_battery_voltage = {
> -       .set = param_set_battery_voltage,
> -       .get = param_get_battery_voltage,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_battery_voltage,
> +                              param_set_battery_voltage,
> +                              param_get_battery_voltage);
>
> -static const struct kernel_param_ops param_ops_battery_charge_counter = {
> -       .set = param_set_battery_charge_counter,
> -       .get = param_get_battery_charge_counter,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_battery_charge_counter,
> +                              param_set_battery_charge_counter,
> +                              param_get_battery_charge_counter);
>
> -static const struct kernel_param_ops param_ops_battery_current = {
> -       .set = param_set_battery_current,
> -       .get = param_get_battery_current,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_battery_current,
> +                              param_set_battery_current,
> +                              param_get_battery_current);
>
> -static const struct kernel_param_ops param_ops_battery_extension = {
> -       .set = param_set_battery_extension,
> -       .get = param_get_battery_extension,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_battery_extension,
> +                              param_set_battery_extension,
> +                              param_get_battery_extension);
>
>  #define param_check_ac_online(name, p) __param_check(name, p, void);
>  #define param_check_usb_online(name, p) __param_check(name, p, void);
> diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
> index 2b4b2a1a8e44..c075b567f84e 100644
> --- a/drivers/scsi/sg.c
> +++ b/drivers/scsi/sg.c
> @@ -1644,10 +1644,8 @@ static int def_reserved_size_set(const char *val, const struct kernel_param *kp)
>         return 0;
>  }
>
> -static const struct kernel_param_ops def_reserved_size_ops = {
> -       .set    = def_reserved_size_set,
> -       .get    = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(def_reserved_size_ops, def_reserved_size_set,
> +                              param_get_int);
>
>  module_param_cb(def_reserved_size, &def_reserved_size_ops, &def_reserved_size,
>                    S_IRUGO | S_IWUSR);
> diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
> index edc2afd5f4ee..676a12b44e88 100644
> --- a/drivers/target/target_core_user.c
> +++ b/drivers/target/target_core_user.c
> @@ -255,10 +255,9 @@ static int tcmu_get_global_max_data_area(char *buffer,
>         return sprintf(buffer, "%d\n", TCMU_PAGES_TO_MBS(tcmu_global_max_pages));
>  }
>
> -static const struct kernel_param_ops tcmu_global_max_data_area_op = {
> -       .set = tcmu_set_global_max_data_area,
> -       .get = tcmu_get_global_max_data_area,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(tcmu_global_max_data_area_op,
> +                              tcmu_set_global_max_data_area,
> +                              tcmu_get_global_max_data_area);
>
>  module_param_cb(global_max_data_area_mb, &tcmu_global_max_data_area_op, NULL,
>                 S_IWUSR | S_IRUGO);
> @@ -292,10 +291,8 @@ static int tcmu_set_block_netlink(const char *str,
>         return 0;
>  }
>
> -static const struct kernel_param_ops tcmu_block_netlink_op = {
> -       .set = tcmu_set_block_netlink,
> -       .get = tcmu_get_block_netlink,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(tcmu_block_netlink_op, tcmu_set_block_netlink,
> +                              tcmu_get_block_netlink);
>
>  module_param_cb(block_netlink, &tcmu_block_netlink_op, NULL, S_IWUSR | S_IRUGO);
>  MODULE_PARM_DESC(block_netlink, "Block new netlink commands.");
> diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c
> index 91f291627132..68275c3f2c9b 100644
> --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c
> +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c
> @@ -83,10 +83,8 @@ static int slider_def_balance_get(char *buf, const struct kernel_param *kp)
>         return sysfs_emit(buf, "%02x\n", slider_values[SOC_POWER_SLIDER_BALANCE]);
>  }
>
> -static const struct kernel_param_ops slider_def_balance_ops = {
> -       .set = slider_def_balance_set,
> -       .get = slider_def_balance_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(slider_def_balance_ops, slider_def_balance_set,
> +                              slider_def_balance_get);
>
>  module_param_cb(slider_balance, &slider_def_balance_ops, NULL, 0644);
>  MODULE_PARM_DESC(slider_balance, "Set slider default value for balance");
> @@ -117,10 +115,8 @@ static int slider_def_offset_get(char *buf, const struct kernel_param *kp)
>         return sysfs_emit(buf, "%02x\n", slider_offset);
>  }
>
> -static const struct kernel_param_ops slider_offset_ops = {
> -       .set = slider_def_offset_set,
> -       .get = slider_def_offset_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(slider_offset_ops, slider_def_offset_set,
> +                              slider_def_offset_get);
>
>  /*
>   * To enhance power efficiency dynamically, the firmware can optionally
> diff --git a/drivers/thermal/intel/intel_powerclamp.c b/drivers/thermal/intel/intel_powerclamp.c
> index ccf380da12f2..98fbc6892714 100644
> --- a/drivers/thermal/intel/intel_powerclamp.c
> +++ b/drivers/thermal/intel/intel_powerclamp.c
> @@ -112,10 +112,7 @@ static int duration_get(char *buf, const struct kernel_param *kp)
>         return ret;
>  }
>
> -static const struct kernel_param_ops duration_ops = {
> -       .set = duration_set,
> -       .get = duration_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(duration_ops, duration_set, duration_get);
>
>  module_param_cb(duration, &duration_ops, NULL, 0644);
>  MODULE_PARM_DESC(duration, "forced idle time for each attempt in msec.");
> @@ -203,10 +200,7 @@ static int cpumask_get(char *buf, const struct kernel_param *kp)
>         return cpumap_print_to_pagebuf(false, buf, idle_injection_cpu_mask);
>  }
>
> -static const struct kernel_param_ops cpumask_ops = {
> -       .set = cpumask_set,
> -       .get = cpumask_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(cpumask_ops, cpumask_set, cpumask_get);
>
>  module_param_cb(cpumask, &cpumask_ops, NULL, 0644);
>  MODULE_PARM_DESC(cpumask, "Mask of CPUs to use for idle injection.");
> @@ -252,10 +246,7 @@ static int max_idle_set(const char *arg, const struct kernel_param *kp)
>         return ret;
>  }
>
> -static const struct kernel_param_ops max_idle_ops = {
> -       .set = max_idle_set,
> -       .get = param_get_byte,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(max_idle_ops, max_idle_set, param_get_byte);
>
>  module_param_cb(max_idle, &max_idle_ops, &max_idle, 0644);
>  MODULE_PARM_DESC(max_idle, "maximum injected idle time to the total CPU time ratio in percent range:1-100");
> @@ -299,10 +290,7 @@ static int window_size_set(const char *arg, const struct kernel_param *kp)
>         return ret;
>  }
>
> -static const struct kernel_param_ops window_size_ops = {
> -       .set = window_size_set,
> -       .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(window_size_ops, window_size_set, param_get_int);
>
>  module_param_cb(window_size, &window_size_ops, &window_size, 0644);
>  MODULE_PARM_DESC(window_size, "sliding window in number of clamping cycles\n"
> diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c
> index 37db8a3e5158..29612a4a32cb 100644
> --- a/drivers/tty/hvc/hvc_iucv.c
> +++ b/drivers/tty/hvc/hvc_iucv.c
> @@ -1290,10 +1290,8 @@ static int param_get_vmidfilter(char *buffer, const struct kernel_param *kp)
>
>  #define param_check_vmidfilter(name, p) __param_check(name, p, void)
>
> -static const struct kernel_param_ops param_ops_vmidfilter = {
> -       .set = param_set_vmidfilter,
> -       .get = param_get_vmidfilter,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_vmidfilter, param_set_vmidfilter,
> +                              param_get_vmidfilter);
>
>  /**
>   * hvc_iucv_init() - z/VM IUCV HVC device driver initialization
> diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
> index c2e4b31b699a..c6279c496279 100644
> --- a/drivers/tty/sysrq.c
> +++ b/drivers/tty/sysrq.c
> @@ -1074,10 +1074,8 @@ static int sysrq_reset_seq_param_set(const char *buffer,
>         return 0;
>  }
>
> -static const struct kernel_param_ops param_ops_sysrq_reset_seq = {
> -       .get    = param_get_ushort,
> -       .set    = sysrq_reset_seq_param_set,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_sysrq_reset_seq,
> +                              sysrq_reset_seq_param_set, param_get_ushort);
>
>  #define param_check_sysrq_reset_seq(name, p)   \
>         __param_check(name, p, unsigned short)
> diff --git a/drivers/ufs/core/ufs-fault-injection.c b/drivers/ufs/core/ufs-fault-injection.c
> index 55db38e75cc4..7d2873da7dc5 100644
> --- a/drivers/ufs/core/ufs-fault-injection.c
> +++ b/drivers/ufs/core/ufs-fault-injection.c
> @@ -11,10 +11,7 @@
>  static int ufs_fault_get(char *buffer, const struct kernel_param *kp);
>  static int ufs_fault_set(const char *val, const struct kernel_param *kp);
>
> -static const struct kernel_param_ops ufs_fault_ops = {
> -       .get = ufs_fault_get,
> -       .set = ufs_fault_set,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(ufs_fault_ops, ufs_fault_set, ufs_fault_get);
>
>  enum { FAULT_INJ_STR_SIZE = 80 };
>
> diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c
> index c1b1d67a1ddc..83100aad2a97 100644
> --- a/drivers/ufs/core/ufs-mcq.c
> +++ b/drivers/ufs/core/ufs-mcq.c
> @@ -43,10 +43,8 @@ static int rw_queue_count_set(const char *val, const struct kernel_param *kp)
>                                      num_possible_cpus());
>  }
>
> -static const struct kernel_param_ops rw_queue_count_ops = {
> -       .set = rw_queue_count_set,
> -       .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(rw_queue_count_ops, rw_queue_count_set,
> +                              param_get_uint);
>
>  static unsigned int rw_queues;
>  module_param_cb(rw_queues, &rw_queue_count_ops, &rw_queues, 0644);
> @@ -59,10 +57,8 @@ static int read_queue_count_set(const char *val, const struct kernel_param *kp)
>                                      num_possible_cpus());
>  }
>
> -static const struct kernel_param_ops read_queue_count_ops = {
> -       .set = read_queue_count_set,
> -       .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(read_queue_count_ops, read_queue_count_set,
> +                              param_get_uint);
>
>  static unsigned int read_queues;
>  module_param_cb(read_queues, &read_queue_count_ops, &read_queues, 0644);
> @@ -75,10 +71,8 @@ static int poll_queue_count_set(const char *val, const struct kernel_param *kp)
>                                      num_possible_cpus());
>  }
>
> -static const struct kernel_param_ops poll_queue_count_ops = {
> -       .set = poll_queue_count_set,
> -       .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(poll_queue_count_ops, poll_queue_count_set,
> +                              param_get_uint);
>
>  static unsigned int poll_queues = 1;
>  module_param_cb(poll_queues, &poll_queue_count_ops, &poll_queues, 0644);
> diff --git a/drivers/ufs/core/ufs-txeq.c b/drivers/ufs/core/ufs-txeq.c
> index b2dc89124353..3bdd87b434ad 100644
> --- a/drivers/ufs/core/ufs-txeq.c
> +++ b/drivers/ufs/core/ufs-txeq.c
> @@ -23,10 +23,7 @@ static int txeq_gear_set(const char *val, const struct kernel_param *kp)
>         return param_set_uint_minmax(val, kp, UFS_HS_G1, UFS_HS_GEAR_MAX);
>  }
>
> -static const struct kernel_param_ops txeq_gear_ops = {
> -       .set = txeq_gear_set,
> -       .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(txeq_gear_ops, txeq_gear_set, param_get_uint);
>
>  static unsigned int adaptive_txeq_gear = UFS_HS_G6;
>  module_param_cb(adaptive_txeq_gear, &txeq_gear_ops, &adaptive_txeq_gear, 0644);
> diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
> index 4805e40ed4d7..4e930710d9a6 100644
> --- a/drivers/ufs/core/ufshcd.c
> +++ b/drivers/ufs/core/ufshcd.c
> @@ -128,10 +128,8 @@ static int uic_cmd_timeout_set(const char *val, const struct kernel_param *kp)
>                                      UIC_CMD_TIMEOUT_MAX);
>  }
>
> -static const struct kernel_param_ops uic_cmd_timeout_ops = {
> -       .set = uic_cmd_timeout_set,
> -       .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(uic_cmd_timeout_ops, uic_cmd_timeout_set,
> +                              param_get_uint);
>
>  module_param_cb(uic_cmd_timeout, &uic_cmd_timeout_ops, &uic_cmd_timeout, 0644);
>  MODULE_PARM_DESC(uic_cmd_timeout,
> @@ -145,10 +143,8 @@ static int dev_cmd_timeout_set(const char *val, const struct kernel_param *kp)
>                                      QUERY_REQ_TIMEOUT_MAX);
>  }
>
> -static const struct kernel_param_ops dev_cmd_timeout_ops = {
> -       .set = dev_cmd_timeout_set,
> -       .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(dev_cmd_timeout_ops, dev_cmd_timeout_set,
> +                              param_get_uint);
>
>  module_param_cb(dev_cmd_timeout, &dev_cmd_timeout_ops, &dev_cmd_timeout, 0644);
>  MODULE_PARM_DESC(dev_cmd_timeout,
> diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
> index 0ffdaefba508..d52ecc886925 100644
> --- a/drivers/usb/core/quirks.c
> +++ b/drivers/usb/core/quirks.c
> @@ -160,10 +160,8 @@ static int quirks_param_set(const char *value, const struct kernel_param *kp)
>         return 0;
>  }
>
> -static const struct kernel_param_ops quirks_param_ops = {
> -       .set = quirks_param_set,
> -       .get = param_get_string,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(quirks_param_ops, quirks_param_set,
> +                              param_get_string);
>
>  static struct kparam_string quirks_param_string = {
>         .maxlen = sizeof(quirks_param),
> diff --git a/drivers/usb/gadget/legacy/serial.c b/drivers/usb/gadget/legacy/serial.c
> index 4974bee6049a..e34717e553da 100644
> --- a/drivers/usb/gadget/legacy/serial.c
> +++ b/drivers/usb/gadget/legacy/serial.c
> @@ -121,10 +121,7 @@ static int enable_set(const char *s, const struct kernel_param *kp)
>         return ret;
>  }
>
> -static const struct kernel_param_ops enable_ops = {
> -       .set = enable_set,
> -       .get = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(enable_ops, enable_set, param_get_bool);
>
>  module_param_cb(enable, &enable_ops, &enable, 0644);
>
> diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
> index fa83fe0defe2..71dd623b95c9 100644
> --- a/drivers/usb/storage/usb.c
> +++ b/drivers/usb/storage/usb.c
> @@ -158,10 +158,7 @@ static int delay_use_get(char *s, const struct kernel_param *kp)
>         return format_delay_ms(delay_ms, 3, "ms", s, PAGE_SIZE);
>  }
>
> -static const struct kernel_param_ops delay_use_ops = {
> -       .set = delay_use_set,
> -       .get = delay_use_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(delay_use_ops, delay_use_set, delay_use_get);
>  module_param_cb(delay_use, &delay_use_ops, &delay_use, 0644);
>  MODULE_PARM_DESC(delay_use, "time to delay before using a new device");
>
> diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
> index 9a1253b9d8c5..fd52f2213e27 100644
> --- a/drivers/vhost/scsi.c
> +++ b/drivers/vhost/scsi.c
> @@ -87,10 +87,9 @@ static int vhost_scsi_get_inline_sg_cnt(char *buf,
>         return sprintf(buf, "%u\n", vhost_scsi_inline_sg_cnt);
>  }
>
> -static const struct kernel_param_ops vhost_scsi_inline_sg_cnt_op = {
> -       .get = vhost_scsi_get_inline_sg_cnt,
> -       .set = vhost_scsi_set_inline_sg_cnt,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(vhost_scsi_inline_sg_cnt_op,
> +                              vhost_scsi_set_inline_sg_cnt,
> +                              vhost_scsi_get_inline_sg_cnt);
>
>  module_param_cb(inline_sg_cnt, &vhost_scsi_inline_sg_cnt_op, NULL, 0644);
>  MODULE_PARM_DESC(inline_sg_cnt, "Set the number of scatterlist entries to pre-allocate. The default is 2048.");
> diff --git a/drivers/virt/nitro_enclaves/ne_misc_dev.c b/drivers/virt/nitro_enclaves/ne_misc_dev.c
> index c91300a73f50..218ddd93f960 100644
> --- a/drivers/virt/nitro_enclaves/ne_misc_dev.c
> +++ b/drivers/virt/nitro_enclaves/ne_misc_dev.c
> @@ -86,10 +86,8 @@ struct ne_devs ne_devs = {
>   */
>  static int ne_set_kernel_param(const char *val, const struct kernel_param *kp);
>
> -static const struct kernel_param_ops ne_cpu_pool_ops = {
> -       .get    = param_get_string,
> -       .set    = ne_set_kernel_param,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(ne_cpu_pool_ops, ne_set_kernel_param,
> +                              param_get_string);
>
>  static char ne_cpus[NE_CPUS_SIZE];
>  static struct kparam_string ne_cpus_arg = {
> diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
> index 595c2274fbb5..f6df9c76ee81 100644
> --- a/drivers/virtio/virtio_mmio.c
> +++ b/drivers/virtio/virtio_mmio.c
> @@ -748,10 +748,8 @@ static int vm_cmdline_get(char *buffer, const struct kernel_param *kp)
>         return strlen(buffer) + 1;
>  }
>
> -static const struct kernel_param_ops vm_cmdline_param_ops = {
> -       .set = vm_cmdline_set,
> -       .get = vm_cmdline_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(vm_cmdline_param_ops, vm_cmdline_set,
> +                              vm_cmdline_get);
>
>  device_param_cb(device, &vm_cmdline_param_ops, NULL, S_IRUSR);
>
> diff --git a/fs/ceph/super.c b/fs/ceph/super.c
> index c05fbd4237f8..dec8024b8ac7 100644
> --- a/fs/ceph/super.c
> +++ b/fs/ceph/super.c
> @@ -1684,10 +1684,8 @@ static int param_set_metrics(const char *val, const struct kernel_param *kp)
>         return 0;
>  }
>
> -static const struct kernel_param_ops param_ops_metrics = {
> -       .set = param_set_metrics,
> -       .get = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_metrics, param_set_metrics,
> +                              param_get_bool);
>
>  bool disable_send_metrics = false;
>  module_param_cb(disable_send_metrics, &param_ops_metrics, &disable_send_metrics, 0644);
> @@ -1695,9 +1693,7 @@ MODULE_PARM_DESC(disable_send_metrics, "Enable sending perf metrics to ceph clus
>
>  /* for both v1 and v2 syntax */
>  static bool mount_support = true;
> -static const struct kernel_param_ops param_ops_mount_syntax = {
> -       .get = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_mount_syntax, NULL, param_get_bool);
>  module_param_cb(mount_syntax_v1, &param_ops_mount_syntax, &mount_support, 0444);
>  module_param_cb(mount_syntax_v2, &param_ops_mount_syntax, &mount_support, 0444);
>
> diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
> index b658b6baf72f..cc955c9952d1 100644
> --- a/fs/fuse/dir.c
> +++ b/fs/fuse/dir.c
> @@ -71,10 +71,7 @@ static int inval_wq_set(const char *val, const struct kernel_param *kp)
>
>         return 0;
>  }
> -static const struct kernel_param_ops inval_wq_ops = {
> -       .set = inval_wq_set,
> -       .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(inval_wq_ops, inval_wq_set, param_get_uint);
>  module_param_cb(inval_wq, &inval_wq_ops, &inval_wq, 0644);
>  __MODULE_PARM_TYPE(inval_wq, "uint");
>  MODULE_PARM_DESC(inval_wq,
> diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
> index af9be0c5f516..f2fba60dc5ed 100644
> --- a/fs/nfs/namespace.c
> +++ b/fs/nfs/namespace.c
> @@ -372,10 +372,8 @@ static int param_get_nfs_timeout(char *buffer, const struct kernel_param *kp)
>         return sysfs_emit(buffer, "%li\n", num);
>  }
>
> -static const struct kernel_param_ops param_ops_nfs_timeout = {
> -       .set = param_set_nfs_timeout,
> -       .get = param_get_nfs_timeout,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_nfs_timeout, param_set_nfs_timeout,
> +                              param_get_nfs_timeout);
>  #define param_check_nfs_timeout(name, p) __param_check(name, p, int)
>
>  module_param(nfs_mountpoint_expiry_timeout, nfs_timeout, 0644);
> diff --git a/fs/nfs/super.c b/fs/nfs/super.c
> index 4cd420b14ce3..59d89a18aba6 100644
> --- a/fs/nfs/super.c
> +++ b/fs/nfs/super.c
> @@ -1419,10 +1419,8 @@ static int param_set_portnr(const char *val, const struct kernel_param *kp)
>         *((unsigned int *)kp->arg) = num;
>         return 0;
>  }
> -static const struct kernel_param_ops param_ops_portnr = {
> -       .set = param_set_portnr,
> -       .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_portnr, param_set_portnr,
> +                              param_get_uint);
>  #define param_check_portnr(name, p) __param_check(name, p, unsigned int)
>
>  module_param_named(callback_tcpport, nfs_callback_set_tcpport, portnr, 0644);
> diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
> index 9a77d8b64ffa..e44f8e18f756 100644
> --- a/fs/ubifs/super.c
> +++ b/fs/ubifs/super.c
> @@ -36,10 +36,8 @@ static int ubifs_default_version_set(const char *val, const struct kernel_param
>         return param_set_int(val, kp);
>  }
>
> -static const struct kernel_param_ops ubifs_default_version_ops = {
> -       .set = ubifs_default_version_set,
> -       .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(ubifs_default_version_ops,
> +                              ubifs_default_version_set, param_get_int);
>
>  int ubifs_default_version = UBIFS_FORMAT_VERSION;
>  module_param_cb(default_version, &ubifs_default_version_ops, &ubifs_default_version, 0600);
> diff --git a/kernel/locking/locktorture.c b/kernel/locking/locktorture.c
> index e618bcf75e2d..38ae3b596ef2 100644
> --- a/kernel/locking/locktorture.c
> +++ b/kernel/locking/locktorture.c
> @@ -98,10 +98,8 @@ static bool cpumask_nonempty(cpumask_var_t mask)
>         return cpumask_available(mask) && !cpumask_empty(mask);
>  }
>
> -static const struct kernel_param_ops lt_bind_ops = {
> -       .set = param_set_cpumask,
> -       .get = param_get_cpumask,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(lt_bind_ops, param_set_cpumask,
> +                              param_get_cpumask);
>
>  module_param_cb(bind_readers, &lt_bind_ops, &bind_readers, 0444);
>  module_param_cb(bind_writers, &lt_bind_ops, &bind_writers, 0444);
> diff --git a/kernel/panic.c b/kernel/panic.c
> index 42e5ebde4585..8698374b0d21 100644
> --- a/kernel/panic.c
> +++ b/kernel/panic.c
> @@ -1214,10 +1214,8 @@ static int panic_print_set(const char *val, const struct kernel_param *kp)
>         return  param_set_ulong(val, kp);
>  }
>
> -static const struct kernel_param_ops panic_print_ops = {
> -       .set    = panic_print_set,
> -       .get    = param_get_ulong,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(panic_print_ops, panic_print_set,
> +                              param_get_ulong);
>  __core_param_cb(panic_print, &panic_print_ops, &panic_print, 0644);
>
>  static int __init oops_setup(char *s)
> diff --git a/kernel/params.c b/kernel/params.c
> index 2cbad1f4dd06..e19fff2926bc 100644
> --- a/kernel/params.c
> +++ b/kernel/params.c
> @@ -297,11 +297,8 @@ void param_free_charp(void *arg)
>  }
>  EXPORT_SYMBOL(param_free_charp);
>
> -const struct kernel_param_ops param_ops_charp = {
> -       .set = param_set_charp,
> -       .get = param_get_charp,
> -       .free = param_free_charp,
> -};
> +DEFINE_KERNEL_PARAM_OPS_FREE(param_ops_charp, param_set_charp, param_get_charp,
> +                            param_free_charp);
>  EXPORT_SYMBOL(param_ops_charp);
>
>  /* Actually could be a bool or an int, for historical reasons. */
> @@ -322,11 +319,7 @@ int param_get_bool(char *buffer, const struct kernel_param *kp)
>  }
>  EXPORT_SYMBOL(param_get_bool);
>
> -const struct kernel_param_ops param_ops_bool = {
> -       .flags = KERNEL_PARAM_OPS_FL_NOARG,
> -       .set = param_set_bool,
> -       .get = param_get_bool,
> -};
> +DEFINE_KERNEL_PARAM_OPS_NOARG(param_ops_bool, param_set_bool, param_get_bool);
>  EXPORT_SYMBOL(param_ops_bool);
>
>  int param_set_bool_enable_only(const char *val, const struct kernel_param *kp)
> @@ -353,11 +346,8 @@ int param_set_bool_enable_only(const char *val, const struct kernel_param *kp)
>  }
>  EXPORT_SYMBOL_GPL(param_set_bool_enable_only);
>
> -const struct kernel_param_ops param_ops_bool_enable_only = {
> -       .flags = KERNEL_PARAM_OPS_FL_NOARG,
> -       .set = param_set_bool_enable_only,
> -       .get = param_get_bool,
> -};
> +DEFINE_KERNEL_PARAM_OPS_NOARG(param_ops_bool_enable_only,
> +                             param_set_bool_enable_only, param_get_bool);
>  EXPORT_SYMBOL_GPL(param_ops_bool_enable_only);
>
>  /* This one must be bool. */
> @@ -381,10 +371,7 @@ int param_get_invbool(char *buffer, const struct kernel_param *kp)
>  }
>  EXPORT_SYMBOL(param_get_invbool);
>
> -const struct kernel_param_ops param_ops_invbool = {
> -       .set = param_set_invbool,
> -       .get = param_get_invbool,
> -};
> +DEFINE_KERNEL_PARAM_OPS(param_ops_invbool, param_set_invbool, param_get_invbool);
>  EXPORT_SYMBOL(param_ops_invbool);
>
>  int param_set_bint(const char *val, const struct kernel_param *kp)
> @@ -403,11 +390,7 @@ int param_set_bint(const char *val, const struct kernel_param *kp)
>  }
>  EXPORT_SYMBOL(param_set_bint);
>
> -const struct kernel_param_ops param_ops_bint = {
> -       .flags = KERNEL_PARAM_OPS_FL_NOARG,
> -       .set = param_set_bint,
> -       .get = param_get_int,
> -};
> +DEFINE_KERNEL_PARAM_OPS_NOARG(param_ops_bint, param_set_bint, param_get_int);
>  EXPORT_SYMBOL(param_ops_bint);
>
>  /* We break the rule and mangle the string. */
> @@ -515,11 +498,8 @@ static void param_array_free(void *arg)
>                         arr->ops->free(arr->elem + arr->elemsize * i);
>  }
>
> -const struct kernel_param_ops param_array_ops = {
> -       .set = param_array_set,
> -       .get = param_array_get,
> -       .free = param_array_free,
> -};
> +DEFINE_KERNEL_PARAM_OPS_FREE(param_array_ops, param_array_set, param_array_get,
> +                            param_array_free);
>  EXPORT_SYMBOL(param_array_ops);
>
>  int param_set_copystring(const char *val, const struct kernel_param *kp)
> @@ -544,10 +524,8 @@ int param_get_string(char *buffer, const struct kernel_param *kp)
>  }
>  EXPORT_SYMBOL(param_get_string);
>
> -const struct kernel_param_ops param_ops_string = {
> -       .set = param_set_copystring,
> -       .get = param_get_string,
> -};
> +DEFINE_KERNEL_PARAM_OPS(param_ops_string, param_set_copystring,
> +                       param_get_string);
>  EXPORT_SYMBOL(param_ops_string);
>
>  /* sysfs output in /sys/modules/XYZ/parameters/ */
> diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
> index af8d07bafe02..aba1e4489447 100644
> --- a/kernel/power/hibernate.c
> +++ b/kernel/power/hibernate.c
> @@ -1528,10 +1528,8 @@ static int hibernate_compressor_param_set(const char *compressor,
>         return ret;
>  }
>
> -static const struct kernel_param_ops hibernate_compressor_param_ops = {
> -       .set    = hibernate_compressor_param_set,
> -       .get    = param_get_string,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(hibernate_compressor_param_ops,
> +                              hibernate_compressor_param_set, param_get_string);
>
>  static struct kparam_string hibernate_compressor_param_string = {
>         .maxlen = sizeof(hibernate_compressor),
> diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
> index 55df6d37145e..e675d7f1b4ee 100644
> --- a/kernel/rcu/tree.c
> +++ b/kernel/rcu/tree.c
> @@ -498,15 +498,11 @@ static int param_set_next_fqs_jiffies(const char *val, const struct kernel_param
>         return ret;
>  }
>
> -static const struct kernel_param_ops first_fqs_jiffies_ops = {
> -       .set = param_set_first_fqs_jiffies,
> -       .get = param_get_ulong,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(first_fqs_jiffies_ops,
> +                              param_set_first_fqs_jiffies, param_get_ulong);
>
> -static const struct kernel_param_ops next_fqs_jiffies_ops = {
> -       .set = param_set_next_fqs_jiffies,
> -       .get = param_get_ulong,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(next_fqs_jiffies_ops, param_set_next_fqs_jiffies,
> +                              param_get_ulong);
>
>  module_param_cb(jiffies_till_first_fqs, &first_fqs_jiffies_ops, &jiffies_till_first_fqs, 0644);
>  module_param_cb(jiffies_till_next_fqs, &next_fqs_jiffies_ops, &jiffies_till_next_fqs, 0644);
> @@ -3979,10 +3975,8 @@ static int param_get_do_rcu_barrier(char *buffer, const struct kernel_param *kp)
>         return sprintf(buffer, "%d\n", atomic_read((atomic_t *)kp->arg));
>  }
>
> -static const struct kernel_param_ops do_rcu_barrier_ops = {
> -       .set = param_set_do_rcu_barrier,
> -       .get = param_get_do_rcu_barrier,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(do_rcu_barrier_ops, param_set_do_rcu_barrier,
> +                              param_get_do_rcu_barrier);
>  static atomic_t do_rcu_barrier;
>  module_param_cb(do_rcu_barrier, &do_rcu_barrier_ops, &do_rcu_barrier, 0644);
>
> diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
> index 345aa11b84b2..fcf31e3e4965 100644
> --- a/kernel/sched/ext.c
> +++ b/kernel/sched/ext.c
> @@ -166,20 +166,15 @@ static int set_slice_us(const char *val, const struct kernel_param *kp)
>         return param_set_uint_minmax(val, kp, 100, 100 * USEC_PER_MSEC);
>  }
>
> -static const struct kernel_param_ops slice_us_param_ops = {
> -       .set = set_slice_us,
> -       .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(slice_us_param_ops, set_slice_us, param_get_uint);
>
>  static int set_bypass_lb_intv_us(const char *val, const struct kernel_param *kp)
>  {
>         return param_set_uint_minmax(val, kp, 0, 10 * USEC_PER_SEC);
>  }
>
> -static const struct kernel_param_ops bypass_lb_intv_us_param_ops = {
> -       .set = set_bypass_lb_intv_us,
> -       .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(bypass_lb_intv_us_param_ops,
> +                              set_bypass_lb_intv_us, param_get_uint);
>
>  #undef MODULE_PARAM_PREFIX
>  #define MODULE_PARAM_PREFIX    "sched_ext."
> diff --git a/kernel/workqueue.c b/kernel/workqueue.c
> index 5f747f241a5f..42562b811d94 100644
> --- a/kernel/workqueue.c
> +++ b/kernel/workqueue.c
> @@ -7162,10 +7162,8 @@ static int wq_affn_dfl_get(char *buffer, const struct kernel_param *kp)
>         return scnprintf(buffer, PAGE_SIZE, "%s\n", wq_affn_names[wq_affn_dfl]);
>  }
>
> -static const struct kernel_param_ops wq_affn_dfl_ops = {
> -       .set    = wq_affn_dfl_set,
> -       .get    = wq_affn_dfl_get,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(wq_affn_dfl_ops, wq_affn_dfl_set,
> +                              wq_affn_dfl_get);
>
>  module_param_cb(default_affinity_scope, &wq_affn_dfl_ops, NULL, 0644);
>
> @@ -7861,10 +7859,8 @@ static int wq_watchdog_param_set_thresh(const char *val,
>         return 0;
>  }
>
> -static const struct kernel_param_ops wq_watchdog_thresh_ops = {
> -       .set    = wq_watchdog_param_set_thresh,
> -       .get    = param_get_ulong,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(wq_watchdog_thresh_ops,
> +                              wq_watchdog_param_set_thresh, param_get_ulong);
>
>  module_param_cb(watchdog_thresh, &wq_watchdog_thresh_ops, &wq_watchdog_thresh,
>                 0644);
> diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> index 18a71a9108d3..cf0405ba0dbd 100644
> --- a/lib/dynamic_debug.c
> +++ b/lib/dynamic_debug.c
> @@ -807,10 +807,8 @@ int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
>  }
>  EXPORT_SYMBOL(param_get_dyndbg_classes);
>
> -const struct kernel_param_ops param_ops_dyndbg_classes = {
> -       .set = param_set_dyndbg_classes,
> -       .get = param_get_dyndbg_classes,
> -};
> +DEFINE_KERNEL_PARAM_OPS(param_ops_dyndbg_classes, param_set_dyndbg_classes,
> +                       param_get_dyndbg_classes);
>  EXPORT_SYMBOL(param_ops_dyndbg_classes);
>
>  #define PREFIX_SIZE 128
> diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
> index 77c2a669b6af..30880b6c726a 100644
> --- a/lib/test_dynamic_debug.c
> +++ b/lib/test_dynamic_debug.c
> @@ -23,10 +23,8 @@ static int param_get_do_prints(char *buffer, const struct kernel_param *kp)
>         do_prints();
>         return scnprintf(buffer, PAGE_SIZE, "did do_prints\n");
>  }
> -static const struct kernel_param_ops param_ops_do_prints = {
> -       .set = param_set_do_prints,
> -       .get = param_get_do_prints,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_do_prints, param_set_do_prints,
> +                              param_get_do_prints);
>  module_param_cb(do_prints, &param_ops_do_prints, NULL, 0600);
>
>  /*
> diff --git a/mm/damon/lru_sort.c b/mm/damon/lru_sort.c
> index 8494040b1ee4..5feb93c5262e 100644
> --- a/mm/damon/lru_sort.c
> +++ b/mm/damon/lru_sort.c
> @@ -405,10 +405,8 @@ static int damon_lru_sort_addr_unit_store(const char *val,
>         return 0;
>  }
>
> -static const struct kernel_param_ops addr_unit_param_ops = {
> -       .set = damon_lru_sort_addr_unit_store,
> -       .get = param_get_ulong,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(addr_unit_param_ops,
> +                              damon_lru_sort_addr_unit_store, param_get_ulong);
>
>  module_param_cb(addr_unit, &addr_unit_param_ops, &addr_unit, 0600);
>  MODULE_PARM_DESC(addr_unit,
> @@ -446,10 +444,8 @@ static int damon_lru_sort_enabled_load(char *buffer,
>         return sprintf(buffer, "%c\n", damon_lru_sort_enabled() ? 'Y' : 'N');
>  }
>
> -static const struct kernel_param_ops enabled_param_ops = {
> -       .set = damon_lru_sort_enabled_store,
> -       .get = damon_lru_sort_enabled_load,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(enabled_param_ops, damon_lru_sort_enabled_store,
> +                              damon_lru_sort_enabled_load);
>
>  module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
>  MODULE_PARM_DESC(enabled,
> @@ -478,10 +474,9 @@ static int damon_lru_sort_kdamond_pid_load(char *buffer,
>         return sprintf(buffer, "%d\n", kdamond_pid);
>  }
>
> -static const struct kernel_param_ops kdamond_pid_param_ops = {
> -       .set = damon_lru_sort_kdamond_pid_store,
> -       .get = damon_lru_sort_kdamond_pid_load,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(kdamond_pid_param_ops,
> +                              damon_lru_sort_kdamond_pid_store,
> +                              damon_lru_sort_kdamond_pid_load);
>
>  /*
>   * PID of the DAMON thread
> diff --git a/mm/damon/reclaim.c b/mm/damon/reclaim.c
> index fe7fce26cf6c..27e772b095fa 100644
> --- a/mm/damon/reclaim.c
> +++ b/mm/damon/reclaim.c
> @@ -307,10 +307,8 @@ static int damon_reclaim_addr_unit_store(const char *val,
>         return 0;
>  }
>
> -static const struct kernel_param_ops addr_unit_param_ops = {
> -       .set = damon_reclaim_addr_unit_store,
> -       .get = param_get_ulong,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(addr_unit_param_ops,
> +                              damon_reclaim_addr_unit_store, param_get_ulong);
>
>  module_param_cb(addr_unit, &addr_unit_param_ops, &addr_unit, 0600);
>  MODULE_PARM_DESC(addr_unit,
> @@ -348,10 +346,8 @@ static int damon_reclaim_enabled_load(char *buffer,
>         return sprintf(buffer, "%c\n", damon_reclaim_enabled() ? 'Y' : 'N');
>  }
>
> -static const struct kernel_param_ops enabled_param_ops = {
> -       .set = damon_reclaim_enabled_store,
> -       .get = damon_reclaim_enabled_load,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(enabled_param_ops, damon_reclaim_enabled_store,
> +                              damon_reclaim_enabled_load);
>
>  module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
>  MODULE_PARM_DESC(enabled,
> @@ -380,10 +376,9 @@ static int damon_reclaim_kdamond_pid_load(char *buffer,
>         return sprintf(buffer, "%d\n", kdamond_pid);
>  }
>
> -static const struct kernel_param_ops kdamond_pid_param_ops = {
> -       .set = damon_reclaim_kdamond_pid_store,
> -       .get = damon_reclaim_kdamond_pid_load,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(kdamond_pid_param_ops,
> +                              damon_reclaim_kdamond_pid_store,
> +                              damon_reclaim_kdamond_pid_load);
>
>  /*
>   * PID of the DAMON thread
> diff --git a/mm/damon/stat.c b/mm/damon/stat.c
> index 3951b762cbdd..6eb548793802 100644
> --- a/mm/damon/stat.c
> +++ b/mm/damon/stat.c
> @@ -22,10 +22,8 @@ static int damon_stat_enabled_store(
>  static int damon_stat_enabled_load(char *buffer,
>                 const struct kernel_param *kp);
>
> -static const struct kernel_param_ops enabled_param_ops = {
> -       .set = damon_stat_enabled_store,
> -       .get = damon_stat_enabled_load,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(enabled_param_ops, damon_stat_enabled_store,
> +                              damon_stat_enabled_load);
>
>  static bool enabled __read_mostly = IS_ENABLED(
>         CONFIG_DAMON_STAT_ENABLED_DEFAULT);
> diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
> index 2a943ec57c85..42e0cf313281 100644
> --- a/mm/memory_hotplug.c
> +++ b/mm/memory_hotplug.c
> @@ -109,10 +109,8 @@ static int get_memmap_mode(char *buffer, const struct kernel_param *kp)
>         return sprintf(buffer, "%c\n", mode ? 'Y' : 'N');
>  }
>
> -static const struct kernel_param_ops memmap_mode_ops = {
> -       .set = set_memmap_mode,
> -       .get = get_memmap_mode,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(memmap_mode_ops, set_memmap_mode,
> +                              get_memmap_mode);
>  module_param_cb(memmap_on_memory, &memmap_mode_ops, &memmap_mode, 0444);
>  MODULE_PARM_DESC(memmap_on_memory, "Enable memmap on memory for memory hotplug\n"
>                  "With value \"force\" it could result in memory wastage due "
> @@ -163,10 +161,8 @@ static int get_online_policy(char *buffer, const struct kernel_param *kp)
>   *                 (auto_movable_ratio, auto_movable_numa_aware) allows for it
>   */
>  static int online_policy __read_mostly = ONLINE_POLICY_CONTIG_ZONES;
> -static const struct kernel_param_ops online_policy_ops = {
> -       .set = set_online_policy,
> -       .get = get_online_policy,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(online_policy_ops, set_online_policy,
> +                              get_online_policy);
>  module_param_cb(online_policy, &online_policy_ops, &online_policy, 0644);
>  MODULE_PARM_DESC(online_policy,
>                 "Set the online policy (\"contig-zones\", \"auto-movable\") "
> diff --git a/mm/page_reporting.c b/mm/page_reporting.c
> index 7418f2e500bb..61351e12b4d9 100644
> --- a/mm/page_reporting.c
> +++ b/mm/page_reporting.c
> @@ -23,15 +23,8 @@ static int page_order_update_notify(const char *val, const struct kernel_param *
>         return  param_set_uint_minmax(val, kp, 0, MAX_PAGE_ORDER);
>  }
>
> -static const struct kernel_param_ops page_reporting_param_ops = {
> -       .set = &page_order_update_notify,
> -       /*
> -        * For the get op, use param_get_int instead of param_get_uint.
> -        * This is to make sure that when unset the initialized value of
> -        * -1 is shown correctly
> -        */
> -       .get = &param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(page_reporting_param_ops,
> +                              &page_order_update_notify, &param_get_int);
>
>  module_param_cb(page_reporting_order, &page_reporting_param_ops,
>                         &page_reporting_order, 0644);
> diff --git a/mm/shuffle.c b/mm/shuffle.c
> index fb1393b8b3a9..114fe7467516 100644
> --- a/mm/shuffle.c
> +++ b/mm/shuffle.c
> @@ -23,10 +23,8 @@ static __meminit int shuffle_param_set(const char *val,
>         return 0;
>  }
>
> -static const struct kernel_param_ops shuffle_param_ops = {
> -       .set = shuffle_param_set,
> -       .get = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(shuffle_param_ops, shuffle_param_set,
> +                              param_get_bool);
>  module_param_cb(shuffle, &shuffle_param_ops, &shuffle_param, 0400);
>
>  /*
> diff --git a/mm/zswap.c b/mm/zswap.c
> index 4b5149173b0e..ed3aa07c2f1d 100644
> --- a/mm/zswap.c
> +++ b/mm/zswap.c
> @@ -90,21 +90,17 @@ static DEFINE_STATIC_KEY_MAYBE(CONFIG_ZSWAP_DEFAULT_ON, zswap_ever_enabled);
>  static bool zswap_enabled = IS_ENABLED(CONFIG_ZSWAP_DEFAULT_ON);
>  static int zswap_enabled_param_set(const char *,
>                                    const struct kernel_param *);
> -static const struct kernel_param_ops zswap_enabled_param_ops = {
> -       .set =          zswap_enabled_param_set,
> -       .get =          param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(zswap_enabled_param_ops, zswap_enabled_param_set,
> +                              param_get_bool);
>  module_param_cb(enabled, &zswap_enabled_param_ops, &zswap_enabled, 0644);
>
>  /* Crypto compressor to use */
>  static char *zswap_compressor = CONFIG_ZSWAP_COMPRESSOR_DEFAULT;
>  static int zswap_compressor_param_set(const char *,
>                                       const struct kernel_param *);
> -static const struct kernel_param_ops zswap_compressor_param_ops = {
> -       .set =          zswap_compressor_param_set,
> -       .get =          param_get_charp,
> -       .free =         param_free_charp,
> -};
> +static DEFINE_KERNEL_PARAM_OPS_FREE(zswap_compressor_param_ops,
> +                                   zswap_compressor_param_set, param_get_charp,
> +                                   param_free_charp);
>  module_param_cb(compressor, &zswap_compressor_param_ops,
>                 &zswap_compressor, 0644);
>
> diff --git a/net/batman-adv/bat_algo.c b/net/batman-adv/bat_algo.c
> index 49e5861b58ec..54d66a948298 100644
> --- a/net/batman-adv/bat_algo.c
> +++ b/net/batman-adv/bat_algo.c
> @@ -134,10 +134,8 @@ static int batadv_param_set_ra(const char *val, const struct kernel_param *kp)
>         return param_set_copystring(algo_name, kp);
>  }
>
> -static const struct kernel_param_ops batadv_param_ops_ra = {
> -       .set = batadv_param_set_ra,
> -       .get = param_get_string,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(batadv_param_ops_ra, batadv_param_set_ra,
> +                              param_get_string);
>
>  static struct kparam_string batadv_param_string_ra = {
>         .maxlen = sizeof(batadv_routing_algo),
> diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c
> index 952121849180..633202a99e4a 100644
> --- a/net/ceph/ceph_common.c
> +++ b/net/ceph/ceph_common.c
> @@ -52,9 +52,8 @@ static int param_get_supported_features(char *buffer,
>  {
>         return sprintf(buffer, "0x%llx", CEPH_FEATURES_SUPPORTED_DEFAULT);
>  }
> -static const struct kernel_param_ops param_ops_supported_features = {
> -       .get = param_get_supported_features,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_supported_features, NULL,
> +                              param_get_supported_features);
>  module_param_cb(supported_features, &param_ops_supported_features, NULL,
>                 0444);
>
> diff --git a/net/ipv4/tcp_dctcp.c b/net/ipv4/tcp_dctcp.c
> index 274e628e7cf8..2c9c3d0f3c3d 100644
> --- a/net/ipv4/tcp_dctcp.c
> +++ b/net/ipv4/tcp_dctcp.c
> @@ -64,10 +64,8 @@ static int dctcp_shift_g_set(const char *val, const struct kernel_param *kp)
>         return param_set_uint_minmax(val, kp, 0, 10);
>  }
>
> -static const struct kernel_param_ops dctcp_shift_g_ops = {
> -       .set = dctcp_shift_g_set,
> -       .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(dctcp_shift_g_ops, dctcp_shift_g_set,
> +                              param_get_uint);
>
>  module_param_cb(dctcp_shift_g, &dctcp_shift_g_ops, &dctcp_shift_g, 0644);
>  MODULE_PARM_DESC(dctcp_shift_g, "parameter g for updating dctcp_alpha");
> diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
> index 68c0595ea2fd..64a3e894fd4c 100644
> --- a/net/sunrpc/auth.c
> +++ b/net/sunrpc/auth.c
> @@ -83,10 +83,8 @@ static int param_get_hashtbl_sz(char *buffer, const struct kernel_param *kp)
>
>  #define param_check_hashtbl_sz(name, p) __param_check(name, p, unsigned int);
>
> -static const struct kernel_param_ops param_ops_hashtbl_sz = {
> -       .set = param_set_hashtbl_sz,
> -       .get = param_get_hashtbl_sz,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_hashtbl_sz, param_set_hashtbl_sz,
> +                              param_get_hashtbl_sz);
>
>  module_param_named(auth_hashtable_size, auth_hashbits, hashtbl_sz, 0644);
>  MODULE_PARM_DESC(auth_hashtable_size, "RPC credential cache hashtable size");
> diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
> index 2e1fe6013361..e8d087798994 100644
> --- a/net/sunrpc/xprtsock.c
> +++ b/net/sunrpc/xprtsock.c
> @@ -3710,10 +3710,8 @@ static int param_set_portnr(const char *val, const struct kernel_param *kp)
>                         RPC_MAX_RESVPORT);
>  }
>
> -static const struct kernel_param_ops param_ops_portnr = {
> -       .set = param_set_portnr,
> -       .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_portnr, param_set_portnr,
> +                              param_get_uint);
>
>  #define param_check_portnr(name, p) \
>         __param_check(name, p, unsigned int);
> @@ -3729,10 +3727,8 @@ static int param_set_slot_table_size(const char *val,
>                         RPC_MAX_SLOT_TABLE);
>  }
>
> -static const struct kernel_param_ops param_ops_slot_table_size = {
> -       .set = param_set_slot_table_size,
> -       .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_slot_table_size,
> +                              param_set_slot_table_size, param_get_uint);
>
>  #define param_check_slot_table_size(name, p) \
>         __param_check(name, p, unsigned int);
> @@ -3745,10 +3741,8 @@ static int param_set_max_slot_table_size(const char *val,
>                         RPC_MAX_SLOT_TABLE_LIMIT);
>  }
>
> -static const struct kernel_param_ops param_ops_max_slot_table_size = {
> -       .set = param_set_max_slot_table_size,
> -       .get = param_get_uint,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_max_slot_table_size,
> +                              param_set_max_slot_table_size, param_get_uint);
>
>  #define param_check_max_slot_table_size(name, p) \
>         __param_check(name, p, unsigned int);
> diff --git a/samples/damon/mtier.c b/samples/damon/mtier.c
> index 775838a23d93..c8018a7ea891 100644
> --- a/samples/damon/mtier.c
> +++ b/samples/damon/mtier.c
> @@ -38,10 +38,8 @@ module_param(node0_mem_free_bp, ulong, 0600);
>  static int damon_sample_mtier_enable_store(
>                 const char *val, const struct kernel_param *kp);
>
> -static const struct kernel_param_ops enabled_param_ops = {
> -       .set = damon_sample_mtier_enable_store,
> -       .get = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(enabled_param_ops,
> +                              damon_sample_mtier_enable_store, param_get_bool);
>
>  static bool enabled __read_mostly;
>  module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
> diff --git a/samples/damon/prcl.c b/samples/damon/prcl.c
> index b7c50f2656ce..7cab9bd0f7bd 100644
> --- a/samples/damon/prcl.c
> +++ b/samples/damon/prcl.c
> @@ -22,10 +22,8 @@ module_param(target_pid, int, 0600);
>  static int damon_sample_prcl_enable_store(
>                 const char *val, const struct kernel_param *kp);
>
> -static const struct kernel_param_ops enabled_param_ops = {
> -       .set = damon_sample_prcl_enable_store,
> -       .get = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(enabled_param_ops,
> +                              damon_sample_prcl_enable_store, param_get_bool);
>
>  static bool enabled __read_mostly;
>  module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
> diff --git a/samples/damon/wsse.c b/samples/damon/wsse.c
> index 799ad4443943..56634853bd0b 100644
> --- a/samples/damon/wsse.c
> +++ b/samples/damon/wsse.c
> @@ -23,10 +23,8 @@ module_param(target_pid, int, 0600);
>  static int damon_sample_wsse_enable_store(
>                 const char *val, const struct kernel_param *kp);
>
> -static const struct kernel_param_ops enabled_param_ops = {
> -       .set = damon_sample_wsse_enable_store,
> -       .get = param_get_bool,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(enabled_param_ops,
> +                              damon_sample_wsse_enable_store, param_get_bool);
>
>  static bool enabled __read_mostly;
>  module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
> diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
> index 3491e9f60194..8a253c743363 100644
> --- a/security/apparmor/lsm.c
> +++ b/security/apparmor/lsm.c
> @@ -1767,38 +1767,30 @@ static struct security_hook_list apparmor_hooks[] __ro_after_init = {
>  static int param_set_aabool(const char *val, const struct kernel_param *kp);
>  static int param_get_aabool(char *buffer, const struct kernel_param *kp);
>  #define param_check_aabool param_check_bool
> -static const struct kernel_param_ops param_ops_aabool = {
> -       .flags = KERNEL_PARAM_OPS_FL_NOARG,
> -       .set = param_set_aabool,
> -       .get = param_get_aabool
> -};
> +static DEFINE_KERNEL_PARAM_OPS_NOARG(param_ops_aabool, param_set_aabool,
> +                                    param_get_aabool);
>
>  static int param_set_aauint(const char *val, const struct kernel_param *kp);
>  static int param_get_aauint(char *buffer, const struct kernel_param *kp);
>  #define param_check_aauint param_check_uint
> -static const struct kernel_param_ops param_ops_aauint = {
> -       .set = param_set_aauint,
> -       .get = param_get_aauint
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_aauint, param_set_aauint,
> +                              param_get_aauint);
>
>  static int param_set_aacompressionlevel(const char *val,
>                                         const struct kernel_param *kp);
>  static int param_get_aacompressionlevel(char *buffer,
>                                         const struct kernel_param *kp);
>  #define param_check_aacompressionlevel param_check_int
> -static const struct kernel_param_ops param_ops_aacompressionlevel = {
> -       .set = param_set_aacompressionlevel,
> -       .get = param_get_aacompressionlevel
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_aacompressionlevel,
> +                              param_set_aacompressionlevel,
> +                              param_get_aacompressionlevel);
>
>  static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp);
>  static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp);
>  #define param_check_aalockpolicy param_check_bool
> -static const struct kernel_param_ops param_ops_aalockpolicy = {
> -       .flags = KERNEL_PARAM_OPS_FL_NOARG,
> -       .set = param_set_aalockpolicy,
> -       .get = param_get_aalockpolicy
> -};
> +static DEFINE_KERNEL_PARAM_OPS_NOARG(param_ops_aalockpolicy,
> +                                    param_set_aalockpolicy,
> +                                    param_get_aalockpolicy);
>
>  static int param_set_debug(const char *val, const struct kernel_param *kp);
>  static int param_get_debug(char *buffer, const struct kernel_param *kp);
> @@ -1879,10 +1871,8 @@ module_param_named(paranoid_load, aa_g_paranoid_load, aabool, S_IRUGO);
>  static int param_get_aaintbool(char *buffer, const struct kernel_param *kp);
>  static int param_set_aaintbool(const char *val, const struct kernel_param *kp);
>  #define param_check_aaintbool param_check_int
> -static const struct kernel_param_ops param_ops_aaintbool = {
> -       .set = param_set_aaintbool,
> -       .get = param_get_aaintbool
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_aaintbool, param_set_aaintbool,
> +                              param_get_aaintbool);
>  /* Boot time disable flag */
>  static int apparmor_enabled __ro_after_init = 1;
>  module_param_named(enabled, apparmor_enabled, aaintbool, 0444);
> diff --git a/sound/hda/controllers/intel.c b/sound/hda/controllers/intel.c
> index c87d75dbd8aa..02bd61e67902 100644
> --- a/sound/hda/controllers/intel.c
> +++ b/sound/hda/controllers/intel.c
> @@ -164,10 +164,7 @@ MODULE_PARM_DESC(ctl_dev_id, "Use control device identifier (based on codec addr
>
>  #ifdef CONFIG_PM
>  static int param_set_xint(const char *val, const struct kernel_param *kp);
> -static const struct kernel_param_ops param_ops_xint = {
> -       .set = param_set_xint,
> -       .get = param_get_int,
> -};
> +static DEFINE_KERNEL_PARAM_OPS(param_ops_xint, param_set_xint, param_get_int);
>  #define param_check_xint param_check_int
>
>  static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
> diff --git a/sound/usb/card.c b/sound/usb/card.c
> index f42d72cd0378..34cbb9d72315 100644
> --- a/sound/usb/card.c
> +++ b/sound/usb/card.c
> @@ -118,11 +118,8 @@ static int param_set_quirkp(const char *val,
>         return param_set_charp(val, kp);
>  }
>
> -static const struct kernel_param_ops param_ops_quirkp = {
> -       .set = param_set_quirkp,
> -       .get = param_get_charp,
> -       .free = param_free_charp,
> -};
> +static DEFINE_KERNEL_PARAM_OPS_FREE(param_ops_quirkp, param_set_quirkp,
> +                                   param_get_charp, param_free_charp);
>
>  #define param_check_quirkp param_check_charp
>
> --
> 2.34.1
>


^ permalink raw reply

* Re: [PATCH 09/11] treewide: Convert custom kernel_param_ops .get callbacks to seq_buf via cocci
From: Rafael J. Wysocki @ 2026-05-22 17:03 UTC (permalink / raw)
  To: Kees Cook
  Cc: Luis Chamberlain, Pengpeng Hou, Petr Pavlu, Richard Weinberger,
	Anton Ivanov, Johannes Berg, Rafael J. Wysocki, Len Brown,
	Corey Minyard, Gabriel Somlo, Michael S. Tsirkin, Jani Nikula,
	Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, David Airlie,
	Simona Vetter, Bart Van Assche, Jason Gunthorpe, Leon Romanovsky,
	Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
	Bjorn Helgaas, Hannes Reinecke, James E.J. Bottomley,
	Martin K. Petersen, Daniel Lezcano, Zhang Rui, Lukasz Luba,
	Greg Kroah-Hartman, Jiri Slaby, Alan Stern, Jason Wang, Xuan Zhuo,
	Eugenio Pérez, Jason Baron, Jim Cromie, Tiwei Bie,
	Benjamin Berg, Ilpo Järvinen, David E. Box,
	Maciej W. Rozycki, Srinivas Pandruvada, Peter Zijlstra,
	Heiko Carstens, Vasily Gorbik, Sean Christopherson, Paolo Bonzini,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	H. Peter Anvin, Vinod Koul, Frank Li, Daniel Gomez, Sami Tolvanen,
	Aaron Tomlin, Alexander Potapenko, Marco Elver, Dmitry Vyukov,
	Andrew Morton, John Johansen, Paul Moore, James Morris,
	Serge E. Hallyn, Andy Shevchenko, Georgia Garcia, kvm, dmaengine,
	linux-modules, kasan-dev, linux-mm, apparmor,
	linux-security-module, linux-um, linux-acpi, openipmi-developer,
	qemu-devel, intel-gfx, dri-devel, linux-rdma, linux-media,
	linux-pci, linux-scsi, linux-pm, linuxppc-dev, linux-serial,
	linux-usb, usb-storage, virtualization, linux-kernel, linux-arch,
	netdev, linux-fsdevel, linux-hardening
In-Reply-To: <20260521133326.2465264-9-kees@kernel.org>

On Thu, May 21, 2026 at 3:33 PM Kees Cook <kees@kernel.org> wrote:
>
> Using the following Coccinelle script, convert struct kernel_param_ops
> .get callbacks from "char *" to "struct seq_buf *" when the only write
> to the buffer is via a final call of scnprintf(), snprintf(), sprintf(),
> or sysfs_emit().
>
> Since seq_buf_printf() will return -1 on overflow, and struct
> kernel_param_ops .get callbacks are expected to truncate without error,
> we must ignore the return value from seq_buf_print() and always return 0
> (as the length is calculated in the common dispatcher code).
>
> @@
> identifier FN, BUF, KP;
> expression FMT;
> expression list ARGS;
> @@
>  int FN(
> -               char *BUF
> +               struct seq_buf *BUF
>                 , const struct kernel_param *KP)
>  {
>         ... when any
> (
> -       return scnprintf(BUF, PAGE_SIZE, FMT, ARGS);
> |
> -       return snprintf(BUF, PAGE_SIZE, FMT, ARGS);
> |
> -       return sprintf(BUF, FMT, ARGS);
> |
> -       return sysfs_emit(BUF, FMT, ARGS);
> )
> +       seq_buf_printf(BUF, FMT, ARGS);
> +       return 0;
>  }
>
> No struct kernel_param_ops initializations need changing since
> DEFINE_KERNEL_PARAM_OPS already routes the pointer to .get or .get_str
> via _Generic based on the function signature, so converted callbacks
> are automatically moved from the .get_str to the .get callback.
>
> Signed-off-by: Kees Cook <kees@kernel.org>

For ACPI:

Acked-by: Rafael J. Wysocki (Intel) <rafael@kernel.org>

> ---
>  arch/s390/kernel/perf_cpum_sf.c               |  6 ++-
>  arch/x86/kernel/msr.c                         |  5 +-
>  arch/x86/kvm/vmx/vmx.c                        | 18 ++++---
>  arch/x86/platform/uv/uv_nmi.c                 | 12 +++--
>  drivers/acpi/ec.c                             | 14 ++++--
>  drivers/acpi/sysfs.c                          |  6 ++-
>  drivers/block/ublk_drv.c                      |  5 +-
>  drivers/char/ipmi/ipmi_msghandler.c           |  6 ++-
>  drivers/firmware/qcom/qcom_scm.c              | 12 +++--
>  drivers/gpu/drm/drm_panic.c                   |  7 +--
>  drivers/infiniband/hw/hfi1/driver.c           |  7 +--
>  drivers/infiniband/ulp/srpt/ib_srpt.c         |  5 +-
>  drivers/input/misc/ati_remote2.c              | 10 ++--
>  drivers/input/mouse/psmouse-base.c            |  9 ++--
>  drivers/md/md.c                               |  5 +-
>  drivers/media/pci/tw686x/tw686x-core.c        |  6 ++-
>  drivers/nvme/host/multipath.c                 |  5 +-
>  drivers/power/supply/test_power.c             | 47 +++++++++++--------
>  drivers/target/target_core_user.c             | 12 +++--
>  .../processor_thermal_soc_slider.c            | 12 +++--
>  drivers/ufs/core/ufs-fault-injection.c        |  7 +--
>  drivers/vhost/scsi.c                          |  5 +-
>  fs/nfs/namespace.c                            |  6 ++-
>  fs/ocfs2/dlmfs/dlmfs.c                        |  5 +-
>  fs/overlayfs/copy_up.c                        |  5 +-
>  kernel/locking/locktorture.c                  |  6 ++-
>  kernel/rcu/tree.c                             |  6 ++-
>  kernel/workqueue.c                            |  6 ++-
>  lib/test_dynamic_debug.c                      |  6 ++-
>  mm/damon/lru_sort.c                           | 14 +++---
>  mm/damon/reclaim.c                            | 14 +++---
>  mm/damon/stat.c                               | 10 ++--
>  mm/memory_hotplug.c                           | 18 ++++---
>  net/ceph/ceph_common.c                        |  5 +-
>  net/sunrpc/auth.c                             |  6 ++-
>  net/sunrpc/svc.c                              |  5 +-
>  security/apparmor/lsm.c                       | 16 ++++---
>  37 files changed, 218 insertions(+), 131 deletions(-)
>
> diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c
> index 76119542562b..75b0d441d238 100644
> --- a/arch/s390/kernel/perf_cpum_sf.c
> +++ b/arch/s390/kernel/perf_cpum_sf.c
> @@ -1991,11 +1991,13 @@ static int s390_pmu_sf_offline_cpu(unsigned int cpu)
>         return cpusf_pmu_setup(cpu, PMC_RELEASE);
>  }
>
> -static int param_get_sfb_size(char *buffer, const struct kernel_param *kp)
> +static int param_get_sfb_size(struct seq_buf *buffer,
> +                             const struct kernel_param *kp)
>  {
>         if (!cpum_sf_avail())
>                 return -ENODEV;
> -       return sprintf(buffer, "%lu,%lu", CPUM_SF_MIN_SDB, CPUM_SF_MAX_SDB);
> +       seq_buf_printf(buffer, "%lu,%lu", CPUM_SF_MIN_SDB, CPUM_SF_MAX_SDB);
> +       return 0;
>  }
>
>  static int param_set_sfb_size(const char *val, const struct kernel_param *kp)
> diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c
> index 5f4e1814dc4d..9f07f66c3cfc 100644
> --- a/arch/x86/kernel/msr.c
> +++ b/arch/x86/kernel/msr.c
> @@ -309,7 +309,7 @@ static int set_allow_writes(const char *val, const struct kernel_param *cp)
>         return 0;
>  }
>
> -static int get_allow_writes(char *buf, const struct kernel_param *kp)
> +static int get_allow_writes(struct seq_buf *buf, const struct kernel_param *kp)
>  {
>         const char *res;
>
> @@ -319,7 +319,8 @@ static int get_allow_writes(char *buf, const struct kernel_param *kp)
>         default: res = "default"; break;
>         }
>
> -       return sprintf(buf, "%s\n", res);
> +       seq_buf_printf(buf, "%s\n", res);
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(allow_writes_ops, set_allow_writes,
> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> index 07f4c7209ac0..00317774a90b 100644
> --- a/arch/x86/kvm/vmx/vmx.c
> +++ b/arch/x86/kvm/vmx/vmx.c
> @@ -368,12 +368,16 @@ static int vmentry_l1d_flush_set(const char *s, const struct kernel_param *kp)
>         return ret;
>  }
>
> -static int vmentry_l1d_flush_get(char *s, const struct kernel_param *kp)
> +static int vmentry_l1d_flush_get(struct seq_buf *s,
> +                                const struct kernel_param *kp)
>  {
> -       if (WARN_ON_ONCE(l1tf_vmx_mitigation >= ARRAY_SIZE(vmentry_l1d_param)))
> -               return sysfs_emit(s, "???\n");
> +       if (WARN_ON_ONCE(l1tf_vmx_mitigation >= ARRAY_SIZE(vmentry_l1d_param))) {
> +               seq_buf_printf(s, "???\n");
> +               return 0;
> +       }
>
> -       return sysfs_emit(s, "%s\n", vmentry_l1d_param[l1tf_vmx_mitigation].option);
> +       seq_buf_printf(s, "%s\n", vmentry_l1d_param[l1tf_vmx_mitigation].option);
> +       return 0;
>  }
>
>  /*
> @@ -459,9 +463,11 @@ static int vmentry_l1d_flush_set(const char *s, const struct kernel_param *kp)
>         pr_warn_once("Kernel compiled without mitigations, ignoring vmentry_l1d_flush\n");
>         return 0;
>  }
> -static int vmentry_l1d_flush_get(char *s, const struct kernel_param *kp)
> +static int vmentry_l1d_flush_get(struct seq_buf *s,
> +                                const struct kernel_param *kp)
>  {
> -       return sysfs_emit(s, "never\n");
> +       seq_buf_printf(s, "never\n");
> +       return 0;
>  }
>  #endif
>
> diff --git a/arch/x86/platform/uv/uv_nmi.c b/arch/x86/platform/uv/uv_nmi.c
> index a7ac80b5f8d9..c401369efe22 100644
> --- a/arch/x86/platform/uv/uv_nmi.c
> +++ b/arch/x86/platform/uv/uv_nmi.c
> @@ -111,9 +111,11 @@ module_param_named(dump_loglevel, uv_nmi_loglevel, int, 0644);
>   * The following values show statistics on how perf events are affecting
>   * this system.
>   */
> -static int param_get_local64(char *buffer, const struct kernel_param *kp)
> +static int param_get_local64(struct seq_buf *buffer,
> +                            const struct kernel_param *kp)
>  {
> -       return sprintf(buffer, "%lu\n", local64_read((local64_t *)kp->arg));
> +       seq_buf_printf(buffer, "%lu\n", local64_read((local64_t *)kp->arg));
> +       return 0;
>  }
>
>  static int param_set_local64(const char *val, const struct kernel_param *kp)
> @@ -207,9 +209,11 @@ static const char * const actions_desc[nmi_act_max] = {
>
>  static enum action_t uv_nmi_action = nmi_act_dump;
>
> -static int param_get_action(char *buffer, const struct kernel_param *kp)
> +static int param_get_action(struct seq_buf *buffer,
> +                           const struct kernel_param *kp)
>  {
> -       return sprintf(buffer, "%s\n", actions[uv_nmi_action]);
> +       seq_buf_printf(buffer, "%s\n", actions[uv_nmi_action]);
> +       return 0;
>  }
>
>  static int param_set_action(const char *val, const struct kernel_param *kp)
> diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
> index 45204538ed87..6478e5290faf 100644
> --- a/drivers/acpi/ec.c
> +++ b/drivers/acpi/ec.c
> @@ -2236,18 +2236,22 @@ static int param_set_event_clearing(const char *val,
>         return result;
>  }
>
> -static int param_get_event_clearing(char *buffer,
> +static int param_get_event_clearing(struct seq_buf *buffer,
>                                     const struct kernel_param *kp)
>  {
>         switch (ec_event_clearing) {
>         case ACPI_EC_EVT_TIMING_STATUS:
> -               return sprintf(buffer, "status\n");
> +               seq_buf_printf(buffer, "status\n");
> +               return 0;
>         case ACPI_EC_EVT_TIMING_QUERY:
> -               return sprintf(buffer, "query\n");
> +               seq_buf_printf(buffer, "query\n");
> +               return 0;
>         case ACPI_EC_EVT_TIMING_EVENT:
> -               return sprintf(buffer, "event\n");
> +               seq_buf_printf(buffer, "event\n");
> +               return 0;
>         default:
> -               return sprintf(buffer, "invalid\n");
> +               seq_buf_printf(buffer, "invalid\n");
> +               return 0;
>         }
>         return 0;
>  }
> diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
> index 3d32a5280432..5247ed7e05cc 100644
> --- a/drivers/acpi/sysfs.c
> +++ b/drivers/acpi/sysfs.c
> @@ -192,9 +192,11 @@ static int param_set_trace_method_name(const char *val,
>         return 0;
>  }
>
> -static int param_get_trace_method_name(char *buffer, const struct kernel_param *kp)
> +static int param_get_trace_method_name(struct seq_buf *buffer,
> +                                      const struct kernel_param *kp)
>  {
> -       return sysfs_emit(buffer, "%s\n", acpi_gbl_trace_method_name);
> +       seq_buf_printf(buffer, "%s\n", acpi_gbl_trace_method_name);
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(param_ops_trace_method,
> diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
> index f7bf7ea2d088..ea35662381bf 100644
> --- a/drivers/block/ublk_drv.c
> +++ b/drivers/block/ublk_drv.c
> @@ -5868,10 +5868,11 @@ static int ublk_set_max_unprivileged_ublks(const char *buf,
>         return param_set_uint_minmax(buf, kp, 0, UBLK_MAX_UBLKS);
>  }
>
> -static int ublk_get_max_unprivileged_ublks(char *buf,
> +static int ublk_get_max_unprivileged_ublks(struct seq_buf *buf,
>                                            const struct kernel_param *kp)
>  {
> -       return sysfs_emit(buf, "%u\n", unprivileged_ublks_max);
> +       seq_buf_printf(buf, "%u\n", unprivileged_ublks_max);
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(ublk_max_unprivileged_ublks_ops,
> diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
> index b5fed11707e8..45941605b88f 100644
> --- a/drivers/char/ipmi/ipmi_msghandler.c
> +++ b/drivers/char/ipmi/ipmi_msghandler.c
> @@ -90,7 +90,8 @@ static int panic_op_write_handler(const char *val,
>         return 0;
>  }
>
> -static int panic_op_read_handler(char *buffer, const struct kernel_param *kp)
> +static int panic_op_read_handler(struct seq_buf *buffer,
> +                                const struct kernel_param *kp)
>  {
>         const char *event_str;
>
> @@ -99,7 +100,8 @@ static int panic_op_read_handler(char *buffer, const struct kernel_param *kp)
>         else
>                 event_str = ipmi_panic_event_str[ipmi_send_panic_event];
>
> -       return sprintf(buffer, "%s\n", event_str);
> +       seq_buf_printf(buffer, "%s\n", event_str);
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(panic_op_ops, panic_op_write_handler,
> diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
> index ef57df53e087..1bdb497e354e 100644
> --- a/drivers/firmware/qcom/qcom_scm.c
> +++ b/drivers/firmware/qcom/qcom_scm.c
> @@ -2694,12 +2694,16 @@ static irqreturn_t qcom_scm_irq_handler(int irq, void *data)
>         return IRQ_HANDLED;
>  }
>
> -static int get_download_mode(char *buffer, const struct kernel_param *kp)
> +static int get_download_mode(struct seq_buf *buffer,
> +                            const struct kernel_param *kp)
>  {
> -       if (download_mode >= ARRAY_SIZE(download_mode_name))
> -               return sysfs_emit(buffer, "unknown mode\n");
> +       if (download_mode >= ARRAY_SIZE(download_mode_name)) {
> +               seq_buf_printf(buffer, "unknown mode\n");
> +               return 0;
> +       }
>
> -       return sysfs_emit(buffer, "%s\n", download_mode_name[download_mode]);
> +       seq_buf_printf(buffer, "%s\n", download_mode_name[download_mode]);
> +       return 0;
>  }
>
>  static int set_download_mode(const char *val, const struct kernel_param *kp)
> diff --git a/drivers/gpu/drm/drm_panic.c b/drivers/gpu/drm/drm_panic.c
> index c35d1adf2ce3..8b3b749284f0 100644
> --- a/drivers/gpu/drm/drm_panic.c
> +++ b/drivers/gpu/drm/drm_panic.c
> @@ -841,10 +841,11 @@ static int drm_panic_type_set(const char *val, const struct kernel_param *kp)
>         return -EINVAL;
>  }
>
> -static int drm_panic_type_get(char *buffer, const struct kernel_param *kp)
> +static int drm_panic_type_get(struct seq_buf *buffer,
> +                             const struct kernel_param *kp)
>  {
> -       return scnprintf(buffer, PAGE_SIZE, "%s\n",
> -                        drm_panic_type_map[drm_panic_type]);
> +       seq_buf_printf(buffer, "%s\n", drm_panic_type_map[drm_panic_type]);
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(drm_panic_ops, drm_panic_type_set,
> diff --git a/drivers/infiniband/hw/hfi1/driver.c b/drivers/infiniband/hw/hfi1/driver.c
> index 5b9b0b38b419..3c3f8d4db99d 100644
> --- a/drivers/infiniband/hw/hfi1/driver.c
> +++ b/drivers/infiniband/hw/hfi1/driver.c
> @@ -41,7 +41,7 @@ MODULE_PARM_DESC(cu, "Credit return units");
>
>  unsigned long hfi1_cap_mask = HFI1_CAP_MASK_DEFAULT;
>  static int hfi1_caps_set(const char *val, const struct kernel_param *kp);
> -static int hfi1_caps_get(char *buffer, const struct kernel_param *kp);
> +static int hfi1_caps_get(struct seq_buf *buffer, const struct kernel_param *kp);
>  static DEFINE_KERNEL_PARAM_OPS(cap_ops, hfi1_caps_set, hfi1_caps_get);
>  module_param_cb(cap_mask, &cap_ops, &hfi1_cap_mask, S_IWUSR | S_IRUGO);
>  MODULE_PARM_DESC(cap_mask, "Bit mask of enabled/disabled HW features");
> @@ -101,14 +101,15 @@ static int hfi1_caps_set(const char *val, const struct kernel_param *kp)
>         return ret;
>  }
>
> -static int hfi1_caps_get(char *buffer, const struct kernel_param *kp)
> +static int hfi1_caps_get(struct seq_buf *buffer, const struct kernel_param *kp)
>  {
>         unsigned long cap_mask = *(unsigned long *)kp->arg;
>
>         cap_mask &= ~HFI1_CAP_LOCKED_SMASK;
>         cap_mask |= ((cap_mask & HFI1_CAP_K2U) << HFI1_CAP_USER_SHIFT);
>
> -       return sysfs_emit(buffer, "0x%lx\n", cap_mask);
> +       seq_buf_printf(buffer, "0x%lx\n", cap_mask);
> +       return 0;
>  }
>
>  struct pci_dev *get_pci_dev(struct rvt_dev_info *rdi)
> diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
> index 9aec5d80117f..97c77d52a86a 100644
> --- a/drivers/infiniband/ulp/srpt/ib_srpt.c
> +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
> @@ -86,9 +86,10 @@ static int srpt_set_u64_x(const char *buffer, const struct kernel_param *kp)
>  {
>         return kstrtou64(buffer, 16, (u64 *)kp->arg);
>  }
> -static int srpt_get_u64_x(char *buffer, const struct kernel_param *kp)
> +static int srpt_get_u64_x(struct seq_buf *buffer, const struct kernel_param *kp)
>  {
> -       return sprintf(buffer, "0x%016llx\n", *(u64 *)kp->arg);
> +       seq_buf_printf(buffer, "0x%016llx\n", *(u64 *)kp->arg);
> +       return 0;
>  }
>  module_param_call(srpt_service_guid, srpt_set_u64_x, srpt_get_u64_x,
>                   &srpt_service_guid, 0444);
> diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c
> index 8b4ef7e163d3..d101fe1c2c4c 100644
> --- a/drivers/input/misc/ati_remote2.c
> +++ b/drivers/input/misc/ati_remote2.c
> @@ -63,12 +63,13 @@ static int ati_remote2_set_channel_mask(const char *val,
>         return ati_remote2_set_mask(val, kp, ATI_REMOTE2_MAX_CHANNEL_MASK);
>  }
>
> -static int ati_remote2_get_channel_mask(char *buffer,
> +static int ati_remote2_get_channel_mask(struct seq_buf *buffer,
>                                         const struct kernel_param *kp)
>  {
>         pr_debug("%s()\n", __func__);
>
> -       return sprintf(buffer, "0x%04x\n", *(unsigned int *)kp->arg);
> +       seq_buf_printf(buffer, "0x%04x\n", *(unsigned int *)kp->arg);
> +       return 0;
>  }
>
>  static int ati_remote2_set_mode_mask(const char *val,
> @@ -79,12 +80,13 @@ static int ati_remote2_set_mode_mask(const char *val,
>         return ati_remote2_set_mask(val, kp, ATI_REMOTE2_MAX_MODE_MASK);
>  }
>
> -static int ati_remote2_get_mode_mask(char *buffer,
> +static int ati_remote2_get_mode_mask(struct seq_buf *buffer,
>                                      const struct kernel_param *kp)
>  {
>         pr_debug("%s()\n", __func__);
>
> -       return sprintf(buffer, "0x%02x\n", *(unsigned int *)kp->arg);
> +       seq_buf_printf(buffer, "0x%02x\n", *(unsigned int *)kp->arg);
> +       return 0;
>  }
>
>  static unsigned int channel_mask = ATI_REMOTE2_MAX_CHANNEL_MASK;
> diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
> index f9ebb1fd0b6f..39a9b87e69d1 100644
> --- a/drivers/input/mouse/psmouse-base.c
> +++ b/drivers/input/mouse/psmouse-base.c
> @@ -44,7 +44,8 @@ MODULE_LICENSE("GPL");
>
>  static unsigned int psmouse_max_proto = PSMOUSE_AUTO;
>  static int psmouse_set_maxproto(const char *val, const struct kernel_param *);
> -static int psmouse_get_maxproto(char *buffer, const struct kernel_param *kp);
> +static int psmouse_get_maxproto(struct seq_buf *buffer,
> +                               const struct kernel_param *kp);
>  static DEFINE_KERNEL_PARAM_OPS(param_ops_proto_abbrev, psmouse_set_maxproto,
>                                psmouse_get_maxproto);
>  #define param_check_proto_abbrev(name, p)      __param_check(name, p, unsigned int)
> @@ -1994,11 +1995,13 @@ static int psmouse_set_maxproto(const char *val, const struct kernel_param *kp)
>         return 0;
>  }
>
> -static int psmouse_get_maxproto(char *buffer, const struct kernel_param *kp)
> +static int psmouse_get_maxproto(struct seq_buf *buffer,
> +                               const struct kernel_param *kp)
>  {
>         int type = *((unsigned int *)kp->arg);
>
> -       return sprintf(buffer, "%s\n", psmouse_protocol_by_type(type)->name);
> +       seq_buf_printf(buffer, "%s\n", psmouse_protocol_by_type(type)->name);
> +       return 0;
>  }
>
>  static int __init psmouse_init(void)
> diff --git a/drivers/md/md.c b/drivers/md/md.c
> index 8b568eee8743..ce3eb1396ad0 100644
> --- a/drivers/md/md.c
> +++ b/drivers/md/md.c
> @@ -10989,9 +10989,10 @@ static __exit void md_exit(void)
>  subsys_initcall(md_init);
>  module_exit(md_exit)
>
> -static int get_ro(char *buffer, const struct kernel_param *kp)
> +static int get_ro(struct seq_buf *buffer, const struct kernel_param *kp)
>  {
> -       return sprintf(buffer, "%d\n", start_readonly);
> +       seq_buf_printf(buffer, "%d\n", start_readonly);
> +       return 0;
>  }
>  static int set_ro(const char *val, const struct kernel_param *kp)
>  {
> diff --git a/drivers/media/pci/tw686x/tw686x-core.c b/drivers/media/pci/tw686x/tw686x-core.c
> index a10e38221817..35a6ff8d77fc 100644
> --- a/drivers/media/pci/tw686x/tw686x-core.c
> +++ b/drivers/media/pci/tw686x/tw686x-core.c
> @@ -69,9 +69,11 @@ static const char *dma_mode_name(unsigned int mode)
>         }
>  }
>
> -static int tw686x_dma_mode_get(char *buffer, const struct kernel_param *kp)
> +static int tw686x_dma_mode_get(struct seq_buf *buffer,
> +                              const struct kernel_param *kp)
>  {
> -       return sprintf(buffer, "%s", dma_mode_name(dma_mode));
> +       seq_buf_printf(buffer, "%s", dma_mode_name(dma_mode));
> +       return 0;
>  }
>
>  static int tw686x_dma_mode_set(const char *val, const struct kernel_param *kp)
> diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
> index f7362377e427..e0c87447074d 100644
> --- a/drivers/nvme/host/multipath.c
> +++ b/drivers/nvme/host/multipath.c
> @@ -85,9 +85,10 @@ static int nvme_set_iopolicy(const char *val, const struct kernel_param *kp)
>         return 0;
>  }
>
> -static int nvme_get_iopolicy(char *buf, const struct kernel_param *kp)
> +static int nvme_get_iopolicy(struct seq_buf *buf, const struct kernel_param *kp)
>  {
> -       return sprintf(buf, "%s\n", nvme_iopolicy_names[iopolicy]);
> +       seq_buf_printf(buf, "%s\n", nvme_iopolicy_names[iopolicy]);
> +       return 0;
>  }
>
>  module_param_call(iopolicy, nvme_set_iopolicy, nvme_get_iopolicy,
> diff --git a/drivers/power/supply/test_power.c b/drivers/power/supply/test_power.c
> index 0bf2bef3383a..9dcd588ab5c9 100644
> --- a/drivers/power/supply/test_power.c
> +++ b/drivers/power/supply/test_power.c
> @@ -490,10 +490,12 @@ static int param_set_ac_online(const char *key, const struct kernel_param *kp)
>         return 0;
>  }
>
> -static int param_get_ac_online(char *buffer, const struct kernel_param *kp)
> +static int param_get_ac_online(struct seq_buf *buffer,
> +                              const struct kernel_param *kp)
>  {
> -       return sprintf(buffer, "%s\n",
> -                       map_get_key(map_ac_online, ac_online, "unknown"));
> +       seq_buf_printf(buffer, "%s\n",
> +                      map_get_key(map_ac_online, ac_online, "unknown"));
> +       return 0;
>  }
>
>  static int param_set_usb_online(const char *key, const struct kernel_param *kp)
> @@ -503,10 +505,12 @@ static int param_set_usb_online(const char *key, const struct kernel_param *kp)
>         return 0;
>  }
>
> -static int param_get_usb_online(char *buffer, const struct kernel_param *kp)
> +static int param_get_usb_online(struct seq_buf *buffer,
> +                               const struct kernel_param *kp)
>  {
> -       return sprintf(buffer, "%s\n",
> -                       map_get_key(map_ac_online, usb_online, "unknown"));
> +       seq_buf_printf(buffer, "%s\n",
> +                      map_get_key(map_ac_online, usb_online, "unknown"));
> +       return 0;
>  }
>
>  static int param_set_battery_status(const char *key,
> @@ -517,10 +521,12 @@ static int param_set_battery_status(const char *key,
>         return 0;
>  }
>
> -static int param_get_battery_status(char *buffer, const struct kernel_param *kp)
> +static int param_get_battery_status(struct seq_buf *buffer,
> +                                   const struct kernel_param *kp)
>  {
> -       return sprintf(buffer, "%s\n",
> -                       map_get_key(map_ac_online, battery_status, "unknown"));
> +       seq_buf_printf(buffer, "%s\n",
> +                      map_get_key(map_ac_online, battery_status, "unknown"));
> +       return 0;
>  }
>
>  static int param_set_battery_health(const char *key,
> @@ -531,10 +537,12 @@ static int param_set_battery_health(const char *key,
>         return 0;
>  }
>
> -static int param_get_battery_health(char *buffer, const struct kernel_param *kp)
> +static int param_get_battery_health(struct seq_buf *buffer,
> +                                   const struct kernel_param *kp)
>  {
> -       return sprintf(buffer, "%s\n",
> -                       map_get_key(map_ac_online, battery_health, "unknown"));
> +       seq_buf_printf(buffer, "%s\n",
> +                      map_get_key(map_ac_online, battery_health, "unknown"));
> +       return 0;
>  }
>
>  static int param_set_battery_present(const char *key,
> @@ -545,11 +553,12 @@ static int param_set_battery_present(const char *key,
>         return 0;
>  }
>
> -static int param_get_battery_present(char *buffer,
> +static int param_get_battery_present(struct seq_buf *buffer,
>                                         const struct kernel_param *kp)
>  {
> -       return sprintf(buffer, "%s\n",
> -                       map_get_key(map_ac_online, battery_present, "unknown"));
> +       seq_buf_printf(buffer, "%s\n",
> +                      map_get_key(map_ac_online, battery_present, "unknown"));
> +       return 0;
>  }
>
>  static int param_set_battery_technology(const char *key,
> @@ -561,12 +570,12 @@ static int param_set_battery_technology(const char *key,
>         return 0;
>  }
>
> -static int param_get_battery_technology(char *buffer,
> +static int param_get_battery_technology(struct seq_buf *buffer,
>                                         const struct kernel_param *kp)
>  {
> -       return sprintf(buffer, "%s\n",
> -                       map_get_key(map_ac_online, battery_technology,
> -                                       "unknown"));
> +       seq_buf_printf(buffer, "%s\n",
> +                      map_get_key(map_ac_online, battery_technology, "unknown"));
> +       return 0;
>  }
>
>  static int param_set_battery_capacity(const char *key,
> diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
> index 676a12b44e88..5e8817a63726 100644
> --- a/drivers/target/target_core_user.c
> +++ b/drivers/target/target_core_user.c
> @@ -249,10 +249,11 @@ static int tcmu_set_global_max_data_area(const char *str,
>         return 0;
>  }
>
> -static int tcmu_get_global_max_data_area(char *buffer,
> +static int tcmu_get_global_max_data_area(struct seq_buf *buffer,
>                                          const struct kernel_param *kp)
>  {
> -       return sprintf(buffer, "%d\n", TCMU_PAGES_TO_MBS(tcmu_global_max_pages));
> +       seq_buf_printf(buffer, "%d\n", TCMU_PAGES_TO_MBS(tcmu_global_max_pages));
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(tcmu_global_max_data_area_op,
> @@ -265,11 +266,12 @@ MODULE_PARM_DESC(global_max_data_area_mb,
>                  "Max MBs allowed to be allocated to all the tcmu device's "
>                  "data areas.");
>
> -static int tcmu_get_block_netlink(char *buffer,
> +static int tcmu_get_block_netlink(struct seq_buf *buffer,
>                                   const struct kernel_param *kp)
>  {
> -       return sprintf(buffer, "%s\n", tcmu_netlink_blocked ?
> -                      "blocked" : "unblocked");
> +       seq_buf_printf(buffer, "%s\n",
> +                      tcmu_netlink_blocked ? "blocked" : "unblocked");
> +       return 0;
>  }
>
>  static int tcmu_set_block_netlink(const char *str,
> diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c
> index 68275c3f2c9b..1a68721748d9 100644
> --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c
> +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c
> @@ -77,10 +77,12 @@ static int slider_def_balance_set(const char *arg, const struct kernel_param *kp
>         return ret;
>  }
>
> -static int slider_def_balance_get(char *buf, const struct kernel_param *kp)
> +static int slider_def_balance_get(struct seq_buf *buf,
> +                                 const struct kernel_param *kp)
>  {
>         guard(mutex)(&slider_param_lock);
> -       return sysfs_emit(buf, "%02x\n", slider_values[SOC_POWER_SLIDER_BALANCE]);
> +       seq_buf_printf(buf, "%02x\n", slider_values[SOC_POWER_SLIDER_BALANCE]);
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(slider_def_balance_ops, slider_def_balance_set,
> @@ -109,10 +111,12 @@ static int slider_def_offset_set(const char *arg, const struct kernel_param *kp)
>         return ret;
>  }
>
> -static int slider_def_offset_get(char *buf, const struct kernel_param *kp)
> +static int slider_def_offset_get(struct seq_buf *buf,
> +                                const struct kernel_param *kp)
>  {
>         guard(mutex)(&slider_param_lock);
> -       return sysfs_emit(buf, "%02x\n", slider_offset);
> +       seq_buf_printf(buf, "%02x\n", slider_offset);
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(slider_offset_ops, slider_def_offset_set,
> diff --git a/drivers/ufs/core/ufs-fault-injection.c b/drivers/ufs/core/ufs-fault-injection.c
> index 7d2873da7dc5..88f348b41614 100644
> --- a/drivers/ufs/core/ufs-fault-injection.c
> +++ b/drivers/ufs/core/ufs-fault-injection.c
> @@ -8,7 +8,7 @@
>  #include <ufs/ufshcd.h>
>  #include "ufs-fault-injection.h"
>
> -static int ufs_fault_get(char *buffer, const struct kernel_param *kp);
> +static int ufs_fault_get(struct seq_buf *buffer, const struct kernel_param *kp);
>  static int ufs_fault_set(const char *val, const struct kernel_param *kp);
>
>  static DEFINE_KERNEL_PARAM_OPS(ufs_fault_ops, ufs_fault_set, ufs_fault_get);
> @@ -31,11 +31,12 @@ MODULE_PARM_DESC(timeout,
>         "Fault injection. timeout=<interval>,<probability>,<space>,<times>");
>  static DECLARE_FAULT_ATTR(ufs_timeout_attr);
>
> -static int ufs_fault_get(char *buffer, const struct kernel_param *kp)
> +static int ufs_fault_get(struct seq_buf *buffer, const struct kernel_param *kp)
>  {
>         const char *fault_str = kp->arg;
>
> -       return sysfs_emit(buffer, "%s\n", fault_str);
> +       seq_buf_printf(buffer, "%s\n", fault_str);
> +       return 0;
>  }
>
>  static int ufs_fault_set(const char *val, const struct kernel_param *kp)
> diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
> index fd52f2213e27..23ca63ebf3d2 100644
> --- a/drivers/vhost/scsi.c
> +++ b/drivers/vhost/scsi.c
> @@ -81,10 +81,11 @@ static int vhost_scsi_set_inline_sg_cnt(const char *buf,
>  }
>  #endif
>
> -static int vhost_scsi_get_inline_sg_cnt(char *buf,
> +static int vhost_scsi_get_inline_sg_cnt(struct seq_buf *buf,
>                                         const struct kernel_param *kp)
>  {
> -       return sprintf(buf, "%u\n", vhost_scsi_inline_sg_cnt);
> +       seq_buf_printf(buf, "%u\n", vhost_scsi_inline_sg_cnt);
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(vhost_scsi_inline_sg_cnt_op,
> diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
> index f2fba60dc5ed..5b7debe5274b 100644
> --- a/fs/nfs/namespace.c
> +++ b/fs/nfs/namespace.c
> @@ -358,7 +358,8 @@ static int param_set_nfs_timeout(const char *val, const struct kernel_param *kp)
>         return 0;
>  }
>
> -static int param_get_nfs_timeout(char *buffer, const struct kernel_param *kp)
> +static int param_get_nfs_timeout(struct seq_buf *buffer,
> +                                const struct kernel_param *kp)
>  {
>         long num = *((int *)kp->arg);
>
> @@ -369,7 +370,8 @@ static int param_get_nfs_timeout(char *buffer, const struct kernel_param *kp)
>                         num = (num + (HZ - 1)) / HZ;
>         } else
>                 num = -1;
> -       return sysfs_emit(buffer, "%li\n", num);
> +       seq_buf_printf(buffer, "%li\n", num);
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(param_ops_nfs_timeout, param_set_nfs_timeout,
> diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c
> index 5821e33df78f..8fd759d31ff9 100644
> --- a/fs/ocfs2/dlmfs/dlmfs.c
> +++ b/fs/ocfs2/dlmfs/dlmfs.c
> @@ -78,10 +78,11 @@ static int param_set_dlmfs_capabilities(const char *val,
>         printk(KERN_ERR "%s: readonly parameter\n", kp->name);
>         return -EINVAL;
>  }
> -static int param_get_dlmfs_capabilities(char *buffer,
> +static int param_get_dlmfs_capabilities(struct seq_buf *buffer,
>                                         const struct kernel_param *kp)
>  {
> -       return sysfs_emit(buffer, DLMFS_CAPABILITIES);
> +       seq_buf_printf(buffer, DLMFS_CAPABILITIES);
> +       return 0;
>  }
>  module_param_call(capabilities, param_set_dlmfs_capabilities,
>                   param_get_dlmfs_capabilities, NULL, 0444);
> diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
> index 13cb60b52bd6..d9a21b813b4f 100644
> --- a/fs/overlayfs/copy_up.c
> +++ b/fs/overlayfs/copy_up.c
> @@ -28,9 +28,10 @@ static int ovl_ccup_set(const char *buf, const struct kernel_param *param)
>         return 0;
>  }
>
> -static int ovl_ccup_get(char *buf, const struct kernel_param *param)
> +static int ovl_ccup_get(struct seq_buf *buf, const struct kernel_param *param)
>  {
> -       return sprintf(buf, "N\n");
> +       seq_buf_printf(buf, "N\n");
> +       return 0;
>  }
>
>  module_param_call(check_copy_up, ovl_ccup_set, ovl_ccup_get, NULL, 0644);
> diff --git a/kernel/locking/locktorture.c b/kernel/locking/locktorture.c
> index 38ae3b596ef2..9c9b6dc25888 100644
> --- a/kernel/locking/locktorture.c
> +++ b/kernel/locking/locktorture.c
> @@ -86,11 +86,13 @@ static int param_set_cpumask(const char *val, const struct kernel_param *kp)
>  }
>
>  // Output a cpumask kernel parameter.
> -static int param_get_cpumask(char *buffer, const struct kernel_param *kp)
> +static int param_get_cpumask(struct seq_buf *buffer,
> +                            const struct kernel_param *kp)
>  {
>         cpumask_var_t *cm_bind = kp->arg;
>
> -       return sprintf(buffer, "%*pbl", cpumask_pr_args(*cm_bind));
> +       seq_buf_printf(buffer, "%*pbl", cpumask_pr_args(*cm_bind));
> +       return 0;
>  }
>
>  static bool cpumask_nonempty(cpumask_var_t mask)
> diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
> index e675d7f1b4ee..ffbbb7d4ff2a 100644
> --- a/kernel/rcu/tree.c
> +++ b/kernel/rcu/tree.c
> @@ -3970,9 +3970,11 @@ static int param_set_do_rcu_barrier(const char *val, const struct kernel_param *
>  /*
>   * Output the number of outstanding rcutree.do_rcu_barrier requests.
>   */
> -static int param_get_do_rcu_barrier(char *buffer, const struct kernel_param *kp)
> +static int param_get_do_rcu_barrier(struct seq_buf *buffer,
> +                                   const struct kernel_param *kp)
>  {
> -       return sprintf(buffer, "%d\n", atomic_read((atomic_t *)kp->arg));
> +       seq_buf_printf(buffer, "%d\n", atomic_read((atomic_t *)kp->arg));
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(do_rcu_barrier_ops, param_set_do_rcu_barrier,
> diff --git a/kernel/workqueue.c b/kernel/workqueue.c
> index 42562b811d94..3fe338d2ca64 100644
> --- a/kernel/workqueue.c
> +++ b/kernel/workqueue.c
> @@ -7157,9 +7157,11 @@ static int wq_affn_dfl_set(const char *val, const struct kernel_param *kp)
>         return 0;
>  }
>
> -static int wq_affn_dfl_get(char *buffer, const struct kernel_param *kp)
> +static int wq_affn_dfl_get(struct seq_buf *buffer,
> +                          const struct kernel_param *kp)
>  {
> -       return scnprintf(buffer, PAGE_SIZE, "%s\n", wq_affn_names[wq_affn_dfl]);
> +       seq_buf_printf(buffer, "%s\n", wq_affn_names[wq_affn_dfl]);
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(wq_affn_dfl_ops, wq_affn_dfl_set,
> diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
> index 30880b6c726a..70faf8ede76d 100644
> --- a/lib/test_dynamic_debug.c
> +++ b/lib/test_dynamic_debug.c
> @@ -18,10 +18,12 @@ static int param_set_do_prints(const char *instr, const struct kernel_param *kp)
>         do_prints();
>         return 0;
>  }
> -static int param_get_do_prints(char *buffer, const struct kernel_param *kp)
> +static int param_get_do_prints(struct seq_buf *buffer,
> +                              const struct kernel_param *kp)
>  {
>         do_prints();
> -       return scnprintf(buffer, PAGE_SIZE, "did do_prints\n");
> +       seq_buf_printf(buffer, "did do_prints\n");
> +       return 0;
>  }
>  static DEFINE_KERNEL_PARAM_OPS(param_ops_do_prints, param_set_do_prints,
>                                param_get_do_prints);
> diff --git a/mm/damon/lru_sort.c b/mm/damon/lru_sort.c
> index 5feb93c5262e..84e607f76126 100644
> --- a/mm/damon/lru_sort.c
> +++ b/mm/damon/lru_sort.c
> @@ -438,10 +438,11 @@ static int damon_lru_sort_enabled_store(const char *val,
>         return damon_lru_sort_turn(enabled);
>  }
>
> -static int damon_lru_sort_enabled_load(char *buffer,
> -               const struct kernel_param *kp)
> +static int damon_lru_sort_enabled_load(struct seq_buf *buffer,
> +                                      const struct kernel_param *kp)
>  {
> -       return sprintf(buffer, "%c\n", damon_lru_sort_enabled() ? 'Y' : 'N');
> +       seq_buf_printf(buffer, "%c\n", damon_lru_sort_enabled() ? 'Y' : 'N');
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(enabled_param_ops, damon_lru_sort_enabled_store,
> @@ -461,8 +462,8 @@ static int damon_lru_sort_kdamond_pid_store(const char *val,
>         return 0;
>  }
>
> -static int damon_lru_sort_kdamond_pid_load(char *buffer,
> -               const struct kernel_param *kp)
> +static int damon_lru_sort_kdamond_pid_load(struct seq_buf *buffer,
> +                                          const struct kernel_param *kp)
>  {
>         int kdamond_pid = -1;
>
> @@ -471,7 +472,8 @@ static int damon_lru_sort_kdamond_pid_load(char *buffer,
>                 if (kdamond_pid < 0)
>                         kdamond_pid = -1;
>         }
> -       return sprintf(buffer, "%d\n", kdamond_pid);
> +       seq_buf_printf(buffer, "%d\n", kdamond_pid);
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(kdamond_pid_param_ops,
> diff --git a/mm/damon/reclaim.c b/mm/damon/reclaim.c
> index 27e772b095fa..546bdf356a40 100644
> --- a/mm/damon/reclaim.c
> +++ b/mm/damon/reclaim.c
> @@ -340,10 +340,11 @@ static int damon_reclaim_enabled_store(const char *val,
>         return damon_reclaim_turn(enabled);
>  }
>
> -static int damon_reclaim_enabled_load(char *buffer,
> -               const struct kernel_param *kp)
> +static int damon_reclaim_enabled_load(struct seq_buf *buffer,
> +                                     const struct kernel_param *kp)
>  {
> -       return sprintf(buffer, "%c\n", damon_reclaim_enabled() ? 'Y' : 'N');
> +       seq_buf_printf(buffer, "%c\n", damon_reclaim_enabled() ? 'Y' : 'N');
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(enabled_param_ops, damon_reclaim_enabled_store,
> @@ -363,8 +364,8 @@ static int damon_reclaim_kdamond_pid_store(const char *val,
>         return 0;
>  }
>
> -static int damon_reclaim_kdamond_pid_load(char *buffer,
> -               const struct kernel_param *kp)
> +static int damon_reclaim_kdamond_pid_load(struct seq_buf *buffer,
> +                                         const struct kernel_param *kp)
>  {
>         int kdamond_pid = -1;
>
> @@ -373,7 +374,8 @@ static int damon_reclaim_kdamond_pid_load(char *buffer,
>                 if (kdamond_pid < 0)
>                         kdamond_pid = -1;
>         }
> -       return sprintf(buffer, "%d\n", kdamond_pid);
> +       seq_buf_printf(buffer, "%d\n", kdamond_pid);
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(kdamond_pid_param_ops,
> diff --git a/mm/damon/stat.c b/mm/damon/stat.c
> index 6eb548793802..70d6b477fc0b 100644
> --- a/mm/damon/stat.c
> +++ b/mm/damon/stat.c
> @@ -19,8 +19,8 @@
>  static int damon_stat_enabled_store(
>                 const char *val, const struct kernel_param *kp);
>
> -static int damon_stat_enabled_load(char *buffer,
> -               const struct kernel_param *kp);
> +static int damon_stat_enabled_load(struct seq_buf *buffer,
> +                                  const struct kernel_param *kp);
>
>  static DEFINE_KERNEL_PARAM_OPS(enabled_param_ops, damon_stat_enabled_store,
>                                damon_stat_enabled_load);
> @@ -306,9 +306,11 @@ static int damon_stat_enabled_store(
>         return 0;
>  }
>
> -static int damon_stat_enabled_load(char *buffer, const struct kernel_param *kp)
> +static int damon_stat_enabled_load(struct seq_buf *buffer,
> +                                  const struct kernel_param *kp)
>  {
> -       return sprintf(buffer, "%c\n", damon_stat_enabled() ? 'Y' : 'N');
> +       seq_buf_printf(buffer, "%c\n", damon_stat_enabled() ? 'Y' : 'N');
> +       return 0;
>  }
>
>  static int __init damon_stat_init(void)
> diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
> index 42e0cf313281..887c18a193ac 100644
> --- a/mm/memory_hotplug.c
> +++ b/mm/memory_hotplug.c
> @@ -100,13 +100,17 @@ static int set_memmap_mode(const char *val, const struct kernel_param *kp)
>         return 0;
>  }
>
> -static int get_memmap_mode(char *buffer, const struct kernel_param *kp)
> +static int get_memmap_mode(struct seq_buf *buffer,
> +                          const struct kernel_param *kp)
>  {
>         int mode = *((int *)kp->arg);
>
> -       if (mode == MEMMAP_ON_MEMORY_FORCE)
> -               return sprintf(buffer, "force\n");
> -       return sprintf(buffer, "%c\n", mode ? 'Y' : 'N');
> +       if (mode == MEMMAP_ON_MEMORY_FORCE) {
> +               seq_buf_printf(buffer, "force\n");
> +               return 0;
> +       }
> +       seq_buf_printf(buffer, "%c\n", mode ? 'Y' : 'N');
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(memmap_mode_ops, set_memmap_mode,
> @@ -147,9 +151,11 @@ static int set_online_policy(const char *val, const struct kernel_param *kp)
>         return 0;
>  }
>
> -static int get_online_policy(char *buffer, const struct kernel_param *kp)
> +static int get_online_policy(struct seq_buf *buffer,
> +                            const struct kernel_param *kp)
>  {
> -       return sprintf(buffer, "%s\n", online_policy_to_str[*((int *)kp->arg)]);
> +       seq_buf_printf(buffer, "%s\n", online_policy_to_str[*((int *)kp->arg)]);
> +       return 0;
>  }
>
>  /*
> diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c
> index 633202a99e4a..583b11a2489c 100644
> --- a/net/ceph/ceph_common.c
> +++ b/net/ceph/ceph_common.c
> @@ -47,10 +47,11 @@ bool libceph_compatible(void *data)
>  }
>  EXPORT_SYMBOL(libceph_compatible);
>
> -static int param_get_supported_features(char *buffer,
> +static int param_get_supported_features(struct seq_buf *buffer,
>                                         const struct kernel_param *kp)
>  {
> -       return sprintf(buffer, "0x%llx", CEPH_FEATURES_SUPPORTED_DEFAULT);
> +       seq_buf_printf(buffer, "0x%llx", CEPH_FEATURES_SUPPORTED_DEFAULT);
> +       return 0;
>  }
>  static DEFINE_KERNEL_PARAM_OPS(param_ops_supported_features, NULL,
>                                param_get_supported_features);
> diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
> index 64a3e894fd4c..5a2b64dcf9e5 100644
> --- a/net/sunrpc/auth.c
> +++ b/net/sunrpc/auth.c
> @@ -73,12 +73,14 @@ static int param_set_hashtbl_sz(const char *val, const struct kernel_param *kp)
>         return -EINVAL;
>  }
>
> -static int param_get_hashtbl_sz(char *buffer, const struct kernel_param *kp)
> +static int param_get_hashtbl_sz(struct seq_buf *buffer,
> +                               const struct kernel_param *kp)
>  {
>         unsigned int nbits;
>
>         nbits = *(unsigned int *)kp->arg;
> -       return sprintf(buffer, "%u\n", 1U << nbits);
> +       seq_buf_printf(buffer, "%u\n", 1U << nbits);
> +       return 0;
>  }
>
>  #define param_check_hashtbl_sz(name, p) __param_check(name, p, unsigned int);
> diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
> index 576fa42e7abf..26b85077ecc8 100644
> --- a/net/sunrpc/svc.c
> +++ b/net/sunrpc/svc.c
> @@ -148,7 +148,7 @@ sunrpc_get_pool_mode(char *buf, size_t size)
>  EXPORT_SYMBOL(sunrpc_get_pool_mode);
>
>  static int
> -param_get_pool_mode(char *buf, const struct kernel_param *kp)
> +param_get_pool_mode(struct seq_buf *buf, const struct kernel_param *kp)
>  {
>         char str[16];
>         int len;
> @@ -162,7 +162,8 @@ param_get_pool_mode(char *buf, const struct kernel_param *kp)
>         str[len] = '\n';
>         str[len + 1] = '\0';
>
> -       return sysfs_emit(buf, "%s", str);
> +       seq_buf_printf(buf, "%s", str);
> +       return 0;
>  }
>
>  module_param_call(pool_mode, param_set_pool_mode, param_get_pool_mode,
> diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
> index a6815b4bd0da..748d08c57f60 100644
> --- a/security/apparmor/lsm.c
> +++ b/security/apparmor/lsm.c
> @@ -1797,10 +1797,11 @@ static int param_set_debug(const char *val, const struct kernel_param *kp);
>  static int param_get_debug(struct seq_buf *buffer, const struct kernel_param *kp);
>
>  static int param_set_audit(const char *val, const struct kernel_param *kp);
> -static int param_get_audit(char *buffer, const struct kernel_param *kp);
> +static int param_get_audit(struct seq_buf *buffer,
> +                          const struct kernel_param *kp);
>
>  static int param_set_mode(const char *val, const struct kernel_param *kp);
> -static int param_get_mode(char *buffer, const struct kernel_param *kp);
> +static int param_get_mode(struct seq_buf *buffer, const struct kernel_param *kp);
>
>  /* Flag values, also controllable via /sys/module/apparmor/parameters
>   * We define special types as we want to do additional mediation.
> @@ -2050,13 +2051,15 @@ static int param_set_debug(const char *val, const struct kernel_param *kp)
>         return 0;
>  }
>
> -static int param_get_audit(char *buffer, const struct kernel_param *kp)
> +static int param_get_audit(struct seq_buf *buffer,
> +                          const struct kernel_param *kp)
>  {
>         if (!apparmor_enabled)
>                 return -EINVAL;
>         if (apparmor_initialized && !aa_current_policy_view_capable(NULL))
>                 return -EPERM;
> -       return sysfs_emit(buffer, "%s\n", audit_mode_names[aa_g_audit]);
> +       seq_buf_printf(buffer, "%s\n", audit_mode_names[aa_g_audit]);
> +       return 0;
>  }
>
>  static int param_set_audit(const char *val, const struct kernel_param *kp)
> @@ -2078,13 +2081,14 @@ static int param_set_audit(const char *val, const struct kernel_param *kp)
>         return 0;
>  }
>
> -static int param_get_mode(char *buffer, const struct kernel_param *kp)
> +static int param_get_mode(struct seq_buf *buffer, const struct kernel_param *kp)
>  {
>         if (!apparmor_enabled)
>                 return -EINVAL;
>         if (apparmor_initialized && !aa_current_policy_view_capable(NULL))
>                 return -EPERM;
> -       return sysfs_emit(buffer, "%s\n", aa_profile_mode_names[aa_g_profile_mode]);
> +       seq_buf_printf(buffer, "%s\n", aa_profile_mode_names[aa_g_profile_mode]);
> +       return 0;
>  }
>
>  static int param_set_mode(const char *val, const struct kernel_param *kp)
> --
> 2.34.1
>


^ permalink raw reply

* Re: [PATCH 10/11] treewide: Manually convert custom kernel_param_ops .get callbacks
From: Rafael J. Wysocki @ 2026-05-22 17:05 UTC (permalink / raw)
  To: Kees Cook
  Cc: Luis Chamberlain, Pengpeng Hou, Petr Pavlu, Richard Weinberger,
	Anton Ivanov, Johannes Berg, Rafael J. Wysocki, Len Brown,
	Corey Minyard, Gabriel Somlo, Michael S. Tsirkin, Jani Nikula,
	Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, David Airlie,
	Simona Vetter, Bart Van Assche, Jason Gunthorpe, Leon Romanovsky,
	Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
	Bjorn Helgaas, Hannes Reinecke, James E.J. Bottomley,
	Martin K. Petersen, Daniel Lezcano, Zhang Rui, Lukasz Luba,
	Greg Kroah-Hartman, Jiri Slaby, Alan Stern, Jason Wang, Xuan Zhuo,
	Eugenio Pérez, Jason Baron, Jim Cromie, Tiwei Bie,
	Benjamin Berg, Ilpo Järvinen, David E. Box,
	Maciej W. Rozycki, Srinivas Pandruvada, Peter Zijlstra,
	Heiko Carstens, Vasily Gorbik, Sean Christopherson, Paolo Bonzini,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	H. Peter Anvin, Vinod Koul, Frank Li, Daniel Gomez, Sami Tolvanen,
	Aaron Tomlin, Alexander Potapenko, Marco Elver, Dmitry Vyukov,
	Andrew Morton, John Johansen, Paul Moore, James Morris,
	Serge E. Hallyn, Andy Shevchenko, Georgia Garcia, kvm, dmaengine,
	linux-modules, kasan-dev, linux-mm, apparmor,
	linux-security-module, linux-um, linux-acpi, openipmi-developer,
	qemu-devel, intel-gfx, dri-devel, linux-rdma, linux-media,
	linux-pci, linux-scsi, linux-pm, linuxppc-dev, linux-serial,
	linux-usb, usb-storage, virtualization, linux-kernel, linux-arch,
	netdev, linux-fsdevel, linux-hardening
In-Reply-To: <20260521133326.2465264-10-kees@kernel.org>

On Thu, May 21, 2026 at 3:33 PM Kees Cook <kees@kernel.org> wrote:
>
> Convert struct kernel_param_ops .get callbacks from legacy "char *" to
> "struct seq_buf *".
>
> Since seq_buf_printf() will return -1 on overflow, and struct
> kernel_param_ops .get callbacks are expected to truncate without error,
> we must ignore the return value from seq_buf_print() and always return 0
> (as the length is calculated in the common dispatcher code).
>
> No struct kernel_param_ops initializations need changing since
> DEFINE_KERNEL_PARAM_OPS already routes the pointer to .get or .get_str
> via _Generic based on the function signature, so converted callbacks
> are automatically moved from the .get_str to the .get callback.
>
> Signed-off-by: Kees Cook <kees@kernel.org>

For ACPI:

Acked-by: Rafael J. Wysocki (Intel) <rafael@kernel.org>

> ---
>  include/linux/dynamic_debug.h            |  8 ++-
>  arch/um/drivers/vfio_kern.c              |  3 +-
>  arch/um/drivers/virtio_uml.c             | 12 ++--
>  drivers/acpi/button.c                    | 19 ++++--
>  drivers/acpi/sysfs.c                     | 83 +++++++++++-------------
>  drivers/char/ipmi/ipmi_watchdog.c        | 33 ++++------
>  drivers/firmware/qemu_fw_cfg.c           | 34 +++++-----
>  drivers/gpu/drm/i915/i915_mitigations.c  | 26 ++++----
>  drivers/infiniband/ulp/srp/ib_srp.c      |  7 +-
>  drivers/media/usb/uvc/uvc_driver.c       |  8 ++-
>  drivers/pci/pcie/aspm.c                  | 17 +++--
>  drivers/scsi/fcoe/fcoe_transport.c       | 22 +++----
>  drivers/thermal/intel/intel_powerclamp.c | 14 ++--
>  drivers/tty/hvc/hvc_iucv.c               | 18 ++---
>  drivers/usb/storage/usb.c                | 20 +++---
>  drivers/virtio/virtio_mmio.c             | 21 +++---
>  lib/dynamic_debug.c                      | 10 ++-
>  17 files changed, 178 insertions(+), 177 deletions(-)
>
> diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
> index 05743900a116..999a25671b6a 100644
> --- a/include/linux/dynamic_debug.h
> +++ b/include/linux/dynamic_debug.h
> @@ -334,8 +334,10 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
>  extern int ddebug_dyndbg_module_param_cb(char *param, char *val,
>                                         const char *modname);
>  struct kernel_param;
> +struct seq_buf;
>  int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp);
> -int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp);
> +int param_get_dyndbg_classes(struct seq_buf *buffer,
> +                            const struct kernel_param *kp);
>
>  #else
>
> @@ -352,9 +354,11 @@ static inline int ddebug_dyndbg_module_param_cb(char *param, char *val,
>  }
>
>  struct kernel_param;
> +struct seq_buf;
>  static inline int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
>  { return 0; }
> -static inline int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
> +static inline int param_get_dyndbg_classes(struct seq_buf *buffer,
> +                                          const struct kernel_param *kp)
>  { return 0; }
>
>  #endif
> diff --git a/arch/um/drivers/vfio_kern.c b/arch/um/drivers/vfio_kern.c
> index fb7988dc5482..7c1119d0d9c1 100644
> --- a/arch/um/drivers/vfio_kern.c
> +++ b/arch/um/drivers/vfio_kern.c
> @@ -623,7 +623,8 @@ static int uml_vfio_cmdline_set(const char *device, const struct kernel_param *k
>         return 0;
>  }
>
> -static int uml_vfio_cmdline_get(char *buffer, const struct kernel_param *kp)
> +static int uml_vfio_cmdline_get(struct seq_buf *buffer,
> +                               const struct kernel_param *kp)
>  {
>         return 0;
>  }
> diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c
> index f9ae745f4586..cea806540625 100644
> --- a/arch/um/drivers/virtio_uml.c
> +++ b/arch/um/drivers/virtio_uml.c
> @@ -1379,23 +1379,21 @@ static int vu_cmdline_get_device(struct device *dev, void *data)
>  {
>         struct platform_device *pdev = to_platform_device(dev);
>         struct virtio_uml_platform_data *pdata = pdev->dev.platform_data;
> -       char *buffer = data;
> -       unsigned int len = strlen(buffer);
> +       struct seq_buf *s = data;
>
> -       snprintf(buffer + len, PAGE_SIZE - len, "%s:%d:%d\n",
> -                pdata->socket_path, pdata->virtio_device_id, pdev->id);
> +       seq_buf_printf(s, "%s:%d:%d\n",
> +                      pdata->socket_path, pdata->virtio_device_id, pdev->id);
>         return 0;
>  }
>
> -static int vu_cmdline_get(char *buffer, const struct kernel_param *kp)
> +static int vu_cmdline_get(struct seq_buf *buffer, const struct kernel_param *kp)
>  {
>         guard(mutex)(&vu_cmdline_lock);
>
> -       buffer[0] = '\0';
>         if (vu_cmdline_parent_registered)
>                 device_for_each_child(&vu_cmdline_parent, buffer,
>                                       vu_cmdline_get_device);
> -       return strlen(buffer) + 1;
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(vu_cmdline_param_ops, vu_cmdline_set,
> diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
> index dc064a388c23..31c624bebc65 100644
> --- a/drivers/acpi/button.c
> +++ b/drivers/acpi/button.c
> @@ -715,19 +715,24 @@ static int param_set_lid_init_state(const char *val,
>         return 0;
>  }
>
> -static int param_get_lid_init_state(char *buf, const struct kernel_param *kp)
> +static int param_get_lid_init_state(struct seq_buf *buf,
> +                                   const struct kernel_param *kp)
>  {
> -       int i, c = 0;
> +       int i;
>
> -       for (i = 0; i < ARRAY_SIZE(lid_init_state_str); i++)
> +       for (i = 0; i < ARRAY_SIZE(lid_init_state_str); i++) {
>                 if (i == lid_init_state)
> -                       c += sprintf(buf + c, "[%s] ", lid_init_state_str[i]);
> +                       seq_buf_printf(buf, "[%s] ", lid_init_state_str[i]);
>                 else
> -                       c += sprintf(buf + c, "%s ", lid_init_state_str[i]);
> +                       seq_buf_printf(buf, "%s ", lid_init_state_str[i]);
> +       }
>
> -       buf[c - 1] = '\n'; /* Replace the final space with a newline */
> +       /* Replace the final space with a newline. */
> +       if (!seq_buf_has_overflowed(buf) && buf->len > 0 &&
> +           buf->buffer[buf->len - 1] == ' ')
> +               buf->buffer[buf->len - 1] = '\n';
>
> -       return c;
> +       return 0;
>  }
>
>  module_param_call(lid_init_state,
> diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
> index 5247ed7e05cc..dff7cc7da8bf 100644
> --- a/drivers/acpi/sysfs.c
> +++ b/drivers/acpi/sysfs.c
> @@ -89,53 +89,49 @@ static const struct acpi_dlevel acpi_debug_levels[] = {
>         ACPI_DEBUG_INIT(ACPI_LV_EVENTS),
>  };
>
> -static int param_get_debug_layer(char *buffer, const struct kernel_param *kp)
> +static int param_get_debug_layer(struct seq_buf *buffer,
> +                                const struct kernel_param *kp)
>  {
> -       int result = 0;
>         int i;
>
> -       result = sprintf(buffer, "%-25s\tHex        SET\n", "Description");
> +       seq_buf_printf(buffer, "%-25s\tHex        SET\n", "Description");
>
>         for (i = 0; i < ARRAY_SIZE(acpi_debug_layers); i++) {
> -               result += sprintf(buffer + result, "%-25s\t0x%08lX [%c]\n",
> -                                 acpi_debug_layers[i].name,
> -                                 acpi_debug_layers[i].value,
> -                                 (acpi_dbg_layer & acpi_debug_layers[i].value)
> -                                 ? '*' : ' ');
> +               seq_buf_printf(buffer, "%-25s\t0x%08lX [%c]\n",
> +                              acpi_debug_layers[i].name,
> +                              acpi_debug_layers[i].value,
> +                              (acpi_dbg_layer & acpi_debug_layers[i].value)
> +                              ? '*' : ' ');
>         }
> -       result +=
> -           sprintf(buffer + result, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS",
> -                   ACPI_ALL_DRIVERS,
> -                   (acpi_dbg_layer & ACPI_ALL_DRIVERS) ==
> -                   ACPI_ALL_DRIVERS ? '*' : (acpi_dbg_layer & ACPI_ALL_DRIVERS)
> -                   == 0 ? ' ' : '-');
> -       result +=
> -           sprintf(buffer + result,
> -                   "--\ndebug_layer = 0x%08X ( * = enabled)\n",
> -                   acpi_dbg_layer);
> +       seq_buf_printf(buffer, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS",
> +                      ACPI_ALL_DRIVERS,
> +                      (acpi_dbg_layer & ACPI_ALL_DRIVERS) == ACPI_ALL_DRIVERS
> +                      ? '*' : (acpi_dbg_layer & ACPI_ALL_DRIVERS) == 0
> +                      ? ' ' : '-');
> +       seq_buf_printf(buffer, "--\ndebug_layer = 0x%08X ( * = enabled)\n",
> +                      acpi_dbg_layer);
>
> -       return result;
> +       return 0;
>  }
>
> -static int param_get_debug_level(char *buffer, const struct kernel_param *kp)
> +static int param_get_debug_level(struct seq_buf *buffer,
> +                                const struct kernel_param *kp)
>  {
> -       int result = 0;
>         int i;
>
> -       result = sprintf(buffer, "%-25s\tHex        SET\n", "Description");
> +       seq_buf_printf(buffer, "%-25s\tHex        SET\n", "Description");
>
>         for (i = 0; i < ARRAY_SIZE(acpi_debug_levels); i++) {
> -               result += sprintf(buffer + result, "%-25s\t0x%08lX [%c]\n",
> -                                 acpi_debug_levels[i].name,
> -                                 acpi_debug_levels[i].value,
> -                                 (acpi_dbg_level & acpi_debug_levels[i].value)
> -                                 ? '*' : ' ');
> +               seq_buf_printf(buffer, "%-25s\t0x%08lX [%c]\n",
> +                              acpi_debug_levels[i].name,
> +                              acpi_debug_levels[i].value,
> +                              (acpi_dbg_level & acpi_debug_levels[i].value)
> +                              ? '*' : ' ');
>         }
> -       result +=
> -           sprintf(buffer + result, "--\ndebug_level = 0x%08X (* = enabled)\n",
> -                   acpi_dbg_level);
> +       seq_buf_printf(buffer, "--\ndebug_level = 0x%08X (* = enabled)\n",
> +                      acpi_dbg_level);
>
> -       return result;
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(param_ops_debug_layer, param_set_uint,
> @@ -247,16 +243,18 @@ static int param_set_trace_state(const char *val,
>         return 0;
>  }
>
> -static int param_get_trace_state(char *buffer, const struct kernel_param *kp)
> +static int param_get_trace_state(struct seq_buf *buffer,
> +                                const struct kernel_param *kp)
>  {
>         if (!(acpi_gbl_trace_flags & ACPI_TRACE_ENABLED))
> -               return sprintf(buffer, "disable\n");
> -       if (!acpi_gbl_trace_method_name)
> -               return sprintf(buffer, "enable\n");
> -       if (acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT)
> -               return sprintf(buffer, "method-once\n");
> +               seq_buf_printf(buffer, "disable\n");
> +       else if (!acpi_gbl_trace_method_name)
> +               seq_buf_printf(buffer, "enable\n");
> +       else if (acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT)
> +               seq_buf_printf(buffer, "method-once\n");
>         else
> -               return sprintf(buffer, "method\n");
> +               seq_buf_printf(buffer, "method\n");
> +       return 0;
>  }
>
>  module_param_call(trace_state, param_set_trace_state, param_get_trace_state,
> @@ -272,14 +270,11 @@ MODULE_PARM_DESC(aml_debug_output,
>                  "To enable/disable the ACPI Debug Object output.");
>
>  /* /sys/module/acpi/parameters/acpica_version */
> -static int param_get_acpica_version(char *buffer,
> +static int param_get_acpica_version(struct seq_buf *buffer,
>                                     const struct kernel_param *kp)
>  {
> -       int result;
> -
> -       result = sprintf(buffer, "%x\n", ACPI_CA_VERSION);
> -
> -       return result;
> +       seq_buf_printf(buffer, "%x\n", ACPI_CA_VERSION);
> +       return 0;
>  }
>
>  module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
> diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
> index 91a99417d204..2bfec85ef331 100644
> --- a/drivers/char/ipmi/ipmi_watchdog.c
> +++ b/drivers/char/ipmi/ipmi_watchdog.c
> @@ -197,11 +197,11 @@ static DEFINE_KERNEL_PARAM_OPS(param_ops_timeout, set_param_timeout,
>                                param_get_int);
>  #define param_check_timeout param_check_int
>
> -typedef int (*action_fn)(const char *intval, char *outval);
> +typedef int (*action_fn)(const char *intval, struct seq_buf *outval);
>
> -static int action_op(const char *inval, char *outval);
> -static int preaction_op(const char *inval, char *outval);
> -static int preop_op(const char *inval, char *outval);
> +static int action_op(const char *inval, struct seq_buf *outval);
> +static int preaction_op(const char *inval, struct seq_buf *outval);
> +static int preop_op(const char *inval, struct seq_buf *outval);
>  static void check_parms(void);
>
>  static int set_param_str(const char *val, const struct kernel_param *kp)
> @@ -227,20 +227,11 @@ static int set_param_str(const char *val, const struct kernel_param *kp)
>         return rv;
>  }
>
> -static int get_param_str(char *buffer, const struct kernel_param *kp)
> +static int get_param_str(struct seq_buf *buffer, const struct kernel_param *kp)
>  {
>         action_fn fn = (action_fn) kp->arg;
> -       int rv, len;
>
> -       rv = fn(NULL, buffer);
> -       if (rv)
> -               return rv;
> -
> -       len = strlen(buffer);
> -       buffer[len++] = '\n';
> -       buffer[len] = 0;
> -
> -       return len;
> +       return fn(NULL, buffer);
>  }
>
>
> @@ -1154,12 +1145,12 @@ static int action_op_set_val(const char *inval)
>         return 0;
>  }
>
> -static int action_op(const char *inval, char *outval)
> +static int action_op(const char *inval, struct seq_buf *outval)
>  {
>         int rv;
>
>         if (outval)
> -               strcpy(outval, action);
> +               seq_buf_printf(outval, "%s\n", action);
>
>         if (!inval)
>                 return 0;
> @@ -1186,12 +1177,12 @@ static int preaction_op_set_val(const char *inval)
>         return 0;
>  }
>
> -static int preaction_op(const char *inval, char *outval)
> +static int preaction_op(const char *inval, struct seq_buf *outval)
>  {
>         int rv;
>
>         if (outval)
> -               strcpy(outval, preaction);
> +               seq_buf_printf(outval, "%s\n", preaction);
>
>         if (!inval)
>                 return 0;
> @@ -1214,12 +1205,12 @@ static int preop_op_set_val(const char *inval)
>         return 0;
>  }
>
> -static int preop_op(const char *inval, char *outval)
> +static int preop_op(const char *inval, struct seq_buf *outval)
>  {
>         int rv;
>
>         if (outval)
> -               strcpy(outval, preop);
> +               seq_buf_printf(outval, "%s\n", preop);
>
>         if (!inval)
>                 return 0;
> diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
> index c87a5449ba8c..4ebc1e327849 100644
> --- a/drivers/firmware/qemu_fw_cfg.c
> +++ b/drivers/firmware/qemu_fw_cfg.c
> @@ -860,7 +860,8 @@ static int fw_cfg_cmdline_set(const char *arg, const struct kernel_param *kp)
>         return PTR_ERR_OR_ZERO(fw_cfg_cmdline_dev);
>  }
>
> -static int fw_cfg_cmdline_get(char *buf, const struct kernel_param *kp)
> +static int fw_cfg_cmdline_get(struct seq_buf *buf,
> +                             const struct kernel_param *kp)
>  {
>         /* stay silent if device was not configured via the command
>          * line, or if the parameter name (ioport/mmio) doesn't match
> @@ -873,22 +874,25 @@ static int fw_cfg_cmdline_get(char *buf, const struct kernel_param *kp)
>
>         switch (fw_cfg_cmdline_dev->num_resources) {
>         case 1:
> -               return snprintf(buf, PAGE_SIZE, PH_ADDR_PR_1_FMT,
> -                               resource_size(&fw_cfg_cmdline_dev->resource[0]),
> -                               fw_cfg_cmdline_dev->resource[0].start);
> +               seq_buf_printf(buf, PH_ADDR_PR_1_FMT,
> +                              resource_size(&fw_cfg_cmdline_dev->resource[0]),
> +                              fw_cfg_cmdline_dev->resource[0].start);
> +               return 0;
>         case 3:
> -               return snprintf(buf, PAGE_SIZE, PH_ADDR_PR_3_FMT,
> -                               resource_size(&fw_cfg_cmdline_dev->resource[0]),
> -                               fw_cfg_cmdline_dev->resource[0].start,
> -                               fw_cfg_cmdline_dev->resource[1].start,
> -                               fw_cfg_cmdline_dev->resource[2].start);
> +               seq_buf_printf(buf, PH_ADDR_PR_3_FMT,
> +                              resource_size(&fw_cfg_cmdline_dev->resource[0]),
> +                              fw_cfg_cmdline_dev->resource[0].start,
> +                              fw_cfg_cmdline_dev->resource[1].start,
> +                              fw_cfg_cmdline_dev->resource[2].start);
> +               return 0;
>         case 4:
> -               return snprintf(buf, PAGE_SIZE, PH_ADDR_PR_4_FMT,
> -                               resource_size(&fw_cfg_cmdline_dev->resource[0]),
> -                               fw_cfg_cmdline_dev->resource[0].start,
> -                               fw_cfg_cmdline_dev->resource[1].start,
> -                               fw_cfg_cmdline_dev->resource[2].start,
> -                               fw_cfg_cmdline_dev->resource[3].start);
> +               seq_buf_printf(buf, PH_ADDR_PR_4_FMT,
> +                              resource_size(&fw_cfg_cmdline_dev->resource[0]),
> +                              fw_cfg_cmdline_dev->resource[0].start,
> +                              fw_cfg_cmdline_dev->resource[1].start,
> +                              fw_cfg_cmdline_dev->resource[2].start,
> +                              fw_cfg_cmdline_dev->resource[3].start);
> +               return 0;
>         }
>
>         /* Should never get here */
> diff --git a/drivers/gpu/drm/i915/i915_mitigations.c b/drivers/gpu/drm/i915/i915_mitigations.c
> index 6061eae84e9c..99cb38f355b6 100644
> --- a/drivers/gpu/drm/i915/i915_mitigations.c
> +++ b/drivers/gpu/drm/i915/i915_mitigations.c
> @@ -95,33 +95,37 @@ static int mitigations_set(const char *val, const struct kernel_param *kp)
>         return 0;
>  }
>
> -static int mitigations_get(char *buffer, const struct kernel_param *kp)
> +static int mitigations_get(struct seq_buf *buffer,
> +                          const struct kernel_param *kp)
>  {
>         unsigned long local = READ_ONCE(mitigations);
> -       int count, i;
>         bool enable;
> +       int i;
>
> -       if (!local)
> -               return scnprintf(buffer, PAGE_SIZE, "%s\n", "off");
> +       if (!local) {
> +               seq_buf_printf(buffer, "%s\n", "off");
> +               return 0;
> +       }
>
>         if (local & BIT(BITS_PER_LONG - 1)) {
> -               count = scnprintf(buffer, PAGE_SIZE, "%s,", "auto");
> +               seq_buf_printf(buffer, "%s,", "auto");
>                 enable = false;
>         } else {
>                 enable = true;
> -               count = 0;
>         }
>
>         for (i = 0; i < ARRAY_SIZE(names); i++) {
>                 if ((local & BIT(i)) != enable)
>                         continue;
> -
> -               count += scnprintf(buffer + count, PAGE_SIZE - count,
> -                                  "%s%s,", enable ? "" : "!", names[i]);
> +               seq_buf_printf(buffer, "%s%s,", enable ? "" : "!", names[i]);
>         }
>
> -       buffer[count - 1] = '\n';
> -       return count;
> +       /* Replace the trailing comma with a newline. */
> +       if (!seq_buf_has_overflowed(buffer) && buffer->len > 0 &&
> +           buffer->buffer[buffer->len - 1] == ',')
> +               buffer->buffer[buffer->len - 1] = '\n';
> +
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(ops, mitigations_set, mitigations_get);
> diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
> index a81515f52a4f..4f53e939eec1 100644
> --- a/drivers/infiniband/ulp/srp/ib_srp.c
> +++ b/drivers/infiniband/ulp/srp/ib_srp.c
> @@ -161,14 +161,15 @@ static struct ib_client srp_client = {
>
>  static struct ib_sa_client srp_sa_client;
>
> -static int srp_tmo_get(char *buffer, const struct kernel_param *kp)
> +static int srp_tmo_get(struct seq_buf *buffer, const struct kernel_param *kp)
>  {
>         int tmo = *(int *)kp->arg;
>
>         if (tmo >= 0)
> -               return sysfs_emit(buffer, "%d\n", tmo);
> +               seq_buf_printf(buffer, "%d\n", tmo);
>         else
> -               return sysfs_emit(buffer, "off\n");
> +               seq_buf_printf(buffer, "off\n");
> +       return 0;
>  }
>
>  static int srp_tmo_set(const char *val, const struct kernel_param *kp)
> diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
> index 2338cab7fef9..1c5c40ce852d 100644
> --- a/drivers/media/usb/uvc/uvc_driver.c
> +++ b/drivers/media/usb/uvc/uvc_driver.c
> @@ -2451,12 +2451,14 @@ static int uvc_reset_resume(struct usb_interface *intf)
>   * Module parameters
>   */
>
> -static int uvc_clock_param_get(char *buffer, const struct kernel_param *kp)
> +static int uvc_clock_param_get(struct seq_buf *buffer,
> +                              const struct kernel_param *kp)
>  {
>         if (uvc_clock_param == CLOCK_MONOTONIC)
> -               return sprintf(buffer, "CLOCK_MONOTONIC");
> +               seq_buf_printf(buffer, "CLOCK_MONOTONIC");
>         else
> -               return sprintf(buffer, "CLOCK_REALTIME");
> +               seq_buf_printf(buffer, "CLOCK_REALTIME");
> +       return 0;
>  }
>
>  static int uvc_clock_param_set(const char *val, const struct kernel_param *kp)
> diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
> index 925373b98dff..af2dd668fe4d 100644
> --- a/drivers/pci/pcie/aspm.c
> +++ b/drivers/pci/pcie/aspm.c
> @@ -1572,16 +1572,19 @@ static int pcie_aspm_set_policy(const char *val,
>         return 0;
>  }
>
> -static int pcie_aspm_get_policy(char *buffer, const struct kernel_param *kp)
> +static int pcie_aspm_get_policy(struct seq_buf *buffer,
> +                               const struct kernel_param *kp)
>  {
> -       int i, cnt = 0;
> -       for (i = 0; i < ARRAY_SIZE(policy_str); i++)
> +       int i;
> +
> +       for (i = 0; i < ARRAY_SIZE(policy_str); i++) {
>                 if (i == aspm_policy)
> -                       cnt += sprintf(buffer + cnt, "[%s] ", policy_str[i]);
> +                       seq_buf_printf(buffer, "[%s] ", policy_str[i]);
>                 else
> -                       cnt += sprintf(buffer + cnt, "%s ", policy_str[i]);
> -       cnt += sprintf(buffer + cnt, "\n");
> -       return cnt;
> +                       seq_buf_printf(buffer, "%s ", policy_str[i]);
> +       }
> +       seq_buf_putc(buffer, '\n');
> +       return 0;
>  }
>
>  module_param_call(policy, pcie_aspm_set_policy, pcie_aspm_get_policy,
> diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c
> index 88d85fc9a52a..aa10514ec46e 100644
> --- a/drivers/scsi/fcoe/fcoe_transport.c
> +++ b/drivers/scsi/fcoe/fcoe_transport.c
> @@ -23,7 +23,8 @@ MODULE_LICENSE("GPL v2");
>
>  static int fcoe_transport_create(const char *, const struct kernel_param *);
>  static int fcoe_transport_destroy(const char *, const struct kernel_param *);
> -static int fcoe_transport_show(char *buffer, const struct kernel_param *kp);
> +static int fcoe_transport_show(struct seq_buf *buffer,
> +                              const struct kernel_param *kp);
>  static struct fcoe_transport *fcoe_transport_lookup(struct net_device *device);
>  static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *device);
>  static int fcoe_transport_enable(const char *, const struct kernel_param *);
> @@ -595,22 +596,21 @@ int fcoe_transport_detach(struct fcoe_transport *ft)
>  }
>  EXPORT_SYMBOL(fcoe_transport_detach);
>
> -static int fcoe_transport_show(char *buffer, const struct kernel_param *kp)
> +static int fcoe_transport_show(struct seq_buf *buffer,
> +                              const struct kernel_param *kp)
>  {
> -       int i, j;
>         struct fcoe_transport *ft = NULL;
>
> -       i = j = sprintf(buffer, "Attached FCoE transports:");
> +       seq_buf_printf(buffer, "Attached FCoE transports:");
>         mutex_lock(&ft_mutex);
> -       list_for_each_entry(ft, &fcoe_transports, list) {
> -               if (i >= PAGE_SIZE - IFNAMSIZ)
> -                       break;
> -               i += snprintf(&buffer[i], IFNAMSIZ, "%s ", ft->name);
> +       if (list_empty(&fcoe_transports)) {
> +               seq_buf_printf(buffer, "none");
> +       } else {
> +               list_for_each_entry(ft, &fcoe_transports, list)
> +                       seq_buf_printf(buffer, "%s ", ft->name);
>         }
>         mutex_unlock(&ft_mutex);
> -       if (i == j)
> -               i += snprintf(&buffer[i], IFNAMSIZ, "none");
> -       return i;
> +       return 0;
>  }
>
>  static int __init fcoe_transport_init(void)
> diff --git a/drivers/thermal/intel/intel_powerclamp.c b/drivers/thermal/intel/intel_powerclamp.c
> index 98fbc6892714..50ec1a0ff1ab 100644
> --- a/drivers/thermal/intel/intel_powerclamp.c
> +++ b/drivers/thermal/intel/intel_powerclamp.c
> @@ -101,15 +101,13 @@ static int duration_set(const char *arg, const struct kernel_param *kp)
>         return ret;
>  }
>
> -static int duration_get(char *buf, const struct kernel_param *kp)
> +static int duration_get(struct seq_buf *buf, const struct kernel_param *kp)
>  {
> -       int ret;
> -
>         mutex_lock(&powerclamp_lock);
> -       ret = sysfs_emit(buf, "%d\n", duration / 1000);
> +       seq_buf_printf(buf, "%d\n", duration / 1000);
>         mutex_unlock(&powerclamp_lock);
>
> -       return ret;
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(duration_ops, duration_set, duration_get);
> @@ -192,12 +190,14 @@ static int cpumask_set(const char *arg, const struct kernel_param *kp)
>         return ret;
>  }
>
> -static int cpumask_get(char *buf, const struct kernel_param *kp)
> +static int cpumask_get(struct seq_buf *buf, const struct kernel_param *kp)
>  {
>         if (!cpumask_available(idle_injection_cpu_mask))
>                 return -ENODEV;
>
> -       return cpumap_print_to_pagebuf(false, buf, idle_injection_cpu_mask);
> +       seq_buf_printf(buf, "%*pb\n", nr_cpu_ids,
> +                      cpumask_bits(idle_injection_cpu_mask));
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(cpumask_ops, cpumask_set, cpumask_get);
> diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c
> index 29612a4a32cb..b27c1dfbd249 100644
> --- a/drivers/tty/hvc/hvc_iucv.c
> +++ b/drivers/tty/hvc/hvc_iucv.c
> @@ -1256,36 +1256,32 @@ static int param_set_vmidfilter(const char *val, const struct kernel_param *kp)
>
>  /**
>   * param_get_vmidfilter() - Get z/VM user ID filter
> - * @buffer:    Buffer to store z/VM user ID filter,
> - *             (buffer size assumption PAGE_SIZE)
> + * @buffer:    seq_buf to store z/VM user ID filter
>   * @kp:                Kernel parameter pointing to the hvc_iucv_filter array
>   *
>   * The function stores the filter as a comma-separated list of z/VM user IDs
>   * in @buffer. Typically, sysfs routines call this function for attr show.
>   */
> -static int param_get_vmidfilter(char *buffer, const struct kernel_param *kp)
> +static int param_get_vmidfilter(struct seq_buf *buffer,
> +                               const struct kernel_param *kp)
>  {
> -       int rc;
>         size_t index, len;
>         void *start, *end;
>
>         if (!machine_is_vm() || !hvc_iucv_devices)
>                 return -ENODEV;
>
> -       rc = 0;
>         read_lock_bh(&hvc_iucv_filter_lock);
>         for (index = 0; index < hvc_iucv_filter_size; index++) {
>                 start = hvc_iucv_filter + (8 * index);
>                 end   = memchr(start, ' ', 8);
>                 len   = (end) ? end - start : 8;
> -               memcpy(buffer + rc, start, len);
> -               rc += len;
> -               buffer[rc++] = ',';
> +               if (index)
> +                       seq_buf_putc(buffer, ',');
> +               seq_buf_printf(buffer, "%.*s", (int)len, (char *)start);
>         }
>         read_unlock_bh(&hvc_iucv_filter_lock);
> -       if (rc)
> -               buffer[--rc] = '\0';    /* replace last comma and update rc */
> -       return rc;
> +       return 0;
>  }
>
>  #define param_check_vmidfilter(name, p) __param_check(name, p, void)
> diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
> index 71dd623b95c9..637e1b8f622f 100644
> --- a/drivers/usb/storage/usb.c
> +++ b/drivers/usb/storage/usb.c
> @@ -115,27 +115,22 @@ static int parse_delay_str(const char *str, int ndecimals, const char *suffix,
>   * @val: The integer value to format, scaled by 10^(@ndecimals).
>   * @ndecimals: Number of decimal to scale down.
>   * @suffix: Suffix string to format.
> - * @str: Where to store the formatted string.
> - * @size: The size of buffer for @str.
> + * @s: Where to store the formatted string.
>   *
>   * Format an integer value in @val scale down by 10^(@ndecimals) without @suffix
>   * if @val is divisible by 10^(@ndecimals).
>   * Otherwise format a value in @val just as it is with @suffix
> - *
> - * Returns the number of characters written into @str.
>   */
> -static int format_delay_ms(unsigned int val, int ndecimals, const char *suffix,
> -                       char *str, int size)
> +static void format_delay_ms(unsigned int val, int ndecimals, const char *suffix,
> +                           struct seq_buf *s)
>  {
>         u64 delay_ms = val;
>         unsigned int rem = do_div(delay_ms, int_pow(10, ndecimals));
> -       int ret;
>
>         if (rem)
> -               ret = scnprintf(str, size, "%u%s\n", val, suffix);
> +               seq_buf_printf(s, "%u%s\n", val, suffix);
>         else
> -               ret = scnprintf(str, size, "%u\n", (unsigned int)delay_ms);
> -       return ret;
> +               seq_buf_printf(s, "%u\n", (unsigned int)delay_ms);
>  }
>
>  static int delay_use_set(const char *s, const struct kernel_param *kp)
> @@ -151,11 +146,12 @@ static int delay_use_set(const char *s, const struct kernel_param *kp)
>         return 0;
>  }
>
> -static int delay_use_get(char *s, const struct kernel_param *kp)
> +static int delay_use_get(struct seq_buf *s, const struct kernel_param *kp)
>  {
>         unsigned int delay_ms = *((unsigned int *)kp->arg);
>
> -       return format_delay_ms(delay_ms, 3, "ms", s, PAGE_SIZE);
> +       format_delay_ms(delay_ms, 3, "ms", s);
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(delay_use_ops, delay_use_set, delay_use_get);
> diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
> index f6df9c76ee81..81a7455e4643 100644
> --- a/drivers/virtio/virtio_mmio.c
> +++ b/drivers/virtio/virtio_mmio.c
> @@ -728,24 +728,21 @@ static int vm_cmdline_set(const char *device,
>
>  static int vm_cmdline_get_device(struct device *dev, void *data)
>  {
> -       char *buffer = data;
> -       unsigned int len = strlen(buffer);
> +       struct seq_buf *s = data;
>         struct platform_device *pdev = to_platform_device(dev);
>
> -       snprintf(buffer + len, PAGE_SIZE - len, "0x%llx@0x%llx:%llu:%d\n",
> -                       pdev->resource[0].end - pdev->resource[0].start + 1ULL,
> -                       (unsigned long long)pdev->resource[0].start,
> -                       (unsigned long long)pdev->resource[1].start,
> -                       pdev->id);
> +       seq_buf_printf(s, "0x%llx@0x%llx:%llu:%d\n",
> +                      pdev->resource[0].end - pdev->resource[0].start + 1ULL,
> +                      (unsigned long long)pdev->resource[0].start,
> +                      (unsigned long long)pdev->resource[1].start,
> +                      pdev->id);
>         return 0;
>  }
>
> -static int vm_cmdline_get(char *buffer, const struct kernel_param *kp)
> +static int vm_cmdline_get(struct seq_buf *s, const struct kernel_param *kp)
>  {
> -       buffer[0] = '\0';
> -       device_for_each_child(&vm_cmdline_parent, buffer,
> -                       vm_cmdline_get_device);
> -       return strlen(buffer) + 1;
> +       device_for_each_child(&vm_cmdline_parent, s, vm_cmdline_get_device);
> +       return 0;
>  }
>
>  static DEFINE_KERNEL_PARAM_OPS(vm_cmdline_param_ops, vm_cmdline_set,
> diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> index cf0405ba0dbd..123f061c2fb2 100644
> --- a/lib/dynamic_debug.c
> +++ b/lib/dynamic_debug.c
> @@ -17,6 +17,7 @@
>  #include <linux/module.h>
>  #include <linux/moduleparam.h>
>  #include <linux/kallsyms.h>
> +#include <linux/seq_buf.h>
>  #include <linux/types.h>
>  #include <linux/mutex.h>
>  #include <linux/proc_fs.h>
> @@ -787,7 +788,8 @@ EXPORT_SYMBOL(param_set_dyndbg_classes);
>   * altered by direct >control.  Displays 0x for DISJOINT, 0-N for
>   * LEVEL Returns: #chars written or <0 on error
>   */
> -int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
> +int param_get_dyndbg_classes(struct seq_buf *buffer,
> +                            const struct kernel_param *kp)
>  {
>         const struct ddebug_class_param *dcp = kp->arg;
>         const struct ddebug_class_map *map = dcp->map;
> @@ -796,11 +798,13 @@ int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
>
>         case DD_CLASS_TYPE_DISJOINT_NAMES:
>         case DD_CLASS_TYPE_DISJOINT_BITS:
> -               return scnprintf(buffer, PAGE_SIZE, "0x%lx\n", *dcp->bits);
> +               seq_buf_printf(buffer, "0x%lx\n", *dcp->bits);
> +               return 0;
>
>         case DD_CLASS_TYPE_LEVEL_NAMES:
>         case DD_CLASS_TYPE_LEVEL_NUM:
> -               return scnprintf(buffer, PAGE_SIZE, "%d\n", *dcp->lvl);
> +               seq_buf_printf(buffer, "%d\n", *dcp->lvl);
> +               return 0;
>         default:
>                 return -1;
>         }
> --
> 2.34.1
>


^ permalink raw reply

* Re: [PATCH v5 02/20] [DO NOT MERGE] s390: Expose protected virtualization through cc_platform_has()
From: JAEHOON KIM @ 2026-05-22 15:35 UTC (permalink / raw)
  To: Aneesh Kumar K.V (Arm), iommu, linux-arm-kernel, linux-kernel,
	linux-coco
  Cc: Robin Murphy, Marek Szyprowski, Will Deacon, Marc Zyngier,
	Steven Price, Suzuki K Poulose, Catalin Marinas, Jiri Pirko,
	Jason Gunthorpe, Mostafa Saleh, Petr Tesarik,
	Alexey Kardashevskiy, Dan Williams, Xu Yilun, linuxppc-dev,
	linux-s390, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Alexander Gordeev,
	Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
	Christian Borntraeger, Sven Schnelle, x86, Halil Pasic,
	Matthew Rosato
In-Reply-To: <20260522042815.370873-3-aneesh.kumar@kernel.org>

On 5/21/2026 11:27 PM, Aneesh Kumar K.V (Arm) wrote:
> Protected virtualization guests use memory encryption, so advertise that to
> the rest of the kernel through cc_platform_has(CC_ATTR_MEM_ENCRYPT).
>
> s390 already forces DMA mappings to be unencrypted for protected
> virtualization guests through force_dma_unencrypted(). Add
> ARCH_HAS_CC_PLATFORM and provide the matching cc_platform_has()
> implementation
>
> Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
> ---
> Cc: Halil Pasic <pasic@linux.ibm.com>
> Cc: Matthew Rosato <mjrosato@linux.ibm.com>
> Cc: Jaehoon  Kim <jhkim@linux.ibm.com>
> ---
>   arch/s390/Kconfig   |  1 +
>   arch/s390/mm/init.c | 14 ++++++++++++++
>   2 files changed, 15 insertions(+)
>
> diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
> index ecbcbb781e40..9b5e6029e043 100644
> --- a/arch/s390/Kconfig
> +++ b/arch/s390/Kconfig
> @@ -87,6 +87,7 @@ config S390
>   	select ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS > 2
>   	select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE
>   	select ARCH_HAS_CC_CAN_LINK
> +	select ARCH_HAS_CC_PLATFORM
>   	select ARCH_HAS_CPU_FINALIZE_INIT
>   	select ARCH_HAS_CURRENT_STACK_POINTER
>   	select ARCH_HAS_DEBUG_VIRTUAL
> diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
> index 1f72efc2a579..ad3c6d92b801 100644
> --- a/arch/s390/mm/init.c
> +++ b/arch/s390/mm/init.c
> @@ -50,6 +50,7 @@
>   #include <linux/virtio_anchor.h>
>   #include <linux/virtio_config.h>
>   #include <linux/execmem.h>
> +#include <linux/cc_platform.h>
>   
>   pgd_t swapper_pg_dir[PTRS_PER_PGD] __section(".bss..swapper_pg_dir");
>   pgd_t invalid_pg_dir[PTRS_PER_PGD] __section(".bss..invalid_pg_dir");
> @@ -140,6 +141,19 @@ bool force_dma_unencrypted(struct device *dev)
>   	return is_prot_virt_guest();
>   }
>   
> +
> +bool cc_platform_has(enum cc_attr attr)
> +{
> +	switch (attr) {
> +	case CC_ATTR_MEM_ENCRYPT:
> +		return is_prot_virt_guest();
> +
> +	default:
> +		return false;
> +	}
> +}
> +EXPORT_SYMBOL_GPL(cc_platform_has);
> +
>   /* protected virtualization */
>   static void __init pv_init(void)
>   {

Hello Aneesh,

Thanks for adding this s390 support patch.

The previous v4 series broke virtio initialization and caused boot
failures on s390. With this patch in v5, the issue is completely
resolved and virtio devices now initialize successfully and are
working well.

I'm going to do some more testing and will let you know if I run
into any issues.

Thanks,
Jaehoon.




^ permalink raw reply

* [PATCH] crypto: nx: fix nx_crypto_ctx_exit argument
From: Sam James @ 2026-05-22 18:01 UTC (permalink / raw)
  To: Breno Leitão, Nayna Jain, Paulo Flabiano Smorigo,
	Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy (CS GROUP), Herbert Xu, David S. Miller,
	Eric Biggers, Ard Biesheuvel
  Cc: Sam James, Eric Biggers, Calvin Buckley, Brad Spengler,
	linux-crypto, linuxppc-dev, linux-kernel

nx_crypto_ctx_shash_exit calls nx_crypto_ctx_exit with crypto_shash_ctx(...)
but crypto_shash_ctx gives a nx_crypto_ctx *, not a crypto_tfm *.

Fix the type in nx_crypto_ctx_exit and drop the bogus crypto_tfm_ctx
call.

This fixes the following oops:

  BUG: Unable to handle kernel data access at 0xc0403effffffffc8
  Faulting instruction address: 0xc000000000396cb4
  Oops: Kernel access of bad area, sig: 11 [#15]
  Call Trace:
   nx_crypto_ctx_shash_exit+0x24/0x60
   crypto_shash_exit_tfm+0x28/0x40
   crypto_destroy_tfm+0x98/0x140
   crypto_exit_ahash_using_shash+0x20/0x40
   crypto_destroy_tfm+0x98/0x140
   hash_release+0x1c/0x30
   alg_sock_destruct+0x38/0x60
   __sk_destruct+0x48/0x2b0
   af_alg_release+0x58/0xb0
   __sock_release+0x68/0x150
   sock_close+0x20/0x40
   __fput+0x110/0x3a0
   sys_close+0x48/0xa0
   system_call_exception+0x140/0x2d0
   system_call_common+0xf4/0x258

.. which came from hardlink(1) opportunistically using AF_ALG.

The same problem exists with nx_crypto_ctx_skcipher_exit getting a context
it wasn't expecting, but apparently nobody hit that for years.

Cc: Eric Biggers <ebiggers@kernel.org>
Fixes: bfd9efddf990 ("crypto: nx - convert AES-ECB to skcipher API")
Fixes: 9420e628e7d8 ("crypto: nx - Use API partial block handling")
Reported-by: Calvin Buckley <calvin@cmpct.info>
Tested-by: Calvin Buckley <calvin@cmpct.info>
Suggested-by: Brad Spengler <brad.spengler@opensrcsec.com>
Signed-off-by: Sam James <sam@gentoo.org>
---
 drivers/crypto/nx/nx.c | 4 +---
 drivers/crypto/nx/nx.h | 2 +-
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c
index 78135fb13f5c..101e7fc7c1af 100644
--- a/drivers/crypto/nx/nx.c
+++ b/drivers/crypto/nx/nx.c
@@ -719,10 +719,8 @@ int nx_crypto_ctx_aes_xcbc_init(struct crypto_shash *tfm)
  * As crypto API contexts are destroyed, this exit hook is called to free the
  * memory associated with it.
  */
-void nx_crypto_ctx_exit(struct crypto_tfm *tfm)
+void nx_crypto_ctx_exit(struct nx_crypto_ctx *nx_ctx)
 {
-	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
-
 	kfree_sensitive(nx_ctx->kmem);
 	nx_ctx->csbcpb = NULL;
 	nx_ctx->csbcpb_aead = NULL;
diff --git a/drivers/crypto/nx/nx.h b/drivers/crypto/nx/nx.h
index 36974f08490a..6dfabfbf8192 100644
--- a/drivers/crypto/nx/nx.h
+++ b/drivers/crypto/nx/nx.h
@@ -153,7 +153,7 @@ int nx_crypto_ctx_aes_ctr_init(struct crypto_skcipher *tfm);
 int nx_crypto_ctx_aes_cbc_init(struct crypto_skcipher *tfm);
 int nx_crypto_ctx_aes_ecb_init(struct crypto_skcipher *tfm);
 int nx_crypto_ctx_sha_init(struct crypto_shash *tfm);
-void nx_crypto_ctx_exit(struct crypto_tfm *tfm);
+void nx_crypto_ctx_exit(struct nx_crypto_ctx *nx_ctx);
 void nx_crypto_ctx_skcipher_exit(struct crypto_skcipher *tfm);
 void nx_crypto_ctx_aead_exit(struct crypto_aead *tfm);
 void nx_crypto_ctx_shash_exit(struct crypto_shash *tfm);

base-commit: 758c807bb943138f887d42d986b645e12446ba9c
-- 
2.54.0



^ permalink raw reply related

* Re: [PATCH] crypto: nx: fix nx_crypto_ctx_exit argument
From: Eric Biggers @ 2026-05-22 18:44 UTC (permalink / raw)
  To: Sam James
  Cc: Breno Leitão, Nayna Jain, Paulo Flabiano Smorigo,
	Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy (CS GROUP), Herbert Xu, David S. Miller,
	Ard Biesheuvel, Calvin Buckley, Brad Spengler, linux-crypto,
	linuxppc-dev, linux-kernel
In-Reply-To: <a3e89c1e8342ffa415b0d29725a0571a4f355d34.1779472902.git.sam@gentoo.org>

On Fri, May 22, 2026 at 07:01:42PM +0100, Sam James wrote:
> nx_crypto_ctx_shash_exit calls nx_crypto_ctx_exit with crypto_shash_ctx(...)
> but crypto_shash_ctx gives a nx_crypto_ctx *, not a crypto_tfm *.
> 
> Fix the type in nx_crypto_ctx_exit and drop the bogus crypto_tfm_ctx
> call.
> 
> This fixes the following oops:
> 
>   BUG: Unable to handle kernel data access at 0xc0403effffffffc8
>   Faulting instruction address: 0xc000000000396cb4
>   Oops: Kernel access of bad area, sig: 11 [#15]
>   Call Trace:
>    nx_crypto_ctx_shash_exit+0x24/0x60
>    crypto_shash_exit_tfm+0x28/0x40
>    crypto_destroy_tfm+0x98/0x140
>    crypto_exit_ahash_using_shash+0x20/0x40
>    crypto_destroy_tfm+0x98/0x140
>    hash_release+0x1c/0x30
>    alg_sock_destruct+0x38/0x60
>    __sk_destruct+0x48/0x2b0
>    af_alg_release+0x58/0xb0
>    __sock_release+0x68/0x150
>    sock_close+0x20/0x40
>    __fput+0x110/0x3a0
>    sys_close+0x48/0xa0
>    system_call_exception+0x140/0x2d0
>    system_call_common+0xf4/0x258
> 
> .. which came from hardlink(1) opportunistically using AF_ALG.
> 
> The same problem exists with nx_crypto_ctx_skcipher_exit getting a context
> it wasn't expecting, but apparently nobody hit that for years.
> 
> Cc: Eric Biggers <ebiggers@kernel.org>
> Fixes: bfd9efddf990 ("crypto: nx - convert AES-ECB to skcipher API")
> Fixes: 9420e628e7d8 ("crypto: nx - Use API partial block handling")

Add:

    Cc: stable@vger.kernel.org

> diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c
> index 78135fb13f5c..101e7fc7c1af 100644
> --- a/drivers/crypto/nx/nx.c
> +++ b/drivers/crypto/nx/nx.c
> @@ -719,10 +719,8 @@ int nx_crypto_ctx_aes_xcbc_init(struct crypto_shash *tfm)
>   * @tfm: the crypto transform pointer for the context
>   *
>   * As crypto API contexts are destroyed, this exit hook is called to free the
>   * memory associated with it.
>   */
> -void nx_crypto_ctx_exit(struct crypto_tfm *tfm)
> +void nx_crypto_ctx_exit(struct nx_crypto_ctx *nx_ctx)

The part of the comment that documents @tfm needs to be updated.

Otherwise this looks good.  Really there's a good chance this driver is
no longer useful (if it ever was) and should just be deleted, but that
would be a separate effort.

Reviewed-by: Eric Biggers <ebiggers@kernel.org>

- Eric


^ permalink raw reply

* Re: [PATCH v1 2/8] powerpc/signal64: Untangle setup_tm_sigcontexts() and user_access_begin()
From: David Laight @ 2026-05-22 18:55 UTC (permalink / raw)
  To: Christophe Leroy (CS GROUP)
  Cc: Michael Ellerman, Nicholas Piggin, Madhavan Srinivasan,
	linux-kernel, linuxppc-dev
In-Reply-To: <28a7b0b9-3c17-4f76-af80-f17f4869f854@kernel.org>

On Fri, 22 May 2026 14:44:55 +0200
"Christophe Leroy (CS GROUP)" <chleroy@kernel.org> wrote:

> Le 22/05/2026 à 14:06, Christophe Leroy (CS GROUP) a écrit :
> > 
> > 
> > Le 22/05/2026 à 13:12, David Laight a écrit :  
> >> On Fri, 22 May 2026 11:56:02 +0200
> >> "Christophe Leroy (CS GROUP)" <chleroy@kernel.org> wrote:
> >>  
> >>> Call setup_tm_sigcontexts() before opening user access to avoid
> >>> having to close and open again.
> >>>
> >>> Signed-off-by: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
> >>> ---
> >>>   arch/powerpc/kernel/signal_64.c | 22 +++++++++-------------
> >>>   1 file changed, 9 insertions(+), 13 deletions(-)
> >>>
> >>> diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/ 
> >>> signal_64.c
> >>> index 86bb5bb4c143..3849af21e1d8 100644
> >>> --- a/arch/powerpc/kernel/signal_64.c
> >>> +++ b/arch/powerpc/kernel/signal_64.c
> >>> @@ -873,6 +873,15 @@ int handle_rt_signal64(struct ksignal *ksig, 
> >>> sigset_t *set,
> >>>       if (!MSR_TM_ACTIVE(msr))
> >>>           prepare_setup_sigcontext(tsk);
> >>> +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
> >>> +    if (MSR_TM_ACTIVE(msr))  
> >>
> >> Can't that be done without the ugly #ifdef?
> >> I assume MSR_TM_ACTIVE() will be zero - so it will all get optimised 
> >> away.  
> > 
> > Yes but struct rt_sigframe field uc_transact only exists when 
> > CONFIG_PPC_TRANSACTIONAL_MEM is defined.
> > 
> > And that would also require a stub setup_tm_sigcontexts()  
> 
> After thinking once more, I think we can do the following, is it better 
> for you ?

Certainly more like the expected style.
setup_tm_sigcontexts() will get inlined, so it doesn't matter what values
are passed as the arguments.

-- David

> 
> diff --git a/arch/powerpc/kernel/signal_64.c 
> b/arch/powerpc/kernel/signal_64.c
> index 86bb5bb4c143..c70732e8002d 100644
> --- a/arch/powerpc/kernel/signal_64.c
> +++ b/arch/powerpc/kernel/signal_64.c
> @@ -203,8 +203,7 @@ static long notrace __unsafe_setup_sigcontext(struct 
> sigcontext __user *sc,
>    * examine the transactional registers in the 2nd sigcontext to 
> determine the
>    * real origin of the signal.
>    */
> -static long setup_tm_sigcontexts(struct sigcontext __user *sc,
> -				 struct sigcontext __user *tm_sc,
> +static long setup_tm_sigcontexts(struct rt_sigframe __user *frame,
>   				 struct task_struct *tsk,
>   				 int signr, sigset_t *set, unsigned long handler,
>   				 unsigned long msr)
> @@ -217,6 +216,8 @@ static long setup_tm_sigcontexts(struct sigcontext 
> __user *sc,
>   	 * Userland shall check AT_HWCAP to know wether it can rely on the
>   	 * v_regs pointer or not.
>   	 */
> +	struct sigcontext __user *sc = &frame->uc.uc_mcontext;
> +	struct sigcontext __user *tm_sc = &frame->uc_transact.uc_mcontext;
>   #ifdef CONFIG_ALTIVEC
>   	elf_vrreg_t __user *v_regs = sigcontext_vmx_regs(sc);
>   	elf_vrreg_t __user *tm_v_regs = sigcontext_vmx_regs(tm_sc);
> @@ -325,6 +326,14 @@ static long setup_tm_sigcontexts(struct sigcontext 
> __user *sc,
> 
>   	return err;
>   }
> +#else
> +static long setup_tm_sigcontexts(struct rt_sigframe __user *frame,
> +				 struct task_struct *tsk,
> +				 int signr, sigset_t *set, unsigned long handler,
> +				 unsigned long msr)
> +{
> +	return -EINVAL;
> +}
>   #endif
> 
>   /*
> @@ -872,6 +881,9 @@ int handle_rt_signal64(struct ksignal *ksig, 
> sigset_t *set,
>   	 */
>   	if (!MSR_TM_ACTIVE(msr))
>   		prepare_setup_sigcontext(tsk);
> +	else
> +		err |= setup_tm_sigcontexts(frame, tsk, ksig->sig, NULL,
> +					    (unsigned long)ksig->ka.sa.sa_handler, msr);
> 
>   	if (!user_write_access_begin(frame, sizeof(*frame)))
>   		goto badframe;
> @@ -889,19 +901,6 @@ int handle_rt_signal64(struct ksignal *ksig, 
> sigset_t *set,
>   		 * ucontext_t (for transactional state) with its uc_link ptr.
>   		 */
>   		unsafe_put_user(&frame->uc_transact, &frame->uc.uc_link, 
> badframe_block);
> -
> -		user_write_access_end();
> -
> -		err |= setup_tm_sigcontexts(&frame->uc.uc_mcontext,
> -					    &frame->uc_transact.uc_mcontext,
> -					    tsk, ksig->sig, NULL,
> -					    (unsigned long)ksig->ka.sa.sa_handler,
> -					    msr);
> -
> -		if (!user_write_access_begin(&frame->uc.uc_sigmask,
> -					     sizeof(frame->uc.uc_sigmask)))
> -			goto badframe;
> -
>   #endif
>   	} else {
>   		unsafe_put_user(0, &frame->uc.uc_link, badframe_block);
> 
> 
> Christophe



^ permalink raw reply

* Re: [PATCH v2 0/5] mm: reduce mmap_lock contention and improve page fault performance
From: Barry Song @ 2026-05-22 21:31 UTC (permalink / raw)
  To: Lorenzo Stoakes
  Cc: David Hildenbrand (Arm), Matthew Wilcox, Liam R. Howlett,
	Suren Baghdasaryan, akpm, linux-mm, vbabka, rppt, mhocko, jack,
	pfalcato, wanglian, chentao, lianux.mm, kunwu.chan, liyangouwen1,
	chrisl, kasong, shikemeng, nphamcs, bhe, youngjun.park,
	linux-arm-kernel, linux-kernel, loongarch, linuxppc-dev,
	linux-riscv, linux-s390, Nanzhe Zhao
In-Reply-To: <ahB6QyHgYq8ksj65@lucifer>

>
> Again this is making me want to sit outside and sip on some lemonade and
> ice :)
>
> Yes - android processes are aggressively multi-threaded, sure of course.
>
> The missing bit here is the forking - what, where, why, when?
>

I really want to know the what, where, why, and when
as well. But since most applications are not
open-source, it is basically a black hole for anyone
other than the owners of those apps.

Let me try to do more investigation to understand what
is going on, although it is really hard.
To be honest, I would rather the Android framework
completely prohibit apps from calling fork(), if
possible.

> And then you say zygote is sometimes multi-threaded but sometimes
> single-threaded, which is adding a whole bunch of confusion on top of all
> that.
>
> I don't find these stack trace dumps all that useful (though thanks of
> course for taking the time to gather them), I think we'd be better off with
> specific data on forking, in some _concise_ _summarised_ form, ideally with
> numbers.
>
> There's such a thing as too much information :))

This trace shows PF I/O in one thread overlapping
with a fork() call in another thread.
But as I explained, I really do not know what kind of
user behavior is behind it.

>
> Anyway, again, please let's see a new _RFC_ with the approach proposed by
> Suren, with some _succinct_ data demonstrating _exactly_ what the problem
> is, so we can make some headway here.

Okay, sure. Thanks for your patience.

>
> And now I'm off for a cornetto! :)

Sounds good :) Enjoy your cornetto!

Best Regards
Barry


^ permalink raw reply

* Re: [PATCH 04/11] treewide: Convert struct kernel_param_ops initializers to DEFINE_KERNEL_PARAM_OPS
From: SeongJae Park @ 2026-05-23  0:38 UTC (permalink / raw)
  To: Kees Cook
  Cc: SeongJae Park, Luis Chamberlain, Pengpeng Hou, Petr Pavlu,
	Richard Weinberger, Anton Ivanov, Johannes Berg,
	Rafael J. Wysocki, Len Brown, Corey Minyard, Gabriel Somlo,
	Michael S. Tsirkin, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
	Tvrtko Ursulin, David Airlie, Simona Vetter, Bart Van Assche,
	Jason Gunthorpe, Leon Romanovsky, Laurent Pinchart, Hans de Goede,
	Mauro Carvalho Chehab, Bjorn Helgaas, Hannes Reinecke,
	James E.J. Bottomley, Martin K. Petersen, Daniel Lezcano,
	Zhang Rui, Lukasz Luba, Greg Kroah-Hartman, Jiri Slaby,
	Alan Stern, Jason Wang, Xuan Zhuo, Eugenio Pérez,
	Jason Baron, Jim Cromie, Tiwei Bie, Benjamin Berg,
	Ilpo Järvinen, David E. Box, Maciej W. Rozycki,
	Srinivas Pandruvada, Peter Zijlstra, Heiko Carstens,
	Vasily Gorbik, Sean Christopherson, Paolo Bonzini,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	H. Peter Anvin, Vinod Koul, Frank Li, Daniel Gomez, Sami Tolvanen,
	Aaron Tomlin, Alexander Potapenko, Marco Elver, Dmitry Vyukov,
	Andrew Morton, John Johansen, Paul Moore, James Morris,
	Serge E. Hallyn, Andy Shevchenko, Georgia Garcia, kvm, dmaengine,
	linux-modules, kasan-dev, linux-mm, apparmor,
	linux-security-module, linux-um, linux-acpi, openipmi-developer,
	qemu-devel, intel-gfx, dri-devel, linux-rdma, linux-media,
	linux-pci, linux-scsi, linux-pm, linuxppc-dev, linux-serial,
	linux-usb, usb-storage, virtualization, linux-kernel, linux-arch,
	netdev, linux-fsdevel, linux-hardening
In-Reply-To: <20260521133326.2465264-4-kees@kernel.org>

On Thu, 21 May 2026 06:33:17 -0700 Kees Cook <kees@kernel.org> wrote:

> Using Coccinelle, rewrite every struct kernel_param_ops initializer that
> sets .get into a DEFINE_KERNEL_PARAM_OPS-family macro invocation,
> for example:
> 
> @@
> declarer name DEFINE_KERNEL_PARAM_OPS;
> identifier OPS;
> expression SET, GET;
> @@
> - const struct kernel_param_ops OPS = {
> -       .set = SET,
> -       .get = GET,
> - };
> + DEFINE_KERNEL_PARAM_OPS(OPS, SET, GET);
> 
> Using the macro for initialization means future changes can manipulate
> the struct layout and callback prototypes without having to change every
> initializer.
> 
> Signed-off-by: Kees Cook <kees@kernel.org>
> ---
[...]
>  mm/damon/lru_sort.c                           | 19 ++---
>  mm/damon/reclaim.c                            | 19 ++---
>  mm/damon/stat.c                               |  6 +-
[...]
>  samples/damon/mtier.c                         |  6 +-
>  samples/damon/prcl.c                          |  6 +-
>  samples/damon/wsse.c                          |  6 +-

For the above DAMON part changes,

Reviewed-by: SeongJae Park <sj@kernel.org>


Thanks,
SJ

[...]


^ permalink raw reply

* Re: [PATCH 09/11] treewide: Convert custom kernel_param_ops .get callbacks to seq_buf via cocci
From: SeongJae Park @ 2026-05-23  0:45 UTC (permalink / raw)
  To: Kees Cook
  Cc: SeongJae Park, Luis Chamberlain, Pengpeng Hou, Petr Pavlu,
	Richard Weinberger, Anton Ivanov, Johannes Berg,
	Rafael J. Wysocki, Len Brown, Corey Minyard, Gabriel Somlo,
	Michael S. Tsirkin, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
	Tvrtko Ursulin, David Airlie, Simona Vetter, Bart Van Assche,
	Jason Gunthorpe, Leon Romanovsky, Laurent Pinchart, Hans de Goede,
	Mauro Carvalho Chehab, Bjorn Helgaas, Hannes Reinecke,
	James E.J. Bottomley, Martin K. Petersen, Daniel Lezcano,
	Zhang Rui, Lukasz Luba, Greg Kroah-Hartman, Jiri Slaby,
	Alan Stern, Jason Wang, Xuan Zhuo, Eugenio Pérez,
	Jason Baron, Jim Cromie, Tiwei Bie, Benjamin Berg,
	Ilpo Järvinen, David E. Box, Maciej W. Rozycki,
	Srinivas Pandruvada, Peter Zijlstra, Heiko Carstens,
	Vasily Gorbik, Sean Christopherson, Paolo Bonzini,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	H. Peter Anvin, Vinod Koul, Frank Li, Daniel Gomez, Sami Tolvanen,
	Aaron Tomlin, Alexander Potapenko, Marco Elver, Dmitry Vyukov,
	Andrew Morton, John Johansen, Paul Moore, James Morris,
	Serge E. Hallyn, Andy Shevchenko, Georgia Garcia, kvm, dmaengine,
	linux-modules, kasan-dev, linux-mm, apparmor,
	linux-security-module, linux-um, linux-acpi, openipmi-developer,
	qemu-devel, intel-gfx, dri-devel, linux-rdma, linux-media,
	linux-pci, linux-scsi, linux-pm, linuxppc-dev, linux-serial,
	linux-usb, usb-storage, virtualization, linux-kernel, linux-arch,
	netdev, linux-fsdevel, linux-hardening, damon
In-Reply-To: <20260521133326.2465264-9-kees@kernel.org>

+ damon@lists.linux.dev

On Thu, 21 May 2026 06:33:22 -0700 Kees Cook <kees@kernel.org> wrote:

> Using the following Coccinelle script, convert struct kernel_param_ops
> .get callbacks from "char *" to "struct seq_buf *" when the only write
> to the buffer is via a final call of scnprintf(), snprintf(), sprintf(),
> or sysfs_emit().
> 
> Since seq_buf_printf() will return -1 on overflow, and struct
> kernel_param_ops .get callbacks are expected to truncate without error,
> we must ignore the return value from seq_buf_print() and always return 0
> (as the length is calculated in the common dispatcher code).
> 
> @@
> identifier FN, BUF, KP;
> expression FMT;
> expression list ARGS;
> @@
>  int FN(
> -               char *BUF
> +               struct seq_buf *BUF
>                 , const struct kernel_param *KP)
>  {
>         ... when any
> (
> -       return scnprintf(BUF, PAGE_SIZE, FMT, ARGS);
> |
> -       return snprintf(BUF, PAGE_SIZE, FMT, ARGS);
> |
> -       return sprintf(BUF, FMT, ARGS);
> |
> -       return sysfs_emit(BUF, FMT, ARGS);
> )
> +       seq_buf_printf(BUF, FMT, ARGS);
> +       return 0;
>  }
> 
> No struct kernel_param_ops initializations need changing since
> DEFINE_KERNEL_PARAM_OPS already routes the pointer to .get or .get_str
> via _Generic based on the function signature, so converted callbacks
> are automatically moved from the .get_str to the .get callback.
> 
> Signed-off-by: Kees Cook <kees@kernel.org>
[...]
>  mm/damon/lru_sort.c                           | 14 +++---
>  mm/damon/reclaim.c                            | 14 +++---
>  mm/damon/stat.c                               | 10 ++--

For the above DAMON changes,

Reviewed-by: SeongJae Park <sj@kernel.org>


Thanks,
SJ

[...]


^ permalink raw reply

* [PATCH] powerpc: Export set_memory_encrypted and set_memory_decrypted
From: T.J. Mercier @ 2026-05-22 22:58 UTC (permalink / raw)
  To: maddy, mpe, npiggin, chleroy, linuxppc-dev, mripard, sumit.semwal
  Cc: lkp, linux-kernel, T.J. Mercier

After commit fd55edff8a0a ("dma-buf: heaps: system: Turn the heap into a
module") the system dma-buf heaps can be built as a module. The
system_cc_shared heap uses set_memory_encrypted and set_memory_decrypted
but those functions are not exported on powerpc. This can result in a
build error like:

>> ERROR: modpost: "set_memory_decrypted" [drivers/dma-buf/heaps/system_heap.ko] undefined!
>> ERROR: modpost: "set_memory_encrypted" [drivers/dma-buf/heaps/system_heap.ko] undefined!

Export the functions so system_heap.ko can be built.

Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202605230046.E9uhmQXM-lkp@intel.com/
Fixes: fd55edff8a0a ("dma-buf: heaps: system: Turn the heap into a module")
Signed-off-by: T.J. Mercier <tjmercier@google.com>
---
 arch/powerpc/platforms/pseries/svm.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/powerpc/platforms/pseries/svm.c b/arch/powerpc/platforms/pseries/svm.c
index 384c9dc1899a..59cf32e51ca3 100644
--- a/arch/powerpc/platforms/pseries/svm.c
+++ b/arch/powerpc/platforms/pseries/svm.c
@@ -50,6 +50,7 @@ int set_memory_encrypted(unsigned long addr, int numpages)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(set_memory_encrypted);
 
 int set_memory_decrypted(unsigned long addr, int numpages)
 {
@@ -63,6 +64,8 @@ int set_memory_decrypted(unsigned long addr, int numpages)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(set_memory_decrypted);
+
 
 /* There's one dispatch log per CPU. */
 #define NR_DTL_PAGE (DISPATCH_LOG_BYTES * CONFIG_NR_CPUS / PAGE_SIZE)
-- 
2.54.0.746.g67dd491aae-goog



^ permalink raw reply related

* [PATCH v2] crypto: nx: fix nx_crypto_ctx_exit argument
From: Sam James @ 2026-05-23  4:08 UTC (permalink / raw)
  To: Breno Leitão, Nayna Jain, Paulo Flabiano Smorigo,
	Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy (CS GROUP), Herbert Xu, David S. Miller,
	Ard Biesheuvel, Eric Biggers
  Cc: Sam James, Eric Biggers, stable, Calvin Buckley, Brad Spengler,
	linux-crypto, linuxppc-dev, linux-kernel
In-Reply-To: <20260522184403.GA35544@quark>

nx_crypto_ctx_shash_exit calls nx_crypto_ctx_exit with crypto_shash_ctx(...)
but crypto_shash_ctx gives a nx_crypto_ctx *, not a crypto_tfm *.

Fix the type in nx_crypto_ctx_exit and drop the bogus crypto_tfm_ctx
call.

This fixes the following oops:

  BUG: Unable to handle kernel data access at 0xc0403effffffffc8
  Faulting instruction address: 0xc000000000396cb4
  Oops: Kernel access of bad area, sig: 11 [#15]
  Call Trace:
   nx_crypto_ctx_shash_exit+0x24/0x60
   crypto_shash_exit_tfm+0x28/0x40
   crypto_destroy_tfm+0x98/0x140
   crypto_exit_ahash_using_shash+0x20/0x40
   crypto_destroy_tfm+0x98/0x140
   hash_release+0x1c/0x30
   alg_sock_destruct+0x38/0x60
   __sk_destruct+0x48/0x2b0
   af_alg_release+0x58/0xb0
   __sock_release+0x68/0x150
   sock_close+0x20/0x40
   __fput+0x110/0x3a0
   sys_close+0x48/0xa0
   system_call_exception+0x140/0x2d0
   system_call_common+0xf4/0x258

.. which came from hardlink(1) opportunistically using AF_ALG.

The same problem exists with nx_crypto_ctx_skcipher_exit getting a context
it wasn't expecting, but apparently nobody hit that for years.

Cc: Eric Biggers <ebiggers@kernel.org>
Cc: stable@vger.kernel.org
Fixes: bfd9efddf990 ("crypto: nx - convert AES-ECB to skcipher API")
Fixes: 9420e628e7d8 ("crypto: nx - Use API partial block handling")
Reviewed-by: Eric Biggers <ebiggers@kernel.org>
Reported-by: Calvin Buckley <calvin@cmpct.info>
Tested-by: Calvin Buckley <calvin@cmpct.info>
Suggested-by: Brad Spengler <brad.spengler@opensrcsec.com>
Signed-off-by: Sam James <sam@gentoo.org>
---
v2: Add stable cc, fix doc for tfm param.

 drivers/crypto/nx/nx.c | 6 ++----
 drivers/crypto/nx/nx.h | 2 +-
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c
index 78135fb13f5c..f4bc947086f8 100644
--- a/drivers/crypto/nx/nx.c
+++ b/drivers/crypto/nx/nx.c
@@ -714,15 +714,13 @@ int nx_crypto_ctx_aes_xcbc_init(struct crypto_shash *tfm)
 /**
  * nx_crypto_ctx_exit - destroy a crypto api context
  *
- * @tfm: the crypto transform pointer for the context
+ * @tfm: the crypto api context
  *
  * As crypto API contexts are destroyed, this exit hook is called to free the
  * memory associated with it.
  */
-void nx_crypto_ctx_exit(struct crypto_tfm *tfm)
+void nx_crypto_ctx_exit(struct nx_crypto_ctx *nx_ctx)
 {
-	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
-
 	kfree_sensitive(nx_ctx->kmem);
 	nx_ctx->csbcpb = NULL;
 	nx_ctx->csbcpb_aead = NULL;
diff --git a/drivers/crypto/nx/nx.h b/drivers/crypto/nx/nx.h
index 36974f08490a..6dfabfbf8192 100644
--- a/drivers/crypto/nx/nx.h
+++ b/drivers/crypto/nx/nx.h
@@ -153,7 +153,7 @@ int nx_crypto_ctx_aes_ctr_init(struct crypto_skcipher *tfm);
 int nx_crypto_ctx_aes_cbc_init(struct crypto_skcipher *tfm);
 int nx_crypto_ctx_aes_ecb_init(struct crypto_skcipher *tfm);
 int nx_crypto_ctx_sha_init(struct crypto_shash *tfm);
-void nx_crypto_ctx_exit(struct crypto_tfm *tfm);
+void nx_crypto_ctx_exit(struct nx_crypto_ctx *nx_ctx);
 void nx_crypto_ctx_skcipher_exit(struct crypto_skcipher *tfm);
 void nx_crypto_ctx_aead_exit(struct crypto_aead *tfm);
 void nx_crypto_ctx_shash_exit(struct crypto_shash *tfm);

base-commit: 758c807bb943138f887d42d986b645e12446ba9c
-- 
2.54.0



^ permalink raw reply related

* Re: [PATCH] crypto: nx: fix nx_crypto_ctx_exit argument
From: Simon Richter @ 2026-05-23  6:30 UTC (permalink / raw)
  To: Eric Biggers; +Cc: linux-crypto, linuxppc-dev
In-Reply-To: <20260522184403.GA35544@quark>


[-- Attachment #1.1: Type: text/plain, Size: 3739 bytes --]

Hi,

On 5/23/26 03:44, Eric Biggers wrote:

> Otherwise this looks good.  Really there's a good chance this driver is
> no longer useful (if it ever was) and should just be deleted, but that
> would be a separate effort.

I happen to have one (well, two) of these, so this is relevant to my 
interests.

tl;dr: the crypto drivers are most likely unused, the hardware is great, 
but the crypto subsystem cannot use it efficiently.

Below drivers/crypto/nx, there are three drivers in a trenchcoat:

  - an NX crypto driver that is not endian safe, can therefore only be 
used on big endian systems, and that implements a bunch of AES modes 
plus SHA256/SHA512, all of them synchronous.
  - an scomp driver with an IBM specific compression algorithm
  - a gzip driver that does not integrate with the crypto subsystem and 
provides its own userspace interface.

The "big endian only" thing is a massive restriction, this is how IBM 
separates enterprise and hobbyist customers, so if there are users of 
this module, then they both have enterprise support contracts.

The gzip mode is really useful, with 4 GB of random data I get

$ time ./nx_gzip test.bin
real 0m2.989s
user 0m1.317s
sys  0m1.665s

$ time gzip -9k test.bin
real 2m57.468s
user 2m55.325s
sys  0m1.682s

so 3 GB/s vs 22 MB/s. Even if I had a workload where I could use all the 
CPU cores in parallel, offloading is still faster, 120W cheaper and 
leaves the CPU free as a bonus, so I think that's a no-brainer.

The "842" compression is mainly designed to be fast, the marketing 
material claims > 25 GB/s, which makes sense, this unit sits on a 128 
bit wide bus clocked at 2 GHz, and the algorithm is designed around 
that. On the other hand it is fairly niche.

I couldn't find numbers for the AES and SHA units, I'd expect them to be 
in the same ballpark, but I cannot measure them easily. CPU is ~500 MB/s 
for SHA1 and SHA512, ~300 MB/s for SHA256, that should be easy to beat 
(even a primitive 2-way SHA256 would be at 4 GB/s, and I doubt IBM left 
it at that).

POWER11 introduces new opcodes, which will shake things up, but these 
machines are on a fairly long replacement cycle.

The main problem with getting the advertised performance is feeding 
requests fast enough. Large requests are easy, but the optimum strategy 
for feeding small requests is just to start submitting, poll old 
requests for completion inbetween, and start requesting interrupts only 
if nothing is complete and it looks like the unit will be busy for a while.

That's not what is currently implemented, and I doubt it could be 
implemented with the current kernel interfaces, so getting decent 
performance inside the kernel would require some redesign.

I suppose that also explains the synchronous implementation: we are 
submitting the request and polling for completion, so overhead is fairly 
minimal and should break even at a few hundred bytes, but obviously that 
is not the ideal way to run this thing.

The endianness issues are trivial to fix (really just needs a sprinkle 
of cpu_to_beXX/beXX_to_cpu when putting the job control blocks together, 
like nx-842 does); if you have a definition of what you would consider a 
"real world" workload for AES I could run that to gather some numbers.

So far however, no one bothered fixing this, and I'm pretty meh about it 
myself since I don't have SHA/AES workloads in the kernel, only in 
userspace.

Other than that, if you decide to remove the driver from the crypto 
subsystem, then nx-gzip should be kept (and probably moved somewhere 
else), because it is not a crypto driver, it just shares a bunch of 
headers with them.

    Simon

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* [RFC v2 0/5] KVM: selftests: add powerpc support
From: Ritesh Harjani (IBM) @ 2026-05-23 11:14 UTC (permalink / raw)
  To: kvm
  Cc: linuxppc-dev, Madhavan Srinivasan, Harsh Prateek Bora,
	Christophe Leroy, Venkat Rao Bagalkote, Nicholas Piggin,
	Misbah Anjum N, Anushree Mathur, Michael Ellerman, linux-kernel,
	Ritesh Harjani (IBM)

Hi All,

This series primarly adds KVM selftests support for powerpc (64-bit, BookS,
radix MMU).

This patch series is originally Nick's work. I have mainly only rebased it on
the latest upstream tree. Since the rebase required few changes to all the four
patches (Patch 1-4), I have dropped the earlier Acked-by from Michael Ellerman.

Since the last series was posted three years ago [1], I am resetting the version
to RFC. This rebase was done as part of a larger effort to improve the selftests
infrastructure for Linux on PowerPC tree. Thanks to Harsh and Maddy for their
help on this.


Testing Updates:
================
1. Tested this on PowerNV P9 with Radix mode. (all selftests passes)
2. Tested this on LPAR (KVM on PowerVM) case. (all selftests except-1 passes).
   The failed testcase (kvm_create_max_vcpus) is because H_GUEST_CREATE_VCPU
   (PAPR HCALL) only supports vcpu_ids 0-2047 i.e. max 2048 vcpus.
   However, kernel always returns NR_CPUS for the KVM_CAP_MAX_VCPUS extension.
   So if the LPAR kernel is built using NR_CPUS=8192, then kvm_create_max_vcpus
   can fail in __vm_vcpu_add(). This failure needs to be handled seperately,
   mostly as fix in kernel.
3. Tested these selftests changes inside x86 kvm guest  - no new failures seen.


RFC v1 -> RFC v2
================
(mostly Sashiko review comments)
1. Fixed x86's stage-2 mmu handling in patch-1 - commit msg has more description
2. Added "cc" into the clobber list for hcalls in patch-3
3. Fixed the size calculation in kvm_arch_vm_post_create in patch-3 for
   allocating 2 pages for 4K pagesize
4. Added patch-5 which prints vcpu_id in case of an error

[RFCv1]: https://lore.kernel.org/linuxppc-dev/cover.1778857539.git.ritesh.list@gmail.com/
[1]: https://lore.kernel.org/all/20231120122920.293076-1-npiggin@gmail.com/

Nicholas Piggin (4):
  KVM: selftests: Move pgd_created check into virt_pgd_alloc
  KVM: selftests: Add aligned guest physical page allocator
  KVM: PPC: selftests: add support for powerpc
  KVM: PPC: selftests: powerpc enable kvm_create_max_vcpus test

Ritesh Harjani (IBM) (1):
  KVM: selftests: Print the vcpu_id when KVM_CREATE_VCPU ioctl fails

 MAINTAINERS                                   |   2 +
 tools/testing/selftests/kvm/Makefile          |   2 +-
 tools/testing/selftests/kvm/Makefile.kvm      |  10 +
 .../testing/selftests/kvm/include/kvm_util.h  |  34 +-
 .../selftests/kvm/include/powerpc/hcall.h     |  17 +
 .../kvm/include/powerpc/kvm_util_arch.h       |  22 +
 .../selftests/kvm/include/powerpc/ppc_asm.h   |  32 ++
 .../selftests/kvm/include/powerpc/processor.h |  38 ++
 .../selftests/kvm/include/powerpc/ucall.h     |  21 +
 .../selftests/kvm/kvm_create_max_vcpus.c      |   9 +
 .../selftests/kvm/lib/arm64/processor.c       |   4 -
 tools/testing/selftests/kvm/lib/guest_modes.c |  20 +-
 tools/testing/selftests/kvm/lib/kvm_util.c    |  44 +-
 .../selftests/kvm/lib/loongarch/processor.c   |   4 -
 .../selftests/kvm/lib/powerpc/handlers.S      |  93 ++++
 .../testing/selftests/kvm/lib/powerpc/hcall.c |  45 ++
 .../selftests/kvm/lib/powerpc/processor.c     | 484 ++++++++++++++++++
 .../testing/selftests/kvm/lib/powerpc/ucall.c |  22 +
 .../selftests/kvm/lib/riscv/processor.c       |   4 -
 .../selftests/kvm/lib/s390/processor.c        |   4 -
 20 files changed, 872 insertions(+), 39 deletions(-)
 create mode 100644 tools/testing/selftests/kvm/include/powerpc/hcall.h
 create mode 100644 tools/testing/selftests/kvm/include/powerpc/kvm_util_arch.h
 create mode 100644 tools/testing/selftests/kvm/include/powerpc/ppc_asm.h
 create mode 100644 tools/testing/selftests/kvm/include/powerpc/processor.h
 create mode 100644 tools/testing/selftests/kvm/include/powerpc/ucall.h
 create mode 100644 tools/testing/selftests/kvm/lib/powerpc/handlers.S
 create mode 100644 tools/testing/selftests/kvm/lib/powerpc/hcall.c
 create mode 100644 tools/testing/selftests/kvm/lib/powerpc/processor.c
 create mode 100644 tools/testing/selftests/kvm/lib/powerpc/ucall.c

--
2.39.5



^ permalink raw reply

* [RFC v2 1/5] KVM: selftests: Move pgd_created check into virt_pgd_alloc
From: Ritesh Harjani (IBM) @ 2026-05-23 11:14 UTC (permalink / raw)
  To: kvm
  Cc: linuxppc-dev, Madhavan Srinivasan, Harsh Prateek Bora,
	Christophe Leroy, Venkat Rao Bagalkote, Nicholas Piggin,
	Misbah Anjum N, Anushree Mathur, Michael Ellerman, linux-kernel,
	Ritesh Harjani (IBM)
In-Reply-To: <cover.1779524962.git.ritesh.list@gmail.com>

From: Nicholas Piggin <npiggin@gmail.com>

virt_arch_pgd_alloc all do the same test and set pgd_created. Move
this into common code -
except for x86's virt_arch_pgd_alloc() -> virt_mmu_init() - because this
can also be called from it's tdp_mmu_init() call for setting up it's
stage-2 mmu.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
[Rebased to latest mainline tree and removed x86 case]
Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
---
 tools/testing/selftests/kvm/include/kvm_util.h        | 5 +++++
 tools/testing/selftests/kvm/lib/arm64/processor.c     | 4 ----
 tools/testing/selftests/kvm/lib/loongarch/processor.c | 4 ----
 tools/testing/selftests/kvm/lib/riscv/processor.c     | 4 ----
 tools/testing/selftests/kvm/lib/s390/processor.c      | 4 ----
 5 files changed, 5 insertions(+), 16 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index 2ecaaa0e9965..3666a8530f31 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -1197,7 +1197,12 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm);
 
 static inline void virt_pgd_alloc(struct kvm_vm *vm)
 {
+	if (vm->mmu.pgd_created)
+		return;
+
 	virt_arch_pgd_alloc(vm);
+
+	vm->mmu.pgd_created = true;
 }
 
 /*
diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c
index 01325bf4d36f..498fbcb0ea16 100644
--- a/tools/testing/selftests/kvm/lib/arm64/processor.c
+++ b/tools/testing/selftests/kvm/lib/arm64/processor.c
@@ -112,13 +112,9 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)
 {
 	size_t nr_pages = vm_page_align(vm, ptrs_per_pgd(vm) * 8) / vm->page_size;
 
-	if (vm->mmu.pgd_created)
-		return;
-
 	vm->mmu.pgd = vm_phy_pages_alloc(vm, nr_pages,
 					 KVM_GUEST_PAGE_TABLE_MIN_PADDR,
 					 vm->memslots[MEM_REGION_PT]);
-	vm->mmu.pgd_created = true;
 }
 
 static void _virt_pg_map(struct kvm_vm *vm, gva_t gva, gpa_t gpa,
diff --git a/tools/testing/selftests/kvm/lib/loongarch/processor.c b/tools/testing/selftests/kvm/lib/loongarch/processor.c
index 64d91fb76522..207055db5f5d 100644
--- a/tools/testing/selftests/kvm/lib/loongarch/processor.c
+++ b/tools/testing/selftests/kvm/lib/loongarch/processor.c
@@ -51,9 +51,6 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)
 	int i;
 	gpa_t child, table;
 
-	if (vm->mmu.pgd_created)
-		return;
-
 	child = table = 0;
 	for (i = 0; i < vm->mmu.pgtable_levels; i++) {
 		invalid_pgtable[i] = child;
@@ -64,7 +61,6 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)
 		child = table;
 	}
 	vm->mmu.pgd = table;
-	vm->mmu.pgd_created = true;
 }
 
 static int virt_pte_none(u64 *ptep, int level)
diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c
index ded5429f3448..75a5d4c46001 100644
--- a/tools/testing/selftests/kvm/lib/riscv/processor.c
+++ b/tools/testing/selftests/kvm/lib/riscv/processor.c
@@ -66,13 +66,9 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)
 {
 	size_t nr_pages = vm_page_align(vm, ptrs_per_pte(vm) * 8) / vm->page_size;
 
-	if (vm->mmu.pgd_created)
-		return;
-
 	vm->mmu.pgd = vm_phy_pages_alloc(vm, nr_pages,
 					 KVM_GUEST_PAGE_TABLE_MIN_PADDR,
 					 vm->memslots[MEM_REGION_PT]);
-	vm->mmu.pgd_created = true;
 }
 
 void virt_arch_pg_map(struct kvm_vm *vm, gva_t gva, gpa_t gpa)
diff --git a/tools/testing/selftests/kvm/lib/s390/processor.c b/tools/testing/selftests/kvm/lib/s390/processor.c
index a9adb3782b35..342b7c92463e 100644
--- a/tools/testing/selftests/kvm/lib/s390/processor.c
+++ b/tools/testing/selftests/kvm/lib/s390/processor.c
@@ -17,16 +17,12 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)
 	TEST_ASSERT(vm->page_size == PAGE_SIZE, "Unsupported page size: 0x%x",
 		    vm->page_size);
 
-	if (vm->mmu.pgd_created)
-		return;
-
 	gpa = vm_phy_pages_alloc(vm, PAGES_PER_REGION,
 				   KVM_GUEST_PAGE_TABLE_MIN_PADDR,
 				   vm->memslots[MEM_REGION_PT]);
 	memset(addr_gpa2hva(vm, gpa), 0xff, PAGES_PER_REGION * vm->page_size);
 
 	vm->mmu.pgd = gpa;
-	vm->mmu.pgd_created = true;
 }
 
 /*
-- 
2.39.5



^ permalink raw reply related

* [RFC v2 2/5] KVM: selftests: Add aligned guest physical page allocator
From: Ritesh Harjani (IBM) @ 2026-05-23 11:14 UTC (permalink / raw)
  To: kvm
  Cc: linuxppc-dev, Madhavan Srinivasan, Harsh Prateek Bora,
	Christophe Leroy, Venkat Rao Bagalkote, Nicholas Piggin,
	Misbah Anjum N, Anushree Mathur, Michael Ellerman, linux-kernel,
	Ritesh Harjani (IBM)
In-Reply-To: <cover.1779524962.git.ritesh.list@gmail.com>

From: Nicholas Piggin <npiggin@gmail.com>

powerpc will require this to allocate MMU tables in guest memory that
are larger than guest base page size.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
[Rebased to latest mainline tree]
Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
---
 .../testing/selftests/kvm/include/kvm_util.h  | 20 +++++++++--
 tools/testing/selftests/kvm/lib/kvm_util.c    | 33 +++++++++----------
 2 files changed, 33 insertions(+), 20 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index 3666a8530f31..c515c918c2c9 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -991,8 +991,8 @@ void kvm_gsi_routing_write(struct kvm_vm *vm, struct kvm_irq_routing *routing);
 const char *exit_reason_str(unsigned int exit_reason);
 
 gpa_t vm_phy_page_alloc(struct kvm_vm *vm, gpa_t min_gpa, u32 memslot);
-gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, gpa_t min_gpa,
-			   u32 memslot, bool protected);
+gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, size_t align,
+			   gpa_t min_gpa, u32 memslot, bool protected);
 gpa_t vm_alloc_page_table(struct kvm_vm *vm);
 
 static inline gpa_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
@@ -1003,10 +1003,24 @@ static inline gpa_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
 	 * protected memory, as the majority of memory for such VMs is
 	 * protected, i.e. using shared memory is effectively opt-in.
 	 */
-	return __vm_phy_pages_alloc(vm, num, min_gpa, memslot,
+	return __vm_phy_pages_alloc(vm, num, 1, min_gpa, memslot,
 				    vm_arch_has_protected_memory(vm));
 }
 
+static inline gpa_t vm_phy_pages_alloc_align(struct kvm_vm *vm, size_t num,
+					     size_t align, gpa_t min_gpa,
+					     u32 memslot)
+{
+	/*
+	 * By default, allocate memory as protected for VMs that support
+	 * protected memory, as the majority of memory for such VMs is
+	 * protected, i.e. using shared memory is effectively opt-in.
+	 */
+	return __vm_phy_pages_alloc(vm, num, align, min_gpa, memslot,
+				    vm_arch_has_protected_memory(vm));
+}
+
+
 /*
  * ____vm_create() does KVM_CREATE_VM and little else.  __vm_create() also
  * loads the test binary into guest memory and creates an IRQ chip (x86 only).
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 2a76eca7029d..cdb004c9ba56 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -1442,7 +1442,7 @@ static gva_t ____vm_alloc(struct kvm_vm *vm, size_t sz, gva_t min_gva,
 	u64 pages = (sz >> vm->page_shift) + ((sz % vm->page_size) != 0);
 
 	virt_pgd_alloc(vm);
-	gpa_t gpa = __vm_phy_pages_alloc(vm, pages,
+	gpa_t gpa = __vm_phy_pages_alloc(vm, pages, 1,
 					   KVM_UTIL_MIN_PFN * vm->page_size,
 					   vm->memslots[type], protected);
 
@@ -2021,7 +2021,7 @@ const char *exit_reason_str(unsigned int exit_reason)
  * and their base address is returned. A TEST_ASSERT failure occurs if
  * not enough pages are available at or above min_gpa.
  */
-gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
+gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, size_t align,
 			   gpa_t min_gpa, u32 memslot,
 			   bool protected)
 {
@@ -2039,23 +2039,22 @@ gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
 	TEST_ASSERT(!protected || region->protected_phy_pages,
 		    "Region doesn't support protected memory");
 
-	base = pg = min_gpa >> vm->page_shift;
-	do {
-		for (; pg < base + num; ++pg) {
-			if (!sparsebit_is_set(region->unused_phy_pages, pg)) {
-				base = pg = sparsebit_next_set(region->unused_phy_pages, pg);
-				break;
+	base = min_gpa >> vm->page_shift;
+again:
+	base = (base + align - 1) & ~(align - 1);
+	for (pg = base; pg < base + num; ++pg) {
+		if (!sparsebit_is_set(region->unused_phy_pages, pg)) {
+			base = sparsebit_next_set(region->unused_phy_pages, pg);
+			if (!base) {
+				fprintf(stderr, "No guest physical page available, "
+					"min_gpa: 0x%lx page_size: 0x%x memslot: %u\n",
+					min_gpa, vm->page_size, memslot);
+				fputs("---- vm dump ----\n", stderr);
+				vm_dump(stderr, vm, 2);
+				abort();
 			}
+			goto again;
 		}
-	} while (pg && pg != base + num);
-
-	if (pg == 0) {
-		fprintf(stderr, "No guest physical page available, "
-			"min_gpa: 0x%lx page_size: 0x%x memslot: %u\n",
-			min_gpa, vm->page_size, memslot);
-		fputs("---- vm dump ----\n", stderr);
-		vm_dump(stderr, vm, 2);
-		abort();
 	}
 
 	for (pg = base; pg < base + num; ++pg) {
-- 
2.39.5



^ permalink raw reply related

* [RFC v2 3/5] KVM: PPC: selftests: add support for powerpc
From: Ritesh Harjani (IBM) @ 2026-05-23 11:14 UTC (permalink / raw)
  To: kvm
  Cc: linuxppc-dev, Madhavan Srinivasan, Harsh Prateek Bora,
	Christophe Leroy, Venkat Rao Bagalkote, Nicholas Piggin,
	Misbah Anjum N, Anushree Mathur, Michael Ellerman, linux-kernel,
	Ritesh Harjani (IBM)
In-Reply-To: <cover.1779524962.git.ritesh.list@gmail.com>

From: Nicholas Piggin <npiggin@gmail.com>

Implement KVM selftests support for powerpc (Book3S-64).

ucalls are implemented with an unsupported PAPR hcall number which will
always cause KVM to exit to userspace.

Virtual memory is implemented for the radix MMU, and only a base page
size is supported (both 4K and 64K).

Guest interrupts are taken in real-mode, so require a page allocated at
gRA 0x0. Interrupt entry is complicated because gVA:gRA is not 1:1
mapped (like the kernel is), so the MMU can not just be switched on and
off.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
[Rebased to latest mainline tree, add "cc" to clobber list and fix the
pagesize calculation in kvm_arch_vm_post_create()]
Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
---
 MAINTAINERS                                   |   2 +
 tools/testing/selftests/kvm/Makefile          |   2 +-
 tools/testing/selftests/kvm/Makefile.kvm      |  10 +
 .../testing/selftests/kvm/include/kvm_util.h  |   9 +
 .../selftests/kvm/include/powerpc/hcall.h     |  17 +
 .../kvm/include/powerpc/kvm_util_arch.h       |  22 +
 .../selftests/kvm/include/powerpc/ppc_asm.h   |  32 ++
 .../selftests/kvm/include/powerpc/processor.h |  38 ++
 .../selftests/kvm/include/powerpc/ucall.h     |  21 +
 tools/testing/selftests/kvm/lib/guest_modes.c |  20 +-
 tools/testing/selftests/kvm/lib/kvm_util.c    |   8 +
 .../selftests/kvm/lib/powerpc/handlers.S      |  93 ++++
 .../testing/selftests/kvm/lib/powerpc/hcall.c |  45 ++
 .../selftests/kvm/lib/powerpc/processor.c     | 484 ++++++++++++++++++
 .../testing/selftests/kvm/lib/powerpc/ucall.c |  22 +
 15 files changed, 822 insertions(+), 3 deletions(-)
 create mode 100644 tools/testing/selftests/kvm/include/powerpc/hcall.h
 create mode 100644 tools/testing/selftests/kvm/include/powerpc/kvm_util_arch.h
 create mode 100644 tools/testing/selftests/kvm/include/powerpc/ppc_asm.h
 create mode 100644 tools/testing/selftests/kvm/include/powerpc/processor.h
 create mode 100644 tools/testing/selftests/kvm/include/powerpc/ucall.h
 create mode 100644 tools/testing/selftests/kvm/lib/powerpc/handlers.S
 create mode 100644 tools/testing/selftests/kvm/lib/powerpc/hcall.c
 create mode 100644 tools/testing/selftests/kvm/lib/powerpc/processor.c
 create mode 100644 tools/testing/selftests/kvm/lib/powerpc/ucall.c

diff --git a/MAINTAINERS b/MAINTAINERS
index f1e5e4258e7b..3c876ea1198e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14118,6 +14118,8 @@ F:	arch/powerpc/include/asm/kvm*
 F:	arch/powerpc/include/uapi/asm/kvm*
 F:	arch/powerpc/kernel/kvm*
 F:	arch/powerpc/kvm/
+F:	tools/testing/selftests/kvm/*/powerpc/
+F:	tools/testing/selftests/kvm/powerpc/
 
 KERNEL VIRTUAL MACHINE FOR RISC-V (KVM/riscv)
 M:	Anup Patel <anup@brainfault.org>
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index f2b223072b62..03d91f00092f 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -3,7 +3,7 @@ top_srcdir = ../../../..
 include $(top_srcdir)/scripts/subarch.include
 ARCH            ?= $(SUBARCH)
 
-ifeq ($(ARCH),$(filter $(ARCH),arm64 s390 riscv x86 x86_64 loongarch))
+ifeq ($(ARCH),$(filter $(ARCH),arm64 s390 riscv x86 x86_64 loongarch powerpc))
 # Top-level selftests allows ARCH=x86_64 :-(
 ifeq ($(ARCH),x86_64)
 	override ARCH := x86
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 9118a5a51b89..825bea7f851d 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -52,6 +52,11 @@ LIBKVM_loongarch += lib/loongarch/processor.c
 LIBKVM_loongarch += lib/loongarch/ucall.c
 LIBKVM_loongarch += lib/loongarch/exception.S
 
+LIBKVM_powerpc += lib/powerpc/handlers.S
+LIBKVM_powerpc += lib/powerpc/processor.c
+LIBKVM_powerpc += lib/powerpc/ucall.c
+LIBKVM_powerpc += lib/powerpc/hcall.c
+
 # Non-compiled test targets
 TEST_PROGS_x86 += x86/nx_huge_pages_test.sh
 
@@ -239,6 +244,11 @@ TEST_GEN_PROGS_loongarch += memslot_perf_test
 TEST_GEN_PROGS_loongarch += set_memory_region_test
 TEST_GEN_PROGS_loongarch += steal_time
 
+TEST_GEN_PROGS_powerpc = $(TEST_GEN_PROGS_COMMON)
+TEST_GEN_PROGS_powerpc += access_tracking_perf_test
+TEST_GEN_PROGS_powerpc += dirty_log_perf_test
+TEST_GEN_PROGS_powerpc += hardware_disable_test
+
 SPLIT_TESTS += arch_timer
 SPLIT_TESTS += get-reg-list
 
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index c515c918c2c9..10f03a182c8b 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -209,6 +209,9 @@ enum vm_guest_mode {
 	VM_MODE_P41V48_4K,
 	VM_MODE_P41V39_4K,
 
+	VM_MODE_P52V52_4K,	/* For powerpc64 */
+	VM_MODE_P52V52_64K,
+
 	NUM_VM_MODES,
 };
 
@@ -268,6 +271,12 @@ extern enum vm_guest_mode vm_mode_default;
 #define MIN_PAGE_SHIFT			12U
 #define ptes_per_page(page_size)	((page_size) / 8)
 
+#elif defined(__powerpc64__)
+
+#define VM_MODE_DEFAULT			vm_mode_default
+#define MIN_PAGE_SHIFT			12U
+#define ptes_per_page(page_size)	((page_size) / 8)
+
 #endif
 
 #define VM_SHAPE_DEFAULT	VM_SHAPE(VM_MODE_DEFAULT)
diff --git a/tools/testing/selftests/kvm/include/powerpc/hcall.h b/tools/testing/selftests/kvm/include/powerpc/hcall.h
new file mode 100644
index 000000000000..4028baa6c5d8
--- /dev/null
+++ b/tools/testing/selftests/kvm/include/powerpc/hcall.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * powerpc hcall defines
+ */
+#ifndef SELFTEST_KVM_HCALL_H
+#define SELFTEST_KVM_HCALL_H
+
+#include <linux/compiler.h>
+
+/* Ucalls use unimplemented PAPR hcall 0 which exits KVM */
+#define H_UCALL	0
+
+int64_t hcall0(uint64_t token);
+int64_t hcall1(uint64_t token, uint64_t arg1);
+int64_t hcall2(uint64_t token, uint64_t arg1, uint64_t arg2);
+
+#endif
diff --git a/tools/testing/selftests/kvm/include/powerpc/kvm_util_arch.h b/tools/testing/selftests/kvm/include/powerpc/kvm_util_arch.h
new file mode 100644
index 000000000000..5d45c25cd299
--- /dev/null
+++ b/tools/testing/selftests/kvm/include/powerpc/kvm_util_arch.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef SELFTEST_KVM_UTIL_ARCH_H
+#define SELFTEST_KVM_UTIL_ARCH_H
+
+#include <stdint.h>
+
+#include "kvm_util_types.h"
+
+struct kvm_mmu_arch {};
+
+/* Page table fragment cache for guest page tables < page size */
+struct vm_pt_frag_cache {
+	gpa_t page;
+	size_t page_nr_used;
+};
+
+struct kvm_vm_arch {
+	gpa_t prtb; /* process table */
+	struct vm_pt_frag_cache pt_frag_cache[2]; /* 256B and 4KB PT caches */
+};
+
+#endif  /* SELFTEST_KVM_UTIL_ARCH_H */
diff --git a/tools/testing/selftests/kvm/include/powerpc/ppc_asm.h b/tools/testing/selftests/kvm/include/powerpc/ppc_asm.h
new file mode 100644
index 000000000000..b9df64659792
--- /dev/null
+++ b/tools/testing/selftests/kvm/include/powerpc/ppc_asm.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * powerpc asm specific defines
+ */
+#ifndef SELFTEST_KVM_PPC_ASM_H
+#define SELFTEST_KVM_PPC_ASM_H
+
+#define STACK_FRAME_MIN_SIZE	112 /* Could be 32 on ELFv2 */
+#define STACK_REDZONE_SIZE	512
+
+#define INT_FRAME_SIZE		(STACK_FRAME_MIN_SIZE + STACK_REDZONE_SIZE)
+
+#define SPR_SRR0	0x01a
+#define SPR_SRR1	0x01b
+#define SPR_CFAR	0x01c
+
+#define MSR_SF		0x8000000000000000ULL
+#define MSR_HV		0x1000000000000000ULL
+#define MSR_VEC		0x0000000002000000ULL
+#define MSR_VSX		0x0000000000800000ULL
+#define MSR_EE		0x0000000000008000ULL
+#define MSR_PR		0x0000000000004000ULL
+#define MSR_FP		0x0000000000002000ULL
+#define MSR_ME		0x0000000000001000ULL
+#define MSR_IR		0x0000000000000020ULL
+#define MSR_DR		0x0000000000000010ULL
+#define MSR_RI		0x0000000000000002ULL
+#define MSR_LE		0x0000000000000001ULL
+
+#define LPCR_ILE	0x0000000002000000ULL
+
+#endif
diff --git a/tools/testing/selftests/kvm/include/powerpc/processor.h b/tools/testing/selftests/kvm/include/powerpc/processor.h
new file mode 100644
index 000000000000..cb75b77c33bb
--- /dev/null
+++ b/tools/testing/selftests/kvm/include/powerpc/processor.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * powerpc processor specific defines
+ */
+#ifndef SELFTEST_KVM_PROCESSOR_H
+#define SELFTEST_KVM_PROCESSOR_H
+
+#include <linux/compiler.h>
+#include "ppc_asm.h"
+
+extern unsigned char __interrupts_start[];
+extern unsigned char __interrupts_end[];
+
+struct kvm_vm;
+struct kvm_vcpu;
+
+struct ex_regs {
+	uint64_t	gprs[32];
+	uint64_t	nia;
+	uint64_t	msr;
+	uint64_t	cfar;
+	uint64_t	lr;
+	uint64_t	ctr;
+	uint64_t	xer;
+	uint32_t	cr;
+	uint32_t	trap;
+	uint64_t	vaddr; /* vaddr of this struct */
+};
+
+void vm_install_exception_handler(struct kvm_vm *vm, int vector,
+			void (*handler)(struct ex_regs *));
+
+static inline void cpu_relax(void)
+{
+	asm volatile("" ::: "memory");
+}
+
+#endif
diff --git a/tools/testing/selftests/kvm/include/powerpc/ucall.h b/tools/testing/selftests/kvm/include/powerpc/ucall.h
new file mode 100644
index 000000000000..e0dbe91e8848
--- /dev/null
+++ b/tools/testing/selftests/kvm/include/powerpc/ucall.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef SELFTEST_KVM_UCALL_H
+#define SELFTEST_KVM_UCALL_H
+
+#include "hcall.h"
+
+#define UCALL_EXIT_REASON	KVM_EXIT_PAPR_HCALL
+
+#define UCALL_R4_UCALL	0x5715 /* regular ucall, r5 contains ucall pointer */
+#define UCALL_R4_SIMPLE	0x0000 /* simple exit usable by asm with no ucall data */
+
+static inline void ucall_arch_init(struct kvm_vm *vm, gpa_t mmio_gpa)
+{
+}
+
+static inline void ucall_arch_do_ucall(gva_t uc)
+{
+	hcall2(H_UCALL, UCALL_R4_UCALL, (uintptr_t)(uc));
+}
+
+#endif
diff --git a/tools/testing/selftests/kvm/lib/guest_modes.c b/tools/testing/selftests/kvm/lib/guest_modes.c
index 7a96c43b5704..439766fad693 100644
--- a/tools/testing/selftests/kvm/lib/guest_modes.c
+++ b/tools/testing/selftests/kvm/lib/guest_modes.c
@@ -4,16 +4,20 @@
  */
 #include "guest_modes.h"
 
-#if defined(__aarch64__) || defined(__riscv)
+#if defined(__aarch64__) || defined(__riscv) || defined(__powerpc64__)
 #include "processor.h"
 enum vm_guest_mode vm_mode_default;
 #endif
 
+#if defined(__powerpc64__)
+#include <unistd.h>
+#endif
+
 struct guest_mode guest_modes[NUM_VM_MODES];
 
 void guest_modes_append_default(void)
 {
-#if !defined(__aarch64__) && !defined(__riscv)
+#if !defined(__aarch64__) && !defined(__riscv) && !defined(__powerpc64__)
 	guest_mode_append(VM_MODE_DEFAULT, true);
 #endif
 
@@ -108,6 +112,18 @@ void guest_modes_append_default(void)
 		TEST_ASSERT(vm_mode_default != NUM_VM_MODES, "No supported mode!");
 	}
 #endif
+#ifdef __powerpc64__
+	{
+		TEST_REQUIRE(kvm_has_cap(KVM_CAP_PPC_MMU_RADIX));
+		/* Radix guest EA and RA are 52-bit on POWER9 and POWER10 */
+		if (sysconf(_SC_PAGESIZE) == 4096)
+			vm_mode_default = VM_MODE_P52V52_4K;
+		else
+			vm_mode_default = VM_MODE_P52V52_64K;
+		guest_mode_append(VM_MODE_P52V52_4K, true);
+		guest_mode_append(VM_MODE_P52V52_64K, true);
+	}
+#endif
 }
 
 void for_each_guest_mode(void (*func)(enum vm_guest_mode, void *), void *arg)
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index cdb004c9ba56..0dc67c1502cf 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -218,6 +218,8 @@ const char *vm_guest_mode_string(u32 i)
 		[VM_MODE_P41V57_4K]	= "PA-bits:41,  VA-bits:57,  4K pages",
 		[VM_MODE_P41V48_4K]	= "PA-bits:41,  VA-bits:48,  4K pages",
 		[VM_MODE_P41V39_4K]	= "PA-bits:41,  VA-bits:39,  4K pages",
+		[VM_MODE_P52V52_4K]	= "PA-bits:52,  VA-bits:52,  4K pages",
+		[VM_MODE_P52V52_64K]	= "PA-bits:52,  VA-bits:52, 64K pages",
 	};
 	_Static_assert(sizeof(strings)/sizeof(char *) == NUM_VM_MODES,
 		       "Missing new mode strings?");
@@ -254,6 +256,8 @@ const struct vm_guest_mode_params vm_guest_mode_params[] = {
 	[VM_MODE_P41V57_4K]	= { 41, 57,  0x1000, 12 },
 	[VM_MODE_P41V48_4K]	= { 41, 48,  0x1000, 12 },
 	[VM_MODE_P41V39_4K]	= { 41, 39,  0x1000, 12 },
+	[VM_MODE_P52V52_4K]	= { 52, 52,  0x1000, 12 },
+	[VM_MODE_P52V52_64K]	= { 52, 52, 0x10000, 16 },
 };
 _Static_assert(sizeof(vm_guest_mode_params)/sizeof(struct vm_guest_mode_params) == NUM_VM_MODES,
 	       "Missing new mode params?");
@@ -371,6 +375,10 @@ struct kvm_vm *____vm_create(struct vm_shape shape)
 	case VM_MODE_P41V39_4K:
 		vm->mmu.pgtable_levels = 3;
 		break;
+	case VM_MODE_P52V52_4K:
+	case VM_MODE_P52V52_64K:
+		vm->mmu.pgtable_levels = 4;
+		break;
 	default:
 		TEST_FAIL("Unknown guest mode: 0x%x", vm->mode);
 	}
diff --git a/tools/testing/selftests/kvm/lib/powerpc/handlers.S b/tools/testing/selftests/kvm/lib/powerpc/handlers.S
new file mode 100644
index 000000000000..b860f6a520a1
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/powerpc/handlers.S
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <ppc_asm.h>
+
+.macro INTERRUPT vec
+. = __interrupts_start + \vec
+	std	%r0,(0*8)(%r13)
+	std	%r3,(3*8)(%r13)
+	mfspr	%r0,SPR_CFAR
+	li	%r3,\vec
+	b	handle_interrupt
+.endm
+
+.balign 0x1000
+.global __interrupts_start
+__interrupts_start:
+INTERRUPT 0x100
+INTERRUPT 0x200
+INTERRUPT 0x300
+INTERRUPT 0x380
+INTERRUPT 0x400
+INTERRUPT 0x480
+INTERRUPT 0x500
+INTERRUPT 0x600
+INTERRUPT 0x700
+INTERRUPT 0x800
+INTERRUPT 0x900
+INTERRUPT 0xa00
+INTERRUPT 0xc00
+INTERRUPT 0xd00
+INTERRUPT 0xf00
+INTERRUPT 0xf20
+INTERRUPT 0xf40
+INTERRUPT 0xf60
+
+virt_handle_interrupt:
+	stdu	%r1,-INT_FRAME_SIZE(%r1)
+	mr	%r3,%r31
+	bl	route_interrupt
+	ld	%r4,(32*8)(%r31) /* NIA */
+	ld	%r5,(33*8)(%r31) /* MSR */
+	ld	%r6,(35*8)(%r31) /* LR */
+	ld	%r7,(36*8)(%r31) /* CTR */
+	ld	%r8,(37*8)(%r31) /* XER */
+	lwz	%r9,(38*8)(%r31) /* CR */
+	mtspr	SPR_SRR0,%r4
+	mtspr	SPR_SRR1,%r5
+	mtlr	%r6
+	mtctr	%r7
+	mtxer	%r8
+	mtcr	%r9
+reg=4
+	ld	%r0,(0*8)(%r31)
+	ld	%r3,(3*8)(%r31)
+.rept 28
+	ld	reg,(reg*8)(%r31)
+	reg=reg+1
+.endr
+	addi	%r1,%r1,INT_FRAME_SIZE
+	rfid
+
+virt_handle_interrupt_p:
+	.llong virt_handle_interrupt
+
+handle_interrupt:
+reg=4
+.rept 28
+	std	reg,(reg*8)(%r13)
+	reg=reg+1
+.endr
+	mfspr	%r4,SPR_SRR0
+	mfspr	%r5,SPR_SRR1
+	mflr	%r6
+	mfctr	%r7
+	mfxer	%r8
+	mfcr	%r9
+	std	%r4,(32*8)(%r13) /* NIA */
+	std	%r5,(33*8)(%r13) /* MSR */
+	std	%r0,(34*8)(%r13) /* CFAR */
+	std	%r6,(35*8)(%r13) /* LR */
+	std	%r7,(36*8)(%r13) /* CTR */
+	std	%r8,(37*8)(%r13) /* XER */
+	stw	%r9,(38*8 + 0)(%r13) /* CR */
+	stw	%r3,(38*8 + 4)(%r13) /* TRAP */
+
+	ld	%r31,(39*8)(%r13) /* vaddr */
+	ld	%r4,virt_handle_interrupt_p - __interrupts_start(0)
+	mtspr	SPR_SRR0,%r4
+	/* Reuse SRR1 */
+
+	rfid
+.global __interrupts_end
+__interrupts_end:
diff --git a/tools/testing/selftests/kvm/lib/powerpc/hcall.c b/tools/testing/selftests/kvm/lib/powerpc/hcall.c
new file mode 100644
index 000000000000..efb4318252be
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/powerpc/hcall.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PAPR (pseries) hcall support.
+ */
+#include "kvm_util.h"
+#include "hcall.h"
+
+int64_t hcall0(uint64_t token)
+{
+	register uintptr_t r3 asm ("r3") = token;
+
+	asm volatile("sc 1" : "+r"(r3) :
+			    : "r0", "r4", "r5", "r6", "r7", "r8", "r9",
+			      "r10", "r11", "r12", "ctr", "xer",
+			      "cc", "memory");
+
+	return r3;
+}
+
+int64_t hcall1(uint64_t token, uint64_t arg1)
+{
+	register uintptr_t r3 asm ("r3") = token;
+	register uintptr_t r4 asm ("r4") = arg1;
+
+	asm volatile("sc 1" : "+r"(r3), "+r"(r4) :
+			    : "r0", "r5", "r6", "r7", "r8", "r9",
+			      "r10", "r11", "r12", "ctr", "xer",
+			      "cc", "memory");
+
+	return r3;
+}
+
+int64_t hcall2(uint64_t token, uint64_t arg1, uint64_t arg2)
+{
+	register uintptr_t r3 asm ("r3") = token;
+	register uintptr_t r4 asm ("r4") = arg1;
+	register uintptr_t r5 asm ("r5") = arg2;
+
+	asm volatile("sc 1" : "+r"(r3), "+r"(r4), "+r"(r5) :
+			    : "r0", "r6", "r7", "r8", "r9",
+			      "r10", "r11", "r12", "ctr", "xer",
+			      "cc", "memory");
+
+	return r3;
+}
diff --git a/tools/testing/selftests/kvm/lib/powerpc/processor.c b/tools/testing/selftests/kvm/lib/powerpc/processor.c
new file mode 100644
index 000000000000..310c67a00b95
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/powerpc/processor.c
@@ -0,0 +1,484 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * KVM selftest powerpc library code - CPU-related functions (page tables...)
+ */
+
+#include <linux/sizes.h>
+
+#include "processor.h"
+#include "kvm_util.h"
+#include "ucall_common.h"
+#include "guest_modes.h"
+#include "hcall.h"
+
+#define RADIX_TREE_SIZE ((0x2UL << 61) | (0x5UL << 5)) /* 52-bits */
+#define RADIX_PGD_INDEX_SIZE 13
+
+static void set_proc_table(struct kvm_vm *vm, int pid, uint64_t dw0, uint64_t dw1)
+{
+	uint64_t *proc_table;
+
+	proc_table = addr_gpa2hva(vm, vm->arch.prtb);
+	proc_table[pid * 2 + 0] = cpu_to_be64(dw0);
+	proc_table[pid * 2 + 1] = cpu_to_be64(dw1);
+}
+
+static void set_radix_proc_table(struct kvm_vm *vm, int pid, gpa_t pgd)
+{
+	set_proc_table(vm, pid, pgd | RADIX_TREE_SIZE | RADIX_PGD_INDEX_SIZE, 0);
+}
+
+void virt_arch_pgd_alloc(struct kvm_vm *vm)
+{
+	struct kvm_ppc_mmuv3_cfg mmu_cfg;
+	gpa_t prtb, pgtb;
+	size_t pgd_pages;
+
+	TEST_ASSERT((vm->mode == VM_MODE_P52V52_4K) ||
+		    (vm->mode == VM_MODE_P52V52_64K),
+		    "Unsupported guest mode, mode: 0x%x", vm->mode);
+
+	prtb = vm_phy_page_alloc(vm, KVM_GUEST_PAGE_TABLE_MIN_PADDR,
+				 vm->memslots[MEM_REGION_PT]);
+	vm->arch.prtb = prtb;
+
+	pgd_pages = (1UL << (RADIX_PGD_INDEX_SIZE + 3)) >> vm->page_shift;
+	if (!pgd_pages)
+		pgd_pages = 1;
+	pgtb = vm_phy_pages_alloc_align(vm, pgd_pages, pgd_pages,
+					KVM_GUEST_PAGE_TABLE_MIN_PADDR,
+					vm->memslots[MEM_REGION_PT]);
+	vm->mmu.pgd = pgtb;
+
+	/* Set the base page directory in the proc table */
+	set_radix_proc_table(vm, 0, pgtb);
+
+	if (vm->mode == VM_MODE_P52V52_4K)
+		mmu_cfg.process_table = prtb | 0x8000000000000000UL | 0x0; /* 4K size */
+	else /* vm->mode == VM_MODE_P52V52_64K */
+		mmu_cfg.process_table = prtb | 0x8000000000000000UL | 0x4; /* 64K size */
+	mmu_cfg.flags = KVM_PPC_MMUV3_RADIX | KVM_PPC_MMUV3_GTSE;
+
+	vm_ioctl(vm, KVM_PPC_CONFIGURE_V3_MMU, &mmu_cfg);
+}
+
+static int pt_shift(struct kvm_vm *vm, int level)
+{
+	switch (level) {
+	case 1:
+		return 13;
+	case 2:
+	case 3:
+		return 9;
+	case 4:
+		if (vm->mode == VM_MODE_P52V52_4K)
+			return 9;
+		else /* vm->mode == VM_MODE_P52V52_64K */
+			return 5;
+	default:
+		TEST_ASSERT(false, "Invalid page table level %d\n", level);
+		return 0;
+	}
+}
+
+static uint64_t pt_entry_coverage(struct kvm_vm *vm, int level)
+{
+	uint64_t size = vm->page_size;
+
+	if (level == 4)
+		return size;
+	size <<= pt_shift(vm, 4);
+	if (level == 3)
+		return size;
+	size <<= pt_shift(vm, 3);
+	if (level == 2)
+		return size;
+	size <<= pt_shift(vm, 2);
+	return size;
+}
+
+static int pt_idx(struct kvm_vm *vm, uint64_t vaddr, int level, uint64_t *nls)
+{
+	switch (level) {
+	case 1:
+		if (nls)
+			*nls = 0x9;
+		return (vaddr >> 39) & 0x1fff;
+	case 2:
+		if (nls)
+			*nls = 0x9;
+		return (vaddr >> 30) & 0x1ff;
+	case 3:
+		if (vm->mode == VM_MODE_P52V52_4K) {
+			if (nls)
+				*nls = 0x9;
+		} else { /* vm->mode == VM_MODE_P52V52_64K */
+			if (nls)
+				*nls = 0x5;
+		}
+		return (vaddr >> 21) & 0x1ff;
+	case 4:
+		if (vm->mode == VM_MODE_P52V52_4K)
+			return (vaddr >> 12) & 0x1ff;
+		else /* vm->mode == VM_MODE_P52V52_64K */
+			return (vaddr >> 16) & 0x1f;
+	default:
+		TEST_ASSERT(false, "Invalid page table level %d\n", level);
+		return 0;
+	}
+}
+
+static uint64_t *virt_get_pte(struct kvm_vm *vm, gpa_t pt,
+			  uint64_t vaddr, int level, uint64_t *nls)
+{
+	int idx = pt_idx(vm, vaddr, level, nls);
+	uint64_t *ptep = addr_gpa2hva(vm, pt + idx * 8);
+
+	return ptep;
+}
+
+#define PTE_VALID	0x8000000000000000ull
+#define PTE_LEAF	0x4000000000000000ull
+#define PTE_REFERENCED	0x0000000000000100ull
+#define PTE_CHANGED	0x0000000000000080ull
+#define PTE_PRIV	0x0000000000000008ull
+#define PTE_READ	0x0000000000000004ull
+#define PTE_RW		0x0000000000000002ull
+#define PTE_EXEC	0x0000000000000001ull
+#define PTE_PAGE_MASK	0x01fffffffffff000ull
+
+#define PDE_VALID	PTE_VALID
+#define PDE_NLS		0x0000000000000011ull
+#define PDE_PT_MASK	0x0fffffffffffff00ull
+
+static gpa_t __vm_alloc_pt(struct kvm_vm *vm, uint64_t pt_shift)
+{
+	gpa_t pt;
+
+	if (pt_shift >= vm->page_shift) {
+		size_t pt_pages = 1ULL << (pt_shift - vm->page_shift);
+
+		pt = vm_phy_pages_alloc_align(vm, pt_pages, pt_pages,
+					KVM_GUEST_PAGE_TABLE_MIN_PADDR,
+					vm->memslots[MEM_REGION_PT]);
+	} else {
+		struct vm_pt_frag_cache *pt_frag_cache;
+
+		if (pt_shift == 8) {
+			pt_frag_cache = &vm->arch.pt_frag_cache[0];
+		} else if (pt_shift == 12) {
+			pt_frag_cache = &vm->arch.pt_frag_cache[1];
+		} else {
+			TEST_ASSERT(0, "Invalid pt_shift:%lu\n", pt_shift);
+			return 0;
+		}
+
+		if (!pt_frag_cache->page) {
+			pt_frag_cache->page = vm_phy_pages_alloc_align(vm, 1, 1,
+						KVM_GUEST_PAGE_TABLE_MIN_PADDR,
+						vm->memslots[MEM_REGION_PT]);
+		}
+		pt = pt_frag_cache->page + pt_frag_cache->page_nr_used;
+		pt_frag_cache->page_nr_used += (1 << pt_shift);
+		if (pt_frag_cache->page_nr_used == vm->page_size) {
+			pt_frag_cache->page = 0;
+			pt_frag_cache->page_nr_used = 0;
+		}
+	}
+
+	return pt;
+}
+
+void virt_arch_pg_map(struct kvm_vm *vm, uint64_t gva, uint64_t gpa)
+{
+	gpa_t pt = vm->mmu.pgd;
+	uint64_t *ptep, pte;
+	int level;
+
+	for (level = 1; level <= 3; level++) {
+		uint64_t nls;
+		uint64_t *pdep = virt_get_pte(vm, pt, gva, level, &nls);
+		uint64_t pde = be64_to_cpu(*pdep);
+
+		if (pde) {
+			TEST_ASSERT((pde & PDE_VALID) && !(pde & PTE_LEAF),
+				    "Invalid PDE at level: %u gva: 0x%lx pde:0x%lx\n",
+				    level, gva, pde);
+			pt = pde & PDE_PT_MASK;
+			continue;
+		}
+
+		pt = __vm_alloc_pt(vm, nls + 3);
+		pde = PDE_VALID | nls | pt;
+		*pdep = cpu_to_be64(pde);
+	}
+
+	ptep = virt_get_pte(vm, pt, gva, level, NULL);
+	pte = be64_to_cpu(*ptep);
+
+	TEST_ASSERT(!pte, "PTE already present at level: %u gva: 0x%lx pte:0x%lx\n",
+		    level, gva, pte);
+
+	pte = PTE_VALID | PTE_LEAF | PTE_REFERENCED | PTE_CHANGED | PTE_PRIV |
+	      PTE_READ | PTE_RW | PTE_EXEC | (gpa & PTE_PAGE_MASK);
+	*ptep = cpu_to_be64(pte);
+}
+
+gpa_t addr_arch_gva2gpa(struct kvm_vm *vm, gva_t gva)
+{
+	gpa_t pt = vm->mmu.pgd;
+	uint64_t *ptep, pte;
+	int level;
+
+	for (level = 1; level <= 3; level++) {
+		uint64_t nls;
+		uint64_t *pdep = virt_get_pte(vm, pt, gva, level, &nls);
+		uint64_t pde = be64_to_cpu(*pdep);
+
+		TEST_ASSERT((pde & PDE_VALID) && !(pde & PTE_LEAF),
+			"PDE not present at level: %u gva: 0x%lx pde:0x%lx\n",
+			level, gva, pde);
+		pt = pde & PDE_PT_MASK;
+	}
+
+	ptep = virt_get_pte(vm, pt, gva, level, NULL);
+	pte = be64_to_cpu(*ptep);
+
+	TEST_ASSERT(pte,
+		"PTE not present at level: %u gva: 0x%lx pte:0x%lx\n",
+		level, gva, pte);
+
+	TEST_ASSERT((pte & PTE_VALID) && (pte & PTE_LEAF) &&
+		    (pte & PTE_READ) && (pte & PTE_RW) && (pte & PTE_EXEC),
+		    "PTE not valid at level: %u gva: 0x%lx pte:0x%lx\n",
+		    level, gva, pte);
+
+	return (pte & PTE_PAGE_MASK) + (gva & (vm->page_size - 1));
+}
+
+static void virt_dump_pt(FILE *stream, struct kvm_vm *vm, gpa_t pt,
+			 gva_t va, int level, uint8_t indent)
+{
+	int size, idx;
+
+	size = 1U << (pt_shift(vm, level) + 3);
+
+	for (idx = 0; idx < size; idx += 8, va += pt_entry_coverage(vm, level)) {
+		uint64_t *page_table = addr_gpa2hva(vm, pt + idx);
+		uint64_t pte = be64_to_cpu(*page_table);
+
+		if (!(pte & PTE_VALID))
+			continue;
+
+		if (pte & PTE_LEAF) {
+			fprintf(stream,
+				"%*s PTE[%d] gVA:0x%016lx -> gRA:0x%016llx\n",
+				indent, "", idx / 8, va, pte & PTE_PAGE_MASK);
+		} else {
+			fprintf(stream, "%*sPDE%d[%d] gVA:0x%016lx\n",
+				indent, "", level, idx / 8, va);
+			virt_dump_pt(stream, vm, pte & PDE_PT_MASK, va,
+				     level + 1, indent + 2);
+		}
+	}
+
+}
+
+void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
+{
+	gpa_t pt = vm->mmu.pgd;
+
+	if (!vm->mmu.pgd_created)
+		return;
+
+	virt_dump_pt(stream, vm, pt, 0, 1, indent);
+}
+
+static unsigned long get_r2(void)
+{
+	unsigned long r2;
+
+	asm("mr %0,%%r2" : "=r"(r2));
+
+	return r2;
+}
+
+void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code)
+{
+	struct kvm_regs regs;
+
+	vcpu_regs_get(vcpu, &regs);
+	regs.pc = (uintptr_t)guest_code;
+	regs.gpr[12] = (uintptr_t)guest_code;
+	vcpu_regs_set(vcpu, &regs);
+}
+
+struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
+{
+	const size_t stack_size = SZ_64K;
+	gva_t stack_vaddr, ex_regs_vaddr;
+	gpa_t ex_regs_paddr;
+	struct ex_regs *ex_regs;
+	struct kvm_regs regs;
+	struct kvm_vcpu *vcpu;
+	uint64_t lpcr;
+
+	stack_vaddr = __vm_alloc(vm, stack_size,
+				       DEFAULT_GUEST_STACK_VADDR_MIN,
+				       MEM_REGION_DATA);
+
+	ex_regs_vaddr = __vm_alloc(vm, stack_size,
+				       DEFAULT_GUEST_STACK_VADDR_MIN,
+				       MEM_REGION_DATA);
+	ex_regs_paddr = addr_gva2gpa(vm, ex_regs_vaddr);
+	ex_regs = addr_gpa2hva(vm, ex_regs_paddr);
+	ex_regs->vaddr = ex_regs_vaddr;
+
+	vcpu = __vm_vcpu_add(vm, vcpu_id);
+
+	vcpu_enable_cap(vcpu, KVM_CAP_PPC_PAPR, 1);
+
+	/* Setup guest registers */
+	vcpu_regs_get(vcpu, &regs);
+	lpcr = vcpu_get_reg(vcpu, KVM_REG_PPC_LPCR_64);
+
+	regs.gpr[1] = stack_vaddr + stack_size - 256;
+	regs.gpr[2] = (uintptr_t)get_r2();
+	regs.gpr[13] = (uintptr_t)ex_regs_paddr;
+
+	regs.msr = MSR_SF | MSR_VEC | MSR_VSX | MSR_FP |
+		   MSR_ME | MSR_IR | MSR_DR | MSR_RI;
+
+	if (BYTE_ORDER == LITTLE_ENDIAN) {
+		regs.msr |= MSR_LE;
+		lpcr |= LPCR_ILE;
+	} else {
+		lpcr &= ~LPCR_ILE;
+	}
+
+	vcpu_regs_set(vcpu, &regs);
+	vcpu_set_reg(vcpu, KVM_REG_PPC_LPCR_64, lpcr);
+
+	return vcpu;
+}
+
+void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...)
+{
+	va_list ap;
+	struct kvm_regs regs;
+	int i;
+
+	TEST_ASSERT(num >= 1 && num <= 5, "Unsupported number of args: %u\n",
+		    num);
+
+	va_start(ap, num);
+	vcpu_regs_get(vcpu, &regs);
+
+	for (i = 0; i < num; i++)
+		regs.gpr[i + 3] = va_arg(ap, uint64_t);
+
+	vcpu_regs_set(vcpu, &regs);
+	va_end(ap);
+}
+
+void vcpu_arch_dump(FILE *stream, struct kvm_vcpu *vcpu, uint8_t indent)
+{
+	struct kvm_regs regs;
+
+	vcpu_regs_get(vcpu, &regs);
+
+	fprintf(stream, "%*sNIA: 0x%016llx  MSR: 0x%016llx\n",
+			indent, "", regs.pc, regs.msr);
+	fprintf(stream, "%*sLR:  0x%016llx  CTR :0x%016llx\n",
+			indent, "", regs.lr, regs.ctr);
+	fprintf(stream, "%*sCR:  0x%08llx          XER :0x%016llx\n",
+			indent, "", regs.cr, regs.xer);
+}
+
+void kvm_arch_vm_post_create(struct kvm_vm *vm, unsigned int nr_vcpus)
+{
+	size_t excp_size = __interrupts_end - __interrupts_start;
+	size_t excp_pages = (excp_size + vm->page_size - 1) / vm->page_size;
+	gpa_t excp_paddr;
+	void *mem;
+
+	excp_paddr = vm_phy_pages_alloc(vm, excp_pages, 0,
+					vm->memslots[MEM_REGION_DATA]);
+
+	TEST_ASSERT(excp_paddr == 0,
+		    "Interrupt vectors not allocated at gPA address 0: (0x%lx)",
+		    excp_paddr);
+
+	mem = addr_gpa2hva(vm, excp_paddr);
+	memcpy(mem, __interrupts_start, excp_size);
+}
+
+void assert_on_unhandled_exception(struct kvm_vcpu *vcpu)
+{
+	struct ucall uc;
+
+	if (get_ucall(vcpu, &uc) == UCALL_UNHANDLED) {
+		gpa_t ex_regs_paddr;
+		struct ex_regs *ex_regs;
+		struct kvm_regs regs;
+
+		vcpu_regs_get(vcpu, &regs);
+		ex_regs_paddr = (gpa_t)regs.gpr[13];
+		ex_regs = addr_gpa2hva(vcpu->vm, ex_regs_paddr);
+
+		TEST_FAIL("Unexpected interrupt in guest NIA:0x%016lx MSR:0x%016lx TRAP:0x%04x",
+			  ex_regs->nia, ex_regs->msr, ex_regs->trap);
+	}
+}
+
+struct handler {
+	void (*fn)(struct ex_regs *regs);
+	int trap;
+};
+
+#define NR_HANDLERS	10
+static struct handler handlers[NR_HANDLERS];
+
+void route_interrupt(struct ex_regs *regs)
+{
+	int i;
+
+	for (i = 0; i < NR_HANDLERS; i++) {
+		if (handlers[i].trap == regs->trap) {
+			handlers[i].fn(regs);
+			return;
+		}
+	}
+
+	ucall(UCALL_UNHANDLED, 0);
+}
+
+void vm_install_exception_handler(struct kvm_vm *vm, int trap,
+			       void (*fn)(struct ex_regs *))
+{
+	int i;
+
+	for (i = 0; i < NR_HANDLERS; i++) {
+		if (!handlers[i].trap || handlers[i].trap == trap) {
+			if (fn == NULL)
+				trap = 0; /* Clear handler */
+			handlers[i].trap = trap;
+			handlers[i].fn = fn;
+			sync_global_to_guest(vm, handlers[i]);
+			return;
+		}
+	}
+
+	TEST_FAIL("Out of exception handlers");
+}
+
+void kvm_selftest_arch_init(void)
+{
+	TEST_REQUIRE(kvm_has_cap(KVM_CAP_PPC_MMU_RADIX));
+
+	/*
+	 * powerpc default mode is set by host page size and not static,
+	 * so start by computing that early.
+	 */
+	guest_modes_append_default();
+}
diff --git a/tools/testing/selftests/kvm/lib/powerpc/ucall.c b/tools/testing/selftests/kvm/lib/powerpc/ucall.c
new file mode 100644
index 000000000000..3481a7a0b850
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/powerpc/ucall.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ucall support. A ucall is a "hypercall to host userspace".
+ */
+#include "kvm_util.h"
+#include "ucall_common.h"
+#include "hcall.h"
+
+void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu)
+{
+	struct kvm_run *run = vcpu->run;
+
+	if (run->exit_reason == UCALL_EXIT_REASON &&
+	    run->papr_hcall.nr == H_UCALL) {
+		struct kvm_regs regs;
+
+		vcpu_regs_get(vcpu, &regs);
+		if (regs.gpr[4] == UCALL_R4_UCALL)
+			return (void *)regs.gpr[5];
+	}
+	return NULL;
+}
-- 
2.39.5



^ permalink raw reply related

* [RFC v2 4/5] KVM: PPC: selftests: powerpc enable kvm_create_max_vcpus test
From: Ritesh Harjani (IBM) @ 2026-05-23 11:14 UTC (permalink / raw)
  To: kvm
  Cc: linuxppc-dev, Madhavan Srinivasan, Harsh Prateek Bora,
	Christophe Leroy, Venkat Rao Bagalkote, Nicholas Piggin,
	Misbah Anjum N, Anushree Mathur, Michael Ellerman, linux-kernel,
	Ritesh Harjani (IBM)
In-Reply-To: <cover.1779524962.git.ritesh.list@gmail.com>

From: Nicholas Piggin <npiggin@gmail.com>

powerpc's maximum permitted vCPU ID depends on the VM's SMT mode, and
the maximum reported by KVM_CAP_MAX_VCPU_ID exceeds a simple non-SMT
VM's limit.

The powerpc KVM selftest port uses non-SMT VMs, so add a workaround
to the kvm_create_max_vcpus test case to limit vCPU IDs to
KVM_CAP_MAX_VCPUS on powerpc.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
[Rebased to latest mainline tree]
Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
---
 tools/testing/selftests/kvm/kvm_create_max_vcpus.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/tools/testing/selftests/kvm/kvm_create_max_vcpus.c b/tools/testing/selftests/kvm/kvm_create_max_vcpus.c
index c5310736ed06..a82c13d6cdf5 100644
--- a/tools/testing/selftests/kvm/kvm_create_max_vcpus.c
+++ b/tools/testing/selftests/kvm/kvm_create_max_vcpus.c
@@ -56,6 +56,15 @@ int main(int argc, char *argv[])
 		    "KVM_MAX_VCPU_IDS (%d) must be at least as large as KVM_MAX_VCPUS (%d).",
 		    kvm_max_vcpu_id, kvm_max_vcpus);

+#ifdef __powerpc64__
+	/*
+	 * powerpc has a particular format for the vcpu ID that depends on
+	 * the guest SMT mode, and the max ID cap is too large for non-SMT
+	 * modes, where the maximum ID is the same as the maximum vCPUs.
+	 */
+	kvm_max_vcpu_id = kvm_max_vcpus;
+#endif
+
 	test_vcpu_creation(0, kvm_max_vcpus);

 	if (kvm_max_vcpu_id > kvm_max_vcpus)
--
2.39.5



^ permalink raw reply related

* [RFC v2 5/5] KVM: selftests: Print the vcpu_id when KVM_CREATE_VCPU ioctl fails
From: Ritesh Harjani (IBM) @ 2026-05-23 11:14 UTC (permalink / raw)
  To: kvm
  Cc: linuxppc-dev, Madhavan Srinivasan, Harsh Prateek Bora,
	Christophe Leroy, Venkat Rao Bagalkote, Nicholas Piggin,
	Misbah Anjum N, Anushree Mathur, Michael Ellerman, linux-kernel,
	Ritesh Harjani (IBM)
In-Reply-To: <cover.1779524962.git.ritesh.list@gmail.com>

Print the vcpu_id and errno when the KVM_CREATE_VCPU ioctl fails, for
debug purposes.
This helped in debugging an issue with KVM on PowerVM, where KVM_CREATE_VCPU
only supports max 2048 vcpus, because the PAPR_HCALL H_GUEST_CREATE_VCPU
("Documentation/arch/powerpc/kvm-nested.rst") supports only up to 0-2047
vcpu_id. However KVM_CAP_MAX_VCPUS capability extension always reports max_vcpus
as NR_CPUS of the host.

Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
---
 tools/testing/selftests/kvm/lib/kvm_util.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 0dc67c1502cf..6a0ee6803623 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -1354,6 +1354,9 @@ struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, u32 vcpu_id)
 	vcpu->vm = vm;
 	vcpu->id = vcpu_id;
 	vcpu->fd = __vm_ioctl(vm, KVM_CREATE_VCPU, (void *)(unsigned long)vcpu_id);
+	if (vcpu->fd < 0)
+		pr_info("Failed KVM_CREATE_VCPU for vcpu_id %u with errno %d\n",
+			vcpu_id, errno);
 	TEST_ASSERT_VM_VCPU_IOCTL(vcpu->fd >= 0, KVM_CREATE_VCPU, vcpu->fd, vm);

 	TEST_ASSERT(vcpu_mmap_sz() >= sizeof(*vcpu->run), "vcpu mmap size "
--
2.39.5



^ permalink raw reply related

* [PATCH 1/3] powerpc/irq: Move __softirq_pending out of irq_stat
From: Shrikanth Hegde @ 2026-05-23 17:40 UTC (permalink / raw)
  To: maddy, linuxppc-dev, tglx; +Cc: sshegde, christophe.leroy, linux-kernel
In-Reply-To: <20260523174016.999456-1-sshegde@linux.ibm.com>

__softirq_pending isn't part of arch specific irq_stats. It is used
by softirq core for various decision making such as whether to kick off
ksoftirqd. 

Move it out of irq_cpustat_t. This makes it simple to make irq_cpustat_t
array based approach.

Signed-off-by: Shrikanth Hegde <sshegde@linux.ibm.com>
---
 arch/powerpc/include/asm/hardirq.h | 3 ++-
 arch/powerpc/kernel/irq.c          | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/include/asm/hardirq.h b/arch/powerpc/include/asm/hardirq.h
index f133b5930ae1..bf3926a0c69c 100644
--- a/arch/powerpc/include/asm/hardirq.h
+++ b/arch/powerpc/include/asm/hardirq.h
@@ -6,7 +6,6 @@
 #include <linux/irq.h>
 
 typedef struct {
-	unsigned int __softirq_pending;
 	unsigned int timer_irqs_event;
 	unsigned int broadcast_irqs_event;
 	unsigned int timer_irqs_others;
@@ -23,6 +22,8 @@ typedef struct {
 } ____cacheline_aligned irq_cpustat_t;
 
 DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
+DECLARE_PER_CPU(unsigned int, __softirq_pending);
+#define local_softirq_pending_ref       __softirq_pending
 
 #define __ARCH_IRQ_STAT
 #define __ARCH_IRQ_EXIT_IRQS_DISABLED
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index a0e8b998c9b5..f33df5e5c23f 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -73,6 +73,7 @@
 
 DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
 EXPORT_PER_CPU_SYMBOL(irq_stat);
+DEFINE_PER_CPU(unsigned int, __softirq_pending);
 
 #ifdef CONFIG_PPC32
 atomic_t ppc_n_lost_interrupts;
-- 
2.47.3



^ permalink raw reply related

* [PATCH 0/3] powerpc/irq: Use optimizations for /proc/interrupts
From: Shrikanth Hegde @ 2026-05-23 17:40 UTC (permalink / raw)
  To: maddy, linuxppc-dev, tglx; +Cc: sshegde, christophe.leroy, linux-kernel

This series is based on work by Thomas Gleixner[1]. 

There are several optimization which helps to bring the time taken to
read /proc/interrupts. Though it is not in fastpaths, still many tools
read it often and this reduction in time will save meaningful amount of
cycle over the long duration.

[1]: https://lore.kernel.org/all/20260517194421.705253664@kernel.org/

Bulk of the design/code is copied from Thomas's work on x86. powerpc had
exact pattern which made it quite easy to port.

Using micro-loops[2] of reading /proc/interrupts shows real benefit of
the series. Bulk of the gain is already achieved using Thomas's
series[1]. This series on top provide some more benefits. As the system
size goes up, benefits could be more.

[2]: https://lore.kernel.org/all/87jysxw65f.ffs@tglx/

======== Performance Data ==================
Time taken to read /proc/interrupts 1000 times[2]
Base		:  103us 
v6		:   63us
v6+patch 1+2	:   57us
v6+patch 1+2+3	:   54us

Base: tip/master at c991e3897ead ("Merge branch into tip/master: 'x86/tdx'")
Depends on v6[1] to be applied first.

Shrikanth Hegde (3):
  powerpc/irq: Move __softirq_pending out of irq_stat
  powerpc/irq: Make irqstats array based
  powerpc/irq: Suppress unlikely interrupt stats by default

 arch/powerpc/include/asm/hardirq.h |  31 ++++---
 arch/powerpc/kernel/dbell.c        |   2 +-
 arch/powerpc/kernel/irq.c          | 131 +++++++++++++++--------------
 arch/powerpc/kernel/time.c         |   6 +-
 arch/powerpc/kernel/traps.c        |  11 +--
 arch/powerpc/kernel/watchdog.c     |   2 +-
 6 files changed, 95 insertions(+), 88 deletions(-)

-- 
2.47.3



^ permalink raw reply

* [PATCH 3/3] powerpc/irq: Suppress unlikely interrupt stats by default
From: Shrikanth Hegde @ 2026-05-23 17:40 UTC (permalink / raw)
  To: maddy, linuxppc-dev, tglx; +Cc: sshegde, christophe.leroy, linux-kernel
In-Reply-To: <20260523174016.999456-1-sshegde@linux.ibm.com>

Some interrupts are always zero and that is expected since they occur
very rarely and are mostly error indications. Don't print them by
default.

"MCE" -  "Machine check exceptions"
"NMI" -  "System Reset interrupts"

Print them if they occur once. Maintain a bitmap to know which
interrupts are to be printed.

Time taken to read /proc/interrupts 1000 times.
Base and v6 details can be found in cover-letter.
Base            :  103us
v6              :   63us
v6+patch 1+2    :   57us
v6+patch 1+2+3  :   54us

Patch 3 shows an additional 5% gain compared to patch 1+2. So it does
make sense to print them only if they are ever set.

Note: Since /proc/interrupts depend on kconfig and arch dependent,
userspace tools don't make explicit assumptions.

Signed-off-by: Shrikanth Hegde <sshegde@linux.ibm.com>
---
 arch/powerpc/include/asm/hardirq.h |  1 +
 arch/powerpc/kernel/irq.c          | 37 +++++++++++++++++++++++++++---
 arch/powerpc/kernel/traps.c        |  4 ++--
 3 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/include/asm/hardirq.h b/arch/powerpc/include/asm/hardirq.h
index 38098e35b241..be6cd5aab016 100644
--- a/arch/powerpc/include/asm/hardirq.h
+++ b/arch/powerpc/include/asm/hardirq.h
@@ -31,6 +31,7 @@ DECLARE_PER_CPU(unsigned int, __softirq_pending);
 #define local_softirq_pending_ref       __softirq_pending
 
 #define inc_irq_stat(index)	__this_cpu_inc(irq_stat.counts[IRQ_COUNT_##index])
+void inc_irq_stat_and_enable(enum irq_stat_counts which);
 
 #define __ARCH_IRQ_STAT
 #define __ARCH_IRQ_EXIT_IRQS_DISABLED
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index e67a18f62142..048ddfa66fc4 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -87,9 +87,13 @@ u32 tau_interrupts(unsigned long cpu);
 struct irq_stat_info {
 	const char	*symbol;
 	const char	*text;
+	int		skip;
 };
 
-#define ISE(idx, sym, txt)[IRQ_COUNT_##idx] = { .symbol = sym, .text = txt}
+/* ISE - IRQ STAT ENABLED, ISC - IRQ STAT CONDITIONAL */
+#define ISE(idx, sym, txt)[IRQ_COUNT_##idx] = { .symbol = sym, .text = txt, .skip = 0}
+#define ISC(idx, sym, txt)[IRQ_COUNT_##idx] = { .symbol = sym, .text = txt, .skip = 1}
+
 
 static struct irq_stat_info irq_stat_info[IRQ_COUNT_MAX] __ro_after_init = {
 	ISE(LOC_TIMER,		"LOC", "  Local timer interrupts for timer event device\n"),
@@ -97,8 +101,8 @@ static struct irq_stat_info irq_stat_info[IRQ_COUNT_MAX] __ro_after_init = {
 	ISE(OTHER_TIMER,	"LOC", "  Local timer interrupts for others\n"),
 	ISE(SPURIOUS,		"SPU", "  Spurious interrupts\n"),
 	ISE(PMI,		"PMI", "  Performance monitoring interrupts\n"),
-	ISE(MCE,		"MCE", "  Machine check exceptions\n"),
-	ISE(NMI_SRESET,		"NMI", "  System Reset interrupts\n"),
+	ISC(MCE,		"MCE", "  Machine check exceptions\n"),
+	ISC(NMI_SRESET,		"NMI", "  System Reset interrupts\n"),
 #ifdef CONFIG_PPC_WATCHDOG
 	ISE(WATCHDOG,		"WDG", "  Watchdog soft-NMI interrupts\n"),
 #endif
@@ -107,11 +111,25 @@ static struct irq_stat_info irq_stat_info[IRQ_COUNT_MAX] __ro_after_init = {
 #endif
 };
 
+/*
+ * Used for default disabled counters to increment the stats and to enable the
+ * entry for /proc/interrupts output.
+ */
+static DECLARE_BITMAP(irq_stat_count_show, IRQ_COUNT_MAX) __read_mostly;
+void inc_irq_stat_and_enable(enum irq_stat_counts which)
+{
+	__this_cpu_inc(irq_stat.counts[which]);
+	set_bit(which, irq_stat_count_show);
+}
+
 int arch_show_interrupts(struct seq_file *p, int prec)
 {
 	const struct irq_stat_info *info = irq_stat_info;
 
 	for (unsigned int i = 0; i < ARRAY_SIZE(irq_stat_info); i++, info++) {
+		if (!test_bit(i, irq_stat_count_show))
+			continue;
+
 		seq_printf(p, "%*s:", prec, info->symbol);
 		irq_proc_emit_counts(p, &irq_stat.counts[i]);
 		seq_puts(p, info->text);
@@ -138,6 +156,19 @@ int arch_show_interrupts(struct seq_file *p, int prec)
 	return 0;
 }
 
+static int __init irq_init_stats(void)
+{
+	struct irq_stat_info *info = irq_stat_info;
+
+	for (unsigned int i = 0; i < ARRAY_SIZE(irq_stat_info); i++, info++) {
+		if (info->skip == 0)
+			set_bit(i, irq_stat_count_show);
+	}
+
+	return 0;
+}
+late_initcall(irq_init_stats);
+
 /*
  * /proc/stat helpers
  */
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index a8f15154bd9a..3eacbd20fc80 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -459,7 +459,7 @@ DEFINE_INTERRUPT_HANDLER_NMI(system_reset_exception)
 	}
 
 	hv_nmi_check_nonrecoverable(regs);
-	inc_irq_stat(NMI_SRESET);
+	inc_irq_stat_and_enable(IRQ_COUNT_NMI_SRESET);
 
 	/* See if any machine dependent calls */
 	if (ppc_md.system_reset_exception) {
@@ -816,7 +816,7 @@ static void __machine_check_exception(struct pt_regs *regs)
 {
 	int recover = 0;
 
-	inc_irq_stat(MCE);
+	inc_irq_stat_and_enable(IRQ_COUNT_MCE);
 
 	add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);
 
-- 
2.47.3



^ permalink raw reply related

* [PATCH 2/3] powerpc/irq: Make irqstats array based
From: Shrikanth Hegde @ 2026-05-23 17:40 UTC (permalink / raw)
  To: maddy, linuxppc-dev, tglx; +Cc: sshegde, christophe.leroy, linux-kernel
In-Reply-To: <20260523174016.999456-1-sshegde@linux.ibm.com>

Current irq_cpustat_t has separate member for handling each arch
specific interrupt type. The same can be achieved with array instead
indexed by corresponding irq counter type.

This helps to,

- Make it easy to integrate into genirq improvements by calling 
  genirq provided irq_proc_emit_counts. That speeds up quite a bit
  by printing all 0's once as much as possible.

- Adding a new vector or software counter only requires to update the table
  and everything just works

- Remove ifdef usage a bit.

- Instead of going through each member, it simply becomes an array
  traversal.

Time taken to read /proc/interrupts 1000 times.
Base and v6 details can be found in cover-letter.
Base		:  103us
v6		:   63us
v6+this_patch	:   57us

A Decent 10% reduction can be seen in a system 240 CPUs. As the system
size increases the gain would be more as emitting 0 would reduce more
and more. 

Signed-off-by: Shrikanth Hegde <sshegde@linux.ibm.com>
---
 arch/powerpc/include/asm/hardirq.h |  27 +++++---
 arch/powerpc/kernel/dbell.c        |   2 +-
 arch/powerpc/kernel/irq.c          | 107 ++++++++++-------------------
 arch/powerpc/kernel/time.c         |   6 +-
 arch/powerpc/kernel/traps.c        |  11 ++-
 arch/powerpc/kernel/watchdog.c     |   2 +-
 6 files changed, 64 insertions(+), 91 deletions(-)

diff --git a/arch/powerpc/include/asm/hardirq.h b/arch/powerpc/include/asm/hardirq.h
index bf3926a0c69c..38098e35b241 100644
--- a/arch/powerpc/include/asm/hardirq.h
+++ b/arch/powerpc/include/asm/hardirq.h
@@ -5,26 +5,33 @@
 #include <linux/threads.h>
 #include <linux/irq.h>
 
-typedef struct {
-	unsigned int timer_irqs_event;
-	unsigned int broadcast_irqs_event;
-	unsigned int timer_irqs_others;
-	unsigned int pmu_irqs;
-	unsigned int mce_exceptions;
-	unsigned int spurious_irqs;
-	unsigned int sreset_irqs;
+enum irq_stat_counts {
+	IRQ_COUNT_LOC_TIMER,
+	IRQ_COUNT_BCT_TIMER,
+	IRQ_COUNT_OTHER_TIMER,
+	IRQ_COUNT_SPURIOUS,
+	IRQ_COUNT_PMI,
+	IRQ_COUNT_MCE,
+	IRQ_COUNT_NMI_SRESET,
 #ifdef CONFIG_PPC_WATCHDOG
-	unsigned int soft_nmi_irqs;
+	IRQ_COUNT_WATCHDOG,
 #endif
 #ifdef CONFIG_PPC_DOORBELL
-	unsigned int doorbell_irqs;
+	IRQ_COUNT_DOORBELL,
 #endif
+	IRQ_COUNT_MAX,
+};
+
+typedef struct {
+	unsigned int counts[IRQ_COUNT_MAX];
 } ____cacheline_aligned irq_cpustat_t;
 
 DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
 DECLARE_PER_CPU(unsigned int, __softirq_pending);
 #define local_softirq_pending_ref       __softirq_pending
 
+#define inc_irq_stat(index)	__this_cpu_inc(irq_stat.counts[IRQ_COUNT_##index])
+
 #define __ARCH_IRQ_STAT
 #define __ARCH_IRQ_EXIT_IRQS_DISABLED
 
diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c
index 5712dd846263..f5e298a4c4c0 100644
--- a/arch/powerpc/kernel/dbell.c
+++ b/arch/powerpc/kernel/dbell.c
@@ -31,7 +31,7 @@ DEFINE_INTERRUPT_HANDLER_ASYNC(doorbell_exception)
 		do_hard_irq_enable();
 
 	kvmppc_clear_host_ipi(smp_processor_id());
-	__this_cpu_inc(irq_stat.doorbell_irqs);
+	inc_irq_stat(DOORBELL);
 
 	smp_ipi_demux_relaxed(); /* already performed the barrier */
 
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index f33df5e5c23f..e67a18f62142 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -84,79 +84,57 @@ u32 tau_interrupts(unsigned long cpu);
 #endif
 #endif /* CONFIG_PPC32 */
 
+struct irq_stat_info {
+	const char	*symbol;
+	const char	*text;
+};
+
+#define ISE(idx, sym, txt)[IRQ_COUNT_##idx] = { .symbol = sym, .text = txt}
+
+static struct irq_stat_info irq_stat_info[IRQ_COUNT_MAX] __ro_after_init = {
+	ISE(LOC_TIMER,		"LOC", "  Local timer interrupts for timer event device\n"),
+	ISE(BCT_TIMER,		"BCT", "  Broadcast timer interrupts for timer event device\n"),
+	ISE(OTHER_TIMER,	"LOC", "  Local timer interrupts for others\n"),
+	ISE(SPURIOUS,		"SPU", "  Spurious interrupts\n"),
+	ISE(PMI,		"PMI", "  Performance monitoring interrupts\n"),
+	ISE(MCE,		"MCE", "  Machine check exceptions\n"),
+	ISE(NMI_SRESET,		"NMI", "  System Reset interrupts\n"),
+#ifdef CONFIG_PPC_WATCHDOG
+	ISE(WATCHDOG,		"WDG", "  Watchdog soft-NMI interrupts\n"),
+#endif
+#ifdef CONFIG_PPC_DOORBELL
+	ISE(DOORBELL,		"DBL", "  Doorbell interrupts\n"),
+#endif
+};
+
 int arch_show_interrupts(struct seq_file *p, int prec)
 {
-	int j;
+	const struct irq_stat_info *info = irq_stat_info;
+
+	for (unsigned int i = 0; i < ARRAY_SIZE(irq_stat_info); i++, info++) {
+		seq_printf(p, "%*s:", prec, info->symbol);
+		irq_proc_emit_counts(p, &irq_stat.counts[i]);
+		seq_puts(p, info->text);
+	}
 
 #if defined(CONFIG_PPC32) && defined(CONFIG_TAU_INT)
 	if (tau_initialized) {
+		int j;
 		seq_printf(p, "%*s:", prec, "TAU");
 		for_each_online_cpu(j)
 			seq_put_decimal_ull_width(p, " ", tau_interrupts(j), 10);
 		seq_puts(p, "  PowerPC             Thermal Assist (cpu temp)\n");
 	}
 #endif /* CONFIG_PPC32 && CONFIG_TAU_INT */
-
-	seq_printf(p, "%*s:", prec, "LOC");
-	for_each_online_cpu(j)
-		seq_put_decimal_ull_width(p, " ", per_cpu(irq_stat, j).timer_irqs_event, 10);
-        seq_printf(p, "  Local timer interrupts for timer event device\n");
-
-	seq_printf(p, "%*s:", prec, "BCT");
-	for_each_online_cpu(j)
-		seq_put_decimal_ull_width(p, " ", per_cpu(irq_stat, j).broadcast_irqs_event, 10);
-	seq_printf(p, "  Broadcast timer interrupts for timer event device\n");
-
-	seq_printf(p, "%*s:", prec, "LOC");
-	for_each_online_cpu(j)
-		seq_put_decimal_ull_width(p, " ", per_cpu(irq_stat, j).timer_irqs_others, 10);
-        seq_printf(p, "  Local timer interrupts for others\n");
-
-	seq_printf(p, "%*s:", prec, "SPU");
-	for_each_online_cpu(j)
-		seq_put_decimal_ull_width(p, " ", per_cpu(irq_stat, j).spurious_irqs, 10);
-	seq_printf(p, "  Spurious interrupts\n");
-
-	seq_printf(p, "%*s:", prec, "PMI");
-	for_each_online_cpu(j)
-		seq_put_decimal_ull_width(p, " ", per_cpu(irq_stat, j).pmu_irqs, 10);
-	seq_printf(p, "  Performance monitoring interrupts\n");
-
-	seq_printf(p, "%*s:", prec, "MCE");
-	for_each_online_cpu(j)
-		seq_put_decimal_ull_width(p, " ", per_cpu(irq_stat, j).mce_exceptions, 10);
-	seq_printf(p, "  Machine check exceptions\n");
-
 #ifdef CONFIG_PPC_BOOK3S_64
 	if (cpu_has_feature(CPU_FTR_HVMODE)) {
+		int j;
 		seq_printf(p, "%*s:", prec, "HMI");
 		for_each_online_cpu(j)
 			seq_put_decimal_ull_width(p, " ", paca_ptrs[j]->hmi_irqs, 10);
 		seq_printf(p, "  Hypervisor Maintenance Interrupts\n");
 	}
 #endif
-
-	seq_printf(p, "%*s:", prec, "NMI");
-	for_each_online_cpu(j)
-		seq_put_decimal_ull_width(p, " ", per_cpu(irq_stat, j).sreset_irqs, 10);
-	seq_printf(p, "  System Reset interrupts\n");
-
-#ifdef CONFIG_PPC_WATCHDOG
-	seq_printf(p, "%*s:", prec, "WDG");
-	for_each_online_cpu(j)
-		seq_put_decimal_ull_width(p, " ", per_cpu(irq_stat, j).soft_nmi_irqs, 10);
-	seq_printf(p, "  Watchdog soft-NMI interrupts\n");
-#endif
-
-#ifdef CONFIG_PPC_DOORBELL
-	if (cpu_has_feature(CPU_FTR_DBELL)) {
-		seq_printf(p, "%*s:", prec, "DBL");
-		for_each_online_cpu(j)
-			seq_put_decimal_ull_width(p, " ", per_cpu(irq_stat, j).doorbell_irqs, 10);
-		seq_printf(p, "  Doorbell interrupts\n");
-	}
-#endif
-
 	return 0;
 }
 
@@ -165,24 +143,15 @@ int arch_show_interrupts(struct seq_file *p, int prec)
  */
 u64 arch_irq_stat_cpu(unsigned int cpu)
 {
-	u64 sum = per_cpu(irq_stat, cpu).timer_irqs_event;
+	irq_cpustat_t *p = per_cpu_ptr(&irq_stat, cpu);
+	u64 sum = 0;
+
+	for (unsigned int i = 0; i < ARRAY_SIZE(irq_stat_info); i++)
+		sum += p->counts[i];
 
-	sum += per_cpu(irq_stat, cpu).broadcast_irqs_event;
-	sum += per_cpu(irq_stat, cpu).pmu_irqs;
-	sum += per_cpu(irq_stat, cpu).mce_exceptions;
-	sum += per_cpu(irq_stat, cpu).spurious_irqs;
-	sum += per_cpu(irq_stat, cpu).timer_irqs_others;
 #ifdef CONFIG_PPC_BOOK3S_64
 	sum += paca_ptrs[cpu]->hmi_irqs;
 #endif
-	sum += per_cpu(irq_stat, cpu).sreset_irqs;
-#ifdef CONFIG_PPC_WATCHDOG
-	sum += per_cpu(irq_stat, cpu).soft_nmi_irqs;
-#endif
-#ifdef CONFIG_PPC_DOORBELL
-	sum += per_cpu(irq_stat, cpu).doorbell_irqs;
-#endif
-
 	return sum;
 }
 
@@ -248,7 +217,7 @@ static void __do_irq(struct pt_regs *regs, unsigned long oldsp)
 
 	/* And finally process it */
 	if (unlikely(!irq))
-		__this_cpu_inc(irq_stat.spurious_irqs);
+		inc_irq_stat(SPURIOUS);
 	else
 		generic_handle_irq(irq);
 
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 4bbeb8644d3d..44da7be36199 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -572,13 +572,13 @@ DEFINE_INTERRUPT_HANDLER_ASYNC(timer_interrupt)
 	now = get_tb();
 	if (now >= *next_tb) {
 		evt->event_handler(evt);
-		__this_cpu_inc(irq_stat.timer_irqs_event);
+		inc_irq_stat(LOC_TIMER);
 	} else {
 		now = *next_tb - now;
 		if (now > decrementer_max)
 			now = decrementer_max;
 		set_dec_or_work(now);
-		__this_cpu_inc(irq_stat.timer_irqs_others);
+		inc_irq_stat(OTHER_TIMER);
 	}
 
 	trace_timer_interrupt_exit(regs);
@@ -591,7 +591,7 @@ EXPORT_SYMBOL(timer_interrupt);
 void timer_broadcast_interrupt(void)
 {
 	tick_receive_broadcast();
-	__this_cpu_inc(irq_stat.broadcast_irqs_event);
+	inc_irq_stat(BCT_TIMER);
 }
 #endif
 
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index cb8e9357383e..a8f15154bd9a 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -459,8 +459,7 @@ DEFINE_INTERRUPT_HANDLER_NMI(system_reset_exception)
 	}
 
 	hv_nmi_check_nonrecoverable(regs);
-
-	__this_cpu_inc(irq_stat.sreset_irqs);
+	inc_irq_stat(NMI_SRESET);
 
 	/* See if any machine dependent calls */
 	if (ppc_md.system_reset_exception) {
@@ -817,7 +816,7 @@ static void __machine_check_exception(struct pt_regs *regs)
 {
 	int recover = 0;
 
-	__this_cpu_inc(irq_stat.mce_exceptions);
+	inc_irq_stat(MCE);
 
 	add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);
 
@@ -1932,8 +1931,7 @@ DEFINE_INTERRUPT_HANDLER(vsx_unavailable_tm)
 DECLARE_INTERRUPT_HANDLER_NMI(performance_monitor_exception_nmi);
 DEFINE_INTERRUPT_HANDLER_NMI(performance_monitor_exception_nmi)
 {
-	__this_cpu_inc(irq_stat.pmu_irqs);
-
+	inc_irq_stat(PMI);
 	perf_irq(regs);
 
 	return 0;
@@ -1943,8 +1941,7 @@ DEFINE_INTERRUPT_HANDLER_NMI(performance_monitor_exception_nmi)
 DECLARE_INTERRUPT_HANDLER_ASYNC(performance_monitor_exception_async);
 DEFINE_INTERRUPT_HANDLER_ASYNC(performance_monitor_exception_async)
 {
-	__this_cpu_inc(irq_stat.pmu_irqs);
-
+	inc_irq_stat(PMI);
 	perf_irq(regs);
 }
 
diff --git a/arch/powerpc/kernel/watchdog.c b/arch/powerpc/kernel/watchdog.c
index 764001deb060..f516eeccc9f6 100644
--- a/arch/powerpc/kernel/watchdog.c
+++ b/arch/powerpc/kernel/watchdog.c
@@ -381,7 +381,7 @@ DEFINE_INTERRUPT_HANDLER_NMI(soft_nmi_interrupt)
 	if (!cpumask_test_cpu(cpu, &wd_cpus_enabled))
 		return 0;
 
-	__this_cpu_inc(irq_stat.soft_nmi_irqs);
+	inc_irq_stat(WATCHDOG);
 
 	tb = get_tb();
 	if (tb - per_cpu(wd_timer_tb, cpu) >= wd_panic_timeout_tb) {
-- 
2.47.3



^ permalink raw reply related

* [PATCH] powerpc/topology: Support coregroup in PowerNV
From: Srikar Dronamraju @ 2026-05-24  1:00 UTC (permalink / raw)
  To: linuxppc-dev, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy, Naveen N Rao
  Cc: skiboot, arbab, mahesh, Srikar Dronamraju, linux-kernel

Coregroup support was only available on PowerPC on PowerVM LPARs.
However if firmware were to expose coregroup-id to the kernel, then
coregroup can even be supported on PowerNV too.

PowerPC Linux kernel will detect support for coregroup by looking at the
primary_domain_index. Till now on PowerNV systems, primary_domain_index
has been the penultimate domain in cpunode ibm,associativity device-tree
property. This would be taken as hint that coregroup support is not
available in the firmware.

If on PowerNV systems, primary_domain_index is not the penultimate
domain in cpunode ibm,associativity device-tree property, then it would
be taken as a hint that coregroup support is available in the firmware.

This logic makes it compatible with PowerVM Systems, where
primary_domain_index is not the penultimate domain in cpunode
ibm,associativity device-tree property.

$ lscpu
Architecture:        ppc64le
Byte Order:          Little Endian
CPU(s):              480
On-line CPU(s) list: 0-479
Thread(s) per core:  8
Core(s) per socket:  15
Socket(s):           4
NUMA node(s):        4
Model:               2.0 (pvr 0080 0200)
Model name:          POWER10, altivec supported
CPU max MHz:         3249.0000
CPU min MHz:         3249.0000
L1d cache:           32K
L1i cache:           48K
L2 cache:            1024K
L3 cache:            4096K
NUMA node0 CPU(s):   0-119
NUMA node1 CPU(s):   120-239
NUMA node2 CPU(s):   240-359
NUMA node3 CPU(s):   360-479

with-out patched firmware and/or Linux-kernel
---------------------------------------------
$ grep -h -r . /sys/devices/system/cpu/*/topology/die_id |sort | uniq -c | sort -n -r
    120 27
    120 18
    120 9
    120 0

$ grep -h -r . /sys/devices/system/cpu/*/topology/die_cpus_list |sort | uniq -c | sort -n -r
    120 360-479
    120 240-359
    120 120-239
    120 0-119

with patched firmware and Linux-kernel
--------------------------------------
grep -h -r . /sys/devices/system/cpu/*/topology/die_id |sort | uniq -c | sort -n -r
     64 6
     64 4
     64 2
     64 0
     56 7
     56 5
     56 3
     56 1
grep -h -r . /sys/devices/system/cpu/*/topology/die_cpus_list |sort | uniq -c | sort -n -r
     64 360-375,392-407,424-439,456-471
     64 240-255,272-287,296-311,328-343
     64 120-135,152-167,184-199,208-223
     64 0-15,32-47,64-79,88-103
     56 376-391,408-423,440-455,472-479
     56 256-271,288-295,312-327,344-359
     56 16-31,48-63,80-87,104-119
     56 136-151,168-183,200-207,224-239

Observation:
Without the patched kernel and/or skiboot, die-id and numa were same.
With patched kernel and/or skiboot, we see 2 die-id per node.
Signed-off-by: Srikar Dronamraju <srikar@linux.ibm.com>
---
 arch/powerpc/include/asm/topology.h | 15 +++--
 arch/powerpc/mm/numa.c              | 87 ++++++++++++++++++++++-------
 2 files changed, 73 insertions(+), 29 deletions(-)

diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h
index 66ed5fe1b718..568e6bc55726 100644
--- a/arch/powerpc/include/asm/topology.h
+++ b/arch/powerpc/include/asm/topology.h
@@ -71,6 +71,7 @@ extern void map_cpu_to_node(int cpu, int node);
 extern void unmap_cpu_from_node(unsigned long cpu);
 #endif /* CONFIG_HOTPLUG_CPU */
 
+extern int cpu_to_coregroup_id(int cpu);
 #else
 
 static inline int early_cpu_to_node(int cpu) { return 0; }
@@ -107,14 +108,6 @@ static inline void map_cpu_to_node(int cpu, int node) {}
 static inline void unmap_cpu_from_node(unsigned long cpu) {}
 #endif /* CONFIG_HOTPLUG_CPU */
 #endif /* CONFIG_SMP */
-
-#endif /* CONFIG_NUMA */
-
-#if defined(CONFIG_NUMA) && defined(CONFIG_PPC_SPLPAR)
-void find_and_update_cpu_nid(int cpu);
-extern int cpu_to_coregroup_id(int cpu);
-#else
-static inline void find_and_update_cpu_nid(int cpu) {}
 static inline int cpu_to_coregroup_id(int cpu)
 {
 #ifdef CONFIG_SMP
@@ -124,6 +117,12 @@ static inline int cpu_to_coregroup_id(int cpu)
 #endif
 }
 
+#endif /* CONFIG_NUMA */
+
+#if defined(CONFIG_NUMA) && defined(CONFIG_PPC_SPLPAR)
+void find_and_update_cpu_nid(int cpu);
+#else
+static inline void find_and_update_cpu_nid(int cpu) {}
 #endif /* CONFIG_NUMA && CONFIG_PPC_SPLPAR */
 
 #include <asm-generic/topology.h>
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index f4cf3ae036de..9b45cc9e1f27 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -432,7 +432,7 @@ static void __init initialize_form2_numa_distance_lookup_table(void)
 
 static int __init find_primary_domain_index(void)
 {
-	int index;
+	int index = -1;
 	struct device_node *root;
 
 	/*
@@ -502,12 +502,9 @@ static int __init find_primary_domain_index(void)
 		distance_ref_points_depth = MAX_DISTANCE_REF_POINTS;
 	}
 
-	of_node_put(root);
-	return index;
-
 err:
 	of_node_put(root);
-	return -1;
+	return index;
 }
 
 static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells)
@@ -892,12 +889,32 @@ static int __init numa_setup_drmem_lmb(struct drmem_lmb *lmb,
 	return 0;
 }
 
+/*
+ * If hierarchy extends beyond primary_domain_index + 1, then next
+ * level corresponds to coregroup.
+ */
+static int detect_and_enable_coregroup(const __be32 *associativity, int index)
+{
+	if (!associativity)
+		return -1;
+
+	if (!index) {
+		index = of_read_number(associativity, 1);
+
+		if (index > primary_domain_index + 1)
+			coregroup_enabled = 1;
+		else
+			index = -1;
+	}
+	return index;
+}
+
 static int __init parse_numa_properties(void)
 {
 	struct device_node *memory, *pci;
-	int default_nid = 0;
-	unsigned long i;
+	int default_nid = 0, index = 0;
 	const __be32 *associativity;
+	unsigned long i;
 
 	if (numa_enabled == 0) {
 		pr_warn("disabled by user\n");
@@ -930,7 +947,6 @@ static int __init parse_numa_properties(void)
 	 */
 	for_each_present_cpu(i) {
 		__be32 vphn_assoc[VPHN_ASSOC_BUFSIZE];
-		struct device_node *cpu;
 		int nid = NUMA_NO_NODE;
 
 		memset(vphn_assoc, 0, VPHN_ASSOC_BUFSIZE * sizeof(__be32));
@@ -938,7 +954,10 @@ static int __init parse_numa_properties(void)
 		if (__vphn_get_associativity(i, vphn_assoc) == 0) {
 			nid = associativity_to_nid(vphn_assoc);
 			initialize_form1_numa_distance(vphn_assoc);
+			if (!index)
+				index = detect_and_enable_coregroup(vphn_assoc, index);
 		} else {
+			struct device_node *cpu;
 
 			/*
 			 * Don't fall back to default_nid yet -- we will plug
@@ -951,6 +970,8 @@ static int __init parse_numa_properties(void)
 			associativity = of_get_associativity(cpu);
 			if (associativity) {
 				nid = associativity_to_nid(associativity);
+				if (!index)
+					index = detect_and_enable_coregroup(associativity, index);
 				initialize_form1_numa_distance(associativity);
 			}
 			of_node_put(cpu);
@@ -1431,9 +1452,26 @@ void find_and_update_cpu_nid(int cpu)
 	pr_debug("%s:%d cpu %d nid %d\n", __func__, __LINE__, cpu, new_nid);
 }
 
+static int topology_update_init(void)
+{
+	topology_inited = 1;
+	return 0;
+}
+device_initcall(topology_update_init);
+
+#else
+static long vphn_get_associativity(unsigned long cpu,
+					__be32 *associativity)
+{
+	return -1;
+}
+#endif /* CONFIG_PPC_SPLPAR */
+
 int cpu_to_coregroup_id(int cpu)
 {
-	__be32 associativity[VPHN_ASSOC_BUFSIZE] = {0};
+	int coregroup_id = cpu_to_core_id(cpu);
+	struct device_node *cpunode = NULL;
+	const __be32 *associativity;
 	int index;
 
 	if (cpu < 0 || cpu > nr_cpu_ids)
@@ -1442,24 +1480,31 @@ int cpu_to_coregroup_id(int cpu)
 	if (!coregroup_enabled)
 		goto out;
 
-	if (!firmware_has_feature(FW_FEATURE_VPHN))
-		goto out;
+	if (firmware_has_feature(FW_FEATURE_VPHN)) {
+		__be32 tmp[VPHN_ASSOC_BUFSIZE] = {0};
 
-	if (vphn_get_associativity(cpu, associativity))
+		if (vphn_get_associativity(cpu, tmp))
+			goto out;
+
+		associativity = tmp;
+
+	} else {
+		cpunode = of_get_cpu_node(cpu, NULL);
+		if (!cpunode)
+			goto out;
+
+		associativity = of_get_associativity(cpunode);
+	}
+	if (!associativity)
 		goto out;
 
 	index = of_read_number(associativity, 1);
 	if (index > primary_domain_index + 1)
-		return of_read_number(&associativity[index - 1], 1);
+		coregroup_id = of_read_number(&associativity[index - 1], 1);
 
 out:
-	return cpu_to_core_id(cpu);
-}
+	if (cpunode)
+		of_node_put(cpunode);
 
-static int topology_update_init(void)
-{
-	topology_inited = 1;
-	return 0;
+	return coregroup_id;
 }
-device_initcall(topology_update_init);
-#endif /* CONFIG_PPC_SPLPAR */
-- 
2.43.0



^ permalink raw reply related

* Re: [PATCH] crypto: nx: fix nx_crypto_ctx_exit argument
From: Breno Leitao @ 2026-05-24  7:10 UTC (permalink / raw)
  To: Sam James
  Cc: Nayna Jain, Paulo Flabiano Smorigo, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy (CS GROUP),
	Herbert Xu, David S. Miller, Eric Biggers, Ard Biesheuvel,
	Eric Biggers, Calvin Buckley, Brad Spengler, linux-crypto,
	linuxppc-dev, linux-kernel
In-Reply-To: <a3e89c1e8342ffa415b0d29725a0571a4f355d34.1779472902.git.sam@gentoo.org>

On Fri, May 22, 2026 at 07:01:42PM +0000, Sam James wrote:
> nx_crypto_ctx_shash_exit calls nx_crypto_ctx_exit with crypto_shash_ctx(...)
> but crypto_shash_ctx gives a nx_crypto_ctx *, not a crypto_tfm *.
> 
> Fix the type in nx_crypto_ctx_exit and drop the bogus crypto_tfm_ctx
> call.
> 
> This fixes the following oops:
> 
>   BUG: Unable to handle kernel data access at 0xc0403effffffffc8
>   Faulting instruction address: 0xc000000000396cb4
>   Oops: Kernel access of bad area, sig: 11 [#15]
>   Call Trace:
>    nx_crypto_ctx_shash_exit+0x24/0x60
>    crypto_shash_exit_tfm+0x28/0x40
>    crypto_destroy_tfm+0x98/0x140
>    crypto_exit_ahash_using_shash+0x20/0x40
>    crypto_destroy_tfm+0x98/0x140
>    hash_release+0x1c/0x30
>    alg_sock_destruct+0x38/0x60
>    __sk_destruct+0x48/0x2b0
>    af_alg_release+0x58/0xb0
>    __sock_release+0x68/0x150
>    sock_close+0x20/0x40
>    __fput+0x110/0x3a0
>    sys_close+0x48/0xa0
>    system_call_exception+0x140/0x2d0
>    system_call_common+0xf4/0x258
> 
> .. which came from hardlink(1) opportunistically using AF_ALG.
> 
> The same problem exists with nx_crypto_ctx_skcipher_exit getting a context
> it wasn't expecting, but apparently nobody hit that for years.
> 
> Cc: Eric Biggers <ebiggers@kernel.org>
> Fixes: bfd9efddf990 ("crypto: nx - convert AES-ECB to skcipher API")
> Fixes: 9420e628e7d8 ("crypto: nx - Use API partial block handling")
> Reported-by: Calvin Buckley <calvin@cmpct.info>
> Tested-by: Calvin Buckley <calvin@cmpct.info>
> Suggested-by: Brad Spengler <brad.spengler@opensrcsec.com>
> Signed-off-by: Sam James <sam@gentoo.org>

Acked-by: Breno Leitao <leitao@debian.org>


^ permalink raw reply


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