Browse Source

Merge branch 'master' into hashfast

Con Kolivas 12 years ago
parent
commit
f29f612182
7 changed files with 177 additions and 105 deletions
  1. 42 11
      cgminer.c
  2. 3 3
      driver-bitfury.c
  3. 29 57
      driver-icarus.c
  4. 6 0
      miner.h
  5. 66 17
      usbutils.c
  6. 29 17
      usbutils.h
  7. 2 0
      util.c

+ 42 - 11
cgminer.c

@@ -94,6 +94,7 @@ struct strategies strategies[] = {
 
 
 static char packagename[256];
 static char packagename[256];
 
 
+bool opt_work_update;
 bool opt_protocol;
 bool opt_protocol;
 static bool opt_benchmark;
 static bool opt_benchmark;
 bool have_longpoll;
 bool have_longpoll;
@@ -1849,6 +1850,8 @@ static void update_gbt(struct pool *pool)
 			applog(LOG_DEBUG, "Successfully retrieved and updated GBT from pool %u %s",
 			applog(LOG_DEBUG, "Successfully retrieved and updated GBT from pool %u %s",
 			       pool->pool_no, pool->rpc_url);
 			       pool->pool_no, pool->rpc_url);
 			cgtime(&pool->tv_idle);
 			cgtime(&pool->tv_idle);
+			if (pool == current_pool())
+				opt_work_update = true;
 		} else {
 		} else {
 			applog(LOG_DEBUG, "Successfully retrieved but FAILED to decipher GBT from pool %u %s",
 			applog(LOG_DEBUG, "Successfully retrieved but FAILED to decipher GBT from pool %u %s",
 			       pool->pool_no, pool->rpc_url);
 			       pool->pool_no, pool->rpc_url);
@@ -1915,6 +1918,8 @@ static void gen_gbt_work(struct pool *pool, struct work *work)
 	work->longpoll = false;
 	work->longpoll = false;
 	work->getwork_mode = GETWORK_MODE_GBT;
 	work->getwork_mode = GETWORK_MODE_GBT;
 	work->work_block = work_block;
 	work->work_block = work_block;
+	/* Nominally allow a driver to ntime roll 60 seconds */
+	work->drv_rolllimit = 60;
 	calc_diff(work, 0);
 	calc_diff(work, 0);
 	cgtime(&work->tv_staged);
 	cgtime(&work->tv_staged);
 }
 }
@@ -3936,6 +3941,25 @@ static void restart_threads(void)
 	mutex_lock(&restart_lock);
 	mutex_lock(&restart_lock);
 	pthread_cond_broadcast(&restart_cond);
 	pthread_cond_broadcast(&restart_cond);
 	mutex_unlock(&restart_lock);
 	mutex_unlock(&restart_lock);
+
+#ifdef USE_USBUTILS
+	/* Cancels any cancellable usb transfers. Flagged as such it means they
+	 * are usualy waiting on a read result and it's safe to abort the read
+	 * early. */
+	cancel_usb_transfers();
+#endif
+}
+
+static void signal_work_update(void)
+{
+	int i;
+
+	applog(LOG_INFO, "Work update message received");
+
+	rd_lock(&mining_thr_lock);
+	for (i = 0; i < mining_threads; i++)
+		mining_thr[i]->work_update = true;
+	rd_unlock(&mining_thr_lock);
 }
 }
 
 
 static void set_curblock(char *hexstr, unsigned char *hash)
 static void set_curblock(char *hexstr, unsigned char *hash)
@@ -5998,6 +6022,8 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
 	work->longpoll = false;
 	work->longpoll = false;
 	work->getwork_mode = GETWORK_MODE_STRATUM;
 	work->getwork_mode = GETWORK_MODE_STRATUM;
 	work->work_block = work_block;
 	work->work_block = work_block;
+	/* Nominally allow a driver to ntime roll 60 seconds */
+	work->drv_rolllimit = 60;
 	calc_diff(work, work->sdiff);
 	calc_diff(work, work->sdiff);
 
 
 	cgtime(&work->tv_staged);
 	cgtime(&work->tv_staged);
@@ -6502,7 +6528,7 @@ void hash_queued_work(struct thr_info *mythr)
 		struct timeval diff;
 		struct timeval diff;
 		int64_t hashes;
 		int64_t hashes;
 
 
-		mythr->work_restart = false;
+		mythr->work_restart = mythr->work_update = false;
 
 
 		fill_queue(mythr, cgpu, drv, thr_id);
 		fill_queue(mythr, cgpu, drv, thr_id);
 
 
