Group: Hardware/research/gpu/radeon/How to patch and test linux-libre in Parabola

From LibrePlanet
Jump to: navigation, search

How to patch and test linux-libre in Parabola

Warning: This tutorial is a work in progress and it's not finished yet.

Feel free to help improving it or completing it.

Tutorial status:

  • Risks: DONE
  • Other setup required for testing: DONE
  • First verify if your GPU is supported by the lastest linux-libre: DONE
  • Find the Linux driver file to patch: DONE
  • Patching linux-libre: DONE
  • Deblobing Linux: TODO: Fix style
  • Building linux-libre: TODO: Fix style
  • Installing the modified linux-libre: TODO: check the zImage path, fix style, add checks (check initramfs path, etc)
  • Booting and testing: mostly done. TODO: fix typos, depends on setup required for testing
  • Xorg drivers: WIP
  • Wayland drivers: TODO

Risks

The probability of breaking the GPU should be low as no GPUs have been broken in this process

However the probability of loosing some data is higher. If you have to power off your computer by pressing the power button for a long time, it may corrupt some data. That can happen when loading the radeon driver.

A workaround is to setup ssh on the machine used for doing the tests, and have another computer ssh into it to shut it down if it happens.

Another way to mitigate the risk is to force the computer with the radeon GPU to check the filesystems at each boot for the duration of the test.

This way if there is some corruptions, you will be informed of it and it might be fixed by the filesystem check. Also such corruption usually only affect data being written. So don't modify/write precious files during the tests.

If you use ext4, that can easily be done with tune2fs. To do that, first write down the default values that your rootfs uses. Replace /dev/sda1 by the block devices of your rootfs. If you use LVM, encryption or other partitioning schemes, it might differ:

sudo tune2fs -l /dev/sda1

This will show the mount count and maximum mount count:

[...]
Mount count:              15
Maximum mount count:      30
[...]

Write it down if you want to restore it after the tests.

To force checking the filesystem at each boot you can use the following commands:

sudo tune2fs -c 1 /dev/sda1
sudo tune2fs -C 1 /dev/sda1

Other setup required for testing

If you don't have ssh setup, loading the radeon driver can sometimes result in a black screen. To prevent that you need to make sure that the radeon driver is not loaded at boot.

blacklist radeon

To prevent the radeon module from being loaded at boot, add modprobe.blacklist=radeon to GRUB_CMDLINE_LINUX_DEFAULT in /etc/default/grub. Then you can regenerate your grub configuration with the following commands:

sudo grub-mkconfig -o /boot/grub/grub.cfg
display manager

Even if the radeon module is blacklisted, the module is typically loaded anyway by Xorg when the display manager starts.

To fix that, make sure that your display manager (gdm, lightdm, etc) is not started at boot.

To do that for lightdm:

sudo systemctl disable lightdm

Or for gdm:

sudo systemctl disable gdm

You will need to adapt the commands above to the display manager you use.

First verify if your GPU is supported by the lastest linux-libre

Now that we have everything setup for testing, we can proceed.

As Parabola usually have very recent linux-libre versions, if you already have linux-libre installed it is usually good enough to test if the radeon gpu works.

Once you booted on that kernel, we need to look if the radeon driver "probed" the card fine.

To do that first make sure that the radeon module is not loaded:

sudo rmmod radeon

After that we will need to clear the kernel log with the following command:

dmesg -c

This will enable us to separate the radeon logs from the other logs.

We can then load the radeon driver:

sudo modprobe radeon

We can then retrieve the logs with the following command:

dmesg

For instance for a GPU that isn't supported we can see something like that:

