28d88d0bf2
Starting with Linux 4.1, the kernel includes vfio-pci. VFIO - "Virtual Function I/O". The VFIO driver is an IOMMU/device agnostic framework for exposing direct device access to userspace, in a secure, IOMMU protected environment. The vfio-pci takes full advantage of IOMMU, has better device support and prevents multiple access to the same device. Binding a pci device to vfio-pci driver is very useful for setting pci-passthrough for a VM Change-Id: I6c7df6840429e1b005908fdcc57a5f4e47fab922
176 lines
5.1 KiB
Bash
Executable File
176 lines
5.1 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Copyright 2016 IBM Corp.
|
|
#
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
#
|
|
#
|
|
# This script manage binding\unbinding a pci device with vfio driver
|
|
# The script gets a string in form of Domain:Bus:Device.Function
|
|
# and perform requested operation according to the command line argument:
|
|
#
|
|
# -h Display help message and exit
|
|
# -l List devices binded to vfio-pci kernel driver
|
|
# -r Force a rescan of pci devices
|
|
# -u PCI_DEVICE Unbind vfio-pci and remove. PCI_DEVICE is Domain:Bus:Device string of the form "0000:00:00.0"
|
|
# -b PCI_DEVICE Bind vfio-pci. PCI_DEVICE is Domain:Bus:Device string of the form "0000:00:00.0"
|
|
|
|
function iommu_group_devs {
|
|
INPUT_PCI_DEV=$1
|
|
INPUT_PCI_DEV_SYSFS_PATH="/sys/bus/pci/devices/$INPUT_PCI_DEV"
|
|
if [[ ! -d $INPUT_PCI_DEV_SYSFS_PATH ]]; then
|
|
echo "There is no device: $INPUT_PCI_DEV" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -d "$INPUT_PCI_DEV_SYSFS_PATH/iommu/" ]]; then
|
|
echo "Check IOMMU definition." 1>&2
|
|
echo "Use intel_iommu=on or iommu=pt iommu=1" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
for pcid in $INPUT_PCI_DEV_SYSFS_PATH/iommu_group/devices/*
|
|
do
|
|
dbdf=${pcid##*/}
|
|
if [[ $(( 0x$(setpci -s $dbdf 0e.b) & 0x7f )) -eq 0 ]]; then
|
|
dev_sysfs_paths+=( ${pcid##*/} )
|
|
fi
|
|
done
|
|
echo "${dev_sysfs_paths[@]}"
|
|
}
|
|
|
|
function vfio_unbind {
|
|
DEV=$1
|
|
echo "Trying to unbind: $DEV"
|
|
if [ -e /sys/bus/pci/drivers/vfio-pci/$DEV/remove ]; then
|
|
echo "Removing device: $DEV" 1>&2
|
|
echo 1 > /sys/bus/pci/drivers/vfio-pci/$DEV/remove
|
|
else
|
|
echo "Device: $DEV not found" 1>&2
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
function vfio_bind {
|
|
DEV=$1
|
|
echo "Trying to bind: $DEV"
|
|
#/sys/bus/pci/devices/0000:20:00.0/iommu_group/devices/0000:20:00.0
|
|
dpath="/sys/bus/pci/devices/$DEV"
|
|
echo "vfio-pci" > "$dpath/driver_override"
|
|
|
|
if [[ -d $dpath ]]; then
|
|
curr_driver=$(readlink $dpath/driver)
|
|
curr_driver=${curr_driver##*/}
|
|
|
|
if [[ $curr_driver == "vfio-pci" ]]; then
|
|
echo "$DEV already bound to vfio-pci" 1>&2
|
|
continue
|
|
else
|
|
echo $DEV > "$dpath/driver/unbind"
|
|
echo "Unbound $DEV from $curr_driver" 1>&2
|
|
fi
|
|
fi
|
|
|
|
echo $DEV > /sys/bus/pci/drivers_probe
|
|
}
|
|
|
|
# Usage info
|
|
show_help() {
|
|
cat << EOF
|
|
Usage: ${0##*/} [-h] [-u PCI_DEVICE] PCI_DEVICE...
|
|
This script enble binding/unbinding pci devices to vfio-pci driver
|
|
|
|
-h Display this help and exit
|
|
-l List devices bind to vfio-pci kernel driver
|
|
-r Force a rescan of pci devices
|
|
-u PCI_DEVICE Unbind vfio-pci. PCI_DEVICE is Domain:Bus:Device string of the form "0000:00:00.0"
|
|
-b PCI_DEVICE Bind vfio-pci. PCI_DEVICE is Domain:Bus:Device string of the form "0000:00:00.0"
|
|
EOF
|
|
}
|
|
|
|
|
|
if [ "$#" -lt 1 ];then
|
|
echo "illegal number of arguments: $#"
|
|
show_help
|
|
exit 1
|
|
fi
|
|
|
|
OPTIND=1
|
|
while getopts "hlru:b:" opt; do
|
|
options_found=1
|
|
case "$opt" in
|
|
h)
|
|
show_help
|
|
exit 0
|
|
;;
|
|
l)
|
|
lspci -k | grep -i vfio-pci -B2 | grep -i fib | awk '{print $1}'
|
|
exit 0
|
|
;;
|
|
r) echo "Run PCI rescan"
|
|
echo 1 > /sys/bus/pci/rescan
|
|
exit $?
|
|
;;
|
|
u) device=$OPTARG
|
|
devs="$(iommu_group_devs $device)"
|
|
if [[ -n $devs ]]; then
|
|
for dpci in $devs
|
|
do
|
|
echo "Remove device: $dpci"
|
|
vfio_unbind $dpci
|
|
if [[ $? -ne 0 ]]; then
|
|
echo "Unbind Devices error" 1>&2
|
|
exit 1
|
|
fi
|
|
done
|
|
exit 0
|
|
fi
|
|
exit 1
|
|
;;
|
|
b) device=$OPTARG
|
|
modprobe -i vfio-pci
|
|
if [[ $? -ne 0 ]]; then
|
|
echo "Error probing vfio-pci" 1>&2
|
|
exit 1
|
|
fi
|
|
devs="$(iommu_group_devs $device)"
|
|
if [[ -n $devs ]]; then
|
|
for dpci in $devs
|
|
do
|
|
echo "Binding device: $dpci"
|
|
vfio_bind $dpci
|
|
if [[ $? -ne 0 ]]; then
|
|
echo "Device binding error: $dpci"
|
|
exit 1
|
|
fi
|
|
done
|
|
exit 0
|
|
fi
|
|
exit 1
|
|
;;
|
|
\?)
|
|
show_help >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
shift "$((OPTIND-1))" # Shift off the options and optional --.
|
|
|
|
if ((!options_found)); then
|
|
echo "no options found"
|
|
show_help
|
|
fi
|