All of lore.kernel.org
 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; 11+ 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 related	[flat|nested] 11+ messages in thread

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

Thread overview: 11+ 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-22 10:04             ` Support TRINITY
2026-09-21 18:03     ` Rafael J. Wysocki (Intel)

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.