radeon 0000:01:05.0: remove_conflicting_pci_framebuffers: bar 0: 0x80000000 -> 0x87ffffff
radeon 0000:01:05.0: remove_conflicting_pci_framebuffers: bar 2: 0x88100000 -> 0x8810ffff
radeon 0000:01:05.0: remove_conflicting_pci_framebuffers: bar 5: 0x88000000 -> 0x880fffff
[drm] initializing kernel modesetting (RS880 0x1002:0x9710 0x1002:0x0000 0x00).
radeon 0000:01:05.0: BAR 6: can't assign [??? 0x00000000 flags 0x20000000] (bogus alignment)
[drm:radeon_get_bios [radeon]] *ERROR* Unable to locate a BIOS ROM
radeon 0000:01:05.0: Fatal error during GPU init
[drm] radeon: finishing device.
[TTM] Memory type 2 has not been initialized
radeon: probe of 0000:01:05.0 failed with error -22
radeon 0000:02:00.0: remove_conflicting_pci_framebuffers: bar 0: 0xa0000000 -> 0xafffffff
radeon 0000:02:00.0: remove_conflicting_pci_framebuffers: bar 2: 0xb8000000 -> 0xb803ffff
radeon 0000:02:00.0: vgaarb: deactivate vga console
[drm] initializing kernel modesetting (VERDE 0x1002:0x683F 0x174B:0x2312 0x00).
ATOM BIOS: E231
radeon 0000:02:00.0: VRAM: 1024M 0x0000000000000000 - 0x000000003FFFFFFF (1024M used)
radeon 0000:02:00.0: GTT: 512M 0x0000000040000000 - 0x000000005FFFFFFF
[drm] Detected VRAM RAM=1024M, BAR=256M
[drm] RAM width 128bits DDR
[TTM] Zone  kernel: Available graphics memory: 889364 KiB
[TTM] Initializing pool allocator
[TTM] Initializing DMA pool allocator
[drm] radeon: 1024M of VRAM memory ready
[drm] radeon: 512M of GTT memory ready.
[drm] Loading verde Microcode
0000:02:00.0: Missing Free firmware (non-Free firmware loading is disabled)
0000:02:00.0: Missing Free firmware (non-Free firmware loading is disabled)
si_cp: Failed to load firmware "/*(DEBLOBBED)*/"
[drm:si_init [radeon]] *ERROR* Failed to load firmware!
radeon 0000:02:00.0: Fatal error during GPU init
[drm] radeon: finishing device.
[TTM] Finalizing pool allocator
[TTM] Finalizing DMA pool allocator
[TTM] Zone  kernel: Used memory at exit: 0 KiB
[drm] radeon: ttm finalized
radeon: probe of 0000:02:00.0 failed with error -2

The most important part in this log is the following:

0000:02:00.0: Missing Free firmware (non-Free firmware loading is disabled)
0000:02:00.0: Missing Free firmware (non-Free firmware loading is disabled)
si_cp: Failed to load firmware "/*(DEBLOBBED)*/"
[drm:si_init [radeon]] *ERROR* Failed to load firmware!
radeon 0000:02:00.0: Fatal error during GPU init
[...]
radeon: probe of 0000:02:00.0 failed with error -2

Here the driver bails out for this GPU.

If the radeon driver doesn't work with the lastest version of linux-libre we will then need to add support for it in linux-libre.

Find the Linux driver file to patch

To find the file to patch, you can look at examples in the table in the radeon wiki page.

Patching linux-libre

First get the linux-libre source scripts. This can for instance be done by downloading the source code from git. This has the advantage of being able to see the changes having been made, and to be able to revert some of the changes in cases of mistakes, without needing to re-download or re-extract everything. This can be done with the following commands:

git clone https://jxself.org/git/linux-libre.git
cd linux-libre

We then need to use the latest version. At the time of writing it's the 5.3.4 version, so I used that in this howto. This can be done with the following command (with 5.3.4 being replaced by the latest version when you are doing it):

git tag | grep 5.3.4

This should give something like that:

deblob-5.3.4-gnu
v5.3.4-gnu

You then need to get the source code for the deblob-<version>-gnu. That can be done like that:

git checkout deblob-5.3.4-gnu -b radeon-test

Replace 5.3.4 by the latest version.

You can then look at which files are now present in the directory:

ls

This should give something like that:

COPYING  deblob-5.3  deblob-check  deblob-main

Here the code doing the clean_sed is in deblob-5.3. This can be found with grep:

grep r600.c *

