mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [REGRESSION] ACPI processor/cpuidle change in 6.18.52 breaks bare-metal Xen dom0 boot
@ 2026-09-20 15:48 Support TRINITY
  2026-09-21 10:00 ` Thorsten Leemhuis
  2026-09-21 15:26 ` Rafael J. Wysocki (Intel)
  0 siblings, 2 replies; 10+ messages in thread
From: Support TRINITY @ 2026-09-20 15:48 UTC (permalink / raw)
  To: regressions, linux-acpi, linux-pm, stable, xen-devel, linux-kernel


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

 
 
 

Hello, 

I am reporting a bare-metal Xen dom0 boot regression seen with Linux 6.18.52. 

On affected systems, Linux 6.18.51 boots successfully as Xen dom0 on bare metal, while Linux 6.18.52 consistently black-screens before dom0 userspace/networking comes up. 

#regzbot introduced: v6.18.51..v6.18.52
#regzbot title: ACPI processor/cpuidle lifecycle change breaks bare-metal Xen dom0 boot
#regzbot link: https://gitlab.alpinelinux.org/alpine/aports/-/work_items/18447 

Tested results: 
 
  - Linux 6.18.51-r0, Xen dom0, bare metal: boots 
  - Linux 6.18.52-r0, Xen dom0, bare metal: black screen before userspace/network 
  - Linux 6.18.52-r0, Xen domU: boots 
  - Linux 6.18.52-r0 with Xenbus notifier change reverted: still fails 
  - Linux 6.18.52-r0 with only ACPI processor/cpuidle changes reverted: boots 
  - Linux 6.18.52-r0 with refined ACPI idle lifecycle patch: boots  

Affected hardware tested: 
 
  - Intel Core i7-4785T thin mini-ITX, 16 GB DDR3 
  - Intel N305 thin mini-ITX, 16 GB DDR5 
  - Supermicro / Intel Xeon E5-1650, 32 GB DDR3  

The successful boot used the regular Xen command line: 

multiboot2 /boot/xen.gz cpufreq=xen:performance
module2 /boot/vmlinuz-lts modules=loop,squashfs,sd-mod,usb-storage,xfs quiet
module2 /boot/initramfs-lts 

No IOMMU workaround, serial console parameter, debug parameter, storage workaround, or Xen command-line change was required. 

The regression was narrowed to ACPI processor/cpuidle changes between 6.18.51 and 6.18.52, specifically the idle-driver registration lifecycle. 

The working 6.18.51-style behavior registers the ACPI idle driver from acpi_processor_power_init() and unregisters it from acpi_processor_power_exit(). 

The failing 6.18.52 behavior registers the ACPI idle driver globally from acpi_processor_driver_init() before driver_register(). 

A first ACPI-only revert confirmed the regression source. A refined candidate patch was then prepared to preserve the working ACPI idle lifecycle while keeping unrelated 6.18.52 safety fixes, including: 
 
  - _LPI bounds checks 
  - cpufreq notifier cleanup on acpi_processor_driver_init() failure  

The refined candidate patch modifies only: 
   - drivers/acpi/processor_driver.c   - drivers/acpi/processor_idle.c   - include/acpi/processor.h  

It does not modify Xen, Xenbus, IOMMU, APIC, PCI/ASPM, intel_idle, syscore, USB, storage, XFS, networking, printk, or the cpuidle core API. 

The earlier cpuidle_disabled() workaround is not included. 

The refined patch has been rebuilt and boot-tested successfully as Xen dom0 on bare metal on TRINITY-EDGE. 

This issue is currently visible to Alpine users because the Alpine v3.24 stable repository contains: 

alpine-release 3.24.2-r0
linux-lts 6.18.52-r0 

Systems tracking Alpine 3.24 stable / latest-stable may therefore receive Linux 6.18.52 as the default LTS kernel. 

Attachments: 
 
  - revert-acpi-idle-registration-lifecycle.patch 
  - APKBUILD  

The original Alpine report is here: 

https://gitlab.alpinelinux.org/alpine/aports/-/work_items/18447 