@@ -6532,7 +6558,8 @@ void hash_queued_work(struct thr_info *mythr)
 		if (unlikely(mythr->work_restart)) {
 		if (unlikely(mythr->work_restart)) {
 			flush_queue(cgpu);
 			flush_queue(cgpu);
 			drv->flush_work(cgpu);
 			drv->flush_work(cgpu);
-		}
+		} else if (mythr->work_update)
+			drv->update_work(cgpu);
 	}
 	}
 	cgpu->deven = DEV_DISABLED;
 	cgpu->deven = DEV_DISABLED;
 }
 }
@@ -6553,7 +6580,7 @@ void hash_driver_work(struct thr_info *mythr)
 		struct timeval diff;
 		struct timeval diff;
 		int64_t hashes;
 		int64_t hashes;
 
 
-		mythr->work_restart = false;
+		mythr->work_restart = mythr->work_update = false;
 
 
 		hashes = drv->scanwork(mythr);
 		hashes = drv->scanwork(mythr);
 
 
@@ -6580,6 +6607,8 @@ void hash_driver_work(struct thr_info *mythr)
 
 
 		if (unlikely(mythr->work_restart))
 		if (unlikely(mythr->work_restart))
 			drv->flush_work(cgpu);
 			drv->flush_work(cgpu);
+		else if (mythr->work_update)
+			drv->update_work(cgpu);
 	}
 	}
 	cgpu->deven = DEV_DISABLED;
 	cgpu->deven = DEV_DISABLED;
 }
 }
@@ -6608,8 +6637,6 @@ void *miner_thread(void *userdata)
 out:
 out:
 	drv->thread_shutdown(mythr);
 	drv->thread_shutdown(mythr);
 
 
-	applog(LOG_ERR, "Thread %d failure, exiting", thr_id);
-
 	return NULL;
 	return NULL;
 }
 }
 
 
@@ -7560,6 +7587,7 @@ static void noop_detect(bool __maybe_unused hotplug)
 {
 {
 }
 }
 #define noop_flush_work noop_reinit_device
 #define noop_flush_work noop_reinit_device
+#define noop_update_work noop_reinit_device
 #define noop_queue_full noop_get_stats
 #define noop_queue_full noop_get_stats
 
 
 /* Fill missing driver drv functions with noops */
 /* Fill missing driver drv functions with noops */
@@ -7593,6 +7621,8 @@ void fill_device_drv(struct device_drv *drv)
 		drv->hash_work = &hash_sole_work;
 		drv->hash_work = &hash_sole_work;
 	if (!drv->flush_work)
 	if (!drv->flush_work)
 		drv->flush_work = &noop_flush_work;
 		drv->flush_work = &noop_flush_work;
+	if (!drv->update_work)
+		drv->update_work = &noop_update_work;
 	if (!drv->queue_full)
 	if (!drv->queue_full)
 		drv->queue_full = &noop_queue_full;
 		drv->queue_full = &noop_queue_full;
 	if (!drv->max_diff)
 	if (!drv->max_diff)
@@ -7810,22 +7840,20 @@ static void probe_pools(void)
 static void *libusb_poll_thread(void __maybe_unused *arg)
 static void *libusb_poll_thread(void __maybe_unused *arg)
 {
 {
 	struct timeval tv_end = {1, 0};
 	struct timeval tv_end = {1, 0};
-	bool inprogress = false;
 
 
 	RenameThread("usbpoll");
 	RenameThread("usbpoll");
 
 
 	while (usb_polling)
 	while (usb_polling)
 		libusb_handle_events_timeout_completed(NULL, &tv_end, NULL);
 		libusb_handle_events_timeout_completed(NULL, &tv_end, NULL);
 
 
+	/* Cancel any cancellable usb transfers */
+	cancel_usb_transfers();
+
 	/* Keep event handling going until there are no async transfers in
 	/* Keep event handling going until there are no async transfers in
 	 * flight. */
 	 * flight. */
 	do {
 	do {
 		libusb_handle_events_timeout_completed(NULL, &tv_end, NULL);
 		libusb_handle_events_timeout_completed(NULL, &tv_end, NULL);
-
-		cg_rlock(&cgusb_fd_lock);
-		inprogress = !!cgusb_transfers;
-		cg_runlock(&cgusb_fd_lock);
-	} while (inprogress);
+	} while (async_usb_transfers());
 
 
 	return NULL;
 	return NULL;
 }
 }
@@ -8313,6 +8341,9 @@ begin_bench:
 		bool lagging = false;
 		bool lagging = false;
 		struct work *work;
 		struct work *work;
 
 
