Browse Source

Merge branch 'cg_merges_20130524b' into bfgminer

Luke Dashjr 13 years ago
parent
commit
e56ddc5655
30 changed files with 738 additions and 572 deletions
  1. 3 2
      Makefile.am
  2. 8 0
      README
  3. 40 2
      README.GPU
  4. 2 2
      README.scrypt
  5. 1 1
      api-example.c
  6. 6 5
      api.c
  7. 1 1
      autogen.sh
  8. 1 0
      ccan/Makefile.am
  9. 4 2
      compat.h
  10. 4 1
      configure.ac
  11. 5 1
      deviceapi.c
  12. 236 321
      driver-avalon.c
  13. 4 7
      driver-avalon.h
  14. 9 8
      driver-bitforce.c
  15. 1 2
      driver-cpu.c
  16. 6 6
      driver-icarus.c
  17. 16 11
      driver-opencl.c
  18. 2 1
      driver-ztex.c
  19. 9 5
      findnonce.c
  20. 4 0
      findnonce.h
  21. 18 1
      fpgautils.c
  22. 3 1
      logging.c
  23. 195 135
      miner.c
  24. 21 13
      miner.h
  25. 9 1
      ocl.c
  26. 16 6
      scrypt.c
  27. 5 5
      scrypt.h
  28. 2 2
      scrypt130511.cl
  29. 94 30
      util.c
  30. 13 0
      util.h

+ 3 - 2
Makefile.am