Please let me know if this should be submitted as a formal patch with Signed-off-by, or if there is a better upstream fix/dependency that should be backported instead. 

Regards,

Tony BONNIN   
 

[-- Attachment #1.2: Type: text/html, Size: 4372 bytes --]

[-- Attachment #2: APKBUILD --]
[-- Type: text/plain, Size: 13937 bytes --]

# Maintainer: Natanael Copa <ncopa@alpinelinux.org>

_flavor=${FLAVOR:-lts}
pkgname=linux-$_flavor
pkgver=6.18.52
_kernver=${pkgver%.*}
pkgrel=0
pkgdesc="Linux lts kernel"
url="https://www.kernel.org"
depends="initramfs-generator"
_depends_dev="perl gmp-dev mpc1-dev mpfr-dev elfutils-dev bash flex bison zstd"
makedepends="$_depends_dev sed installkernel bc linux-headers linux-firmware-any openssl-dev>3 mawk
	diffutils elfutils findutils zstd pahole python3 gcc>=13.1.1_git20230624 bpftool"
options="!strip !check"
source="https://cdn.kernel.org/pub/linux/kernel/v${pkgver%%.*}.x/linux-$_kernver.tar.xz
	0001-powerpc-boot-wrapper-Add-z-notext-flag-for-ppc64le.patch
	0002-x86-Compress-vmlinux-with-zstd-19-instead-of-22.patch
	0003-kexec-add-kexec_load_disabled-boot-option.patch
	0004-objtool-respect-AWK-setting.patch
	0005-powerpc-config-defang-gcc-check-for-stack-protector-.patch
	0001-x86-CPU-AMD-avoid-printing-reset-reasons-on-Xen-domU.patch
	revert-acpi-idle-registration-lifecycle.patch
	sophgo-fixes.patch

	lts.aarch64.config
	lts.armv7.config
	lts.loongarch64.config
	lts.ppc64le.config
	lts.riscv64.config
	lts.s390x.config
	lts.x86.config
	lts.x86_64.config

	virt.aarch64.config
	virt.armv7.config
	virt.ppc64le.config
	virt.x86.config
	virt.x86_64.config
	"

# Allow adding custom flavor config via FLAVOR var
# The config file should be named ${FLAVOR}.${CARCH}.config
if [ -n "$FLAVOR" ]; then
	source="$source
	${FLAVOR}.${CARCH}.config"
fi

subpackages="$pkgname-dev:_dev:$CBUILD_ARCH $pkgname-doc"
for _i in $source; do
	case $_i in
	*.$CARCH.config)
		_f=${_i%."$CARCH".config}
		if [ -n "$FLAVOR" ] && [ "$_f" != "$FLAVOR" ]; then
			# skip flavors that don't match
			continue
		fi
		_flavors="$_flavors $_f"
		if [ "linux-$_f" != "$pkgname" ]; then
			subpackages="$subpackages linux-$_f::$CBUILD_ARCH linux-$_f-dev:_dev:$CBUILD_ARCH"
		fi
		;;
	esac
done
builddir="$srcdir"/linux-$_kernver

if [ "${pkgver%.0}" = "$pkgver" ]; then
	# Prepend to apply first
	source="patch-$pkgver.patch.xz::https://cdn.kernel.org/pub/linux/kernel/v${pkgver%%.*}.x/patch-$pkgver.xz $source"
fi
arch="all !armhf"
license="GPL-2.0-only"

# secfixes are not tracked
# https://gitlab.alpinelinux.org/alpine/aports/-/work_items/18194

prepare() {
	default_prepare

	# remove localversion from patch if any
	rm -f localversion*
}

_kernelarch() {
	local arch="$1"
	case "$arch" in
		aarch64*) arch="arm64" ;;
		arm*) arch="arm" ;;
		ppc*) arch="powerpc" ;;
		s390*) arch="s390" ;;
		riscv*) arch="riscv" ;;
		loongarch64) arch="loongarch" ;;
	esac
	echo "$arch"
}

