Browse Source

Merge branch 'monarch_201407' into bfgminer

Luke Dashjr 11 years ago
parent
commit
cd129d51d2
6 changed files with 168 additions and 17 deletions
  1. 6 0
      Makefile.am
  2. 15 8
      README.ASIC
  3. 1 0
      configure.ac
  4. 19 3
      driver-bitforce.c
  5. 10 6
      lowl-pci.c
  6. 117 0
      setup-vfio

+ 6 - 0
Makefile.am

@@ -41,6 +41,8 @@ INCLUDES	= -fno-strict-aliasing
 
 
 bin_PROGRAMS	= bfgminer
 bin_PROGRAMS	= bfgminer
 
 
+sbin_SCRIPTS =
+
 if HAVE_WINDOWS
 if HAVE_WINDOWS
 else
 else
 bin_SCRIPTS = start-bfgminer.sh
 bin_SCRIPTS = start-bfgminer.sh
@@ -354,6 +356,10 @@ endif
 
 
 if NEED_BFG_LOWL_PCI
 if NEED_BFG_LOWL_PCI
 bfgminer_SOURCES += lowl-pci.c lowl-pci.h
 bfgminer_SOURCES += lowl-pci.c lowl-pci.h
+
+if USE_VFIO
+sbin_SCRIPTS += setup-vfio
+endif
 endif
 endif
 
 
 if NEED_BFG_LOWL_SPI
 if NEED_BFG_LOWL_SPI

+ 15 - 8
README.ASIC

@@ -200,22 +200,29 @@ To enable uio on your cards, you may need to do:
     sudo modprobe uio_pci_generic
     sudo modprobe uio_pci_generic
     echo 1cf9 0001 | sudo tee /sys/bus/pci/drivers/uio_pci_generic/new_id
     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 and tell it to accept the
-Monarch:
+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
     sudo modprobe vfio-pci
-    echo 1cf9 0001 | sudo tee /sys/bus/pci/drivers/vfio-pci/new_id
 Next, identify what the device ids are for your card(s):
 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
     lspci -D | grep 1cf9  # the first number of each line is the device id
 From that, you can identify its IOMMU group, and list all devices sharing that
 From that, you can identify its IOMMU group, and list all devices sharing that
 group:
 group:
-    readlink /sys/bus/pci/devices/<device_id>/iommu_group
-    ls /sys/kernel/iommu_groups/<iommu_group>/devices/
+    readlink "/sys/bus/pci/devices/$DEVICE_ID/iommu_group"
+    ls "/sys/kernel/iommu_groups/$IOMMU_GROUP_ID/devices/"
 All of the devices listed (other than the Monarch), if any, will need to be
 All of the devices listed (other than the Monarch), if any, will need to be
 disabled and unbound! To do that, use:
 disabled and unbound! To do that, use:
-    echo <device_id> | sudo tee /sys/bus/pci/devices/<device_id>/driver/unbind
+    echo "$DEVICE_ID" | sudo tee "/sys/bus/pci/devices/$DEVICE_ID/driver/unbind"
+    echo "$DEVICE_CODE" | sudo tee /sys/bus/pci/drivers/vfio-pci/new_id
+Note that $DEVICE_ID should be something like "0000:01:00.0" and $DEVICE_CODE is
+something like "1cf9 0001" (this example is the Monarch itself).
 If you want to run BFGMiner as a normal user:
 If you want to run BFGMiner as a normal user:
-    chown <username> /dev/vfio/<iommu_group>
+    chown "$USERNAME" "/dev/vfio/$IOMMU_GROUP_ID"
 Depending on your system, you may also need to do:
 Depending on your system, you may also need to do:
     echo 1 | sudo tee /sys/module/vfio_iommu_type1/parameters/allow_unsafe_interrupts
     echo 1 | sudo tee /sys/module/vfio_iommu_type1/parameters/allow_unsafe_interrupts
 
 

+ 1 - 0
configure.ac

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

+ 19 - 3
driver-bitforce.c

