Commit 55dc5f21 authored by Ben Walker's avatar Ben Walker
Browse files

Add vfio support to scripts.



cleanup.sh and unbind.sh have been combined into a single
setup.sh that takes one optional parameter (reset). If no
parameter is given, the script will automatically bind
all NVMe and IOAT devices to either uio_pci_generic
or vfio-pci, as appropriate based on IOMMU settings. If
the reset parameter is given, the devices will be bound back
to the appropriate kernel drivers.

Change-Id: I25db3234f1ecfb352a281e5093f4c1aa455152ae
Signed-off-by: default avatarBen Walker <benjamin.walker@intel.com>
parent c0a1cd38
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -88,4 +88,4 @@ any NVMe and I/OAT devices must be unbound from the native kernel drivers.
SPDK includes scripts to automate this process on both Linux and FreeBSD.

    1) scripts/configure_hugepages.sh
    2) scripts/unbind.sh
    2) scripts/setup.sh
+3 −3
Original line number Diff line number Diff line
@@ -10,7 +10,7 @@ if [ $EUID -ne 0 ]; then
	exit 1
fi

trap "process_core; $rootdir/scripts/cleanup.sh; exit 1" SIGINT SIGTERM EXIT
trap "process_core; $rootdir/scripts/setup.sh reset; exit 1" SIGINT SIGTERM EXIT

timing_enter autotest

@@ -38,7 +38,7 @@ timing_enter afterboot
./scripts/configure_hugepages.sh 1024
timing_exit afterboot

./scripts/unbind.sh
./scripts/setup.sh

#####################
# Unit Tests
@@ -52,7 +52,7 @@ time test/lib/ioat/ioat.sh

timing_exit lib

./scripts/cleanup.sh
./scripts/setup.sh reset
./scripts/build_kmod.sh clean

timing_exit autotest
+2 −1
Original line number Diff line number Diff line
@@ -448,7 +448,8 @@ spdk_pci_device_has_non_uio_driver(struct spdk_pci_device *dev)
		driver_begin = driver;
	}

	return strcmp(driver_begin, "uio_pci_generic") != 0;
	return (strcmp(driver_begin, "uio_pci_generic") != 0 &&
		strcmp(driver_begin, "vfio-pci") != 0);
}
#endif

scripts/cleanup.sh

deleted100755 → 0
+0 −28
Original line number Diff line number Diff line
#!/usr/bin/env bash

set -e

function cleanup_linux() {
	# detach pci devices from uio driver
	grep -q "^uio_pci_generic" /proc/modules && rmmod uio_pci_generic

	# bind NVMe devices to NVMe driver if no kernel device
	if [ -d "/sys/bus/pci/drivers/nvme" ]; then
		device=`find /sys/bus/pci/drivers/nvme -name "0000*" -print`
		if [ -z "$device" ]; then
			rmmod nvme
			modprobe nvme
		fi
	fi
}

function cleanup_freebsd {
	kldunload contigmem.ko || true
	kldunload nic_uio.ko || true
}

if [ `uname` = Linux ]; then
	cleanup_linux
else
	cleanup_freebsd
fi

scripts/setup.sh

0 → 100755
+138 −0
Original line number Diff line number Diff line
#!/usr/bin/env bash

set -e

rootdir=$(readlink -f $(dirname $0))/..

function linux_iter_pci {
	# Argument is the class code
	# TODO: More specifically match against only class codes in the grep
	# step.
	lspci -mm -n | grep $1 | tr -d '"' | awk -F " " '{print "0000:"$1}'
}

