Browse Source

Merge branch 'bfgminer-2.6.x' into bfgminer

Conflicts:
	miner.c
Luke Dashjr 13 years ago
parent
commit
877be483c4
16 changed files with 393 additions and 95 deletions
  1. 14 1
      API-README
  2. 5 0
      FPGA-README
  3. 7 0
      Makefile.am
  4. 51 0
      NEWS
  5. 2 0
      README
  6. 40 18
      adl.c
  7. 56 10
      api.c
  8. 106 0
      bitforce-firmware-flash.c
  9. 6 2
      configure.ac
  10. 14 0
      debian/changelog
  11. 1 1
      debian/control
  12. 45 18
      driver-opencl.c
  13. 1 0
      driver-opencl.h
  14. 39 35
      miner.c
  15. 6 4
      miner.h
  16. 0 6
      util.c

+ 14 - 1
API-README

@@ -282,6 +282,12 @@ The list of requests - a (*) means it requires privileged access - and replies a
                none           There is no reply section just the STATUS section
                               stating what failover-only was set to
 
+ coin          COIN           Coin mining information:
+                              Hash Method=sha256/scrypt,
+                              Current Block Time=N.N, <- 0 means none
+                              Current Block Hash=XXXX..., <- blank if none
+                              LP=true/false| <- LP is in use on at least 1 pool
+
 When you enable, disable or restart a GPU or PGA, you will also get Thread messages
 in the BFGMiner status window
 
@@ -334,7 +340,14 @@ miner.php - an example web page to access the API
 Feature Changelog for external applications using the API:
 
 
-API V1.16
+API V1.17 (BFGMiner v2.6.5)
+
+Added API commands:
+ 'coin'
+
+----------
+
+API V1.16 (BFGMiner v2.6.5)
 
 Added API commands:
  'failover-only'

+ 5 - 0
FPGA-README

@@ -13,6 +13,11 @@ a cost of 1% in overall hashrate so this feature is disabled by default. It
 is only recommended you enable this if you are mining with a minirig on
 p2pool.
 
+BFGMiner also bundles a bitforce-firmware-flash utility on Linux. Using this,
+you can change the bitstream firmware on BitFORCE Singles. It is untested with
+other devices. Use at your own risk! Windows users may use Butterfly Labs
+EasyMiner to change firmware.
+
 
 Icarus
 

+ 7 - 0
Makefile.am

@@ -23,6 +23,7 @@ bin_SCRIPTS	= *.cl
 bfgminer_LDFLAGS	= $(PTHREAD_FLAGS)
 bfgminer_LDADD	= $(DLOPEN_FLAGS) @LIBCURL_LIBS@ @JANSSON_LIBS@ @PTHREAD_LIBS@ \
 		  @NCURSES_LIBS@ @PDCURSES_LIBS@ @WS2_LIBS@ \
+		  @TIMER_LIBS@ \
 		  @UDEV_LIBS@ @USB_LIBS@ \
 		  @MATH_LIBS@ lib/libgnu.a ccan/libccan.a
 bfgminer_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib
@@ -78,6 +79,12 @@ endif
 
 if HAS_BITFORCE
 bfgminer_SOURCES += driver-bitforce.c
+
+if HAVE_WINDOWS
+else
+bin_PROGRAMS += bitforce-firmware-flash
+bitforce_firmware_flash_SOURCES = bitforce-firmware-flash.c
+endif
 endif
 
 if HAS_ICARUS

+ 51 - 0
NEWS

@@ -1,3 +1,54 @@
+BFGMiner Version 2.6.5 - August 20, 2012
+
+- API new command 'coin' with mining information
+- Add message to share if it's a resubmit.
+- Add virtual adl mapping for when none is specified on the command line to
+not crash without a map specified.
+- Fix ADL gpu-map not working when there are more ADL devices than openCL.
+Patch supplied and tested by Nite69.
+- bitforce: Initial import of Linux-only bitforce-firmware-flash utility
+- Revert stale-on-arrival failsafe, since it ends up needing exceptions for
+everything
+- Bugfix: opencl: Declare opencl_dynamic_cleanup in header
+- Even if we want to submit stale shares, give up if we have more submissions
+waiting on threads (even before failing)
+- Even if we want to submit stale shares, give up if they've failed and we
+have more submissions waiting on threads
+- opencl: Use timeBeginPeriod on Windows to ensure gettimeofday has sufficient
+precision for dynamic intensity
+- Bugfix: opencl: Move ADL fanspeed warning messages to a new thread to get
+around summary-update deadlocking
+- README: Note that user groups don't get updated until re-login
+- Initialise cnt in libztex.c
+- Don't try to start devices that don't support scrypt when scrypt mining.
+- Repeating on timeout in ztex could make the code never return.
+- Offset libusb reads/writes by length written as well in ztex.
+- Cope with timeouts and partial reads in ztex code.
+- If there are more devices than nDevs, don't iterate over them as they may
+overwrite devices mapped below that with the mapping option.
+- Fix README faq on bfl auto-detect.
+- Set memory clock based on memdiff if present from with engine changes,
+allowing it to parallel manual changes from the menu as well.
+- api.c typo
+- API allow display/change failover-only setting
+- API-README corrections
+- miner.php documentation (in API-README) v0.1
+- Bugfix: opencl: Show blank device-info statline area if GPU doesn't have
+ADL, to fix column alignment
+- README: Document usage of 0 to indicate "leave at default" for comma-
+delimited GPU options
+- Correct API-README versions to match when BFGMiner included them
+- API-README update changelog
+- Minimise locking and unlocking when getting counts by reusing shared mutex
+lock functions.
+- Avoid getting more work if by the time the getwork thread is spawned we find
+ourselves with enough work.
+- The bitforce buffer is cleared and hw error count incremented on return from a
+failed send_work already so no need to do it within the send_work function.
+- Don't make mandatory work and its clones last forever.
+- modminer: Log debug info for nonces found
+
+
 BFGMiner Version 2.6.4 - August 11, 2012
 
 - Bugfix: Define my_cancellable_getch in miner.h