_prepareconfig() {
	local _flavor="$1"
	local _arch="$2"
	local _config=$_flavor.$_arch.config
	local _builddir="$srcdir"/build-$_flavor.$_arch
	mkdir -p "$_builddir"
	echo "-$pkgrel-$_flavor" > "$_builddir"/localversion-alpine

	cp "$srcdir"/$_config "$_builddir"/.config
	msg "Configuring $_flavor kernel ($_arch)"
	make -C "$builddir" \
		O="$_builddir" \
		ARCH="$(_kernelarch $_arch)" \
		olddefconfig

	if grep "CONFIG_MODULE_SIG=y" "$_builddir"/.config >/dev/null; then
		if [ -f "$KERNEL_SIGNING_KEY" ]; then
			sed -i -e "s:^CONFIG_MODULE_SIG_KEY=.*:CONFIG_MODULE_SIG_KEY=\"$KERNEL_SIGNING_KEY\":" \
				"$_builddir"/.config
			msg "Using $KERNEL_SIGNING_KEY to sign $_flavor kernel ($_arch) modules"
		else
			warning "KERNEL_SIGNING_KEY was not set. A signing key will be generated, but 3rd"
			warning "party modules can not be signed"
		fi
	fi
}

listconfigs() {
	for i in $source; do
		case "$i" in
			*.config) echo $i;;
		esac
	done
}

prepareconfigs() {
	for _config in $(listconfigs); do
		local _flavor=${_config%%.*}
		local _arch=${_config%.config}
		_arch=${_arch#*.}
		local _builddir="$srcdir"/build-$_flavor.$_arch
		_prepareconfig "$_flavor" "$_arch"
	done
}

# this is supposed to be run before version is bumped so we can compare
# what new kernel config knobs are introduced
prepareupdate() {
	clean && fetch && unpack && prepare && deps
	prepareconfigs
	rm -r "$builddir"
}

updateconfigs() {
	if ! [ -d "$builddir" ]; then
		deps && fetch && unpack && prepare
	fi
	for _config in ${CONFIGS:-$(listconfigs)}; do
		msg "updating $_config"
		local _flavor=${_config%%.*}
		local _arch=${_config%.config}
		_arch=${_arch#*.}
		local _builddir="$srcdir"/build-$_flavor.$_arch
		mkdir -p "$_builddir"
		echo "-$pkgrel-$_flavor" > "$_builddir"/localversion-alpine
		local actions="listnewconfig oldconfig"
		if ! [ -f "$_builddir"/.config ]; then
			cp "$srcdir"/$_config "$_builddir"/.config
			actions="olddefconfig"
		fi
		env | grep ^CONFIG_ >> "$_builddir"/.config || true
		make -j1 -C "$builddir" \
			O="$_builddir" \
			ARCH="$(_kernelarch $_arch)" \
			$actions savedefconfig

		cp "$_builddir"/defconfig "$startdir"/$_config
	done
}

set_kbuild_timestamp() {
	# KBUILD_BUILD_TIMESTAMP needs to be parsable by busybox date
	export KBUILD_BUILD_TIMESTAMP="$(date '+%Y-%m-%d %H:%M:%S' -u${SOURCE_DATE_EPOCH:+d @$SOURCE_DATE_EPOCH})"
}

build() {
	unset LDFLAGS
	# for some reason these sometimes leak into the kernel build,
	# -Werror=format-security breaks some stuff
	unset CFLAGS CPPFLAGS CXXFLAGS
	set_kbuild_timestamp
	for i in $_flavors; do
		_prepareconfig "$i" "$CARCH"
	done
	for i in $_flavors; do
		msg "Building $i kernel"
		cd "$srcdir"/build-$i.$CARCH

		# set org in cert for modules signing
		# https://www.kernel.org/doc/html/v6.1/admin-guide/module-signing.html#generating-signing-keys
		mkdir -p certs
		sed -e 's/#O = Unspecified company/O = alpinelinux.org/' \
			"$builddir"/certs/default_x509.genkey \
			> certs/x509.genkey

		make ARCH="$(_kernelarch $CARCH)" \
			CC="${CC:-gcc}" \
			AWK="${AWK:-mawk}" \
			KBUILD_BUILD_VERSION="$((pkgrel + 1 ))-Alpine"

		if grep -q '^CONFIG_DEBUG_INFO_BTF=y' .config; then
			# Generate vmlinux.h
			bpftool btf dump file vmlinux format c > vmlinux.h

			if [ "$CARCH" = "ppc64le" ]; then
				# ppc64le installs the uncompressed vmlinux, which is extremely
				# large with BTF debuginfo unless stripped
				eu-strip --remove-comment vmlinux
			fi
		fi
	done
}

_package() {
	local _buildflavor="$1" _outdir="$2"
	set_kbuild_timestamp

	cd "$srcdir"/build-$_buildflavor.$CARCH
	local _abi_release="$(make -s kernelrelease)"
	# modules_install seems to regenerate a defect Modules.symvers on s390x. Work
	# around it by backing it up and restore it after modules_install
	cp Module.symvers Module.symvers.backup

	mkdir -p "$_outdir"/boot "$_outdir"/lib/modules

	local _install
	case "$CARCH" in
		arm*|aarch64|riscv*) _install="zinstall dtbs_install";;
		*) _install=install;;
	esac

	make modules_install $_install \
		ARCH="$(_kernelarch $CARCH)" \
		INSTALL_MOD_PATH="$_outdir" \
		INSTALL_MOD_STRIP=1 \
		INSTALL_PATH="$_outdir"/boot \
		INSTALL_DTBS_PATH="$_outdir/boot/dtbs-$_buildflavor"

	cp Module.symvers.backup Module.symvers

	rm -f "$_outdir"/lib/modules/"$_abi_release"/build \
		"$_outdir"/lib/modules/"$_abi_release"/source
	rm -rf "$_outdir"/lib/firmware

	install -D -m644 include/config/kernel.release \
		"$_outdir"/usr/share/kernel/$_buildflavor/kernel.release

	ln -sf /boot/vmlinuz-"$_buildflavor" \
		"$_outdir"/lib/modules/"$_abi_release"/vmlinuz
}