+		if (opt_work_update)
+			signal_work_update();
+		opt_work_update = false;
 		cp = current_pool();
 		cp = current_pool();
 
 
 		/* If the primary pool is a getwork pool and cannot roll work,
 		/* If the primary pool is a getwork pool and cannot roll work,

+ 3 - 3
driver-bitfury.c

@@ -248,7 +248,7 @@ static int64_t bitfury_scanwork(struct thr_info *thr)
 	cgtime(&tv_now);
 	cgtime(&tv_now);
 	ms_diff = 600 - ms_tdiff(&tv_now, &info->tv_start);
 	ms_diff = 600 - ms_tdiff(&tv_now, &info->tv_start);
 	if (ms_diff > 0) {
 	if (ms_diff > 0) {
-		usb_read_timeout(bitfury, info->buf, 512, &amount, ms_diff, C_BF1_GETRES);
+		usb_read_timeout_cancellable(bitfury, info->buf, 512, &amount, ms_diff, C_BF1_GETRES);
 		info->tot += amount;
 		info->tot += amount;
 	}
 	}
 
 
@@ -261,8 +261,8 @@ static int64_t bitfury_scanwork(struct thr_info *thr)
 	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, BF1MSGSIZE,
-			      &amount, ms_diff, C_BF1_GETRES);
+	usb_read_once_timeout_cancellable(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);

+ 29 - 57
driver-icarus.c

@@ -471,70 +471,42 @@ static void rev(unsigned char *s, size_t l)
 #define ICA_NONCE_RESTART 1
 #define ICA_NONCE_RESTART 1
 #define ICA_NONCE_TIMEOUT 2
 #define ICA_NONCE_TIMEOUT 2
 
 
-static int icarus_get_nonce(struct cgpu_info *icarus, unsigned char *buf, struct timeval *tv_start, struct timeval *tv_finish, struct thr_info *thr, int read_time)
+static int icarus_get_nonce(struct cgpu_info *icarus, unsigned char *buf, struct timeval *tv_start,
+			    struct timeval *tv_finish, struct thr_info *thr, int read_time)
 {
 {
 	struct ICARUS_INFO *info = (struct ICARUS_INFO *)(icarus->device_data);
 	struct ICARUS_INFO *info = (struct ICARUS_INFO *)(icarus->device_data);
-	struct timeval read_start, read_finish;
-	int err, amt;
-	int rc = 0, delay;
-	int read_amount = ICARUS_READ_SIZE;
-	bool first = true;
+	int err, amt, rc;
 
 
-	cgtime(tv_start);
-	while (true) {
-		if (icarus->usbinfo.nodev)
-			return ICA_NONCE_ERROR;
-
-		cgtime(&read_start);
-		err = usb_read_ii_timeout(icarus, info->intinfo,
-					  (char *)buf, read_amount, &amt,
-					  info->timeout, C_GETRESULTS);
-		cgtime(&read_finish);
-		if (err < 0 && err != LIBUSB_ERROR_TIMEOUT) {
-			applog(LOG_ERR, "%s%i: Comms error (rerr=%d amt=%d)",
-					icarus->drv->name, icarus->device_id, err, amt);
-			dev_error(icarus, REASON_DEV_COMMS_ERROR);
-			return ICA_NONCE_ERROR;
-		}
-
-		if (first)
-			copy_time(tv_finish, &read_finish);
-
-		if (amt >= read_amount)
-			return ICA_NONCE_OK;
-
-		rc = SECTOMS(tdiff(&read_finish, tv_start));
-		if (rc >= read_time) {
-			if (amt > 0)
-				applog(LOG_DEBUG, "Icarus Read: Timeout reading for %d ms", rc);
-			else
-				applog(LOG_DEBUG, "Icarus Read: No data for %d ms", rc);
-			return ICA_NONCE_TIMEOUT;
-		}
-
-		if (thr && thr->work_restart) {
-			applog(LOG_DEBUG, "Icarus Read: Work restart at %d ms", rc);
-			return ICA_NONCE_RESTART;
-		}
+	if (icarus->usbinfo.nodev)
+		return ICA_NONCE_ERROR;
 
 
-		if (amt > 0) {
-			buf += amt;
-			read_amount -= amt;
-			first = false;
-		}
+	cgtime(tv_start);
+	err = usb_read_ii_timeout_cancellable(icarus, info->intinfo, (char *)buf,
+					      ICARUS_READ_SIZE, &amt, read_time,
+					      C_GETRESULTS);
+	cgtime(tv_finish);
+
+	if (err < 0 && err != LIBUSB_ERROR_TIMEOUT) {
+		applog(LOG_ERR, "%s%i: Comms error (rerr=%d amt=%d)", icarus->drv->name,
+		       icarus->device_id, err, amt);
+		dev_error(icarus, REASON_DEV_COMMS_ERROR);
+		return ICA_NONCE_ERROR;
+	}
 
 
-		if (info->timeout < ICARUS_WAIT_TIMEOUT) {
-			delay = ICARUS_WAIT_TIMEOUT - rc;
-			if (delay > 0) {
-				cgsleep_ms(delay);
+	if (amt >= ICARUS_READ_SIZE)
+		return ICA_NONCE_OK;
 
 
-				if (thr && thr->work_restart) {
-					applog(LOG_DEBUG, "Icarus Read: Work restart at %d ms", rc);
-					return ICA_NONCE_RESTART;
-				}
-			}
-		}
+	rc = SECTOMS(tdiff(tv_finish, tv_start));
+	if (thr && thr->work_restart) {
+		applog(LOG_DEBUG, "Icarus Read: Work restart at %d ms", rc);
+		return ICA_NONCE_RESTART;
 	}
 	}
+
+	if (amt > 0)
+		applog(LOG_DEBUG, "Icarus Read: Timeout reading for %d ms", rc);
+	else
+		applog(LOG_DEBUG, "Icarus Read: No data for %d ms", rc);
+	return ICA_NONCE_TIMEOUT;
 }
 }
 
 
 static const char *timing_mode_str(enum timing_mode timing_mode)
 static const char *timing_mode_str(enum timing_mode timing_mode)

+ 6 - 0
miner.h

@@ -364,7 +364,10 @@ struct device_drv {
 	 * the main loop that it should not add any further work to the table.
 	 * the main loop that it should not add any further work to the table.
 	 */
 	 */
 	bool (*queue_full)(struct cgpu_info *);
 	bool (*queue_full)(struct cgpu_info *);