@@ -92,6 +92,7 @@ struct bitforce_data {
 	bool is_open;
 	bool is_open;
 	struct lowl_pci_handle *lph;
 	struct lowl_pci_handle *lph;
 	uint8_t lasttag;
 	uint8_t lasttag;
+	uint8_t lasttag_read;
 	bytes_t getsbuf;
 	bytes_t getsbuf;
 	int xlink_id;
 	int xlink_id;
 	unsigned char next_work_ob[70];  // Data aligned for 32-bit access
 	unsigned char next_work_ob[70];  // Data aligned for 32-bit access
@@ -219,6 +220,8 @@ bool bitforce_pci_open(struct cgpu_info * const dev)
 	if (!devdata->lph)
 	if (!devdata->lph)
 		return false;
 		return false;
 	devdata->lasttag = (lowl_pci_get_word(devdata->lph, 2, 2) >> 16) & 0xff;
 	devdata->lasttag = (lowl_pci_get_word(devdata->lph, 2, 2) >> 16) & 0xff;
+	devdata->lasttag_read = 0;
+	bytes_reset(&devdata->getsbuf);
 	devdata->is_open = true;
 	devdata->is_open = true;
 	return devdata->is_open;
 	return devdata->is_open;
 }
 }
@@ -242,8 +245,14 @@ void _bitforce_pci_read(struct cgpu_info * const dev)
 	uint32_t resp;
 	uint32_t resp;
 	bytes_t *b = &devdata->getsbuf;
 	bytes_t *b = &devdata->getsbuf;
 	
 	
-	if (!bytes_len(&devdata->getsbuf))
+	if (devdata->lasttag != devdata->lasttag_read)
 	{
 	{
+		if (unlikely(bytes_len(b)))
+		{
+			applog(LOG_WARNING, "%s: %ld bytes remaining in read buffer at new command", dev->dev_repr, (long)bytes_len(&devdata->getsbuf));
+			bytes_reset(b);
+		}
+		
 		while (((resp = lowl_pci_get_word(devdata->lph, 2, 2)) & 0xff0000) != looking_for)
 		while (((resp = lowl_pci_get_word(devdata->lph, 2, 2)) & 0xff0000) != looking_for)
 			cgsleep_ms(1);
 			cgsleep_ms(1);
 		
 		
@@ -254,6 +263,8 @@ void _bitforce_pci_read(struct cgpu_info * const dev)
 		void * const buf = bytes_preappend(b, resp + LOWL_PCI_GET_DATA_PADDING);
 		void * const buf = bytes_preappend(b, resp + LOWL_PCI_GET_DATA_PADDING);
 		if (lowl_pci_read_data(devdata->lph, buf, resp, 1, 0))
 		if (lowl_pci_read_data(devdata->lph, buf, resp, 1, 0))
 			bytes_postappend(b, resp);
 			bytes_postappend(b, resp);
+		
+		devdata->lasttag_read = devdata->lasttag;
 	}
 	}
 }
 }
 
 