# main flavor installs in $pkgdir
package() {
	depends="$depends linux-firmware-any"

	_package "$_flavor" "$pkgdir"

	# copy files for linux-lts-doc sub package
	mkdir -p "$pkgdir"/usr/share/doc
	cp -r "$builddir"/Documentation \
		"$pkgdir"/usr/share/doc/linux-doc-"$pkgver"/
	# remove files that aren't part of the documentation itself
	for nondoc in \
		.gitignore conf.py docutils.conf \
		Kconfig Makefile
	do
		rm "$pkgdir"/usr/share/doc/linux-doc-"$pkgver"/"$nondoc"
	done
	# create /usr/share/doc/linux-doc symlink
	cd "$pkgdir"/usr/share/doc; ln -s linux-doc-"$pkgver" linux-doc
}

# subflavors install in $subpkgdir
virt() {
	_package virt "$subpkgdir"
}

_dev() {
	local _flavor=$(echo $subpkgname | sed -E 's/(^linux-|-dev$)//g')
	local _builddir="$srcdir"/build-$_flavor.$CARCH
	local _abi_release="$(make -C "$_builddir" -s kernelrelease)"
	local _karch="$(_kernelarch $CARCH | sed 's/x86_64/x86/')"
	# copy the only the parts that we really need for build 3rd party
	# kernel modules and install those as /usr/src/linux-headers,
	# simlar to what ubuntu does
	#
	# this way you dont need to install the 300-400 kernel sources to
	# build a tiny kernel module
	#
	pkgdesc="Headers and script for third party modules for $_flavor kernel"
	depends="$_depends_dev"
	local dir="$subpkgdir"/usr/src/linux-headers-"$_abi_release"
	set_kbuild_timestamp

	# first we import config, run prepare to set up for building
	# external modules, and create the scripts
	mkdir -p "$dir"
	cp -a "$_builddir"/.config "$_builddir"/localversion-alpine \
		"$dir"/

	install -D -t "$dir"/certs "$_builddir"/certs/signing_key.x509 || :

	# Install vmlinux.h
	if grep -q '^CONFIG_DEBUG_INFO_BTF=y' "$_builddir"/.config; then
		install -Dm644 "$_builddir"/vmlinux.h -t "$dir/"
	fi

	make -C "$builddir" \
		O="$dir" \
		ARCH="$(_kernelarch $CARCH)" \
		AWK="${AWK:-mawk}" \
		prepare modules_prepare scripts

	# remove the stuff that points to real sources. we want 3rd party
	# modules to believe this is the sources
	rm "$dir"/Makefile "$dir"/source

	# copy the needed stuff from real sources
	#
	# this is taken from ubuntu kernel build script
	# http://kernel.ubuntu.com/git/ubuntu/ubuntu-zesty.git/tree/debian/rules.d/3-binary-indep.mk
	cd "$builddir"
	find .  -path './include/*' -prune \
		-o -path './scripts/*' -prune -o -type f \
		\( -name 'Makefile*' -o -name 'Kconfig*' -o -name 'Kbuild*' -o \
		   -name '*.sh' -o -name '*.pl' -o -name '*.lds' -o -name 'Platform' \) \
		-print | cpio -pdm "$dir"

	cp -a scripts include "$dir"

	find "arch/$_karch" "tools/include" "tools/arch/$_karch" -type f -path '*/include/*' \
		-print | cpio -pdm "$dir"

	install -Dm644 "$srcdir"/build-$_flavor.$CARCH/Module.symvers \
		"$dir"/Module.symvers

	# remove unneeded things
	msg "Removing documentation..."
	rm -r "$dir"/Documentation
	sed -i -e '/Documentation/d' "$dir"/Kconfig
	find "$dir" -type f \( -name '*.o' -o -name '*.cmd' \) -exec rm -v -- {} +

	mkdir -p "$subpkgdir"/lib/modules/"$_abi_release"
	ln -sf /usr/src/linux-headers-"$_abi_release" \
		"$subpkgdir"/lib/modules/"$_abi_release"/build
}

