Linux – disable specific PCI device at boot

driverslinux

I've just reinstalled Debian on my Sony VAIO laptop, and my dmesg and virtual consoles all get spammed with the same messages over and over again.

[   59.662381] hub 1-1:1.0: unable to enumerate USB device on port 2
[   59.901732] usb 1-1.2: new high-speed USB device number 91 using ehci_hcd
[   59.917940] hub 1-1:1.0: unable to enumerate USB device on port 2
[   60.157256] usb 1-1.2: new high-speed USB device number 92 using ehci_hcd

I believe these messages are coming from an internally connected USB device, most likely the webcam (since that's the only thing that doesn't work). The only way I can seem to have it shut up (without killing my actually useful USB ports) is to disable one of the USB host controllers:

# echo "0000:00:1a.0" > /sys/bus/pci/drivers/ehci_hcd/unbind

This also takes down my Bluetooth interface, but I'm fine with that.

I would like this setting to persist, so that I can painlessly use my virtual console again in case I need it. I want my operating system (Debian amd64) to never wake it up, but I don't know how to do this. I've tried to blacklist the module alias for the PCI device, but it seems to be ignored:

$ cat /sys/bus/pci/devices/0000\:00\:1a.0/modalias 
pci:v00008086d00003B3Csv0000104Dsd00009071bc0Csc03i20

$ cat /etc/modprobe.d/blacklist
blacklist pci:v00008086d00003B3Csv0000104Dsd00009071bc0Csc03i20

How do I ensure that this specific PCI device is never automatically activated, without disabling its driver altogether?


-edit- The module was renamed recently, now the following works from userland:

echo "0000:00:1a.0" > /sys/bus/pci/drivers/ehci-pci/unbind

Still, I'm looking for a way to stop the kernel from binding that device in the first place.

Best Answer

I recently ran into this issue while configuring my xen box with multiple usb devices. I wanted one to be used by Dom-0, and the other to be used by a VM, so I needed the device to be available to xen-pciback. However, the usb driver was complied into my kernel, so I couldn't just blacklist the driver. My solution was to create a custom initramfs script that unbinds the specific pci port very early in the boot process.

This is Ubuntu 2016.04, but it should work in earlier versions.

There are three files involved. I named them for my specific use case, but ymmv:

The first file, named /etc/unbindpci file which is a simple csv of the pci device number and the driver (configure as needed here):

0000:08:00.0,xhci_hcd
0000:03:00.0,radeon

Second file /etc/initramfs-tools/hooks/xenfiles, which copies the above config into the initramfs.

#! /bin/bash

if [ -f /etc/unbindpci ]; then
  cp -pP /etc/unbindpci $DESTDIR/etc/unbindpci
fi

Third file is what does the work at boot time, I placed it in /etc/initramfs-tools/scripts/init-top/unbind-early-pci:

#!/bin/sh

PREREQ=""
prereqs()
{
        echo "$PREREQ"
}
case $1 in
# get pre-requisites
prereqs)
        prereqs
        exit 0
        ;;
esac

# This only executes if in a xen Dom-0.
# Edit if that's not your use case!          
if [ -f /sys/hypervisor/uuid -a -f /etc/unbindpci ]; then
        if [ $(cat /sys/hypervisor/uuid) = "00000000-0000-0000-0000-000000000000" ]; then
                echo "Unbinding pci ports..."
                IFS=,
                while read addr driver; do
                        if [ -f /sys/bus/pci/drivers/$driver/unbind ]; then
                                echo "Unbinding $addr, device $driver"
                                echo $addr > /sys/bus/pci/drivers/$driver/unbind
                        fi
                done < /etc/unbindpci
        fi
fi

Finally, run update-initramfs -k all -u and reboot.

I could include support for comments in the config file, and there is a lot of cleanup to do here, but it works for me.

Related Question