function configure_linux {
	driver_name=vfio-pci
	if [ -z "$(ls /sys/kernel/iommu_groups)" ]; then
		# No IOMMU. Use uio.
		driver_name=uio_pci_generic
	fi

	# NVMe
	modprobe $driver_name || true
	for bdf in $(linux_iter_pci 0108); do
		if [ -e "/sys/bus/pci/devices/$bdf/driver" ]; then
			# Unbind the device from whatever driver it is currently bound to
			echo $bdf > "/sys/bus/pci/devices/$bdf/driver/unbind"
		fi
		# Bind this device to the new driver
		ven_dev_id=$(lspci -n -s $bdf | cut -d' ' -f3 | sed 's/:/ /')
		echo "Binding $bdf ($ven_dev_id) to $driver_name"
		echo $ven_dev_id > "/sys/bus/pci/drivers/$driver_name/new_id"
	done


	# IOAT
	TMP=`mktemp`
	#collect all the device_id info of ioat devices.
	grep "PCI_DEVICE_ID_INTEL_IOAT" $rootdir/lib/ioat/ioat_pci.h \
	| awk -F"x" '{print $2}' > $TMP

	for dev_id in `cat $TMP`; do
		# Abuse linux_iter_pci by giving it a device ID instead of a class code
		for bdf in $(linux_iter_pci $dev_id); do
			if [ -e "/sys/bus/pci/devices/$bdf/driver" ]; then
				# Unbind the device from whatever driver it is currently bound to
				echo $bdf > "/sys/bus/pci/devices/$bdf/driver/unbind"
			fi
			# Bind this device to the new driver
			ven_dev_id=$(lspci -n -s $bdf | cut -d' ' -f3 | sed 's/:/ /')
			echo "Binding $bdf ($ven_dev_id) to $driver_name"
			echo $ven_dev_id > "/sys/bus/pci/drivers/$driver_name/new_id"
		done
	done
	rm $TMP

	echo "1" > "/sys/bus/pci/rescan"
}

function reset_linux {
	# NVMe
	modprobe nvme || true
	for bdf in $(linux_iter_pci 0108); do
		ven_dev_id=$(lspci -n -s $bdf | cut -d' ' -f3 | sed 's/:/ /')
		if [ -e "/sys/bus/pci/devices/$bdf/driver" ]; then
			# Unregister this device from the driver it was bound to.
			echo $ven_dev_id > "/sys/bus/pci/devices/$bdf/driver/remove_id"
			# Unbind the device from whatever driver it is currently bound to
			echo $bdf > "/sys/bus/pci/devices/$bdf/driver/unbind"
		fi
		# Bind this device back to the nvme driver
		echo "Binding $bdf ($ven_dev_id) to nvme"
		echo $bdf > "/sys/bus/pci/drivers/nvme/bind"
	done


	# IOAT
	TMP=`mktemp`
	#collect all the device_id info of ioat devices.
	grep "PCI_DEVICE_ID_INTEL_IOAT" $rootdir/lib/ioat/ioat_pci.h \
	| awk -F"x" '{print $2}' > $TMP

	modprobe ioatdma || true
	for dev_id in `cat $TMP`; do
		# Abuse linux_iter_pci by giving it a device ID instead of a class code
		for bdf in $(linux_iter_pci $dev_id); do
			ven_dev_id=$(lspci -n -s $bdf | cut -d' ' -f3 | sed 's/:/ /')
			if [ -e "/sys/bus/pci/devices/$bdf/driver" ]; then
				# Unregister this device from the driver it was bound to.
				echo $ven_dev_id > "/sys/bus/pci/devices/$bdf/driver/remove_id"
				# Unbind the device from whatever driver it is currently bound to
				echo $bdf > "/sys/bus/pci/devices/$bdf/driver/unbind"
			fi
			# Bind this device back to the nvme driver
			echo "Binding $bdf ($ven_dev_id) to ioatdma"
			echo $bdf > "/sys/bus/pci/drivers/ioatdma/bind"
		done
	done
	rm $TMP

	echo "1" > "/sys/bus/pci/rescan"
}

function configure_freebsd {
	TMP=`mktemp`
	AWK_PROG="{if (count > 0) printf \",\"; printf \"%s:%s:%s\",\$2,\$3,\$4; count++}"
	echo $AWK_PROG > $TMP
	PCICONF=`pciconf -l | grep 'class=0x010802\|^ioat'`
	BDFS=`echo $PCICONF | awk -F: -f $TMP`
	kldunload nic_uio.ko || true
	kenv hw.nic_uio.bdfs=$BDFS
	kldload nic_uio.ko
	rm $TMP
}

function reset_freebsd {
	kldunload contigmem.ko || true
	kldunload nic_uio.ko || true
}

mode=$1
if [ "$mode" == "" ]; then
	mode="config"
fi

if [ `uname` = Linux ]; then
	if [ "$mode" == "config" ]; then
		configure_linux
	elif [ "$mode" == "reset" ]; then
		reset_linux
	fi
else
	if [ "$mode" == "config" ]; then
		configure_freebsd
	elif [ "$mode" == "reset" ]; then
		reset_freebsd
	fi
fi
Loading