sha512sums="
f1c32303a8eb7f20c7f5c8d592a23140ff880075d0e4151bf96d5b0365ff64b35324753894d8ba822ad797e673b2a878f18d6a2f557dd6d3aca1fcc8d4e5764d  patch-6.18.52.patch.xz
88599ffdec96d150c1feb9b261ba93bb0301a9d0e1ad6bef7aeab1f5372cbfc57d8b43c7e902bd8f76921d1dbd8189663c142ea869e51d0e2b483b150ee00fe0  linux-6.18.tar.xz
b296717ef0cd63978142b4d47b3bc49faa04daf77e115e702ba611cc254a6e782cdab7d5639e724cd5f029cfb6a3dc33c3036f346d681d1fdfe0df723c7e0321  0001-powerpc-boot-wrapper-Add-z-notext-flag-for-ppc64le.patch
055e10e7b3e00bb3621389315d5206a8feb5022a1f0dc51c3aa107facfe83d191da05a502a0c62488be7299677a63c1da84f87c42cbf3125788c56db67e810ee  0002-x86-Compress-vmlinux-with-zstd-19-instead-of-22.patch
e1d2d5358f5b8189236108973395f00eafce8db6d5baaf55025b1360f08ab7cffc930d3818719f220b98e7e8541cc8a7f056611b6e290f224a102c1addbe34ac  0003-kexec-add-kexec_load_disabled-boot-option.patch
28c83be4c97152001381cd5e3a8acb8552a42d9dac9aaec8f096e3762b7944035aa5a4363fb4602f9bb427c4f72cfd2f996a0a725f7f9e07ab250317985aff9e  0004-objtool-respect-AWK-setting.patch
5ce79416f8f111c36393718656e3eeb4cb0adccd117dcf661876d1564010e5c58b6351cc4116d187d0a9a838bcca0fecc236d81ac71afb940b89ccb14f21e179  0005-powerpc-config-defang-gcc-check-for-stack-protector-.patch
4e72af8e77a555d2a850837b64a525a51d5d118048584dc3ea0d0e8620bb56bf56b69a94aa67dac879b841c9ba033e33d94610da0028fde7b6602ad2fe63f02f  0001-x86-CPU-AMD-avoid-printing-reset-reasons-on-Xen-domU.patch
f5c9c99e637eb47c582e2db57c2609be803c6d6037717a949a0dd181ba50cd4ea19678da81ded9de737e1669ca81f371a4809258a71eb7fef73e46212b1cdfab  revert-acpi-idle-registration-lifecycle.patch
855522b816bbb2b0738251cf24714c2566c7aacad39aaf6adcebd0a256d11f64ff2762ecdace0ab1bac38db87fd579863f852f799356a368f057c166e4deb03c  sophgo-fixes.patch
fc69158d31d9d3c951d057aee01397f46c5a72462334f14b79aa538294c1900338bc6af154c9bda051fb29eff11541d8c1893d735a12b7bafb86cdb0f98a5485  lts.aarch64.config
e8036dc7b74ffa09f84c0d13246a637aa7326df3da3729a158177be9b47036ff06d5ded2886b567b55fac44dcb937ca7271751ca5dc5a7bfed5a91df1ecaf4ce  lts.armv7.config
6b2af88167234828c9793aeefc8ccc0ed5ae7d6814bbaff30a91c0b336b95e2008697608c9630e8507a493e02d3a7fc798e490467eac969ede14db9b92e21e17  lts.loongarch64.config
77a84a8a3b1ae289fe88aef9183f2eafc49379f55e7745700534801a56c0f7f0d900af19a231d25e48c7acab46f23a88df15044d9efe4ff16881c43984cdc40c  lts.ppc64le.config
2bf106cd7ddc04dcb69c69ae73e9a1f95b964190301c272856ea7ee68820d77aceaa90ededa741da0ec9355fc942ad9647ef3e3c49b232455d93a4f727b8bcd9  lts.riscv64.config
34622b02baf05ac9f9dfa3cbcd817368b9ea0bc2056a55e4cab770e0e0100f8cdc9ddb0b68bbdfe381f6f3d8b1a81bbd55f56db43a824b691f8788907ed6fa23  lts.s390x.config
33903e3a877734ab5f3fd2b03589817dc996f5114e66a34abe30ae137b61de6960478fd4d33174da319939bf4b77d7aba809ccf5566acf46946fca476f03e35f  lts.x86.config
32db10060987654c515342eabad99ff68471aca739159a6dcbf79b2157e0dbe15138be67bd25acf326eae13e1790f07c77f179e3f21f9ba9ffd340a91006d5cd  lts.x86_64.config
ffbe61069184a46baf90cbffeba5512df7e0d0b11c2404f629ad698bdfb6199269618013abdc2895a9bc960bb5e0425ee4f8a928fca08aae5b5ff97e49023e3f  virt.aarch64.config
77b6dfe665ddd3a896a4a9e7807d6d2aff7d3270eb98a7342cd08a5304446a62d4755ad80e5a0df404e1809738f5b9e82201743289c3348993074d723b5990c1  virt.armv7.config
7145644f2950ff16a158060cb4266431b3f696bfba23bc84d570e8135889024f3e92cdeac61bdf4ff490cf0e6f0065ca7ebd0508efff6a91e1eab8e6f655eef4  virt.ppc64le.config
6acc6d3e54a70eb8cfc35da824589ad45167c1380e0c4a01bc479f965a24de9c07ec17c7e5ba045a9ce0a11a7858ff1659eac9888ebb6174c6bdd341e514b834  virt.x86.config
0da34fd867f797004369e75157e764604093d1ae957fc686fe2343ecb30a271bc5c0ad876526fe5954cf5bf6e3affb71dba3a802f9089271cd51e1c2fa411201  virt.x86_64.config
"

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: revert-acpi-idle-registration-lifecycle.patch --]
[-- Type: text/x-diff; name=revert-acpi-idle-registration-lifecycle.patch, Size: 6521 bytes --]