This should give out the files with r600.c:

 deblob-5.3:reject_firmware drivers/gpu/drm/radeon/r600.c
 deblob-5.3:clean_blob drivers/gpu/drm/radeon/r600.c
 deblob-5.3:' drivers/gpu/drm/radeon/r600.c 'enable blobless activation'
 deblob-check:    blobname 'radeon[/]\(R\([67]0\|V6[1237]\|S7[1378]\)[05]\|CEDAR\|REDWOOD\|JUNIPER\|CYPRESS\|%s\)_\(pfp\|rlc\|me\)\.bin' drivers/gpu/drm/radeon/r600.c
 deblob-check:    blobname 'radeon[/]SUMO2\?_\(pfp\|me\)\.bin' drivers/gpu/drm/radeon/r600.c
 deblob-check:    blobname 'radeon[/]\(R\([67]0\|V6[1237]\|S7[1378]\)[05]\|CEDAR\|REDWOOD\|JUNIPER\|CYPRESS\|SUMO2\?\|%s\)_\(pfp\|[mc]e\|rlc\|s\?mc\)\.bin' drivers/gpu/drm/radeon/r600.c

Here if we look in deblob-5.3 we have:

clean_sed '
/r = r600_init_microcode(rdev);/,/}/ s,return r;,/*(DEBLOBBED)*/,
' drivers/gpu/drm/radeon/r600.c 'enable blobless activation'

So we now found the place where to add code to enable GPUs that are not supported yet.

We can then proceed to patch that deblob-5.3 file to:

  • add a clean_sed line for the driver, so it would not fail if the firmware is absent
  • Move the reject_firmware and clean_blob before the clean_sed as it is done this way for other Radeon GPUs

For adding support for the Northern Islands GPUs (ni.c) I then did a patch that looked like that:

 clean_blob drivers/gpu/drm/radeon/r100.c
 reject_firmware drivers/gpu/drm/radeon/r600.c
 clean_blob drivers/gpu/drm/radeon/r600.c
+reject_firmware drivers/gpu/drm/radeon/ni.c
+clean_blob drivers/gpu/drm/radeon/ni.c
 # Something like this might work on other radeon cards too.  If you
 # have such cards, please give it a try, and report back either way,
 # so that we can make more cards work, or at least add comments so
@@ -891,8 +893,9 @@ clean_sed '
 clean_sed '
 /r = r600_init_microcode(rdev);/,/}/ s,return r;,/*(DEBLOBBED)*/,
 ' drivers/gpu/drm/radeon/rv770.c 'enable blobless activation'
-reject_firmware drivers/gpu/drm/radeon/ni.c
-clean_blob drivers/gpu/drm/radeon/ni.c
+clean_sed '
+/r = ni_init_microcode(rdev);/,/}/ s,return r;,/*(DEBLOBBED)*/,
+' drivers/gpu/drm/radeon/ni.c 'enable blobless activation'
 reject_firmware drivers/gpu/drm/radeon/si.c
 clean_blob drivers/gpu/drm/radeon/si.c
 reject_firmware drivers/gpu/drm/radeon/cik.c

You need to do something similar for the GPU family you're adding support for.

Deblobing Linux

Then I downloaded Linux 5.3.4. I used git as I like to be able to see the changes:

cd ../
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
cd linux
git checkout v5.3.4 -b radeon-test

I then ran the deblob-5.3.4 script:

../linux-libre/deblob-5.3

It's then a good idea to commit the changes. If you use git and that you don't commit the changes, the kernel build process will find that you have changes not in git and append -dirty to your kernel version. As we later rely on 5.3.4-gnu-custom as kernel name and not 5.3.4-gnu-custom-dirty, it's a good idea to do it now before building the kernel. Commiting the changes can be done like that:

export GIT_AUTHOR_NAME="linux libre deblob patch"
export GIT_COMMITTER_NAME="linux libre deblob patch"
export GIT_AUTHOR_EMAIL="linux-libre@fsfla.org"
export GIT_COMMITTER_EMAIL="linux-libre@fsfla.org"
git commit -a -m "deblob patch"

Building linux-libre

I then used the linux-libre build configuration from Parabola:

cd ../
git clone git://git.parabola.nu/abslibre.git
cd ../linux-libre
cp ../libre/linux-libre/config.x86_64 .config

Since we're already running the lastest version of linux-libre, which comes from Parabola, we need to make sure that the modules will be installed in a different directory. Adding -custom the the kernel version should work for that:

sed 's#^CONFIG_LOCALVERSION=".*"$#CONFIG_LOCALVERSION="-custom"#' -i .config

