# Bind a device to a driver
# $1: pci bus address (ex: 0000:04:00.0)
# $2: driver
bind_device () {
        echo "Binding $1 to $2"
        sysfs_dev=/sys/bus/pci/devices/$1
        if [ -e ${sysfs_dev}/driver ]; then
                sudo sh -c "echo $1 > ${sysfs_dev}/driver/unbind"
        fi
        sudo sh -c "echo $2 > ${sysfs_dev}/driver_override"
        sudo sh -c "echo $1 > /sys/bus/pci/drivers/$2/bind"
        if [ ! -e ${sysfs_dev}/driver ]; then
                echo "Failed to bind device $1 to driver $2" >&2
                return 1
        fi
}

# Bind a device and devices in the same iommu group to a driver
# $1: pci bus address (ex: 0000:04:00.0)
# $2: driver
bind_device_and_siblings () {
        bind_device $1 $2
        # take devices in the same iommu group
        for dir in $sysfs_dev/iommu_group/devices/*; do
                [ -e "$dir" ] || continue
                sibling=$(basename $(readlink -e "$dir"))
                # we can skip ourself
                [ "$sibling" = "$1" ] && continue
                bind_device $sibling $2
        done
}

# get the iommu group of a device
# $1: pci bus address (ex: 0000:04:00.0)
get_iommu_group () {
        iommu_is_enabled || echo -n "noiommu-"
        echo $(basename $(readlink -f /sys/bus/pci/devices/$1/iommu_group))
}

# return 0 (success) if there is at least one file in /sys/class/iommu
iommu_is_enabled() {
        for f in /sys/class/iommu/*; do
                if [ -e "$f" ]; then
                        return 0
                fi
        done
        return 1
}

# get arguments to be passed to docker cli
# $*: list of pci devices
get_vfio_device_args () {
        iommu_is_enabled || echo -n "--cap-add=SYS_RAWIO "
        echo "--device /dev/vfio/vfio "
        for d in $*; do
                echo -n "--device /dev/vfio/$(get_iommu_group $d) "
        done
        echo
}