Revert the ACPI idle driver registration lifecycle introduced by upstream
commit 13ebeef6a1b9 ("ACPI: processor: idle: Optimize ACPI idle driver
registration").

That change moved ACPI idle driver registration out of
acpi_processor_power_init() and ahead of driver_register(). This breaks the
established lifecycle on Xen dom0, where cpuidle is disabled during early
architecture setup. Restore the 6.18.51 per-processor registration behavior.

Keep unrelated 6.18.52 fixes, notably _LPI bounds validation and cpufreq
notifier cleanup on initialization failure.

diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index 06589bf48..174dfb0ac 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -259,11 +259,9 @@ static int __init acpi_processor_driver_init(void)
 		acpi_processor_ignore_ppc_init();
 	}
 
-	acpi_processor_register_idle_driver();
-
 	result = driver_register(&acpi_processor_driver);
 	if (result < 0)
-		goto unregister_idle_drv;
+		goto unregister_cpufreq;
 
 	result = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
 				   "acpi/cpu-drv:online",
@@ -289,9 +287,7 @@ static int __init acpi_processor_driver_init(void)
 err:
 	driver_unregister(&acpi_processor_driver);
 
-unregister_idle_drv:
-	acpi_processor_unregister_idle_driver();
-
+unregister_cpufreq:
 	if (acpi_processor_cpufreq_init) {
 		cpufreq_unregister_notifier(&acpi_processor_notifier_block,
 					    CPUFREQ_POLICY_NOTIFIER);
@@ -315,7 +311,6 @@ static void __exit acpi_processor_driver_exit(void)
 	cpuhp_remove_state_nocalls(hp_online);
 	cpuhp_remove_state_nocalls(CPUHP_ACPI_CPUDRV_DEAD);
 	driver_unregister(&acpi_processor_driver);
-	acpi_processor_unregister_idle_driver();
 }
 
 module_init(acpi_processor_driver_init);
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 5c6f736ba..7b4e948fa 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -831,13 +831,19 @@ static int acpi_processor_setup_cstates(struct acpi_processor *pr)
 	return 0;
 }
 
