From b1b93054cd923f6f5ab0e8a7acd9528341f4bf90 Mon Sep 17 00:00:00 2001 From: Kano Date: Sun, 26 May 2013 08:34:06 +1000 Subject: [PATCH 1/3] usbutils handle bulk_transfer partial writes --- usbutils.c | 63 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 16 deletions(-) diff --git a/usbutils.c b/usbutils.c index 3b148059..1e272b99 100644 --- a/usbutils.c +++ b/usbutils.c @@ -2040,7 +2040,7 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro first = false; done = tdiff(&tv_finish, &read_start); - // N.B. this is return LIBUSB_SUCCESS with whatever size has already been read + // N.B. this is: return LIBUSB_SUCCESS with whatever size has already been read if (unlikely(done >= max)) break; @@ -2120,7 +2120,7 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro first = false; done = tdiff(&tv_finish, &read_start); - // N.B. this is return LIBUSB_SUCCESS with whatever size has already been read + // N.B. this is: return LIBUSB_SUCCESS with whatever size has already been read if (unlikely(done >= max)) break; @@ -2140,33 +2140,64 @@ int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pr { struct cg_usb_device *usbdev = cgpu->usbdev; #if DO_USB_STATS - struct timeval tv_start, tv_finish; + struct timeval tv_start; #endif - int err, sent; + struct timeval read_start, tv_finish; + unsigned int initial_timeout; + double max, done; + bool first = true; + int err, sent, tot; USBDEBUG("USB debug: _usb_write(%s (nodev=%s),ep=%d,buf='%s',bufsiz=%zu,proc=%p,timeout=%u,cmd=%s)", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), ep, (char *)str_text(buf), bufsiz, processed, timeout, usb_cmdname(cmd)); + *processed = 0; + if (cgpu->usbinfo.nodev) { - *processed = 0; #if DO_USB_STATS rejected_inc(cgpu); #endif return LIBUSB_ERROR_NO_DEVICE; } - sent = 0; - STATS_TIMEVAL(&tv_start); - err = libusb_bulk_transfer(usbdev->handle, - usbdev->found->eps[ep].ep, - (unsigned char *)buf, - bufsiz, &sent, - timeout == DEVTIMEOUT ? usbdev->found->timeout : timeout); - STATS_TIMEVAL(&tv_finish); - USB_STATS(cgpu, &tv_start, &tv_finish, err, cmd, SEQ0); + if (timeout == DEVTIMEOUT) + timeout = usbdev->found->timeout; - 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); + tot = 0; + err = LIBUSB_SUCCESS; + initial_timeout = timeout; + max = ((double)timeout) / 1000.0; + cgtime(&read_start); + while (bufsiz > 0) { + sent = 0; + STATS_TIMEVAL(&tv_start); + err = libusb_bulk_transfer(usbdev->handle, + usbdev->found->eps[ep].ep, + (unsigned char *)buf, + bufsiz, &sent, timeout); + STATS_TIMEVAL(&tv_finish); + USB_STATS(cgpu, &tv_start, &tv_finish, err, cmd, first ? SEQ0 : SEQ1); + + 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); + + tot += sent; + + if (err) + break; + + buf += sent; + bufsiz -= sent; + + first = false; + + done = tdiff(&tv_finish, &read_start); + // N.B. this is: return LIBUSB_SUCCESS with whatever size was written + if (unlikely(done >= max)) + break; - *processed = sent; + timeout = initial_timeout - (done * 1000); + } + + *processed = tot; if (NODEV(err)) release_cgpu(cgpu); From aa9bf2cbb92f2ca056f8fdb5fef9b1ff380cf992 Mon Sep 17 00:00:00 2001 From: Kano Date: Sun, 26 May 2013 10:33:47 +1000 Subject: [PATCH 2/3] usbutils include transfer mode in usbstats --- usbutils.c | 112 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 91 insertions(+), 21 deletions(-) diff --git a/usbutils.c b/usbutils.c index 1e272b99..83a774d3 100644 --- a/usbutils.c +++ b/usbutils.c @@ -338,6 +338,21 @@ static struct usb_in_use_list *in_use_head = NULL; static bool stats_initialised = false; +// NONE must be 0 - calloced +#define MODE_NONE 0 +#define MODE_CTRL_READ (1 << 0) +#define MODE_CTRL_WRITE (1 << 1) +#define MODE_BULK_READ (1 << 2) +#define MODE_BULK_WRITE (1 << 3) + +#define MODE_SEP_STR "+" +#define MODE_NONE_STR "X" +#define MODE_CTRL_READ_STR "cr" +#define MODE_CTRL_WRITE_STR "cw" +#define MODE_BULK_READ_STR "br" +#define MODE_BULK_WRITE_STR "bw" + +// One for each CMD, TIMEOUT, ERROR struct cg_usb_stats_item { uint64_t count; double total_delay; @@ -351,11 +366,14 @@ struct cg_usb_stats_item { #define CMD_TIMEOUT 1 #define CMD_ERROR 2 +// One for each C_CMD struct cg_usb_stats_details { int seq; + uint32_t modes; struct cg_usb_stats_item item[CMD_ERROR+1]; }; +// One for each device struct cg_usb_stats { char *name; int device_id; @@ -1787,11 +1805,55 @@ void usb_detect(struct device_drv *drv, bool (*device_detect)(struct libusb_devi #define DO_USB_STATS 1 #if DO_USB_STATS -#define USB_STATS(sgpu, sta, fin, err, cmd, seq) stats(cgpu, sta, fin, err, cmd, seq) +#define USB_STATS(sgpu, sta, fin, err, mode, cmd, seq) \ + stats(cgpu, sta, fin, err, mode, cmd, seq) #define STATS_TIMEVAL(tv) cgtime(tv) +#define USB_REJECT(sgpu, mode) rejected_inc(sgpu, mode) #else #define USB_STATS(sgpu, sta, fin, err, cmd, seq) #define STATS_TIMEVAL(tv) +#define USB_REJECT(sgpu, mode) +#endif + +#if DO_USB_STATS +static void modes_str(char *buf, uint32_t modes) +{ + bool first; + + *buf = '\0'; + + if (modes == MODE_NONE) + strcpy(buf, MODE_NONE_STR); + else { + first = true; + + if (modes & MODE_CTRL_READ) { + strcpy(buf, MODE_CTRL_READ_STR); + first = false; + } + + if (modes & MODE_CTRL_WRITE) { + if (!first) + strcat(buf, MODE_SEP_STR); + strcat(buf, MODE_CTRL_WRITE_STR); + first = false; + } + + if (modes & MODE_BULK_READ) { + if (!first) + strcat(buf, MODE_SEP_STR); + strcat(buf, MODE_BULK_READ_STR); + first = false; + } + + if (modes & MODE_BULK_WRITE) { + if (!first) + strcat(buf, MODE_SEP_STR); + strcat(buf, MODE_BULK_WRITE_STR); + first = false; + } + } +} #endif // The stat data can be spurious due to not locking it before copying it - @@ -1806,6 +1868,7 @@ struct api_data *api_usb_stats(__maybe_unused int *count) struct api_data *root = NULL; int device; int cmdseq; + char modes_s[32]; if (next_stat == 0) return NULL; @@ -1829,6 +1892,8 @@ struct api_data *api_usb_stats(__maybe_unused int *count) root = api_add_int(root, "ID", &(sta->device_id), false); root = api_add_const(root, "Stat", usb_commands[cmdseq/2], false); root = api_add_int(root, "Seq", &(details->seq), true); + modes_str(modes_s, details->modes); + root = api_add_string(root, "Modes", modes_s, true); root = api_add_uint64(root, "Count", &(details->item[CMD_CMD].count), true); root = api_add_double(root, "Total Delay", @@ -1882,10 +1947,15 @@ static void newstats(struct cgpu_info *cgpu) mutex_unlock(&cgusb_lock); usb_stats = realloc(usb_stats, sizeof(*usb_stats) * next_stat); + if (!usb_stats) + quit(1, "USB failed to realloc usb_stats %d", next_stat); usb_stats[next_stat-1].name = cgpu->drv->name; usb_stats[next_stat-1].device_id = -1; usb_stats[next_stat-1].details = calloc(1, sizeof(struct cg_usb_stats_details) * C_MAX * 2); + if (!usb_stats[next_stat-1].details) + quit(1, "USB failed to calloc details for %d", next_stat); + for (i = 1; i < C_MAX * 2; i += 2) usb_stats[next_stat-1].details[i].seq = 1; } @@ -1903,7 +1973,7 @@ void update_usb_stats(__maybe_unused struct cgpu_info *cgpu) } #if DO_USB_STATS -static void stats(struct cgpu_info *cgpu, struct timeval *tv_start, struct timeval *tv_finish, int err, enum usb_cmds cmd, int seq) +static void stats(struct cgpu_info *cgpu, struct timeval *tv_start, struct timeval *tv_finish, int err, int mode, enum usb_cmds cmd, int seq) { struct cg_usb_stats_details *details; double diff; @@ -1913,6 +1983,7 @@ static void stats(struct cgpu_info *cgpu, struct timeval *tv_start, struct timev newstats(cgpu); details = &(usb_stats[cgpu->usbinfo.usbstat - 1].details[cmd * 2 + seq]); + details->modes |= mode; diff = tdiff(tv_finish, tv_start); @@ -1942,7 +2013,7 @@ static void stats(struct cgpu_info *cgpu, struct timeval *tv_start, struct timev details->item[item].count++; } -static void rejected_inc(struct cgpu_info *cgpu) +static void rejected_inc(struct cgpu_info *cgpu, uint32_t mode) { struct cg_usb_stats_details *details; int item = CMD_ERROR; @@ -1951,7 +2022,7 @@ static void rejected_inc(struct cgpu_info *cgpu) newstats(cgpu); details = &(usb_stats[cgpu->usbinfo.usbstat - 1].details[C_REJECTED * 2 + 0]); - + details->modes |= mode; details->item[item].count++; } #endif @@ -1985,9 +2056,8 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro if (cgpu->usbinfo.nodev) { *buf = '\0'; *processed = 0; -#if DO_USB_STATS - rejected_inc(cgpu); -#endif + USB_REJECT(cgpu, MODE_BULK_READ); + return LIBUSB_ERROR_NO_DEVICE; } @@ -2013,7 +2083,8 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro usbdev->found->eps[ep].ep, ptr, usbbufread, &got, timeout); STATS_TIMEVAL(&tv_finish); - USB_STATS(cgpu, &tv_start, &tv_finish, err, cmd, first ? SEQ0 : SEQ1); + USB_STATS(cgpu, &tv_start, &tv_finish, err, + MODE_BULK_READ, cmd, first ? SEQ0 : SEQ1); ptr[got] = '\0'; USBDEBUG("USB debug: @_usb_read(%s (nodev=%s)) first=%s err=%d%s got=%d ptr='%s' usbbufread=%zu", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), bool_str(first), err, isnodev(err), got, (char *)str_text((char *)ptr), usbbufread); @@ -2075,7 +2146,8 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro usbdev->found->eps[ep].ep, ptr, usbbufread, &got, timeout); cgtime(&tv_finish); - USB_STATS(cgpu, &tv_start, &tv_finish, err, cmd, first ? SEQ0 : SEQ1); + USB_STATS(cgpu, &tv_start, &tv_finish, err, + MODE_BULK_READ, cmd, first ? SEQ0 : SEQ1); ptr[got] = '\0'; USBDEBUG("USB debug: @_usb_read(%s (nodev=%s)) first=%s err=%d%s got=%d ptr='%s' usbbufread=%zu", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), bool_str(first), err, isnodev(err), got, (char *)str_text((char *)ptr), usbbufread); @@ -2153,9 +2225,8 @@ int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pr *processed = 0; if (cgpu->usbinfo.nodev) { -#if DO_USB_STATS - rejected_inc(cgpu); -#endif + USB_REJECT(cgpu, MODE_BULK_WRITE); + return LIBUSB_ERROR_NO_DEVICE; } @@ -2175,7 +2246,8 @@ int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pr (unsigned char *)buf, bufsiz, &sent, timeout); STATS_TIMEVAL(&tv_finish); - USB_STATS(cgpu, &tv_start, &tv_finish, err, cmd, first ? SEQ0 : SEQ1); + USB_STATS(cgpu, &tv_start, &tv_finish, err, + MODE_BULK_WRITE, cmd, first ? SEQ0 : SEQ1); 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); @@ -2217,9 +2289,8 @@ int _usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest USBDEBUG("USB debug: _usb_transfer(%s (nodev=%s),type=%"PRIu8",req=%"PRIu8",value=%"PRIu16",index=%"PRIu16",siz=%d,timeout=%u,cmd=%s)", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), request_type, bRequest, wValue, wIndex, siz, timeout, usb_cmdname(cmd)); if (cgpu->usbinfo.nodev) { -#if DO_USB_STATS - rejected_inc(cgpu); -#endif + USB_REJECT(cgpu, MODE_CTRL_WRITE); + return LIBUSB_ERROR_NO_DEVICE; } @@ -2244,7 +2315,7 @@ int _usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest (unsigned char *)buf, (uint16_t)siz, timeout == DEVTIMEOUT ? usbdev->found->timeout : timeout); STATS_TIMEVAL(&tv_finish); - USB_STATS(cgpu, &tv_start, &tv_finish, err, cmd, SEQ0); + USB_STATS(cgpu, &tv_start, &tv_finish, err, MODE_CTRL_WRITE, cmd, SEQ0); USBDEBUG("USB debug: @_usb_transfer(%s (nodev=%s)) err=%d%s", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), err, isnodev(err)); @@ -2268,9 +2339,8 @@ int _usb_transfer_read(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRe USBDEBUG("USB debug: _usb_transfer_read(%s (nodev=%s),type=%"PRIu8",req=%"PRIu8",value=%"PRIu16",index=%"PRIu16",bufsiz=%d,timeout=%u,cmd=%s)", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), request_type, bRequest, wValue, wIndex, bufsiz, timeout, usb_cmdname(cmd)); if (cgpu->usbinfo.nodev) { -#if DO_USB_STATS - rejected_inc(cgpu); -#endif + USB_REJECT(cgpu, MODE_CTRL_READ); + return LIBUSB_ERROR_NO_DEVICE; } @@ -2282,7 +2352,7 @@ int _usb_transfer_read(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRe (unsigned char *)buf, (uint16_t)bufsiz, timeout == DEVTIMEOUT ? usbdev->found->timeout : timeout); STATS_TIMEVAL(&tv_finish); - USB_STATS(cgpu, &tv_start, &tv_finish, err, cmd, SEQ0); + USB_STATS(cgpu, &tv_start, &tv_finish, err, MODE_CTRL_READ, cmd, SEQ0); USBDEBUG("USB debug: @_usb_transfer_read(%s (nodev=%s)) amt/err=%d%s%s%s", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), err, isnodev(err), err > 0 ? " = " : BLANK, err > 0 ? bin2hex((unsigned char *)buf, (size_t)err) : BLANK); From 6c952105edde10dd10c036d07a1703ebc2f5cbf5 Mon Sep 17 00:00:00 2001 From: Kano Date: Sun, 26 May 2013 10:49:42 +1000 Subject: [PATCH 3/3] usbutils ensure it compiles without stats --- usbutils.c | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/usbutils.c b/usbutils.c index 83a774d3..c8323e6a 100644 --- a/usbutils.c +++ b/usbutils.c @@ -336,8 +336,13 @@ struct usb_in_use_list { // List of in use devices static struct usb_in_use_list *in_use_head = NULL; +// Set this to 0 to remove stats processing +#define DO_USB_STATS 1 + static bool stats_initialised = false; +#if DO_USB_STATS + // NONE must be 0 - calloced #define MODE_NONE 0 #define MODE_CTRL_READ (1 << 0) @@ -386,6 +391,17 @@ struct cg_usb_stats { static struct cg_usb_stats *usb_stats = NULL; static int next_stat = 0; +#define USB_STATS(sgpu, sta, fin, err, mode, cmd, seq) \ + stats(cgpu, sta, fin, err, mode, cmd, seq) +#define STATS_TIMEVAL(tv) cgtime(tv) +#define USB_REJECT(sgpu, mode) rejected_inc(sgpu, mode) +#else +#define USB_STATS(sgpu, sta, fin, err, mode, cmd, seq) +#define STATS_TIMEVAL(tv) +#define USB_REJECT(sgpu, mode) + +#endif // DO_USB_STATS + static const char **usb_commands; static const char *C_REJECTED_S = "RejectedNoDevice"; @@ -1801,20 +1817,6 @@ void usb_detect(struct device_drv *drv, bool (*device_detect)(struct libusb_devi libusb_free_device_list(list, 1); } -// Set this to 0 to remove stats processing -#define DO_USB_STATS 1 - -#if DO_USB_STATS -#define USB_STATS(sgpu, sta, fin, err, mode, cmd, seq) \ - stats(cgpu, sta, fin, err, mode, cmd, seq) -#define STATS_TIMEVAL(tv) cgtime(tv) -#define USB_REJECT(sgpu, mode) rejected_inc(sgpu, mode) -#else -#define USB_STATS(sgpu, sta, fin, err, cmd, seq) -#define STATS_TIMEVAL(tv) -#define USB_REJECT(sgpu, mode) -#endif - #if DO_USB_STATS static void modes_str(char *buf, uint32_t modes) { @@ -2029,7 +2031,7 @@ static void rejected_inc(struct cgpu_info *cgpu, uint32_t mode) #define USB_MAX_READ 8192 -int _usb_read(struct cgpu_info *cgpu, int ep, 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 ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, const char *end, __maybe_unused enum usb_cmds cmd, bool readonce) { struct cg_usb_device *usbdev = cgpu->usbdev; bool ftdi = (usbdev->usb_type == USB_TYPE_FTDI); @@ -2040,7 +2042,7 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro unsigned int initial_timeout; double max, done; int bufleft, err, got, tot; - bool first = true; + __maybe_unused bool first = true; unsigned char *search; int endlen; @@ -2082,7 +2084,7 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro err = libusb_bulk_transfer(usbdev->handle, usbdev->found->eps[ep].ep, ptr, usbbufread, &got, timeout); - STATS_TIMEVAL(&tv_finish); + cgtime(&tv_finish); USB_STATS(cgpu, &tv_start, &tv_finish, err, MODE_BULK_READ, cmd, first ? SEQ0 : SEQ1); ptr[got] = '\0'; @@ -2208,7 +2210,7 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro return err; } -int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, enum usb_cmds cmd) +int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, __maybe_unused enum usb_cmds cmd) { struct cg_usb_device *usbdev = cgpu->usbdev; #if DO_USB_STATS @@ -2217,7 +2219,7 @@ int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pr struct timeval read_start, tv_finish; unsigned int initial_timeout; double max, done; - bool first = true; + __maybe_unused bool first = true; int err, sent, tot; USBDEBUG("USB debug: _usb_write(%s (nodev=%s),ep=%d,buf='%s',bufsiz=%zu,proc=%p,timeout=%u,cmd=%s)", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), ep, (char *)str_text(buf), bufsiz, processed, timeout, usb_cmdname(cmd)); @@ -2245,7 +2247,7 @@ int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pr usbdev->found->eps[ep].ep, (unsigned char *)buf, bufsiz, &sent, timeout); - STATS_TIMEVAL(&tv_finish); + cgtime(&tv_finish); USB_STATS(cgpu, &tv_start, &tv_finish, err, MODE_BULK_WRITE, cmd, first ? SEQ0 : SEQ1); @@ -2277,7 +2279,7 @@ int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pr return err; } -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, __maybe_unused enum usb_cmds cmd) { struct cg_usb_device *usbdev = cgpu->usbdev; #if DO_USB_STATS @@ -2328,7 +2330,7 @@ int _usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest return err; } -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, __maybe_unused enum usb_cmds cmd) { struct cg_usb_device *usbdev = cgpu->usbdev; #if DO_USB_STATS