Browse Source

Merge branch 'bfl'

Conflicts:
	miner.h
nfactor-troky
Con Kolivas 13 years ago
parent
commit
732783faa6
  1. 94
      cgminer.c
  2. 366
      driver-bitforce.c
  3. 7
      miner.h

94
cgminer.c

@ -3373,10 +3373,6 @@ static void hashmeter(int thr_id, struct timeval *diff,
thr_info[thr_id].cgpu->device_last_well = time(NULL); thr_info[thr_id].cgpu->device_last_well = time(NULL);
} }
/* Don't bother calculating anything if we're not displaying it */
if (opt_realquiet || !opt_log_interval)
return;
secs = (double)diff->tv_sec + ((double)diff->tv_usec / 1000000.0); secs = (double)diff->tv_sec + ((double)diff->tv_usec / 1000000.0);
/* So we can call hashmeter from a non worker thread */ /* So we can call hashmeter from a non worker thread */
@ -4170,6 +4166,7 @@ disabled:
tq_pop(mythr->q, NULL); /* Ignore ping that's popped */ tq_pop(mythr->q, NULL); /* Ignore ping that's popped */
thread_reportin(mythr); thread_reportin(mythr);
applog(LOG_WARNING, "Thread %d being re-enabled", thr_id); applog(LOG_WARNING, "Thread %d being re-enabled", thr_id);
if (api->thread_enable) api->thread_enable(mythr);
} }
sdiff.tv_sec = sdiff.tv_usec = 0; sdiff.tv_sec = sdiff.tv_usec = 0;
@ -4455,9 +4452,16 @@ static void age_work(void)
/* Makes sure the hashmeter keeps going even if mining threads stall, updates /* Makes sure the hashmeter keeps going even if mining threads stall, updates
* the screen at regular intervals, and restarts threads if they appear to have * the screen at regular intervals, and restarts threads if they appear to have
* died. */ * died. */
#define WATCHDOG_INTERVAL 3
#define WATCHDOG_SICK_TIME 60
#define WATCHDOG_DEAD_TIME 600
#define WATCHDOG_SICK_COUNT (WATCHDOG_SICK_TIME/WATCHDOG_INTERVAL)
#define WATCHDOG_DEAD_COUNT (WATCHDOG_DEAD_TIME/WATCHDOG_INTERVAL)
#define WATCHDOG_LOW_HASH 1.0 /* consider < 1MH too low for any device */
static void *watchdog_thread(void __maybe_unused *userdata) static void *watchdog_thread(void __maybe_unused *userdata)
{ {
const unsigned int interval = 3; const unsigned int interval = WATCHDOG_INTERVAL;
struct timeval zero_tv; struct timeval zero_tv;
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
@ -4530,24 +4534,27 @@ static void *watchdog_thread(void __maybe_unused *userdata)
} }
} }
#ifdef HAVE_OPENCL
for (i = 0; i < total_devices; ++i) { for (i = 0; i < total_devices; ++i) {
struct cgpu_info *cgpu = devices[i]; struct cgpu_info *cgpu = devices[i];
struct thr_info *thr = cgpu->thr[0]; struct thr_info *thr = cgpu->thr[0];
enum dev_enable *denable; enum dev_enable *denable;
bool dev_count_well;
bool dev_count_sick;
bool dev_count_dead;
char dev_str[8];
int gpu; int gpu;
if (cgpu->api != &opencl_api) if (cgpu->api->get_stats)
continue; cgpu->api->get_stats(cgpu);
/* Use only one thread per device to determine if the GPU is healthy */
if (i >= nDevs) gpu = cgpu->device_id;
break;
gpu = thr->cgpu->device_id;
denable = &cgpu->deven; denable = &cgpu->deven;
sprintf(dev_str, "%s%d", cgpu->api->name, gpu);
#ifdef HAVE_ADL #ifdef HAVE_ADL
if (adl_active && gpus[gpu].has_adl) if (adl_active && cgpu->has_adl)
gpu_autotune(gpu, denable); gpu_autotune(gpu, denable);
if (opt_debug && gpus[gpu].has_adl) { if (opt_debug && cgpu->has_adl) {
int engineclock = 0, memclock = 0, activity = 0, fanspeed = 0, fanpercent = 0, powertune = 0; int engineclock = 0, memclock = 0, activity = 0, fanspeed = 0, fanpercent = 0, powertune = 0;
float temp = 0, vddc = 0; float temp = 0, vddc = 0;
@ -4556,55 +4563,64 @@ static void *watchdog_thread(void __maybe_unused *userdata)
temp, fanpercent, fanspeed, engineclock, memclock, vddc, activity, powertune); temp, fanpercent, fanspeed, engineclock, memclock, vddc, activity, powertune);
} }
#endif #endif
/* Thread is waiting on getwork or disabled */ /* Thread is waiting on getwork or disabled */
if (thr->getwork || *denable == DEV_DISABLED) if (thr->getwork || *denable == DEV_DISABLED)
continue; continue;
if (gpus[gpu].status != LIFE_WELL && now.tv_sec - thr->last.tv_sec < 60) { if (cgpu->rolling < WATCHDOG_LOW_HASH)
applog(LOG_ERR, "Device %d recovered, GPU %d declared WELL!", i, gpu); cgpu->low_count++;
gpus[gpu].status = LIFE_WELL; else
gpus[gpu].device_last_well = time(NULL); cgpu->low_count = 0;
} else if (now.tv_sec - thr->last.tv_sec > 60 && gpus[gpu].status == LIFE_WELL) {
thr->rolling = thr->cgpu->rolling = 0; dev_count_well = (cgpu->low_count < WATCHDOG_SICK_COUNT);
gpus[gpu].status = LIFE_SICK; dev_count_sick = (cgpu->low_count > WATCHDOG_SICK_COUNT);
applog(LOG_ERR, "Device %d idle for more than 60 seconds, GPU %d declared SICK!", i, gpu); dev_count_dead = (cgpu->low_count > WATCHDOG_DEAD_COUNT);
if (gpus[gpu].status != LIFE_WELL && (now.tv_sec - thr->last.tv_sec < WATCHDOG_SICK_TIME) && dev_count_well) {
applog(LOG_ERR, "%s: Recovered, declaring WELL!", dev_str);
cgpu->status = LIFE_WELL;
cgpu->device_last_well = time(NULL);
} else if (cgpu->status == LIFE_WELL && ((now.tv_sec - thr->last.tv_sec > WATCHDOG_SICK_TIME) || dev_count_sick)) {
thr->rolling = cgpu->rolling = 0;
cgpu->status = LIFE_SICK;
applog(LOG_ERR, "%s: Idle for more than 60 seconds, declaring SICK!", dev_str);
gettimeofday(&thr->sick, NULL); gettimeofday(&thr->sick, NULL);
gpus[gpu].device_last_not_well = time(NULL); cgpu->device_last_not_well = time(NULL);
gpus[gpu].device_not_well_reason = REASON_DEV_SICK_IDLE_60; cgpu->device_not_well_reason = REASON_DEV_SICK_IDLE_60;
gpus[gpu].dev_sick_idle_60_count++; cgpu->dev_sick_idle_60_count++;
#ifdef HAVE_ADL #ifdef HAVE_ADL
if (adl_active && gpus[gpu].has_adl && gpu_activity(gpu) > 50) { if (adl_active && cgpu->has_adl && gpu_activity(gpu) > 50) {
applog(LOG_ERR, "GPU still showing activity suggesting a hard hang."); applog(LOG_ERR, "GPU still showing activity suggesting a hard hang.");
applog(LOG_ERR, "Will not attempt to auto-restart it."); applog(LOG_ERR, "Will not attempt to auto-restart it.");
} else } else
#endif #endif
if (opt_restart) { if (opt_restart) {
applog(LOG_ERR, "Attempting to restart GPU"); applog(LOG_ERR, "%s: Attempting to restart", dev_str);
reinit_device(thr->cgpu); reinit_device(cgpu);
} }
} else if (now.tv_sec - thr->last.tv_sec > 600 && gpus[i].status == LIFE_SICK) { } else if (cgpu->status == LIFE_SICK && ((now.tv_sec - thr->last.tv_sec > WATCHDOG_DEAD_TIME) || dev_count_dead)) {
gpus[gpu].status = LIFE_DEAD; cgpu->status = LIFE_DEAD;
applog(LOG_ERR, "Device %d not responding for more than 10 minutes, GPU %d declared DEAD!", i, gpu); applog(LOG_ERR, "%s: Not responded for more than 10 minutes, declaring DEAD!", dev_str);
gettimeofday(&thr->sick, NULL); gettimeofday(&thr->sick, NULL);
gpus[gpu].device_last_not_well = time(NULL); cgpu->device_last_not_well = time(NULL);
gpus[gpu].device_not_well_reason = REASON_DEV_DEAD_IDLE_600; cgpu->device_not_well_reason = REASON_DEV_DEAD_IDLE_600;
gpus[gpu].dev_dead_idle_600_count++; cgpu->dev_dead_idle_600_count++;
} else if (now.tv_sec - thr->sick.tv_sec > 60 && } else if (now.tv_sec - thr->sick.tv_sec > 60 &&
(gpus[i].status == LIFE_SICK || gpus[i].status == LIFE_DEAD)) { (cgpu->status == LIFE_SICK || cgpu->status == LIFE_DEAD)) {
/* Attempt to restart a GPU that's sick or dead once every minute */ /* Attempt to restart a GPU that's sick or dead once every minute */
gettimeofday(&thr->sick, NULL); gettimeofday(&thr->sick, NULL);
#ifdef HAVE_ADL #ifdef HAVE_ADL
if (adl_active && gpus[gpu].has_adl && gpu_activity(gpu) > 50) { if (adl_active && cgpu->has_adl && gpu_activity(gpu) > 50) {
/* Again do not attempt to restart a device that may have hard hung */ /* Again do not attempt to restart a device that may have hard hung */
} else } else
#endif #endif
if (opt_restart) if (opt_restart)
reinit_device(thr->cgpu); reinit_device(cgpu);
} }
} }
#endif
} }
return NULL; return NULL;
@ -5491,6 +5507,7 @@ begin_bench:
quit(1, "API thread create failed"); quit(1, "API thread create failed");
pthread_detach(thr->pth); pthread_detach(thr->pth);
#ifdef HAVE_CURSES #ifdef HAVE_CURSES
/* Create curses input thread for keyboard input. Create this last so /* Create curses input thread for keyboard input. Create this last so
* that we know all threads are created since this can call kill_work * that we know all threads are created since this can call kill_work
@ -5529,3 +5546,4 @@ begin_bench:
return 0; return 0;
} }

366
driver-bitforce.c

@ -20,6 +20,11 @@
#include "fpgautils.h" #include "fpgautils.h"
#include "miner.h" #include "miner.h"
#define BITFORCE_SLEEP_MS 3000
#define BITFORCE_TIMEOUT_MS 10000
#define BITFORCE_CHECK_INTERVAL_MS 10
#define WORK_CHECK_INTERVAL_MS 50
#define MAX_START_DELAY_US 100000
struct device_api bitforce_api; struct device_api bitforce_api;
@ -29,71 +34,71 @@ static void BFgets(char *buf, size_t bufLen, int fd)
{ {
do do
--bufLen; --bufLen;
while (likely(bufLen && read(fd, buf, 1) && (buf++)[0] != '\n')) while (likely(bufLen && read(fd, buf, 1) && (buf++)[0] != '\n'));
;
buf[0] = '\0'; buf[0] = '\0';
} }
static ssize_t BFwrite2(int fd, const void *buf, ssize_t bufLen) static ssize_t BFwrite(int fd, const void *buf, ssize_t bufLen)
{ {
return write(fd, buf, bufLen); if ((bufLen) != write(fd, buf, bufLen))
return 0;
else
return bufLen;
} }
#define BFwrite(fd, buf, bufLen) do { \
if ((bufLen) != BFwrite2(fd, buf, bufLen)) { \
applog(LOG_ERR, "Error writing to BitForce (" #buf ")"); \
return 0; \
} \
} while(0)
#define BFclose(fd) close(fd) #define BFclose(fd) close(fd)
static bool bitforce_detect_one(const char *devpath) static bool bitforce_detect_one(const char *devpath)
{ {
char *s; int fdDev = BFopen(devpath);
struct cgpu_info *bitforce;
char pdevbuf[0x100]; char pdevbuf[0x100];
char *s;
applog(LOG_DEBUG, "BitForce Detect: Attempting to open %s", devpath); applog(LOG_DEBUG, "BFL: Attempting to open %s", devpath);
int fdDev = BFopen(devpath);
if (unlikely(fdDev == -1)) { if (unlikely(fdDev == -1)) {
applog(LOG_ERR, "BitForce Detect: Failed to open %s", devpath); applog(LOG_ERR, "BFL: Failed to open %s", devpath);
return false; return false;
} }
BFwrite(fdDev, "ZGX", 3); BFwrite(fdDev, "ZGX", 3);
BFgets(pdevbuf, sizeof(pdevbuf), fdDev); BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
if (unlikely(!pdevbuf[0])) { if (unlikely(!pdevbuf[0])) {
applog(LOG_ERR, "Error reading from BitForce (ZGX)"); applog(LOG_ERR, "BFL: Error reading (ZGX)");
return 0; return 0;
} }
BFclose(fdDev); BFclose(fdDev);
if (unlikely(!strstr(pdevbuf, "SHA256"))) { if (unlikely(!strstr(pdevbuf, "SHA256"))) {
applog(LOG_DEBUG, "BitForce Detect: Didn't recognise BitForce on %s", devpath); applog(LOG_ERR, "BFL: Didn't recognise BitForce on %s", devpath);
return false; return false;
} }
// We have a real BitForce! // We have a real BitForce!
struct cgpu_info *bitforce;
bitforce = calloc(1, sizeof(*bitforce)); bitforce = calloc(1, sizeof(*bitforce));
bitforce->api = &bitforce_api; bitforce->api = &bitforce_api;
bitforce->device_path = strdup(devpath); bitforce->device_path = strdup(devpath);
bitforce->deven = DEV_ENABLED; bitforce->deven = DEV_ENABLED;
bitforce->threads = 1; bitforce->threads = 1;
if (likely((!memcmp(pdevbuf, ">>>ID: ", 7)) && (s = strstr(pdevbuf + 3, ">>>")))) bitforce->sleep_ms = BITFORCE_SLEEP_MS;
{
if (likely((!memcmp(pdevbuf, ">>>ID: ", 7)) && (s = strstr(pdevbuf + 3, ">>>")))) {
s[0] = '\0'; s[0] = '\0';
bitforce->name = strdup(pdevbuf + 7); bitforce->name = strdup(pdevbuf + 7);
} }
mutex_init(&bitforce->device_mutex);
return add_cgpu(bitforce); return add_cgpu(bitforce);
} }
static char bitforce_detect_auto() static char bitforce_detect_auto()
{ {
return return (serial_autodetect_udev (bitforce_detect_one, "BitFORCE*SHA256") ?:
serial_autodetect_udev (bitforce_detect_one, "BitFORCE*SHA256") ?:
serial_autodetect_devserial(bitforce_detect_one, "BitFORCE_SHA256") ?: serial_autodetect_devserial(bitforce_detect_one, "BitFORCE_SHA256") ?:
0; 0);
} }
static void bitforce_detect() static void bitforce_detect()
@ -104,6 +109,7 @@ static void bitforce_detect()
static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce) static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce)
{ {
float gt = bitforce->temp; float gt = bitforce->temp;
if (gt > 0) if (gt > 0)
tailsprintf(buf, "%5.1fC ", gt); tailsprintf(buf, "%5.1fC ", gt);
else else
@ -114,79 +120,112 @@ static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce)
static bool bitforce_thread_prepare(struct thr_info *thr) static bool bitforce_thread_prepare(struct thr_info *thr)
{ {
struct cgpu_info *bitforce = thr->cgpu; struct cgpu_info *bitforce = thr->cgpu;
int fdDev = BFopen(bitforce->device_path);
struct timeval now; struct timeval now;
int fdDev = BFopen(bitforce->device_path); if (unlikely(fdDev == -1)) {
if (unlikely(-1 == fdDev)) { applog(LOG_ERR, "BFL%i: Failed to open %s", bitforce->device_id, bitforce->device_path);
applog(LOG_ERR, "Failed to open BitForce on %s", bitforce->device_path);
return false; return false;
} }
bitforce->device_fd = fdDev; bitforce->device_fd = fdDev;
applog(LOG_INFO, "Opened BitForce on %s", bitforce->device_path); applog(LOG_INFO, "BFL%i: Opened %s", bitforce->device_id, bitforce->device_path);
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
get_datestamp(bitforce->init, &now); get_datestamp(bitforce->init, &now);
return true; return true;
} }
static uint64_t bitforce_scanhash(struct thr_info *thr, struct work *work, uint64_t __maybe_unused max_nonce) static void biforce_clear_buffer(struct cgpu_info *bitforce)
{ {
struct cgpu_info *bitforce = thr->cgpu;
int fdDev = bitforce->device_fd; int fdDev = bitforce->device_fd;
char pdevbuf[0x100];
applog(LOG_DEBUG, "BFL%i: Clearing read buffer", bitforce->device_id);
mutex_lock(&bitforce->device_mutex);
do {
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
} while (pdevbuf[0]);
mutex_unlock(&bitforce->device_mutex);
}
int i, thr_id = thr->id; void bitforce_init(struct cgpu_info *bitforce)
{
char *devpath = bitforce->device_path;
int fdDev = bitforce->device_fd;
char pdevbuf[0x100]; char pdevbuf[0x100];
unsigned char ob[61] = ">>>>>>>>12345678901234567890123456789012123456789012>>>>>>>>";
struct timeval tdiff;
char *pnoncebuf;
char *s; char *s;
uint32_t nonce;
BFwrite(fdDev, "ZDX", 3); applog(LOG_WARNING, "BFL%i: Re-initalizing", bitforce->device_id);
biforce_clear_buffer(bitforce);
mutex_lock(&bitforce->device_mutex);
if (fdDev)
BFclose(fdDev);
bitforce->device_fd = 0;
fdDev = BFopen(devpath);
if (unlikely(fdDev == -1)) {
mutex_unlock(&bitforce->device_mutex);
applog(LOG_ERR, "BFL%i: Failed to open %s", bitforce->device_id, devpath);
return;
}
BFwrite(fdDev, "ZGX", 3);
BFgets(pdevbuf, sizeof(pdevbuf), fdDev); BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
if (unlikely(!pdevbuf[0])) { if (unlikely(!pdevbuf[0])) {
applog(LOG_ERR, "Error reading from BitForce (ZDX)"); mutex_unlock(&bitforce->device_mutex);
return 0; applog(LOG_ERR, "BFL%i: Error reading (ZGX)", bitforce->device_id);
} return;
if (unlikely(pdevbuf[0] != 'O' || pdevbuf[1] != 'K')) {
applog(LOG_ERR, "BitForce ZDX reports: %s", pdevbuf);
return 0;
} }
memcpy(ob + 8, work->midstate, 32); if (unlikely(!strstr(pdevbuf, "SHA256"))) {
memcpy(ob + 8 + 32, work->data + 64, 12); mutex_unlock(&bitforce->device_mutex);
BFwrite(fdDev, ob, 60); applog(LOG_ERR, "BFL%i: Didn't recognise BitForce on %s returned: %s", bitforce->device_id, devpath, pdevbuf);
if (opt_debug) { return;
s = bin2hex(ob + 8, 44);
applog(LOG_DEBUG, "BitForce block data: %s", s);
free(s);
} }
BFgets(pdevbuf, sizeof(pdevbuf), fdDev); if (likely((!memcmp(pdevbuf, ">>>ID: ", 7)) && (s = strstr(pdevbuf + 3, ">>>")))) {
if (unlikely(!pdevbuf[0])) { s[0] = '\0';
applog(LOG_ERR, "Error reading from BitForce (block data)"); bitforce->name = strdup(pdevbuf + 7);
return 0;
} }
if (unlikely(pdevbuf[0] != 'O' || pdevbuf[1] != 'K')) {
applog(LOG_ERR, "BitForce block data reports: %s", pdevbuf); bitforce->device_fd = fdDev;
return 0; mutex_unlock(&bitforce->device_mutex);
} }
static bool bitforce_get_temp(struct cgpu_info *bitforce)
{
int fdDev = bitforce->device_fd;
char pdevbuf[0x100];
char *s;
if (!fdDev)
return false;
mutex_lock(&bitforce->device_mutex);
BFwrite(fdDev, "ZLX", 3); BFwrite(fdDev, "ZLX", 3);
BFgets(pdevbuf, sizeof(pdevbuf), fdDev); BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
mutex_unlock(&bitforce->device_mutex);
if (unlikely(!pdevbuf[0])) { if (unlikely(!pdevbuf[0])) {
applog(LOG_ERR, "Error reading from BitForce (ZKX)"); applog(LOG_ERR, "BFL%i: Error: Get temp returned empty string", bitforce->device_id);
return 0; bitforce->temp = 0;
return false;
} }
if ((!strncasecmp(pdevbuf, "TEMP", 4)) && (s = strchr(pdevbuf + 4, ':'))) { if ((!strncasecmp(pdevbuf, "TEMP", 4)) && (s = strchr(pdevbuf + 4, ':'))) {
float temp = strtof(s + 1, NULL); float temp = strtof(s + 1, NULL);
if (temp > 0) { if (temp > 0) {
bitforce->temp = temp; bitforce->temp = temp;
if (temp > bitforce->cutofftemp) { if (temp > bitforce->cutofftemp) {
applog(LOG_WARNING, "Hit thermal cutoff limit on %s %d, disabling!", bitforce->api->name, bitforce->device_id); applog(LOG_WARNING, "BFL%i: Hit thermal cutoff limit, disabling!", bitforce->device_id);
bitforce->deven = DEV_RECOVER; bitforce->deven = DEV_RECOVER;
bitforce->device_last_not_well = time(NULL); bitforce->device_last_not_well = time(NULL);
@ -195,46 +234,114 @@ static uint64_t bitforce_scanhash(struct thr_info *thr, struct work *work, uint6
} }
} }
} }
return true;
}
/* Initially wait 2/3 of the average cycle time so we can request more static bool bitforce_send_work(struct thr_info *thr, struct work *work)
* work before full scan is up ~ 3.4 seconds */ {
tdiff.tv_sec = 3; unsigned char ob[61] = ">>>>>>>>12345678901234567890123456789012123456789012>>>>>>>>";
tdiff.tv_usec = 4000000; struct cgpu_info *bitforce = thr->cgpu;
if (!restart_wait(&tdiff)) int fdDev = bitforce->device_fd;
return 0; char pdevbuf[0x100];
queue_request(thr, false); char *s;
i = 3400;
/* Now wait another second; no bistream should be finished by now */ if (!fdDev)
tdiff.tv_sec = 1; return false;
tdiff.tv_usec = 0; re_send:
if (!restart_wait(&tdiff)) mutex_lock(&bitforce->device_mutex);
return 0; BFwrite(fdDev, "ZDX", 3);
i += 1000; BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
if (!pdevbuf[0] || (pdevbuf[0] == 'B')) {
mutex_unlock(&bitforce->device_mutex);
bitforce->wait_ms += WORK_CHECK_INTERVAL_MS;
usleep(WORK_CHECK_INTERVAL_MS * 1000);
goto re_send;
} else if (unlikely(pdevbuf[0] != 'O' || pdevbuf[1] != 'K')) {
mutex_unlock(&bitforce->device_mutex);
applog(LOG_ERR, "BFL%i: Error: Send work reports: %s", bitforce->device_id, pdevbuf);
return false;
}
/* Now start looking for results. Stupid polling every 10ms... */ memcpy(ob + 8, work->midstate, 32);
while (42) { memcpy(ob + 8 + 32, work->data + 64, 12);
if (unlikely(work_restart[thr_id].restart))
return 0;
usleep(10000);
i += 10;
BFwrite(fdDev, "ZFX", 3); BFwrite(fdDev, ob, 60);
BFgets(pdevbuf, sizeof(pdevbuf), fdDev); BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
mutex_unlock(&bitforce->device_mutex);
if (opt_debug) {
s = bin2hex(ob + 8, 44);
applog(LOG_DEBUG, "BFL%i: block data: %s", bitforce->device_id, s);
free(s);
}
if (unlikely(!pdevbuf[0])) { if (unlikely(!pdevbuf[0])) {
applog(LOG_ERR, "Error reading from BitForce (ZFX)"); applog(LOG_ERR, "BFL%i: Error: Send block data returned empty string", bitforce->device_id);
return 0; return false;
} }
if (pdevbuf[0] != 'B')
if (unlikely(pdevbuf[0] != 'O' || pdevbuf[1] != 'K')) {
applog(LOG_ERR, "BFL%i: Error: Send block data reports: %s", bitforce->device_id, pdevbuf);
return false;
}
return true;
}
static uint64_t bitforce_get_result(struct thr_info *thr, struct work *work)
{
unsigned int delay_time_ms = BITFORCE_CHECK_INTERVAL_MS;
struct cgpu_info *bitforce = thr->cgpu;
int fdDev = bitforce->device_fd;
char pdevbuf[0x100];
char *pnoncebuf;
uint32_t nonce;
if (!fdDev)
return 0;
while (bitforce->wait_ms < BITFORCE_TIMEOUT_MS) {
if (unlikely(work_restart[thr->id].restart))
return 1;
mutex_lock(&bitforce->device_mutex);
BFwrite(fdDev, "ZFX", 3);
BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
mutex_unlock(&bitforce->device_mutex);
if (pdevbuf[0] && pdevbuf[0] != 'B') /* BFL does not respond during throttling */
break; break;
/* if BFL is throttling, no point checking so quickly */
delay_time_ms = (pdevbuf[0] ? BITFORCE_CHECK_INTERVAL_MS : 2*WORK_CHECK_INTERVAL_MS);
usleep(delay_time_ms * 1000);
bitforce->wait_ms += delay_time_ms;
}
if (bitforce->wait_ms >= BITFORCE_TIMEOUT_MS) {
applog(LOG_ERR, "BFL%i: took longer than 10s", bitforce->device_id);
bitforce->device_last_not_well = time(NULL);
bitforce->device_not_well_reason = REASON_DEV_OVER_HEAT;
bitforce->dev_over_heat_count++;
return 1;
} else if (pdevbuf[0] == 'N') {/* Hashing complete (NONCE-FOUND or NO-NONCE) */
/* Simple timing adjustment */
delay_time_ms = bitforce->sleep_ms;
if (bitforce->wait_ms > (bitforce->sleep_ms + BITFORCE_CHECK_INTERVAL_MS))
bitforce->sleep_ms += (unsigned int) ((double) (bitforce->wait_ms - bitforce->sleep_ms) / 1.6);
else if (bitforce->wait_ms == bitforce->sleep_ms)
bitforce->sleep_ms -= BITFORCE_CHECK_INTERVAL_MS;
if (delay_time_ms != bitforce->sleep_ms)
applog(LOG_DEBUG, "BFL%i: Wait time changed to: %d. Waited: %d", bitforce->device_id, bitforce->sleep_ms, bitforce->wait_ms);
} }
applog(LOG_DEBUG, "BitForce waited %dms until %s\n", i, pdevbuf);
applog(LOG_DEBUG, "BFL%i: waited %dms until %s", bitforce->device_id, bitforce->wait_ms, pdevbuf);
work->blk.nonce = 0xffffffff; work->blk.nonce = 0xffffffff;
if (pdevbuf[2] == '-') if (pdevbuf[2] == '-')
return 0xffffffff; return 0xffffffff; /* No valid nonce found */
else if (pdevbuf[0] == 'I')
return 1; /* Device idle */
else if (strncasecmp(pdevbuf, "NONCE-FOUND", 11)) { else if (strncasecmp(pdevbuf, "NONCE-FOUND", 11)) {
applog(LOG_ERR, "BitForce result reports: %s", pdevbuf); applog(LOG_WARNING, "BFL%i: Error: Get result reports: %s", bitforce->device_id, pdevbuf);
return 0; return 1;
} }
pnoncebuf = &pdevbuf[12]; pnoncebuf = &pdevbuf[12];
@ -244,7 +351,6 @@ static uint64_t bitforce_scanhash(struct thr_info *thr, struct work *work, uint6
#ifndef __BIG_ENDIAN__ #ifndef __BIG_ENDIAN__
nonce = swab32(nonce); nonce = swab32(nonce);
#endif #endif
submit_nonce(thr, work, nonce); submit_nonce(thr, work, nonce);
if (pnoncebuf[8] != ',') if (pnoncebuf[8] != ',')
break; break;
@ -254,11 +360,95 @@ static uint64_t bitforce_scanhash(struct thr_info *thr, struct work *work, uint6
return 0xffffffff; return 0xffffffff;
} }
static void bitforce_shutdown(struct thr_info *thr)
{
struct cgpu_info *bitforce = thr->cgpu;
BFclose(bitforce->device_fd);
bitforce->device_fd = 0;
}
static void biforce_thread_enable(struct thr_info *thr)
{
struct cgpu_info *bitforce = thr->cgpu;
bitforce_init(bitforce);
}
static uint64_t bitforce_scanhash(struct thr_info *thr, struct work *work, uint64_t __maybe_unused max_nonce)
{
struct cgpu_info *bitforce = thr->cgpu;
unsigned int sleep_time;
struct timeval tdiff;
uint64_t ret;
bitforce->wait_ms = 0;
ret = bitforce_send_work(thr, work);
/* Initially wait 2/3 of the average cycle time so we can request more
work before full scan is up */
sleep_time = (2 * bitforce->sleep_ms) / 3;
tdiff.tv_sec = sleep_time / 1000;
tdiff.tv_usec = sleep_time * 1000 - (tdiff.tv_sec * 1000000);
if (!restart_wait(&tdiff))
return 1;
bitforce->wait_ms += sleep_time;
queue_request(thr, false);
/* Now wait athe final 1/3rd; no bitforce should be finished by now */
sleep_time = bitforce->sleep_ms - sleep_time;
tdiff.tv_sec = sleep_time / 1000;
tdiff.tv_usec = sleep_time * 1000 - (tdiff.tv_sec * 1000000);
if (!restart_wait(&tdiff))
return 1;
bitforce->wait_ms += sleep_time;
if (ret)
ret = bitforce_get_result(thr, work);
if (!ret) {
ret = 1;
applog(LOG_ERR, "BFL%i: Comms error", bitforce->device_id);
bitforce->device_last_not_well = time(NULL);
bitforce->device_not_well_reason = REASON_DEV_NOSTART;
bitforce->dev_nostart_count++;
/* empty read buffer */
biforce_clear_buffer(bitforce);
}
return ret;
}
static bool bitforce_get_stats(struct cgpu_info *bitforce)
{
return bitforce_get_temp(bitforce);
}
static bool bitforce_thread_init(struct thr_info *thr)
{
struct cgpu_info *bitforce = thr->cgpu;
unsigned int wait;
/* Pause each new thread a random time between 0-100ms
so the devices aren't making calls all at the same time. */
wait = (rand() * MAX_START_DELAY_US)/RAND_MAX;
applog(LOG_DEBUG, "BFL%i: Delaying start by %dms", bitforce->device_id, wait / 1000);
usleep(wait);
return true;
}
struct device_api bitforce_api = { struct device_api bitforce_api = {
.dname = "bitforce", .dname = "bitforce",
.name = "BFL", .name = "BFL",
.api_detect = bitforce_detect, .api_detect = bitforce_detect,
.reinit_device = bitforce_init,
.get_statline_before = get_bitforce_statline_before, .get_statline_before = get_bitforce_statline_before,
.get_stats = bitforce_get_stats,
.thread_prepare = bitforce_thread_prepare, .thread_prepare = bitforce_thread_prepare,
.thread_init = bitforce_thread_init,
.scanhash = bitforce_scanhash, .scanhash = bitforce_scanhash,
.thread_shutdown = bitforce_shutdown,
.thread_enable = biforce_thread_enable
}; };

7
miner.h

@ -236,6 +236,7 @@ struct device_api {
void (*get_statline_before)(char*, struct cgpu_info*); void (*get_statline_before)(char*, struct cgpu_info*);
void (*get_statline)(char*, struct cgpu_info*); void (*get_statline)(char*, struct cgpu_info*);
struct api_data *(*get_api_stats)(struct cgpu_info*); struct api_data *(*get_api_stats)(struct cgpu_info*);
bool (*get_stats)(struct cgpu_info*);
// Thread-specific functions // Thread-specific functions
bool (*thread_prepare)(struct thr_info*); bool (*thread_prepare)(struct thr_info*);
@ -245,6 +246,7 @@ struct device_api {
bool (*prepare_work)(struct thr_info*, struct work*); bool (*prepare_work)(struct thr_info*, struct work*);
uint64_t (*scanhash)(struct thr_info*, struct work*, uint64_t); uint64_t (*scanhash)(struct thr_info*, struct work*, uint64_t);
void (*thread_shutdown)(struct thr_info*); void (*thread_shutdown)(struct thr_info*);
void (*thread_enable)(struct thr_info*);
}; };
enum dev_enable { enum dev_enable {
@ -315,12 +317,17 @@ struct cgpu_info {
#endif #endif
int device_fd; int device_fd;
}; };
#ifdef USE_BITFORCE
unsigned int wait_ms;
unsigned int sleep_ms;
#endif
pthread_mutex_t device_mutex; pthread_mutex_t device_mutex;
enum dev_enable deven; enum dev_enable deven;
int accepted; int accepted;
int rejected; int rejected;
int hw_errors; int hw_errors;
unsigned int low_count;
double rolling; double rolling;
double total_mhashes; double total_mhashes;
double utility; double utility;

Loading…
Cancel
Save