+	/* Tell the driver of a block change */
 	void (*flush_work)(struct cgpu_info *);
 	void (*flush_work)(struct cgpu_info *);
+	/* Tell the driver of an updated work template for eg. stratum */
+	void (*update_work)(struct cgpu_info *);
 
 
 	void (*hw_error)(struct thr_info *);
 	void (*hw_error)(struct thr_info *);
 	void (*thread_shutdown)(struct thr_info *);
 	void (*thread_shutdown)(struct thr_info *);
@@ -612,6 +615,7 @@ struct thr_info {
 	double	rolling;
 	double	rolling;
 
 
 	bool	work_restart;
 	bool	work_restart;
+	bool	work_update;
 };
 };
 
 
 struct string_elist {
 struct string_elist {
@@ -990,6 +994,7 @@ struct pool;
 #define API_MCAST_CODE "FTW"
 #define API_MCAST_CODE "FTW"
 #define API_MCAST_ADDR "224.0.0.75"
 #define API_MCAST_ADDR "224.0.0.75"
 
 
+extern bool opt_work_update;
 extern bool opt_protocol;
 extern bool opt_protocol;
 extern bool have_longpoll;
 extern bool have_longpoll;
 extern char *opt_kernel_path;
 extern char *opt_kernel_path;
@@ -1385,6 +1390,7 @@ struct work {
 	unsigned char	hash2[32];
 	unsigned char	hash2[32];
 
 
 	int		rolls;
 	int		rolls;
+	int		drv_rolllimit; /* How much the driver can roll ntime */
 
 
 	dev_blk_ctx	blk;
 	dev_blk_ctx	blk;
 
 

+ 66 - 17
usbutils.c

@@ -95,9 +95,10 @@
 		.epinfos = _epinfosy \
 		.epinfos = _epinfosy \
 	}
 	}
 
 
-/* Keep a global counter of how many async transfers are in place to avoid
- * shutting down the usb polling thread while they exist. */
-int cgusb_transfers;
+/* Linked list of all async transfers in progress. Protected by cgusb_fd_lock.
+ * This allows us to not stop the usb polling thread till all are complete, and
+ * to find cancellable transfers. */
+static struct list_head ut_list;
 
 
 #ifdef USE_BFLSC
 #ifdef USE_BFLSC
 // N.B. transfer size is 512 with USB2.0, but only 64 with USB1.1
 // N.B. transfer size is 512 with USB2.0, but only 64 with USB1.1
@@ -2247,8 +2248,44 @@ static char *find_end(unsigned char *buf, unsigned char *ptr, int ptrlen, int to
 struct usb_transfer {
 struct usb_transfer {
 	cgsem_t cgsem;
 	cgsem_t cgsem;
 	struct libusb_transfer *transfer;
 	struct libusb_transfer *transfer;
+	bool cancellable;
+	struct list_head list;
 };
 };
 
 
+bool async_usb_transfers(void)
+{
+	bool ret;
+
+	cg_rlock(&cgusb_fd_lock);
+	ret = !list_empty(&ut_list);
+	cg_runlock(&cgusb_fd_lock);
+
+	return ret;
+}
+
+/* Cancellable transfers should only be labelled as such if it is safe for them
+ * to effectively mimic timing out early. This flag is usually used to signify
+ * a read is waiting on a non-critical response that takes a long time and the
+ * driver wishes it be aborted if work restart message has been sent. */
+void cancel_usb_transfers(void)
+{
+	struct usb_transfer *ut;
+	int cancellations = 0;
+
+	cg_wlock(&cgusb_fd_lock);
+	list_for_each_entry(ut, &ut_list, list) {
+		if (ut->cancellable) {
+			ut->cancellable = false;
+			libusb_cancel_transfer(ut->transfer);
+			cancellations++;
+		}
+	}
+	cg_wunlock(&cgusb_fd_lock);
+
+	if (cancellations)
+		applog(LOG_DEBUG, "Cancelled %d USB transfers", cancellations);
+}
+
 static void init_usb_transfer(struct usb_transfer *ut)
 static void init_usb_transfer(struct usb_transfer *ut)
 {
 {
 	cgsem_init(&ut->cgsem);
 	cgsem_init(&ut->cgsem);
@@ -2256,22 +2293,24 @@ static void init_usb_transfer(struct usb_transfer *ut)
 	if (unlikely(!ut->transfer))
 	if (unlikely(!ut->transfer))
 		quit(1, "Failed to libusb_alloc_transfer");
 		quit(1, "Failed to libusb_alloc_transfer");
 	ut->transfer->user_data = ut;
 	ut->transfer->user_data = ut;
+	ut->cancellable = false;
 }
 }
 
 
 static void complete_usb_transfer(struct usb_transfer *ut)
 static void complete_usb_transfer(struct usb_transfer *ut)
 {
 {
-	cgsem_destroy(&ut->cgsem);
-	libusb_free_transfer(ut->transfer);
-
 	cg_wlock(&cgusb_fd_lock);
 	cg_wlock(&cgusb_fd_lock);
-	cgusb_transfers--;
+	list_del(&ut->list);
 	cg_wunlock(&cgusb_fd_lock);
 	cg_wunlock(&cgusb_fd_lock);
+
+	cgsem_destroy(&ut->cgsem);
+	libusb_free_transfer(ut->transfer);
 }
 }
 
 
 static void LIBUSB_CALL transfer_callback(struct libusb_transfer *transfer)
 static void LIBUSB_CALL transfer_callback(struct libusb_transfer *transfer)
 {
 {
 	struct usb_transfer *ut = transfer->user_data;
 	struct usb_transfer *ut = transfer->user_data;
 
 
+	ut->cancellable = false;
 	cgsem_post(&ut->cgsem);
 	cgsem_post(&ut->cgsem);
 }
 }
 
 
@@ -2326,13 +2365,18 @@ static int callback_wait(struct usb_transfer *ut, int *transferred, unsigned int
 	return ret;
 	return ret;
 }
 }
 
 
-static int usb_submit_transfer(struct libusb_transfer *transfer)
+static int usb_submit_transfer(struct usb_transfer *ut, struct libusb_transfer *transfer,
+			       bool cancellable)
 {
 {
 	int err;
 	int err;
 
 
+	INIT_LIST_HEAD(&ut->list);
+
 	cg_wlock(&cgusb_fd_lock);
 	cg_wlock(&cgusb_fd_lock);
 	err = libusb_submit_transfer(transfer);
 	err = libusb_submit_transfer(transfer);
-	cgusb_transfers++;
+	if (likely(!err))
+		ut->cancellable = cancellable;
+	list_add(&ut->list, &ut_list);
 	cg_wunlock(&cgusb_fd_lock);
 	cg_wunlock(&cgusb_fd_lock);
 
 
 	return err;
 	return err;
@@ -2343,7 +2387,7 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo,
 		  int epinfo, unsigned char *data, int length,
 		  int epinfo, unsigned char *data, int length,
 		  int *transferred, unsigned int timeout,
 		  int *transferred, unsigned int timeout,
 		  struct cgpu_info *cgpu, __maybe_unused int mode,
 		  struct cgpu_info *cgpu, __maybe_unused int mode,
-		  enum usb_cmds cmd, __maybe_unused int seq)
+		  enum usb_cmds cmd, __maybe_unused int seq, bool cancellable)
 {
 {
 	struct usb_epinfo *usb_epinfo;
 	struct usb_epinfo *usb_epinfo;
 	struct usb_transfer ut;
 	struct usb_transfer ut;
@@ -2381,7 +2425,7 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo,
 	libusb_fill_bulk_transfer(ut.transfer, dev_handle, endpoint, buf, length,
 	libusb_fill_bulk_transfer(ut.transfer, dev_handle, endpoint, buf, length,
 				  transfer_callback, &ut, 0);
 				  transfer_callback, &ut, 0);
 	STATS_TIMEVAL(&tv_start);
 	STATS_TIMEVAL(&tv_start);
-	err = usb_submit_transfer(ut.transfer);
+	err = usb_submit_transfer(&ut, ut.transfer, cancellable);
 	errn = errno;
 	errn = errno;
 	if (!err)
 	if (!err)
 		err = callback_wait(&ut, transferred, timeout);
 		err = callback_wait(&ut, transferred, timeout);
@@ -2417,7 +2461,7 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo,
 	return err;
 	return err;
 }
 }
 
 
-int _usb_read(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_t bufsiz, int *processed, unsigned int timeout, const char *end, enum usb_cmds cmd, bool readonce)
+int _usb_read(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_t bufsiz, int *processed, unsigned int timeout, const char *end, enum usb_cmds cmd, bool readonce, bool cancellable)
 {
 {
 	struct cg_usb_device *usbdev;
 	struct cg_usb_device *usbdev;
 	bool ftdi;
 	bool ftdi;
@@ -2500,7 +2544,8 @@ int _usb_read(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_t
 			}
 			}
 			err = usb_bulk_transfer(usbdev->handle, intinfo, epinfo,
 			err = usb_bulk_transfer(usbdev->handle, intinfo, epinfo,
 						ptr, usbbufread, &got, timeout,
 						ptr, usbbufread, &got, timeout,
-						cgpu, MODE_BULK_READ, cmd, first ? SEQ0 : SEQ1);
+						cgpu, MODE_BULK_READ, cmd, first ? SEQ0 : SEQ1,
+						cancellable);
 			cgtime(&tv_finish);
 			cgtime(&tv_finish);
 			ptr[got] = '\0';
 			ptr[got] = '\0';
 
 
@@ -2600,7 +2645,8 @@ int _usb_read(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_t
 		}
 		}
 		err = usb_bulk_transfer(usbdev->handle, intinfo, epinfo,
 		err = usb_bulk_transfer(usbdev->handle, intinfo, epinfo,
 					ptr, usbbufread, &got, timeout,
 					ptr, usbbufread, &got, timeout,
-					cgpu, MODE_BULK_READ, cmd, first ? SEQ0 : SEQ1);
+					cgpu, MODE_BULK_READ, cmd, first ? SEQ0 : SEQ1,
+					cancellable);
 		cgtime(&tv_finish);
 		cgtime(&tv_finish);
 		ptr[got] = '\0';
 		ptr[got] = '\0';
 
 
@@ -2749,7 +2795,8 @@ int _usb_write(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_
 		}
 		}
 		err = usb_bulk_transfer(usbdev->handle, intinfo, epinfo,
 		err = usb_bulk_transfer(usbdev->handle, intinfo, epinfo,
 					(unsigned char *)buf, bufsiz, &sent, timeout,
 					(unsigned char *)buf, bufsiz, &sent, timeout,
-					cgpu, MODE_BULK_WRITE, cmd, first ? SEQ0 : SEQ1);
+					cgpu, MODE_BULK_WRITE, cmd, first ? SEQ0 : SEQ1,
+					false);
 		cgtime(&tv_finish);
 		cgtime(&tv_finish);
 
 
 		USBDEBUG("USB debug: @_usb_write(%s (nodev=%s)) err=%d%s sent=%d", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), err, isnodev(err), sent);
 		USBDEBUG("USB debug: @_usb_write(%s (nodev=%s)) err=%d%s sent=%d", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), err, isnodev(err), sent);
