Linux ACPI
 help / color / mirror / Atom feed
* Re: [RFC PATCH 1/3] mm/numa: add exclusive node pool and numa=standby boot parameter
From: Mike Rapoport @ 2026-06-14  9:08 UTC (permalink / raw)
  To: Gregory Price
  Cc: linux-mm, x86, linux-doc, linux-kernel, linux-acpi, driver-core,
	kernel-team, corbet, skhan, dave.hansen, luto, peterz, tglx,
	mingo, bp, hpa, rafael, lenb, gregkh, dakr, akpm, rdunlap,
	feng.tang, dapeng1.mi, elver, kuba, ebiggers, lirongqing, paulmck,
	dave.jiang, jic23, xueshuai, kai.huang
In-Reply-To: <airAUSrNjbSEwuti@gourry-fedora-PF4VCD3F>

On Thu, Jun 11, 2026 at 10:04:01AM -0400, Gregory Price wrote:
> On Thu, Jun 11, 2026 at 12:00:17PM +0300, Mike Rapoport wrote:
> > > 1) Can we do dynamic addition of nodes?
> > > 
> > >    Not Trivially
> > > 
> > >    Some services utilize num_possible_nodes() as a static value to
> > >    calculate the amount of resources to use at runtime (bpf, md/raid5).
> > > 
> > >    Example: futex_init uses num_possible_nodes() as part of its
> > >             hashsize calculation during __init.
> > 
> > AFAIU, we don't add the additional nodes for generic hotplug memory but
> > rather for exclusive use of by drivers/applications that are aware of these
> > nodes.
> 
> The intent is to use for "non-generic" hotplug (see the whole private
> node series [1]), which would eventually still use the hotplug mechanism
> just not for generic memory.
> 
> [1] https://lore.kernel.org/linux-mm/20260222084842.1824063-1-gourry@gourry.net/
> 
> > Wouldn't adding them to possible nodes actually skew the calculation of the
> > resources by the services utilizing num_possible_nodes()?
> > 
> > With the futex_init() example, won't be hashsize scaled down two much
> > because we've added these special nodes to the possible mask?
> >
> 
> The result is the same as BIOS reserving nodes with PXM entries that
> don't get used.  The CXL ACPI Tables do this for CXL Fixed Memory
> Windows that may never be hotplugged.

Well, even without CXL there could be nodes that may never be hotplugged, I
suppose that with CXL the difference between available and possible
nodes can get much larger.
 
> So really i think you're pointing out that futex_init() here probably
> shouldn't be using num_possible_nodes?

I'd rather say that num_possible_nodes() with and without CXL (or other
differentiated memory) has different semantics.
Maybe we need to add a new primitive for possible differentiated nodes and
keep num_possible_nodes() to mean "number of possible nodes with normal
memory".
 
> ~Gregory

-- 
Sincerely yours,
Mike.

^ permalink raw reply

* Re: [PATCH v2 02/16] device property: Add fwnode_graph_get_next_port_endpoint()
From: Andy Shevchenko @ 2026-06-13 13:00 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Bartosz Golaszewski, Greg Kroah-Hartman, Daniel Scally,
	Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
	Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Matthias Brugger, AngeloGioacchino Del Regno, Alan Stern,
	linux-acpi, driver-core, linux-pm, linux-usb, devicetree,
	linux-mediatek, linux-arm-kernel, linux-kernel,
	Manivannan Sadhasivam
In-Reply-To: <CAGXv+5EHHWfiWgqPpf-RMKoSQLc2cd9OA4Z36SNoL5C53kVh2g@mail.gmail.com>

On Fri, Jun 12, 2026 at 04:20:18PM +0900, Chen-Yu Tsai wrote:
> On Wed, Jun 10, 2026 at 11:08 PM Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
> > On Wed, Jun 10, 2026 at 04:40:36PM +0800, Chen-Yu Tsai wrote:

...

> > > +struct fwnode_handle *fwnode_graph_get_next_port_endpoint(const struct fwnode_handle *port,
> > > +                                                       struct fwnode_handle *prev)
> > > +{
> > > +     struct fwnode_handle *ep;
> >
> > Unused?
> >
> > > +     while (1) {
> >
> > This is usually harder to read and follow. It's like "pay much attention on
> > the code", but here no rocket science, no code to really pay attention to.
> >
> > > +             prev = fwnode_get_next_child_node(port, prev);
> > > +             if (!prev)
> > > +                     break;
> > > +
> > > +             if (WARN(!fwnode_name_eq(prev, "endpoint"),
> > > +                      "non endpoint node is used (%pfw)", prev))
> > > +                     continue;
> > > +
> > > +             break;
> > > +     }
> > > +
> > > +     return prev;
> > > +}
> >
> > So, this can be rewritten as
> >
> >         ep = prev;
> >         do {
> >                 ep = fwnode_get_next_child_node(port, ep);
> >                 if (fwnode_name_eq(ep, "endpoint"))
> >                         break;
> >
> >                 WARN_ON(ep, ...);
> >         } while (ep);
> >
> >         return ep;
> >
> > But also big question why? to WARN*(). There is no use in the entire
> > property.c.
> 
> Will drop. This function was lifted from drivers/of/property.c then
> adapted to the fwnode APIs, so it still has the structure of its
> origin. With the WARN() gone, rewriting it as do {} while() becomes:
> 
> do {
>         prev = fwnode_get_next_child_node(port, prev);
>         if (prev && fwnode_name_eq(prev, "endpoint"))

'prev &&' is not needed.

>                 break;
> } while (prev);
> 
> return prev;

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply

* [rafael-pm:bleeding-edge] BUILD SUCCESS 058cd2920302bb1478643b44f9dcc9d6d8e542b9
From: kernel test robot @ 2026-06-12 17:55 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: linux-acpi, linux-pm

tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git bleeding-edge
branch HEAD: 058cd2920302bb1478643b44f9dcc9d6d8e542b9  Merge branch 'experimental/acpi-driver-work' into bleeding-edge

elapsed time: 966m

configs tested: 162
configs skipped: 13

The following configs have been built successfully.
More configs may be tested in the coming days.

tested configs:
alpha                             allnoconfig    gcc-16.1.0
alpha                            allyesconfig    gcc-16.1.0
alpha                               defconfig    gcc-16.1.0
arc                              allmodconfig    gcc-16.1.0
arc                               allnoconfig    gcc-16.1.0
arc                              allyesconfig    gcc-16.1.0
arc                                 defconfig    gcc-16.1.0
arc                   randconfig-001-20260612    gcc-13.4.0
arc                   randconfig-002-20260612    gcc-15.2.0
arm                               allnoconfig    clang-23
arm                              allyesconfig    gcc-16.1.0
arm                                 defconfig    clang-23
arm                   randconfig-001-20260612    gcc-11.5.0
arm                   randconfig-002-20260612    gcc-10.5.0
arm                   randconfig-003-20260612    gcc-11.5.0
arm                   randconfig-004-20260612    gcc-13.4.0
arm64                             allnoconfig    gcc-16.1.0
arm64                               defconfig    gcc-16.1.0
arm64                 randconfig-001-20260612    gcc-13.4.0
arm64                 randconfig-002-20260612    clang-23
arm64                 randconfig-003-20260612    gcc-9.5.0
arm64                 randconfig-004-20260612    gcc-11.5.0
csky                             allmodconfig    gcc-16.1.0
csky                              allnoconfig    gcc-16.1.0
csky                                defconfig    gcc-16.1.0
csky                  randconfig-001-20260612    gcc-11.5.0
csky                  randconfig-002-20260612    gcc-13.4.0
hexagon                          allmodconfig    clang-23
hexagon                           allnoconfig    clang-23
hexagon                             defconfig    clang-23
hexagon               randconfig-001-20260612    clang-23
hexagon               randconfig-002-20260612    clang-23
i386                             allmodconfig    gcc-14
i386                              allnoconfig    gcc-14
i386                             allyesconfig    gcc-14
i386        buildonly-randconfig-001-20260612    clang-22
i386        buildonly-randconfig-002-20260612    gcc-14
i386        buildonly-randconfig-003-20260612    gcc-14
i386        buildonly-randconfig-004-20260612    gcc-14
i386        buildonly-randconfig-005-20260612    gcc-14
i386        buildonly-randconfig-006-20260612    clang-22
i386                                defconfig    clang-22
i386                  randconfig-001-20260612    gcc-14
i386                  randconfig-002-20260612    clang-22
i386                  randconfig-003-20260612    gcc-14
i386                  randconfig-004-20260612    gcc-14
i386                  randconfig-005-20260612    clang-22
i386                  randconfig-006-20260612    clang-22
i386                  randconfig-007-20260612    gcc-12
i386                  randconfig-011-20260612    clang-22
i386                  randconfig-012-20260612    clang-22
i386                  randconfig-013-20260612    clang-22
i386                  randconfig-014-20260612    clang-22
i386                  randconfig-015-20260612    gcc-14
i386                  randconfig-016-20260612    gcc-14
i386                  randconfig-017-20260612    clang-22
loongarch                         allnoconfig    clang-20
loongarch                           defconfig    clang-23
loongarch             randconfig-001-20260612    clang-23
loongarch             randconfig-002-20260612    gcc-16.1.0
m68k                             allmodconfig    gcc-16.1.0
m68k                              allnoconfig    gcc-16.1.0
m68k                             allyesconfig    gcc-16.1.0
m68k                                defconfig    gcc-16.1.0
microblaze                        allnoconfig    gcc-16.1.0
microblaze                       allyesconfig    gcc-16.1.0
microblaze                          defconfig    gcc-16.1.0
mips                             allmodconfig    gcc-16.1.0
mips                              allnoconfig    gcc-16.1.0
mips                             allyesconfig    gcc-16.1.0
nios2                            allmodconfig    gcc-11.5.0
nios2                             allnoconfig    gcc-11.5.0
nios2                               defconfig    gcc-11.5.0
nios2                 randconfig-001-20260612    gcc-11.5.0
nios2                 randconfig-002-20260612    gcc-11.5.0
openrisc                         allmodconfig    gcc-16.1.0
openrisc                          allnoconfig    gcc-16.1.0
openrisc                            defconfig    gcc-16.1.0
parisc                           allmodconfig    gcc-16.1.0
parisc                            allnoconfig    gcc-16.1.0
parisc                           allyesconfig    gcc-16.1.0
parisc                              defconfig    gcc-16.1.0
parisc                randconfig-001-20260612    gcc-12.5.0
parisc                randconfig-002-20260612    gcc-14.3.0
parisc64                            defconfig    gcc-16.1.0
powerpc                          allmodconfig    gcc-16.1.0
powerpc                           allnoconfig    gcc-16.1.0
powerpc                     mpc5200_defconfig    clang-23
powerpc64             randconfig-001-20260612    gcc-8.5.0
powerpc64             randconfig-002-20260612    gcc-11.5.0
riscv                            allmodconfig    clang-23
riscv                             allnoconfig    gcc-16.1.0
riscv                            allyesconfig    clang-23
riscv                               defconfig    clang-23
riscv                 randconfig-001-20260612    gcc-13.4.0
riscv                 randconfig-002-20260612    clang-23
s390                             allmodconfig    clang-23
s390                              allnoconfig    clang-23
s390                             allyesconfig    gcc-16.1.0
s390                                defconfig    clang-18
s390                  randconfig-001-20260612    clang-23
s390                  randconfig-002-20260612    gcc-8.5.0
sh                               allmodconfig    gcc-16.1.0
sh                                allnoconfig    gcc-16.1.0
sh                               allyesconfig    gcc-16.1.0
sh                                  defconfig    gcc-16.1.0
sh                    randconfig-001-20260612    gcc-11.5.0
sh                    randconfig-002-20260612    gcc-13.4.0
sparc                             allnoconfig    gcc-16.1.0
sparc                               defconfig    gcc-16.1.0
sparc                 randconfig-001-20260612    gcc-8.5.0
sparc                 randconfig-002-20260612    gcc-8.5.0
sparc64                          allmodconfig    clang-20
sparc64                             defconfig    clang-23
sparc64               randconfig-001-20260612    clang-20
sparc64               randconfig-002-20260612    gcc-12.5.0
um                               allmodconfig    clang-23
um                                allnoconfig    clang-16
um                               allyesconfig    gcc-14
um                                  defconfig    clang-23
um                             i386_defconfig    gcc-14
um                    randconfig-001-20260612    gcc-14
um                    randconfig-002-20260612    clang-23
um                           x86_64_defconfig    clang-23
x86_64                           allmodconfig    clang-22
x86_64                            allnoconfig    clang-22
x86_64                           allyesconfig    clang-22
x86_64               buildonly-randconfig-001    gcc-12
x86_64      buildonly-randconfig-001-20260612    clang-22
x86_64               buildonly-randconfig-002    clang-22
x86_64      buildonly-randconfig-002-20260612    gcc-14
x86_64               buildonly-randconfig-003    gcc-14
x86_64      buildonly-randconfig-003-20260612    clang-22
x86_64               buildonly-randconfig-004    gcc-14
x86_64      buildonly-randconfig-004-20260612    clang-22
x86_64               buildonly-randconfig-005    gcc-14
x86_64      buildonly-randconfig-005-20260612    clang-22
x86_64               buildonly-randconfig-006    clang-22
x86_64      buildonly-randconfig-006-20260612    gcc-14
x86_64                              defconfig    gcc-14
x86_64                randconfig-001-20260612    clang-22
x86_64                randconfig-002-20260612    gcc-14
x86_64                randconfig-003-20260612    gcc-14
x86_64                randconfig-004-20260612    gcc-14
x86_64                randconfig-005-20260612    gcc-14
x86_64                randconfig-006-20260612    clang-22
x86_64                randconfig-011-20260612    gcc-14
x86_64                randconfig-012-20260612    clang-22
x86_64                randconfig-013-20260612    clang-22
x86_64                randconfig-014-20260612    gcc-14
x86_64                randconfig-015-20260612    gcc-14
x86_64                randconfig-016-20260612    gcc-14
x86_64                randconfig-071-20260612    gcc-14
x86_64                randconfig-072-20260612    gcc-12
x86_64                randconfig-073-20260612    clang-22
x86_64                randconfig-074-20260612    clang-22
x86_64                randconfig-075-20260612    clang-22
x86_64                randconfig-076-20260612    clang-22
x86_64                          rhel-9.4-rust    clang-22
xtensa                            allnoconfig    gcc-16.1.0
xtensa                randconfig-001-20260612    gcc-10.5.0
xtensa                randconfig-002-20260612    gcc-12.5.0

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply

* [GIT PULL] ACPI support updates for 7.2-rc1
From: Rafael J. Wysocki @ 2026-06-12 17:41 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: ACPI Devel Maling List, Linux PM, Linux Kernel Mailing List

Hi Linus,

This goes early for your convenience.

Please pull from the tag

 git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git \
 acpi-7.2-rc1

with top-most commit 615f90d3b1b7900d591a9162793f616b051f07b8

 Merge branches 'acpi-processor', 'acpi-cppc' and 'acpi-pci'

on top of commit 4549871118cf616eecdd2d939f78e3b9e1dddc48

 Linux 7.1-rc7

to receive ACPI support updates for 7.2-rc1.

These update the ACPICA code in the kernel to upstream version 20260408,
introduce support for devres-based management of ACPI notify handlers
and update some core ACPI device drivers on top of that (which includes
some fixes and cleanups), add _DEP support for PCI/CXL roots and Intel
CVS devices, fix a couple of assorted issues and clean up code:

 - Fix multiple issues related to probe, removal and missing NVDIMM
   device notifications in the ACPI NFIT driver (Rafael Wysocki)

 - Add support for devres-based management of ACPI notify handlers to
   the ACPI core (Rafael Wysocki)

 - Switch multiple core ACPI device drivers (including the ACPI PAD,
   ACPI video bus, ACPI HED, ACPI thermal zone, ACPI AC, ACPI battery,
   and ACPI NFIT drivers) over to using devres-based resource management
   during probe (Rafael Wysocki)

 - Replace mutex_lock/unlock() with guard()/scoped_guard() in the ACPI
   PMIC driver (Maxwell Doose)

 - Fix message kref handling in the dead device path of the ACPI IPMI
   address space handler (Yuho Choi)

 - Use sysfs_emit() in idlecpus_show() in the ACPI processor aggregator
   device (PAD) driver (Yury Norov)

 - Clean up device_id_scheme initialization in the ACPI video bus driver
   (Jean-Ralph Aviles)

 - Clean up lid handling in the ACPI button driver and
   acpi_button_probe(), reorganize installing and removing event
   handlers in that driver and switch it over to using devres-based
   resource management during probe (Rafael Wysocki)

 - Add support for the Legacy Virtual Register (LVR) field in I2C serial
   bus resource descriptors to ACPICA (Akhil R)

 - Fix multiple issues related to bounds checks, input validation,
   use-after-free, and integer overflow checks in the AML interpreter
   in ACPICA (ikaros)

 - Update the copyright year to 2026 in ACPICA files and make minor
   changes related to ACPI 6.6 support (Pawel Chmielewski)

 - Remove spurious precision from format used to dump parse trees in
   ACPICA (David Laight)

 - Add modern standby DSM GUIDs to ACPICA header files (Daniel Schaefer)

 - Fix FADT 32/64X length mismatch warning in ACPICA (Abdelkader Boudih)

 - Update D3hot/cold device power states definitions in ACPICA header
   files (Aymeric Wibo)

 - Fix NULL pointer dereference in acpi_ns_custom_package() (Weiming
   Shi)

 - Update ACPICA version to 20260408 (Saket Dumbre)

 - Add cpuidle driver check in acpi_processor_register_idle_driver() to
   avoid evaluating _CST unnecessarily (Tony W Wang-oc)

 - Suppress UBSAN warning caused by field misuse during PCC-based
   register access in the ACPI CPPC library (Jeremy Linton)

 - Add support for CPPC v4 to the ACPI CPPC library (Sumit Gupta)

 - Update the ACPI device enumeration code to honor _DEP for ACPI0016
   PCI/CXL host bridges and make the ACPI PCI root driver clear _DEP
   dependencies for PCI roots that have become operational (Chen Pei)

Thanks!


---------------

Abdelkader Boudih (1):
      ACPICA: Fix FADT 32/64X length mismatch warning

Akhil R (5):
      ACPICA: Add LVR to acrestyp.h
      ACPICA: Fetch LVR I2C resource descriptor
      ACPICA: Change LVR to 8 bit value
      ACPICA: Mention the LVR bits
      ACPICA: fix I2C LVR item count in the conversion table

Aymeric Wibo (1):
      ACPICA: actypes: Distinguish between D3hot/cold

Chen Pei (2):
      ACPI: PCI: Clear _DEP dependencies after PCI root bridge attach
      ACPI: scan: Honor _DEP for ACPI0016 PCI/CXL host bridge

Daniel Schaefer (1):
      ACPICA: Add modern standby DSM GUIDs

David Laight (1):
      ACPICA: Remove spurious precision from format used to dump parse trees

Jean-Ralph Aviles (1):
      ACPI: video: Do not initialise device_id_scheme directly

Jeremy Linton (1):
      ACPI: CPPC: Suppress UBSAN warning caused by field misuse

Maxwell Doose (1):
      ACPI: PMIC: Replace mutex_lock/unlock() with guard()/scoped_guard()

Miguel Vadillo (1):
      ACPI: scan: Honor _DEP for Intel CVS devices

Pawel Chmielewski (2):
      ACPICA: actbl2.h: ACPI 6.6: Updates for MADT MPWakeup
      ACPICA: Update the copyright year to 2026

Rafael J. Wysocki (37):
      ACPI: bus: Introduce devm_acpi_install_notify_handler()
      ACPI: NFIT: core: Use devm_acpi_install_notify_handler()
      ACPI: AC: Switch over to devres-based resource management
      ACPI: battery: Switch over to devres-based resource management
      ACPI: HED: Refine guarding against adding a second instance
      ACPI: HED: Switch over to devres-based resource management
      ACPI: thermal: Switch over to devres-based resource management
      ACPI: PAD: Rearrange acpi_pad_notify()
      ACPI: PAD: Pass struct device pointer to acpi_pad_notify()
      ACPI: PAD: Fix teardown ordering in acpi_pad_remove()
      ACPI: PAD: Switch over to devres-based resource management
      ACPI: video: Reduce the number of auxiliary device dereferences
      ACPI: video: Rearrange probe and remove code
      ACPI: video: Use devm action for video bus object cleanup
      ACPI: video: Use devm action for freeing video devices
      ACPI: video: Use devm for video->entry and backlight cleanup
      ACPI: video: Switch over to devres-based resource management
      ACPI: button: Fix lid_device value leak past driver removal
      ACPI: button: Pass ACPI handle to acpi_lid_evaluate_state()
      ACPI: button: Improve warning message regarding lid state
      ACPI: button: Use bool for representing boolean values
      ACPI: button: Eliminate ternary operator from acpi_lid_evaluate_state()
      ACPI: button: Change return type of two functions to void
      ACPI: button: Eliminate redundant conditional statement
      ACPI: button: Use local pointer to platform device dev field in probe
      ACPI: button: Rework device verification during probe
      ACPI: button: Drop redundant variable from acpi_button_probe()
      ACPI: button: Merge two switch () statements in acpi_button_probe()
      ACPI: button: Clean up adding and removing lid procfs interface
      ACPI: button: Use string literals for generating netlink messages
      ACPI: button: Reorganize installing and removing event handlers
      ACPI: button: Switch over to devres-based resource management
      ACPI: bus: Clean up devm_acpi_install_notify_handler()
      ACPI: NFIT: core: Fix possible NULL pointer dereference
      ACPI: NFIT: core: Fix acpi_nfit_init() error cleanup
      ACPI: NFIT: core: Eliminate redundant local variable
      ACPI: NFIT: core: Fix possible deadlock and missing notifications

Saket Dumbre (1):
      ACPICA: Update version to 20260408

Sumit Gupta (1):
      ACPI: CPPC: Add support for CPPC v4

Tony W Wang-oc (1):
      ACPI: processor: Add cpuidle driver check in
acpi_processor_register_idle_driver()

Weiming Shi (1):
      ACPICA: Fix NULL pointer dereference in acpi_ns_custom_package()

Yuho Choi (1):
      ACPI: IPMI: Fix message kref handling on dead device

Yury Norov (1):
      ACPI: PAD: Use sysfs_emit() in idlecpus_show()

ikaros (14):
      ACPICA: Fix condition check in acpi_ps_parse_loop()
      ACPICA: Add alias node support in namespace handling
      ACPICA: Fix use-after-free in acpi_ds_terminate_control_method()
      ACPICA: validate byte_count in acpi_ps_get_next_package_length()
      ACPICA: add boundary checks in acpi_ps_get_next_field()
      ACPICA: Prevent adding invalid references
      ACPICA: Fix integer overflow in acpi_ex_opcode_3A_1T_1R() (mid_op)
      ACPICA: Improve argument parsing in acpi_ps_get_next_simple_arg()
      ACPICA: validate handler object type in two places
      ACPICA: Add validation for node in acpi_ns_build_normalized_path()
      ACPICA: Enhance buffer validation in acpi_ut_walk_aml_resources()
      ACPICA: Enhance OEM ID and Table ID validation in acpi_ex_load_table_op()
      ACPICA: Add package limit checks in parser functions
      ACPICA: add boundary checks in two places

