From 2b075cccbfef6ea8343052426fa669bc1c41175a Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 24 Oct 2013 21:42:04 +1100 Subject: [PATCH 01/19] Create a linked list of potentially cancellable usb transfers. --- usbutils.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/usbutils.c b/usbutils.c index b9d6254e..05a3fd82 100644 --- a/usbutils.c +++ b/usbutils.c @@ -96,6 +96,12 @@ /* 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; +static struct list_head ct_list; + +struct cancellable_transfer { + cgsem_t *cgsem; + struct list_head list; +}; #ifdef USE_BFLSC // N.B. transfer size is 512 with USB2.0, but only 64 with USB1.1 @@ -2212,15 +2218,22 @@ static char *find_end(unsigned char *buf, unsigned char *ptr, int ptrlen, int to struct usb_transfer { cgsem_t cgsem; struct libusb_transfer *transfer; + bool cancellable; + struct cancellable_transfer ct; }; -static void init_usb_transfer(struct usb_transfer *ut) +static void init_usb_transfer(struct usb_transfer *ut, bool cancellable) { cgsem_init(&ut->cgsem); ut->transfer = libusb_alloc_transfer(0); if (unlikely(!ut->transfer)) quit(1, "Failed to libusb_alloc_transfer"); ut->transfer->user_data = ut; + if (cancellable) { + ut->cancellable = true; + INIT_LIST_HEAD(&ut->ct.list); + list_add(&ct_list, &ut->ct.list); + } } static void complete_usb_transfer(struct usb_transfer *ut) @@ -2231,6 +2244,9 @@ static void complete_usb_transfer(struct usb_transfer *ut) cg_wlock(&cgusb_fd_lock); cgusb_transfers--; cg_wunlock(&cgusb_fd_lock); + + if (ut->cancellable) + list_del(&ut->ct.list); } static void LIBUSB_CALL transfer_callback(struct libusb_transfer *transfer) @@ -2341,7 +2357,7 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo, USBDEBUG("USB debug: @usb_bulk_transfer(%s (nodev=%s),intinfo=%d,epinfo=%d,data=%p,length=%d,timeout=%u,mode=%d,cmd=%s,seq=%d) endpoint=%d", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), intinfo, epinfo, data, length, timeout, mode, usb_cmdname(cmd), seq, (int)endpoint); - init_usb_transfer(&ut); + init_usb_transfer(&ut, false); /* We give the transfer no timeout since we manage timeouts ourself */ libusb_fill_bulk_transfer(ut.transfer, dev_handle, endpoint, buf, length, transfer_callback, &ut, 0); @@ -2773,7 +2789,7 @@ static int usb_control_transfer(struct cgpu_info *cgpu, libusb_device_handle *de if (unlikely(cgpu->shutdown)) return libusb_control_transfer(dev_handle, bmRequestType, bRequest, wValue, wIndex, buffer, wLength, timeout); - init_usb_transfer(&ut); + init_usb_transfer(&ut, false); libusb_fill_control_setup(buf, bmRequestType, bRequest, wValue, wIndex, wLength); if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT) @@ -3284,12 +3300,14 @@ void usb_cleanup(void) drv_count[X##_drv.drv_id].limit = lim; \ found = true; \ } -void usb_initialise() +void usb_initialise(void) { char *fre, *ptr, *comma, *colon; int bus, dev, lim, i; bool found; + INIT_LIST_HEAD(&ct_list); + for (i = 0; i < DRIVER_MAX; i++) { drv_count[i].count = 0; drv_count[i].limit = 999999; From 19ec360f7c63f3d20355187610a6fa99831a2fdd Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 24 Oct 2013 21:45:41 +1100 Subject: [PATCH 02/19] Pass the cancellable option to _usb_read options to decide on whether to add usb transfers to the list of cancellable transfers. --- usbutils.c | 15 +++++++++------ usbutils.h | 30 +++++++++++++++--------------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/usbutils.c b/usbutils.c index 05a3fd82..4e06d217 100644 --- a/usbutils.c +++ b/usbutils.c @@ -2324,7 +2324,7 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo, int epinfo, unsigned char *data, int length, int *transferred, unsigned int timeout, 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_transfer ut; @@ -2357,7 +2357,7 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo, USBDEBUG("USB debug: @usb_bulk_transfer(%s (nodev=%s),intinfo=%d,epinfo=%d,data=%p,length=%d,timeout=%u,mode=%d,cmd=%s,seq=%d) endpoint=%d", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), intinfo, epinfo, data, length, timeout, mode, usb_cmdname(cmd), seq, (int)endpoint); - init_usb_transfer(&ut, false); + init_usb_transfer(&ut, cancellable); /* We give the transfer no timeout since we manage timeouts ourself */ libusb_fill_bulk_transfer(ut.transfer, dev_handle, endpoint, buf, length, transfer_callback, &ut, 0); @@ -2398,7 +2398,7 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo, 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; bool ftdi; @@ -2481,7 +2481,8 @@ int _usb_read(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_t } err = usb_bulk_transfer(usbdev->handle, intinfo, epinfo, ptr, usbbufread, &got, timeout, - cgpu, MODE_BULK_READ, cmd, first ? SEQ0 : SEQ1); + cgpu, MODE_BULK_READ, cmd, first ? SEQ0 : SEQ1, + cancellable); cgtime(&tv_finish); ptr[got] = '\0'; @@ -2581,7 +2582,8 @@ int _usb_read(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_t } err = usb_bulk_transfer(usbdev->handle, intinfo, epinfo, ptr, usbbufread, &got, timeout, - cgpu, MODE_BULK_READ, cmd, first ? SEQ0 : SEQ1); + cgpu, MODE_BULK_READ, cmd, first ? SEQ0 : SEQ1, + cancellable); cgtime(&tv_finish); ptr[got] = '\0'; @@ -2730,7 +2732,8 @@ int _usb_write(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_ } err = usb_bulk_transfer(usbdev->handle, intinfo, epinfo, (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); 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); diff --git a/usbutils.h b/usbutils.h index 68031e58..98e37289 100644 --- a/usbutils.h +++ b/usbutils.h @@ -367,7 +367,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 *)); struct api_data *api_usb_stats(int *count); 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_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); @@ -392,46 +392,46 @@ void usb_initialise(); void *usb_resource_thread(void *userdata); #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_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) \ - _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) \ - _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) \ - _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_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) \ - _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) \ - _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) \ - _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) \ - _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) \ - _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) \ - _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_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_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) \ _usb_write(cgpu, DEFAULT_INTINFO, DEFAULT_EP_OUT, buf, bufsiz, wrote, DEVTIMEOUT, cmd) From b52bb5c9e2e652ca6f2292deafbb4ecea419e81d Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 24 Oct 2013 21:50:52 +1100 Subject: [PATCH 03/19] Alter the usb cancellable list only under cgusb_fd_lock write lock. --- usbutils.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/usbutils.c b/usbutils.c index 4e06d217..6fe3e63e 100644 --- a/usbutils.c +++ b/usbutils.c @@ -2222,18 +2222,13 @@ struct usb_transfer { struct cancellable_transfer ct; }; -static void init_usb_transfer(struct usb_transfer *ut, bool cancellable) +static void init_usb_transfer(struct usb_transfer *ut) { cgsem_init(&ut->cgsem); ut->transfer = libusb_alloc_transfer(0); if (unlikely(!ut->transfer)) quit(1, "Failed to libusb_alloc_transfer"); ut->transfer->user_data = ut; - if (cancellable) { - ut->cancellable = true; - INIT_LIST_HEAD(&ut->ct.list); - list_add(&ct_list, &ut->ct.list); - } } static void complete_usb_transfer(struct usb_transfer *ut) @@ -2243,10 +2238,9 @@ static void complete_usb_transfer(struct usb_transfer *ut) cg_wlock(&cgusb_fd_lock); cgusb_transfers--; - cg_wunlock(&cgusb_fd_lock); - if (ut->cancellable) list_del(&ut->ct.list); + cg_wunlock(&cgusb_fd_lock); } static void LIBUSB_CALL transfer_callback(struct libusb_transfer *transfer) @@ -2307,13 +2301,19 @@ static int callback_wait(struct usb_transfer *ut, int *transferred, unsigned int 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; cg_wlock(&cgusb_fd_lock); err = libusb_submit_transfer(transfer); cgusb_transfers++; + if (cancellable) { + ut->cancellable = true; + INIT_LIST_HEAD(&ut->ct.list); + list_add(&ct_list, &ut->ct.list); + } cg_wunlock(&cgusb_fd_lock); return err; @@ -2357,12 +2357,12 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo, USBDEBUG("USB debug: @usb_bulk_transfer(%s (nodev=%s),intinfo=%d,epinfo=%d,data=%p,length=%d,timeout=%u,mode=%d,cmd=%s,seq=%d) endpoint=%d", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), intinfo, epinfo, data, length, timeout, mode, usb_cmdname(cmd), seq, (int)endpoint); - init_usb_transfer(&ut, cancellable); + init_usb_transfer(&ut); /* We give the transfer no timeout since we manage timeouts ourself */ libusb_fill_bulk_transfer(ut.transfer, dev_handle, endpoint, buf, length, transfer_callback, &ut, 0); STATS_TIMEVAL(&tv_start); - err = usb_submit_transfer(ut.transfer); + err = usb_submit_transfer(&ut, ut.transfer, cancellable); errn = errno; if (!err) err = callback_wait(&ut, transferred, timeout); @@ -2792,14 +2792,14 @@ static int usb_control_transfer(struct cgpu_info *cgpu, libusb_device_handle *de if (unlikely(cgpu->shutdown)) return libusb_control_transfer(dev_handle, bmRequestType, bRequest, wValue, wIndex, buffer, wLength, timeout); - init_usb_transfer(&ut, false); + init_usb_transfer(&ut); libusb_fill_control_setup(buf, bmRequestType, bRequest, wValue, wIndex, wLength); if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT) memcpy(buf + LIBUSB_CONTROL_SETUP_SIZE, buffer, wLength); libusb_fill_control_transfer(ut.transfer, dev_handle, buf, transfer_callback, &ut, 0); - err = usb_submit_transfer(ut.transfer); + err = usb_submit_transfer(&ut, ut.transfer, false); if (!err) err = callback_wait(&ut, &transferred, timeout); if (err == LIBUSB_SUCCESS && transferred) { From c2c698778416fde00eab91e1b96b37a0b5b24253 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 24 Oct 2013 21:52:50 +1100 Subject: [PATCH 04/19] Specifically set the cancellable state for it to not be uninitialised in the usb transfer struct. --- usbutils.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/usbutils.c b/usbutils.c index 6fe3e63e..232e19f0 100644 --- a/usbutils.c +++ b/usbutils.c @@ -2313,7 +2313,8 @@ static int usb_submit_transfer(struct usb_transfer *ut, struct libusb_transfer * ut->cancellable = true; INIT_LIST_HEAD(&ut->ct.list); list_add(&ct_list, &ut->ct.list); - } + } else + ut->cancellable = false;; cg_wunlock(&cgusb_fd_lock); return err; From c96f096577bb1d90096ae3801afd3cf25cdd51f4 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 24 Oct 2013 21:54:35 +1100 Subject: [PATCH 05/19] Add wrappers for usb_read_cancellable and usb_read_timeout_cancellable --- usbutils.c | 2 +- usbutils.h | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/usbutils.c b/usbutils.c index 232e19f0..19d1854b 100644 --- a/usbutils.c +++ b/usbutils.c @@ -2314,7 +2314,7 @@ static int usb_submit_transfer(struct usb_transfer *ut, struct libusb_transfer * INIT_LIST_HEAD(&ut->ct.list); list_add(&ct_list, &ut->ct.list); } else - ut->cancellable = false;; + ut->cancellable = false; cg_wunlock(&cgusb_fd_lock); return err; diff --git a/usbutils.h b/usbutils.h index 98e37289..2750c098 100644 --- a/usbutils.h +++ b/usbutils.h @@ -394,6 +394,9 @@ void *usb_resource_thread(void *userdata); #define usb_read(cgpu, buf, bufsiz, read, cmd) \ _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) \ _usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, false, false) @@ -427,6 +430,9 @@ void *usb_resource_thread(void *userdata); #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, 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) \ _usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, false, false) From 51660838da165b6a11c489ab032ef9b6a2080ffa Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 24 Oct 2013 21:58:25 +1100 Subject: [PATCH 06/19] Don't bother having a separate cancellable transfer struct for usb transfers, simply include the list in the usb_transfer struct. --- usbutils.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/usbutils.c b/usbutils.c index 19d1854b..f5ccbd6c 100644 --- a/usbutils.c +++ b/usbutils.c @@ -98,11 +98,6 @@ int cgusb_transfers; static struct list_head ct_list; -struct cancellable_transfer { - cgsem_t *cgsem; - struct list_head list; -}; - #ifdef USE_BFLSC // N.B. transfer size is 512 with USB2.0, but only 64 with USB1.1 static struct usb_epinfo bas_epinfos[] = { @@ -2219,7 +2214,7 @@ struct usb_transfer { cgsem_t cgsem; struct libusb_transfer *transfer; bool cancellable; - struct cancellable_transfer ct; + struct list_head list; }; static void init_usb_transfer(struct usb_transfer *ut) @@ -2239,7 +2234,7 @@ static void complete_usb_transfer(struct usb_transfer *ut) cg_wlock(&cgusb_fd_lock); cgusb_transfers--; if (ut->cancellable) - list_del(&ut->ct.list); + list_del(&ut->list); cg_wunlock(&cgusb_fd_lock); } @@ -2311,8 +2306,8 @@ static int usb_submit_transfer(struct usb_transfer *ut, struct libusb_transfer * cgusb_transfers++; if (cancellable) { ut->cancellable = true; - INIT_LIST_HEAD(&ut->ct.list); - list_add(&ct_list, &ut->ct.list); + INIT_LIST_HEAD(&ut->list); + list_add(&ct_list, &ut->list); } else ut->cancellable = false; cg_wunlock(&cgusb_fd_lock); From d2feacdfb2a03c56f873d7391030db892745533a Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 24 Oct 2013 22:26:13 +1100 Subject: [PATCH 07/19] Cancel cancellable usb transfers on work restart messages. --- cgminer.c | 4 ++++ usbutils.c | 16 ++++++++++++++++ usbutils.h | 4 ++++ 3 files changed, 24 insertions(+) diff --git a/cgminer.c b/cgminer.c index d2982415..07bd7900 100644 --- a/cgminer.c +++ b/cgminer.c @@ -3929,6 +3929,10 @@ static void restart_threads(void) mutex_lock(&restart_lock); pthread_cond_broadcast(&restart_cond); mutex_unlock(&restart_lock); + +#ifdef USE_USBUTILS + cancel_usb_transfers(); +#endif } static void set_curblock(char *hexstr, unsigned char *hash) diff --git a/usbutils.c b/usbutils.c index f5ccbd6c..90e890ae 100644 --- a/usbutils.c +++ b/usbutils.c @@ -2217,6 +2217,22 @@ struct usb_transfer { struct list_head list; }; +void cancel_usb_transfers(void) +{ + struct usb_transfer *ut; + int cancellations = 0; + + cg_rlock(&cgusb_fd_lock); + list_for_each_entry(ut, &ct_list, list) { + libusb_cancel_transfer(ut->transfer); + cancellations++; + } + cg_runlock(&cgusb_fd_lock); + + if (cancellations) + applog(LOG_DEBUG, "Cancelled %d USB transfers", cancellations); +} + static void init_usb_transfer(struct usb_transfer *ut) { cgsem_init(&ut->cgsem); diff --git a/usbutils.h b/usbutils.h index 2750c098..22533376 100644 --- a/usbutils.h +++ b/usbutils.h @@ -356,6 +356,7 @@ enum usb_cmds { struct device_drv; struct cgpu_info; +void cancel_usb_transfers(void); void usb_all(int level); 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); @@ -409,6 +410,9 @@ void *usb_resource_thread(void *userdata); #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, 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) \ _usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, true, false) From eb5b611483587f05df7799fd50c6e89c32ffb55c Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 24 Oct 2013 22:26:48 +1100 Subject: [PATCH 08/19] Use cancellable transfers on bitfury device. --- driver-bitfury.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/driver-bitfury.c b/driver-bitfury.c index e5757f5b..260f4f60 100644 --- a/driver-bitfury.c +++ b/driver-bitfury.c @@ -248,7 +248,7 @@ static int64_t bitfury_scanwork(struct thr_info *thr) cgtime(&tv_now); ms_diff = 600 - ms_tdiff(&tv_now, &info->tv_start); 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; } @@ -261,8 +261,8 @@ static int64_t bitfury_scanwork(struct thr_info *thr) 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, 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; while (amount) { usb_read_once_timeout(bitfury, info->buf + info->tot, 512, &amount, 10, C_BF1_GETRES); From 9d8e3df0a8f0fed49961061a8077728effa8975d Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 25 Oct 2013 04:07:09 +1100 Subject: [PATCH 09/19] Add usb transfer cancellation on shutdown and documentation regarding where cancellable transfers are suitable. --- cgminer.c | 6 ++++++ usbutils.c | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/cgminer.c b/cgminer.c index 07bd7900..d7d91ef0 100644 --- a/cgminer.c +++ b/cgminer.c @@ -3931,6 +3931,9 @@ static void restart_threads(void) 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 } @@ -7814,6 +7817,9 @@ static void *libusb_poll_thread(void __maybe_unused *arg) while (usb_polling) 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 * flight. */ do { diff --git a/usbutils.c b/usbutils.c index 90e890ae..58114137 100644 --- a/usbutils.c +++ b/usbutils.c @@ -2217,6 +2217,10 @@ struct usb_transfer { struct list_head list; }; +/* 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; From 2b998936fe240bc1904629d359ddf76ae1ac31fe Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 25 Oct 2013 04:13:32 +1100 Subject: [PATCH 10/19] Add a usb_read_ii_timeout_cancellable wrapper --- usbutils.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/usbutils.h b/usbutils.h index 22533376..52441be8 100644 --- a/usbutils.h +++ b/usbutils.h @@ -440,6 +440,9 @@ void *usb_resource_thread(void *userdata); #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, 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) \ _usb_read(cgpu, DEFAULT_INTINFO, ep, buf, bufsiz, read, timeout, NULL, cmd, false, false) From f8fdff4ad2fa9810c96d4034851d7f4008996c67 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 25 Oct 2013 04:25:32 +1100 Subject: [PATCH 11/19] Use cancellable usb transfers in the icarus driver to avoid having to loop and poll when waiting for a response and to speed up work restart response time. --- driver-icarus.c | 86 +++++++++++++++++-------------------------------- 1 file changed, 29 insertions(+), 57 deletions(-) diff --git a/driver-icarus.c b/driver-icarus.c index 871e1783..5b0af8d9 100644 --- a/driver-icarus.c +++ b/driver-icarus.c @@ -471,70 +471,42 @@ static void rev(unsigned char *s, size_t l) #define ICA_NONCE_RESTART 1 #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 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->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) From e22035f02491573b326581f05e55e5ee08803c72 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 25 Oct 2013 05:10:08 +1100 Subject: [PATCH 12/19] Check for presence of thr in icarus get nonce for startup nonce testing to work. --- driver-icarus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-icarus.c b/driver-icarus.c index 5b0af8d9..43a460eb 100644 --- a/driver-icarus.c +++ b/driver-icarus.c @@ -497,7 +497,7 @@ static int icarus_get_nonce(struct cgpu_info *icarus, unsigned char *buf, struct return ICA_NONCE_OK; rc = SECTOMS(tdiff(tv_finish, tv_start)); - if (thr->work_restart) { + if (thr && thr->work_restart) { applog(LOG_DEBUG, "Icarus Read: Work restart at %d ms", rc); return ICA_NONCE_RESTART; } From 7b5884caa58b4611e9a9efcec59270fb9e22409e Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 25 Oct 2013 08:43:55 +1100 Subject: [PATCH 13/19] Add cancellable transfers correctly to the ct_list --- usbutils.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/usbutils.c b/usbutils.c index 58114137..5f41fd05 100644 --- a/usbutils.c +++ b/usbutils.c @@ -96,6 +96,8 @@ /* 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 cancellable transfers. */ static struct list_head ct_list; #ifdef USE_BFLSC @@ -2327,7 +2329,7 @@ static int usb_submit_transfer(struct usb_transfer *ut, struct libusb_transfer * if (cancellable) { ut->cancellable = true; INIT_LIST_HEAD(&ut->list); - list_add(&ct_list, &ut->list); + list_add(&ut->list, &ct_list); } else ut->cancellable = false; cg_wunlock(&cgusb_fd_lock); From d342bcbe8127443c3e19aabc344c0f8918548c59 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 25 Oct 2013 11:56:32 +1100 Subject: [PATCH 14/19] Provide a mechanism for informing drivers of updated work templates for stratum and gbt mining. --- cgminer.c | 30 +++++++++++++++++++++++++++--- miner.h | 5 +++++ util.c | 2 ++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/cgminer.c b/cgminer.c index d7d91ef0..cb4fa45c 100644 --- a/cgminer.c +++ b/cgminer.c @@ -90,6 +90,7 @@ struct strategies strategies[] = { static char packagename[256]; +bool opt_work_update; bool opt_protocol; static bool opt_benchmark; bool have_longpoll; @@ -1842,6 +1843,8 @@ static void update_gbt(struct pool *pool) applog(LOG_DEBUG, "Successfully retrieved and updated GBT from pool %u %s", pool->pool_no, pool->rpc_url); cgtime(&pool->tv_idle); + if (pool == current_pool()) + opt_work_update = true; } else { applog(LOG_DEBUG, "Successfully retrieved but FAILED to decipher GBT from pool %u %s", pool->pool_no, pool->rpc_url); @@ -3938,6 +3941,18 @@ static void restart_threads(void) #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) { unsigned char hash_swap[32]; @@ -6502,7 +6517,7 @@ void hash_queued_work(struct thr_info *mythr) struct timeval diff; int64_t hashes; - mythr->work_restart = false; + mythr->work_restart = mythr->work_update = false; fill_queue(mythr, cgpu, drv, thr_id); @@ -6532,7 +6547,8 @@ void hash_queued_work(struct thr_info *mythr) if (unlikely(mythr->work_restart)) { flush_queue(cgpu); drv->flush_work(cgpu); - } + } else if (mythr->work_update) + drv->update_work(cgpu); } cgpu->deven = DEV_DISABLED; } @@ -6553,7 +6569,7 @@ void hash_driver_work(struct thr_info *mythr) struct timeval diff; int64_t hashes; - mythr->work_restart = false; + mythr->work_restart = mythr->work_update = false; hashes = drv->scanwork(mythr); @@ -6580,6 +6596,8 @@ void hash_driver_work(struct thr_info *mythr) if (unlikely(mythr->work_restart)) drv->flush_work(cgpu); + else if (mythr->work_update) + drv->update_work(cgpu); } cgpu->deven = DEV_DISABLED; } @@ -7560,6 +7578,7 @@ static void noop_detect(bool __maybe_unused hotplug) { } #define noop_flush_work noop_reinit_device +#define noop_update_work noop_reinit_device #define noop_queue_full noop_get_stats /* Fill missing driver drv functions with noops */ @@ -7593,6 +7612,8 @@ void fill_device_drv(struct device_drv *drv) drv->hash_work = &hash_sole_work; if (!drv->flush_work) drv->flush_work = &noop_flush_work; + if (!drv->update_work) + drv->update_work = &noop_update_work; if (!drv->queue_full) drv->queue_full = &noop_queue_full; if (!drv->max_diff) @@ -8316,6 +8337,9 @@ begin_bench: bool lagging = false; struct work *work; + if (opt_work_update) + signal_work_update(); + opt_work_update = false; cp = current_pool(); /* If the primary pool is a getwork pool and cannot roll work, diff --git a/miner.h b/miner.h index 4e3b5a17..9087c27e 100644 --- a/miner.h +++ b/miner.h @@ -363,7 +363,10 @@ struct device_drv { * the main loop that it should not add any further work to the table. */ bool (*queue_full)(struct cgpu_info *); + /* Tell the driver of a block change */ 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 (*thread_shutdown)(struct thr_info *); @@ -611,6 +614,7 @@ struct thr_info { double rolling; bool work_restart; + bool work_update; }; struct string_elist { @@ -989,6 +993,7 @@ struct pool; #define API_MCAST_CODE "FTW" #define API_MCAST_ADDR "224.0.0.75" +extern bool opt_work_update; extern bool opt_protocol; extern bool have_longpoll; extern char *opt_kernel_path; diff --git a/util.c b/util.c index 87d7bac6..363c73c4 100644 --- a/util.c +++ b/util.c @@ -1610,6 +1610,8 @@ static bool parse_notify(struct pool *pool, json_t *val) pool->getwork_requested++; total_getworks++; ret = true; + if (pool == current_pool()) + opt_work_update = true; out: return ret; } From 0da551fac14c907b125dfc3633977632d101cfd7 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 25 Oct 2013 12:30:39 +1100 Subject: [PATCH 15/19] Use a linked list for all usb transfers instead of just cancellable ones. --- cgminer.c | 8 +------- usbutils.c | 58 +++++++++++++++++++++++++++++++----------------------- usbutils.h | 3 +-- 3 files changed, 35 insertions(+), 34 deletions(-) diff --git a/cgminer.c b/cgminer.c index cb4fa45c..44b51c56 100644 --- a/cgminer.c +++ b/cgminer.c @@ -7831,7 +7831,6 @@ static void probe_pools(void) static void *libusb_poll_thread(void __maybe_unused *arg) { struct timeval tv_end = {1, 0}; - bool inprogress = false; RenameThread("usbpoll"); @@ -7843,14 +7842,9 @@ static void *libusb_poll_thread(void __maybe_unused *arg) /* Keep event handling going until there are no async transfers in * flight. */ - do { + while (async_usb_transfers()) libusb_handle_events_timeout_completed(NULL, &tv_end, NULL); - cg_rlock(&cgusb_fd_lock); - inprogress = !!cgusb_transfers; - cg_runlock(&cgusb_fd_lock); - } while (inprogress); - return NULL; } diff --git a/usbutils.c b/usbutils.c index 5f41fd05..201bd899 100644 --- a/usbutils.c +++ b/usbutils.c @@ -93,12 +93,10 @@ .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 cancellable transfers. */ -static struct list_head ct_list; +/* 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 // N.B. transfer size is 512 with USB2.0, but only 64 with USB1.1 @@ -2219,6 +2217,17 @@ struct usb_transfer { 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 @@ -2228,12 +2237,15 @@ void cancel_usb_transfers(void) struct usb_transfer *ut; int cancellations = 0; - cg_rlock(&cgusb_fd_lock); - list_for_each_entry(ut, &ct_list, list) { - libusb_cancel_transfer(ut->transfer); - cancellations++; + 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_runlock(&cgusb_fd_lock); + cg_wunlock(&cgusb_fd_lock); if (cancellations) applog(LOG_DEBUG, "Cancelled %d USB transfers", cancellations); @@ -2250,20 +2262,19 @@ static void init_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); - cgusb_transfers--; - if (ut->cancellable) - list_del(&ut->list); + list_del(&ut->list); cg_wunlock(&cgusb_fd_lock); + + cgsem_destroy(&ut->cgsem); + libusb_free_transfer(ut->transfer); } static void LIBUSB_CALL transfer_callback(struct libusb_transfer *transfer) { struct usb_transfer *ut = transfer->user_data; + ut->cancellable = false; cgsem_post(&ut->cgsem); } @@ -2323,15 +2334,12 @@ static int usb_submit_transfer(struct usb_transfer *ut, struct libusb_transfer * { int err; + INIT_LIST_HEAD(&ut->list); + ut->cancellable = cancellable; + cg_wlock(&cgusb_fd_lock); err = libusb_submit_transfer(transfer); - cgusb_transfers++; - if (cancellable) { - ut->cancellable = true; - INIT_LIST_HEAD(&ut->list); - list_add(&ut->list, &ct_list); - } else - ut->cancellable = false; + list_add(&ut->list, &ut_list); cg_wunlock(&cgusb_fd_lock); return err; @@ -3327,7 +3335,7 @@ void usb_initialise(void) int bus, dev, lim, i; bool found; - INIT_LIST_HEAD(&ct_list); + INIT_LIST_HEAD(&ut_list); for (i = 0; i < DRIVER_MAX; i++) { drv_count[i].count = 0; diff --git a/usbutils.h b/usbutils.h index 52441be8..2c9e5ad2 100644 --- a/usbutils.h +++ b/usbutils.h @@ -117,8 +117,6 @@ #define DEFAULT_EP_IN 0 #define DEFAULT_EP_OUT 1 -int cgusb_transfers; - struct usb_epinfo { uint8_t att; uint16_t size; @@ -356,6 +354,7 @@ enum usb_cmds { struct device_drv; struct cgpu_info; +bool async_usb_transfers(void); void cancel_usb_transfers(void); void usb_all(int level); const char *usb_cmdname(enum usb_cmds cmd); From 4c979d756fb94b28317d01b10aec02b647fbcf81 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 25 Oct 2013 12:46:47 +1100 Subject: [PATCH 16/19] Do one extra guaranteed libusb event handling before testing if there are any pending async usb transfers. --- cgminer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 44b51c56..993ad320 100644 --- a/cgminer.c +++ b/cgminer.c @@ -7842,8 +7842,9 @@ static void *libusb_poll_thread(void __maybe_unused *arg) /* Keep event handling going until there are no async transfers in * flight. */ - while (async_usb_transfers()) + do { libusb_handle_events_timeout_completed(NULL, &tv_end, NULL); + } while (async_usb_transfers()); return NULL; } From 4728dd82d1842d6387b9e10006a47282f6f36ef6 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 25 Oct 2013 12:54:10 +1100 Subject: [PATCH 17/19] Remove the applog on miner threads dying to prevent deadlocks on exit. --- cgminer.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/cgminer.c b/cgminer.c index 993ad320..5caf08a1 100644 --- a/cgminer.c +++ b/cgminer.c @@ -6626,8 +6626,6 @@ void *miner_thread(void *userdata) out: drv->thread_shutdown(mythr); - applog(LOG_ERR, "Thread %d failure, exiting", thr_id); - return NULL; } From 0657b64e388ff484c94b87870680b245c8acaabf Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 25 Oct 2013 13:36:21 +1100 Subject: [PATCH 18/19] Only set libusb cancellable status if the transfer succeeds. --- usbutils.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/usbutils.c b/usbutils.c index 201bd899..3e32b81c 100644 --- a/usbutils.c +++ b/usbutils.c @@ -2258,6 +2258,7 @@ static void init_usb_transfer(struct usb_transfer *ut) if (unlikely(!ut->transfer)) quit(1, "Failed to libusb_alloc_transfer"); ut->transfer->user_data = ut; + ut->cancellable = false; } static void complete_usb_transfer(struct usb_transfer *ut) @@ -2335,10 +2336,11 @@ static int usb_submit_transfer(struct usb_transfer *ut, struct libusb_transfer * int err; INIT_LIST_HEAD(&ut->list); - ut->cancellable = cancellable; cg_wlock(&cgusb_fd_lock); err = libusb_submit_transfer(transfer); + if (likely(!err)) + ut->cancellable = cancellable; list_add(&ut->list, &ut_list); cg_wunlock(&cgusb_fd_lock); From 316e6d61c9631214d92472524254ba1c4d960872 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 25 Oct 2013 14:29:43 +1100 Subject: [PATCH 19/19] Put an entry into the work struct telling drivers how much they can roll the ntime themselves. --- cgminer.c | 4 ++++ miner.h | 1 + 2 files changed, 5 insertions(+) diff --git a/cgminer.c b/cgminer.c index 5caf08a1..dd43fa0e 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1911,6 +1911,8 @@ static void gen_gbt_work(struct pool *pool, struct work *work) work->longpoll = false; work->getwork_mode = GETWORK_MODE_GBT; work->work_block = work_block; + /* Nominally allow a driver to ntime roll 60 seconds */ + work->drv_rolllimit = 60; calc_diff(work, 0); cgtime(&work->tv_staged); } @@ -6013,6 +6015,8 @@ static void gen_stratum_work(struct pool *pool, struct work *work) work->longpoll = false; work->getwork_mode = GETWORK_MODE_STRATUM; work->work_block = work_block; + /* Nominally allow a driver to ntime roll 60 seconds */ + work->drv_rolllimit = 60; calc_diff(work, work->sdiff); cgtime(&work->tv_staged); diff --git a/miner.h b/miner.h index 9087c27e..874f1721 100644 --- a/miner.h +++ b/miner.h @@ -1389,6 +1389,7 @@ struct work { unsigned char hash2[32]; int rolls; + int drv_rolllimit; /* How much the driver can roll ntime */ dev_blk_ctx blk;