@@ -2815,7 +2862,7 @@ static int usb_control_transfer(struct cgpu_info *cgpu, libusb_device_handle *de
 		memcpy(buf + LIBUSB_CONTROL_SETUP_SIZE, buffer, wLength);
 		memcpy(buf + LIBUSB_CONTROL_SETUP_SIZE, buffer, wLength);
 	libusb_fill_control_transfer(ut.transfer, dev_handle, buf, transfer_callback,
 	libusb_fill_control_transfer(ut.transfer, dev_handle, buf, transfer_callback,
 				     &ut, 0);
 				     &ut, 0);
-	err = usb_submit_transfer(ut.transfer);
+	err = usb_submit_transfer(&ut, ut.transfer, false);
 	if (!err)
 	if (!err)
 		err = callback_wait(&ut, &transferred, timeout);
 		err = callback_wait(&ut, &transferred, timeout);
 	if (err == LIBUSB_SUCCESS && transferred) {
 	if (err == LIBUSB_SUCCESS && transferred) {
@@ -3320,12 +3367,14 @@ void usb_cleanup(void)
 	drv_count[X##_drv.drv_id].limit = lim; \
 	drv_count[X##_drv.drv_id].limit = lim; \
 	found = true; \
 	found = true; \
 	}
 	}
-void usb_initialise()
+void usb_initialise(void)
 {
 {
 	char *fre, *ptr, *comma, *colon;
 	char *fre, *ptr, *comma, *colon;
 	int bus, dev, lim, i;
 	int bus, dev, lim, i;
 	bool found;
 	bool found;
 
 
+	INIT_LIST_HEAD(&ut_list);
+
 	for (i = 0; i < DRIVER_MAX; i++) {
 	for (i = 0; i < DRIVER_MAX; i++) {
 		drv_count[i].count = 0;
 		drv_count[i].count = 0;
 		drv_count[i].limit = 999999;
 		drv_count[i].limit = 999999;

+ 29 - 17
usbutils.h

@@ -117,8 +117,6 @@
 #define DEFAULT_EP_IN 0
 #define DEFAULT_EP_IN 0
 #define DEFAULT_EP_OUT 1
 #define DEFAULT_EP_OUT 1
 
 
-int cgusb_transfers;
-
 struct usb_epinfo {
 struct usb_epinfo {
 	uint8_t att;
 	uint8_t att;
 	uint16_t size;
 	uint16_t size;
@@ -376,6 +374,8 @@ enum usb_cmds {
 struct device_drv;
 struct device_drv;
 struct cgpu_info;
 struct cgpu_info;
 
 
+bool async_usb_transfers(void);
+void cancel_usb_transfers(void);
 void usb_all(int level);
 void usb_all(int level);
 const char *usb_cmdname(enum usb_cmds cmd);
 const char *usb_cmdname(enum usb_cmds cmd);
 void usb_applog(struct cgpu_info *bflsc, enum usb_cmds cmd, char *msg, int amount, int err);
 void usb_applog(struct cgpu_info *bflsc, enum usb_cmds cmd, char *msg, int amount, int err);
@@ -387,7 +387,7 @@ bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find
 void usb_detect(struct device_drv *drv, bool (*device_detect)(struct libusb_device *, struct usb_find_devices *));
 void usb_detect(struct device_drv *drv, bool (*device_detect)(struct libusb_device *, struct usb_find_devices *));
 struct api_data *api_usb_stats(int *count);
 struct api_data *api_usb_stats(int *count);
 void update_usb_stats(struct cgpu_info *cgpu);
 void update_usb_stats(struct cgpu_info *cgpu);
-int _usb_read(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_t bufsiz, int *processed, unsigned int timeout, const char *end, enum usb_cmds cmd, bool readonce);
+int _usb_read(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_t bufsiz, int *processed, unsigned int timeout, const char *end, enum usb_cmds cmd, bool readonce, bool cancellable);
 int _usb_write(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_t bufsiz, int *processed, unsigned int timeout, enum usb_cmds);
 int _usb_write(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_t bufsiz, int *processed, unsigned int timeout, enum usb_cmds);
 int _usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint32_t *data, int siz, unsigned int timeout, enum usb_cmds cmd);
 int _usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint32_t *data, int siz, unsigned int timeout, enum usb_cmds cmd);
 int _usb_transfer_read(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, char *buf, int bufsiz, int *amount, unsigned int timeout, enum usb_cmds cmd);
 int _usb_transfer_read(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, char *buf, int bufsiz, int *amount, unsigned int timeout, enum usb_cmds cmd);
@@ -412,46 +412,58 @@ void usb_initialise();
 void *usb_resource_thread(void *userdata);
 void *usb_resource_thread(void *userdata);
 
 
 #define usb_read(cgpu, buf, bufsiz, read, cmd) \
 #define usb_read(cgpu, buf, bufsiz, read, cmd) \
-	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, false)
+	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, false, false)
+
+#define usb_read_cancellable(cgpu, buf, bufsiz, read, cmd) \
+	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, false, true)
 
 
 #define usb_read_ii(cgpu, intinfo, buf, bufsiz, read, cmd) \
 #define usb_read_ii(cgpu, intinfo, buf, bufsiz, read, cmd) \
-	_usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, false)
+	_usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, false, false)
 
 
 #define usb_read_once(cgpu, buf, bufsiz, read, cmd) \
 #define usb_read_once(cgpu, buf, bufsiz, read, cmd) \
-	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, true)
+	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, true, false)
 
 
 #define usb_read_ii_once(cgpu, intinfo, buf, bufsiz, read, cmd) \
 #define usb_read_ii_once(cgpu, intinfo, buf, bufsiz, read, cmd) \
-	_usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, true)
+	_usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, true, false)
 
 
 #define usb_read_once_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \
 #define usb_read_once_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \
