[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#550392: firmware-linux: Radeon kernel modesetting requires pre-initramfs firmware loading



Package: firmware-linux
Version: 0.18
Severity: wishlist
Tags: patch

(Yes I know, I'm way ahead of the curve. Since I had to tackle this problem, I figured I might just as well publish my results)

Starting with kernel 2.6.32, the radeon in-kernel driver will stall the boot process while waiting for the microcode to be supplied. The 2.6.31 kernel did not do this (was it in-kernel before?). I'm using kernel modesetting, and have not tried the non-kms case but I suspect it will stall as well (but maybe later in the boot process). Entries in dmesg look like:

[    0.316326] [drm] Loading R300 Microcode
[    0.316332] platform radeon_cp.0: firmware: requesting radeon/R300_cp.bin
[   60.316136] radeon_cp: Failed to load firmware "radeon/R300_cp.bin"
[   60.316177] [drm:r100_cp_init] *ERROR* Failed to load firmware!
[...]
[   60.318534] [drm] Forcing AGP to PCI mode
[   60.318847] [drm] GPU reset succeed (RBBM_STATUS=0x00000140)
[...]
[   60.319458] [drm] Loading R300 Microcode
[   60.319463] platform radeon_cp.0: firmware: requesting radeon/R300_cp.bin
[  120.316114] radeon_cp: Failed to load firmware "radeon/R300_cp.bin"
[  120.316156] [drm:r100_cp_init] *ERROR* Failed to load firmware!
[  120.316194] radeon 0000:01:00.0: failled initializing CP (-2).
[  120.316230] radeon 0000:01:00.0: Disabling GPU acceleration

So the machine will appear to hang for two minutes. The regular firmware loading sequences do not appear to work when KMS is enabled (radeon.modeset=1), because the kernel will only try to load this firmware once: before running /init !

This means that even when the firmware and the udev firmware agent are available in the initramfs, the firmware load will fail because /sys isn't mounted yet. And without /sys, there is no way to abort the firmware load either.

I'm attaching the script I use to get around this issue. Basically, what I'm doing is reproducing part of the initialization performed by /init before spawning the Udev firmware agent. I'm not really sure what to do about /sys though: the current implementation introduces a race condition where /sys might get unmounted after /init has run. It might be better to just leave /sys mounted and have /init mount it again, but I'm not sure about the implications (my tests showed no negative consequences). This script must be installed as /sbin/hotplug - no code has run yet to alter the path to the hotplug event manager...

I'm filing this against firmware-linux because that's where the Radeon firmware lives. If there is a better place where this should be fixed, please feel free to redirect. And if you already have a better solution in place, feel free to ignore me :)


-- System Information:
Debian Release: squeeze/sid
  APT prefers testing
  APT policy: (800, 'testing'), (550, 'stable'), (101, 'unstable'), (100, 'experimental')
Architecture: i386 (i686)

Kernel: Linux 2.6.32-rc3 (PREEMPT)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8) (ignored: LC_ALL set to en_US.UTF-8)
Shell: /bin/sh linked to /bin/dash

firmware-linux depends on no packages.

firmware-linux recommends no packages.

Versions of packages firmware-linux suggests:
ii  initramfs-tools               0.93.4     tools for generating an initramfs
ii  linux-image-2.6.30-2-686 [lin 2.6.30-8   Linux 2.6.30 image on PPro/Celeron
ii  linux-image-2.6.31-rc9 [linux 20090909   Linux kernel binary image for vers
ii  linux-image-2.6.32-rc3 [linux 20091008   Linux kernel binary image for vers

-- no debconf information
#!/bin/sh
#
## Simple firmware hotplug handler. When kernel modesetting is enabled for ATi
## Radeon graphics cards, the firmware load is triggered even before running
## /init (but still after initramfs is unpacked). This means that the hotplug
## script itself becomes responsible for mounting /sys, because otherwise the
## firmware can't be loaded.
## Ignoring the firmware request is not an option - the kernel will simply keep
## waiting for data until the timeout has passed, which is 60 seconds by
## default. Aborting the firmware load can be performed by echo'ing -1 to the
## firmware control file, but that also requires /sys to be mounted.

# no console - messages won't be visible
#echo "HOTPLUG Loading, please wait..."


# only respond to firmware requests
if [ -n "$FIRMWARE" ]; then
	MTSYS=
	[ -d /sys ] || mkdir /sys
	[ -d /sys/kernel ] || MTSYS=1
	[ -z "$MTSYS" ] || mount -t sysfs -o nodev,noexec,nosuid none /sys

	# try the udev firmware loader first
	if [ -x /lib/udev/firmware.agent ]; then
		. /lib/udev/firmware.agent
	else
		# poor-man's loader script
		if [ -r /lib/firmware/$FIRMWARE ]; then
			echo 1 > /sys/$DEVPATH/loading
			cat /lib/firmware/$FIRMWARE > /sys/$DEVPATH/data
			echo 0 > /sys/$DEVPATH/loading
		else
			echo -1 > /sys/$DEVPATH/loading
		fi
	fi
	# perform cleanup so as not to confuse /init
	[ -z "$MTSYS" ] || umount /sys
fi


exit 0


Reply to: