-
Notifications
You must be signed in to change notification settings - Fork 66
Porting a new version of DRM drivers from Linux
Porting a new version of the DRM drivers consists of:
- taking the source code from the target version of Linux, patching it as little as possible,
- adapting linuxkpi if needed
To make the porting effort as clear and transparent as possible, we take
individual Git commits to Linux’ DRM drivers and replay them in the drm-kmod
repository.
The use of linuxpki is critical here because it allows to keep the drivers as close as possible to their upstream copy in Linux and make it easier to update them to a later version.
The whole stack is split info two layers:
- the linuxkpi that offers a Linux driver API on top of FreeBSD
- the DRM drivers themselves
linuxkpi is used by several drivers, not only the DRM ones. It lives in the
FreeBSD source tree at sys/compat/linuxkpi/common
.
The file hierarchy underneath reproduces the Linux hierarchy.
drm-kmod
contains the DRM drivers, some code shared between them, Makefiles
to compile everything on FreeBSD and scripts to help the porting effort.
drm-kmod
|-- drivers # The drivers and shared code from Linux, lightly patched.
| `-- gpu
| `-- drm
| |-- amd
| `-- i915
|
|-- amd # AMD driver Makefiles.
|-- drm # Shared code Makefiles.
|-- i915 # Intel driver Makefiles.
|-- radeon # Legacy AMD driver Makefiles.
|
`-- scripts # Helper scripts.
There is a linuxkpi
directory at the root of the repository as well. It used
to contain a part of the linuxkpi source code. Nowadays, we make all changes
in the FreeBSD source tree, to ensure it can be used and it works with other
drivers. The remaining directory in drm-kmod
can be used temporarily while
working on the drivers to make iterations faster, but it should not be use for
long term.
You need to be familiar with the compilation and use of a FreeBSD kernel compiled from sources. Instructions will be restated in this document but we will not go into great details about them.
You also need to be able to compile and install the DRM drivers from sources. Please read the "Install from sources" instructions and make sure this works for you first.
Finally, the helper scripts used later depend on GNU patch and GNU sed:
sudo pkg install patch gsed
It is recommended to install and use a separate kernel and drivers during porting, separate from your stable kernel. There is also a great chance that linuxkpi will have to be adapted to reflect changes and additions in Linux.
-
Clone the freebsd-src Git repository:
git clone https://git.FreeBSD.org/src.git /path/to/freebsd-src cd /path/to/freebse-src
-
Compile the kernel:
make -j12 buildkernel DEBUG_FLAGS=-g KERNCONF=GENERIC
-
Install the kernel in a dedicated directory:
sudo make installkernel DEBUG_FLAGS=-g KERNCONF=GENERIC INSTKERNNAME=kernel.drm
Use
make reinstallkernel
after you installed it a first time.
-
Clone the drm-kmod Git repository:
git clone https://github.com/freebsd/drm-kmod.git /path/to/drm-kmod cd /path/to/drm-kmod
-
Compile the drivers:
make -j12 DEBUG_FLAGS=-g SYSDIR=/path/to/freebsd-src/sys
-
Install the drivers:
sudo make install DEBUG_FLAGS=-g SYSDIR=/path/to/freebsd-src/sys KMODDIR=/boot/kernel.drm
Reboot and use this freshly installed kernel with the drivers to ensure that the current driver works before beginning an upgade, except if your GPU is unsupported yet of course.
We try to port drivers from the immediate next version of Linux. This is easier to review and debug, and allow to ship more often.
The commands below will take the update from Linux 6.6 to 6.7 as an example.
-
Clone the Linux Git repository and switch to the target version tag:
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git /path/to/linux-src cd /path/to/linux-src git checkout v6.7 # Select the appropriate tag here.
Switching to the target tag is not strictly necessary because the helper script uses given references, not the actual working copy. But it can be useful later if you need to look at the matching Linux source code.
-
Go to your
drm-kmod
clone:cd /path/to/drm-kmod
-
Extract DRM drivers-related patches from Linux repository between the source and target versions:
./scripts/drmgeneratepatch \ /path/to/linux-src \ /path/to/patches-6.7 \ v6.6..v6.7
The
/path/to/patches-6.7
will created by the script. This place can be any one. It will be passed to following commands. -
Filter out already applied patches:
./scripts/drmcheckapplied /path/to/patches-6.7
This script goes through the extracted patches and compares their commit message first line to the git-log of
drm-kmod
. If it detects that a patch was previously applied, it moves it to/path/to/patches-6.7/alreadyapplied
.This can happen when a commit was backported to older release branches in Linux.
Keep these already applied patches around because you might need them: indeed, the backported and already applied copy of that patch may not be identical. For instance, the original patch modified a piece of code that did not exist in an older release branch. Therefore you may have to re-apply parts of these already applied patches.
This is the main part of the whole porting process. The scripts/drmpatch
script automates part of the loop:
- It applies the next patch to
drm-kmod
- It compiles the result
- It goes back to step 1 until all patches are applied
env SYSDIR=/path/to/freebsd-src/sys \
./scripts/drmpatch /path/to/patches-6.7
Note that you may need to set $SYSDIR
as well because drmpatch
wants to compile the drivers.
The next few paragraphs go through the different outcomes.
If a patch was applied successfully, drmpatch
moves it to
/path/to/patches-6.7/applied
.
If drmpatch
failed to apply a patch, it leaves the drm-kmod
repository
untouched and moves the failing patch to /path/to/patches-6.7/rej
.
What you can do about it:
- Apply it manually and see what it actually rejected
- Work on the conflict
Once the conflict is fixed and the drivers compile successfully, you can commit
the patch and move the patch manually to /path/to/patches-6.7/applied
.
The are two common reasons:
- There are compilation warnings.
- linuxkpi lacks a new API or there was a breaking change to an existing API.
- A new file was added and has to be added to the kernel module
One thing to keep in mind: upstream commits are developed in a topic branch over time by several teams — in particular Intel and AMD employees. There may be changes that span over multiple commites and they are not squashed together at the end. Therefore, some commit just don’t compile and they are finished in a later commit.
We try to make sure every single commit is buildable to ensure git-biesct works smoothly, but it is not always possible.
Do not try to fix the warning! We want to keep the sources as close as possible to upstream.
Instead, add a compiler flag to ignore that warning for that specific file to the relevant Makefile.
Here is an example from amd/amdgpu/Makefile
:
CWARNFLAGS.amdgpu_acpi.c= -Wno-missing-prototypes -Wno-incompatible-pointer-types
CWARNFLAGS.amdgpu_atpx_handler.c= -Wno-missing-prototypes
CWARNFLAGS.amdgpu_bo_list.c= -Wno-unused-but-set-variable -Wno-tautological-constant-out-of-range-compare
CWARNFLAGS.amdgpu_csa.c= -Wno-unused-but-set-variable
CWARNFLAGS.amdgpu_device.c= -Wno-missing-prototypes -Wno-unused-but-set-variable
Finally, add this Makefile change to the commit responsible for that warning.
The DRM drivers starts to use an API that changed or is new in the target version of Linux.
Do not replace the code in the drivers with something FreeBSD-specific.
Instead, adapt linuxkpi to support that added/changed API. While doing this, keep in mind that linuxkpi has to work with older versions of the DRM drivers as well as other drivers (like WiFi devices). Therefore, try to make the change in a backward-compatible way.
Also, isolate all your changes to linuxkpi in atomic commits. They will have to be submitted and reviewed individually.
If you do have to make a FreeBSD-specific change in the drivers — for instance because you want to comment out lines that are simply irrelevant of FreeBSD —, you must keep the original Linux version unmodified and use preprocessor directives to add the FreeBSD flavor:
#ifdef __linux__
/* Unmodified Linux code */
#elif defined(__FreeBSD__)
/* FreeBSD code */
#endif
When updating and patching this code with code from Linux there are often merge conflicts where the code has been changed. If there are no markers it is difficult to know what code to keep and what to throw away.
Pull requests that do not follow this will not be accepted.
Unless obvious what your code does, please leave a comment to explain to fellow developers why you patched it. The source code is the documentation!
The drmpatch
tries to detect added/deleted files and will error out in this
case. Sometimes it can’t do that and you will get a compilation/link error.
In any case, you will have to update the corresponding Makefiles.
Once done, add this change to the commit that connected the files to the build in Linux. Note that files may have been added in a previous commits and connected to the build later.
Once all patches have been successfully applied and the drivers compile and work, it is recommended to review the full diff between your work and the Linux original sources.
Of course, the diff should not be that huge. It is useful to scan through some minor changes that where missed in the process.
You can reduce the diff and all all these minor changes either to the commit they should have been part of, or a final "Reduce diff with Linux 6.7" commit.
Once done, or even before to get feedback early, you can submit a pull request to https://github.com/freebsd/drm-kmod.
You should also submit any patches to linuxkpi to https://reviews.freebsd.org/.
In the pull request description, give a summary of the instructions to compile and test the update.
Include the list of linuxkpi and links to their reviews on Phabricator and their status (pending review or committed to freebsd-src).
Here is an example: freebsd/drm-kmod#267.