diff --git a/cgminer.c b/cgminer.c index e8e4737d..19d34e6a 100644 --- a/cgminer.c +++ b/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); } - /* 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); /* 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 */ thread_reportin(mythr); 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; @@ -4455,9 +4452,16 @@ static void age_work(void) /* 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 * 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) { - const unsigned int interval = 3; + const unsigned int interval = WATCHDOG_INTERVAL; struct timeval zero_tv; 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) { struct cgpu_info *cgpu = devices[i]; struct thr_info *thr = cgpu->thr[0]; enum dev_enable *denable; + bool dev_count_well; + bool dev_count_sick; + bool dev_count_dead; + char dev_str[8]; int gpu; - if (cgpu->api != &opencl_api) - continue; - /* Use only one thread per device to determine if the GPU is healthy */ - if (i >= nDevs) - break; - gpu = thr->cgpu->device_id; + if (cgpu->api->get_stats) + cgpu->api->get_stats(cgpu); + + gpu = cgpu->device_id; denable = &cgpu->deven; + sprintf(dev_str, "%s%d", cgpu->api->name, gpu); + #ifdef HAVE_ADL - if (adl_active && gpus[gpu].has_adl) + if (adl_active && cgpu->has_adl) 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; 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); } #endif + /* Thread is waiting on getwork or disabled */ if (thr->getwork || *denable == DEV_DISABLED) continue; - if (gpus[gpu].status != LIFE_WELL && now.tv_sec - thr->last.tv_sec < 60) { - applog(LOG_ERR, "Device %d recovered, GPU %d declared WELL!", i, gpu); - gpus[gpu].status = LIFE_WELL; - gpus[gpu].device_last_well = time(NULL); - } else if (now.tv_sec - thr->last.tv_sec > 60 && gpus[gpu].status == LIFE_WELL) { - thr->rolling = thr->cgpu->rolling = 0; - gpus[gpu].status = LIFE_SICK; - applog(LOG_ERR, "Device %d idle for more than 60 seconds, GPU %d declared SICK!", i, gpu); + if (cgpu->rolling < WATCHDOG_LOW_HASH) + cgpu->low_count++; + else + cgpu->low_count = 0; + + dev_count_well = (cgpu->low_count < WATCHDOG_SICK_COUNT); + dev_count_sick = (cgpu->low_count > WATCHDOG_SICK_COUNT); + 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); - gpus[gpu].device_last_not_well = time(NULL); - gpus[gpu].device_not_well_reason = REASON_DEV_SICK_IDLE_60; - gpus[gpu].dev_sick_idle_60_count++; + cgpu->device_last_not_well = time(NULL); + cgpu->device_not_well_reason = REASON_DEV_SICK_IDLE_60; + cgpu->dev_sick_idle_60_count++; #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, "Will not attempt to auto-restart it."); } else #endif if (opt_restart) { - applog(LOG_ERR, "Attempting to restart GPU"); - reinit_device(thr->cgpu); + applog(LOG_ERR, "%s: Attempting to restart", dev_str); + reinit_device(cgpu); } - } else if (now.tv_sec - thr->last.tv_sec > 600 && gpus[i].status == LIFE_SICK) { - gpus[gpu].status = LIFE_DEAD; - applog(LOG_ERR, "Device %d not responding for more than 10 minutes, GPU %d declared DEAD!", i, gpu); + } else if (cgpu->status == LIFE_SICK && ((now.tv_sec - thr->last.tv_sec > WATCHDOG_DEAD_TIME) || dev_count_dead)) { + cgpu->status = LIFE_DEAD; + applog(LOG_ERR, "%s: Not responded for more than 10 minutes, declaring DEAD!", dev_str); gettimeofday(&thr->sick, NULL); - gpus[gpu].device_last_not_well = time(NULL); - gpus[gpu].device_not_well_reason = REASON_DEV_DEAD_IDLE_600; - gpus[gpu].dev_dead_idle_600_count++; + cgpu->device_last_not_well = time(NULL); + cgpu->device_not_well_reason = REASON_DEV_DEAD_IDLE_600; + cgpu->dev_dead_idle_600_count++; } 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 */ gettimeofday(&thr->sick, NULL); #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 */ } else #endif if (opt_restart) - reinit_device(thr->cgpu); + reinit_device(cgpu); } } -#endif } return NULL; @@ -5482,7 +5498,7 @@ begin_bench: quit(1, "tq_new failed for gpur_thr_id"); if (thr_info_create(thr, NULL, reinit_gpu, thr)) quit(1, "reinit_gpu thread create failed"); -#endif +#endif /* Create API socket thread */ api_thr_id = mining_threads + 5; @@ -5491,6 +5507,7 @@ begin_bench: quit(1, "API thread create failed"); pthread_detach(thr->pth); + #ifdef HAVE_CURSES /* Create curses input thread for keyboard input. Create this last so * that we know all threads are created since this can call kill_work @@ -5529,3 +5546,4 @@ begin_bench: return 0; } + diff --git a/driver-bitforce.c b/driver-bitforce.c index 23dc39b3..ba239113 100644 --- a/driver-bitforce.c +++ b/driver-bitforce.c @@ -20,6 +20,11 @@ #include "fpgautils.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; @@ -29,71 +34,71 @@ static void BFgets(char *buf, size_t bufLen, int fd) { do --bufLen; - while (likely(bufLen && read(fd, buf, 1) && (buf++)[0] != '\n')) - ; + while (likely(bufLen && read(fd, buf, 1) && (buf++)[0] != '\n')); + 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) static bool bitforce_detect_one(const char *devpath) { - char *s; + int fdDev = BFopen(devpath); + struct cgpu_info *bitforce; 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)) { - applog(LOG_ERR, "BitForce Detect: Failed to open %s", devpath); + applog(LOG_ERR, "BFL: Failed to open %s", devpath); return false; } + BFwrite(fdDev, "ZGX", 3); BFgets(pdevbuf, sizeof(pdevbuf), fdDev); if (unlikely(!pdevbuf[0])) { - applog(LOG_ERR, "Error reading from BitForce (ZGX)"); + applog(LOG_ERR, "BFL: Error reading (ZGX)"); return 0; } + BFclose(fdDev); 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; } // We have a real BitForce! - struct cgpu_info *bitforce; bitforce = calloc(1, sizeof(*bitforce)); bitforce->api = &bitforce_api; bitforce->device_path = strdup(devpath); bitforce->deven = DEV_ENABLED; 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'; bitforce->name = strdup(pdevbuf + 7); } + + mutex_init(&bitforce->device_mutex); return add_cgpu(bitforce); } static char bitforce_detect_auto() { - return - serial_autodetect_udev (bitforce_detect_one, "BitFORCE*SHA256") ?: - serial_autodetect_devserial(bitforce_detect_one, "BitFORCE_SHA256") ?: - 0; + return (serial_autodetect_udev (bitforce_detect_one, "BitFORCE*SHA256") ?: + serial_autodetect_devserial(bitforce_detect_one, "BitFORCE_SHA256") ?: + 0); } static void bitforce_detect() @@ -104,6 +109,7 @@ static void bitforce_detect() static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce) { float gt = bitforce->temp; + if (gt > 0) tailsprintf(buf, "%5.1fC ", gt); 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) { struct cgpu_info *bitforce = thr->cgpu; - + int fdDev = BFopen(bitforce->device_path); struct timeval now; - int fdDev = BFopen(bitforce->device_path); - if (unlikely(-1 == fdDev)) { - applog(LOG_ERR, "Failed to open BitForce on %s", bitforce->device_path); + if (unlikely(fdDev == -1)) { + applog(LOG_ERR, "BFL%i: Failed to open %s", bitforce->device_id, bitforce->device_path); return false; } 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); get_datestamp(bitforce->init, &now); 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; + char pdevbuf[0x100]; - int i, thr_id = thr->id; + 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); +} + +void bitforce_init(struct cgpu_info *bitforce) +{ + char *devpath = bitforce->device_path; + int fdDev = bitforce->device_fd; char pdevbuf[0x100]; - unsigned char ob[61] = ">>>>>>>>12345678901234567890123456789012123456789012>>>>>>>>"; - struct timeval tdiff; - char *pnoncebuf; char *s; - uint32_t nonce; - BFwrite(fdDev, "ZDX", 3); - BFgets(pdevbuf, sizeof(pdevbuf), fdDev); - if (unlikely(!pdevbuf[0])) { - 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; - } + applog(LOG_WARNING, "BFL%i: Re-initalizing", bitforce->device_id); - memcpy(ob + 8, work->midstate, 32); - memcpy(ob + 8 + 32, work->data + 64, 12); - BFwrite(fdDev, ob, 60); - if (opt_debug) { - s = bin2hex(ob + 8, 44); - applog(LOG_DEBUG, "BitForce block data: %s", s); - free(s); + 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); + if (unlikely(!pdevbuf[0])) { - applog(LOG_ERR, "Error reading from BitForce (block data)"); - return 0; + mutex_unlock(&bitforce->device_mutex); + applog(LOG_ERR, "BFL%i: Error reading (ZGX)", bitforce->device_id); + return; } - if (unlikely(pdevbuf[0] != 'O' || pdevbuf[1] != 'K')) { - applog(LOG_ERR, "BitForce block data reports: %s", pdevbuf); - return 0; + + if (unlikely(!strstr(pdevbuf, "SHA256"))) { + mutex_unlock(&bitforce->device_mutex); + applog(LOG_ERR, "BFL%i: Didn't recognise BitForce on %s returned: %s", bitforce->device_id, devpath, pdevbuf); + return; } + + if (likely((!memcmp(pdevbuf, ">>>ID: ", 7)) && (s = strstr(pdevbuf + 3, ">>>")))) { + s[0] = '\0'; + bitforce->name = strdup(pdevbuf + 7); + } + + bitforce->device_fd = fdDev; + 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); BFgets(pdevbuf, sizeof(pdevbuf), fdDev); + mutex_unlock(&bitforce->device_mutex); + if (unlikely(!pdevbuf[0])) { - applog(LOG_ERR, "Error reading from BitForce (ZKX)"); - return 0; + applog(LOG_ERR, "BFL%i: Error: Get temp returned empty string", bitforce->device_id); + bitforce->temp = 0; + return false; } + if ((!strncasecmp(pdevbuf, "TEMP", 4)) && (s = strchr(pdevbuf + 4, ':'))) { float temp = strtof(s + 1, NULL); + if (temp > 0) { bitforce->temp = temp; 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->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 - * work before full scan is up ~ 3.4 seconds */ - tdiff.tv_sec = 3; - tdiff.tv_usec = 4000000; - if (!restart_wait(&tdiff)) - return 0; - queue_request(thr, false); - i = 3400; +static bool bitforce_send_work(struct thr_info *thr, struct work *work) +{ + unsigned char ob[61] = ">>>>>>>>12345678901234567890123456789012123456789012>>>>>>>>"; + struct cgpu_info *bitforce = thr->cgpu; + int fdDev = bitforce->device_fd; + char pdevbuf[0x100]; + char *s; - /* Now wait another second; no bistream should be finished by now */ - tdiff.tv_sec = 1; - tdiff.tv_usec = 0; - if (!restart_wait(&tdiff)) - return 0; - i += 1000; + if (!fdDev) + return false; +re_send: + mutex_lock(&bitforce->device_mutex); + BFwrite(fdDev, "ZDX", 3); + 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; + } + + memcpy(ob + 8, work->midstate, 32); + memcpy(ob + 8 + 32, work->data + 64, 12); + + BFwrite(fdDev, ob, 60); + 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])) { + applog(LOG_ERR, "BFL%i: Error: Send block data returned empty string", bitforce->device_id); + return false; + } - /* Now start looking for results. Stupid polling every 10ms... */ - while (42) { - if (unlikely(work_restart[thr_id].restart)) - return 0; - usleep(10000); - i += 10; + 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); - if (unlikely(!pdevbuf[0])) { - applog(LOG_ERR, "Error reading from BitForce (ZFX)"); - return 0; - } - if (pdevbuf[0] != 'B') - break; + mutex_unlock(&bitforce->device_mutex); + if (pdevbuf[0] && pdevbuf[0] != 'B') /* BFL does not respond during throttling */ + 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; - if (pdevbuf[2] == '-') - return 0xffffffff; + if (pdevbuf[2] == '-') + return 0xffffffff; /* No valid nonce found */ + else if (pdevbuf[0] == 'I') + return 1; /* Device idle */ else if (strncasecmp(pdevbuf, "NONCE-FOUND", 11)) { - applog(LOG_ERR, "BitForce result reports: %s", pdevbuf); - return 0; + applog(LOG_WARNING, "BFL%i: Error: Get result reports: %s", bitforce->device_id, pdevbuf); + return 1; } pnoncebuf = &pdevbuf[12]; @@ -244,7 +351,6 @@ static uint64_t bitforce_scanhash(struct thr_info *thr, struct work *work, uint6 #ifndef __BIG_ENDIAN__ nonce = swab32(nonce); #endif - submit_nonce(thr, work, nonce); if (pnoncebuf[8] != ',') break; @@ -254,11 +360,95 @@ static uint64_t bitforce_scanhash(struct thr_info *thr, struct work *work, uint6 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 = { .dname = "bitforce", .name = "BFL", .api_detect = bitforce_detect, + .reinit_device = bitforce_init, .get_statline_before = get_bitforce_statline_before, + .get_stats = bitforce_get_stats, .thread_prepare = bitforce_thread_prepare, + .thread_init = bitforce_thread_init, .scanhash = bitforce_scanhash, + .thread_shutdown = bitforce_shutdown, + .thread_enable = biforce_thread_enable }; diff --git a/miner.h b/miner.h index 8feaa793..c50fa3e3 100644 --- a/miner.h +++ b/miner.h @@ -236,6 +236,7 @@ struct device_api { void (*get_statline_before)(char*, struct cgpu_info*); void (*get_statline)(char*, struct cgpu_info*); struct api_data *(*get_api_stats)(struct cgpu_info*); + bool (*get_stats)(struct cgpu_info*); // Thread-specific functions bool (*thread_prepare)(struct thr_info*); @@ -245,6 +246,7 @@ struct device_api { bool (*prepare_work)(struct thr_info*, struct work*); uint64_t (*scanhash)(struct thr_info*, struct work*, uint64_t); void (*thread_shutdown)(struct thr_info*); + void (*thread_enable)(struct thr_info*); }; enum dev_enable { @@ -315,12 +317,17 @@ struct cgpu_info { #endif int device_fd; }; +#ifdef USE_BITFORCE + unsigned int wait_ms; + unsigned int sleep_ms; +#endif pthread_mutex_t device_mutex; enum dev_enable deven; int accepted; int rejected; int hw_errors; + unsigned int low_count; double rolling; double total_mhashes; double utility;