-	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, true)
+	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, true, false)
+
+#define usb_read_once_timeout_cancellable(cgpu, buf, bufsiz, read, timeout, cmd) \
+	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, true, true)
 
 
 #define usb_read_ii_once_timeout(cgpu, intinfo, buf, bufsiz, read, timeout, cmd) \
 #define usb_read_ii_once_timeout(cgpu, intinfo, buf, bufsiz, read, timeout, cmd) \
-	_usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, true)
+	_usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, true, false)
 
 
 #define usb_read_nl(cgpu, buf, bufsiz, read, cmd) \
 #define usb_read_nl(cgpu, buf, bufsiz, read, cmd) \
-	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, "\n", cmd, false)
+	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, "\n", cmd, false, false)
 
 
 #define usb_read_nl_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \
 #define usb_read_nl_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \
-	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, "\n", cmd, false)
+	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, "\n", cmd, false, false)
 
 
 #define usb_read_ok(cgpu, buf, bufsiz, read, cmd) \
 #define usb_read_ok(cgpu, buf, bufsiz, read, cmd) \
-	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, "OK\n", cmd, false)
+	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, "OK\n", cmd, false, false)
 
 
 #define usb_read_ok_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \
 #define usb_read_ok_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \
-	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, "OK\n", cmd, false)
+	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, "OK\n", cmd, false, false)
 
 
 #define usb_read_ep(cgpu, ep, buf, bufsiz, read, cmd) \
 #define usb_read_ep(cgpu, ep, buf, bufsiz, read, cmd) \
