Browse Source

Merge remote-tracking branch 'upstream/master'

nfactor-troky
James Z.M. Gao 12 years ago
parent
commit
57fcd07bdd
  1. 4
      Makefile.am
  2. 44
      README
  3. 2
      api-example.c
  4. 16
      api.c
  5. 116
      cgminer.c
  6. 23
      configure.ac
  7. 1038
      driver-avalon.c
  8. 130
      driver-avalon.h
  9. 22
      fpgautils.c
  10. 2
      fpgautils.h
  11. 77
      hexdump.c
  12. 14
      miner.h
  13. 4
      usbutils.c
  14. 2
      usbutils.h
  15. 91
      util.c

4
Makefile.am

@ -100,6 +100,10 @@ if HAS_ICARUS
cgminer_SOURCES += driver-icarus.c cgminer_SOURCES += driver-icarus.c
endif endif
if HAS_AVALON
cgminer_SOURCES += driver-avalon.c
endif
if HAS_MODMINER if HAS_MODMINER
cgminer_SOURCES += driver-modminer.c cgminer_SOURCES += driver-modminer.c
bitstreamsdir = $(bindir)/bitstreams bitstreamsdir = $(bindir)/bitstreams

44
README

@ -984,6 +984,10 @@ Q: Can I mine with Nvidia or Intel GPUs?
A: Yes but their hashrate is very poor and likely you'll be using much more A: Yes but their hashrate is very poor and likely you'll be using much more
energy than you'll be earning in coins. energy than you'll be earning in coins.
Q: Can I mine on both Nvidia and AMD GPUs at the same time?
A: No, you must run one instance of cgminer with the --gpu-platform option for
each.
Q: Can I mine on Linux without running Xorg? Q: Can I mine on Linux without running Xorg?
A: With Nvidia you can, but with AMD you cannot. A: With Nvidia you can, but with AMD you cannot.
@ -1001,13 +1005,51 @@ A: You are generating garbage hashes due to your choice of settings. Your
Work Utility (WU) value will confirm you are not generating garbage. You Work Utility (WU) value will confirm you are not generating garbage. You
should be getting about .9WU per kHash. If not, then try decreasing your should be getting about .9WU per kHash. If not, then try decreasing your
intensity, do not increase the number of gpu-threads, and consider adding intensity, do not increase the number of gpu-threads, and consider adding
system RAM to match your GPU ram. system RAM to match your GPU ram. You may also be using a bad combination
of driver and/or SDK.
Q: Scrypt fails to initialise the kernel every time? Q: Scrypt fails to initialise the kernel every time?
A: Your parameters are too high. Don't add GPU threads, don't set intensity A: Your parameters are too high. Don't add GPU threads, don't set intensity
too high, decrease thread concurrency. See the SCRYPT-README for a lot more too high, decrease thread concurrency. See the SCRYPT-README for a lot more
help. help.
Q: Cgminer stops mining (or my GPUs go DEAD) and I can't close it?
A: Once the driver has crashed, there is no way for cgminer to close cleanly.
You will have to kill it, and depending on how corrupted your driver state
has gotten, you may even need to reboot. Windows is known to reset drivers
when they fail and cgminer will be stuck trying to use the old driver instance.
Q: I can't get any monitoring of temperatures or fanspeed with cgminer when
I start it remotely?
A: With linux, make sure to export the DISPLAY variable. On windows, you
cannot access these monitoring values via RDP. This should work with tightVNC
or teamviewer though.
Q: I change my GPU engine/memory/voltage and cgminer reports back no change?
A: Cgminer asks the GPU using the ATI Display Library to change settings, but
the driver and hardware are free to do what it wants with that query, including
ignoring it. Some GPUs are locked with one or more of those properties as well.
Q: I have multiple GPUs and although many devices show up, it appears to be
working only on one GPU splitting it up.
A: Your driver setup is failing to properly use the accessory GPUs. Your
driver may be configured wrong or you have a driver version that needs a dummy
plug on all the GPUs that aren't connected to a monitor.
Q: I have some random GPU performance related problem not addressed above.
A: Seriously, it's the driver and/or SDK. Uninstall them and start again,
noting there is no clean way to uninstall them so you have to use extra tools
or do it manually.
Q: Do I need to recompile after updating my driver/SDK?
A: No. The software is unchanged regardless of which driver/SDK/ADL_SDK version
you are running. However if you change SDKs you should delete any generated
.bin files for them to be recreated with the new SDK.
Q: I switch users on windows and my mining stops working?
A: That's correct, it does. It's a permissions issue that there is no known
fix for.
Q: My network gets slower and slower and then dies for a minute? Q: My network gets slower and slower and then dies for a minute?
A; Try the --net-delay option. A; Try the --net-delay option.

2
api-example.c

