Notes about binding/unbinding pci&pcie devices。

当使用vfio pass-thru devices时,个人常用的方式为:

1
2
3
gpudevice=`cat /sys/bus/pci/devices/0000:00:02.0/device`
echo 0000:00:02.0 > /sys/bus/pci/devices/0000:00:02.0/driver/unbind
echo "8086 $gpudevice" > /sys/bus/pci/drivers/vfio-pci/new_id

但是被问到了一个问题:为什么没用如下这一步呢?

1
echo 0000:00:02.0 > /sys/bus/pci/driver/vfio-pci/bind

发现自己无法回答该问题,因此,就有了本文。

对于new_idbind的权威解释如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
What:		/sys/bus/pci/drivers/.../bind
What: /sys/devices/pciX/.../bind
Date: December 2003
Contact: linux-pci@vger.kernel.org
Description:
Writing a device location to this file will cause
the driver to attempt to bind to the device found at
this location. This is useful for overriding default
bindings. The format for the location is: DDDD:BB:DD.F.
That is Domain:Bus:Device.Function and is the same as
found in /sys/bus/pci/devices/. For example::

# echo 0000:00:19.0 > /sys/bus/pci/drivers/foo/bind

What: /sys/bus/pci/drivers/.../new_id
What: /sys/devices/pciX/.../new_id
Date: December 2003
Contact: linux-pci@vger.kernel.org
Description:
Writing a device ID to this file will attempt to
dynamically add a new device ID to a PCI device driver.
This may allow the driver to support more hardware than
was included in the driver's static device ID support
table at compile time. The format for the device ID is:
VVVV DDDD SVVV SDDD CCCC MMMM PPPP. That is Vendor ID,
Device ID, Subsystem Vendor ID, Subsystem Device ID,
Class, Class Mask, and Private Driver Data. The Vendor ID
and Device ID fields are required, the rest are optional.
Upon successfully adding an ID, the driver will probe
for the device and attempt to bind to it. For example::

# echo "8086 10f5" > /sys/bus/pci/drivers/foo/new_id

信息量还是不够,那只能继续!

binding/unbinding devices to vfio-pci可知:

The driver core will probe any unbound devices as soon as a new_id is added to vfio-pci.

That can be changed by:

1
# echo 0 > /sys/bus/pci/drivers_autoprobe

结论: 写入new_id node,如果drivers_autoprobe开启,就会自动bind,无需写入bind node。否则,还是需要写入bind node。

若想研究细节,那只能看Linux内核源码了。

new_id: new_id_store

drivers_autoprobe: drivers_autoprobe_store

1
2
3
4
5
6
7
8
9
10
new_id_store
pci_add_dynid
driver_attach
__driver_attach
driver_probe_device
__driver_probe_device
really_probe
driver_bound
driver_deferred_probe_trigger
deferred_probe_work
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
static DECLARE_WORK(deferred_probe_work, deferred_probe_work_func);
deferred_probe_work_func
bus_probe_device

/**
* bus_probe_device - probe drivers for a new device
* @dev: device to probe
*
* - Automatically probe for a driver if the bus allows it.
*/
void bus_probe_device(struct device *dev)
{
struct bus_type *bus = dev->bus;

if (bus->p->drivers_autoprobe)
device_initial_probe(dev);

...
}