Browse Source

Merge branch 'master' of https://github.com/kanoi/cgminer into kanoi-usb

nfactor-troky
Con Kolivas 12 years ago
parent
commit
70b5b84052
  1. 57
      API-README
  2. 25
      FPGA-README
  3. 6
      Makefile.am
  4. 20
      README
  5. 175
      api.c
  6. 328
      cgminer.c
  7. 7
      configure.ac
  8. 670
      driver-bitforce.c
  9. 9
      driver-cpu.c
  10. 2
      driver-cpu.h
  11. 19
      driver-icarus.c
  12. 182
      driver-modminer.c
  13. 70
      driver-opencl.c
  14. 2
      driver-opencl.h
  15. 10
      driver-ztex.c
  16. 2
      findnonce.c
  17. 10
      fpgautils.c
  18. 14
      fpgautils.h
  19. 44
      miner.h
  20. 287
      miner.php
  21. 720
      usbutils.c
  22. 77
      usbutils.h
  23. 35
      util.c

57
API-README

@ -347,6 +347,18 @@ The list of requests - a (*) means it requires privileged access - and replies a
The current options are: The current options are:
MMQ opt=clock val=160 to 230 (and a multiple of 2) MMQ opt=clock val=160 to 230 (and a multiple of 2)
zero|Which,true/false (*)
none There is no reply section just the STATUS section
stating that the zero, and optional summary, was done
If Which='all', all normal cgminer and API statistics
will be zeroed other than the numbers displayed by the
usbstats and stats commands
If Which='bestshare', only the 'Best Share' values
are zeroed for each pool and the global 'Best Share'
The true/false option determines if a full summary is
shown on the cgminer display like is normally displayed
on exit.
When you enable, disable or restart a GPU or PGA, you will also get Thread messages When you enable, disable or restart a GPU or PGA, you will also get Thread messages
in the cgminer status window in the cgminer status window
@ -400,7 +412,18 @@ miner.php - an example web page to access the API
Feature Changelog for external applications using the API: Feature Changelog for external applications using the API:
API V1.23 API V1.24
Added API commands:
'zero'
Modified API commands:
'pools' - add 'Best Share'
'devs' and 'pga' - add 'No Device' for PGAs if MMQ or BFL compiled
----------
API V1.23 (cgminer v2.10.2)
Added API commands: Added API commands:
'pgaset' - with: MMQ opt=clock val=160 to 230 (and a multiple of 2) 'pgaset' - with: MMQ opt=clock val=160 to 230 (and a multiple of 2)
@ -930,6 +953,38 @@ true
--------- ---------
Default:
$userlist = null;
Define password checking and default access
null means there is no password checking
$userlist is an array of 3 arrays e.g.
$userlist = array('sys' => array('boss' => 'bpass'),
'usr' => array('user' => 'upass', 'pleb' => 'ppass'),
'def' => array('Pools'));
'sys' is an array of system users and passwords (full access)
'usr' is an array of user level users and passwords (readonly access)
'def' is an array of custompages that anyone not logged in can view
Any of the 3 can be null, meaning there are none of that item
All validated 'usr' users are given $readonly = true; access
All validated 'sys' users are given the $readonly access you defined
If 'def' has one or more values, and allowcustompages is true, then
anyone without a password can see the list of custompage buttons given
in 'def' and will see the first one when they go to the web page, with
a login button at the top right
From the login page, if you login with no username or password, it will
show the first 'def' custompage (if there are any)
If you are logged in, it will show a logout button at the top right
---------
Default: Default:
$notify = true; $notify = true;

25
FPGA-README

@ -2,15 +2,8 @@
This README contains extended details about FPGA mining with cgminer This README contains extended details about FPGA mining with cgminer
ModMinerQuad (MMQ) For ModMinerQuad (MMQ) and BitForce (BFL)
------------------ -----------------------------------------
The mining bitstream does not survive a power cycle, so cgminer will upload
it, if it needs to, before it starts mining (approx 7min 40sec)
The red LED also flashes while it is uploading the bitstream
-
When mining on windows, the driver being used will determine if mining will work. When mining on windows, the driver being used will determine if mining will work.
@ -39,7 +32,17 @@ problems:
--usb-dump 0 --usb-dump 0
It will only help if you have a working MMQ device attached to the computer It will only help if you have a working MMQ or BFL device attached to the
computer
ModMinerQuad (MMQ)
------------------
The mining bitstream does not survive a power cycle, so cgminer will upload
it, if it needs to, before it starts mining (approx 7min 40sec)
The red LED also flashes while it is uploading the bitstream
- -
@ -130,7 +133,7 @@ modem-manager software
TODO: check that all MMQ's have the same product ID TODO: check that all MMQ's have the same product ID
Bitforce (BFL) BitForce (BFL)
-------------- --------------
--bfl-range Use nonce range on bitforce devices if supported --bfl-range Use nonce range on bitforce devices if supported

6
Makefile.am