@ -145,7 +145,7 @@
static const char SEPARATOR = '|'; static const char SEPARATOR = '|';
static const char COMMA = ','; static const char COMMA = ',';
static const char EQ = '='; static const char EQ = '=';
static int ONLY = 0; static int ONLY;
void display(char *buf) void display(char *buf)
{ {

16
api.c

@ -29,7 +29,7 @@
#include "util.h" #include "util.h"
#include "driver-cpu.h" /* for algo_names[], TODO: re-factor dependency */ #include "driver-cpu.h" /* for algo_names[], TODO: re-factor dependency */
#if defined(USE_BFLSC) #if defined(USE_BFLSC) || defined(USE_AVALON)
#define HAVE_AN_ASIC 1 #define HAVE_AN_ASIC 1
#endif #endif
@ -179,6 +179,9 @@ static const char *DEVICECODE = ""
#ifdef USE_ICARUS #ifdef USE_ICARUS
"ICA " "ICA "
#endif #endif
#ifdef USE_AVALON
"AVA "
#endif
#ifdef USE_ZTEX #ifdef USE_ZTEX
"ZTX " "ZTX "
#endif #endif
@ -605,9 +608,6 @@ struct CODES {
static int my_thr_id = 0; static int my_thr_id = 0;
static bool bye; static bool bye;
#if defined(HAVE_OPENCL) || defined (HAVE_AN_ASIC) || defined(HAVE_AN_FPGA)
static bool ping = true;
#endif
// Used to control quit restart access to shutdown variables // Used to control quit restart access to shutdown variables
static pthread_mutex_t quit_restart_lock; static pthread_mutex_t quit_restart_lock;
@ -1178,6 +1178,10 @@ static int numascs()
rd_lock(&devices_lock); rd_lock(&devices_lock);
for (i = 0; i < total_devices; i++) { for (i = 0; i < total_devices; i++) {
#ifdef USE_AVALON
if (devices[i]->drv->drv_id == DRIVER_AVALON)
count++;
#endif
#ifdef USE_BFLSC #ifdef USE_BFLSC
if (devices[i]->drv->drv_id == DRIVER_BFLSC) if (devices[i]->drv->drv_id == DRIVER_BFLSC)
count++; count++;
@ -1194,6 +1198,10 @@ static int ascdevice(int ascid)
rd_lock(&devices_lock); rd_lock(&devices_lock);
for (i = 0; i < total_devices; i++) { for (i = 0; i < total_devices; i++) {
#ifdef USE_AVALON
if (devices[i]->drv->drv_id == DRIVER_AVALON)
count++;
#endif
#ifdef USE_BFLSC #ifdef USE_BFLSC
if (devices[i]->drv->drv_id == DRIVER_BFLSC) if (devices[i]->drv->drv_id == DRIVER_BFLSC)
count++; count++;

116
cgminer.c

@ -48,6 +48,7 @@
#include "driver-opencl.h" #include "driver-opencl.h"
#include "bench_block.h" #include "bench_block.h"
#include "scrypt.h" #include "scrypt.h"
#include "driver-avalon.h"
#if defined(unix) #if defined(unix)
#include <errno.h> #include <errno.h>
@ -55,9 +56,9 @@
#include <sys/wait.h> #include <sys/wait.h>
#endif #endif
#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_MODMINER) #if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_AVALON) || defined(USE_MODMINER)
# define USE_FPGA # define USE_FPGA
#if defined(USE_ICARUS) #if defined(USE_ICARUS) || defined(USE_AVALON)
# define USE_FPGA_SERIAL # define USE_FPGA_SERIAL
#endif #endif
#elif defined(USE_ZTEX) #elif defined(USE_ZTEX)
@ -138,6 +139,9 @@ bool opt_disable_pool;
char *opt_icarus_options = NULL; char *opt_icarus_options = NULL;
char *opt_icarus_timing = NULL; char *opt_icarus_timing = NULL;
bool opt_worktime; bool opt_worktime;
#ifdef USE_AVALON
char *opt_avalon_options = NULL;
#endif
#ifdef USE_USBUTILS #ifdef USE_USBUTILS
char *opt_usb_select = NULL; char *opt_usb_select = NULL;
int opt_usbdump = -1; int opt_usbdump = -1;
@ -394,6 +398,7 @@ struct thr_info *get_thread(int thr_id)
rd_lock(&mining_thr_lock); rd_lock(&mining_thr_lock);
thr = mining_thr[thr_id]; thr = mining_thr[thr_id];
rd_unlock(&mining_thr_lock); rd_unlock(&mining_thr_lock);
return thr; return thr;
} }
@ -411,6 +416,7 @@ struct cgpu_info *get_devices(int id)
rd_lock(&devices_lock); rd_lock(&devices_lock);
cgpu = devices[id]; cgpu = devices[id];
rd_unlock(&devices_lock); rd_unlock(&devices_lock);
return cgpu; return cgpu;
} }
@ -451,6 +457,7 @@ static void sharelog(const char*disposition, const struct work*work)
ret = fwrite(s, rv, 1, sharelog_file); ret = fwrite(s, rv, 1, sharelog_file);
fflush(sharelog_file); fflush(sharelog_file);
mutex_unlock(&sharelog_lock); mutex_unlock(&sharelog_lock);
if (ret != 1) if (ret != 1)
applog(LOG_ERR, "sharelog fwrite error"); applog(LOG_ERR, "sharelog fwrite error");
} }
@ -496,6 +503,7 @@ static bool pool_tset(struct pool *pool, bool *var)
ret = *var; ret = *var;
*var = true; *var = true;
mutex_unlock(&pool->pool_lock); mutex_unlock(&pool->pool_lock);
return ret; return ret;
} }
@ -507,6 +515,7 @@ bool pool_tclear(struct pool *pool, bool *var)
ret = *var; ret = *var;
*var = false; *var = false;
mutex_unlock(&pool->pool_lock); mutex_unlock(&pool->pool_lock);
return ret; return ret;
} }
@ -517,6 +526,7 @@ struct pool *current_pool(void)
cg_rlock(&control_lock); cg_rlock(&control_lock);
pool = currentpool; pool = currentpool;
cg_runlock(&control_lock); cg_runlock(&control_lock);
return pool; return pool;
} }
@ -786,6 +796,7 @@ static void load_temp_cutoffs()
devices[i]->cutofftemp = opt_cutofftemp; devices[i]->cutofftemp = opt_cutofftemp;
} }
rd_unlock(&devices_lock); rd_unlock(&devices_lock);
return; return;
} }
if (device <= 1) { if (device <= 1) {
@ -833,6 +844,15 @@ static char *set_icarus_timing(const char *arg)
} }
#endif #endif
#ifdef USE_AVALON
static char *set_avalon_options(const char *arg)
{
opt_set_charp(arg, &opt_avalon_options);
return NULL;
}
#endif
#ifdef USE_USBUTILS #ifdef USE_USBUTILS
static char *set_usb_select(const char *arg) static char *set_usb_select(const char *arg)
{ {
@ -1032,6 +1052,11 @@ static struct opt_table opt_config_table[] = {
OPT_WITH_ARG("--icarus-timing", OPT_WITH_ARG("--icarus-timing",
set_icarus_timing, NULL, NULL, set_icarus_timing, NULL, NULL,
opt_hidden), opt_hidden),
#endif
#ifdef USE_AVALON
OPT_WITH_ARG("--avalon-options",
set_avalon_options, NULL, NULL,
opt_hidden),
#endif #endif
OPT_WITHOUT_ARG("--load-balance", OPT_WITHOUT_ARG("--load-balance",
set_loadbalance, &pool_strategy, set_loadbalance, &pool_strategy,
@ -1105,7 +1130,7 @@ static struct opt_table opt_config_table[] = {
#ifdef USE_FPGA_SERIAL #ifdef USE_FPGA_SERIAL
OPT_WITH_ARG("--scan-serial|-S", OPT_WITH_ARG("--scan-serial|-S",
add_serial, NULL, NULL, add_serial, NULL, NULL,
"Serial port to probe for FPGA Mining device"), "Serial port to probe for Icarus FPGA Mining device"),
#endif #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,
@ -1359,6 +1384,9 @@ static char *opt_verusage_and_exit(const char *extra)
#ifdef USE_ICARUS #ifdef USE_ICARUS
"icarus " "icarus "
#endif #endif
#ifdef USE_AVALON
"avalon "
#endif
#ifdef USE_MODMINER #ifdef USE_MODMINER
"modminer " "modminer "
#endif #endif
@ -1470,9 +1498,11 @@ static struct work *make_work(void)
if (unlikely(!work)) if (unlikely(!work))
quit(1, "Failed to calloc work in make_work"); quit(1, "Failed to calloc work in make_work");
cg_wlock(&control_lock); cg_wlock(&control_lock);
work->id = total_work++; work->id = total_work++;
cg_wunlock(&control_lock); cg_wunlock(&control_lock);
return work; return work;
} }
@ -1865,6 +1895,7 @@ static int total_staged(void)
mutex_lock(stgd_lock); mutex_lock(stgd_lock);
ret = __total_staged(); ret = __total_staged();
mutex_unlock(stgd_lock); mutex_unlock(stgd_lock);
return ret; return ret;
} }
@ -2040,10 +2071,8 @@ static void curses_print_status(void)
pool->has_gbt ? "GBT" : "LP", pool->rpc_user); pool->has_gbt ? "GBT" : "LP", pool->rpc_user);
} }
wclrtoeol(statuswin); wclrtoeol(statuswin);
cg_rlock(&ch_lock);
mvwprintw(statuswin, 5, 0, " Block: %s... Diff:%s Started: %s Best share: %s ", mvwprintw(statuswin, 5, 0, " Block: %s... Diff:%s Started: %s Best share: %s ",
current_hash, block_diff, blocktime, best_share); current_hash, block_diff, blocktime, best_share);
cg_runlock(&ch_lock);
mvwhline(statuswin, 6, 0, '-', 80); mvwhline(statuswin, 6, 0, '-', 80);
mvwhline(statuswin, statusy - 1, 0, '-', 80); mvwhline(statuswin, statusy - 1, 0, '-', 80);
mvwprintw(statuswin, devcursor - 1, 1, "[P]ool management %s[S]ettings [D]isplay options [Q]uit", mvwprintw(statuswin, devcursor - 1, 1, "[P]ool management %s[S]ettings [D]isplay options [Q]uit",
@ -2916,7 +2945,6 @@ static void recruit_curl(struct pool *pool)
list_add(&ce->node, &pool->curlring); list_add(&ce->node, &pool->curlring);
pool->curls++; pool->curls++;
applog(LOG_DEBUG, "Recruited curl %d for pool %d", pool->curls, pool->pool_no);
} }
/* Grab an available curl if there is one. If not, then recruit extra curls /* Grab an available curl if there is one. If not, then recruit extra curls
@ -2927,23 +2955,29 @@ static void recruit_curl(struct pool *pool)
static struct curl_ent *pop_curl_entry(struct pool *pool) static struct curl_ent *pop_curl_entry(struct pool *pool)
{ {
int curl_limit = opt_delaynet ? 5 : (mining_threads + opt_queue) * 2; int curl_limit = opt_delaynet ? 5 : (mining_threads + opt_queue) * 2;
bool recruited = false;
struct curl_ent *ce; struct curl_ent *ce;
mutex_lock(&pool->pool_lock); mutex_lock(&pool->pool_lock);
retry: retry:
if (!pool->curls) if (!pool->curls) {
recruit_curl(pool); recruit_curl(pool);
else if (list_empty(&pool->curlring)) { recruited = true;
} else if (list_empty(&pool->curlring)) {
if (pool->curls >= curl_limit) { if (pool->curls >= curl_limit) {
pthread_cond_wait(&pool->cr_cond, &pool->pool_lock); pthread_cond_wait(&pool->cr_cond, &pool->pool_lock);
goto retry; goto retry;
} else } else {
recruit_curl(pool); recruit_curl(pool);
recruited = true;
}
} }
ce = list_entry(pool->curlring.next, struct curl_ent, node); ce = list_entry(pool->curlring.next, struct curl_ent, node);
list_del(&ce->node); list_del(&ce->node);
mutex_unlock(&pool->pool_lock); mutex_unlock(&pool->pool_lock);
if (recruited)
applog(LOG_DEBUG, "Recruited curl for pool %d", pool->pool_no);
return ce; return ce;
} }
@ -3073,7 +3107,6 @@ static bool clone_available(void)
roll_work(work); roll_work(work);
work_clone = make_clone(work); work_clone = make_clone(work);
roll_work(work); roll_work(work);
applog(LOG_DEBUG, "Pushing cloned available work to stage thread");
cloned = true; cloned = true;
break; break;
} }
@ -3082,8 +3115,10 @@ static bool clone_available(void)
out_unlock: out_unlock:
mutex_unlock(stgd_lock); mutex_unlock(stgd_lock);
if (cloned) if (cloned) {
applog(LOG_DEBUG, "Pushing cloned available work to stage thread");
stage_work(work_clone); stage_work(work_clone);
}
return cloned; return cloned;
} }
@ -3133,10 +3168,12 @@ static bool stale_work(struct work *work, bool share)
} }
same_job = true; same_job = true;
cg_rlock(&pool->data_lock); cg_rlock(&pool->data_lock);
if (strcmp(work->job_id, pool->swork.job_id)) if (strcmp(work->job_id, pool->swork.job_id))
same_job = false; same_job = false;
cg_runlock(&pool->data_lock); cg_runlock(&pool->data_lock);
if (!same_job) { if (!same_job) {
applog(LOG_DEBUG, "Work stale due to stratum job_id mismatch"); applog(LOG_DEBUG, "Work stale due to stratum job_id mismatch");
return true; return true;
@ -3180,6 +3217,7 @@ static uint64_t share_diff(const struct work *work)
if (unlikely(!d64)) if (unlikely(!d64))
d64 = 1; d64 = 1;
ret = diffone / d64; ret = diffone / d64;
cg_wlock(&control_lock); cg_wlock(&control_lock);
if (ret > best_diff) { if (ret > best_diff) {
best_diff = ret; best_diff = ret;
@ -3188,6 +3226,7 @@ static uint64_t share_diff(const struct work *work)
if (ret > work->pool->best_diff) if (ret > work->pool->best_diff)
work->pool->best_diff = ret; work->pool->best_diff = ret;
cg_wunlock(&control_lock); cg_wunlock(&control_lock);
return ret; return ret;
} }
@ -3252,6 +3291,7 @@ static void *submit_work_thread(void *userdata)
total_diff_stale += work->work_difficulty; total_diff_stale += work->work_difficulty;
pool->diff_stale += work->work_difficulty; pool->diff_stale += work->work_difficulty;
mutex_unlock(&stats_lock); mutex_unlock(&stats_lock);
goto out; goto out;
} }
work->stale = true; work->stale = true;
@ -3291,10 +3331,12 @@ static void *submit_work_thread(void *userdata)
if (likely(stratum_send(pool, s, strlen(s)))) { if (likely(stratum_send(pool, s, strlen(s)))) {
if (pool_tclear(pool, &pool->submit_fail)) if (pool_tclear(pool, &pool->submit_fail))
applog(LOG_WARNING, "Pool %d communication resumed, submitting work", pool->pool_no); applog(LOG_WARNING, "Pool %d communication resumed, submitting work", pool->pool_no);
mutex_lock(&sshare_lock); mutex_lock(&sshare_lock);
HASH_ADD_INT(stratum_shares, id, sshare); HASH_ADD_INT(stratum_shares, id, sshare);
pool->sshares++; pool->sshares++;
mutex_unlock(&sshare_lock); mutex_unlock(&sshare_lock);
applog(LOG_DEBUG, "Successfully submitted, adding to stratum_shares db"); applog(LOG_DEBUG, "Successfully submitted, adding to stratum_shares db");
submitted = true; submitted = true;
break; break;
@ -3340,6 +3382,7 @@ static void *submit_work_thread(void *userdata)
total_diff_stale += work->work_difficulty; total_diff_stale += work->work_difficulty;
pool->diff_stale += work->work_difficulty; pool->diff_stale += work->work_difficulty;
mutex_unlock(&stats_lock); mutex_unlock(&stats_lock);
break; break;
} }
@ -3567,8 +3610,9 @@ static void set_curblock(char *hexstr, unsigned char *hash)
free(current_fullhash); free(current_fullhash);
current_fullhash = bin2hex(block_hash_swap, 32); current_fullhash = bin2hex(block_hash_swap, 32);
get_timestamp(blocktime, &block_timeval); get_timestamp(blocktime, &block_timeval);
applog(LOG_INFO, "New block: %s... diff %s", current_hash, block_diff);
cg_wunlock(&ch_lock); cg_wunlock(&ch_lock);
applog(LOG_INFO, "New block: %s... diff %s", current_hash, block_diff);
} }
/* Search to see if this string is from a block that has been seen before */ /* Search to see if this string is from a block that has been seen before */
@ -3579,6 +3623,7 @@ static bool block_exists(char *hexstr)
rd_lock(&blk_lock); rd_lock(&blk_lock);
HASH_FIND_STR(blocks, hexstr, s); HASH_FIND_STR(blocks, hexstr, s);
rd_unlock(&blk_lock); rd_unlock(&blk_lock);
if (s) if (s)
return true; return true;
return false; return false;
@ -3667,6 +3712,7 @@ static bool test_work_current(struct work *work)
quit (1, "test_work_current OOM"); quit (1, "test_work_current OOM");
strcpy(s->hash, hexstr); strcpy(s->hash, hexstr);
s->block_no = new_blocks++; s->block_no = new_blocks++;
wr_lock(&blk_lock); wr_lock(&blk_lock);
/* Only keep the last hour's worth of blocks in memory since /* Only keep the last hour's worth of blocks in memory since
* work from blocks before this is virtually impossible and we * work from blocks before this is virtually impossible and we
@ -3683,6 +3729,7 @@ static bool test_work_current(struct work *work)
HASH_ADD_STR(blocks, hash, s); HASH_ADD_STR(blocks, hash, s);
set_blockdiff(work); set_blockdiff(work);
wr_unlock(&blk_lock); wr_unlock(&blk_lock);
if (deleted_block) if (deleted_block)
applog(LOG_DEBUG, "Deleted block %d from database", deleted_block); applog(LOG_DEBUG, "Deleted block %d from database", deleted_block);
set_curblock(hexstr, work->data); set_curblock(hexstr, work->data);
@ -4675,6 +4722,7 @@ static void hashmeter(int thr_id, struct timeval *diff,
local_mhashes_done = 0; local_mhashes_done = 0;
out_unlock: out_unlock:
mutex_unlock(&hash_lock); mutex_unlock(&hash_lock);
if (showlog) { if (showlog) {
if (!curses_active) { if (!curses_active) {
printf("%s \r", statusline); printf("%s \r", statusline);
@ -4737,6 +4785,7 @@ static bool parse_stratum_response(struct pool *pool, char *s)
} }
id = json_integer_value(id_val); id = json_integer_value(id_val);
mutex_lock(&sshare_lock); mutex_lock(&sshare_lock);
HASH_FIND_INT(stratum_shares, &id, sshare); HASH_FIND_INT(stratum_shares, &id, sshare);
if (sshare) { if (sshare) {
@ -4744,6 +4793,7 @@ static bool parse_stratum_response(struct pool *pool, char *s)
pool->sshares--; pool->sshares--;
} }
mutex_unlock(&sshare_lock); mutex_unlock(&sshare_lock);
if (!sshare) { if (!sshare) {
if (json_is_true(res_val)) if (json_is_true(res_val))
applog(LOG_NOTICE, "Accepted untracked stratum share from pool %d", pool->pool_no); applog(LOG_NOTICE, "Accepted untracked stratum share from pool %d", pool->pool_no);
@ -4814,6 +4864,7 @@ static int cp_prio(void)
cg_rlock(&control_lock); cg_rlock(&control_lock);
prio = currentpool->prio; prio = currentpool->prio;
cg_runlock(&control_lock); cg_runlock(&control_lock);
return prio; return prio;
} }
@ -4875,6 +4926,7 @@ static bool supports_resume(struct pool *pool)
cg_rlock(&pool->data_lock); cg_rlock(&pool->data_lock);
ret = (pool->sessionid != NULL); ret = (pool->sessionid != NULL);
cg_runlock(&pool->data_lock); cg_runlock(&pool->data_lock);
return ret; return ret;
} }
@ -5707,15 +5759,20 @@ static void fill_queue(struct thr_info *mythr, struct cgpu_info *cgpu, struct de
{ {
thread_reportout(mythr); thread_reportout(mythr);
do { do {
struct work *work; bool need_work;
rd_lock(&cgpu->qlock);
need_work = (HASH_COUNT(cgpu->queued_work) == cgpu->queued_count);
rd_unlock(&cgpu->qlock);
if (need_work) {
struct work *work = get_work(mythr, thr_id);
wr_lock(&cgpu->qlock);
if (HASH_COUNT(cgpu->queued_work) == cgpu->queued_count) {
work = get_work(mythr, thr_id);
work->device_diff = MIN(drv->max_diff, work->work_difficulty); work->device_diff = MIN(drv->max_diff, work->work_difficulty);
wr_lock(&cgpu->qlock);
HASH_ADD_INT(cgpu->queued_work, id, work); HASH_ADD_INT(cgpu->queued_work, id, work);
}
wr_unlock(&cgpu->qlock); wr_unlock(&cgpu->qlock);
}
/* The queue_full function should be used by the driver to /* The queue_full function should be used by the driver to
* actually place work items on the physical device if it * actually place work items on the physical device if it
* does have a queue. */ * does have a queue. */
@ -5789,6 +5846,7 @@ void work_completed(struct cgpu_info *cgpu, struct work *work)
cgpu->queued_count--; cgpu->queued_count--;
HASH_DEL(cgpu->queued_work, work); HASH_DEL(cgpu->queued_work, work);
wr_unlock(&cgpu->qlock); wr_unlock(&cgpu->qlock);
free_work(work); free_work(work);
} }
@ -6129,6 +6187,7 @@ static void reap_curl(struct pool *pool)
int reaped = 0; int reaped = 0;
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
mutex_lock(&pool->pool_lock); mutex_lock(&pool->pool_lock);
list_for_each_entry_safe(ent, iter, &pool->curlring, node) { list_for_each_entry_safe(ent, iter, &pool->curlring, node) {
if (pool->curls < 2) if (pool->curls < 2)
@ -6142,6 +6201,7 @@ static void reap_curl(struct pool *pool)
} }
} }
mutex_unlock(&pool->pool_lock); mutex_unlock(&pool->pool_lock);
if (reaped) if (reaped)
applog(LOG_DEBUG, "Reaped %d curl%s from pool %d", reaped, reaped > 1 ? "s" : "", pool->pool_no); applog(LOG_DEBUG, "Reaped %d curl%s from pool %d", reaped, reaped > 1 ? "s" : "", pool->pool_no);
} }
@ -6264,6 +6324,7 @@ static void *watchdog_thread(void __maybe_unused *userdata)
applog(LOG_WARNING, "Will restart execution as scheduled at %02d:%02d", applog(LOG_WARNING, "Will restart execution as scheduled at %02d:%02d",
schedstart.tm.tm_hour, schedstart.tm.tm_min); schedstart.tm.tm_hour, schedstart.tm.tm_min);
sched_paused = true; sched_paused = true;
rd_lock(&mining_thr_lock); rd_lock(&mining_thr_lock);
for (i = 0; i < mining_threads; i++) for (i = 0; i < mining_threads; i++)
mining_thr[i]->pause = true; mining_thr[i]->pause = true;
@ -6538,15 +6599,20 @@ static void *test_pool_thread(void *arg)
if (pool_active(pool, false)) { if (pool_active(pool, false)) {
pool_tset(pool, &pool->lagging); pool_tset(pool, &pool->lagging);
pool_tclear(pool, &pool->idle); pool_tclear(pool, &pool->idle);
bool first_pool = false;
cg_wlock(&control_lock); cg_wlock(&control_lock);
if (!pools_active) { if (!pools_active) {
currentpool = pool; currentpool = pool;
if (pool->pool_no != 0) if (pool->pool_no != 0)
applog(LOG_NOTICE, "Switching to pool %d %s - first alive pool", pool->pool_no, pool->rpc_url); first_pool = true;
pools_active = true; pools_active = true;
} }
cg_wunlock(&control_lock); cg_wunlock(&control_lock);
if (unlikely(first_pool))
applog(LOG_NOTICE, "Switching to pool %d %s - first alive pool", pool->pool_no, pool->rpc_url);
pool_resus(pool); pool_resus(pool);
} else } else
pool_died(pool); pool_died(pool);
@ -6751,6 +6817,10 @@ extern struct device_drv bitforce_drv;
extern struct device_drv icarus_drv; extern struct device_drv icarus_drv;
#endif #endif
#ifdef USE_AVALON
extern struct device_drv avalon_drv;
#endif
#ifdef USE_MODMINER #ifdef USE_MODMINER
extern struct device_drv modminer_drv; extern struct device_drv modminer_drv;
#endif #endif
@ -6856,9 +6926,11 @@ void fill_device_drv(struct cgpu_info *cgpu)
void enable_device(struct cgpu_info *cgpu) void enable_device(struct cgpu_info *cgpu)
{ {
cgpu->deven = DEV_ENABLED; cgpu->deven = DEV_ENABLED;
wr_lock(&devices_lock); wr_lock(&devices_lock);
devices[cgpu->cgminer_id = cgminer_id_count++] = cgpu; devices[cgpu->cgminer_id = cgminer_id_count++] = cgpu;
wr_unlock(&devices_lock); wr_unlock(&devices_lock);
if (hotplug_mode) { if (hotplug_mode) {
new_threads += cgpu->threads; new_threads += cgpu->threads;
#ifdef HAVE_CURSES #ifdef HAVE_CURSES
@ -6901,9 +6973,11 @@ bool add_cgpu(struct cgpu_info*cgpu)
cgpu->device_id = d->lastid = 0; cgpu->device_id = d->lastid = 0;
HASH_ADD_STR(devids, name, d); HASH_ADD_STR(devids, name, d);
} }
wr_lock(&devices_lock); wr_lock(&devices_lock);
devices = realloc(devices, sizeof(struct cgpu_info *) * (total_devices + new_devices + 2)); devices = realloc(devices, sizeof(struct cgpu_info *) * (total_devices + new_devices + 2));
wr_unlock(&devices_lock); wr_unlock(&devices_lock);
if (hotplug_mode) if (hotplug_mode)
devices[total_devices + new_devices++] = cgpu; devices[total_devices + new_devices++] = cgpu;
else else
@ -6942,6 +7016,7 @@ static void hotplug_process()
wr_lock(&mining_thr_lock); wr_lock(&mining_thr_lock);
mining_thr = realloc(mining_thr, sizeof(thr) * (mining_threads + new_threads + 1)); mining_thr = realloc(mining_thr, sizeof(thr) * (mining_threads + new_threads + 1));
wr_unlock(&mining_thr_lock); wr_unlock(&mining_thr_lock);
if (!mining_thr) if (!mining_thr)
quit(1, "Failed to hotplug realloc mining_thr"); quit(1, "Failed to hotplug realloc mining_thr");
for (i = 0; i < new_threads; i++) { for (i = 0; i < new_threads; i++) {
@ -7270,6 +7345,11 @@ int main(int argc, char *argv[])
icarus_drv.drv_detect(); icarus_drv.drv_detect();
#endif #endif
#ifdef USE_AVALON
if (!opt_scrypt)
avalon_drv.drv_detect();
#endif
#ifdef USE_BFLSC #ifdef USE_BFLSC
if (!opt_scrypt) if (!opt_scrypt)
bflsc_drv.drv_detect(); bflsc_drv.drv_detect();

23
configure.ac

@ -252,6 +252,17 @@ if test "x$icarus" = xyes; then
fi fi
AM_CONDITIONAL([HAS_ICARUS], [test x$icarus = xyes]) AM_CONDITIONAL([HAS_ICARUS], [test x$icarus = xyes])
avalon="no"
AC_ARG_ENABLE([avalon],
[AC_HELP_STRING([--enable-avalon],[Compile support for Avalon (default disabled)])],
[avalon=$enableval]
)
if test "x$avalon" = xyes; then
AC_DEFINE([USE_AVALON], [1], [Defined to 1 if Avalon support is wanted])
fi
AM_CONDITIONAL([HAS_AVALON], [test x$avalon = xyes])
modminer="no" modminer="no"
AC_ARG_ENABLE([modminer], AC_ARG_ENABLE([modminer],
@ -298,7 +309,7 @@ else
]) ])
fi fi
AM_CONDITIONAL([NEED_FPGAUTILS], [test x$icarus$bitforce$modminer$ztex != xnononono]) AM_CONDITIONAL([NEED_FPGAUTILS], [test x$avalon$icarus$bitforce$modminer$ztex != xnonononono])
AM_CONDITIONAL([NEED_USBUTILS_C], [test x$bitforce$modminer$bflsc != xnonono]) AM_CONDITIONAL([NEED_USBUTILS_C], [test x$bitforce$modminer$bflsc != xnonono])
AM_CONDITIONAL([HAVE_CURSES], [test x$curses = xyes]) AM_CONDITIONAL([HAVE_CURSES], [test x$curses = xyes])
AM_CONDITIONAL([WANT_JANSSON], [test x$request_jansson = xtrue]) AM_CONDITIONAL([WANT_JANSSON], [test x$request_jansson = xtrue])
@ -523,14 +534,14 @@ if test "x$opencl" != xno; then
else else
echo " OpenCL...............: NOT FOUND. GPU mining support DISABLED" echo " OpenCL...............: NOT FOUND. GPU mining support DISABLED"
if test "x$cpumining$bitforce$icarus$ztex$modminer$bflsc" = xnononononono; then if test "x$cpumining$bitforce$avalon$icarus$ztex$modminer$bflsc" = xnonononononono; then
AC_MSG_ERROR([No mining configured in]) AC_MSG_ERROR([No mining configured in])
fi fi
echo " scrypt...............: Disabled (needs OpenCL)" echo " scrypt...............: Disabled (needs OpenCL)"
fi fi
else else
echo " OpenCL...............: Detection overrided. GPU mining support DISABLED" echo " OpenCL...............: Detection overrided. GPU mining support DISABLED"
if test "x$cpumining$bitforce$icarus$ztex$modminer$bflsc" = xnononononono; then if test "x$cpumining$bitforce$icarus$avalon$ztex$modminer$bflsc" = xnonononononono; then
AC_MSG_ERROR([No mining configured in]) AC_MSG_ERROR([No mining configured in])
fi fi
echo " scrypt...............: Disabled (needs OpenCL)" echo " scrypt...............: Disabled (needs OpenCL)"
@ -547,6 +558,12 @@ else
fi fi
echo echo
if test "x$avalon" = xyes; then
echo " Avalon.ASICs.........: Enabled"
else
echo " Avalon.ASICs.........: Disabled"
fi
if test "x$bflsc" = xyes; then if test "x$bflsc" = xyes; then
echo " BFL.ASICs............: Enabled" echo " BFL.ASICs............: Enabled"
else else

1038
driver-avalon.c

File diff suppressed because it is too large Load Diff

130
driver-avalon.h

@ -0,0 +1,130 @@
/*
* Copyright 2013 Avalon project
*
* 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 3 of the License, or (at your option)
* any later version. See COPYING for more details.
*/
#ifndef AVALON_H
#define AVALON_H
#ifdef USE_AVALON
#define AVALON_RESET_FAULT_DECISECONDS 1
#define AVALON_MINER_THREADS 1
#define AVALON_IO_SPEED 115200
#define AVALON_HASH_TIME_FACTOR ((float)1.67/0x32)
#define AVALON_RESET_PITCH (300*1000*1000)
#define AVALON_FAN_FACTOR 120
#define AVALON_DEFAULT_FAN_MAX_PWM 0xA0 /* 100% */
#define AVALON_DEFAULT_FAN_MIN_PWM 0x20 /* 20% */
#define AVALON_DEFAULT_TIMEOUT 0x32
#define AVALON_DEFAULT_FREQUENCY 256
#define AVALON_DEFAULT_MINER_NUM 0x20
#define AVALON_DEFAULT_ASIC_NUM 0xA
struct avalon_task {
uint8_t reset :1;
uint8_t flush_fifo :1;
uint8_t fan_eft :1;
uint8_t timer_eft :1;
uint8_t asic_num :4;
uint8_t fan_pwm_data;
uint8_t timeout_data;
uint8_t miner_num;
uint8_t nonce_elf :1;
uint8_t gate_miner_elf :1;
uint8_t asic_pll :1;
uint8_t gate_miner :1;
uint8_t _pad0 :4;
uint8_t _pad1[3];
uint32_t _pad2;
uint8_t midstate[32];
uint8_t data[12];
} __attribute__((packed, aligned(4)));
struct avalon_result {
uint32_t nonce;
uint8_t data[12];
uint8_t midstate[32];
uint8_t fan0;
uint8_t fan1;
uint8_t fan2;
uint8_t temp0;
uint8_t temp1;
uint8_t temp2;
uint8_t _pad0[2];
uint16_t fifo_wp;
uint16_t fifo_rp;
uint8_t chip_num;
uint8_t pwm_data;
uint8_t timeout;
uint8_t miner_num;
} __attribute__((packed, aligned(4)));
struct avalon_info {
int baud;
int miner_count;
int asic_count;
int timeout;
int fan0;
int fan1;
int fan2;
int temp0;
int temp1;
int temp2;
int temp_max;
int temp_history_count;
int temp_history_index;
int temp_sum;
int temp_old;
int fan_pwm;
int no_matching_work;
int matching_work[AVALON_DEFAULT_MINER_NUM];
int frequency;
};
#define AVALON_WRITE_SIZE (sizeof(struct avalon_task))
#define AVALON_READ_SIZE (sizeof(struct avalon_result))
#define AVALON_ARRAY_SIZE 4
#define AVA_GETS_ERROR -1
#define AVA_GETS_OK 0
#define AVA_GETS_RESTART 1
#define AVA_GETS_TIMEOUT 2
#define AVA_SEND_ERROR -1
#define AVA_SEND_OK 0
#define AVA_SEND_BUFFER_EMPTY 1
#define AVA_SEND_BUFFER_FULL 2
#define AVA_BUFFER_FULL 0
#define AVA_BUFFER_EMPTY 1
#define avalon_open2(devpath, baud, purge) serial_open(devpath, baud, AVALON_RESET_FAULT_DECISECONDS, purge)
#define avalon_open(devpath, baud) avalon_open2(devpath, baud, true)
#define avalon_close(fd) close(fd)
#define avalon_buffer_full(fd) get_serial_cts(fd)
#define AVALON_READ_TIME(baud) ((double)AVALON_READ_SIZE * (double)8.0 / (double)(baud))
#define ASSERT1(condition) __maybe_unused static char sizeof_uint32_t_must_be_4[(condition)?1:-1]
ASSERT1(sizeof(uint32_t) == 4);
extern struct avalon_info **avalon_info;
#endif /* USE_AVALON */
#endif /* AVALON_H */

22
fpgautils.c

@ -1,4 +1,5 @@
/* /*
* Copyright 2013 Con Kolivas <kernel@kolivas.org>
* Copyright 2012 Luke Dashjr * Copyright 2012 Luke Dashjr
* Copyright 2012 Andrew Smith * Copyright 2012 Andrew Smith
* *
@ -19,6 +20,7 @@
#ifndef WIN32 #ifndef WIN32
#include <errno.h> #include <errno.h>
#include <termios.h> #include <termios.h>
#include <sys/ioctl.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
@ -32,10 +34,12 @@
#ifdef HAVE_LIBUDEV #ifdef HAVE_LIBUDEV
#include <libudev.h> #include <libudev.h>
#include <sys/ioctl.h>
#endif #endif
#include "elist.h" #include "elist.h"
#include "logging.h" #include "logging.h"
#include "miner.h"
#include "fpgautils.h" #include "fpgautils.h"
#ifdef HAVE_LIBUDEV #ifdef HAVE_LIBUDEV
@ -382,6 +386,14 @@ int serial_open(const char *devpath, unsigned long baud, signed short timeout, b
switch (baud) { switch (baud) {
case 0: case 0:
break; break;
case 19200:
cfsetispeed(&my_termios, B19200);
cfsetospeed(&my_termios, B19200);
break;
case 38400:
cfsetispeed(&my_termios, B38400);
cfsetospeed(&my_termios, B38400);
break;
case 57600: case 57600:
cfsetispeed(&my_termios, B57600); cfsetispeed(&my_termios, B57600);
cfsetospeed(&my_termios, B57600); cfsetospeed(&my_termios, B57600);
@ -570,4 +582,14 @@ size_t _select_write(int fd, char *buf, size_t siz, struct timeval *timeout)
return wrote; return wrote;
} }
int get_serial_cts(int fd)
{
int flags;
if (!fd)
return -1;
ioctl(fd, TIOCMGET, &flags);
return (flags & TIOCM_CTS) ? 1 : 0;
}
#endif // ! WIN32 #endif // ! WIN32

2
fpgautils.h

@ -36,6 +36,8 @@ extern ssize_t _serial_read(int fd, char *buf, size_t buflen, char *eol);
extern FILE *open_bitstream(const char *dname, const char *filename); extern FILE *open_bitstream(const char *dname, const char *filename);
extern int get_serial_cts(int fd);
#ifndef WIN32 #ifndef WIN32
extern const struct timeval tv_timeout_default; extern const struct timeval tv_timeout_default;
extern const struct timeval tv_inter_char_default; extern const struct timeval tv_inter_char_default;

77
hexdump.c

@ -0,0 +1,77 @@
/*
* hexdump implementation without depenecies to *printf()
* output is equal to 'hexdump -C'
* should be compatible to 64bit architectures
*
* Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define hex_print(p) applog(LOG_DEBUG, "%s", p)
static char nibble[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
#define BYTES_PER_LINE 0x10
void hexdump(const uint8_t *p, unsigned int len)
{
unsigned int i, addr;
unsigned int wordlen = sizeof(void*);
unsigned char v, line[BYTES_PER_LINE * 5];
for (addr = 0; addr < len; addr += BYTES_PER_LINE) {
/* clear line */
for (i = 0; i < sizeof(line); i++) {
if (i == wordlen * 2 + 52 ||
i == wordlen * 2 + 69) {
line[i] = '|';
continue;
}
if (i == wordlen * 2 + 70) {
line[i] = '\0';
continue;
}
line[i] = ' ';
}
/* print address */
for (i = 0; i < wordlen * 2; i++) {
v = addr >> ((wordlen * 2 - i - 1) * 4);
line[i] = nibble[v & 0xf];
}
/* dump content */
for (i = 0; i < BYTES_PER_LINE; i++) {
int pos = (wordlen * 2) + 3 + (i / 8);
if (addr + i >= len)
break;
v = p[addr + i];
line[pos + (i * 3) + 0] = nibble[v >> 4];
line[pos + (i * 3) + 1] = nibble[v & 0xf];
/* character printable? */
line[(wordlen * 2) + 53 + i] =
(v >= ' ' && v <= '~') ? v : '.';
}
hex_print(line);
}
}

