Browse Source

bitforce: Support for PCI interface via UIO

Luke Dashjr 12 years ago
parent
commit
e6dbe977e5
2 changed files with 153 additions and 0 deletions
  1. 1 0
      configure.ac
  2. 152 0
      driver-bitforce.c

+ 1 - 0
configure.ac

@@ -79,6 +79,7 @@ dnl Checks for header files.
 AC_HEADER_STDC
 AC_HEADER_STDC
 AC_CHECK_HEADERS(syslog.h)
 AC_CHECK_HEADERS(syslog.h)
 AC_CHECK_HEADERS([sys/epoll.h])
 AC_CHECK_HEADERS([sys/epoll.h])
+AC_CHECK_HEADERS([sys/mman.h])
 AC_CHECK_HEADERS([sys/prctl.h])
 AC_CHECK_HEADERS([sys/prctl.h])
 AC_CHECK_HEADERS([sys/file.h])
 AC_CHECK_HEADERS([sys/file.h])
 AC_CHECK_HEADERS([linux/spi/spidev.h])
 AC_CHECK_HEADERS([linux/spi/spidev.h])

+ 152 - 0
driver-bitforce.c

@@ -20,6 +20,14 @@
 #include <sys/time.h>
 #include <sys/time.h>
 #include <unistd.h>
 #include <unistd.h>
 
 
+#ifdef HAVE_SYS_MMAN_H
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#endif
+
 #include "compat.h"
 #include "compat.h"
 #include "deviceapi.h"
 #include "deviceapi.h"
 #include "miner.h"
 #include "miner.h"
