mirror of
https://github.com/GOSTSec/sgminer
synced 2025-01-25 22:14:36 +00:00
Merge branch 'master' into libusbx
Conflicts: api.c cgminer.c miner.h usbutils.c
This commit is contained in:
commit
64f5cac62c
13
API-README
13
API-README
@ -277,13 +277,13 @@ The list of requests - a (*) means it requires privileged access - and replies:
|
|||||||
none There is no reply section just the STATUS section
|
none There is no reply section just the STATUS section
|
||||||
stating the results of the identify request
|
stating the results of the identify request
|
||||||
This is only available if PGA mining is enabled
|
This is only available if PGA mining is enabled
|
||||||
and currently only BFL singles support this
|
and currently only BFL singles and Cairnsmore1's
|
||||||
command
|
with the appropriate firmware support this command
|
||||||
On a BFL single it will flash the led on the front
|
On a BFL single it will flash the led on the front
|
||||||
of the device for appoximately 4s
|
of the device for appoximately 4s
|
||||||
All other non BFL PGA devices will return a
|
All other non BFL,ICA PGA devices will return a
|
||||||
warning status message stating that they dont
|
warning status message stating that they dont
|
||||||
support it
|
support it. Non-CMR ICAs will ignore the command.
|
||||||
This adds a 4s delay to the BFL share being
|
This adds a 4s delay to the BFL share being
|
||||||
processed so you may get a message stating that
|
processed so you may get a message stating that
|
||||||
procssing took longer than 7000ms if the request
|
procssing took longer than 7000ms if the request
|
||||||
@ -364,6 +364,7 @@ The list of requests - a (*) means it requires privileged access - and replies:
|
|||||||
|
|
||||||
The current options are:
|
The current options are:
|
||||||
MMQ opt=clock val=160 to 230 (a multiple of 2)
|
MMQ opt=clock val=160 to 230 (a multiple of 2)
|
||||||
|
CMR opt=clock val=100 to 220
|
||||||
|
|
||||||
zero|Which,true/false (*)
|
zero|Which,true/false (*)
|
||||||
none There is no reply section just the STATUS section
|
none There is no reply section just the STATUS section
|
||||||
@ -433,8 +434,8 @@ The list of requests - a (*) means it requires privileged access - and replies:
|
|||||||
help message about the options available
|
help message about the options available
|
||||||
|
|
||||||
The current options are:
|
The current options are:
|
||||||
AVA+BTB opt=freq val=256 to 450 - chip frequency
|
AVA+BTB opt=freq val=256 to 1024 - chip frequency
|
||||||
BTB opt=millivolts val=1000 to 1310 - corevoltage
|
BTB opt=millivolts val=1000 to 1400 - corevoltage
|
||||||
|
|
||||||
When you enable, disable or restart a GPU, PGA or ASC, you will also get
|
When you enable, disable or restart a GPU, PGA or ASC, you will also get
|
||||||
Thread messages in the cgminer status window
|
Thread messages in the cgminer status window
|
||||||
|
93
NEWS
93
NEWS
@ -1,3 +1,96 @@
|
|||||||
|
|
||||||
|
- We are always dependent on libusb handling events so use the blocking
|
||||||
|
libusb_handle_events in the polling thread and use a bool to know if we should
|
||||||
|
continue polling.
|
||||||
|
- Use fractional hashrate return values in bitfury_scanhash to minimise the
|
||||||
|
number of times we return 0 based on hashrate so far to further damp out
|
||||||
|
displayed hashrate.
|
||||||
|
- Check for presence of driver name in DRIVER_COUNT_FOUND to prevent strcmp on a
|
||||||
|
null pointer when a driver is not built in.
|
||||||
|
- CMR allow sending flash and clock commands
|
||||||
|
- Kill off threads that have failed using hash_sole_work instead of just
|
||||||
|
disabling them.
|
||||||
|
- Make the bf1 getinfo size a macro
|
||||||
|
- Failing to add_cgpu in bitfury should be a terminal failure.
|
||||||
|
- Check return values when attempting to open a BF1 device and set the msg size
|
||||||
|
as a macro.
|
||||||
|
- Display errors on failed usb read and write and consider sequential IO errors
|
||||||
|
a permanent failure.
|
||||||
|
- Use libusb's own error name function instead of hand coding the error names.
|
||||||
|
- Limit ms_tdiff to 1 hour as a sanity check.
|
||||||
|
- Enable the usb buffer in avalon driver.
|
||||||
|
- Check for async transfer variants of error messages.
|
||||||
|
- Remove unused variables.
|
||||||
|
- Try switching pools if for some reason we end up with only idle pools and have
|
||||||
|
ended up current_pool set to an idle one.
|
||||||
|
- Check a pool is stable for >5 mins before switching back to it.
|
||||||
|
- Minimise the time between dropping the read devlock and grabbing the write
|
||||||
|
devlock to avoid tons of logging spam in the interim.
|
||||||
|
- Check for libusb transfer stall error to be consistent with async IO errors
|
||||||
|
returned for a halt condition.
|
||||||
|
- Check for continuous IO errors on USB and consider the device inactive if more
|
||||||
|
than retry max.
|
||||||
|
- Make the devlock a cglock in usbutils and only grab the write lock for
|
||||||
|
fundamental changes allowing us to send and receive transfers concurrently
|
||||||
|
without lock contention.
|
||||||
|
- Prevent overflows in us_tdiff and ms_tdiff.
|
||||||
|
- Change second initialise message on bitfury verbose mode.
|
||||||
|
- Submitting an ntime offset nonce needs to be done on a copy of the work
|
||||||
|
instead of the original so abstract out shared components as much as possible,
|
||||||
|
minimising strdups in copy_work and make submit_work_async work take copied
|
||||||
|
work, cleaning up code in the process.
|
||||||
|
- Provide a way for drivers to submit work that it has internally rolled the
|
||||||
|
ntime value by returning the amount it has ntime rolled to be added.
|
||||||
|
- Typo in configure.ac
|
||||||
|
- Remove unmaintained broken ztex driver.
|
||||||
|
- Icarus - use a data structure for I/O rather than magic numbers
|
||||||
|
- delete old tracked ccan/opt/*.o files
|
||||||
|
- klondike correct cvtKlnToC() temperature calculation
|
||||||
|
- klondike - correct 1st reply debug based on define
|
||||||
|
- klondike - debug dump structured replies
|
||||||
|
- klondike - avoid division by zero if maxcount is unexpectedly zero
|
||||||
|
- klondike store and report errorcount and noise
|
||||||
|
- klondike - fix chipstats api stats buffer overrun with 16 chips
|
||||||
|
- klondike add new nonecount only once
|
||||||
|
- klondike - report mh/s based on nonces found + put old estimate into API stats
|
||||||
|
- klondike use a memcpy
|
||||||
|
- klondike fix bracket tabs indenting
|
||||||
|
- api.c missing Klondike from ASIC list
|
||||||
|
- Klondike update code to current git
|
||||||
|
- Add 2nd CMR to 01-cgminer.rules
|
||||||
|
- Add Klondike to 01-cgminer.rules
|
||||||
|
- Klondike to main directory
|
||||||
|
- Klondike consistent code spacing
|
||||||
|
- Klondike update driver code to current git
|
||||||
|
- update firmware for 16 chips, add dist files
|
||||||
|
- beta final 0.3.0 release
|
||||||
|
- updated firmware, IOC method
|
||||||
|
- prevent nonces when not state W
|
||||||
|
- added driver config option support
|
||||||
|
- fixes for 300 MHz, fix K1 parts list
|
||||||
|
- update driver, docs
|
||||||
|
- update firmware & utils
|
||||||
|
- updated cgminer driver for 3.3.1
|
||||||
|
- update firmware and driver, create new cgminer fork
|
||||||
|
- update klondike driver
|
||||||
|
- add cgminer driver file as-is
|
||||||
|
- Add API output displaying USB cancellations.
|
||||||
|
- Store statistics on how often we have to cancel async bulk transfers and add a
|
||||||
|
debug message whenever we do.
|
||||||
|
- Treat any unexpected timeouts waiting for async transfers as though there may
|
||||||
|
be a usb halt condition and attempt to clear the halt before cancelling the
|
||||||
|
tranfer.
|
||||||
|
- Remove zero packet flag on usb as it's unsupported outside linux and
|
||||||
|
unnecessary.
|
||||||
|
- Fake the libusb transfer timed out message if we force cancel it with our own
|
||||||
|
async functions.
|
||||||
|
- Use asynchronous transfers for all bulk transfers, allowing us to use our own
|
||||||
|
timers and cancelling transfers that take too long.
|
||||||
|
- Add libusb error warning message when significant error occurs.
|
||||||
|
- Icarus CMR2 detect FPGA setup
|
||||||
|
- Disable bitfury device thread on it disappearing.
|
||||||
|
|
||||||
|
|
||||||
Version 3.5.0 - 29th September 2013
|
Version 3.5.0 - 29th September 2013
|
||||||
|
|
||||||
- Add magic init sequence required on BF1 devices to get them mining on windows.
|
- Add magic init sequence required on BF1 devices to get them mining on windows.
|
||||||
|
1
api.c
1
api.c
@ -3141,7 +3141,6 @@ static int itemstats(struct io_data *io_data, int i, char *id, struct cgminer_st
|
|||||||
}
|
}
|
||||||
|
|
||||||
root = api_add_string(root, "USB tmo", details, true);
|
root = api_add_string(root, "USB tmo", details, true);
|
||||||
root = api_add_int(root, "USB cancellations", &cgpu->usb_cancels, false);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
42
cgminer.c
42
cgminer.c
@ -175,6 +175,8 @@ char *opt_usb_select = NULL;
|
|||||||
int opt_usbdump = -1;
|
int opt_usbdump = -1;
|
||||||
bool opt_usb_list_all;
|
bool opt_usb_list_all;
|
||||||
cgsem_t usb_resource_sem;
|
cgsem_t usb_resource_sem;
|
||||||
|
static pthread_t usb_poll_thread;
|
||||||
|
static bool usb_polling;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char *opt_kernel_path;
|
char *opt_kernel_path;
|
||||||
@ -3216,6 +3218,8 @@ static void __kill_work(void)
|
|||||||
/* Release USB resources in case it's a restart
|
/* Release USB resources in case it's a restart
|
||||||
* and not a QUIT */
|
* and not a QUIT */
|
||||||
if (!opt_scrypt) {
|
if (!opt_scrypt) {
|
||||||
|
usb_polling = false;
|
||||||
|
|
||||||
applog(LOG_DEBUG, "Releasing all USB devices");
|
applog(LOG_DEBUG, "Releasing all USB devices");
|
||||||
usb_cleanup();
|
usb_cleanup();
|
||||||
|
|
||||||
@ -5786,10 +5790,9 @@ out:
|
|||||||
|
|
||||||
static void pool_resus(struct pool *pool)
|
static void pool_resus(struct pool *pool)
|
||||||
{
|
{
|
||||||
if (pool_strategy == POOL_FAILOVER && pool->prio < cp_prio()) {
|
if (pool_strategy == POOL_FAILOVER && pool->prio < cp_prio())
|
||||||
applog(LOG_WARNING, "Pool %d %s alive", pool->pool_no, pool->rpc_url);
|
applog(LOG_WARNING, "Pool %d %s alive, testing stability", pool->pool_no, pool->rpc_url);
|
||||||
switch_pools(NULL);
|
else
|
||||||
} else
|
|
||||||
applog(LOG_INFO, "Pool %d %s alive", pool->pool_no, pool->rpc_url);
|
applog(LOG_INFO, "Pool %d %s alive", pool->pool_no, pool->rpc_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6255,7 +6258,8 @@ static void hash_sole_work(struct thr_info *mythr)
|
|||||||
applog(LOG_ERR, "%s %d failure, disabling!", drv->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, drv);
|
cgpu->shutdown = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
hashes_done += hashes;
|
hashes_done += hashes;
|
||||||
@ -6867,7 +6871,20 @@ static void *watchpool_thread(void __maybe_unused *userdata)
|
|||||||
if (pool_active(pool, true) && pool_tclear(pool, &pool->idle))
|
if (pool_active(pool, true) && pool_tclear(pool, &pool->idle))
|
||||||
pool_resus(pool);
|
pool_resus(pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Only switch pools if the failback pool has been
|
||||||
|
* alive for more than 5 minutes to prevent
|
||||||
|
* intermittently failing pools from being used. */
|
||||||
|
if (!pool->idle && pool_strategy == POOL_FAILOVER && pool->prio < cp_prio() &&
|
||||||
|
now.tv_sec - pool->tv_idle.tv_sec > 300) {
|
||||||
|
applog(LOG_WARNING, "Pool %d %s stable for 5 mins",
|
||||||
|
pool->pool_no, pool->rpc_url);
|
||||||
|
switch_pools(NULL);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_pool()->idle)
|
||||||
|
switch_pools(NULL);
|
||||||
|
|
||||||
if (pool_strategy == POOL_ROTATE && now.tv_sec - rotate_tv.tv_sec > 60 * opt_rotate_period) {
|
if (pool_strategy == POOL_ROTATE && now.tv_sec - rotate_tv.tv_sec > 60 * opt_rotate_period) {
|
||||||
cgtime(&rotate_tv);
|
cgtime(&rotate_tv);
|
||||||
@ -7067,6 +7084,9 @@ static void log_print_status(struct cgpu_info *cgpu)
|
|||||||
applog(LOG_WARNING, "%s", logline);
|
applog(LOG_WARNING, "%s", logline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void noop_get_statline(char __maybe_unused *buf, size_t __maybe_unused bufsiz, struct cgpu_info __maybe_unused *cgpu);
|
||||||
|
void blank_get_statline_before(char *buf, size_t bufsiz, struct cgpu_info __maybe_unused *cgpu);
|
||||||
|
|
||||||
void print_summary(void)
|
void print_summary(void)
|
||||||
{
|
{
|
||||||
struct timeval diff;
|
struct timeval diff;
|
||||||
@ -7138,6 +7158,8 @@ void print_summary(void)
|
|||||||
for (i = 0; i < total_devices; ++i) {
|
for (i = 0; i < total_devices; ++i) {
|
||||||
struct cgpu_info *cgpu = get_devices(i);
|
struct cgpu_info *cgpu = get_devices(i);
|
||||||
|
|
||||||
|
cgpu->drv->get_statline_before = &blank_get_statline_before;
|
||||||
|
cgpu->drv->get_statline = &noop_get_statline;
|
||||||
log_print_status(cgpu);
|
log_print_status(cgpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7232,6 +7254,7 @@ static void *test_pool_thread(void *arg)
|
|||||||
applog(LOG_NOTICE, "Switching to pool %d %s - first alive pool", pool->pool_no, pool->rpc_url);
|
applog(LOG_NOTICE, "Switching to pool %d %s - first alive pool", pool->pool_no, pool->rpc_url);
|
||||||
|
|
||||||
pool_resus(pool);
|
pool_resus(pool);
|
||||||
|
switch_pools(NULL);
|
||||||
} else
|
} else
|
||||||
pool_died(pool);
|
pool_died(pool);
|
||||||
|
|
||||||
@ -7728,19 +7751,15 @@ static void probe_pools(void)
|
|||||||
#ifdef USE_USBUTILS
|
#ifdef USE_USBUTILS
|
||||||
static void *libusb_poll_thread(void __maybe_unused *arg)
|
static void *libusb_poll_thread(void __maybe_unused *arg)
|
||||||
{
|
{
|
||||||
struct timeval tv = { 0, USB_ASYNC_POLL * 1000 };
|
|
||||||
|
|
||||||
RenameThread("usbpoll");
|
RenameThread("usbpoll");
|
||||||
|
|
||||||
pthread_detach(pthread_self());
|
pthread_detach(pthread_self());
|
||||||
while (42)
|
while (usb_polling)
|
||||||
libusb_handle_events_timeout(NULL, &tv);
|
libusb_handle_events(NULL);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static pthread_t usb_poll_thread;
|
|
||||||
|
|
||||||
static void initialise_usb(void) {
|
static void initialise_usb(void) {
|
||||||
int err = libusb_init(NULL);
|
int err = libusb_init(NULL);
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -7751,6 +7770,7 @@ static void initialise_usb(void) {
|
|||||||
mutex_init(&cgusb_lock);
|
mutex_init(&cgusb_lock);
|
||||||
mutex_init(&cgusbres_lock);
|
mutex_init(&cgusbres_lock);
|
||||||
cglock_init(&cgusb_fd_lock);
|
cglock_init(&cgusb_fd_lock);
|
||||||
|
usb_polling = true;
|
||||||
pthread_create(&usb_poll_thread, NULL, libusb_poll_thread, NULL);
|
pthread_create(&usb_poll_thread, NULL, libusb_poll_thread, NULL);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -720,6 +720,7 @@ static bool avalon_detect_one(libusb_device *dev, struct usb_find_devices *found
|
|||||||
* all ourselves so set it to std usb type */
|
* all ourselves so set it to std usb type */
|
||||||
avalon->usbdev->usb_type = USB_TYPE_STD;
|
avalon->usbdev->usb_type = USB_TYPE_STD;
|
||||||
usb_set_pps(avalon, AVALON_USB_PACKETSIZE);
|
usb_set_pps(avalon, AVALON_USB_PACKETSIZE);
|
||||||
|
usb_buffer_enable(avalon);
|
||||||
|
|
||||||
/* We have a real Avalon! */
|
/* We have a real Avalon! */
|
||||||
avalon_initialise(avalon);
|
avalon_initialise(avalon);
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
|
|
||||||
/* Wait longer 1/3 longer than it would take for a full nonce range */
|
/* Wait longer 1/3 longer than it would take for a full nonce range */
|
||||||
#define BF1WAIT 1600
|
#define BF1WAIT 1600
|
||||||
|
#define BF1MSGSIZE 7
|
||||||
|
#define BF1INFOSIZE 14
|
||||||
|
|
||||||
static void bitfury_empty_buffer(struct cgpu_info *bitfury)
|
static void bitfury_empty_buffer(struct cgpu_info *bitfury)
|
||||||
{
|
{
|
||||||
@ -26,18 +28,29 @@ static void bitfury_empty_buffer(struct cgpu_info *bitfury)
|
|||||||
} while (amount);
|
} while (amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bitfury_open(struct cgpu_info *bitfury)
|
static int bitfury_open(struct cgpu_info *bitfury)
|
||||||
{
|
{
|
||||||
uint32_t buf[2];
|
uint32_t buf[2];
|
||||||
|
int err;
|
||||||
|
|
||||||
bitfury_empty_buffer(bitfury);
|
bitfury_empty_buffer(bitfury);
|
||||||
/* Magic sequence to reset device only really needed for windows but
|
/* Magic sequence to reset device only really needed for windows but
|
||||||
* harmless on linux. */
|
* harmless on linux. */
|
||||||
buf[0] = 0x80250000;
|
buf[0] = 0x80250000;
|
||||||
buf[1] = 0x00000800;
|
buf[1] = 0x00000800;
|
||||||
usb_transfer(bitfury, 0, 9, 1, 0, C_BF1_RESET);
|
err = usb_transfer(bitfury, 0, 9, 1, 0, C_BF1_RESET);
|
||||||
usb_transfer(bitfury, 0x21, 0x22, 0, 0, C_BF1_OPEN);
|
if (!err)
|
||||||
usb_transfer_data(bitfury, 0x21, 0x20, 0x0000, 0, buf, 7, C_BF1_INIT);
|
err = usb_transfer(bitfury, 0x21, 0x22, 0, 0, C_BF1_OPEN);
|
||||||
|
if (!err) {
|
||||||
|
err = usb_transfer_data(bitfury, 0x21, 0x20, 0x0000, 0, buf,
|
||||||
|
BF1MSGSIZE, C_BF1_INIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err < 0) {
|
||||||
|
applog(LOG_INFO, "%s %d: Failed to open with error %s", bitfury->drv->name,
|
||||||
|
bitfury->device_id, libusb_error_name(err));
|
||||||
|
}
|
||||||
|
return (err == BF1MSGSIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bitfury_close(struct cgpu_info *bitfury)
|
static void bitfury_close(struct cgpu_info *bitfury)
|
||||||
@ -63,15 +76,15 @@ static bool bitfury_getinfo(struct cgpu_info *bitfury, struct bitfury_info *info
|
|||||||
bitfury->drv->name, bitfury->device_id);
|
bitfury->drv->name, bitfury->device_id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
err = usb_read(bitfury, buf, 14, &amount, C_BF1_GETINFO);
|
err = usb_read(bitfury, buf, BF1INFOSIZE, &amount, C_BF1_GETINFO);
|
||||||
if (err) {
|
if (err) {
|
||||||
applog(LOG_INFO, "%s %d: Failed to read GETINFO",
|
applog(LOG_INFO, "%s %d: Failed to read GETINFO",
|
||||||
bitfury->drv->name, bitfury->device_id);
|
bitfury->drv->name, bitfury->device_id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (amount != 14) {
|
if (amount != BF1INFOSIZE) {
|
||||||
applog(LOG_INFO, "%s %d: Getinfo received %d bytes instead of 14",
|
applog(LOG_INFO, "%s %d: Getinfo received %d bytes instead of %d",
|
||||||
bitfury->drv->name, bitfury->device_id, amount);
|
bitfury->drv->name, bitfury->device_id, amount, BF1INFOSIZE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
info->version = buf[1];
|
info->version = buf[1];
|
||||||
@ -95,15 +108,16 @@ static bool bitfury_reset(struct cgpu_info *bitfury)
|
|||||||
bitfury->drv->name, bitfury->device_id);
|
bitfury->drv->name, bitfury->device_id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
err = usb_read_timeout(bitfury, buf, 7, &amount, BF1WAIT, C_BF1_GETRESET);
|
err = usb_read_timeout(bitfury, buf, BF1MSGSIZE, &amount, BF1WAIT,
|
||||||
|
C_BF1_GETRESET);
|
||||||
if (err) {
|
if (err) {
|
||||||
applog(LOG_INFO, "%s %d: Failed to read GETRESET",
|
applog(LOG_INFO, "%s %d: Failed to read GETRESET",
|
||||||
bitfury->drv->name, bitfury->device_id);
|
bitfury->drv->name, bitfury->device_id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (amount != 7) {
|
if (amount != BF1MSGSIZE) {
|
||||||
applog(LOG_INFO, "%s %d: Getreset received %d bytes instead of 7",
|
applog(LOG_INFO, "%s %d: Getreset received %d bytes instead of %d",
|
||||||
bitfury->drv->name, bitfury->device_id, amount);
|
bitfury->drv->name, bitfury->device_id, amount, BF1MSGSIZE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
applog(LOG_DEBUG, "%s %d: Getreset returned %s", bitfury->drv->name,
|
applog(LOG_DEBUG, "%s %d: Getreset returned %s", bitfury->drv->name,
|
||||||
@ -128,10 +142,14 @@ static bool bitfury_detect_one(struct libusb_device *dev, struct usb_find_device
|
|||||||
if (!info)
|
if (!info)
|
||||||
quit(1, "Failed to calloc info in bitfury_detect_one");
|
quit(1, "Failed to calloc info in bitfury_detect_one");
|
||||||
bitfury->device_data = info;
|
bitfury->device_data = info;
|
||||||
|
/* This does not artificially raise hashrate, it simply allows the
|
||||||
|
* hashrate to adapt quickly on starting. */
|
||||||
|
info->total_nonces = 1;
|
||||||
|
|
||||||
usb_buffer_enable(bitfury);
|
usb_buffer_enable(bitfury);
|
||||||
|
|
||||||
bitfury_open(bitfury);
|
if (!bitfury_open(bitfury))
|
||||||
|
goto out_close;
|
||||||
|
|
||||||
/* Send getinfo request */
|
/* Send getinfo request */
|
||||||
if (!bitfury_getinfo(bitfury, info))
|
if (!bitfury_getinfo(bitfury, info))
|
||||||
@ -145,7 +163,7 @@ static bool bitfury_detect_one(struct libusb_device *dev, struct usb_find_device
|
|||||||
bitfury_empty_buffer(bitfury);
|
bitfury_empty_buffer(bitfury);
|
||||||
|
|
||||||
if (!add_cgpu(bitfury))
|
if (!add_cgpu(bitfury))
|
||||||
goto out_close;
|
quit(1, "Failed to add_cgpu in bitfury_detect_one");
|
||||||
|
|
||||||
update_usb_stats(bitfury);
|
update_usb_stats(bitfury);
|
||||||
applog(LOG_INFO, "%s %d: Successfully initialised %s",
|
applog(LOG_INFO, "%s %d: Successfully initialised %s",
|
||||||
@ -208,6 +226,8 @@ static int64_t bitfury_scanhash(struct thr_info *thr, struct work *work,
|
|||||||
struct cgpu_info *bitfury = thr->cgpu;
|
struct cgpu_info *bitfury = thr->cgpu;
|
||||||
struct bitfury_info *info = bitfury->device_data;
|
struct bitfury_info *info = bitfury->device_data;
|
||||||
struct timeval tv_now;
|
struct timeval tv_now;
|
||||||
|
double nonce_rate;
|
||||||
|
int64_t ret = 0;
|
||||||
int amount, i;
|
int amount, i;
|
||||||
char buf[45];
|
char buf[45];
|
||||||
int ms_diff;
|
int ms_diff;
|
||||||
@ -235,7 +255,8 @@ static int64_t bitfury_scanhash(struct thr_info *thr, struct work *work,
|
|||||||
ms_diff = BF1WAIT - ms_tdiff(&tv_now, &info->tv_start);
|
ms_diff = BF1WAIT - ms_tdiff(&tv_now, &info->tv_start);
|
||||||
if (unlikely(ms_diff < 10))
|
if (unlikely(ms_diff < 10))
|
||||||
ms_diff = 10;
|
ms_diff = 10;
|
||||||
usb_read_once_timeout(bitfury, info->buf + info->tot, 7, &amount, ms_diff, C_BF1_GETRES);
|
usb_read_once_timeout(bitfury, info->buf + info->tot, BF1MSGSIZE,
|
||||||
|
&amount, ms_diff, C_BF1_GETRES);
|
||||||
info->tot += amount;
|
info->tot += amount;
|
||||||
while (amount) {
|
while (amount) {
|
||||||
usb_read_once_timeout(bitfury, info->buf + info->tot, 512, &amount, 10, C_BF1_GETRES);
|
usb_read_once_timeout(bitfury, info->buf + info->tot, 512, &amount, 10, C_BF1_GETRES);
|
||||||
@ -249,7 +270,7 @@ static int64_t bitfury_scanhash(struct thr_info *thr, struct work *work,
|
|||||||
usb_write(bitfury, buf, 45, &amount, C_BF1_REQWORK);
|
usb_write(bitfury, buf, 45, &amount, C_BF1_REQWORK);
|
||||||
cgtime(&info->tv_start);
|
cgtime(&info->tv_start);
|
||||||
/* Get response acknowledging work */
|
/* Get response acknowledging work */
|
||||||
usb_read(bitfury, buf, 7, &amount, C_BF1_GETWORK);
|
usb_read(bitfury, buf, BF1MSGSIZE, &amount, C_BF1_GETWORK);
|
||||||
|
|
||||||
/* Only happens on startup */
|
/* Only happens on startup */
|
||||||
if (unlikely(!info->prevwork[BF1ARRAY_SIZE]))
|
if (unlikely(!info->prevwork[BF1ARRAY_SIZE]))
|
||||||
@ -257,7 +278,7 @@ static int64_t bitfury_scanhash(struct thr_info *thr, struct work *work,
|
|||||||
|
|
||||||
/* Search for what work the nonce matches in order of likelihood. Last
|
/* Search for what work the nonce matches in order of likelihood. Last
|
||||||
* entry is end of result marker. */
|
* entry is end of result marker. */
|
||||||
for (i = 0; i < info->tot - 7; i += 7) {
|
for (i = 0; i < info->tot - BF1MSGSIZE; i += BF1MSGSIZE) {
|
||||||
uint32_t nonce;
|
uint32_t nonce;
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
@ -279,23 +300,30 @@ cascade:
|
|||||||
info->prevwork[i] = info->prevwork[i - 1];
|
info->prevwork[i] = info->prevwork[i - 1];
|
||||||
info->prevwork[0] = copy_work(work);
|
info->prevwork[0] = copy_work(work);
|
||||||
work->blk.nonce = 0xffffffff;
|
work->blk.nonce = 0xffffffff;
|
||||||
if (info->nonces) {
|
|
||||||
info->nonces--;
|
info->cycles++;
|
||||||
return (int64_t)0xffffffff;
|
info->total_nonces += info->nonces;
|
||||||
|
info->saved_nonces += info->nonces;
|
||||||
|
info->nonces = 0;
|
||||||
|
nonce_rate = (double)info->total_nonces / (double)info->cycles;
|
||||||
|
if (info->saved_nonces >= nonce_rate) {
|
||||||
|
info->saved_nonces -= nonce_rate;
|
||||||
|
ret = (double)0xffffffff * nonce_rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(bitfury->usbinfo.nodev)) {
|
if (unlikely(bitfury->usbinfo.nodev)) {
|
||||||
applog(LOG_WARNING, "%s %d: Device disappeared, disabling thread",
|
applog(LOG_WARNING, "%s %d: Device disappeared, disabling thread",
|
||||||
bitfury->drv->name, bitfury->device_id);
|
bitfury->drv->name, bitfury->device_id);
|
||||||
return -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct api_data *bitfury_api_stats(struct cgpu_info *cgpu)
|
static struct api_data *bitfury_api_stats(struct cgpu_info *cgpu)
|
||||||
{
|
{
|
||||||
struct bitfury_info *info = cgpu->device_data;
|
struct bitfury_info *info = cgpu->device_data;
|
||||||
struct api_data *root = NULL;
|
struct api_data *root = NULL;
|
||||||
|
double nonce_rate;
|
||||||
char serial[16];
|
char serial[16];
|
||||||
int version;
|
int version;
|
||||||
|
|
||||||
@ -304,6 +332,8 @@ static struct api_data *bitfury_api_stats(struct cgpu_info *cgpu)
|
|||||||
root = api_add_string(root, "Product", info->product, false);
|
root = api_add_string(root, "Product", info->product, false);
|
||||||
sprintf(serial, "%08x", info->serial);
|
sprintf(serial, "%08x", info->serial);
|
||||||
root = api_add_string(root, "Serial", serial, true);
|
root = api_add_string(root, "Serial", serial, true);
|
||||||
|
nonce_rate = (double)info->total_nonces / (double)info->cycles;
|
||||||
|
root = api_add_double(root, "NonceRate", &nonce_rate, true);
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,9 @@ struct bitfury_info {
|
|||||||
char buf[512];
|
char buf[512];
|
||||||
int tot;
|
int tot;
|
||||||
int nonces;
|
int nonces;
|
||||||
|
int total_nonces;
|
||||||
|
double saved_nonces;
|
||||||
|
int cycles;
|
||||||
struct timeval tv_start;
|
struct timeval tv_start;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
229
driver-icarus.c
229
driver-icarus.c
@ -108,6 +108,8 @@ ASSERT1(sizeof(uint32_t) == 4);
|
|||||||
#define CAIRNSMORE2_HASH_TIME 0.0000000066600
|
#define CAIRNSMORE2_HASH_TIME 0.0000000066600
|
||||||
#define NANOSEC 1000000000.0
|
#define NANOSEC 1000000000.0
|
||||||
|
|
||||||
|
#define CAIRNSMORE2_INTS 4
|
||||||
|
|
||||||
// Icarus Rev3 doesn't send a completion message when it finishes
|
// Icarus Rev3 doesn't send a completion message when it finishes
|
||||||
// the full nonce range, so to avoid being idle we must abort the
|
// the full nonce range, so to avoid being idle we must abort the
|
||||||
// work (by starting a new work item) shortly before it finishes
|
// work (by starting a new work item) shortly before it finishes
|
||||||
@ -178,6 +180,7 @@ static const char *MODE_VALUE_STR = "value";
|
|||||||
static const char *MODE_UNKNOWN_STR = "unknown";
|
static const char *MODE_UNKNOWN_STR = "unknown";
|
||||||
|
|
||||||
struct ICARUS_INFO {
|
struct ICARUS_INFO {
|
||||||
|
enum sub_ident ident;
|
||||||
int intinfo;
|
int intinfo;
|
||||||
|
|
||||||
// time to calculate the golden_ob
|
// time to calculate the golden_ob
|
||||||
@ -216,17 +219,43 @@ struct ICARUS_INFO {
|
|||||||
int fpga_count;
|
int fpga_count;
|
||||||
uint32_t nonce_mask;
|
uint32_t nonce_mask;
|
||||||
|
|
||||||
bool initialised;
|
uint8_t cmr2_speed;
|
||||||
|
bool speed_next_work;
|
||||||
|
bool flash_next_work;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ICARUS_MIDSTATE_SIZE 32
|
#define ICARUS_MIDSTATE_SIZE 32
|
||||||
#define ICARUS_UNUSED_SIZE 20
|
#define ICARUS_UNUSED_SIZE 16
|
||||||
#define ICARUS_WORK_SIZE 12
|
#define ICARUS_WORK_SIZE 12
|
||||||
|
|
||||||
#define ICARUS_WORK_DATA_OFFSET 64
|
#define ICARUS_WORK_DATA_OFFSET 64
|
||||||
|
|
||||||
|
#define ICARUS_CMR2_SPEED_FACTOR 2.5
|
||||||
|
#define ICARUS_CMR2_SPEED_MIN_INT 100
|
||||||
|
#define ICARUS_CMR2_SPEED_DEF_INT 180
|
||||||
|
#define ICARUS_CMR2_SPEED_MAX_INT 220
|
||||||
|
#define CMR2_INT_TO_SPEED(_speed) ((uint8_t)((float)_speed / ICARUS_CMR2_SPEED_FACTOR))
|
||||||
|
#define ICARUS_CMR2_SPEED_MIN CMR2_INT_TO_SPEED(ICARUS_CMR2_SPEED_MIN_INT)
|
||||||
|
#define ICARUS_CMR2_SPEED_DEF CMR2_INT_TO_SPEED(ICARUS_CMR2_SPEED_DEF_INT)
|
||||||
|
#define ICARUS_CMR2_SPEED_MAX CMR2_INT_TO_SPEED(ICARUS_CMR2_SPEED_MAX_INT)
|
||||||
|
#define ICARUS_CMR2_SPEED_INC 1
|
||||||
|
#define ICARUS_CMR2_SPEED_DEC -1
|
||||||
|
#define ICARUS_CMR2_SPEED_FAIL -10
|
||||||
|
|
||||||
|
#define ICARUS_CMR2_PREFIX ((uint8_t)0xB7)
|
||||||
|
#define ICARUS_CMR2_CMD_SPEED ((uint8_t)0)
|
||||||
|
#define ICARUS_CMR2_CMD_FLASH ((uint8_t)1)
|
||||||
|
#define ICARUS_CMR2_DATA_FLASH_OFF ((uint8_t)0)
|
||||||
|
#define ICARUS_CMR2_DATA_FLASH_ON ((uint8_t)1)
|
||||||
|
#define ICARUS_CMR2_CHECK ((uint8_t)0x6D)
|
||||||
|
|
||||||
struct ICARUS_WORK {
|
struct ICARUS_WORK {
|
||||||
uint8_t midstate[ICARUS_MIDSTATE_SIZE];
|
uint8_t midstate[ICARUS_MIDSTATE_SIZE];
|
||||||
|
// These 4 bytes are for CMR2 bitstreams that handle MHz adjustment
|
||||||
|
uint8_t check;
|
||||||
|
uint8_t data;
|
||||||
|
uint8_t cmd;
|
||||||
|
uint8_t prefix;
|
||||||
uint8_t unused[ICARUS_UNUSED_SIZE];
|
uint8_t unused[ICARUS_UNUSED_SIZE];
|
||||||
uint8_t work[ICARUS_WORK_SIZE];
|
uint8_t work[ICARUS_WORK_SIZE];
|
||||||
};
|
};
|
||||||
@ -423,8 +452,6 @@ static void icarus_initialise(struct cgpu_info *icarus, int baud)
|
|||||||
quit(1, "icarus_intialise() called with invalid %s cgid %i ident=%d",
|
quit(1, "icarus_intialise() called with invalid %s cgid %i ident=%d",
|
||||||
icarus->drv->name, icarus->cgminer_id, ident);
|
icarus->drv->name, icarus->cgminer_id, ident);
|
||||||
}
|
}
|
||||||
|
|
||||||
info->initialised = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rev(unsigned char *s, size_t l)
|
static void rev(unsigned char *s, size_t l)
|
||||||
@ -820,9 +847,10 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
|
|||||||
char *nonce_hex;
|
char *nonce_hex;
|
||||||
int baud, uninitialised_var(work_division), uninitialised_var(fpga_count);
|
int baud, uninitialised_var(work_division), uninitialised_var(fpga_count);
|
||||||
struct cgpu_info *icarus;
|
struct cgpu_info *icarus;
|
||||||
int ret, err, amount, tries;
|
int ret, err, amount, tries, i;
|
||||||
enum sub_ident ident;
|
|
||||||
bool ok;
|
bool ok;
|
||||||
|
bool cmr2_ok[CAIRNSMORE2_INTS];
|
||||||
|
int cmr2_count;
|
||||||
|
|
||||||
if ((sizeof(workdata) << 1) != (sizeof(golden_ob) - 1))
|
if ((sizeof(workdata) << 1) != (sizeof(golden_ob) - 1))
|
||||||
quithere(1, "Data and golden_ob sizes don't match");
|
quithere(1, "Data and golden_ob sizes don't match");
|
||||||
@ -843,8 +871,8 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
|
|||||||
quit(1, "Failed to malloc ICARUS_INFO");
|
quit(1, "Failed to malloc ICARUS_INFO");
|
||||||
icarus->device_data = (void *)info;
|
icarus->device_data = (void *)info;
|
||||||
|
|
||||||
ident = usb_ident(icarus);
|
info->ident = usb_ident(icarus);
|
||||||
switch (ident) {
|
switch (info->ident) {
|
||||||
case IDENT_ICA:
|
case IDENT_ICA:
|
||||||
case IDENT_BLT:
|
case IDENT_BLT:
|
||||||
case IDENT_LLT:
|
case IDENT_LLT:
|
||||||
@ -853,19 +881,32 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
|
|||||||
info->timeout = ICARUS_WAIT_TIMEOUT;
|
info->timeout = ICARUS_WAIT_TIMEOUT;
|
||||||
break;
|
break;
|
||||||
case IDENT_CMR2:
|
case IDENT_CMR2:
|
||||||
|
if (found->intinfo_count != CAIRNSMORE2_INTS) {
|
||||||
|
quithere(1, "CMR2 Interface count (%d) isn't expected: %d",
|
||||||
|
found->intinfo_count,
|
||||||
|
CAIRNSMORE2_INTS);
|
||||||
|
}
|
||||||
info->timeout = ICARUS_CMR2_TIMEOUT;
|
info->timeout = ICARUS_CMR2_TIMEOUT;
|
||||||
|
cmr2_count = 0;
|
||||||
|
for (i = 0; i < CAIRNSMORE2_INTS; i++)
|
||||||
|
cmr2_ok[i] = false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
quit(1, "%s icarus_detect_one() invalid %s ident=%d",
|
quit(1, "%s icarus_detect_one() invalid %s ident=%d",
|
||||||
icarus->drv->dname, icarus->drv->dname, ident);
|
icarus->drv->dname, icarus->drv->dname, info->ident);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For CMR2 test each USB Interface
|
||||||
|
|
||||||
|
cmr2_retry:
|
||||||
|
|
||||||
tries = 2;
|
tries = 2;
|
||||||
ok = false;
|
ok = false;
|
||||||
while (!ok && tries-- > 0) {
|
while (!ok && tries-- > 0) {
|
||||||
icarus_initialise(icarus, baud);
|
icarus_initialise(icarus, baud);
|
||||||
|
|
||||||
err = usb_write(icarus, (void *)(&workdata), sizeof(workdata), &amount, C_SENDTESTWORK);
|
err = usb_write_ii(icarus, info->intinfo,
|
||||||
|
(char *)(&workdata), sizeof(workdata), &amount, C_SENDWORK);
|
||||||
|
|
||||||
if (err != LIBUSB_SUCCESS || amount != sizeof(workdata))
|
if (err != LIBUSB_SUCCESS || amount != sizeof(workdata))
|
||||||
continue;
|
continue;
|
||||||
@ -879,7 +920,7 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
|
|||||||
if (strncmp(nonce_hex, golden_nonce, 8) == 0)
|
if (strncmp(nonce_hex, golden_nonce, 8) == 0)
|
||||||
ok = true;
|
ok = true;
|
||||||
else {
|
else {
|
||||||
if (tries < 0) {
|
if (tries < 0 && info->ident != IDENT_CMR2) {
|
||||||
applog(LOG_ERR,
|
applog(LOG_ERR,
|
||||||
"Icarus Detect: "
|
"Icarus Detect: "
|
||||||
"Test failed at %s: get %s, should: %s",
|
"Test failed at %s: get %s, should: %s",
|
||||||
@ -889,13 +930,50 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
|
|||||||
free(nonce_hex);
|
free(nonce_hex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ok)
|
if (!ok) {
|
||||||
|
if (info->ident != IDENT_CMR2)
|
||||||
goto unshin;
|
goto unshin;
|
||||||
|
|
||||||
|
if (info->intinfo < CAIRNSMORE2_INTS-1) {
|
||||||
|
info->intinfo++;
|
||||||
|
goto cmr2_retry;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (info->ident == IDENT_CMR2) {
|
||||||
|
applog(LOG_DEBUG,
|
||||||
|
"Icarus Detect: "
|
||||||
|
"Test succeeded at %s i%d: got %s",
|
||||||
|
icarus->device_path, info->intinfo, golden_nonce);
|
||||||
|
|
||||||
|
cmr2_ok[info->intinfo] = true;
|
||||||
|
cmr2_count++;
|
||||||
|
if (info->intinfo < CAIRNSMORE2_INTS-1) {
|
||||||
|
info->intinfo++;
|
||||||
|
goto cmr2_retry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->ident == IDENT_CMR2) {
|
||||||
|
if (cmr2_count == 0) {
|
||||||
|
applog(LOG_ERR,
|
||||||
|
"Icarus Detect: Test failed at %s: for all %d CMR2 Interfaces",
|
||||||
|
icarus->device_path, CAIRNSMORE2_INTS);
|
||||||
|
goto unshin;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the interface to the first one that succeeded
|
||||||
|
for (i = 0; i < CAIRNSMORE2_INTS; i++)
|
||||||
|
if (cmr2_ok[i]) {
|
||||||
|
info->intinfo = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
applog(LOG_DEBUG,
|
applog(LOG_DEBUG,
|
||||||
"Icarus Detect: "
|
"Icarus Detect: "
|
||||||
"Test succeeded at %s: got %s",
|
"Test succeeded at %s: got %s",
|
||||||
icarus->device_path, golden_nonce);
|
icarus->device_path, golden_nonce);
|
||||||
|
}
|
||||||
|
|
||||||
/* We have a real Icarus! */
|
/* We have a real Icarus! */
|
||||||
if (!add_cgpu(icarus))
|
if (!add_cgpu(icarus))
|
||||||
@ -906,6 +984,18 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
|
|||||||
applog(LOG_INFO, "%s%d: Found at %s",
|
applog(LOG_INFO, "%s%d: Found at %s",
|
||||||
icarus->drv->name, icarus->device_id, icarus->device_path);
|
icarus->drv->name, icarus->device_id, icarus->device_path);
|
||||||
|
|
||||||
|
if (info->ident == IDENT_CMR2) {
|
||||||
|
applog(LOG_INFO, "%s%d: with %d Interface%s",
|
||||||
|
icarus->drv->name, icarus->device_id,
|
||||||
|
cmr2_count, cmr2_count > 1 ? "s" : "");
|
||||||
|
|
||||||
|
// Assume 1 or 2 are running FPGA pairs
|
||||||
|
if (cmr2_count < 3) {
|
||||||
|
work_division = fpga_count = 2;
|
||||||
|
info->Hs /= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
applog(LOG_DEBUG, "%s%d: Init baud=%d work_division=%d fpga_count=%d",
|
applog(LOG_DEBUG, "%s%d: Init baud=%d work_division=%d fpga_count=%d",
|
||||||
icarus->drv->name, icarus->device_id, baud, work_division, fpga_count);
|
icarus->drv->name, icarus->device_id, baud, work_division, fpga_count);
|
||||||
|
|
||||||
@ -919,12 +1009,15 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
|
|||||||
|
|
||||||
set_timing_mode(this_option_offset, icarus);
|
set_timing_mode(this_option_offset, icarus);
|
||||||
|
|
||||||
if (usb_ident(icarus) == IDENT_CMR2) {
|
if (info->ident == IDENT_CMR2) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 1; i < icarus->usbdev->found->intinfo_count; i++) {
|
for (i = info->intinfo + 1; i < icarus->usbdev->found->intinfo_count; i++) {
|
||||||
struct cgpu_info *cgtmp;
|
struct cgpu_info *cgtmp;
|
||||||
struct ICARUS_INFO *intmp;
|
struct ICARUS_INFO *intmp;
|
||||||
|
|
||||||
|
if (!cmr2_ok[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
cgtmp = usb_copy_cgpu(icarus);
|
cgtmp = usb_copy_cgpu(icarus);
|
||||||
if (!cgtmp) {
|
if (!cgtmp) {
|
||||||
applog(LOG_ERR, "%s%d: Init failed initinfo %d",
|
applog(LOG_ERR, "%s%d: Init failed initinfo %d",
|
||||||
@ -984,6 +1077,45 @@ static bool icarus_prepare(__maybe_unused struct thr_info *thr)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cmr2_command(struct cgpu_info *icarus, uint8_t cmd, uint8_t data)
|
||||||
|
{
|
||||||
|
struct ICARUS_INFO *info = (struct ICARUS_INFO *)(icarus->device_data);
|
||||||
|
struct ICARUS_WORK workdata;
|
||||||
|
int amount;
|
||||||
|
|
||||||
|
memset((void *)(&workdata), 0, sizeof(workdata));
|
||||||
|
|
||||||
|
workdata.prefix = ICARUS_CMR2_PREFIX;
|
||||||
|
workdata.cmd = cmd;
|
||||||
|
workdata.data = data;
|
||||||
|
workdata.check = workdata.data ^ workdata.cmd ^ workdata.prefix ^ ICARUS_CMR2_CHECK;
|
||||||
|
|
||||||
|
usb_write_ii(icarus, info->intinfo, (char *)(&workdata), sizeof(workdata), &amount, C_SENDWORK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmr2_commands(struct cgpu_info *icarus)
|
||||||
|
{
|
||||||
|
struct ICARUS_INFO *info = (struct ICARUS_INFO *)(icarus->device_data);
|
||||||
|
|
||||||
|
if (info->speed_next_work) {
|
||||||
|
info->speed_next_work = false;
|
||||||
|
cmr2_command(icarus, ICARUS_CMR2_CMD_SPEED, info->cmr2_speed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->flash_next_work) {
|
||||||
|
info->flash_next_work = false;
|
||||||
|
cmr2_command(icarus, ICARUS_CMR2_CMD_FLASH, ICARUS_CMR2_DATA_FLASH_ON);
|
||||||
|
cgsleep_ms(250);
|
||||||
|
cmr2_command(icarus, ICARUS_CMR2_CMD_FLASH, ICARUS_CMR2_DATA_FLASH_OFF);
|
||||||
|
cgsleep_ms(250);
|
||||||
|
cmr2_command(icarus, ICARUS_CMR2_CMD_FLASH, ICARUS_CMR2_DATA_FLASH_ON);
|
||||||
|
cgsleep_ms(250);
|
||||||
|
cmr2_command(icarus, ICARUS_CMR2_CMD_FLASH, ICARUS_CMR2_DATA_FLASH_OFF);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
|
static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
|
||||||
__maybe_unused int64_t max_nonce)
|
__maybe_unused int64_t max_nonce)
|
||||||
{
|
{
|
||||||
@ -1014,9 +1146,6 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
|
|||||||
if (icarus->usbinfo.nodev)
|
if (icarus->usbinfo.nodev)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (!info->initialised)
|
|
||||||
icarus_initialise(icarus, info->baud);
|
|
||||||
|
|
||||||
elapsed.tv_sec = elapsed.tv_usec = 0;
|
elapsed.tv_sec = elapsed.tv_usec = 0;
|
||||||
|
|
||||||
memset((void *)(&workdata), 0, sizeof(workdata));
|
memset((void *)(&workdata), 0, sizeof(workdata));
|
||||||
@ -1025,6 +1154,9 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
|
|||||||
rev((void *)(&(workdata.midstate)), ICARUS_MIDSTATE_SIZE);
|
rev((void *)(&(workdata.midstate)), ICARUS_MIDSTATE_SIZE);
|
||||||
rev((void *)(&(workdata.work)), ICARUS_WORK_SIZE);
|
rev((void *)(&(workdata.work)), ICARUS_WORK_SIZE);
|
||||||
|
|
||||||
|
if (info->speed_next_work || info->flash_next_work)
|
||||||
|
cmr2_commands(icarus);
|
||||||
|
|
||||||
// We only want results for the work we are about to send
|
// We only want results for the work we are about to send
|
||||||
usb_buffer_clear(icarus);
|
usb_buffer_clear(icarus);
|
||||||
|
|
||||||
@ -1245,17 +1377,80 @@ static struct api_data *icarus_api_stats(struct cgpu_info *cgpu)
|
|||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void icarus_statline_before(char *buf, size_t bufsiz, struct cgpu_info *cgpu)
|
||||||
|
{
|
||||||
|
struct ICARUS_INFO *info = (struct ICARUS_INFO *)(cgpu->device_data);
|
||||||
|
|
||||||
|
if (info->ident == IDENT_CMR2 && info->cmr2_speed > 0)
|
||||||
|
tailsprintf(buf, bufsiz, "%5.1fMhz", (float)(info->cmr2_speed) * ICARUS_CMR2_SPEED_FACTOR);
|
||||||
|
else
|
||||||
|
tailsprintf(buf, bufsiz, " ");
|
||||||
|
|
||||||
|
tailsprintf(buf, bufsiz, " | ");
|
||||||
|
}
|
||||||
|
|
||||||
static void icarus_shutdown(__maybe_unused struct thr_info *thr)
|
static void icarus_shutdown(__maybe_unused struct thr_info *thr)
|
||||||
{
|
{
|
||||||
// TODO: ?
|
// TODO: ?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void icarus_identify(struct cgpu_info *cgpu)
|
||||||
|
{
|
||||||
|
struct ICARUS_INFO *info = (struct ICARUS_INFO *)(cgpu->device_data);
|
||||||
|
|
||||||
|
if (info->ident == IDENT_CMR2)
|
||||||
|
info->flash_next_work = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *icarus_set(struct cgpu_info *cgpu, char *option, char *setting, char *replybuf)
|
||||||
|
{
|
||||||
|
struct ICARUS_INFO *info = (struct ICARUS_INFO *)(cgpu->device_data);
|
||||||
|
int val;
|
||||||
|
|
||||||
|
if (info->ident != IDENT_CMR2) {
|
||||||
|
strcpy(replybuf, "no set options available");
|
||||||
|
return replybuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcasecmp(option, "help") == 0) {
|
||||||
|
sprintf(replybuf, "clock: range %d-%d",
|
||||||
|
ICARUS_CMR2_SPEED_MIN_INT, ICARUS_CMR2_SPEED_MAX_INT);
|
||||||
|
return replybuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcasecmp(option, "clock") == 0) {
|
||||||
|
if (!setting || !*setting) {
|
||||||
|
sprintf(replybuf, "missing clock setting");
|
||||||
|
return replybuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = atoi(setting);
|
||||||
|
if (val < ICARUS_CMR2_SPEED_MIN_INT || val > ICARUS_CMR2_SPEED_MAX_INT) {
|
||||||
|
sprintf(replybuf, "invalid clock: '%s' valid range %d-%d",
|
||||||
|
setting,
|
||||||
|
ICARUS_CMR2_SPEED_MIN_INT,
|
||||||
|
ICARUS_CMR2_SPEED_MAX_INT);
|
||||||
|
}
|
||||||
|
|
||||||
|
info->cmr2_speed = CMR2_INT_TO_SPEED(val);
|
||||||
|
info->speed_next_work = true;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(replybuf, "Unknown option: %s", option);
|
||||||
|
return replybuf;
|
||||||
|
}
|
||||||
|
|
||||||
struct device_drv icarus_drv = {
|
struct device_drv icarus_drv = {
|
||||||
.drv_id = DRIVER_icarus,
|
.drv_id = DRIVER_icarus,
|
||||||
.dname = "Icarus",
|
.dname = "Icarus",
|
||||||
.name = "ICA",
|
.name = "ICA",
|
||||||
.drv_detect = icarus_detect,
|
.drv_detect = icarus_detect,
|
||||||
.get_api_stats = icarus_api_stats,
|
.get_api_stats = icarus_api_stats,
|
||||||
|
.get_statline_before = icarus_statline_before,
|
||||||
|
.set_device = icarus_set,
|
||||||
|
.identify_device = icarus_identify,
|
||||||
.thread_prepare = icarus_prepare,
|
.thread_prepare = icarus_prepare,
|
||||||
.scanhash = icarus_scanhash,
|
.scanhash = icarus_scanhash,
|
||||||
.thread_shutdown = icarus_shutdown,
|
.thread_shutdown = icarus_shutdown,
|
||||||
|
9
miner.h
9
miner.h
@ -472,7 +472,6 @@ struct cgpu_info {
|
|||||||
#endif
|
#endif
|
||||||
#ifdef USE_USBUTILS
|
#ifdef USE_USBUTILS
|
||||||
struct cg_usb_info usbinfo;
|
struct cg_usb_info usbinfo;
|
||||||
int usb_cancels;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_MODMINER
|
#ifdef USE_MODMINER
|
||||||
char fpgaid;
|
char fpgaid;
|
||||||
@ -881,6 +880,14 @@ static inline void cg_runlock(cglock_t *lock)
|
|||||||
rd_unlock(&lock->rwlock);
|
rd_unlock(&lock->rwlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This drops the read lock and grabs a write lock. It does NOT protect data
|
||||||
|
* between the two locks! */
|
||||||
|
static inline void cg_ruwlock(cglock_t *lock)
|
||||||
|
{
|
||||||
|
rd_unlock_noyield(&lock->rwlock);
|
||||||
|
cg_wlock(lock);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void cg_wunlock(cglock_t *lock)
|
static inline void cg_wunlock(cglock_t *lock)
|
||||||
{
|
{
|
||||||
wr_unlock_noyield(&lock->rwlock);
|
wr_unlock_noyield(&lock->rwlock);
|
||||||
|
85
usbutils.c
85
usbutils.c
@ -1300,12 +1300,11 @@ static void release_cgpu(struct cgpu_info *cgpu)
|
|||||||
{
|
{
|
||||||
struct cg_usb_device *cgusb = cgpu->usbdev;
|
struct cg_usb_device *cgusb = cgpu->usbdev;
|
||||||
struct cgpu_info *lookcgpu;
|
struct cgpu_info *lookcgpu;
|
||||||
int i, pstate;
|
int i;
|
||||||
|
|
||||||
DEVWLOCK(cgpu, pstate);
|
|
||||||
// It has already been done
|
// It has already been done
|
||||||
if (cgpu->usbinfo.nodev)
|
if (cgpu->usbinfo.nodev)
|
||||||
goto out_unlock;
|
return;
|
||||||
|
|
||||||
applog(LOG_DEBUG, "USB release %s%i",
|
applog(LOG_DEBUG, "USB release %s%i",
|
||||||
cgpu->drv->name, cgpu->device_id);
|
cgpu->drv->name, cgpu->device_id);
|
||||||
@ -1335,8 +1334,6 @@ static void release_cgpu(struct cgpu_info *cgpu)
|
|||||||
|
|
||||||
_usb_uninit(cgpu);
|
_usb_uninit(cgpu);
|
||||||
cgminer_usb_unlock_bd(cgpu->drv, cgpu->usbinfo.bus_number, cgpu->usbinfo.device_address);
|
cgminer_usb_unlock_bd(cgpu->drv, cgpu->usbinfo.bus_number, cgpu->usbinfo.device_address);
|
||||||
out_unlock:
|
|
||||||
DEVWUNLOCK(cgpu, pstate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2125,7 +2122,6 @@ static void stats(struct cgpu_info *cgpu, struct timeval *tv_start, struct timev
|
|||||||
case LIBUSB_SUCCESS:
|
case LIBUSB_SUCCESS:
|
||||||
item = CMD_CMD;
|
item = CMD_CMD;
|
||||||
break;
|
break;
|
||||||
case LIBUSB_TRANSFER_TIMED_OUT:
|
|
||||||
case LIBUSB_ERROR_TIMEOUT:
|
case LIBUSB_ERROR_TIMEOUT:
|
||||||
item = CMD_TIMEOUT;
|
item = CMD_TIMEOUT;
|
||||||
break;
|
break;
|
||||||
@ -2222,8 +2218,7 @@ static void LIBUSB_CALL bulk_callback(struct libusb_transfer *transfer)
|
|||||||
|
|
||||||
/* Wait for callback function to tell us it has finished the USB transfer, but
|
/* Wait for callback function to tell us it has finished the USB transfer, but
|
||||||
* use our own timer to cancel the request if we go beyond the timeout. */
|
* use our own timer to cancel the request if we go beyond the timeout. */
|
||||||
static int callback_wait(struct cgpu_info *cgpu, struct usb_transfer *ut, int *transferred,
|
static int callback_wait(struct usb_transfer *ut, int *transferred, unsigned int timeout)
|
||||||
unsigned int timeout)
|
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer= ut->transfer;
|
struct libusb_transfer *transfer= ut->transfer;
|
||||||
struct timespec ts_now, ts_end;
|
struct timespec ts_now, ts_end;
|
||||||
@ -2231,28 +2226,21 @@ static int callback_wait(struct cgpu_info *cgpu, struct usb_transfer *ut, int *t
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
cgtime(&tv_now);
|
cgtime(&tv_now);
|
||||||
timeout = timeout + USB_ASYNC_POLL;
|
|
||||||
ms_to_timespec(&ts_end, timeout);
|
ms_to_timespec(&ts_end, timeout);
|
||||||
timeval_to_spec(&ts_now, &tv_now);
|
timeval_to_spec(&ts_now, &tv_now);
|
||||||
timeraddspec(&ts_end, &ts_now);
|
timeraddspec(&ts_end, &ts_now);
|
||||||
ret = pthread_cond_timedwait(&ut->cond, &ut->mutex, &ts_end);
|
ret = pthread_cond_timedwait(&ut->cond, &ut->mutex, &ts_end);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
/* Assume that if we timed out on the conditional then the
|
/* We are emulating a timeout ourself here */
|
||||||
* transfer has stalled for some reason and attempt to clear
|
|
||||||
* a halt as a solution. Then cancel the transaction, treating
|
|
||||||
* it the same as a timeout. */
|
|
||||||
libusb_clear_halt(transfer->dev_handle, transfer->endpoint);
|
|
||||||
libusb_cancel_transfer(transfer);
|
libusb_cancel_transfer(transfer);
|
||||||
applog(LOG_DEBUG, "%s%i: libusb cancelling async bulk transfer",
|
|
||||||
cgpu->drv->name, cgpu->device_id);
|
|
||||||
cgpu->usb_cancels++;
|
|
||||||
|
|
||||||
/* Now wait for the callback function to be invoked. */
|
/* Now wait for the callback function to be invoked. */
|
||||||
pthread_cond_wait(&ut->cond, &ut->mutex);
|
pthread_cond_wait(&ut->cond, &ut->mutex);
|
||||||
/* Fake the timed out message since it's effectively that */
|
}
|
||||||
ret = LIBUSB_TRANSFER_TIMED_OUT;
|
|
||||||
} else
|
|
||||||
ret = transfer->status;
|
ret = transfer->status;
|
||||||
|
if (ret == LIBUSB_TRANSFER_CANCELLED)
|
||||||
|
ret = LIBUSB_TRANSFER_TIMED_OUT;
|
||||||
|
|
||||||
/* No need to sort out mutexes here since they won't be reused */
|
/* No need to sort out mutexes here since they won't be reused */
|
||||||
*transferred = transfer->actual_length;
|
*transferred = transfer->actual_length;
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
@ -2295,8 +2283,9 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo,
|
|||||||
|
|
||||||
init_usb_transfer(&ut);
|
init_usb_transfer(&ut);
|
||||||
mutex_lock(&ut.mutex);
|
mutex_lock(&ut.mutex);
|
||||||
|
/* We give the transfer no timeout since we manage timeouts ourself */
|
||||||
libusb_fill_bulk_transfer(ut.transfer, dev_handle, endpoint, buf, length,
|
libusb_fill_bulk_transfer(ut.transfer, dev_handle, endpoint, buf, length,
|
||||||
bulk_callback, &ut, timeout);
|
bulk_callback, &ut, 0);
|
||||||
|
|
||||||
STATS_TIMEVAL(&tv_start);
|
STATS_TIMEVAL(&tv_start);
|
||||||
cg_rlock(&cgusb_fd_lock);
|
cg_rlock(&cgusb_fd_lock);
|
||||||
@ -2304,7 +2293,7 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo,
|
|||||||
cg_runlock(&cgusb_fd_lock);
|
cg_runlock(&cgusb_fd_lock);
|
||||||
errn = errno;
|
errn = errno;
|
||||||
if (!err)
|
if (!err)
|
||||||
err = callback_wait(cgpu, &ut, transferred, timeout);
|
err = callback_wait(&ut, transferred, timeout);
|
||||||
|
|
||||||
STATS_TIMEVAL(&tv_finish);
|
STATS_TIMEVAL(&tv_finish);
|
||||||
USB_STATS(cgpu, &tv_start, &tv_finish, err, mode, cmd, seq, timeout);
|
USB_STATS(cgpu, &tv_start, &tv_finish, err, mode, cmd, seq, timeout);
|
||||||
@ -2315,6 +2304,9 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo,
|
|||||||
usb_cmdname(cmd), *transferred, err, errn);
|
usb_cmdname(cmd), *transferred, err, errn);
|
||||||
|
|
||||||
if (err == LIBUSB_ERROR_PIPE || err == LIBUSB_TRANSFER_STALL) {
|
if (err == LIBUSB_ERROR_PIPE || err == LIBUSB_TRANSFER_STALL) {
|
||||||
|
int retries = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
cgpu->usbinfo.last_pipe = time(NULL);
|
cgpu->usbinfo.last_pipe = time(NULL);
|
||||||
cgpu->usbinfo.pipe_count++;
|
cgpu->usbinfo.pipe_count++;
|
||||||
applog(LOG_INFO, "%s%i: libusb pipe error, trying to clear",
|
applog(LOG_INFO, "%s%i: libusb pipe error, trying to clear",
|
||||||
@ -2325,6 +2317,7 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo,
|
|||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
cgpu->usbinfo.clear_fail_count++;
|
cgpu->usbinfo.clear_fail_count++;
|
||||||
|
} while (err && ++retries < USB_RETRY_MAX);
|
||||||
}
|
}
|
||||||
if ((endpoint & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN)
|
if ((endpoint & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN)
|
||||||
memcpy(data, buf, length);
|
memcpy(data, buf, length);
|
||||||
@ -2599,10 +2592,12 @@ out_unlock:
|
|||||||
err = LIBUSB_ERROR_OTHER;
|
err = LIBUSB_ERROR_OTHER;
|
||||||
}
|
}
|
||||||
out_noerrmsg:
|
out_noerrmsg:
|
||||||
DEVRUNLOCK(cgpu, pstate);
|
if (NODEV(err)) {
|
||||||
|
cg_ruwlock(&cgpu->usbinfo.devlock);
|
||||||
if (NODEV(err))
|
|
||||||
release_cgpu(cgpu);
|
release_cgpu(cgpu);
|
||||||
|
DEVWUNLOCK(cgpu, pstate);
|
||||||
|
} else
|
||||||
|
DEVRUNLOCK(cgpu, pstate);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -2697,10 +2692,12 @@ int _usb_write(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_
|
|||||||
err = LIBUSB_ERROR_OTHER;
|
err = LIBUSB_ERROR_OTHER;
|
||||||
}
|
}
|
||||||
out_noerrmsg:
|
out_noerrmsg:
|
||||||
DEVRUNLOCK(cgpu, pstate);
|
if (NODEV(err)) {
|
||||||
|
cg_ruwlock(&cgpu->usbinfo.devlock);
|
||||||
if (NODEV(err))
|
|
||||||
release_cgpu(cgpu);
|
release_cgpu(cgpu);
|
||||||
|
DEVWUNLOCK(cgpu, pstate);
|
||||||
|
} else
|
||||||
|
DEVRUNLOCK(cgpu, pstate);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -2772,8 +2769,8 @@ int __usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bReques
|
|||||||
IOERR_CHECK(cgpu, err);
|
IOERR_CHECK(cgpu, err);
|
||||||
|
|
||||||
if (err < 0 && err != LIBUSB_ERROR_TIMEOUT) {
|
if (err < 0 && err != LIBUSB_ERROR_TIMEOUT) {
|
||||||
applog(LOG_WARNING, "%s %i usb transfer error: %s", cgpu->drv->name, cgpu->device_id,
|
applog(LOG_WARNING, "%s %i usb transfer error(%d): %s", cgpu->drv->name, cgpu->device_id,
|
||||||
libusb_error_name(err));
|
err, libusb_error_name(err));
|
||||||
}
|
}
|
||||||
out_:
|
out_:
|
||||||
return err;
|
return err;
|
||||||
@ -2787,10 +2784,13 @@ int _usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest
|
|||||||
|
|
||||||
err = __usb_transfer(cgpu, request_type, bRequest, wValue, wIndex, data, siz, timeout, cmd);
|
err = __usb_transfer(cgpu, request_type, bRequest, wValue, wIndex, data, siz, timeout, cmd);
|
||||||
|
|
||||||
DEVRUNLOCK(cgpu, pstate);
|
if (NOCONTROLDEV(err)) {
|
||||||
|
cg_ruwlock(&cgpu->usbinfo.devlock);
|
||||||
if (NOCONTROLDEV(err))
|
|
||||||
release_cgpu(cgpu);
|
release_cgpu(cgpu);
|
||||||
|
cg_dwlock(&cgpu->usbinfo.devlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEVRUNLOCK(cgpu, pstate);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -2856,14 +2856,17 @@ int _usb_transfer_read(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRe
|
|||||||
err = 0;
|
err = 0;
|
||||||
}
|
}
|
||||||
if (err < 0 && err != LIBUSB_ERROR_TIMEOUT) {
|
if (err < 0 && err != LIBUSB_ERROR_TIMEOUT) {
|
||||||
applog(LOG_WARNING, "%s %i usb transfer read error: %s", cgpu->drv->name, cgpu->device_id,
|
applog(LOG_WARNING, "%s %i usb transfer read error(%d): %s", cgpu->drv->name, cgpu->device_id,
|
||||||
libusb_error_name(err));
|
err, libusb_error_name(err));
|
||||||
}
|
}
|
||||||
out_noerrmsg:
|
out_noerrmsg:
|
||||||
DEVRUNLOCK(cgpu, pstate);
|
if (NOCONTROLDEV(err)) {
|
||||||
|
cg_ruwlock(&cgpu->usbinfo.devlock);
|
||||||
if (NOCONTROLDEV(err))
|
|
||||||
release_cgpu(cgpu);
|
release_cgpu(cgpu);
|
||||||
|
cg_dwlock(&cgpu->usbinfo.devlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEVRUNLOCK(cgpu, pstate);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -3129,7 +3132,7 @@ void usb_set_dev_start(struct cgpu_info *cgpu)
|
|||||||
void usb_cleanup(void)
|
void usb_cleanup(void)
|
||||||
{
|
{
|
||||||
struct cgpu_info *cgpu;
|
struct cgpu_info *cgpu;
|
||||||
int count;
|
int count, pstate;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
hotplug_time = 0;
|
hotplug_time = 0;
|
||||||
@ -3147,7 +3150,9 @@ void usb_cleanup(void)
|
|||||||
case DRIVER_icarus:
|
case DRIVER_icarus:
|
||||||
case DRIVER_avalon:
|
case DRIVER_avalon:
|
||||||
case DRIVER_klondike:
|
case DRIVER_klondike:
|
||||||
|
DEVWLOCK(cgpu, pstate);
|
||||||
release_cgpu(cgpu);
|
release_cgpu(cgpu);
|
||||||
|
DEVWUNLOCK(cgpu, pstate);
|
||||||
count++;
|
count++;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -3186,7 +3191,7 @@ void usb_cleanup(void)
|
|||||||
cgsem_destroy(&usb_resource_sem);
|
cgsem_destroy(&usb_resource_sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DRIVER_COUNT_FOUND(X) if (strcasecmp(ptr, X##_drv.name) == 0) { \
|
#define DRIVER_COUNT_FOUND(X) if (X##_drv.name && strcasecmp(ptr, X##_drv.name) == 0) { \
|
||||||
drv_count[X##_drv.drv_id].limit = lim; \
|
drv_count[X##_drv.drv_id].limit = lim; \
|
||||||
found = true; \
|
found = true; \
|
||||||
}
|
}
|
||||||
|
2
util.c
2
util.c
@ -2006,7 +2006,7 @@ static bool setup_stratum_socket(struct pool *pool)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
applog(LOG_NOTICE, "Failed to connect to stratum on %s:%s",
|
applog(LOG_INFO, "Failed to connect to stratum on %s:%s",
|
||||||
sockaddr_url, sockaddr_port);
|
sockaddr_url, sockaddr_port);
|
||||||
freeaddrinfo(servinfo);
|
freeaddrinfo(servinfo);
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user