@@ -6,6 +6,7 @@ EXTRA_DIST	= example.conf m4/gnulib-cache.m4 linux-usb-bfgminer \
 		  API.class API.java api-example.c windows-build.txt \
 		  API.class API.java api-example.c windows-build.txt \
 		  bitstreams/* README.FPGA README.RPC README.scrypt \
 		  bitstreams/* README.FPGA README.RPC README.scrypt \
 		  README.GPU \
 		  README.GPU \
+		  hexdump.c \
                   api-example.py
                   api-example.py
 
 
 SUBDIRS		= lib ccan
 SUBDIRS		= lib ccan
@@ -19,7 +20,7 @@ bin_SCRIPTS	= $(top_srcdir)/*.cl
 bfgminer_LDFLAGS	= $(PTHREAD_FLAGS)
 bfgminer_LDFLAGS	= $(PTHREAD_FLAGS)
 bfgminer_LDADD	= $(DLOPEN_FLAGS) @LIBCURL_LIBS@ @JANSSON_LIBS@ @PTHREAD_LIBS@ \
 bfgminer_LDADD	= $(DLOPEN_FLAGS) @LIBCURL_LIBS@ @JANSSON_LIBS@ @PTHREAD_LIBS@ \
 		  @NCURSES_LIBS@ @PDCURSES_LIBS@ @WS2_LIBS@ \
 		  @NCURSES_LIBS@ @PDCURSES_LIBS@ @WS2_LIBS@ \
-		  @UDEV_LIBS@ @LIBUSB_LIBS@ \
+		  @UDEV_LIBS@ @LIBUSB_LIBS@ @MM_LIBS@ \
 		  @MATH_LIBS@ lib/libgnu.a ccan/libccan.a
 		  @MATH_LIBS@ lib/libgnu.a ccan/libccan.a
 bfgminer_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib @LIBUSB_CFLAGS@ @LIBCURL_CFLAGS@
 bfgminer_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib @LIBUSB_CFLAGS@ @LIBCURL_CFLAGS@
 
 
@@ -118,7 +119,7 @@ bfgminer_SOURCES += driver-cairnsmore.c
 endif
 endif
 
 
 if HAS_AVALON
 if HAS_AVALON
-bfgminer_SOURCES += driver-avalon.c
+bfgminer_SOURCES += driver-avalon.c driver-avalon.h
 endif
 endif
 
 
 if HAS_MODMINER
 if HAS_MODMINER

+ 8 - 0
README

@@ -641,6 +641,14 @@ A: Start BFGMiner with your regular commands and add -D -T --verbose and provide
 the full startup output and a summary of your hardware, operating system, ATI
 the full startup output and a summary of your hardware, operating system, ATI
 driver version and ATI stream version.
 driver version and ATI stream version.
 
 
+Q: Can I mine with BFGMiner on a Mac?
+A: BFGMiner will compile on OS X, but the performance of GPU mining is
+compromised due to the OpenCL implementation on OS X, there is no temperature or
+fanspeed monitoring, and the cooling design of most Macs, despite having
+powerful GPUs, will usually not cope with constant usage leading to a high risk
+of thermal damage. It is highly recommended not to mine on a Mac unless it is to
+a USB device.
+
 Q: My network gets slower and slower and then dies for a minute?
 Q: My network gets slower and slower and then dies for a minute?
 A; Try the --net-delay option.
 A; Try the --net-delay option.
 
 

+ 40 - 2
README.GPU

@@ -357,7 +357,8 @@ Q: Which AMD driver is the best?
 A: Unfortunately AMD has a history of having quite a few releases with issues
 A: Unfortunately AMD has a history of having quite a few releases with issues
 when it comes to mining, either in terms of breaking mining, increasing CPU
 when it comes to mining, either in terms of breaking mining, increasing CPU
 usage or very low hashrates. Only experimentation can tell you for sure, but
 usage or very low hashrates. Only experimentation can tell you for sure, but
-some good releases were 11.6, 11.12, 12.4 and 12.8
+some good releases were 11.6, 11.12, 12.4 and 12.8. Note that older cards may
+not work with the newer drivers.
 
 
 Q: I have multiple SDKs installed, can I choose which one it uses?
 Q: I have multiple SDKs installed, can I choose which one it uses?
 A: Run bfgminer with the -n option and it will list all the platforms currently
 A: Run bfgminer with the -n option and it will list all the platforms currently
@@ -407,6 +408,10 @@ Q: Can I mine with Nvidia or Intel GPUs?
 A: Yes, but their hashrate is very poor and likely you'll be using much more
 A: Yes, but their hashrate is very poor and likely you'll be using much more
 energy than you'll be earning in coins.
 energy than you'll be earning in coins.
 
 
+Q: Can I mine on both Nvidia and AMD GPUs at the same time?
+A: No, you must run one instance of BFGMiner with the --gpu-platform option for
+each.
+
 Q: Can I mine on Linux without running Xorg?
 Q: Can I mine on Linux without running Xorg?
 A: With Nvidia you can, but with AMD you cannot.
 A: With Nvidia you can, but with AMD you cannot.
 
 
@@ -422,12 +427,45 @@ Q: My scrypt hashrate is high but the pool reports only a tiny proportion of my
 hashrate?
 hashrate?
 A: You are generating garbage hashes due to your choice of settings. Try
 A: You are generating garbage hashes due to your choice of settings. Try
 decreasing your intensity, do not increase the number of gpu-threads, and
 decreasing your intensity, do not increase the number of gpu-threads, and
-consider adding system RAM to match your GPU ram.
+consider adding system RAM to match your GPU ram. You may also be using a bad
+combination of driver and/or SDK.
 
 
 Q: Scrypt fails to initialise the kernel every time?
 Q: Scrypt fails to initialise the kernel every time?
 A: Your parameters are too high. Don't add GPU threads, don't set intensity too
 A: Your parameters are too high. Don't add GPU threads, don't set intensity too
 high, decrease thread concurrency. See the README.scrypt for a lot more help.
 high, decrease thread concurrency. See the README.scrypt for a lot more help.
 
 
+Q: BFGMiner stops mining (or my GPUs go DEAD) and I can't close it?
+A: Once the driver has crashed, there is no way for BFGMiner to close cleanly.
+You will have to kill it, and depending on how corrupted your driver state has
+gotten, you may even need to reboot. Windows is known to reset drivers when they
+fail and BFGMiner will be stuck trying to use the old driver instance.
+
+Q: I can't get any monitoring of temperatures or fanspeed with BFGMiner when I
+start it remotely?
+A: With Linux, make sure to export the DISPLAY variable. On Windows, you cannot
+access these monitoring values via RDP. This should work with TightVNC or
+TeamViewer, though.
+
+Q: I change my GPU engine/memory/voltage and BFGMiner reports back no change?
+A: BFGMiner asks the GPU using the ATI Display Library to change settings, but
+the driver and hardware are free to do what it wants with that query, including
+ignoring it. Some GPUs are locked with one or more of those properties as well.
+
+Q: I have multiple GPUs and although many devices show up, it appears to be
+working only on one GPU splitting it up.
+A: Your driver setup is failing to properly use the accessory GPUs. Your driver
+may be configured wrong or you have a driver version that needs a dummy plug on
+all the GPUs that aren't connected to a monitor.
+
+Q: I have some random GPU performance related problem not addressed above.
+A: Seriously, it's the driver and/or SDK. Uninstall them and start again,
+noting there is no clean way to uninstall them so you have to use extra tools
+or do it manually.
+
+Q: Do I need to recompile after updating my driver/SDK?
+A: No. The software is unchanged regardless of which driver/SDK/ADL version you
+are running.
+
 Q: Should I use crossfire/SLI?
 Q: Should I use crossfire/SLI?
 A: It does not benefit mining at all and depending on the GPU may actually
 A: It does not benefit mining at all and depending on the GPU may actually
 worsen performance.
 worsen performance.

+ 2 - 2
README.scrypt

@@ -218,8 +218,8 @@ without crashing the GPU, you will have to use a lower memclock.
 Then, and only then, bother trying to increase intensity further.
 Then, and only then, bother trying to increase intensity further.
 
 
 My final settings were:
 My final settings were:
---gpu-engine 1157  --gpu-memclock 1900 -I 20
-for a hashrate of 725kH.
+--gpu-engine 1141  --gpu-memclock 1875 -I 20
+for a hashrate of 745kH.
 
 
 Note I did not bother setting a thread concurrency. Once you have the magic
 Note I did not bother setting a thread concurrency. Once you have the magic
 endpoint, look at what tc was chosen by the bin file generated and then hard
 endpoint, look at what tc was chosen by the bin file generated and then hard

+ 1 - 1
api-example.c

@@ -138,7 +138,7 @@
 static const char SEPARATOR = '|';
 static const char SEPARATOR = '|';
 static const char COMMA = ',';
 static const char COMMA = ',';
 static const char EQ = '=';
 static const char EQ = '=';
-static int ONLY = 0;
+static int ONLY;
 
 
 void display(char *buf)
 void display(char *buf)
 {
 {

+ 6 - 5
api.c

@@ -161,9 +161,6 @@ static const char *SCRYPTSTR = "scrypt";
 static const char *SHA256STR = "sha256";
 static const char *SHA256STR = "sha256";
 
 
 static const char *DEVICECODE = ""
 static const char *DEVICECODE = ""
-#ifdef USE_AVALON
-			"AVA "
-#endif
 #ifdef HAVE_OPENCL
 #ifdef HAVE_OPENCL
 			"GPU "
 			"GPU "
 #endif
 #endif
@@ -173,6 +170,9 @@ static const char *DEVICECODE = ""
 #ifdef USE_ICARUS
 #ifdef USE_ICARUS
 			"ICA "
 			"ICA "
 #endif
 #endif
+#ifdef USE_AVALON
+			"AVA "
+#endif
 #ifdef USE_X6500
 #ifdef USE_X6500
 			"XBS "
 			"XBS "
 #endif
 #endif
@@ -836,7 +836,7 @@ static struct api_data *api_add_data_full(struct api_data *root, char *name, enu
 
 
 	api_data = (struct api_data *)malloc(sizeof(struct api_data));
 	api_data = (struct api_data *)malloc(sizeof(struct api_data));
 
 
-	api_data->name = name;
+	api_data->name = strdup(name);
 	api_data->type = type;
 	api_data->type = type;
 
 
 	if (root == NULL) {
 	if (root == NULL) {
@@ -1143,6 +1143,7 @@ static struct api_data *print_data(struct api_data *root, char *buf, bool isjson
 
 
 		buf = strchr(buf, '\0');
 		buf = strchr(buf, '\0');
 
 
+		free(root->name);
 		if (root->type == API_JSON)
 		if (root->type == API_JSON)
 			json_decref((json_t *)root->data);
 			json_decref((json_t *)root->data);
 		if (root->data_was_malloc)
 		if (root->data_was_malloc)
@@ -3277,7 +3278,7 @@ static void send_result(struct io_data *io_data, SOCKETTYPE c, bool isjson)
 		n = send(c, buf, tosend, 0);
 		n = send(c, buf, tosend, 0);
 
 
 		if (SOCKETFAIL(n)) {
 		if (SOCKETFAIL(n)) {
-			if (errno == EAGAIN || errno == EWOULDBLOCK)
+			if (sock_blocks())
 				continue;
 				continue;
 
 
 			applog(LOG_WARNING, "API: send (%d) failed: %s", tosend, SOCKERRMSG);
 			applog(LOG_WARNING, "API: send (%d) failed: %s", tosend, SOCKERRMSG);

+ 1 - 1
autogen.sh

@@ -14,5 +14,5 @@ echo 'Running autoreconf -if...'
 	cd "${bs_dir}"
 	cd "${bs_dir}"
 	rm -rf autom4te.cache
 	rm -rf autom4te.cache
 	rm -f aclocal.m4 ltmain.sh
 	rm -f aclocal.m4 ltmain.sh
-	autoreconf -if
+	autoreconf -if ${AC_FLAGS}
 )
 )

+ 1 - 0
ccan/Makefile.am

@@ -1,3 +1,4 @@
 noinst_LIBRARIES	= libccan.a
 noinst_LIBRARIES	= libccan.a
 
 
 libccan_a_SOURCES	= compiler/compiler.h opt/helpers.c opt/opt.c opt/opt.h opt/parse.c opt/private.h opt/usage.c typesafe_cb/typesafe_cb.h
 libccan_a_SOURCES	= compiler/compiler.h opt/helpers.c opt/opt.c opt/opt.h opt/parse.c opt/private.h opt/usage.c typesafe_cb/typesafe_cb.h
+libccan_a_CPPFLAGS	= -I$(top_srcdir)

+ 4 - 2
compat.h

@@ -79,12 +79,14 @@ struct tm *localtime_convert(time_t t)
 #endif
 #endif
 
 
 #ifndef HAVE_NANOSLEEP
 #ifndef HAVE_NANOSLEEP
+extern void cgtime(struct timeval *);
+
 static inline int nanosleep(const struct timespec *req, struct timespec *rem)
 static inline int nanosleep(const struct timespec *req, struct timespec *rem)
 {
 {
 	struct timeval tstart;
 	struct timeval tstart;
 	DWORD msecs;
 	DWORD msecs;
 
 
-	gettimeofday(&tstart, NULL);
+	cgtime(&tstart);
 	msecs = (req->tv_sec * 1000) + ((999999 + req->tv_nsec) / 1000000);
 	msecs = (req->tv_sec * 1000) + ((999999 + req->tv_nsec) / 1000000);
 
 
 	if (SleepEx(msecs, true) == WAIT_IO_COMPLETION) {
 	if (SleepEx(msecs, true) == WAIT_IO_COMPLETION) {
@@ -97,7 +99,7 @@ static inline int nanosleep(const struct timespec *req, struct timespec *rem)
 				++tdone.tv_sec;
 				++tdone.tv_sec;
 			}
 			}
 
 
-			gettimeofday(&tnow, NULL);
+			cgtime(&tnow);
 			if (timercmp(&tnow, &tdone, >))
 			if (timercmp(&tnow, &tdone, >))
 				return 0;
 				return 0;
 			timersub(&tdone, &tnow, &tleft);
 			timersub(&tdone, &tnow, &tleft);

+ 4 - 1
configure.ac

@@ -66,6 +66,7 @@ have_cygwin=false
 have_win32=false
 have_win32=false
 DLOPEN_FLAGS="-ldl"
 DLOPEN_FLAGS="-ldl"
 WS2_LIBS=""
 WS2_LIBS=""
+MM_LIBS=""
 MATH_LIBS="-lm"
 MATH_LIBS="-lm"
 
 
 case $target in
 case $target in
@@ -88,6 +89,7 @@ case $target in
     have_win32=true
     have_win32=true
     DLOPEN_FLAGS=""
     DLOPEN_FLAGS=""
     WS2_LIBS="-lws2_32"
     WS2_LIBS="-lws2_32"
+    MM_LIBS="-lwinmm"
     AC_DEFINE([_WIN32_WINNT], [0x0501], "WinNT version for XP+ support")
     AC_DEFINE([_WIN32_WINNT], [0x0501], "WinNT version for XP+ support")
     AC_DEFINE([FD_SETSIZE], [4096], [Maximum sockets before fd_set overflows])
     AC_DEFINE([FD_SETSIZE], [4096], [Maximum sockets before fd_set overflows])
     ;;
     ;;
@@ -742,7 +744,7 @@ AC_DEFINE_UNQUOTED([PHATK_KERNNAME], ["phatk121016"], [Filename for phatk kernel
 AC_DEFINE_UNQUOTED([POCLBM_KERNNAME], ["poclbm130302"], [Filename for poclbm kernel])
 AC_DEFINE_UNQUOTED([POCLBM_KERNNAME], ["poclbm130302"], [Filename for poclbm kernel])
 AC_DEFINE_UNQUOTED([DIAKGCN_KERNNAME], ["diakgcn121016"], [Filename for diakgcn kernel])
 AC_DEFINE_UNQUOTED([DIAKGCN_KERNNAME], ["diakgcn121016"], [Filename for diakgcn kernel])
 AC_DEFINE_UNQUOTED([DIABLO_KERNNAME], ["diablo130302"], [Filename for diablo kernel])
 AC_DEFINE_UNQUOTED([DIABLO_KERNNAME], ["diablo130302"], [Filename for diablo kernel])
-AC_DEFINE_UNQUOTED([SCRYPT_KERNNAME], ["scrypt130302"], [Filename for scrypt kernel])
+AC_DEFINE_UNQUOTED([SCRYPT_KERNNAME], ["scrypt130511"], [Filename for scrypt kernel])
 
 
 
 
 AC_SUBST(PTHREAD_FLAGS)
 AC_SUBST(PTHREAD_FLAGS)
@@ -752,6 +754,7 @@ AC_SUBST(NCURSES_CPPFLAGS)
 AC_SUBST(NCURSES_LIBS)
 AC_SUBST(NCURSES_LIBS)
 AC_SUBST(PDCURSES_LIBS)
 AC_SUBST(PDCURSES_LIBS)
 AC_SUBST(WS2_LIBS)
 AC_SUBST(WS2_LIBS)
+AC_SUBST(MM_LIBS)
 AC_SUBST(MATH_LIBS)
 AC_SUBST(MATH_LIBS)
 AC_SUBST(UDEV_LIBS)
 AC_SUBST(UDEV_LIBS)
 AC_SUBST(YASM_FMT)
 AC_SUBST(YASM_FMT)

+ 5 - 1
deviceapi.c

@@ -580,7 +580,7 @@ out:
 	return NULL;
 	return NULL;
 }
 }
 
 
-bool add_cgpu(struct cgpu_info*cgpu)
+bool add_cgpu(struct cgpu_info *cgpu)
 {
 {
 	int lpcount;
 	int lpcount;
 	
 	
@@ -632,6 +632,10 @@ bool add_cgpu(struct cgpu_info*cgpu)
 	}
 	}
 	
 	
 	wr_unlock(&devices_lock);
 	wr_unlock(&devices_lock);
+
+	mutex_lock(&stats_lock);
+	cgpu->last_device_valid_work = time(NULL);
+	mutex_unlock(&stats_lock);
 	
 	
 	return true;
 	return true;
 }
 }

+ 236 - 321
driver-avalon.c

@@ -17,10 +17,10 @@
 #include <stdio.h>
 #include <stdio.h>
 #include <sys/time.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/types.h>
-#include <sys/select.h>
 #include <dirent.h>
 #include <dirent.h>
 #include <unistd.h>
 #include <unistd.h>
 #ifndef WIN32
 #ifndef WIN32
+  #include <sys/select.h>
   #include <termios.h>
   #include <termios.h>
   #include <sys/stat.h>
   #include <sys/stat.h>
   #include <fcntl.h>
   #include <fcntl.h>
@@ -28,6 +28,7 @@
     #define O_CLOEXEC 0
     #define O_CLOEXEC 0
   #endif
   #endif
 #else
 #else
+  #include "compat.h"
   #include <windows.h>
   #include <windows.h>
   #include <io.h>
   #include <io.h>
 #endif
 #endif
@@ -38,9 +39,10 @@
 #include "fpgautils.h"
 #include "fpgautils.h"
 #include "driver-avalon.h"
 #include "driver-avalon.h"
 #include "hexdump.c"
 #include "hexdump.c"
+#include "util.h"
 
 
 static int option_offset = -1;
 static int option_offset = -1;
-struct avalon_info **avalon_info;
+struct avalon_info **avalon_infos;
 struct device_drv avalon_drv;
 struct device_drv avalon_drv;
 
 
 static int avalon_init_task(struct avalon_task *at,
 static int avalon_init_task(struct avalon_task *at,
@@ -172,7 +174,7 @@ static int avalon_send_task(int fd, const struct avalon_task *at,
 	buf[4] = tt;
 	buf[4] = tt;
 #endif
 #endif
 	if (likely(avalon)) {
 	if (likely(avalon)) {
-		info = avalon_info[avalon->device_id];
+		info = avalon_infos[avalon->device_id];
 		delay = nr_len * 10 * 1000000000ULL;
 		delay = nr_len * 10 * 1000000000ULL;
 		delay = delay / info->baud;
 		delay = delay / info->baud;
 	}
 	}
@@ -180,7 +182,7 @@ static int avalon_send_task(int fd, const struct avalon_task *at,
 	if (at->reset)
 	if (at->reset)
 		nr_len = 1;
 		nr_len = 1;
 	if (opt_debug) {
 	if (opt_debug) {
-		applog(LOG_DEBUG, "Avalon: Sent(%d):", nr_len);
+		applog(LOG_DEBUG, "Avalon: Sent(%u):", (unsigned int)nr_len);
 		hexdump((uint8_t *)buf, nr_len);
 		hexdump((uint8_t *)buf, nr_len);
 	}
 	}
 	ret = write(fd, buf, nr_len);
 	ret = write(fd, buf, nr_len);
@@ -202,30 +204,40 @@ static int avalon_send_task(int fd, const struct avalon_task *at,
 	return AVA_SEND_BUFFER_EMPTY;
 	return AVA_SEND_BUFFER_EMPTY;
 }
 }
 
 
-static int avalon_gets(int fd, uint8_t *buf, int read_count,
-		       struct thr_info *thr, struct timeval *tv_finish)
+static inline int avalon_gets(int fd, uint8_t *buf, struct thr_info *thr,
+		       struct timeval *tv_finish)
 {
 {
-	ssize_t ret = 0;
-	int rc = 0;
 	int read_amount = AVALON_READ_SIZE;
 	int read_amount = AVALON_READ_SIZE;
 	bool first = true;
 	bool first = true;
+	ssize_t ret = 0;
 
 
 	while (true) {
 	while (true) {
-		struct timeval timeout = {0, 100000};
+		struct timeval timeout;
 		fd_set rd;
 		fd_set rd;
 
 
+		if (unlikely(thr->work_restart)) {
+			applog(LOG_DEBUG, "Avalon: Work restart");
+			return AVA_GETS_RESTART;
+		}
+
+		timeout.tv_sec = 0;
+		timeout.tv_usec = 100000;
+
 		FD_ZERO(&rd);
 		FD_ZERO(&rd);
 		FD_SET(fd, &rd);
 		FD_SET(fd, &rd);
 		ret = select(fd + 1, &rd, NULL, NULL, &timeout);
 		ret = select(fd + 1, &rd, NULL, NULL, &timeout);
-		if (unlikely(ret < 0))
+		if (unlikely(ret < 0)) {
+			applog(LOG_ERR, "Avalon: Error %d on select in avalon_gets", errno);
 			return AVA_GETS_ERROR;
 			return AVA_GETS_ERROR;
+		}
 		if (ret) {
 		if (ret) {
 			ret = read(fd, buf, read_amount);
 			ret = read(fd, buf, read_amount);
-			if (unlikely(ret < 0))
+			if (unlikely(ret < 0)) {
+				applog(LOG_ERR, "Avalon: Error %d on read in avalon_gets", errno);
 				return AVA_GETS_ERROR;
 				return AVA_GETS_ERROR;
+			}
 			if (likely(first)) {
 			if (likely(first)) {
-				if (likely(tv_finish))
-					gettimeofday(tv_finish, NULL);
+				cgtime(tv_finish);
 				first = false;
 				first = false;
 			}
 			}
 			if (likely(ret >= read_amount))
 			if (likely(ret >= read_amount))
@@ -235,43 +247,23 @@ static int avalon_gets(int fd, uint8_t *buf, int read_count,
 			continue;
 			continue;
 		}
 		}
 
 
-		rc++;
-		if (rc >= read_count) {
-			if (opt_debug) {
-				applog(LOG_WARNING,
-				       "Avalon: No data in %.2f seconds",
-				       (float)rc/(float)AVALON_TIME_FACTOR);
-			}
-			return AVA_GETS_TIMEOUT;
-		}
-
-		if (thr && thr->work_restart) {
-			if (opt_debug) {
-				applog(LOG_WARNING,
-				       "Avalon: Work restart at %.2f seconds",
-				       (float)(rc)/(float)AVALON_TIME_FACTOR);
-			}
+		if (unlikely(thr->work_restart)) {
+			applog(LOG_DEBUG, "Avalon: Work restart");
 			return AVA_GETS_RESTART;
 			return AVA_GETS_RESTART;
 		}
 		}
+
+		return AVA_GETS_TIMEOUT;
 	}
 	}
 }
 }
 
 
 static int avalon_get_result(int fd, struct avalon_result *ar,
 static int avalon_get_result(int fd, struct avalon_result *ar,
 			     struct thr_info *thr, struct timeval *tv_finish)
 			     struct thr_info *thr, struct timeval *tv_finish)
 {
 {
-	struct cgpu_info *avalon;
-	struct avalon_info *info;
 	uint8_t result[AVALON_READ_SIZE];
 	uint8_t result[AVALON_READ_SIZE];
-	int ret, read_count = AVALON_RESET_FAULT_DECISECONDS * AVALON_TIME_FACTOR;
-
-	if (likely(thr)) {
-		avalon = thr->cgpu;
-		info = avalon_info[avalon->device_id];
-		read_count = info->read_count;
-	}
+	int ret;
 
 
 	memset(result, 0, AVALON_READ_SIZE);
 	memset(result, 0, AVALON_READ_SIZE);
-	ret = avalon_gets(fd, result, read_count, thr, tv_finish);
+	ret = avalon_gets(fd, result, thr, tv_finish);
 
 
 	if (ret == AVA_GETS_OK) {
 	if (ret == AVA_GETS_OK) {
 		if (opt_debug) {
 		if (opt_debug) {
@@ -284,35 +276,65 @@ static int avalon_get_result(int fd, struct avalon_result *ar,
 	return ret;
 	return ret;
 }
 }
 
 
-static int avalon_decode_nonce(struct thr_info *thr, struct work **work,
-			       struct avalon_result *ar, uint32_t *nonce)
+static bool avalon_decode_nonce(struct thr_info *thr, struct avalon_result *ar,
+				uint32_t *nonce)
 {
 {
 	struct cgpu_info *avalon;
 	struct cgpu_info *avalon;
 	struct avalon_info *info;
 	struct avalon_info *info;
-	int avalon_get_work_count, i;
-
-	if (unlikely(!work))
-		return -1;
+	struct work *work;
 
 
 	avalon = thr->cgpu;
 	avalon = thr->cgpu;
-	info = avalon_info[avalon->device_id];
-	avalon_get_work_count = info->miner_count;
+	if (unlikely(!avalon->works))
+		return false;
 
 
-	for (i = 0; i < avalon_get_work_count; i++) {
-		if (work[i] &&
-		    !memcmp(ar->data, work[i]->data + 64, 12) &&
-		    !memcmp(ar->midstate, work[i]->midstate, 32))
-			break;
-	}
-	if (i == avalon_get_work_count)
-		return -1;
+	work = find_queued_work_bymidstate(avalon, (char *)ar->midstate, 32,
+					   (char *)ar->data, 64, 12);
+	if (!work)
+		return false;
 
 
-	info->matching_work[i]++;
+	info = avalon_infos[avalon->device_id];
+	info->matching_work[work->subid]++;
 	*nonce = htole32(ar->nonce);
 	*nonce = htole32(ar->nonce);
+	submit_nonce(thr, work, *nonce);
 
 
-	applog(LOG_DEBUG, "Avalon: match to work[%d](%p): %d",i, work[i],
-	       info->matching_work[i]);
-	return i;
+	return true;
+}
+
+static void avalon_get_reset(int fd, struct avalon_result *ar)
+{
+	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;
+
+	memset(result, 0, AVALON_READ_SIZE);
+	memset(ar, 0, AVALON_READ_SIZE);
+	FD_ZERO(&rd);
+	FD_SET(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;
+	}
+	if (!ret) {
+		applog(LOG_WARNING, "Avalon: Timeout on select in avalon_get_reset");
+		return;
+	}
+	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;
+		}
+		read_amount -= ret;
+		offset += ret;
+	} while (read_amount > 0);
+	if (opt_debug) {
+		applog(LOG_DEBUG, "Avalon: get:");
+		hexdump((uint8_t *)result, AVALON_READ_SIZE);
+	}
+	memcpy((uint8_t *)ar, result, AVALON_READ_SIZE);
 }
 }
 
 
 static int avalon_reset(int fd, struct avalon_result *ar)
 static int avalon_reset(int fd, struct avalon_result *ar)
@@ -333,7 +355,7 @@ static int avalon_reset(int fd, struct avalon_result *ar)
 	if (ret == AVA_SEND_ERROR)
 	if (ret == AVA_SEND_ERROR)
 		return 1;
 		return 1;
 
 
-	avalon_get_result(fd, ar, NULL, NULL);
+	avalon_get_reset(fd, ar);
 
 
 	buf = (uint8_t *)ar;
 	buf = (uint8_t *)ar;
 	/* Sometimes there is one extra 0 byte for some reason in the buffer,
 	/* Sometimes there is one extra 0 byte for some reason in the buffer,
@@ -367,7 +389,7 @@ static void avalon_idle(struct cgpu_info *avalon)
 	struct avalon_task at;
 	struct avalon_task at;
 
 
 	int fd = avalon->device_fd;
 	int fd = avalon->device_fd;
-	struct avalon_info *info = avalon_info[avalon->device_id];
+	struct avalon_info *info = avalon_infos[avalon->device_id];
 	int avalon_get_work_count = info->miner_count;
 	int avalon_get_work_count = info->miner_count;
 
 
 	i = 0;
 	i = 0;
@@ -560,19 +582,19 @@ static bool avalon_detect_one(const char *devpath)
 		   * return false; */
 		   * return false; */
 	}
 	}
 	
 	
-	avalon_info = realloc(avalon_info,
-			      sizeof(struct avalon_info *) *
-			      (total_devices + 1));
+	avalon_infos = realloc(avalon_infos,
+			       sizeof(struct avalon_info *) *
+			       (total_devices + 1));
 
 
 	applog(LOG_INFO, "Avalon Detect: Found at %s, mark as %d",
 	applog(LOG_INFO, "Avalon Detect: Found at %s, mark as %d",
 	       devpath, avalon->device_id);
 	       devpath, avalon->device_id);
 
 
-	avalon_info[avalon->device_id] = (struct avalon_info *)
+	avalon_infos[avalon->device_id] = (struct avalon_info *)
 		malloc(sizeof(struct avalon_info));
 		malloc(sizeof(struct avalon_info));
-	if (unlikely(!(avalon_info[avalon->device_id])))
-		quit(1, "Failed to malloc avalon_info");
+	if (unlikely(!(avalon_infos[avalon->device_id])))
+		quit(1, "Failed to malloc avalon_infos");
 
 
-	info = avalon_info[avalon->device_id];
+	info = avalon_infos[avalon->device_id];
 
 
 	memset(info, 0, sizeof(struct avalon_info));
 	memset(info, 0, sizeof(struct avalon_info));
 
 