---------------

 drivers/acpi/ac.c                                  |  37 +-
 drivers/acpi/acpi_ipmi.c                           |   2 +-
 drivers/acpi/acpi_pad.c                            |  38 +-
 drivers/acpi/acpi_video.c                          | 139 ++++---
 drivers/acpi/acpica/acapps.h                       |   4 +-
 drivers/acpi/acpica/accommon.h                     |   2 +-
 drivers/acpi/acpica/acconvert.h                    |   2 +-
 drivers/acpi/acpica/acdebug.h                      |   2 +-
 drivers/acpi/acpica/acdispat.h                     |   2 +-
 drivers/acpi/acpica/acevents.h                     |   2 +-
 drivers/acpi/acpica/acglobal.h                     |   2 +-
 drivers/acpi/acpica/achware.h                      |   2 +-
 drivers/acpi/acpica/acinterp.h                     |   2 +-
 drivers/acpi/acpica/aclocal.h                      |   3 +-
 drivers/acpi/acpica/acmacros.h                     |   2 +-
 drivers/acpi/acpica/acnamesp.h                     |   2 +-
 drivers/acpi/acpica/acobject.h                     |   2 +-
 drivers/acpi/acpica/acopcode.h                     |   2 +-
 drivers/acpi/acpica/acparser.h                     |   2 +-
 drivers/acpi/acpica/acpredef.h                     |   2 +-
 drivers/acpi/acpica/acresrc.h                      |   2 +-
 drivers/acpi/acpica/acstruct.h                     |   2 +-
 drivers/acpi/acpica/actables.h                     |   2 +-
 drivers/acpi/acpica/acutils.h                      |   2 +-
 drivers/acpi/acpica/amlcode.h                      |   2 +-
 drivers/acpi/acpica/amlresrc.h                     |   2 +-
 drivers/acpi/acpica/dbhistry.c                     |   2 +-
 drivers/acpi/acpica/dsargs.c                       |   2 +-
 drivers/acpi/acpica/dscontrol.c                    |   2 +-
 drivers/acpi/acpica/dsdebug.c                      |   2 +-
 drivers/acpi/acpica/dsfield.c                      |   2 +-
 drivers/acpi/acpica/dsinit.c                       |   2 +-
 drivers/acpi/acpica/dsmethod.c                     |  45 +-
 drivers/acpi/acpica/dsobject.c                     |   2 +-
 drivers/acpi/acpica/dsopcode.c                     |   2 +-
 drivers/acpi/acpica/dspkginit.c                    |   2 +-
 drivers/acpi/acpica/dswexec.c                      |   2 +-
 drivers/acpi/acpica/dswload.c                      |   2 +-
 drivers/acpi/acpica/dswload2.c                     |   2 +-
 drivers/acpi/acpica/dswscope.c                     |   2 +-
 drivers/acpi/acpica/dswstate.c                     |   2 +-
 drivers/acpi/acpica/evevent.c                      |   2 +-
 drivers/acpi/acpica/evglock.c                      |   2 +-
 drivers/acpi/acpica/evgpe.c                        |   2 +-
 drivers/acpi/acpica/evgpeblk.c                     |   2 +-
 drivers/acpi/acpica/evgpeinit.c                    |   2 +-
 drivers/acpi/acpica/evgpeutil.c                    |   2 +-
 drivers/acpi/acpica/evhandler.c                    |  13 +-
 drivers/acpi/acpica/evmisc.c                       |   2 +-
 drivers/acpi/acpica/evregion.c                     |   2 +-
 drivers/acpi/acpica/evrgnini.c                     |   2 +-
 drivers/acpi/acpica/evxface.c                      |   2 +-
 drivers/acpi/acpica/evxfevnt.c                     |   2 +-
 drivers/acpi/acpica/evxfgpe.c                      |   2 +-
 drivers/acpi/acpica/evxfregn.c                     |   2 +-
 drivers/acpi/acpica/exconcat.c                     |   2 +-
 drivers/acpi/acpica/exconfig.c                     |  28 +-
 drivers/acpi/acpica/exconvrt.c                     |   2 +-
 drivers/acpi/acpica/excreate.c                     |   2 +-
 drivers/acpi/acpica/exdebug.c                      |   2 +-
 drivers/acpi/acpica/exdump.c                       |   2 +-
 drivers/acpi/acpica/exfield.c                      |   2 +-
 drivers/acpi/acpica/exfldio.c                      |   2 +-
 drivers/acpi/acpica/exmisc.c                       |   2 +-
 drivers/acpi/acpica/exmutex.c                      |   2 +-
 drivers/acpi/acpica/exnames.c                      |   2 +-
 drivers/acpi/acpica/exoparg1.c                     |   2 +-
 drivers/acpi/acpica/exoparg2.c                     |   2 +-
 drivers/acpi/acpica/exoparg3.c                     |   4 +-
 drivers/acpi/acpica/exoparg6.c                     |   2 +-
 drivers/acpi/acpica/exprep.c                       |   2 +-
 drivers/acpi/acpica/exregion.c                     |   2 +-
 drivers/acpi/acpica/exresnte.c                     |   2 +-
 drivers/acpi/acpica/exresolv.c                     |   2 +-
 drivers/acpi/acpica/exresop.c                      |   2 +-
 drivers/acpi/acpica/exserial.c                     |   2 +-
 drivers/acpi/acpica/exstore.c                      |   2 +-
 drivers/acpi/acpica/exstoren.c                     |   2 +-
 drivers/acpi/acpica/exstorob.c                     |   2 +-
 drivers/acpi/acpica/exsystem.c                     |   2 +-
 drivers/acpi/acpica/extrace.c                      |   2 +-
 drivers/acpi/acpica/exutils.c                      |   2 +-
 drivers/acpi/acpica/hwacpi.c                       |   2 +-
 drivers/acpi/acpica/hwesleep.c                     |   2 +-
 drivers/acpi/acpica/hwgpe.c                        |   2 +-
 drivers/acpi/acpica/hwsleep.c                      |   2 +-
 drivers/acpi/acpica/hwtimer.c                      |   2 +-
 drivers/acpi/acpica/hwvalid.c                      |   2 +-
 drivers/acpi/acpica/hwxface.c                      |   2 +-
 drivers/acpi/acpica/hwxfsleep.c                    |   2 +-
 drivers/acpi/acpica/nsarguments.c                  |   2 +-
 drivers/acpi/acpica/nsconvert.c                    |   2 +-
 drivers/acpi/acpica/nsdump.c                       |   2 +-
 drivers/acpi/acpica/nsdumpdv.c                     |   2 +-
 drivers/acpi/acpica/nsinit.c                       |   2 +-
 drivers/acpi/acpica/nsload.c                       |   2 +-
 drivers/acpi/acpica/nsnames.c                      |   6 +
 drivers/acpi/acpica/nsobject.c                     |   6 +
 drivers/acpi/acpica/nsparse.c                      |   2 +-
 drivers/acpi/acpica/nspredef.c                     |   2 +-
 drivers/acpi/acpica/nsprepkg.c                     |   9 +-
 drivers/acpi/acpica/nsrepair.c                     |   2 +-
 drivers/acpi/acpica/nsrepair2.c                    |   2 +-
 drivers/acpi/acpica/nsutils.c                      |   2 +-
 drivers/acpi/acpica/nswalk.c                       |   2 +-
 drivers/acpi/acpica/nsxfname.c                     |   6 +-
 drivers/acpi/acpica/psargs.c                       | 136 ++++++-
 drivers/acpi/acpica/psloop.c                       |  32 +-
 drivers/acpi/acpica/psobject.c                     |   2 +-
 drivers/acpi/acpica/psopcode.c                     |   2 +-
 drivers/acpi/acpica/psopinfo.c                     |   2 +-
 drivers/acpi/acpica/psparse.c                      |  16 +-
 drivers/acpi/acpica/psscope.c                      |   2 +-
 drivers/acpi/acpica/pstree.c                       |   2 +-
 drivers/acpi/acpica/psutils.c                      |   2 +-
 drivers/acpi/acpica/pswalk.c                       |   6 +-
 drivers/acpi/acpica/psxface.c                      |   2 +-
 drivers/acpi/acpica/rsserial.c                     |   7 +-
 drivers/acpi/acpica/tbdata.c                       |   2 +-
 drivers/acpi/acpica/tbfadt.c                       |   5 +-
 drivers/acpi/acpica/tbfind.c                       |   2 +-
 drivers/acpi/acpica/tbinstal.c                     |   2 +-
 drivers/acpi/acpica/tbprint.c                      |   2 +-
 drivers/acpi/acpica/tbutils.c                      |   2 +-
 drivers/acpi/acpica/tbxface.c                      |   2 +-
 drivers/acpi/acpica/tbxfload.c                     |   2 +-
 drivers/acpi/acpica/tbxfroot.c                     |   2 +-
 drivers/acpi/acpica/utaddress.c                    |   2 +-
 drivers/acpi/acpica/utalloc.c                      |   2 +-
 drivers/acpi/acpica/utascii.c                      |   2 +-
 drivers/acpi/acpica/utbuffer.c                     |   2 +-
 drivers/acpi/acpica/utcache.c                      |   2 +-
 drivers/acpi/acpica/utcksum.c                      |   2 +-
 drivers/acpi/acpica/utcopy.c                       |  12 +-
 drivers/acpi/acpica/utdebug.c                      |   2 +-
 drivers/acpi/acpica/utdecode.c                     |   2 +-
 drivers/acpi/acpica/uteval.c                       |   2 +-
 drivers/acpi/acpica/utglobal.c                     |   2 +-
 drivers/acpi/acpica/uthex.c                        |   2 +-
 drivers/acpi/acpica/utids.c                        |   2 +-
 drivers/acpi/acpica/utinit.c                       |   2 +-
 drivers/acpi/acpica/utlock.c                       |   2 +-
 drivers/acpi/acpica/utobject.c                     |   2 +-
 drivers/acpi/acpica/utosi.c                        |   2 +-
 drivers/acpi/acpica/utpredef.c                     |   2 +-
 drivers/acpi/acpica/utprint.c                      |   2 +-
 drivers/acpi/acpica/utresrc.c                      |  30 ++
 drivers/acpi/acpica/uttrack.c                      |   2 +-
 drivers/acpi/acpica/utuuid.c                       |   2 +-
 drivers/acpi/acpica/utxface.c                      |   2 +-
 drivers/acpi/acpica/utxfinit.c                     |   2 +-
 drivers/acpi/battery.c                             |  75 ++--
 drivers/acpi/bus.c                                 |  67 +++
 drivers/acpi/button.c                              | 452 +++++++++++----------
 drivers/acpi/cppc_acpi.c                           |  34 +-
 drivers/acpi/hed.c                                 |  25 +-
 drivers/acpi/nfit/core.c                           | 102 +++--
 drivers/acpi/pci_root.c                            |   4 +
 drivers/acpi/pmic/intel_pmic.c                     |  37 +-
 drivers/acpi/processor_idle.c                      |   9 +
 drivers/acpi/scan.c                                |   6 +-
 drivers/acpi/thermal.c                             |  53 +--
 include/acpi/acbuffer.h                            |   2 +-
 include/acpi/acconfig.h                            |   2 +-
 include/acpi/acexcep.h                             |   2 +-
 include/acpi/acnames.h                             |   2 +-
 include/acpi/acoutput.h                            |   2 +-
 include/acpi/acpi.h                                |   2 +-
 include/acpi/acpi_bus.h                            |   2 +
 include/acpi/acpiosxf.h                            |   2 +-
 include/acpi/acpixf.h                              |   4 +-
 include/acpi/acrestyp.h                            |   3 +-
 include/acpi/actbl.h                               |   2 +-
 include/acpi/actbl1.h                              |   2 +-
 include/acpi/actbl2.h                              |   4 +-
 include/acpi/actbl3.h                              |   2 +-
 include/acpi/actypes.h                             |   8 +-
 include/acpi/acuuid.h                              |   7 +-
 include/acpi/cppc_acpi.h                           |   8 +-
 include/acpi/platform/acenv.h                      |   2 +-
 include/acpi/platform/acenvex.h                    |   2 +-
 include/acpi/platform/acgcc.h                      |   2 +-
 include/acpi/platform/acgccex.h                    |   2 +-
 include/acpi/platform/aclinux.h                    |   2 +-
 include/acpi/platform/aclinuxex.h                  |   2 +-
 include/acpi/platform/aczephyr.h                   |   2 +-
 tools/power/acpi/common/cmfsize.c                  |   2 +-
 tools/power/acpi/common/getopt.c                   |   2 +-
 .../acpi/os_specific/service_layers/oslinuxtbl.c   |   2 +-
 .../acpi/os_specific/service_layers/osunixdir.c    |   2 +-
 .../acpi/os_specific/service_layers/osunixmap.c    |   2 +-
 .../acpi/os_specific/service_layers/osunixxf.c     |   2 +-
 tools/power/acpi/tools/acpidump/acpidump.h         |   2 +-
 tools/power/acpi/tools/acpidump/apdump.c           |   2 +-
 tools/power/acpi/tools/acpidump/apfiles.c          |   2 +-
 tools/power/acpi/tools/acpidump/apmain.c           |   2 +-
 196 files changed, 1109 insertions(+), 687 deletions(-)

^ permalink raw reply

* [PATCH] mailbox: pcc: Notify clients on polled completion
From: Sudeep Holla @ 2026-06-12 17:02 UTC (permalink / raw)
  To: linux-kernel, linux-acpi; +Cc: Sudeep Holla, Jassi Brar, Cristian Marussi

PCC channels without a platform interrupt rely on the mailbox
polling path to detect command completion.

That path currently only reports transmit completion to the mailbox
core, so clients that wait for their receive callback do not get
notified when the command completes.

Call mbox_chan_received_data() when polling observes completion on a
channel without a platform IRQ, matching the interrupt-driven
completion path.

Reported-by: Cristian Marussi <cristian.marussi@arm.com>
Signed-off-by: Sudeep Holla <sudeep.holla@kernel.org>
---
 drivers/mailbox/pcc.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c