+ 2 - 0
README

@@ -226,6 +226,8 @@ To use FPGAs, you will need to be sure the user BFGMiner is running as has
 appropriate permissions. This varies by operating system.
 On Gentoo: sudo usermod <username> -a -G uucp
 On Ubuntu: sudo usermod <username> -a -G dialout
+Note that on GNU/Linux systems, you will usually need to login again before
+group changes take effect.
 
 By default, BFGMiner will scan for autodetected FPGAs unless at least one
 -S is specified for that driver. If you specify -S and still want BFGMiner

+ 40 - 18
adl.c

@@ -310,9 +310,10 @@ void init_adl(int nDevs)
 		if (gpus[i].mapped) {
 			vadapters[gpus[i].virtual_adl].virtual_gpu = i;
 			applog(LOG_INFO, "Mapping OpenCL device %d to ADL device %d", i, gpus[i].virtual_adl);
-		}
+		} else
+			gpus[i].virtual_adl = i;
 	}
-			
+
 	if (!devs_match) {
 		applog(LOG_ERR, "WARNING: Number of OpenCL and ADL devices did not match!");
 		applog(LOG_ERR, "Hardware monitoring may NOT match up with devices!");
@@ -351,11 +352,12 @@ void init_adl(int nDevs)
 		int iAdapterIndex;
 		int lpAdapterID;
 		ADLODPerformanceLevels *lpOdPerformanceLevels;
-		int lev;
+		int lev, adlGpu;
 
-		i = vadapters[gpu].id;
+		adlGpu = gpus[gpu].virtual_adl;
+		i = vadapters[adlGpu].id;
 		iAdapterIndex = lpInfo[i].iAdapterIndex;
-		gpus[gpu].virtual_gpu = vadapters[gpu].virtual_gpu;
+		gpus[gpu].virtual_gpu = vadapters[adlGpu].virtual_gpu;
 
 		/* Get unique identifier of the adapter, 0 means not AMD */
 		result = ADL_Adapter_ID_Get(iAdapterIndex, &lpAdapterID);
@@ -365,11 +367,11 @@ void init_adl(int nDevs)
 		}
 
 		if (gpus[gpu].deven == DEV_DISABLED) {
-			gpus[i].gpu_engine =
-			gpus[i].gpu_memclock =
-			gpus[i].gpu_vddc =
-			gpus[i].gpu_fan =
-			gpus[i].gpu_powertune = 0;
+			gpus[gpu].gpu_engine =
+			gpus[gpu].gpu_memclock =
+			gpus[gpu].gpu_vddc =
+			gpus[gpu].gpu_fan =
+			gpus[gpu].gpu_powertune = 0;
 			continue;
 		}
 
@@ -692,6 +694,29 @@ static int __gpu_fanpercent(struct gpu_adl *ga)
 	return ga->lpFanSpeedValue.iFanSpeed;
 }
 
+/* Failure log messages are handled by another (new) thread, since
+ * gpu_fanpercent is called inside a curses UI update (which holds
+ * the console lock, and would deadlock if we tried to log from
+ * within) */
+static void *gpu_fanpercent_failure(void *userdata)
+{
+	int *data = userdata;
+	bool had_twin = data[0];
+	int gpu = data[1];
+
+	applog(LOG_WARNING, "GPU %d stopped reporting fanspeed due to driver corruption", gpu);
+	if (opt_restart) {
+		applog(LOG_WARNING, "Restart enabled, will attempt to restart BFGMiner");
+		applog(LOG_WARNING, "You can disable this with the --no-restart option");
+		app_restart();
+	}
+	applog(LOG_WARNING, "Disabling fanspeed monitoring on this device");
+	if (had_twin) {
+		applog(LOG_WARNING, "Disabling fanspeed linking on GPU twins");
+	}
+	return NULL;
+}
+
 int gpu_fanpercent(int gpu)
 {
 	struct gpu_adl *ga;
@@ -705,19 +730,16 @@ int gpu_fanpercent(int gpu)
 	ret = __gpu_fanpercent(ga);
 	unlock_adl();
 	if (unlikely(ga->has_fanspeed && ret == -1)) {
-		applog(LOG_WARNING, "GPU %d stopped reporting fanspeed due to driver corruption", gpu);
-		if (opt_restart) {
-			applog(LOG_WARNING, "Restart enabled, will attempt to restart BFGMiner");
-			applog(LOG_WARNING, "You can disable this with the --no-restart option");
-			app_restart();
-		}
-		applog(LOG_WARNING, "Disabling fanspeed monitoring on this device");
+		pthread_t thr;
+		int *data = malloc(sizeof(int) * 2);
+		data[0] = ga->twin ? 1 : 0;
+		data[1] = gpu;
 		ga->has_fanspeed = false;
 		if (ga->twin) {
-			applog(LOG_WARNING, "Disabling fanspeed linking on GPU twins");
 			ga->twin->twin = NULL;;
 			ga->twin = NULL;
 		}
+		pthread_create(&thr, NULL, gpu_fanpercent_failure, data);
 	}
 	return ret;
 }

+ 56 - 10
api.c

@@ -188,6 +188,11 @@ static const char *NULLSTR = "(null)";
 static const char *TRUESTR = "true";
 static const char *FALSESTR = "false";
 
+#ifdef USE_SCRYPT
+static const char *SCRYPTSTR = "scrypt";
+#endif
+static const char *SHA256STR = "sha256";
+
 static const char *DEVICECODE = ""
 #ifdef HAVE_OPENCL
 			"GPU "
@@ -233,7 +238,7 @@ static const char *OSINFO =
 #define _SUMMARY	"SUMMARY"
 #define _STATUS		"STATUS"
 #define _VERSION	"VERSION"
