Browse Source

BitForce FPGA support

cgminer will scan for and mine BitForce FPGAs on USB ports by providing the
new --scan-serial <device> option, or autodetect them by searching
/dev/serial/by-id for *BitFORCE_SHA256*
nfactor-troky
Luke Dashjr 13 years ago
parent
commit
5dfc8b694f
  1. 4
      Makefile.am
  2. 219
      bitforce.c
  3. 16
      configure.ac
  4. 29
      main.c
  5. 31
      miner.h

4
Makefile.am

@ -60,3 +60,7 @@ AM_CFLAGS = -DHAS_YASM
endif endif
endif endif
endif endif
if USE_BITFORCE
cgminer_SOURCES += bitforce.c
endif

219
bitforce.c

@ -0,0 +1,219 @@
/*
* Copyright 2012 Luke Dashjr
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version. See COPYING for more details.
*/
#include <limits.h>
#include <pthread.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <dirent.h>
#include <termios.h>
#include <unistd.h>
#include "elist.h"
#include "miner.h"
struct device_api bitforce_api;
static bool bitforce_detect_one(const char *devpath)
{
char pdevbuf[0x100];
int i = 0;
if (total_devices == MAX_DEVICES)
return false;
FILE *fileDev = fopen(devpath, "r+b");
if (unlikely(!fileDev))
{
applog(LOG_DEBUG, "BitForce Detect: Failed to open %s", devpath);
return false;
}
setbuf(fileDev, NULL);
fprintf(fileDev, "ZGX");
if (!fgets(pdevbuf, sizeof(pdevbuf), fileDev))
{
applog(LOG_ERR, "Error reading from BitForce (ZGX)");
return 0;
}
fclose(fileDev);
if (unlikely(!strstr(pdevbuf, "SHA256")))
{
applog(LOG_DEBUG, "BitForce Detect: Didn't recognize BitForce on %s", devpath);
return false;
}
// We have a real BitForce!
struct cgpu_info *bitforce;
bitforce = calloc(1, sizeof(*bitforce));
devices[total_devices++] = bitforce;
bitforce->api = &bitforce_api;
bitforce->device_id = i++;
bitforce->device_path = strdup(devpath);
bitforce->enabled = true;
bitforce->threads = 1;
return true;
}
static void bitforce_detect_auto()
{
DIR *D;
struct dirent *de;
const char udevdir[] = "/dev/serial/by-id";
char devpath[sizeof(udevdir) + 1 + NAME_MAX];
char *devfile = devpath + sizeof(udevdir);
D = opendir(udevdir);
if (!D)
return;
memcpy(devpath, udevdir, sizeof(udevdir) - 1);
devpath[sizeof(udevdir) - 1] = '/';
while ( (de = readdir(D)) ) {
if (!strstr(de->d_name, "BitFORCE_SHA256"))
continue;
strcpy(devfile, de->d_name);
bitforce_detect_one(devpath);
}
closedir(D);
}
static void bitforce_detect()
{
struct string_elist *iter, *tmp;
list_for_each_entry_safe(iter, tmp, &scan_devices, list) {
if (bitforce_detect_one(iter->string))
string_elist_del(iter);
}
bitforce_detect_auto();
}
static bool bitforce_thread_prepare(struct thr_info *thr)
{
struct cgpu_info *bitforce = thr->cgpu;
struct timeval now;
FILE *fileDev = fopen(bitforce->device_path, "r+b");
if (unlikely(!fileDev))
{
applog(LOG_ERR, "Failed to open BitForce on %s", bitforce->device_path);
return false;
}
{
int nDevFD = fileno(fileDev);
struct termios pattr;
tcgetattr(nDevFD, &pattr);
pattr.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
pattr.c_oflag &= ~OPOST;
pattr.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
pattr.c_cflag &= ~(CSIZE | PARENB);
pattr.c_cflag |= CS8;
tcsetattr(nDevFD, TCSANOW, &pattr);
}
setbuf(fileDev, NULL);
bitforce->device_file = fileDev;
applog(LOG_INFO, "Opened BitForce on %s", bitforce->device_path);
gettimeofday(&now, NULL);
get_datestamp(bitforce->init, &now);
return true;
}
static uint64_t bitforce_scanhash(struct thr_info *thr, struct work *work, uint64_t max_nonce)
{
struct cgpu_info *bitforce = thr->cgpu;
FILE *fileDev = bitforce->device_file;
char pdevbuf[0x100];
unsigned char ob[61] = ">>>>>>>>12345678901234567890123456789012123456789012>>>>>>>>";
int i;
char *pnoncebuf;
uint32_t nonce;
fprintf(fileDev, "ZDX");
if (!fgets(pdevbuf, sizeof(pdevbuf), fileDev)) {
applog(LOG_ERR, "Error reading from BitForce (ZDX)");
return 0;
}
if (unlikely(pdevbuf[0] != 'O' || pdevbuf[1] != 'K'))
{
applog(LOG_ERR, "BitForce ZDX reports: %s", pdevbuf);
return 0;
}
memcpy(ob + 8, work->midstate, 32);
memcpy(ob + 8 + 32, work->data + 64, 12);
fwrite(ob, 60, 1, fileDev);
applog(LOG_DEBUG, "BitForce block data: %s", bin2hex(ob + 8, 44));
if (!fgets(pdevbuf, sizeof(pdevbuf), fileDev))
{
applog(LOG_ERR, "Error reading from BitForce (block data)");
return 0;
}
if (unlikely(pdevbuf[0] != 'O' || pdevbuf[1] != 'K'))
{
applog(LOG_ERR, "BitForce block data reports: %s", pdevbuf);
return 0;
}
usleep(4500000);
i = 4500;
while (1) {
fprintf(fileDev, "ZFX");
if (!fgets(pdevbuf, sizeof(pdevbuf), fileDev))
{
applog(LOG_ERR, "Error reading from BitForce (ZFX)");
return 0;
}
if (pdevbuf[0] != 'B')
break;
usleep(10000);
i += 10;
}
applog(LOG_DEBUG, "BitForce waited %dms until %s\n", i, pdevbuf);
work->blk.nonce = 0xffffffff;
if (pdevbuf[2] == '-')
return 0xffffffff;
else
if (strncasecmp(pdevbuf, "NONCE-FOUND", 11)) {
applog(LOG_ERR, "BitForce result reports: %s", pdevbuf);
return 0;
}
pnoncebuf = &pdevbuf[12];
while (1) {
hex2bin((void*)&nonce, pnoncebuf, 4);
#ifndef __BIG_ENDIAN__
nonce = swab32(nonce);
#endif
submit_nonce(thr, work, nonce);
if (pnoncebuf[8] != ',')
break;
pnoncebuf += 9;
}
return 0xffffffff;
}
struct device_api bitforce_api = {
.name = "BFL",
.api_detect = bitforce_detect,
// .reinit_device = TODO
.thread_prepare = bitforce_thread_prepare,
.scanhash = bitforce_scanhash,
};