We also need to make sure that the kernel modules aren't installed in something like /lib/modules/5.3.4-gnu-custom-00001-g753741f48fdc but in something like /lib/modules/5.3.4-gnu-custom instead. To do that makes sure that CONFIG_LOCALVERSION_AUTO is deactivated with the following command:

sed 's/^CONFIG_LOCALVERSION_AUTO=y$/# CONFIG_LOCALVERSION_AUTO is not set/g' -i .config

We can then proceed to compile the kernel:

jobs="-j$(grep processor /proc/cpuinfo  | wc -l)"
make ${jobs} ; make ${jobs} modules

This will take several hours, even on fast computers, because, as we have the same configuration than Parabola, it will compile many modules. The advantage of doing it this way is that Parabola already took care of selecting the modules required to operate the computer, so we don't need to spend hours and hours researching that. It also helps a lot with testing, as the modified Radeon driver will then be tested with configuration being used by a distribution using linux-libre. So this will decrease the probability of breaking software or hardware.

Installing the modified linux-libre

We then need to install the modules and the kernel image:

sudo make modules_install
sudo install arch/x86/boot/bzImage /boot/vmlinuz-linux-custom

Once built and installed, we still need to boot on that kernel. To do that we need to:

  • Generate an initramfs for it
  • Update your bootloader's configuration.

To generate the initramfs, you need to add a configuration file in /etc/mkinitcpio.d/.

To do that you can add the following to /etc/mkinitcpio.d/linux-custom.preset:

 ALL_config="/etc/mkinitcpio.conf"
 ALL_kver="/boot/vmlinuz-linux-custom"
 PRESETS=('default' 'fallback')
 default_image="/boot/initramfs-linux-custom.img"
 fallback_image="/boot/initramfs-linux-custom-fallback.img"
 fallback_options="-S autodetect"

You can then generate the initramfs with the following command:

sudo mkinitcpio -p linux-custom

Now that the initramfs is generated, you then need to update the bootloader configuration before booting, so it could add an entry with the linux-custom. For GRUB, that can be done with the following command:

sudo grub-mkconfig -o /boot/grub/grub.cfg

Booting and testing

To boot on linux-custom, just select it in the bootloader menu during the boot.

Then you need to login inside the text console.

Once this is done it's advised to clear the kernel log, so that, after loading the radeon module, it will make it easier to retrieve the kenrel logs that are generated by the radeon driver. This can be done with the following command:

sudo dmesg -c

You can then load the radeon driver with the following command:

sudo modprobe radeon

If you have a black screen, something went wrong.

If not, the console typically gets black for less than 10 seconds, and then the display comes back with an increased resolution. It's also a good idea to use the laptop a bit to capture the log and so on to make sure that the laptop was still usable after loading the module.

After loading the radeon module, you can finally look at the new kernel messages with the following command:

dmesg