@ -82,6 +82,10 @@ if NEED_FPGAUTILS
cgminer_SOURCES += fpgautils.c fpgautils.h cgminer_SOURCES += fpgautils.c fpgautils.h
endif endif
if NEED_USBUTILS_C
cgminer_SOURCES += usbutils.c
endif
if HAS_BITFORCE if HAS_BITFORCE
cgminer_SOURCES += driver-bitforce.c cgminer_SOURCES += driver-bitforce.c
endif endif
@ -91,7 +95,7 @@ cgminer_SOURCES += driver-icarus.c
endif endif
if HAS_MODMINER if HAS_MODMINER
cgminer_SOURCES += driver-modminer.c usbutils.c cgminer_SOURCES += driver-modminer.c
bitstreamsdir = $(bindir)/bitstreams bitstreamsdir = $(bindir)/bitstreams
dist_bitstreams_DATA = bitstreams/* dist_bitstreams_DATA = bitstreams/*
endif endif

20
README

@ -220,15 +220,16 @@ SCRYPT only options:
See SCRYPT-README for more information regarding litecoin mining. See SCRYPT-README for more information regarding litecoin mining.
FPGA mining boards(BitForce, Icarus, ModMiner, Ztex) only options: FPGA mining boards (BitForce, Icarus, ModMiner, Ztex) only options:
cgminer will automatically find your ModMiner or Ztex FPGAs cgminer will automatically find your ModMiner, BitForce or Ztex FPGAs
independent of the --scan-serial options specified below
--scan-serial|-S <arg> Serial port to probe for FPGA mining device --scan-serial|-S <arg> Serial port to probe for Icarus mining device
This option is only for BitForce and/or Icarus FPGAs This option is only for Icarus bitstream FPGAs
By default, cgminer will scan for autodetected FPGAs unless at least one By default, cgminer will scan for autodetected Icarus unless at least one
-S is specified for that driver. If you specify -S and still want cgminer -S is specified for that driver. If you specify -S and still want cgminer
to scan, you must also use "-S auto". If you want to prevent cgminer from to scan, you must also use "-S auto". If you want to prevent cgminer from
scanning without specifying a device, you can use "-S noauto". Note that scanning without specifying a device, you can use "-S noauto". Note that
@ -237,13 +238,14 @@ device depending on the version of udev being used.
On linux <arg> is usually of the format /dev/ttyUSBn On linux <arg> is usually of the format /dev/ttyUSBn
On windows <arg> is usually of the format \\.\COMn On windows <arg> is usually of the format \\.\COMn
(where n = the correct device number for the FPGA device) (where n = the correct device number for the Icarus device)
The official supplied binaries are compiled with support for all FPGAs. The official supplied binaries are compiled with support for all FPGAs.
To force the code to only attempt detection with a specific driver, To force the code to only attempt detection with a specific driver,
prepend the argument with the driver name followed by a colon. prepend the argument with the driver name followed by a colon.
For example, "icarus:/dev/ttyUSB0" or "bitforce:\\.\COM5" For example, "icarus:/dev/ttyUSB0" or using the short name: "ica:/dev/ttyUSB0"
or using the short name: "ica:/dev/ttyUSB0" or "bfl:\\.\COM5" This option not longer matters since Icarus is the only serial-USB
device that uses it
For other FPGA details see the FPGA-README For other FPGA details see the FPGA-README
@ -455,7 +457,7 @@ The block display shows:
Block: 0074c5e482e34a506d2a051a... Started: [17:17:22] Best share: 2.71K Block: 0074c5e482e34a506d2a051a... Started: [17:17:22] Best share: 2.71K
This shows a short stretch of the current block, when the new block started, This shows a short stretch of the current block, when the new block started,
and the all time best difficulty share you've submitted since starting cgminer and the all time best difficulty share you've found since starting cgminer
this time. this time.

175
api.c

@ -1,5 +1,5 @@
/* /*
* Copyright 2011-2012 Andrew Smith * Copyright 2011-2013 Andrew Smith
* Copyright 2011-2012 Con Kolivas * Copyright 2011-2012 Con Kolivas
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
@ -133,7 +133,7 @@ static const char SEPARATOR = '|';
#define SEPSTR "|" #define SEPSTR "|"
static const char GPUSEP = ','; static const char GPUSEP = ',';
static const char *APIVERSION = "1.23"; static const char *APIVERSION = "1.24";
static const char *DEAD = "Dead"; static const char *DEAD = "Dead";
#if defined(HAVE_OPENCL) || defined(HAVE_AN_FPGA) #if defined(HAVE_OPENCL) || defined(HAVE_AN_FPGA)
static const char *SICK = "Sick"; static const char *SICK = "Sick";
@ -387,6 +387,12 @@ static const char *JSON_PARAMETER = "parameter";
#define MSG_PGASETERR 93 #define MSG_PGASETERR 93
#endif #endif
#define MSG_ZERMIS 94
#define MSG_ZERINV 95
#define MSG_ZERSUM 96
#define MSG_ZERNOSUM 97
#define MSG_USBNODEV 98
enum code_severity { enum code_severity {
SEVERITY_ERR, SEVERITY_ERR,
SEVERITY_WARN, SEVERITY_WARN,
@ -558,6 +564,13 @@ struct CODES {
{ SEVERITY_INFO, MSG_PGAHELP, PARAM_BOTH, "PGA %d set help: %s" }, { SEVERITY_INFO, MSG_PGAHELP, PARAM_BOTH, "PGA %d set help: %s" },
{ SEVERITY_SUCC, MSG_PGASETOK, PARAM_BOTH, "PGA %d set OK" }, { SEVERITY_SUCC, MSG_PGASETOK, PARAM_BOTH, "PGA %d set OK" },
{ SEVERITY_ERR, MSG_PGASETERR, PARAM_BOTH, "PGA %d set failed: %s" }, { SEVERITY_ERR, MSG_PGASETERR, PARAM_BOTH, "PGA %d set failed: %s" },
#endif
{ SEVERITY_ERR, MSG_ZERMIS, PARAM_NONE, "Missing zero parameters" },
{ SEVERITY_ERR, MSG_ZERINV, PARAM_STR, "Invalid zero parameter '%s'" },
{ SEVERITY_SUCC, MSG_ZERSUM, PARAM_STR, "Zeroed %s stats with summary" },
{ SEVERITY_SUCC, MSG_ZERNOSUM, PARAM_STR, "Zeroed %s stats without summary" },
#if defined(USE_MODMINER) || defined(USE_BITFORCE)
{ SEVERITY_ERR, MSG_USBNODEV, PARAM_PGA, "PGA%d has no device" },
#endif #endif
{ SEVERITY_FAIL, 0, 0, NULL } { SEVERITY_FAIL, 0, 0, NULL }
}; };
@ -599,22 +612,6 @@ struct APIGROUPS {
static struct IP4ACCESS *ipaccess = NULL; static struct IP4ACCESS *ipaccess = NULL;
static int ips = 0; static int ips = 0;
#ifdef USE_BITFORCE
extern struct device_api bitforce_api;
#endif
#ifdef USE_ICARUS
extern struct device_api icarus_api;
#endif
#ifdef USE_ZTEX
extern struct device_api ztex_api;
#endif
#ifdef USE_MODMINER
extern struct device_api modminer_api;
#endif
struct io_data { struct io_data {
size_t siz; size_t siz;
char *ptr; char *ptr;
@ -1153,19 +1150,19 @@ static int numpgas()
for (i = 0; i < total_devices; i++) { for (i = 0; i < total_devices; i++) {
#ifdef USE_BITFORCE #ifdef USE_BITFORCE
if (devices[i]->api == &bitforce_api) if (devices[i]->drv->drv == DRIVER_BITFORCE)
count++; count++;
#endif #endif
#ifdef USE_ICARUS #ifdef USE_ICARUS
if (devices[i]->api == &icarus_api) if (devices[i]->drv->drv == DRIVER_ICARUS)
count++; count++;
#endif #endif
#ifdef USE_ZTEX #ifdef USE_ZTEX
if (devices[i]->api == &ztex_api) if (devices[i]->drv->drv == DRIVER_ZTEX)
count++; count++;
#endif #endif
#ifdef USE_MODMINER #ifdef USE_MODMINER
if (devices[i]->api == &modminer_api) if (devices[i]->drv->drv == DRIVER_MODMINER)
count++; count++;
#endif #endif
} }
@ -1179,19 +1176,19 @@ static int pgadevice(int pgaid)
for (i = 0; i < total_devices; i++) { for (i = 0; i < total_devices; i++) {
#ifdef USE_BITFORCE #ifdef USE_BITFORCE
if (devices[i]->api == &bitforce_api) if (devices[i]->drv->drv == DRIVER_BITFORCE)
count++; count++;
#endif #endif
#ifdef USE_ICARUS #ifdef USE_ICARUS
if (devices[i]->api == &icarus_api) if (devices[i]->drv->drv == DRIVER_ICARUS)
count++; count++;
#endif #endif
#ifdef USE_ZTEX #ifdef USE_ZTEX
if (devices[i]->api == &ztex_api) if (devices[i]->drv->drv == DRIVER_ZTEX)
count++; count++;
#endif #endif
#ifdef USE_MODMINER #ifdef USE_MODMINER
if (devices[i]->api == &modminer_api) if (devices[i]->drv->drv == DRIVER_MODMINER)
count++; count++;
#endif #endif
if (count == (pgaid + 1)) if (count == (pgaid + 1))
@ -1535,11 +1532,11 @@ static void pgastatus(struct io_data *io_data, int pga, bool isjson, bool precom
float temp = cgpu->temp; float temp = cgpu->temp;
#ifdef USE_ZTEX #ifdef USE_ZTEX
if (cgpu->api == &ztex_api && cgpu->device_ztex) if (cgpu->drv->drv == DRIVER_ZTEX && cgpu->device_ztex)
frequency = cgpu->device_ztex->freqM1 * (cgpu->device_ztex->freqM + 1); frequency = cgpu->device_ztex->freqM1 * (cgpu->device_ztex->freqM + 1);
#endif #endif
#ifdef USE_MODMINER #ifdef USE_MODMINER
if (cgpu->api == &modminer_api) if (cgpu->drv->drv == DRIVER_MODMINER)
frequency = cgpu->clock; frequency = cgpu->clock;
#endif #endif
@ -1553,7 +1550,7 @@ static void pgastatus(struct io_data *io_data, int pga, bool isjson, bool precom
status = (char *)status2str(cgpu->status); status = (char *)status2str(cgpu->status);
root = api_add_int(root, "PGA", &pga, false); root = api_add_int(root, "PGA", &pga, false);
root = api_add_string(root, "Name", cgpu->api->name, false); root = api_add_string(root, "Name", cgpu->drv->name, false);
root = api_add_int(root, "ID", &(cgpu->device_id), false); root = api_add_int(root, "ID", &(cgpu->device_id), false);
root = api_add_string(root, "Enabled", enabled, false); root = api_add_string(root, "Enabled", enabled, false);
root = api_add_string(root, "Status", status, false); root = api_add_string(root, "Status", status, false);
@ -1577,6 +1574,9 @@ static void pgastatus(struct io_data *io_data, int pga, bool isjson, bool precom
root = api_add_diff(root, "Difficulty Accepted", &(cgpu->diff_accepted), false); root = api_add_diff(root, "Difficulty Accepted", &(cgpu->diff_accepted), false);
root = api_add_diff(root, "Difficulty Rejected", &(cgpu->diff_rejected), false); root = api_add_diff(root, "Difficulty Rejected", &(cgpu->diff_rejected), false);
root = api_add_diff(root, "Last Share Difficulty", &(cgpu->last_share_diff), false); root = api_add_diff(root, "Last Share Difficulty", &(cgpu->last_share_diff), false);
#if defined(USE_MODMINER) || defined(USE_BITFORCE)
root = api_add_bool(root, "No Device", &(cgpu->usbinfo.nodev), false);
#endif
root = print_data(root, buf, isjson, precom); root = print_data(root, buf, isjson, precom);
io_add(io_data, buf); io_add(io_data, buf);
@ -1777,6 +1777,9 @@ static void pgaenable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char
struct cgpu_info *cgpu = devices[dev]; struct cgpu_info *cgpu = devices[dev];
applog(LOG_DEBUG, "API: request to pgaenable pgaid %d device %d %s%u",
id, dev, cgpu->drv->name, cgpu->device_id);
if (cgpu->deven != DEV_DISABLED) { if (cgpu->deven != DEV_DISABLED) {
message(io_data, MSG_PGALRENA, id, NULL, isjson); message(io_data, MSG_PGALRENA, id, NULL, isjson);
return; return;
@ -1789,11 +1792,21 @@ static void pgaenable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char
} }
#endif #endif
#if defined(USE_MODMINER) || defined(USE_BITFORCE)
if (cgpu->usbinfo.nodev) {
message(io_data, MSG_USBNODEV, id, NULL, isjson);
return;
}
#endif
for (i = 0; i < mining_threads; i++) { for (i = 0; i < mining_threads; i++) {
pga = thr_info[i].cgpu->device_id; mutex_lock(&mining_thr_lock);
thr = mining_thr[i];
mutex_unlock(&mining_thr_lock);
pga = thr->cgpu->cgminer_id;
if (pga == dev) { if (pga == dev) {
thr = &thr_info[i];
cgpu->deven = DEV_ENABLED; cgpu->deven = DEV_ENABLED;
applog(LOG_DEBUG, "API: pushing ping (%d) to thread %d", ping, thr->id);
tq_push(thr->q, &ping); tq_push(thr->q, &ping);
} }
} }
@ -1830,6 +1843,9 @@ static void pgadisable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, cha
struct cgpu_info *cgpu = devices[dev]; struct cgpu_info *cgpu = devices[dev];
applog(LOG_DEBUG, "API: request to pgadisable pgaid %d device %d %s%u",
id, dev, cgpu->drv->name, cgpu->device_id);
if (cgpu->deven == DEV_DISABLED) { if (cgpu->deven == DEV_DISABLED) {
message(io_data, MSG_PGALRDIS, id, NULL, isjson); message(io_data, MSG_PGALRDIS, id, NULL, isjson);
return; return;
@ -1868,12 +1884,12 @@ static void pgaidentify(struct io_data *io_data, __maybe_unused SOCKETTYPE c, ch
} }
struct cgpu_info *cgpu = devices[dev]; struct cgpu_info *cgpu = devices[dev];
struct device_api *api = cgpu->api; struct device_drv *drv = cgpu->drv;
if (!api->identify_device) if (!drv->identify_device)
message(io_data, MSG_PGANOID, id, NULL, isjson); message(io_data, MSG_PGANOID, id, NULL, isjson);
else { else {
api->identify_device(cgpu); drv->identify_device(cgpu);
message(io_data, MSG_PGAIDENT, id, NULL, isjson); message(io_data, MSG_PGAIDENT, id, NULL, isjson);
} }
} }
@ -1993,6 +2009,7 @@ static void poolstatus(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __m
else else
root = api_add_const(root, "Stratum URL", BLANK, false); root = api_add_const(root, "Stratum URL", BLANK, false);
root = api_add_bool(root, "Has GBT", &(pool->has_gbt), false); root = api_add_bool(root, "Has GBT", &(pool->has_gbt), false);
root = api_add_uint64(root, "Best Share", &(pool->best_diff), true);
root = print_data(root, buf, isjson, isjson && (i > 0)); root = print_data(root, buf, isjson, isjson && (i > 0));
io_add(io_data, buf); io_add(io_data, buf);
@ -2081,23 +2098,27 @@ static void gpuenable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char
return; return;
} }
applog(LOG_DEBUG, "API: request to gpuenable gpuid %d %s%u",
id, gpus[id].drv->name, gpus[id].device_id);
if (gpus[id].deven != DEV_DISABLED) { if (gpus[id].deven != DEV_DISABLED) {
message(io_data, MSG_ALRENA, id, NULL, isjson); message(io_data, MSG_ALRENA, id, NULL, isjson);
return; return;
} }
for (i = 0; i < gpu_threads; i++) { for (i = 0; i < gpu_threads; i++) {
gpu = thr_info[i].cgpu->device_id; mutex_lock(&mining_thr_lock);
thr = mining_thr[i];
mutex_unlock(&mining_thr_lock);
gpu = thr->cgpu->device_id;
if (gpu == id) { if (gpu == id) {
thr = &thr_info[i];
if (thr->cgpu->status != LIFE_WELL) { if (thr->cgpu->status != LIFE_WELL) {
message(io_data, MSG_GPUMRE, id, NULL, isjson); message(io_data, MSG_GPUMRE, id, NULL, isjson);
return; return;
} }
gpus[id].deven = DEV_ENABLED; gpus[id].deven = DEV_ENABLED;
applog(LOG_DEBUG, "API: pushing ping (%d) to thread %d", ping, thr->id);
tq_push(thr->q, &ping); tq_push(thr->q, &ping);
} }
} }
@ -2124,6 +2145,9 @@ static void gpudisable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, cha
return; return;
} }
applog(LOG_DEBUG, "API: request to gpudisable gpuid %d %s%u",
id, gpus[id].drv->name, gpus[id].device_id);
if (gpus[id].deven == DEV_DISABLED) { if (gpus[id].deven == DEV_DISABLED) {
message(io_data, MSG_ALRDIS, id, NULL, isjson); message(io_data, MSG_ALRDIS, id, NULL, isjson);
return; return;
@ -2752,7 +2776,7 @@ void notifystatus(struct io_data *io_data, int device, struct cgpu_info *cgpu, b
// ALL counters (and only counters) must start the name with a '*' // ALL counters (and only counters) must start the name with a '*'
// Simplifies future external support for identifying new counters // Simplifies future external support for identifying new counters
root = api_add_int(root, "NOTIFY", &device, false); root = api_add_int(root, "NOTIFY", &device, false);
root = api_add_string(root, "Name", cgpu->api->name, false); root = api_add_string(root, "Name", cgpu->drv->name, false);
root = api_add_int(root, "ID", &(cgpu->device_id), false); root = api_add_int(root, "ID", &(cgpu->device_id), false);
root = api_add_time(root, "Last Well", &(cgpu->device_last_well), false); root = api_add_time(root, "Last Well", &(cgpu->device_last_well), false);
root = api_add_time(root, "Last Not Well", &(cgpu->device_last_not_well), false); root = api_add_time(root, "Last Not Well", &(cgpu->device_last_not_well), false);
@ -2816,9 +2840,9 @@ static void devdetails(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __m
cgpu = devices[i]; cgpu = devices[i];
root = api_add_int(root, "DEVDETAILS", &i, false); root = api_add_int(root, "DEVDETAILS", &i, false);
root = api_add_string(root, "Name", cgpu->api->name, false); root = api_add_string(root, "Name", cgpu->drv->name, false);
root = api_add_int(root, "ID", &(cgpu->device_id), false); root = api_add_int(root, "ID", &(cgpu->device_id), false);
root = api_add_string(root, "Driver", cgpu->api->dname, false); root = api_add_string(root, "Driver", cgpu->drv->dname, false);
root = api_add_const(root, "Kernel", cgpu->kname ? : BLANK, false); root = api_add_const(root, "Kernel", cgpu->kname ? : BLANK, false);
root = api_add_const(root, "Model", cgpu->name ? : BLANK, false); root = api_add_const(root, "Model", cgpu->name ? : BLANK, false);
root = api_add_const(root, "Device Path", cgpu->device_path ? : BLANK, false); root = api_add_const(root, "Device Path", cgpu->device_path ? : BLANK, false);
@ -2895,6 +2919,8 @@ static int itemstats(struct io_data *io_data, int i, char *id, struct cgminer_st
root = api_add_uint64(root, "Bytes Sent", &(pool_stats->bytes_sent), false); root = api_add_uint64(root, "Bytes Sent", &(pool_stats->bytes_sent), false);
root = api_add_uint64(root, "Times Recv", &(pool_stats->times_received), false); root = api_add_uint64(root, "Times Recv", &(pool_stats->times_received), false);
root = api_add_uint64(root, "Bytes Recv", &(pool_stats->bytes_received), false); root = api_add_uint64(root, "Bytes Recv", &(pool_stats->bytes_received), false);
root = api_add_uint64(root, "Net Bytes Sent", &(pool_stats->net_bytes_sent), false);
root = api_add_uint64(root, "Net Bytes Recv", &(pool_stats->net_bytes_received), false);
} }
if (extra) if (extra)
@ -2922,13 +2948,13 @@ static void minerstats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __m
for (j = 0; j < total_devices; j++) { for (j = 0; j < total_devices; j++) {
struct cgpu_info *cgpu = devices[j]; struct cgpu_info *cgpu = devices[j];
if (cgpu && cgpu->api) { if (cgpu && cgpu->drv) {
if (cgpu->api->get_api_stats) if (cgpu->drv->get_api_stats)
extra = cgpu->api->get_api_stats(cgpu); extra = cgpu->drv->get_api_stats(cgpu);
else else
extra = NULL; extra = NULL;
sprintf(id, "%s%d", cgpu->api->name, cgpu->device_id); sprintf(id, "%s%d", cgpu->drv->name, cgpu->device_id);
i = itemstats(io_data, i, id, &(cgpu->cgminer_stats), NULL, extra, isjson); i = itemstats(io_data, i, id, &(cgpu->cgminer_stats), NULL, extra, isjson);
} }
} }
@ -3120,7 +3146,7 @@ static void usbstats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __may
{ {
struct api_data *root = NULL; struct api_data *root = NULL;
#ifdef USE_MODMINER #if defined(USE_MODMINER) || defined(USE_BITFORCE)
char buf[TMPBUFSIZ]; char buf[TMPBUFSIZ];
bool io_open = false; bool io_open = false;
int count = 0; int count = 0;
@ -3133,7 +3159,7 @@ static void usbstats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __may
return; return;
} }
#ifdef USE_MODMINER #if defined(USE_MODMINER) || defined(USE_BITFORCE)
message(io_data, MSG_USBSTA, 0, NULL, isjson); message(io_data, MSG_USBSTA, 0, NULL, isjson);
@ -3194,16 +3220,16 @@ static void pgaset(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe
} }
struct cgpu_info *cgpu = devices[dev]; struct cgpu_info *cgpu = devices[dev];
struct device_api *api = cgpu->api; struct device_drv *drv = cgpu->drv;
char *set = strchr(opt, ','); char *set = strchr(opt, ',');
if (set) if (set)
*(set++) = '\0'; *(set++) = '\0';
if (!api->set_device) if (!drv->set_device)
message(io_data, MSG_PGANOSET, id, NULL, isjson); message(io_data, MSG_PGANOSET, id, NULL, isjson);
else { else {
char *ret = api->set_device(cgpu, opt, set, buf); char *ret = drv->set_device(cgpu, opt, set, buf);
if (ret) { if (ret) {
if (strcasecmp(opt, "help") == 0) if (strcasecmp(opt, "help") == 0)
message(io_data, MSG_PGAHELP, id, ret, isjson); message(io_data, MSG_PGAHELP, id, ret, isjson);
@ -3215,6 +3241,54 @@ static void pgaset(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe
} }
#endif #endif
static void dozero(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
{
if (param == NULL || *param == '\0') {
message(io_data, MSG_ZERMIS, 0, NULL, isjson);
return;
}
char *sum = strchr(param, ',');
if (sum)
*(sum++) = '\0';
if (!sum || !*sum) {
message(io_data, MSG_MISBOOL, 0, NULL, isjson);
return;
}
bool all = false;
bool bs = false;
if (strcasecmp(param, "all") == 0)
all = true;
else if (strcasecmp(param, "bestshare") == 0)
bs = true;
if (all == false && bs == false) {
message(io_data, MSG_ZERINV, 0, param, isjson);
return;
}
*sum = tolower(*sum);
if (*sum != 't' && *sum != 'f') {
message(io_data, MSG_INVBOOL, 0, NULL, isjson);
return;
}
bool dosum = (*sum == 't');
if (dosum)
print_summary();
if (all)
zero_stats();
if (bs)
zero_bestshare();
if (dosum)
message(io_data, MSG_ZERSUM, 0, all ? "All" : "BestShare", isjson);
else
message(io_data, MSG_ZERNOSUM, 0, all ? "All" : "BestShare", isjson);
}
static void checkcommand(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, char group); static void checkcommand(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, char group);
struct CMDS { struct CMDS {
@ -3274,6 +3348,7 @@ struct CMDS {
#ifdef HAVE_AN_FPGA #ifdef HAVE_AN_FPGA
{ "pgaset", pgaset, true }, { "pgaset", pgaset, true },
#endif #endif
{ "zero", dozero, true },
{ NULL, NULL, false } { NULL, NULL, false }
}; };

328
cgminer.c

@ -146,7 +146,8 @@ bool opt_bfl_noncerange;
#endif #endif
#define QUIET (opt_quiet || opt_realquiet) #define QUIET (opt_quiet || opt_realquiet)
struct thr_info *thr_info; struct thr_info *control_thr;
struct thr_info **mining_thr;
static int gwsched_thr_id; static int gwsched_thr_id;
static int stage_thr_id; static int stage_thr_id;
static int watchpool_thr_id; static int watchpool_thr_id;
@ -156,7 +157,7 @@ static int input_thr_id;
#endif #endif
int gpur_thr_id; int gpur_thr_id;
static int api_thr_id; static int api_thr_id;
static int total_threads; static int total_control_threads;
#ifdef HAVE_LIBUSB #ifdef HAVE_LIBUSB
pthread_mutex_t cgusb_lock; pthread_mutex_t cgusb_lock;
@ -171,6 +172,7 @@ static pthread_rwlock_t blk_lock;
static pthread_mutex_t sshare_lock; static pthread_mutex_t sshare_lock;
pthread_rwlock_t netacc_lock; pthread_rwlock_t netacc_lock;
pthread_mutex_t mining_thr_lock;
static pthread_mutex_t lp_lock; static pthread_mutex_t lp_lock;
static pthread_cond_t lp_cond; static pthread_cond_t lp_cond;
@ -377,7 +379,9 @@ static void sharelog(const char*disposition, const struct work*work)
return; return;
thr_id = work->thr_id; thr_id = work->thr_id;
cgpu = thr_info[thr_id].cgpu; mutex_lock(&mining_thr_lock);
cgpu = mining_thr[thr_id]->cgpu;
mutex_unlock(&mining_thr_lock);
pool = work->pool; pool = work->pool;
t = (unsigned long int)(work->tv_work_found.tv_sec); t = (unsigned long int)(work->tv_work_found.tv_sec);
target = bin2hex(work->target, sizeof(work->target)); target = bin2hex(work->target, sizeof(work->target));
@ -385,7 +389,7 @@ static void sharelog(const char*disposition, const struct work*work)
data = bin2hex(work->data, sizeof(work->data)); data = bin2hex(work->data, sizeof(work->data));
// timestamp,disposition,target,pool,dev,thr,sharehash,sharedata // timestamp,disposition,target,pool,dev,thr,sharehash,sharedata
rv = snprintf(s, sizeof(s), "%lu,%s,%s,%s,%s%u,%u,%s,%s\n", t, disposition, target, pool->rpc_url, cgpu->api->name, cgpu->device_id, thr_id, hash, data); rv = snprintf(s, sizeof(s), "%lu,%s,%s,%s,%s%u,%u,%s,%s\n", t, disposition, target, pool->rpc_url, cgpu->drv->name, cgpu->device_id, thr_id, hash, data);
free(target); free(target);
free(hash); free(hash);
free(data); free(data);
@ -1722,7 +1726,13 @@ out:
int dev_from_id(int thr_id) int dev_from_id(int thr_id)
{ {
return thr_info[thr_id].cgpu->device_id; struct cgpu_info *cgpu;
mutex_lock(&mining_thr_lock);
cgpu = mining_thr[thr_id]->cgpu;
mutex_unlock(&mining_thr_lock);
return cgpu->device_id;
} }
/* Make the change in the recent value adjust dynamically when the difference /* Make the change in the recent value adjust dynamically when the difference
@ -1875,9 +1885,9 @@ static void get_statline(char *buf, struct cgpu_info *cgpu)
suffix_string(dh64, displayed_hashes, 4); suffix_string(dh64, displayed_hashes, 4);
suffix_string(dr64, displayed_rolling, 4); suffix_string(dr64, displayed_rolling, 4);
sprintf(buf, "%s%d ", cgpu->api->name, cgpu->device_id); sprintf(buf, "%s%d ", cgpu->drv->name, cgpu->device_id);
if (cgpu->api->get_statline_before) if (cgpu->drv->get_statline_before)
cgpu->api->get_statline_before(buf, cgpu); cgpu->drv->get_statline_before(buf, cgpu);
else else
tailsprintf(buf, " | "); tailsprintf(buf, " | ");
tailsprintf(buf, "(%ds):%s (avg):%sh/s | A:%d R:%d HW:%d U:%.1f/m", tailsprintf(buf, "(%ds):%s (avg):%sh/s | A:%d R:%d HW:%d U:%.1f/m",
@ -1888,15 +1898,19 @@ static void get_statline(char *buf, struct cgpu_info *cgpu)
cgpu->rejected, cgpu->rejected,
cgpu->hw_errors, cgpu->hw_errors,
cgpu->utility); cgpu->utility);
if (cgpu->api->get_statline) if (cgpu->drv->get_statline)
cgpu->api->get_statline(buf, cgpu); cgpu->drv->get_statline(buf, cgpu);
} }
static void text_print_status(int thr_id) static void text_print_status(int thr_id)
{ {
struct cgpu_info *cgpu = thr_info[thr_id].cgpu; struct cgpu_info *cgpu;
char logline[256]; char logline[256];
mutex_lock(&mining_thr_lock);
cgpu = mining_thr[thr_id]->cgpu;
mutex_unlock(&mining_thr_lock);
if (cgpu) { if (cgpu) {
get_statline(logline, cgpu); get_statline(logline, cgpu);
printf("%s\n", logline); printf("%s\n", logline);
@ -1960,21 +1974,25 @@ static int dev_width;
static void curses_print_devstatus(int thr_id) static void curses_print_devstatus(int thr_id)
{ {
static int awidth = 1, rwidth = 1, hwwidth = 1, uwidth = 1; static int awidth = 1, rwidth = 1, hwwidth = 1, uwidth = 1;
struct cgpu_info *cgpu = thr_info[thr_id].cgpu; struct cgpu_info *cgpu;
char logline[256]; char logline[256];
char displayed_hashes[16], displayed_rolling[16]; char displayed_hashes[16], displayed_rolling[16];
uint64_t dh64, dr64; uint64_t dh64, dr64;
mutex_lock(&mining_thr_lock);
cgpu = mining_thr[thr_id]->cgpu;
mutex_unlock(&mining_thr_lock);
if (devcursor + cgpu->cgminer_id > LINES - 2 || opt_compact) if (devcursor + cgpu->cgminer_id > LINES - 2 || opt_compact)
return; return;
cgpu->utility = cgpu->accepted / total_secs * 60; cgpu->utility = cgpu->accepted / total_secs * 60;
wmove(statuswin,devcursor + cgpu->cgminer_id, 0); wmove(statuswin,devcursor + cgpu->cgminer_id, 0);
wprintw(statuswin, " %s %*d: ", cgpu->api->name, dev_width, cgpu->device_id); wprintw(statuswin, " %s %*d: ", cgpu->drv->name, dev_width, cgpu->device_id);
if (cgpu->api->get_statline_before) { if (cgpu->drv->get_statline_before) {
logline[0] = '\0'; logline[0] = '\0';
cgpu->api->get_statline_before(logline, cgpu); cgpu->drv->get_statline_before(logline, cgpu);
wprintw(statuswin, "%s", logline); wprintw(statuswin, "%s", logline);
} }
else else
@ -1986,11 +2004,11 @@ static void curses_print_devstatus(int thr_id)
suffix_string(dr64, displayed_rolling, 4); suffix_string(dr64, displayed_rolling, 4);
if (cgpu->status == LIFE_DEAD) if (cgpu->status == LIFE_DEAD)
wprintw(statuswin, "DEAD "); wprintw(statuswin, "DEAD ");
else if (cgpu->status == LIFE_SICK) else if (cgpu->status == LIFE_SICK)
wprintw(statuswin, "SICK "); wprintw(statuswin, "SICK ");
else if (cgpu->deven == DEV_DISABLED) else if (cgpu->deven == DEV_DISABLED)
wprintw(statuswin, "OFF "); wprintw(statuswin, "OFF ");
else if (cgpu->deven == DEV_RECOVER) else if (cgpu->deven == DEV_RECOVER)
wprintw(statuswin, "REST "); wprintw(statuswin, "REST ");
else else
@ -2007,9 +2025,9 @@ static void curses_print_devstatus(int thr_id)
hwwidth, cgpu->hw_errors, hwwidth, cgpu->hw_errors,
uwidth + 3, cgpu->utility); uwidth + 3, cgpu->utility);
if (cgpu->api->get_statline) { if (cgpu->drv->get_statline) {
logline[0] = '\0'; logline[0] = '\0';
cgpu->api->get_statline(logline, cgpu); cgpu->drv->get_statline(logline, cgpu);
wprintw(statuswin, "%s", logline); wprintw(statuswin, "%s", logline);
} }
@ -2212,7 +2230,11 @@ share_result(json_t *val, json_t *res, json_t *err, const struct work *work,
char *hashshow, bool resubmit, char *worktime) char *hashshow, bool resubmit, char *worktime)
{ {
struct pool *pool = work->pool; struct pool *pool = work->pool;
struct cgpu_info *cgpu = thr_info[work->thr_id].cgpu; struct cgpu_info *cgpu;
mutex_lock(&mining_thr_lock);
cgpu = mining_thr[work->thr_id]->cgpu;
mutex_unlock(&mining_thr_lock);
if (json_is_true(res) || (work->gbt && json_is_null(res))) { if (json_is_true(res) || (work->gbt && json_is_null(res))) {
mutex_lock(&stats_lock); mutex_lock(&stats_lock);
@ -2234,10 +2256,10 @@ share_result(json_t *val, json_t *res, json_t *err, const struct work *work,
if (!QUIET) { if (!QUIET) {
if (total_pools > 1) if (total_pools > 1)
applog(LOG_NOTICE, "Accepted %s %s %d pool %d %s%s", applog(LOG_NOTICE, "Accepted %s %s %d pool %d %s%s",
hashshow, cgpu->api->name, cgpu->device_id, work->pool->pool_no, resubmit ? "(resubmit)" : "", worktime); hashshow, cgpu->drv->name, cgpu->device_id, work->pool->pool_no, resubmit ? "(resubmit)" : "", worktime);
else else
applog(LOG_NOTICE, "Accepted %s %s %d %s%s", applog(LOG_NOTICE, "Accepted %s %s %d %s%s",
hashshow, cgpu->api->name, cgpu->device_id, resubmit ? "(resubmit)" : "", worktime); hashshow, cgpu->drv->name, cgpu->device_id, resubmit ? "(resubmit)" : "", worktime);
} }
sharelog("accept", work); sharelog("accept", work);
if (opt_shares && total_accepted >= opt_shares) { if (opt_shares && total_accepted >= opt_shares) {
@ -2302,7 +2324,7 @@ share_result(json_t *val, json_t *res, json_t *err, const struct work *work,
} }
applog(LOG_NOTICE, "Rejected %s %s %d %s%s %s%s", applog(LOG_NOTICE, "Rejected %s %s %d %s%s %s%s",
hashshow, cgpu->api->name, cgpu->device_id, where, reason, resubmit ? "(resubmit)" : "", worktime); hashshow, cgpu->drv->name, cgpu->device_id, where, reason, resubmit ? "(resubmit)" : "", worktime);
sharelog(disposition, work); sharelog(disposition, work);
} }
@ -2349,6 +2371,8 @@ static uint64_t share_diff(const struct work *work)
best_diff = ret; best_diff = ret;
suffix_string(best_diff, best_share, 0); suffix_string(best_diff, best_share, 0);
} }
if (ret > work->pool->best_diff)
work->pool->best_diff = ret;
mutex_unlock(&control_lock); mutex_unlock(&control_lock);
return ret; return ret;
} }
@ -2360,13 +2384,17 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit)
char *s; char *s;
bool rc = false; bool rc = false;
int thr_id = work->thr_id; int thr_id = work->thr_id;
struct cgpu_info *cgpu = thr_info[thr_id].cgpu; struct cgpu_info *cgpu;
struct pool *pool = work->pool; struct pool *pool = work->pool;
int rolltime; int rolltime;
struct timeval tv_submit, tv_submit_reply; struct timeval tv_submit, tv_submit_reply;
char hashshow[64 + 4] = ""; char hashshow[64 + 4] = "";
char worktime[200] = ""; char worktime[200] = "";
mutex_lock(&mining_thr_lock);
cgpu = mining_thr[thr_id]->cgpu;
mutex_unlock(&mining_thr_lock);
#ifdef __BIG_ENDIAN__ #ifdef __BIG_ENDIAN__
int swapcounter = 0; int swapcounter = 0;
for (swapcounter = 0; swapcounter < 32; swapcounter++) for (swapcounter = 0; swapcounter < 32; swapcounter++)
@ -2574,7 +2602,7 @@ static inline struct pool *select_pool(bool lagging)
return pool; return pool;
} }
static double DIFFEXACTONE = 26959946667150639794667015087019630673637144422540572481103610249216.0; static double DIFFEXACTONE = 26959946667150639794667015087019630673637144422540572481103610249215.0;
/* /*
* Calculate the work share difficulty * Calculate the work share difficulty
@ -2730,8 +2758,6 @@ static void disable_curses(void)
} }
#endif #endif
static void print_summary(void);
static void __kill_work(void) static void __kill_work(void)
{ {
struct thr_info *thr; struct thr_info *thr;
@ -2744,18 +2770,20 @@ static void __kill_work(void)
applog(LOG_DEBUG, "Killing off watchpool thread"); applog(LOG_DEBUG, "Killing off watchpool thread");
/* Kill the watchpool thread */ /* Kill the watchpool thread */
thr = &thr_info[watchpool_thr_id]; thr = &control_thr[watchpool_thr_id];
thr_info_cancel(thr); thr_info_cancel(thr);
applog(LOG_DEBUG, "Killing off watchdog thread"); applog(LOG_DEBUG, "Killing off watchdog thread");
/* Kill the watchdog thread */ /* Kill the watchdog thread */
thr = &thr_info[watchdog_thr_id]; thr = &control_thr[watchdog_thr_id];
thr_info_cancel(thr); thr_info_cancel(thr);
applog(LOG_DEBUG, "Stopping mining threads"); applog(LOG_DEBUG, "Stopping mining threads");
/* Stop the mining threads*/ /* Stop the mining threads*/
for (i = 0; i < mining_threads; i++) { for (i = 0; i < mining_threads; i++) {
thr = &thr_info[i]; mutex_lock(&mining_thr_lock);
thr = mining_thr[i];
mutex_unlock(&mining_thr_lock);
thr_info_freeze(thr); thr_info_freeze(thr);
thr->pause = true; thr->pause = true;
} }
@ -2765,17 +2793,19 @@ static void __kill_work(void)
applog(LOG_DEBUG, "Killing off mining threads"); applog(LOG_DEBUG, "Killing off mining threads");
/* Kill the mining threads*/ /* Kill the mining threads*/
for (i = 0; i < mining_threads; i++) { for (i = 0; i < mining_threads; i++) {
thr = &thr_info[i]; mutex_lock(&mining_thr_lock);
thr = mining_thr[i];
mutex_unlock(&mining_thr_lock);
thr_info_cancel(thr); thr_info_cancel(thr);
} }
applog(LOG_DEBUG, "Killing off stage thread"); applog(LOG_DEBUG, "Killing off stage thread");
/* Stop the others */ /* Stop the others */
thr = &thr_info[stage_thr_id]; thr = &control_thr[stage_thr_id];
thr_info_cancel(thr); thr_info_cancel(thr);
applog(LOG_DEBUG, "Killing off API thread"); applog(LOG_DEBUG, "Killing off API thread");
thr = &thr_info[api_thr_id]; thr = &control_thr[api_thr_id];
thr_info_cancel(thr); thr_info_cancel(thr);
} }
@ -3369,8 +3399,10 @@ static void restart_threads(void)
/* Discard staged work that is now stale */ /* Discard staged work that is now stale */
discard_stale(); discard_stale();
mutex_lock(&mining_thr_lock);
for (i = 0; i < mining_threads; i++) for (i = 0; i < mining_threads; i++)
thr_info[i].work_restart = true; mining_thr[i]->work_restart = true;
mutex_unlock(&mining_thr_lock);
mutex_lock(&restart_lock); mutex_lock(&restart_lock);
pthread_cond_broadcast(&restart_cond); pthread_cond_broadcast(&restart_cond);
@ -3914,6 +3946,20 @@ void write_config(FILE *fcfg)
json_escape_free(); json_escape_free();
} }
void zero_bestshare(void)
{
int i;
best_diff = 0;
memset(best_share, 0, 8);
suffix_string(best_diff, best_share, 0);
for (i = 0; i < total_pools; i++) {
struct pool *pool = pools[i];
pool->best_diff = 0;
}
}
void zero_stats(void) void zero_stats(void)
{ {
int i; int i;
@ -3930,10 +3976,11 @@ void zero_stats(void)
total_go = 0; total_go = 0;
total_ro = 0; total_ro = 0;
total_secs = 1.0; total_secs = 1.0;
best_diff = 0;
total_diff1 = 0; total_diff1 = 0;
memset(best_share, 0, 8); found_blocks = 0;
suffix_string(best_diff, best_share, 0); total_diff_accepted = 0;
total_diff_rejected = 0;
total_diff_stale = 0;
for (i = 0; i < total_pools; i++) { for (i = 0; i < total_pools; i++) {
struct pool *pool = pools[i]; struct pool *pool = pools[i];
@ -3945,8 +3992,16 @@ void zero_stats(void)
pool->discarded_work = 0; pool->discarded_work = 0;
pool->getfail_occasions = 0; pool->getfail_occasions = 0;
pool->remotefail_occasions = 0; pool->remotefail_occasions = 0;
pool->last_share_time = 0;
pool->diff1 = 0;
pool->diff_accepted = 0;
pool->diff_rejected = 0;
pool->diff_stale = 0;
pool->last_share_diff = 0;
} }
zero_bestshare();
mutex_lock(&hash_lock); mutex_lock(&hash_lock);
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];
@ -3956,6 +4011,11 @@ void zero_stats(void)
cgpu->rejected = 0; cgpu->rejected = 0;
cgpu->hw_errors = 0; cgpu->hw_errors = 0;
cgpu->utility = 0.0; cgpu->utility = 0.0;
cgpu->last_share_pool_time = 0;
cgpu->diff1 = 0;
cgpu->diff_accepted = 0;
cgpu->diff_rejected = 0;
cgpu->last_share_diff = 0;
} }
mutex_unlock(&hash_lock); mutex_unlock(&hash_lock);
} }
@ -4378,20 +4438,23 @@ static void hashmeter(int thr_id, struct timeval *diff,
bool showlog = false; bool showlog = false;
char displayed_hashes[16], displayed_rolling[16]; char displayed_hashes[16], displayed_rolling[16];
uint64_t dh64, dr64; uint64_t dh64, dr64;
struct thr_info *thr;
local_mhashes = (double)hashes_done / 1000000.0; local_mhashes = (double)hashes_done / 1000000.0;
/* Update the last time this thread reported in */ /* Update the last time this thread reported in */
if (thr_id >= 0) { if (thr_id >= 0) {
gettimeofday(&thr_info[thr_id].last, NULL); mutex_lock(&mining_thr_lock);
thr_info[thr_id].cgpu->device_last_well = time(NULL); thr = mining_thr[thr_id];
mutex_unlock(&mining_thr_lock);
gettimeofday(&(thr->last), NULL);
thr->cgpu->device_last_well = time(NULL);
} }
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 */
if (thr_id >= 0) { if (thr_id >= 0) {
struct thr_info *thr = &thr_info[thr_id]; struct cgpu_info *cgpu = thr->cgpu;
struct cgpu_info *cgpu = thr_info[thr_id].cgpu;
double thread_rolling = 0.0; double thread_rolling = 0.0;
int i; int i;
@ -4574,8 +4637,8 @@ static void clear_stratum_shares(struct pool *pool)
if (cleared) { if (cleared) {
applog(LOG_WARNING, "Lost %d shares due to stratum disconnect on pool %d", cleared, pool->pool_no); applog(LOG_WARNING, "Lost %d shares due to stratum disconnect on pool %d", cleared, pool->pool_no);
pool->stale_shares++; pool->stale_shares += cleared;
total_stale++; total_stale += cleared;
} }
} }
@ -4881,7 +4944,7 @@ retry_stratum:
calc_diff(work, 0); calc_diff(work, 0);
applog(LOG_DEBUG, "Pushing pooltest work to base pool"); applog(LOG_DEBUG, "Pushing pooltest work to base pool");
tq_push(thr_info[stage_thr_id].q, work); tq_push(control_thr[stage_thr_id].q, work);
total_getworks++; total_getworks++;
pool->getwork_requested++; pool->getwork_requested++;
ret = true; ret = true;
@ -5221,15 +5284,15 @@ static bool hashtest(struct thr_info *thr, struct work *work)
if (hash2_32[7] != 0) { if (hash2_32[7] != 0) {
applog(LOG_WARNING, "%s%d: invalid nonce - HW error", applog(LOG_WARNING, "%s%d: invalid nonce - HW error",
thr->cgpu->api->name, thr->cgpu->device_id); thr->cgpu->drv->name, thr->cgpu->device_id);
mutex_lock(&stats_lock); mutex_lock(&stats_lock);
hw_errors++; hw_errors++;
thr->cgpu->hw_errors++; thr->cgpu->hw_errors++;
mutex_unlock(&stats_lock); mutex_unlock(&stats_lock);
if (thr->cgpu->api->hw_error) if (thr->cgpu->drv->hw_error)
thr->cgpu->api->hw_error(thr); thr->cgpu->drv->hw_error(thr);
goto out; goto out;
} }
@ -5277,7 +5340,7 @@ static inline bool abandon_work(struct work *work, struct timeval *wdiff, uint64
} }
static void mt_disable(struct thr_info *mythr, const int thr_id, static void mt_disable(struct thr_info *mythr, const int thr_id,
struct device_api *api) struct device_drv *drv)
{ {
applog(LOG_WARNING, "Thread %d being disabled", thr_id); applog(LOG_WARNING, "Thread %d being disabled", thr_id);
mythr->rolling = mythr->cgpu->rolling = 0; mythr->rolling = mythr->cgpu->rolling = 0;
@ -5288,8 +5351,8 @@ static void mt_disable(struct thr_info *mythr, const int thr_id,
} while (mythr->pause); } while (mythr->pause);
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) if (drv->thread_enable)
api->thread_enable(mythr); drv->thread_enable(mythr);
} }
void *miner_thread(void *userdata) void *miner_thread(void *userdata)
@ -5297,7 +5360,7 @@ void *miner_thread(void *userdata)
struct thr_info *mythr = userdata; struct thr_info *mythr = userdata;
const int thr_id = mythr->id; const int thr_id = mythr->id;
struct cgpu_info *cgpu = mythr->cgpu; struct cgpu_info *cgpu = mythr->cgpu;
struct device_api *api = cgpu->api; struct device_drv *drv = cgpu->drv;
struct cgminer_stats *dev_stats = &(cgpu->cgminer_stats); struct cgminer_stats *dev_stats = &(cgpu->cgminer_stats);
struct cgminer_stats *pool_stats; struct cgminer_stats *pool_stats;
struct timeval getwork_start; struct timeval getwork_start;
@ -5306,7 +5369,7 @@ void *miner_thread(void *userdata)
const long cycle = opt_log_interval / 5 ? : 1; const long cycle = opt_log_interval / 5 ? : 1;
struct timeval tv_start, tv_end, tv_workstart, tv_lastupdate; struct timeval tv_start, tv_end, tv_workstart, tv_lastupdate;
struct timeval diff, sdiff, wdiff = {0, 0}; struct timeval diff, sdiff, wdiff = {0, 0};
uint32_t max_nonce = api->can_limit_work ? api->can_limit_work(mythr) : 0xffffffff; uint32_t max_nonce = drv->can_limit_work ? drv->can_limit_work(mythr) : 0xffffffff;
int64_t hashes_done = 0; int64_t hashes_done = 0;
int64_t hashes; int64_t hashes;
struct work *work; struct work *work;
@ -5320,7 +5383,7 @@ void *miner_thread(void *userdata)
gettimeofday(&getwork_start, NULL); gettimeofday(&getwork_start, NULL);
if (api->thread_init && !api->thread_init(mythr)) { if (drv->thread_init && !drv->thread_init(mythr)) {
dev_error(cgpu, REASON_THREAD_FAIL_INIT); dev_error(cgpu, REASON_THREAD_FAIL_INIT);
goto out; goto out;
} }
@ -5340,7 +5403,7 @@ void *miner_thread(void *userdata)
gettimeofday(&tv_workstart, NULL); gettimeofday(&tv_workstart, NULL);
work->blk.nonce = 0; work->blk.nonce = 0;
cgpu->max_hashes = 0; cgpu->max_hashes = 0;
if (api->prepare_work && !api->prepare_work(mythr, work)) { if (drv->prepare_work && !drv->prepare_work(mythr, work)) {
applog(LOG_ERR, "work prepare failed, exiting " applog(LOG_ERR, "work prepare failed, exiting "
"mining thread %d", thr_id); "mining thread %d", thr_id);
break; break;
@ -5382,16 +5445,16 @@ void *miner_thread(void *userdata)
gettimeofday(&(work->tv_work_start), NULL); gettimeofday(&(work->tv_work_start), NULL);
thread_reportin(mythr); thread_reportin(mythr);
hashes = api->scanhash(mythr, work, work->blk.nonce + max_nonce); hashes = drv->scanhash(mythr, work, work->blk.nonce + max_nonce);
thread_reportin(mythr); thread_reportin(mythr);
gettimeofday(&getwork_start, NULL); gettimeofday(&getwork_start, NULL);
if (unlikely(hashes == -1)) { if (unlikely(hashes == -1)) {
applog(LOG_ERR, "%s %d failure, disabling!", api->name, cgpu->device_id); applog(LOG_ERR, "%s %d failure, disabling!", drv->name, cgpu->device_id);
cgpu->deven = DEV_DISABLED; cgpu->deven = DEV_DISABLED;
dev_error(cgpu, REASON_THREAD_ZERO_HASH); dev_error(cgpu, REASON_THREAD_ZERO_HASH);
mt_disable(mythr, thr_id, api); mt_disable(mythr, thr_id, drv);
} }
hashes_done += hashes; hashes_done += hashes;
@ -5412,7 +5475,7 @@ void *miner_thread(void *userdata)
if (unlikely((long)sdiff.tv_sec < cycle)) { if (unlikely((long)sdiff.tv_sec < cycle)) {
int mult; int mult;
if (likely(!api->can_limit_work || max_nonce == 0xffffffff)) if (likely(!drv->can_limit_work || max_nonce == 0xffffffff))
continue; continue;
mult = 1000000 / ((sdiff.tv_usec + 0x400) / 0x400) + 0x10; mult = 1000000 / ((sdiff.tv_usec + 0x400) / 0x400) + 0x10;
@ -5421,9 +5484,9 @@ void *miner_thread(void *userdata)
max_nonce = 0xffffffff; max_nonce = 0xffffffff;
else else
max_nonce = (max_nonce * mult) / 0x400; max_nonce = (max_nonce * mult) / 0x400;
} else if (unlikely(sdiff.tv_sec > cycle) && api->can_limit_work) } else if (unlikely(sdiff.tv_sec > cycle) && drv->can_limit_work)
max_nonce = max_nonce * cycle / sdiff.tv_sec; max_nonce = max_nonce * cycle / sdiff.tv_sec;
else if (unlikely(sdiff.tv_usec > 100000) && api->can_limit_work) else if (unlikely(sdiff.tv_usec > 100000) && drv->can_limit_work)
max_nonce = max_nonce * 0x400 / (((cycle * 1000000) + sdiff.tv_usec) / (cycle * 1000000 / 0x400)); max_nonce = max_nonce * 0x400 / (((cycle * 1000000) + sdiff.tv_usec) / (cycle * 1000000 / 0x400));
timersub(&tv_end, &tv_lastupdate, &diff); timersub(&tv_end, &tv_lastupdate, &diff);
@ -5449,7 +5512,7 @@ void *miner_thread(void *userdata)
} }
if (unlikely(mythr->pause || cgpu->deven != DEV_ENABLED)) if (unlikely(mythr->pause || cgpu->deven != DEV_ENABLED))
mt_disable(mythr, thr_id, api); mt_disable(mythr, thr_id, drv);
sdiff.tv_sec = sdiff.tv_usec = 0; sdiff.tv_sec = sdiff.tv_usec = 0;
} while (!abandon_work(work, &wdiff, cgpu->max_hashes)); } while (!abandon_work(work, &wdiff, cgpu->max_hashes));
@ -5457,8 +5520,8 @@ void *miner_thread(void *userdata)
} }
out: out:
if (api->thread_shutdown) if (drv->thread_shutdown)
api->thread_shutdown(mythr); drv->thread_shutdown(mythr);
thread_reportin(mythr); thread_reportin(mythr);
applog(LOG_ERR, "Thread %d failure, exiting", thr_id); applog(LOG_ERR, "Thread %d failure, exiting", thr_id);
@ -5686,8 +5749,8 @@ out:
void reinit_device(struct cgpu_info *cgpu) void reinit_device(struct cgpu_info *cgpu)
{ {
if (cgpu->api->reinit_device) if (cgpu->drv->reinit_device)
cgpu->api->reinit_device(cgpu); cgpu->drv->reinit_device(cgpu);
} }
static struct timeval rotate_tv; static struct timeval rotate_tv;
@ -5829,12 +5892,10 @@ 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;
for (i = 0; i < mining_threads; i++) { mutex_lock(&mining_thr_lock);
struct thr_info *thr; for (i = 0; i < mining_threads; i++)
thr = &thr_info[i]; mining_thr[i]->pause = true;
mutex_unlock(&mining_thr_lock);
thr->pause = true;
}
} else if (sched_paused && should_run()) { } else if (sched_paused && should_run()) {
applog(LOG_WARNING, "Restarting execution as per start time %02d:%02d scheduled", applog(LOG_WARNING, "Restarting execution as per start time %02d:%02d scheduled",
schedstart.tm.tm_hour, schedstart.tm.tm_min); schedstart.tm.tm_hour, schedstart.tm.tm_min);
@ -5845,7 +5906,10 @@ static void *watchdog_thread(void __maybe_unused *userdata)
for (i = 0; i < mining_threads; i++) { for (i = 0; i < mining_threads; i++) {
struct thr_info *thr; struct thr_info *thr;
thr = &thr_info[i];
mutex_lock(&mining_thr_lock);
thr = mining_thr[i];
mutex_unlock(&mining_thr_lock);
/* Don't touch disabled devices */ /* Don't touch disabled devices */
if (thr->cgpu->deven == DEV_DISABLED) if (thr->cgpu->deven == DEV_DISABLED)
@ -5862,12 +5926,12 @@ static void *watchdog_thread(void __maybe_unused *userdata)
char dev_str[8]; char dev_str[8];
int gpu; int gpu;
if (cgpu->api->get_stats) if (cgpu->drv->get_stats)
cgpu->api->get_stats(cgpu); cgpu->drv->get_stats(cgpu);
gpu = cgpu->device_id; gpu = cgpu->device_id;
denable = &cgpu->deven; denable = &cgpu->deven;
sprintf(dev_str, "%s%d", cgpu->api->name, gpu); sprintf(dev_str, "%s%d", cgpu->drv->name, gpu);
#ifdef HAVE_ADL #ifdef HAVE_ADL
if (adl_active && cgpu->has_adl) if (adl_active && cgpu->has_adl)
@ -5887,7 +5951,7 @@ static void *watchdog_thread(void __maybe_unused *userdata)
continue; continue;
#ifdef WANT_CPUMINE #ifdef WANT_CPUMINE
if (!strcmp(cgpu->api->dname, "cpu")) if (cgpu->drv->drv == DRIVER_CPU)
continue; continue;
#endif #endif
if (cgpu->status != LIFE_WELL && (now.tv_sec - thr->last.tv_sec < WATCHDOG_SICK_TIME)) { if (cgpu->status != LIFE_WELL && (now.tv_sec - thr->last.tv_sec < WATCHDOG_SICK_TIME)) {
@ -5944,7 +6008,7 @@ static void log_print_status(struct cgpu_info *cgpu)
applog(LOG_WARNING, "%s", logline); applog(LOG_WARNING, "%s", logline);
} }
static void print_summary(void) void print_summary(void)
{ {
struct timeval diff; struct timeval diff;
int hours, mins, secs, i; int hours, mins, secs, i;
@ -6277,26 +6341,27 @@ void enable_curses(void) {
/* TODO: fix need a dummy CPU device_api even if no support for CPU mining */ /* TODO: fix need a dummy CPU device_api even if no support for CPU mining */
#ifndef WANT_CPUMINE #ifndef WANT_CPUMINE
struct device_api cpu_api; struct device_drv cpu_drv;
struct device_api cpu_api = { struct device_drv cpu_drv = {
.drv = DRIVER_CPU,
.name = "CPU", .name = "CPU",
}; };
#endif #endif
#ifdef USE_BITFORCE #ifdef USE_BITFORCE
extern struct device_api bitforce_api; extern struct device_drv bitforce_drv;
#endif #endif
#ifdef USE_ICARUS #ifdef USE_ICARUS
extern struct device_api icarus_api; extern struct device_drv icarus_drv;
#endif #endif
#ifdef USE_MODMINER #ifdef USE_MODMINER
extern struct device_api modminer_api; extern struct device_drv modminer_drv;
#endif #endif
#ifdef USE_ZTEX #ifdef USE_ZTEX
extern struct device_api ztex_api; extern struct device_drv ztex_drv;
#endif #endif
@ -6311,7 +6376,7 @@ void enable_device(struct cgpu_info *cgpu)
adj_width(mining_threads, &dev_width); adj_width(mining_threads, &dev_width);
#endif #endif
#ifdef HAVE_OPENCL #ifdef HAVE_OPENCL
if (cgpu->api == &opencl_api) { if (cgpu->drv->drv == DRIVER_OPENCL) {
gpu_threads += cgpu->threads; gpu_threads += cgpu->threads;
} }
#endif #endif
@ -6328,12 +6393,12 @@ bool add_cgpu(struct cgpu_info*cgpu)
static struct _cgpu_devid_counter *devids = NULL; static struct _cgpu_devid_counter *devids = NULL;
struct _cgpu_devid_counter *d; struct _cgpu_devid_counter *d;
HASH_FIND_STR(devids, cgpu->api->name, d); HASH_FIND_STR(devids, cgpu->drv->name, d);
if (d) if (d)
cgpu->device_id = ++d->lastid; cgpu->device_id = ++d->lastid;
else { else {
d = malloc(sizeof(*d)); d = malloc(sizeof(*d));
memcpy(d->name, cgpu->api->name, sizeof(d->name)); memcpy(d->name, cgpu->drv->name, sizeof(d->name));
cgpu->device_id = d->lastid = 0; cgpu->device_id = d->lastid = 0;
HASH_ADD_STR(devids, name, d); HASH_ADD_STR(devids, name, d);
} }
@ -6342,6 +6407,21 @@ bool add_cgpu(struct cgpu_info*cgpu)
return true; return true;
} }
struct device_drv *copy_drv(struct device_drv *drv)
{
struct device_drv *copy;
char buf[100];
if (unlikely(!(copy = malloc(sizeof(*copy))))) {
sprintf(buf, "Failed to allocate device_drv copy of %s (%s)",
drv->name, drv->copy ? "copy" : "original");
quit(1, buf);
}
memcpy(copy, drv, sizeof(*copy));
copy->copy = true;
return copy;
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
bool pools_active = false; bool pools_active = false;
@ -6382,6 +6462,7 @@ int main(int argc, char *argv[])
mutex_init(&sshare_lock); mutex_init(&sshare_lock);
rwlock_init(&blk_lock); rwlock_init(&blk_lock);
rwlock_init(&netacc_lock); rwlock_init(&netacc_lock);
mutex_init(&mining_thr_lock);
mutex_init(&lp_lock); mutex_init(&lp_lock);
if (unlikely(pthread_cond_init(&lp_cond, NULL))) if (unlikely(pthread_cond_init(&lp_cond, NULL)))
@ -6551,32 +6632,32 @@ int main(int argc, char *argv[])
#ifdef HAVE_OPENCL #ifdef HAVE_OPENCL
if (!opt_nogpu) if (!opt_nogpu)
opencl_api.api_detect(); opencl_drv.drv_detect();
gpu_threads = 0; gpu_threads = 0;
#endif #endif
#ifdef USE_ICARUS #ifdef USE_ICARUS
if (!opt_scrypt) if (!opt_scrypt)
icarus_api.api_detect(); icarus_drv.drv_detect();
#endif #endif
#ifdef USE_BITFORCE #ifdef USE_BITFORCE
if (!opt_scrypt) if (!opt_scrypt)
bitforce_api.api_detect(); bitforce_drv.drv_detect();
#endif #endif
#ifdef USE_MODMINER #ifdef USE_MODMINER
if (!opt_scrypt) if (!opt_scrypt)
modminer_api.api_detect(); modminer_drv.drv_detect();
#endif #endif
#ifdef USE_ZTEX #ifdef USE_ZTEX
if (!opt_scrypt) if (!opt_scrypt)
ztex_api.api_detect(); ztex_drv.drv_detect();
#endif #endif
#ifdef WANT_CPUMINE #ifdef WANT_CPUMINE
cpu_api.api_detect(); cpu_drv.drv_detect();
#endif #endif
if (devices_enabled == -1) { if (devices_enabled == -1) {
@ -6584,9 +6665,9 @@ int main(int argc, char *argv[])
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];
if (cgpu->name) if (cgpu->name)
applog(LOG_ERR, " %2d. %s %d: %s (driver: %s)", i, cgpu->api->name, cgpu->device_id, cgpu->name, cgpu->api->dname); applog(LOG_ERR, " %2d. %s %d: %s (driver: %s)", i, cgpu->drv->name, cgpu->device_id, cgpu->name, cgpu->drv->dname);
else else
applog(LOG_ERR, " %2d. %s %d (driver: %s)", i, cgpu->api->name, cgpu->device_id, cgpu->api->dname); applog(LOG_ERR, " %2d. %s %d (driver: %s)", i, cgpu->drv->name, cgpu->device_id, cgpu->drv->dname);
} }
quit(0, "%d devices listed", total_devices); quit(0, "%d devices listed", total_devices);
} }
@ -6600,7 +6681,7 @@ int main(int argc, char *argv[])
enable_device(devices[i]); enable_device(devices[i]);
} else if (i < total_devices) { } else if (i < total_devices) {
if (opt_removedisabled) { if (opt_removedisabled) {
if (devices[i]->api == &cpu_api) if (devices[i]->drv->drv == DRIVER_CPU)
--opt_n_threads; --opt_n_threads;
} else { } else {
enable_device(devices[i]); enable_device(devices[i]);
@ -6666,14 +6747,23 @@ int main(int argc, char *argv[])
fork_monitor(); fork_monitor();
#endif // defined(unix) #endif // defined(unix)
total_threads = mining_threads + 7; mining_thr = calloc(mining_threads, sizeof(thr));
thr_info = calloc(total_threads, sizeof(*thr)); if (!mining_thr)
if (!thr_info) quit(1, "Failed to calloc mining_thr");
quit(1, "Failed to calloc thr_info"); for (i = 0; i < mining_threads; i++) {
mining_thr[i] = calloc(1, sizeof(*thr));
if (!mining_thr[i])
quit(1, "Failed to calloc mining_thr[%d]", i);
}
gwsched_thr_id = mining_threads; total_control_threads = 7;
stage_thr_id = mining_threads + 1; control_thr = calloc(total_control_threads, sizeof(*thr));
thr = &thr_info[stage_thr_id]; if (!control_thr)
quit(1, "Failed to calloc control_thr");
gwsched_thr_id = 0;
stage_thr_id = 1;
thr = &control_thr[stage_thr_id];
thr->q = tq_new(); thr->q = tq_new();
if (!thr->q) if (!thr->q)
quit(1, "Failed to tq_new"); quit(1, "Failed to tq_new");
@ -6765,14 +6855,16 @@ begin_bench:
cgpu->status = LIFE_INIT; cgpu->status = LIFE_INIT;
for (j = 0; j < cgpu->threads; ++j, ++k) { for (j = 0; j < cgpu->threads; ++j, ++k) {
thr = &thr_info[k]; mutex_lock(&mining_thr_lock);
thr = mining_thr[k];
mutex_unlock(&mining_thr_lock);
thr->id = k; thr->id = k;
thr->cgpu = cgpu; thr->cgpu = cgpu;
thr->device_thread = j; thr->device_thread = j;
thr->q = tq_new(); thr->q = tq_new();
if (!thr->q) if (!thr->q)
quit(1, "tq_new failed in starting %s%d mining thread (#%d)", cgpu->api->name, cgpu->device_id, i); quit(1, "tq_new failed in starting %s%d mining thread (#%d)", cgpu->drv->name, cgpu->device_id, i);
/* Enable threads for devices set not to mine but disable /* Enable threads for devices set not to mine but disable
* their queue in case we wish to enable them later */ * their queue in case we wish to enable them later */
@ -6782,7 +6874,7 @@ begin_bench:
tq_push(thr->q, &ping); tq_push(thr->q, &ping);
} }
if (cgpu->api->thread_prepare && !cgpu->api->thread_prepare(thr)) if (cgpu->drv->thread_prepare && !cgpu->drv->thread_prepare(thr))
continue; continue;
thread_reportout(thr); thread_reportout(thr);
@ -6810,15 +6902,15 @@ begin_bench:
gettimeofday(&total_tv_start, NULL); gettimeofday(&total_tv_start, NULL);
gettimeofday(&total_tv_end, NULL); gettimeofday(&total_tv_end, NULL);
watchpool_thr_id = mining_threads + 2; watchpool_thr_id = 2;
thr = &thr_info[watchpool_thr_id]; thr = &control_thr[watchpool_thr_id];
/* start watchpool thread */ /* start watchpool thread */
if (thr_info_create(thr, NULL, watchpool_thread, NULL)) if (thr_info_create(thr, NULL, watchpool_thread, NULL))
quit(1, "watchpool thread create failed"); quit(1, "watchpool thread create failed");
pthread_detach(thr->pth); pthread_detach(thr->pth);
watchdog_thr_id = mining_threads + 3; watchdog_thr_id = 3;
thr = &thr_info[watchdog_thr_id]; thr = &control_thr[watchdog_thr_id];
/* start watchdog thread */ /* start watchdog thread */
if (thr_info_create(thr, NULL, watchdog_thread, NULL)) if (thr_info_create(thr, NULL, watchdog_thread, NULL))
quit(1, "watchdog thread create failed"); quit(1, "watchdog thread create failed");
@ -6826,8 +6918,8 @@ begin_bench:
#ifdef HAVE_OPENCL #ifdef HAVE_OPENCL
/* Create reinit gpu thread */ /* Create reinit gpu thread */
gpur_thr_id = mining_threads + 4; gpur_thr_id = 4;
thr = &thr_info[gpur_thr_id]; thr = &control_thr[gpur_thr_id];
thr->q = tq_new(); thr->q = tq_new();
if (!thr->q) if (!thr->q)
quit(1, "tq_new failed for gpur_thr_id"); quit(1, "tq_new failed for gpur_thr_id");
@ -6836,8 +6928,8 @@ begin_bench:
#endif #endif
/* Create API socket thread */ /* Create API socket thread */
api_thr_id = mining_threads + 5; api_thr_id = 5;
thr = &thr_info[api_thr_id]; thr = &control_thr[api_thr_id];
if (thr_info_create(thr, NULL, api_thread, thr)) if (thr_info_create(thr, NULL, api_thread, thr))
quit(1, "API thread create failed"); quit(1, "API thread create failed");
@ -6845,13 +6937,17 @@ begin_bench:
/* 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
* to try and shut down ll previous threads. */ * to try and shut down ll previous threads. */
input_thr_id = mining_threads + 6; input_thr_id = 6;
thr = &thr_info[input_thr_id]; thr = &control_thr[input_thr_id];
if (thr_info_create(thr, NULL, input_thread, thr)) if (thr_info_create(thr, NULL, input_thread, thr))
quit(1, "input thread create failed"); quit(1, "input thread create failed");
pthread_detach(thr->pth); pthread_detach(thr->pth);
#endif #endif
/* Just to be sure */
if (total_control_threads != 7)
quit(1, "incorrect total_control_threads (%d) should be 7", total_control_threads);
/* Once everything is set up, main() becomes the getwork scheduler */ /* Once everything is set up, main() becomes the getwork scheduler */
while (42) { while (42) {
int ts, max_staged = opt_queue; int ts, max_staged = opt_queue;

7
configure.ac

@ -273,6 +273,7 @@ fi
AM_CONDITIONAL([NEED_FPGAUTILS], [test x$icarus$bitforce$modminer$ztex != xnononono]) AM_CONDITIONAL([NEED_FPGAUTILS], [test x$icarus$bitforce$modminer$ztex != xnononono])
AM_CONDITIONAL([NEED_USBUTILS_C], [test x$bitforce$modminer != xnono])
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])
AM_CONDITIONAL([HAVE_WINDOWS], [test x$have_win32 = xtrue]) AM_CONDITIONAL([HAVE_WINDOWS], [test x$have_win32 = xtrue])
@ -321,7 +322,7 @@ fi
AM_CONDITIONAL([HAS_YASM], [test x$has_yasm = xtrue]) AM_CONDITIONAL([HAS_YASM], [test x$has_yasm = xtrue])
if test "x$bitforce" != xno; then if test "x$icarus" != xno; then
AC_ARG_WITH([libudev], [AC_HELP_STRING([--without-libudev], [Autodetect FPGAs using libudev (default enabled)])], AC_ARG_WITH([libudev], [AC_HELP_STRING([--without-libudev], [Autodetect FPGAs using libudev (default enabled)])],
[libudev=$withval], [libudev=$withval],
[libudev=auto] [libudev=auto]
@ -343,7 +344,7 @@ AM_CONDITIONAL([HAVE_LIBUDEV], [test x$libudev != xno])
PKG_PROG_PKG_CONFIG() PKG_PROG_PKG_CONFIG()
if test "x$ztex$modminer" != xnono; then if test "x$ztex$modminer$bitforce" != xnonono; then
case $target in case $target in
*-*-freebsd*) *-*-freebsd*)
LIBUSB_LIBS="-lusb" LIBUSB_LIBS="-lusb"
@ -508,7 +509,7 @@ else
echo " Ztex.FPGAs...........: Disabled" echo " Ztex.FPGAs...........: Disabled"
fi fi
if test "x$bitforce" != xno; then if test "x$icarus" != xno; then
echo " libudev.detection....: $libudev" echo " libudev.detection....: $libudev"
fi fi

670
driver-bitforce.c

@ -1,4 +1,5 @@
/* /*
* Copyright 2012-2013 Andrew Smith
* Copyright 2012 Luke Dashjr * Copyright 2012 Luke Dashjr
* Copyright 2012 Con Kolivas * Copyright 2012 Con Kolivas
* *
@ -19,34 +20,35 @@
#include "config.h" #include "config.h"
#ifdef WIN32 #ifdef WIN32
#include <windows.h> #include <windows.h>
#define dlsym (void*)GetProcAddress
#define dlclose FreeLibrary
typedef unsigned long FT_STATUS;
typedef PVOID FT_HANDLE;
__stdcall FT_STATUS (*FT_ListDevices)(PVOID pArg1, PVOID pArg2, DWORD Flags);
__stdcall FT_STATUS (*FT_Open)(int idx, FT_HANDLE*);
__stdcall FT_STATUS (*FT_GetComPortNumber)(FT_HANDLE, LPLONG lplComPortNumber);
__stdcall FT_STATUS (*FT_Close)(FT_HANDLE);
const uint32_t FT_OPEN_BY_DESCRIPTION = 2;
const uint32_t FT_LIST_ALL = 0x20000000;
const uint32_t FT_LIST_NUMBER_ONLY = 0x80000000;
enum {
FT_OK,
};
// Code must deal with a timeout. Make it 1 second on windows, 0.1 on linux.
#define BFopen(devpath) serial_open(devpath, 0, 10, true)
#else /* WIN32 */
#define BFopen(devpath) serial_open(devpath, 0, 1, true)
#endif /* WIN32 */ #endif /* WIN32 */
#include "compat.h" #include "compat.h"
#include "miner.h" #include "miner.h"
#include "fpgautils.h" #include "usbutils.h"
#define BITFORCE_IDENTIFY "ZGX"
#define BITFORCE_IDENTIFY_LEN (sizeof(BITFORCE_IDENTIFY)-1)
#define BITFORCE_FLASH "ZMX"
#define BITFORCE_FLASH_LEN (sizeof(BITFORCE_FLASH)-1)
#define BITFORCE_TEMPERATURE "ZLX"
#define BITFORCE_TEMPERATURE_LEN (sizeof(BITFORCE_TEMPERATURE)-1)
#define BITFORCE_SENDRANGE "ZPX"
#define BITFORCE_SENDRANGE_LEN (sizeof(BITFORCE_SENDRANGE)-1)
#define BITFORCE_SENDWORK "ZDX"
#define BITFORCE_SENDWORK_LEN (sizeof(BITFORCE_SENDWORK)-1)
#define BITFORCE_WORKSTATUS "ZFX"
#define BITFORCE_WORKSTATUS_LEN (sizeof(BITFORCE_WORKSTATUS)-1)
// Either of Nonce or No-nonce start with:
#define BITFORCE_EITHER "N"
#define BITFORCE_EITHER_LEN 1
#define BITFORCE_NONCE "NONCE-FOUND"
#define BITFORCE_NONCE_LEN (sizeof(BITFORCE_NONCE)-1)
#define BITFORCE_NO_NONCE "NO-NONCE"
#define BITFORCE_NO_NONCE_MATCH 3
#define BITFORCE_IDLE "IDLE"
#define BITFORCE_IDLE_MATCH 1
#define BITFORCE_SLEEP_MS 500 #define BITFORCE_SLEEP_MS 500
#define BITFORCE_TIMEOUT_S 7 #define BITFORCE_TIMEOUT_S 7
@ -62,62 +64,197 @@ enum {
#define KNAME_WORK "full work" #define KNAME_WORK "full work"
#define KNAME_RANGE "nonce range" #define KNAME_RANGE "nonce range"
struct device_api bitforce_api; #define BITFORCE_BUFSIZ (0x200)
static void BFgets(char *buf, size_t bufLen, int fd) // If initialisation fails the first time,
{ // sleep this amount (ms) and try again
do { #define REINIT_TIME_FIRST_MS 100
buf[0] = '\0'; // Max ms per sleep
--bufLen; #define REINIT_TIME_MAX_MS 800
} while (likely(bufLen && read(fd, buf, 1) == 1 && (buf++)[0] != '\n')); // Keep trying up to this many us
#define REINIT_TIME_MAX 3000000
buf[0] = '\0'; static const char *blank = "";
}
struct device_drv bitforce_drv;
static ssize_t BFwrite(int fd, const void *buf, ssize_t bufLen) static void bitforce_initialise(struct cgpu_info *bitforce, bool lock)
{ {
if ((bufLen) != write(fd, buf, bufLen)) int err;
return 0;
else if (lock)
return bufLen; mutex_lock(&bitforce->device_mutex);
}
#define BFclose(fd) close(fd) // Reset
err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_RESET,
FTDI_VALUE_RESET, bitforce->usbdev->found->interface, C_RESET);
if (opt_debug)
applog(LOG_DEBUG, "%s%i: reset got err %d",
bitforce->drv->name, bitforce->device_id, err);
if (bitforce->usbinfo.nodev)
goto failed;
// Set data control
err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_DATA,
FTDI_VALUE_DATA, bitforce->usbdev->found->interface, C_SETDATA);
if (opt_debug)
applog(LOG_DEBUG, "%s%i: setdata got err %d",
bitforce->drv->name, bitforce->device_id, err);
if (bitforce->usbinfo.nodev)
goto failed;
// Set the baud
err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_BAUD, FTDI_VALUE_BAUD,
(FTDI_INDEX_BAUD & 0xff00) | bitforce->usbdev->found->interface,
C_SETBAUD);
if (opt_debug)
applog(LOG_DEBUG, "%s%i: setbaud got err %d",
bitforce->drv->name, bitforce->device_id, err);
if (bitforce->usbinfo.nodev)
goto failed;
// Set Flow Control
err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_FLOW,
FTDI_VALUE_FLOW, bitforce->usbdev->found->interface, C_SETFLOW);
if (opt_debug)
applog(LOG_DEBUG, "%s%i: setflowctrl got err %d",
bitforce->drv->name, bitforce->device_id, err);
if (bitforce->usbinfo.nodev)
goto failed;
// Set Modem Control
err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_MODEM,
FTDI_VALUE_MODEM, bitforce->usbdev->found->interface, C_SETMODEM);
if (opt_debug)
applog(LOG_DEBUG, "%s%i: setmodemctrl got err %d",
bitforce->drv->name, bitforce->device_id, err);
if (bitforce->usbinfo.nodev)
goto failed;
// Clear any sent data
err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_RESET,
FTDI_VALUE_PURGE_TX, bitforce->usbdev->found->interface, C_PURGETX);
if (opt_debug)
applog(LOG_DEBUG, "%s%i: purgetx got err %d",
bitforce->drv->name, bitforce->device_id, err);
if (bitforce->usbinfo.nodev)
goto failed;
// Clear any received data
err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_RESET,
FTDI_VALUE_PURGE_RX, bitforce->usbdev->found->interface, C_PURGERX);
if (opt_debug)
applog(LOG_DEBUG, "%s%i: purgerx got err %d",
bitforce->drv->name, bitforce->device_id, err);
failed:
if (lock)
mutex_unlock(&bitforce->device_mutex);
}
static bool bitforce_detect_one(const char *devpath) static bool bitforce_detect_one(struct libusb_device *dev, struct usb_find_devices *found)
{ {
int fdDev = BFopen(devpath); char buf[BITFORCE_BUFSIZ+1];
struct cgpu_info *bitforce; char devpath[20];
char pdevbuf[0x100]; int err, amount;
char *s; char *s;
struct timeval init_start, init_now;
int init_sleep, init_count;
bool ident_first;
applog(LOG_DEBUG, "BFL: Attempting to open %s", devpath); struct cgpu_info *bitforce = NULL;
bitforce = calloc(1, sizeof(*bitforce));
bitforce->drv = &bitforce_drv;
bitforce->deven = DEV_ENABLED;
bitforce->threads = 1;
if (unlikely(fdDev == -1)) { if (!usb_init(bitforce, dev, found)) {
applog(LOG_ERR, "BFL: Failed to open %s", devpath); applog(LOG_ERR, "%s detect (%d:%d) failed to initialise (incorrect device?)",
return false; bitforce->drv->dname,
(int)(bitforce->usbinfo.bus_number),
(int)(bitforce->usbinfo.device_address));
goto shin;
} }
BFwrite(fdDev, "ZGX", 3); sprintf(devpath, "%d:%d",
pdevbuf[0] = '\0'; (int)(bitforce->usbinfo.bus_number),
BFgets(pdevbuf, sizeof(pdevbuf), fdDev); (int)(bitforce->usbinfo.device_address));
if (unlikely(!pdevbuf[0])) {
applog(LOG_ERR, "BFL: Error reading/timeout (ZGX)");
return 0; // Allow 2 complete attempts if the 1st time returns an unrecognised reply
ident_first = true;
retry:
init_count = 0;
init_sleep = REINIT_TIME_FIRST_MS;
gettimeofday(&init_start, NULL);
reinit:
bitforce_initialise(bitforce, false);
if ((err = usb_write(bitforce, BITFORCE_IDENTIFY, BITFORCE_IDENTIFY_LEN, &amount, C_REQUESTIDENTIFY)) < 0 || amount != BITFORCE_IDENTIFY_LEN) {
applog(LOG_ERR, "%s detect (%s) send identify request failed (%d:%d)",
bitforce->drv->dname, devpath, amount, err);
goto unshin;
} }
BFclose(fdDev); if ((err = usb_ftdi_read_nl(bitforce, buf, sizeof(buf)-1, &amount, C_GETIDENTIFY)) < 0 || amount < 1) {
if (unlikely(!strstr(pdevbuf, "SHA256"))) { init_count++;
applog(LOG_ERR, "BFL: Didn't recognise BitForce on %s", devpath); gettimeofday(&init_now, NULL);
return false; if (us_tdiff(&init_now, &init_start) <= REINIT_TIME_MAX) {
if (init_count == 2) {
applog(LOG_WARNING, "%s detect (%s) 2nd init failed (%d:%d) - retrying",
bitforce->drv->dname, devpath, amount, err);
}
nmsleep(init_sleep);
if ((init_sleep * 2) <= REINIT_TIME_MAX_MS)
init_sleep *= 2;
goto reinit;
}
if (init_count > 0)
applog(LOG_WARNING, "%s detect (%s) init failed %d times %.2fs",
bitforce->drv->dname, devpath, init_count, tdiff(&init_now, &init_start));
if (err < 0) {
applog(LOG_ERR, "%s detect (%s) error identify reply (%d:%d)",
bitforce->drv->dname, devpath, amount, err);
} else {
applog(LOG_ERR, "%s detect (%s) empty identify reply (%d)",
bitforce->drv->dname, devpath, amount);
}
goto unshin;
}
buf[amount] = '\0';
if (unlikely(!strstr(buf, "SHA256"))) {
if (ident_first) {
applog(LOG_WARNING, "%s detect (%s) didn't recognise '%s' trying again ...",
bitforce->drv->dname, devpath, buf);
ident_first = false;
goto retry;
}
applog(LOG_ERR, "%s detect (%s) didn't recognise '%s' on 2nd attempt",
bitforce->drv->dname, devpath, buf);
goto unshin;
}
if (likely((!memcmp(buf, ">>>ID: ", 7)) && (s = strstr(buf + 3, ">>>")))) {
s[0] = '\0';
bitforce->name = strdup(buf + 7);
} else {
bitforce->name = (char *)blank;
} }
// We have a real BitForce! // We have a real BitForce!
bitforce = calloc(1, sizeof(*bitforce)); applog(LOG_DEBUG, "%s (%s) identified as: '%s'",
bitforce->api = &bitforce_api; bitforce->drv->dname, devpath, bitforce->name);
bitforce->device_path = strdup(devpath);
bitforce->deven = DEV_ENABLED;
bitforce->threads = 1;
/* Initially enable support for nonce range and disable it later if it /* Initially enable support for nonce range and disable it later if it
* fails */ * fails */
if (opt_bfl_noncerange) { if (opt_bfl_noncerange) {
@ -129,108 +266,39 @@ static bool bitforce_detect_one(const char *devpath)
bitforce->kname = KNAME_WORK; bitforce->kname = KNAME_WORK;
} }
if (likely((!memcmp(pdevbuf, ">>>ID: ", 7)) && (s = strstr(pdevbuf + 3, ">>>")))) { bitforce->device_path = strdup(devpath);
s[0] = '\0';
bitforce->name = strdup(pdevbuf + 7);
}
mutex_init(&bitforce->device_mutex); if (!add_cgpu(bitforce))
goto unshin;
return add_cgpu(bitforce); update_usb_stats(bitforce);
}
#define LOAD_SYM(sym) do { \ mutex_init(&bitforce->device_mutex);
if (!(sym = dlsym(dll, #sym))) { \
applog(LOG_DEBUG, "Failed to load " #sym ", not using FTDI bitforce autodetect"); \
goto out; \
} \
} while(0)
#ifdef WIN32 return true;
static int bitforce_autodetect_ftdi(void)
{
char devpath[] = "\\\\.\\COMnnnnn";
char *devpathnum = &devpath[7];
char **bufptrs;
char *buf;
int found = 0;
DWORD i;
FT_STATUS ftStatus;
DWORD numDevs;
HMODULE dll = LoadLibrary("FTD2XX.DLL");
if (!dll) {
applog(LOG_DEBUG, "FTD2XX.DLL failed to load, not using FTDI bitforce autodetect");
return 0;
}
LOAD_SYM(FT_ListDevices);
LOAD_SYM(FT_Open);
LOAD_SYM(FT_GetComPortNumber);
LOAD_SYM(FT_Close);
ftStatus = FT_ListDevices(&numDevs, NULL, FT_LIST_NUMBER_ONLY);
if (ftStatus != FT_OK) {
applog(LOG_DEBUG, "FTDI device count failed, not using FTDI bitforce autodetect");
goto out;
}
applog(LOG_DEBUG, "FTDI reports %u devices", (unsigned)numDevs);
buf = alloca(65 * numDevs);
bufptrs = alloca(sizeof(*bufptrs) * (numDevs + 1));
for (i = 0; i < numDevs; ++i)
bufptrs[i] = &buf[i * 65];
bufptrs[numDevs] = NULL;
ftStatus = FT_ListDevices(bufptrs, &numDevs, FT_LIST_ALL | FT_OPEN_BY_DESCRIPTION);
if (ftStatus != FT_OK) {
applog(LOG_DEBUG, "FTDI device list failed, not using FTDI bitforce autodetect");
goto out;
}
for (i = numDevs; i > 0; ) { unshin:
--i;
bufptrs[i][64] = '\0';
if (!(strstr(bufptrs[i], "BitFORCE") && strstr(bufptrs[i], "SHA256"))) usb_uninit(bitforce);
continue;
FT_HANDLE ftHandle; shin:
if (FT_OK != FT_Open(i, &ftHandle))
continue;
LONG lComPortNumber;
ftStatus = FT_GetComPortNumber(ftHandle, &lComPortNumber);
FT_Close(ftHandle);
if (FT_OK != ftStatus || lComPortNumber < 0)
continue;
sprintf(devpathnum, "%d", (int)lComPortNumber); free(bitforce->device_path);
if (bitforce_detect_one(devpath)) if (bitforce->name != blank)
++found; free(bitforce->name);
}
out: if (bitforce->drv->copy)
dlclose(dll); free(bitforce->drv);
return found;
}
#else
static int bitforce_autodetect_ftdi(void)
{
return 0;
}
#endif
static int bitforce_detect_auto(void) free(bitforce);
{
return (serial_autodetect_udev (bitforce_detect_one, "BitFORCE*SHA256") ?: return false;
serial_autodetect_devserial(bitforce_detect_one, "BitFORCE_SHA256") ?:
bitforce_autodetect_ftdi() ?:
0);
} }
static void bitforce_detect(void) static void bitforce_detect(void)
{ {
serial_detect_auto(&bitforce_api, bitforce_detect_one, bitforce_detect_auto); usb_detect(&bitforce_drv, bitforce_detect_one);
} }
static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce) static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce)
@ -247,105 +315,17 @@ 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;
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, "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 void bitforce_clear_buffer(struct cgpu_info *bitforce)
{
int fdDev = bitforce->device_fd;
char pdevbuf[0x100];
int count = 0;
if (!fdDev)
return;
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] && (++count < 10));
mutex_unlock(&bitforce->device_mutex);
}
void bitforce_init(struct cgpu_info *bitforce)
{
char *devpath = bitforce->device_path;
int fdDev = bitforce->device_fd, retries = 0;
char pdevbuf[0x100];
char *s;
applog(LOG_WARNING, "BFL%i: Re-initialising", bitforce->device_id);
bitforce_clear_buffer(bitforce);
mutex_lock(&bitforce->device_mutex);
if (fdDev) {
BFclose(fdDev);
sleep(5);
}
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;
}
do {
BFwrite(fdDev, "ZGX", 3);
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
if (unlikely(!pdevbuf[0])) {
mutex_unlock(&bitforce->device_mutex);
applog(LOG_ERR, "BFL%i: Error reading/timeout (ZGX)", bitforce->device_id);
return;
}
if (retries++)
nmsleep(10);
} while (!strstr(pdevbuf, "BUSY") && (retries * 10 < BITFORCE_TIMEOUT_MS));
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;
bitforce->sleep_ms = BITFORCE_SLEEP_MS;
mutex_unlock(&bitforce->device_mutex);
}
static void bitforce_flash_led(struct cgpu_info *bitforce) static void bitforce_flash_led(struct cgpu_info *bitforce)
{ {
int fdDev = bitforce->device_fd; int err, amount;
if (!fdDev)
return;
/* Do not try to flash the led if we're polling for a result to /* Do not try to flash the led if we're polling for a result to
* minimise the chance of interleaved results */ * minimise the chance of interleaved results */
@ -353,19 +333,22 @@ static void bitforce_flash_led(struct cgpu_info *bitforce)
return; return;
/* It is not critical flashing the led so don't get stuck if we /* It is not critical flashing the led so don't get stuck if we
* can't grab the mutex here */ * can't grab the mutex now */
if (mutex_trylock(&bitforce->device_mutex)) if (mutex_trylock(&bitforce->device_mutex))
return; return;
BFwrite(fdDev, "ZMX", 3); if ((err = usb_write(bitforce, BITFORCE_FLASH, BITFORCE_FLASH_LEN, &amount, C_REQUESTFLASH)) < 0 || amount != BITFORCE_FLASH_LEN) {
applog(LOG_ERR, "%s%i: flash request failed (%d:%d)",
bitforce->drv->name, bitforce->device_id, amount, err);
} else {
/* However, this stops anything else getting a reply
* So best to delay any other access to the BFL */
sleep(4);
}
/* Once we've tried - don't do it until told to again */ /* Once we've tried - don't do it until told to again */
bitforce->flash_led = false; bitforce->flash_led = false;
/* However, this stops anything else getting a reply
* So best to delay any other access to the BFL */
sleep(4);
mutex_unlock(&bitforce->device_mutex); mutex_unlock(&bitforce->device_mutex);
return; // nothing is returned by the BFL return; // nothing is returned by the BFL
@ -373,11 +356,12 @@ static void bitforce_flash_led(struct cgpu_info *bitforce)
static bool bitforce_get_temp(struct cgpu_info *bitforce) static bool bitforce_get_temp(struct cgpu_info *bitforce)
{ {
int fdDev = bitforce->device_fd; char buf[BITFORCE_BUFSIZ+1];
char pdevbuf[0x100]; int err, amount;
char *s; char *s;
if (!fdDev) // Device is gone
if (bitforce->usbinfo.nodev)
return false; return false;
/* Do not try to get the temperature if we're polling for a result to /* Do not try to get the temperature if we're polling for a result to
@ -396,18 +380,30 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
if (mutex_trylock(&bitforce->device_mutex)) if (mutex_trylock(&bitforce->device_mutex))
return false; return false;
BFwrite(fdDev, "ZLX", 3); if ((err = usb_write(bitforce, BITFORCE_TEMPERATURE, BITFORCE_TEMPERATURE_LEN, &amount, C_REQUESTTEMPERATURE)) < 0 || amount != BITFORCE_TEMPERATURE_LEN) {
pdevbuf[0] = '\0'; mutex_unlock(&bitforce->device_mutex);
BFgets(pdevbuf, sizeof(pdevbuf), fdDev); applog(LOG_ERR, "%s%i: Error: Request temp invalid/timed out (%d:%d)",
mutex_unlock(&bitforce->device_mutex); bitforce->drv->name, bitforce->device_id, amount, err);
bitforce->hw_errors++;
return false;
}
if (unlikely(!pdevbuf[0])) { if ((err = usb_ftdi_read_nl(bitforce, buf, sizeof(buf)-1, &amount, C_GETTEMPERATURE)) < 0 || amount < 1) {
applog(LOG_ERR, "BFL%i: Error: Get temp returned empty string/timed out", bitforce->device_id); mutex_unlock(&bitforce->device_mutex);
if (err < 0) {
applog(LOG_ERR, "%s%i: Error: Get temp return invalid/timed out (%d:%d)",
bitforce->drv->name, bitforce->device_id, amount, err);
} else {
applog(LOG_ERR, "%s%i: Error: Get temp returned nothing (%d:%d)",
bitforce->drv->name, bitforce->device_id, amount, err);
}
bitforce->hw_errors++; bitforce->hw_errors++;
return false; return false;
} }
if ((!strncasecmp(pdevbuf, "TEMP", 4)) && (s = strchr(pdevbuf + 4, ':'))) { mutex_unlock(&bitforce->device_mutex);
if ((!strncasecmp(buf, "TEMP", 4)) && (s = strchr(buf + 4, ':'))) {
float temp = strtof(s + 1, NULL); float temp = strtof(s + 1, NULL);
/* Cope with older software that breaks and reads nonsense /* Cope with older software that breaks and reads nonsense
@ -418,7 +414,8 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
if (temp > 0) { if (temp > 0) {
bitforce->temp = temp; bitforce->temp = temp;
if (unlikely(bitforce->cutofftemp > 0 && temp > bitforce->cutofftemp)) { if (unlikely(bitforce->cutofftemp > 0 && temp > bitforce->cutofftemp)) {
applog(LOG_WARNING, "BFL%i: Hit thermal cutoff limit, disabling!", bitforce->device_id); applog(LOG_WARNING, "%s%i: Hit thermal cutoff limit, disabling!",
bitforce->drv->name, bitforce->device_id);
bitforce->deven = DEV_RECOVER; bitforce->deven = DEV_RECOVER;
dev_error(bitforce, REASON_DEV_THERMAL_CUTOFF); dev_error(bitforce, REASON_DEV_THERMAL_CUTOFF);
} }
@ -427,11 +424,12 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
/* Use the temperature monitor as a kind of watchdog for when /* Use the temperature monitor as a kind of watchdog for when
* our responses are out of sync and flush the buffer to * our responses are out of sync and flush the buffer to
* hopefully recover */ * hopefully recover */
applog(LOG_WARNING, "BFL%i: Garbled response probably throttling, clearing buffer", bitforce->device_id); applog(LOG_WARNING, "%s%i: Garbled response probably throttling, clearing buffer",
bitforce->drv->name, bitforce->device_id);
dev_error(bitforce, REASON_DEV_THROTTLE); dev_error(bitforce, REASON_DEV_THROTTLE);
/* Count throttling episodes as hardware errors */ /* Count throttling episodes as hardware errors */
bitforce->hw_errors++; bitforce->hw_errors++;
bitforce_clear_buffer(bitforce); bitforce_initialise(bitforce, true);
return false; return false;
} }
@ -441,35 +439,53 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
static bool bitforce_send_work(struct thr_info *thr, struct work *work) static bool bitforce_send_work(struct thr_info *thr, struct work *work)
{ {
struct cgpu_info *bitforce = thr->cgpu; struct cgpu_info *bitforce = thr->cgpu;
int fdDev = bitforce->device_fd;
unsigned char ob[70]; unsigned char ob[70];
char pdevbuf[0x100]; char buf[BITFORCE_BUFSIZ+1];
int err, amount;
char *s; char *s;
char *cmd;
int len;
if (!fdDev)
return false;
re_send: re_send:
if (bitforce->nonce_range) {
cmd = BITFORCE_SENDRANGE;
len = BITFORCE_SENDRANGE_LEN;
} else {
cmd = BITFORCE_SENDWORK;
len = BITFORCE_SENDWORK_LEN;
}
mutex_lock(&bitforce->device_mutex); mutex_lock(&bitforce->device_mutex);
if (bitforce->nonce_range) if ((err = usb_write(bitforce, cmd, len, &amount, C_REQUESTSENDWORK)) < 0 || amount != len) {
BFwrite(fdDev, "ZPX", 3); mutex_unlock(&bitforce->device_mutex);
else applog(LOG_ERR, "%s%i: request send work failed (%d:%d)",
BFwrite(fdDev, "ZDX", 3); bitforce->drv->name, bitforce->device_id, amount, err);
pdevbuf[0] = '\0'; return false;
BFgets(pdevbuf, sizeof(pdevbuf), fdDev); }
if (!pdevbuf[0] || !strncasecmp(pdevbuf, "B", 1)) {
if ((err = usb_ftdi_read_nl(bitforce, buf, sizeof(buf)-1, &amount, C_REQUESTSENDWORKSTATUS)) < 0) {
mutex_unlock(&bitforce->device_mutex);
applog(LOG_ERR, "%s%d: read request send work status failed (%d:%d)",
bitforce->drv->name, bitforce->device_id, amount, err);
return false;
}
if (amount == 0 || !buf[0] || !strncasecmp(buf, "B", 1)) {
mutex_unlock(&bitforce->device_mutex); mutex_unlock(&bitforce->device_mutex);
nmsleep(WORK_CHECK_INTERVAL_MS); nmsleep(WORK_CHECK_INTERVAL_MS);
goto re_send; goto re_send;
} else if (unlikely(strncasecmp(pdevbuf, "OK", 2))) { } else if (unlikely(strncasecmp(buf, "OK", 2))) {
mutex_unlock(&bitforce->device_mutex); mutex_unlock(&bitforce->device_mutex);
if (bitforce->nonce_range) { if (bitforce->nonce_range) {
applog(LOG_WARNING, "BFL%i: Does not support nonce range, disabling", bitforce->device_id); applog(LOG_WARNING, "%s%i: Does not support nonce range, disabling",
bitforce->drv->name, bitforce->device_id);
bitforce->nonce_range = false; bitforce->nonce_range = false;
bitforce->sleep_ms *= 5; bitforce->sleep_ms *= 5;
bitforce->kname = KNAME_WORK; bitforce->kname = KNAME_WORK;
goto re_send; goto re_send;
} }
applog(LOG_ERR, "BFL%i: Error: Send work reports: %s", bitforce->device_id, pdevbuf); applog(LOG_ERR, "%s%i: Error: Send work reports: %s",
bitforce->drv->name, bitforce->device_id, buf);
return false; return false;
} }
@ -479,7 +495,7 @@ re_send:
if (!bitforce->nonce_range) { if (!bitforce->nonce_range) {
sprintf((char *)ob + 8 + 32 + 12, ">>>>>>>>"); sprintf((char *)ob + 8 + 32 + 12, ">>>>>>>>");
work->blk.nonce = bitforce->nonces = 0xffffffff; work->blk.nonce = bitforce->nonces = 0xffffffff;
BFwrite(fdDev, ob, 60); len = 60;
} else { } else {
uint32_t *nonce; uint32_t *nonce;
@ -491,26 +507,41 @@ re_send:
*nonce = htobe32(work->blk.nonce + bitforce->nonces); *nonce = htobe32(work->blk.nonce + bitforce->nonces);
work->blk.nonce += bitforce->nonces + 1; work->blk.nonce += bitforce->nonces + 1;
sprintf((char *)ob + 8 + 32 + 12 + 8, ">>>>>>>>"); sprintf((char *)ob + 8 + 32 + 12 + 8, ">>>>>>>>");
BFwrite(fdDev, ob, 68); len = 68;
}
if ((err = usb_write(bitforce, (char *)ob, len, &amount, C_SENDWORK)) < 0 || amount != len) {
mutex_unlock(&bitforce->device_mutex);
applog(LOG_ERR, "%s%i: send work failed (%d:%d)",
bitforce->drv->name, bitforce->device_id, amount, err);
return false;
}
if ((err = usb_ftdi_read_nl(bitforce, buf, sizeof(buf)-1, &amount, C_SENDWORKSTATUS)) < 0) {
mutex_unlock(&bitforce->device_mutex);
applog(LOG_ERR, "%s%d: read send work status failed (%d:%d)",
bitforce->drv->name, bitforce->device_id, amount, err);
return false;
} }
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
mutex_unlock(&bitforce->device_mutex); mutex_unlock(&bitforce->device_mutex);
if (opt_debug) { if (opt_debug) {
s = bin2hex(ob + 8, 44); s = bin2hex(ob + 8, 44);
applog(LOG_DEBUG, "BFL%i: block data: %s", bitforce->device_id, s); applog(LOG_DEBUG, "%s%i: block data: %s",
bitforce->drv->name, bitforce->device_id, s);
free(s); free(s);
} }
if (unlikely(!pdevbuf[0])) { if (amount == 0 || !buf[0]) {
applog(LOG_ERR, "BFL%i: Error: Send block data returned empty string/timed out", bitforce->device_id); applog(LOG_ERR, "%s%i: Error: Send block data returned empty string/timed out",
bitforce->drv->name, bitforce->device_id);
return false; return false;
} }
if (unlikely(strncasecmp(pdevbuf, "OK", 2))) { if (unlikely(strncasecmp(buf, "OK", 2))) {
applog(LOG_ERR, "BFL%i: Error: Send block data reports: %s", bitforce->device_id, pdevbuf); applog(LOG_ERR, "%s%i: Error: Send block data reports: %s",
bitforce->drv->name, bitforce->device_id, buf);
return false; return false;
} }
@ -521,53 +552,52 @@ re_send:
static int64_t bitforce_get_result(struct thr_info *thr, struct work *work) static int64_t bitforce_get_result(struct thr_info *thr, struct work *work)
{ {
struct cgpu_info *bitforce = thr->cgpu; struct cgpu_info *bitforce = thr->cgpu;
int fdDev = bitforce->device_fd;
unsigned int delay_time_ms; unsigned int delay_time_ms;
struct timeval elapsed; struct timeval elapsed;
struct timeval now; struct timeval now;
char pdevbuf[0x100]; char buf[BITFORCE_BUFSIZ+1];
int amount;
char *pnoncebuf; char *pnoncebuf;
uint32_t nonce; uint32_t nonce;
if (!fdDev)
return -1;
while (1) { while (1) {
if (unlikely(thr->work_restart)) if (unlikely(thr->work_restart))
return 0; return 0;
mutex_lock(&bitforce->device_mutex); mutex_lock(&bitforce->device_mutex);
BFwrite(fdDev, "ZFX", 3); usb_write(bitforce, BITFORCE_WORKSTATUS, BITFORCE_WORKSTATUS_LEN, &amount, C_REQUESTWORKSTATUS);
pdevbuf[0] = '\0'; usb_ftdi_read_nl(bitforce, buf, sizeof(buf)-1, &amount, C_GETWORKSTATUS);
BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
mutex_unlock(&bitforce->device_mutex); mutex_unlock(&bitforce->device_mutex);
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
timersub(&now, &bitforce->work_start_tv, &elapsed); timersub(&now, &bitforce->work_start_tv, &elapsed);
if (elapsed.tv_sec >= BITFORCE_LONG_TIMEOUT_S) { if (elapsed.tv_sec >= BITFORCE_LONG_TIMEOUT_S) {
applog(LOG_ERR, "BFL%i: took %dms - longer than %dms", bitforce->device_id, applog(LOG_ERR, "%s%i: took %dms - longer than %dms",
bitforce->drv->name, bitforce->device_id,
tv_to_ms(elapsed), BITFORCE_LONG_TIMEOUT_MS); tv_to_ms(elapsed), BITFORCE_LONG_TIMEOUT_MS);
return 0; return 0;
} }
if (pdevbuf[0] && strncasecmp(pdevbuf, "B", 1)) /* BFL does not respond during throttling */ if (amount > 0 && buf[0] && strncasecmp(buf, "B", 1)) /* BFL does not respond during throttling */
break; break;
/* if BFL is throttling, no point checking so quickly */ /* if BFL is throttling, no point checking so quickly */
delay_time_ms = (pdevbuf[0] ? BITFORCE_CHECK_INTERVAL_MS : 2 * WORK_CHECK_INTERVAL_MS); delay_time_ms = (buf[0] ? BITFORCE_CHECK_INTERVAL_MS : 2 * WORK_CHECK_INTERVAL_MS);
nmsleep(delay_time_ms); nmsleep(delay_time_ms);
bitforce->wait_ms += delay_time_ms; bitforce->wait_ms += delay_time_ms;
} }
if (elapsed.tv_sec > BITFORCE_TIMEOUT_S) { if (elapsed.tv_sec > BITFORCE_TIMEOUT_S) {
applog(LOG_ERR, "BFL%i: took %dms - longer than %dms", bitforce->device_id, applog(LOG_ERR, "%s%i: took %dms - longer than %dms",
bitforce->drv->name, bitforce->device_id,
tv_to_ms(elapsed), BITFORCE_TIMEOUT_MS); tv_to_ms(elapsed), BITFORCE_TIMEOUT_MS);
dev_error(bitforce, REASON_DEV_OVER_HEAT); dev_error(bitforce, REASON_DEV_OVER_HEAT);
if (!pdevbuf[0]) /* Only return if we got nothing after timeout - there still may be results */ /* Only return if we got nothing after timeout - there still may be results */
if (amount == 0)
return 0; return 0;
} else if (!strncasecmp(pdevbuf, "N", 1)) {/* Hashing complete (NONCE-FOUND or NO-NONCE) */ } else if (!strncasecmp(buf, BITFORCE_EITHER, BITFORCE_EITHER_LEN)) {
/* Simple timing adjustment. Allow a few polls to cope with /* Simple timing adjustment. Allow a few polls to cope with
* OS timer delays being variably reliable. wait_ms will * OS timer delays being variably reliable. wait_ms will
* always equal sleep_ms when we've waited greater than or * always equal sleep_ms when we've waited greater than or
@ -584,26 +614,31 @@ static int64_t bitforce_get_result(struct thr_info *thr, struct work *work)
} }
if (delay_time_ms != bitforce->sleep_ms) if (delay_time_ms != bitforce->sleep_ms)
applog(LOG_DEBUG, "BFL%i: Wait time changed to: %d, waited %u", bitforce->device_id, bitforce->sleep_ms, bitforce->wait_ms); applog(LOG_DEBUG, "%s%i: Wait time changed to: %d, waited %u",
bitforce->drv->name, bitforce->device_id,
bitforce->sleep_ms, bitforce->wait_ms);
/* Work out the average time taken. Float for calculation, uint for display */ /* Work out the average time taken. Float for calculation, uint for display */
bitforce->avg_wait_f += (tv_to_ms(elapsed) - bitforce->avg_wait_f) / TIME_AVG_CONSTANT; bitforce->avg_wait_f += (tv_to_ms(elapsed) - bitforce->avg_wait_f) / TIME_AVG_CONSTANT;
bitforce->avg_wait_d = (unsigned int) (bitforce->avg_wait_f + 0.5); bitforce->avg_wait_d = (unsigned int) (bitforce->avg_wait_f + 0.5);
} }
applog(LOG_DEBUG, "BFL%i: waited %dms until %s", bitforce->device_id, bitforce->wait_ms, pdevbuf); applog(LOG_DEBUG, "%s%i: waited %dms until %s",
if (!strncasecmp(&pdevbuf[2], "-", 1)) bitforce->drv->name, bitforce->device_id,
bitforce->wait_ms, buf);
if (!strncasecmp(buf, BITFORCE_NO_NONCE, BITFORCE_NO_NONCE_MATCH))
return bitforce->nonces; /* No valid nonce found */ return bitforce->nonces; /* No valid nonce found */
else if (!strncasecmp(pdevbuf, "I", 1)) else if (!strncasecmp(buf, BITFORCE_IDLE, BITFORCE_IDLE_MATCH))
return 0; /* Device idle */ return 0; /* Device idle */
else if (strncasecmp(pdevbuf, "NONCE-FOUND", 11)) { else if (strncasecmp(buf, BITFORCE_NONCE, BITFORCE_NONCE_LEN)) {
bitforce->hw_errors++; bitforce->hw_errors++;
applog(LOG_WARNING, "BFL%i: Error: Get result reports: %s", bitforce->device_id, pdevbuf); applog(LOG_WARNING, "%s%i: Error: Get result reports: %s",
bitforce_clear_buffer(bitforce); bitforce->drv->name, bitforce->device_id, buf);
bitforce_initialise(bitforce, true);
return 0; return 0;
} }
pnoncebuf = &pdevbuf[12]; pnoncebuf = &buf[12];
while (1) { while (1) {
hex2bin((void*)&nonce, pnoncebuf, 4); hex2bin((void*)&nonce, pnoncebuf, 4);
@ -612,7 +647,8 @@ static int64_t bitforce_get_result(struct thr_info *thr, struct work *work)
#endif #endif
if (unlikely(bitforce->nonce_range && (nonce >= work->blk.nonce || if (unlikely(bitforce->nonce_range && (nonce >= work->blk.nonce ||
(work->blk.nonce > 0 && nonce < work->blk.nonce - bitforce->nonces - 1)))) { (work->blk.nonce > 0 && nonce < work->blk.nonce - bitforce->nonces - 1)))) {
applog(LOG_WARNING, "BFL%i: Disabling broken nonce range support", bitforce->device_id); applog(LOG_WARNING, "%s%i: Disabling broken nonce range support",
bitforce->drv->name, bitforce->device_id);
bitforce->nonce_range = false; bitforce->nonce_range = false;
work->blk.nonce = 0xffffffff; work->blk.nonce = 0xffffffff;
bitforce->sleep_ms *= 5; bitforce->sleep_ms *= 5;
@ -628,19 +664,16 @@ static int64_t bitforce_get_result(struct thr_info *thr, struct work *work)
return bitforce->nonces; return bitforce->nonces;
} }
static void bitforce_shutdown(struct thr_info *thr) static void bitforce_shutdown(__maybe_unused struct thr_info *thr)
{ {
struct cgpu_info *bitforce = thr->cgpu; // struct cgpu_info *bitforce = thr->cgpu;
BFclose(bitforce->device_fd);
bitforce->device_fd = 0;
} }
static void biforce_thread_enable(struct thr_info *thr) static void biforce_thread_enable(struct thr_info *thr)
{ {
struct cgpu_info *bitforce = thr->cgpu; struct cgpu_info *bitforce = thr->cgpu;
bitforce_init(bitforce); bitforce_initialise(bitforce, true);
} }
static int64_t bitforce_scanhash(struct thr_info *thr, struct work *work, int64_t __maybe_unused max_nonce) static int64_t bitforce_scanhash(struct thr_info *thr, struct work *work, int64_t __maybe_unused max_nonce)
@ -649,6 +682,10 @@ static int64_t bitforce_scanhash(struct thr_info *thr, struct work *work, int64_
bool send_ret; bool send_ret;
int64_t ret; int64_t ret;
// Device is gone
if (bitforce->usbinfo.nodev)
return -1;
send_ret = bitforce_send_work(thr, work); send_ret = bitforce_send_work(thr, work);
if (!restart_wait(bitforce->sleep_ms)) if (!restart_wait(bitforce->sleep_ms))
@ -665,11 +702,11 @@ static int64_t bitforce_scanhash(struct thr_info *thr, struct work *work, int64_
if (ret == -1) { if (ret == -1) {
ret = 0; ret = 0;
applog(LOG_ERR, "BFL%i: Comms error", bitforce->device_id); applog(LOG_ERR, "%s%i: Comms error", bitforce->drv->name, bitforce->device_id);
dev_error(bitforce, REASON_DEV_COMMS_ERROR); dev_error(bitforce, REASON_DEV_COMMS_ERROR);
bitforce->hw_errors++; bitforce->hw_errors++;
/* empty read buffer */ /* empty read buffer */
bitforce_clear_buffer(bitforce); bitforce_initialise(bitforce, true);
} }
return ret; return ret;
} }
@ -692,7 +729,8 @@ static bool bitforce_thread_init(struct thr_info *thr)
/* Pause each new thread at least 100ms between initialising /* Pause each new thread at least 100ms between initialising
* so the devices aren't making calls all at the same time. */ * so the devices aren't making calls all at the same time. */
wait = thr->id * MAX_START_DELAY_MS; wait = thr->id * MAX_START_DELAY_MS;
applog(LOG_DEBUG, "BFL%i: Delaying start by %dms", bitforce->device_id, wait / 1000); applog(LOG_DEBUG, "%s%d: Delaying start by %dms",
bitforce->drv->name, bitforce->device_id, wait / 1000);
nmsleep(wait); nmsleep(wait);
return true; return true;
@ -712,12 +750,12 @@ static struct api_data *bitforce_api_stats(struct cgpu_info *cgpu)
return root; return root;
} }
struct device_api bitforce_api = { struct device_drv bitforce_drv = {
.dname = "bitforce", .drv = DRIVER_BITFORCE,
.dname = "BitForce",
.name = "BFL", .name = "BFL",
.api_detect = bitforce_detect, .drv_detect = bitforce_detect,
.get_api_stats = bitforce_api_stats, .get_api_stats = bitforce_api_stats,
.reinit_device = bitforce_init,
.get_statline_before = get_bitforce_statline_before, .get_statline_before = get_bitforce_statline_before,
.get_stats = bitforce_get_stats, .get_stats = bitforce_get_stats,
.identify_device = bitforce_identify, .identify_device = bitforce_identify,

9
driver-cpu.c

@ -758,7 +758,7 @@ static void cpu_detect()
struct cgpu_info *cgpu; struct cgpu_info *cgpu;
cgpu = &cpus[i]; cgpu = &cpus[i];
cgpu->api = &cpu_api; cgpu->drv = &cpu_drv;
cgpu->deven = DEV_ENABLED; cgpu->deven = DEV_ENABLED;
cgpu->threads = 1; cgpu->threads = 1;
cgpu->kname = algo_names[opt_algo]; cgpu->kname = algo_names[opt_algo];
@ -768,7 +768,7 @@ static void cpu_detect()
static void reinit_cpu_device(struct cgpu_info *cpu) static void reinit_cpu_device(struct cgpu_info *cpu)
{ {
tq_push(thr_info[cpur_thr_id].q, cpu); tq_push(control_thr[cpur_thr_id].q, cpu);
} }
static bool cpu_thread_prepare(struct thr_info *thr) static bool cpu_thread_prepare(struct thr_info *thr)
@ -843,10 +843,11 @@ CPUSearch:
return last_nonce - first_nonce + 1; return last_nonce - first_nonce + 1;
} }
struct device_api cpu_api = { struct device_drv cpu_drv = {
.drv = DRIVER_CPU,
.dname = "cpu", .dname = "cpu",
.name = "CPU", .name = "CPU",
.api_detect = cpu_detect, .drv_detect = cpu_detect,
.reinit_device = reinit_cpu_device, .reinit_device = reinit_cpu_device,
.thread_prepare = cpu_thread_prepare, .thread_prepare = cpu_thread_prepare,
.can_limit_work = cpu_can_limit_work, .can_limit_work = cpu_can_limit_work,

2
driver-cpu.h

@ -53,7 +53,7 @@ enum sha256_algos {
extern const char *algo_names[]; extern const char *algo_names[];
extern bool opt_usecpu; extern bool opt_usecpu;
extern struct device_api cpu_api; extern struct device_drv cpu_drv;
extern char *set_algo(const char *arg, enum sha256_algos *algo); extern char *set_algo(const char *arg, enum sha256_algos *algo);
extern void show_algo(char buf[OPT_SHOW_LEN], const enum sha256_algos *algo); extern void show_algo(char buf[OPT_SHOW_LEN], const enum sha256_algos *algo);

19
driver-icarus.c

@ -208,7 +208,7 @@ static struct ICARUS_INFO **icarus_info;
// //
static int option_offset = -1; static int option_offset = -1;
struct device_api icarus_api; struct device_drv icarus_drv;
static void rev(unsigned char *s, size_t l) static void rev(unsigned char *s, size_t l)
{ {
@ -571,7 +571,7 @@ static bool icarus_detect_one(const char *devpath)
/* We have a real Icarus! */ /* We have a real Icarus! */
struct cgpu_info *icarus; struct cgpu_info *icarus;
icarus = calloc(1, sizeof(struct cgpu_info)); icarus = calloc(1, sizeof(struct cgpu_info));
icarus->api = &icarus_api; icarus->drv = &icarus_drv;
icarus->device_path = strdup(devpath); icarus->device_path = strdup(devpath);
icarus->device_fd = -1; icarus->device_fd = -1;
icarus->threads = 1; icarus->threads = 1;
@ -609,7 +609,7 @@ static bool icarus_detect_one(const char *devpath)
static void icarus_detect() static void icarus_detect()
{ {
serial_detect(&icarus_api, icarus_detect_one); serial_detect(&icarus_drv, icarus_detect_one);
} }
static bool icarus_prepare(struct thr_info *thr) static bool icarus_prepare(struct thr_info *thr)
@ -668,7 +668,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
icarus = thr->cgpu; icarus = thr->cgpu;
if (icarus->device_fd == -1) if (icarus->device_fd == -1)
if (!icarus_prepare(thr)) { if (!icarus_prepare(thr)) {
applog(LOG_ERR, "ICA%i: Comms error", icarus->device_id); applog(LOG_ERR, "%s%i: Comms error", icarus->drv->name, icarus->device_id);
dev_error(icarus, REASON_DEV_COMMS_ERROR); dev_error(icarus, REASON_DEV_COMMS_ERROR);
// fail the device if the reopen attempt fails // fail the device if the reopen attempt fails
@ -688,7 +688,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
ret = icarus_write(fd, ob_bin, sizeof(ob_bin)); ret = icarus_write(fd, ob_bin, sizeof(ob_bin));
if (ret) { if (ret) {
do_icarus_close(thr); do_icarus_close(thr);
applog(LOG_ERR, "ICA%i: Comms error", icarus->device_id); applog(LOG_ERR, "%s%i: Comms error", icarus->drv->name, icarus->device_id);
dev_error(icarus, REASON_DEV_COMMS_ERROR); dev_error(icarus, REASON_DEV_COMMS_ERROR);
return 0; /* This should never happen */ return 0; /* This should never happen */
} }
@ -708,7 +708,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
ret = icarus_gets(nonce_bin, fd, &tv_finish, thr, info->read_count); ret = icarus_gets(nonce_bin, fd, &tv_finish, thr, info->read_count);
if (ret == ICA_GETS_ERROR) { if (ret == ICA_GETS_ERROR) {
do_icarus_close(thr); do_icarus_close(thr);
applog(LOG_ERR, "ICA%i: Comms error", icarus->device_id); applog(LOG_ERR, "%s%i: Comms error", icarus->drv->name, icarus->device_id);
dev_error(icarus, REASON_DEV_COMMS_ERROR); dev_error(icarus, REASON_DEV_COMMS_ERROR);
return 0; return 0;
} }
@ -900,10 +900,11 @@ static void icarus_shutdown(struct thr_info *thr)
do_icarus_close(thr); do_icarus_close(thr);
} }
struct device_api icarus_api = { struct device_drv icarus_drv = {
.dname = "icarus", .drv = DRIVER_ICARUS,
.dname = "Icarus",
.name = "ICA", .name = "ICA",
.api_detect = icarus_detect, .drv_detect = icarus_detect,
.get_api_stats = icarus_api_stats, .get_api_stats = icarus_api_stats,
.thread_prepare = icarus_prepare, .thread_prepare = icarus_prepare,
.scanhash = icarus_scanhash, .scanhash = icarus_scanhash,

182
driver-modminer.c

@ -1,5 +1,5 @@
/* /*
* Copyright 2012 Andrew Smith * Copyright 2012-2013 Andrew Smith
* Copyright 2012 Luke Dashjr * Copyright 2012 Luke Dashjr
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
@ -87,7 +87,7 @@
// Limit when reducing shares_to_good // Limit when reducing shares_to_good
#define MODMINER_MIN_BACK 12 #define MODMINER_MIN_BACK 12
struct device_api modminer_api; struct device_drv modminer_drv;
// 45 noops sent when detecting, in case the device was left in "start job" reading // 45 noops sent when detecting, in case the device was left in "start job" reading
static const char NOOP[] = MODMINER_PING "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"; static const char NOOP[] = MODMINER_PING "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
@ -100,15 +100,15 @@ static void do_ping(struct cgpu_info *modminer)
// Don't care if it fails // Don't care if it fails
err = usb_write(modminer, (char *)NOOP, sizeof(NOOP)-1, &amount, C_PING); err = usb_write(modminer, (char *)NOOP, sizeof(NOOP)-1, &amount, C_PING);
applog(LOG_DEBUG, "%s%u: flush noop got %d err %d", applog(LOG_DEBUG, "%s%u: flush noop got %d err %d",
modminer->api->name, modminer->fpgaid, amount, err); modminer->drv->name, modminer->fpgaid, amount, err);
// Clear any outstanding data // Clear any outstanding data
while ((err = usb_read(modminer, buf, sizeof(buf)-1, &amount, C_CLEAR)) == 0 && amount > 0) while ((err = usb_read(modminer, buf, sizeof(buf)-1, &amount, C_CLEAR)) == 0 && amount > 0)
applog(LOG_DEBUG, "%s%u: clear got %d", applog(LOG_DEBUG, "%s%u: clear got %d",
modminer->api->name, modminer->fpgaid, amount); modminer->drv->name, modminer->fpgaid, amount);
applog(LOG_DEBUG, "%s%u: final clear got %d err %d", applog(LOG_DEBUG, "%s%u: final clear got %d err %d",
modminer->api->name, modminer->fpgaid, amount, err); modminer->drv->name, modminer->fpgaid, amount, err);
} }
static bool modminer_detect_one(struct libusb_device *dev, struct usb_find_devices *found) static bool modminer_detect_one(struct libusb_device *dev, struct usb_find_devices *found)
@ -121,42 +121,57 @@ static bool modminer_detect_one(struct libusb_device *dev, struct usb_find_devic
struct cgpu_info *modminer = NULL; struct cgpu_info *modminer = NULL;
modminer = calloc(1, sizeof(*modminer)); modminer = calloc(1, sizeof(*modminer));
modminer->api = &modminer_api; modminer->drv = &modminer_drv;
modminer->modminer_mutex = calloc(1, sizeof(*(modminer->modminer_mutex))); modminer->modminer_mutex = calloc(1, sizeof(*(modminer->modminer_mutex)));
mutex_init(modminer->modminer_mutex); mutex_init(modminer->modminer_mutex);
modminer->fpgaid = (char)0; modminer->fpgaid = (char)0;
if (!usb_init(modminer, dev, found)) if (!usb_init(modminer, dev, found)) {
applog(LOG_ERR, "%s detect (%d:%d) failed to initialise (incorrect device?)",
modminer->drv->dname,
(int)(modminer->usbinfo.bus_number),
(int)(modminer->usbinfo.device_address));
goto shin; goto shin;
}
sprintf(devpath, "%d:%d",
(int)(modminer->usbinfo.bus_number),
(int)(modminer->usbinfo.device_address));
do_ping(modminer); do_ping(modminer);
if ((err = usb_write(modminer, MODMINER_GET_VERSION, 1, &amount, C_REQUESTVERSION)) < 0 || amount != 1) { if ((err = usb_write(modminer, MODMINER_GET_VERSION, 1, &amount, C_REQUESTVERSION)) < 0 || amount != 1) {
applog(LOG_ERR, "ModMiner detect: send version request failed (%d:%d)", amount, err); applog(LOG_ERR, "%s detect (%s) send version request failed (%d:%d)",
modminer->drv->dname, devpath, amount, err);
goto unshin; goto unshin;
} }
if ((err = usb_read(modminer, buf, sizeof(buf)-1, &amount, C_GETVERSION)) < 0 || amount < 1) { if ((err = usb_read(modminer, buf, sizeof(buf)-1, &amount, C_GETVERSION)) < 0 || amount < 1) {
if (err < 0) if (err < 0)
applog(LOG_ERR, "ModMiner detect: no version reply (%d)", err); applog(LOG_ERR, "%s detect (%s) no version reply (%d)",
modminer->drv->dname, devpath, err);
else else
applog(LOG_ERR, "ModMiner detect: empty version reply (%d)", amount); applog(LOG_ERR, "%s detect (%s) empty version reply (%d)",
modminer->drv->dname, devpath, amount);
applog(LOG_DEBUG, "ModMiner detect: check the firmware"); applog(LOG_DEBUG, "%s detect (%s) check the firmware",
modminer->drv->dname, devpath);
goto unshin; goto unshin;
} }
buf[amount] = '\0'; buf[amount] = '\0';
devname = strdup(buf); devname = strdup(buf);
applog(LOG_DEBUG, "ModMiner identified as: %s", devname); applog(LOG_DEBUG, "%s (%s) identified as: %s", modminer->drv->dname, devpath, devname);
if ((err = usb_write(modminer, MODMINER_FPGA_COUNT, 1, &amount, C_REQUESTFPGACOUNT) < 0 || amount != 1)) { if ((err = usb_write(modminer, MODMINER_FPGA_COUNT, 1, &amount, C_REQUESTFPGACOUNT) < 0 || amount != 1)) {
applog(LOG_ERR, "ModMiner detect: FPGA count request failed (%d:%d)", amount, err); applog(LOG_ERR, "%s detect (%s) FPGA count request failed (%d:%d)",
modminer->drv->dname, devpath, amount, err);
goto unshin; goto unshin;
} }
if ((err = usb_read(modminer, buf, 1, &amount, C_GETFPGACOUNT)) < 0 || amount != 1) { if ((err = usb_read(modminer, buf, 1, &amount, C_GETFPGACOUNT)) < 0 || amount != 1) {
applog(LOG_ERR, "ModMiner detect: no FPGA count reply (%d:%d)", amount, err); applog(LOG_ERR, "%s detect (%s) no FPGA count reply (%d:%d)",
modminer->drv->dname, devpath, amount, err);
goto unshin; goto unshin;
} }
@ -164,16 +179,19 @@ static bool modminer_detect_one(struct libusb_device *dev, struct usb_find_devic
// can detect with modminer->cgusb->serial ? // can detect with modminer->cgusb->serial ?
if (buf[0] == 0) { if (buf[0] == 0) {
applog(LOG_ERR, "ModMiner detect: zero FPGA count from %s", devname); applog(LOG_ERR, "%s detect (%s) zero FPGA count from %s",
modminer->drv->dname, devpath, devname);
goto unshin; goto unshin;
} }
if (buf[0] < 1 || buf[0] > 4) { if (buf[0] < 1 || buf[0] > 4) {
applog(LOG_ERR, "ModMiner detect: invalid FPGA count (%u) from %s", buf[0], devname); applog(LOG_ERR, "%s detect (%s) invalid FPGA count (%u) from %s",
modminer->drv->dname, devpath, buf[0], devname);
goto unshin; goto unshin;
} }
applog(LOG_DEBUG, "ModMiner %s has %u FPGAs", devname, buf[0]); applog(LOG_DEBUG, "%s (%s) %s has %u FPGAs",
modminer->drv->dname, devpath, devname, buf[0]);
modminer->name = devname; modminer->name = devname;
@ -182,19 +200,21 @@ static bool modminer_detect_one(struct libusb_device *dev, struct usb_find_devic
for (i = 0; i < buf[0]; i++) { for (i = 0; i < buf[0]; i++) {
struct cgpu_info *tmp = calloc(1, sizeof(*tmp)); struct cgpu_info *tmp = calloc(1, sizeof(*tmp));
tmp->api = modminer->api; tmp->drv = copy_drv(modminer->drv);
tmp->name = devname; tmp->name = devname;
sprintf(devpath, "%d:%d:%d", sprintf(devpath, "%d:%d:%d",
(int)(modminer->usbdev->bus_number), (int)(modminer->usbinfo.bus_number),
(int)(modminer->usbdev->device_address), (int)(modminer->usbinfo.device_address),
i); i);
tmp->device_path = strdup(devpath); tmp->device_path = strdup(devpath);
tmp->usbdev = modminer->usbdev; tmp->usbdev = modminer->usbdev;
tmp->usbinfo.bus_number = modminer->usbinfo.bus_number;
tmp->usbinfo.device_address = modminer->usbinfo.device_address;
// Only the first copy gets the already used stats // Only the first copy gets the already used stats
if (!added) if (!added)
tmp->usbstat = modminer->usbstat; tmp->usbinfo.usbstat = modminer->usbinfo.usbstat;
tmp->fpgaid = (char)i; tmp->fpgaid = (char)i;
tmp->modminer_mutex = modminer->modminer_mutex; tmp->modminer_mutex = modminer->modminer_mutex;
tmp->deven = DEV_ENABLED; tmp->deven = DEV_ENABLED;
@ -202,6 +222,8 @@ static bool modminer_detect_one(struct libusb_device *dev, struct usb_find_devic
if (!add_cgpu(tmp)) { if (!add_cgpu(tmp)) {
free(tmp->device_path); free(tmp->device_path);
if (tmp->drv->copy)
free(tmp->drv);
free(tmp); free(tmp);
goto unshin; goto unshin;
} }
@ -211,6 +233,9 @@ static bool modminer_detect_one(struct libusb_device *dev, struct usb_find_devic
added = true; added = true;
} }
if (modminer->drv->copy)
free(modminer->drv);
free(modminer); free(modminer);
return true; return true;
@ -223,6 +248,9 @@ shin:
if (!added) if (!added)
free(modminer->modminer_mutex); free(modminer->modminer_mutex);
if (modminer->drv->copy)
free(modminer->drv);
free(modminer); free(modminer);
if (added) if (added)
@ -233,7 +261,7 @@ shin:
static void modminer_detect() static void modminer_detect()
{ {
usb_detect(&modminer_api, modminer_detect_one); usb_detect(&modminer_drv, modminer_detect_one);
} }
static bool get_expect(struct cgpu_info *modminer, FILE *f, char c) static bool get_expect(struct cgpu_info *modminer, FILE *f, char c)
@ -242,13 +270,13 @@ static bool get_expect(struct cgpu_info *modminer, FILE *f, char c)
if (fread(&buf, 1, 1, f) != 1) { if (fread(&buf, 1, 1, f) != 1) {
applog(LOG_ERR, "%s%u: Error (%d) reading bitstream (%c)", applog(LOG_ERR, "%s%u: Error (%d) reading bitstream (%c)",
modminer->api->name, modminer->device_id, errno, c); modminer->drv->name, modminer->device_id, errno, c);
return false; return false;
} }
if (buf != c) { if (buf != c) {
applog(LOG_ERR, "%s%u: firmware code mismatch (%c)", applog(LOG_ERR, "%s%u: bitstream code mismatch (%c)",
modminer->api->name, modminer->device_id, c); modminer->drv->name, modminer->device_id, c);
return false; return false;
} }
@ -262,7 +290,7 @@ static bool get_info(struct cgpu_info *modminer, FILE *f, char *buf, int bufsiz,
if (fread(siz, 2, 1, f) != 1) { if (fread(siz, 2, 1, f) != 1) {
applog(LOG_ERR, "%s%u: Error (%d) reading bitstream '%s' len", applog(LOG_ERR, "%s%u: Error (%d) reading bitstream '%s' len",
modminer->api->name, modminer->device_id, errno, name); modminer->drv->name, modminer->device_id, errno, name);
return false; return false;
} }
@ -270,13 +298,13 @@ static bool get_info(struct cgpu_info *modminer, FILE *f, char *buf, int bufsiz,
if (len >= bufsiz) { if (len >= bufsiz) {
applog(LOG_ERR, "%s%u: Bitstream '%s' len too large (%d)", applog(LOG_ERR, "%s%u: Bitstream '%s' len too large (%d)",
modminer->api->name, modminer->device_id, name, len); modminer->drv->name, modminer->device_id, name, len);
return false; return false;
} }
if (fread(buf, len, 1, f) != 1) { if (fread(buf, len, 1, f) != 1) {
applog(LOG_ERR, "%s%u: Error (%d) reading bitstream '%s'", errno, applog(LOG_ERR, "%s%u: Error (%d) reading bitstream '%s'", errno,
modminer->api->name, modminer->device_id, errno, name); modminer->drv->name, modminer->device_id, errno, name);
return false; return false;
} }
@ -302,7 +330,7 @@ static bool get_status_timeout(struct cgpu_info *modminer, char *msg, unsigned i
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Error (%d:%d) getting %s reply", applog(LOG_ERR, "%s%u: Error (%d:%d) getting %s reply",
modminer->api->name, modminer->device_id, amount, err, msg); modminer->drv->name, modminer->device_id, amount, err, msg);
return false; return false;
} }
@ -311,7 +339,7 @@ static bool get_status_timeout(struct cgpu_info *modminer, char *msg, unsigned i
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Error, invalid %s reply (was %d should be 1)", applog(LOG_ERR, "%s%u: Error, invalid %s reply (was %d should be 1)",
modminer->api->name, modminer->device_id, msg, buf[0]); modminer->drv->name, modminer->device_id, msg, buf[0]);
return false; return false;
} }
@ -343,7 +371,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Error (%d) opening bitstream file %s", applog(LOG_ERR, "%s%u: Error (%d) opening bitstream file %s",
modminer->api->name, modminer->device_id, errno, bsfile); modminer->drv->name, modminer->device_id, errno, bsfile);
return false; return false;
} }
@ -352,7 +380,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Error (%d) reading bitstream magic", applog(LOG_ERR, "%s%u: Error (%d) reading bitstream magic",
modminer->api->name, modminer->device_id, errno); modminer->drv->name, modminer->device_id, errno);
goto dame; goto dame;
} }
@ -361,7 +389,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: bitstream has incorrect magic (%u,%u) instead of (%u,%u)", applog(LOG_ERR, "%s%u: bitstream has incorrect magic (%u,%u) instead of (%u,%u)",
modminer->api->name, modminer->device_id, modminer->drv->name, modminer->device_id,
buf[0], buf[1], buf[0], buf[1],
BITSTREAM_MAGIC_0, BITSTREAM_MAGIC_1); BITSTREAM_MAGIC_0, BITSTREAM_MAGIC_1);
@ -372,7 +400,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Error (%d) bitstream seek failed", applog(LOG_ERR, "%s%u: Error (%d) bitstream seek failed",
modminer->api->name, modminer->device_id, errno); modminer->drv->name, modminer->device_id, errno);
goto dame; goto dame;
} }
@ -384,7 +412,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
goto undame; goto undame;
applog(LOG_DEBUG, "%s%u: bitstream file '%s' info:", applog(LOG_DEBUG, "%s%u: bitstream file '%s' info:",
modminer->api->name, modminer->device_id, bsfile); modminer->drv->name, modminer->device_id, bsfile);
applog(LOG_DEBUG, " Design name: '%s'", buf); applog(LOG_DEBUG, " Design name: '%s'", buf);
@ -399,7 +427,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Bad usercode in bitstream file", applog(LOG_ERR, "%s%u: Bad usercode in bitstream file",
modminer->api->name, modminer->device_id); modminer->drv->name, modminer->device_id);
goto dame; goto dame;
} }
@ -408,7 +436,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: bitstream doesn't support user code", applog(LOG_ERR, "%s%u: bitstream doesn't support user code",
modminer->api->name, modminer->device_id); modminer->drv->name, modminer->device_id);
goto dame; goto dame;
} }
@ -446,7 +474,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Error (%d) reading bitstream data len", applog(LOG_ERR, "%s%u: Error (%d) reading bitstream data len",
modminer->api->name, modminer->device_id, errno); modminer->drv->name, modminer->device_id, errno);
goto dame; goto dame;
} }
@ -460,7 +488,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
*ptr = '\0'; *ptr = '\0';
applog(LOG_WARNING, "%s%u: Programming all FPGA on %s ... Mining will not start until complete", applog(LOG_WARNING, "%s%u: Programming all FPGA on %s ... Mining will not start until complete",
modminer->api->name, modminer->device_id, devmsg); modminer->drv->name, modminer->device_id, devmsg);
buf[0] = MODMINER_PROGRAM; buf[0] = MODMINER_PROGRAM;
buf[1] = fpgaid; buf[1] = fpgaid;
@ -473,7 +501,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Program init failed (%d:%d)", applog(LOG_ERR, "%s%u: Program init failed (%d:%d)",
modminer->api->name, modminer->device_id, amount, err); modminer->drv->name, modminer->device_id, amount, err);
goto dame; goto dame;
} }
@ -492,7 +520,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: bitstream file read error %d (%d bytes left)", applog(LOG_ERR, "%s%u: bitstream file read error %d (%d bytes left)",
modminer->api->name, modminer->device_id, errno, len); modminer->drv->name, modminer->device_id, errno, len);
goto dame; goto dame;
} }
@ -507,7 +535,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
if (opt_debug) if (opt_debug)
applog(LOG_DEBUG, "%s%u: Program timeout (%d:%d) sent %d tries %d", applog(LOG_DEBUG, "%s%u: Program timeout (%d:%d) sent %d tries %d",
modminer->api->name, modminer->device_id, modminer->drv->name, modminer->device_id,
amount, err, remaining, tries); amount, err, remaining, tries);
if (!get_status(modminer, "write status", C_PROGRAMSTATUS2)) if (!get_status(modminer, "write status", C_PROGRAMSTATUS2))
@ -517,7 +545,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Program failed (%d:%d) sent %d", applog(LOG_ERR, "%s%u: Program failed (%d:%d) sent %d",
modminer->api->name, modminer->device_id, amount, err, remaining); modminer->drv->name, modminer->device_id, amount, err, remaining);
goto dame; goto dame;
} }
@ -532,7 +560,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
if (upto >= nextmsg) { if (upto >= nextmsg) {
applog(LOG_WARNING, applog(LOG_WARNING,
"%s%u: Programming %.1f%% (%d out of %d)", "%s%u: Programming %.1f%% (%d out of %d)",
modminer->api->name, modminer->device_id, upto*100, (totlen - len), totlen); modminer->drv->name, modminer->device_id, upto*100, (totlen - len), totlen);
nextmsg += 0.1; nextmsg += 0.1;
} }
@ -542,7 +570,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
goto undame; goto undame;
applog(LOG_WARNING, "%s%u: Programming completed for all FPGA on %s", applog(LOG_WARNING, "%s%u: Programming completed for all FPGA on %s",
modminer->api->name, modminer->device_id, devmsg); modminer->drv->name, modminer->device_id, devmsg);
// Give it a 2/3s delay after programming // Give it a 2/3s delay after programming
nmsleep(666); nmsleep(666);
@ -599,6 +627,7 @@ static bool modminer_fpga_prepare(struct thr_info *thr)
* *
* N.B. clock must always be a multiple of 2 * N.B. clock must always be a multiple of 2
*/ */
static const char *clocknodev = "clock failed - no device";
static const char *clockoldwork = "clock already changed for this work"; static const char *clockoldwork = "clock already changed for this work";
static const char *clocktoolow = "clock too low"; static const char *clocktoolow = "clock too low";
static const char *clocktoohi = "clock too high"; static const char *clocktoohi = "clock too high";
@ -612,6 +641,10 @@ static const char *modminer_delta_clock(struct thr_info *thr, int delta, bool te
unsigned char cmd[6], buf[1]; unsigned char cmd[6], buf[1];
int err, amount; int err, amount;
// Device is gone
if (modminer->usbinfo.nodev)
return clocknodev;
// Only do once if multiple shares per work or multiple reasons // Only do once if multiple shares per work or multiple reasons
if (!state->new_work && !force) if (!state->new_work && !force)
return clockoldwork; return clockoldwork;
@ -653,7 +686,7 @@ static const char *modminer_delta_clock(struct thr_info *thr, int delta, bool te
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Error writing set clock speed (%d:%d)", applog(LOG_ERR, "%s%u: Error writing set clock speed (%d:%d)",
modminer->api->name, modminer->device_id, amount, err); modminer->drv->name, modminer->device_id, amount, err);
return clocksetfail; return clocksetfail;
} }
@ -662,7 +695,7 @@ static const char *modminer_delta_clock(struct thr_info *thr, int delta, bool te
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Error reading set clock speed (%d:%d)", applog(LOG_ERR, "%s%u: Error reading set clock speed (%d:%d)",
modminer->api->name, modminer->device_id, amount, err); modminer->drv->name, modminer->device_id, amount, err);
return clockreplyfail; return clockreplyfail;
} }
@ -670,7 +703,7 @@ static const char *modminer_delta_clock(struct thr_info *thr, int delta, bool te
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_WARNING, "%s%u: Set clock speed %sto %u", applog(LOG_WARNING, "%s%u: Set clock speed %sto %u",
modminer->api->name, modminer->device_id, modminer->drv->name, modminer->device_id,
(delta < 0) ? "down " : (delta > 0 ? "up " : ""), (delta < 0) ? "down " : (delta > 0 ? "up " : ""),
modminer->clock); modminer->clock);
@ -691,7 +724,7 @@ static bool modminer_fpga_init(struct thr_info *thr)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Error requesting USER code (%d:%d)", applog(LOG_ERR, "%s%u: Error requesting USER code (%d:%d)",
modminer->api->name, modminer->device_id, amount, err); modminer->drv->name, modminer->device_id, amount, err);
return false; return false;
} }
@ -700,14 +733,14 @@ static bool modminer_fpga_init(struct thr_info *thr)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Error reading USER code (%d:%d)", applog(LOG_ERR, "%s%u: Error reading USER code (%d:%d)",
modminer->api->name, modminer->device_id, amount, err); modminer->drv->name, modminer->device_id, amount, err);
return false; return false;
} }
if (memcmp(buf, BISTREAM_USER_ID, 4)) { if (memcmp(buf, BISTREAM_USER_ID, 4)) {
applog(LOG_ERR, "%s%u: FPGA not programmed", applog(LOG_ERR, "%s%u: FPGA not programmed",
modminer->api->name, modminer->device_id); modminer->drv->name, modminer->device_id);
if (!modminer_fpga_upload_bitstream(modminer)) if (!modminer_fpga_upload_bitstream(modminer))
return false; return false;
@ -717,7 +750,7 @@ static bool modminer_fpga_init(struct thr_info *thr)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_DEBUG, "%s%u: FPGA is already programmed :)", applog(LOG_DEBUG, "%s%u: FPGA is already programmed :)",
modminer->api->name, modminer->device_id); modminer->drv->name, modminer->device_id);
} }
modminer->clock = MODMINER_DEF_CLOCK; modminer->clock = MODMINER_DEF_CLOCK;
@ -767,13 +800,10 @@ static bool modminer_start_work(struct thr_info *thr)
mutex_lock(modminer->modminer_mutex); mutex_lock(modminer->modminer_mutex);
if ((err = usb_write(modminer, (char *)(state->next_work_cmd), 46, &amount, C_SENDWORK)) < 0 || amount != 46) { if ((err = usb_write(modminer, (char *)(state->next_work_cmd), 46, &amount, C_SENDWORK)) < 0 || amount != 46) {
// TODO: err = LIBUSB_ERROR_NO_DEVICE means the MMQ disappeared
// - need to delete it and rescan for it? (after a delay?)
// but check all (4) disappeared
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Start work failed (%d:%d)", applog(LOG_ERR, "%s%u: Start work failed (%d:%d)",
modminer->api->name, modminer->device_id, amount, err); modminer->drv->name, modminer->device_id, amount, err);
return false; return false;
} }
@ -799,6 +829,10 @@ static void check_temperature(struct thr_info *thr)
int tbytes, tamount; int tbytes, tamount;
int amount; int amount;
// Device is gone
if (modminer->usbinfo.nodev)
return;
if (state->one_byte_temp) { if (state->one_byte_temp) {
cmd[0] = MODMINER_TEMP1; cmd[0] = MODMINER_TEMP1;
tbytes = 1; tbytes = 1;
@ -827,14 +861,14 @@ static void check_temperature(struct thr_info *thr)
if (modminer->temp < MODMINER_RECOVER_TEMP) { if (modminer->temp < MODMINER_RECOVER_TEMP) {
state->overheated = false; state->overheated = false;
applog(LOG_WARNING, "%s%u: Recovered, temp less than (%.1f) now %.3f", applog(LOG_WARNING, "%s%u: Recovered, temp less than (%.1f) now %.3f",
modminer->api->name, modminer->device_id, modminer->drv->name, modminer->device_id,
MODMINER_RECOVER_TEMP, modminer->temp); MODMINER_RECOVER_TEMP, modminer->temp);
} }
} }
else if (modminer->temp >= MODMINER_OVERHEAT_TEMP) { else if (modminer->temp >= MODMINER_OVERHEAT_TEMP) {
if (modminer->temp >= MODMINER_CUTOFF_TEMP) { if (modminer->temp >= MODMINER_CUTOFF_TEMP) {
applog(LOG_WARNING, "%s%u: Hit thermal cutoff limit! (%.1f) at %.3f", applog(LOG_WARNING, "%s%u: Hit thermal cutoff limit! (%.1f) at %.3f",
modminer->api->name, modminer->device_id, modminer->drv->name, modminer->device_id,
MODMINER_CUTOFF_TEMP, modminer->temp); MODMINER_CUTOFF_TEMP, modminer->temp);
modminer_delta_clock(thr, MODMINER_CLOCK_CUTOFF, true, false); modminer_delta_clock(thr, MODMINER_CLOCK_CUTOFF, true, false);
@ -842,7 +876,7 @@ static void check_temperature(struct thr_info *thr)
dev_error(modminer, REASON_DEV_THERMAL_CUTOFF); dev_error(modminer, REASON_DEV_THERMAL_CUTOFF);
} else { } else {
applog(LOG_WARNING, "%s%u: Overheat limit (%.1f) reached %.3f", applog(LOG_WARNING, "%s%u: Overheat limit (%.1f) reached %.3f",
modminer->api->name, modminer->device_id, modminer->drv->name, modminer->device_id,
MODMINER_OVERHEAT_TEMP, modminer->temp); MODMINER_OVERHEAT_TEMP, modminer->temp);
// If it's defined to be 0 then don't call modminer_delta_clock() // If it's defined to be 0 then don't call modminer_delta_clock()
@ -883,6 +917,10 @@ static uint64_t modminer_process_results(struct thr_info *thr)
double timeout; double timeout;
int temploop; int temploop;
// Device is gone
if (modminer->usbinfo.nodev)
return -1;
// If we are overheated it will just keep checking for results // If we are overheated it will just keep checking for results
// since we can't stop the work // since we can't stop the work
// The next work will not start until the temp drops // The next work will not start until the temp drops
@ -896,9 +934,6 @@ static uint64_t modminer_process_results(struct thr_info *thr)
while (1) { while (1) {
mutex_lock(modminer->modminer_mutex); mutex_lock(modminer->modminer_mutex);
if ((err = usb_write(modminer, cmd, 2, &amount, C_REQUESTWORKSTATUS)) < 0 || amount != 2) { if ((err = usb_write(modminer, cmd, 2, &amount, C_REQUESTWORKSTATUS)) < 0 || amount != 2) {
// TODO: err = LIBUSB_ERROR_NO_DEVICE means the MMQ disappeared
// - need to delete it and rescan for it? (after a delay?)
// but check all (4) disappeared
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
// timeoutloop never resets so the timeouts can't // timeoutloop never resets so the timeouts can't
@ -909,7 +944,7 @@ static uint64_t modminer_process_results(struct thr_info *thr)
} }
applog(LOG_ERR, "%s%u: Error sending (get nonce) (%d:%d)", applog(LOG_ERR, "%s%u: Error sending (get nonce) (%d:%d)",
modminer->api->name, modminer->device_id, amount, err); modminer->drv->name, modminer->device_id, amount, err);
return -1; return -1;
} }
@ -936,7 +971,7 @@ static uint64_t modminer_process_results(struct thr_info *thr)
} }
applog(LOG_ERR, "%s%u: Error reading (get nonce) (%d:%d)", applog(LOG_ERR, "%s%u: Error reading (get nonce) (%d:%d)",
modminer->api->name, modminer->device_id, amount+amount2, err); modminer->drv->name, modminer->device_id, amount+amount2, err);
} }
if (memcmp(&nonce, "\xff\xff\xff\xff", 4)) { if (memcmp(&nonce, "\xff\xff\xff\xff", 4)) {
@ -975,7 +1010,7 @@ static uint64_t modminer_process_results(struct thr_info *thr)
if (state->death_stage_one) { if (state->death_stage_one) {
modminer_delta_clock(thr, MODMINER_CLOCK_DEAD, false, true); modminer_delta_clock(thr, MODMINER_CLOCK_DEAD, false, true);
applog(LOG_ERR, "%s%u: DEATH clock down", applog(LOG_ERR, "%s%u: DEATH clock down",
modminer->api->name, modminer->device_id); modminer->drv->name, modminer->device_id);
// reset the death info and DISABLE it // reset the death info and DISABLE it
state->last_nonce.tv_sec = 0; state->last_nonce.tv_sec = 0;
@ -985,7 +1020,7 @@ static uint64_t modminer_process_results(struct thr_info *thr)
} else { } else {
modminer_delta_clock(thr, MODMINER_CLOCK_DEAD, false, true); modminer_delta_clock(thr, MODMINER_CLOCK_DEAD, false, true);
applog(LOG_ERR, "%s%u: death clock down", applog(LOG_ERR, "%s%u: death clock down",
modminer->api->name, modminer->device_id); modminer->drv->name, modminer->device_id);
state->death_stage_one = true; state->death_stage_one = true;
} }
@ -1045,6 +1080,10 @@ static int64_t modminer_scanhash(struct thr_info *thr, struct work *work, int64_
bool startwork; bool startwork;
struct timeval tv1, tv2; struct timeval tv1, tv2;
// Device is gone
if (thr->cgpu->usbinfo.nodev)
return -1;
// Don't start new work if overheated // Don't start new work if overheated
if (state->overheated == true) { if (state->overheated == true) {
gettimeofday(&tv1, NULL); gettimeofday(&tv1, NULL);
@ -1054,6 +1093,10 @@ static int64_t modminer_scanhash(struct thr_info *thr, struct work *work, int64_
while (state->overheated == true) { while (state->overheated == true) {
check_temperature(thr); check_temperature(thr);
// Device is gone
if (thr->cgpu->usbinfo.nodev)
return -1;
if (state->overheated == true) { if (state->overheated == true) {
gettimeofday(&tv2, NULL); gettimeofday(&tv2, NULL);
@ -1141,10 +1184,11 @@ static char *modminer_set_device(struct cgpu_info *modminer, char *option, char
return replybuf; return replybuf;
} }
struct device_api modminer_api = { struct device_drv modminer_drv = {
.dname = "modminer", .drv = DRIVER_MODMINER,
.dname = "ModMiner",
.name = "MMQ", .name = "MMQ",
.api_detect = modminer_detect, .drv_detect = modminer_detect,
.get_statline_before = get_modminer_statline_before, .get_statline_before = get_modminer_statline_before,
.set_device = modminer_set_device, .set_device = modminer_set_device,
.thread_prepare = modminer_fpga_prepare, .thread_prepare = modminer_fpga_prepare,

70
driver-opencl.c

@ -50,24 +50,24 @@ extern int gpur_thr_id;
extern bool opt_noadl; extern bool opt_noadl;
extern bool have_opencl; extern bool have_opencl;
extern void *miner_thread(void *userdata); extern void *miner_thread(void *userdata);
extern int dev_from_id(int thr_id); extern int dev_from_id(int thr_id);
extern void tailsprintf(char *f, const char *fmt, ...); extern void tailsprintf(char *f, const char *fmt, ...);
extern void wlog(const char *f, ...); extern void wlog(const char *f, ...);
extern void decay_time(double *f, double fadd); extern void decay_time(double *f, double fadd);
/**********************************************/ /**********************************************/
#ifdef HAVE_OPENCL
struct device_drv opencl_drv;
#endif
#ifdef HAVE_ADL #ifdef HAVE_ADL
extern float gpu_temp(int gpu); extern float gpu_temp(int gpu);
extern int gpu_fanspeed(int gpu); extern int gpu_fanspeed(int gpu);
extern int gpu_fanpercent(int gpu); extern int gpu_fanpercent(int gpu);
#endif #endif
#ifdef HAVE_OPENCL #ifdef HAVE_OPENCL
char *set_vector(char *arg) char *set_vector(char *arg)
{ {
@ -591,28 +591,20 @@ char *set_intensity(char *arg)
return NULL; return NULL;
} }
#endif
#ifdef HAVE_OPENCL
struct device_api opencl_api;
char *print_ndevs_and_exit(int *ndevs) char *print_ndevs_and_exit(int *ndevs)
{ {
opt_log_output = true; opt_log_output = true;
opencl_api.api_detect(); opencl_drv.drv_detect();
clear_adl(*ndevs); clear_adl(*ndevs);
applog(LOG_INFO, "%i GPU devices max detected", *ndevs); applog(LOG_INFO, "%i GPU devices max detected", *ndevs);
exit(*ndevs); exit(*ndevs);
} }
#endif #endif
struct cgpu_info gpus[MAX_GPUDEVICES]; /* Maximum number apparently possible */ struct cgpu_info gpus[MAX_GPUDEVICES]; /* Maximum number apparently possible */
struct cgpu_info *cpus; struct cgpu_info *cpus;
#ifdef HAVE_OPENCL #ifdef HAVE_OPENCL
/* In dynamic mode, only the first thread of each device will be in use. /* In dynamic mode, only the first thread of each device will be in use.
@ -624,7 +616,11 @@ void pause_dynamic_threads(int gpu)
int i; int i;
for (i = 1; i < cgpu->threads; i++) { for (i = 1; i < cgpu->threads; i++) {
struct thr_info *thr = &thr_info[i]; struct thr_info *thr;
mutex_lock(&mining_thr_lock);
thr = mining_thr[i];
mutex_unlock(&mining_thr_lock);
if (!thr->pause && cgpu->dynamic) { if (!thr->pause && cgpu->dynamic) {
applog(LOG_WARNING, "Disabling extra threads due to dynamic mode."); applog(LOG_WARNING, "Disabling extra threads due to dynamic mode.");
@ -637,9 +633,6 @@ void pause_dynamic_threads(int gpu)
} }
} }
struct device_api opencl_api;
#endif /* HAVE_OPENCL */ #endif /* HAVE_OPENCL */
#if defined(HAVE_OPENCL) && defined(HAVE_CURSES) #if defined(HAVE_OPENCL) && defined(HAVE_CURSES)
@ -716,7 +709,9 @@ retry:
else else
wlog("%d\n", gpus[gpu].intensity); wlog("%d\n", gpus[gpu].intensity);
for (i = 0; i < mining_threads; i++) { for (i = 0; i < mining_threads; i++) {
thr = &thr_info[i]; mutex_lock(&mining_thr_lock);
thr = mining_thr[i];
mutex_unlock(&mining_thr_lock);
if (thr->cgpu != cgpu) if (thr->cgpu != cgpu)
continue; continue;
get_datestamp(checkin, &thr->last); get_datestamp(checkin, &thr->last);
@ -771,9 +766,11 @@ retry:
} }
gpus[selected].deven = DEV_ENABLED; gpus[selected].deven = DEV_ENABLED;
for (i = 0; i < mining_threads; ++i) { for (i = 0; i < mining_threads; ++i) {
thr = &thr_info[i]; mutex_lock(&mining_thr_lock);
thr = mining_thr[i];
mutex_unlock(&mining_thr_lock);
cgpu = thr->cgpu; cgpu = thr->cgpu;
if (cgpu->api != &opencl_api) if (cgpu->drv->drv != DRIVER_OPENCL)
continue; continue;
if (dev_from_id(i) != selected) if (dev_from_id(i) != selected)
continue; continue;
@ -1158,14 +1155,18 @@ select_cgpu:
gpu = cgpu->device_id; gpu = cgpu->device_id;
for (thr_id = 0; thr_id < mining_threads; ++thr_id) { for (thr_id = 0; thr_id < mining_threads; ++thr_id) {
thr = &thr_info[thr_id]; mutex_lock(&mining_thr_lock);
thr = mining_thr[thr_id];
mutex_unlock(&mining_thr_lock);
cgpu = thr->cgpu; cgpu = thr->cgpu;
if (cgpu->api != &opencl_api) if (cgpu->drv->drv != DRIVER_OPENCL)
continue; continue;
if (dev_from_id(thr_id) != gpu) if (dev_from_id(thr_id) != gpu)
continue; continue;
thr = &thr_info[thr_id]; mutex_lock(&mining_thr_lock);
thr = mining_thr[thr_id];
mutex_unlock(&mining_thr_lock);
if (!thr) { if (!thr) {
applog(LOG_WARNING, "No reference to thread %d exists", thr_id); applog(LOG_WARNING, "No reference to thread %d exists", thr_id);
continue; continue;
@ -1183,9 +1184,11 @@ select_cgpu:
for (thr_id = 0; thr_id < mining_threads; ++thr_id) { for (thr_id = 0; thr_id < mining_threads; ++thr_id) {
int virtual_gpu; int virtual_gpu;
thr = &thr_info[thr_id]; mutex_lock(&mining_thr_lock);
thr = mining_thr[thr_id];
mutex_unlock(&mining_thr_lock);
cgpu = thr->cgpu; cgpu = thr->cgpu;
if (cgpu->api != &opencl_api) if (cgpu->drv->drv != DRIVER_OPENCL)
continue; continue;
if (dev_from_id(thr_id) != gpu) if (dev_from_id(thr_id) != gpu)
continue; continue;
@ -1220,9 +1223,11 @@ select_cgpu:
get_datestamp(cgpu->init, &now); get_datestamp(cgpu->init, &now);
for (thr_id = 0; thr_id < mining_threads; ++thr_id) { for (thr_id = 0; thr_id < mining_threads; ++thr_id) {
thr = &thr_info[thr_id]; mutex_lock(&mining_thr_lock);
thr = mining_thr[thr_id];
mutex_unlock(&mining_thr_lock);
cgpu = thr->cgpu; cgpu = thr->cgpu;
if (cgpu->api != &opencl_api) if (cgpu->drv->drv != DRIVER_OPENCL)
continue; continue;
if (dev_from_id(thr_id) != gpu) if (dev_from_id(thr_id) != gpu)
continue; continue;
@ -1243,8 +1248,6 @@ void *reinit_gpu(__maybe_unused void *userdata)
#ifdef HAVE_OPENCL #ifdef HAVE_OPENCL
struct device_api opencl_api;
static void opencl_detect() static void opencl_detect()
{ {
int i; int i;
@ -1263,7 +1266,7 @@ static void opencl_detect()
cgpu = &gpus[i]; cgpu = &gpus[i];
cgpu->deven = DEV_ENABLED; cgpu->deven = DEV_ENABLED;
cgpu->api = &opencl_api; cgpu->drv = &opencl_drv;
cgpu->device_id = i; cgpu->device_id = i;
cgpu->threads = opt_g_threads; cgpu->threads = opt_g_threads;
cgpu->virtual_gpu = i; cgpu->virtual_gpu = i;
@ -1276,7 +1279,7 @@ static void opencl_detect()
static void reinit_opencl_device(struct cgpu_info *gpu) static void reinit_opencl_device(struct cgpu_info *gpu)
{ {
tq_push(thr_info[gpur_thr_id].q, gpu); tq_push(control_thr[gpur_thr_id].q, gpu);
} }
#ifdef HAVE_ADL #ifdef HAVE_ADL
@ -1570,10 +1573,11 @@ static void opencl_thread_shutdown(struct thr_info *thr)
clReleaseContext(clState->context); clReleaseContext(clState->context);
} }
struct device_api opencl_api = { struct device_drv opencl_drv = {
.drv = DRIVER_OPENCL,
.dname = "opencl", .dname = "opencl",
.name = "GPU", .name = "GPU",
.api_detect = opencl_detect, .drv_detect = opencl_detect,
.reinit_device = reinit_opencl_device, .reinit_device = reinit_opencl_device,
#ifdef HAVE_ADL #ifdef HAVE_ADL
.get_statline_before = get_opencl_statline_before, .get_statline_before = get_opencl_statline_before,

2
driver-opencl.h

@ -30,6 +30,6 @@ extern void pause_dynamic_threads(int gpu);
extern bool have_opencl; extern bool have_opencl;
extern int opt_platform_id; extern int opt_platform_id;
extern struct device_api opencl_api; extern struct device_drv opencl_drv;
#endif /* __DEVICE_GPU_H__ */ #endif /* __DEVICE_GPU_H__ */

10
driver-ztex.c

@ -30,7 +30,7 @@
#define GOLDEN_BACKLOG 5 #define GOLDEN_BACKLOG 5
struct device_api ztex_api; struct device_drv ztex_drv;
// Forward declarations // Forward declarations
static void ztex_disable(struct thr_info* thr); static void ztex_disable(struct thr_info* thr);
@ -68,7 +68,7 @@ static void ztex_detect(void)
for (i = 0; i < cnt; i++) { for (i = 0; i < cnt; i++) {
ztex = calloc(1, sizeof(struct cgpu_info)); ztex = calloc(1, sizeof(struct cgpu_info));
ztex->api = &ztex_api; ztex->drv = &ztex_drv;
ztex->device_ztex = ztex_devices[i]->dev; ztex->device_ztex = ztex_devices[i]->dev;
ztex->threads = 1; ztex->threads = 1;
ztex->device_ztex->fpgaNum = 0; ztex->device_ztex->fpgaNum = 0;
@ -82,7 +82,7 @@ static void ztex_detect(void)
for (j = 1; j < fpgacount; j++) { for (j = 1; j < fpgacount; j++) {
ztex = calloc(1, sizeof(struct cgpu_info)); ztex = calloc(1, sizeof(struct cgpu_info));
ztex->api = &ztex_api; ztex->drv = &ztex_drv;
ztex_slave = calloc(1, sizeof(struct libztex_device)); ztex_slave = calloc(1, sizeof(struct libztex_device));
memcpy(ztex_slave, ztex_devices[i]->dev, sizeof(struct libztex_device)); memcpy(ztex_slave, ztex_devices[i]->dev, sizeof(struct libztex_device));
ztex->device_ztex = ztex_slave; ztex->device_ztex = ztex_slave;
@ -394,10 +394,10 @@ static void ztex_disable(struct thr_info *thr)
ztex_shutdown(thr); ztex_shutdown(thr);
} }
struct device_api ztex_api = { struct device_drv ztex_drv = {
.dname = "ztex", .dname = "ztex",
.name = "ZTX", .name = "ZTX",
.api_detect = ztex_detect, .drv_detect = ztex_detect,
.get_statline_before = ztex_statline_before, .get_statline_before = ztex_statline_before,
.thread_prepare = ztex_prepare, .thread_prepare = ztex_prepare,
.scanhash = ztex_scanhash, .scanhash = ztex_scanhash,

2
findnonce.c

@ -204,7 +204,7 @@ static void *postcalc_hash(void *userdata)
* end of the res[] array */ * end of the res[] array */
if (unlikely(pcd->res[FOUND] & ~FOUND)) { if (unlikely(pcd->res[FOUND] & ~FOUND)) {
applog(LOG_WARNING, "%s%d: invalid nonce count - HW error", applog(LOG_WARNING, "%s%d: invalid nonce count - HW error",
thr->cgpu->api->name, thr->cgpu->device_id); thr->cgpu->drv->name, thr->cgpu->device_id);
hw_errors++; hw_errors++;
thr->cgpu->hw_errors++; thr->cgpu->hw_errors++;
pcd->res[FOUND] &= FOUND; pcd->res[FOUND] &= FOUND;

10
fpgautils.c

@ -104,14 +104,14 @@ int serial_autodetect_devserial(__maybe_unused detectone_func_t detectone, __may
#endif #endif
} }
int _serial_detect(struct device_api *api, detectone_func_t detectone, autoscan_func_t autoscan, bool forceauto) int _serial_detect(struct device_drv *drv, detectone_func_t detectone, autoscan_func_t autoscan, bool forceauto)
{ {
struct string_elist *iter, *tmp; struct string_elist *iter, *tmp;
const char *dev, *colon; const char *dev, *colon;
bool inhibitauto = false; bool inhibitauto = false;
char found = 0; char found = 0;
size_t namel = strlen(api->name); size_t namel = strlen(drv->name);
size_t dnamel = strlen(api->dname); size_t dnamel = strlen(drv->dname);
list_for_each_entry_safe(iter, tmp, &scan_devices, list) { list_for_each_entry_safe(iter, tmp, &scan_devices, list) {
dev = iter->string; dev = iter->string;
@ -119,8 +119,8 @@ int _serial_detect(struct device_api *api, detectone_func_t detectone, autoscan_
size_t idlen = colon - dev; size_t idlen = colon - dev;
// allow either name:device or dname:device // allow either name:device or dname:device
if ((idlen != namel || strncasecmp(dev, api->name, idlen)) if ((idlen != namel || strncasecmp(dev, drv->name, idlen))
&& (idlen != dnamel || strncasecmp(dev, api->dname, idlen))) && (idlen != dnamel || strncasecmp(dev, drv->dname, idlen)))
continue; continue;
dev = colon + 1; dev = colon + 1;

14
fpgautils.h

@ -16,13 +16,13 @@
typedef bool(*detectone_func_t)(const char*); typedef bool(*detectone_func_t)(const char*);
typedef int(*autoscan_func_t)(); typedef int(*autoscan_func_t)();
extern int _serial_detect(struct device_api *api, detectone_func_t, autoscan_func_t, bool force_autoscan); extern int _serial_detect(struct device_drv *drv, detectone_func_t, autoscan_func_t, bool force_autoscan);
#define serial_detect_fauto(api, detectone, autoscan) \ #define serial_detect_fauto(drv, detectone, autoscan) \
_serial_detect(api, detectone, autoscan, true) _serial_detect(drv, detectone, autoscan, true)
#define serial_detect_auto(api, detectone, autoscan) \ #define serial_detect_auto(drv, detectone, autoscan) \
_serial_detect(api, detectone, autoscan, false) _serial_detect(drv, detectone, autoscan, false)
#define serial_detect(api, detectone) \ #define serial_detect(drv, detectone) \
_serial_detect(api, detectone, NULL, false) _serial_detect(drv, detectone, NULL, false)
extern int serial_autodetect_devserial(detectone_func_t, const char *prodname); extern int serial_autodetect_devserial(detectone_func_t, const char *prodname);
extern int serial_autodetect_udev(detectone_func_t, const char *prodname); extern int serial_autodetect_udev(detectone_func_t, const char *prodname);

44
miner.h

@ -114,7 +114,7 @@ static inline int fsync (int fd)
#include "libztex.h" #include "libztex.h"
#endif #endif
#ifdef USE_MODMINER #if defined(USE_MODMINER) || defined(USE_BITFORCE)
#include "usbutils.h" #include "usbutils.h"
#endif #endif
@ -196,6 +196,15 @@ static inline int fsync (int fd)
#endif #endif
#endif #endif
enum drv_driver {
DRIVER_OPENCL,
DRIVER_ICARUS,
DRIVER_BITFORCE,
DRIVER_MODMINER,
DRIVER_ZTEX,
DRIVER_CPU,
};
enum alive { enum alive {
LIFE_WELL, LIFE_WELL,
LIFE_SICK, LIFE_SICK,
@ -263,12 +272,14 @@ struct api_data;
struct thr_info; struct thr_info;
struct work; struct work;
struct device_api { struct device_drv {
enum drv_driver drv;
char *dname; char *dname;
char *name; char *name;
// API-global functions // DRV-global functions
void (*api_detect)(); void (*drv_detect)();
// Device-specific functions // Device-specific functions
void (*reinit_device)(struct cgpu_info *); void (*reinit_device)(struct cgpu_info *);
@ -288,8 +299,13 @@ struct device_api {
void (*hw_error)(struct thr_info *); void (*hw_error)(struct thr_info *);
void (*thread_shutdown)(struct thr_info *); void (*thread_shutdown)(struct thr_info *);
void (*thread_enable)(struct thr_info *); void (*thread_enable)(struct thr_info *);
// Does it need to be free()d?
bool copy;
}; };
extern struct device_drv *copy_drv(struct device_drv*);
enum dev_enable { enum dev_enable {
DEV_ENABLED, DEV_ENABLED,
DEV_DISABLED, DEV_DISABLED,
@ -359,13 +375,15 @@ struct cgminer_pool_stats {
uint32_t max_diff_count; uint32_t max_diff_count;
uint64_t times_sent; uint64_t times_sent;
uint64_t bytes_sent; uint64_t bytes_sent;
uint64_t net_bytes_sent;
uint64_t times_received; uint64_t times_received;
uint64_t bytes_received; uint64_t bytes_received;
uint64_t net_bytes_received;
}; };
struct cgpu_info { struct cgpu_info {
int cgminer_id; int cgminer_id;
struct device_api *api; struct device_drv *drv;
int device_id; int device_id;
char *name; char *name;
char *device_path; char *device_path;
@ -374,13 +392,17 @@ struct cgpu_info {
#ifdef USE_ZTEX #ifdef USE_ZTEX
struct libztex_device *device_ztex; struct libztex_device *device_ztex;
#endif #endif
#ifdef USE_MODMINER #if defined(USE_MODMINER) || defined(USE_BITFORCE)
struct cg_usb_device *usbdev; struct cg_usb_device *usbdev;
#endif #endif
#ifdef USE_ICARUS
int device_fd; int device_fd;
#endif
}; };
#if defined(USE_MODMINER) || defined(USE_BITFORCE)
struct cg_usb_info usbinfo;
#endif
#ifdef USE_MODMINER #ifdef USE_MODMINER
int usbstat;
char fpgaid; char fpgaid;
unsigned char clock; unsigned char clock;
pthread_mutex_t *modminer_mutex; pthread_mutex_t *modminer_mutex;
@ -715,6 +737,7 @@ extern pthread_mutex_t cgusb_lock;
extern pthread_mutex_t hash_lock; extern pthread_mutex_t hash_lock;
extern pthread_mutex_t console_lock; extern pthread_mutex_t console_lock;
extern pthread_mutex_t ch_lock; extern pthread_mutex_t ch_lock;
extern pthread_mutex_t mining_thr_lock;
extern pthread_mutex_t restart_lock; extern pthread_mutex_t restart_lock;
extern pthread_cond_t restart_cond; extern pthread_cond_t restart_cond;
@ -739,6 +762,7 @@ extern void api(int thr_id);
extern struct pool *current_pool(void); extern struct pool *current_pool(void);
extern int enabled_pools; extern int enabled_pools;
extern bool detect_stratum(struct pool *pool, char *url); extern bool detect_stratum(struct pool *pool, char *url);
extern void print_summary(void);
extern struct pool *add_pool(void); extern struct pool *add_pool(void);
extern void add_pool_details(struct pool *pool, bool live, char *url, char *user, char *pass); extern void add_pool_details(struct pool *pool, bool live, char *url, char *user, char *pass);
@ -761,7 +785,8 @@ extern int num_processors;
extern int hw_errors; extern int hw_errors;
extern bool use_syslog; extern bool use_syslog;
extern bool opt_quiet; extern bool opt_quiet;
extern struct thr_info *thr_info; extern struct thr_info *control_thr;
extern struct thr_info **mining_thr;
extern struct cgpu_info gpus[MAX_GPUDEVICES]; extern struct cgpu_info gpus[MAX_GPUDEVICES];
extern int gpu_threads; extern int gpu_threads;
#ifdef USE_SCRYPT #ifdef USE_SCRYPT
@ -920,6 +945,7 @@ struct pool {
time_t last_share_time; time_t last_share_time;
double last_share_diff; double last_share_diff;
uint64_t best_diff;
struct cgminer_stats cgminer_stats; struct cgminer_stats cgminer_stats;
struct cgminer_pool_stats cgminer_pool_stats; struct cgminer_pool_stats cgminer_pool_stats;
@ -1056,6 +1082,8 @@ extern void kill_work(void);
extern void switch_pools(struct pool *selected); extern void switch_pools(struct pool *selected);
extern void remove_pool(struct pool *pool); extern void remove_pool(struct pool *pool);
extern void write_config(FILE *fcfg); extern void write_config(FILE *fcfg);
extern void zero_bestshare(void);
extern void zero_stats(void);
extern void default_save_file(char *filename); extern void default_save_file(char *filename);
extern bool log_curses_only(int prio, const char *f, va_list ap); extern bool log_curses_only(int prio, const char *f, va_list ap);
extern void clear_logwin(void); extern void clear_logwin(void);

287
miner.php

@ -8,7 +8,7 @@ global $checklastshare, $poolinputs, $hidefields;
global $ignorerefresh, $changerefresh, $autorefresh; global $ignorerefresh, $changerefresh, $autorefresh;
global $allowcustompages, $customsummarypages; global $allowcustompages, $customsummarypages;
global $miner_font_family, $miner_font_size; global $miner_font_family, $miner_font_size;
global $colouroverride, $placebuttons; global $colouroverride, $placebuttons, $userlist;
# #
# See API-README for more details of these variables and how # See API-README for more details of these variables and how
# to configure miner.php # to configure miner.php
@ -20,6 +20,9 @@ $title = 'Mine';
# Set $readonly to false then it will check cgminer 'privileged' # Set $readonly to false then it will check cgminer 'privileged'
$readonly = false; $readonly = false;
# #
# Set $userlist to null to allow anyone access or read API-README
$userlist = null;
#
# Set $notify to false to NOT attempt to display the notify command # Set $notify to false to NOT attempt to display the notify command
# Set $notify to true to attempt to display the notify command # Set $notify to true to attempt to display the notify command
$notify = true; $notify = true;
@ -113,16 +116,17 @@ $poolspage = array(
'POOL.Difficulty Rejected=Diff Rej', 'POOL.Difficulty Rejected=Diff Rej',
'POOL.Has Stratum=Stratum', 'POOL.Stratum Active=StrAct', 'POOL.Has Stratum=Stratum', 'POOL.Stratum Active=StrAct',
'POOL.Has GBT=GBT', 'STATS.Times Sent=TSent', 'POOL.Has GBT=GBT', 'STATS.Times Sent=TSent',
'STATS.Bytes Sent=BSent', 'STATS.Times Recv=TRecv', 'STATS.Bytes Sent=BSent', 'STATS.Net Bytes Sent=NSent',
'STATS.Bytes Recv=BRecv')); 'STATS.Times Recv=TRecv', 'STATS.Bytes Recv=BRecv',
'STATS.Net Bytes Recv=NRecv'));
# #
$poolssum = array( $poolssum = array(
'SUMMARY' => array('MHS av', 'Found Blocks', 'Accepted', 'SUMMARY' => array('MHS av', 'Found Blocks', 'Accepted',
'Rejected', 'Utility', 'Hardware Errors', 'Rejected', 'Utility', 'Hardware Errors',
'Work Utility'), 'Work Utility'),
'POOL+STATS' => array('POOL.Difficulty Accepted', 'POOL.Difficulty Rejected', 'POOL+STATS' => array('POOL.Difficulty Accepted', 'POOL.Difficulty Rejected',
'STATS.Times Sent', 'STATS.Bytes Sent', 'STATS.Times Sent', 'STATS.Bytes Sent', 'STATS.Net Bytes Sent',
'STATS.Times Recv', 'STATS.Bytes Recv')); 'STATS.Times Recv', 'STATS.Bytes Recv', 'STATS.Net Bytes Recv'));
# #
$poolsext = array( $poolsext = array(
'POOL+STATS' => array( 'POOL+STATS' => array(
@ -130,7 +134,8 @@ $poolsext = array(
'group' => array('POOL.URL', 'POOL.Has Stratum', 'POOL.Stratum Active', 'POOL.Has GBT'), 'group' => array('POOL.URL', 'POOL.Has Stratum', 'POOL.Stratum Active', 'POOL.Has GBT'),
'calc' => array('POOL.Difficulty Accepted' => 'sum', 'POOL.Difficulty Rejected' => 'sum', 'calc' => array('POOL.Difficulty Accepted' => 'sum', 'POOL.Difficulty Rejected' => 'sum',
'STATS.Times Sent' => 'sum', 'STATS.Bytes Sent' => 'sum', 'STATS.Times Sent' => 'sum', 'STATS.Bytes Sent' => 'sum',
'STATS.Times Recv' => 'sum', 'STATS.Bytes Recv' => 'sum'), 'STATS.Net Bytes Sent' => 'sum', 'STATS.Times Recv' => 'sum',
'STATS.Bytes Recv' => 'sum', 'STATS.Net Bytes Recv' => 'sum'),
'having' => array(array('STATS.Bytes Recv', '>', 0))) 'having' => array(array('STATS.Bytes Recv', '>', 0)))
); );
@ -212,6 +217,10 @@ $rigerror = array();
global $rownum; global $rownum;
$rownum = 0; $rownum = 0;
# #
// Login
global $ses;
$ses = 'rutroh';
#
function getcss($cssname, $dom = false) function getcss($cssname, $dom = false)
{ {
global $colourtable, $colouroverride; global $colourtable, $colouroverride;
@ -239,7 +248,7 @@ function getdom($domname)
return getcss($domname, true); return getcss($domname, true);
} }
# #
function htmlhead($checkapi, $rig, $pg = null) function htmlhead($checkapi, $rig, $pg = null, $noscript = false)
{ {
global $title, $miner_font_family, $miner_font_size; global $title, $miner_font_family, $miner_font_size;
global $error, $readonly, $poolinputs, $here; global $error, $readonly, $poolinputs, $here;
@ -285,8 +294,10 @@ td.lst { $miner_font ".getcss('td.lst')."}
td.hi { $miner_font ".getcss('td.hi')."} td.hi { $miner_font ".getcss('td.hi')."}
td.lo { $miner_font ".getcss('td.lo')."} td.lo { $miner_font ".getcss('td.lo')."}
</style> </style>
</head><body".getdom('body')."> </head><body".getdom('body').">\n";
<script type='text/javascript'> if ($noscript === false)
{
echo "<script type='text/javascript'>
function pr(a,m){if(m!=null){if(!confirm(m+'?'))return}window.location='$here?ref=$autorefresh'+a}\n"; function pr(a,m){if(m!=null){if(!confirm(m+'?'))return}window.location='$here?ref=$autorefresh'+a}\n";
if ($ignorerefresh == false) if ($ignorerefresh == false)
@ -300,8 +311,9 @@ function prs2(a,n,r){var v=document.getElementById('gi'+n).value;var c=a.substr(
if ($poolinputs === true) if ($poolinputs === true)
echo "function cbs(s){var t=s.replace(/\\\\/g,'\\\\\\\\'); return t.replace(/,/g, '\\\\,')}\nfunction pla(r){var u=document.getElementById('purl').value;var w=document.getElementById('pwork').value;var p=document.getElementById('ppass').value;pr('&rig='+r+'&arg=addpool|'+cbs(u)+','+cbs(w)+','+cbs(p),'Add Pool '+u)}\nfunction psp(r){var p=document.getElementById('prio').value;pr('&rig='+r+'&arg=poolpriority|'+p,'Set Pool Priorities to '+p)}\n"; echo "function cbs(s){var t=s.replace(/\\\\/g,'\\\\\\\\'); return t.replace(/,/g, '\\\\,')}\nfunction pla(r){var u=document.getElementById('purl').value;var w=document.getElementById('pwork').value;var p=document.getElementById('ppass').value;pr('&rig='+r+'&arg=addpool|'+cbs(u)+','+cbs(w)+','+cbs(p),'Add Pool '+u)}\nfunction psp(r){var p=document.getElementById('prio').value;pr('&rig='+r+'&arg=poolpriority|'+p,'Set Pool Priorities to '+p)}\n";
} }
echo "</script>\n";
}
?> ?>
</script>
<table width=100% height=100% border=0 cellpadding=0 cellspacing=0 summary='Mine'> <table width=100% height=100% border=0 cellpadding=0 cellspacing=0 summary='Mine'>
<tr><td align=center valign=top> <tr><td align=center valign=top>
<table border=0 cellpadding=4 cellspacing=0 summary='Mine'> <table border=0 cellpadding=4 cellspacing=0 summary='Mine'>
@ -578,6 +590,14 @@ function classlastshare($when, $alldata, $warnclass, $errorclass)
return ''; return '';
} }
# #
function endzero($num)
{
$rep = preg_replace('/0*$/', '', $num);
if ($rep === '')
$rep = '0';
return $rep;
}
#
function fmt($section, $name, $value, $when, $alldata) function fmt($section, $name, $value, $when, $alldata)
{ {
global $dfmt, $rownum; global $dfmt, $rownum;
@ -840,12 +860,16 @@ function fmt($section, $name, $value, $when, $alldata)
case 'total.Diff1 Work': case 'total.Diff1 Work':
case 'STATS.Times Sent': case 'STATS.Times Sent':
case 'STATS.Bytes Sent': case 'STATS.Bytes Sent':
case 'STATS.Net Bytes Sent':
case 'STATS.Times Recv': case 'STATS.Times Recv':
case 'STATS.Bytes Recv': case 'STATS.Bytes Recv':
case 'STATS.Net Bytes Recv':
case 'total.Times Sent': case 'total.Times Sent':
case 'total.Bytes Sent': case 'total.Bytes Sent':
case 'total.Net Bytes Sent':
case 'total.Times Recv': case 'total.Times Recv':
case 'total.Bytes Recv': case 'total.Bytes Recv':
case 'total.Net Bytes Recv':
$parts = explode('.', $value, 2); $parts = explode('.', $value, 2);
if (count($parts) == 1) if (count($parts) == 1)
$dec = ''; $dec = '';
@ -853,6 +877,23 @@ function fmt($section, $name, $value, $when, $alldata)
$dec = '.'.$parts[1]; $dec = '.'.$parts[1];
$ret = number_format((float)$parts[0]).$dec; $ret = number_format((float)$parts[0]).$dec;
break; break;
case 'STATS.Hs':
case 'STATS.W':
case 'STATS.history_time':
case 'STATS.Pool Wait':
case 'STATS.Pool Max':
case 'STATS.Pool Min':
case 'STATS.Pool Av':
case 'STATS.Min Diff':
case 'STATS.Max Diff':
case 'STATS.Work Diff':
$parts = explode('.', $value, 2);
if (count($parts) == 1)
$dec = '';
else
$dec = '.'.endzero($parts[1]);
$ret = number_format((float)$parts[0]).$dec;
break;
case 'GPU.Status': case 'GPU.Status':
case 'PGA.Status': case 'PGA.Status':
case 'DEVS.Status': case 'DEVS.Status':
@ -1507,7 +1548,6 @@ function doforeach($cmd, $des, $sum, $head, $datetime)
# #
function refreshbuttons() function refreshbuttons()
{ {
global $readonly;
global $ignorerefresh, $changerefresh, $autorefresh; global $ignorerefresh, $changerefresh, $autorefresh;
if ($ignorerefresh == false && $changerefresh == true) if ($ignorerefresh == false && $changerefresh == true)
@ -1521,7 +1561,7 @@ function refreshbuttons()
# #
function pagebuttons($rig, $pg) function pagebuttons($rig, $pg)
{ {
global $readonly, $rigs; global $readonly, $rigs, $userlist, $ses;
global $allowcustompages, $customsummarypages; global $allowcustompages, $customsummarypages;
if ($rig === null) if ($rig === null)
@ -1557,18 +1597,33 @@ function pagebuttons($rig, $pg)
} }
echo '<tr><td><table cellpadding=0 cellspacing=0 border=0><tr><td nowrap>'; echo '<tr><td><table cellpadding=0 cellspacing=0 border=0><tr><td nowrap>';
if ($prev !== null) if ($userlist === null || isset($_SESSION[$ses]))
echo riginput($prev, 'Prev').'&nbsp;'; {
echo "<input type=button value='Refresh' onclick='pr(\"$refresh\",null)'>&nbsp;"; if ($prev !== null)
if ($next !== null) echo riginput($prev, 'Prev').'&nbsp;';
echo riginput($next, 'Next').'&nbsp;'; echo "<input type=button value='Refresh' onclick='pr(\"$refresh\",null)'>&nbsp;";
echo '&nbsp;'; if ($next !== null)
if (count($rigs) > 1) echo riginput($next, 'Next').'&nbsp;';
echo "<input type=button value='Summary' onclick='pr(\"\",null)'>&nbsp;"; echo '&nbsp;';
if (count($rigs) > 1)
echo "<input type=button value='Summary' onclick='pr(\"\",null)'>&nbsp;";
}
if ($allowcustompages === true) if ($allowcustompages === true)
foreach ($customsummarypages as $pagename => $data) {
if ($userlist === null || isset($_SESSION[$ses]))
$list = $customsummarypages;
else
{
if ($userlist !== null && isset($userlist['def']))
$list = array_flip($userlist['def']);
else
$list = array();
}
foreach ($list as $pagename => $data)
echo "<input type=button value='$pagename' onclick='pr(\"&pg=$pagename\",null)'>&nbsp;"; echo "<input type=button value='$pagename' onclick='pr(\"&pg=$pagename\",null)'>&nbsp;";
}
echo '</td><td width=100%>&nbsp;</td><td nowrap>'; echo '</td><td width=100%>&nbsp;</td><td nowrap>';
if ($rig !== null && $readonly === false) if ($rig !== null && $readonly === false)
@ -1580,6 +1635,12 @@ function pagebuttons($rig, $pg)
echo "&nbsp;<input type=button value='Quit' onclick='prc(\"quit&rig=$rig\",\"Quit CGMiner$rg\")'>"; echo "&nbsp;<input type=button value='Quit' onclick='prc(\"quit&rig=$rig\",\"Quit CGMiner$rg\")'>";
} }
refreshbuttons(); refreshbuttons();
if (isset($_SESSION[$ses]))
echo "&nbsp;<input type=button value='Logout' onclick='pr(\"&logout=1\",null)'>";
else
if ($userlist !== null)
echo "&nbsp;<input type=button value='Login' onclick='pr(\"&login=1\",null)'>";
echo "</td></tr></table></td></tr>"; echo "</td></tr></table></td></tr>";
} }
# #
@ -2410,13 +2471,126 @@ function showcustompage($pagename)
pagebuttons(null, $pagename); pagebuttons(null, $pagename);
} }
# #
function onlylogin()
{
global $here;
htmlhead(false, null, null, true);
?>
<tr height=15%><td>&nbsp;</td></tr>
<tr><td>
<center>
<table width=384 height=368 cellpadding=0 cellspacing=0 border=0>
<tr><td>
<table width=100% height=100% border=0 align=center cellpadding=5 cellspacing=0>
<tr><td><form action='<?php echo $here; ?>' method=post>
<table width=200 border=0 align=center cellpadding=5 cellspacing=0>
<tr><td height=120 colspan=2>&nbsp;</td></tr>
<tr><td colspan=2 align=center valign=middle>
<h2>LOGIN</h2></td></tr>
<tr><td align=center valign=middle><div align=right>Username:</div></td>
<td height=33 align=center valign=middle>
<input type=text name=rut size=18></td></tr>
<tr><td align=center valign=middle><div align=right>Password:</div></td>
<td height=33 align=center valign=middle>
<input type=password name=roh size=18></td></tr>
<tr valign=top><td></td><td><input type=submit value=Login>
</td></tr>
</table></form></td></tr>
</table></td></tr>
</table></center>
</td></tr>
<?php
}
#
function checklogin()
{
global $allowcustompages, $customsummarypages;
global $readonly, $userlist, $ses;
$out = trim(getparam('logout', true));
if ($out !== null && $out !== '' && isset($_SESSION[$ses]))
unset($_SESSION[$ses]);
$login = trim(getparam('login', true));
if ($login !== null && $login !== '')
{
if (isset($_SESSION[$ses]))
unset($_SESSION[$ses]);
onlylogin();
return 'login';
}
if ($userlist === null)
return false;
$rut = trim(getparam('rut', true));
$roh = trim(getparam('roh', true));
if (($rut !== null && $rut !== '') || ($roh !== null && $roh !== ''))
{
if (isset($_SESSION[$ses]))
unset($_SESSION[$ses]);
if ($rut !== null && $rut !== '' && $roh !== null && $roh !== '')
{
if (isset($userlist['sys']) && isset($userlist['sys'][$rut])
&& ($userlist['sys'][$rut] === $roh))
{
$_SESSION[$ses] = true;
return false;
}
if (isset($userlist['usr']) && isset($userlist['usr'][$rut])
&& ($userlist['usr'][$rut] === $roh))
{
$_SESSION[$ses] = false;
$readonly = true;
return false;
}
}
}
if (isset($_SESSION[$ses]))
{
if ($_SESSION[$ses] == false)
$readonly = true;
return false;
}
if (isset($userlist['def']) && $allowcustompages === true)
{
// Ensure at least one exists
foreach ($userlist['def'] as $pg)
if (isset($customsummarypages[$pg]))
return true;
}
onlylogin();
return 'login';
}
#
function display() function display()
{ {
global $miner, $port; global $miner, $port;
global $readonly, $notify, $rigs; global $readonly, $notify, $rigs;
global $ignorerefresh, $autorefresh; global $ignorerefresh, $autorefresh;
global $allowcustompages; global $allowcustompages, $customsummarypages;
global $placebuttons; global $placebuttons;
global $userlist, $ses;
$pagesonly = checklogin();
if ($pagesonly === 'login')
return;
if ($rigs == null or count($rigs) == 0)
{
otherrow("<td>No rigs defined</td>");
return;
}
if ($ignorerefresh == false) if ($ignorerefresh == false)
{ {
@ -2425,52 +2599,65 @@ function display()
$autorefresh = intval($ref); $autorefresh = intval($ref);
} }
$rig = trim(getparam('rig', true)); if ($pagesonly !== true)
$arg = trim(getparam('arg', true));
$preprocess = null;
if ($arg != null and $arg != '')
{ {
$num = null; $rig = trim(getparam('rig', true));
if ($rig != null and $rig != '')
{
if ($rig >= 0 and $rig < count($rigs))
$num = $rig;
}
else
if (count($rigs) == 0)
$num = 0;
if ($num != null) $arg = trim(getparam('arg', true));
$preprocess = null;
if ($arg != null and $arg != '')
{ {
$parts = explode(':', $rigs[$num], 3); if ($rig != null and $rig != '' and $rig >= 0 and $rig < count($rigs))
if (count($parts) >= 2)
{ {
$miner = $parts[0]; $parts = explode(':', $rigs[$rig], 3);
$port = $parts[1]; if (count($parts) >= 2)
{
$miner = $parts[0];
$port = $parts[1];
if ($readonly !== true) if ($readonly !== true)
$preprocess = $arg; $preprocess = $arg;
}
} }
} }
} }
if ($rigs == null or count($rigs) == 0)
{
otherrow("<td>No rigs defined</td>");
return;
}
if ($allowcustompages === true) if ($allowcustompages === true)
{ {
$pg = trim(getparam('pg', true)); $pg = trim(getparam('pg', true));
if ($pg != null && $pg != '') if ($pagesonly === true)
{
if ($pg !== null && $pg !== '')
{
if ($userlist !== null && isset($userlist['def'])
&& !in_array($pg, $userlist['def']))
$pg = null;
}
else
{
if ($userlist !== null && isset($userlist['def']))
foreach ($userlist['def'] as $pglook)
if (isset($customsummarypages[$pglook]))
{
$pg = $pglook;
break;
}
}
}
if ($pg !== null && $pg !== '')
{ {
showcustompage($pg); showcustompage($pg);
return; return;
} }
} }
if ($pagesonly === true)
{
onlylogin();
return;
}
if (count($rigs) == 1) if (count($rigs) == 1)
{ {
$parts = explode(':', $rigs[0], 3); $parts = explode(':', $rigs[0], 3);

720
usbutils.c

File diff suppressed because it is too large Load Diff

77
usbutils.h

@ -1,5 +1,5 @@
/* /*
* Copyright 2012 Andrew Smith * Copyright 2012-2013 Andrew Smith
* *
* This program is free software; you can redistribute it and/or modify it * 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 * under the terms of the GNU General Public License as published by the Free
@ -12,6 +12,29 @@
#include <libusb.h> #include <libusb.h>
// for 0x0403/0x6014 FT232H (and possibly others?)
#define FTDI_TYPE_OUT (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT)
#define FTDI_REQUEST_RESET ((uint8_t)0)
#define FTDI_REQUEST_MODEM ((uint8_t)1)
#define FTDI_REQUEST_FLOW ((uint8_t)2)
#define FTDI_REQUEST_BAUD ((uint8_t)3)
#define FTDI_REQUEST_DATA ((uint8_t)4)
#define FTDI_VALUE_RESET 0
#define FTDI_VALUE_PURGE_RX 1
#define FTDI_VALUE_PURGE_TX 2
// baud with a 0 divisor is 120,000,000/10
//#define FTDI_VALUE_BAUD (0)
//#define FTDI_INDEX_BAUD (0)
#define FTDI_VALUE_BAUD 0xc068
#define FTDI_INDEX_BAUD 0x0200
#define FTDI_VALUE_DATA 0
#define FTDI_VALUE_FLOW 0
#define FTDI_VALUE_MODEM 0x0303
// Use the device defined timeout // Use the device defined timeout
#define DEVTIMEOUT 0 #define DEVTIMEOUT 0
@ -32,6 +55,7 @@ struct usb_find_devices {
const char *name; const char *name;
uint16_t idVendor; uint16_t idVendor;
uint16_t idProduct; uint16_t idProduct;
int kernel;
int config; int config;
int interface; int interface;
unsigned int timeout; unsigned int timeout;
@ -44,8 +68,6 @@ struct cg_usb_device {
libusb_device_handle *handle; libusb_device_handle *handle;
pthread_mutex_t *mutex; pthread_mutex_t *mutex;
struct libusb_device_descriptor *descriptor; struct libusb_device_descriptor *descriptor;
uint8_t bus_number;
uint8_t device_address;
uint16_t usbver; uint16_t usbver;
int speed; int speed;
char *prod_string; char *prod_string;
@ -55,8 +77,18 @@ struct cg_usb_device {
unsigned char interfaceVersion; // ?? unsigned char interfaceVersion; // ??
}; };
struct cg_usb_info {
uint8_t bus_number;
uint8_t device_address;
int usbstat;
bool nodev;
int nodev_count;
struct timeval last_nodev;
};
enum usb_cmds { enum usb_cmds {
C_PING = 0, C_REJECTED = 0,
C_PING,
C_CLEAR, C_CLEAR,
C_REQUESTVERSION, C_REQUESTVERSION,
C_GETVERSION, C_GETVERSION,
@ -78,32 +110,49 @@ enum usb_cmds {
C_SENDWORKSTATUS, C_SENDWORKSTATUS,
C_REQUESTWORKSTATUS, C_REQUESTWORKSTATUS,
C_GETWORKSTATUS, C_GETWORKSTATUS,
C_REQUESTIDENTIFY,
C_GETIDENTIFY,
C_REQUESTFLASH,
C_REQUESTSENDWORK,
C_REQUESTSENDWORKSTATUS,
C_RESET,
C_SETBAUD,
C_SETDATA,
C_SETFLOW,
C_SETMODEM,
C_PURGERX,
C_PURGETX,
C_MAX C_MAX
}; };
struct device_api; struct device_drv;
struct cgpu_info; struct cgpu_info;
void usb_uninit(struct cgpu_info *cgpu); void usb_uninit(struct cgpu_info *cgpu);
void release_cgpu(struct cgpu_info *cgpu);
bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find_devices *found); bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find_devices *found);
void usb_detect(struct device_api *api, bool (*device_detect)(struct libusb_device *, struct usb_find_devices *)); void usb_detect(struct device_drv *drv, bool (*device_detect)(struct libusb_device *, struct usb_find_devices *));
struct api_data *api_usb_stats(int *count); struct api_data *api_usb_stats(int *count);
void update_usb_stats(struct cgpu_info *cgpu); void update_usb_stats(struct cgpu_info *cgpu);
int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, int eol, enum usb_cmds); int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, int eol, enum usb_cmds, bool ftdi);
int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, enum usb_cmds); int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, enum usb_cmds);
int _usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned int timeout, enum usb_cmds cmd);
void usb_cleanup(); void usb_cleanup();
#define usb_read(cgpu, buf, bufsiz, read, cmd) \ #define usb_read(cgpu, buf, bufsiz, read, cmd) \
_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, -1, cmd) _usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, -1, cmd, false)
#define usb_read_nl(cgpu, buf, bufsiz, read, cmd) \
_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, '\n', cmd, false)
#define usb_read_ep(cgpu, ep, buf, bufsiz, read, cmd) \ #define usb_read_ep(cgpu, ep, buf, bufsiz, read, cmd) \
_usb_read(cgpu, ep, buf, bufsiz, read, DEVTIMEOUT, -1, cmd) _usb_read(cgpu, ep, buf, bufsiz, read, DEVTIMEOUT, -1, cmd, false)
#define usb_read_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \ #define usb_read_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \
_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, timeout, -1, cmd) _usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, timeout, -1, cmd, false)
#define usb_read_ep_timeout(cgpu, ep, buf, bufsiz, read, timeout, cmd) \ #define usb_read_ep_timeout(cgpu, ep, buf, bufsiz, read, timeout, cmd) \
_usb_read(cgpu, ep, buf, bufsiz, read, timeout, -1, cmd) _usb_read(cgpu, ep, buf, bufsiz, read, timeout, -1, cmd, false)
#define usb_write(cgpu, buf, bufsiz, wrote, cmd) \ #define usb_write(cgpu, buf, bufsiz, wrote, cmd) \
_usb_write(cgpu, DEFAULT_EP_OUT, buf, bufsiz, wrote, DEVTIMEOUT, cmd) _usb_write(cgpu, DEFAULT_EP_OUT, buf, bufsiz, wrote, DEVTIMEOUT, cmd)
@ -117,4 +166,10 @@ void usb_cleanup();
#define usb_write_ep_timeout(cgpu, ep, buf, bufsiz, wrote, timeout, cmd) \ #define usb_write_ep_timeout(cgpu, ep, buf, bufsiz, wrote, timeout, cmd) \
_usb_write(cgpu, ep, buf, bufsiz, wrote, timeout, cmd) _usb_write(cgpu, ep, buf, bufsiz, wrote, timeout, cmd)
#define usb_ftdi_read_nl(cgpu, buf, bufsiz, read, cmd) \
_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, '\n', cmd, true)
#define usb_transfer(cgpu, typ, req, val, idx, cmd) \
_usb_transfer(cgpu, typ, req, val, idx, DEVTIMEOUT, cmd)
#endif #endif

35
util.c

@ -261,6 +261,30 @@ static void set_nettime(void)
wr_unlock(&netacc_lock); wr_unlock(&netacc_lock);
} }
static int curl_debug_cb(__maybe_unused CURL *handle, curl_infotype type,
__maybe_unused unsigned char *data, size_t size,
void *userdata)
{
struct pool *pool = (struct pool *)userdata;
switch(type) {
case CURLINFO_HEADER_IN:
case CURLINFO_DATA_IN:
case CURLINFO_SSL_DATA_IN:
pool->cgminer_pool_stats.net_bytes_received += size;
break;
case CURLINFO_HEADER_OUT:
case CURLINFO_DATA_OUT:
case CURLINFO_SSL_DATA_OUT:
pool->cgminer_pool_stats.net_bytes_sent += size;
break;
case CURLINFO_TEXT:
default:
break;
}
return 0;
}
json_t *json_rpc_call(CURL *curl, const char *url, json_t *json_rpc_call(CURL *curl, const char *url,
const char *userpass, const char *rpc_req, const char *userpass, const char *rpc_req,
bool probe, bool longpoll, int *rolltime, bool probe, bool longpoll, int *rolltime,
@ -287,10 +311,11 @@ json_t *json_rpc_call(CURL *curl, const char *url,
probing = !pool->probed; probing = !pool->probed;
curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout); curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
#if 0 /* Disable curl debugging since it spews to stderr */ // CURLOPT_VERBOSE won't write to stderr if we use CURLOPT_DEBUGFUNCTION
if (opt_protocol) curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, curl_debug_cb);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)pool);
#endif curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_ENCODING, ""); curl_easy_setopt(curl, CURLOPT_ENCODING, "");
@ -912,6 +937,7 @@ 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;
return true; return true;
} }
@ -1041,6 +1067,7 @@ char *recv_line(struct pool *pool)
pool->cgminer_pool_stats.times_received++; pool->cgminer_pool_stats.times_received++;
pool->cgminer_pool_stats.bytes_received += len; pool->cgminer_pool_stats.bytes_received += len;
pool->cgminer_pool_stats.net_bytes_received += len;
out: out:
if (!sret) if (!sret)
clear_sock(pool); clear_sock(pool);

Loading…
Cancel
Save