-	_usb_read(cgpu, DEFAULT_INTINFO, ep, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, false)
+	_usb_read(cgpu, DEFAULT_INTINFO, ep, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, false, false)
 
 
 #define usb_read_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \
 #define usb_read_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \
-	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, false)
+	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, false, false)
+
+#define usb_read_timeout_cancellable(cgpu, buf, bufsiz, read, timeout, cmd) \
+	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, false, true)
 
 
 #define usb_read_ii_timeout(cgpu, intinfo, buf, bufsiz, read, timeout, cmd) \
 #define usb_read_ii_timeout(cgpu, intinfo, buf, bufsiz, read, timeout, cmd) \
-	_usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, false)
+	_usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, false, false)
+
+#define usb_read_ii_timeout_cancellable(cgpu, intinfo, buf, bufsiz, read, timeout, cmd) \
+	_usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, false, true)
 
 
 #define usb_read_ep_timeout(cgpu, ep, buf, bufsiz, read, timeout, cmd) \
 #define usb_read_ep_timeout(cgpu, ep, buf, bufsiz, read, timeout, cmd) \
-	_usb_read(cgpu, DEFAULT_INTINFO, ep, buf, bufsiz, read, timeout, NULL, cmd, false)
+	_usb_read(cgpu, DEFAULT_INTINFO, ep, buf, bufsiz, read, timeout, NULL, cmd, false, false)
 
 
 #define usb_write(cgpu, buf, bufsiz, wrote, cmd) \
 #define usb_write(cgpu, buf, bufsiz, wrote, cmd) \
 	_usb_write(cgpu, DEFAULT_INTINFO, DEFAULT_EP_OUT, buf, bufsiz, wrote, DEVTIMEOUT, cmd)
 	_usb_write(cgpu, DEFAULT_INTINFO, DEFAULT_EP_OUT, buf, bufsiz, wrote, DEVTIMEOUT, cmd)

+ 2 - 0
util.c

@@ -1610,6 +1610,8 @@ static bool parse_notify(struct pool *pool, json_t *val)
 	pool->getwork_requested++;
 	pool->getwork_requested++;
 	total_getworks++;
 	total_getworks++;
 	ret = true;
 	ret = true;
+	if (pool == current_pool())
+		opt_work_update = true;
 out:
 out:
 	return ret;
 	return ret;
 }
 }