disable specific PCI device at boot

Solution 1:

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.

Solution 2:

You can remove a PCI device by adding a udev rule under /etc/udev/rules.d :

ACTION=="add", KERNEL=="0000:00:03.0", SUBSYSTEM=="pci", RUN+="/bin/sh -c 'echo 1 > /sys/bus/pci/devices/0000:00:03.0/remove'"

Replace 0000:00:03.0 with the pci device address you want to remove

Solution 3:

None of the answers solved my similar problem, but they did put me on the path to solving it!

My syslog error:

[  334.940158] hub 1-0:1.0: unable to enumerate USB device on port 7

This is an internal usb hub-port for a bluetooth option I do not have.

unbind to the pci device just resulted in the hub popping back up as another hub (5 in my case) and flooding syslog further.

By chance I noticed an unbind structure under /sys/bus/usb/drivers/hub. Using examples above I just added the following in rc.local:

echo "1-0:1.0" > /sys/bus/usb/drivers/hub/unbind

Result is syslog silence! Now to add kshurig's script example for power management and I should be golden.