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: