Browse Source

setup-vfio: New shell script to automatically configure VFIO

Luke Dashjr 11 years ago
parent
commit
7fc43d8e18
4 changed files with 132 additions and 2 deletions
  1. 6 0
      Makefile.am
  2. 8 2
      README.ASIC
  3. 1 0
      configure.ac
  4. 117 0
      setup-vfio

+ 6 - 0
Makefile.am

@@ -40,6 +40,8 @@ INCLUDES	= -fno-strict-aliasing
 
 bin_PROGRAMS	= bfgminer
 
+sbin_SCRIPTS =
+
 bfgminer_LDFLAGS	= $(PTHREAD_FLAGS)
 bfgminer_LDADD	= $(DLOPEN_FLAGS) @LIBCURL_LIBS@ @JANSSON_LIBS@ @PTHREAD_LIBS@ \
 		  @NCURSES_LIBS@ @PDCURSES_LIBS@ @WS2_LIBS@ \
@@ -301,6 +303,10 @@ endif
 
 if NEED_BFG_LOWL_PCI
 bfgminer_SOURCES += lowl-pci.c lowl-pci.h
+
+if USE_VFIO
+sbin_SCRIPTS += setup-vfio
+endif
 endif
 
 bin_PROGRAMS += bfgminer-rpc

+ 8 - 2
README.ASIC

@@ -209,8 +209,14 @@ To enable uio on your cards, you may need to do:
     sudo modprobe uio_pci_generic
     echo 1cf9 0001 | sudo tee /sys/bus/pci/drivers/uio_pci_generic/new_id
 
-Enabling vfio is similar, but more complicated, but allows you to run BFGMiner
-without root privileges. First, load the kernel module:
+Enabling vfio is similar, but allows you to run BFGMiner without root
+privileges. Since setting this up is more complicated, BFGMiner includes a
+setup-vfio script (which must be run with root permissions). Simply run:
+    sudo setup-vfio --unsafe --user $(whoami) 1cf9 0001
+You will be asked about each Monarch found, and must answer 'yes' to each one.
+
+If you wish to manually setup VFIO, follow these steps:
+First, load the kernel module:
     sudo modprobe vfio-pci
 Next, identify what the device ids are for your card(s):
     lspci -D | grep 1cf9  # the first number of each line is the device id

+ 1 - 0
configure.ac

@@ -1031,6 +1031,7 @@ if test x$need_lowl_pci = xyes; then
 		AC_DEFINE([USE_VFIO], [1], [Defined to 1 if lowlevel PCI drivers should support VFIO])
 	fi
 fi
+AM_CONDITIONAL([USE_VFIO], [test x$need_lowl_pci$vfio = xyesyes])
 
 lowllist="$lowllist usb/need_lowl_usb"
 if test x$need_lowl_usb = xyes; then

+ 117 - 0
setup-vfio

