Installing a custom kernel with USB 3.0 support

This documents my personal flow for downloading and installing a Linux kernel with my xHCI and USB 3.0 code. Until the code is in the upstream kernel and shipping in Linux distributions, you’ll have to follow these directions to get Linux USB 3.0 support.

Background

This tutorial is mostly for vendors who want to test their USB 3.0 devices or xHCI host controller prototypes. This assumes you already have a standard Debian or Ubuntu installation. There are many helpful guides for installing Ubuntu or Debian, so I won’t go into detail on that here.

There are also other guides for creating a custom kernel, but most walk you through creating a .deb package. Going through the extra steps of creating the package adds too much time if you’re updating your kernel a lot in order to track an upstream git tree.

Pre-work

First, you need to install some extra software that may not come with a standard Ubuntu or Debian install. You can install software by using a gui installer (like synaptic). You can also open a terminal (found under the Applications menu in Gnome and under the System menu in KDE) and install software using the command line. I’ll assume you’re using the command line in this tutorial.

First install the packages necessary to compile the Linux kernel. If you’re on Debian, type the following:

sudo aptitude install wget make git-core libncurses5-dev

If you’re on Ubuntu, use this command instead:

sudo aptitude install wget make git-core lib32ncurses5-dev

Next, you’ll need to add a script to install the Linux kernel.

mkdir ~/bin/
cd ~/bin/
wget http://minilop.net/~sarah/installkernel
sudo chmod a+x installkernel

A standard Debian or Ubuntu install should add the bin directory in your homedir to your path automatically whenever you start a new terminal shell. To make sure you can run that script, close your current terminal, restart a new terminal, and type

echo $PATH

You should see /home/username/bin in the output (replace username with whatever username you picked). You can also make sure the script is in your path by typing “installker” and hitting tab. If the command expands to “installkernel”, then your path is set correctly and the script permissions are right. If not, follow the next instructions.

Using the installkernel script

Now add that script to your PATH in your rc file for your terminal shell of choice. Bash is the default option, so edit (or create) the .bashrc file in your home directory. You can use vim, emacs, or even OpenOffice Writer to edit this file. If you must use OpenOffice Writer, make sure you save the file with the name “.bashrc” with a Text encoded (txt) file type, and uncheck the “Automatic file name extension” box.

Add this line to your .bashrc:

PATH=”~/bin:$PATH”

If you already have a line that starts with PATH, simply add the ~/bin: after
the first double quote.

Downloading a custom kernel

Most custom kernels are hosted on git.kernel.org. They are kept under revision control using the VCS called “git”. This means the kernels are updated often, and you may need to use git to update to the latest version. That’s explained later.

In this tutorial, I’ll assume you want to download my custom kernel to test USB 3.0 host controllers and devices.

First, move to your homedirectory and “clone” the git repository so you have a local copy checked out:

cd
git clone git://git.kernel.org/pub/scm/linux/kernel/git/sarah/xhci.git

Downloading the kernel may take a while. If you’re behind a firewall, you may need to set the $http\_proxy environment variable (by adding a “http\_proxy=url” line to your .bashrc) and use http to clone the repository. In this case, replace the last command with

git clone http://www.kernel.org/pub/scm/linux/kernel/git/sarah/xhci.git

You should see output like “Initialized empty Git repository in /home/username/xhci/.git/”. If nothing else happens for a couple minutes after that output, then you probably have firewall problems.

Choosing your kernel configuration

First, change directories into the newly created repository clone:

cd xhci/

Now we need to choose the configuration options for the new kernel, and compile it. A configuration file describes your system configuration, and whether you want drivers compiled into the kernel or if you want the drivers to be dynamically loadable as a module.

You can use the configuration file that the default distribution install created by typing:

cp /boot/config-`uname -r` .config

Now we need to change or add new configuration options:

make menuconfig

This will present a text-based GUI of all the configuration options for the Linux kernel. This is everything from what file systems to support (like FAT or EXT3) to what drivers to load (like SCSI, USB, or networking cards). A driver is built into the kernel if it has a star “*” by it. The driver is a dynamically loadable module if it has an “M” by it. If the option has nothing in the brackets, it won’t be compiled. If you want a driver to be a module, just hit the “m” key. If you don’t want a driver, hit “n”; if you want to compile a module into the kernel or say yes to a configuration option, hit “y”.

To be able to use my USB 3.0 code, navigate to Device Drivers and onto the USB support menu. Make sure “Support for Host-side USB” is a dynamically loadable module by moving the cursor to that item and hitting the ‘m’ key. You may get a message that other drivers depend on host-side USB being built into the kernel. If so, you need to make sure all the drivers under this menu with a star by them (“*”) are changed to be modules (with an “M”) by them.

You need to change a few more things in this menu. Choose to compile the xHCI (USB 3.0) host controller driver as a module by hitting “m”. Turn off (hit “n”) on the “USB selective suspend/resume and wakeup” option, since that isn’t supported by the driver yet. Turn on debugging for the USB subsystem by hitting “y” on “USB verbose debug messages” and “USB announce new devices”. Also turn on the “Debugging for the xHCI host controller” option.

Compiling and installing your kernel

Now that you have your kernel configured, compile your kernel by typing

make -j4

This may take a while. Go get a cup of tea or wander off for lunch. Once that compile finishes, you’re ready to install your kernel by typing

sudo make modules_install install

That will take a bit, but not as long as the compile.

Controlling when the xHCI driver is loaded

This next step is optional. If you follow the above steps exactly, the xHCI driver will be loaded automatically when you boot the new kernel. It’s much easier for me to look at debug output from the driver if it’s not interspersed with boot code. To do that, you should dynamically load the driver after the machine finishes booting.

First, we have to prevent the driver from being loaded automatically at boot time by black-listing the module. (Thanks to GotenXiao for the tip!) Just execute this command:

echo “blacklist xhci” > /etc/modprobe.d/xhci

Now whenever you want to load the xHCI driver, type the following (after you’ve rebooted into the new kernel):

sudo modprobe xhci

When you want to unload the module, type this:

sudo modprobe -r xhci

This is equivalent to enabling and then disabling the driver in the Windows system manager.

Updating your kernel

If the kernel.org tree gets patches added to it, or it’s updated to a newer kernel, you’ll need to update your local checkout. There are a couple ways to this, depending on if you have local changes to the files. If you haven’t modified any files, it’s safe to type these two commands from within your xhci directory:

git fetch
git reset –hard origin/master

This resets the local checkout to exactly what’s in the remote repository. If you have local changes, you’ll need to do something more complicated in order to merge in or rebase against the remote repository changes.

You’ll need compile and install the new code using the steps above, and then reboot.

Debugging

I suggest that when you run the xHCI driver, you have two tabs in your terminal window open. In one tab, redirect the kernel debugging messages to a file, and display the output using the tee command (thanks to Mike for the tip!):

tail -f /var/log/kern.log | tee ~/xhci-log-`date +%Y-%m-%d-%H-%M`.txt

The date part adds the current year-month-day-hour-minute to the logfile name so you don’t overwrite an old log file.

In the second tab, start the xHCI driver after 5 seconds. The slight delay allows you time to switch back to the first tab to watch the driver debug messages. In the second tab, type:

sleep 5 && sudo modprobe xhci

Send the logfile to me if you have issues. You may need to use netconsole to capture the kernel debug messages if your system is hanging because of a driver bug.

2 thoughts on “Installing a custom kernel with USB 3.0 support

Comments are closed.