14
miner.h

@ -120,9 +120,11 @@ static inline int fsync (int fd)
#if (!defined(WIN32) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) \ #if (!defined(WIN32) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) \
|| (defined(WIN32) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) || (defined(WIN32) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)))
#ifndef bswap_16
#define bswap_16 __builtin_bswap16 #define bswap_16 __builtin_bswap16
#define bswap_32 __builtin_bswap32 #define bswap_32 __builtin_bswap32
#define bswap_64 __builtin_bswap64 #define bswap_64 __builtin_bswap64
#endif
#else #else
#if HAVE_BYTESWAP_H #if HAVE_BYTESWAP_H
#include <byteswap.h> #include <byteswap.h>
@ -421,10 +423,16 @@ struct cgpu_info {
#ifdef USE_USBUTILS #ifdef USE_USBUTILS
struct cg_usb_device *usbdev; struct cg_usb_device *usbdev;
#endif #endif
#ifdef USE_ICARUS #if defined(USE_ICARUS) || defined(USE_AVALON)
int device_fd; int device_fd;
#endif #endif
}; };
#ifdef USE_AVALON
struct work **works;
int work_array;
int queued;
int results;
#endif
#ifdef USE_USBUTILS #ifdef USE_USBUTILS
struct cg_usb_info usbinfo; struct cg_usb_info usbinfo;
#endif #endif
@ -787,6 +795,9 @@ extern bool opt_restart;
extern char *opt_icarus_options; extern char *opt_icarus_options;
extern char *opt_icarus_timing; extern char *opt_icarus_timing;
extern bool opt_worktime; extern bool opt_worktime;
#ifdef USE_AVALON
extern char *opt_avalon_options;
#endif
#ifdef USE_USBUTILS #ifdef USE_USBUTILS
extern char *opt_usb_select; extern char *opt_usb_select;
extern int opt_usbdump; extern int opt_usbdump;
@ -795,6 +806,7 @@ extern bool opt_usb_list_all;
#ifdef USE_BITFORCE #ifdef USE_BITFORCE
extern bool opt_bfl_noncerange; extern bool opt_bfl_noncerange;
#endif #endif
extern bool ping;
extern int swork_id; extern int swork_id;
extern pthread_rwlock_t netacc_lock; extern pthread_rwlock_t netacc_lock;