@@ -0,0 +1,117 @@
+#!/bin/bash
+
+DEVICES_PATH=/sys/bus/pci/devices
+VFIO_MODULE="vfio-pci"
+VFIO_PCI_NEW_ID=/sys/bus/pci/drivers/${VFIO_MODULE}/new_id
+Interactive=true
+UnsafeInts=false
+CHOWN_USER=
+
+die() {
+	echo "$@" >&2
+	exit 1
+}
+
+dieusage() {
+	die "Usage: $0 [--unsafe] [--user <username>] [--yes] <vendor> <device>"
+}
+
+yesno() {
+	if ! $Interactive; then
+		$2
+		return
+	fi
+	while true; do
+		echo -n "$1 "
+		read answer
+		case "$answer" in
+		yes|y|ye)
+			return 0
+			;;
+		no|n)
+			return 1
+			;;
+		*)
+			echo "Please enter 'yes' or 'no'."
+		esac
+	done
+}
+
+while [ "$#" -gt 0 ]; do
+	case "$1" in
+	--help|-h)
+		dieusage
+		;;
+	--unsafe)
+		UnsafeInts=true
+		;;
+	--user|-u)
+		shift
+		CHOWN_USER="$1"
+		;;
+	--yes|-y)
+		Interactive=false
+		;;
+	*)
+		if [ -n "$WANT_VENDOR" ]; then
+			WANT_DEVICE="$1"
+		else
+			WANT_VENDOR="$1"
+		fi
+		;;
+	esac
+	shift
+done
+
+[ -n "$WANT_DEVICE" ] || dieusage
+
+modprobe ${VFIO_MODULE} || die 'Failed to load ${VFIO_MODULE} module'
+for TARGET_DEVICE_ID in $(ls $DEVICES_PATH); do
+	{ grep -q '^0x'"${WANT_VENDOR}" "${DEVICES_PATH}/${TARGET_DEVICE_ID}/vendor" && grep -q '^0x'"${WANT_DEVICE}" "${DEVICES_PATH}/${TARGET_DEVICE_ID}/device"; } || continue
+	
+	echo "Found $(lspci -s "$TARGET_DEVICE_ID")"
+	extradevs=
+	extradevsn=0
+	extradevsq=
+	for RELATED_DEVICE_ID in $(ls "${DEVICES_PATH}/${TARGET_DEVICE_ID}/iommu_group/devices/"); do
+		if [ "$RELATED_DEVICE_ID" = "$TARGET_DEVICE_ID" ] ||
+		 {
+		  { ! [ -e "${DEVICES_PATH}/${RELATED_DEVICE_ID}/driver" ]; } ||
+		  [ "$(basename "$(readlink "${DEVICES_PATH}/${RELATED_DEVICE_ID}/driver")")" = "${VFIO_MODULE}" ]
+		 } ||
+		 grep -q '^0x060400$' "${DEVICES_PATH}/${RELATED_DEVICE_ID}/class"; then
+			extradevsq="$extradevsq $RELATED_DEVICE_ID"
+		else
+			extradevs="$extradevs $RELATED_DEVICE_ID"
+			let ++extradevsn
+		fi
+	done
+	if [ "$extradevsn" -gt 0 ]; then
+		if [ $extradevsn -gt 1 ]; then
+			echo "Enabling VFIO for this device will also disable the following $extradevsn devices:"
+		else
+			echo "Enabling VFIO for this device will also disable this device:"
+		fi
+		for RELATED_DEVICE_ID in ${extradevs}; do
+			echo "- $(lspci -s "$RELATED_DEVICE_ID")"
+		done
+	fi
+	yesno 'Enable VFIO?' true || continue
+	
+	if $UnsafeInts; then
+		echo 1 >/sys/module/vfio_iommu_type1/parameters/allow_unsafe_interrupts || die 'Failed to enable unsafe interrupts'
+	fi
+	for RELATED_DEVICE_ID in ${extradevsq} ${extradevs}; do
+		if [ -e "${DEVICES_PATH}/${RELATED_DEVICE_ID}/driver" ]; then
+			echo "$RELATED_DEVICE_ID" >"${DEVICES_PATH}/${RELATED_DEVICE_ID}/driver/unbind" || die "Failed to unbind $RELATED_DEVICE_ID"
+			echo "$(<"${DEVICES_PATH}/${RELATED_DEVICE_ID}/vendor") $(<"${DEVICES_PATH}/${RELATED_DEVICE_ID}/device")" >"${VFIO_PCI_NEW_ID}" || die "Failed to associate device id with ${VFIO_MODULE} module"
+		fi
+	done
+	IOMMU_GROUP="$(basename "$(readlink "${DEVICES_PATH}/${TARGET_DEVICE_ID}/iommu_group")")"
+	VFIO_DEVICE="/dev/vfio/$IOMMU_GROUP"
+	[ -e "$VFIO_DEVICE" ] || die "$VFIO_DEVICE does not exist"
+	if [ -n "${CHOWN_USER}" ]; then
+		chown "${CHOWN_USER}" "$VFIO_DEVICE" || die "Failed to chown $VFIO_DEVICE to $CHOWN_USER"
+	fi
+	echo "VFIO enabled on $VFIO_DEVICE"
+done