It should print something like that:

 Linux agpgart interface v0.103
 [drm] radeon kernel modesetting enabled.
 radeon 0000:00:01.0: remove_conflicting_pci_framebuffers: bar 0: 0xe0000000 -> 0xefffffff
 radeon 0000:00:01.0: remove_conflicting_pci_framebuffers: bar 2: 0xf0280000 -> 0xf02bffff
 radeon 0000:00:01.0: vgaarb: deactivate vga console
 Console: switching to colour dummy device 80x25
 [drm] initializing kernel modesetting (ARUBA 0x1002:0x990B 0x1002:0x990B 0x00).
 ATOM BIOS: 113
 radeon 0000:00:01.0: VRAM: 512M 0x0000000000000000 - 0x000000001FFFFFFF (512M used)
 radeon 0000:00:01.0: GTT: 1024M 0x0000000020000000 - 0x000000005FFFFFFF
 [drm] Detected VRAM RAM=512M, BAR=256M
 [drm] RAM width 64bits DDR
 [TTM] Zone  kernel: Available graphics memory: 3809790 KiB
 [TTM] Zone   dma32: Available graphics memory: 2097152 KiB
 [TTM] Initializing pool allocator
 [TTM] Initializing DMA pool allocator
 [drm] radeon: 512M of VRAM memory ready
 [drm] radeon: 1024M of GTT memory ready.
 [drm] Loading ARUBA Microcode
 0000:00:01.0: Missing Free firmware (non-Free firmware loading is disabled)
 ni_cp: Failed to load firmware "/*(DEBLOBBED)*/"
 [drm:cayman_init [radeon]] *ERROR* Failed to load firmware!
 [drm] Internal thermal controller without fan control
 [drm] radeon: power management initialized
 0000:00:01.0: Missing Free firmware (non-Free firmware loading is disabled)
 radeon 0000:00:01.0: radeon_uvd: Can't load firmware "/*(DEBLOBBED)*/"
 radeon 0000:00:01.0: failed UVD (-2) init.
 0000:00:01.0: Missing Free firmware (non-Free firmware loading is disabled)
 radeon 0000:00:01.0: radeon_vce: Can't load firmware "/*(DEBLOBBED)*/"
 radeon 0000:00:01.0: failed VCE (-2) init.
 [drm] GART: num cpu pages 262144, num gpu pages 262144
 [drm] PCIE GART of 1024M enabled (table at 0x0000000000040000).
 radeon 0000:00:01.0: WB enabled
 radeon 0000:00:01.0: fence driver on ring 0 use gpu addr 0x0000000020000c00 and cpu addr 0x00000000e742fc62
 radeon 0000:00:01.0: fence driver on ring 1 use gpu addr 0x0000000020000c04 and cpu addr 0x0000000055d88f08
 radeon 0000:00:01.0: fence driver on ring 2 use gpu addr 0x0000000020000c08 and cpu addr 0x000000007193ef67
 radeon 0000:00:01.0: fence driver on ring 3 use gpu addr 0x0000000020000c0c and cpu addr 0x00000000f260dfaf
 radeon 0000:00:01.0: fence driver on ring 4 use gpu addr 0x0000000020000c10 and cpu addr 0x0000000013e54c0e
 [drm] Supports vblank timestamp caching Rev 2 (21.10.2013).
 [drm] Driver supports precise vblank timestamp query.
 radeon 0000:00:01.0: radeon: MSI limited to 32-bit
 radeon 0000:00:01.0: radeon: using MSI.
 [drm] radeon: irq initialized.
 [drm:cayman_startup [radeon]] *ERROR* radeon: IH init failed (-22).
 radeon 0000:00:01.0: disabling GPU acceleration
 [drm] radeon atom DIG backlight initialized
 [drm] Radeon Display Connectors
 [drm] Connector 0:
 [drm]   eDP-1
 [drm]   HPD1
 [drm]   DDC: 0x6530 0x6530 0x6534 0x6534 0x6538 0x6538 0x653c 0x653c
 [drm]   Encoders:
 [drm]     LCD1: INTERNAL_UNIPHY2
 [drm] Connector 1:
 [drm]   VGA-1
 [drm]   HPD2
 [drm]   DDC: 0x6540 0x6540 0x6544 0x6544 0x6548 0x6548 0x654c 0x654c
 [drm]   Encoders:
 [drm]     CRT1: INTERNAL_UNIPHY2
 [drm]     CRT1: NUTMEG
 [drm] Connector 2:
 [drm]   HDMI-A-1
 [drm]   HPD3
 [drm]   DDC: 0x6550 0x6550 0x6554 0x6554 0x6558 0x6558 0x655c 0x655c
 [drm]   Encoders:
 [drm]     DFP1: INTERNAL_UNIPHY
 [drm] fb mappable at 0xE0241000
 [drm] vram apper at 0xE0000000
 [drm] size 4325376
 [drm] fb depth is 24
 [drm]    pitch is 5632
 fbcon: radeondrmfb (fb0) is primary device
 Console: switching to colour frame buffer device 170x48
 radeon 0000:00:01.0: fb0: radeondrmfb frame buffer device
 [drm] Initialized radeon 2.50.0 20080528 for 0000:00:01.0 on minor 0

You can easily save it to a file with the following command:

dmesg > radeon_test.log

Along with the patch, that information can be useful for linux-libre.

At this point, since everything went fine, you can send the patch to the linux-libre mailing list, along with the log and your observations that everything went fine (the display worked, the resolution increased, etc).

Xorg drivers

At this point you can also try the radeon driver for Xorg but it may or may not work as some of the features sometimes rely on 3D acceleration. Alternative drivers like "modesettings" are usually available and Xorg can be configured to use that instead of the Radeon driver.

Wayland drivers ?

TODO