@@ -580,8 +602,6 @@ static bool avalon_detect_one(const char *devpath)
 	info->miner_count = miner_count;
 	info->miner_count = miner_count;
 	info->asic_count = asic_count;
 	info->asic_count = asic_count;
 	info->timeout = timeout;
 	info->timeout = timeout;
-	info->read_count = ((float)info->timeout * AVALON_HASH_TIME_FACTOR *
-			    AVALON_TIME_FACTOR) / (float)info->miner_count;
 
 
 	info->fan_pwm = AVALON_DEFAULT_FAN_MIN_PWM;
 	info->fan_pwm = AVALON_DEFAULT_FAN_MIN_PWM;
 	info->temp_max = 0;
 	info->temp_max = 0;
@@ -595,14 +615,11 @@ static bool avalon_detect_one(const char *devpath)
 	info->temp_old = 0;
 	info->temp_old = 0;
 	info->frequency = frequency;
 	info->frequency = frequency;
 
 
-	/* Do something for failed reset ? */
-	if (0) {
-		/* Set asic to idle mode after detect */
-		avalon_idle(avalon);
-		avalon->device_fd = -1;
+	/* Set asic to idle mode after detect */
+	avalon_idle(avalon);
+	avalon->device_fd = -1;
 
 
-		avalon_close(fd);
-	}
+	avalon_close(fd);
 	return true;
 	return true;
 }
 }
 
 
@@ -623,7 +640,7 @@ static void avalon_init(struct cgpu_info *avalon)
 
 
 	avalon->device_fd = -1;
 	avalon->device_fd = -1;
 	fd = avalon_open(avalon->device_path,
 	fd = avalon_open(avalon->device_path,
-			     avalon_info[avalon->device_id]->baud);
+			     avalon_infos[avalon->device_id]->baud);
 	if (unlikely(fd == -1)) {
 	if (unlikely(fd == -1)) {
 		applog(LOG_ERR, "Avalon: Failed to open on %s",
 		applog(LOG_ERR, "Avalon: Failed to open on %s",
 		       avalon->device_path);
 		       avalon->device_path);
@@ -636,7 +653,6 @@ static void avalon_init(struct cgpu_info *avalon)
 		return;
 		return;
 	}
 	}
 
 
-	avalon->status = LIFE_INIT;
 	avalon->device_fd = fd;
 	avalon->device_fd = fd;
 	__avalon_init(avalon);
 	__avalon_init(avalon);
 }
 }
@@ -644,43 +660,53 @@ static void avalon_init(struct cgpu_info *avalon)
 static bool avalon_prepare(struct thr_info *thr)
 static bool avalon_prepare(struct thr_info *thr)
 {
 {
 	struct cgpu_info *avalon = thr->cgpu;
 	struct cgpu_info *avalon = thr->cgpu;
+	struct avalon_info *info = avalon_infos[avalon->device_id];
 	struct timeval now;
 	struct timeval now;
 
 
+	free(avalon->works);
+	avalon->works = calloc(info->miner_count * sizeof(struct work *),
+			       AVALON_ARRAY_SIZE);
+	if (!avalon->works)
+		quit(1, "Failed to calloc avalon works in avalon_prepare");
 	if (avalon->device_fd == -1)
 	if (avalon->device_fd == -1)
 		avalon_init(avalon);
 		avalon_init(avalon);
 	else
 	else
 		__avalon_init(avalon);
 		__avalon_init(avalon);
 
 
-	gettimeofday(&now, NULL);
+	cgtime(&now);
 	get_datestamp(avalon->init, &now);
 	get_datestamp(avalon->init, &now);
 	return true;
 	return true;
 }
 }
 
 
-static void avalon_free_work(struct thr_info *thr, struct work **work)
+static void avalon_free_work(struct thr_info *thr)
 {
 {
 	struct cgpu_info *avalon;
 	struct cgpu_info *avalon;
 	struct avalon_info *info;
 	struct avalon_info *info;
+	struct work **works;
 	int i;
 	int i;
 
 
-	if (unlikely(!work))
-		return;
-
 	avalon = thr->cgpu;
 	avalon = thr->cgpu;
-	info = avalon_info[avalon->device_id];
+	avalon->queued = 0;
+	if (unlikely(!avalon->works))
+		return;
+	works = avalon->works;
+	info = avalon_infos[avalon->device_id];
 
 
-	for (i = 0; i < info->miner_count; i++)
-		if (likely(work[i])) {
-			free_work(work[i]);
-			work[i] = NULL;
+	for (i = 0; i < info->miner_count * 4; i++) {
+		if (works[i]) {
+			work_completed(avalon, works[i]);
+			works[i] = NULL;
 		}
 		}
+	}
 }
 }
 
 
 static void do_avalon_close(struct thr_info *thr)
 static void do_avalon_close(struct thr_info *thr)
 {
 {
 	struct avalon_result ar;
 	struct avalon_result ar;
 	struct cgpu_info *avalon = thr->cgpu;
 	struct cgpu_info *avalon = thr->cgpu;
-	struct avalon_info *info = avalon_info[avalon->device_id];
+	struct avalon_info *info = avalon_infos[avalon->device_id];
 
 
+	avalon_free_work(thr);
 	nmsleep(1000);
 	nmsleep(1000);
 	avalon_reset(avalon->device_fd, &ar);
 	avalon_reset(avalon->device_fd, &ar);
 	avalon_idle(avalon);
 	avalon_idle(avalon);
@@ -688,16 +714,10 @@ static void do_avalon_close(struct thr_info *thr)
 	avalon->device_fd = -1;
 	avalon->device_fd = -1;
 
 
 	info->no_matching_work = 0;
 	info->no_matching_work = 0;
-	avalon_free_work(thr, info->bulk0);
-	avalon_free_work(thr, info->bulk1);
-	avalon_free_work(thr, info->bulk2);
-	avalon_free_work(thr, info->bulk3);
 }
 }
 
 
 static inline void record_temp_fan(struct avalon_info *info, struct avalon_result *ar, float *temp_avg)
 static inline void record_temp_fan(struct avalon_info *info, struct avalon_result *ar, float *temp_avg)
 {
 {
-	int max;
-
 	info->fan0 = ar->fan0 * AVALON_FAN_FACTOR;
 	info->fan0 = ar->fan0 * AVALON_FAN_FACTOR;
 	info->fan1 = ar->fan1 * AVALON_FAN_FACTOR;
 	info->fan1 = ar->fan1 * AVALON_FAN_FACTOR;
 	info->fan2 = ar->fan2 * AVALON_FAN_FACTOR;
 	info->fan2 = ar->fan2 * AVALON_FAN_FACTOR;
@@ -718,24 +738,14 @@ static inline void record_temp_fan(struct avalon_info *info, struct avalon_resul
 		info->temp2 = 0 - ((~ar->temp2 & 0x7f) + 1);
 		info->temp2 = 0 - ((~ar->temp2 & 0x7f) + 1);
 	}
 	}
 
 
-	*temp_avg = info->temp2;
-
-	max = info->temp_max;
-	if (info->temp0 > max)
-		max = info->temp0;
-	if (info->temp1 > max)
-		max = info->temp1;
-	if (info->temp2 > max)
-		max = info->temp2;
-	if (max >= 100) {	/* FIXME: fix the root cause on fpga controller firmware */
-		if (opt_debug) {
-			applog(LOG_DEBUG, "Avalon: temp_max: %d", max);
-			hexdump((uint8_t *)ar, AVALON_READ_SIZE);
-		}
-		return;
-	}
+	*temp_avg = info->temp2 > info->temp1 ? info->temp2 : info->temp1;
 
 
-	info->temp_max = max;
+	if (info->temp0 > info->temp_max)
+		info->temp_max = info->temp0;
+	if (info->temp1 > info->temp_max)
+		info->temp_max = info->temp1;
+	if (info->temp2 > info->temp_max)
+		info->temp_max = info->temp2;
 }
 }
 
 
 static inline void adjust_fan(struct avalon_info *info)
 static inline void adjust_fan(struct avalon_info *info)
@@ -756,29 +766,61 @@ static inline void adjust_fan(struct avalon_info *info)
 	}
 	}
 }
 }
 
 