-#define _MINECON	"CONFIG"
+#define _MINECONFIG	"CONFIG"
 #define _GPU		"GPU"
 
 #ifdef HAVE_AN_FPGA
@@ -253,6 +258,7 @@ static const char *OSINFO =
 #define _RESTART	"RESTART"
 #define _MINESTATS	"STATS"
 #define _CHECK		"CHECK"
+#define _MINECOIN	"COIN"
 
 static const char ISJSON = '{';
 #define JSON0		"{"
@@ -268,7 +274,7 @@ static const char ISJSON = '{';
 #define JSON_SUMMARY	JSON1 _SUMMARY JSON2
 #define JSON_STATUS	JSON1 _STATUS JSON2
 #define JSON_VERSION	JSON1 _VERSION JSON2
-#define JSON_MINECON	JSON1 _MINECON JSON2
+#define JSON_MINECONFIG	JSON1 _MINECONFIG JSON2
 #define JSON_GPU	JSON1 _GPU JSON2
 
 #ifdef HAVE_AN_FPGA
@@ -289,6 +295,7 @@ static const char ISJSON = '{';
 #define JSON_CLOSE	JSON3
 #define JSON_MINESTATS	JSON1 _MINESTATS JSON2
 #define JSON_CHECK	JSON1 _CHECK JSON2
+#define JSON_MINECOIN	JSON1 _MINECOIN JSON2
 #define JSON_END	JSON4 JSON5
 
 static const char *JSON_COMMAND = "command";
@@ -330,7 +337,7 @@ static const char *JSON_PARAMETER = "parameter";
 #define MSG_NOGPUADL 30
 #define MSG_INVINT 31
 #define MSG_GPUINT 32
-#define MSG_MINECON 33
+#define MSG_MINECONFIG 33
 #define MSG_GPUMERR 34
 #define MSG_GPUMEM 35
 #define MSG_GPUEERR 36
@@ -383,6 +390,7 @@ static const char *JSON_PARAMETER = "parameter";
 #define MSG_MISBOOL 75
 #define MSG_INVBOOL 76
 #define MSG_FOO 77