16
configure.ac

@ -181,6 +181,15 @@ else
DLOPEN_FLAGS="" DLOPEN_FLAGS=""
fi fi
bitforce=yes
AC_ARG_ENABLE([bitforce],
[AC_HELP_STRING([--disable-bitforce],[Don't compile support for BitForce FPGAs])],
[bitforce=$enableval]
)
if test "x$bitforce" != xno; then
AC_DEFINE([USE_BITFORCE], [1], [Defined to 1 if BitForce support is wanted.])
fi
AC_SEARCH_LIBS(addstr, ncurses pdcurses, , AC_SEARCH_LIBS(addstr, ncurses pdcurses, ,
AC_MSG_ERROR([Could not find curses library - please install libncurses-dev or pdcurses-dev])) AC_MSG_ERROR([Could not find curses library - please install libncurses-dev or pdcurses-dev]))
@ -190,6 +199,7 @@ AC_CHECK_LIB(pdcurses, addstr, PDCURSES_LIBS=-lpdcurses)
AM_CONDITIONAL([WANT_JANSSON], [test x$request_jansson = xtrue]) AM_CONDITIONAL([WANT_JANSSON], [test x$request_jansson = xtrue])
AM_CONDITIONAL([HAVE_WINDOWS], [test x$have_win32 = xtrue]) AM_CONDITIONAL([HAVE_WINDOWS], [test x$have_win32 = xtrue])
AM_CONDITIONAL([HAVE_x86_64], [test x$have_x86_64 = xtrue]) AM_CONDITIONAL([HAVE_x86_64], [test x$have_x86_64 = xtrue])
AM_CONDITIONAL([USE_BITFORCE], [test x$bitforce != xno])
if test x$request_jansson = xtrue if test x$request_jansson = xtrue
then then
@ -312,18 +322,20 @@ echo
echo "Configuration Options Summary:" echo "Configuration Options Summary:"
echo echo
echo " BitForce.FPGAs.......: $bitforce"
if test "x$opencl" != xno; then if test "x$opencl" != xno; then
if test $found_opencl = 1; then if test $found_opencl = 1; then
echo " OpenCL...............: FOUND. GPU mining support enabled" echo " OpenCL...............: FOUND. GPU mining support enabled"
else else
echo " OpenCL...............: NOT FOUND. GPU mining support DISABLED" echo " OpenCL...............: NOT FOUND. GPU mining support DISABLED"
if test "x$cpumining" != xyes; then if test "x$cpumining$bitforce" = xnono; then
AC_MSG_ERROR([No mining configured in]) AC_MSG_ERROR([No mining configured in])
fi fi
fi fi
else else
echo " OpenCL...............: Detection overrided. GPU mining support DISABLED" echo " OpenCL...............: Detection overrided. GPU mining support DISABLED"
if test "x$cpumining" != xyes; then if test "x$cpumining$bitforce" = xnono; then
AC_MSG_ERROR([No mining configured in]) AC_MSG_ERROR([No mining configured in])
fi fi
fi fi

29
main.c

@ -216,6 +216,7 @@ static bool opt_restart = true;
static bool opt_nogpu; static bool opt_nogpu;
#endif #endif
struct list_head scan_devices;
int nDevs; int nDevs;
static int opt_g_threads = 2; static int opt_g_threads = 2;
static signed int devices_enabled = 0; static signed int devices_enabled = 0;
@ -1003,6 +1004,12 @@ static char *set_float_0_to_99(const char *arg, float *f)
return NULL; return NULL;
} }
static char *add_serial(char *arg)
{
string_elist_add(arg, &scan_devices);
return NULL;
}
static char *set_devices(char *arg) static char *set_devices(char *arg)
{ {
int i = strtol(arg, &arg, 0); int i = strtol(arg, &arg, 0);
@ -1670,6 +1677,11 @@ static struct opt_table opt_config_table[] = {
OPT_WITHOUT_ARG("--round-robin", OPT_WITHOUT_ARG("--round-robin",
set_rr, &pool_strategy, set_rr, &pool_strategy,
"Change multipool strategy from failover to round robin on failure"), "Change multipool strategy from failover to round robin on failure"),
#ifdef USE_BITFORCE
OPT_WITH_ARG("--scan-serial|-S",
add_serial, NULL, NULL,
"Serial port to probe for BitForce device"),
#endif
OPT_WITH_ARG("--scan-time|-s", OPT_WITH_ARG("--scan-time|-s",
set_int_0_to_9999, opt_show_intval, &opt_scantime, set_int_0_to_9999, opt_show_intval, &opt_scantime,
"Upper bound on time spent scanning current work, in seconds"), "Upper bound on time spent scanning current work, in seconds"),
@ -4340,6 +4352,7 @@ static inline bool abandon_work(int thr_id, struct work *work, struct timeval *w
{ {
if (wdiff->tv_sec > opt_scantime || if (wdiff->tv_sec > opt_scantime ||
work->blk.nonce >= MAXTHREADS - hashes || work->blk.nonce >= MAXTHREADS - hashes ||
hashes >= 0xfffffffe ||
stale_work(work, false)) stale_work(work, false))
return true; return true;
return false; return false;
@ -4432,7 +4445,7 @@ static void *miner_thread(void *userdata)
} }
} }
if (sdiff.tv_sec < cycle) { if (unlikely(sdiff.tv_sec < cycle)) {
if (likely(!api->can_limit_work || max_nonce == 0xffffffff)) if (likely(!api->can_limit_work || max_nonce == 0xffffffff))
continue; continue;
@ -5386,7 +5399,7 @@ static void cpu_detect()
#endif /* !WIN32 */ #endif /* !WIN32 */
if (opt_n_threads < 0 || !forced_n_threads) { if (opt_n_threads < 0 || !forced_n_threads) {
if (nDevs && !opt_usecpu) if (total_devices && !opt_usecpu)
opt_n_threads = 0; opt_n_threads = 0;
else else
opt_n_threads = num_processors; opt_n_threads = num_processors;
@ -5803,6 +5816,12 @@ struct device_api opencl_api = {
}; };
#endif #endif
#ifdef USE_BITFORCE
extern struct device_api bitforce_api;
#endif
static int cgminer_id_count = 0; static int cgminer_id_count = 0;
void enable_device(struct cgpu_info *cgpu) void enable_device(struct cgpu_info *cgpu)
@ -5877,6 +5896,8 @@ int main (int argc, char *argv[])
HASH_ADD_STR(blocks, hash, block); HASH_ADD_STR(blocks, hash, block);
strcpy(current_block, block->hash); strcpy(current_block, block->hash);
INIT_LIST_HEAD(&scan_devices);
memset(gpus, 0, sizeof(gpus)); memset(gpus, 0, sizeof(gpus));
for (i = 0; i < MAX_GPUDEVICES; i++) for (i = 0; i < MAX_GPUDEVICES; i++)
gpus[i].dynamic = true; gpus[i].dynamic = true;
@ -5946,6 +5967,10 @@ int main (int argc, char *argv[])
opencl_api.api_detect(); opencl_api.api_detect();
#endif #endif
#ifdef USE_BITFORCE
bitforce_api.api_detect();
#endif
#ifdef WANT_CPUMINE #ifdef WANT_CPUMINE
cpu_api.api_detect(); cpu_api.api_detect();
#endif #endif

31
miner.h

@ -236,6 +236,9 @@ struct cgpu_info {
int cgminer_id; int cgminer_id;
struct device_api *api; struct device_api *api;
int device_id; int device_id;
char *device_path;
FILE *device_file;
bool enabled; bool enabled;
int accepted; int accepted;
int rejected; int rejected;
@ -297,6 +300,32 @@ struct thr_info {
extern int thr_info_create(struct thr_info *thr, pthread_attr_t *attr, void *(*start) (void *), void *arg); extern int thr_info_create(struct thr_info *thr, pthread_attr_t *attr, void *(*start) (void *), void *arg);
extern void thr_info_cancel(struct thr_info *thr); extern void thr_info_cancel(struct thr_info *thr);
struct string_elist {
char *string;
bool free_me;
struct list_head list;
};
static inline void string_elist_add(const char *s, struct list_head *head)
{
struct string_elist *n;
n = calloc(1, sizeof(*n));
n->string = strdup(s);
n->free_me = true;
list_add_tail(&n->list, head);
}
static inline void string_elist_del(struct string_elist *item)
{
if (item->free_me)
free(item->string);
list_del(&item->list);
}
static inline uint32_t swab32(uint32_t v) static inline uint32_t swab32(uint32_t v)
{ {
return bswap_32(v); return bswap_32(v);
@ -468,6 +497,7 @@ extern void api(void);
#define MAX_DEVICES 32 #define MAX_DEVICES 32
#define MAX_POOLS (32) #define MAX_POOLS (32)
extern struct list_head scan_devices;
extern int nDevs; extern int nDevs;
extern int opt_n_threads; extern int opt_n_threads;
extern int num_processors; extern int num_processors;
@ -581,6 +611,7 @@ enum cl_kernel {
KL_PHATK, KL_PHATK,
}; };
extern void get_datestamp(char *, struct timeval *);
bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce); bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce);
extern void wlogprint(const char *f, ...); extern void wlogprint(const char *f, ...);
extern int curses_int(const char *query); extern int curses_int(const char *query);

Loading…
Cancel
Save