@@ -349,7 +360,12 @@ ssize_t bitforce_read(struct cgpu_info * const proc, void * const buf, const siz
 	ssize_t rv;
 	ssize_t rv;
 	
 	
 	if (likely(devdata->is_open))
 	if (likely(devdata->is_open))
-		rv = devdata->lowlif->read(buf, bufLen, dev);
+	{
+		if (bufLen == 0)
+			rv = 0;
+		else
+			rv = devdata->lowlif->read(buf, bufLen, dev);
+	}
 	else
 	else
 		rv = -1;
 		rv = -1;
 	
 	
@@ -1635,7 +1651,7 @@ static bool bitforce_thread_init(struct thr_info *thr)
 		bitforce->sleep_ms = BITFORCE_SLEEP_MS;
 		bitforce->sleep_ms = BITFORCE_SLEEP_MS;
 		bitforce->device_data = data = malloc(sizeof(*data));
 		bitforce->device_data = data = malloc(sizeof(*data));
 		*data = (struct bitforce_data){
 		*data = (struct bitforce_data){
-			.lowlif = &bfllif_vcom,
+			.lowlif = initdata->lowlif,
 			.xlink_id = xlink_id,
 			.xlink_id = xlink_id,
 			.next_work_ob = ">>>>>>>>|---------- MidState ----------||-DataTail-||Nonces|>>>>>>>>",
 			.next_work_ob = ">>>>>>>>|---------- MidState ----------||-DataTail-||Nonces|>>>>>>>>",
 			.proto = BFP_RANGE,
 			.proto = BFP_RANGE,

+ 10 - 6
lowl-pci.c

@@ -102,7 +102,7 @@ struct lowl_pci_handle {
 	off_t baroff[6];
 	off_t baroff[6];
 #endif
 #endif
 #ifdef USE_LOWL_PCI_MMAP
 #ifdef USE_LOWL_PCI_MMAP
-	uint32_t *bar[6];
+	volatile uint32_t *bar[6];
 	size_t barsz[6];
 	size_t barsz[6];
 #endif
 #endif
 };
 };
@@ -113,20 +113,24 @@ void lowl_pci_close_mmap(struct lowl_pci_handle * const lph)
 {
 {
 	for (int i = 0; i < 6; ++i)
 	for (int i = 0; i < 6; ++i)
 		if (lph->bar[i])
 		if (lph->bar[i])
-			munmap(lph->bar[i], lph->barsz[i]);
+			munmap((void*)lph->bar[i], lph->barsz[i]);
 	free(lph);
 	free(lph);
 }
 }
 
 
 static
 static
 const uint32_t *lowl_pci_get_words_mmap(struct lowl_pci_handle * const lph, void * const buf, const size_t words, const int bar, const off_t offset)
 const uint32_t *lowl_pci_get_words_mmap(struct lowl_pci_handle * const lph, void * const buf, const size_t words, const int bar, const off_t offset)
 {
 {
-	return &lph->bar[bar][offset];
+	volatile uint32_t *src = &lph->bar[bar][offset];
+	uint32_t *dest = buf;
+	for (int i = 0; i < words; ++i)
+		*(dest++) = *(src++);
+	return buf;
 }
 }
 
 
 static
 static
 bool lowl_pci_set_words_mmap(struct lowl_pci_handle * const lph, const uint32_t *buf, const size_t words, const int bar, const off_t offset)
 bool lowl_pci_set_words_mmap(struct lowl_pci_handle * const lph, const uint32_t *buf, const size_t words, const int bar, const off_t offset)
 {
 {
-	uint32_t *dest = &lph->bar[bar][offset];
+	volatile uint32_t *dest = &lph->bar[bar][offset];
 	for (int i = 0; i < words; ++i)
 	for (int i = 0; i < words; ++i)
 		*(dest++) = *(buf++);
 		*(dest++) = *(buf++);
 	return true;
 	return true;
@@ -242,7 +246,7 @@ struct lowl_pci_handle *lowl_pci_open_uio(const char * const path, const struct
 err:
 err:
 	for (int i = 0; i < 6; ++i)
 	for (int i = 0; i < 6; ++i)
 		if (lph->bar[i])
 		if (lph->bar[i])
-			munmap(lph->bar[i], lph->barsz[i]);
+			munmap((void*)lph->bar[i], lph->barsz[i]);
 	free(lph);
 	free(lph);
 	return NULL;
 	return NULL;
 }
 }
@@ -396,7 +400,7 @@ struct lowl_pci_handle *lowl_pci_open_vfio(const char * const path, const struct
 err:
 err:
 	for (int i = 0; i < 6; ++i)
 	for (int i = 0; i < 6; ++i)
 		if (lph->bar[i])
 		if (lph->bar[i])
-			munmap(lph->bar[i], lph->barsz[i]);
+			munmap((void*)lph->bar[i], lph->barsz[i]);
 	if (device != -1)
 	if (device != -1)
 		close(device);
 		close(device);
 	if (group != -1)
 	if (group != -1)

+ 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"
+		fi
+		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"
+	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