+#define MSG_MINECOIN 78
 
 enum code_severity {
 	SEVERITY_ERR,
@@ -497,7 +505,7 @@ struct CODES {
  { SEVERITY_ERR,   MSG_NOGPUADL,PARAM_GPU,	"GPU %d does not have ADL" },
  { SEVERITY_ERR,   MSG_INVINT,	PARAM_STR,	"Invalid intensity (%s) - must be '" _DYNAMIC  "' or range " _MIN_INTENSITY_STR " - " _MAX_INTENSITY_STR },
  { SEVERITY_INFO,  MSG_GPUINT,	PARAM_BOTH,	"GPU %d set new intensity to %s" },
- { SEVERITY_SUCC,  MSG_MINECON, PARAM_NONE,	"BFGMiner config" },
+ { SEVERITY_SUCC,  MSG_MINECONFIG,PARAM_NONE,	"BFGMiner config" },
 #ifdef HAVE_OPENCL
  { SEVERITY_ERR,   MSG_GPUMERR,	PARAM_BOTH,	"Setting GPU %d memoryclock to (%s) reported failure" },
  { SEVERITY_SUCC,  MSG_GPUMEM,	PARAM_BOTH,	"Setting GPU %d memoryclock to (%s) reported success" },
@@ -529,12 +537,13 @@ struct CODES {
  { SEVERITY_SUCC,  MSG_REMPOOL, PARAM_BOTH,	"Removed pool %d:'%s'" },
  { SEVERITY_SUCC,  MSG_NOTIFY,	PARAM_NONE,	"Notify" },
  { SEVERITY_SUCC,  MSG_DEVDETAILS,PARAM_NONE,	"Device Details" },
- { SEVERITY_SUCC,  MSG_MINESTATS,PARAM_NONE,	"CGMiner stats" },
+ { SEVERITY_SUCC,  MSG_MINESTATS,PARAM_NONE,	"BFGMiner stats" },
  { SEVERITY_ERR,   MSG_MISCHK,	PARAM_NONE,	"Missing check cmd" },
  { SEVERITY_SUCC,  MSG_CHECK,	PARAM_NONE,	"Check command" },
  { SEVERITY_ERR,   MSG_MISBOOL,	PARAM_NONE,	"Missing parameter: true/false" },
  { SEVERITY_ERR,   MSG_INVBOOL,	PARAM_NONE,	"Invalid parameter should be true or false" },
  { SEVERITY_SUCC,  MSG_FOO,	PARAM_BOOL,	"Failover-Only set to %s" },
+ { SEVERITY_SUCC,  MSG_MINECOIN,PARAM_NONE,	"BFGMiner coin" },
  { SEVERITY_FAIL, 0, 0, NULL }
 };
 
@@ -1253,9 +1262,9 @@ static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
 #endif
 
 	sprintf(io_buffer, isjson
-		? "%s," JSON_MINECON
-		: "%s" _MINECON ",",
-		message(MSG_MINECON, 0, NULL, isjson));
+		? "%s," JSON_MINECONFIG
+		: "%s" _MINECONFIG ",",
+		message(MSG_MINECONFIG, 0, NULL, isjson));
 
 	root = api_add_int(root, "GPU Count", &gpucount, false);
 	root = api_add_int(root, "PGA Count", &pgacount, false);
@@ -2664,6 +2673,42 @@ static void failoveronly(__maybe_unused SOCKETTYPE c, char *param, bool isjson,
 	strcpy(io_buffer, message(MSG_FOO, tf, NULL, isjson));
 }
 
+static void minecoin(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
+{
+	struct api_data *root = NULL;
+	char buf[TMPBUFSIZ];
+
+	sprintf(io_buffer, isjson
+		? "%s," JSON_MINECOIN
+		: "%s" _MINECOIN ",",
+		message(MSG_MINECOIN, 0, NULL, isjson));
+
+#ifdef USE_SCRYPT
+	if (opt_scrypt)
+		root = api_add_const(root, "Hash Method", SCRYPTSTR, false);
+	else
+#endif
+		root = api_add_const(root, "Hash Method", SHA256STR, false);
+
+        mutex_lock(&ch_lock);
+	if (current_fullhash && *current_fullhash) {
+		root = api_add_timeval(root, "Current Block Time", &block_timeval, true);
+		root = api_add_string(root, "Current Block Hash", current_fullhash, true);
+	} else {
+		struct timeval t = {0,0};
+		root = api_add_timeval(root, "Current Block Time", &t, true);
+		root = api_add_const(root, "Current Block Hash", BLANK, false);
+	}
+        mutex_unlock(&ch_lock);
+
+	root = api_add_bool(root, "LP", &have_longpoll, false);
+
+	root = print_data(root, buf, isjson);
+	if (isjson)
+		strcat(buf, JSON_CLOSE);
+	strcat(io_buffer, buf);
+}
+
 static void checkcommand(__maybe_unused SOCKETTYPE c, char *param, bool isjson, char group);
 
 struct CMDS {
@@ -2716,6 +2761,7 @@ struct CMDS {
 	{ "stats",		minerstats,	false },
 	{ "check",		checkcommand,	false },
 	{ "failover-only",	failoveronly,	true },
+	{ "coin",		minecoin,	false },
 	{ NULL,			NULL,		false }
 };
 
@@ -3070,7 +3116,7 @@ static void *quit_thread(__maybe_unused void *userdata)
 	mutex_unlock(&quit_restart_lock);
 
 	if (opt_debug)
-		applog(LOG_DEBUG, "API: killing cgminer");
+		applog(LOG_DEBUG, "API: killing BFGMiner");
 
 	kill_work();
 
@@ -3086,7 +3132,7 @@ static void *restart_thread(__maybe_unused void *userdata)
 	mutex_unlock(&quit_restart_lock);
 
 	if (opt_debug)
-		applog(LOG_DEBUG, "API: restarting cgminer");
+		applog(LOG_DEBUG, "API: restarting BFGMiner");
 
 	app_restart();
 

+ 106 - 0
bitforce-firmware-flash.c

@@ -0,0 +1,106 @@
+/*
+ * Copyright 2012 Luke Dashjr
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
+ */
+
+#define _BSD_SOURCE
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <libgen.h>
+#include <arpa/inet.h>
+
+#define BFL_FILE_MAGIC   "BFLDATA"
+#define BFL_UPLOAD_MAGIC "NGH-STREAM"
+
+#define myassert(expr, n, ...)  do {  \
+	if (!(expr))  \
+	{  \
+		fprintf(stderr, __VA_ARGS__);  \
+		return n;  \
+	}  \
+} while(0)
+
+#define ERRRESP(buf)  buf, (buf[strlen(buf)-1] == '\n' ? "" : "\n")
+
+#define WAITFOROK(n, msg)  do {  \
+	myassert(fgets(buf, sizeof(buf), BFL), n, "Error reading response from " msg "\n");  \
+	myassert(!strcmp(buf, "OK\n"), n, "Invalid response from " msg ": %s%s", ERRRESP(buf));  \
+} while(0)
+
+int
+main(int argc, char**argv) {
+	myassert(argc == 3, 1, "Usage: %s <serialdev> <firmware.bfl>\n", argv[0]);
+	setbuf(stdout, NULL);
+	
+	// Check filename
+	char *FWname = basename(strdup(argv[2]));
+	size_t FWnameLen = strlen(FWname);
+	myassert(FWnameLen <= 255, 0x0f, "Firmware filename '%s' is too long\n", FWname);
+	uint8_t n8 = FWnameLen;
+	
+	// Open and check firmware file
+	FILE *FW = fopen(argv[2], "r");
+	myassert(FW, 0x10, "Failed to open '%s' for reading\n", argv[2]);
+	char buf[0x20];
+	myassert(1 == fread(buf, 7, 1, FW), 0x10, "Failed to read from '%s'\n", argv[2]);
+	myassert(!memcmp(buf, BFL_FILE_MAGIC, sizeof(BFL_FILE_MAGIC)-1), 0x11, "'%s' doesn't look like a BFL firmware\n", argv[2]);
+	myassert(!fseek(FW, 0, SEEK_END), 0x12, "Failed to find end of '%s'\n", argv[2]);
+	long FWlen = ftell(FW);
+	myassert(FWlen > 0, 0x12, "Couldn't get size of '%s'\n", argv[2]);
+	myassert(!fseek(FW, 7, SEEK_SET), 0x12, "Failed to rewind firmware file after getting size\n");
+	FWlen -= 7;
+	printf("Firmware file looks OK :)\n");
+	
+	// Open device
+	FILE *BFL = fopen(argv[1], "r+");
+	myassert(BFL, 0x20, "Failed to open '%s' for read/write\n", argv[1]);
+	myassert(!setvbuf(BFL, NULL, _IOFBF, 1032), 0x21, "Failed to setup buffer for device");
+	
+	// ZAX: Start firmware upload
+	printf("Starting firmware upload... ");
+	myassert(1 == fwrite("ZAX", 3, 1, BFL), 0x22, "Failed to issue ZAX command\n");
+	WAITFOROK(0x22, "ZAX");
+	
+	// Firmware upload header
+	myassert(1 == fwrite(BFL_UPLOAD_MAGIC, sizeof(BFL_UPLOAD_MAGIC)-1, 1, BFL), 0x23, "Failed to send firmware upload header (magic)\n");
+	uint32_t n32 = htonl(FWlen - FWlen / 6);
+	myassert(1 == fwrite(&n32, sizeof(n32), 1, BFL), 0x23, "Failed to send firmware upload header (size)\n");
+	myassert(1 == fwrite("\0\0", 2        , 1, BFL), 0x23, "Failed to send firmware upload header (padding 1)\n");
+	myassert(1 == fwrite(&n8, sizeof(n8)  , 1, BFL), 0x23, "Failed to send firmware upload header (filename length)\n");
+	myassert(1 == fwrite(FWname, n8       , 1, BFL), 0x23, "Failed to send firmware upload header (filename)\n");
+	myassert(1 == fwrite("\0>>>>>>>>", 9  , 1, BFL), 0x23, "Failed to send firmware upload header (padding 2)\n");
+	WAITFOROK(0x23, "firmware upload header");
+	printf("OK, sending...\n");
+	
+	// Actual firmware upload
+	for (long i = 0, j = 0; i < FWlen; ++i)
+	{
+		myassert(1 == fread(&n8, sizeof(n8), 1, FW), 0x30, "Error reading data from firmware file\n");
+		if (5 == i % 6)
+			continue;
+		n8 ^= 0x2f;
+		myassert(1 == fwrite(&n8, sizeof(n8), 1, BFL), 0x31, "Error sending data to device\n");
+		if (!(++j % 0x400))
+		{
+			myassert(1 == fwrite(">>>>>>>>", 8, 1, BFL), 0x32, "Error sending block-finish to device\n");
+			printf("\r%5.2f%% complete", (double)i * 100. / (double)FWlen);
+			WAITFOROK(0x32, "block-finish");
+		}
+	}
+	printf("\r100%% complete :)\n");
+	myassert(1 == fwrite(">>>>>>>>", 8, 1, BFL), 0x3f, "Error sending upload-finished to device\n");
+	myassert(fgets(buf, sizeof(buf), BFL), 0x3f, "Error reading response from upload-finished\n");  \
+	myassert(!strcmp(buf, "DONE\n"), 0x3f, "Invalid response from upload-finished: %s%s", ERRRESP(buf));  \
+	
+	// ZBX: Finish programming
+	printf("Waiting for device... ");
+	myassert(1 == fwrite("ZBX", 3, 1, BFL), 0x40, "Failed to issue ZBX command\n");
+	WAITFOROK(0x40, "ZBX");
+	printf("ALL DONE!\n");
+}

+ 6 - 2
configure.ac

@@ -2,7 +2,7 @@
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 m4_define([v_maj], [2])
 m4_define([v_min], [6])
-m4_define([v_mic], [4])
+m4_define([v_mic], [5])
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 m4_define([v_ver], [v_maj.v_min.v_mic])
 m4_define([lt_rev], m4_eval(v_maj + v_min))
@@ -68,6 +68,7 @@ USB_LIBS=""
 USB_FLAGS=""
 DLOPEN_FLAGS="-ldl"
 WS2_LIBS=""
+TIMER_LIBS=""
 MATH_LIBS="-lm"
 
 case $target in
@@ -86,6 +87,7 @@ case $target in
 	PTHREAD_FLAGS=""
 	DLOPEN_FLAGS=""
 	WS2_LIBS="-lws2_32"
+	TIMER_LIBS="-lwinmm"
 	;;
   *-*-mingw*)
     have_x86_64=false