index 636879ae1db7..7c9451ab4527 100644
--- a/drivers/mailbox/pcc.c
+++ b/drivers/mailbox/pcc.c
@@ -447,9 +447,14 @@ static int pcc_send_data(struct mbox_chan *chan, void *data)
 
 static bool pcc_last_tx_done(struct mbox_chan *chan)
 {
+	bool ret;
 	struct pcc_chan_info *pchan = chan->con_priv;
 
-	return pcc_mbox_cmd_complete_check(pchan);
+	ret = pcc_mbox_cmd_complete_check(pchan);
+	if (ret && !pchan->plat_irq)
+		mbox_chan_received_data(chan, NULL);
+
+	return ret;
 }
 
 /**
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH v5 09/10] dt-bindings: firmware: add arm,ras-cper
From: Rob Herring @ 2026-06-12 14:49 UTC (permalink / raw)
  To: Ahmed Tiba
  Cc: Jonathan Cameron, will, xueshuai, saket.dumbre, mchehab, dave,
	djbw, bp, tony.luck, guohanjun, lenb, skhan, vishal.l.verma,
	rafael, corbet, ira.weiny, dave.jiang, krzk+dt, catalin.marinas,
	alison.schofield, conor+dt, linux-arm-kernel, Michael.Zhao2,
	linux-doc, linux-kernel, linux-cxl, Dmitry.Lamerov, devicetree,
	linux-acpi, linux-edac, acpica-devel
In-Reply-To: <ceb19cb6-7083-44ad-a262-a8198f489257@arm.com>

On Thu, Jun 11, 2026 at 03:22:21PM +0100, Ahmed Tiba wrote:
> On 29/05/2026 17:44, Jonathan Cameron wrote:
> > On Fri, 29 May 2026 10:50:49 +0100
> > Ahmed Tiba<ahmed.tiba@arm.com> wrote:
> > >   .../devicetree/bindings/firmware/arm,ras-cper.yaml | 54 ++++++++++++++++++++++
> > >   MAINTAINERS                                        |  5 ++
> > >   2 files changed, 59 insertions(+)
> > > 
> > > diff --git a/Documentation/devicetree/bindings/firmware/arm,ras-cper.yaml b/Documentation/devicetree/bindings/firmware/arm,ras-cper.yaml
> > > new file mode 100644
> > > index 000000000000..3d4de096093f
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/firmware/arm,ras-cper.yaml
> > > @@ -0,0 +1,54 @@
> > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > +%YAML 1.2
> > > +---
> > > +$id:http://devicetree.org/schemas/firmware/arm,ras-cper.yaml#
> > > +$schema:http://devicetree.org/meta-schemas/core.yaml#
> > > +
> > > +title: Arm RAS CPER provider
> > > +
> > > +maintainers:
> > > +  - Ahmed Tiba<ahmed.tiba@arm.com>
> > > +
> > > +description:
> > > +  Arm Reliability, Availability and Serviceability (RAS) firmware can expose
> > > +  a firmware-first CPER error source directly via DeviceTree. Firmware
> > > +  provides the CPER Generic Error Status block and notifies the OS through
> > > +  an interrupt.
> > I'd like some spec references in here if possible.
> I can add a reference to the UEFI CPER specification for the Generic
> Error Status record format.
> 
> For the firmware-first DT description itself I do not have a more specific
> public reference to cite.

Is there a platform actually using this with DT (FVP doesn't really 
count)?

Rob

^ permalink raw reply

* Re: [PATCH v1 3/4] ACPI: APEI: GHES: Add Grace and Vera KUnit coverage
From: Julian Braha @ 2026-06-12 13:58 UTC (permalink / raw)
  To: Kai-Heng Feng, rafael, shuah, kees
  Cc: csoto, mochs, Tony Luck, Borislav Petkov, Hanjun Guo,
	Mauro Carvalho Chehab, Shuai Xue, Len Brown, Jonathan Cameron,
	Nathan Chancellor, Dave Jiang, Fabio M. De Francesco,
	linux-kernel, linux-acpi
In-Reply-To: <20260612120929.28965-4-kaihengf@nvidia.com>

On 6/12/26 13:09, Kai-Heng Feng wrote:

> +config ACPI_APEI_GHES_NVIDIA_KUNIT_TEST
> +	tristate "NVIDIA GHES vendor record handler KUnit tests"
> +	depends on KUNIT && ACPI_APEI_GHES_NVIDIA
> +	default KUNIT_ALL_TESTS
> +	help
> +	  KUnit tests for NVIDIA GHES vendor CPER parser helpers.
> +	  They cover Grace helper decoding, Vera payload parsing, and
> +	  section routing.
> +	  They are enabled only for KUnit test builds.
> +	  They are not intended for production firmware paths.
> +
> +	  If unsure, say N.
> +

Hi Kai-Heng, could you hide this option from the Kconfig frontend
when KUNIT_ALL_TESTS is enabled?

E.g.:
tristate "NVIDIA GHES vendor record handler KUnit tests" if !KUNIT_ALL_TESTS

From Documentation/dev-tools/kunit/style.rst:
"This Kconfig entry must:
<snip>
* be visible only if ``CONFIG_KUNIT_ALL_TESTS`` is not enabled."

- Julian Braha

^ permalink raw reply

* [PATCH v1 3/4] ACPI: APEI: GHES: Add Grace and Vera KUnit coverage
From: Kai-Heng Feng @ 2026-06-12 12:09 UTC (permalink / raw)
  To: rafael, shuah, kees
  Cc: csoto, mochs, Kai-Heng Feng, Tony Luck, Borislav Petkov,
	Hanjun Guo, Mauro Carvalho Chehab, Shuai Xue, Len Brown,
	Jonathan Cameron, Nathan Chancellor, Dave Jiang,
	Fabio M. De Francesco, linux-kernel, linux-acpi
In-Reply-To: <20260612120929.28965-1-kaihengf@nvidia.com>

Verify the Grace and Vera decoders against real binary records
captured from firmware before deploying to production hardware.
Tests cover both the happy path and the rejection of malformed
inputs across all constraint categories.

Signed-off-by: Kai-Heng Feng <kaihengf@nvidia.com>
---
 drivers/acpi/apei/Kconfig                     |  17 +-
 drivers/acpi/apei/Makefile                    |   1 +
 drivers/acpi/apei/ghes-nvidia-test-fixtures.h | 233 ++++++
 drivers/acpi/apei/ghes-nvidia-test.c          | 704 ++++++++++++++++++
 4 files changed, 953 insertions(+), 2 deletions(-)
 create mode 100644 drivers/acpi/apei/ghes-nvidia-test-fixtures.h
 create mode 100644 drivers/acpi/apei/ghes-nvidia-test.c

diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig
index 428458c623f0..163bbf7a6a35 100644
--- a/drivers/acpi/apei/Kconfig
+++ b/drivers/acpi/apei/Kconfig
@@ -80,14 +80,27 @@ config ACPI_APEI_GHES_NVIDIA
 	help
 	  Support for decoding NVIDIA-specific CPER sections delivered via
 	  the APEI GHES vendor record notifier chain. Registers a handler
-	  for the NVIDIA section GUID and logs error signatures, severity,
-	  socket, and diagnostic register address-value pairs.
+	  for the NVIDIA Grace and Vera section GUIDs and logs the decoded
+	  NVIDIA error records.

 	  Enable on NVIDIA server platforms (e.g. DGX, HGX) that expose
 	  ACPI device NVDA2012 in their firmware tables.

 	  If unsure, say N.

+config ACPI_APEI_GHES_NVIDIA_KUNIT_TEST
+	tristate "NVIDIA GHES vendor record handler KUnit tests"
+	depends on KUNIT && ACPI_APEI_GHES_NVIDIA
+	default KUNIT_ALL_TESTS
+	help
+	  KUnit tests for NVIDIA GHES vendor CPER parser helpers.
+	  They cover Grace helper decoding, Vera payload parsing, and
+	  section routing.
+	  They are enabled only for KUnit test builds.
+	  They are not intended for production firmware paths.
+
+	  If unsure, say N.
+
 config ACPI_APEI_ERST_DEBUG
 	tristate "APEI Error Record Serialization Table (ERST) Debug Support"
 	depends on ACPI_APEI
diff --git a/drivers/acpi/apei/Makefile b/drivers/acpi/apei/Makefile
index 66588d6be56f..210a57242044 100644
--- a/drivers/acpi/apei/Makefile
+++ b/drivers/acpi/apei/Makefile
@@ -11,5 +11,6 @@ einj-y				:= einj-core.o
 einj-$(CONFIG_ACPI_APEI_EINJ_CXL) += einj-cxl.o
 obj-$(CONFIG_ACPI_APEI_ERST_DEBUG) += erst-dbg.o
 obj-$(CONFIG_ACPI_APEI_GHES_NVIDIA) += ghes-nvidia.o
+obj-$(CONFIG_ACPI_APEI_GHES_NVIDIA_KUNIT_TEST) += ghes-nvidia-test.o

 apei-y := apei-base.o hest.o erst.o bert.o
diff --git a/drivers/acpi/apei/ghes-nvidia-test-fixtures.h b/drivers/acpi/apei/ghes-nvidia-test-fixtures.h
new file mode 100644
index 000000000000..705c879c785e
--- /dev/null
+++ b/drivers/acpi/apei/ghes-nvidia-test-fixtures.h
@@ -0,0 +1,233 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef GHES_NVIDIA_TEST_FIXTURES_H
+#define GHES_NVIDIA_TEST_FIXTURES_H
+
+#include <linux/types.h>
+
+/*
+ * Source: cper-tools/test_data/vera_msft.json
+ * cper-tools commit: bf18f75406422e73e11b8b1ff80e3c9d9cfb032a
+ * Boundary: CPER.Oem.Nvidia.Unknown.Data.
+ * Each payload equals the Vera GUID section body located in DiagnosticData.
+ */
+
+/* Redfish Id 10, signature L1 RESET, real sample. */
+/* Vera section index 0, offset 200, length 80. */
+/* sha256 fc11639e506eb8d79e7ff16a0556463ac4b1304bface935c0cd13efc0b3e317f. */
+static const u8 vera_l1_reset_id10[] = {
+	0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x4c, 0x31, 0x20, 0x52, 0x45, 0x53, 0x45, 0x54,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
+	0x07, 0x41, 0x01, 0x00, 0xc0, 0x01, 0xfe, 0x06, 0x00, 0x00, 0x00, 0x00,
+	0x81, 0xc1, 0x18, 0x78, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
+	0x15, 0xfe, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+/* Redfish Id 40, signature CRASHDUMP-ID, real sample. */
+/* Vera section index 0, offset 200, length 304. */
+/* sha256 3ba93201740e6bd868b48ec40c3d52b235c1ebc59528fc81974079c21bf2a6a2. */
+static const u8 vera_crashdump_id_id40[] = {
+	0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x43, 0x52, 0x41, 0x53, 0x48, 0x44, 0x55, 0x4d,
+	0x50, 0x2d, 0x49, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
+	0x07, 0x41, 0x01, 0x00, 0xc0, 0x01, 0xfe, 0x06, 0x00, 0x00, 0x00, 0x00,
+	0x81, 0xc1, 0x18, 0x78, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x01, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x83, 0x72, 0x65, 0x6c, 0x5f, 0x37, 0x33, 0x2e, 0x37,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x64, 0x69, 0x72, 0x74,
+	0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85,
+	0x44, 0x24, 0x4e, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x10, 0x00,
+	0x14, 0xfe, 0x00, 0x00, 0x07, 0x41, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x04, 0x07, 0x03, 0x03, 0x14, 0xfe, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x20, 0x00, 0x15, 0xfe, 0x00, 0x00,
+	0x9d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x04, 0x00,
+	0x14, 0xfe, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x14, 0x0a, 0x04, 0x00, 0x14, 0xfe, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x18, 0x0a, 0x04, 0x00, 0x14, 0xfe, 0x00, 0x00,
+	0x40, 0x60, 0x30, 0x06, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0a, 0x04, 0x00,
+	0x14, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x20, 0x0a, 0x04, 0x00, 0x14, 0xfe, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x24, 0x0a, 0x04, 0x00, 0x14, 0xfe, 0x00, 0x00,
+	0xfc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x0a, 0x04, 0x00,
+	0x14, 0xfe, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x2c, 0x0a, 0x04, 0x00, 0x14, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+};
+
+/* Redfish Id 41, signature CRASHDUMP-S1, real sample. */
+/* Vera section index 0, offset 200, length 2008. */
+/* sha256 54db30564d3324240f088a1533c113407f1d81bcd652ef0d27d958c490aee5ce. */
+static const u8 vera_crashdump_s1_id41[] = {
+	0x01, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x43, 0x52, 0x41, 0x53, 0x48, 0x44, 0x55, 0x4d,
+	0x50, 0x2d, 0x53, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
+	0x07, 0x41, 0x01, 0x00, 0xc0, 0x01, 0xfe, 0x06, 0x00, 0x00, 0x00, 0x00,
+	0x81, 0xc1, 0x18, 0x78, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x88, 0x07, 0x00, 0x00, 0x53, 0x56, 0x7f, 0xa1,
+	0xd1, 0xd7, 0x7f, 0xe5, 0xaa, 0x34, 0xde, 0x7d, 0xe9, 0x3e, 0xc4, 0xd4,
+	0x92, 0xe8, 0x10, 0xa1, 0x4c, 0xfc, 0xf9, 0x2e, 0x02, 0x87, 0xc5, 0x6e,
+	0x44, 0xfb, 0xb5, 0x59, 0xac, 0xfa, 0xa8, 0x15, 0x75, 0x46, 0x2d, 0x67,
+	0x84, 0xe0, 0x78, 0x14, 0xe4, 0x18, 0x8e, 0x30, 0x46, 0xff, 0xbe, 0x5e,
+	0x15, 0x3e, 0x61, 0xf4, 0xcc, 0x3d, 0x2e, 0xdf, 0x1b, 0xf9, 0x1f, 0x1c,
+	0xa3, 0xf8, 0x35, 0x34, 0xe1, 0x4c, 0xb7, 0xd0, 0xcc, 0xda, 0xf1, 0xbc,
+	0x02, 0x8d, 0xc2, 0x6b, 0x5d, 0x56, 0xd4, 0x48, 0x89, 0x7f, 0xb2, 0x64,
+	0xda, 0xa0, 0xf4, 0xed, 0xef, 0xf7, 0x5f, 0x29, 0x38, 0x51, 0x59, 0x35,
+	0x1f, 0x52, 0x63, 0xa8, 0x45, 0x02, 0x7a, 0x24, 0xf6, 0x26, 0x83, 0x29,
+	0x65, 0x01, 0x77, 0x0e, 0xb2, 0x5e, 0xac, 0xf2, 0xd4, 0xc0, 0x09, 0x94,
+	0x5c, 0x4d, 0x55, 0xaf, 0xcf, 0xb7, 0x8c, 0xad, 0x47, 0xcf, 0x02, 0x2c,
+	0x8c, 0x0f, 0x28, 0xf1, 0x4c, 0x15, 0x66, 0xb0, 0xb4, 0x7d, 0xd1, 0xf6,
+	0x90, 0xc8, 0x5e, 0x64, 0x16, 0x9f, 0x5f, 0x3f, 0x50, 0xc9, 0x62, 0x91,
+	0x87, 0xd8, 0xd7, 0xe9, 0x9f, 0x7b, 0xcd, 0xc9, 0xfe, 0xa1, 0xd3, 0xf2,
+	0xc2, 0x95, 0xc7, 0x37, 0x34, 0x6c, 0xc4, 0xc0, 0x53, 0x56, 0x01, 0x2c,
+	0x96, 0x63, 0xdb, 0x2c, 0xea, 0x09, 0xa0, 0xaa, 0xe5, 0xe2, 0x48, 0x18,
+	0x3c, 0x68, 0xf9, 0xa0, 0x7f, 0x98, 0x5a, 0xe3, 0xe8, 0x8e, 0x83, 0x71,
+	0x51, 0x79, 0xc3, 0x14, 0xf1, 0xf4, 0xac, 0xd5, 0xd9, 0x8c, 0xab, 0x33,
+	0x4e, 0x9f, 0xc2, 0xb7, 0xed, 0x6f, 0x78, 0x81, 0x77, 0x34, 0xb8, 0xea,
+	0xb0, 0x71, 0xa1, 0x4d, 0x08, 0x40, 0xad, 0x4c, 0x95, 0x6a, 0x21, 0x96,
+	0x07, 0x12, 0x62, 0xed, 0x42, 0xa9, 0xe4, 0xa8, 0x88, 0xc7, 0x81, 0xff,
+	0x88, 0x07, 0x00, 0x00, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x83, 0xbc, 0x15, 0xd9, 0x0b, 0x6b, 0x3b, 0x3b, 0xff, 0x77, 0xb2, 0x7c,
+	0x0c, 0xdd, 0xfb, 0x00, 0x7e, 0x0a, 0x88, 0x47, 0x8a, 0xf2, 0xf8, 0xc5,
+	0x07, 0x51, 0x0e, 0xd7, 0xcb, 0x78, 0xea, 0x89, 0x37, 0x2a, 0x44, 0x0d,
+	0x74, 0x4f, 0x9e, 0x6d, 0x2c, 0xf9, 0x53, 0xed, 0x38, 0x34, 0xca, 0x38,
+	0x7d, 0x96, 0xfe, 0x9a, 0x9b, 0x23, 0x3b, 0x17, 0x17, 0x69, 0xe6, 0x6c,
+	0x0e, 0xe6, 0x71, 0xf5, 0x59, 0xf6, 0xc4, 0x82, 0xd6, 0x83, 0xb1, 0x76,
+	0x41, 0x22, 0x53, 0x72, 0x9f, 0x85, 0x0d, 0xdc, 0x67, 0x22, 0x35, 0xd3,
+	0xe3, 0xaf, 0x10, 0x50, 0xc8, 0xe1, 0xb0, 0xea, 0xc9, 0x1a, 0x3e, 0x02,
+	0x36, 0xea, 0x94, 0xb1, 0x27, 0xfc, 0xc9, 0x61, 0xcb, 0x6f, 0xb0, 0x50,
+	0xe1, 0x85, 0x1c, 0x2d, 0x5f, 0xb5, 0x63, 0x38, 0x69, 0x02, 0xb3, 0x7d,
+	0xb3, 0xb5, 0xe0, 0xfe, 0x5a, 0xf1, 0x0d, 0x83, 0xd9, 0x51, 0xcc, 0xa2,
+	0xb5, 0x41, 0x3b, 0xd1, 0xf5, 0x58, 0xe8, 0x54, 0x49, 0x78, 0xc1, 0x8b,
+	0x70, 0xf1, 0x94, 0x45, 0x18, 0x4b, 0x19, 0x58, 0xe6, 0x0a, 0x08, 0x27,
+	0xe7, 0x95, 0xd6, 0x82, 0xb7, 0x8c, 0xae, 0xae, 0x58, 0x33, 0xc2, 0x02,
+	0xf8, 0xfb, 0x8a, 0x73, 0xe4, 0x0b, 0x75, 0x9b, 0x00, 0x76, 0x14, 0x31,
+	0x5e, 0xf5, 0xf0, 0x8b, 0xb7, 0x6b, 0xaf, 0xdd, 0x8b, 0x52, 0xc9, 0x79,
+	0xe7, 0xd3, 0x17, 0x90, 0xa4, 0xb0, 0xa0, 0x97, 0xcf, 0xba, 0x37, 0x1d,
+	0xe0, 0xbf, 0x31, 0xff, 0xe9, 0x3a, 0x50, 0x5b, 0xf8, 0x94, 0xd0, 0x33,
+	0xf9, 0x2d, 0x2e, 0x54, 0xfa, 0x11, 0x63, 0x06, 0xf2, 0x32, 0xb9, 0x7b,
+	0xd9, 0xc6, 0x12, 0x60, 0xa6, 0x16, 0xac, 0xc8, 0x02, 0xf7, 0xd6, 0xd5,
+	0xb6, 0x2e, 0xf0, 0xb3, 0x05, 0x39, 0x47, 0xd4, 0xa9, 0xed, 0x1a, 0xca,
+	0x4c, 0x4f, 0x83, 0x2d, 0xcc, 0x5c, 0xa7, 0x02, 0x01, 0x84, 0xc9, 0x07,
+	0xa5, 0x6a, 0xf7, 0xbe, 0x3d, 0xc2, 0x09, 0xe8, 0xc8, 0xf8, 0x4b, 0x71,
+	0xa8, 0x79, 0x6c, 0x68, 0xda, 0x35, 0xe1, 0xd2, 0x9d, 0xa6, 0xb3, 0x70,
+	0xf6, 0xcb, 0x66, 0x41, 0xde, 0x86, 0x11, 0x2a, 0xd0, 0xa1, 0x84, 0x99,
+	0x5b, 0xdf, 0x74, 0x26, 0x18, 0xba, 0x6f, 0x3e, 0x46, 0xef, 0xe7, 0xd2,
+	0xfd, 0xe5, 0xa8, 0xba, 0xff, 0xe4, 0xe0, 0x50, 0x9f, 0x23, 0xe5, 0x03,
+	0x81, 0xc2, 0xab, 0x74, 0xd8, 0xc4, 0xe9, 0xd5, 0xf6, 0x7f, 0x86, 0x6b,
+	0x06, 0xfc, 0x62, 0x0f, 0xeb, 0xa3, 0xc4, 0xa0, 0xad, 0x70, 0xad, 0x9b,
+	0xdf, 0xd1, 0x75, 0x28, 0xdc, 0xf2, 0x24, 0x87, 0x6e, 0x85, 0x67, 0xfb,
+	0xbb, 0x38, 0x86, 0xd8, 0x77, 0x15, 0x35, 0x41, 0x53, 0x69, 0x71, 0xd9,
+	0x33, 0x00, 0x2c, 0x56, 0x45, 0xfd, 0xfc, 0xea, 0xf9, 0x8f, 0xd7, 0x04,
+	0x6a, 0x8d, 0xf5, 0x4b, 0xd1, 0x5a, 0x66, 0x7e, 0xe0, 0xeb, 0x06, 0x80,
+	0xc2, 0x14, 0x00, 0x49, 0x1c, 0x62, 0x54, 0xdb, 0x4b, 0x80, 0xc1, 0xa1,
+	0xe3, 0x36, 0xc0, 0x58, 0x0f, 0x6c, 0x65, 0xfc, 0xc8, 0x4d, 0x85, 0xa5,
+	0x5e, 0xb2, 0xbd, 0x5e, 0x2d, 0x47, 0x14, 0x77, 0x32, 0x7e, 0x39, 0x0b,
+	0xba, 0xcd, 0x30, 0x4b, 0x8e, 0x3b, 0x6d, 0x66, 0x59, 0x73, 0x16, 0x0b,
+	0x23, 0x99, 0xb5, 0x09, 0xb7, 0x8f, 0xb2, 0x96, 0x1f, 0x74, 0x08, 0x36,
+	0x1f, 0xcd, 0x46, 0x90, 0x1b, 0xe9, 0xfe, 0xe1, 0xcb, 0x7e, 0x06, 0x98,
+	0x74, 0x47, 0x2f, 0x57, 0x0b, 0x72, 0xea, 0x0d, 0x25, 0xed, 0x92, 0x70,
+	0x0d, 0x00, 0x5f, 0x48, 0xe3, 0xff, 0x3f, 0x39, 0xfc, 0xa9, 0x66, 0xa9,
+	0x95, 0x33, 0xcd, 0x8b, 0x22, 0x11, 0xd9, 0xff, 0x7e, 0x5c, 0x9d, 0x80,
+	0xc5, 0xed, 0x99, 0x78, 0x5c, 0x33, 0xdd, 0x0e, 0xca, 0x6a, 0xe2, 0xb6,
+	0x3a, 0x66, 0xbd, 0x1d, 0x60, 0x96, 0x28, 0x20, 0xbd, 0x8c, 0xf4, 0x6c,
+	0xcb, 0xc3, 0x9b, 0x19, 0x78, 0xd7, 0x57, 0xa3, 0xc3, 0x12, 0x95, 0x11,
+	0x3d, 0xab, 0x44, 0x0d, 0x78, 0xbb, 0x2e, 0x0b, 0x4e, 0x0c, 0x94, 0x75,
+	0xe7, 0x8f, 0x5c, 0xad, 0xe4, 0x2f, 0x9c, 0x26, 0x00, 0x01, 0x71, 0xe1,
+	0x36, 0xcf, 0xb1, 0x00, 0x8f, 0xf7, 0x86, 0x79, 0x2e, 0x79, 0x9e, 0xd5,
+	0x8b, 0x53, 0x0d, 0x28, 0x6c, 0xb9, 0xa2, 0xdf, 0x04, 0xe3, 0x78, 0x6d,
+	0xcb, 0xb7, 0xf9, 0xea, 0x20, 0x4a, 0x5d, 0x92, 0x64, 0x88, 0x7d, 0xc4,
+	0x5a, 0x21, 0x86, 0x12, 0x46, 0x49, 0x6d, 0xbc, 0x03, 0xd5, 0xeb, 0xf6,
+	0xe3, 0x38, 0x4a, 0xaa, 0xce, 0x45, 0x91, 0x6a, 0xc0, 0x59, 0x1b, 0x6c,
+	0x98, 0xb2, 0xe0, 0x29, 0x91, 0x01, 0xb5, 0x44, 0x48, 0xa6, 0xd3, 0x78,
+	0x5a, 0xe1, 0xe4, 0x8c, 0xd9, 0x33, 0xa0, 0xd5, 0xe1, 0x83, 0xd6, 0x5a,
+	0xe3, 0x5f, 0xe6, 0xf8, 0xfd, 0x21, 0x12, 0xff, 0x9e, 0x71, 0x70, 0x7f,
+	0x17, 0xe2, 0x41, 0xf2, 0xb1, 0x4a, 0x84, 0x6b, 0x88, 0xb6, 0xb9, 0xed,
+	0xdb, 0x0b, 0x84, 0x6f, 0x07, 0x94, 0xc7, 0x8e, 0xcc, 0xc2, 0xb2, 0x49,
+	0x3d, 0xf8, 0x70, 0x1a, 0x9b, 0x4d, 0x13, 0x0c, 0xe7, 0xeb, 0x75, 0x5d,
+	0xfb, 0x10, 0x16, 0xf9, 0xf1, 0xac, 0x4b, 0xe3, 0x65, 0x5f, 0xaa, 0xbb,
+	0x31, 0xac, 0x4d, 0x74, 0x11, 0x62, 0x64, 0xd1, 0x90, 0x6e, 0x45, 0xaf,
+	0x2d, 0xb2, 0xa5, 0xfa, 0x57, 0x67, 0xaa, 0x4c, 0x3f, 0x81, 0x72, 0x93,
+	0x8a, 0xfb, 0xeb, 0x19, 0x9d, 0x9a, 0x10, 0x8d, 0xce, 0xb8, 0xe9, 0x3f,
+	0x97, 0x3e, 0xb2, 0x2d, 0x3e, 0xaf, 0x19, 0x39, 0xb0, 0xea, 0x33, 0x09,
+	0x25, 0xbc, 0x6f, 0x88, 0x25, 0x75, 0x11, 0x2b, 0xd9, 0x42, 0x8d, 0x48,
+	0x8e, 0xe7, 0x51, 0x4e, 0xd4, 0xee, 0xd4, 0xf1, 0xe1, 0x94, 0xfb, 0xbd,
+	0x01, 0x87, 0xa5, 0xd6, 0x94, 0x36, 0x6f, 0x37, 0xcd, 0x70, 0x49, 0xfd,
+	0x6a, 0x94, 0xb0, 0xc8, 0xe5, 0xb9, 0xdb, 0x83, 0x72, 0xa0, 0xd8, 0x5e,
+	0x00, 0x3e, 0x3d, 0x56, 0xc9, 0xae, 0xf6, 0xe7, 0xb1, 0xba, 0xdd, 0x6d,
+	0x59, 0x2a, 0x6a, 0x50, 0x66, 0xfd, 0xf1, 0x1f, 0x18, 0xe4, 0xf9, 0x59,
+	0x16, 0xf1, 0x25, 0x42, 0x7c, 0xab, 0xc5, 0xea, 0x64, 0x31, 0xf7, 0xcf,
+	0xdd, 0x56, 0xc4, 0xbd, 0xb5, 0xe6, 0xb4, 0xda, 0x41, 0xb7, 0xfa, 0x05,
+	0x06, 0x57, 0x51, 0xd8, 0xc4, 0xf7, 0x3c, 0xc8, 0x54, 0x55, 0x5c, 0x2c,
+	0xd2, 0x17, 0xec, 0x27, 0xd3, 0xbf, 0xf3, 0xc8, 0xba, 0xbf, 0x75, 0xcf,
+	0x1f, 0x78, 0x42, 0x1a, 0x4f, 0xb0, 0xcb, 0xd7, 0x84, 0xc6, 0xbd, 0x40,
+	0x07, 0xbf, 0x47, 0xe9, 0x17, 0x2f, 0xad, 0xec, 0x64, 0x8b, 0xca, 0x7c,
+	0x49, 0x4c, 0xda, 0xf9, 0x5f, 0x28, 0x1d, 0x2d, 0xc3, 0x8d, 0x15, 0xa6,
+	0x0f, 0x95, 0x76, 0x99, 0xb5, 0x76, 0x68, 0x97, 0x91, 0x93, 0xca, 0x9d,
+	0x61, 0x50, 0xa7, 0xa7, 0xf7, 0xce, 0xd5, 0x14, 0xe5, 0xb2, 0x50, 0x50,
+	0x21, 0x73, 0x00, 0x21, 0x4f, 0x12, 0x79, 0x7f, 0x68, 0x27, 0x52, 0xf2,
+	0x2c, 0x9d, 0x2d, 0x4f, 0x66, 0x3e, 0xf1, 0xb5, 0x68, 0x77, 0xc9, 0xd5,
+	0x16, 0x01, 0xb2, 0x6d, 0x46, 0x7c, 0xce, 0x8d, 0x67, 0x77, 0x27, 0xdd,
+	0x4b, 0x16, 0xd7, 0x7b, 0x16, 0xfd, 0x6b, 0x18, 0x36, 0xeb, 0xa5, 0xd6,
+	0xd1, 0x21, 0xdb, 0x27, 0x01, 0x9a, 0x22, 0xa1, 0xbf, 0x45, 0xda, 0xf7,
+	0xe4, 0x07, 0x26, 0x0c, 0x84, 0xe1, 0x81, 0x1c, 0xf9, 0x38, 0x4a, 0x26,
+	0xb3, 0xe3, 0x90, 0x13, 0x5e, 0xb7, 0xd5, 0xaf, 0xcb, 0x7d, 0xc1, 0xf7,
+	0x23, 0x2d, 0x96, 0xc8, 0xe7, 0x3e, 0x21, 0x2c, 0xee, 0xa8, 0xd7, 0x83,
+	0xf1, 0xd7, 0xf0, 0xce, 0xca, 0x80, 0xb5, 0xbd, 0x89, 0x10, 0x71, 0x38,
+	0x8c, 0xa2, 0xa1, 0x07, 0x93, 0xa9, 0xd9, 0x4d, 0xa5, 0x9b, 0x66, 0x68,
+	0x06, 0x65, 0x8d, 0x26, 0xff, 0xcb, 0xf2, 0xf5, 0x09, 0x7c, 0xf1, 0x7f,
+	0x55, 0x3f, 0x61, 0x78, 0xb8, 0x27, 0x77, 0xb8, 0x30, 0x91, 0x10, 0x3f,
+	0x57, 0xec, 0xfd, 0x82, 0xd2, 0xd3, 0x8a, 0x27, 0xa5, 0x26, 0x87, 0x01,
+	0x8a, 0x20, 0x9a, 0x5d, 0xe9, 0x88, 0xa7, 0x70, 0xb0, 0x06, 0x04, 0xe8,
+	0xa0, 0x15, 0x2c, 0x0b, 0xe5, 0xea, 0x79, 0x57, 0xad, 0x8c, 0xe2, 0x98,
+	0xcd, 0xbf, 0x74, 0x1c, 0xb6, 0x06, 0xc6, 0x17, 0x12, 0x2b, 0xa4, 0xa6,
+	0xfe, 0xe7, 0x94, 0xf9, 0xb6, 0x95, 0xf0, 0xfc, 0xe5, 0x57, 0xfe, 0xf9,
+	0x1d, 0xd4, 0x29, 0xc0, 0x06, 0xf9, 0x5f, 0x14, 0x73, 0x14, 0x1d, 0x42,
+	0x1f, 0x70, 0xa0, 0xd5, 0x3d, 0x0d, 0xbe, 0xfb, 0xb3, 0xe0, 0xae, 0x35,
+	0x34, 0x40, 0xa9, 0xca, 0x5d, 0x6f, 0x4f, 0x3a, 0x3b, 0x9e, 0xe2, 0xed,
+	0x85, 0xa9, 0x53, 0xb9, 0xb2, 0x43, 0x5e, 0x95, 0x7a, 0x30, 0x63, 0x2a,
+	0x84, 0x40, 0x1b, 0x86, 0x2d, 0x74, 0xf6, 0xf3, 0x3b, 0x40, 0x5b, 0x16,
+	0x51, 0xa1, 0xaa, 0x70, 0xed, 0xb3, 0x96, 0x66, 0x9b, 0x6b, 0x57, 0x4d,
+	0x0d, 0x8b, 0x2a, 0x9b, 0x27, 0xb6, 0x04, 0xa5, 0x19, 0xb2, 0x17, 0xad,
+	0x6f, 0x6f, 0xef, 0x8c, 0xae, 0x87, 0x58, 0xc9, 0xbd, 0x51, 0xf9, 0x6b,
+	0x7d, 0x5c, 0xd1, 0x42, 0x10, 0xa1, 0x5c, 0x66, 0x13, 0xaa, 0xe0, 0xfc,
+	0x91, 0x95, 0x63, 0x0a, 0x0b, 0x3d, 0x5c, 0xd1, 0x64, 0xda, 0xaf, 0x7b,
+	0x1b, 0x0a, 0x09, 0x9f, 0xf8, 0xd9, 0x43, 0x7b, 0x7d, 0xe1, 0x34, 0x68,
+	0x6a, 0xb2, 0x3a, 0x16, 0x99, 0x2f, 0x29, 0x5f, 0xa3, 0xe6, 0x03, 0x74,
+	0x42, 0x49, 0x6a, 0x33, 0x15, 0x93, 0x5e, 0xa5, 0xab, 0x13, 0x77, 0x3a,
+	0x1a, 0x78, 0x6d, 0xe5, 0x06, 0x1f, 0xa4, 0x6f, 0xdc, 0xa8, 0xc8, 0x93,
+	0x9f, 0x4d, 0x99, 0xba, 0xb1, 0x6d, 0x8d, 0x1d, 0xc0, 0x6b, 0xff, 0x16,
+	0x7d, 0xb3, 0xfc, 0xe0, 0xd7, 0xd4, 0xb2, 0x69, 0x32, 0x38, 0x64, 0xef,
+	0x04, 0xba, 0x7b, 0xa5, 0x5e, 0xc6, 0x1f, 0x1d, 0xd0, 0xf8, 0x6b, 0xd8,
+	0x35, 0xb9, 0x9e, 0x2f, 0x62, 0x36, 0xf5, 0x88, 0x41, 0x90, 0x1f, 0xc7,
+	0xc3, 0x96, 0x1b, 0x4f, 0xc4, 0x87, 0x0c, 0xea, 0xdb, 0x8f, 0xea, 0x6a,
+	0xe9, 0xdc, 0x30, 0xc4, 0x6c, 0x23, 0x9b, 0xac, 0x8b, 0xf6, 0xa6, 0xbf,
+	0xc0, 0xd6, 0x00, 0xf6, 0x92, 0x3f, 0xd3, 0x83, 0xfe, 0x74, 0x7c, 0x19,
+	0x74, 0xfb, 0xe7, 0x72, 0x81, 0x17, 0x32, 0x32, 0xb8, 0x4b, 0x5d, 0x70,
+	0x67, 0x14, 0xe1, 0xee,
+};
+
+#endif
diff --git a/drivers/acpi/apei/ghes-nvidia-test.c b/drivers/acpi/apei/ghes-nvidia-test.c
new file mode 100644
index 000000000000..5c84da82f898
--- /dev/null
+++ b/drivers/acpi/apei/ghes-nvidia-test.c
@@ -0,0 +1,704 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <kunit/test.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/unaligned.h>
+#include <linux/uuid.h>
+
+#include "ghes-nvidia.h"
+#include "ghes-nvidia-test-fixtures.h"
+
+static const u8 grace_valid_two_regs[] = {
+	'N', 'V', 'D', 'A', '-', 'G', 'R', 'A',
+	'C', 'E', 0, 0, 0, 0, 0, 0,
+	0x34, 0x12, 0x78, 0x56, 0x02, 0x03, 0x02, 0x00,
+	0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
+	0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const u8 grace_valid_zero_regs[] = {
+	'N', 'V', 'D', 'A', '-', 'G', 'R', 'A',
+	'C', 'E', 0, 0, 0, 0, 0, 0,
+	0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00,
+	0xef, 0xbe, 0xad, 0xde, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const u8 grace_valid_full_signature[] = {
+	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+	'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+	0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00,
+	0xef, 0xbe, 0xad, 0xde, 0x00, 0x00, 0x00, 0x00,
+};
+
+static void nvidia_ghes_grace_decodes_registers(struct kunit *test)
+{
+	struct nvidia_ghes_decoded decoded = {};
+	u64 addr, val;
+
+	KUNIT_EXPECT_EQ(test, 0,
+			nvidia_ghes_decode_grace(NULL, grace_valid_two_regs,
+						 sizeof(grace_valid_two_regs),
+						 &decoded));
+	KUNIT_EXPECT_EQ(test, NVIDIA_GHES_FORMAT_GRACE, decoded.format);
+	KUNIT_EXPECT_STREQ(test, "NVDA-GRACE", decoded.signature);
+	KUNIT_EXPECT_EQ(test, 0x1234, decoded.error_type);
+	KUNIT_EXPECT_EQ(test, 0x5678, decoded.error_instance);
+	KUNIT_EXPECT_EQ(test, 2, decoded.severity);
+	KUNIT_EXPECT_EQ(test, 3, decoded.socket);
+	KUNIT_EXPECT_EQ(test, 2, decoded.number_regs);
+	KUNIT_EXPECT_EQ(test, 0x0102030405060708ULL, decoded.instance_base);
+	KUNIT_EXPECT_EQ(test, 0,
+			nvidia_ghes_grace_reg_pair(&decoded, 0, &addr, &val));
+	KUNIT_EXPECT_EQ(test, 0x1000ULL, addr);
+	KUNIT_EXPECT_EQ(test, 0x1111ULL, val);
+	KUNIT_EXPECT_EQ(test, 0,
+			nvidia_ghes_grace_reg_pair(&decoded, 1, &addr, &val));
+	KUNIT_EXPECT_EQ(test, 0x2000ULL, addr);
+	KUNIT_EXPECT_EQ(test, 0x2222ULL, val);
+}
+
+static void nvidia_ghes_grace_accepts_zero_registers(struct kunit *test)
+{
+	struct nvidia_ghes_decoded decoded = {};
+
+	KUNIT_EXPECT_EQ(test, 0,
+			nvidia_ghes_decode_grace(NULL, grace_valid_zero_regs,
+						 sizeof(grace_valid_zero_regs),
+						 &decoded));
+	KUNIT_EXPECT_EQ(test, NVIDIA_GHES_FORMAT_GRACE, decoded.format);
+	KUNIT_EXPECT_EQ(test, 0, decoded.number_regs);
+	KUNIT_EXPECT_PTR_EQ(test, NULL, decoded.grace_regs);
+}
+
+static void nvidia_ghes_grace_copies_non_nul_signature(struct kunit *test)
+{
+	struct nvidia_ghes_decoded decoded = {};
+
+	KUNIT_EXPECT_EQ(test, 0,
+			nvidia_ghes_decode_grace(NULL, grace_valid_full_signature,
+						 sizeof(grace_valid_full_signature),
+						 &decoded));
+	KUNIT_EXPECT_STREQ(test, "ABCDEFGHIJKLMNOP", decoded.signature);
+	KUNIT_EXPECT_EQ(test, '\0', decoded.signature[16]);
+}
+
+static void nvidia_ghes_grace_rejects_truncated_header(struct kunit *test)
+{
+	struct nvidia_ghes_decoded decoded = {};
+
+	KUNIT_EXPECT_EQ(test, -ENODATA,
+			nvidia_ghes_decode_grace(NULL, grace_valid_two_regs,
+						 sizeof(grace_valid_zero_regs) - 1,
+						 &decoded));
+}
+
+static void nvidia_ghes_grace_rejects_truncated_registers(struct kunit *test)
+{
+	struct nvidia_ghes_decoded decoded = {};
+
+	KUNIT_EXPECT_EQ(test, -ENODATA,
+			nvidia_ghes_decode_grace(NULL, grace_valid_two_regs,
+						 sizeof(grace_valid_two_regs) - 1,
+						 &decoded));
+}
+
+static const u8 vera_chip_serial[] = {
+	0xc0, 0x01, 0xfe, 0x06, 0x00, 0x00, 0x00, 0x00,
+	0x81, 0xc1, 0x18, 0x78, 0x01, 0x00, 0x00, 0x00,
+};
+
+#define VERA_EVENT_HDR_SIZE	32
+#define VERA_CPU_INFO_SIZE	32
+#define VERA_CONTEXT_HDR_SIZE	16
+#define VERA_FIRST_CONTEXT_OFFSET	(VERA_EVENT_HDR_SIZE + VERA_CPU_INFO_SIZE)
+
+static u8 *nvidia_ghes_kunit_memdup(struct kunit *test, const u8 *src, size_t len)
+{
+	u8 *buf;
+
+	buf = kunit_kmalloc(test, len, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, buf);
+	memcpy(buf, src, len);
+
+	return buf;
+}
+
+static u8 *vera_make_synthetic(struct kunit *test, u8 version, u8 info_size,
+			       u16 format, const u8 *data, u32 data_size,
+			       size_t *len)
+{
+	u8 *buf;
+	size_t context_offset;
+
+	KUNIT_ASSERT_TRUE(test, info_size >= VERA_CPU_INFO_SIZE);
+
+	context_offset = VERA_EVENT_HDR_SIZE + info_size;
+	*len = context_offset + VERA_CONTEXT_HDR_SIZE + data_size;
+	buf = kunit_kzalloc(test, *len, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, buf);
+
+	buf[0] = version;
+	buf[1] = 1;
+	buf[2] = 0;
+	put_unaligned_le16(0x22, &buf[4]);
+	memcpy(&buf[16], "SYNTH", 5);
+	put_unaligned_le16(0, &buf[32]);
+	buf[34] = info_size;
+	buf[35] = 0;
+	put_unaligned_le32(0x14107, &buf[36]);
+	memcpy(&buf[40], vera_chip_serial, sizeof(vera_chip_serial));
+	put_unaligned_le64(0, &buf[56]);
+	put_unaligned_le32(VERA_CONTEXT_HDR_SIZE, &buf[context_offset]);
+	put_unaligned_le16(0, &buf[context_offset + 4]);
+	put_unaligned_le16(format, &buf[context_offset + 8]);
+	put_unaligned_le16(0, &buf[context_offset + 10]);
+	put_unaligned_le32(data_size, &buf[context_offset + 12]);
+	memcpy(&buf[context_offset + VERA_CONTEXT_HDR_SIZE], data, data_size);
+
+	return buf;
+}
+
+static u8 *vera_make_synthetic_default(struct kunit *test, u16 format,
+				       const u8 *data, u32 data_size, size_t *len)
+{
+	return vera_make_synthetic(test, 1, VERA_CPU_INFO_SIZE, format, data,
+				   data_size, len);
+}
+
+static int nvidia_ghes_vera_context_u64_pair(const struct nvidia_ghes_vera_context *ctx,
+					     unsigned int index, u64 *addr, u64 *val)
+{
+	int count;
+
+	if (!ctx || !addr || !val || ctx->data_format_type != 1)
+		return -EINVAL;
+
+	count = nvidia_ghes_vera_context_entry_count(ctx);
+	if (count < 0)
+		return count;
+	if (index >= count)
+		return -ERANGE;
+
+	*addr = get_unaligned_le64(ctx->data + index * 16);
+	*val = get_unaligned_le64(ctx->data + index * 16 + 8);
+
+	return 0;
+}
+
+static int nvidia_ghes_vera_context_u32_pair(const struct nvidia_ghes_vera_context *ctx,
+					     unsigned int index, u32 *addr, u32 *val)
+{
+	int count;
+
+	if (!ctx || !addr || !val || ctx->data_format_type != 2)
+		return -EINVAL;
+
+	count = nvidia_ghes_vera_context_entry_count(ctx);
+	if (count < 0)
+		return count;
+	if (index >= count)
+		return -ERANGE;
+
+	*addr = get_unaligned_le32(ctx->data + index * 8);
+	*val = get_unaligned_le32(ctx->data + index * 8 + 4);
+
+	return 0;
+}
+
+static int nvidia_ghes_vera_context_u64_value(const struct nvidia_ghes_vera_context *ctx,
+					      unsigned int index, u64 *val)
+{
+	int count;
+
+	if (!ctx || !val || ctx->data_format_type != 3)
+		return -EINVAL;
+
+	count = nvidia_ghes_vera_context_entry_count(ctx);
+	if (count < 0)
+		return count;
+	if (index >= count)
+		return -ERANGE;
+
+	*val = get_unaligned_le64(ctx->data + index * 8);
+
+	return 0;
+}
+
+static int nvidia_ghes_vera_context_u32_value(const struct nvidia_ghes_vera_context *ctx,
+					      unsigned int index, u32 *val)
+{
+	int count;
+
+	if (!ctx || !val || ctx->data_format_type != 4)
+		return -EINVAL;
+
+	count = nvidia_ghes_vera_context_entry_count(ctx);
+	if (count < 0)
+		return count;
+	if (index >= count)
+		return -ERANGE;
+
+	*val = get_unaligned_le32(ctx->data + index * 4);
+
+	return 0;
+}
+
+static void nvidia_ghes_vera_decodes_l1_reset(struct kunit *test)
+{
+	struct nvidia_ghes_decoded decoded = {};
+
+	KUNIT_EXPECT_EQ(test, 0,
+			nvidia_ghes_decode_vera(NULL, vera_l1_reset_id10,
+						sizeof(vera_l1_reset_id10),
+						&decoded));
+	KUNIT_EXPECT_EQ(test, NVIDIA_GHES_FORMAT_VERA, decoded.format);
+	KUNIT_EXPECT_STREQ(test, "L1 RESET", decoded.signature);
+	KUNIT_EXPECT_EQ(test, 1, decoded.event_context_count);
+	KUNIT_EXPECT_EQ(test, 1, decoded.event_type);
+	KUNIT_EXPECT_EQ(test, 39, decoded.event_sub_type);
+	KUNIT_EXPECT_EQ(test, 0, decoded.source_device_type);
+	KUNIT_EXPECT_EQ(test, 0, decoded.socket);
+	KUNIT_EXPECT_EQ(test, 0x14107U, decoded.architecture);
+	KUNIT_EXPECT_MEMEQ(test, decoded.chip_serial_number, vera_chip_serial,
+			   sizeof(vera_chip_serial));
+	KUNIT_EXPECT_EQ(test, 0xfe1500200000ULL, decoded.instance_base);
+	KUNIT_EXPECT_EQ(test, 16U, decoded.contexts[0].context_size);
+	KUNIT_EXPECT_EQ(test, 1, decoded.contexts[0].data_format_type);
+	KUNIT_EXPECT_EQ(test, 0U, decoded.contexts[0].data_size);
+}
+
+static void nvidia_ghes_vera_decodes_crashdump_id(struct kunit *test)
+{
+	struct nvidia_ghes_decoded decoded = {};
+	u64 addr, val;
+
+	KUNIT_EXPECT_EQ(test, 0,
+			nvidia_ghes_decode_vera(NULL, vera_crashdump_id_id40,
+						sizeof(vera_crashdump_id_id40),
+						&decoded));
+	KUNIT_EXPECT_STREQ(test, "CRASHDUMP-ID", decoded.signature);
+	KUNIT_EXPECT_MEMEQ(test, decoded.chip_serial_number, vera_chip_serial,
+			   sizeof(vera_chip_serial));
+	KUNIT_EXPECT_EQ(test, 240U, decoded.contexts[0].context_size);
+	KUNIT_EXPECT_EQ(test, 1, decoded.contexts[0].data_format_type);
+	KUNIT_EXPECT_EQ(test, 224U, decoded.contexts[0].data_size);
+	KUNIT_EXPECT_EQ(test, 14, nvidia_ghes_vera_context_entry_count(&decoded.contexts[0]));
+	KUNIT_EXPECT_EQ(test, 0,
+			nvidia_ghes_vera_context_u64_pair(&decoded.contexts[0], 0,
+							  &addr, &val));
+	KUNIT_EXPECT_EQ(test, 0x8300000000000000ULL, addr);
+	KUNIT_EXPECT_EQ(test, 0x372e33375f6c6572ULL, val);
+}
+
+static void nvidia_ghes_vera_decodes_crashdump_s1_opaque_context(struct kunit *test)
+{
+	struct nvidia_ghes_decoded decoded = {};
+	u64 val;
+
+	KUNIT_EXPECT_EQ(test, 0,
+			nvidia_ghes_decode_vera(NULL, vera_crashdump_s1_id41,
+						sizeof(vera_crashdump_s1_id41),
+						&decoded));
+	KUNIT_EXPECT_STREQ(test, "CRASHDUMP-S1", decoded.signature);
+	KUNIT_EXPECT_EQ(test, 4096, decoded.event_type);
+	KUNIT_EXPECT_EQ(test, 2304, decoded.event_sub_type);
+	KUNIT_EXPECT_MEMEQ(test, decoded.chip_serial_number, vera_chip_serial,
+			   sizeof(vera_chip_serial));
+	KUNIT_EXPECT_EQ(test, 16U, decoded.contexts[0].context_size);
+	KUNIT_EXPECT_EQ(test, 0, decoded.contexts[0].data_format_type);
+	KUNIT_EXPECT_EQ(test, 1928U, decoded.contexts[0].data_size);
+	KUNIT_EXPECT_NOT_NULL(test, decoded.contexts[0].data);
+	KUNIT_EXPECT_EQ(test, 0x53, decoded.contexts[0].data[0]);
+	KUNIT_EXPECT_EQ(test, 0x56, decoded.contexts[0].data[1]);
+	KUNIT_EXPECT_EQ(test, 0x7f, decoded.contexts[0].data[2]);
+	KUNIT_EXPECT_EQ(test, -EINVAL,
+			nvidia_ghes_vera_context_u64_value(&decoded.contexts[0], 0, &val));
+}
+
+static void nvidia_ghes_vera_decodes_format2_u32_pairs(struct kunit *test)
+{
+	static const u8 data[] = {
+		0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a,
+	};
+	struct nvidia_ghes_decoded decoded = {};
+	size_t len;
+	u8 *buf;
+	u32 addr, val;
+
+	buf = vera_make_synthetic_default(test, 2, data, sizeof(data), &len);
+	KUNIT_EXPECT_EQ(test, 0, nvidia_ghes_decode_vera(NULL, buf, len, &decoded));
+	KUNIT_EXPECT_EQ(test, 1, nvidia_ghes_vera_context_entry_count(&decoded.contexts[0]));
+	KUNIT_EXPECT_EQ(test, 0,
+			nvidia_ghes_vera_context_u32_pair(&decoded.contexts[0], 0,
+							  &addr, &val));
+	KUNIT_EXPECT_EQ(test, 0x12345678U, addr);
+	KUNIT_EXPECT_EQ(test, 0x9abcdef0U, val);
+}
+
+static void nvidia_ghes_vera_decodes_format3_u64_values(struct kunit *test)
+{
+	static const u8 data[] = {
+		0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
+	};
+	struct nvidia_ghes_decoded decoded = {};
+	size_t len;
+	u8 *buf;
+	u64 val;
+
+	buf = vera_make_synthetic_default(test, 3, data, sizeof(data), &len);
+	KUNIT_EXPECT_EQ(test, 0, nvidia_ghes_decode_vera(NULL, buf, len, &decoded));
+	KUNIT_EXPECT_EQ(test, 1, nvidia_ghes_vera_context_entry_count(&decoded.contexts[0]));
+	KUNIT_EXPECT_EQ(test, 0,
+			nvidia_ghes_vera_context_u64_value(&decoded.contexts[0], 0, &val));
+	KUNIT_EXPECT_EQ(test, 0x0102030405060708ULL, val);
+}
+
+static void nvidia_ghes_vera_decodes_format4_u32_values(struct kunit *test)
+{
+	static const u8 data[] = {
+		0x78, 0x56, 0x34, 0x12,
+	};
+	struct nvidia_ghes_decoded decoded = {};
+	size_t len;
+	u8 *buf;
+	u32 val;
+
+	buf = vera_make_synthetic_default(test, 4, data, sizeof(data), &len);
+	KUNIT_EXPECT_EQ(test, 0, nvidia_ghes_decode_vera(NULL, buf, len, &decoded));
+	KUNIT_EXPECT_EQ(test, 1, nvidia_ghes_vera_context_entry_count(&decoded.contexts[0]));
+	KUNIT_EXPECT_EQ(test, 0,
+			nvidia_ghes_vera_context_u32_value(&decoded.contexts[0], 0, &val));
+	KUNIT_EXPECT_EQ(test, 0x12345678U, val);
+}
+
+static void nvidia_ghes_vera_rejects_truncated_event_header(struct kunit *test)
+{
+	struct nvidia_ghes_decoded decoded = {};
+
+	KUNIT_EXPECT_EQ(test, -ENODATA,
+			nvidia_ghes_decode_vera(NULL, vera_l1_reset_id10,
+						VERA_EVENT_HDR_SIZE - 1,
+						&decoded));
+}
+
+static void nvidia_ghes_vera_rejects_truncated_cpu_info(struct kunit *test)
+{
+	struct nvidia_ghes_decoded decoded = {};
+
+	KUNIT_EXPECT_EQ(test, -ENODATA,
+			nvidia_ghes_decode_vera(NULL, vera_l1_reset_id10,
+						VERA_FIRST_CONTEXT_OFFSET - 1,
+						&decoded));
+}
+
+static void nvidia_ghes_vera_rejects_truncated_context_header(struct kunit *test)
+{
+	struct nvidia_ghes_decoded decoded = {};
+
+	KUNIT_EXPECT_EQ(test, -ENODATA,
+			nvidia_ghes_decode_vera(NULL, vera_l1_reset_id10,
+						VERA_FIRST_CONTEXT_OFFSET +
+						VERA_CONTEXT_HDR_SIZE - 1,
+						&decoded));
+}
+
+static void nvidia_ghes_vera_rejects_too_many_contexts(struct kunit *test)
+{
+	struct nvidia_ghes_decoded decoded = {};
+	u8 *buf;
+
+	buf = nvidia_ghes_kunit_memdup(test, vera_l1_reset_id10, sizeof(vera_l1_reset_id10));
+	buf[1] = NVIDIA_GHES_MAX_CONTEXTS + 1;
+
+	KUNIT_EXPECT_EQ(test, -E2BIG,
+			nvidia_ghes_decode_vera(NULL, buf, sizeof(vera_l1_reset_id10), &decoded));
+}
+
+static void nvidia_ghes_vera_rejects_bad_info_size(struct kunit *test)
+{
+	struct nvidia_ghes_decoded decoded = {};
+	u8 *buf;
+
+	buf = nvidia_ghes_kunit_memdup(test, vera_l1_reset_id10, sizeof(vera_l1_reset_id10));
+	buf[34] = 31;
+
+	KUNIT_EXPECT_EQ(test, -EINVAL,
+			nvidia_ghes_decode_vera(NULL, buf, sizeof(vera_l1_reset_id10), &decoded));
+}
+
+static void nvidia_ghes_vera_rejects_unsupported_version(struct kunit *test)
+{
+	struct nvidia_ghes_decoded decoded = {};
+	u8 *buf;
+
+	buf = nvidia_ghes_kunit_memdup(test, vera_l1_reset_id10, sizeof(vera_l1_reset_id10));
+	buf[0] = 2;
+
+	KUNIT_EXPECT_EQ(test, -EOPNOTSUPP,
+			nvidia_ghes_decode_vera(NULL, buf, sizeof(vera_l1_reset_id10), &decoded));
+}
+
+static void nvidia_ghes_vera_accepts_extended_cpu_info(struct kunit *test)
+{
+	static const u8 data[] = {
+		0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
+	};
+	struct nvidia_ghes_decoded decoded = {};
+	size_t len;
+	u8 *buf;
+	u64 val;
+
+	buf = vera_make_synthetic(test, 1, VERA_CPU_INFO_SIZE + 4, 3,
+				  data, sizeof(data), &len);
+	KUNIT_EXPECT_EQ(test, 0, nvidia_ghes_decode_vera(NULL, buf, len, &decoded));
+	KUNIT_EXPECT_EQ(test, VERA_CONTEXT_HDR_SIZE, decoded.contexts[0].context_size);
+	KUNIT_EXPECT_EQ(test, 3, decoded.contexts[0].data_format_type);
+	KUNIT_EXPECT_EQ(test, 8U, decoded.contexts[0].data_size);
+	KUNIT_EXPECT_EQ(test, 1, nvidia_ghes_vera_context_entry_count(&decoded.contexts[0]));
+	KUNIT_EXPECT_EQ(test, 0,
+			nvidia_ghes_vera_context_u64_value(&decoded.contexts[0], 0, &val));
+	KUNIT_EXPECT_EQ(test, 0x0102030405060708ULL, val);
+}
+
+static void nvidia_ghes_vera_rejects_short_context_size(struct kunit *test)
+{
+	struct nvidia_ghes_decoded decoded = {};
+	u8 *buf;
+
+	buf = nvidia_ghes_kunit_memdup(test, vera_l1_reset_id10, sizeof(vera_l1_reset_id10));
+	put_unaligned_le32(15, &buf[VERA_FIRST_CONTEXT_OFFSET]);
+
+	KUNIT_EXPECT_EQ(test, -EINVAL,
+			nvidia_ghes_decode_vera(NULL, buf, sizeof(vera_l1_reset_id10), &decoded));
+}
+
+static void nvidia_ghes_vera_rejects_ambiguous_context_size(struct kunit *test)
+{
+	static const u8 data[] = {
+		0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
+	};
+	struct nvidia_ghes_decoded decoded = {};
+	size_t len;
+	u8 *buf;
+
+	buf = vera_make_synthetic_default(test, 3, data, sizeof(data), &len);
+	put_unaligned_le32(20, &buf[VERA_FIRST_CONTEXT_OFFSET]);
+
+	KUNIT_EXPECT_EQ(test, -EINVAL, nvidia_ghes_decode_vera(NULL, buf, len, &decoded));
+}
+
+static void nvidia_ghes_vera_rejects_data_beyond_section(struct kunit *test)
+{
+	static const u8 data[] = {
+		0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
+	};
+	struct nvidia_ghes_decoded decoded = {};
+	size_t len;
+	u8 *buf;
+
+	buf = vera_make_synthetic_default(test, 3, data, sizeof(data), &len);
+	put_unaligned_le32(16, &buf[VERA_FIRST_CONTEXT_OFFSET + 12]);
+
+	KUNIT_EXPECT_EQ(test, -ENODATA, nvidia_ghes_decode_vera(NULL, buf, len, &decoded));
+}
+
+static void nvidia_ghes_vera_rejects_mis_sized_format1(struct kunit *test)
+{
+	struct nvidia_ghes_decoded decoded = {};
+	u8 *buf;
+
+	buf = nvidia_ghes_kunit_memdup(test, vera_crashdump_id_id40,
+				       sizeof(vera_crashdump_id_id40));
+	put_unaligned_le32(15, &buf[VERA_FIRST_CONTEXT_OFFSET + 12]);
+
+	KUNIT_EXPECT_EQ(test, -EINVAL,
+			nvidia_ghes_decode_vera(NULL, buf, sizeof(vera_crashdump_id_id40), &decoded));
+}
+
+static void nvidia_ghes_vera_rejects_mis_sized_format2(struct kunit *test)
+{
+	static const u8 data[] = {
+		0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc,
+	};
+	struct nvidia_ghes_decoded decoded = {};
+	size_t len;
+	u8 *buf;
+
+	buf = vera_make_synthetic_default(test, 2, data, sizeof(data), &len);
+	KUNIT_EXPECT_EQ(test, -EINVAL, nvidia_ghes_decode_vera(NULL, buf, len, &decoded));
+}
+
+static void nvidia_ghes_vera_rejects_mis_sized_format3(struct kunit *test)
+{
+	static const u8 data[] = {
+		0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02,
+	};
+	struct nvidia_ghes_decoded decoded = {};
+	size_t len;
+	u8 *buf;
+
+	buf = vera_make_synthetic_default(test, 3, data, sizeof(data), &len);
+	KUNIT_EXPECT_EQ(test, -EINVAL, nvidia_ghes_decode_vera(NULL, buf, len, &decoded));
+}
+
+static void nvidia_ghes_vera_rejects_mis_sized_format4(struct kunit *test)
+{
+	static const u8 data[] = {
+		0x78, 0x56, 0x34,
+	};
+	struct nvidia_ghes_decoded decoded = {};
+	size_t len;
+	u8 *buf;
+
+	buf = vera_make_synthetic_default(test, 4, data, sizeof(data), &len);
+	KUNIT_EXPECT_EQ(test, -EINVAL, nvidia_ghes_decode_vera(NULL, buf, len, &decoded));
+}
+
+static void nvidia_ghes_vera_rejects_unsupported_source_device(struct kunit *test)
+{
+	struct nvidia_ghes_decoded decoded = {};
+	u8 *buf;
+
+	buf = nvidia_ghes_kunit_memdup(test, vera_l1_reset_id10, sizeof(vera_l1_reset_id10));
+	buf[2] = 1;
+
+	KUNIT_EXPECT_EQ(test, -EOPNOTSUPP,
+			nvidia_ghes_decode_vera(NULL, buf, sizeof(vera_l1_reset_id10), &decoded));
+}
+
+static void nvidia_ghes_vera_rejects_unsupported_data_format(struct kunit *test)
+{
+	struct nvidia_ghes_decoded decoded = {};
+	u8 *buf;
+
+	buf = nvidia_ghes_kunit_memdup(test, vera_l1_reset_id10, sizeof(vera_l1_reset_id10));
+	put_unaligned_le16(5, &buf[VERA_FIRST_CONTEXT_OFFSET + 8]);
+
+	KUNIT_EXPECT_EQ(test, -EOPNOTSUPP,
+			nvidia_ghes_decode_vera(NULL, buf, sizeof(vera_l1_reset_id10), &decoded));
+}
+
+static void nvidia_ghes_vera_copies_non_nul_signature(struct kunit *test)
+{
+	struct nvidia_ghes_decoded decoded = {};
+	u8 *buf;
+
+	buf = nvidia_ghes_kunit_memdup(test, vera_l1_reset_id10, sizeof(vera_l1_reset_id10));
+	memcpy(&buf[16], "ABCDEFGHIJKLMNOP", 16);
+
+	KUNIT_EXPECT_EQ(test, 0,
+			nvidia_ghes_decode_vera(NULL, buf, sizeof(vera_l1_reset_id10), &decoded));
+	KUNIT_EXPECT_STREQ(test, "ABCDEFGHIJKLMNOP", decoded.signature);
+	KUNIT_EXPECT_EQ(test, '\0', decoded.signature[16]);
+}
+
+static void nvidia_ghes_guid_routes_grace(struct kunit *test)
+{
+	const guid_t guid = GUID_INIT(0x6d5244f2, 0x2712, 0x11ec,
+				      0xbe, 0xa7, 0xcb, 0x3f, 0xdb, 0x95, 0xc7, 0x86);
+
+	KUNIT_EXPECT_EQ(test, NVIDIA_GHES_FORMAT_GRACE,
+			nvidia_ghes_format_from_guid(&guid));
+}
+
+static void nvidia_ghes_guid_routes_vera(struct kunit *test)
+{
+	const guid_t guid = GUID_INIT(0x9068e568, 0x6ca0, 0x11f0,
+				      0xae, 0xaf, 0x15, 0x93, 0x43, 0x59, 0x1e, 0xac);
+
+	KUNIT_EXPECT_EQ(test, NVIDIA_GHES_FORMAT_VERA,
+			nvidia_ghes_format_from_guid(&guid));
+}
+
+static void nvidia_ghes_guid_rejects_unknown(struct kunit *test)
+{
+	const guid_t guid = GUID_INIT(0x00000000, 0x0000, 0x0000,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+
+	KUNIT_EXPECT_EQ(test, NVIDIA_GHES_FORMAT_UNKNOWN,
+			nvidia_ghes_format_from_guid(&guid));
+}
+
+static void nvidia_ghes_grace_reg_pair_rejects_null_decoded(struct kunit *test)
+{
+	u64 addr, val;
+
+	KUNIT_EXPECT_EQ(test, -EINVAL,
+			nvidia_ghes_grace_reg_pair(NULL, 0, &addr, &val));
+}
+
+static void nvidia_ghes_grace_reg_pair_rejects_wrong_format(struct kunit *test)
+{
+	struct nvidia_ghes_decoded decoded = {
+		.format = NVIDIA_GHES_FORMAT_VERA,
+	};
+	u64 addr, val;
+
+	KUNIT_EXPECT_EQ(test, -EINVAL,
+			nvidia_ghes_grace_reg_pair(&decoded, 0, &addr, &val));
+}
+
+static void nvidia_ghes_grace_reg_pair_rejects_out_of_range(struct kunit *test)
+{
+	struct nvidia_ghes_decoded decoded = {
+		.format = NVIDIA_GHES_FORMAT_GRACE,
+		.number_regs = 0,
+	};
+	u64 addr, val;
+
+	KUNIT_EXPECT_EQ(test, -ERANGE,
+			nvidia_ghes_grace_reg_pair(&decoded, 0, &addr, &val));
+}
+
+static struct kunit_case nvidia_ghes_test_cases[] = {
+	KUNIT_CASE(nvidia_ghes_grace_decodes_registers),
+	KUNIT_CASE(nvidia_ghes_grace_accepts_zero_registers),
+	KUNIT_CASE(nvidia_ghes_grace_copies_non_nul_signature),
+	KUNIT_CASE(nvidia_ghes_grace_rejects_truncated_header),
+	KUNIT_CASE(nvidia_ghes_grace_rejects_truncated_registers),
+	KUNIT_CASE(nvidia_ghes_grace_reg_pair_rejects_null_decoded),
+	KUNIT_CASE(nvidia_ghes_grace_reg_pair_rejects_wrong_format),
+	KUNIT_CASE(nvidia_ghes_grace_reg_pair_rejects_out_of_range),
+	KUNIT_CASE(nvidia_ghes_vera_decodes_l1_reset),
+	KUNIT_CASE(nvidia_ghes_vera_decodes_crashdump_id),
+	KUNIT_CASE(nvidia_ghes_vera_decodes_crashdump_s1_opaque_context),
+	KUNIT_CASE(nvidia_ghes_vera_decodes_format2_u32_pairs),
+	KUNIT_CASE(nvidia_ghes_vera_decodes_format3_u64_values),
+	KUNIT_CASE(nvidia_ghes_vera_decodes_format4_u32_values),
+	KUNIT_CASE(nvidia_ghes_vera_rejects_truncated_event_header),
+	KUNIT_CASE(nvidia_ghes_vera_rejects_truncated_cpu_info),
+	KUNIT_CASE(nvidia_ghes_vera_rejects_truncated_context_header),
+	KUNIT_CASE(nvidia_ghes_vera_rejects_too_many_contexts),
+	KUNIT_CASE(nvidia_ghes_vera_rejects_bad_info_size),
+	KUNIT_CASE(nvidia_ghes_vera_rejects_unsupported_version),
+	KUNIT_CASE(nvidia_ghes_vera_accepts_extended_cpu_info),
+	KUNIT_CASE(nvidia_ghes_vera_rejects_short_context_size),
+	KUNIT_CASE(nvidia_ghes_vera_rejects_ambiguous_context_size),
+	KUNIT_CASE(nvidia_ghes_vera_rejects_data_beyond_section),
+	KUNIT_CASE(nvidia_ghes_vera_rejects_mis_sized_format1),
+	KUNIT_CASE(nvidia_ghes_vera_rejects_mis_sized_format2),
+	KUNIT_CASE(nvidia_ghes_vera_rejects_mis_sized_format3),
+	KUNIT_CASE(nvidia_ghes_vera_rejects_mis_sized_format4),
+	KUNIT_CASE(nvidia_ghes_vera_rejects_unsupported_source_device),
+	KUNIT_CASE(nvidia_ghes_vera_rejects_unsupported_data_format),
+	KUNIT_CASE(nvidia_ghes_vera_copies_non_nul_signature),
+	KUNIT_CASE(nvidia_ghes_guid_routes_grace),
+	KUNIT_CASE(nvidia_ghes_guid_routes_vera),
+	KUNIT_CASE(nvidia_ghes_guid_rejects_unknown),
+	{}
+};
+
+static struct kunit_suite nvidia_ghes_test_suite = {
+	.name = "ghes-nvidia",
+	.test_cases = nvidia_ghes_test_cases,
+};
+
+kunit_test_suite(nvidia_ghes_test_suite);
+
+MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
+MODULE_DESCRIPTION("KUnit tests for NVIDIA GHES CPER parser helpers");
+MODULE_LICENSE("GPL");
-- 
2.50.1 (Apple Git-155)


^ permalink raw reply related

* [PATCH v1 2/4] ACPI: APEI: GHES: Add NVIDIA Vera decoder
From: Kai-Heng Feng @ 2026-06-12 12:09 UTC (permalink / raw)
  To: rafael, shuah, kees
  Cc: csoto, mochs, Kai-Heng Feng, Tony Luck, Borislav Petkov,
	Hanjun Guo, Mauro Carvalho Chehab, Shuai Xue, Len Brown,
	linux-acpi, linux-kernel
In-Reply-To: <20260612120929.28965-1-kaihengf@nvidia.com>

Vera is NVIDIA's next-generation server SoC. Its CPER section uses a
different GUID and a different binary layout from Grace, so it needs
its own decoder. Without this, firmware-reported hardware errors on
Vera platforms are received but not decoded.

Signed-off-by: Kai-Heng Feng <kaihengf@nvidia.com>
---
 drivers/acpi/apei/ghes-nvidia.c | 368 ++++++++++++++++++++++++++++++--
 drivers/acpi/apei/ghes-nvidia.h |  29 ++-
 2 files changed, 382 insertions(+), 15 deletions(-)

diff --git a/drivers/acpi/apei/ghes-nvidia.c b/drivers/acpi/apei/ghes-nvidia.c
index af445152def0..c74c155dd2ba 100644
--- a/drivers/acpi/apei/ghes-nvidia.c
+++ b/drivers/acpi/apei/ghes-nvidia.c
@@ -7,18 +7,27 @@

 #include <linux/acpi.h>
 #include <linux/module.h>
+#include <linux/overflow.h>
 #include <linux/platform_device.h>
+#include <linux/slab.h>
 #include <linux/types.h>
+#include <linux/unaligned.h>
 #include <linux/uuid.h>
+#include <kunit/visibility.h>
 #include <acpi/ghes.h>

-#include <kunit/visibility.h>
 #include "ghes-nvidia.h"

+#define NVIDIA_GHES_VERA_VERSION	1
+
 static const guid_t nvidia_grace_sec_guid =
 	GUID_INIT(0x6d5244f2, 0x2712, 0x11ec,
 		  0xbe, 0xa7, 0xcb, 0x3f, 0xdb, 0x95, 0xc7, 0x86);

+static const guid_t nvidia_vera_sec_guid =
+	GUID_INIT(0x9068e568, 0x6ca0, 0x11f0,
+		  0xae, 0xaf, 0x15, 0x93, 0x43, 0x59, 0x1e, 0xac);
+
 struct cper_sec_nvidia {
 	char	signature[16];
 	__le16	error_type;
@@ -31,11 +40,51 @@ struct cper_sec_nvidia {
 	struct nvidia_ghes_grace_reg regs[] __counted_by(number_regs);
 };

+struct cper_sec_nvidia_vera_event {
+	u8	version;
+	u8	event_context_count;
+	u8	source_device_type;
+	u8	reserved;
+	__le16	event_type;
+	__le16	event_sub_type;
+	__le64	event_link_id;
+	char	source_module_signature[16];
+} __packed;
+
+struct cper_sec_nvidia_vera_cpu_info {
+	__le16	info_version;
+	u8	info_size;
+	u8	socket_number;
+	__le32	architecture;
+	u8	chip_serial_number[16];
+	__le64	instance_base;
+} __packed;
+
+struct cper_sec_nvidia_vera_context {
+	__le32	context_size;
+	__le16	context_version;
+	__le16	reserved;
+	__le16	data_format_type;
+	__le16	data_format_version;
+	__le32	data_size;
+} __packed;
+
 struct nvidia_ghes_private {
 	struct notifier_block	nb;
 	struct device		*dev;
 };

+VISIBLE_IF_KUNIT
+enum nvidia_ghes_format nvidia_ghes_format_from_guid(const guid_t *guid)
+{
+	if (guid_equal(guid, &nvidia_grace_sec_guid))
+		return NVIDIA_GHES_FORMAT_GRACE;
+	if (guid_equal(guid, &nvidia_vera_sec_guid))
+		return NVIDIA_GHES_FORMAT_VERA;
+	return NVIDIA_GHES_FORMAT_UNKNOWN;
+}
+EXPORT_SYMBOL_IF_KUNIT(nvidia_ghes_format_from_guid);
+
 VISIBLE_IF_KUNIT
 int nvidia_ghes_decode_grace(struct device *dev, const void *buf,
 			     size_t len,
@@ -81,7 +130,7 @@ EXPORT_SYMBOL_IF_KUNIT(nvidia_ghes_decode_grace);

 VISIBLE_IF_KUNIT
 int nvidia_ghes_grace_reg_pair(const struct nvidia_ghes_decoded *decoded,
-				      unsigned int index, u64 *addr, u64 *val)
+			       unsigned int index, u64 *addr, u64 *val)
 {
 	const struct nvidia_ghes_grace_reg *regs;

@@ -98,6 +147,220 @@ int nvidia_ghes_grace_reg_pair(const struct nvidia_ghes_decoded *decoded,
 }
 EXPORT_SYMBOL_IF_KUNIT(nvidia_ghes_grace_reg_pair);

+static int nvidia_ghes_vera_validate_context_data(u16 data_format_type,
+						  u32 data_size)
+{
+	switch (data_format_type) {
+	case 0:
+		return 0;
+	case 1:
+		return data_size % 16 ? -EINVAL : 0;
+	case 2:
+	case 3:
+		return data_size % 8 ? -EINVAL : 0;
+	case 4:
+		return data_size % 4 ? -EINVAL : 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+VISIBLE_IF_KUNIT
+int nvidia_ghes_decode_vera(struct device *dev, const void *buf,
+			    size_t len,
+			    struct nvidia_ghes_decoded *decoded)
+{
+	const struct cper_sec_nvidia_vera_event *event = buf;
+	const struct cper_sec_nvidia_vera_cpu_info *cpu_info;
+	const struct cper_sec_nvidia_vera_context *context;
+	const u8 *bytes = buf;
+	size_t data_end_advance;
+	size_t advance;
+	size_t offset;
+	int ret;
+
+	if (!buf || !decoded)
+		return -EINVAL;
+	if (len < sizeof(*event)) {
+		if (dev)
+			dev_err_ratelimited(dev, "Vera event header truncated (%zu < %zu)\n",
+					    len, sizeof(*event));
+		return -ENODATA;
+	}
+	if (event->version != NVIDIA_GHES_VERA_VERSION)
+		return -EOPNOTSUPP;
+	if (event->source_device_type != 0)
+		return -EOPNOTSUPP;
+
+	offset = sizeof(*event);
+	if (len - offset < sizeof(*cpu_info)) {
+		if (dev)
+			dev_err_ratelimited(dev, "Vera CPU info truncated (%zu < %zu)\n",
+					    len - offset, sizeof(*cpu_info));
+		return -ENODATA;
+	}
+
+	cpu_info = (const void *)(bytes + offset);
+	if (cpu_info->info_size < sizeof(*cpu_info)) {
+		if (dev)
+			dev_err_ratelimited(dev, "Vera CPU info size %u smaller than header %zu\n",
+					    cpu_info->info_size, sizeof(*cpu_info));
+		return -EINVAL;
+	}
+	if (len - offset < cpu_info->info_size) {
+		if (dev)
+			dev_err_ratelimited(dev, "Vera CPU info extends past section (%u > %zu)\n",
+					    cpu_info->info_size, len - offset);
+		return -ENODATA;
+	}
+
+	offset += cpu_info->info_size;
+	if (event->event_context_count > NVIDIA_GHES_MAX_CONTEXTS) {
+		if (dev)
+			dev_err_ratelimited(dev, "Vera context count %u exceeds maximum %u\n",
+					    event->event_context_count,
+					    NVIDIA_GHES_MAX_CONTEXTS);
+		return -E2BIG;
+	}
+
+	memset(decoded, 0, sizeof(*decoded));
+	decoded->format = NVIDIA_GHES_FORMAT_VERA;
+	memcpy(decoded->signature, event->source_module_signature,
+	       sizeof(event->source_module_signature));
+	decoded->signature[sizeof(event->source_module_signature)] = '\0';
+	decoded->event_context_count = event->event_context_count;
+	decoded->source_device_type = event->source_device_type;
+	decoded->event_type = get_unaligned_le16(&event->event_type);
+	decoded->event_sub_type = get_unaligned_le16(&event->event_sub_type);
+	decoded->event_link_id = get_unaligned_le64(&event->event_link_id);
+	decoded->socket = cpu_info->socket_number;
+	decoded->architecture = get_unaligned_le32(&cpu_info->architecture);
+	memcpy(decoded->chip_serial_number, cpu_info->chip_serial_number,
+	       sizeof(cpu_info->chip_serial_number));
+	decoded->instance_base = get_unaligned_le64(&cpu_info->instance_base);
+
+	for (int i = 0; i < event->event_context_count; i++) {
+		struct nvidia_ghes_vera_context *decoded_context = &decoded->contexts[i];
+		u32 context_size;
+		u32 data_size;
+		u16 data_format_type;
+
+		if (len - offset < sizeof(*context)) {
+			if (dev)
+				dev_err_ratelimited(dev, "Vera context[%d] header truncated (%zu < %zu)\n",
+						    i, len - offset, sizeof(*context));
+			return -ENODATA;
+		}
+
+		context = (const void *)(bytes + offset);
+		context_size = get_unaligned_le32(&context->context_size);
+		data_format_type = get_unaligned_le16(&context->data_format_type);
+		data_size = get_unaligned_le32(&context->data_size);
+
+		if (context_size < sizeof(*context)) {
+			if (dev)
+				dev_err_ratelimited(dev,
+						    "Vera context[%d] size %u smaller than header %zu\n",
+						    i, context_size, sizeof(*context));
+			return -EINVAL;
+		}
+		if (data_format_type > 4) {
+			if (dev)
+				dev_dbg(dev,
+					"Vera context[%d] unsupported data format %u\n",
+					i, data_format_type);
+			return -EOPNOTSUPP;
+		}
+		if (check_add_overflow((size_t)data_size, sizeof(*context),
+				       &data_end_advance)) {
+			if (dev)
+				dev_err_ratelimited(dev,
+						    "Vera context[%d] data_size %u overflows section accounting\n",
+						    i, data_size);
+			return -EOVERFLOW;
+		}
+
+		if (data_end_advance > len - offset) {
+			if (dev)
+				dev_err_ratelimited(dev,
+						    "Vera context[%d] data extends past section (%zu > %zu)\n",
+						    i, data_end_advance, len - offset);
+			return -ENODATA;
+		}
+
+		/*
+		 * Some Vera payloads use only the header size here and
+		 * place the format-specific payload immediately after it.
+		 */
+		if (context_size == sizeof(*context))
+			advance = data_end_advance;
+		else if (data_size <= context_size - sizeof(*context))
+			advance = context_size;
+		else {
+			if (dev)
+				dev_err_ratelimited(dev,
+						    "Vera context[%d] data_size %u exceeds context_size %u\n",
+						    i, data_size, context_size);
+			return -EINVAL;
+		}
+
+		if (advance > len - offset) {
+			if (dev)
+				dev_err_ratelimited(dev,
+						    "Vera context[%d] advance %zu extends past section (%zu)\n",
+						    i, advance, len - offset);
+			return -ENODATA;
+		}
+
+		ret = nvidia_ghes_vera_validate_context_data(data_format_type, data_size);
+		if (ret) {
+			if (dev)
+				dev_err_ratelimited(dev,
+						    "Vera context[%d] format %u rejected data_size %u (ret=%d)\n",
+						    i, data_format_type, data_size, ret);
+			return ret;
+		}
+
+		decoded_context->context_size = context_size;
+		decoded_context->context_version =
+			get_unaligned_le16(&context->context_version);
+		decoded_context->data_format_type = data_format_type;
+		decoded_context->data_format_version =
+			get_unaligned_le16(&context->data_format_version);
+		decoded_context->data_size = data_size;
+		decoded_context->data = bytes + offset + sizeof(*context);
+		offset += advance;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_IF_KUNIT(nvidia_ghes_decode_vera);
+
+VISIBLE_IF_KUNIT
+int nvidia_ghes_vera_context_entry_count(const struct nvidia_ghes_vera_context *ctx)
+{
+	if (!ctx)
+		return -EINVAL;
+	if (ctx->data_size > INT_MAX)
+		return -EOVERFLOW;
+
+	switch (ctx->data_format_type) {
+	case 0:
+		return 0;
+	case 1:
+		return ctx->data_size / 16;
+	case 2:
+		return ctx->data_size / 8;
+	case 3:
+		return ctx->data_size / 8;
+	case 4:
+		return ctx->data_size / 4;
+	default:
+		return -EINVAL;
+	}
+}
+EXPORT_SYMBOL_IF_KUNIT(nvidia_ghes_vera_context_entry_count);
+
 static void nvidia_ghes_print_grace(struct device *dev,
 				    const struct nvidia_ghes_decoded *decoded,
 				    bool fatal)
@@ -111,7 +374,8 @@ static void nvidia_ghes_print_grace(struct device *dev,
 	dev_printk(level, dev, "severity: %u\n", decoded->severity);
 	dev_printk(level, dev, "socket: %u\n", decoded->socket);
 	dev_printk(level, dev, "number_regs: %u\n", decoded->number_regs);
-	dev_printk(level, dev, "instance_base: 0x%016llx\n", decoded->instance_base);
+	dev_printk(level, dev, "instance_base: 0x%016llx\n",
+		   decoded->instance_base);

 	for (int i = 0; i < decoded->number_regs; i++) {
 		if (nvidia_ghes_grace_reg_pair(decoded, i, &addr, &val))
@@ -121,12 +385,52 @@ static void nvidia_ghes_print_grace(struct device *dev,
 	}
 }

+static void nvidia_ghes_print_vera(struct device *dev,
+				   const struct nvidia_ghes_decoded *decoded,
+				   bool fatal, unsigned long ghes_severity)
+{
+	const char *level = fatal ? KERN_ERR : KERN_INFO;
+
+	dev_printk(level, dev, "signature: %s\n", decoded->signature);
+	dev_printk(level, dev, "event_type: %u\n", decoded->event_type);
+	dev_printk(level, dev, "event_sub_type: %u\n", decoded->event_sub_type);
+	dev_printk(level, dev, "ghes_severity: %lu\n", ghes_severity);
+	dev_printk(level, dev, "event_link_id: 0x%016llx\n",
+		   decoded->event_link_id);
+	dev_printk(level, dev, "socket: %u\n", decoded->socket);
+	dev_printk(level, dev, "architecture: 0x%x\n", decoded->architecture);
+	dev_printk(level, dev, "chip_serial_number: %*phN\n",
+		   (int)sizeof(decoded->chip_serial_number),
+		   decoded->chip_serial_number);
+	dev_printk(level, dev, "instance_base: 0x%016llx\n", decoded->instance_base);
+	dev_printk(level, dev, "event_context_count: %u\n", decoded->event_context_count);
+
+	for (int i = 0; i < decoded->event_context_count; i++) {
+		const struct nvidia_ghes_vera_context *ctx = &decoded->contexts[i];
+		int entries = nvidia_ghes_vera_context_entry_count(ctx);
+
+		dev_printk(level, dev,
+			   "context[%d]: version=%u format=%u format_version=%u context_size=%u data_size=%u\n",
+			   i, ctx->context_version, ctx->data_format_type,
+			   ctx->data_format_version, ctx->context_size, ctx->data_size);
+		if (ctx->data_format_type == 0 && ctx->data_size > 0) {
+			int prefix_len = ctx->data_size > 16 ? 16 : ctx->data_size;
+
+			dev_printk(level, dev, "context[%d]_opaque_prefix: %*phN\n",
+				   i, prefix_len, ctx->data);
+		} else if (entries >= 0) {
+			dev_printk(level, dev, "context[%d]_entries: %d\n", i, entries);
+		}
+	}
+}
+
 static int nvidia_ghes_notify(struct notifier_block *nb,
 			      unsigned long event, void *data)
 {
 	struct acpi_hest_generic_data *gdata = data;
-	struct nvidia_ghes_decoded decoded;
+	struct nvidia_ghes_decoded *decoded;
 	struct nvidia_ghes_private *priv;
+	enum nvidia_ghes_format format;
 	const void *payload;
 	guid_t sec_guid;
 	u32 len;
@@ -134,26 +438,64 @@ static int nvidia_ghes_notify(struct notifier_block *nb,
 	bool fatal;

 	import_guid(&sec_guid, gdata->section_type);
-	if (!guid_equal(&sec_guid, &nvidia_grace_sec_guid))
+	format = nvidia_ghes_format_from_guid(&sec_guid);
+	if (format == NVIDIA_GHES_FORMAT_UNKNOWN)
 		return NOTIFY_DONE;

 	priv = container_of(nb, struct nvidia_ghes_private, nb);
 	len = acpi_hest_get_error_length(gdata);
+
 	payload = acpi_hest_get_payload(gdata);
 	fatal = event >= GHES_SEV_RECOVERABLE;
+	decoded = kzalloc_obj(*decoded);
+	if (!decoded) {
+		dev_err_ratelimited(priv->dev,
+				    "Failed to allocate NVIDIA CPER decode buffer\n");
+		return NOTIFY_OK;
+	}
+
+	switch (format) {
+	case NVIDIA_GHES_FORMAT_GRACE:
+		ret = nvidia_ghes_decode_grace(priv->dev, payload, len, decoded);
+		break;
+	case NVIDIA_GHES_FORMAT_VERA:
+		ret = nvidia_ghes_decode_vera(priv->dev, payload, len, decoded);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}

-	ret = nvidia_ghes_decode_grace(priv->dev, payload, len, &decoded);
 	if (ret) {
-		dev_err(priv->dev,
-			"Malformed NVIDIA CPER section, error_data_length: %u, ret: %d\n",
-			len, ret);
-		return NOTIFY_OK;
+		if (ret == -EOPNOTSUPP && format == NVIDIA_GHES_FORMAT_VERA)
+			dev_info(priv->dev,
+				 "Unsupported NVIDIA Vera CPER section, error_data_length: %u, ret: %d\n",
+				 len, ret);
+		else if (format == NVIDIA_GHES_FORMAT_GRACE)
+			dev_err(priv->dev,
+				"Malformed NVIDIA Grace CPER section, error_data_length: %u, ret: %d\n",
+				len, ret);
+		else
+			dev_err(priv->dev,
+				"Malformed NVIDIA Vera CPER section, error_data_length: %u, ret: %d\n",
+				len, ret);
+		goto out;
 	}

-	dev_printk(fatal ? KERN_ERR : KERN_INFO, priv->dev,
-		   "NVIDIA CPER section, error_data_length: %u\n", len);
-	nvidia_ghes_print_grace(priv->dev, &decoded, fatal);
+	if (format == NVIDIA_GHES_FORMAT_GRACE)
+		dev_printk(fatal ? KERN_ERR : KERN_INFO, priv->dev,
+			   "NVIDIA Grace CPER section, error_data_length: %u\n", len);
+	else
+		dev_printk(fatal ? KERN_ERR : KERN_INFO, priv->dev,
+			   "NVIDIA Vera CPER section, error_data_length: %u\n", len);
+
+	if (format == NVIDIA_GHES_FORMAT_VERA)
+		nvidia_ghes_print_vera(priv->dev, decoded, fatal, event);
+	else
+		nvidia_ghes_print_grace(priv->dev, decoded, fatal);

+out:
+	kfree(decoded);
 	return NOTIFY_OK;
 }

diff --git a/drivers/acpi/apei/ghes-nvidia.h b/drivers/acpi/apei/ghes-nvidia.h
index f0592fa41abf..7fff088e1dc1 100644
--- a/drivers/acpi/apei/ghes-nvidia.h
+++ b/drivers/acpi/apei/ghes-nvidia.h
@@ -3,36 +3,61 @@
 #define GHES_NVIDIA_H

 #include <linux/types.h>
+#include <linux/uuid.h>
 #include <kunit/visibility.h>

-struct device;
-
 enum nvidia_ghes_format {
 	NVIDIA_GHES_FORMAT_UNKNOWN,
 	NVIDIA_GHES_FORMAT_GRACE,
+	NVIDIA_GHES_FORMAT_VERA,
 };

+#define NVIDIA_GHES_MAX_CONTEXTS 16
+
 struct nvidia_ghes_grace_reg {
 	__le64 addr;
 	__le64 val;
 };

+struct nvidia_ghes_vera_context {
+	u32 context_size;
+	u16 context_version;
+	u16 data_format_type;
+	u16 data_format_version;
+	u32 data_size;
+	const u8 *data;
+};
+
 struct nvidia_ghes_decoded {
 	enum nvidia_ghes_format format;
 	char signature[17];
 	u16 error_type;
 	u16 error_instance;
+	u16 event_type;
+	u16 event_sub_type;
 	u8 severity;
 	u8 socket;
 	u8 number_regs;
+	u8 source_device_type;
+	u8 event_context_count;
+	u32 architecture;
+	u64 event_link_id;
 	u64 instance_base;
+	u8 chip_serial_number[16];
 	const struct nvidia_ghes_grace_reg *grace_regs;
+	struct nvidia_ghes_vera_context contexts[NVIDIA_GHES_MAX_CONTEXTS];
 };

+VISIBLE_IF_KUNIT enum nvidia_ghes_format nvidia_ghes_format_from_guid(const guid_t *guid);
 VISIBLE_IF_KUNIT int nvidia_ghes_decode_grace(struct device *dev, const void *buf,
 					      size_t len,
 					      struct nvidia_ghes_decoded *decoded);
 VISIBLE_IF_KUNIT int nvidia_ghes_grace_reg_pair(const struct nvidia_ghes_decoded *decoded,
 						unsigned int index, u64 *addr, u64 *val);
+VISIBLE_IF_KUNIT int nvidia_ghes_decode_vera(struct device *dev, const void *buf,
+					     size_t len,
+					     struct nvidia_ghes_decoded *decoded);
+VISIBLE_IF_KUNIT
+int nvidia_ghes_vera_context_entry_count(const struct nvidia_ghes_vera_context *ctx);

 #endif
-- 
2.50.1 (Apple Git-155)


^ permalink raw reply related

* [PATCH v1 1/4] ACPI: APEI: GHES: Refactor Grace decoder helpers
From: Kai-Heng Feng @ 2026-06-12 12:09 UTC (permalink / raw)
  To: rafael, shuah, kees
  Cc: csoto, mochs, Kai-Heng Feng, Tony Luck, Borislav Petkov,
	Hanjun Guo, Mauro Carvalho Chehab, Shuai Xue, Len Brown,
	Gustavo A. R. Silva, linux-kernel, linux-acpi, linux-hardening
In-Reply-To: <20260612120929.28965-1-kaihengf@nvidia.com>

Split the Grace CPER processing into a separate decode step and a
print step so the parser can be exercised by KUnit without a live
ACPI device. Introduce ghes-nvidia.h to hold shared types that the
Vera decoder added in the next commit will also reference.

Signed-off-by: Kai-Heng Feng <kaihengf@nvidia.com>
---
 drivers/acpi/apei/ghes-nvidia.c | 148 +++++++++++++++++++++-----------
 drivers/acpi/apei/ghes-nvidia.h |  38 ++++++++
 2 files changed, 137 insertions(+), 49 deletions(-)
 create mode 100644 drivers/acpi/apei/ghes-nvidia.h

diff --git a/drivers/acpi/apei/ghes-nvidia.c b/drivers/acpi/apei/ghes-nvidia.c
index 597275d81de8..af445152def0 100644
--- a/drivers/acpi/apei/ghes-nvidia.c
+++ b/drivers/acpi/apei/ghes-nvidia.c
@@ -12,7 +12,10 @@
 #include <linux/uuid.h>
 #include <acpi/ghes.h>

-static const guid_t nvidia_sec_guid =
+#include <kunit/visibility.h>
+#include "ghes-nvidia.h"
+
+static const guid_t nvidia_grace_sec_guid =
 	GUID_INIT(0x6d5244f2, 0x2712, 0x11ec,
 		  0xbe, 0xa7, 0xcb, 0x3f, 0xdb, 0x95, 0xc7, 0x86);

@@ -25,10 +28,7 @@ struct cper_sec_nvidia {
 	u8	number_regs;
 	u8	reserved;
 	__le64	instance_base;
-	struct {
-		__le64	addr;
-		__le64	val;
-	} regs[] __counted_by(number_regs);
+	struct nvidia_ghes_grace_reg regs[] __counted_by(number_regs);
 };

 struct nvidia_ghes_private {
@@ -36,73 +36,123 @@ struct nvidia_ghes_private {
 	struct device		*dev;
 };

-static void nvidia_ghes_print_error(struct device *dev,
-				    const struct cper_sec_nvidia *nvidia_err,
-				    size_t error_data_length, bool fatal)
+VISIBLE_IF_KUNIT
+int nvidia_ghes_decode_grace(struct device *dev, const void *buf,
+			     size_t len,
+			     struct nvidia_ghes_decoded *decoded)
 {
-	const char *level = fatal ? KERN_ERR : KERN_INFO;
+	const struct cper_sec_nvidia *nvidia_err = buf;
 	size_t min_size;

-	dev_printk(level, dev, "signature: %.16s\n", nvidia_err->signature);
-	dev_printk(level, dev, "error_type: %u\n", le16_to_cpu(nvidia_err->error_type));
-	dev_printk(level, dev, "error_instance: %u\n", le16_to_cpu(nvidia_err->error_instance));
-	dev_printk(level, dev, "severity: %u\n", nvidia_err->severity);
-	dev_printk(level, dev, "socket: %u\n", nvidia_err->socket);
-	dev_printk(level, dev, "number_regs: %u\n", nvidia_err->number_regs);
-	dev_printk(level, dev, "instance_base: 0x%016llx\n",
-		   le64_to_cpu(nvidia_err->instance_base));
-
-	if (nvidia_err->number_regs == 0)
-		return;
-
-	/*
-	 * Validate that all registers fit within error_data_length.
-	 * Each register pair is two little-endian u64s.
-	 */
+	if (!buf || !decoded)
+		return -EINVAL;
+	if (len < sizeof(*nvidia_err)) {
+		if (dev)
+			dev_err(dev, "Section too small (%zu < %zu)\n",
+				len, sizeof(*nvidia_err));
+		return -ENODATA;
+	}
+
 	min_size = struct_size(nvidia_err, regs, nvidia_err->number_regs);
-	if (error_data_length < min_size) {
-		dev_err(dev, "Invalid number_regs %u (section size %zu, need %zu)\n",
-			nvidia_err->number_regs, error_data_length, min_size);
-		return;
+	if (len < min_size) {
+		if (dev)
+			dev_err(dev,
+				"Invalid number_regs %u (section size %zu, need %zu)\n",
+				nvidia_err->number_regs, len, min_size);
+		return -ENODATA;
 	}

-	for (int i = 0; i < nvidia_err->number_regs; i++)
+	memset(decoded, 0, sizeof(*decoded));
+	decoded->format = NVIDIA_GHES_FORMAT_GRACE;
+	memcpy(decoded->signature, nvidia_err->signature, sizeof(nvidia_err->signature));
+	decoded->signature[sizeof(nvidia_err->signature)] = '\0';
+	decoded->error_type = le16_to_cpu(nvidia_err->error_type);
+	decoded->error_instance = le16_to_cpu(nvidia_err->error_instance);
+	decoded->severity = nvidia_err->severity;
+	decoded->socket = nvidia_err->socket;
+	decoded->number_regs = nvidia_err->number_regs;
+	decoded->instance_base = le64_to_cpu(nvidia_err->instance_base);
+	if (nvidia_err->number_regs)
+		decoded->grace_regs = nvidia_err->regs;
+
+	return 0;
+}
+EXPORT_SYMBOL_IF_KUNIT(nvidia_ghes_decode_grace);
+
+VISIBLE_IF_KUNIT
+int nvidia_ghes_grace_reg_pair(const struct nvidia_ghes_decoded *decoded,
+				      unsigned int index, u64 *addr, u64 *val)
+{
+	const struct nvidia_ghes_grace_reg *regs;
+
+	if (!decoded || decoded->format != NVIDIA_GHES_FORMAT_GRACE || !addr || !val)
+		return -EINVAL;
+	if (index >= decoded->number_regs)
+		return -ERANGE;
+
+	regs = decoded->grace_regs;
+	*addr = le64_to_cpu(regs[index].addr);
+	*val = le64_to_cpu(regs[index].val);
+
+	return 0;
+}
+EXPORT_SYMBOL_IF_KUNIT(nvidia_ghes_grace_reg_pair);
+
+static void nvidia_ghes_print_grace(struct device *dev,
+				    const struct nvidia_ghes_decoded *decoded,
+				    bool fatal)
+{
+	const char *level = fatal ? KERN_ERR : KERN_INFO;
+	u64 addr, val;
+
+	dev_printk(level, dev, "signature: %s\n", decoded->signature);
+	dev_printk(level, dev, "error_type: %u\n", decoded->error_type);
+	dev_printk(level, dev, "error_instance: %u\n", decoded->error_instance);
+	dev_printk(level, dev, "severity: %u\n", decoded->severity);
+	dev_printk(level, dev, "socket: %u\n", decoded->socket);
+	dev_printk(level, dev, "number_regs: %u\n", decoded->number_regs);
+	dev_printk(level, dev, "instance_base: 0x%016llx\n", decoded->instance_base);
+
+	for (int i = 0; i < decoded->number_regs; i++) {
+		if (nvidia_ghes_grace_reg_pair(decoded, i, &addr, &val))
+			break;
 		dev_printk(level, dev, "register[%d]: address=0x%016llx value=0x%016llx\n",
-			   i, le64_to_cpu(nvidia_err->regs[i].addr),
-			   le64_to_cpu(nvidia_err->regs[i].val));
+			   i, addr, val);
+	}
 }

 static int nvidia_ghes_notify(struct notifier_block *nb,
 			      unsigned long event, void *data)
 {
 	struct acpi_hest_generic_data *gdata = data;
+	struct nvidia_ghes_decoded decoded;
 	struct nvidia_ghes_private *priv;
-	const struct cper_sec_nvidia *nvidia_err;
+	const void *payload;
 	guid_t sec_guid;
+	u32 len;
+	int ret;
+	bool fatal;

 	import_guid(&sec_guid, gdata->section_type);
-	if (!guid_equal(&sec_guid, &nvidia_sec_guid))
+	if (!guid_equal(&sec_guid, &nvidia_grace_sec_guid))
 		return NOTIFY_DONE;

 	priv = container_of(nb, struct nvidia_ghes_private, nb);
-
-	if (acpi_hest_get_error_length(gdata) < sizeof(*nvidia_err)) {
-		dev_err(priv->dev, "Section too small (%d < %zu)\n",
-			acpi_hest_get_error_length(gdata), sizeof(*nvidia_err));
+	len = acpi_hest_get_error_length(gdata);
+	payload = acpi_hest_get_payload(gdata);
+	fatal = event >= GHES_SEV_RECOVERABLE;
+
+	ret = nvidia_ghes_decode_grace(priv->dev, payload, len, &decoded);
+	if (ret) {
+		dev_err(priv->dev,
+			"Malformed NVIDIA CPER section, error_data_length: %u, ret: %d\n",
+			len, ret);
 		return NOTIFY_OK;
 	}

-	nvidia_err = acpi_hest_get_payload(gdata);
-
-	if (event >= GHES_SEV_RECOVERABLE)
-		dev_err(priv->dev, "NVIDIA CPER section, error_data_length: %u\n",
-			acpi_hest_get_error_length(gdata));
-	else
-		dev_info(priv->dev, "NVIDIA CPER section, error_data_length: %u\n",
-			 acpi_hest_get_error_length(gdata));
-
-	nvidia_ghes_print_error(priv->dev, nvidia_err, acpi_hest_get_error_length(gdata),
-				event >= GHES_SEV_RECOVERABLE);
+	dev_printk(fatal ? KERN_ERR : KERN_INFO, priv->dev,
+		   "NVIDIA CPER section, error_data_length: %u\n", len);
+	nvidia_ghes_print_grace(priv->dev, &decoded, fatal);

 	return NOTIFY_OK;
 }
diff --git a/drivers/acpi/apei/ghes-nvidia.h b/drivers/acpi/apei/ghes-nvidia.h
new file mode 100644
index 000000000000..f0592fa41abf
--- /dev/null
+++ b/drivers/acpi/apei/ghes-nvidia.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef GHES_NVIDIA_H
+#define GHES_NVIDIA_H
+
+#include <linux/types.h>
+#include <kunit/visibility.h>
+
+struct device;
+
+enum nvidia_ghes_format {
+	NVIDIA_GHES_FORMAT_UNKNOWN,
+	NVIDIA_GHES_FORMAT_GRACE,
+};
+
+struct nvidia_ghes_grace_reg {
+	__le64 addr;
+	__le64 val;
+};
+
+struct nvidia_ghes_decoded {
+	enum nvidia_ghes_format format;
+	char signature[17];
+	u16 error_type;
+	u16 error_instance;
+	u8 severity;
+	u8 socket;
+	u8 number_regs;
+	u64 instance_base;
+	const struct nvidia_ghes_grace_reg *grace_regs;
+};
+
+VISIBLE_IF_KUNIT int nvidia_ghes_decode_grace(struct device *dev, const void *buf,
+					      size_t len,
+					      struct nvidia_ghes_decoded *decoded);
+VISIBLE_IF_KUNIT int nvidia_ghes_grace_reg_pair(const struct nvidia_ghes_decoded *decoded,
+						unsigned int index, u64 *addr, u64 *val);
+
+#endif
-- 
2.50.1 (Apple Git-155)


^ permalink raw reply related

* Re: [PATCH v2 11/16] power: sequencing: pcie-m2: Add usb and sdio targets for E-key connector
From: Chen-Yu Tsai @ 2026-06-12  9:17 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Bartosz Golaszewski, Greg Kroah-Hartman, Daniel Scally,
	Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
	Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Matthias Brugger, AngeloGioacchino Del Regno, Alan Stern,
	linux-acpi, driver-core, linux-pm, linux-usb, devicetree,
	linux-mediatek, linux-arm-kernel, linux-kernel,
	Manivannan Sadhasivam
In-Reply-To: <ail2VcubjT7HNGUC@ashevche-desk.local>

On Wed, Jun 10, 2026 at 11:36 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Wed, Jun 10, 2026 at 04:40:45PM +0800, Chen-Yu Tsai wrote:
> > The M.2 E-key connector allows either PCIe or SDIO for WiFi and USB or
> > UART for BT. Currently the driver only supports PCIe and UART.
> >
> > Add power sequencing targets for SDIO and USB. To avoid adding a
> > complicated dependency tree, rename the existing power sequencing units
> > "pcie" and "uart" to "wifi" and "bt". The existing target names are left
> > untouched. The new "sdio" and "usb" targets just point to the renamed
> > "wifi" and "bt" units.
>
> Why can we do that? No breakage? Only internal names? No ABI affected?
> Please, clarify all this in the commit message.

Will do.

In short, the target names (which are not modified) are used by the
consumer, while the unit names are internal only.


ChenYu

^ permalink raw reply

* Re: [PATCH v2 10/16] power: sequencing: pcie-m2: support matching on remote "port" node
From: Chen-Yu Tsai @ 2026-06-12  9:12 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Bartosz Golaszewski, Greg Kroah-Hartman, Daniel Scally,
	Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
	Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Matthias Brugger, AngeloGioacchino Del Regno, Alan Stern,
	linux-acpi, driver-core, linux-pm, linux-usb, devicetree,
	linux-mediatek, linux-arm-kernel, linux-kernel,
	Manivannan Sadhasivam
In-Reply-To: <ail1sAxgh5Xtkj2y@ashevche-desk.local>

On Wed, Jun 10, 2026 at 11:33 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Wed, Jun 10, 2026 at 04:40:44PM +0800, Chen-Yu Tsai wrote:
> > A USB hub can have multiple ports, and this driver needs to
> > differentiate which port is being matched to. The USB hub driver now
> > associates the "port" node with the usb_port device, so here we can
> > use the remote "port" node to check for a match. Then fall back to
> > the remote device node for the other connection types.
>
> ...
>
> > +             if (remote_port && remote_port == dev_of_node(dev))
> > +                     return PWRSEQ_MATCH_OK;
> >               if (remote && (remote == dev_of_node(dev)))
> >                       return PWRSEQ_MATCH_OK;
>
> We have device_match_of_node() IIRC the name of that API.

Ack. Will also replace the existing instance.

^ permalink raw reply

* Re: [PATCH v2 08/16] Revert "dt-bindings: usb: mediatek,mtk-xhci: Add port for SuperSpeed EP"
From: Krzysztof Kozlowski @ 2026-06-12  8:59 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Bartosz Golaszewski, Greg Kroah-Hartman, Andy Shevchenko,
	Daniel Scally, Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
	Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Matthias Brugger, AngeloGioacchino Del Regno, Alan Stern,
	linux-acpi, driver-core, linux-pm, linux-usb, devicetree,
	linux-mediatek, linux-arm-kernel, linux-kernel,
	Manivannan Sadhasivam
In-Reply-To: <20260610084053.2059858-9-wenst@chromium.org>

On Wed, Jun 10, 2026 at 04:40:42PM +0800, Chen-Yu Tsai wrote:
> This reverts commit 454a1e3cd36c113341d7b71e8e691c6e47ab4a8a.
> 
> mtk-xhci handles both USB 2.0 High Speed (HS) and USB 3.x SuperSpeed
> (SS) host connections. And there are USB 2.0 only mtk-xhci blocks.
> The SSUSB controller handles the device or gadget mode. Saying that
> SSUSB handles the HS portion is wrong.
> 
> Fixes: 454a1e3cd36c ("dt-bindings: usb: mediatek,mtk-xhci: Add port for SuperSpeed EP")
> Cc: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
> ---
>  Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml | 4 ----
>  1 file changed, 4 deletions(-)

Please squash both commits. Reverting just for sake of revert is
pointless. We want wrong binding to be corrected, not to be reverted.
You revert something if there is nothing to fix afterwards, IOW.

Best regards,
Krzysztof


^ permalink raw reply

* Re: [PATCH v2 07/16] usb: hub: Power on connected M.2 E-key connectors
From: Chen-Yu Tsai @ 2026-06-12  8:55 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Alan Stern, linux-acpi, driver-core, linux-pm, linux-usb,
	devicetree, linux-mediatek, linux-arm-kernel, linux-kernel,
	Manivannan Sadhasivam, Greg Kroah-Hartman, Andy Shevchenko,
	Daniel Scally, Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
	Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Matthias Brugger, AngeloGioacchino Del Regno
In-Reply-To: <CAMRc=Mc3DqGb2MsvM4tjcqFuRraAO+EftO1UrtNFvR5dMRXmVA@mail.gmail.com>

On Thu, Jun 11, 2026 at 6:11 PM Bartosz Golaszewski <brgl@kernel.org> wrote:
>
> On Wed, 10 Jun 2026 10:40:41 +0200, Chen-Yu Tsai <wenst@chromium.org> said:
> > The new M.2 E-key connector can have a USB connection. For the USB device
> > on this connector to work, its power must be enabled and the W_DISABLE2#
> > signal deasserted. The connector driver handles this and provides a
> > toggle over the power sequencing API.
> >
> > This feature currently only supports a directly connected (no mux in
> > between) M.2 E-key connector. Existing USB connector types are not
> > covered. The USB A connector was recently added to the onboard devices
> > driver. USB B connectors have historically been managed by the USB
> > gadget or dual-role device controller drivers. USB C connectors are
> > handled by TCPM drivers.
> >
> > The power sequencing API does not know whether a power sequence provider
> > is not needed or not available yet, so we only request it for connectors
> > that we know need it, which at this time is just the E-key connector.
> >
> > On the USB side, the port firmware node (if present) is tied to the
> > usb_port device. This device is used to acquire the power sequencing
> > descriptor. This allows the provider to tell the different ports on one
> > hub apart.
> >
> > This feature is not implemented in the onboard USB devices driver. The
> > power sequencing API expects the consumer device to make the request,
> > but there is no device node to instantiate a platform device to tie
> > the driver to. The connector is not a child node of the USB host or
> > hub, and the graph connection is from a USB port to the connector.
> > And the connector itself already has a driver.
> >
> > Power sequencing is not directly enabled in the connector driver as
> > that would completely decouple the timing of it from the USB subsystem.
> > It would not be possible for the USB subsystem to toggle the power
> > for a power cycle or to disable the port.
> >
> > This change depends on another change to make the power sequencing
> > framework bool instead of tristate. The USB core and hub driver are
> > bool, so if the power sequencing framework is built as a module, the
> > kernel will fail to link.
> >
>
> That bit needs to go away I suppose?

Yeah, instead we need

    config USB
        depends on POWER_SEQUENCING && !POWER_SEQUENCING

But I ran into a dozen or so drivers that have "select USB", mostly
input devices:

    config TOUCHSCREEN_USB_COMPOSITE
        tristate "USB Touchscreen Driver"
        depends on USB_ARCH_HAS_HCD
        select USB

Kconfig complains about unmet dependencies.

> I see Andy has some suggestions but in general I like this approach much better
> than adding the pwrseq_get_index() function. Thanks!

Thanks!

ChenYu

^ permalink raw reply

* Re: [PATCH v6 0/2] gpiolib: acpi: Add robust bounds-checking and safe address handling
From: Mika Westerberg @ 2026-06-12  8:52 UTC (permalink / raw)
  To: Marco Scardovi
  Cc: Mika Westerberg, Andy Shevchenko, Linus Walleij,
	Bartosz Golaszewski, linux-gpio, linux-acpi, linux-kernel
In-Reply-To: <20260610154204.110379-1-scardracs@disroot.org>

Hi,

On Wed, Jun 10, 2026 at 05:42:02PM +0200, Marco Scardovi wrote:
> Hi all,
> 
> The series adds explicit bounds checking for GPIO pin accesses and
> ensures safe handling of ACPI addresses in OperationRegion handlers,
> without referring to truncation or wrap-around behavior, which does
> not apply.

I'm fine with these now.

For both,

Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>

^ permalink raw reply

* Re: [PATCH v2 04/16] usb: hub: Return actual error from hub_configure() in hub_probe()
From: Chen-Yu Tsai @ 2026-06-12  7:51 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Bartosz Golaszewski, Greg Kroah-Hartman, Daniel Scally,
	Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
	Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Matthias Brugger, AngeloGioacchino Del Regno, Alan Stern,
	linux-acpi, driver-core, linux-pm, linux-usb, devicetree,
	linux-mediatek, linux-arm-kernel, linux-kernel,
	Manivannan Sadhasivam
In-Reply-To: <ailytpKQcvYTUH7j@ashevche-desk.local>

On Wed, Jun 10, 2026 at 11:20 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Wed, Jun 10, 2026 at 04:40:38PM +0800, Chen-Yu Tsai wrote:
> > The addition of power sequencing descriptor handling in the USB hub code
> > requires dealing with deferred probing from pwrseq_get(). The power
> > sequencing provider may not yet be available when the USB hub probes.
> >
> > Return the actual error code from hub_configure() when it fails, so that
> > the driver core can notice the deferred probe request.
>
> Makes sense to me.
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>
> One nit-pick, though.
>
> ...
>
> > -     if (hub_configure(hub, &desc->endpoint[0].desc) >= 0) {
> > +     ret = hub_configure(hub, &desc->endpoint[0].desc);
> > +     if (ret >= 0) {
> >               onboard_dev_create_pdevs(hdev, &hub->onboard_devs);
> >
> >               return 0;
> >       }
> >
> >       hub_disconnect(intf);
> > -     return -ENODEV;
> > +     return ret;
>
> Can we convert to regular pattern, id est checking for errors first?

Sure. Will do it together in the next version.


ChenYu

>         ret = hub_configure(hub, &desc->endpoint[0].desc);
>         if (ret < 0) {
>                 hub_disconnect(intf);
>                 return ret;
>         }
>
>         onboard_dev_create_pdevs(hdev, &hub->onboard_devs);
>
>         return 0;
>
> --
> With Best Regards,
> Andy Shevchenko
>
>

^ permalink raw reply

* Re: [PATCH v6 6/9] dt-bindings: connector: m2: Add M.2 1620 LGA soldered down connector
From: Dmitry Baryshkov @ 2026-06-12  7:50 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Stephan Gerhold, Mark Pearson, Rob Herring, Manivannan Sadhasivam,
	Greg KH, Jiri Slaby, Nathan Chancellor, Nicolas Schier,
	Hans de Goede, Ilpo Järvinen, Derek J . Clark,
	Krzysztof Kozlowski, Conor Dooley, Marcel Holtmann,
	Luiz Augusto von Dentz, Bartosz Golaszewski, Andy Shevchenko,
	Bartosz Golaszewski, linux-serial, linux-kernel, linux-kbuild,
	platform-driver-x86@vger.kernel.org, linux-pci, devicetree,
	linux-arm-msm, linux-bluetooth, linux-pm,
	linux-acpi@vger.kernel.org
In-Reply-To: <eftahohsx3bbvmgxuciofjjcrybnsm2qc752hwyt65rb2uwaon@h32nh5fcpo7p>

On Wed, Jun 10, 2026 at 06:44:59PM +0200, Manivannan Sadhasivam wrote:
> On Tue, Mar 31, 2026 at 06:29:51PM +0200, Stephan Gerhold wrote:
> > On Wed, Mar 25, 2026 at 05:36:08PM +0530, Manivannan Sadhasivam wrote:
> > > On Mon, Mar 23, 2026 at 01:23:07PM -0400, Mark Pearson wrote:
> > > > On Mon, Mar 23, 2026, at 12:52 PM, Manivannan Sadhasivam wrote:
> > > > > On Mon, Mar 23, 2026 at 06:45:15PM +0200, Dmitry Baryshkov wrote:
> > > > >> On Mon, Mar 23, 2026 at 09:26:04PM +0530, Manivannan Sadhasivam wrote:
> > > > >> > On Mon, Mar 23, 2026 at 05:14:30PM +0200, Dmitry Baryshkov wrote:
> > > > >> > > On Mon, Mar 23, 2026 at 07:14:25PM +0530, Manivannan Sadhasivam wrote:
> > > > >> > > > On Mon, Mar 23, 2026 at 08:39:55AM -0500, Rob Herring wrote:
> > > > >> > > > > On Mon, Mar 23, 2026 at 7:16 AM Manivannan Sadhasivam <mani@kernel.org> wrote:
> > > > >> > > > > >
> > > > >> > > > > > On Sun, Mar 22, 2026 at 06:37:13PM -0500, Rob Herring wrote:
> > > > >> > > > > > > On Tue, Mar 17, 2026 at 09:59:56AM +0530, Manivannan Sadhasivam wrote:
> > > > >> > > > > > > > Lenovo Thinkpad T14s is found to have a soldered down version of M.2 1620
> > > > >> > > > > > > > LGA connector. Though, there is no 1620 LGA form factor defined in the M.2
> > > > >> > > > > > > > spec, it looks very similar to the M.2 Key E connector. So add the
> > > > >> > > > > > > > "pcie-m2-1620-lga-connector" compatible with "pcie-m2-e-connector" fallback
> > > > >> > > > > > > > to reuse the Key E binding.
> > > > >> > > > > > >
> > > > >> > > > > > > What is LGA?
> > > > >> > > > > > >
> > > > >> > > > > >
> > > > >> > > > > > Land Grid Array
> > > > >> > > > > >
> > > > >> > > > > > > If not in the spec, is it really something generic?
> > > > >> > > > > > >
> > > > >> > > > > >
> > > > >> > > > > > Good question. Yes and No! LGA is not something that Lenovo only uses. Other
> > > > >> > > > > > vendors may also use this form factor. PCIe connectors are full of innovation as
> > > > >> > > > > > the spec gives room for hardware designers to be as innovative as possible to
> > > > >> > > > > > save the BOM cost.
> > > > >> > > > > 
> > > > >> > > > > innovation == incompatible changes
> > > > >> > > > > 
> > > > >> > > > 
> > > > >> > > > Yes, I was trying to sound nice :)
> > > > >> > > > 
> > > > >> > > > > > This is why I do not want to make it Lenovo specific. But if you prefer that, I
> > > > >> > > > > > can name it as "lenovo,pcie-m2-1620-lga-connector".
> > > > >> > > > > 
> > > > >> > > > > Depends if you think that s/w needs to know the differences. Hard to
> > > > >> > > > > say with a sample size of 1.
> > > > >> > > > > 
> > > > >> > > > 
> > > > >> > > > Sure. Will add the 'lenovo' prefix then.
> > > > >> > > 
> > > > >> > > Is it really Lenovo? Or is it some other module vendor, whose LGAs are
> > > > >> > > being used by Lenovo?
> > > > >> > > 
> > > > >> > > I remember that DB820c also used some kind of a module for the WiFi card
> > > > >> > > (which might be M.2 compatible or might not, I can't find exact docs at
> > > > >> > > this point).
> > > > >> > > 
> > > > >> > 
> > > > >> > I don't know. These kind of designs might be reused by several vendors. But
> > > > >> > considering that we should not make it generic, I'd go with Lenovo as that's
> > > > >> > the only vendor we know as of now.
> > > > >> 
> > > > >> ... and later we learn that other vendors use the same idea /pinout,
> > > > >> then nothing stops us from still telling that it's a
> > > > >> "lenovo,pcie-m2-something-lga". 
> > > > >> 
> > > > >
> > > > > How do you possibly know whether a single vendor has introduced this form factor
> > > > > or reused by multiple ones? Atleast, I don't have access to such a source to
> > > > > confirm.
> > > > >
> > > > I've not really been following this thread/patchset in detail; but want me to try and check with the T14s platform team if this device is specifically made for us (Lenovo) or not?
> > > > I doubt it is - we just don't do that usually, but I can go and ask the question if it will help resolve this (with the caveat that it could hold up the review for a bit and I may not be able to get a straight answer)
> > > > 
> > > 
> > > I can drop this specific patch in the meantime.
> > > 
> > > > My vote (for what little it's worth) would be to make it non-Lenovo specific. Then when the same part causes issues on another vendors platform I won't get asked questions about why Lenovo is breaking <other vendor> :)
> > > > 
> > > 
> > > Even if Lenovo prefix is used, it won't break other vendors. Just that we will
> > > end up adding more compatibles.
> > > 
> > > Anyhow, I'll wait for your reply and drop this patch for next revision.
> > > 
> > 
> > If you need a vendor prefix, I think "qcom," would be more appropriate
> > than Lenovo. This form factor is used by most vendors for recent
> > soldered Qualcomm-based wireless cards, not just Lenovo:
> > 
> >  - Dell XPS 13 9345 has exactly the same soldered M.2 card, I assume
> >    there are several other vendors as well.
> > 
> >  - https://www.sparklan.com/product/wnsq-290be/ is a third-party
> >    (Qualcomm-based) M.2 LGA 1620 card, in the block diagram the
> >    pinout is called "QM.2 1620 LGA 168pin".
> > 
> >  - If you press F9 while booting the ThinkPad T14s, you should get to a
> >    screen with "Regulatory Information". For the T14s, this screen says
> >    "Contains FCC ID: J9C-QCNCM825". This is the WiFi/BT module in the
> >    soldered form factor. If you look that up on the FCC website, the
> >    applicant for this module is "Qualcomm Technologies, Inc.". This
> >    seems to be some kind of "modular certification" that vendors can
> >    reuse/adapt without going through the whole process again.
> > 
> > Perhaps you should ask around inside Qualcomm? :-)
> > 
> 
> Sorry for getting back after this long. I did ask around, but our HW folks are
> saying that Qcom is not the first one to use LGA M.2 modules. They claim that
> other vendors also do that.

I think, the idea was that there is no single standard for LGA modules
(please correct me if I'm wrong, I haven't checked the latest PCIe
standards).

> 
> But for this specific card, it should be fine to use the 'qcom' prefix as
> apparently the module was supplied by Qcom.
> 
> I'll submit the bindings patch together with DTS change for T14s.
> 
> - Mani
> 
> -- 
> மணிவண்ணன் சதாசிவம்

-- 
With best wishes
Dmitry

^ permalink raw reply

* Re: [PATCH v2 6/6] irqchip/gic-v5: Enable GICv5 IWB ACPI probe ordering detection
From: Lorenzo Pieralisi @ 2026-06-12  7:46 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Len Brown, Sunil V L, Marc Zyngier, Thomas Gleixner, Huacai Chen,
	Anup Patel, Hanjun Guo, Sudeep Holla, Catalin Marinas,
	Will Deacon, linux-riscv, linux-kernel, linux-acpi,
	linux-arm-kernel, loongarch
In-Reply-To: <CAJZ5v0ibZKfzJwGyUb92-K1N9C_ab0QujpAKCrvMdyygquS1Vw@mail.gmail.com>

On Mon, Jun 08, 2026 at 07:18:15PM +0200, Rafael J. Wysocki wrote:
> On Wed, Jun 3, 2026 at 10:21 AM Lorenzo Pieralisi <lpieralisi@kernel.org> wrote:
> >
> > Register an ACPI hook in the ACPI interrupt management code for GICv5 to
> > retrieve the ACPI interrupt controller handle (if any) of the controller
> > handling a specific GSI, by updating the acpi_set_irq_model() call with
> > the gic_v5_get_gsi_handle() function pointer parameter.
> >
> > gicv5_get_gsi_handle() allows ACPI core to detect the ACPI handle
> > of the controller that manages a specific GSI interrupt.
> >
> > Update the IWB driver to clear device dependencies in ACPI core once the
> > IWB driver has probed.
> >
> > Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org>
> > Cc: Thomas Gleixner <tglx@kernel.org>
> > Cc: Marc Zyngier <maz@kernel.org>
> > ---
> >  drivers/irqchip/irq-gic-v5-iwb.c |  5 +++++
> >  drivers/irqchip/irq-gic-v5.c     | 13 +++++++++++--
> >  2 files changed, 16 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/irqchip/irq-gic-v5-iwb.c b/drivers/irqchip/irq-gic-v5-iwb.c
> > index 9103feb70ce8..a02cb9537b15 100644
> > --- a/drivers/irqchip/irq-gic-v5-iwb.c
> > +++ b/drivers/irqchip/irq-gic-v5-iwb.c
> > @@ -269,6 +269,11 @@ static int gicv5_iwb_device_probe(struct platform_device *pdev)
> >         if (IS_ERR(iwb_node))
> >                 return PTR_ERR(iwb_node);
> >
> > +#ifdef CONFIG_ACPI
> > +       if (has_acpi_companion(&pdev->dev))
> > +               acpi_dev_clear_dependencies(ACPI_COMPANION(&pdev->dev));
> > +#endif
> 
> I would rather add a wrapper for this, along with an empty stub for
> the !CONFIG_ACPI case.

Given that this has no OF counterpart, I'd rather add an empty stub
for acpi_dev_clear_dependencies() and remove the ifdef - I am not
sure that adding a FW agnostic:

dev_clear_dependencies()

would help much but that's just my opinion. Then the question is whether I
should convert all other acpi_dev_clear_dependencies() users (with ifdeffery
included) in tree.

Thanks,
Lorenzo

> 
> > +
> >         return 0;
> >  }
> >
> > diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c
> > index 03cc2830b260..26cfaea1af41 100644
> > --- a/drivers/irqchip/irq-gic-v5.c
> > +++ b/drivers/irqchip/irq-gic-v5.c
> > @@ -1217,11 +1217,19 @@ static struct fwnode_handle *gsi_domain_handle;
> >  static struct fwnode_handle *gic_v5_get_gsi_domain_id(u32 gsi)
> >  {
> >         if (FIELD_GET(GICV5_GSI_IC_TYPE, gsi) == GICV5_GSI_IWB_TYPE)
> > -               return iort_iwb_handle(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi));
> > +               return iort_iwb_handle_fwnode(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi));
> 
> Why is this change needed?
> 
> >
> >         return gsi_domain_handle;
> >  }
> >
> > +static acpi_handle gic_v5_get_gsi_handle(u32 gsi)
> > +{
> > +       if (FIELD_GET(GICV5_GSI_IC_TYPE, gsi) == GICV5_GSI_IWB_TYPE)
> > +               return iort_iwb_handle(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi));
> > +
> > +       return NULL;
> > +}
> > +
> >  static int __init gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
> >  {
> >         struct acpi_madt_gicv5_irs *irs = (struct acpi_madt_gicv5_irs *)header;
> > @@ -1242,7 +1250,8 @@ static int __init gic_acpi_init(union acpi_subtable_headers *header, const unsig
> >         if (ret)
> >                 goto out_irs;
> >
> > -       acpi_set_irq_model(ACPI_IRQ_MODEL_GIC_V5, gic_v5_get_gsi_domain_id, NULL);
> > +       acpi_set_irq_model(ACPI_IRQ_MODEL_GIC_V5, gic_v5_get_gsi_domain_id,
> > +                          gic_v5_get_gsi_handle);
> >
> >         return 0;
> >
> >
> > --

^ permalink raw reply

* Re: [PATCH v2 02/16] device property: Add fwnode_graph_get_next_port_endpoint()
From: Chen-Yu Tsai @ 2026-06-12  7:20 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Bartosz Golaszewski, Greg Kroah-Hartman, Daniel Scally,
	Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
	Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Matthias Brugger, AngeloGioacchino Del Regno, Alan Stern,
	linux-acpi, driver-core, linux-pm, linux-usb, devicetree,
	linux-mediatek, linux-arm-kernel, linux-kernel,
	Manivannan Sadhasivam
In-Reply-To: <ailv8HpnrCH3Zb8C@ashevche-desk.local>

On Wed, Jun 10, 2026 at 11:08 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Wed, Jun 10, 2026 at 04:40:36PM +0800, Chen-Yu Tsai wrote:
> > Due to design constraints of the power sequencing API, the consumer
> > must first be sure that the other side is actually a provider, or it
> > will continually get -EPROBE_DEFER when requesting the power
> > sequencing descriptor.
> >
> > In the upcoming USB power sequencing integration, the USB hub driver
> > first needs to check whether a graph connection exists, and whether
> > the other side of the connection is a supported connector type. The
> > USB port is tied to a "port" firmware node, and this new helper will
> > be used to get the endpoint under the known "port" firmware node.
>
> ...
>
> > +/**
> > + * fwnode_graph_get_next_port_endpoint - Get next endpoint firmware node in port
> > + * @port: Pointer to the target port firmware node
> > + * @prev: Previous endpoint node or %NULL to get the first
> > + *
> > + * The caller is responsible for calling fwnode_handle_put() on the returned
> > + * fwnode pointer. Note that this function also puts a reference to @prev
> > + * unconditionally.
> > + *
> > + * Return: an endpoint firmware node pointer or %NULL if no more endpoints
> > + * are available.
>
> Yeah, you see, even here is inconsistency with previously added kernel-doc.
>
> > + */
> > +struct fwnode_handle *fwnode_graph_get_next_port_endpoint(const struct fwnode_handle *port,
> > +                                                       struct fwnode_handle *prev)
> > +{
> > +     struct fwnode_handle *ep;
>
> Unused?
>
> > +     while (1) {
>
> This is usually harder to read and follow. It's like "pay much attention on
> the code", but here no rocket science, no code to really pay attention to.
>
> > +             prev = fwnode_get_next_child_node(port, prev);
> > +             if (!prev)
> > +                     break;
> > +
> > +             if (WARN(!fwnode_name_eq(prev, "endpoint"),
> > +                      "non endpoint node is used (%pfw)", prev))
> > +                     continue;
> > +
> > +             break;
> > +     }
> > +
> > +     return prev;
> > +}
>
> So, this can be rewritten as
>
>         ep = prev;
>         do {
>                 ep = fwnode_get_next_child_node(port, ep);
>                 if (fwnode_name_eq(ep, "endpoint"))
>                         break;
>
>                 WARN_ON(ep, ...);
>         } while (ep);
>
>         return ep;
>
> But also big question why? to WARN*(). There is no use in the entire
> property.c.

Will drop. This function was lifted from drivers/of/property.c then
adapted to the fwnode APIs, so it still has the structure of its
origin. With the WARN() gone, rewriting it as do {} while() becomes:

do {
        prev = fwnode_get_next_child_node(port, prev);
        if (prev && fwnode_name_eq(prev, "endpoint"))
                break;
} while (prev);

return prev;


Thanks
ChenYu

^ permalink raw reply

* Re: [PATCH v2 01/16] device property: Add fwnode_graph_get_port_by_id()
From: Chen-Yu Tsai @ 2026-06-12  7:07 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Bartosz Golaszewski, Greg Kroah-Hartman, Daniel Scally,
	Heikki Krogerus, Sakari Ailus, Rafael J. Wysocki,
	Danilo Krummrich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Matthias Brugger, AngeloGioacchino Del Regno, Alan Stern,
	linux-acpi, driver-core, linux-pm, linux-usb, devicetree,
	linux-mediatek, linux-arm-kernel, linux-kernel,
	Manivannan Sadhasivam
In-Reply-To: <ailtMyYhbkOgaZWw@ashevche-desk.local>

On Wed, Jun 10, 2026 at 10:57 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Wed, Jun 10, 2026 at 04:40:35PM +0800, Chen-Yu Tsai wrote:
> > In some cases the driver needs a reference to the port firmware node.
> > Once such case is the upcoming USB power sequencing integration. The
> > USB hub port is tied to the corresponding port firmware node if it
> > exists.
> >
> > Provide a helper for this.
>
> Okay, if it's really needed.
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>
> ...
>
> > +/**
> > + * fwnode_graph_get_port_by_id - get the port matching a given id
> > + * @fwnode: parent fwnode_handle containing the graph
> > + * @id: id of the port
> > + *
> > + * Return: A 'port' firmware node pointer with refcount incremented.
> > + *
> > + * The caller is responsible for calling fwnode_handle_put() on the returned
> > + * fwnode pointer.
>
> Note, the Return section must be last one in the kernel-doc. The last paragraph
> sounds to me as a better fit for main description. Basically check how other
> kernel-doc(s) in this file are organised and follow that pattern.

Will fix. I likely just copied it from the nearest function which happened
to not have a Return section. I did a quick look through and it seems many
of them are missing this.

ChenYu

^ permalink raw reply

* Re: [PATCH v4 1/3] device property: fix infinite loop in fwnode_for_each_child_node()
From: Xu Yang @ 2026-06-12  6:47 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Xu Yang, linux-acpi, driver-core, linux-kernel, Daniel Scally,
	Heikki Krogerus, Sakari Ailus, Greg Kroah-Hartman,
	Rafael J. Wysocki, Danilo Krummrich, stable
In-Reply-To: <20260611203537.1786399-2-andriy.shevchenko@linux.intel.com>

On Thu, Jun 11, 2026 at 10:31:06PM +0200, Andy Shevchenko wrote:
> From: Xu Yang <xu.yang_2@nxp.com>
> 
> When iterate over children of a fwnode that has a secondary fwnode,
> fwnode_get_next_child_node() can enter an infinite loop if the secondary
> fwnode has more than one child.
> 
>                        Parent        Child
>       (Primary fwnode)   FWa:   {FWa1, FWa2, FWa3}
>     (Secondary fwnode)   FWb:   {FWb1, FWb2}
> 
> In this case:
> 
>  ┌─> fwnode_get_next_child_node(FWa, FWa1)
>  │    - fwnode_call_ptr_op(FWa, get_next_child_node, FWa1) returns FWa2
>  │
>  │   ...
>  │
>  │   fwnode_get_next_child_node(FWa, FWa3)
>  │    - fwnode_call_ptr_op(FWa, get_next_child_node, FWa3) returns NULL
>  │    - fwnode_call_ptr_op(FWb, get_next_child_node, FWa3) returns FWb1
>  │
>  │   fwnode_get_next_child_node(FWa, FWb1)
>  │    - fwnode_call_ptr_op(FWa, get_next_child_node, FWb1) returns FWa1
>  └────┘
> 
> This cause fwnode_for_each_child_node() to loop indefinitely, reapeatedly
> output {FWa1, FWa2, FWa3, FWb1, FWa1, ...}.
> 
> The root cause is that when the current child (FWb1) belongs to the
> secondary fwnode, calling get_next_child_node() on the parimary fwnode
> incorrectly returns the first child (FWa1) again instead of NULL.
> 
> Fix this by dynamically checking the parent fwnode of the current child
> before calling get_next_child_node(). This approach follows the pattern
> established in commit b5b41ab6b0c1 ("device property: Check
> fwnode->secondary in fwnode_graph_get_next_endpoint()").
> 
> Fixes: 2692c614f8f0 ("device property: Allow secondary lookup in fwnode_get_next_child_node()")
> Cc: stable@vger.kernel.org
> Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
> Tested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

Tested-by: Xu Yang <xu.yang_2@nxp.com>

Thanks,
Xu Yang

> ---
>  drivers/base/property.c | 19 ++++++++++++++++---
>  1 file changed, 16 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/base/property.c b/drivers/base/property.c
> index 8e0148a37fff..f7b30d9c8716 100644
> --- a/drivers/base/property.c
> +++ b/drivers/base/property.c
> @@ -807,18 +807,31 @@ struct fwnode_handle *
>  fwnode_get_next_child_node(const struct fwnode_handle *fwnode,
>  			   struct fwnode_handle *child)
>  {
> +	const struct fwnode_handle *parent;
> +	struct fwnode_handle *child_parent __free(fwnode_handle) = NULL;
>  	struct fwnode_handle *next;
>  
> -	if (IS_ERR_OR_NULL(fwnode))
> +	/*
> +	 * If this function is in a loop and the previous iteration returned
> +	 * an child from fwnode->secondary, then we need to use the secondary
> +	 * as parent rather than @fwnode.
> +	 */
> +	if (child) {
> +		child_parent = fwnode_get_parent(child);
> +		parent = child_parent;
> +	} else {
> +		parent = fwnode;
> +	}
> +	if (IS_ERR_OR_NULL(parent))
>  		return NULL;
>  
>  	/* Try to find a child in primary fwnode */
> -	next = fwnode_call_ptr_op(fwnode, get_next_child_node, child);
> +	next = fwnode_call_ptr_op(parent, get_next_child_node, child);
>  	if (next)
>  		return next;
>  
>  	/* When no more children in primary, continue with secondary */
> -	return fwnode_call_ptr_op(fwnode->secondary, get_next_child_node, child);
> +	return fwnode_get_next_child_node(parent->secondary, NULL);
>  }
>  EXPORT_SYMBOL_GPL(fwnode_get_next_child_node);
>  
> -- 
> 2.50.1
> 

^ permalink raw reply

* Re: [PATCH v2 05/16] usb: hub: Associate port@ fwnode with USB port device
From: Chen-Yu Tsai @ 2026-06-12  5:46 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Heikki Krogerus, Bartosz Golaszewski, Greg Kroah-Hartman,
	Daniel Scally, Sakari Ailus, Rafael J. Wysocki, Danilo Krummrich,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Alan Stern, linux-acpi, driver-core,
	linux-pm, linux-usb, devicetree, linux-mediatek, linux-arm-kernel,
	linux-kernel, Manivannan Sadhasivam
In-Reply-To: <aisEccAOm3qoXjxd@ashevche-desk.local>

On Fri, Jun 12, 2026 at 3:54 AM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Thu, Jun 11, 2026 at 06:48:56PM +0300, Heikki Krogerus wrote:
> > On Thu, Jun 11, 2026 at 11:35:13AM +0200, Bartosz Golaszewski wrote:
> > > On Thu, Jun 11, 2026 at 10:37 AM Andy Shevchenko
> > > <andriy.shevchenko@linux.intel.com> wrote:
> > > > On Thu, Jun 11, 2026 at 04:20:58AM -0400, Bartosz Golaszewski wrote:
> > > > > On Wed, 10 Jun 2026 16:16:12 +0200, Andy Shevchenko
> > > > > <andriy.shevchenko@linux.intel.com> said:
> > > > > > On Wed, Jun 10, 2026 at 04:40:39PM +0800, Chen-Yu Tsai wrote:
> > > > > >> When a USB hub port is connected to a connector in a firmware node
> > > > > >> graph, the port itself has a node in the graph.
> > > > > >>
> > > > > >> Associate the port's firmware node with the USB port's device,
> > > > > >> usb_port::dev. This is used in later changes for the M.2 slot power
> > > > > >> sequencing provider to match against the requesting port.
> > > > > >
> > > > > > Okay, would this affect ACPI-based systems? if so, how?
> > > > > > Can you elaborate on that, please?
> > > > >
> > > > > Is it possible that there's an ACPI device node associated with the port like
> > > > > on some DT systems? I don't think so and there should be no impact IMO but I
> > > > > also don't know enough about ACPI.
> >
> > There are device nodes for the USB ports in ACPI, and I think they get
> > always assigned in drivers/usb/core/usb-acpi.c.
> >
> > > > The API is agnostic. There is a possibility to have software nodes associated
> > > > with the port. I think the best is to be sure that ACPI-aware people who are
> > > > experts in USB will check this (Heikki?).
> >
> > I can't say what's the impact from this patch - I'm not an expert with
> > this side of USB. Is there a danger that we end up overwriting the
> > ACPI node for the port, or something else?
>
> Exactly this one is my worrying, but I haven't checked the actual flow.

Looking through ACPI code, ACPI_COMPANION_SET() is used, which boils
down to

    set_primary_fwnode(dev, acpi_fwnode_handle(acpi_dev))

This is called through

usb_hub_create_port_device()
  device_register()
    device_add()
      device_platform_notify()
        acpi_device_notify()
          usb_acpi_find_companion()
            usb_acpi_find_companion_for_port()
          acpi_bind_one()
            ACPI_COMPANION_SET()
              set_primary_fwnode()

Looking at device_add_software_node(), all swnodes are secondary.

set_primary_fwnode() seems to be able to make the ACPI handle / fwnode
the primary, keeping any existing fwnode as the secondary. However
if we do end up assigning a primary fwnode to the device using
device_set_node() as in this patch, set_primary_fwnode() is going
to complain loudly.

On another front, the ACPI representation of the USB ports looks nothing
like the OF graphs, at least on my X1 Carbon:

For a usb port device on the root hub such as

  /sys/bus/usb/devices/4-0:1.0/usb4-port1/firmware_node/path

looks like

  \_SB_.PC00.XHCI.RHUB.SS01

while a usb port's firmware node link

  /sys/bus/usb/devices/4-0:1.0/usb4-port1//firmware_node

resolves to

  /sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:19/device:1a/device:29

Neither looks anything like the graph "port" / "endpoint" node names.
So maybe we're in the clear here.

Besides the loud warning from set_primary_fwnode(), the major issue stemming
from a wrong node is that power management (through ACPI) is likely to fail.

If we're still concerned, I think we can skip the assignment if the fwnode
is an ACPI node, i.e. check it with is_acpi_node().


I've never worked on ACPI systems, so this is just me checking the code.


Thanks
ChenYu

^ permalink raw reply

* Re: [PATCH v4 2/3] device property: Refactor to use RAII approach
From: Andy Shevchenko @ 2026-06-11 21:12 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Xu Yang, linux-acpi, driver-core, linux-kernel, Daniel Scally,
	Heikki Krogerus, Sakari Ailus, Greg Kroah-Hartman,
	Danilo Krummrich
In-Reply-To: <CAJZ5v0jPkVr9=6HZ2gbCTtcQjmrH+3yZaiXi5jfkfD8aLzOPug@mail.gmail.com>

On Thu, Jun 11, 2026 at 10:46:31PM +0200, Rafael J. Wysocki wrote:
> On Thu, Jun 11, 2026 at 10:35 PM Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
> > In a couple of functions code can be made cleaner with help of
> > __free() macro. Refactor these to use RAII approach.

...

> >  fwnode_graph_get_next_endpoint(const struct fwnode_handle *fwnode,
> >                                struct fwnode_handle *prev)
> >  {
> > -       struct fwnode_handle *ep, *port_parent = NULL;
> >         const struct fwnode_handle *parent;
> > +       struct fwnode_handle *port_parent __free(fwnode_handle) = NULL;
> 
> The thing on the right-hand side of the assignment should be a
> constructor, shouldn't it?

Nope. It's a recommendation to do a such, but in this case it's hard to achieve
(since the constructor is inside the conditional scope) and actually is not needed
as we don't mix up with other RAII calls, such a guard()().

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply

* Re: [PATCH v4 2/3] device property: Refactor to use RAII approach
From: Rafael J. Wysocki @ 2026-06-11 20:46 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Xu Yang, linux-acpi, driver-core, linux-kernel, Daniel Scally,
	Heikki Krogerus, Sakari Ailus, Greg Kroah-Hartman,
	Rafael J. Wysocki, Danilo Krummrich
In-Reply-To: <20260611203537.1786399-3-andriy.shevchenko@linux.intel.com>

On Thu, Jun 11, 2026 at 10:35 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> In a couple of functions code can be made cleaner with help of
> __free() macro. Refactor these to use RAII approach.
>
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
>  drivers/base/property.c | 22 ++++++++--------------
>  1 file changed, 8 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/base/property.c b/drivers/base/property.c
> index f7b30d9c8716..808e8a90c125 100644
> --- a/drivers/base/property.c
> +++ b/drivers/base/property.c
> @@ -7,10 +7,10 @@
>   *          Mika Westerberg <mika.westerberg@linux.intel.com>
>   */
>
> +#include <linux/cleanup.h>
>  #include <linux/device.h>
>  #include <linux/err.h>
>  #include <linux/export.h>
> -#include <linux/kconfig.h>
>  #include <linux/of.h>
>  #include <linux/property.h>
>  #include <linux/phy.h>
> @@ -517,7 +517,6 @@ EXPORT_SYMBOL_GPL(fwnode_property_read_string);
>  int fwnode_property_match_string(const struct fwnode_handle *fwnode,
>         const char *propname, const char *string)
>  {
> -       const char **values;
>         int nval, ret;
>
>         nval = fwnode_property_string_array_count(fwnode, propname);
> @@ -527,20 +526,18 @@ int fwnode_property_match_string(const struct fwnode_handle *fwnode,
>         if (nval == 0)
>                 return -ENODATA;
>
> -       values = kcalloc(nval, sizeof(*values), GFP_KERNEL);
> +       const char **values __free(kfree) = kcalloc(nval, sizeof(*values), GFP_KERNEL);
>         if (!values)
>                 return -ENOMEM;
>
>         ret = fwnode_property_read_string_array(fwnode, propname, values, nval);
>         if (ret < 0)
> -               goto out_free;
> +               return ret;
>
>         ret = match_string(values, nval, string);
>         if (ret < 0)
> -               ret = -ENODATA;
> +               return -ENODATA;
>
> -out_free:
> -       kfree(values);
>         return ret;
>  }
>  EXPORT_SYMBOL_GPL(fwnode_property_match_string);
> @@ -1128,8 +1125,9 @@ struct fwnode_handle *
>  fwnode_graph_get_next_endpoint(const struct fwnode_handle *fwnode,
>                                struct fwnode_handle *prev)
>  {
> -       struct fwnode_handle *ep, *port_parent = NULL;
>         const struct fwnode_handle *parent;
> +       struct fwnode_handle *port_parent __free(fwnode_handle) = NULL;

The thing on the right-hand side of the assignment should be a
constructor, shouldn't it?

> +       struct fwnode_handle *ep;
>
>         /*
>          * If this function is in a loop and the previous iteration returned
> @@ -1147,13 +1145,9 @@ fwnode_graph_get_next_endpoint(const struct fwnode_handle *fwnode,
>
>         ep = fwnode_call_ptr_op(parent, graph_get_next_endpoint, prev);
>         if (ep)
> -               goto out_put_port_parent;
> +               return ep;
>
> -       ep = fwnode_graph_get_next_endpoint(parent->secondary, NULL);
> -
> -out_put_port_parent:
> -       fwnode_handle_put(port_parent);
> -       return ep;
> +       return fwnode_graph_get_next_endpoint(parent->secondary, NULL);
>  }
>  EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint);
>
> --
> 2.50.1
>

^ permalink raw reply

* Re: [PATCH v3 0/2] device property: fix child iteration issues with secondary fwnodes
From: Andy Shevchenko @ 2026-06-11 20:36 UTC (permalink / raw)
  To: Xu Yang
  Cc: Daniel Scally, Heikki Krogerus, Sakari Ailus, Greg Kroah-Hartman,
	Rafael J. Wysocki, Danilo Krummrich, Mauro Carvalho Chehab,
	Laurent Pinchart, linux-acpi, driver-core, linux-kernel,
	Bartosz Golaszewski, Xu Yang, stable
In-Reply-To: <aipsAxc4j68D2YCz@ashevche-desk.local>

On Thu, Jun 11, 2026 at 11:04:25AM +0300, Andy Shevchenko wrote:
> On Mon, Jun 08, 2026 at 10:41:45AM +0800, Xu Yang wrote:
> > On Fri, Jun 05, 2026 at 06:52:49PM +0300, Andy Shevchenko wrote:
> > > On Fri, Jun 05, 2026 at 06:07:41PM +0300, Andy Shevchenko wrote:
> > > > On Fri, Jun 05, 2026 at 06:31:16PM +0800, Xu Yang wrote:
> > > > > This series fixes two issues in the fwnode child iteration logic when
> > > > > a secondary fwnode is present.
> > > > > 
> > > > > The first issue is  a refcount imbalance in software_node_get_next_child().
> > > > > When a software node is used as a secondary fwnode, the iteration code may
> > > > > incorrectly decrement the refcount of child nodes that do not belong to the
> > > > > software node hierarchy. This results in refcount underflow and possible
> > > > > use-after-free.
> > > > > 
> > > > > The second issue is an infinite loop in fwnode_for_each_child_node(), caused
> > > > > by improper handling of iteration state across primary and secondary fwnodes.
> > > > > When iterating over children from both primary and secondary fwnodes, the code
> > > > > may incorrectly resume iteration from the primary fwnode even when the current
> > > > > child belongs to the secondary, leading to repeated traversal and a loop.
> > > > > 
> > > > > Both issues are triggered when mixing different fwnode types through the
> > > > > secondary mechanism, and stem from incorrect assumptions about ownership
> > > > > and traversal context of child nodes.
> > > > 
> > > > > ---
> > > > > Changes in v3:
> > > > > - remove software node patch 
> > > > 
> > > > Hmm... Maybe I was unclear. My question was to investigate the way to actually
> > > > move software node to use the swnode APIs (and not fwnode ones) and be on par
> > > > with what OF code does. This series does the opposite and adds a hack to the
> > > > next_child implementation.
> > > > 
> > > > > - add a kunit test case suggested by Andy Shevchenko
> > > > 
> > > > But thanks for the test case!
> > > 
> > > I'm preparing another patch (just a clean up) and I see that your test cases
> > > indeed fail without any other patch being applied. Also noticed that the test
> > > cases are not fully compliant with the requirement of the "primary"/"secondary"
> > > fwnode flavours. But this doesn't affect the execution.
> > > 
> > > I will play more with this to understand the problem better.
> > 
> > OK. Suggestions on the fwnode flavours would be appreciated :)
> 
> I think your approach is what we should go with. I will send a v4 with my tags
> and some amendments.

I sent a v4 here:
20260611203537.1786399-1-andriy.shevchenko@linux.intel.com
Please, test and confirm it also works for you as expected.

-- 
With Best Regards,
Andy Shevchenko



^ 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