4
usbutils.c

@ -294,6 +294,8 @@ static const char *C_REQUESTQUEJOB_S = "RequestQueJob";
static const char *C_REQUESTQUEJOBSTATUS_S = "RequestQueJobStatus"; static const char *C_REQUESTQUEJOBSTATUS_S = "RequestQueJobStatus";
static const char *C_QUEJOB_S = "QueJob"; static const char *C_QUEJOB_S = "QueJob";
static const char *C_QUEJOBSTATUS_S = "QueJobStatus"; static const char *C_QUEJOBSTATUS_S = "QueJobStatus";
static const char *C_QUEFLUSH_S = "QueFlush";
static const char *C_QUEFLUSHREPLY_S = "QueFlushReply";
#ifdef EOL #ifdef EOL
#undef EOL #undef EOL
@ -759,6 +761,8 @@ static void cgusb_check_init()
usb_commands[C_REQUESTQUEJOBSTATUS] = C_REQUESTQUEJOBSTATUS_S; usb_commands[C_REQUESTQUEJOBSTATUS] = C_REQUESTQUEJOBSTATUS_S;
usb_commands[C_QUEJOB] = C_QUEJOB_S; usb_commands[C_QUEJOB] = C_QUEJOB_S;
usb_commands[C_QUEJOBSTATUS] = C_QUEJOBSTATUS_S; usb_commands[C_QUEJOBSTATUS] = C_QUEJOBSTATUS_S;
usb_commands[C_QUEFLUSH] = C_QUEFLUSH_S;
usb_commands[C_QUEFLUSHREPLY] = C_QUEFLUSHREPLY_S;
stats_initialised = true; stats_initialised = true;
} }