@@ -93,6 +95,7 @@ case $target in
     PTHREAD_FLAGS=""
     DLOPEN_FLAGS=""
     WS2_LIBS="-lws2_32"
+	TIMER_LIBS="-lwinmm"
     ;;
   powerpc-*-darwin*)
     CFLAGS="$CFLAGS -faltivec"
@@ -373,6 +376,7 @@ AC_SUBST(PTHREAD_LIBS)
 AC_SUBST(NCURSES_LIBS)
 AC_SUBST(PDCURSES_LIBS)
 AC_SUBST(WS2_LIBS)
+AC_SUBST(TIMER_LIBS)
 AC_SUBST(MATH_LIBS)
 AC_SUBST(UDEV_LIBS)
 AC_SUBST(USB_LIBS)
@@ -467,7 +471,7 @@ echo "Compilation............: make (or gmake)"
 echo "  CPPFLAGS.............: $CPPFLAGS"
 echo "  CFLAGS...............: $CFLAGS"
 echo "  LDFLAGS..............: $LDFLAGS $PTHREAD_FLAGS $USB_FLAGS"
-echo "  LDADD................: $DLOPEN_FLAGS $LIBCURL_LIBS $JANSSON_LIBS $PTHREAD_LIBS $NCURSES_LIBS $PDCURSES_LIBS $WS2_LIBS $MATH_LIBS $UDEV_LIBS $USB_LIBS"
+echo "  LDADD................: $DLOPEN_FLAGS $LIBCURL_LIBS $JANSSON_LIBS $PTHREAD_LIBS $NCURSES_LIBS $PDCURSES_LIBS $WS2_LIBS $TIMER_LIBS $MATH_LIBS $UDEV_LIBS $USB_LIBS"
 echo
 echo "Installation...........: make install (as root if needed, with 'su' or 'sudo')"
 echo "  prefix...............: $prefix"

+ 14 - 0
debian/changelog