@@ -81,6 +89,9 @@ struct bitforce_lowl_interface {
 struct bitforce_data {
 struct bitforce_data {
 	struct bitforce_lowl_interface *lowlif;
 	struct bitforce_lowl_interface *lowlif;
 	bool is_open;
 	bool is_open;
+	volatile uint32_t *bar[3];
+	uint8_t lasttag;
+	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
 	unsigned char *next_work_obs;    // Start of data to send
 	unsigned char *next_work_obs;    // Start of data to send
@@ -163,6 +174,147 @@ static struct bitforce_lowl_interface bfllif_vcom = {
 	.write = bitforce_vcom_write,
 	.write = bitforce_vcom_write,
 };
 };
 
 
+#ifdef HAVE_SYS_MMAN_H
+static
+void *bitforce_mmap_bar(const char * const devpath, const int bar, const size_t sz, const int prot)
+{
+	char buf[0x100];
+	snprintf(buf, sizeof(buf), "/sys/bus/pci/devices/%s/resource%d", devpath, bar);
+	const int fd = open(buf, O_RDWR);
+	if (fd == -1)
+		return MAP_FAILED;
+	void * const rv = mmap(NULL, sz, prot, MAP_SHARED, fd, 0);
+	close(fd);
+	return rv;
+}
+
+static
+bool bitforce_uio_open(struct cgpu_info * const dev)
+{
+	struct bitforce_data * const devdata = dev->device_data;
+	const char * const devpath = dev->device_path;
+	devdata->bar[0] = bitforce_mmap_bar(devpath, 0, 0x1000, PROT_WRITE);
+	if (devdata->bar[0] == MAP_FAILED)
+	{
+		applog(LOG_ERR, "%s: mmap bar 0 failed", dev->dev_repr);
+mapfailA:
+		devdata->bar[0] = NULL;
+		return false;
+	}
+	devdata->bar[1] = bitforce_mmap_bar(devpath, 1, 0x1000, PROT_READ);
+	if (devdata->bar[1] == MAP_FAILED)
+	{
+		applog(LOG_ERR, "%s: mmap bar 1 failed", dev->dev_repr);
+mapfailB:
+		munmap((void*)devdata->bar[0], 0x1000);
+		goto mapfailA;
+	}
+	devdata->bar[2] = bitforce_mmap_bar(devpath, 2,   0x80, PROT_READ | PROT_WRITE);
+	if (devdata->bar[2] == MAP_FAILED)
+	{
+		applog(LOG_ERR, "%s: mmap bar 2 failed", dev->dev_repr);
+		munmap((void*)devdata->bar[1], 0x1000);
+		goto mapfailB;
+	}
+	devdata->is_open = true;
+	return devdata->is_open;
+}
+
+static
+void bitforce_uio_close(struct cgpu_info * const dev)
+{
+	struct bitforce_data * const devdata = dev->device_data;
+	if (devdata->is_open)
+	{
+		munmap((void*)devdata->bar[0], 0x1000);
+		munmap((void*)devdata->bar[1], 0x1000);
+		munmap((void*)devdata->bar[2],   0x80);
+		devdata->is_open = false;
+	}
+}
+
+static
+void bitforce_uio_gets(char * const buf, size_t bufLen, struct cgpu_info * const dev)
+{
+	struct bitforce_data * const devdata = dev->device_data;
+	const volatile uint32_t * const respreg = &devdata->bar[2][2];
+	const volatile uint32_t *respdata = devdata->bar[1];
+	const uint32_t looking_for = (uint32_t)devdata->lasttag << 0x10;
+	uint32_t resp;
+	bytes_t *b = &devdata->getsbuf;
+	
+	if (!bytes_len(&devdata->getsbuf))
+	{
+		while (((resp = *respreg) & 0xff0000) != looking_for)
+			cgsleep_ms(1);
+		
+		resp &= 0xffff;
+		if (unlikely(resp > 0x1000))
+			resp = 0x1000;
+		
+		const uint32_t respwords = (resp + 3) / 4;
+		swap32tobe(bytes_preappend(b, respwords * 4), (void*)respdata, respwords);
+		bytes_postappend(b, resp);
+	}
+	
+	ssize_t linelen = (bytes_find(b, '\n') + 1) ?: bytes_len(b);
+	if (linelen > --bufLen)
+		linelen = bufLen;
+	
+	memcpy(buf, bytes_buf(b), linelen);
+	bytes_shift(b, linelen);
+	buf[linelen] = '\0';
+}
+
+static
+ssize_t bitforce_uio_write(struct cgpu_info * const dev, const void * const bufp, ssize_t bufLen)
+{
+	const uint8_t *buf = bufp;
+	struct bitforce_data * const devdata = dev->device_data;
+	volatile uint32_t * const cmdreg = &devdata->bar[2][0];
+	volatile uint32_t * cmdbuf = devdata->bar[0];
+	uint32_t lastu32;
+	
+	if (unlikely(bufLen > 0x1000))
+		return 0;
+	
+	while (bufLen > 3)
+	{
+		*(cmdbuf++) = ((uint32_t)buf[0] << 0x18)
+		            | ((uint32_t)buf[1] << 0x10)
+		            | ((uint16_t)buf[2] <<    8)
+		            | buf[3];
+		buf += 4;
+		bufLen -= 4;
+	}
+	lastu32 = 0;
+	switch (bufLen)
+	{
+		case 3:
+			lastu32 |= ((uint16_t)buf[2] <<    8);
+		case 2:
+			lastu32 |= ((uint32_t)buf[1] << 0x10);
+		case 1:
+			lastu32 |= ((uint32_t)buf[0] << 0x18);
+			*cmdbuf = lastu32;
+		default:
+			;
+	}
+	if (++devdata->lasttag == 0)
+		++devdata->lasttag;
+	*cmdreg = ((uint32_t)devdata->lasttag << 0x10) | bufLen;
+	
+	return bufLen;
+}
+
+static struct bitforce_lowl_interface bfllif_uio = {
+	.open = bitforce_uio_open,
+	.close = bitforce_uio_close,
+	.gets = bitforce_uio_gets,
+	.write = bitforce_uio_write,
+};
+#endif
+
 static
 static
 void bitforce_close(struct cgpu_info * const proc)
 void bitforce_close(struct cgpu_info * const proc)
 {
 {