Browse Source

Merge branch 'master' into libusbx

Conflicts:
	api.c
	cgminer.c
	miner.h
	usbutils.c
nfactor-troky
Con Kolivas 11 years ago
parent
commit
64f5cac62c
  1. 13
      API-README
  2. 93
      NEWS
  3. 1
      api.c
  4. 42
      cgminer.c
  5. 1
      driver-avalon.c
  6. 74
      driver-bitfury.c
  7. 3
      driver-bitfury.h
  8. 239
      driver-icarus.c
  9. 9
      miner.h
  10. 103
      usbutils.c
  11. 2
      util.c

13
API-README

@ -277,13 +277,13 @@ The list of requests - a (*) means it requires privileged access - and replies: @@ -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
stating the results of the identify request
This is only available if PGA mining is enabled
and currently only BFL singles support this
command
and currently only BFL singles and Cairnsmore1's
with the appropriate firmware support this command
On a BFL single it will flash the led on the front
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
support it
support it. Non-CMR ICAs will ignore the command.
This adds a 4s delay to the BFL share being
processed so you may get a message stating that
procssing took longer than 7000ms if the request
@ -364,6 +364,7 @@ The list of requests - a (*) means it requires privileged access - and replies: @@ -364,6 +364,7 @@ The list of requests - a (*) means it requires privileged access - and replies:
The current options are:
MMQ opt=clock val=160 to 230 (a multiple of 2)
CMR opt=clock val=100 to 220
zero|Which,true/false (*)
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: @@ -433,8 +434,8 @@ The list of requests - a (*) means it requires privileged access - and replies:
help message about the options available
The current options are:
AVA+BTB opt=freq val=256 to 450 - chip frequency
BTB opt=millivolts val=1000 to 1310 - corevoltage
AVA+BTB opt=freq val=256 to 1024 - chip frequency
BTB opt=millivolts val=1000 to 1400 - corevoltage
When you enable, disable or restart a GPU, PGA or ASC, you will also get
Thread messages in the cgminer status window

93
NEWS

@ -1,3 +1,96 @@ @@ -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
- Add magic init sequence required on BF1 devices to get them mining on windows.

1
api.c

@ -3141,7 +3141,6 @@ static int itemstats(struct io_data *io_data, int i, char *id, struct cgminer_st @@ -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_int(root, "USB cancellations", &cgpu->usb_cancels, false);
#endif
}

42
cgminer.c