2
usbutils.h

@ -131,6 +131,8 @@ enum usb_cmds {
C_REQUESTQUEJOBSTATUS, C_REQUESTQUEJOBSTATUS,
C_QUEJOB, C_QUEJOB,
C_QUEJOBSTATUS, C_QUEJOBSTATUS,
C_QUEFLUSH,
C_QUEFLUSHREPLY,
C_MAX C_MAX
}; };

91
util.c

@ -710,9 +710,7 @@ void tq_free(struct thread_q *tq)
static void tq_freezethaw(struct thread_q *tq, bool frozen) static void tq_freezethaw(struct thread_q *tq, bool frozen)
{ {
mutex_lock(&tq->mutex); mutex_lock(&tq->mutex);
tq->frozen = frozen; tq->frozen = frozen;
pthread_cond_signal(&tq->cond); pthread_cond_signal(&tq->cond);
mutex_unlock(&tq->mutex); mutex_unlock(&tq->mutex);
} }
@ -740,14 +738,12 @@ bool tq_push(struct thread_q *tq, void *data)
INIT_LIST_HEAD(&ent->q_node); INIT_LIST_HEAD(&ent->q_node);
mutex_lock(&tq->mutex); mutex_lock(&tq->mutex);
if (!tq->frozen) { if (!tq->frozen) {
list_add_tail(&ent->q_node, &tq->q); list_add_tail(&ent->q_node, &tq->q);
} else { } else {
free(ent); free(ent);
rc = false; rc = false;
} }
pthread_cond_signal(&tq->cond); pthread_cond_signal(&tq->cond);
mutex_unlock(&tq->mutex); mutex_unlock(&tq->mutex);
@ -761,7 +757,6 @@ void *tq_pop(struct thread_q *tq, const struct timespec *abstime)
int rc; int rc;
mutex_lock(&tq->mutex); mutex_lock(&tq->mutex);
if (!list_empty(&tq->q)) if (!list_empty(&tq->q))
goto pop; goto pop;
@ -773,16 +768,15 @@ void *tq_pop(struct thread_q *tq, const struct timespec *abstime)
goto out; goto out;
if (list_empty(&tq->q)) if (list_empty(&tq->q))
goto out; goto out;
pop: pop:
ent = list_entry(tq->q.next, struct tq_ent, q_node); ent = list_entry(tq->q.next, struct tq_ent, q_node);
rval = ent->data; rval = ent->data;
list_del(&ent->q_node); list_del(&ent->q_node);
free(ent); free(ent);
out: out:
mutex_unlock(&tq->mutex); mutex_unlock(&tq->mutex);
return rval; return rval;
} }
@ -898,16 +892,20 @@ bool extract_sockaddr(struct pool *pool, char *url)
return true; return true;
} }
enum send_ret {
SEND_OK,
SEND_SELECTFAIL,
SEND_SENDFAIL,
SEND_INACTIVE
};
/* Send a single command across a socket, appending \n to it. This should all /* Send a single command across a socket, appending \n to it. This should all
* be done under stratum lock except when first establishing the socket */ * be done under stratum lock except when first establishing the socket */
static bool __stratum_send(struct pool *pool, char *s, ssize_t len) static enum send_ret __stratum_send(struct pool *pool, char *s, ssize_t len)
{ {
SOCKETTYPE sock = pool->sock; SOCKETTYPE sock = pool->sock;
ssize_t ssent = 0; ssize_t ssent = 0;
if (opt_protocol)
applog(LOG_DEBUG, "SEND: %s", s);
strcat(s, "\n"); strcat(s, "\n");
len++; len++;
@ -918,16 +916,12 @@ static bool __stratum_send(struct pool *pool, char *s, ssize_t len)
FD_ZERO(&wd); FD_ZERO(&wd);
FD_SET(sock, &wd); FD_SET(sock, &wd);
if (select(sock + 1, NULL, &wd, NULL, &timeout) < 1) { if (select(sock + 1, NULL, &wd, NULL, &timeout) < 1)
applog(LOG_DEBUG, "Write select failed on pool %d sock", pool->pool_no); return SEND_SELECTFAIL;
return false;
}
sent = send(pool->sock, s + ssent, len, 0); sent = send(pool->sock, s + ssent, len, 0);
if (sent < 0) { if (sent < 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK) { if (errno != EAGAIN && errno != EWOULDBLOCK)
applog(LOG_DEBUG, "Failed to curl_easy_send in stratum_send"); return SEND_SENDFAIL;
return false;
}
sent = 0; sent = 0;
} }
ssent += sent; ssent += sent;
@ -937,21 +931,37 @@ static bool __stratum_send(struct pool *pool, char *s, ssize_t len)
pool->cgminer_pool_stats.times_sent++; pool->cgminer_pool_stats.times_sent++;
pool->cgminer_pool_stats.bytes_sent += ssent; pool->cgminer_pool_stats.bytes_sent += ssent;
pool->cgminer_pool_stats.net_bytes_sent += ssent; pool->cgminer_pool_stats.net_bytes_sent += ssent;
return true; return SEND_OK;
} }
bool stratum_send(struct pool *pool, char *s, ssize_t len) bool stratum_send(struct pool *pool, char *s, ssize_t len)
{ {
bool ret = false; enum send_ret ret = SEND_INACTIVE;
if (opt_protocol)
applog(LOG_DEBUG, "SEND: %s", s);
mutex_lock(&pool->stratum_lock); mutex_lock(&pool->stratum_lock);
if (pool->stratum_active) if (pool->stratum_active)
ret = __stratum_send(pool, s, len); ret = __stratum_send(pool, s, len);
else
applog(LOG_DEBUG, "Stratum send failed due to no pool stratum_active");
mutex_unlock(&pool->stratum_lock); mutex_unlock(&pool->stratum_lock);
return ret; /* This is to avoid doing applog under stratum_lock */
switch (ret) {
default:
case SEND_OK:
break;
case SEND_SELECTFAIL:
applog(LOG_DEBUG, "Write select failed on pool %d sock", pool->pool_no);
break;
case SEND_SENDFAIL:
applog(LOG_DEBUG, "Failed to curl_easy_send in stratum_send");
break;
case SEND_INACTIVE:
applog(LOG_DEBUG, "Stratum send failed due to no pool stratum_active");
break;
}
return (ret == SEND_OK);
} }
static bool socket_full(struct pool *pool, bool wait) static bool socket_full(struct pool *pool, bool wait)
@ -1011,7 +1021,8 @@ static void recalloc_sock(struct pool *pool, size_t len)
if (new < pool->sockbuf_size) if (new < pool->sockbuf_size)
return; return;
new = new + (RBUFSIZE - (new % RBUFSIZE)); new = new + (RBUFSIZE - (new % RBUFSIZE));
applog(LOG_DEBUG, "Recallocing pool sockbuf to %d", new); // Avoid potentially recursive locking
// applog(LOG_DEBUG, "Recallocing pool sockbuf to %d", new);
pool->sockbuf = realloc(pool->sockbuf, new); pool->sockbuf = realloc(pool->sockbuf, new);
if (!pool->sockbuf) if (!pool->sockbuf)
quit(1, "Failed to realloc pool sockbuf in recalloc_sock"); quit(1, "Failed to realloc pool sockbuf in recalloc_sock");
@ -1019,6 +1030,12 @@ static void recalloc_sock(struct pool *pool, size_t len)
pool->sockbuf_size = new; pool->sockbuf_size = new;
} }
enum recv_ret {
RECV_OK,
RECV_CLOSED,
RECV_RECVFAIL
};
/* Peeks at a socket to find the first end of line and then reads just that /* Peeks at a socket to find the first end of line and then reads just that
* from the socket and returns that as a malloced char */ * from the socket and returns that as a malloced char */
char *recv_line(struct pool *pool) char *recv_line(struct pool *pool)
@ -1027,6 +1044,7 @@ char *recv_line(struct pool *pool)
char *tok, *sret = NULL; char *tok, *sret = NULL;
if (!strstr(pool->sockbuf, "\n")) { if (!strstr(pool->sockbuf, "\n")) {
enum recv_ret ret = RECV_OK;
struct timeval rstart, now; struct timeval rstart, now;
gettimeofday(&rstart, NULL); gettimeofday(&rstart, NULL);
@ -1044,11 +1062,11 @@ char *recv_line(struct pool *pool)
memset(s, 0, RBUFSIZE); memset(s, 0, RBUFSIZE);
n = recv(pool->sock, s, RECVSIZE, 0); n = recv(pool->sock, s, RECVSIZE, 0);
if (!n) { if (!n) {
applog(LOG_DEBUG, "Socket closed waiting in recv_line"); ret = RECV_CLOSED;
break; break;
} }
if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
applog(LOG_DEBUG, "Failed to recv sock in recv_line"); ret = RECV_RECVFAIL;
break; break;
} }
slen = strlen(s); slen = strlen(s);
@ -1057,6 +1075,18 @@ char *recv_line(struct pool *pool)
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
} while (tdiff(&now, &rstart) < 60 && !strstr(pool->sockbuf, "\n")); } while (tdiff(&now, &rstart) < 60 && !strstr(pool->sockbuf, "\n"));
mutex_unlock(&pool->stratum_lock); mutex_unlock(&pool->stratum_lock);
switch (ret) {
default:
case RECV_OK:
break;
case RECV_CLOSED:
applog(LOG_DEBUG, "Socket closed waiting in recv_line");
break;
case RECV_RECVFAIL:
applog(LOG_DEBUG, "Failed to recv sock in recv_line");
break;
}
} }
buflen = strlen(pool->sockbuf); buflen = strlen(pool->sockbuf);
@ -1441,6 +1471,7 @@ static bool setup_stratum_curl(struct pool *pool)
if (unlikely(!pool->stratum_curl)) if (unlikely(!pool->stratum_curl))
quit(1, "Failed to curl_easy_init in initiate_stratum"); quit(1, "Failed to curl_easy_init in initiate_stratum");
mutex_unlock(&pool->stratum_lock); mutex_unlock(&pool->stratum_lock);
curl = pool->stratum_curl; curl = pool->stratum_curl;
if (!pool->sockbuf) { if (!pool->sockbuf) {
@ -1470,6 +1501,8 @@ static bool setup_stratum_curl(struct pool *pool)
curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1); curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1);
if (curl_easy_perform(curl)) { if (curl_easy_perform(curl)) {
applog(LOG_INFO, "Stratum connect failed to pool %d: %s", pool->pool_no, curl_err_str); applog(LOG_INFO, "Stratum connect failed to pool %d: %s", pool->pool_no, curl_err_str);
curl_easy_cleanup(curl);
pool->stratum_curl = NULL;
return false; return false;
} }
curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, (long *)&pool->sock); curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, (long *)&pool->sock);
@ -1517,6 +1550,7 @@ void suspend_stratum(struct pool *pool)
{ {
clear_sockbuf(pool); clear_sockbuf(pool);
applog(LOG_INFO, "Closing socket for stratum pool %d", pool->pool_no); applog(LOG_INFO, "Closing socket for stratum pool %d", pool->pool_no);
mutex_lock(&pool->stratum_lock); mutex_lock(&pool->stratum_lock);
pool->stratum_active = pool->stratum_notify = false; pool->stratum_active = pool->stratum_notify = false;
if (pool->stratum_curl) { if (pool->stratum_curl) {
@ -1561,7 +1595,7 @@ resend:
sprintf(s, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": [\""PACKAGE"/"VERSION"\"]}", swork_id++); sprintf(s, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": [\""PACKAGE"/"VERSION"\"]}", swork_id++);
} }
if (!__stratum_send(pool, s, strlen(s))) { if (__stratum_send(pool, s, strlen(s)) != SEND_OK) {
applog(LOG_DEBUG, "Failed to send s in initiate_stratum"); applog(LOG_DEBUG, "Failed to send s in initiate_stratum");
goto out; goto out;
} }
@ -1654,6 +1688,7 @@ out:
free(pool->nonce1); free(pool->nonce1);
pool->sessionid = pool->nonce1 = NULL; pool->sessionid = pool->nonce1 = NULL;
cg_wunlock(&pool->data_lock); cg_wunlock(&pool->data_lock);
applog(LOG_DEBUG, "Failed to resume stratum, trying afresh"); applog(LOG_DEBUG, "Failed to resume stratum, trying afresh");
noresume = true; noresume = true;
goto resend; goto resend;

Loading…
Cancel
Save