Commit 930317e123157122ef386ed55c894d171c6e0ae6

Con Kolivas 2013-05-25T13:25:38

Rework avalon reset sequence to include idling of chips and waiting for them to go idle followed by 2nd reset and then checking result.

diff --git a/driver-avalon.c b/driver-avalon.c
index 1ab2efc..6accf45 100644
--- a/driver-avalon.c
+++ b/driver-avalon.c
@@ -299,68 +299,139 @@ static bool avalon_decode_nonce(struct thr_info *thr, struct avalon_result *ar,
 	return true;
 }
 
-static void avalon_get_reset(int fd, struct avalon_result *ar)
+static int avalon_write(int fd, char *buf, ssize_t len)
 {
-	int read_amount = AVALON_READ_SIZE;
-	uint8_t result[AVALON_READ_SIZE];
-	struct timeval timeout = {1, 0};
-	ssize_t ret = 0, offset = 0;
-	fd_set rd;
+	ssize_t wrote = 0;
 
-	memset(result, 0, AVALON_READ_SIZE);
-	memset(ar, 0, AVALON_READ_SIZE);
-	FD_ZERO(&rd);
-	FD_SET((SOCKETTYPE)fd, &rd);
-	ret = select(fd + 1, &rd, NULL, NULL, &timeout);
-	if (unlikely(ret < 0)) {
-		applog(LOG_WARNING, "Avalon: Error %d on select in avalon_get_reset", errno);
-		return;
+	while (len > 0) {
+		struct timeval timeout;
+		ssize_t ret;
+		fd_set wd;
+
+		timeout.tv_sec = 0;
+		timeout.tv_usec = 1000;
+		FD_ZERO(&wd);
+		FD_SET((SOCKETTYPE)fd, &wd);
+		ret = select(fd + 1, NULL, &wd, NULL, &timeout);
+		if (unlikely(ret < 1)) {
+			applog(LOG_WARNING, "Select error on avalon_write");
+			return AVA_SEND_ERROR;
+		}
+		ret = write(fd, buf + wrote, len);
+		if (unlikely(ret < 1)) {
+			applog(LOG_WARNING, "Write error on avalon_write");
+			return AVA_SEND_ERROR;
+		}
+		wrote += ret;
+		len -= ret;
 	}
-	if (!ret) {
-		applog(LOG_WARNING, "Avalon: Timeout on select in avalon_get_reset");
-		return;
+
+	return 0;
+}
+
+static int avalon_read(int fd, char *buf, ssize_t len)
+{
+	ssize_t aread = 0;
+
+	while (len > 0) {
+		struct timeval timeout;
+		ssize_t ret;
+		fd_set rd;
+
+		timeout.tv_sec = 0;
+		timeout.tv_usec = 1000;
+		FD_ZERO(&rd);
+		FD_SET((SOCKETTYPE)fd, &rd);
+		ret = select(fd + 1, &rd, NULL, NULL, &timeout);
+		if (unlikely(ret < 1)) {
+			applog(LOG_WARNING, "Select error on avalon_read");
+			return AVA_GETS_ERROR;
+		}
+		ret = read(fd, buf + aread, len);
+		if (unlikely(ret < 1)) {
+			applog(LOG_WARNING, "Read error on avalon_read");
+			return AVA_GETS_ERROR;
+		}
+		aread += ret;
+		len -= ret;
 	}
+
+	return 0;
+}
+
+/* Non blocking clearing of anything in the buffer */
+static void avalon_clear_readbuf(int fd)
+{
+	ssize_t ret;
+
 	do {
-		ret = read(fd, result + offset, read_amount);
-		if (unlikely(ret < 0)) {
-			applog(LOG_WARNING, "Avalon: Error %d on read in avalon_get_reset", errno);
-			return;
+		struct timeval timeout;
+		char buf[AVALON_FTDI_READSIZE];
+		fd_set rd;
+
+		timeout.tv_sec = timeout.tv_usec = 0;
+		FD_ZERO(&rd);
+		FD_SET((SOCKETTYPE)fd, &rd);
+		ret = select(fd + 1, &rd, NULL, NULL, &timeout);
+		if (ret > 0)
+			ret = read(fd, buf, AVALON_FTDI_READSIZE);
+	} while (ret > 0);
+}
+
+static void avalon_idle(struct cgpu_info *avalon)
+{
+	struct avalon_info *info = avalon->device_data;
+	int i, fd = avalon->device_fd;
+
+	for (i = 0; i < info->miner_count; i++) {
+		struct avalon_task at;
+		int ret;
+
+		if (unlikely(avalon_buffer_full(fd))) {
+			applog(LOG_WARNING, "Avalon buffer full in avalon_idle");
+			break;
 		}
-		read_amount -= ret;
-		offset += ret;
-	} while (read_amount > 0);
-	if (opt_debug) {
-		applog(LOG_DEBUG, "Avalon: get:");
-		hexdump((uint8_t *)result, AVALON_READ_SIZE);
+		avalon_init_task(&at, 0, 0, info->fan_pwm,
+				 info->timeout, info->asic_count,
+				 info->miner_count, 1, 1, info->frequency);
+		ret = avalon_write(fd, (char *)&at, AVALON_WRITE_SIZE);
+		if (unlikely(ret == AVA_SEND_ERROR))
+			break;
 	}
-	memcpy((uint8_t *)ar, result, AVALON_READ_SIZE);
+	applog(LOG_ERR, "Avalon: Going to idle mode");
+	sleep(2);
+	avalon_clear_readbuf(fd);
+	applog(LOG_ERR, "Avalon: Idle");
 }
 
-static int avalon_reset(int fd, struct avalon_result *ar)
+static int avalon_reset(struct cgpu_info *avalon, int fd)
 {
-	struct avalon_task at;
+	struct avalon_result ar;
 	uint8_t *buf;
 	int ret, i = 0;
 	struct timespec p;
 
-	avalon_init_task(&at, 1, 0,
-			 AVALON_DEFAULT_FAN_MAX_PWM,
-			 AVALON_DEFAULT_TIMEOUT,
-			 AVALON_DEFAULT_ASIC_NUM,
-			 AVALON_DEFAULT_MINER_NUM,
-			 0, 0,
-			 AVALON_DEFAULT_FREQUENCY);
-	ret = avalon_send_task(fd, &at, NULL);
-	if (ret == AVA_SEND_ERROR)
-		return 1;
-
-	avalon_get_reset(fd, ar);
-
-	buf = (uint8_t *)ar;
-	/* Sometimes there is one extra 0 byte for some reason in the buffer,
-	 * so work around it. */
-	if (buf[0] == 0)
-		buf = (uint8_t  *)(ar + 1);
+	/* Reset once, then send command to go idle */
+	ret = avalon_write(fd, "ad", 2);
+	if (unlikely(ret == AVA_SEND_ERROR))
+		return -1;
+	p.tv_sec = 0;
+	p.tv_nsec = AVALON_RESET_PITCH;
+	nanosleep(&p, NULL);
+	avalon_clear_readbuf(fd);
+	avalon_idle(avalon);
+	/* Reset again, then check result */
+	ret = avalon_write(fd, "ad", 2);
+	if (unlikely(ret == AVA_SEND_ERROR))
+		return -1;
+
+	ret = avalon_read(fd, (char *)&ar, AVALON_READ_SIZE);
+	if (unlikely(ret == AVA_GETS_ERROR))
+		return -1;
+
+	nanosleep(&p, NULL);
+
+	buf = (uint8_t *)&ar;
 	if (buf[0] == 0xAA && buf[1] == 0x55 &&
 	    buf[2] == 0xAA && buf[3] == 0x55) {
 		for (i = 4; i < 11; i++)
@@ -368,10 +439,6 @@ static int avalon_reset(int fd, struct avalon_result *ar)
 				break;
 	}
 
-	p.tv_sec = 0;
-	p.tv_nsec = AVALON_RESET_PITCH;
-	nanosleep(&p, NULL);
-
 	if (i != 11) {
 		applog(LOG_ERR, "Avalon: Reset failed! not an Avalon?"
 		       " (%d: %02x %02x %02x %02x)",
@@ -382,38 +449,6 @@ static int avalon_reset(int fd, struct avalon_result *ar)
 	return 0;
 }
 
-static void avalon_idle(struct cgpu_info *avalon)
-{
-	int i, ret;
-	struct avalon_task at;
-
-	int fd = avalon->device_fd;
-	struct avalon_info *info = avalon->device_data;
-	int avalon_get_work_count = info->miner_count;
-
-	i = 0;
-	while (true) {
-		avalon_init_task(&at, 0, 0, info->fan_pwm,
-				 info->timeout, info->asic_count,
-				 info->miner_count, 1, 1, info->frequency);
-		ret = avalon_send_task(fd, &at, avalon);
-		if (unlikely(ret == AVA_SEND_ERROR ||
-			     (ret == AVA_SEND_BUFFER_EMPTY &&
-			      (i + 1 == avalon_get_work_count * 2)))) {
-			applog(LOG_ERR, "AVA%i: Comms error", avalon->device_id);
-			return;
-		}
-		if (i + 1 == avalon_get_work_count * 2)
-			break;
-
-		if (ret == AVA_SEND_BUFFER_FULL)
-			break;
-
-		i++;
-	}
-	applog(LOG_ERR, "Avalon: Goto idle mode");
-}
-
 static void get_options(int this_option_offset, int *baud, int *miner_count,
 			int *asic_count, int *timeout, int *frequency)
 {
@@ -550,29 +585,9 @@ static void get_options(int this_option_offset, int *baud, int *miner_count,
 	}
 }
 
-/* Non blocking clearing of anything in the buffer */
-static void avalon_clear_readbuf(int fd)
-{
-	ssize_t ret;
-
-	do {
-		struct timeval timeout;
-		char buf[AVALON_FTDI_READSIZE];
-		fd_set rd;
-
-		timeout.tv_sec = timeout.tv_usec = 0;
-		FD_ZERO(&rd);
-		FD_SET((SOCKETTYPE)fd, &rd);
-		ret = select(fd + 1, &rd, NULL, NULL, &timeout);
-		if (ret > 0)
-			ret = read(fd, buf, AVALON_FTDI_READSIZE);
-	} while (ret > 0);
-}
-
 static bool avalon_detect_one(const char *devpath)
 {
 	struct avalon_info *info;
-	struct avalon_result ar;
 	int fd, ret;
 	int baud, miner_count, asic_count, timeout, frequency = 0;
 	struct cgpu_info *avalon;
@@ -600,7 +615,7 @@ static bool avalon_detect_one(const char *devpath)
 	avalon->threads = AVALON_MINER_THREADS;
 	add_cgpu(avalon);
 
-	ret = avalon_reset(fd, &ar);
+	ret = avalon_reset(avalon, fd);
 	if (ret) {
 		; /* FIXME: I think IT IS avalon and wait on reset;
 		   * avalon_close(fd);
@@ -640,8 +655,6 @@ static bool avalon_detect_one(const char *devpath)
 	info->temp_old = 0;
 	info->frequency = frequency;
 
-	/* Set asic to idle mode after detect */
-	avalon_idle(avalon);
 	avalon->device_fd = -1;
 
 	avalon_close(fd);
@@ -661,7 +674,6 @@ static void __avalon_init(struct cgpu_info *avalon)
 static void avalon_init(struct cgpu_info *avalon)
 {
 	struct avalon_info *info = avalon->device_data;
-	struct avalon_result ar;
 	int fd, ret;
 
 	avalon->device_fd = -1;
@@ -672,7 +684,7 @@ static void avalon_init(struct cgpu_info *avalon)
 		return;
 	}
 
-	ret = avalon_reset(fd, &ar);
+	ret = avalon_reset(avalon, fd);
 	if (ret) {
 		avalon_close(fd);
 		return;
@@ -727,14 +739,12 @@ static void avalon_free_work(struct thr_info *thr)
 
 static void do_avalon_close(struct thr_info *thr)
 {
-	struct avalon_result ar;
 	struct cgpu_info *avalon = thr->cgpu;
 	struct avalon_info *info = avalon->device_data;
 
 	avalon_free_work(thr);
 	sleep(1);
-	avalon_reset(avalon->device_fd, &ar);
-	avalon_idle(avalon);
+	avalon_reset(avalon, avalon->device_fd);
 	avalon_close(avalon->device_fd);
 	avalon->device_fd = -1;