@ -175,6 +175,8 @@ char *opt_usb_select = NULL; @@ -175,6 +175,8 @@ char *opt_usb_select = NULL;
int opt_usbdump = -1;
bool opt_usb_list_all;
cgsem_t usb_resource_sem;
static pthread_t usb_poll_thread;
static bool usb_polling;
#endif
char *opt_kernel_path;
@ -3216,6 +3218,8 @@ static void __kill_work(void) @@ -3216,6 +3218,8 @@ static void __kill_work(void)
/* Release USB resources in case it's a restart
* and not a QUIT */
if (!opt_scrypt) {
usb_polling = false;
applog(LOG_DEBUG, "Releasing all USB devices");
usb_cleanup();
@ -5786,10 +5790,9 @@ out: @@ -5786,10 +5790,9 @@ out:
static void pool_resus(struct pool *pool)
{
if (pool_strategy == POOL_FAILOVER && pool->prio < cp_prio()) {
applog(LOG_WARNING, "Pool %d %s alive", pool->pool_no, pool->rpc_url);
switch_pools(NULL);
} else
if (pool_strategy == POOL_FAILOVER && pool->prio < cp_prio())
applog(LOG_WARNING, "Pool %d %s alive, testing stability", pool->pool_no, pool->rpc_url);
else
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) @@ -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);
cgpu->deven = DEV_DISABLED;
dev_error(cgpu, REASON_THREAD_ZERO_HASH);
mt_disable(mythr, thr_id, drv);
cgpu->shutdown = true;
break;
}
hashes_done += hashes;
@ -6867,8 +6871,21 @@ static void *watchpool_thread(void __maybe_unused *userdata) @@ -6867,8 +6871,21 @@ static void *watchpool_thread(void __maybe_unused *userdata)
if (pool_active(pool, true) && pool_tclear(pool, &pool->idle))
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) {
cgtime(&rotate_tv);
switch_pools(NULL);
@ -7067,6 +7084,9 @@ static void log_print_status(struct cgpu_info *cgpu) @@ -7067,6 +7084,9 @@ static void log_print_status(struct cgpu_info *cgpu)
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)
{
struct timeval diff;
@ -7138,6 +7158,8 @@ void print_summary(void) @@ -7138,6 +7158,8 @@ void print_summary(void)
for (i = 0; i < total_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);
}
@ -7232,6 +7254,7 @@ static void *test_pool_thread(void *arg) @@ -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);
pool_resus(pool);
switch_pools(NULL);
} else
pool_died(pool);
@ -7728,19 +7751,15 @@ static void probe_pools(void) @@ -7728,19 +7751,15 @@ static void probe_pools(void)
#ifdef USE_USBUTILS
static void *libusb_poll_thread(void __maybe_unused *arg)
{
struct timeval tv = { 0, USB_ASYNC_POLL * 1000 };
RenameThread("usbpoll");
pthread_detach(pthread_self());
while (42)
libusb_handle_events_timeout(NULL, &tv);
while (usb_polling)
libusb_handle_events(NULL);
return NULL;
}
static pthread_t usb_poll_thread;
static void initialise_usb(void) {
int err = libusb_init(NULL);
if (err) {
@ -7751,6 +7770,7 @@ static void initialise_usb(void) { @@ -7751,6 +7770,7 @@ static void initialise_usb(void) {
mutex_init(&cgusb_lock);
mutex_init(&cgusbres_lock);
cglock_init(&cgusb_fd_lock);
usb_polling = true;
pthread_create(&usb_poll_thread, NULL, libusb_poll_thread, NULL);
}
#else

1
driver-avalon.c

@ -720,6 +720,7 @@ static bool avalon_detect_one(libusb_device *dev, struct usb_find_devices *found @@ -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 */
avalon->usbdev->usb_type = USB_TYPE_STD;
usb_set_pps(avalon, AVALON_USB_PACKETSIZE);
usb_buffer_enable(avalon);
/* We have a real Avalon! */
avalon_initialise(avalon);

74
driver-bitfury.c

@ -15,6 +15,8 @@ @@ -15,6 +15,8 @@
/* Wait longer 1/3 longer than it would take for a full nonce range */
#define BF1WAIT 1600
#define BF1MSGSIZE 7
#define BF1INFOSIZE 14
static void bitfury_empty_buffer(struct cgpu_info *bitfury)
{
@ -26,18 +28,29 @@ static void bitfury_empty_buffer(struct cgpu_info *bitfury) @@ -26,18 +28,29 @@ static void bitfury_empty_buffer(struct cgpu_info *bitfury)
} while (amount);
}
static void bitfury_open(struct cgpu_info *bitfury)
static int bitfury_open(struct cgpu_info *bitfury)
{
uint32_t buf[2];
int err;
bitfury_empty_buffer(bitfury);
/* Magic sequence to reset device only really needed for windows but
* harmless on linux. */
buf[0] = 0x80250000;
buf[1] = 0x00000800;
usb_transfer(bitfury, 0, 9, 1, 0, C_BF1_RESET);
usb_transfer(bitfury, 0x21, 0x22, 0, 0, C_BF1_OPEN);
usb_transfer_data(bitfury, 0x21, 0x20, 0x0000, 0, buf, 7, C_BF1_INIT);
err = usb_transfer(bitfury, 0, 9, 1, 0, C_BF1_RESET);
if (!err)
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)
@ -63,15 +76,15 @@ static bool bitfury_getinfo(struct cgpu_info *bitfury, struct bitfury_info *info @@ -63,15 +76,15 @@ static bool bitfury_getinfo(struct cgpu_info *bitfury, struct bitfury_info *info
bitfury->drv->name, bitfury->device_id);
return false;
}
err = usb_read(bitfury, buf, 14, &amount, C_BF1_GETINFO);
err = usb_read(bitfury, buf, BF1INFOSIZE, &amount, C_BF1_GETINFO);
if (err) {
applog(LOG_INFO, "%s %d: Failed to read GETINFO",
bitfury->drv->name, bitfury->device_id);
return false;
}
if (amount != 14) {
applog(LOG_INFO, "%s %d: Getinfo received %d bytes instead of 14",
bitfury->drv->name, bitfury->device_id, amount);
if (amount != BF1INFOSIZE) {
applog(LOG_INFO, "%s %d: Getinfo received %d bytes instead of %d",
bitfury->drv->name, bitfury->device_id, amount, BF1INFOSIZE);
return false;
}
info->version = buf[1];
@ -95,15 +108,16 @@ static bool bitfury_reset(struct cgpu_info *bitfury) @@ -95,15 +108,16 @@ static bool bitfury_reset(struct cgpu_info *bitfury)
bitfury->drv->name, bitfury->device_id);
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) {
applog(LOG_INFO, "%s %d: Failed to read GETRESET",
bitfury->drv->name, bitfury->device_id);
return false;
}
if (amount != 7) {
applog(LOG_INFO, "%s %d: Getreset received %d bytes instead of 7",
bitfury->drv->name, bitfury->device_id, amount);
if (amount != BF1MSGSIZE) {
applog(LOG_INFO, "%s %d: Getreset received %d bytes instead of %d",
bitfury->drv->name, bitfury->device_id, amount, BF1MSGSIZE);
return false;
}
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 @@ -128,10 +142,14 @@ static bool bitfury_detect_one(struct libusb_device *dev, struct usb_find_device
if (!info)
quit(1, "Failed to calloc info in bitfury_detect_one");
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);
bitfury_open(bitfury);
if (!bitfury_open(bitfury))
goto out_close;
/* Send getinfo request */
if (!bitfury_getinfo(bitfury, info))
@ -145,7 +163,7 @@ static bool bitfury_detect_one(struct libusb_device *dev, struct usb_find_device @@ -145,7 +163,7 @@ static bool bitfury_detect_one(struct libusb_device *dev, struct usb_find_device
bitfury_empty_buffer(bitfury);
if (!add_cgpu(bitfury))
goto out_close;
quit(1, "Failed to add_cgpu in bitfury_detect_one");
update_usb_stats(bitfury);
applog(LOG_INFO, "%s %d: Successfully initialised %s",
@ -208,6 +226,8 @@ static int64_t bitfury_scanhash(struct thr_info *thr, struct work *work, @@ -208,6 +226,8 @@ static int64_t bitfury_scanhash(struct thr_info *thr, struct work *work,
struct cgpu_info *bitfury = thr->cgpu;
struct bitfury_info *info = bitfury->device_data;
struct timeval tv_now;
double nonce_rate;
int64_t ret = 0;
int amount, i;
char buf[45];
int ms_diff;
@ -235,7 +255,8 @@ static int64_t bitfury_scanhash(struct thr_info *thr, struct work *work, @@ -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);
if (unlikely(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;
while (amount) {
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, @@ -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);
cgtime(&info->tv_start);
/* 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 */
if (unlikely(!info->prevwork[BF1ARRAY_SIZE]))
@ -257,7 +278,7 @@ static int64_t bitfury_scanhash(struct thr_info *thr, struct work *work, @@ -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
* 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;
int j;
@ -279,23 +300,30 @@ cascade: @@ -279,23 +300,30 @@ cascade:
info->prevwork[i] = info->prevwork[i - 1];
info->prevwork[0] = copy_work(work);
work->blk.nonce = 0xffffffff;
if (info->nonces) {
info->nonces--;
return (int64_t)0xffffffff;
info->cycles++;
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)) {
applog(LOG_WARNING, "%s %d: Device disappeared, disabling thread",
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)
{
struct bitfury_info *info = cgpu->device_data;
struct api_data *root = NULL;
double nonce_rate;
char serial[16];
int version;
@ -304,6 +332,8 @@ static struct api_data *bitfury_api_stats(struct cgpu_info *cgpu) @@ -304,6 +332,8 @@ static struct api_data *bitfury_api_stats(struct cgpu_info *cgpu)
root = api_add_string(root, "Product", info->product, false);
sprintf(serial, "%08x", info->serial);
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;
}

3
driver-bitfury.h

@ -24,6 +24,9 @@ struct bitfury_info { @@ -24,6 +24,9 @@ struct bitfury_info {
char buf[512];
int tot;
int nonces;
int total_nonces;
double saved_nonces;
int cycles;
struct timeval tv_start;
};

239
driver-icarus.c

@ -108,6 +108,8 @@ ASSERT1(sizeof(uint32_t) == 4); @@ -108,6 +108,8 @@ ASSERT1(sizeof(uint32_t) == 4);
#define CAIRNSMORE2_HASH_TIME 0.0000000066600
#define NANOSEC 1000000000.0
#define CAIRNSMORE2_INTS 4
// Icarus Rev3 doesn't send a completion message when it finishes
// the full nonce range, so to avoid being idle we must abort the
// work (by starting a new work item) shortly before it finishes
@ -178,6 +180,7 @@ static const char *MODE_VALUE_STR = "value"; @@ -178,6 +180,7 @@ static const char *MODE_VALUE_STR = "value";
static const char *MODE_UNKNOWN_STR = "unknown";
struct ICARUS_INFO {
enum sub_ident ident;
int intinfo;
// time to calculate the golden_ob
@ -216,17 +219,43 @@ struct ICARUS_INFO { @@ -216,17 +219,43 @@ struct ICARUS_INFO {
int fpga_count;
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_UNUSED_SIZE 20
#define ICARUS_UNUSED_SIZE 16
#define ICARUS_WORK_SIZE 12
#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 {
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 work[ICARUS_WORK_SIZE];
};
@ -423,8 +452,6 @@ static void icarus_initialise(struct cgpu_info *icarus, int baud) @@ -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",
icarus->drv->name, icarus->cgminer_id, ident);
}
info->initialised = true;
}
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 @@ -820,9 +847,10 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
char *nonce_hex;
int baud, uninitialised_var(work_division), uninitialised_var(fpga_count);
struct cgpu_info *icarus;
int ret, err, amount, tries;
enum sub_ident ident;
int ret, err, amount, tries, i;
bool ok;
bool cmr2_ok[CAIRNSMORE2_INTS];
int cmr2_count;
if ((sizeof(workdata) << 1) != (sizeof(golden_ob) - 1))
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 @@ -843,8 +871,8 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
quit(1, "Failed to malloc ICARUS_INFO");
icarus->device_data = (void *)info;
ident = usb_ident(icarus);
switch (ident) {
info->ident = usb_ident(icarus);
switch (info->ident) {
case IDENT_ICA:
case IDENT_BLT:
case IDENT_LLT:
@ -853,19 +881,32 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices @@ -853,19 +881,32 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
info->timeout = ICARUS_WAIT_TIMEOUT;
break;
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;
cmr2_count = 0;
for (i = 0; i < CAIRNSMORE2_INTS; i++)
cmr2_ok[i] = false;
break;
default:
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;
ok = false;
while (!ok && tries-- > 0) {
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))
continue;
@ -879,7 +920,7 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices @@ -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)
ok = true;
else {
if (tries < 0) {
if (tries < 0 && info->ident != IDENT_CMR2) {
applog(LOG_ERR,
"Icarus Detect: "
"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 @@ -889,13 +930,50 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
free(nonce_hex);
}
if (!ok)
goto unshin;
if (!ok) {
if (info->ident != IDENT_CMR2)
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;
}
}
}
applog(LOG_DEBUG,
"Icarus Detect: "
"Test succeeded at %s: got %s",
icarus->device_path, golden_nonce);
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,
"Icarus Detect: "
"Test succeeded at %s: got %s",
icarus->device_path, golden_nonce);
}
/* We have a real Icarus! */
if (!add_cgpu(icarus))
@ -906,6 +984,18 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices @@ -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",
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",
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 @@ -919,12 +1009,15 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
set_timing_mode(this_option_offset, icarus);
if (usb_ident(icarus) == IDENT_CMR2) {
if (info->ident == IDENT_CMR2) {
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 ICARUS_INFO *intmp;
if (!cmr2_ok[i])
continue;
cgtmp = usb_copy_cgpu(icarus);
if (!cgtmp) {
applog(LOG_ERR, "%s%d: Init failed initinfo %d",
@ -984,6 +1077,45 @@ static bool icarus_prepare(__maybe_unused struct thr_info *thr) @@ -984,6 +1077,45 @@ static bool icarus_prepare(__maybe_unused struct thr_info *thr)
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,
__maybe_unused int64_t max_nonce)
{
@ -1014,9 +1146,6 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, @@ -1014,9 +1146,6 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
if (icarus->usbinfo.nodev)
return -1;
if (!info->initialised)
icarus_initialise(icarus, info->baud);
elapsed.tv_sec = elapsed.tv_usec = 0;
memset((void *)(&workdata), 0, sizeof(workdata));
@ -1025,6 +1154,9 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, @@ -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.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
usb_buffer_clear(icarus);
@ -1245,17 +1377,80 @@ static struct api_data *icarus_api_stats(struct cgpu_info *cgpu) @@ -1245,17 +1377,80 @@ static struct api_data *icarus_api_stats(struct cgpu_info *cgpu)
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)
{
// 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 = {
.drv_id = DRIVER_icarus,
.dname = "Icarus",
.name = "ICA",
.drv_detect = icarus_detect,
.get_api_stats = icarus_api_stats,
.get_statline_before = icarus_statline_before,
.set_device = icarus_set,
.identify_device = icarus_identify,
.thread_prepare = icarus_prepare,
.scanhash = icarus_scanhash,
.thread_shutdown = icarus_shutdown,

9
miner.h

@ -472,7 +472,6 @@ struct cgpu_info { @@ -472,7 +472,6 @@ struct cgpu_info {
#endif
#ifdef USE_USBUTILS
struct cg_usb_info usbinfo;
int usb_cancels;
#endif
#ifdef USE_MODMINER
char fpgaid;
@ -881,6 +880,14 @@ static inline void cg_runlock(cglock_t *lock) @@ -881,6 +880,14 @@ static inline void cg_runlock(cglock_t *lock)
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)
{
wr_unlock_noyield(&lock->rwlock);

103
usbutils.c

@ -1300,12 +1300,11 @@ static void release_cgpu(struct cgpu_info *cgpu) @@ -1300,12 +1300,11 @@ static void release_cgpu(struct cgpu_info *cgpu)
{
struct cg_usb_device *cgusb = cgpu->usbdev;
struct cgpu_info *lookcgpu;
int i, pstate;
int i;
DEVWLOCK(cgpu, pstate);
// It has already been done
if (cgpu->usbinfo.nodev)
goto out_unlock;
return;
applog(LOG_DEBUG, "USB release %s%i",
cgpu->drv->name, cgpu->device_id);
@ -1335,8 +1334,6 @@ static void release_cgpu(struct cgpu_info *cgpu) @@ -1335,8 +1334,6 @@ static void release_cgpu(struct cgpu_info *cgpu)
_usb_uninit(cgpu);
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 @@ -2125,7 +2122,6 @@ static void stats(struct cgpu_info *cgpu, struct timeval *tv_start, struct timev
case LIBUSB_SUCCESS:
item = CMD_CMD;
break;
case LIBUSB_TRANSFER_TIMED_OUT:
case LIBUSB_ERROR_TIMEOUT:
item = CMD_TIMEOUT;
break;
@ -2222,8 +2218,7 @@ static void LIBUSB_CALL bulk_callback(struct libusb_transfer *transfer) @@ -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
* 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,
unsigned int timeout)
static int callback_wait(struct usb_transfer *ut, int *transferred, unsigned int timeout)
{
struct libusb_transfer *transfer= ut->transfer;
struct timespec ts_now, ts_end;
@ -2231,28 +2226,21 @@ static int callback_wait(struct cgpu_info *cgpu, struct usb_transfer *ut, int *t @@ -2231,28 +2226,21 @@ static int callback_wait(struct cgpu_info *cgpu, struct usb_transfer *ut, int *t
int ret;
cgtime(&tv_now);
timeout = timeout + USB_ASYNC_POLL;
ms_to_timespec(&ts_end, timeout);
timeval_to_spec(&ts_now, &tv_now);
timeraddspec(&ts_end, &ts_now);
ret = pthread_cond_timedwait(&ut->cond, &ut->mutex, &ts_end);
if (ret) {
/* Assume that if we timed out on the conditional then the
* 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);
/* We are emulating a timeout ourself here */
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. */
pthread_cond_wait(&ut->cond, &ut->mutex);
/* Fake the timed out message since it's effectively that */
}
ret = transfer->status;
if (ret == LIBUSB_TRANSFER_CANCELLED)
ret = LIBUSB_TRANSFER_TIMED_OUT;
} else
ret = transfer->status;
/* No need to sort out mutexes here since they won't be reused */
*transferred = transfer->actual_length;
libusb_free_transfer(transfer);
@ -2295,8 +2283,9 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo, @@ -2295,8 +2283,9 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo,
init_usb_transfer(&ut);
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,
bulk_callback, &ut, timeout);
bulk_callback, &ut, 0);
STATS_TIMEVAL(&tv_start);
cg_rlock(&cgusb_fd_lock);
@ -2304,7 +2293,7 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo, @@ -2304,7 +2293,7 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo,
cg_runlock(&cgusb_fd_lock);
errn = errno;
if (!err)
err = callback_wait(cgpu, &ut, transferred, timeout);
err = callback_wait(&ut, transferred, timeout);
STATS_TIMEVAL(&tv_finish);
USB_STATS(cgpu, &tv_start, &tv_finish, err, mode, cmd, seq, timeout);
@ -2315,16 +2304,20 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo, @@ -2315,16 +2304,20 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo,
usb_cmdname(cmd), *transferred, err, errn);
if (err == LIBUSB_ERROR_PIPE || err == LIBUSB_TRANSFER_STALL) {
cgpu->usbinfo.last_pipe = time(NULL);
cgpu->usbinfo.pipe_count++;
applog(LOG_INFO, "%s%i: libusb pipe error, trying to clear",
cgpu->drv->name, cgpu->device_id);
err = libusb_clear_halt(dev_handle, endpoint);
applog(LOG_DEBUG, "%s%i: libusb pipe error%scleared",
cgpu->drv->name, cgpu->device_id, err ? " not " : " ");
int retries = 0;
if (err)
cgpu->usbinfo.clear_fail_count++;
do {
cgpu->usbinfo.last_pipe = time(NULL);
cgpu->usbinfo.pipe_count++;
applog(LOG_INFO, "%s%i: libusb pipe error, trying to clear",
cgpu->drv->name, cgpu->device_id);
err = libusb_clear_halt(dev_handle, endpoint);
applog(LOG_DEBUG, "%s%i: libusb pipe error%scleared",
cgpu->drv->name, cgpu->device_id, err ? " not " : " ");
if (err)
cgpu->usbinfo.clear_fail_count++;
} while (err && ++retries < USB_RETRY_MAX);
}
if ((endpoint & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN)
memcpy(data, buf, length);
@ -2599,10 +2592,12 @@ out_unlock: @@ -2599,10 +2592,12 @@ out_unlock:
err = LIBUSB_ERROR_OTHER;
}
out_noerrmsg:
DEVRUNLOCK(cgpu, pstate);
if (NODEV(err))
if (NODEV(err)) {
cg_ruwlock(&cgpu->usbinfo.devlock);
release_cgpu(cgpu);
DEVWUNLOCK(cgpu, pstate);
} else
DEVRUNLOCK(cgpu, pstate);
return err;
}
@ -2697,10 +2692,12 @@ int _usb_write(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_ @@ -2697,10 +2692,12 @@ int _usb_write(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_
err = LIBUSB_ERROR_OTHER;
}
out_noerrmsg:
DEVRUNLOCK(cgpu, pstate);
if (NODEV(err))
if (NODEV(err)) {
cg_ruwlock(&cgpu->usbinfo.devlock);
release_cgpu(cgpu);
DEVWUNLOCK(cgpu, pstate);
} else
DEVRUNLOCK(cgpu, pstate);
return err;
}
@ -2772,8 +2769,8 @@ int __usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bReques @@ -2772,8 +2769,8 @@ int __usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bReques
IOERR_CHECK(cgpu, err);
if (err < 0 && err != LIBUSB_ERROR_TIMEOUT) {
applog(LOG_WARNING, "%s %i usb transfer error: %s", cgpu->drv->name, cgpu->device_id,
libusb_error_name(err));
applog(LOG_WARNING, "%s %i usb transfer error(%d): %s", cgpu->drv->name, cgpu->device_id,
err, libusb_error_name(err));
}
out_:
return err;
@ -2787,10 +2784,13 @@ int _usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest @@ -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);
DEVRUNLOCK(cgpu, pstate);
if (NOCONTROLDEV(err))
if (NOCONTROLDEV(err)) {
cg_ruwlock(&cgpu->usbinfo.devlock);
release_cgpu(cgpu);
cg_dwlock(&cgpu->usbinfo.devlock);
}
DEVRUNLOCK(cgpu, pstate);
return err;
}
@ -2856,14 +2856,17 @@ int _usb_transfer_read(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRe @@ -2856,14 +2856,17 @@ int _usb_transfer_read(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRe
err = 0;
}
if (err < 0 && err != LIBUSB_ERROR_TIMEOUT) {
applog(LOG_WARNING, "%s %i usb transfer read error: %s", cgpu->drv->name, cgpu->device_id,
libusb_error_name(err));
applog(LOG_WARNING, "%s %i usb transfer read error(%d): %s", cgpu->drv->name, cgpu->device_id,
err, libusb_error_name(err));
}
out_noerrmsg:
DEVRUNLOCK(cgpu, pstate);
if (NOCONTROLDEV(err))
if (NOCONTROLDEV(err)) {
cg_ruwlock(&cgpu->usbinfo.devlock);
release_cgpu(cgpu);
cg_dwlock(&cgpu->usbinfo.devlock);
}
DEVRUNLOCK(cgpu, pstate);
return err;
}
@ -3129,7 +3132,7 @@ void usb_set_dev_start(struct cgpu_info *cgpu) @@ -3129,7 +3132,7 @@ void usb_set_dev_start(struct cgpu_info *cgpu)
void usb_cleanup(void)
{
struct cgpu_info *cgpu;
int count;
int count, pstate;
int i;
hotplug_time = 0;
@ -3147,7 +3150,9 @@ void usb_cleanup(void) @@ -3147,7 +3150,9 @@ void usb_cleanup(void)
case DRIVER_icarus:
case DRIVER_avalon:
case DRIVER_klondike:
DEVWLOCK(cgpu, pstate);
release_cgpu(cgpu);
DEVWUNLOCK(cgpu, pstate);
count++;
break;
default:
@ -3186,7 +3191,7 @@ void usb_cleanup(void) @@ -3186,7 +3191,7 @@ void usb_cleanup(void)
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; \
found = true; \
}

2
util.c

@ -2006,7 +2006,7 @@ static bool setup_stratum_socket(struct pool *pool) @@ -2006,7 +2006,7 @@ static bool setup_stratum_socket(struct pool *pool)
break;
}
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);
freeaddrinfo(servinfo);
return false;

Loading…
Cancel
Save