disable specific PCI device at boot

14

6

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.

Rhymoid

Posted 2013-01-25T22:06:40.963

Reputation: 187

1Would an acceptable approach be to disable this particular USB device through the USB bus rather than the PCI bus? – slm – 2013-02-20T14:06:12.103

Also are you sure you can blacklist using a pci:... string like that? I've only ever seen kernel modules blacklistable in the /etc/modprobe.d/blacklist file. Couldn't you use lspci -k to identify which module the device wants and then black list that instead? – slm – 2013-02-20T14:13:51.150

After adding the entry to the blacklist, did you update-initramfs -u -k all? – Stefan Seidel – 2013-02-21T10:14:29.200

@StefanSeidel: Good point. I have now, but it doesn't seem to help. Perhaps slm is right in thinking that blacklisting a modalias like this needs a different syntax or method. – Rhymoid – 2013-02-21T14:55:19.023

@slm: I'm not sure if I can block modaliases through the modprobe blacklist (my system seems to ignore the line I gave it), but I can't just remove the module (ehci_hcd), since that would disable all USB hosts on my system. I just want to disable this specific device, based on its vendor, dev, subvendor, and subdev. – Rhymoid – 2013-02-21T14:58:58.567

I wasn't able to figure out a way to accomplish what you want, have you had any further luck? – slm – 2013-02-25T04:03:55.817

Not yet. I had the idea to hack around in /lib/modules/\uname -r`/modules.alias`, but I'm not sure if that'll work at all. – Rhymoid – 2013-02-25T11:25:34.833

If that PCI device is an EHCI controller, disabling it will probably knock out at least some, and possibly all, of your computer's external USB ports as well. USB uses a tree topology, where a single controller can support many devices; it's unlikely that your motherboard has a separate EHCI controller just for the webcam.

– Wyzard – 2013-03-05T00:23:44.207

@Wyzard: there are two PCI devices on my laptop that have EHCI controller functions. The controller for my external ports is a different PCI device than the controller for hardwired devices. Maybe unlikely, but still true. – Rhymoid – 2013-03-05T12:28:49.560

I have a similar problem with the PCI devices for the HDMI output on my ATI video cards. Best solution so far is to disable them in rc.local but it would be nice to be able to tell the kernel to ignore them completely. – Raman – 2013-07-30T15:03:19.943

Answers

4

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.

Steve Czetty

Posted 2013-01-25T22:06:40.963

Reputation: 156

It's still a solution where you unbind the PCI device after it was initialised, but hey, it looks better than solving it in /etc/init.d! I'm not using the machine right now, and I might never boot it again with Debian, so I can't test it. However, because it would probably have worked in my case, I'll accept it as an answer. – Rhymoid – 2016-04-25T20:10:43.177

Agreed, I still haven't found a solution for preventing the device initialization without blacklisting the module. The "radeon" line is an example of an early attempt at that, actually. – Steve Czetty – 2016-04-25T20:19:58.043

Funny I thought udev did all the bus walk through and loading during kernel boot and anything grub did in initramfs was read only and lost. when the kernel is loaded. I had tried to setup setpci in initramfs-tools but gave up and am trying a udev rule now. – WinEunuuchs2Unix – 2017-11-29T01:20:26.157

4

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.

Kujo770

Posted 2013-01-25T22:06:40.963

Reputation: 41

4

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

lunastorm

Posted 2013-01-25T22:06:40.963

Reputation: 41

This is pretty useful. However, as the OP mentioned, this will result in all USB ports going down. Is there anyway to add a rule for a specific device and vendor id so that the devices works with all other USB ports but will disregard a given device? – Mosty Mostacho – 2014-06-03T04:33:48.803

2

Found this thread on askubuntu:

Using lspci -vv to identify a device's PCI slot that you want to disable, it sounded like you could use this command to turn that slot's device off:

% echo 0 > /sys/bus/pci/slot/$N/power

slm

Posted 2013-01-25T22:06:40.963

Reputation: 7 449

1I know how I can disable it at any other time, but I want to stop the kernel from activating it at all. Besides, since this is a hardwired PCI device (like most USB controllers), it has no slot. The machine I'm talking about is a laptop, and the only slot it has (/sys/bus/pci/slots/1) is the ExpressCard slot on the outside, which I can manually vacate. – Rhymoid – 2013-02-20T08:39:38.837

2

When you already have echo "0000:00:1a.0" > /sys/bus/pci/drivers/ehci_hcd/unbind in /etc/rc.local for boot than you just need to put it into a script for the power management deamon aswell.

Goes like this: Create an executable bash script file named 0_disable_webcam in directory /etc/pm/sleep.d/:

#!/bin/sh
case "$1" in
        resume|thaw)
                echo "0000:00:1a.0" > /sys/bus/pci/drivers/ehci_hcd/unbind
                ;;
esac

It should work instantly. I tried it with an usb thumb drive and it worked (meaning it remained disabled) as long as the drive was plugged. Replugging would need udev rules but since your webcam will not be unplugged it should work. If that does not do the trick I have another suggestion.

kschurig

Posted 2013-01-25T22:06:40.963

Reputation: 56

If the above does not work then you have to find the correct usb port. I guess it is "1-1.2" ( otherwise check with tree /sys/bus/pci/devices/0000\:00\:1a.0/ under "usbX" which means the port is a similar number). If it is "1-1.2" instead of your echo "0000:00:1a.0" > /sys/bus/pci/drivers/ehci_hcd/unbind the script should have echo "auto" > /sys/bus/usb/devices/1-1.2/power/control; echo -n "1-1.2" > /sys/bus/usb/drivers/usb/unbind. – kschurig – 2013-02-24T00:01:27.550

0

not an answer to your question as much as a work around.

Why not simply suppress the logging of the messages to the console by modifying syslog / (I don't know if you use syslog or rsyslog or something else, so I can't really point you more specifically in the correct directory, but if you search your syslog config files for "console" and "tty", that would give you a good starting place - in fact, you can probably change console to /dev/tty1 [for example] and have messages only log to tty1 rather then all consoles.

The other solution (to answer your question, but I don't like), you could blacklist the ehci_hcd module (if its loaded), or recompile your kernel to use it only a s a module. Have a look at http://www.cyberciti.biz/faq/rhel-redhat-centos-kernel-usb-reset-high-speed-ehci_hcd/ which resolves exactly the question you are asking

davidgo

Posted 2013-01-25T22:06:40.963

Reputation: 49 152