Browse Source

Merge branch 'icarus-dev' into avalon-usbdev

Con Kolivas 12 years ago
parent
commit
2d4a1db57e
1 changed files with 152 additions and 49 deletions
  1. 152 49
      usbutils.c

+ 152 - 49
usbutils.c

@@ -336,8 +336,28 @@ 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)
+#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 +371,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;
@@ -368,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";
@@ -1783,15 +1817,45 @@ 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, cmd, seq) stats(cgpu, sta, fin, err, cmd, seq)
-#define STATS_TIMEVAL(tv) cgtime(tv)
-#else
-#define USB_STATS(sgpu, sta, fin, err, cmd, seq)
-#define STATS_TIMEVAL(tv)
+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 +1870,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 +1894,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 +1949,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 +1975,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 +1985,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 +2015,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,14 +2024,14 @@ 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
 
 #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);
@@ -1969,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;
 
@@ -1985,9 +2058,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;
 	}
 
@@ -2012,8 +2084,9 @@ 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);
-			USB_STATS(cgpu, &tv_start, &tv_finish, err, cmd, first ? SEQ0 : SEQ1);
+			cgtime(&tv_finish);
+			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);
@@ -2040,7 +2113,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;
 
@@ -2075,7 +2148,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);
@@ -2120,7 +2194,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;
 
@@ -2136,37 +2210,68 @@ 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
-	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;
+	__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));
 
+	*processed = 0;
+
 	if (cgpu->usbinfo.nodev) {
-		*processed = 0;
-#if DO_USB_STATS
-		rejected_inc(cgpu);
-#endif
+		USB_REJECT(cgpu, MODE_BULK_WRITE);
+
 		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;
+
+	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);
+		cgtime(&tv_finish);
+		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);
+		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);
 
-	*processed = 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;
+
+		timeout = initial_timeout - (done * 1000);
+	}
+
+	*processed = tot;
 
 	if (NODEV(err))
 		release_cgpu(cgpu);
@@ -2174,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
@@ -2186,9 +2291,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;
 	}
 
@@ -2213,7 +2317,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));
 
@@ -2226,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
@@ -2237,9 +2341,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;
 	}
 
@@ -2251,7 +2354,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);