@@ -1,3 +1,17 @@
+bfgminer (2.6.5-0precise1) precise; urgency=low
+
+  * New BitFORCE firmware flash utility. When compiled with BitFORCE support, run `bitforce-firmware-flash` to get usage.
+  * Fixed hanging when using "Switch User" on Windows. This feature still kills ADL, though, so use --no-restart (and don't enable fan control or overclocking) if you plan to use it.
+  * Fixed dynamic mode on Windows. By default, Windows timer resolution is only 15ms and we're trying to sample much smaller than that. This was leading to the time taken to do GPU work appearing as zero for many samples. Now, a Windows multimedia timing API will be used to request more precision.
+  * gpu-memdiff should now take effect when you change gpu engine clock from the menu as well.
+  * The ADL gpu-map feature should work now when you have more ADL devices than OpenCL (eg, ATI cards that don't support OpenCL).
+  * More tweaks to the queueing mechanism to increase efficiency and keep minirigs fully work laden.
+  * Failover-only can now be changed via the RPC API.
+  * Updated miner.php from Kano
+
+ -- Luke Dashjr <luke+bfgminer@dashjr.org>  Mon, 20 Aug 2012 23:59:19 -0000
+
+
 bfgminer (2.6.4-0precise1) precise; urgency=low
 
   * More drastic improvements to ModMiner clock adjustment algorithm. Downclocking should be more conservative, and BFGMiner will even raise the clock speed when it's doing well.

+ 1 - 1
debian/control

@@ -2,7 +2,7 @@ Source: bfgminer
 Priority: optional
 Section: misc
 Maintainer: Luke Dashjr <luke_bfgminer@dashjr.org>
-Standards-Version: 2.6.4
+Standards-Version: 2.6.5
 Build-Depends: build-essential, debhelper, autoconf, automake, libtool, libssl-dev, yasm, pkg-config, libudev-dev, libcurl4-openssl-dev, wget, unzip, libncurses5-dev, libudev-dev, libusb-1.0-0-dev
 
 Package: bfgminer

+ 45 - 18
driver-opencl.c

@@ -832,6 +832,21 @@ struct cgpu_info *cpus;
 
 #ifdef HAVE_OPENCL
 
+#ifdef WIN32
+static UINT timeperiod_set;
+#endif
+
+void opencl_dynamic_cleanup() {
+#ifdef WIN32
+	if (timeperiod_set) {
+		timeEndPeriod(timeperiod_set);
+		timeperiod_set = 0;
+	}
+#endif
+}
+
+extern int opt_dynamic_interval;
+
 /* In dynamic mode, only the first thread of each device will be in use.
  * This potentially could start a thread that was stopped with the start-stop
  * options if one were to disable dynamic from the menu on a paused GPU */
@@ -839,10 +854,18 @@ void pause_dynamic_threads(int gpu)
 {
 	struct cgpu_info *cgpu = &gpus[gpu];
 	int i;
+#ifdef WIN32
+	bool any_dynamic = false;
+#endif
 
 	for (i = 1; i < cgpu->threads; i++) {
 		struct thr_info *thr = &thr_info[i];
 
+#ifdef WIN32
+		if (cgpu->dynamic)
+			any_dynamic = true;
+#endif
+
 		if (!thr->pause && cgpu->dynamic) {
 			applog(LOG_WARNING, "Disabling extra threads due to dynamic mode.");
 			applog(LOG_WARNING, "Tune dynamic intensity with --gpu-dyninterval");
@@ -852,6 +875,20 @@ void pause_dynamic_threads(int gpu)
 		if (!cgpu->dynamic && cgpu->deven != DEV_DISABLED)
 			tq_push(thr->q, &ping);
 	}
+
+#ifdef WIN32
+	if (any_dynamic) {
+		if (!timeperiod_set) {
+			timeperiod_set = opt_dynamic_interval > 3 ? (opt_dynamic_interval / 2) : 1;
+			if (TIMERR_NOERROR != timeBeginPeriod(timeperiod_set))
+				timeperiod_set = 0;
+		}
+	} else {
+		if (timeperiod_set) {
+			opencl_dynamic_cleanup();
+		}
+	}
+#endif
 }
 
 
@@ -1741,7 +1778,6 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
 	_clState *clState = clStates[thr_id];
 	const cl_kernel *kernel = &clState->kernel;
 	const int dynamic_us = opt_dynamic_interval * 1000;
-	struct timeval tv_gpuend;
 	cl_bool blocking;
 
 	cl_int status;
@@ -1760,17 +1796,13 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
 		clFinish(clState->commandQueue);
 
 	if (gpu->dynamic) {
-		double gpu_us;
-
-		/* Windows returns the same time for gettimeofday due to its
-		 * 15ms timer resolution, so we must average the result over
-		 * at least 5 values that are actually different to get an
-		 * accurate result */
-		gpu->intervals++;
-		gettimeofday(&tv_gpuend, NULL);
-		gpu_us = us_tdiff(&tv_gpuend, &gpu->tv_gpumid);
-		if (gpu_us > 0 && ++gpu->hit > 4) {
-			gpu_us = us_tdiff(&tv_gpuend, &gpu->tv_gpustart) / gpu->intervals;
+		struct timeval diff;
+		suseconds_t gpu_us;
+
+		gettimeofday(&gpu->tv_gpuend, NULL);
+		timersub(&gpu->tv_gpuend, &gpu->tv_gpustart, &diff);
+		gpu_us = diff.tv_sec * 1000000 + diff.tv_usec;
+		if (likely(gpu_us >= 0)) {
 			gpu->gpu_us_average = (gpu->gpu_us_average + gpu_us * 0.63) / 1.63;
 
 			/* Try to not let the GPU be out for longer than 
@@ -1783,7 +1815,6 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
 				if (gpu->intensity < MAX_INTENSITY)
 					++gpu->intensity;
 			}
-			gpu->intervals = gpu->hit = 0;
 		}
 	}
 	set_threads_hashes(clState->vwidth, &threads, &hashes, globalThreads,
@@ -1819,11 +1850,7 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
 			clFinish(clState->commandQueue);
 	}
 
-	gettimeofday(&gpu->tv_gpumid, NULL);
-	if (!gpu->intervals) {
-		gpu->tv_gpustart.tv_sec = gpu->tv_gpumid.tv_sec;
-		gpu->tv_gpustart.tv_usec = gpu->tv_gpumid.tv_usec;
-	}
+	gettimeofday(&gpu->tv_gpustart, NULL);
 
 	if (clState->goffset) {
 		size_t global_work_offset[1];

+ 1 - 0
driver-opencl.h

@@ -25,6 +25,7 @@ extern char *set_thread_concurrency(char *arg);
 #endif
 extern char *set_kernel(char *arg);
 void manage_gpu(void);
+extern void opencl_dynamic_cleanup();
 extern void pause_dynamic_threads(int gpu);
 
 extern bool have_opencl;

+ 39 - 35
miner.c

@@ -88,7 +88,7 @@ static char packagename[255];
 bool opt_protocol;
 static bool opt_benchmark;
 static bool want_longpoll = true;
-static bool have_longpoll;
+bool have_longpoll;
 static bool want_per_device_stats;
 bool use_syslog;
 bool opt_quiet;
@@ -177,7 +177,7 @@ static pthread_mutex_t hash_lock;
 static pthread_mutex_t qd_lock;
 static pthread_mutex_t *stgd_lock;
 pthread_mutex_t console_lock;
-static pthread_mutex_t ch_lock;
+pthread_mutex_t ch_lock;
 static pthread_rwlock_t blk_lock;
 
 pthread_rwlock_t netacc_lock;
@@ -226,8 +226,10 @@ bool curses_active;
 static char current_block[37];
 static char *current_hash;
 static uint32_t current_block_id;
+char *current_fullhash;
 static char datestamp[40];
 static char blocktime[30];
+struct timeval block_timeval;
 
 struct block {
 	char hash[37];
@@ -1921,7 +1923,7 @@ static void reject_pool(struct pool *pool)
 	pool->enabled = POOL_REJECTING;
 }
 
-static bool submit_upstream_work(const struct work *work, CURL *curl)
+static bool submit_upstream_work(const struct work *work, CURL *curl, bool resubmit)
 {
 	char *hexstr = NULL;
 	json_t *val, *res;
@@ -1992,11 +1994,11 @@ static bool submit_upstream_work(const struct work *work, CURL *curl)
 		applog(LOG_DEBUG, "PROOF OF WORK RESULT: true (yay!!!)");
 		if (!QUIET) {
 			if (total_pools > 1)
-				applog(LOG_NOTICE, "Accepted %s %s %d pool %d",
-				       hashshow, cgpu->api->name, cgpu->device_id, work->pool->pool_no);
+				applog(LOG_NOTICE, "Accepted %s %s %d pool %d %s",
+				       hashshow, cgpu->api->name, cgpu->device_id, work->pool->pool_no, resubmit ? "(resubmit)" : "");
 			else
-				applog(LOG_NOTICE, "Accepted %s %s %d",
-				       hashshow, cgpu->api->name, cgpu->device_id);
+				applog(LOG_NOTICE, "Accepted %s %s %d %s",
+				       hashshow, cgpu->api->name, cgpu->device_id, resubmit ? "(resubmit)" : "");
 		}
 		sharelog("accept", work);
 		if (opt_shares && total_accepted >= opt_shares) {
@@ -2045,8 +2047,8 @@ static bool submit_upstream_work(const struct work *work, CURL *curl)
 			} else
 				strcpy(reason, "");
 
-			applog(LOG_NOTICE, "Rejected %s %s %d %s%s",
-			       hashshow, cgpu->api->name, cgpu->device_id, where, reason);
+			applog(LOG_NOTICE, "Rejected %s %s %d %s%s %s",
+			       hashshow, cgpu->api->name, cgpu->device_id, where, reason, resubmit ? "(resubmit)" : "");
 			sharelog(disposition, work);
 		}
 
@@ -2463,8 +2465,7 @@ static int global_queued(void)
 	return ret;
 }
 
-static bool stale_work3(struct work *work, bool share, bool failoveronly);
-#define stale_work(work, share)  stale_work3(work, share, opt_fail_only)
+static bool stale_work(struct work *work, bool share);
 
 static inline bool should_roll(struct work *work)
 {
@@ -2658,7 +2659,7 @@ static bool workio_get_work(struct workio_cmd *wc)
 	return true;
 }
 
-static bool stale_work3(struct work *work, bool share, bool failoveronly)
+static bool stale_work(struct work *work, bool share)
 {
 	struct timeval now;
 	time_t work_expiry;
@@ -2695,7 +2696,6 @@ static bool stale_work3(struct work *work, bool share, bool failoveronly)
 	} else {
 		/* If this work isn't for the latest Bitcoin block, it's stale */
 		/* But only care about the current pool if failover-only */
-		/* Note this intentionally uses the global option, not the param */
 		if (block_id != (opt_fail_only ? pool->block_id : current_block_id))
 		{
 			applog(LOG_DEBUG, "Work stale due to block mismatch (%08lx != %d ? %08lx : %08lx)", (long)block_id, (int)opt_fail_only, (long)pool->block_id, (long)current_block_id);
@@ -2726,7 +2726,7 @@ static bool stale_work3(struct work *work, bool share, bool failoveronly)
 
 	/* If the user only wants strict failover, any work from a pool other than
 	 * the current one is always considered stale */
-	if (failoveronly && !share && pool != current_pool() && !work->mandatory &&
+	if (opt_fail_only && !share && pool != current_pool() && !work->mandatory &&
 	    pool_strategy != POOL_LOADBALANCE && pool_strategy != POOL_BALANCE) {
 		applog(LOG_DEBUG, "Work stale due to fail only pool mismatch (pool %u vs %u)", pool->pool_no, current_pool()->pool_no);
 		return true;
@@ -2758,6 +2758,7 @@ static void *submit_work_thread(void *userdata)
 	struct workio_cmd *wc = (struct workio_cmd *)userdata;
 	struct work *work;
 	struct pool *pool;
+	bool resubmit;
 	struct curl_ent *ce;
 	int failures;
 	time_t staleexpire;
@@ -2770,12 +2771,18 @@ static void *submit_work_thread(void *userdata)
 next_submit:
 	work = wc->work;
 	pool = work->pool;
+	resubmit = false;
 	failures = 0;
 
 	check_solve(work);
 
 	if (stale_work(work, true)) {
 		work->stale = true;
+		if (unlikely(!list_empty(&submit_waiting))) {
+			applog(LOG_WARNING, "Stale share detected while queued submissions are waiting, discarding");
+			submit_discard_share(work);
+			goto out;
+		}
 		if (opt_submit_stale)
 			applog(LOG_NOTICE, "Stale share detected, submitting as user requested");
 		else if (pool->submit_old)
@@ -2790,7 +2797,8 @@ next_submit:
 
 	ce = pop_curl_entry(pool);
 	/* submit solution to bitcoin via JSON-RPC */
-	while (!submit_upstream_work(work, ce->curl)) {
+	while (!submit_upstream_work(work, ce->curl, resubmit)) {
+		resubmit = true;
 		if ((!work->stale) && stale_work(work, true)) {
 			work->stale = true;
 			if (opt_submit_stale)
@@ -2809,8 +2817,12 @@ next_submit:
 			submit_discard_share(work);
 			break;
 		}
-		else if (unlikely(work->stale && opt_retries < 0)) {
-			if (staleexpire <= time(NULL)) {
+		else if (work->stale) {
+			if (unlikely(!list_empty(&submit_waiting))) {
+				applog(LOG_WARNING, "Stale share failed to submit while queued submissions are waiting, discarding");
+				submit_discard_share(work);
+				break;
+			} else if (unlikely(opt_retries < 0 && staleexpire <= time(NULL))) {
 				applog(LOG_NOTICE, "Stale share failed to submit for 5 minutes, discarding");
 				submit_discard_share(work);
 				break;
@@ -3094,23 +3106,28 @@ static void restart_threads(void)
 static void set_curblock(char *hexstr, unsigned char *hash)
 {
 	unsigned char hash_swap[32];
-	struct timeval tv_now;
+	unsigned char block_hash_swap[32];
 	char *old_hash;
 
 	current_block_id = ((uint32_t*)hash)[1];
 	strcpy(current_block, hexstr);
-	gettimeofday(&tv_now, NULL);
-	get_timestamp(blocktime, &tv_now);
 	swap256(hash_swap, hash);
+	swap256(block_hash_swap, hash+4);
 
 	/* Don't free current_hash directly to avoid dereferencing when read
-	 * elsewhere */
+	 * elsewhere - and update block_timeval inside the same lock */
 	mutex_lock(&ch_lock);
+	gettimeofday(&block_timeval, NULL);
 	old_hash = current_hash;
 	current_hash = bin2hex(hash_swap, 16);
 	free(old_hash);
+	old_hash = current_fullhash;
+	current_fullhash = bin2hex(block_hash_swap, 32);
+	free(old_hash);
 	mutex_unlock(&ch_lock);
 
+	get_timestamp(blocktime, &block_timeval);
+
 	if (unlikely(!current_hash))
 		quit (1, "set_curblock OOM");
 	applog(LOG_INFO, "New block: %s...", current_hash);
@@ -3284,20 +3301,6 @@ static void *stage_thread(void *userdata)
 
 		test_work_current(work);
 
-		if (stale_work3(work, false, false)) {
-			struct timeval now;
-			gettimeofday(&now, NULL);
-			if (work->tv_staged.tv_sec >= now.tv_sec - 2) {
-				// Only for freshly fetched work, disable the pool giving it to us stale
-				struct pool *pool = work->pool;
-				applog(LOG_WARNING, "Pool %u gave us stale-on-arrival work, disabling!", pool->pool_no);
-				reject_pool(pool);
-				if (pool == current_pool())
-					switch_pools(NULL);
-			}
-			continue;
-		}
-
 		applog(LOG_DEBUG, "Pushing work to getwork queue");
 
 		if (unlikely(!hash_push(work))) {
@@ -5409,6 +5412,7 @@ static void clean_up(void)
 {
 #ifdef HAVE_OPENCL
 	clear_adl(nDevs);
+	opencl_dynamic_cleanup();
 #endif
 #ifdef HAVE_LIBUSB
         libusb_exit(NULL);

+ 6 - 4
miner.h

@@ -406,10 +406,9 @@ struct cgpu_info {
 	int opt_tc, thread_concurrency;
 	int shaders;
 #endif
-	struct timeval tv_gpustart;
-	struct timeval tv_gpumid;
+	struct timeval tv_gpustart;;
+	struct timeval tv_gpuend;
 	double gpu_us_average;
-	int intervals, hit;
 #endif
 
 	float temp;
@@ -483,7 +482,6 @@ extern int thr_info_create(struct thr_info *thr, pthread_attr_t *attr, void *(*s
 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 void rename_thr(const char* name);
 
 struct string_elist {
@@ -607,6 +605,7 @@ static inline void rwlock_init(pthread_rwlock_t *lock)
 struct pool;
 
 extern bool opt_protocol;
+extern bool have_longpoll;
 extern char *opt_kernel_path;
 extern char *opt_socks_proxy;
 extern char *cgminer_path;
@@ -650,6 +649,7 @@ extern bool fulltest(const unsigned char *hash, const unsigned char *target);
 extern int opt_scantime;
 
 extern pthread_mutex_t console_lock;
+extern pthread_mutex_t ch_lock;
 
 extern pthread_mutex_t restart_lock;
 extern pthread_cond_t restart_cond;
@@ -726,6 +726,8 @@ extern const int opt_cutofftemp;
 extern int opt_fail_pause;
 extern int opt_log_interval;
 extern unsigned long long global_hashrate;
+extern char *current_fullhash;
+extern struct timeval block_timeval;
 
 #ifdef HAVE_OPENCL
 typedef struct {

+ 0 - 6
util.c

@@ -719,12 +719,6 @@ void nmsleep(unsigned int msecs)
 	} while (ret == -1 && errno == EINTR);
 }
 
-/* Returns the microseconds difference between end and start times as a double */
-double us_tdiff(struct timeval *end, struct timeval *start)
-{
-	return end->tv_sec * 1000000 + end->tv_usec - start->tv_sec * 1000000 - start->tv_usec;
-}
-
 void rename_thr(const char* name) {
 #if defined(PR_SET_NAME)
 	// Only the first 15 characters are used (16 - NUL terminator)