-static int64_t avalon_scanhash(struct thr_info *thr, struct work **work,
-			       __maybe_unused int64_t max_nonce)
+/* We use a replacement algorithm to only remove references to work done from
+ * the buffer when we need the extra space for new work. */
+static bool avalon_fill(struct cgpu_info *avalon)
+{
+	int subid, slot, mc = avalon_infos[avalon->device_id]->miner_count;
+	struct work *work;
+
+	if (avalon->queued >= mc)
+		return true;
+	work = get_queued(avalon);
+	if (unlikely(!work))
+		return false;
+	subid = avalon->queued++;
+	work->subid = subid;
+	slot = avalon->work_array * mc + subid;
+	if (likely(avalon->works[slot]))
+		work_completed(avalon, avalon->works[slot]);
+	avalon->works[slot] = work;
+	if (avalon->queued >= mc)
+		return true;
+	return false;
+}
+
+static void avalon_rotate_array(struct cgpu_info *avalon)
+{
+	avalon->queued = 0;
+	if (++avalon->work_array >= AVALON_ARRAY_SIZE)
+		avalon->work_array = 0;
+}
+
+static int64_t avalon_scanhash(struct thr_info *thr)
 {
 {
 	struct cgpu_info *avalon;
 	struct cgpu_info *avalon;
-	int fd, ret, full;
+	struct work **works;
+	int fd, ret = AVA_GETS_OK, full;
 
 
 	struct avalon_info *info;
 	struct avalon_info *info;
 	struct avalon_task at;
 	struct avalon_task at;
 	struct avalon_result ar;
 	struct avalon_result ar;
-	int i, work_i0, work_i1, work_i2, work_i3;
+	int i;
 	int avalon_get_work_count;
 	int avalon_get_work_count;
+	int start_count, end_count;
 
 
 	struct timeval tv_start, tv_finish, elapsed;
 	struct timeval tv_start, tv_finish, elapsed;
 	uint32_t nonce;
 	uint32_t nonce;
 	int64_t hash_count;
 	int64_t hash_count;
 	static int first_try = 0;
 	static int first_try = 0;
-	int result_count, result_wrong;
+	int result_wrong;
 
 
 	avalon = thr->cgpu;
 	avalon = thr->cgpu;
-	info = avalon_info[avalon->device_id];
+	works = avalon->works;
+	info = avalon_infos[avalon->device_id];
 	avalon_get_work_count = info->miner_count;
 	avalon_get_work_count = info->miner_count;
 
 
-	if (unlikely(avalon->device_fd == -1))
+	if (unlikely(avalon->device_fd == -1)) {
 		if (!avalon_prepare(thr)) {
 		if (!avalon_prepare(thr)) {
 			applog(LOG_ERR, "AVA%i: Comms error(open)",
 			applog(LOG_ERR, "AVA%i: Comms error(open)",
 			       avalon->device_id);
 			       avalon->device_id);
@@ -786,35 +828,25 @@ static int64_t avalon_scanhash(struct thr_info *thr, struct work **work,
 			/* fail the device if the reopen attempt fails */
 			/* fail the device if the reopen attempt fails */
 			return -1;
 			return -1;
 		}
 		}
+	}
 	fd = avalon->device_fd;
 	fd = avalon->device_fd;
 #ifndef WIN32
 #ifndef WIN32
 	tcflush(fd, TCOFLUSH);
 	tcflush(fd, TCOFLUSH);
 #endif
 #endif
 
 
-	for (i = 0; i < avalon_get_work_count; i++) {
-		info->bulk0[i] = info->bulk1[i];
-		info->bulk1[i] = info->bulk2[i];
-		info->bulk2[i] = info->bulk3[i];
-		info->bulk3[i] = work[i];
-		applog(LOG_DEBUG, "Avalon: bulk0/1/2 buffer [%d]: %p, %p, %p, %p",
-		       i, info->bulk0[i], info->bulk1[i], info->bulk2[i], info->bulk3[i]);
-	}
-
-	i = 0;
+	start_count = avalon->work_array * avalon_get_work_count;
+	end_count = start_count + avalon_get_work_count;
+	i = start_count;
 	while (true) {
 	while (true) {
 		avalon_init_task(&at, 0, 0, info->fan_pwm,
 		avalon_init_task(&at, 0, 0, info->fan_pwm,
 				 info->timeout, info->asic_count,
 				 info->timeout, info->asic_count,
 				 info->miner_count, 1, 0, info->frequency);
 				 info->miner_count, 1, 0, info->frequency);
-		avalon_create_task(&at, work[i]);
+		avalon_create_task(&at, works[i]);
 		ret = avalon_send_task(fd, &at, avalon);
 		ret = avalon_send_task(fd, &at, avalon);
 		if (unlikely(ret == AVA_SEND_ERROR ||
 		if (unlikely(ret == AVA_SEND_ERROR ||
 			     (ret == AVA_SEND_BUFFER_EMPTY &&
 			     (ret == AVA_SEND_BUFFER_EMPTY &&
-			      (i + 1 == avalon_get_work_count) &&
+			      (i + 1 == end_count) &&
 			      first_try))) {
 			      first_try))) {
-			avalon_free_work(thr, info->bulk0);
-			avalon_free_work(thr, info->bulk1);
-			avalon_free_work(thr, info->bulk2);
-			avalon_free_work(thr, info->bulk3);
 			do_avalon_close(thr);
 			do_avalon_close(thr);
 			applog(LOG_ERR, "AVA%i: Comms error(buffer)",
 			applog(LOG_ERR, "AVA%i: Comms error(buffer)",
 			       avalon->device_id);
 			       avalon->device_id);
@@ -824,12 +856,13 @@ static int64_t avalon_scanhash(struct thr_info *thr, struct work **work,
 			avalon_init(avalon);
 			avalon_init(avalon);
 			return 0;	/* This should never happen */
 			return 0;	/* This should never happen */
 		}
 		}
-		if (ret == AVA_SEND_BUFFER_EMPTY && (i + 1 == avalon_get_work_count)) {
+		if (ret == AVA_SEND_BUFFER_EMPTY && (i + 1 == end_count)) {
 			first_try = 1;
 			first_try = 1;
+			avalon_rotate_array(avalon);
 			return 0xffffffff;
 			return 0xffffffff;
 		}
 		}
 
 
-		work[i]->blk.nonce = 0xffffffff;
+		works[i]->blk.nonce = 0xffffffff;
 
 
 		if (ret == AVA_SEND_BUFFER_FULL)
 		if (ret == AVA_SEND_BUFFER_FULL)
 			break;
 			break;
@@ -840,14 +873,11 @@ static int64_t avalon_scanhash(struct thr_info *thr, struct work **work,
 		first_try = 0;
 		first_try = 0;
 
 
 	elapsed.tv_sec = elapsed.tv_usec = 0;
 	elapsed.tv_sec = elapsed.tv_usec = 0;
-	gettimeofday(&tv_start, NULL);
+	cgtime(&tv_start);
 
 
-	result_count = 0;
 	result_wrong = 0;
 	result_wrong = 0;
 	hash_count = 0;
 	hash_count = 0;
 	while (true) {
 	while (true) {
-		work_i0 = work_i1 = work_i2 = work_i3 = -1;
-
 		full = avalon_buffer_full(fd);
 		full = avalon_buffer_full(fd);
 		applog(LOG_DEBUG, "Avalon: Buffer full: %s",
 		applog(LOG_DEBUG, "Avalon: Buffer full: %s",
 		       ((full == AVA_BUFFER_FULL) ? "Yes" : "No"));
 		       ((full == AVA_BUFFER_FULL) ? "Yes" : "No"));
@@ -856,194 +886,96 @@ static int64_t avalon_scanhash(struct thr_info *thr, struct work **work,
 
 
 		ret = avalon_get_result(fd, &ar, thr, &tv_finish);
 		ret = avalon_get_result(fd, &ar, thr, &tv_finish);
 		if (unlikely(ret == AVA_GETS_ERROR)) {
 		if (unlikely(ret == AVA_GETS_ERROR)) {
-			avalon_free_work(thr, info->bulk0);
-			avalon_free_work(thr, info->bulk1);
-			avalon_free_work(thr, info->bulk2);
-			avalon_free_work(thr, info->bulk3);
 			do_avalon_close(thr);
 			do_avalon_close(thr);
 			applog(LOG_ERR,
 			applog(LOG_ERR,
 			       "AVA%i: Comms error(read)", avalon->device_id);
 			       "AVA%i: Comms error(read)", avalon->device_id);
 			dev_error(avalon, REASON_DEV_COMMS_ERROR);
 			dev_error(avalon, REASON_DEV_COMMS_ERROR);
 			return 0;
 			return 0;
 		}
 		}
+		if (unlikely(ret == AVA_GETS_RESTART))
+			break;
 		if (unlikely(ret == AVA_GETS_TIMEOUT)) {
 		if (unlikely(ret == AVA_GETS_TIMEOUT)) {
 			timersub(&tv_finish, &tv_start, &elapsed);
 			timersub(&tv_finish, &tv_start, &elapsed);
 			applog(LOG_DEBUG, "Avalon: no nonce in (%ld.%06lds)",
 			applog(LOG_DEBUG, "Avalon: no nonce in (%ld.%06lds)",
-			       elapsed.tv_sec, elapsed.tv_usec);
+			       (long)elapsed.tv_sec, (long)elapsed.tv_usec);
 			continue;
 			continue;
 		}
 		}
-		if (unlikely(ret == AVA_GETS_RESTART)) {
-			avalon_free_work(thr, info->bulk0);
-			avalon_free_work(thr, info->bulk1);
-			avalon_free_work(thr, info->bulk2);
-			avalon_free_work(thr, info->bulk3);
-			break;
+
+		if (!avalon_decode_nonce(thr, &ar, &nonce)) {
+			info->no_matching_work++;
+			result_wrong++;
+
+			if (unlikely(result_wrong >= avalon_get_work_count))
+				break;
+
+			if (opt_debug) {
+				timersub(&tv_finish, &tv_start, &elapsed);
+				applog(LOG_DEBUG,"Avalon: no matching work: %d"
+				" (%ld.%06lds)", info->no_matching_work,
+				(long)elapsed.tv_sec, (long)elapsed.tv_usec);
+			}
+			continue;
 		}
 		}
-		result_count++;
-
-		work_i0 = avalon_decode_nonce(thr, info->bulk0, &ar, &nonce);
-		if (work_i0 < 0) {
-			work_i1 = avalon_decode_nonce(thr, info->bulk1, &ar, &nonce);
-			if (work_i1 < 0) {
-				work_i2 = avalon_decode_nonce(thr, info->bulk2, &ar, &nonce);
-				if (work_i2 < 0) {
-					work_i3 = avalon_decode_nonce(thr, info->bulk3, &ar, &nonce);
-					if (work_i3 < 0) {
-						info->no_matching_work++;
-						result_wrong++;
-
-						if (opt_debug) {
-							timersub(&tv_finish, &tv_start, &elapsed);
-							applog(LOG_DEBUG,"Avalon: no matching work: %d"
-							" (%ld.%06lds)", info->no_matching_work,
-							elapsed.tv_sec, elapsed.tv_usec);
-						}
-						continue;
-					} else
-						submit_nonce(thr, info->bulk3[work_i3], nonce);
-				} else
-					submit_nonce(thr, info->bulk2[work_i2], nonce);
-			} else
-				submit_nonce(thr, info->bulk1[work_i1], nonce);
-		} else
-			submit_nonce(thr, info->bulk0[work_i0], nonce);
-
-		hash_count += nonce;
+
+		hash_count += 0xffffffff;
 		if (opt_debug) {
 		if (opt_debug) {
 			timersub(&tv_finish, &tv_start, &elapsed);
 			timersub(&tv_finish, &tv_start, &elapsed);
 			applog(LOG_DEBUG,
 			applog(LOG_DEBUG,
-			       "Avalon: nonce = 0x%08x = 0x%08llx hashes "
-			       "(%ld.%06lds)", nonce, hash_count,
+			       "Avalon: nonce = 0x%08x = 0x%08"PRIx64" hashes "
+			       "(%ld.%06lds)", nonce, (uint64_t)hash_count,
 			       elapsed.tv_sec, elapsed.tv_usec);
 			       elapsed.tv_sec, elapsed.tv_usec);
 		}
 		}
 	}
 	}
-	if (result_wrong && result_count == result_wrong) {
-		/* This mean FPGA controller give all wrong result
-		 * try to reset the Avalon */
-		avalon_free_work(thr, info->bulk0);
-		avalon_free_work(thr, info->bulk1);
-		avalon_free_work(thr, info->bulk2);
-		avalon_free_work(thr, info->bulk3);
+	if (hash_count && avalon->results < AVALON_ARRAY_SIZE)
+		avalon->results++;
+	if (unlikely((result_wrong >= avalon_get_work_count) ||
+	    (!hash_count && ret != AVA_GETS_RESTART && --avalon->results < 0))) {
+		/* Look for all invalid results, or consecutive failure
+		 * to generate any results suggesting the FPGA
+		 * controller has screwed up. */
 		do_avalon_close(thr);
 		do_avalon_close(thr);
 		applog(LOG_ERR,
 		applog(LOG_ERR,
-		       "AVA%i: FPGA controller mess up", avalon->device_id);
+			"AVA%i: FPGA controller messed up, %d wrong results",
+			avalon->device_id, result_wrong);
 		dev_error(avalon, REASON_DEV_COMMS_ERROR);
 		dev_error(avalon, REASON_DEV_COMMS_ERROR);
-		do_avalon_close(thr);
 		nmsleep(1000);
 		nmsleep(1000);
 		avalon_init(avalon);
 		avalon_init(avalon);
 		return 0;
 		return 0;
 	}
 	}
 
 
-	avalon_free_work(thr, info->bulk0);
-
-	record_temp_fan(info, &ar, &(avalon->temp));
-	applog(LOG_INFO,
-	       "Avalon: Fan1: %d/m, Fan2: %d/m, Fan3: %d/m\t"
-	       "Temp1: %dC, Temp2: %dC, Temp3: %dC, TempMAX: %dC",
-	       info->fan0, info->fan1, info->fan2,
-	       info->temp0, info->temp1, info->temp2, info->temp_max);
-	info->temp_history_index++;
-	info->temp_sum += info->temp2;
-	applog(LOG_DEBUG, "Avalon: temp_index: %d, temp_count: %d, temp_old: %d",
-	       info->temp_history_index, info->temp_history_count, info->temp_old);
-	if (info->temp_history_index == info->temp_history_count) {
-		adjust_fan(info);
-		info->temp_history_index = 0;
-		info->temp_sum = 0;
-	}
-
-	/*
-	 * FIXME: Each work split to 10 pieces, each piece send to a
-	 * asic(256MHs). one work can be mulit-nonce back. it is not
-	 * easy calculate correct hash on such situation. so I simplely
-	 * add each nonce to hash_count. base on Utility/m hash_count*2
-	 * give a very good result.
-	 *
-	 * Any patch will be great.
-	 */
-	return (hash_count * 2);
-}
-
-// minerloop_scanhash hacked to handle Avalon's many processors
-static
-void minerloop_avalon(struct thr_info *mythr)
-{
-	const int thr_id = mythr->id;
-	struct cgpu_info *cgpu = mythr->cgpu;
-	struct device_drv *api = cgpu->drv;
-	struct timeval tv_start, tv_end;
-	struct timeval tv_hashes;
-	uint32_t max_nonce = api->can_limit_work ? api->can_limit_work(mythr) : 0xffffffff;
-	int64_t hashes;
-	struct avalon_info *info = avalon_info[cgpu->device_id];
-	int i;
-	int avalon_get_work_count = info->miner_count;
-	struct work **work = calloc(1,
-				    avalon_get_work_count * sizeof(struct work *));
-	if (!work)
-		quit(1, "Faile on Avalon calloc");
-	const bool primary = (!mythr->device_thread) || mythr->primary_thread;
-	
-	while (1) {
-		mythr->work_restart = false;
-		for (i = 0; i < avalon_get_work_count; i++)
-			request_work(mythr);
-		for (i = 0; i < avalon_get_work_count; i++) {
-			work[i] = get_work(mythr);
-			work[i]->blk.nonce = 0;
+	avalon_rotate_array(avalon);
+
+	if (hash_count) {
+		record_temp_fan(info, &ar, &(avalon->temp));
+		applog(LOG_INFO,
+		       "Avalon: Fan1: %d/m, Fan2: %d/m, Fan3: %d/m\t"
+		       "Temp1: %dC, Temp2: %dC, Temp3: %dC, TempMAX: %dC",
+		       info->fan0, info->fan1, info->fan2,
+		       info->temp0, info->temp1, info->temp2, info->temp_max);
+		info->temp_history_index++;
+		info->temp_sum += avalon->temp;
+		applog(LOG_DEBUG, "Avalon: temp_index: %d, temp_count: %d, temp_old: %d",
+		       info->temp_history_index, info->temp_history_count, info->temp_old);
+		if (info->temp_history_index == info->temp_history_count) {
+			adjust_fan(info);
+			info->temp_history_index = 0;
+			info->temp_sum = 0;
 		}
 		}
-		for (i = 0; i < avalon_get_work_count; i++) {
-			if (api->prepare_work && !api->prepare_work(mythr, work[i])) {
-				applog(LOG_ERR, "work prepare failed, exiting "
-					"mining thread %d", thr_id);
-				break;
-			}
-			gettimeofday(&(work[i]->tv_work_start), NULL);
-		}
-		
-		do {
-			thread_reportin(mythr);
-			gettimeofday(&tv_start, NULL);
-			hashes = api->scanhash_queue(mythr, work, max_nonce);
-			gettimeofday(&tv_end, NULL);
-			thread_reportin(mythr);
-			
-			timersub(&tv_end, &tv_start, &tv_hashes);
-			if (!hashes_done(mythr, hashes, &tv_hashes, api->can_limit_work ? &max_nonce : NULL))
-				goto disabled;
-			
-			if (unlikely(mythr->work_restart)) {
-				/* Apart from device_thread 0, we stagger the
-				 * starting of every next thread to try and get
-				 * all devices busy before worrying about
-				 * getting work for their extra threads */
-				if (!primary) {
-					struct timespec rgtp;
-
-					rgtp.tv_sec = 0;
-					rgtp.tv_nsec = 250 * mythr->device_thread * 1000000;
-					nanosleep(&rgtp, NULL);
-				}
-				break;
-			}
-			
-			if (unlikely(mythr->pause || cgpu->deven != DEV_ENABLED))
-disabled:
-				mt_disable(mythr);
-		} while (false);
 	}
 	}
-	free(work);
+
+	/* This hashmeter is just a utility counter based on returned shares */
+	return hash_count;
 }
 }
 
 
-static struct api_data *avalon_drv_stats(struct cgpu_info *cgpu)
+static struct api_data *avalon_api_stats(struct cgpu_info *cgpu)
 {
 {
 	struct api_data *root = NULL;
 	struct api_data *root = NULL;
-	struct avalon_info *info = avalon_info[cgpu->device_id];
+	struct avalon_info *info = avalon_infos[cgpu->device_id];
+	int i;
 
 
 	root = api_add_int(root, "baud", &(info->baud), false);
 	root = api_add_int(root, "baud", &(info->baud), false);
 	root = api_add_int(root, "miner_count", &(info->miner_count),false);
 	root = api_add_int(root, "miner_count", &(info->miner_count),false);
 	root = api_add_int(root, "asic_count", &(info->asic_count), false);
 	root = api_add_int(root, "asic_count", &(info->asic_count), false);
-	root = api_add_int(root, "read_count", &(info->read_count), false);
 	root = api_add_int(root, "timeout", &(info->timeout), false);
 	root = api_add_int(root, "timeout", &(info->timeout), false);
 	root = api_add_int(root, "frequency", &(info->frequency), false);
 	root = api_add_int(root, "frequency", &(info->frequency), false);
 
 
@@ -1057,30 +989,12 @@ static struct api_data *avalon_drv_stats(struct cgpu_info *cgpu)
 	root = api_add_int(root, "temp_max", &(info->temp_max), false);
 	root = api_add_int(root, "temp_max", &(info->temp_max), false);
 
 
 	root = api_add_int(root, "no_matching_work", &(info->no_matching_work), false);
 	root = api_add_int(root, "no_matching_work", &(info->no_matching_work), false);
-	root = api_add_int(root, "matching_work_count1", &(info->matching_work[0]), false);
-	root = api_add_int(root, "matching_work_count2", &(info->matching_work[1]), false);
-	root = api_add_int(root, "matching_work_count3", &(info->matching_work[2]), false);
-	root = api_add_int(root, "matching_work_count4", &(info->matching_work[3]), false);
-	root = api_add_int(root, "matching_work_count5", &(info->matching_work[4]), false);
-	root = api_add_int(root, "matching_work_count6", &(info->matching_work[5]), false);
-	root = api_add_int(root, "matching_work_count7", &(info->matching_work[6]), false);
-	root = api_add_int(root, "matching_work_count8", &(info->matching_work[7]), false);
-	root = api_add_int(root, "matching_work_count9", &(info->matching_work[8]), false);
-	root = api_add_int(root, "matching_work_count10", &(info->matching_work[9]), false);
-	root = api_add_int(root, "matching_work_count11", &(info->matching_work[10]), false);
-	root = api_add_int(root, "matching_work_count12", &(info->matching_work[11]), false);
-	root = api_add_int(root, "matching_work_count13", &(info->matching_work[12]), false);
-	root = api_add_int(root, "matching_work_count14", &(info->matching_work[13]), false);
-	root = api_add_int(root, "matching_work_count15", &(info->matching_work[14]), false);
-	root = api_add_int(root, "matching_work_count16", &(info->matching_work[15]), false);
-	root = api_add_int(root, "matching_work_count17", &(info->matching_work[16]), false);
-	root = api_add_int(root, "matching_work_count18", &(info->matching_work[17]), false);
-	root = api_add_int(root, "matching_work_count19", &(info->matching_work[18]), false);
-	root = api_add_int(root, "matching_work_count20", &(info->matching_work[19]), false);
-	root = api_add_int(root, "matching_work_count21", &(info->matching_work[20]), false);
-	root = api_add_int(root, "matching_work_count22", &(info->matching_work[21]), false);
-	root = api_add_int(root, "matching_work_count23", &(info->matching_work[22]), false);
-	root = api_add_int(root, "matching_work_count24", &(info->matching_work[23]), false);
+	for (i = 0; i < info->miner_count; i++) {
+		char mcw[24];
+
+		sprintf(mcw, "match_work_count%d", i + 1);
+		root = api_add_int(root, mcw, &(info->matching_work[i]), false);
+	}
 
 
 	return root;
 	return root;
 }
 }
@@ -1095,9 +1009,10 @@ struct device_drv avalon_drv = {
 	.name = "AVA",
 	.name = "AVA",
 	.drv_detect = avalon_detect,
 	.drv_detect = avalon_detect,
 	.thread_prepare = avalon_prepare,
 	.thread_prepare = avalon_prepare,
-	.minerloop = minerloop_avalon,
-	.scanhash_queue = avalon_scanhash,
-	.get_api_stats = avalon_drv_stats,
+	.minerloop = hash_queued_work,
+	.queue_full = avalon_fill,
+	.scanwork = avalon_scanhash,
+	.get_api_stats = avalon_api_stats,
 	.reinit_device = avalon_init,
 	.reinit_device = avalon_init,
 	.thread_shutdown = avalon_shutdown,
 	.thread_shutdown = avalon_shutdown,
 };
 };

+ 4 - 7
driver-avalon.h

@@ -10,7 +10,8 @@
 #ifndef AVALON_H
 #ifndef AVALON_H
 #define AVALON_H
 #define AVALON_H
 
 
-#define AVALON_TIME_FACTOR 10
+#ifdef USE_AVALON
+
 #define AVALON_RESET_FAULT_DECISECONDS 1
 #define AVALON_RESET_FAULT_DECISECONDS 1
 #define AVALON_MINER_THREADS 1
 #define AVALON_MINER_THREADS 1
 
 
@@ -71,8 +72,6 @@ struct avalon_result {
 } __attribute__((packed, aligned(4)));
 } __attribute__((packed, aligned(4)));
 
 
 struct avalon_info {
 struct avalon_info {
-	int read_count;
-
 	int baud;
 	int baud;
 	int miner_count;
 	int miner_count;
 	int asic_count;
 	int asic_count;
@@ -94,16 +93,13 @@ struct avalon_info {
 
 
 	int no_matching_work;
 	int no_matching_work;
 	int matching_work[AVALON_DEFAULT_MINER_NUM];
 	int matching_work[AVALON_DEFAULT_MINER_NUM];
-	struct work *bulk0[AVALON_DEFAULT_MINER_NUM];
-	struct work *bulk1[AVALON_DEFAULT_MINER_NUM];
-	struct work *bulk2[AVALON_DEFAULT_MINER_NUM];
-	struct work *bulk3[AVALON_DEFAULT_MINER_NUM];
 
 
 	int frequency;
 	int frequency;
 };
 };
 
 
 #define AVALON_WRITE_SIZE (sizeof(struct avalon_task))
 #define AVALON_WRITE_SIZE (sizeof(struct avalon_task))
 #define AVALON_READ_SIZE (sizeof(struct avalon_result))
 #define AVALON_READ_SIZE (sizeof(struct avalon_result))
+#define AVALON_ARRAY_SIZE 4
 
 
 #define AVA_GETS_ERROR -1
 #define AVA_GETS_ERROR -1
 #define AVA_GETS_OK 0
 #define AVA_GETS_OK 0
@@ -130,4 +126,5 @@ ASSERT1(sizeof(uint32_t) == 4);
 
 
 extern struct avalon_info **avalon_info;
 extern struct avalon_info **avalon_info;
 
 
+#endif /* USE_AVALON */
 #endif	/* AVALON_H */
 #endif	/* AVALON_H */

+ 9 - 8
driver-bitforce.c

@@ -22,6 +22,7 @@
 #include "deviceapi.h"
 #include "deviceapi.h"
 #include "miner.h"
 #include "miner.h"
 #include "fpgautils.h"
 #include "fpgautils.h"
+#include "util.h"
 
 
 #define BITFORCE_SLEEP_MS 500
 #define BITFORCE_SLEEP_MS 500
 #define BITFORCE_TIMEOUT_S 7
 #define BITFORCE_TIMEOUT_S 7
@@ -286,7 +287,7 @@ static bool bitforce_thread_prepare(struct thr_info *thr)
 	bitforce->device_fd = fdDev;
 	bitforce->device_fd = fdDev;
 
 
 	applog(LOG_INFO, "%s: Opened %s", bitforce->dev_repr, bitforce->device_path);
 	applog(LOG_INFO, "%s: Opened %s", bitforce->dev_repr, bitforce->device_path);
-	gettimeofday(&now, NULL);
+	cgtime(&now);
 	get_datestamp(bitforce->init, &now);
 	get_datestamp(bitforce->init, &now);
 
 
 	return true;
 	return true;
@@ -699,7 +700,7 @@ re_send:
 	bitforce_cmd2(fdDev, data->xlink_id, pdevbuf, sizeof(pdevbuf), data->next_work_cmd, ob, data->next_work_obsz);
 	bitforce_cmd2(fdDev, data->xlink_id, pdevbuf, sizeof(pdevbuf), data->next_work_cmd, ob, data->next_work_obsz);
 	if (!pdevbuf[0] || !strncasecmp(pdevbuf, "B", 1)) {
 	if (!pdevbuf[0] || !strncasecmp(pdevbuf, "B", 1)) {
 		mutex_unlock(mutexp);
 		mutex_unlock(mutexp);
-		gettimeofday(&tv_now, NULL);
+		cgtime(&tv_now);
 		timer_set_delay(&thr->tv_poll, &tv_now, WORK_CHECK_INTERVAL_MS * 1000);
 		timer_set_delay(&thr->tv_poll, &tv_now, WORK_CHECK_INTERVAL_MS * 1000);
 		data->poll_func = 1;
 		data->poll_func = 1;
 		return;
 		return;
@@ -727,7 +728,7 @@ re_send:
 
 
 	dbg_block_data(bitforce);
 	dbg_block_data(bitforce);
 
 
-	gettimeofday(&tv_now, NULL);
+	cgtime(&tv_now);
 	bitforce->work_start_tv = tv_now;
 	bitforce->work_start_tv = tv_now;
 	
 	
 	timer_set_delay(&thr->tv_morework, &tv_now, bitforce->sleep_ms * 1000);
 	timer_set_delay(&thr->tv_morework, &tv_now, bitforce->sleep_ms * 1000);
@@ -764,7 +765,7 @@ int bitforce_zox(struct thr_info *thr, const char *cmd)
 		size_t szleft = sizeof(data->noncebuf) - cls, sz;
 		size_t szleft = sizeof(data->noncebuf) - cls, sz;
 		
 		
 		if (count && data->queued)
 		if (count && data->queued)
-			gettimeofday(&bitforce->work_start_tv, NULL);
+			cgtime(&bitforce->work_start_tv);
 		
 		
 		while (true)
 		while (true)
 		{
 		{
@@ -813,7 +814,7 @@ void bitforce_job_get_results(struct thr_info *thr, struct work *work)
 	bool stale;
 	bool stale;
 	int count;
 	int count;
 
 
-	gettimeofday(&now, NULL);
+	cgtime(&now);
 	timersub(&now, &bitforce->work_start_tv, &elapsed);
 	timersub(&now, &bitforce->work_start_tv, &elapsed);
 	bitforce->wait_ms = tv_to_ms(elapsed);
 	bitforce->wait_ms = tv_to_ms(elapsed);
 	bitforce->polling = true;
 	bitforce->polling = true;
@@ -849,7 +850,7 @@ void bitforce_job_get_results(struct thr_info *thr, struct work *work)
 		const char *cmd = (data->proto == BFP_QUEUE) ? "ZOX" : "ZFX";
 		const char *cmd = (data->proto == BFP_QUEUE) ? "ZOX" : "ZFX";
 		count = bitforce_zox(thr, cmd);
 		count = bitforce_zox(thr, cmd);
 
 
-		gettimeofday(&now, NULL);
+		cgtime(&now);
 		timersub(&now, &bitforce->work_start_tv, &elapsed);
 		timersub(&now, &bitforce->work_start_tv, &elapsed);
 
 
 		if (elapsed.tv_sec >= BITFORCE_LONG_TIMEOUT_S) {
 		if (elapsed.tv_sec >= BITFORCE_LONG_TIMEOUT_S) {
@@ -1381,7 +1382,7 @@ bool bitforce_send_queue(struct thr_info *thr)
 	}
 	}
 	
 	
 	if (!data->queued)
 	if (!data->queued)
-		gettimeofday(&data->tv_hashmeter_start, NULL);
+		cgtime(&data->tv_hashmeter_start);
 	
 	
 	queued_ok = atoi(&buf[9]);
 	queued_ok = atoi(&buf[9]);
 	data->queued += queued_ok;
 	data->queued += queued_ok;
@@ -1511,7 +1512,7 @@ next_qline: (void)0;
 		applog(LOG_DEBUG, "%"PRIpreprv": Received %d queue results after %ums; Wait time unchanged (queued<=%d)",
 		applog(LOG_DEBUG, "%"PRIpreprv": Received %d queue results after %ums; Wait time unchanged (queued<=%d)",
 		       bitforce->proc_repr, count, bitforce->sleep_ms, data->queued);
 		       bitforce->proc_repr, count, bitforce->sleep_ms, data->queued);
 	
 	
-	gettimeofday(&tv_now, NULL);
+	cgtime(&tv_now);
 	timersub(&tv_now, &data->tv_hashmeter_start, &tv_elapsed);
 	timersub(&tv_now, &data->tv_hashmeter_start, &tv_elapsed);
 	hashes_done(thr, (uint64_t)bitforce->nonces * count, &tv_elapsed, NULL);
 	hashes_done(thr, (uint64_t)bitforce->nonces * count, &tv_elapsed, NULL);
 	data->tv_hashmeter_start = tv_now;
 	data->tv_hashmeter_start = tv_now;

+ 1 - 2
driver-cpu.c

@@ -75,7 +75,6 @@ static inline void affine_to_cpu(int __maybe_unused id, int __maybe_unused cpu)
 
 
 
 
 /* TODO: resolve externals */
 /* TODO: resolve externals */
-extern void submit_work_async(const struct work *work_in, struct timeval *tv);
 extern char *set_int_range(const char *arg, int *i, int min, int max);
 extern char *set_int_range(const char *arg, int *i, int min, int max);
 extern int dev_from_id(int thr_id);
 extern int dev_from_id(int thr_id);
 
 
@@ -840,7 +839,7 @@ CPUSearch:
 	/* if nonce found, submit work */
 	/* if nonce found, submit work */
 	if (unlikely(rc)) {
 	if (unlikely(rc)) {
 		applog(LOG_DEBUG, "%"PRIpreprv" found something?", thr->cgpu->proc_repr);
 		applog(LOG_DEBUG, "%"PRIpreprv" found something?", thr->cgpu->proc_repr);
-		submit_work_async(work, NULL);
+		submit_nonce(thr, work, last_nonce);
 		work->blk.nonce = last_nonce + 1;
 		work->blk.nonce = last_nonce + 1;
 		goto CPUSearch;
 		goto CPUSearch;
 	}
 	}

+ 6 - 6
driver-icarus.c

@@ -242,7 +242,7 @@ int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, struct th
 			return ICA_GETS_ERROR;
 			return ICA_GETS_ERROR;
 
 
 		if (first)
 		if (first)
-			gettimeofday(tv_finish, NULL);
+			cgtime(tv_finish);
 
 
 		if (ret >= read_amount)
 		if (ret >= read_amount)
 		{
 		{
@@ -576,7 +576,7 @@ bool icarus_detect_custom(const char *devpath, struct device_drv *api, struct IC
 
 
 	hex2bin(ob_bin, golden_ob, sizeof(ob_bin));
 	hex2bin(ob_bin, golden_ob, sizeof(ob_bin));
 	icarus_write(fd, ob_bin, sizeof(ob_bin));
 	icarus_write(fd, ob_bin, sizeof(ob_bin));
-	gettimeofday(&tv_start, NULL);
+	cgtime(&tv_start);
 
 
 	memset(nonce_bin, 0, sizeof(nonce_bin));
 	memset(nonce_bin, 0, sizeof(nonce_bin));
 	icarus_gets(nonce_bin, fd, &tv_finish, NULL, 1);
 	icarus_gets(nonce_bin, fd, &tv_finish, NULL, 1);
@@ -672,7 +672,7 @@ static bool icarus_prepare(struct thr_info *thr)
 	icarus->device_fd = fd;
 	icarus->device_fd = fd;
 
 
 	applog(LOG_INFO, "Opened Icarus on %s", icarus->device_path);
 	applog(LOG_INFO, "Opened Icarus on %s", icarus->device_path);
-	gettimeofday(&now, NULL);
+	cgtime(&now);
 	get_datestamp(icarus->init, &now);
 	get_datestamp(icarus->init, &now);
 
 
 	struct icarus_state *state;
 	struct icarus_state *state;
@@ -766,7 +766,7 @@ static bool icarus_start_work(struct thr_info *thr, const unsigned char *ob_bin)
 	int ret;
 	int ret;
 	char *ob_hex;
 	char *ob_hex;
 
 
-	gettimeofday(&state->tv_workstart, NULL);
+	cgtime(&state->tv_workstart);
 
 
 	ret = icarus_write(fd, ob_bin, 64);
 	ret = icarus_write(fd, ob_bin, 64);
 	if (ret) {
 	if (ret) {
@@ -996,7 +996,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	&&  !was_hw_error
 	&&  !was_hw_error
 	&&  ((nonce & info->nonce_mask) > END_CONDITION)
 	&&  ((nonce & info->nonce_mask) > END_CONDITION)
 	&&  ((nonce & info->nonce_mask) < (info->nonce_mask & ~END_CONDITION))) {
 	&&  ((nonce & info->nonce_mask) < (info->nonce_mask & ~END_CONDITION))) {
-		gettimeofday(&tv_history_start, NULL);
+		cgtime(&tv_history_start);
 
 
 		history0 = &(info->history[0]);
 		history0 = &(info->history[0]);
 
 
@@ -1085,7 +1085,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 					Hs, W, read_count, fullnonce);
 					Hs, W, read_count, fullnonce);
 		}
 		}
 		info->history_count++;
 		info->history_count++;
-		gettimeofday(&tv_history_finish, NULL);
+		cgtime(&tv_history_finish);
 
 
 		timersub(&tv_history_finish, &tv_history_start, &tv_history_finish);
 		timersub(&tv_history_finish, &tv_history_start, &tv_history_finish);
 		timeradd(&tv_history_finish, &(info->history_time), &(info->history_time));
 		timeradd(&tv_history_finish, &(info->history_time), &(info->history_time));

+ 16 - 11
driver-opencl.c

@@ -44,6 +44,7 @@
 #include "findnonce.h"
 #include "findnonce.h"
 #include "ocl.h"
 #include "ocl.h"
 #include "adl.h"
 #include "adl.h"
+#include "util.h"
 
 
 /* TODO: cleanup externals ********************/
 /* TODO: cleanup externals ********************/
 
 
@@ -1355,7 +1356,7 @@ select_cgpu:
 
 
 		thr->rolling = thr->cgpu->rolling = 0;
 		thr->rolling = thr->cgpu->rolling = 0;
 		/* Reports the last time we tried to revive a sick GPU */
 		/* Reports the last time we tried to revive a sick GPU */
-		gettimeofday(&thr->sick, NULL);
+		cgtime(&thr->sick);
 		if (!pthread_cancel(thr->pth)) {
 		if (!pthread_cancel(thr->pth)) {
 			applog(LOG_WARNING, "Thread %d still exists, killing it off", thr_id);
 			applog(LOG_WARNING, "Thread %d still exists, killing it off", thr_id);
 		} else
 		} else
@@ -1395,7 +1396,7 @@ select_cgpu:
 		applog(LOG_WARNING, "Thread %d restarted", thr_id);
 		applog(LOG_WARNING, "Thread %d restarted", thr_id);
 	}
 	}
 
 
-	gettimeofday(&now, NULL);
+	cgtime(&now);
 	get_datestamp(sel_cgpu->init, &now);
 	get_datestamp(sel_cgpu->init, &now);
 
 
 	proc_enable(cgpu);
 	proc_enable(cgpu);
@@ -1587,9 +1588,10 @@ static bool opencl_thread_prepare(struct thr_info *thr)
 	int virtual_gpu = cgpu->virtual_gpu;
 	int virtual_gpu = cgpu->virtual_gpu;
 	int i = thr->id;
 	int i = thr->id;
 	static bool failmessage = false;
 	static bool failmessage = false;
+	int buffersize = opt_scrypt ? SCRYPT_BUFFERSIZE : BUFFERSIZE;
 
 
 	if (!blank_res)
 	if (!blank_res)
-		blank_res = calloc(BUFFERSIZE, 1);
+		blank_res = calloc(buffersize, 1);
 	if (!blank_res) {
 	if (!blank_res) {
 		applog(LOG_ERR, "Failed to calloc in opencl_thread_init");
 		applog(LOG_ERR, "Failed to calloc in opencl_thread_init");
 		return false;
 		return false;
@@ -1651,7 +1653,7 @@ static bool opencl_thread_prepare(struct thr_info *thr)
 		}
 		}
 	}
 	}
 	applog(LOG_INFO, "initCl() finished. Found %s", name);
 	applog(LOG_INFO, "initCl() finished. Found %s", name);
-	gettimeofday(&now, NULL);
+	cgtime(&now);
 	get_datestamp(cgpu->init, &now);
 	get_datestamp(cgpu->init, &now);
 
 
 	have_opencl = true;
 	have_opencl = true;
@@ -1668,6 +1670,7 @@ static bool opencl_thread_init(struct thr_info *thr)
 	cl_int status = 0;
 	cl_int status = 0;
 	thrdata = calloc(1, sizeof(*thrdata));
 	thrdata = calloc(1, sizeof(*thrdata));
 	thr->cgpu_data = thrdata;
 	thr->cgpu_data = thrdata;
+	int buffersize = opt_scrypt ? SCRYPT_BUFFERSIZE : BUFFERSIZE;
 
 
 	if (!thrdata) {
 	if (!thrdata) {
 		applog(LOG_ERR, "Failed to calloc in opencl_thread_init");
 		applog(LOG_ERR, "Failed to calloc in opencl_thread_init");
@@ -1695,7 +1698,7 @@ static bool opencl_thread_init(struct thr_info *thr)
 			break;
 			break;
 	}
 	}
 
 
-	thrdata->res = calloc(BUFFERSIZE, 1);
+	thrdata->res = calloc(buffersize, 1);
 
 
 	if (!thrdata->res) {
 	if (!thrdata->res) {
 		free(thrdata);
 		free(thrdata);
@@ -1704,7 +1707,7 @@ static bool opencl_thread_init(struct thr_info *thr)
 	}
 	}
 
 
 	status |= clEnqueueWriteBuffer(clState->commandQueue, clState->outputBuffer, CL_TRUE, 0,
 	status |= clEnqueueWriteBuffer(clState->commandQueue, clState->outputBuffer, CL_TRUE, 0,
-			BUFFERSIZE, blank_res, 0, NULL, NULL);
+				       buffersize, blank_res, 0, NULL, NULL);
 	if (unlikely(status != CL_SUCCESS)) {
 	if (unlikely(status != CL_SUCCESS)) {
 		applog(LOG_ERR, "Error: clEnqueueWriteBuffer failed.");
 		applog(LOG_ERR, "Error: clEnqueueWriteBuffer failed.");
 		return false;
 		return false;
@@ -1745,13 +1748,15 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
 	size_t globalThreads[1];
 	size_t globalThreads[1];
 	size_t localThreads[1] = { clState->wsize };
 	size_t localThreads[1] = { clState->wsize };
 	int64_t hashes;
 	int64_t hashes;
+	int found = opt_scrypt ? SCRYPT_FOUND : FOUND;
+	int buffersize = opt_scrypt ? SCRYPT_BUFFERSIZE : BUFFERSIZE;
 
 
 	/* Windows' timer resolution is only 15ms so oversample 5x */
 	/* Windows' timer resolution is only 15ms so oversample 5x */
 	if (gpu->dynamic && (++gpu->intervals * dynamic_us) > 70000) {
 	if (gpu->dynamic && (++gpu->intervals * dynamic_us) > 70000) {
 		struct timeval tv_gpuend;
 		struct timeval tv_gpuend;
 		double gpu_us;
 		double gpu_us;
 
 
-		gettimeofday(&tv_gpuend, NULL);
+		cgtime(&tv_gpuend);
 		gpu_us = us_tdiff(&tv_gpuend, &gpu->tv_gpustart) / gpu->intervals;
 		gpu_us = us_tdiff(&tv_gpuend, &gpu->tv_gpustart) / gpu->intervals;
 		if (gpu_us > dynamic_us) {
 		if (gpu_us > dynamic_us) {
 			if (gpu->intensity > MIN_INTENSITY)
 			if (gpu->intensity > MIN_INTENSITY)
@@ -1789,7 +1794,7 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
 	}
 	}
 
 
 	status = clEnqueueReadBuffer(clState->commandQueue, clState->outputBuffer, CL_FALSE, 0,
 	status = clEnqueueReadBuffer(clState->commandQueue, clState->outputBuffer, CL_FALSE, 0,
-			BUFFERSIZE, thrdata->res, 0, NULL, NULL);
+				     buffersize, thrdata->res, 0, NULL, NULL);
 	if (unlikely(status != CL_SUCCESS)) {
 	if (unlikely(status != CL_SUCCESS)) {
 		applog(LOG_ERR, "Error: clEnqueueReadBuffer failed error %d. (clEnqueueReadBuffer)", status);
 		applog(LOG_ERR, "Error: clEnqueueReadBuffer failed error %d. (clEnqueueReadBuffer)", status);
 		return -1;
 		return -1;
@@ -1804,17 +1809,17 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
 	clFinish(clState->commandQueue);
 	clFinish(clState->commandQueue);
 
 
 	/* FOUND entry is used as a counter to say how many nonces exist */
 	/* FOUND entry is used as a counter to say how many nonces exist */
-	if (thrdata->res[FOUND]) {
+	if (thrdata->res[found]) {
 		/* Clear the buffer again */
 		/* Clear the buffer again */
 		status = clEnqueueWriteBuffer(clState->commandQueue, clState->outputBuffer, CL_FALSE, 0,
 		status = clEnqueueWriteBuffer(clState->commandQueue, clState->outputBuffer, CL_FALSE, 0,
-				BUFFERSIZE, blank_res, 0, NULL, NULL);
+					      buffersize, blank_res, 0, NULL, NULL);
 		if (unlikely(status != CL_SUCCESS)) {
 		if (unlikely(status != CL_SUCCESS)) {
 			applog(LOG_ERR, "Error: clEnqueueWriteBuffer failed.");
 			applog(LOG_ERR, "Error: clEnqueueWriteBuffer failed.");
 			return -1;
 			return -1;
 		}
 		}
 		applog(LOG_DEBUG, "GPU %d found something?", gpu->device_id);
 		applog(LOG_DEBUG, "GPU %d found something?", gpu->device_id);
 		postcalc_hash_async(thr, work, thrdata->res);
 		postcalc_hash_async(thr, work, thrdata->res);
-		memset(thrdata->res, 0, BUFFERSIZE);
+		memset(thrdata->res, 0, buffersize);
 		/* This finish flushes the writebuffer set with CL_FALSE in clEnqueueWriteBuffer */
 		/* This finish flushes the writebuffer set with CL_FALSE in clEnqueueWriteBuffer */
 		clFinish(clState->commandQueue);
 		clFinish(clState->commandQueue);
 	}
 	}

+ 2 - 1
driver-ztex.c

@@ -33,6 +33,7 @@
 #include "dynclock.h"
 #include "dynclock.h"
 #include "fpgautils.h"
 #include "fpgautils.h"
 #include "libztex.h"
 #include "libztex.h"
+#include "util.h"
 
 
 #define GOLDEN_BACKLOG 5
 #define GOLDEN_BACKLOG 5
 
 
@@ -357,7 +358,7 @@ static bool ztex_prepare(struct thr_info *thr)
 	struct cgpu_info *cgpu = thr->cgpu;
 	struct cgpu_info *cgpu = thr->cgpu;
 	struct libztex_device *ztex = cgpu->device_ztex;
 	struct libztex_device *ztex = cgpu->device_ztex;
 
 
-	gettimeofday(&now, NULL);
+	cgtime(&now);
 	get_datestamp(cgpu->init, &now);
 	get_datestamp(cgpu->init, &now);
 
 
 	if (cgpu->proc_id)
 	if (cgpu->proc_id)

+ 9 - 5
findnonce.c

@@ -136,7 +136,7 @@ void precalc_hash(dev_blk_ctx *blk, uint32_t *state, uint32_t *data)
 struct pc_data {
 struct pc_data {
 	struct thr_info *thr;
 	struct thr_info *thr;
 	struct work work;
 	struct work work;
-	uint32_t res[MAXBUFFERS];
+	uint32_t res[SCRYPT_MAXBUFFERS];
 	pthread_t pth;
 	pthread_t pth;
 	int found;
 	int found;
 };
 };
@@ -146,21 +146,22 @@ static void *postcalc_hash(void *userdata)
 	struct pc_data *pcd = (struct pc_data *)userdata;
 	struct pc_data *pcd = (struct pc_data *)userdata;
 	struct thr_info *thr = pcd->thr;
 	struct thr_info *thr = pcd->thr;
 	unsigned int entry = 0;
 	unsigned int entry = 0;
+	int found = opt_scrypt ? SCRYPT_FOUND : FOUND;
 
 
 	pthread_detach(pthread_self());
 	pthread_detach(pthread_self());
 	RenameThread("postcalchsh");
 	RenameThread("postcalchsh");
 
 
 	/* To prevent corrupt values in FOUND from trying to read beyond the
 	/* To prevent corrupt values in FOUND from trying to read beyond the
 	 * end of the res[] array */
 	 * end of the res[] array */
-	if (unlikely(pcd->res[FOUND] & ~FOUND)) {
+	if (unlikely(pcd->res[found] & ~found)) {
 		applog(LOG_WARNING, "%"PRIpreprv": invalid nonce count - HW error",
 		applog(LOG_WARNING, "%"PRIpreprv": invalid nonce count - HW error",
 				thr->cgpu->proc_repr);
 				thr->cgpu->proc_repr);
 		hw_errors++;
 		hw_errors++;
 		thr->cgpu->hw_errors++;
 		thr->cgpu->hw_errors++;
-		pcd->res[FOUND] &= FOUND;
+		pcd->res[found] &= found;
 	}
 	}
 
 
-	for (entry = 0; entry < pcd->res[FOUND]; entry++) {
+	for (entry = 0; entry < pcd->res[found]; entry++) {
 		uint32_t nonce = pcd->res[entry];
 		uint32_t nonce = pcd->res[entry];
 
 
 		applog(LOG_DEBUG, "OCL NONCE %u found in slot %d", nonce, entry);
 		applog(LOG_DEBUG, "OCL NONCE %u found in slot %d", nonce, entry);
@@ -176,6 +177,8 @@ static void *postcalc_hash(void *userdata)
 void postcalc_hash_async(struct thr_info *thr, struct work *work, uint32_t *res)
 void postcalc_hash_async(struct thr_info *thr, struct work *work, uint32_t *res)
 {
 {
 	struct pc_data *pcd = malloc(sizeof(struct pc_data));
 	struct pc_data *pcd = malloc(sizeof(struct pc_data));
+	int buffersize;
+
 	if (unlikely(!pcd)) {
 	if (unlikely(!pcd)) {
 		applog(LOG_ERR, "Failed to malloc pc_data in postcalc_hash_async");
 		applog(LOG_ERR, "Failed to malloc pc_data in postcalc_hash_async");
 		return;
 		return;
@@ -185,7 +188,8 @@ void postcalc_hash_async(struct thr_info *thr, struct work *work, uint32_t *res)
 		.thr = thr,
 		.thr = thr,
 	};
 	};
 	__copy_work(&pcd->work, work);
 	__copy_work(&pcd->work, work);
-	memcpy(&pcd->res, res, BUFFERSIZE);
+	buffersize = opt_scrypt ? SCRYPT_BUFFERSIZE : BUFFERSIZE;
+	memcpy(&pcd->res, res, buffersize);
 
 
 	if (pthread_create(&pcd->pth, NULL, postcalc_hash, (void *)pcd)) {
 	if (pthread_create(&pcd->pth, NULL, postcalc_hash, (void *)pcd)) {
 		applog(LOG_ERR, "Failed to create postcalc_hash thread");
 		applog(LOG_ERR, "Failed to create postcalc_hash thread");

+ 4 - 0
findnonce.h

@@ -8,6 +8,10 @@
 #define BUFFERSIZE (sizeof(uint32_t) * MAXBUFFERS)
 #define BUFFERSIZE (sizeof(uint32_t) * MAXBUFFERS)
 #define FOUND (0x0F)
 #define FOUND (0x0F)
 
 
+#define SCRYPT_MAXBUFFERS (0x100)
+#define SCRYPT_BUFFERSIZE (sizeof(uint32_t) * SCRYPT_MAXBUFFERS)
+#define SCRYPT_FOUND (0xFF)
+
 #ifdef HAVE_OPENCL
 #ifdef HAVE_OPENCL
 extern void precalc_hash(dev_blk_ctx *blk, uint32_t *state, uint32_t *data);
 extern void precalc_hash(dev_blk_ctx *blk, uint32_t *state, uint32_t *data);
 extern void postcalc_hash_async(struct thr_info *thr, struct work *work, uint32_t *res);
 extern void postcalc_hash_async(struct thr_info *thr, struct work *work, uint32_t *res);

+ 18 - 1
fpgautils.c

@@ -1,5 +1,6 @@
 /*
 /*
  * Copyright 2012-2013 Luke Dashjr
  * Copyright 2012-2013 Luke Dashjr
+ * Copyright 2013 Con Kolivas
  * Copyright 2012 Andrew Smith
  * Copyright 2012 Andrew Smith
  * Copyright 2013 Xiangfu
  * Copyright 2013 Xiangfu
  *
  *
@@ -27,8 +28,8 @@
 #ifndef WIN32
 #ifndef WIN32
 #include <errno.h>
 #include <errno.h>
 #include <termios.h>
 #include <termios.h>
-#include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <sys/ioctl.h>
+#include <sys/stat.h>
 #include <unistd.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <fcntl.h>
 #ifndef O_CLOEXEC
 #ifndef O_CLOEXEC
@@ -57,10 +58,12 @@ enum {
 
 
 #ifdef HAVE_LIBUDEV
 #ifdef HAVE_LIBUDEV
 #include <libudev.h>
 #include <libudev.h>
+#include <sys/ioctl.h>
 #endif
 #endif
 
 
 #include "elist.h"
 #include "elist.h"
 #include "logging.h"
 #include "logging.h"
+#include "miner.h"
 #include "fpgautils.h"
 #include "fpgautils.h"
 
 
 #define SEARCH_NEEDLES_BEGIN()  {  \
 #define SEARCH_NEEDLES_BEGIN()  {  \
@@ -928,5 +931,19 @@ int set_serial_rts(int fd, int rts)
 	ioctl(fd, TIOCMSET, &flags);
 	ioctl(fd, TIOCMSET, &flags);
 	return flags & TIOCM_CTS;
 	return flags & TIOCM_CTS;
 }
 }
+#else
+int get_serial_cts(const int fd)
+{
+	if (!fd)
+		return -1;
+	const HANDLE fh = (HANDLE)_get_osfhandle(fd);
+	if (!fh)
+		return -1;
 
 
+	DWORD flags;
+	if (!GetCommModemStatus(fh, &flags))
+		return -1;
+
+	return (flags & MS_CTS_ON) ? 1 : 0;
+}
 #endif // ! WIN32
 #endif // ! WIN32

+ 3 - 1
logging.c

@@ -15,6 +15,7 @@
 #include "compat.h"
 #include "compat.h"
 #include "logging.h"
 #include "logging.h"
 #include "miner.h"
 #include "miner.h"
+// #include "util.h"
 
 
 bool opt_debug = false;
 bool opt_debug = false;
 bool opt_debug_console = false;  // Only used if opt_debug is also enabled
 bool opt_debug_console = false;  // Only used if opt_debug is also enabled
@@ -99,7 +100,7 @@ static void log_generic(int prio, const char *fmt, va_list ap)
 		struct tm _tm;
 		struct tm _tm;
 		struct tm *tm = &_tm;
 		struct tm *tm = &_tm;
 
 
-		gettimeofday(&tv, NULL);
+		cgtime(&tv);
 
 
 		localtime_r(&tv.tv_sec, tm);
 		localtime_r(&tv.tv_sec, tm);
 
 
@@ -119,6 +120,7 @@ static void log_generic(int prio, const char *fmt, va_list ap)
 
 
 			va_copy(apc, ap);
 			va_copy(apc, ap);
 			vfprintf(stderr, f, apc);	/* atomic write to stderr */
 			vfprintf(stderr, f, apc);	/* atomic write to stderr */
+			va_end(apc);
 			fflush(stderr);
 			fflush(stderr);
 		}
 		}
 
 

File diff suppressed because it is too large
+ 195 - 135
miner.c


+ 21 - 13
miner.h

@@ -289,9 +289,6 @@ struct device_drv {
 	uint64_t (*can_limit_work)(struct thr_info *);
 	uint64_t (*can_limit_work)(struct thr_info *);
 	bool (*thread_init)(struct thr_info *);
 	bool (*thread_init)(struct thr_info *);
 	bool (*prepare_work)(struct thr_info *, struct work *);
 	bool (*prepare_work)(struct thr_info *, struct work *);
-#ifdef USE_AVALON
-	int64_t (*scanhash_queue)(struct thr_info *, struct work **, int64_t);
-#endif
 	int64_t (*scanhash)(struct thr_info *, struct work *, int64_t);
 	int64_t (*scanhash)(struct thr_info *, struct work *, int64_t);
 	int64_t (*scanwork)(struct thr_info *);
 	int64_t (*scanwork)(struct thr_info *);
 
 
@@ -436,6 +433,12 @@ struct cgpu_info {
 		struct ft232r_device_handle *device_ft232r;
 		struct ft232r_device_handle *device_ft232r;
 #endif
 #endif
 	};
 	};
+#ifdef USE_AVALON
+	struct work **works;
+	int work_array;
+	int queued;
+	int results;
+#endif
 #ifdef USE_BITFORCE
 #ifdef USE_BITFORCE
 	struct timeval work_start_tv;
 	struct timeval work_start_tv;
 	unsigned int wait_ms;
 	unsigned int wait_ms;
@@ -535,6 +538,7 @@ struct cgpu_info {
 
 
 	pthread_rwlock_t qlock;
 	pthread_rwlock_t qlock;
 	struct work *queued_work;
 	struct work *queued_work;
+	unsigned int queued_count;
 };
 };
 
 
 extern void renumber_cgpu(struct cgpu_info *);
 extern void renumber_cgpu(struct cgpu_info *);
@@ -603,13 +607,6 @@ struct thr_info {
 	notifier_t work_restart_notifier;
 	notifier_t work_restart_notifier;
 };
 };
 
 
-extern int thr_info_create(struct thr_info *thr, pthread_attr_t *attr, void *(*start) (void *), void *arg);
-extern void thr_info_cancel(struct thr_info *thr);
-extern void thr_info_freeze(struct thr_info *thr);
-extern void nmsleep(unsigned int msecs);
-extern double us_tdiff(struct timeval *end, struct timeval *start);
-extern double tdiff(struct timeval *end, struct timeval *start);
-
 struct string_elist {
 struct string_elist {
 	char *string;
 	char *string;
 	bool free_me;
 	bool free_me;
@@ -839,7 +836,9 @@ extern bool opt_restart;
 extern char *opt_icarus_options;
 extern char *opt_icarus_options;
 extern char *opt_icarus_timing;
 extern char *opt_icarus_timing;
 extern bool opt_worktime;
 extern bool opt_worktime;
+#ifdef USE_AVALON
 extern char *opt_avalon_options;
 extern char *opt_avalon_options;
+#endif
 #ifdef USE_BITFORCE
 #ifdef USE_BITFORCE
 extern bool opt_bfl_noncerange;
 extern bool opt_bfl_noncerange;
 #endif
 #endif
@@ -870,6 +869,7 @@ extern int opt_scantime;
 extern int opt_expiry;
 extern int opt_expiry;
 
 
 extern cglock_t control_lock;
 extern cglock_t control_lock;
+extern pthread_mutex_t stats_lock;
 extern pthread_mutex_t hash_lock;
 extern pthread_mutex_t hash_lock;
 extern pthread_mutex_t console_lock;
 extern pthread_mutex_t console_lock;
 extern cglock_t ch_lock;
 extern cglock_t ch_lock;
@@ -882,6 +882,7 @@ extern void clear_stratum_shares(struct pool *pool);
 extern void hashmeter2(struct thr_info *);
 extern void hashmeter2(struct thr_info *);
 extern bool stale_work(struct work *, bool share);
 extern bool stale_work(struct work *, bool share);
 extern bool stale_work_future(struct work *, bool share, unsigned long ustime);
 extern bool stale_work_future(struct work *, bool share, unsigned long ustime);
+extern void set_target(unsigned char *dest_target, double diff);
 
 
 extern void kill_work(void);
 extern void kill_work(void);
 extern void app_restart(void);
 extern void app_restart(void);
@@ -1159,6 +1160,8 @@ struct work {
 	unsigned char	target[32];
 	unsigned char	target[32];
 	unsigned char	hash[32];
 	unsigned char	hash[32];
 
 
+	uint64_t	share_diff;
+
 	int		rolls;
 	int		rolls;
 
 
 	dev_blk_ctx	blk;
 	dev_blk_ctx	blk;
@@ -1191,6 +1194,10 @@ struct work {
 	
 	
 	double		work_difficulty;
 	double		work_difficulty;
 
 
+	// Allow devices to identify work if multiple sub-devices
+	// DEPRECATED: New code should be using multiple processors instead
+	char		subid;
+
 	blktemplate_t	*tmpl;
 	blktemplate_t	*tmpl;
 	int		*tmpl_refcount;
 	int		*tmpl_refcount;
 	unsigned int	dataid;
 	unsigned int	dataid;
@@ -1208,10 +1215,11 @@ struct work {
 };
 };
 
 
 extern void get_datestamp(char *, struct timeval *);
 extern void get_datestamp(char *, struct timeval *);
+extern void inc_hw_errors(struct thr_info *thr);
 enum test_nonce2_result {
 enum test_nonce2_result {
-	TNR_GOOD,
-	TNR_HIGH,
-	TNR_BAD,
+	TNR_GOOD = 1,
+	TNR_HIGH = 0,
+	TNR_BAD = -1,
 };
 };
 extern enum test_nonce2_result _test_nonce2(struct work *, uint32_t nonce, bool checktarget);
 extern enum test_nonce2_result _test_nonce2(struct work *, uint32_t nonce, bool checktarget);
 #define test_nonce(work, nonce, checktarget)  (_test_nonce2(work, nonce, checktarget) == TNR_GOOD)
 #define test_nonce(work, nonce, checktarget)  (_test_nonce2(work, nonce, checktarget) == TNR_GOOD)

+ 9 - 1
ocl.c

@@ -212,7 +212,12 @@ CL_API_ENTRY cl_int CL_API_CALL
                        cl_event *       /* event */) CL_API_SUFFIX__VERSION_1_0;
                        cl_event *       /* event */) CL_API_SUFFIX__VERSION_1_0;
 
 
 int opt_platform_id = -1;
 int opt_platform_id = -1;
+#ifdef __APPLE__
+// Apple OpenCL doesn't like using binaries this way
+bool opt_opencl_binaries;
+#else
 bool opt_opencl_binaries = true;
 bool opt_opencl_binaries = true;
+#endif
 
 
 char *file_contents(const char *filename, int *length)
 char *file_contents(const char *filename, int *length)
 {
 {
@@ -668,6 +673,8 @@ _clState *initCl(unsigned int gpu, char *name, size_t nameSize)
 
 
 	if (cgpu->work_size && cgpu->work_size <= clState->max_work_size)
 	if (cgpu->work_size && cgpu->work_size <= clState->max_work_size)
 		clState->wsize = cgpu->work_size;
 		clState->wsize = cgpu->work_size;
+	else if (opt_scrypt)
+		clState->wsize = 256;
 	else if (strstr(name, "Tahiti"))
 	else if (strstr(name, "Tahiti"))
 		clState->wsize = 64;
 		clState->wsize = 64;
 	else
 	else
@@ -1027,7 +1034,8 @@ built:
 			applog(LOG_ERR, "Error %d: clCreateBuffer (CLbuffer0)", status);
 			applog(LOG_ERR, "Error %d: clCreateBuffer (CLbuffer0)", status);
 			return NULL;
 			return NULL;
 		}
 		}
-	}
+		clState->outputBuffer = clCreateBuffer(clState->context, CL_MEM_WRITE_ONLY, SCRYPT_BUFFERSIZE, NULL, &status);
+	} else
 #endif
 #endif
 	clState->outputBuffer = clCreateBuffer(clState->context, CL_MEM_WRITE_ONLY, BUFFERSIZE, NULL, &status);
 	clState->outputBuffer = clCreateBuffer(clState->context, CL_MEM_WRITE_ONLY, BUFFERSIZE, NULL, &status);
 	if (status != CL_SUCCESS) {
 	if (status != CL_SUCCESS) {

+ 16 - 6
scrypt.c

@@ -405,7 +405,7 @@ static void scrypt_1024_1_1_256_sp(const uint32_t* input, char* scratchpad, uint
 /* 131583 rounded up to 4 byte alignment */
 /* 131583 rounded up to 4 byte alignment */
 #define SCRATCHBUF_SIZE	(131584)
 #define SCRATCHBUF_SIZE	(131584)
 
 
-void scrypt_outputhash(struct work *work)
+void scrypt_regenhash(struct work *work)
 {
 {
 	uint32_t data[20];
 	uint32_t data[20];
 	char *scratchbuf;
 	char *scratchbuf;
@@ -419,10 +419,12 @@ void scrypt_outputhash(struct work *work)
 	flip32(ohash, ohash);
 	flip32(ohash, ohash);
 }
 }
 
 
+static const uint32_t diff1targ = 0x0000ffff;
+
 /* Used externally as confirmation of correct OCL code */
 /* Used externally as confirmation of correct OCL code */
-bool scrypt_test(unsigned char *pdata, const unsigned char *ptarget, uint32_t nonce)
+int scrypt_test(unsigned char *pdata, const unsigned char *ptarget, uint32_t nonce)
 {
 {
-	uint32_t tmp_hash7, Htarg = ((const uint32_t *)ptarget)[7];
+	uint32_t tmp_hash7, Htarg = le32toh(((const uint32_t *)ptarget)[7]);
 	uint32_t data[20], ohash[8];
 	uint32_t data[20], ohash[8];
 	char *scratchbuf;
 	char *scratchbuf;
 
 
@@ -432,7 +434,15 @@ bool scrypt_test(unsigned char *pdata, const unsigned char *ptarget, uint32_t no
 	scrypt_1024_1_1_256_sp(data, scratchbuf, ohash);
 	scrypt_1024_1_1_256_sp(data, scratchbuf, ohash);
 	tmp_hash7 = be32toh(ohash[7]);
 	tmp_hash7 = be32toh(ohash[7]);
 
 
-	return (tmp_hash7 <= Htarg);
+	applog(LOG_DEBUG, "htarget %08lx diff1 %08lx hash %08lx",
+				(long unsigned int)Htarg,
+				(long unsigned int)diff1targ,
+				(long unsigned int)tmp_hash7);
+	if (tmp_hash7 > diff1targ)
+		return -1;
+	if (tmp_hash7 > Htarg)
+		return 0;
+	return 1;
 }
 }
 
 
 bool scanhash_scrypt(struct thr_info *thr, const unsigned char __maybe_unused *pmidstate,
 bool scanhash_scrypt(struct thr_info *thr, const unsigned char __maybe_unused *pmidstate,
@@ -444,7 +454,7 @@ bool scanhash_scrypt(struct thr_info *thr, const unsigned char __maybe_unused *p
 	char *scratchbuf;
 	char *scratchbuf;
 	uint32_t data[20];
 	uint32_t data[20];
 	uint32_t tmp_hash7;
 	uint32_t tmp_hash7;
-	uint32_t Htarg = ((const uint32_t *)ptarget)[7];
+	uint32_t Htarg = le32toh(((const uint32_t *)ptarget)[7]);
 	bool ret = false;
 	bool ret = false;
 
 
 	be32enc_vect(data, (const uint32_t *)pdata, 19);
 	be32enc_vect(data, (const uint32_t *)pdata, 19);
@@ -459,7 +469,7 @@ bool scanhash_scrypt(struct thr_info *thr, const unsigned char __maybe_unused *p
 		uint32_t ostate[8];
 		uint32_t ostate[8];
 
 
 		*nonce = ++n;
 		*nonce = ++n;
-		data[19] = n;
+		data[19] = htobe32(n);
 		scrypt_1024_1_1_256_sp(data, scratchbuf, ostate);
 		scrypt_1024_1_1_256_sp(data, scratchbuf, ostate);
 		tmp_hash7 = be32toh(ostate[7]);
 		tmp_hash7 = be32toh(ostate[7]);
 
 

+ 5 - 5
scrypt.h

@@ -4,19 +4,19 @@
 #include "miner.h"
 #include "miner.h"
 
 
 #ifdef USE_SCRYPT
 #ifdef USE_SCRYPT
-extern bool scrypt_test(unsigned char *pdata, const unsigned char *ptarget,
+extern int scrypt_test(unsigned char *pdata, const unsigned char *ptarget,
 			uint32_t nonce);
 			uint32_t nonce);
-extern void scrypt_outputhash(struct work *work);
+extern void scrypt_regenhash(struct work *work);
 
 
 #else /* USE_SCRYPT */
 #else /* USE_SCRYPT */
-static inline bool scrypt_test(__maybe_unused unsigned char *pdata,
+static inline int scrypt_test(__maybe_unused unsigned char *pdata,
 			       __maybe_unused const unsigned char *ptarget,
 			       __maybe_unused const unsigned char *ptarget,
 			       __maybe_unused uint32_t nonce)
 			       __maybe_unused uint32_t nonce)
 {
 {
-	return false;
+	return 0;
 }
 }
 
 
-static inline void scrypt_outputhash(__maybe_unused struct work *work)
+static inline void scrypt_regenhash(__maybe_unused struct work *work)
 {
 {
 }
 }
 #endif /* USE_SCRYPT */
 #endif /* USE_SCRYPT */

+ 2 - 2
scrypt130302.cl → scrypt130511.cl

@@ -808,8 +808,8 @@ void scrypt_core(uint4 X[8], __global uint4*restrict lookup)
 	unshittify(X);
 	unshittify(X);
 }
 }
 
 
-#define FOUND (0x0F)
-#define SETFOUND(Xnonce) output[output[FOUND]++] = Xnonce
+#define SCRYPT_FOUND (0xFF)
+#define SETFOUND(Xnonce) output[output[SCRYPT_FOUND]++] = Xnonce
 
 
 __attribute__((reqd_work_group_size(WORKSIZE, 1, 1)))
 __attribute__((reqd_work_group_size(WORKSIZE, 1, 1)))
 __kernel void search(__global const uint4 * restrict input,
 __kernel void search(__global const uint4 * restrict input,

+ 94 - 30
util.c

@@ -32,6 +32,7 @@
 # include <pthread_np.h>
 # include <pthread_np.h>
 #endif
 #endif
 #ifndef WIN32
 #ifndef WIN32
+#include <fcntl.h>
 # ifdef __linux
 # ifdef __linux
 #  include <sys/prctl.h>
 #  include <sys/prctl.h>
 # endif
 # endif
@@ -40,9 +41,11 @@
 # include <netinet/tcp.h>
 # include <netinet/tcp.h>
 # include <netdb.h>
 # include <netdb.h>
 #else
 #else
+# include <windows.h>
 # include <winsock2.h>
 # include <winsock2.h>
 # include <mstcpip.h>
 # include <mstcpip.h>
 # include <ws2tcpip.h>
 # include <ws2tcpip.h>
+# include <mmsystem.h>
 #endif
 #endif
 
 
 #include "miner.h"
 #include "miner.h"
@@ -234,21 +237,35 @@ out:
 
 
 static int keep_sockalive(SOCKETTYPE fd)
 static int keep_sockalive(SOCKETTYPE fd)
 {
 {
+	const int tcp_one = 1;
 	const int tcp_keepidle = 45;
 	const int tcp_keepidle = 45;
 	const int tcp_keepintvl = 30;
 	const int tcp_keepintvl = 30;
-	const int keepalive = 1;
 	int ret = 0;
 	int ret = 0;
 
 
+	if (unlikely(setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const char *)&tcp_one, sizeof(tcp_one))))
+		ret = 1;
 
 
 #ifndef WIN32
 #ifndef WIN32
-	const int tcp_keepcnt = 1;
+	int flags = fcntl(fd, F_GETFL, 0);
 
 
-	if (unlikely(setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive))))
-		ret = 1;
+	fcntl(fd, F_SETFL, O_NONBLOCK | flags);
+#else
+	u_long flags = 1;
 
 
-# ifdef __linux
+	ioctlsocket(fd, FIONBIO, &flags);
+#endif
+
+	if (!opt_delaynet)
+#ifndef __linux
+		if (unlikely(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void *)&tcp_one, sizeof(tcp_one))))
+#else /* __linux */
+		if (unlikely(setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&tcp_one, sizeof(tcp_one))))
+#endif /* __linux */
+			ret = 1;
+
+#ifdef __linux
 
 
-	if (unlikely(setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &tcp_keepcnt, sizeof(tcp_keepcnt))))
+	if (unlikely(setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &tcp_one, sizeof(tcp_one))))
 		ret = 1;
 		ret = 1;
 
 
 	if (unlikely(setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &tcp_keepidle, sizeof(tcp_keepidle))))
 	if (unlikely(setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &tcp_keepidle, sizeof(tcp_keepidle))))
@@ -256,15 +273,16 @@ static int keep_sockalive(SOCKETTYPE fd)
 
 
 	if (unlikely(setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &tcp_keepintvl, sizeof(tcp_keepintvl))))
 	if (unlikely(setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &tcp_keepintvl, sizeof(tcp_keepintvl))))
 		ret = 1;
 		ret = 1;
-# endif /* __linux */
-# ifdef __APPLE_CC__
+#endif /* __linux */
+
+#ifdef __APPLE_CC__
 
 
 	if (unlikely(setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &tcp_keepintvl, sizeof(tcp_keepintvl))))
 	if (unlikely(setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &tcp_keepintvl, sizeof(tcp_keepintvl))))
 		ret = 1;
 		ret = 1;
 
 
-# endif /* __APPLE_CC__ */
+#endif /* __APPLE_CC__ */
 
 
-#else /* WIN32 */
+#ifdef WIN32
 
 
 	const int zero = 0;
 	const int zero = 0;
 	struct tcp_keepalive vals;
 	struct tcp_keepalive vals;
@@ -274,9 +292,6 @@ static int keep_sockalive(SOCKETTYPE fd)
 
 
 	DWORD outputBytes;
 	DWORD outputBytes;
 
 
-	if (unlikely(setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const char *)&keepalive, sizeof(keepalive))))
-		ret = 1;
-
 	if (unlikely(WSAIoctl(fd, SIO_KEEPALIVE_VALS, &vals, sizeof(vals), NULL, 0, &outputBytes, NULL, NULL)))
 	if (unlikely(WSAIoctl(fd, SIO_KEEPALIVE_VALS, &vals, sizeof(vals), NULL, 0, &outputBytes, NULL, NULL)))
 		ret = 1;
 		ret = 1;
 
 
@@ -307,7 +322,7 @@ static void last_nettime(struct timeval *last)
 static void set_nettime(void)
 static void set_nettime(void)
 {
 {
 	wr_lock(&netacc_lock);
 	wr_lock(&netacc_lock);
-	gettimeofday(&nettime, NULL);
+	cgtime(&nettime);
 	wr_unlock(&netacc_lock);
 	wr_unlock(&netacc_lock);
 }
 }
 
 
@@ -463,7 +478,7 @@ void json_rpc_call_async(CURL *curl, const char *url,
 			long long now_msecs, last_msecs;
 			long long now_msecs, last_msecs;
 			struct timeval now, last;
 			struct timeval now, last;
 
 
-			gettimeofday(&now, NULL);
+			cgtime(&now);
 			last_nettime(&last);
 			last_nettime(&last);
 			now_msecs = (long long)now.tv_sec * 1000;
 			now_msecs = (long long)now.tv_sec * 1000;
 			now_msecs += now.tv_usec / 1000;
 			now_msecs += now.tv_usec / 1000;
@@ -775,7 +790,7 @@ bool hash_target_check_v(const unsigned char *hash, const unsigned char *target)
 		applog(LOG_DEBUG, " Proof: %s\nTarget: %s\nTrgVal? %s",
 		applog(LOG_DEBUG, " Proof: %s\nTarget: %s\nTrgVal? %s",
 			hash_str,
 			hash_str,
 			target_str,
 			target_str,
-			rc ? "YES (hash < target)" :
+			rc ? "YES (hash <= target)" :
 			     "no (false positive; hash > target)");
 			     "no (false positive; hash > target)");
 
 
 		free(hash_str);
 		free(hash_str);
@@ -831,9 +846,7 @@ void tq_free(struct thread_q *tq)
 static void tq_freezethaw(struct thread_q *tq, bool frozen)
 static void tq_freezethaw(struct thread_q *tq, bool frozen)
 {
 {
 	mutex_lock(&tq->mutex);
 	mutex_lock(&tq->mutex);
-
 	tq->frozen = frozen;
 	tq->frozen = frozen;
-
 	pthread_cond_signal(&tq->cond);
 	pthread_cond_signal(&tq->cond);
 	mutex_unlock(&tq->mutex);
 	mutex_unlock(&tq->mutex);
 }
 }
@@ -861,14 +874,12 @@ bool tq_push(struct thread_q *tq, void *data)
 	INIT_LIST_HEAD(&ent->q_node);
 	INIT_LIST_HEAD(&ent->q_node);
 
 
 	mutex_lock(&tq->mutex);
 	mutex_lock(&tq->mutex);
-
 	if (!tq->frozen) {
 	if (!tq->frozen) {
 		list_add_tail(&ent->q_node, &tq->q);
 		list_add_tail(&ent->q_node, &tq->q);
 	} else {
 	} else {
 		free(ent);
 		free(ent);
 		rc = false;
 		rc = false;
 	}
 	}
-
 	pthread_cond_signal(&tq->cond);
 	pthread_cond_signal(&tq->cond);
 	mutex_unlock(&tq->mutex);
 	mutex_unlock(&tq->mutex);
 
 
@@ -882,7 +893,6 @@ void *tq_pop(struct thread_q *tq, const struct timespec *abstime)
 	int rc;
 	int rc;
 
 
 	mutex_lock(&tq->mutex);
 	mutex_lock(&tq->mutex);
-
 	if (!list_empty(&tq->q))
 	if (!list_empty(&tq->q))
 		goto pop;
 		goto pop;
 
 
@@ -894,16 +904,15 @@ void *tq_pop(struct thread_q *tq, const struct timespec *abstime)
 		goto out;
 		goto out;
 	if (list_empty(&tq->q))
 	if (list_empty(&tq->q))
 		goto out;
 		goto out;
-
 pop:
 pop:
 	ent = list_entry(tq->q.next, struct tq_ent, q_node);
 	ent = list_entry(tq->q.next, struct tq_ent, q_node);
 	rval = ent->data;
 	rval = ent->data;
 
 
 	list_del(&ent->q_node);
 	list_del(&ent->q_node);
 	free(ent);
 	free(ent);
-
 out:
 out:
 	mutex_unlock(&tq->mutex);
 	mutex_unlock(&tq->mutex);
+
 	return rval;
 	return rval;
 }
 }
 
 
@@ -1050,6 +1059,9 @@ void nmsleep(unsigned int msecs)
 	int ret;
 	int ret;
 	ldiv_t d;
 	ldiv_t d;
 
 
+#ifdef WIN32
+	timeBeginPeriod(1);
+#endif
 	d = ldiv(msecs, 1000);
 	d = ldiv(msecs, 1000);
 	tleft.tv_sec = d.quot;
 	tleft.tv_sec = d.quot;
 	tleft.tv_nsec = d.rem * 1000000;
 	tleft.tv_nsec = d.rem * 1000000;
@@ -1058,6 +1070,48 @@ void nmsleep(unsigned int msecs)
 		twait.tv_nsec = tleft.tv_nsec;
 		twait.tv_nsec = tleft.tv_nsec;
 		ret = nanosleep(&twait, &tleft);
 		ret = nanosleep(&twait, &tleft);
 	} while (ret == -1 && errno == EINTR);
 	} while (ret == -1 && errno == EINTR);
+#ifdef WIN32
+	timeEndPeriod(1);
+#endif
+}
+
+/* This is a cgminer gettimeofday wrapper. Since we always call gettimeofday
+ * with tz set to NULL, and windows' default resolution is only 15ms, this
+ * gives us higher resolution times on windows. */
+void cgtime(struct timeval *tv)
+{
+#ifdef WIN32
+	timeBeginPeriod(1);
+#endif
+	gettimeofday(tv, NULL);
+#ifdef WIN32
+	timeEndPeriod(1);
+#endif
+}
+
+void subtime(struct timeval *a, struct timeval *b)
+{
+	timersub(a, b, b);
+}
+
+void addtime(struct timeval *a, struct timeval *b)
+{
+	timeradd(a, b, b);
+}
+
+bool time_more(struct timeval *a, struct timeval *b)
+{
+	return timercmp(a, b, >);
+}
+
+bool time_less(struct timeval *a, struct timeval *b)
+{
+	return timercmp(a, b, <);
+}
+
+void copy_time(struct timeval *dest, const struct timeval *src)
+{
+	memcpy(dest, src, sizeof(struct timeval));
 }
 }
 
 
 /* Returns the microseconds difference between end and start times as a double */
 /* Returns the microseconds difference between end and start times as a double */
@@ -1136,7 +1190,7 @@ static enum send_ret __stratum_send(struct pool *pool, char *s, ssize_t len)
 	len++;
 	len++;
 
 
 	while (len > 0 ) {
 	while (len > 0 ) {
-		struct timeval timeout = {0, 0};
+		struct timeval timeout = {1, 0};
 		ssize_t sent;
 		ssize_t sent;
 		fd_set wd;
 		fd_set wd;
 
 
@@ -1144,7 +1198,13 @@ static enum send_ret __stratum_send(struct pool *pool, char *s, ssize_t len)
 		FD_SET(sock, &wd);
 		FD_SET(sock, &wd);
 		if (select(sock + 1, NULL, &wd, NULL, &timeout) < 1)
 		if (select(sock + 1, NULL, &wd, NULL, &timeout) < 1)
 			return SEND_SELECTFAIL;
 			return SEND_SELECTFAIL;
+#ifdef __APPLE__
+		sent = send(pool->sock, s + ssent, len, SO_NOSIGPIPE);
+#elif WIN32
 		sent = send(pool->sock, s + ssent, len, 0);
 		sent = send(pool->sock, s + ssent, len, 0);
+#else
+		sent = send(pool->sock, s + ssent, len, MSG_NOSIGNAL);
+#endif
 		if (sent < 0) {
 		if (sent < 0) {
 			if (!sock_blocks())
 			if (!sock_blocks())
 				return SEND_SENDFAIL;
 				return SEND_SENDFAIL;
@@ -1203,7 +1263,7 @@ static bool socket_full(struct pool *pool, bool wait)
 	if (wait)
 	if (wait)
 		timeout.tv_sec = 60;
 		timeout.tv_sec = 60;
 	else
 	else
-		timeout.tv_sec = 0;
+		timeout.tv_sec = 1;
 	if (select(sock + 1, &rd, NULL, NULL, &timeout) > 0)
 	if (select(sock + 1, &rd, NULL, NULL, &timeout) > 0)
 		return true;
 		return true;
 	return false;
 	return false;
@@ -1248,7 +1308,8 @@ static void recalloc_sock(struct pool *pool, size_t len)
 	if (new < pool->sockbuf_size)
 	if (new < pool->sockbuf_size)
 		return;
 		return;
 	new = new + (RBUFSIZE - (new % RBUFSIZE));
 	new = new + (RBUFSIZE - (new % RBUFSIZE));
-	applog(LOG_DEBUG, "Recallocing pool sockbuf to %lu", (unsigned long)new);
+	// Avoid potentially recursive locking
+	// applog(LOG_DEBUG, "Recallocing pool sockbuf to %lu", (unsigned long)new);
 	pool->sockbuf = realloc(pool->sockbuf, new);
 	pool->sockbuf = realloc(pool->sockbuf, new);
 	if (!pool->sockbuf)
 	if (!pool->sockbuf)
 		quit(1, "Failed to realloc pool sockbuf in recalloc_sock");
 		quit(1, "Failed to realloc pool sockbuf in recalloc_sock");
@@ -1273,7 +1334,7 @@ char *recv_line(struct pool *pool)
 		enum recv_ret ret = RECV_OK;
 		enum recv_ret ret = RECV_OK;
 		struct timeval rstart, now;
 		struct timeval rstart, now;
 
 
-		gettimeofday(&rstart, NULL);
+		cgtime(&rstart);
 		if (!socket_full(pool, true)) {
 		if (!socket_full(pool, true)) {
 			applog(LOG_DEBUG, "Timed out waiting for data on socket_full");
 			applog(LOG_DEBUG, "Timed out waiting for data on socket_full");
 			goto out;
 			goto out;
@@ -1292,7 +1353,7 @@ char *recv_line(struct pool *pool)
 				break;
 				break;
 			}
 			}
 			if (n < 0) {
 			if (n < 0) {
-				if (!sock_blocks()) {
+				if (!sock_blocks() || !socket_full(pool, false)) {
 					ret = RECV_RECVFAIL;
 					ret = RECV_RECVFAIL;
 					break;
 					break;
 				}
 				}
@@ -1301,7 +1362,7 @@ char *recv_line(struct pool *pool)
 				recalloc_sock(pool, slen);
 				recalloc_sock(pool, slen);
 				strcat(pool->sockbuf, s);
 				strcat(pool->sockbuf, s);
 			}
 			}
-			gettimeofday(&now, NULL);
+			cgtime(&now);
 		} while (tdiff(&now, &rstart) < 60 && !strstr(pool->sockbuf, "\n"));
 		} while (tdiff(&now, &rstart) < 60 && !strstr(pool->sockbuf, "\n"));
 		mutex_unlock(&pool->stratum_lock);
 		mutex_unlock(&pool->stratum_lock);
 
 
@@ -1798,6 +1859,7 @@ static bool setup_stratum_curl(struct pool *pool)
 	if (pool->sockbuf)
 	if (pool->sockbuf)
 		pool->sockbuf[0] = '\0';
 		pool->sockbuf[0] = '\0';
 	mutex_unlock(&pool->stratum_lock);
 	mutex_unlock(&pool->stratum_lock);
+
 	curl = pool->stratum_curl;
 	curl = pool->stratum_curl;
 
 
 	if (!pool->sockbuf) {
 	if (!pool->sockbuf) {
@@ -1815,7 +1877,8 @@ static bool setup_stratum_curl(struct pool *pool)
 	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_err_str);
 	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_err_str);
 	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
 	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
 	curl_easy_setopt(curl, CURLOPT_URL, s);
 	curl_easy_setopt(curl, CURLOPT_URL, s);
-	curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1);
+	if (!opt_delaynet)
+		curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1);
 
 
 	/* We use DEBUGFUNCTION to count bytes sent/received, and verbose is needed
 	/* We use DEBUGFUNCTION to count bytes sent/received, and verbose is needed
 	 * to enable it */
 	 * to enable it */
@@ -1889,6 +1952,7 @@ void suspend_stratum(struct pool *pool)
 {
 {
 	clear_sockbuf(pool);
 	clear_sockbuf(pool);
 	applog(LOG_INFO, "Closing socket for stratum pool %d", pool->pool_no);
 	applog(LOG_INFO, "Closing socket for stratum pool %d", pool->pool_no);
+
 	mutex_lock(&pool->stratum_lock);
 	mutex_lock(&pool->stratum_lock);
 	pool->stratum_active = pool->stratum_notify = false;
 	pool->stratum_active = pool->stratum_notify = false;
 	if (pool->stratum_curl) {
 	if (pool->stratum_curl) {

+ 13 - 0
util.h

@@ -56,6 +56,7 @@
 #endif
 #endif
 extern char *json_dumps_ANY(json_t *, size_t flags);
 extern char *json_dumps_ANY(json_t *, size_t flags);
 
 
+struct thr_info;
 struct pool;
 struct pool;
 enum dev_reason;
 enum dev_reason;
 struct cgpu_info;
 struct cgpu_info;
@@ -71,6 +72,18 @@ extern void real_block_target(unsigned char *target, const unsigned char *data);
 extern bool hash_target_check(const unsigned char *hash, const unsigned char *target);
 extern bool hash_target_check(const unsigned char *hash, const unsigned char *target);
 extern bool hash_target_check_v(const unsigned char *hash, const unsigned char *target);
 extern bool hash_target_check_v(const unsigned char *hash, const unsigned char *target);
 
 
+int thr_info_create(struct thr_info *thr, pthread_attr_t *attr, void *(*start) (void *), void *arg);
+void thr_info_freeze(struct thr_info *thr);
+void thr_info_cancel(struct thr_info *thr);
+void nmsleep(unsigned int msecs);
+void cgtime(struct timeval *tv);
+void subtime(struct timeval *a, struct timeval *b);
+void addtime(struct timeval *a, struct timeval *b);
+bool time_more(struct timeval *a, struct timeval *b);
+bool time_less(struct timeval *a, struct timeval *b);
+void copy_time(struct timeval *dest, const struct timeval *src);
+double us_tdiff(struct timeval *end, struct timeval *start);
+double tdiff(struct timeval *end, struct timeval *start);
 bool stratum_send(struct pool *pool, char *s, ssize_t len);
 bool stratum_send(struct pool *pool, char *s, ssize_t len);
 bool sock_full(struct pool *pool);
 bool sock_full(struct pool *pool);
 char *recv_line(struct pool *pool);
 char *recv_line(struct pool *pool);

Some files were not shown because too many files changed in this diff