-static inline void acpi_processor_update_max_cstate(void)
+static inline void acpi_processor_cstate_first_run_checks(void)
 {
+	static int first_run;
+
+	if (first_run)
+		return;
 	dmi_check_system(processor_power_dmi_table);
 	max_cstate = acpi_processor_cstate_check(max_cstate);
 	if (max_cstate < ACPI_C_STATES_MAX)
 		pr_notice("processor limited to max C-state %d\n", max_cstate);
 
+	first_run++;
+
 	if (nocst)
 		return;
 
@@ -846,7 +852,7 @@ static inline void acpi_processor_update_max_cstate(void)
 #else
 
 static inline int disabled_by_idle_boot_param(void) { return 0; }
-static inline void acpi_processor_update_max_cstate(void) { }
+static inline void acpi_processor_cstate_first_run_checks(void) { }
 static int acpi_processor_get_cstate_info(struct acpi_processor *pr)
 {
 	return -ENODEV;
@@ -1365,59 +1371,7 @@ int acpi_processor_power_state_has_changed(struct acpi_processor *pr)
 	return 0;
 }
 
-void acpi_processor_register_idle_driver(void)
-{
-	struct acpi_processor *pr;
-	int ret = -ENODEV;
-	int cpu;
-
-	/*
-	 * If a cpuidle driver is already registered, there is no need to
-	 * evaluate _CST or attempt to register the ACPI idle driver.
-	 */
-	if (cpuidle_get_driver()) {
-		pr_debug("cpuidle driver %pS already registered.\n", cpuidle_get_driver());
-		return;
-	}
-
-	acpi_processor_update_max_cstate();
-
-	/*
-	 * ACPI idle driver is used by all possible CPUs.
-	 * Use the processor power info of one in them to set up idle states.
-	 * Note that the existing idle handler will be used on platforms that
-	 * only support C1.
-	 */
-	for_each_possible_cpu(cpu) {
-		pr = per_cpu(processors, cpu);
-		if (!pr)
-			continue;
-
-		ret = acpi_processor_get_power_info(pr);
-		if (!ret) {
-			pr->flags.power_setup_done = 1;
-			acpi_processor_setup_cpuidle_states(pr);
-			break;
-		}
-	}
-
-	if (ret) {
-		pr_debug("No ACPI power information from any CPUs.\n");
-		return;
-	}
-
-	ret = cpuidle_register_driver(&acpi_idle_driver);
-	if (ret) {
-		pr_debug("register %s failed.\n", acpi_idle_driver.name);
-		return;
-	}
-	pr_debug("%s registered with cpuidle.\n", acpi_idle_driver.name);
-}
-
-void acpi_processor_unregister_idle_driver(void)
-{
-	cpuidle_unregister_driver(&acpi_idle_driver);
-}
+static int acpi_processor_registered;
 
 int acpi_processor_power_init(struct acpi_processor *pr)
 {
@@ -1427,10 +1381,27 @@ int acpi_processor_power_init(struct acpi_processor *pr)
 	if (disabled_by_idle_boot_param())
 		return 0;
 
+	acpi_processor_cstate_first_run_checks();
+
 	if (!acpi_processor_get_power_info(pr))
 		pr->flags.power_setup_done = 1;
 
+	/*
+	 * Install the idle handler if processor power management is supported.
+	 * Note that the existing idle handler is used on platforms that only
+	 * support C1.
+	 */
 	if (pr->flags.power) {
+		/* Register acpi_idle_driver if not already registered */
+		if (!acpi_processor_registered) {
+			acpi_processor_setup_cpuidle_states(pr);
+			retval = cpuidle_register_driver(&acpi_idle_driver);
+			if (retval)
+				return retval;
+			pr_debug("%s registered with cpuidle\n",
+				 acpi_idle_driver.name);
+		}
+
 		dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 		if (!dev)
 			return -ENOMEM;
@@ -1443,11 +1414,14 @@ int acpi_processor_power_init(struct acpi_processor *pr)
 		 */
 		retval = cpuidle_register_device(dev);
 		if (retval) {
+			if (acpi_processor_registered == 0)
+				cpuidle_unregister_driver(&acpi_idle_driver);
 
 			per_cpu(acpi_cpuidle_device, pr->id) = NULL;
 			kfree(dev);
 			return retval;
 		}
+		acpi_processor_registered++;
 	}
 	return 0;
 }
@@ -1461,6 +1435,10 @@ int acpi_processor_power_exit(struct acpi_processor *pr)
 
 	if (pr->flags.power) {
 		cpuidle_unregister_device(dev);
+		acpi_processor_registered--;
+		if (acpi_processor_registered == 0)
+			cpuidle_unregister_driver(&acpi_idle_driver);
+
 		kfree(dev);
 	}
 
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index ff864c1ce..d0eccbd92 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -423,8 +423,6 @@ int acpi_processor_power_init(struct acpi_processor *pr);
 int acpi_processor_power_exit(struct acpi_processor *pr);
 int acpi_processor_power_state_has_changed(struct acpi_processor *pr);
 int acpi_processor_hotplug(struct acpi_processor *pr);
-void acpi_processor_register_idle_driver(void);
-void acpi_processor_unregister_idle_driver(void);
 #else
 static inline int acpi_processor_power_init(struct acpi_processor *pr)
 {


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-09-22  2:23 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-20 15:48 [REGRESSION] ACPI processor/cpuidle change in 6.18.52 breaks bare-metal Xen dom0 boot Support TRINITY
2026-09-21 10:00 ` Thorsten Leemhuis
2026-09-21 13:06   ` Support TRINITY
2026-09-21 15:26 ` Rafael J. Wysocki (Intel)
2026-09-21 16:44   ` Marek Marczykowski-Górecki
2026-09-21 17:46     ` Support TRINITY
2026-09-21 18:05       ` Rafael J. Wysocki (Intel)
2026-09-21 18:29         ` Support TRINITY
2026-09-22  2:23           ` Sasha Levin
2026-09-21 18:03     ` Rafael J. Wysocki (Intel)

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

all inboxes | Powered by JetHome®