Browse Source

Merge branch 'bfgminer' into kncasic

Conflicts:
	.travis.yml
	configure.ac
Luke Dashjr 11 years ago
parent
commit
2cb8e65ab1
45 changed files with 2075 additions and 745 deletions
  1. 2 2
      .travis.deps
  2. 1 0
      .travis.script
  3. 3 1
      .travis.yml
  4. 1 0
      AUTHORS
  5. 39 0
      NEWS
  6. 32 14
      README
  7. 16 1
      README.ASIC
  8. 12 2
      README.RPC
  9. 64 34
      api.c
  10. 1 2
      configure.ac
  11. 7 0
      debian/changelog
  12. 1 1
      debian/control
  13. 22 0
      deviceapi.c
  14. 3 0
      deviceapi.h
  15. 7 1
      driver-cointerra.c
  16. 15 19
      driver-cpu.c
  17. 62 34
      driver-dualminer.c
  18. 5 2
      driver-getwork.c
  19. 1 16
      driver-gridseed.c
  20. 7 0
      driver-icarus.h
  21. 219 50
      driver-minergate.c
  22. 229 114
      driver-opencl.c
  23. 9 5
      driver-opencl.h
  24. 13 4
      driver-proxy.c
  25. 136 24
      driver-stratum.c
  26. 99 84
      driver-titan.c
  27. 1 2
      driver-zeusminer.c
  28. 12 3
      findnonce.c
  29. 6 0
      findnonce.h
  30. 3 3
      gc3355.c
  31. 1 1
      gc3355.h
  32. 1 1
      knc-asic
  33. 3 3
      libbitfury.c
  34. 566 113
      miner.c
  35. 98 35
      miner.h
  36. 148 152
      ocl.c
  37. 29 8
      ocl.h
  38. 1 1
      openwrt/bfgminer/Makefile
  39. 3 3
      scrypt.c
  40. 1 1
      scrypt.h
  41. 65 4
      titan-asic.c
  42. 14 0
      titan-asic.h
  43. 109 3
      util.c
  44. 3 1
      util.h
  45. 5 1
      winhacks.h

+ 2 - 2
.travis.deps

@@ -29,7 +29,7 @@ fi
 if [ -n "$CROSS_BINPKGS" ]; then
 if [ -n "$CROSS_BINPKGS" ]; then
 	wget "https://github.com/luke-jr/cross-binpkgs/archive/${CROSS_BINPKGS}.zip"
 	wget "https://github.com/luke-jr/cross-binpkgs/archive/${CROSS_BINPKGS}.zip"
 	unzip "${CROSS_BINPKGS}.zip"
 	unzip "${CROSS_BINPKGS}.zip"
-	for f in "cross-binpkgs-${CROSS_BINPKGS}"/*/*; do
-		sudo tar -C "/usr/${CROSS_BINPKGS}/" -xjvpf "$f"
+	for f in "cross-binpkgs-${CROSS_BINPKGS/+/-}"/*/*; do
+		sudo tar -C "/usr/${CROSS_BINPKGS/+*/}/" -xjvpf "$f"
 	done
 	done
 fi
 fi

+ 1 - 0
.travis.script

@@ -2,6 +2,7 @@ test "x$1" = "xI-am-okay-with-destroying-my-system" || exit 1
 set -ex
 set -ex
 
 
 if [ -n "$CROSS_BINPKGS" ]; then
 if [ -n "$CROSS_BINPKGS" ]; then
+	CROSS_BINPKGS="${CROSS_BINPKGS/+*/}"
 	myCC="${CROSS_BINPKGS}-gcc"
 	myCC="${CROSS_BINPKGS}-gcc"
 	CC_ARGS="-I/usr/${CROSS_BINPKGS}/usr/include"
 	CC_ARGS="-I/usr/${CROSS_BINPKGS}/usr/include"
 	export LDFLAGS="-L/usr/${CROSS_BINPKGS}/usr/lib -L/usr/${CROSS_BINPKGS}/usr/bin"
 	export LDFLAGS="-L/usr/${CROSS_BINPKGS}/usr/lib -L/usr/${CROSS_BINPKGS}/usr/bin"

+ 3 - 1
.travis.yml

@@ -15,7 +15,9 @@ matrix:
       env: myCC='clang' UBUNTU_DEPS='libhidapi-dev linux-libc-dev' EXTRA_DEPS='pkg-config libncursesw5-dev libudev-dev libusb-1.0-0-dev libevent-dev libmicrohttpd-dev libi2c-dev yasm libsensors4-dev' BUILD_CFLAGS='-Werror' CONFIGURE_ARGS='--enable-other-drivers --enable-scrypt --without-system-libbase58 --enable-tool'
       env: myCC='clang' UBUNTU_DEPS='libhidapi-dev linux-libc-dev' EXTRA_DEPS='pkg-config libncursesw5-dev libudev-dev libusb-1.0-0-dev libevent-dev libmicrohttpd-dev libi2c-dev yasm libsensors4-dev' BUILD_CFLAGS='-Werror' CONFIGURE_ARGS='--enable-other-drivers --enable-scrypt --without-system-libbase58 --enable-tool'
     - compiler: ": pkgconf"
     - compiler: ": pkgconf"
       env: myCC='clang' UBUNTU_DEPS='libhidapi-dev linux-libc-dev pkgconf' EXTRA_DEPS='libncursesw5-dev libudev-dev libusb-1.0-0-dev libevent-dev libmicrohttpd-dev libi2c-dev yasm libsensors4-dev' BUILD_CFLAGS='-Werror' CONFIGURE_ARGS='--enable-other-drivers --enable-scrypt --without-system-libbase58 --enable-tool'
       env: myCC='clang' UBUNTU_DEPS='libhidapi-dev linux-libc-dev pkgconf' EXTRA_DEPS='libncursesw5-dev libudev-dev libusb-1.0-0-dev libevent-dev libmicrohttpd-dev libi2c-dev yasm libsensors4-dev' BUILD_CFLAGS='-Werror' CONFIGURE_ARGS='--enable-other-drivers --enable-scrypt --without-system-libbase58 --enable-tool'
-    - compiler: ": MinGW64"
+    - compiler: ": MinGW64 ncurses"
+      env: UBUNTU_DEPS='gcc-mingw-w64-x86-64' EXTRA_DEPS='pkg-config yasm' CROSS_BINPKGS='x86_64-w64-mingw32+ncurses' BUILD_CFLAGS='-Werror' CONFIGURE_ARGS='--enable-other-drivers --enable-scrypt --without-system-libbase58 --host=x86_64-w64-mingw32 --disable-knc --disable-bfsb --disable-jingtian --disable-metabank --disable-minergate --disable-titan --disable-kncasic'
+    - compiler: ": MinGW64 pdcurses"
       env: UBUNTU_DEPS='gcc-mingw-w64-x86-64' EXTRA_DEPS='pkg-config yasm' CROSS_BINPKGS='x86_64-w64-mingw32' BUILD_CFLAGS='-Werror' CONFIGURE_ARGS='--enable-other-drivers --enable-scrypt --without-system-libbase58 --host=x86_64-w64-mingw32 --disable-knc --disable-bfsb --disable-jingtian --disable-metabank --disable-minergate --disable-titan --disable-kncasic'
       env: UBUNTU_DEPS='gcc-mingw-w64-x86-64' EXTRA_DEPS='pkg-config yasm' CROSS_BINPKGS='x86_64-w64-mingw32' BUILD_CFLAGS='-Werror' CONFIGURE_ARGS='--enable-other-drivers --enable-scrypt --without-system-libbase58 --host=x86_64-w64-mingw32 --disable-knc --disable-bfsb --disable-jingtian --disable-metabank --disable-minergate --disable-titan --disable-kncasic'
     - compiler: ": Std SHA2"
     - compiler: ": Std SHA2"
       env: myCC='clang' UBUNTU_DEPS='libhidapi-dev linux-libc-dev' EXTRA_DEPS='pkg-config libncursesw5-dev libudev-dev libusb-1.0-0-dev libevent-dev libmicrohttpd-dev libi2c-dev yasm libsensors4-dev' CONFIGURE_ARGS=''
       env: myCC='clang' UBUNTU_DEPS='libhidapi-dev linux-libc-dev' EXTRA_DEPS='pkg-config libncursesw5-dev libudev-dev libusb-1.0-0-dev libevent-dev libmicrohttpd-dev libi2c-dev yasm libsensors4-dev' CONFIGURE_ARGS=''

+ 1 - 0
AUTHORS

@@ -77,6 +77,7 @@ Rusty Russell <rusty@rustcorp.com.au>
 slax0r <frcole@gmail.com>
 slax0r <frcole@gmail.com>
 Teemu Suikki <zuikkis@gmail.com>
 Teemu Suikki <zuikkis@gmail.com>
 Thorsten Gilling <tgilling@web.de>
 Thorsten Gilling <tgilling@web.de>
+Tim Bartletts <github@tim.bartletts.id.au>
 Tydus <Tydus@Tydus.org>
 Tydus <Tydus@Tydus.org>
 Ufasoft <support@ufasoft.com>
 Ufasoft <support@ufasoft.com>
 Vitalii Demianets <vitalii@orsoc.se>
 Vitalii Demianets <vitalii@orsoc.se>

+ 39 - 0
NEWS

@@ -1,3 +1,41 @@
+BFGMiner Version 4.10.0 - October 21, 2014
+
+- Upgraded Windows libjansson from 2.6 to 2.7
+- i2c-tools are not required by Titan
+- minergate: Fix hashmeter
+- minergate: Support minergate-side ntime rolling for SP30 only
+- minergate: Autodetect SP30 on /tmp/connection_pipe_sp30
+- minergate: Make stats file configurable
+- minergate: SP30 only wants max 10 queue requests at a time
+- minergate: Use work_completed flag for SP30
+- minergate: Only SP10 has a second winner_nonce
+- minergate: Simplify multi-winner_nonce handling
+- Bugfix: minergate: Correct endian for 2nd winner_nonce
+- minergate: Vary max jobs queued
+- minergate: Vary number of requests/responses per packet
+- minergate: Support --set MGT:protover=N
+- Titan: fix compiler warning "maybe-uninitialized"
+- Titan: Increase die inactivity timeout to 20 secs
+- Titan: Slightly improve some debug messages
+- Titan: Use multi-part batched SPI transfers for flushes (saves 2 secs on each
+flush)
+- Titan: Fix buffer overflow
+- Titan: Increase queue prefill value up to 20
+- Titan: Flag for fast broadcast flushes. Not enabled: DC/DCs trip off easily!
+- Titan: Monitor die health, reconfigure it if no shares in 10 seconds
+- Titan: Make log level of some messages lower, to not clobber the screen
+- Titan: Work assignment and flushing is per-die, not per-ASIC
+- Titan: Set flush flag after re-configuring the die
+- Titan: Refactoring: intermediate variables for first_proc and repr
+- Titan: Flush cores one-by-one right before reconfiguring them
+- Titan: Define for the broadcast core address
+- Titan: Re-configuring dies through API command "procset"
+- Titan: Use correct version of knc_titan_setup_core
+- Titan: configure_one_die func for configuring single die
+- Titan: fill all non-found ASIC structs with the same (invalid) data
+- Titan: Core init parameters (nonce range) independent of number of found dies
+
+
 BFGMiner Version 4.9.0 - October 5, 2014
 BFGMiner Version 4.9.0 - October 5, 2014
 
 
 - Upgraded Windows libraries:
 - Upgraded Windows libraries:
@@ -89,6 +127,7 @@ trouble
 - Bugfix: async minerloop fix for devices disabled at start
 - Bugfix: async minerloop fix for devices disabled at start
 - twinfury: Implement device protocol dump more low-level
 - twinfury: Implement device protocol dump more low-level
 
 
+
 BFGMiner Version 4.8.0 - September 10, 2014
 BFGMiner Version 4.8.0 - September 10, 2014
 
 
 - Improve precision of total_secs used in (at least) RPC summary Elapsed
 - Improve precision of total_secs used in (at least) RPC summary Elapsed

+ 32 - 14
README

@@ -2,9 +2,8 @@ BFGMiner:
 St. Barbara's Faithfully Glorified Mining Initiative Naturally Exceeding Rivals
 St. Barbara's Faithfully Glorified Mining Initiative Naturally Exceeding Rivals
 or Basically a Freaking Good Miner
 or Basically a Freaking Good Miner
 
 
-This is a multi-threaded multi-pool ASIC, FPGA, GPU and CPU miner with dynamic
-clocking, monitoring, and fanspeed support for bitcoin. Do not use on multiple
-block chains at the same time!
+This is a multi-threaded, multi-blockchain, multi-pool ASIC, FPGA, GPU and CPU
+miner with dynamic clocking, monitoring, and fanspeed support for bitcoin.
 
 
 This code is provided entirely free of charge by the programmer in his spare
 This code is provided entirely free of charge by the programmer in his spare
 time so donations would be greatly appreciated. Please consider donating to the
 time so donations would be greatly appreciated. Please consider donating to the
@@ -46,6 +45,10 @@ Multiple pools:
 
 
 bfgminer -o http://pool1:port -u pool1username -p pool1password -o http://pool2:port -u pool2usernmae -p pool2password
 bfgminer -o http://pool1:port -u pool1username -p pool1password -o http://pool2:port -u pool2usernmae -p pool2password
 
 
+Multiple blockchains:
+
+bfgminer -o http://pool1:port -u pool1username -p pool1password --pool-goal default -o http://pool2:port -u pool2usernmae -p pool2password --pool-goal freicoin
+
 Single pool with a standard http proxy:
 Single pool with a standard http proxy:
 
 
 bfgminer -o http://pool:port -x http://proxy:port -u username -p password
 bfgminer -o http://pool:port -x http://proxy:port -u username -p password
@@ -252,7 +255,6 @@ Options for both config file and command line:
 --cmd-idle <arg>    Execute a command when a device is allowed to be idle (rest or wait)
 --cmd-idle <arg>    Execute a command when a device is allowed to be idle (rest or wait)
 --cmd-sick <arg>    Execute a command when a device is declared sick
 --cmd-sick <arg>    Execute a command when a device is declared sick
 --cmd-dead <arg>    Execute a command when a device is declared dead
 --cmd-dead <arg>    Execute a command when a device is declared dead
---coinbase-addr <arg> Set coinbase payout address for solo mining
 --coinbase-check-addr <arg> A list of address to check against in coinbase payout list received from the previous-defined pool, separated by ','
 --coinbase-check-addr <arg> A list of address to check against in coinbase payout list received from the previous-defined pool, separated by ','
 --coinbase-check-total <arg> The least total payout amount expected in coinbase received from the previous-defined pool
 --coinbase-check-total <arg> The least total payout amount expected in coinbase received from the previous-defined pool
 --coinbase-check-percent <arg> The least benefit percentage expected for the sum of addr(s) listed in --cbaddr argument for previous-defined pool
 --coinbase-check-percent <arg> The least benefit percentage expected for the sum of addr(s) listed in --cbaddr argument for previous-defined pool
@@ -268,6 +270,7 @@ Options for both config file and command line:
 --expiry-lp <arg>   Upper bound on how many seconds after getting work we consider a share from it stale (with longpoll active) (default: 3600)
 --expiry-lp <arg>   Upper bound on how many seconds after getting work we consider a share from it stale (with longpoll active) (default: 3600)
 --failover-only     Don't leak work to backup pools when primary pool is lagging
 --failover-only     Don't leak work to backup pools when primary pool is lagging
 --failover-switch-delay <arg> Delay in seconds before switching back to a failed pool (default: 300)
 --failover-switch-delay <arg> Delay in seconds before switching back to a failed pool (default: 300)
+--generate-to <arg> Set an address to generate to for solo mining
 --force-dev-init    Always initialize devices when possible (such as bitstream uploads to some FPGAs)
 --force-dev-init    Always initialize devices when possible (such as bitstream uploads to some FPGAs)
 --kernel-path <arg> Specify a path to where bitstream and kernel files are
 --kernel-path <arg> Specify a path to where bitstream and kernel files are
 --load-balance      Change multipool strategy from failover to quota based balance
 --load-balance      Change multipool strategy from failover to quota based balance
@@ -289,6 +292,7 @@ Options for both config file and command line:
 --noncelog <arg>    Create log of all nonces found
 --noncelog <arg>    Create log of all nonces found
 --pass|-p <arg>     Password for bitcoin JSON-RPC server
 --pass|-p <arg>     Password for bitcoin JSON-RPC server
 --per-device-stats  Force verbose mode and output per-device statistics
 --per-device-stats  Force verbose mode and output per-device statistics
+--pool-goal <arg>   Named goal for the previous-defined pool
 --pool-priority <arg> Priority for just the previous-defined pool
 --pool-priority <arg> Priority for just the previous-defined pool
 --pool-proxy|-x     Proxy URI to use for connecting to just the previous-defined pool
 --pool-proxy|-x     Proxy URI to use for connecting to just the previous-defined pool
 --protocol-dump|-P  Verbose dump of protocol-level activities
 --protocol-dump|-P  Verbose dump of protocol-level activities
@@ -467,14 +471,16 @@ the range of current share difficulties, whether block notification is working
 work.
 work.
 
 
 The block display shows:
 The block display shows:
-Block: ...1b89f8d3 #217364  Diff:7.67M (54.93Th/s)  Started: [17:17:22]
+Block #217364: ...1b89f8d3  Diff:7.67M (54.93T)  Started: [17:17:22]  I:12.99mBTC/hr
 
 
-This shows a short stretch of the current block, the next block's height and
-difficulty (including the network hashrate that difficulty represents), and when
-the search for the new block started.
+This shows a short stretch of the next block's height, the current block,
+difficulty (including the network hashrate that difficulty represents), when the
+search for the new block started, and finally expected Income, calculated by
+actual shares submitted in 100% PPS value (assumes Bitcoin, does not account for
+altcoin conversions!).
 
 
 The BFGMiner status line shows:
 The BFGMiner status line shows:
- ST:1  F:0  NB:1  AS:0  BW:[ 75/241 B/s]  E:2.42  I:12.99mBTC/hr  BS:2.71k
+ ST:1  F:0  NB:1  AS:0  BW:[ 75/241 B/s]  E:2.42  BS:2.71k
 
 
 ST is STaged work items (ready to use).
 ST is STaged work items (ready to use).
 F  is network Failure occasions (server down or slow to provide work)
 F  is network Failure occasions (server down or slow to provide work)
@@ -483,8 +489,6 @@ AS is Active Submissions (shares in the process of submitting)
 BW is BandWidth usage on the network (received/sent)
 BW is BandWidth usage on the network (received/sent)
 E  is Efficiency defined as number of shares accepted (multiplied by their
 E  is Efficiency defined as number of shares accepted (multiplied by their
           difficulty) per 2 KB of bandwidth
           difficulty) per 2 KB of bandwidth
-I  is expected Income, calculated by actual shares submitted in 100% PPS value
-          (assumes Bitcoin, does not account for altcoin conversions!)
 BS is the all time Best Share difficulty you've found
 BS is the all time Best Share difficulty you've found
 
 
 The totals line shows the following:
 The totals line shows the following:
@@ -557,10 +561,11 @@ SOLO MINING
 
 
 BFGMiner supports solo mining with any GBT-compatible bitcoin node (such as
 BFGMiner supports solo mining with any GBT-compatible bitcoin node (such as
 bitcoind). To use this mode, you need to specify the URL of your bitcoind node
 bitcoind). To use this mode, you need to specify the URL of your bitcoind node
-using the usual pool options (--url, --userpass, etc), and the --coinbase-addr
+using the usual pool options (--url, --userpass, etc), and the --generate-to
 option to specify the Bitcoin address you wish to receive the block rewards
 option to specify the Bitcoin address you wish to receive the block rewards
 mined. When you run Bitcoin Core on the same computer as your miner, the pool
 mined. When you run Bitcoin Core on the same computer as your miner, the pool
-itself will be automatically configured for you.
+itself will be automatically configured for you (on the default goal). Please be
+aware that solo mining via GBT is at this time only supported for Bitcoin.
 
 
 IMPORTANT: If you are solo mining with more than one instance of BFGMiner (or
 IMPORTANT: If you are solo mining with more than one instance of BFGMiner (or
 any other software) per payout address, you must also specify data using the
 any other software) per payout address, you must also specify data using the
@@ -577,7 +582,20 @@ rejected; this does not indicate that it has stopped mining.
 Example solo mining usage:
 Example solo mining usage:
 
 
 bfgminer -o http://localhost:8332 -u username -p password \
 bfgminer -o http://localhost:8332 -u username -p password \
-    --coinbase-addr 1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh \
+    --generate-to 1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh \
+    --coinbase-sig "rig1: This is Joe's block!"
+
+If you want to solo mine on multiple GBT-compatible Bitcoin blockchains, you can
+specify --generate-to multiple times with a goal name prefix followed by a
+colon. Note that at this time, the coinbase sig is always shared across all
+goals/pools.
+
+Example multi-blockchain solo mining usage:
+
+bfgminer -o http://localhost:8332 -u username -p password \
+    --generate-to 1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh \
+    -o http://localhost:7221 -u user2 -p password --pool-goal mychain \
+    --generate-to mychain:1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh \
     --coinbase-sig "rig1: This is Joe's block!"
     --coinbase-sig "rig1: This is Joe's block!"
 
 
 
 

+ 16 - 1
README.ASIC

@@ -89,6 +89,21 @@ For example:
     sudo bfgminer -S bfsb:auto
     sudo bfgminer -S bfsb:auto
 
 
 
 
+BFx2
+----
+
+You will need to install the WinUSB driver instead of the default FTDI serial
+driver. The easiest way to do this is using Zadig: http://zadig.akeo.ie/
+
+Note that since it's impossible to tell the BFx2 apart from various other
+devices (including BFL/Cairnsmore1 miners and even many non-mining devices!),
+you must run with the -S bfx:all option (or 'bfx:all' at the M+ menu).
+
+I do not know what this will do with other devices; it may start fires,
+launch nuclear missiles (please don't run BFGMiner on computers with
+missile controls), etc.
+
+
 BI*FURY
 BI*FURY
 -------
 -------
 
 
@@ -217,7 +232,7 @@ Build instructions:
 git clone git@github.com:KnCMiner/bfgminer.git
 git clone git@github.com:KnCMiner/bfgminer.git
 cd bfgminer
 cd bfgminer
 ./autogen.sh
 ./autogen.sh
-./configure --enable-scrypt --enable-titan --disable-other-drivers CFLAGS="-Iuthash/src"
+./configure --enable-scrypt --enable-titan --disable-other-drivers
 make
 make
 sudo /etc/init.d/bfgminer.sh restart
 sudo /etc/init.d/bfgminer.sh restart
 screen -r
 screen -r

+ 12 - 2
README.RPC

@@ -213,12 +213,12 @@ The list of requests - a (*) means it requires privileged access - and replies:
                               stating the results of enabling pool N
                               stating the results of enabling pool N
                               The Msg includes the pool URL
                               The Msg includes the pool URL
 
 
- addpool|URL,USR,PASS (*)
+ addpool|URL,USR,PASS[,GOAL] (*)
                none           There is no reply section just the STATUS section
                none           There is no reply section just the STATUS section
                               stating the results of attempting to add pool N
                               stating the results of attempting to add pool N
                               The Msg includes the pool URL
                               The Msg includes the pool URL
                               Use '\\' to get a '\' and '\,' to include a comma
                               Use '\\' to get a '\' and '\,' to include a comma
-                              inside URL, USR or PASS
+                              inside URL, USR, PASS, or GOAL
 
 
  poolpriority|N,... (*)
  poolpriority|N,... (*)
                none           There is no reply section just the STATUS section
                none           There is no reply section just the STATUS section
@@ -449,6 +449,16 @@ https://www.npmjs.org/package/miner-rpc
 Feature Changelog for external applications using the API:
 Feature Changelog for external applications using the API:
 
 
 
 
+API V3.3
+
+Modified API command:
+ 'addpool' - accept an additional argument to indicate mining goal by name
+ 'coin' - return multiple elements, when there are multiple mining goals
+          defined; add 'Difficulty Accepted'
+ 'pools' - add 'Mining Goal'
+
+---------
+
 API V3.2 (BFGMiner v4.1.0)
 API V3.2 (BFGMiner v4.1.0)
 
 
 Modified API command:
 Modified API command:

+ 64 - 34
api.c

@@ -26,6 +26,8 @@
 #include <unistd.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/types.h>
 
 
+#include <uthash.h>
+
 #include "compat.h"
 #include "compat.h"
 #include "deviceapi.h"
 #include "deviceapi.h"
 #ifdef USE_LIBMICROHTTPD
 #ifdef USE_LIBMICROHTTPD
@@ -170,11 +172,9 @@ static const char ISJSON = '{';
 #define JSON_PGAS	JSON1 _PGAS JSON2
 #define JSON_PGAS	JSON1 _PGAS JSON2
 #define JSON_CPUS	JSON1 _CPUS JSON2
 #define JSON_CPUS	JSON1 _CPUS JSON2
 #define JSON_NOTIFY	JSON1 _NOTIFY JSON2
 #define JSON_NOTIFY	JSON1 _NOTIFY JSON2
-#define JSON_DEVDETAILS	JSON1 _DEVDETAILS JSON2
 #define JSON_CLOSE	JSON3
 #define JSON_CLOSE	JSON3
 #define JSON_MINESTATS	JSON1 _MINESTATS JSON2
 #define JSON_MINESTATS	JSON1 _MINESTATS JSON2
 #define JSON_CHECK	JSON1 _CHECK JSON2
 #define JSON_CHECK	JSON1 _CHECK JSON2
-#define JSON_MINECOIN	JSON1 _MINECOIN JSON2
 #define JSON_DEBUGSET	JSON1 _DEBUGSET JSON2
 #define JSON_DEBUGSET	JSON1 _DEBUGSET JSON2
 #define JSON_SETCONFIG	JSON1 _SETCONFIG JSON2
 #define JSON_SETCONFIG	JSON1 _SETCONFIG JSON2
 #define JSON_END	JSON4 JSON5
 #define JSON_END	JSON4 JSON5
@@ -411,7 +411,7 @@ struct CODES {
  { SEVERITY_ERR,   MSG_MISVAL,	PARAM_NONE,	"Missing comma after GPU number" },
  { SEVERITY_ERR,   MSG_MISVAL,	PARAM_NONE,	"Missing comma after GPU number" },
  { SEVERITY_ERR,   MSG_NOADL,	PARAM_NONE,	"ADL is not available" },
  { SEVERITY_ERR,   MSG_NOADL,	PARAM_NONE,	"ADL is not available" },
  { SEVERITY_ERR,   MSG_NOGPUADL,PARAM_GPU,	"GPU %d does not have ADL" },
  { 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_SHA_INTENSITY_STR " - " MAX_SCRYPT_INTENSITY_STR },
+ { SEVERITY_ERR,   MSG_INVINT,	PARAM_STR,	"Invalid intensity (%s) - must be '" _DYNAMIC  "' or range -10 - 31" },
  { SEVERITY_INFO,  MSG_GPUINT,	PARAM_BOTH,	"GPU %d set new intensity to %s" },
  { SEVERITY_INFO,  MSG_GPUINT,	PARAM_BOTH,	"GPU %d set new intensity to %s" },
  { SEVERITY_SUCC,  MSG_MINECONFIG,PARAM_NONE,	"BFGMiner config" },
  { SEVERITY_SUCC,  MSG_MINECONFIG,PARAM_NONE,	"BFGMiner config" },
 #ifdef HAVE_OPENCL
 #ifdef HAVE_OPENCL
@@ -1934,6 +1934,7 @@ static void poolstatus(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __m
 		root = api_add_string(root, "Status", status, false);
 		root = api_add_string(root, "Status", status, false);
 		root = api_add_int(root, "Priority", &(pool->prio), false);
 		root = api_add_int(root, "Priority", &(pool->prio), false);
 		root = api_add_int(root, "Quota", &pool->quota, false);
 		root = api_add_int(root, "Quota", &pool->quota, false);
+		root = api_add_string(root, "Mining Goal", pool->goal->name, false);
 		root = api_add_string(root, "Long Poll", lp, false);
 		root = api_add_string(root, "Long Poll", lp, false);
 		root = api_add_uint(root, "Getworks", &(pool->getwork_requested), false);
 		root = api_add_uint(root, "Getworks", &(pool->getwork_requested), false);
 		root = api_add_int(root, "Accepted", &(pool->accepted), false);
 		root = api_add_int(root, "Accepted", &(pool->accepted), false);
@@ -2341,7 +2342,7 @@ static void switchpool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, cha
 	}
 	}
 
 
 	pool = pools[id];
 	pool = pools[id];
-	pool->failover_only = false;
+	manual_enable_pool(pool);
 	cg_runlock(&control_lock);
 	cg_runlock(&control_lock);
 	switch_pools(pool);
 	switch_pools(pool);
 
 
@@ -2365,7 +2366,7 @@ static void copyadvanceafter(char ch, char **param, char **buf)
 	*(dst_b++) = '\0';
 	*(dst_b++) = '\0';
 }
 }
 
 
-static bool pooldetails(char *param, char **url, char **user, char **pass)
+static bool pooldetails(char *param, char **url, char **user, char **pass, char **goalname)
 {
 {
 	char *ptr, *buf;
 	char *ptr, *buf;
 
 
@@ -2393,6 +2394,12 @@ static bool pooldetails(char *param, char **url, char **user, char **pass)
 
 
 	// copy pass
 	// copy pass
 	copyadvanceafter(',', &param, &buf);
 	copyadvanceafter(',', &param, &buf);
+	
+	if (*param)
+		*goalname = buf;
+	
+	// copy goalname
+	copyadvanceafter(',', &param, &buf);
 
 
 	return true;
 	return true;
 
 
@@ -2403,7 +2410,7 @@ exitsama:
 
 
 static void addpool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
 static void addpool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
 {
 {
-	char *url, *user, *pass;
+	char *url, *user, *pass, *goalname = "default";
 	struct pool *pool;
 	struct pool *pool;
 	char *ptr;
 	char *ptr;
 
 
@@ -2412,7 +2419,8 @@ static void addpool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *
 		return;
 		return;
 	}
 	}
 
 
-	if (!pooldetails(param, &url, &user, &pass)) {
+	if (!pooldetails(param, &url, &user, &pass, &goalname))
+	{
 		ptr = escape_string(param, isjson);
 		ptr = escape_string(param, isjson);
 		message(io_data, MSG_INVPDP, 0, ptr, isjson);
 		message(io_data, MSG_INVPDP, 0, ptr, isjson);
 		if (ptr != param)
 		if (ptr != param)
@@ -2421,7 +2429,8 @@ static void addpool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *
 		return;
 		return;
 	}
 	}
 
 
-	pool = add_pool();
+	struct mining_goal_info * const goal = get_mining_goal(goalname);
+	pool = add_pool2(goal);
 	detect_stratum(pool, url);
 	detect_stratum(pool, url);
 	add_pool_details(pool, true, url, user, pass);
 	add_pool_details(pool, true, url, user, pass);
 
 
@@ -2459,8 +2468,7 @@ static void enablepool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, cha
 		return;
 		return;
 	}
 	}
 
 
-	pool->failover_only = false;
-	enable_pool(pool);
+	manual_enable_pool(pool);
 
 
 	message(io_data, MSG_ENAPOOL, id, NULL, isjson);
 	message(io_data, MSG_ENAPOOL, id, NULL, isjson);
 }
 }
@@ -2674,7 +2682,11 @@ static void gpuintensity(struct io_data *io_data, __maybe_unused SOCKETTYPE c, c
 		if (data->dynamic)
 		if (data->dynamic)
 			strcpy(intensitystr, DYNAMIC);
 			strcpy(intensitystr, DYNAMIC);
 		else
 		else
-			snprintf(intensitystr, sizeof(intensitystr), "%g", oclthreads_to_intensity(data->oclthreads, !opt_scrypt));
+		{
+			const char *iunit;
+			float intensity = opencl_proc_get_intensity(cgpu, &iunit);
+			snprintf(intensitystr, sizeof(intensitystr), "%s%g", iunit, intensity);
+		}
 	}
 	}
 	else
 	else
 	{
 	{
@@ -3063,36 +3075,54 @@ static void minecoin(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __may
 {
 {
 	struct api_data *root = NULL;
 	struct api_data *root = NULL;
 	char buf[TMPBUFSIZ];
 	char buf[TMPBUFSIZ];
-	bool io_open;
 
 
 	message(io_data, MSG_MINECOIN, 0, NULL, isjson);
 	message(io_data, MSG_MINECOIN, 0, NULL, isjson);
-	io_open = io_add(io_data, isjson ? COMSTR JSON_MINECOIN : _MINECOIN COMSTR);
 
 
+	struct mining_goal_info *goal, *tmpgoal;
+	bool precom = false;
+	HASH_ITER(hh, mining_goals, goal, tmpgoal)
+	{
+		if (goal->is_default)
+			io_add(io_data, isjson ? COMSTR JSON1 _MINECOIN JSON2 : _MINECOIN COMSTR);
+		else
+		{
+			sprintf(buf, isjson ? COMSTR JSON1 _MINECOIN "%u" JSON2 : _MINECOIN "%u" COMSTR, goal->id);
+			io_add(io_data, buf);
+		}
+		
+		switch (goal->malgo->algo)
+		{
 #ifdef USE_SCRYPT
 #ifdef USE_SCRYPT
-	if (opt_scrypt)
-		root = api_add_const(root, "Hash Method", SCRYPTSTR, false);
-	else
+			case POW_SCRYPT:
+				root = api_add_const(root, "Hash Method", SCRYPTSTR, false);
+				break;
 #endif
 #endif
-		root = api_add_const(root, "Hash Method", SHA256STR, false);
+			case POW_SHA256D:
+				root = api_add_const(root, "Hash Method", SHA256STR, false);
+				break;
+			default:
+				break;
+		}
 
 
-	cg_rlock(&ch_lock);
-	if (current_fullhash && *current_fullhash) {
-		root = api_add_time(root, "Current Block Time", &block_time, true);
-		root = api_add_string(root, "Current Block Hash", current_fullhash, true);
-	} else {
-		time_t t = 0;
-		root = api_add_time(root, "Current Block Time", &t, true);
-		root = api_add_const(root, "Current Block Hash", BLANK, false);
+		cg_rlock(&ch_lock);
+		struct blockchain_info * const blkchain = goal->blkchain;
+		struct block_info * const blkinfo = blkchain->currentblk;
+		root = api_add_time(root, "Current Block Time", &blkinfo->first_seen_time, true);
+		char fullhash[(sizeof(blkinfo->prevblkhash) * 2) + 1];
+		blkhashstr(fullhash, blkinfo->prevblkhash);
+		root = api_add_string(root, "Current Block Hash", fullhash, true);
+		cg_runlock(&ch_lock);
+
+		root = api_add_bool(root, "LP", &goal->have_longpoll, false);
+		root = api_add_diff(root, "Network Difficulty", &goal->current_diff, true);
+		
+		root = api_add_diff(root, "Difficulty Accepted", &goal->diff_accepted, false);
+		
+		root = print_data(root, buf, isjson, precom);
+		io_add(io_data, buf);
+		if (isjson)
+			io_add(io_data, JSON_CLOSE);
 	}
 	}
-	cg_runlock(&ch_lock);
-
-	root = api_add_bool(root, "LP", &have_longpoll, false);
-	root = api_add_diff(root, "Network Difficulty", &current_diff, true);
-
-	root = print_data(root, buf, isjson, false);
-	io_add(io_data, buf);
-	if (isjson && io_open)
-		io_close(io_data);
 }
 }
 
 
 static void debugstate(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
 static void debugstate(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)

+ 1 - 2
configure.ac

@@ -14,7 +14,7 @@ dnl * any later version.  See COPYING for more details.
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 m4_define([v_maj], [4])
 m4_define([v_maj], [4])
-m4_define([v_min], [9])
+m4_define([v_min], [99])
 m4_define([v_mic], [0])
 m4_define([v_mic], [0])
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 m4_define([v_ver], [v_maj.v_min.v_mic])
 m4_define([v_ver], [v_maj.v_min.v_mic])
@@ -818,7 +818,6 @@ if test "x$titan" != xno && test "x$titan" != xauto; then
 		AC_MSG_ERROR([You explicitly enabled KnC Titan, but did not enable scrypt])
 		AC_MSG_ERROR([You explicitly enabled KnC Titan, but did not enable scrypt])
 	fi
 	fi
 	need_knc_asic=yes
 	need_knc_asic=yes
-	need_linux_i2c_dev=yes
 	AC_DEFINE([USE_TITAN], [1], [Defined to 1 if KnC Titan support is wanted])
 	AC_DEFINE([USE_TITAN], [1], [Defined to 1 if KnC Titan support is wanted])
 	AC_DEFINE_UNQUOTED([CONTROLLER_BOARD_$titan_controller],[1])
 	AC_DEFINE_UNQUOTED([CONTROLLER_BOARD_$titan_controller],[1])
 	AH_TEMPLATE([CONTROLLER_BOARD_BACKPLANE])
 	AH_TEMPLATE([CONTROLLER_BOARD_BACKPLANE])

+ 7 - 0
debian/changelog

@@ -1,3 +1,10 @@
+bfgminer (4.10.0-0precise1) precise; urgency=low
+
+  * minergate: Support for Spondoolies SP30.
+  * titan: Numerous fixes and improvements from the KnCMiner team.
+
+ -- Luke Dashjr <luke+bfgminer@dashjr.org>  Tue, 21 Oct 2014 04:01:46 -0000
+
 bfgminer (4.9.0-0precise1) precise; urgency=low
 bfgminer (4.9.0-0precise1) precise; urgency=low
 
 
   * titan: Driver for KnCMiner's scrypt ASIC machine.
   * titan: Driver for KnCMiner's scrypt ASIC machine.

+ 1 - 1
debian/control

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

+ 22 - 0
deviceapi.c

@@ -86,6 +86,28 @@ void bfg_devapi_init()
 }
 }
 
 
 
 
+float common_sha256d_and_scrypt_min_nonce_diff(struct cgpu_info * const proc, const struct mining_algorithm * const malgo)
+{
+	switch (malgo->algo)
+	{
+#ifdef USE_SCRYPT
+		case POW_SCRYPT:
+			return 1./0x10000;
+#endif
+		case POW_SHA256D:
+			return 1.;
+		default:
+			return -1.;
+	}
+}
+
+#ifdef USE_SCRYPT
+float common_scrypt_min_nonce_diff(struct cgpu_info * const proc, const struct mining_algorithm * const malgo)
+{
+	return (malgo->algo == POW_SCRYPT) ? (1./0x10000) : -1.;
+}
+#endif
+
 bool hashes_done(struct thr_info *thr, int64_t hashes, struct timeval *tvp_hashes, uint32_t *max_nonce)
 bool hashes_done(struct thr_info *thr, int64_t hashes, struct timeval *tvp_hashes, uint32_t *max_nonce)
 {
 {
 	struct cgpu_info *cgpu = thr->cgpu;
 	struct cgpu_info *cgpu = thr->cgpu;

+ 3 - 0
deviceapi.h

@@ -42,6 +42,9 @@ extern void _bfg_register_driver(const struct device_drv *);
 
 
 extern bool bfg_need_detect_rescan;
 extern bool bfg_need_detect_rescan;
 
 
+extern float common_sha256d_and_scrypt_min_nonce_diff(struct cgpu_info *, const struct mining_algorithm *);
+extern float common_scrypt_min_nonce_diff(struct cgpu_info *, const struct mining_algorithm *);
+
 extern void request_work(struct thr_info *);
 extern void request_work(struct thr_info *);
 extern struct work *get_work(struct thr_info *);
 extern struct work *get_work(struct thr_info *);
 extern bool hashes_done(struct thr_info *, int64_t hashes, struct timeval *tvp_hashes, uint32_t *max_nonce);
 extern bool hashes_done(struct thr_info *, int64_t hashes, struct timeval *tvp_hashes, uint32_t *max_nonce);

+ 7 - 1
driver-cointerra.c

@@ -272,6 +272,12 @@ bool cointerra_wait_for_info(struct cointerra_info * const ctainfo, struct lowl_
 	return true;
 	return true;
 }
 }
 
 
+static
+float cointerra_min_nonce_diff(struct cgpu_info * const proc, const struct mining_algorithm * const malgo)
+{
+	return (malgo->algo == POW_SHA256D) ? CTA_INIT_DIFF : -1.;
+}
+
 static
 static
 bool cointerra_lowl_probe(const struct lowlevel_device_info * const info)
 bool cointerra_lowl_probe(const struct lowlevel_device_info * const info)
 {
 {
@@ -316,7 +322,6 @@ bool cointerra_lowl_probe(const struct lowlevel_device_info * const info)
 		.dev_product = maybe_strdup(info->product),
 		.dev_product = maybe_strdup(info->product),
 		.dev_serial = maybe_strdup(info->serial),
 		.dev_serial = maybe_strdup(info->serial),
 		.deven = DEV_ENABLED,
 		.deven = DEV_ENABLED,
-		.min_nonce_diff = CTA_INIT_DIFF,
 	};
 	};
 	const bool rv = add_cgpu(dev);
 	const bool rv = add_cgpu(dev);
 	applog(LOG_INFO, "%s: Successfully set up %s",
 	applog(LOG_INFO, "%s: Successfully set up %s",
@@ -1357,6 +1362,7 @@ static const struct bfg_set_device_definition cointerra_set_device_funcs[] = {
 struct device_drv cointerra_drv = {
 struct device_drv cointerra_drv = {
 	.dname = "cointerra",
 	.dname = "cointerra",
 	.name = "CTA",
 	.name = "CTA",
+	.drv_min_nonce_diff = cointerra_min_nonce_diff,
 	.lowl_match = cointerra_lowl_match,
 	.lowl_match = cointerra_lowl_match,
 	.lowl_probe = cointerra_lowl_probe,
 	.lowl_probe = cointerra_lowl_probe,
 	.thread_init = cta_prepare,
 	.thread_init = cta_prepare,

+ 15 - 19
driver-cpu.c

@@ -665,14 +665,10 @@ static enum sha256_algos pick_fastest_algo()
 	return best_algo;
 	return best_algo;
 }
 }
 
 
-/* FIXME: Use asprintf for better errors. */
 char *set_algo(const char *arg, enum sha256_algos *algo)
 char *set_algo(const char *arg, enum sha256_algos *algo)
 {
 {
 	enum sha256_algos i;
 	enum sha256_algos i;
 
 
-	if (opt_scrypt)
-		return "Can only use scrypt algorithm";
-
 	for (i = 0; i < ARRAY_SIZE(algo_names); i++) {
 	for (i = 0; i < ARRAY_SIZE(algo_names); i++) {
 		if (algo_names[i] && !strcmp(arg, algo_names[i])) {
 		if (algo_names[i] && !strcmp(arg, algo_names[i])) {
 			*algo = i;
 			*algo = i;
@@ -682,13 +678,6 @@ char *set_algo(const char *arg, enum sha256_algos *algo)
 	return "Unknown algorithm";
 	return "Unknown algorithm";
 }
 }
 
 
-#ifdef WANT_SCRYPT
-void set_scrypt_algo(enum sha256_algos *algo)
-{
-	*algo = ALGO_SCRYPT;
-}
-#endif
-
 void show_algo(char buf[OPT_SHOW_LEN], const enum sha256_algos *algo)
 void show_algo(char buf[OPT_SHOW_LEN], const enum sha256_algos *algo)
 {
 {
 	strncpy(buf, algo_names[*algo], OPT_SHOW_LEN);
 	strncpy(buf, algo_names[*algo], OPT_SHOW_LEN);
@@ -805,9 +794,6 @@ static bool cpu_thread_init(struct thr_info *thr)
 
 
 	cgpu->kname = algo_names[opt_algo];
 	cgpu->kname = algo_names[opt_algo];
 	
 	
-	if (opt_algo == ALGO_SCRYPT)
-		cgpu->min_nonce_diff = 1./0x10000;
-	
 	/* Set worker threads to nice 19 and then preferentially to SCHED_IDLE
 	/* Set worker threads to nice 19 and then preferentially to SCHED_IDLE
 	 * and if that fails, then SCHED_BATCH. No need for this to be an
 	 * and if that fails, then SCHED_BATCH. No need for this to be an
 	 * error if it fails */
 	 * error if it fails */
@@ -834,7 +820,20 @@ CPUSearch:
 
 
 	/* scan nonces for a proof-of-work hash */
 	/* scan nonces for a proof-of-work hash */
 	{
 	{
-		sha256_func func = sha256_funcs[opt_algo];
+		sha256_func func = NULL;
+		switch (work_mining_algorithm(work)->algo)
+		{
+#ifdef USE_SCRYPT
+			case POW_SCRYPT:
+				func = scanhash_scrypt;
+				break;
+#endif
+			case POW_SHA256D:
+				func = sha256_funcs[opt_algo];
+				break;
+		}
+		if (unlikely(!func))
+			applogr(0, LOG_ERR, "%"PRIpreprv": Unknown mining algorithm", thr->cgpu->proc_repr);
 		rc = (*func)(
 		rc = (*func)(
 			thr,
 			thr,
 			work->midstate,
 			work->midstate,
@@ -867,7 +866,7 @@ struct device_drv cpu_drv = {
 	.dname = "cpu",
 	.dname = "cpu",
 	.name = "CPU",
 	.name = "CPU",
 	.probe_priority = 120,
 	.probe_priority = 120,
-	.supported_algos = POW_SHA256D | POW_SCRYPT,
+	.drv_min_nonce_diff = common_sha256d_and_scrypt_min_nonce_diff,
 	.drv_detect = cpu_detect,
 	.drv_detect = cpu_detect,
 	.thread_prepare = cpu_thread_prepare,
 	.thread_prepare = cpu_thread_prepare,
 	.can_limit_work = cpu_can_limit_work,
 	.can_limit_work = cpu_can_limit_work,
@@ -875,6 +874,3 @@ struct device_drv cpu_drv = {
 	.scanhash = cpu_scanhash,
 	.scanhash = cpu_scanhash,
 };
 };
 #endif
 #endif
-
-
-

+ 62 - 34
driver-dualminer.c

@@ -33,11 +33,6 @@
   #include <io.h>
   #include <io.h>
 #endif
 #endif
 
 
-// mining both Scrypt & SHA2 at the same time with two processes
-// SHA2 process must be run first, no arg requirements, first serial port will be used
-// Scrypt process must be launched after, --scrypt and --dual-mode args required
-bool opt_dual_mode = false;
-
 #define DUALMINER_IO_SPEED 115200
 #define DUALMINER_IO_SPEED 115200
 
 
 #define DUALMINER_SCRYPT_SM_HASH_TIME   0.00001428571429
 #define DUALMINER_SCRYPT_SM_HASH_TIME   0.00001428571429
@@ -85,6 +80,16 @@ const struct bfg_set_device_definition dualminer_set_device_funcs[];
 
 
 // device helper functions
 // device helper functions
 
 
+static inline
+bool dualminer_is_scrypt(struct ICARUS_INFO * const info)
+{
+#ifdef USE_SCRYPT
+	return info->scrypt;
+#else
+	return false;
+#endif
+}
+
 static
 static
 void dualminer_teardown_device(int fd)
 void dualminer_teardown_device(int fd)
 {
 {
@@ -102,37 +107,27 @@ void dualminer_init_hashrate(struct cgpu_info * const cgpu)
 
 
 	// get clear to send (CTS) status
 	// get clear to send (CTS) status
 	if ((gc3355_get_cts_status(fd) != 1) &&  // 0.9v - dip-switch set to B
 	if ((gc3355_get_cts_status(fd) != 1) &&  // 0.9v - dip-switch set to B
-		(opt_scrypt))
+		(dualminer_is_scrypt(info)))
 		// adjust hash-rate for voltage
 		// adjust hash-rate for voltage
 		info->Hs = DUALMINER_SCRYPT_DM_HASH_TIME;
 		info->Hs = DUALMINER_SCRYPT_DM_HASH_TIME;
 }
 }
 
 
-static
-bool dualminer_init(struct thr_info * const thr)
-{
-	struct cgpu_info * const cgpu = thr->cgpu;
-	
-	if (opt_scrypt)
-		cgpu->min_nonce_diff = 1./0x10000;
-	
-	return icarus_init(thr);
-}
-
 // runs when job starts and the device has been reset (or first run)
 // runs when job starts and the device has been reset (or first run)
 static
 static
 void dualminer_init_firstrun(struct cgpu_info *icarus)
 void dualminer_init_firstrun(struct cgpu_info *icarus)
 {
 {
+	struct ICARUS_INFO * const info = icarus->device_data;
 	int fd = icarus->device_fd;
 	int fd = icarus->device_fd;
 
 
-	gc3355_init_dualminer(fd, opt_pll_freq, !opt_dual_mode, false);
+	gc3355_init_dualminer(fd, opt_pll_freq, !info->dual_mode, false, dualminer_is_scrypt(info));
 	
 	
 	dualminer_init_hashrate(icarus);
 	dualminer_init_hashrate(icarus);
 
 
 	applog(LOG_DEBUG, "%"PRIpreprv": dualminer: Init: pll=%d, scrypt: %d, scrypt only: %d",
 	applog(LOG_DEBUG, "%"PRIpreprv": dualminer: Init: pll=%d, scrypt: %d, scrypt only: %d",
 		   icarus->proc_repr,
 		   icarus->proc_repr,
 		   opt_pll_freq,
 		   opt_pll_freq,
-		   opt_scrypt,
-		   opt_scrypt && !opt_dual_mode);
+		   dualminer_is_scrypt(info),
+		   dualminer_is_scrypt(info) && !info->dual_mode);
 }
 }
 
 
 // set defaults for options that the user didn't specify
 // set defaults for options that the user didn't specify
@@ -160,15 +155,31 @@ void dualminer_set_defaults(int fd)
 	}
 	}
 }
 }
 
 
+float dualminer_min_nonce_diff(struct cgpu_info * const proc, const struct mining_algorithm * const malgo)
+{
+	struct ICARUS_INFO * const info = proc ? proc->device_data : NULL;
+	switch (malgo->algo)
+	{
+#ifdef USE_SCRYPT
+		case POW_SCRYPT:
+			return ((!info) || dualminer_is_scrypt(info)) ? (1./0x10000) : -1.;
+#endif
+		case POW_SHA256D:
+			return (info && dualminer_is_scrypt(info)) ? -1. : 1.;
+		default:
+			return -1.;
+	}
+}
+
 // ICARUS_INFO functions - icarus-common.h
 // ICARUS_INFO functions - icarus-common.h
 
 
 // runs after fd is opened but before the device detection code
 // runs after fd is opened but before the device detection code
 static
 static
-bool dualminer_detect_init(const char *devpath, int fd, struct ICARUS_INFO * __maybe_unused info)
+bool dualminer_detect_init(const char *devpath, int fd, struct ICARUS_INFO * const info)
 {
 {
 	dualminer_set_defaults(fd);
 	dualminer_set_defaults(fd);
 	
 	
-	gc3355_init_dualminer(fd, opt_pll_freq, !opt_dual_mode, true);
+	gc3355_init_dualminer(fd, opt_pll_freq, !info->dual_mode, true, dualminer_is_scrypt(info));
 
 
 	return true;
 	return true;
 }
 }
@@ -178,6 +189,7 @@ static
 bool dualminer_job_start(struct thr_info * const thr)
 bool dualminer_job_start(struct thr_info * const thr)
 {
 {
 	struct cgpu_info *icarus = thr->cgpu;
 	struct cgpu_info *icarus = thr->cgpu;
+	struct ICARUS_INFO * const info = icarus->device_data;
 	struct icarus_state * const state = thr->cgpu_data;
 	struct icarus_state * const state = thr->cgpu_data;
 	int fd = icarus->device_fd;
 	int fd = icarus->device_fd;
 
 
@@ -185,9 +197,9 @@ bool dualminer_job_start(struct thr_info * const thr)
 		// runs when job starts and the device has been reset (or first run)
 		// runs when job starts and the device has been reset (or first run)
 		dualminer_init_firstrun(icarus);
 		dualminer_init_firstrun(icarus);
 
 
-	if (opt_scrypt)
+	if (dualminer_is_scrypt(info))
 	{
 	{
-		if (opt_dual_mode)
+		if (info->dual_mode)
 			gc3355_scrypt_reset(fd);
 			gc3355_scrypt_reset(fd);
 		else
 		else
 			gc3355_scrypt_only_reset(fd);
 			gc3355_scrypt_only_reset(fd);
@@ -221,10 +233,15 @@ bool dualminer_detect_one(const char *devpath)
 		.nonce_littleendian = true,
 		.nonce_littleendian = true,
 		.work_division = 1,
 		.work_division = 1,
 		.detect_init_func = dualminer_detect_init,
 		.detect_init_func = dualminer_detect_init,
-		.job_start_func = dualminer_job_start
+		.job_start_func = dualminer_job_start,
+#ifdef USE_SCRYPT
+		.scrypt = (get_mining_goal("default")->malgo->algo == POW_SCRYPT),
+#endif
 	};
 	};
 
 
-	if (opt_scrypt)
+	drv_set_defaults(drv, dualminer_set_device_funcs, info, devpath, detectone_meta_info.serial, 1);
+
+	if (dualminer_is_scrypt(info))
 	{
 	{
 		info->golden_ob = (char*)scrypt_golden_ob;
 		info->golden_ob = (char*)scrypt_golden_ob;
 		info->golden_nonce = (char*)scrypt_golden_nonce;
 		info->golden_nonce = (char*)scrypt_golden_nonce;
@@ -237,15 +254,13 @@ bool dualminer_detect_one(const char *devpath)
 		info->Hs = DUALMINER_SHA2_DM_HASH_TIME;
 		info->Hs = DUALMINER_SHA2_DM_HASH_TIME;
 	}
 	}
 
 
-	drv_set_defaults(drv, dualminer_set_device_funcs, info, devpath, detectone_meta_info.serial, 1);
-
 	if (!icarus_detect_custom(devpath, drv, info))
 	if (!icarus_detect_custom(devpath, drv, info))
 	{
 	{
 		free(info);
 		free(info);
 		return false;
 		return false;
 	}
 	}
 
 
-	if (opt_scrypt)
+	if (dualminer_is_scrypt(info))
 		info->read_count = DUALMINER_SCRYPT_READ_COUNT; // 4.8s to read
 		info->read_count = DUALMINER_SCRYPT_READ_COUNT; // 4.8s to read
 	else
 	else
 		info->read_count = DUALMINER_SHA2_READ_COUNT; // 1.6s to read
 		info->read_count = DUALMINER_SHA2_READ_COUNT; // 1.6s to read
@@ -259,14 +274,28 @@ bool dualminer_detect_one(const char *devpath)
 static
 static
 const char *dualminer_set_dual_mode(struct cgpu_info * const proc, const char * const option, const char * const setting, char * const replybuf, enum bfg_set_device_replytype * const success)
 const char *dualminer_set_dual_mode(struct cgpu_info * const proc, const char * const option, const char * const setting, char * const replybuf, enum bfg_set_device_replytype * const success)
 {
 {
+	struct ICARUS_INFO * const info = proc->device_data;
 	int val = atoi(setting);
 	int val = atoi(setting);
-	opt_dual_mode = val == 1;
+	info->dual_mode = val == 1;
+	return NULL;
+}
+
+#ifdef USE_SCRYPT
+static
+const char *dualminer_set_scrypt(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const out_success)
+{
+	struct ICARUS_INFO * const info = proc->device_data;
+	info->scrypt = atoi(newvalue);
 	return NULL;
 	return NULL;
 }
 }
+#endif
 
 
 static
 static
 const struct bfg_set_device_definition dualminer_set_device_funcs[] = {
 const struct bfg_set_device_definition dualminer_set_device_funcs[] = {
-	{"dual_mode", dualminer_set_dual_mode, "set to 1 to enable dual algorithm mining with two BFGMiner processes"},
+	{"dual_mode", dualminer_set_dual_mode, "set to 1 to enable dual algorithm mining"},
+#ifdef USE_SCRYPT
+	{"scrypt", dualminer_set_scrypt, "set to 1 to put in scrypt mode"},
+#endif
 	{NULL},
 	{NULL},
 };
 };
 
 
@@ -298,7 +327,7 @@ bool dualminer_job_prepare(struct thr_info *thr, struct work *work, __maybe_unus
 
 
 	memset(state->ob_bin, 0, info->ob_size);
 	memset(state->ob_bin, 0, info->ob_size);
 
 
-	if (opt_scrypt)
+	if (dualminer_is_scrypt(info))
 		gc3355_scrypt_prepare_work(state->ob_bin, work);
 		gc3355_scrypt_prepare_work(state->ob_bin, work);
 	else
 	else
 		gc3355_sha2_prepare_work(state->ob_bin, work);
 		gc3355_sha2_prepare_work(state->ob_bin, work);
@@ -329,9 +358,8 @@ void dualminer_drv_init()
 	dualminer_drv = icarus_drv;
 	dualminer_drv = icarus_drv;
 	dualminer_drv.dname = "dualminer";
 	dualminer_drv.dname = "dualminer";
 	dualminer_drv.name = "DMU";
 	dualminer_drv.name = "DMU";
-	dualminer_drv.supported_algos = POW_SCRYPT | POW_SHA256D;
+	dualminer_drv.drv_min_nonce_diff = dualminer_min_nonce_diff;
 	dualminer_drv.lowl_probe = dualminer_lowl_probe;
 	dualminer_drv.lowl_probe = dualminer_lowl_probe;
-	dualminer_drv.thread_init = dualminer_init;
 	dualminer_drv.thread_shutdown = dualminer_thread_shutdown;
 	dualminer_drv.thread_shutdown = dualminer_thread_shutdown;
 	dualminer_drv.job_prepare = dualminer_job_prepare;
 	dualminer_drv.job_prepare = dualminer_job_prepare;
 	dualminer_drv.set_device = dualminer_set_device;
 	dualminer_drv.set_device = dualminer_set_device;

+ 5 - 2
driver-getwork.c

@@ -185,7 +185,8 @@ int handle_getwork(struct MHD_Connection *conn, bytes_t *upbuf)
 		size_t replysz = 590 + idstr_sz;
 		size_t replysz = 590 + idstr_sz;
 		
 		
 		work = get_work(thr);
 		work = get_work(thr);
-		work->nonce_diff = client->desired_share_pdiff;
+		const struct mining_algorithm * const malgo = work_mining_algorithm(work);
+		work->nonce_diff = client->desired_share_pdiff ?: malgo->reasonable_low_nonce_diff;
 		if (work->nonce_diff > work->work_difficulty)
 		if (work->nonce_diff > work->work_difficulty)
 			work->nonce_diff = work->work_difficulty;
 			work->nonce_diff = work->work_difficulty;
 		
 		
@@ -201,13 +202,15 @@ int handle_getwork(struct MHD_Connection *conn, bytes_t *upbuf)
 		memcpy(&reply[442], "\",\"hash1\":\"00000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000010000\"},\"id\":", 147);
 		memcpy(&reply[442], "\",\"hash1\":\"00000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000010000\"},\"id\":", 147);
 		memcpy(&reply[589], idstr ?: "0", idstr_sz);
 		memcpy(&reply[589], idstr ?: "0", idstr_sz);
 		memcpy(&reply[589 + idstr_sz], "}", 1);
 		memcpy(&reply[589 + idstr_sz], "}", 1);
-		if (opt_scrypt)
+#ifdef USE_SCRYPT
+		if (malgo->algo == POW_SCRYPT)
 		{
 		{
 			replysz += 21;
 			replysz += 21;
 			reply = realloc(reply, replysz);
 			reply = realloc(reply, replysz);
 			memmove(&reply[443 + 21], &reply[443], replysz - (443 + 21));
 			memmove(&reply[443 + 21], &reply[443], replysz - (443 + 21));
 			memcpy(&reply[443], ",\"algorithm\":\"scrypt\"", 21);
 			memcpy(&reply[443], ",\"algorithm\":\"scrypt\"", 21);
 		}
 		}
+#endif
 		
 		
 		timer_set_now(&work->tv_work_start);
 		timer_set_now(&work->tv_work_start);
 		HASH_ADD_KEYPTR(hh, client->work, work->data, 76, work);
 		HASH_ADD_KEYPTR(hh, client->work, work->data, 76, work);

+ 1 - 16
driver-gridseed.c

@@ -215,24 +215,12 @@ bool gridseed_lowl_probe(const struct lowlevel_device_info * const info)
  * setup & shutdown
  * setup & shutdown
  */
  */
 
 
-static
-bool gridseed_thread_prepare(struct thr_info *thr)
-{
-	thr->cgpu_data = calloc(1, sizeof(*thr->cgpu_data));
-	
-	struct cgpu_info *device = thr->cgpu;
-	device->min_nonce_diff = 1./0x10000;
-
-	return true;
-}
-
 static
 static
 void gridseed_thread_shutdown(struct thr_info *thr)
 void gridseed_thread_shutdown(struct thr_info *thr)
 {
 {
 	struct cgpu_info *device = thr->cgpu;
 	struct cgpu_info *device = thr->cgpu;
 
 
 	gc3355_close(device->device_fd);
 	gc3355_close(device->device_fd);
-	free(thr->cgpu_data);
 }
 }
 
 
 /*
 /*
@@ -446,14 +434,11 @@ struct device_drv gridseed_drv =
 	// metadata
 	// metadata
 	.dname = "gridseed",
 	.dname = "gridseed",
 	.name = "GSD",
 	.name = "GSD",
-	.supported_algos = POW_SCRYPT,
+	.drv_min_nonce_diff = common_scrypt_min_nonce_diff,
 	
 	
 	// detect device
 	// detect device
 	.lowl_probe = gridseed_lowl_probe,
 	.lowl_probe = gridseed_lowl_probe,
 	
 	
-	// initialize device
-	.thread_prepare = gridseed_thread_prepare,
-	
 	// specify mining type - scanhash
 	// specify mining type - scanhash
 	.minerloop = minerloop_scanhash,
 	.minerloop = minerloop_scanhash,
 	
 	

+ 7 - 0
driver-icarus.h

@@ -134,6 +134,13 @@ struct ICARUS_INFO {
 	bool (*detect_init_func)(const char *devpath, int fd, struct ICARUS_INFO *);
 	bool (*detect_init_func)(const char *devpath, int fd, struct ICARUS_INFO *);
 	bool (*job_start_func)(struct thr_info *);
 	bool (*job_start_func)(struct thr_info *);
 	
 	
+#ifdef USE_DUALMINER
+#ifdef USE_SCRYPT
+	bool scrypt;
+#endif
+	bool dual_mode;
+#endif
+	
 #ifdef USE_ZEUSMINER
 #ifdef USE_ZEUSMINER
 	// Hardware information, doesn't affect anything directly
 	// Hardware information, doesn't affect anything directly
 	uint16_t freq;
 	uint16_t freq;

+ 219 - 50
driver-minergate.c

@@ -33,27 +33,40 @@
 
 
 static const char * const minergate_stats_file = "/var/run/mg_rate_temp";
 static const char * const minergate_stats_file = "/var/run/mg_rate_temp";
 
 
-#define MINERGATE_PROTOCOL_VER  6
 #define MINERGATE_MAGIC  0xcaf4
 #define MINERGATE_MAGIC  0xcaf4
-static const int minergate_max_responses = 300;
 #define MINERGATE_PKT_HEADER_SZ       8
 #define MINERGATE_PKT_HEADER_SZ       8
 #define MINERGATE_PKT_REQ_ITEM_SZ  0x34
 #define MINERGATE_PKT_REQ_ITEM_SZ  0x34
-#define MINERGATE_PKT_REQ_MAX     100
-#define MINERGATE_PKT_RSP_ITEM_SZ  0x14
-#define MINERGATE_PKT_RSP_MAX     300
 #define MINERGATE_POLL_US      100000
 #define MINERGATE_POLL_US      100000
 #define MINERGATE_RETRY_US    5000000
 #define MINERGATE_RETRY_US    5000000
 
 
-#define MINERGATE_PKT_REQ_SZ  (MINERGATE_PKT_HEADER_SZ + (MINERGATE_PKT_REQ_ITEM_SZ * MINERGATE_PKT_REQ_MAX))
-#define MINERGATE_PKT_RSP_SZ  (MINERGATE_PKT_HEADER_SZ + (MINERGATE_PKT_RSP_ITEM_SZ * MINERGATE_PKT_RSP_MAX))
-
 BFG_REGISTER_DRIVER(minergate_drv)
 BFG_REGISTER_DRIVER(minergate_drv)
 
 
+enum minergate_protocol_ver {
+	MPV_SP10 =  6,
+	MPV_SP30 = 30,
+};
+
 enum minergate_reqpkt_flags {
 enum minergate_reqpkt_flags {
 	MRPF_FIRST = 1,
 	MRPF_FIRST = 1,
 	MRPF_FLUSH = 2,
 	MRPF_FLUSH = 2,
 };
 };
 
 
+struct minergate_config {
+	uint8_t protover;
+	int n_req;
+	int n_req_queue;
+	int n_rsp;
+	int queue;
+	char *stats_file;
+	int minimum_roll;
+	int desired_roll;
+	int work_duration;
+	
+	int pkt_req_sz;
+	int pkt_rsp_sz;
+	int pkt_rsp_item_sz;
+};
+
 struct minergate_state {
 struct minergate_state {
 	work_device_id_t next_jobid;
 	work_device_id_t next_jobid;
 	unsigned ready_to_queue;
 	unsigned ready_to_queue;
@@ -107,18 +120,118 @@ ssize_t minergate_read(const int fd, void * const buf_p, size_t bufLen)
 	return ret;
 	return ret;
 }
 }
 
 
+
+#define DEF_POSITIVE_VAR(VARNAME)  \
+static  \
+const char *minergate_init_ ## VARNAME(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const out_success)  \
+{  \
+	struct minergate_config * const mgcfg = proc->device_data;  \
+	int nv = atoi(newvalue);  \
+	if (nv < 0)  \
+		return #VARNAME " must be positive";  \
+	mgcfg->VARNAME = nv;  \
+	return NULL;  \
+}  \
+// END OF DEF_POSITIVE_VAR
+
 static
 static
-bool minergate_detect_one(const char * const devpath)
+const char *minergate_init_protover(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const out_success)
+{
+	struct minergate_config * const mgcfg = proc->device_data;
+	
+	int i = atoi(newvalue);
+	
+	if (i != MPV_SP10 || i != MPV_SP30)
+		return "Invalid protocol version";
+	
+	mgcfg->protover = i;
+	
+	return NULL;
+}
+
+DEF_POSITIVE_VAR(n_req)
+DEF_POSITIVE_VAR(n_req_queue)
+DEF_POSITIVE_VAR(n_rsp)
+DEF_POSITIVE_VAR(queue)
+
+static
+const char *minergate_init_stats_file(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const out_success)
+{
+	struct minergate_config * const mgcfg = proc->device_data;
+	free(mgcfg->stats_file);
+	mgcfg->stats_file = trimmed_strdup(newvalue);
+	return NULL;
+}
+
+DEF_POSITIVE_VAR(work_duration)
+DEF_POSITIVE_VAR(minimum_roll)
+DEF_POSITIVE_VAR(desired_roll)
+
+static const struct bfg_set_device_definition minergate_set_device_funcs_probe[] = {
+	{"protover", minergate_init_protover, NULL},
+	{"n_req", minergate_init_n_req, NULL},
+	{"n_req_queue", minergate_init_n_req_queue, NULL},
+	{"n_rsp", minergate_init_n_rsp, NULL},
+	{"queue", minergate_init_queue, NULL},
+	{"stats_file", minergate_init_stats_file, NULL},
+	{"work_duration", minergate_init_work_duration, NULL},
+	{"minimum_roll", minergate_init_minimum_roll, NULL},
+	{"desired_roll", minergate_init_desired_roll, NULL},
+	{NULL},
+};
+
+static
+bool minergate_detect_one_extra(const char * const devpath, const enum minergate_protocol_ver def_protover)
 {
 {
 	bool rv = false;
 	bool rv = false;
 	const int fd = minergate_open(devpath);
 	const int fd = minergate_open(devpath);
 	if (unlikely(fd < 0))
 	if (unlikely(fd < 0))
 		applogr(false, LOG_DEBUG, "%s: %s: Cannot connect", minergate_drv.dname, devpath);
 		applogr(false, LOG_DEBUG, "%s: %s: Cannot connect", minergate_drv.dname, devpath);
 	
 	
+	struct minergate_config * const mgcfg = malloc(sizeof(*mgcfg));
+	*mgcfg = (struct minergate_config){
+		.protover = def_protover,
+		.work_duration = -1,
+		.minimum_roll = -1,
+		.desired_roll = -1,
+	};
+	drv_set_defaults(&minergate_drv, minergate_set_device_funcs_probe, mgcfg, devpath, NULL, 1);
+	switch (mgcfg->protover)
+	{
+		case MPV_SP10:
+			BFGINIT(mgcfg->n_req, 100);
+			BFGINIT(mgcfg->n_req_queue, mgcfg->n_req);
+			BFGINIT(mgcfg->n_rsp, 300);
+			BFGINIT(mgcfg->queue, 300);
+			mgcfg->pkt_rsp_item_sz = 0x14;
+			mgcfg->minimum_roll = mgcfg->desired_roll = 0;  // not supported
+			break;
+		case MPV_SP30:
+			BFGINIT(mgcfg->n_req, 30);
+			BFGINIT(mgcfg->n_req_queue, min(10, mgcfg->n_req));
+			BFGINIT(mgcfg->n_rsp, 60);
+			BFGINIT(mgcfg->queue, 40);
+			mgcfg->pkt_rsp_item_sz = 0x10;
+			if (mgcfg->minimum_roll == -1)
+				mgcfg->minimum_roll = 60;
+			break;
+	}
+	BFGINIT(mgcfg->stats_file, strdup(minergate_stats_file));
+	mgcfg->desired_roll = max(mgcfg->desired_roll, mgcfg->minimum_roll);
+	if (mgcfg->work_duration == -1)
+		mgcfg->work_duration = 0x10;  // reasonable guess?
+	mgcfg->pkt_req_sz = MINERGATE_PKT_HEADER_SZ + (MINERGATE_PKT_REQ_ITEM_SZ * mgcfg->n_req);
+	mgcfg->pkt_rsp_sz = MINERGATE_PKT_HEADER_SZ + (mgcfg->pkt_rsp_item_sz * mgcfg->n_rsp);
+	
 	int epfd = -1;
 	int epfd = -1;
-	uint8_t buf[MINERGATE_PKT_REQ_SZ] = {0xbf, 0x90, MINERGATE_PROTOCOL_VER, MRPF_FIRST, 0,0, 0 /* req count */,};
+	uint8_t buf[mgcfg->pkt_req_sz];
+	buf[0] = 0xbf;
+	buf[1] = 0x90;
+	buf[2] = mgcfg->protover;
+	buf[3] = MRPF_FIRST;
 	pk_u16le(buf, 4, MINERGATE_MAGIC);
 	pk_u16le(buf, 4, MINERGATE_MAGIC);
-	if (MINERGATE_PKT_REQ_SZ != write(fd, buf, MINERGATE_PKT_REQ_SZ))
+	memset(&buf[6], '\0', mgcfg->pkt_req_sz - 6);
+	if (mgcfg->pkt_req_sz != write(fd, buf, mgcfg->pkt_req_sz))
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: write incomplete or failed", minergate_drv.dname, devpath);
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: write incomplete or failed", minergate_drv.dname, devpath);
 	
 	
 	epfd = epoll_create(1);
 	epfd = epoll_create(1);
@@ -145,13 +258,13 @@ bool minergate_detect_one(const char * const devpath)
 	
 	
 	if (buf[1] != 0x90)
 	if (buf[1] != 0x90)
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: %s mismatch", minergate_drv.dname, devpath, "request_id");
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: %s mismatch", minergate_drv.dname, devpath, "request_id");
-	if (buf[2] != MINERGATE_PROTOCOL_VER)
+	if (buf[2] != mgcfg->protover)
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: %s mismatch", minergate_drv.dname, devpath, "Protocol version");
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: %s mismatch", minergate_drv.dname, devpath, "Protocol version");
 	if (upk_u16le(buf, 4) != MINERGATE_MAGIC)
 	if (upk_u16le(buf, 4) != MINERGATE_MAGIC)
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: %s mismatch", minergate_drv.dname, devpath, "magic");
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: %s mismatch", minergate_drv.dname, devpath, "magic");
 	
 	
 	uint16_t responses = upk_u16le(buf, 6);
 	uint16_t responses = upk_u16le(buf, 6);
-	if (responses > minergate_max_responses)
+	if (responses > mgcfg->n_rsp)
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: More than maximum responses", minergate_drv.dname, devpath);
 		return_via_applog(out, , LOG_DEBUG, "%s: %s: More than maximum responses", minergate_drv.dname, devpath);
 	
 	
 	if (bfg_claim_any2(&minergate_drv, devpath, "unix", devpath))
 	if (bfg_claim_any2(&minergate_drv, devpath, "unix", devpath))
@@ -161,22 +274,36 @@ bool minergate_detect_one(const char * const devpath)
 	*cgpu = (struct cgpu_info){
 	*cgpu = (struct cgpu_info){
 		.drv = &minergate_drv,
 		.drv = &minergate_drv,
 		.device_path = strdup(devpath),
 		.device_path = strdup(devpath),
+		.device_data = mgcfg,
 		.deven = DEV_ENABLED,
 		.deven = DEV_ENABLED,
 		.threads = 1,
 		.threads = 1,
 	};
 	};
 	rv = add_cgpu(cgpu);
 	rv = add_cgpu(cgpu);
 	
 	
 out:
 out:
+	if (!rv)
+		free(mgcfg);
 	close(fd);
 	close(fd);
 	if (epfd >= 0)
 	if (epfd >= 0)
 		close(epfd);
 		close(epfd);
 	return rv;
 	return rv;
 }
 }
 
 
+static
+bool minergate_detect_one(const char * const devpath)
+{
+	return minergate_detect_one_extra(devpath, MPV_SP10);
+}
+
 static
 static
 int minergate_detect_auto(void)
 int minergate_detect_auto(void)
 {
 {
-	return minergate_detect_one("/tmp/connection_pipe") ? 1 : 0;
+	int total = 0;
+	if (minergate_detect_one_extra("/tmp/connection_pipe", MPV_SP10))
+		++total;
+	if (minergate_detect_one_extra("/tmp/connection_pipe_sp30", MPV_SP30))
+		++total;
+	return total;
 }
 }
 
 
 static
 static
@@ -189,13 +316,14 @@ static
 bool minergate_init(struct thr_info * const thr)
 bool minergate_init(struct thr_info * const thr)
 {
 {
 	struct cgpu_info * const dev = thr->cgpu;
 	struct cgpu_info * const dev = thr->cgpu;
+	struct minergate_config * const mgcfg = dev->device_data;
 	
 	
 	const int fd = minergate_open(dev->device_path);
 	const int fd = minergate_open(dev->device_path);
 	dev->device_fd = fd;
 	dev->device_fd = fd;
 	if (fd < 0)
 	if (fd < 0)
 		applogr(false, LOG_ERR, "%s: Cannot connect", dev->dev_repr);
 		applogr(false, LOG_ERR, "%s: Cannot connect", dev->dev_repr);
 	
 	
-	struct minergate_state * const state = malloc(sizeof(*state) + MINERGATE_PKT_REQ_SZ);
+	struct minergate_state * const state = malloc(sizeof(*state) + mgcfg->pkt_req_sz);
 	if (!state)
 	if (!state)
 		applogr(false, LOG_ERR, "%s: %s failed", dev->dev_repr, "malloc");
 		applogr(false, LOG_ERR, "%s: %s failed", dev->dev_repr, "malloc");
 	*state = (struct minergate_state){
 	*state = (struct minergate_state){
@@ -205,8 +333,8 @@ bool minergate_init(struct thr_info * const thr)
 	thr->work = thr->work_list = NULL;
 	thr->work = thr->work_list = NULL;
 	
 	
 	mutex_init(&dev->device_mutex);
 	mutex_init(&dev->device_mutex);
-	memset(state->req_buffer, 0, MINERGATE_PKT_REQ_SZ);
-	pk_u8(state->req_buffer, 2, MINERGATE_PROTOCOL_VER);
+	memset(state->req_buffer, 0, mgcfg->pkt_req_sz);
+	pk_u8(state->req_buffer, 2, mgcfg->protover);
 	state->req_buffer[3] = MRPF_FIRST | MRPF_FLUSH;
 	state->req_buffer[3] = MRPF_FIRST | MRPF_FLUSH;
 	pk_u16le(state->req_buffer, 4, MINERGATE_MAGIC);
 	pk_u16le(state->req_buffer, 4, MINERGATE_MAGIC);
 	timer_set_delay_from_now(&thr->tv_poll, 0);
 	timer_set_delay_from_now(&thr->tv_poll, 0);
@@ -217,14 +345,15 @@ bool minergate_init(struct thr_info * const thr)
 static
 static
 bool minergate_queue_full(struct thr_info * const thr)
 bool minergate_queue_full(struct thr_info * const thr)
 {
 {
-	static const unsigned max_minergate_jobs = 300, max_requests = 100;
+	struct cgpu_info * const dev = thr->cgpu;
+	struct minergate_config * const mgcfg = dev->device_data;
 	struct minergate_state * const state = thr->cgpu_data;
 	struct minergate_state * const state = thr->cgpu_data;
 	bool qf;
 	bool qf;
 	
 	
-	if (HASH_COUNT(thr->work) + state->ready_to_queue >= max_minergate_jobs)
+	if (HASH_COUNT(thr->work) + state->ready_to_queue >= mgcfg->queue)
 		qf = true;
 		qf = true;
 	else
 	else
-	if (state->ready_to_queue >= max_requests)
+	if (state->ready_to_queue >= mgcfg->n_req_queue)
 		qf = true;
 		qf = true;
 	else
 	else
 	if (state->req_buffer[3] & MRPF_FLUSH)
 	if (state->req_buffer[3] & MRPF_FLUSH)
@@ -241,6 +370,7 @@ static
 bool minergate_queue_append(struct thr_info * const thr, struct work * const work)
 bool minergate_queue_append(struct thr_info * const thr, struct work * const work)
 {
 {
 	struct cgpu_info * const dev = thr->cgpu;
 	struct cgpu_info * const dev = thr->cgpu;
+	struct minergate_config * const mgcfg = dev->device_data;
 	struct minergate_state * const state = thr->cgpu_data;
 	struct minergate_state * const state = thr->cgpu_data;
 	
 	
 	if (minergate_queue_full(thr))
 	if (minergate_queue_full(thr))
@@ -250,6 +380,20 @@ bool minergate_queue_append(struct thr_info * const thr, struct work * const wor
 	work->tv_stamp.tv_sec = 0;
 	work->tv_stamp.tv_sec = 0;
 	
 	
 	uint8_t * const my_buf = &state->req_buffer[MINERGATE_PKT_HEADER_SZ + (MINERGATE_PKT_REQ_ITEM_SZ * state->ready_to_queue++)];
 	uint8_t * const my_buf = &state->req_buffer[MINERGATE_PKT_HEADER_SZ + (MINERGATE_PKT_REQ_ITEM_SZ * state->ready_to_queue++)];
+	
+	if (mgcfg->desired_roll)
+	{
+		struct timeval tv_now, tv_latest;
+		timer_set_now(&tv_now);
+		timer_set_delay(&tv_latest, &tv_now, mgcfg->work_duration * 1000000LL);
+		int ntimeroll = work_ntime_range(work, &tv_now, &tv_latest, mgcfg->desired_roll);
+		// NOTE: If minimum_roll bumps ntimeroll up, we may get rejects :(
+		ntimeroll = min(0xff, max(mgcfg->minimum_roll, ntimeroll));
+		pk_u8(my_buf, 0x31, ntimeroll);  // ntime limit
+	}
+	else
+		pk_u8(my_buf, 0x31, 0);  // ntime limit
+	
 	pk_u32be(my_buf,  0, work->device_id);
 	pk_u32be(my_buf,  0, work->device_id);
 	memcpy(&my_buf[   4], &work->data[0x48], 4);  // nbits
 	memcpy(&my_buf[   4], &work->data[0x48], 4);  // nbits
 	memcpy(&my_buf[   8], &work->data[0x44], 4);  // ntime
 	memcpy(&my_buf[   8], &work->data[0x44], 4);  // ntime
@@ -263,9 +407,8 @@ bool minergate_queue_append(struct thr_info * const thr, struct work * const wor
 	const uint16_t zerobits = log2(floor(work->nonce_diff * 4294967296));
 	const uint16_t zerobits = log2(floor(work->nonce_diff * 4294967296));
 	work->nonce_diff = pow(2, zerobits) / 4294967296;
 	work->nonce_diff = pow(2, zerobits) / 4294967296;
 	pk_u8(my_buf, 0x30, zerobits);
 	pk_u8(my_buf, 0x30, zerobits);
-	
-	pk_u8(my_buf, 0x31,    0);  // ntime limit
-	pk_u8(my_buf, 0x32,    0);  // ntime offset
+	// 0x31 is ntimeroll, which must be set before data ntime (in case it's changed)
+	pk_u8(my_buf, 0x32,    0);  // pv6: ntime offset ; pv30: reserved
 	pk_u8(my_buf, 0x33,    0);  // reserved
 	pk_u8(my_buf, 0x33,    0);  // reserved
 	
 	
 	struct work *oldwork;
 	struct work *oldwork;
@@ -305,17 +448,40 @@ void minergate_queue_flush(struct thr_info * const thr)
 	timer_set_delay_from_now(&thr->tv_poll, 0);
 	timer_set_delay_from_now(&thr->tv_poll, 0);
 }
 }
 
 
+static
+bool minergate_submit(struct thr_info * const thr, struct work * const work, const uint32_t nonce, const uint8_t ntime_offset, int64_t * const hashes)
+{
+	if (!nonce)
+		return false;
+	
+	if (likely(work))
+	{
+		submit_noffset_nonce(thr, work, nonce, ntime_offset);
+		
+		struct cgpu_info * const dev = thr->cgpu;
+		struct minergate_config * const mgcfg = dev->device_data;
+		if (mgcfg->desired_roll)
+			*hashes += 0x100000000 * work->nonce_diff;
+	}
+	else
+		inc_hw_errors3(thr, NULL, &nonce, 1.);
+	
+	return true;
+}
+
 static
 static
 void minergate_poll(struct thr_info * const thr)
 void minergate_poll(struct thr_info * const thr)
 {
 {
 	struct cgpu_info * const dev = thr->cgpu;
 	struct cgpu_info * const dev = thr->cgpu;
+	struct minergate_config * const mgcfg = dev->device_data;
 	struct minergate_state * const state = thr->cgpu_data;
 	struct minergate_state * const state = thr->cgpu_data;
 	const int fd = dev->device_fd;
 	const int fd = dev->device_fd;
+	uint8_t buf[mgcfg->pkt_rsp_sz];
 	
 	
 	if (opt_dev_protocol || state->ready_to_queue)
 	if (opt_dev_protocol || state->ready_to_queue)
 		applog(LOG_DEBUG, "%s: Polling with %u new jobs", dev->dev_repr, state->ready_to_queue);
 		applog(LOG_DEBUG, "%s: Polling with %u new jobs", dev->dev_repr, state->ready_to_queue);
 	pk_u16le(state->req_buffer, 6, state->ready_to_queue);
 	pk_u16le(state->req_buffer, 6, state->ready_to_queue);
-	if (MINERGATE_PKT_REQ_SZ != write(fd, state->req_buffer, MINERGATE_PKT_REQ_SZ))
+	if (mgcfg->pkt_req_sz != write(fd, state->req_buffer, mgcfg->pkt_req_sz))
 		return_via_applog(err, , LOG_ERR, "%s: write incomplete or failed", dev->dev_repr);
 		return_via_applog(err, , LOG_ERR, "%s: write incomplete or failed", dev->dev_repr);
 	
 	
 	uint8_t flags = state->req_buffer[3];
 	uint8_t flags = state->req_buffer[3];
@@ -323,11 +489,10 @@ void minergate_poll(struct thr_info * const thr)
 	state->ready_to_queue = 0;
 	state->ready_to_queue = 0;
 	thr->work_list = NULL;
 	thr->work_list = NULL;
 	
 	
-	uint8_t buf[MINERGATE_PKT_RSP_SZ];
-	if (minergate_read(fd, buf, MINERGATE_PKT_RSP_SZ) != MINERGATE_PKT_RSP_SZ)
+	if (minergate_read(fd, buf, mgcfg->pkt_rsp_sz) != mgcfg->pkt_rsp_sz)
 		return_via_applog(err, , LOG_ERR, "%s: %s failed", dev->dev_repr, "read");
 		return_via_applog(err, , LOG_ERR, "%s: %s failed", dev->dev_repr, "read");
 	
 	
-	if (upk_u8(buf, 2) != MINERGATE_PROTOCOL_VER || upk_u16le(buf, 4) != MINERGATE_MAGIC)
+	if (upk_u8(buf, 2) != mgcfg->protover || upk_u16le(buf, 4) != MINERGATE_MAGIC)
 		return_via_applog(err, , LOG_ERR, "%s: Protocol mismatch", dev->dev_repr);
 		return_via_applog(err, , LOG_ERR, "%s: Protocol mismatch", dev->dev_repr);
 	
 	
 	uint8_t *jobrsp = &buf[MINERGATE_PKT_HEADER_SZ];
 	uint8_t *jobrsp = &buf[MINERGATE_PKT_HEADER_SZ];
@@ -336,40 +501,40 @@ void minergate_poll(struct thr_info * const thr)
 	if (rsp_count || opt_dev_protocol)
 	if (rsp_count || opt_dev_protocol)
 		applog(LOG_DEBUG, "%s: Received %u job completions", dev->dev_repr, rsp_count);
 		applog(LOG_DEBUG, "%s: Received %u job completions", dev->dev_repr, rsp_count);
 	uint32_t nonce;
 	uint32_t nonce;
+	uint8_t ntime_offset;
 	int64_t hashes = 0;
 	int64_t hashes = 0;
-	for (unsigned i = 0; i < rsp_count; ++i, (jobrsp += MINERGATE_PKT_RSP_ITEM_SZ))
+	for (unsigned i = 0; i < rsp_count; ++i, (jobrsp += mgcfg->pkt_rsp_item_sz))
 	{
 	{
 		work_device_id_t jobid = upk_u32be(jobrsp, 0);
 		work_device_id_t jobid = upk_u32be(jobrsp, 0);
 		nonce = upk_u32le(jobrsp, 8);
 		nonce = upk_u32le(jobrsp, 8);
+		ntime_offset = upk_u8(jobrsp, (mgcfg->protover == MPV_SP10) ? 0x10 : 0xc);
+		
 		HASH_FIND(hh, thr->work, &jobid, sizeof(jobid), work);
 		HASH_FIND(hh, thr->work, &jobid, sizeof(jobid), work);
-		if (!work)
-		{
+		if (unlikely(!work))
 			applog(LOG_ERR, "%s: Unknown job %"PRIwdi, dev->dev_repr, jobid);
 			applog(LOG_ERR, "%s: Unknown job %"PRIwdi, dev->dev_repr, jobid);
-			if (nonce)
+		
+		if (minergate_submit(thr, work, nonce, ntime_offset, &hashes))
+		{
+			if (mgcfg->protover == MPV_SP10)
 			{
 			{
-				inc_hw_errors3(thr, NULL, &nonce, 1.);
 				nonce = upk_u32le(jobrsp, 0xc);
 				nonce = upk_u32le(jobrsp, 0xc);
-				if (nonce)
-					inc_hw_errors3(thr, NULL, &nonce, 1.);
+				minergate_submit(thr, work, nonce, ntime_offset, &hashes);
 			}
 			}
-			else
-				inc_hw_errors_only(thr);
-			continue;
 		}
 		}
-		if (nonce)
+		else
+		if (unlikely(!work))
+			// Increment HW errors even if no nonce to submit
+			inc_hw_errors_only(thr);
+		
+		const bool work_completed = (mgcfg->protover == MPV_SP10) ? (bool)work : (bool)jobrsp[0xe];
+		if (work_completed)
 		{
 		{
-			submit_nonce(thr, work, nonce);
-			
-			nonce = upk_u32be(jobrsp, 0xc);
-			if (nonce)
-				submit_nonce(thr, work, nonce);
+			HASH_DEL(thr->work, work);
+			applog(LOG_DEBUG, "%s: %s job %"PRIwdi" completed", dev->dev_repr, work->tv_stamp.tv_sec ? "Flushed" : "Active", work->device_id);
+			if ((!mgcfg->desired_roll) && !work->tv_stamp.tv_sec)
+				hashes += 0x100000000 * work->nonce_diff;
+			free_work(work);
 		}
 		}
-		
-		HASH_DEL(thr->work, work);
-		applog(LOG_DEBUG, "%s: %s job %"PRIwdi" completed", dev->dev_repr, work->tv_stamp.tv_sec ? "Flushed" : "Active", work->device_id);
-		if (!work->tv_stamp.tv_sec)
-			hashes += 100000000 * work->nonce_diff;
-		free_work(work);
 	}
 	}
 	hashes_done2(thr, hashes, NULL);
 	hashes_done2(thr, hashes, NULL);
 	
 	
@@ -396,10 +561,14 @@ static
 bool minergate_get_stats(struct cgpu_info * const dev)
 bool minergate_get_stats(struct cgpu_info * const dev)
 {
 {
 	static const int skip_stats = 1;
 	static const int skip_stats = 1;
+	struct minergate_config * const mgcfg = dev->device_data;
 	struct thr_info * const thr = dev->thr[0];
 	struct thr_info * const thr = dev->thr[0];
 	struct minergate_state * const state = thr->cgpu_data;
 	struct minergate_state * const state = thr->cgpu_data;
 	
 	
-	FILE *F = fopen(minergate_stats_file, "r");
+	if (!(mgcfg->stats_file && mgcfg->stats_file[0]))
+		return true;
+	
+	FILE *F = fopen(mgcfg->stats_file, "r");
 	char buf[0x100];
 	char buf[0x100];
 	if (F)
 	if (F)
 	{
 	{

+ 229 - 114
driver-opencl.c

@@ -260,8 +260,6 @@ load_opencl_symbols() {
 #endif
 #endif
 
 
 
 
-typedef cl_int (*queue_kernel_parameters_func_t)(_clState *, struct work *, cl_uint);
-
 struct opencl_kernel_interface {
 struct opencl_kernel_interface {
 	const char *kiname;
 	const char *kiname;
 	queue_kernel_parameters_func_t queue_kernel_parameters_func;
 	queue_kernel_parameters_func_t queue_kernel_parameters_func;
@@ -308,6 +306,10 @@ void opencl_early_init()
 		struct opencl_device_data * const data = &dataarray[i];
 		struct opencl_device_data * const data = &dataarray[i];
 		*data = (struct opencl_device_data){
 		*data = (struct opencl_device_data){
 			.dynamic = true,
 			.dynamic = true,
+			.intensity = intensity_not_set,
+#ifdef USE_SCRYPT
+			.lookup_gap = 2,
+#endif
 		};
 		};
 		gpus[i] = (struct cgpu_info){
 		gpus[i] = (struct cgpu_info){
 			.device_data = data,
 			.device_data = data,
@@ -375,8 +377,8 @@ _SET_INT_LIST(worksize, (v >= 1 && v <= 9999)       , work_size)
 
 
 #ifdef USE_SCRYPT
 #ifdef USE_SCRYPT
 _SET_INT_LIST(shaders           , true, shaders)
 _SET_INT_LIST(shaders           , true, shaders)
-_SET_INT_LIST(lookup_gap        , true, opt_lg )
-_SET_INT_LIST(thread_concurrency, true, opt_tc )
+_SET_INT_LIST(lookup_gap        , true, lookup_gap)
+_SET_INT_LIST(thread_concurrency, true, thread_concurrency)
 #endif
 #endif
 
 
 enum cl_kernels select_kernel(const char * const arg)
 enum cl_kernels select_kernel(const char * const arg)
@@ -405,20 +407,26 @@ const char *opencl_get_kernel_interface_name(const enum cl_kernels kern)
 static
 static
 bool _set_kernel(struct cgpu_info * const cgpu, const char *_val)
 bool _set_kernel(struct cgpu_info * const cgpu, const char *_val)
 {
 {
-	FILE *F;
 	struct opencl_device_data * const data = cgpu->device_data;
 	struct opencl_device_data * const data = cgpu->device_data;
 	
 	
 	size_t knamelen = strlen(_val);
 	size_t knamelen = strlen(_val);
 	char filename[knamelen + 3 + 1];
 	char filename[knamelen + 3 + 1];
 	sprintf(filename, "%s.cl", _val);
 	sprintf(filename, "%s.cl", _val);
 	
 	
-	F = opencl_open_kernel(filename);
-	if (!F)
+	int dummy_srclen;
+	enum cl_kernels interface;
+	char *src = opencl_kernel_source(filename, &dummy_srclen, &interface);
+	if (!src)
 		return false;
 		return false;
-	fclose(F);
+	free(src);
 	
 	
-	free(data->kernel_file);
-	data->kernel_file = strdup(_val);
+	char **kfp = &data->kernel_file_sha256d;
+#ifdef USE_SCRYPT
+	if (interface == KL_SCRYPT)
+		kfp = &data->kernel_file_scrypt;
+#endif
+	free(*kfp);
+	*kfp = strdup(_val);
 	
 	
 	return true;
 	return true;
 }
 }
@@ -655,22 +663,6 @@ _SET_INT_LIST(temp_overheat, (v >=     0 && v <   200), adl.overtemp )
 #endif
 #endif
 
 
 #ifdef HAVE_OPENCL
 #ifdef HAVE_OPENCL
-// SHA256d "intensity" has an artificial offset of -15
-double oclthreads_to_intensity(const unsigned long oclthreads, const bool is_sha256d)
-{
-	double intensity = log2(oclthreads);
-	if (is_sha256d)
-		intensity -= 15.;
-	return intensity;
-}
-
-unsigned long intensity_to_oclthreads(double intensity, const bool is_sha256d)
-{
-	if (is_sha256d)
-		intensity += 15;
-	return pow(2, intensity);
-}
-
 double oclthreads_to_xintensity(const unsigned long oclthreads, const cl_uint max_compute_units)
 double oclthreads_to_xintensity(const unsigned long oclthreads, const cl_uint max_compute_units)
 {
 {
 	return (double)oclthreads / (double)max_compute_units / 64.;
 	return (double)oclthreads / (double)max_compute_units / 64.;
@@ -681,10 +673,33 @@ unsigned long xintensity_to_oclthreads(const double xintensity, const cl_uint ma
 	return xintensity * max_compute_units * 0x40;
 	return xintensity * max_compute_units * 0x40;
 }
 }
 
 
+static int min_intensity, max_intensity;
+
+// NOTE: This can't be attribute-constructor because then it would race with the mining_algorithms list being populated
+static
+void opencl_calc_intensity_range()
+{
+	RUNONCE();
+	
+	min_intensity = INT_MAX;
+	max_intensity = INT_MIN;
+	struct mining_algorithm *malgo;
+	LL_FOREACH(mining_algorithms, malgo)
+	{
+		const int malgo_min_intensity = malgo->opencl_oclthreads_to_intensity(malgo->opencl_min_oclthreads);
+		const int malgo_max_intensity = malgo->opencl_oclthreads_to_intensity(malgo->opencl_max_oclthreads);
+		if (malgo_min_intensity < min_intensity)
+			min_intensity = malgo_min_intensity;
+		if (malgo_max_intensity > max_intensity)
+			max_intensity = malgo_max_intensity;
+	}
+}
+
 bool opencl_set_intensity_from_str(struct cgpu_info * const cgpu, const char *_val)
 bool opencl_set_intensity_from_str(struct cgpu_info * const cgpu, const char *_val)
 {
 {
 	struct opencl_device_data * const data = cgpu->device_data;
 	struct opencl_device_data * const data = cgpu->device_data;
 	unsigned long oclthreads = 0;
 	unsigned long oclthreads = 0;
+	float intensity = intensity_not_set;
 	bool dynamic = false;
 	bool dynamic = false;
 	
 	
 	if (!strncasecmp(_val, "d", 1))
 	if (!strncasecmp(_val, "d", 1))
@@ -713,9 +728,11 @@ bool opencl_set_intensity_from_str(struct cgpu_info * const cgpu, const char *_v
 	if (isdigit(_val[0]))
 	if (isdigit(_val[0]))
 	{
 	{
 		const double v = atof(_val);
 		const double v = atof(_val);
-		if (v < MIN_INTENSITY || v > MAX_GPU_INTENSITY)
+		opencl_calc_intensity_range();
+		if (v < min_intensity || v > max_intensity)
 			return false;
 			return false;
-		oclthreads = intensity_to_oclthreads(v, !opt_scrypt);
+		oclthreads = 1;
+		intensity = v;
 	}
 	}
 	
 	
 	// Make actual assignments after we know the values are valid
 	// Make actual assignments after we know the values are valid
@@ -723,6 +740,7 @@ bool opencl_set_intensity_from_str(struct cgpu_info * const cgpu, const char *_v
 	if (data->oclthreads)
 	if (data->oclthreads)
 	{
 	{
 		data->oclthreads = oclthreads;
 		data->oclthreads = oclthreads;
+		data->intensity = intensity;
 		pause_dynamic_threads(cgpu->device_id);
 		pause_dynamic_threads(cgpu->device_id);
 	}
 	}
 	else
 	else
@@ -804,14 +822,29 @@ struct device_drv opencl_api;
 
 
 #endif /* HAVE_OPENCL */
 #endif /* HAVE_OPENCL */
 
 
+float opencl_proc_get_intensity(struct cgpu_info * const proc, const char ** const iunit)
+{
+	struct opencl_device_data * const data = proc->device_data;
+	struct thr_info *thr = proc->thr[0];
+	const int thr_id = thr->id;
+	_clState * const clState = clStates[thr_id];
+	float intensity = data->intensity;
+	if (intensity == intensity_not_set)
+	{
+		intensity = oclthreads_to_xintensity(data->oclthreads, clState->max_compute_units);
+		*iunit = data->dynamic ? "dx" : "x";
+	}
+	else
+		*iunit = data->dynamic ? "d" : "";
+	return intensity;
+}
+
 #if defined(HAVE_OPENCL) && defined(HAVE_CURSES)
 #if defined(HAVE_OPENCL) && defined(HAVE_CURSES)
 static
 static
 void opencl_wlogprint_status(struct cgpu_info *cgpu)
 void opencl_wlogprint_status(struct cgpu_info *cgpu)
 {
 {
 	struct opencl_device_data * const data = cgpu->device_data;
 	struct opencl_device_data * const data = cgpu->device_data;
 	struct thr_info *thr = cgpu->thr[0];
 	struct thr_info *thr = cgpu->thr[0];
-	const int thr_id = thr->id;
-	_clState * const clState = clStates[thr_id];
 	int i;
 	int i;
 	char checkin[40];
 	char checkin[40];
 	double displayed_rolling;
 	double displayed_rolling;
@@ -820,16 +853,9 @@ void opencl_wlogprint_status(struct cgpu_info *cgpu)
 	strcpy(logline, ""); // In case it has no data
 	strcpy(logline, ""); // In case it has no data
 	
 	
 	{
 	{
-		double intensity = oclthreads_to_intensity(data->oclthreads, !opt_scrypt);
-		double xintensity = oclthreads_to_xintensity(data->oclthreads, clState->max_compute_units);
-		const char *iunit = "";
-		if (xintensity - (int)xintensity < intensity - (int)intensity)
-		{
-			intensity = xintensity;
-			iunit = "x";
-		}
-		tailsprintf(logline, sizeof(logline), "I:%s%s%g ",
-		            (data->dynamic ? "d" : ""),
+		const char *iunit;
+		float intensity = opencl_proc_get_intensity(cgpu, &iunit);
+		tailsprintf(logline, sizeof(logline), "I:%s%g ",
 		            iunit,
 		            iunit,
 		            intensity);
 		            intensity);
 	}
 	}
@@ -923,17 +949,12 @@ const char *opencl_tui_handle_choice(struct cgpu_info *cgpu, int input)
 	{
 	{
 		case 'i': case 'I':
 		case 'i': case 'I':
 		{
 		{
+			char promptbuf[0x40];
 			char *intvar;
 			char *intvar;
 
 
-			if (opt_scrypt) {
-				intvar = curses_input("Set GPU scan intensity (d or "
-						      MIN_SCRYPT_INTENSITY_STR " -> "
-						      MAX_SCRYPT_INTENSITY_STR ")");
-			} else {
-				intvar = curses_input("Set GPU scan intensity (d or "
-						      MIN_SHA_INTENSITY_STR " -> "
-						      MAX_SHA_INTENSITY_STR ")");
-			}
+			opencl_calc_intensity_range();
+			snprintf(promptbuf, sizeof(promptbuf), "Set GPU scan intensity (d or %d -> %d)", min_intensity, max_intensity);
+			intvar = curses_input(promptbuf);
 			if (!intvar)
 			if (!intvar)
 				return "Invalid intensity\n";
 				return "Invalid intensity\n";
 			if (!strncasecmp(intvar, "d", 1)) {
 			if (!strncasecmp(intvar, "d", 1)) {
@@ -1007,10 +1028,10 @@ struct opencl_work_data *_opencl_work_data(struct work * const work)
 }
 }
 
 
 static
 static
-cl_int queue_poclbm_kernel(_clState * const clState, struct work * const work, const cl_uint threads)
+cl_int queue_poclbm_kernel(const struct opencl_kernel_info * const kinfo, _clState * const clState, struct work * const work, const cl_uint threads)
 {
 {
 	struct opencl_work_data * const blk = _opencl_work_data(work);
 	struct opencl_work_data * const blk = _opencl_work_data(work);
-	cl_kernel *kernel = &clState->kernel;
+	const cl_kernel * const kernel = &kinfo->kernel;
 	unsigned int num = 0;
 	unsigned int num = 0;
 	cl_int status = 0;
 	cl_int status = 0;
 
 
@@ -1031,7 +1052,8 @@ cl_int queue_poclbm_kernel(_clState * const clState, struct work * const work, c
 	CL_SET_BLKARG(cty_g);
 	CL_SET_BLKARG(cty_g);
 	CL_SET_BLKARG(cty_h);
 	CL_SET_BLKARG(cty_h);
 
 
-	if (!clState->goffset) {
+	if (!kinfo->goffset)
+	{
 		cl_uint vwidth = clState->vwidth;
 		cl_uint vwidth = clState->vwidth;
 		uint *nonces = alloca(sizeof(uint) * vwidth);
 		uint *nonces = alloca(sizeof(uint) * vwidth);
 		unsigned int i;
 		unsigned int i;
@@ -1062,10 +1084,10 @@ cl_int queue_poclbm_kernel(_clState * const clState, struct work * const work, c
 }
 }
 
 
 static
 static
-cl_int queue_phatk_kernel(_clState * const clState, struct work * const work, __maybe_unused const cl_uint threads)
+cl_int queue_phatk_kernel(const struct opencl_kernel_info * const kinfo, _clState * const clState, struct work * const work, __maybe_unused const cl_uint threads)
 {
 {
 	struct opencl_work_data * const blk = _opencl_work_data(work);
 	struct opencl_work_data * const blk = _opencl_work_data(work);
-	cl_kernel *kernel = &clState->kernel;
+	const cl_kernel * const kernel = &kinfo->kernel;
 	cl_uint vwidth = clState->vwidth;
 	cl_uint vwidth = clState->vwidth;
 	unsigned int i, num = 0;
 	unsigned int i, num = 0;
 	cl_int status = 0;
 	cl_int status = 0;
@@ -1107,14 +1129,14 @@ cl_int queue_phatk_kernel(_clState * const clState, struct work * const work, __
 }
 }
 
 
 static
 static
-cl_int queue_diakgcn_kernel(_clState * const clState, struct work * const work, __maybe_unused const cl_uint threads)
+cl_int queue_diakgcn_kernel(const struct opencl_kernel_info * const kinfo, _clState * const clState, struct work * const work, __maybe_unused const cl_uint threads)
 {
 {
 	struct opencl_work_data * const blk = _opencl_work_data(work);
 	struct opencl_work_data * const blk = _opencl_work_data(work);
-	cl_kernel *kernel = &clState->kernel;
+	const cl_kernel * const kernel = &kinfo->kernel;
 	unsigned int num = 0;
 	unsigned int num = 0;
 	cl_int status = 0;
 	cl_int status = 0;
 
 
-	if (!clState->goffset) {
+	if (!kinfo->goffset) {
 		cl_uint vwidth = clState->vwidth;
 		cl_uint vwidth = clState->vwidth;
 		uint *nonces = alloca(sizeof(uint) * vwidth);
 		uint *nonces = alloca(sizeof(uint) * vwidth);
 		unsigned int i;
 		unsigned int i;
@@ -1169,14 +1191,14 @@ cl_int queue_diakgcn_kernel(_clState * const clState, struct work * const work,
 }
 }
 
 
 static
 static
-cl_int queue_diablo_kernel(_clState * const clState, struct work * const work, const cl_uint threads)
+cl_int queue_diablo_kernel(const struct opencl_kernel_info * const kinfo, _clState * const clState, struct work * const work, const cl_uint threads)
 {
 {
 	struct opencl_work_data * const blk = _opencl_work_data(work);
 	struct opencl_work_data * const blk = _opencl_work_data(work);
-	cl_kernel *kernel = &clState->kernel;
+	const cl_kernel * const kernel = &kinfo->kernel;
 	unsigned int num = 0;
 	unsigned int num = 0;
 	cl_int status = 0;
 	cl_int status = 0;
 
 
-	if (!clState->goffset) {
+	if (!kinfo->goffset) {
 		cl_uint vwidth = clState->vwidth;
 		cl_uint vwidth = clState->vwidth;
 		uint *nonces = alloca(sizeof(uint) * vwidth);
 		uint *nonces = alloca(sizeof(uint) * vwidth);
 		unsigned int i;
 		unsigned int i;
@@ -1225,10 +1247,10 @@ cl_int queue_diablo_kernel(_clState * const clState, struct work * const work, c
 
 
 #ifdef USE_SCRYPT
 #ifdef USE_SCRYPT
 static
 static
-cl_int queue_scrypt_kernel(_clState * const clState, struct work * const work, __maybe_unused const cl_uint threads)
+cl_int queue_scrypt_kernel(const struct opencl_kernel_info * const kinfo, _clState * const clState, struct work * const work, __maybe_unused const cl_uint threads)
 {
 {
 	unsigned char *midstate = work->midstate;
 	unsigned char *midstate = work->midstate;
-	cl_kernel *kernel = &clState->kernel;
+	const cl_kernel * const kernel = &kinfo->kernel;
 	unsigned int num = 0;
 	unsigned int num = 0;
 	cl_uint le_target;
 	cl_uint le_target;
 	cl_int status = 0;
 	cl_int status = 0;
@@ -1327,7 +1349,7 @@ select_cgpu:
 		//free(clState);
 		//free(clState);
 
 
 		applog(LOG_INFO, "Reinit GPU thread %d", thr_id);
 		applog(LOG_INFO, "Reinit GPU thread %d", thr_id);
-		clStates[thr_id] = initCl(virtual_gpu, name, sizeof(name));
+		clStates[thr_id] = opencl_create_clState(virtual_gpu, name, sizeof(name));
 		if (!clStates[thr_id]) {
 		if (!clStates[thr_id]) {
 			applog(LOG_ERR, "Failed to reinit GPU thread %d", thr_id);
 			applog(LOG_ERR, "Failed to reinit GPU thread %d", thr_id);
 			goto select_cgpu;
 			goto select_cgpu;
@@ -1388,13 +1410,9 @@ static int opencl_autodetect()
 	if (!nDevs)
 	if (!nDevs)
 		return 0;
 		return 0;
 
 
-	/* If opt_g_threads is not set, use default 1 thread on scrypt and
-	 * 2 for regular mining */
 	if (opt_g_threads == -1) {
 	if (opt_g_threads == -1) {
-		if (opt_scrypt)
-			opt_g_threads = 1;
-		else
-			opt_g_threads = 2;
+		// NOTE: This should ideally default to 2 for non-scrypt
+		opt_g_threads = 1;
 	}
 	}
 
 
 #ifdef HAVE_SENSORS
 #ifdef HAVE_SENSORS
@@ -1440,9 +1458,13 @@ static int opencl_autodetect()
 
 
 static void opencl_detect()
 static void opencl_detect()
 {
 {
-	int flags = 0;
-	if (!opt_scrypt)
-		flags |= GDF_DEFAULT_NOAUTO;
+	int flags = GDF_DEFAULT_NOAUTO;
+	struct mining_goal_info *goal, *tmpgoal;
+	HASH_ITER(hh, mining_goals, goal, tmpgoal)
+	{
+		if (!goal->malgo->opencl_nodefault)
+			flags &= ~GDF_DEFAULT_NOAUTO;
+	}
 	generic_detect(&opencl_api, NULL, opencl_autodetect, flags);
 	generic_detect(&opencl_api, NULL, opencl_autodetect, flags);
 }
 }
 
 
@@ -1541,8 +1563,18 @@ get_opencl_api_extra_device_status(struct cgpu_info *gpu)
 	root = api_add_int(root, "Powertune", &pt, true);
 	root = api_add_int(root, "Powertune", &pt, true);
 
 
 	char intensity[20];
 	char intensity[20];
-	uint32_t oclthreads = data->oclthreads;
-	double intensityf = oclthreads_to_intensity(oclthreads, !opt_scrypt);
+	uint32_t oclthreads;
+	double intensityf = data->intensity;
+	// FIXME: Some way to express intensities malgo-neutral?
+	struct mining_goal_info * const goal = get_mining_goal("default");
+	struct mining_algorithm * const malgo = goal->malgo;
+	if (data->intensity == intensity_not_set)
+	{
+		oclthreads = data->oclthreads;
+		intensityf = malgo->opencl_oclthreads_to_intensity(oclthreads);
+	}
+	else
+		oclthreads = malgo->opencl_intensity_to_oclthreads(intensityf);
 	double xintensity = oclthreads_to_xintensity(oclthreads, clState->max_compute_units);
 	double xintensity = oclthreads_to_xintensity(oclthreads, clState->max_compute_units);
 	if (data->dynamic)
 	if (data->dynamic)
 		strcpy(intensity, "D");
 		strcpy(intensity, "D");
@@ -1557,7 +1589,6 @@ get_opencl_api_extra_device_status(struct cgpu_info *gpu)
 }
 }
 
 
 struct opencl_thread_data {
 struct opencl_thread_data {
-	cl_int (*queue_kernel_parameters)(_clState *, struct work *, cl_uint);
 	uint32_t *res;
 	uint32_t *res;
 };
 };
 
 
@@ -1572,7 +1603,7 @@ static bool opencl_thread_prepare(struct thr_info *thr)
 	int virtual_gpu = data->virtual_gpu;
 	int virtual_gpu = data->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;
+	int buffersize = OPENCL_MAX_BUFFERSIZE;
 
 
 	if (!blank_res)
 	if (!blank_res)
 		blank_res = calloc(buffersize, 1);
 		blank_res = calloc(buffersize, 1);
@@ -1583,7 +1614,7 @@ static bool opencl_thread_prepare(struct thr_info *thr)
 
 
 	strcpy(name, "");
 	strcpy(name, "");
 	applog(LOG_INFO, "Init GPU thread %i GPU %i virtual GPU %i", i, gpu, virtual_gpu);
 	applog(LOG_INFO, "Init GPU thread %i GPU %i virtual GPU %i", i, gpu, virtual_gpu);
-	clStates[i] = initCl(virtual_gpu, name, sizeof(name));
+	clStates[i] = opencl_create_clState(virtual_gpu, name, sizeof(name));
 	if (!clStates[i]) {
 	if (!clStates[i]) {
 #ifdef HAVE_CURSES
 #ifdef HAVE_CURSES
 		if (use_curses)
 		if (use_curses)
@@ -1629,35 +1660,13 @@ 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;
+	int buffersize = OPENCL_MAX_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");
 		return false;
 		return false;
 	}
 	}
 
 
-	switch (clState->chosen_kernel) {
-		case KL_POCLBM:
-			thrdata->queue_kernel_parameters = &queue_poclbm_kernel;
-			break;
-		case KL_PHATK:
-			thrdata->queue_kernel_parameters = &queue_phatk_kernel;
-			break;
-		case KL_DIAKGCN:
-			thrdata->queue_kernel_parameters = &queue_diakgcn_kernel;
-			break;
-#ifdef USE_SCRYPT
-		case KL_SCRYPT:
-			thrdata->queue_kernel_parameters = &queue_scrypt_kernel;
-			gpu->min_nonce_diff = 1./0x10000;
-			break;
-#endif
-		default:
-		case KL_DIABLO:
-			thrdata->queue_kernel_parameters = &queue_diablo_kernel;
-			break;
-	}
-
 	thrdata->res = calloc(buffersize, 1);
 	thrdata->res = calloc(buffersize, 1);
 
 
 	if (!thrdata->res) {
 	if (!thrdata->res) {
@@ -1683,9 +1692,8 @@ static bool opencl_thread_init(struct thr_info *thr)
 
 
 static bool opencl_prepare_work(struct thr_info __maybe_unused *thr, struct work *work)
 static bool opencl_prepare_work(struct thr_info __maybe_unused *thr, struct work *work)
 {
 {
-#ifdef USE_SCRYPT
-	if (!opt_scrypt)
-#endif
+	const struct mining_algorithm * const malgo = work_mining_algorithm(work);
+	if (malgo->algo == POW_SHA256D)
 	{
 	{
 		struct opencl_work_data * const blk = _opencl_work_data(work);
 		struct opencl_work_data * const blk = _opencl_work_data(work);
 		precalc_hash(blk, (uint32_t *)(work->midstate), (uint32_t *)(work->data + 64));
 		precalc_hash(blk, (uint32_t *)(work->midstate), (uint32_t *)(work->data + 64));
@@ -1695,6 +1703,90 @@ static bool opencl_prepare_work(struct thr_info __maybe_unused *thr, struct work
 
 
 extern int opt_dynamic_interval;
 extern int opt_dynamic_interval;
 
 
+const struct opencl_kernel_info *opencl_scanhash_get_kernel(struct cgpu_info * const cgpu, _clState * const clState, const struct mining_algorithm * const malgo)
+{
+	struct opencl_device_data * const data = cgpu->device_data;
+	struct opencl_kernel_info *kernelinfo = NULL;
+	char *kernel_file;
+	switch (malgo->algo)
+	{
+		case POW_SHA256D:
+			kernelinfo = &clState->kernel_sha256d;
+			if (!data->kernel_file_sha256d)
+			{
+				const char * const vbuff = clState->platform_ver_str;
+				if (clState->is_mesa)
+				{
+					applog(LOG_INFO, "Selecting phatk kernel for Mesa");
+					data->kernel_file_sha256d = strdup("phatk");
+				}
+				else  /* Detect all 2.6 SDKs not with Tahiti and use diablo kernel */
+				if (!strstr(cgpu->name, "Tahiti") &&
+				   (strstr(vbuff, "844.4") ||  // Linux 64 bit ATI 2.6 SDK
+				    strstr(vbuff, "851.4") ||  // Windows 64 bit ""
+				    strstr(vbuff, "831.4") ||
+				    strstr(vbuff, "898.1") ||  // 12.2 driver SDK 
+				    strstr(vbuff, "923.1") ||  // 12.4
+				    strstr(vbuff, "938.2") ||  // SDK 2.7
+				    strstr(vbuff, "1113.2")))  // SDK 2.8
+				{
+					applog(LOG_INFO, "Selecting diablo kernel");
+					data->kernel_file_sha256d = strdup("diablo");
+				}
+				else  /* Detect all 7970s, older ATI and NVIDIA and use poclbm */
+				if (strstr(cgpu->name, "Tahiti") || !clState->hasBitAlign)
+				{
+					applog(LOG_INFO, "Selecting poclbm kernel");
+					data->kernel_file_sha256d = strdup("poclbm");
+				}
+				else  /* Use phatk for the rest R5xxx R6xxx */
+				{
+					applog(LOG_INFO, "Selecting phatk kernel");
+					data->kernel_file_sha256d = strdup("phatk");
+				}
+			}
+			kernel_file = data->kernel_file_sha256d;
+			break;
+#ifdef USE_SCRYPT
+		case POW_SCRYPT:
+			kernelinfo = &clState->kernel_scrypt;
+			BFGINIT(data->kernel_file_scrypt, strdup("scrypt"));
+			kernel_file = data->kernel_file_scrypt;
+			break;
+#endif
+	}
+	if (!kernelinfo)
+		applogr(NULL, LOG_ERR, "%s: Unsupported mining algorithm", cgpu->dev_repr);
+	if (!kernelinfo->loaded)
+	{
+		if (!opencl_load_kernel(cgpu, clState, cgpu->name, kernelinfo, kernel_file, malgo))
+			applogr(NULL, LOG_ERR, "%s: Failed to load kernel", cgpu->dev_repr);
+		
+		switch (kernelinfo->interface)
+		{
+			case KL_POCLBM:
+				kernelinfo->queue_kernel_parameters = &queue_poclbm_kernel;
+				break;
+			case KL_PHATK:
+				kernelinfo->queue_kernel_parameters = &queue_phatk_kernel;
+				break;
+			case KL_DIAKGCN:
+				kernelinfo->queue_kernel_parameters = &queue_diakgcn_kernel;
+				break;
+#ifdef USE_SCRYPT
+			case KL_SCRYPT:
+				kernelinfo->queue_kernel_parameters = &queue_scrypt_kernel;
+				break;
+#endif
+			default:
+			case KL_DIABLO:
+				kernelinfo->queue_kernel_parameters = &queue_diablo_kernel;
+				break;
+		}
+	}
+	return kernelinfo;
+}
+
 static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
 static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
 				int64_t __maybe_unused max_nonce)
 				int64_t __maybe_unused max_nonce)
 {
 {
@@ -1703,15 +1795,28 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
 	struct cgpu_info *gpu = thr->cgpu;
 	struct cgpu_info *gpu = thr->cgpu;
 	struct opencl_device_data * const data = gpu->device_data;
 	struct opencl_device_data * const data = gpu->device_data;
 	_clState *clState = clStates[thr_id];
 	_clState *clState = clStates[thr_id];
-	const cl_kernel *kernel = &clState->kernel;
+	const struct mining_algorithm * const malgo = work_mining_algorithm(work);
+	const struct opencl_kernel_info *kinfo = opencl_scanhash_get_kernel(gpu, clState, malgo);
+	if (!kinfo)
+		return -1;
+	const cl_kernel * const kernel = &kinfo->kernel;
 	const int dynamic_us = opt_dynamic_interval * 1000;
 	const int dynamic_us = opt_dynamic_interval * 1000;
 
 
 	cl_int status;
 	cl_int status;
 	size_t globalThreads[1];
 	size_t globalThreads[1];
-	size_t localThreads[1] = { clState->wsize };
+	size_t localThreads[1] = { kinfo->wsize };
 	int64_t hashes;
 	int64_t hashes;
-	int found = opt_scrypt ? SCRYPT_FOUND : FOUND;
-	int buffersize = opt_scrypt ? SCRYPT_BUFFERSIZE : BUFFERSIZE;
+	int found = FOUND;
+	int buffersize = BUFFERSIZE;
+#ifdef USE_SCRYPT
+	if (malgo->algo == POW_SCRYPT)
+	{
+		found = SCRYPT_FOUND;
+		buffersize = SCRYPT_BUFFERSIZE;
+	}
+#endif
+	if (data->intensity != intensity_not_set)
+		data->oclthreads = malgo->opencl_intensity_to_oclthreads(data->intensity);
 
 
 	/* Windows' timer resolution is only 15ms so oversample 5x */
 	/* Windows' timer resolution is only 15ms so oversample 5x */
 	if (data->dynamic && (++data->intervals * dynamic_us) > 70000) {
 	if (data->dynamic && (++data->intervals * dynamic_us) > 70000) {
@@ -1721,16 +1826,18 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
 		cgtime(&tv_gpuend);
 		cgtime(&tv_gpuend);
 		gpu_us = us_tdiff(&tv_gpuend, &data->tv_gpustart) / data->intervals;
 		gpu_us = us_tdiff(&tv_gpuend, &data->tv_gpustart) / data->intervals;
 		if (gpu_us > dynamic_us) {
 		if (gpu_us > dynamic_us) {
-			const unsigned long min_oclthreads = intensity_to_oclthreads(MIN_INTENSITY, !opt_scrypt);
+			const unsigned long min_oclthreads = malgo->opencl_min_oclthreads;
 			data->oclthreads /= 2;
 			data->oclthreads /= 2;
 			if (data->oclthreads < min_oclthreads)
 			if (data->oclthreads < min_oclthreads)
 				data->oclthreads = min_oclthreads;
 				data->oclthreads = min_oclthreads;
 		} else if (gpu_us < dynamic_us / 2) {
 		} else if (gpu_us < dynamic_us / 2) {
-			const unsigned long max_oclthreads = intensity_to_oclthreads(MAX_INTENSITY, !opt_scrypt);
+			const unsigned long max_oclthreads = malgo->opencl_max_oclthreads;
 			data->oclthreads *= 2;
 			data->oclthreads *= 2;
 			if (data->oclthreads > max_oclthreads)
 			if (data->oclthreads > max_oclthreads)
 				data->oclthreads = max_oclthreads;
 				data->oclthreads = max_oclthreads;
 		}
 		}
+		if (data->intensity != intensity_not_set)
+			data->intensity = malgo->opencl_oclthreads_to_intensity(data->oclthreads);
 		memcpy(&(data->tv_gpustart), &tv_gpuend, sizeof(struct timeval));
 		memcpy(&(data->tv_gpustart), &tv_gpuend, sizeof(struct timeval));
 		data->intervals = 0;
 		data->intervals = 0;
 	}
 	}
@@ -1744,13 +1851,14 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
 	if (hashes > gpu->max_hashes)
 	if (hashes > gpu->max_hashes)
 		gpu->max_hashes = hashes;
 		gpu->max_hashes = hashes;
 
 
-	status = thrdata->queue_kernel_parameters(clState, work, globalThreads[0]);
+	status = kinfo->queue_kernel_parameters(kinfo, clState, work, globalThreads[0]);
 	if (unlikely(status != CL_SUCCESS)) {
 	if (unlikely(status != CL_SUCCESS)) {
 		applog(LOG_ERR, "Error: clSetKernelArg of all params failed.");
 		applog(LOG_ERR, "Error: clSetKernelArg of all params failed.");
 		return -1;
 		return -1;
 	}
 	}
 
 
-	if (clState->goffset) {
+	if (kinfo->goffset)
+	{
 		size_t global_work_offset[1];
 		size_t global_work_offset[1];
 
 
 		global_work_offset[0] = work->blk.nonce;
 		global_work_offset[0] = work->blk.nonce;
@@ -1798,13 +1906,20 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
 	return hashes;
 	return hashes;
 }
 }
 
 
+static
+void opencl_clean_kernel_info(struct opencl_kernel_info * const kinfo)
+{
+	clReleaseKernel(kinfo->kernel);
+	clReleaseProgram(kinfo->program);
+}
+
 static void opencl_thread_shutdown(struct thr_info *thr)
 static void opencl_thread_shutdown(struct thr_info *thr)
 {
 {
 	const int thr_id = thr->id;
 	const int thr_id = thr->id;
 	_clState *clState = clStates[thr_id];
 	_clState *clState = clStates[thr_id];
 
 
-	clReleaseKernel(clState->kernel);
-	clReleaseProgram(clState->program);
+	opencl_clean_kernel_info(&clState->kernel_sha256d);
+	opencl_clean_kernel_info(&clState->kernel_scrypt);
 	clReleaseCommandQueue(clState->commandQueue);
 	clReleaseCommandQueue(clState->commandQueue);
 	clReleaseContext(clState->context);
 	clReleaseContext(clState->context);
 }
 }
@@ -1869,7 +1984,7 @@ struct device_drv opencl_api = {
 	.dname = "opencl",
 	.dname = "opencl",
 	.name = "OCL",
 	.name = "OCL",
 	.probe_priority = 110,
 	.probe_priority = 110,
-	.supported_algos = POW_SHA256D | POW_SCRYPT,
+	.drv_min_nonce_diff = common_sha256d_and_scrypt_min_nonce_diff,
 	.drv_detect = opencl_detect,
 	.drv_detect = opencl_detect,
 	.reinit_device = reinit_opencl_device,
 	.reinit_device = reinit_opencl_device,
 	.watchdog = opencl_watchdog,
 	.watchdog = opencl_watchdog,

+ 9 - 5
driver-opencl.h

@@ -1,6 +1,7 @@
 #ifndef BFG_DRIVER_OPENCL
 #ifndef BFG_DRIVER_OPENCL
 #define BFG_DRIVER_OPENCL
 #define BFG_DRIVER_OPENCL
 
 
+#include <float.h>
 #include <stdbool.h>
 #include <stdbool.h>
 
 
 #include "CL/cl.h"
 #include "CL/cl.h"
@@ -18,23 +19,27 @@ enum opencl_binary_usage {
 	OBU_NONE     = 4,
 	OBU_NONE     = 4,
 };
 };
 
 
+static const float intensity_not_set = FLT_MAX;
+
 struct opencl_device_data {
 struct opencl_device_data {
 	bool mapped;
 	bool mapped;
 	int virtual_gpu;
 	int virtual_gpu;
 	int virtual_adl;
 	int virtual_adl;
 	unsigned long oclthreads;
 	unsigned long oclthreads;
+	float intensity;
 	char *_init_intensity;
 	char *_init_intensity;
 	bool dynamic;
 	bool dynamic;
 	
 	
 	cl_uint vwidth;
 	cl_uint vwidth;
 	size_t work_size;
 	size_t work_size;
-	char *kernel_file;
+	char *kernel_file_sha256d;
 	cl_ulong max_alloc;
 	cl_ulong max_alloc;
 	
 	
 	enum opencl_binary_usage opt_opencl_binaries;
 	enum opencl_binary_usage opt_opencl_binaries;
 #ifdef USE_SCRYPT
 #ifdef USE_SCRYPT
-	int opt_lg, lookup_gap;
-	size_t opt_tc, thread_concurrency;
+	char *kernel_file_scrypt;
+	int lookup_gap;
+	size_t thread_concurrency;
 	size_t shaders;
 	size_t shaders;
 #endif
 #endif
 	struct timeval tv_gpustart;
 	struct timeval tv_gpustart;
@@ -59,8 +64,7 @@ struct opencl_device_data {
 #endif
 #endif
 };
 };
 
 
-extern double oclthreads_to_intensity(unsigned long oclthreads, bool is_sha256d);
-extern unsigned long intensity_to_oclthreads(double intensity, bool is_sha256d);
+extern float opencl_proc_get_intensity(struct cgpu_info *, const char **iunit);
 extern unsigned long xintensity_to_oclthreads(double xintensity, cl_uint max_compute_units);
 extern unsigned long xintensity_to_oclthreads(double xintensity, cl_uint max_compute_units);
 extern bool opencl_set_intensity_from_str(struct cgpu_info *, const char *newvalue);
 extern bool opencl_set_intensity_from_str(struct cgpu_info *, const char *newvalue);
 
 

+ 13 - 4
driver-proxy.c

@@ -70,6 +70,12 @@ void *prune_worklog_thread(void *userdata)
 	return NULL;
 	return NULL;
 }
 }
 
 
+static
+float proxy_min_nonce_diff(struct cgpu_info * const proc, const struct mining_algorithm * const malgo)
+{
+	return minimum_pdiff;
+}
+
 static
 static
 void proxy_first_client(struct cgpu_info *cgpu)
 void proxy_first_client(struct cgpu_info *cgpu)
 {
 {
@@ -99,7 +105,6 @@ struct proxy_client *proxy_find_or_create_client(const char *username)
 			.threads = 0,
 			.threads = 0,
 			.device_data = client,
 			.device_data = client,
 			.device_path = user,
 			.device_path = user,
-			.min_nonce_diff = (opt_scrypt ? (1./0x10000) : 1.),
 		};
 		};
 		timer_set_now(&cgpu->cgminer_stats.start_tv);
 		timer_set_now(&cgpu->cgminer_stats.start_tv);
 		if (unlikely(!create_new_cgpus(add_cgpu_live, cgpu)))
 		if (unlikely(!create_new_cgpus(add_cgpu_live, cgpu)))
@@ -112,7 +117,7 @@ struct proxy_client *proxy_find_or_create_client(const char *username)
 		*client = (struct proxy_client){
 		*client = (struct proxy_client){
 			.username = user,
 			.username = user,
 			.cgpu = cgpu,
 			.cgpu = cgpu,
-			.desired_share_pdiff = opt_scrypt ? (1./0x10000) : 1.,
+			.desired_share_pdiff = 0.,
 		};
 		};
 		
 		
 		b = HASH_COUNT(proxy_clients);
 		b = HASH_COUNT(proxy_clients);
@@ -133,14 +138,17 @@ struct proxy_client *proxy_find_or_create_client(const char *username)
 	return client;
 	return client;
 }
 }
 
 
+// See also, stratumsrv_init_diff in driver-stratum.c
 static
 static
 const char *proxy_set_diff(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const success)
 const char *proxy_set_diff(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const success)
 {
 {
 	struct proxy_client * const client = proc->device_data;
 	struct proxy_client * const client = proc->device_data;
-	const double nv = atof(newvalue);
-	if (nv <= 0)
+	double nv = atof(newvalue);
+	if (nv < 0)
 		return "Invalid difficulty";
 		return "Invalid difficulty";
 	
 	
+	if (nv <= minimum_pdiff)
+		nv = minimum_pdiff;
 	client->desired_share_pdiff = nv;
 	client->desired_share_pdiff = nv;
 	
 	
 #ifdef USE_LIBEVENT
 #ifdef USE_LIBEVENT
@@ -167,6 +175,7 @@ static const struct bfg_set_device_definition proxy_set_device_funcs[] = {
 struct device_drv proxy_drv = {
 struct device_drv proxy_drv = {
 	.dname = "proxy",
 	.dname = "proxy",
 	.name = "PXY",
 	.name = "PXY",
+	.drv_min_nonce_diff = proxy_min_nonce_diff,
 #ifdef HAVE_CURSES
 #ifdef HAVE_CURSES
 	.proc_wlogprint_status = proxy_wlogprint_status,
 	.proc_wlogprint_status = proxy_wlogprint_status,
 #endif
 #endif

+ 136 - 24
driver-stratum.c

@@ -15,6 +15,7 @@
 #include <winsock2.h>
 #include <winsock2.h>
 #endif
 #endif
 
 
+#include <float.h>
 #include <stdbool.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdint.h>
 #include <string.h>
 #include <string.h>
@@ -34,8 +35,8 @@
 
 
 #define _ssm_client_octets     work2d_xnonce1sz
 #define _ssm_client_octets     work2d_xnonce1sz
 #define _ssm_client_xnonce2sz  work2d_xnonce2sz
 #define _ssm_client_xnonce2sz  work2d_xnonce2sz
-static char *_ssm_notify;
-static int _ssm_notify_sz;
+static char *_ssm_notify, *_ssm_setgoal;
+static int _ssm_notify_sz, _ssm_setgoal_sz;
 static struct stratumsrv_job *_ssm_last_ssj;
 static struct stratumsrv_job *_ssm_last_ssj;
 static struct event *ev_notify;
 static struct event *ev_notify;
 static notifier_t _ssm_update_notifier;
 static notifier_t _ssm_update_notifier;
@@ -65,12 +66,21 @@ struct stratumsrv_conn_userlist {
 	struct stratumsrv_conn_userlist *next;
 	struct stratumsrv_conn_userlist *next;
 };
 };
 
 
+enum stratumsrv_conn_capability {
+	SCC_NOTIFY    = 1 << 0,
+	SCC_SET_DIFF  = 1 << 1,
+	SCC_SET_GOAL  = 1 << 2,
+};
+typedef uint8_t stratumsrv_conn_capabilities_t;
+
 struct stratumsrv_conn {
 struct stratumsrv_conn {
 	struct bufferevent *bev;
 	struct bufferevent *bev;
+	stratumsrv_conn_capabilities_t capabilities;
 	uint32_t xnonce1_le;
 	uint32_t xnonce1_le;
 	struct timeval tv_hashes_done;
 	struct timeval tv_hashes_done;
 	bool hashes_done_ext;
 	bool hashes_done_ext;
 	float current_share_pdiff;
 	float current_share_pdiff;
+	bool desired_default_share_pdiff;  // Set if any authenticated user is configured for the default
 	float desired_share_pdiff;
 	float desired_share_pdiff;
 	struct stratumsrv_conn_userlist *authorised_users;
 	struct stratumsrv_conn_userlist *authorised_users;
 	
 	
@@ -93,6 +103,15 @@ void stratumsrv_send_set_difficulty(struct stratumsrv_conn * const conn, const f
 
 
 #define _ssm_gen_dummy_work work2d_gen_dummy_work
 #define _ssm_gen_dummy_work work2d_gen_dummy_work
 
 
+static
+float stratumsrv_choose_share_pdiff(const struct stratumsrv_conn * const conn, const struct mining_algorithm * const malgo)
+{
+	float conn_pdiff = conn->desired_share_pdiff;
+	if (conn->desired_default_share_pdiff && malgo->reasonable_low_nonce_diff < conn_pdiff)
+		conn_pdiff = malgo->reasonable_low_nonce_diff;
+	return conn_pdiff;
+}
+
 static
 static
 bool stratumsrv_update_notify_str(struct pool * const pool, bool clean)
 bool stratumsrv_update_notify_str(struct pool * const pool, bool clean)
 {
 {
@@ -145,6 +164,10 @@ bool stratumsrv_update_notify_str(struct pool * const pool, bool clean)
 	bin2hex(ntime, &ntime_n, 4);
 	bin2hex(ntime, &ntime_n, 4);
 	p += sprintf(p, "],\"%s\",\"%s\",\"%s\",%s],\"method\":\"mining.notify\",\"id\":null}\n", version, nbits, ntime, clean ? "true" : "false");
 	p += sprintf(p, "],\"%s\",\"%s\",\"%s\",%s],\"method\":\"mining.notify\",\"id\":null}\n", version, nbits, ntime, clean ? "true" : "false");
 	
 	
+	const size_t setgoalbufsz = 49 + strlen(pool->goal->name) + (pool->goalname ? (1 + strlen(pool->goalname)) : 0) + 12 + strlen(pool->goal->malgo->name) + 5 + 1;
+	char * const setgoalbuf = malloc(setgoalbufsz);
+	snprintf(setgoalbuf, setgoalbufsz, "{\"method\":\"mining.set_goal\",\"id\":null,\"params\":[\"%s%s%s\",{\"malgo\":\"%s\"}]}\n", pool->goal->name, pool->goalname ? "/" : "", pool->goalname ?: "", pool->goal->malgo->name);
+	
 	ssj = malloc(sizeof(*ssj));
 	ssj = malloc(sizeof(*ssj));
 	*ssj = (struct stratumsrv_job){
 	*ssj = (struct stratumsrv_job){
 		.my_job_id = strdup(my_job_id),
 		.my_job_id = strdup(my_job_id),
@@ -165,20 +188,37 @@ bool stratumsrv_update_notify_str(struct pool * const pool, bool clean)
 	assert(_ssm_notify_sz <= bufsz);
 	assert(_ssm_notify_sz <= bufsz);
 	free(_ssm_notify);
 	free(_ssm_notify);
 	_ssm_notify = buf;
 	_ssm_notify = buf;
+	const bool setgoal_changed = _ssm_setgoal ? strcmp(setgoalbuf, _ssm_setgoal) : true;
+	if (setgoal_changed)
+	{
+		free(_ssm_setgoal);
+		_ssm_setgoal = setgoalbuf;
+		_ssm_setgoal_sz = setgoalbufsz - 1;
+	}
+	else
+		free(setgoalbuf);
 	_ssm_last_ssj = ssj;
 	_ssm_last_ssj = ssj;
 	
 	
 	float pdiff = target_diff(ssj->swork.target);
 	float pdiff = target_diff(ssj->swork.target);
+	const struct mining_goal_info * const goal = pool->goal;
+	const struct mining_algorithm * const malgo = goal->malgo;
 	LL_FOREACH(_ssm_connections, conn)
 	LL_FOREACH(_ssm_connections, conn)
 	{
 	{
 		if (unlikely(!conn->xnonce1_le))
 		if (unlikely(!conn->xnonce1_le))
 			continue;
 			continue;
-		float conn_pdiff = conn->desired_share_pdiff;
-		if (pdiff < conn_pdiff)
-			conn_pdiff = pdiff;
-		ssj->job_pdiff[conn->xnonce1_le] = conn_pdiff;
-		if (conn_pdiff != conn->current_share_pdiff)
-			stratumsrv_send_set_difficulty(conn, conn_pdiff);
-		bufferevent_write(conn->bev, _ssm_notify, _ssm_notify_sz);
+		if (setgoal_changed && (conn->capabilities & SCC_SET_GOAL))
+			bufferevent_write(conn->bev, setgoalbuf, setgoalbufsz);
+		if (likely(conn->capabilities & SCC_SET_DIFF))
+		{
+			float conn_pdiff = stratumsrv_choose_share_pdiff(conn, malgo);
+			if (pdiff < conn_pdiff)
+				conn_pdiff = pdiff;
+			ssj->job_pdiff[conn->xnonce1_le] = conn_pdiff;
+			if (conn_pdiff != conn->current_share_pdiff)
+				stratumsrv_send_set_difficulty(conn, conn_pdiff);
+		}
+		if (likely(conn->capabilities & SCC_NOTIFY))
+			bufferevent_write(conn->bev, _ssm_notify, _ssm_notify_sz);
 	}
 	}
 	
 	
 	return true;
 	return true;
@@ -195,15 +235,21 @@ void stratumsrv_client_changed_diff(struct proxy_client * const client)
 		++connections_affected;
 		++connections_affected;
 		
 		
 		float desired_share_pdiff = client->desired_share_pdiff;
 		float desired_share_pdiff = client->desired_share_pdiff;
+		bool any_default_share_pdiff = !desired_share_pdiff;
 		LL_FOREACH(conn->authorised_users, ule2)
 		LL_FOREACH(conn->authorised_users, ule2)
 		{
 		{
 			struct proxy_client * const other_client = ule2->client;
 			struct proxy_client * const other_client = ule2->client;
+			if (!other_client->desired_share_pdiff)
+				any_default_share_pdiff = true;
+			else
 			if (other_client->desired_share_pdiff < desired_share_pdiff)
 			if (other_client->desired_share_pdiff < desired_share_pdiff)
 				desired_share_pdiff = other_client->desired_share_pdiff;
 				desired_share_pdiff = other_client->desired_share_pdiff;
 		}
 		}
-		if (conn->desired_share_pdiff != desired_share_pdiff)
+		BFGINIT(desired_share_pdiff, FLT_MAX);
+		if (conn->desired_share_pdiff != desired_share_pdiff || conn->desired_default_share_pdiff != any_default_share_pdiff)
 		{
 		{
 			conn->desired_share_pdiff = desired_share_pdiff;
 			conn->desired_share_pdiff = desired_share_pdiff;
+			conn->desired_default_share_pdiff = any_default_share_pdiff;
 			++connections_changed;
 			++connections_changed;
 		}
 		}
 	}
 	}
@@ -369,18 +415,55 @@ void _stratumsrv_failure(struct bufferevent * const bev, const char * const idst
 }while(0)
 }while(0)
 
 
 static
 static
-void _stratumsrv_success(struct bufferevent * const bev, const char * const idstr)
+void stratumsrv_success2(struct bufferevent * const bev, const char * const idstr, const char * const resultstr)
 {
 {
 	if (!idstr)
 	if (!idstr)
 		return;
 		return;
 	
 	
-	size_t bufsz = 36 + strlen(idstr);
+	size_t bufsz = 32 + strlen(resultstr) + strlen(idstr);
 	char buf[bufsz];
 	char buf[bufsz];
 	
 	
-	bufsz = sprintf(buf, "{\"result\":true,\"id\":%s,\"error\":null}\n", idstr);
+	bufsz = sprintf(buf, "{\"result\":%s,\"id\":%s,\"error\":null}\n", resultstr, idstr);
 	bufferevent_write(bev, buf, bufsz);
 	bufferevent_write(bev, buf, bufsz);
 }
 }
 
 
+static inline
+void _stratumsrv_success(struct bufferevent * const bev, const char * const idstr)
+{
+	stratumsrv_success2(bev, idstr, "true");
+}
+
+static
+void stratumsrv_mining_capabilities(struct bufferevent * const bev, json_t * const params, const char * const idstr, struct stratumsrv_conn * const conn)
+{
+	if (json_is_null(params) || (!json_is_array(params)))
+		return_stratumsrv_failure(20, "Bad params");
+	
+	conn->capabilities = 0;
+	
+	json_t * const caps = (json_array_size(params) < 1) ? NULL : json_array_get(params, 0);
+	if (caps && (!json_is_null(caps)) && json_is_array(caps))
+	{
+		for (size_t i = json_array_size(caps); i-- > 0; )
+		{
+			json_t * const j = json_array_get(caps, i);
+			if (!json_is_string(j))
+				continue;
+			const char * const s = json_string_value(j);
+			if (!strcasecmp(s, "notify"))
+				conn->capabilities |= SCC_NOTIFY;
+			else
+			if (!strcasecmp(s, "set_difficulty"))
+				conn->capabilities |= SCC_SET_DIFF;
+			else
+			if (!strcasecmp(s, "set_goal"))
+				conn->capabilities |= SCC_SET_GOAL;
+		}
+	}
+	
+	stratumsrv_success2(bev, idstr, "null");
+}
+
 static
 static
 void stratumsrv_mining_subscribe(struct bufferevent * const bev, json_t * const params, const char * const idstr, struct stratumsrv_conn * const conn)
 void stratumsrv_mining_subscribe(struct bufferevent * const bev, json_t * const params, const char * const idstr, struct stratumsrv_conn * const conn)
 {
 {
@@ -407,12 +490,22 @@ void stratumsrv_mining_subscribe(struct bufferevent * const bev, json_t * const
 	bufsz = sprintf(buf, "{\"id\":%s,\"result\":[[[\"mining.set_difficulty\",\"x\"],[\"mining.notify\",\"%s\"]],\"%s\",%d],\"error\":null}\n", idstr, xnonce1x, xnonce1x, _ssm_client_xnonce2sz);
 	bufsz = sprintf(buf, "{\"id\":%s,\"result\":[[[\"mining.set_difficulty\",\"x\"],[\"mining.notify\",\"%s\"]],\"%s\",%d],\"error\":null}\n", idstr, xnonce1x, xnonce1x, _ssm_client_xnonce2sz);
 	bufferevent_write(bev, buf, bufsz);
 	bufferevent_write(bev, buf, bufsz);
 	
 	
-	float pdiff = target_diff(_ssm_last_ssj->swork.target);
-	if (pdiff > conn->desired_share_pdiff)
-		pdiff = conn->desired_share_pdiff;
-	_ssm_last_ssj->job_pdiff[*xnonce1_p] = pdiff;
-	stratumsrv_send_set_difficulty(conn, pdiff);
-	bufferevent_write(bev, _ssm_notify, _ssm_notify_sz);
+	if (conn->capabilities & SCC_SET_GOAL)
+		bufferevent_write(conn->bev, _ssm_setgoal, _ssm_setgoal_sz);
+	if (likely(conn->capabilities & SCC_SET_DIFF))
+	{
+		const struct pool * const pool = _ssm_last_ssj->swork.pool;
+		const struct mining_goal_info * const goal = pool->goal;
+		const struct mining_algorithm * const malgo = goal->malgo;
+		float pdiff = target_diff(_ssm_last_ssj->swork.target);
+		const float conn_pdiff = stratumsrv_choose_share_pdiff(conn, malgo);
+		if (pdiff > conn_pdiff)
+			pdiff = conn_pdiff;
+		_ssm_last_ssj->job_pdiff[*xnonce1_p] = pdiff;
+		stratumsrv_send_set_difficulty(conn, pdiff);
+	}
+	if (likely(conn->capabilities & SCC_NOTIFY))
+		bufferevent_write(bev, _ssm_notify, _ssm_notify_sz);
 }
 }
 
 
 static
 static
@@ -427,8 +520,19 @@ void stratumsrv_mining_authorize(struct bufferevent * const bev, json_t * const
 	if (unlikely(!client))
 	if (unlikely(!client))
 		return_stratumsrv_failure(20, "Failed creating new cgpu");
 		return_stratumsrv_failure(20, "Failed creating new cgpu");
 	
 	
-	if ((!conn->authorised_users) || client->desired_share_pdiff < conn->desired_share_pdiff)
-		conn->desired_share_pdiff = client->desired_share_pdiff;
+	if (client->desired_share_pdiff)
+	{
+		if (!conn->authorised_users)
+			conn->desired_default_share_pdiff = false;
+		if ((!conn->authorised_users) || client->desired_share_pdiff < conn->desired_share_pdiff)
+			conn->desired_share_pdiff = client->desired_share_pdiff;
+	}
+	else
+	{
+		conn->desired_default_share_pdiff = true;
+		if (!conn->authorised_users)
+			conn->desired_share_pdiff = FLT_MAX;
+	}
 	
 	
 	struct stratumsrv_conn_userlist *ule = malloc(sizeof(*ule));
 	struct stratumsrv_conn_userlist *ule = malloc(sizeof(*ule));
 	*ule = (struct stratumsrv_conn_userlist){
 	*ule = (struct stratumsrv_conn_userlist){
@@ -585,6 +689,9 @@ errout:
 	else
 	else
 	if (!strcasecmp(method, "mining.subscribe"))
 	if (!strcasecmp(method, "mining.subscribe"))
 		stratumsrv_mining_subscribe(bev, params, idstr, conn);
 		stratumsrv_mining_subscribe(bev, params, idstr, conn);
+	else
+	if (!strcasecmp(method, "mining.capabilities"))
+		stratumsrv_mining_capabilities(bev, params, idstr, conn);
 	else
 	else
 		_stratumsrv_failure(bev, idstr, -3, "Method not supported");
 		_stratumsrv_failure(bev, idstr, -3, "Method not supported");
 	
 	
@@ -644,15 +751,18 @@ void stratumsrv_event(struct bufferevent *bev, short events, void *p)
 	}
 	}
 }
 }
 
 
+// See also, proxy_set_diff in driver-proxy.c
 static
 static
 const char *stratumsrv_init_diff(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const success)
 const char *stratumsrv_init_diff(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const success)
 {
 {
 	struct stratumsrv_conn * const conn = proc->device_data;
 	struct stratumsrv_conn * const conn = proc->device_data;
 	
 	
-	const double nv = atof(newvalue);
-	if (nv <= 0)
+	double nv = atof(newvalue);
+	if (nv < 0)
 		return "Invalid difficulty";
 		return "Invalid difficulty";
 	
 	
+	if (nv <= minimum_pdiff)
+		nv = minimum_pdiff;
 	conn->desired_share_pdiff = nv;
 	conn->desired_share_pdiff = nv;
 	
 	
 	return NULL;
 	return NULL;
@@ -672,7 +782,9 @@ void stratumlistener(struct evconnlistener *listener, evutil_socket_t sock, stru
 	conn = malloc(sizeof(*conn));
 	conn = malloc(sizeof(*conn));
 	*conn = (struct stratumsrv_conn){
 	*conn = (struct stratumsrv_conn){
 		.bev = bev,
 		.bev = bev,
-		.desired_share_pdiff = opt_scrypt ? (1./0x10000) : 1.,
+		.capabilities = SCC_NOTIFY | SCC_SET_DIFF,
+		.desired_share_pdiff = FLT_MAX,
+		.desired_default_share_pdiff = true,
 	};
 	};
 	drv_set_defaults(&proxy_drv, stratumsrv_set_device_funcs_newconnect, conn, NULL, NULL, 1);
 	drv_set_defaults(&proxy_drv, stratumsrv_set_device_funcs_newconnect, conn, NULL, NULL, 1);
 	LL_PREPEND(_ssm_connections, conn);
 	LL_PREPEND(_ssm_connections, conn);

+ 99 - 84
driver-titan.c

@@ -85,6 +85,8 @@ struct knc_titan_info {
 	struct cgpu_info *cgpu;
 	struct cgpu_info *cgpu;
 	int cores;
 	int cores;
 	struct knc_titan_die dies[KNC_TITAN_MAX_ASICS][KNC_TITAN_DIES_PER_ASIC];
 	struct knc_titan_die dies[KNC_TITAN_MAX_ASICS][KNC_TITAN_DIES_PER_ASIC];
+	bool asic_served_by_fpga[KNC_TITAN_MAX_ASICS];
+	struct timeval tv_prev;
 
 
 	struct work *workqueue;
 	struct work *workqueue;
 	int workqueue_size;
 	int workqueue_size;
@@ -209,7 +211,7 @@ static void knc_titan_clean_flush(const char *repr, void * const ctx, int asic,
 	knc_titan_set_work(repr, ctx, asic, die, core, 0, NULL, true, &unused, &report);
 	knc_titan_set_work(repr, ctx, asic, die, core, 0, NULL, true, &unused, &report);
 }
 }
 
 
-static uint32_t nonce_tops[KNC_TITAN_DIES_PER_ASIC][KNC_TITAN_CORES_PER_DIE];
+static uint32_t nonce_tops[KNC_TITAN_CORES_PER_DIE];
 static bool nonce_tops_inited = false;
 static bool nonce_tops_inited = false;
 
 
 static void get_nonce_range(int dieno, int coreno, uint32_t *nonce_bottom, uint32_t *nonce_top)
 static void get_nonce_range(int dieno, int coreno, uint32_t *nonce_bottom, uint32_t *nonce_top)
@@ -217,33 +219,28 @@ static void get_nonce_range(int dieno, int coreno, uint32_t *nonce_bottom, uint3
 	if (!nonce_tops_inited) {
 	if (!nonce_tops_inited) {
 		uint32_t top;
 		uint32_t top;
 		double nonce_f, nonce_step;
 		double nonce_f, nonce_step;
-		int die, core;
+		int core;
 
 
 		nonce_f = 0.0;
 		nonce_f = 0.0;
-		nonce_step = 4294967296.0 / KNC_TITAN_CORES_PER_ASIC;
-
-		for (die = 0; die < KNC_TITAN_DIES_PER_ASIC; ++die) {
-			for (core = 0; core < KNC_TITAN_CORES_PER_DIE; ++core) {
-				nonce_f += nonce_step;
-				if ((core < (KNC_TITAN_CORES_PER_DIE - 1)) || (die < (KNC_TITAN_DIES_PER_ASIC - 1)))
-					top = nonce_f;
-				else
-					top = 0xFFFFFFFF;
-				nonce_tops[die][core] = top;
-			}
+		nonce_step = 4294967296.0 / KNC_TITAN_CORES_PER_DIE;
+
+		for (core = 0; core < KNC_TITAN_CORES_PER_DIE; ++core) {
+			nonce_f += nonce_step;
+			if (core < (KNC_TITAN_CORES_PER_DIE - 1))
+				top = nonce_f;
+			else
+				top = 0xFFFFFFFF;
+			nonce_tops[core] = top;
 		}
 		}
 
 
 		nonce_tops_inited = true;
 		nonce_tops_inited = true;
 	}
 	}
 
 
-	*nonce_top = nonce_tops[dieno][coreno];
+	*nonce_top = nonce_tops[coreno];
 	if (coreno > 0) {
 	if (coreno > 0) {
-		*nonce_bottom = nonce_tops[dieno][coreno - 1] + 1;
+		*nonce_bottom = nonce_tops[coreno - 1] + 1;
 		return;
 		return;
 	}
 	}
-	if (dieno > 0) {
-		*nonce_bottom = nonce_tops[dieno - 1][KNC_TITAN_CORES_PER_DIE - 1] + 1;
-	}
 	*nonce_bottom = 0;
 	*nonce_bottom = 0;
 }
 }
 
 
@@ -278,6 +275,7 @@ static bool configure_one_die(struct knc_titan_info *knc, int asic, int die)
 
 
 	first_proc = die_p->first_proc;
 	first_proc = die_p->first_proc;
 	repr = first_proc->device->dev_repr;
 	repr = first_proc->device->dev_repr;
+	bool success = true;
 	for (proc = first_proc; proc; proc = proc->next_proc) {
 	for (proc = first_proc; proc; proc = proc->next_proc) {
 		mythr = proc->thr[0];
 		mythr = proc->thr[0];
 		knccore = mythr->cgpu_data;
 		knccore = mythr->cgpu_data;
@@ -286,9 +284,10 @@ static bool configure_one_die(struct knc_titan_info *knc, int asic, int die)
 		knc_titan_clean_flush(repr, knc->ctx, knccore->asicno, knccore->dieno, knccore->coreno);
 		knc_titan_clean_flush(repr, knc->ctx, knccore->asicno, knccore->dieno, knccore->coreno);
 		get_nonce_range(knccore->dieno, knccore->coreno, &setup_params.nonce_bottom, &setup_params.nonce_top);
 		get_nonce_range(knccore->dieno, knccore->coreno, &setup_params.nonce_bottom, &setup_params.nonce_top);
 		applog(LOG_DEBUG, "%s[%d:%d:%d]: Setup core, nonces 0x%08X - 0x%08X", repr, knccore->asicno, knccore->dieno, knccore->coreno, setup_params.nonce_bottom, setup_params.nonce_top);
 		applog(LOG_DEBUG, "%s[%d:%d:%d]: Setup core, nonces 0x%08X - 0x%08X", repr, knccore->asicno, knccore->dieno, knccore->coreno, setup_params.nonce_bottom, setup_params.nonce_top);
-		knc_titan_setup_core_local(repr, knc->ctx, knccore->asicno, knccore->dieno, knccore->coreno, &setup_params);
+		if (!knc_titan_setup_core_local(repr, knc->ctx, knccore->asicno, knccore->dieno, knccore->coreno, &setup_params))
+			success = false;
 	}
 	}
-	applog(LOG_NOTICE, "%s[%d-%d] Die configured", repr, asic, die);
+	applog(LOG_NOTICE, "%s[%d-%d] Die configur%s", repr, asic, die, success ? "ed successfully" : "ation failed");
 	die_p->need_flush = true;
 	die_p->need_flush = true;
 	timer_set_now(&(die_p->last_share));
 	timer_set_now(&(die_p->last_share));
 	die_p->broadcast_flushes = false;
 	die_p->broadcast_flushes = false;
@@ -296,6 +295,12 @@ static bool configure_one_die(struct knc_titan_info *knc, int asic, int die)
 	return true;
 	return true;
 }
 }
 
 
+static
+float titan_min_nonce_diff(struct cgpu_info * const proc, const struct mining_algorithm * const malgo)
+{
+	return (malgo->algo == POW_SCRYPT) ? DEFAULT_DIFF_FILTERING_FLOAT : -1.;
+}
+
 static bool knc_titan_init(struct thr_info * const thr)
 static bool knc_titan_init(struct thr_info * const thr)
 {
 {
 	const int max_cores = KNC_TITAN_CORES_PER_ASIC;
 	const int max_cores = KNC_TITAN_CORES_PER_ASIC;
@@ -308,7 +313,6 @@ static bool knc_titan_init(struct thr_info * const thr)
 	int asic_cores[KNC_TITAN_MAX_ASICS] = {0};
 	int asic_cores[KNC_TITAN_MAX_ASICS] = {0};
 
 
 	for (proc = cgpu; proc; ) {
 	for (proc = cgpu; proc; ) {
-		proc->min_nonce_diff = DEFAULT_DIFF_FILTERING_FLOAT;
 		if (proc->device != proc) {
 		if (proc->device != proc) {
 			applog(LOG_WARNING, "%"PRIpreprv": Extra processor?", proc->proc_repr);
 			applog(LOG_WARNING, "%"PRIpreprv": Extra processor?", proc->proc_repr);
 			proc = proc->next_proc;
 			proc = proc->next_proc;
@@ -358,6 +362,7 @@ static bool knc_titan_init(struct thr_info * const thr)
 		}
 		}
 
 
 		knc->cores = total_cores;
 		knc->cores = total_cores;
+		knc->asic_served_by_fpga[asic] = true;
 	}
 	}
 
 
 	cgpu_set_defaults(cgpu);
 	cgpu_set_defaults(cgpu);
@@ -367,6 +372,9 @@ static bool knc_titan_init(struct thr_info * const thr)
 
 
 	knc = cgpu->device_data;
 	knc = cgpu->device_data;
 	for (asic = 0; asic < KNC_TITAN_MAX_ASICS; ++asic) {
 	for (asic = 0; asic < KNC_TITAN_MAX_ASICS; ++asic) {
+		knc_titan_setup_spi("ASIC", knc->ctx, asic, KNC_TITAN_FPGA_SPI_DIVIDER,
+				    KNC_TITAN_FPGA_SPI_PRECLK, KNC_TITAN_FPGA_SPI_DECLK,
+				    KNC_TITAN_FPGA_SPI_SSLOWMIN);
 		for (die = 0; die < KNC_TITAN_DIES_PER_ASIC; ++die) {
 		for (die = 0; die < KNC_TITAN_DIES_PER_ASIC; ++die) {
 			configure_one_die(knc, asic, die);
 			configure_one_die(knc, asic, die);
 			knc->dies[asic][die].next_slot = KNC_TITAN_MIN_WORK_SLOT_NUM;
 			knc->dies[asic][die].next_slot = KNC_TITAN_MIN_WORK_SLOT_NUM;
@@ -430,9 +438,7 @@ static bool die_reconfigure(struct knc_titan_info * const knc, int asic, int die
 
 
 static bool knc_titan_prepare_work(struct thr_info *thr, struct work *work)
 static bool knc_titan_prepare_work(struct thr_info *thr, struct work *work)
 {
 {
-	struct cgpu_info * const cgpu = thr->cgpu;
-
-	work->nonce_diff = cgpu->min_nonce_diff;
+	work->nonce_diff = DEFAULT_DIFF_FILTERING_FLOAT;
 	return true;
 	return true;
 }
 }
 
 
@@ -512,6 +518,7 @@ static void knc_titan_queue_flush(struct thr_info * const thr)
 			for (die = 0; die < KNC_TITAN_DIES_PER_ASIC; ++die) {
 			for (die = 0; die < KNC_TITAN_DIES_PER_ASIC; ++die) {
 				knc->dies[asic][die].need_flush = true;
 				knc->dies[asic][die].need_flush = true;
 			}
 			}
+			knc->asic_served_by_fpga[asic] = true;
 		}
 		}
 		timer_set_now(&thr->tv_poll);
 		timer_set_now(&thr->tv_poll);
 	}
 	}
@@ -522,12 +529,41 @@ static void knc_titan_queue_flush(struct thr_info * const thr)
 #define	DIE_FROM_WORKID(workid)			((((uint32_t)(workid)) >> 8) & 0xFF)
 #define	DIE_FROM_WORKID(workid)			((((uint32_t)(workid)) >> 8) & 0xFF)
 #define	SLOT_FROM_WORKID(workid)		(((uint32_t)(workid)) & 0xFF)
 #define	SLOT_FROM_WORKID(workid)		(((uint32_t)(workid)) & 0xFF)
 
 
+static bool knc_titan_process_report(struct knc_titan_info * const knc, struct knc_titan_core * const knccore, struct knc_report * const report)
+{
+	int i, tmp_int;
+	struct work *work;
+	struct cgpu_info * const proc = knccore->proc;
+	bool ret = false;
+
+	for (i = 0; i < KNC_TITAN_NONCES_PER_REPORT; ++i) {
+		if ((report->nonce[i].slot == knccore->last_nonce.slot) &&
+		    (report->nonce[i].nonce == knccore->last_nonce.nonce))
+			break;
+		ret = true;
+		tmp_int = MAKE_WORKID(knccore->asicno, knccore->dieno, report->nonce[i].slot);
+		HASH_FIND_INT(knc->devicework, &tmp_int, work);
+		if (!work) {
+			applog(LOG_WARNING, "%"PRIpreprv"[%d:%d:%d]: Got nonce for unknown work in slot %u", proc->proc_repr, knccore->asicno, knccore->dieno, knccore->coreno, (unsigned)report->nonce[i].slot);
+			continue;
+		}
+		if (submit_nonce(proc->thr[0], work, report->nonce[i].nonce)) {
+			hashes_done2(proc->thr[0], DEFAULT_DIFF_HASHES_PER_NONCE, NULL);
+			knccore->hwerr_in_row = 0;
+		}
+	}
+	knccore->last_nonce.slot = report->nonce[0].slot;
+	knccore->last_nonce.nonce = report->nonce[0].nonce;
+	
+	return ret;
+}
+
 static void knc_titan_poll(struct thr_info * const thr)
 static void knc_titan_poll(struct thr_info * const thr)
 {
 {
 	struct thr_info *mythr;
 	struct thr_info *mythr;
 	struct cgpu_info * const cgpu = thr->cgpu, *proc;
 	struct cgpu_info * const cgpu = thr->cgpu, *proc;
 	struct knc_titan_info * const knc = cgpu->device_data;
 	struct knc_titan_info * const knc = cgpu->device_data;
-	struct knc_titan_core *knccore, *core1;
+	struct knc_titan_core *knccore;
 	struct work *work, *tmp;
 	struct work *work, *tmp;
 	int workaccept = 0;
 	int workaccept = 0;
 	unsigned long delay_usecs = KNC_POLL_INTERVAL_US;
 	unsigned long delay_usecs = KNC_POLL_INTERVAL_US;
@@ -535,15 +571,17 @@ static void knc_titan_poll(struct thr_info * const thr)
 	struct knc_die_info die_info;
 	struct knc_die_info die_info;
 	int asic;
 	int asic;
 	int die;
 	int die;
-	int i, tmp_int;
 	struct knc_titan_die *die_p;
 	struct knc_titan_die *die_p;
-	struct timeval tv_now, tv_prev;
-	bool any_was_flushed = false;
+	struct timeval tv_now;
+	int num_request_busy;
+	int num_status_byte_error[4];
+	bool fpga_status_checked;
 
 
 	knc_titan_prune_local_queue(thr);
 	knc_titan_prune_local_queue(thr);
-	timer_set_now(&tv_prev);
 
 
 	for (asic = 0; asic < KNC_TITAN_MAX_ASICS; ++asic) {
 	for (asic = 0; asic < KNC_TITAN_MAX_ASICS; ++asic) {
+                fpga_status_checked = false;
+                num_request_busy = KNC_TITAN_DIES_PER_ASIC;
 		for (die = 0; die < KNC_TITAN_DIES_PER_ASIC; ++die) {
 		for (die = 0; die < KNC_TITAN_DIES_PER_ASIC; ++die) {
 			die_p = &(knc->dies[asic][die]);
 			die_p = &(knc->dies[asic][die]);
 			if (0 >= die_p->cores)
 			if (0 >= die_p->cores)
@@ -564,32 +602,30 @@ static void knc_titan_poll(struct thr_info * const thr)
 							work_accepted = true;
 							work_accepted = true;
 						}
 						}
 					} else {
 					} else {
-						/* Use unicasts */
-						bool work_acc_arr[die_p->cores];
-						struct knc_report reports[die_p->cores];
-						for (proc = first_proc; proc; proc = proc->next_proc) {
-							mythr = proc->thr[0];
-							core1 = mythr->cgpu_data;
-							if ((core1->dieno != die) || (core1->asicno != asic))
-								break;
-							work_acc_arr[core1->coreno] = false;
+						/* Use FPGA accelerated unicasts */
+						if (!fpga_status_checked) {
+							timer_set_now(&knc->tv_prev);
+							knc_titan_get_work_status(first_proc->device->dev_repr, knc->ctx, asic, &num_request_busy, num_status_byte_error);
+							fpga_status_checked = true;
 						}
 						}
-						if (knc_titan_set_work_multi(first_proc->device->dev_repr, knc->ctx, asic, die, 0, die_p->next_slot, work, true, work_acc_arr, reports, die_p->cores)) {
-							for (proc = first_proc; proc; proc = proc->next_proc) {
-								mythr = proc->thr[0];
-								core1 = mythr->cgpu_data;
-								if ((core1->dieno != die) || (core1->asicno != asic))
-									break;
-								if (work_acc_arr[core1->coreno]) {
-									core1->last_nonce.slot = reports[core1->coreno].nonce[0].slot;
-									core1->last_nonce.nonce = reports[core1->coreno].nonce[0].nonce;
-									work_accepted = true;
-								}
+						if (num_request_busy == 0) {
+							if (knc_titan_set_work_parallel(first_proc->device->dev_repr, knc->ctx, asic, 1 << die, 0, die_p->next_slot, work, true, die_p->cores, KNC_TITAN_FPGA_RETRIES)) {
+								work_accepted = true;
 							}
 							}
 						}
 						}
 					}
 					}
 				} else {
 				} else {
-					if (!knc_titan_set_work(first_proc->dev_repr, knc->ctx, asic, die, ALL_CORES, die_p->next_slot, work, false, &work_accepted, &report))
+					if (knc->asic_served_by_fpga[asic]) {
+						knc_titan_get_work_status(first_proc->device->dev_repr, knc->ctx, asic, &num_request_busy, num_status_byte_error);
+						if (num_request_busy == 0) {
+							timer_set_now(&tv_now);
+							double diff = ((tv_now.tv_sec - knc->tv_prev.tv_sec) * 1000000.0 + (tv_now.tv_usec - knc->tv_prev.tv_usec)) / 1000000.0;
+							applog(LOG_INFO, "%s: Flush took %f secs for ASIC %d", knc_titan_drv.dname, diff, asic);
+							applog(LOG_DEBUG, "FPGA CRC error counters: %d %d %d %d", num_status_byte_error[0], num_status_byte_error[1], num_status_byte_error[2], num_status_byte_error[3]);
+							knc->asic_served_by_fpga[asic] = false;
+						}
+					}
+					if (knc->asic_served_by_fpga[asic] || !knc_titan_set_work(first_proc->dev_repr, knc->ctx, asic, die, ALL_CORES, die_p->next_slot, work, false, &work_accepted, &report))
 						work_accepted = false;
 						work_accepted = false;
 				}
 				}
 				knccore = first_proc->thr[0]->cgpu_data;
 				knccore = first_proc->thr[0]->cgpu_data;
@@ -597,32 +633,30 @@ static void knc_titan_poll(struct thr_info * const thr)
 					break;
 					break;
 				bool was_flushed = false;
 				bool was_flushed = false;
 				if (die_p->need_flush || need_replace) {
 				if (die_p->need_flush || need_replace) {
-					struct work *work1, *tmp1;
 					applog(LOG_NOTICE, "%s[%d-%d] Flushing stale works (%s)", first_proc->dev_repr, asic, die,
 					applog(LOG_NOTICE, "%s[%d-%d] Flushing stale works (%s)", first_proc->dev_repr, asic, die,
 					       die_p->need_flush ? "New work" : "Slot collision");
 					       die_p->need_flush ? "New work" : "Slot collision");
 					die_p->need_flush = false;
 					die_p->need_flush = false;
 					die_p->first_slot = die_p->next_slot;
 					die_p->first_slot = die_p->next_slot;
-					HASH_ITER(hh, knc->devicework, work1, tmp1) {
-						if ( (asic == ASIC_FROM_WORKID(work1->device_id)) &&
-							 (die == DIE_FROM_WORKID(work1->device_id)) ) {
-							HASH_DEL(knc->devicework, work1);
-							free_work(work1);
-						}
-					}
 					delay_usecs = 0;
 					delay_usecs = 0;
 					was_flushed = true;
 					was_flushed = true;
-					any_was_flushed = true;
 				}
 				}
 				--knc->workqueue_size;
 				--knc->workqueue_size;
 				DL_DELETE(knc->workqueue, work);
 				DL_DELETE(knc->workqueue, work);
 				work->device_id = MAKE_WORKID(asic, die, die_p->next_slot);
 				work->device_id = MAKE_WORKID(asic, die, die_p->next_slot);
+				struct work *work1, *tmp1;
+				HASH_ITER(hh, knc->devicework, work1, tmp1) {
+					if (work->device_id == work1->device_id) {
+						HASH_DEL(knc->devicework, work1);
+						free_work(work1);
+					}
+				}
 				HASH_ADD(hh, knc->devicework, device_id, sizeof(work->device_id), work);
 				HASH_ADD(hh, knc->devicework, device_id, sizeof(work->device_id), work);
 				if (++(die_p->next_slot) > KNC_TITAN_MAX_WORK_SLOT_NUM)
 				if (++(die_p->next_slot) > KNC_TITAN_MAX_WORK_SLOT_NUM)
 					die_p->next_slot = KNC_TITAN_MIN_WORK_SLOT_NUM;
 					die_p->next_slot = KNC_TITAN_MIN_WORK_SLOT_NUM;
 				++workaccept;
 				++workaccept;
 				/* If we know for sure that this work was urgent, then we don't need to hurry up
 				/* If we know for sure that this work was urgent, then we don't need to hurry up
 				 * with filling next slot, we have plenty of time until current work completes.
 				 * with filling next slot, we have plenty of time until current work completes.
-				 * So, better to proceed with other ASICs/knc. */
+				 * So, better to proceed with other ASICs/dies. */
 				if (was_flushed)
 				if (was_flushed)
 					break;
 					break;
 			}
 			}
@@ -631,10 +665,6 @@ static void knc_titan_poll(struct thr_info * const thr)
 
 
 	applog(LOG_DEBUG, "%s: %d jobs accepted to queue (max=%d)", knc_titan_drv.dname, workaccept, knc->workqueue_max);
 	applog(LOG_DEBUG, "%s: %d jobs accepted to queue (max=%d)", knc_titan_drv.dname, workaccept, knc->workqueue_max);
 	timer_set_now(&tv_now);
 	timer_set_now(&tv_now);
-	if (any_was_flushed) {
-		double diff = ((tv_now.tv_sec - tv_prev.tv_sec) * 1000000.0 + (tv_now.tv_usec - tv_prev.tv_usec)) / 1000000.0;
-		applog(LOG_INFO, "%s: Flush took %f secs", knc_titan_drv.dname, diff);
-	}
 
 
 	for (asic = 0; asic < KNC_TITAN_MAX_ASICS; ++asic) {
 	for (asic = 0; asic < KNC_TITAN_MAX_ASICS; ++asic) {
 		for (die = 0; die < KNC_TITAN_DIES_PER_ASIC; ++die) {
 		for (die = 0; die < KNC_TITAN_DIES_PER_ASIC; ++die) {
@@ -643,35 +673,20 @@ static void knc_titan_poll(struct thr_info * const thr)
 				continue;
 				continue;
 			die_info.cores = die_p->cores; /* core hint */
 			die_info.cores = die_p->cores; /* core hint */
 			die_info.version = KNC_VERSION_TITAN;
 			die_info.version = KNC_VERSION_TITAN;
-			if (!knc_titan_get_info(cgpu->dev_repr, knc->ctx, asic, die, &die_info))
+			if (knc->asic_served_by_fpga[asic] || !knc_titan_get_info(cgpu->dev_repr, knc->ctx, asic, die, &die_info))
 				continue;
 				continue;
 			for (proc = die_p->first_proc; proc; proc = proc->next_proc) {
 			for (proc = die_p->first_proc; proc; proc = proc->next_proc) {
 				mythr = proc->thr[0];
 				mythr = proc->thr[0];
 				knccore = mythr->cgpu_data;
 				knccore = mythr->cgpu_data;
+				thread_reportin(mythr);
 				if ((knccore->dieno != die) || (knccore->asicno != asic))
 				if ((knccore->dieno != die) || (knccore->asicno != asic))
 					break;
 					break;
 				if (!die_info.has_report[knccore->coreno])
 				if (!die_info.has_report[knccore->coreno])
 					continue;
 					continue;
 				if (!knc_titan_get_report(proc->proc_repr, knc->ctx, asic, die, knccore->coreno, &report))
 				if (!knc_titan_get_report(proc->proc_repr, knc->ctx, asic, die, knccore->coreno, &report))
 					continue;
 					continue;
-				timer_set_now(&(die_p->last_share));
-				for (i = 0; i < KNC_TITAN_NONCES_PER_REPORT; ++i) {
-					if ((report.nonce[i].slot == knccore->last_nonce.slot) &&
-					    (report.nonce[i].nonce == knccore->last_nonce.nonce))
-						break;
-					tmp_int = MAKE_WORKID(asic, die, report.nonce[i].slot);
-					HASH_FIND_INT(knc->devicework, &tmp_int, work);
-					if (!work) {
-						applog(LOG_WARNING, "%"PRIpreprv"[%d:%d:%d]: Got nonce for unknown work in slot %u", proc->proc_repr, asic, die, knccore->coreno, (unsigned)report.nonce[i].slot);
-						continue;
-					}
-					if (submit_nonce(mythr, work, report.nonce[i].nonce)) {
-						hashes_done2(mythr, DEFAULT_DIFF_HASHES_PER_NONCE, NULL);
-						knccore->hwerr_in_row = 0;
-					}
-				}
-				knccore->last_nonce.slot = report.nonce[0].slot;
-				knccore->last_nonce.nonce = report.nonce[0].nonce;
+				if (knc_titan_process_report(knc, knccore, &report))
+					timer_set_now(&(die_p->last_share));
 			}
 			}
 		}
 		}
 
 
@@ -792,7 +807,7 @@ struct device_drv knc_titan_drv =
 	/* metadata */
 	/* metadata */
 	.dname = "titan",
 	.dname = "titan",
 	.name = "KNC",
 	.name = "KNC",
-	.supported_algos = POW_SCRYPT,
+	.drv_min_nonce_diff = titan_min_nonce_diff,
 	.drv_detect = knc_titan_detect,
 	.drv_detect = knc_titan_detect,
 
 
 	.thread_init = knc_titan_init,
 	.thread_init = knc_titan_init,

+ 1 - 2
driver-zeusminer.c

@@ -219,7 +219,6 @@ bool zeusminer_thread_init(struct thr_info * const thr)
 {
 {
 	struct cgpu_info * const device = thr->cgpu;
 	struct cgpu_info * const device = thr->cgpu;
 	
 	
-	device->min_nonce_diff = 1./0x10000;
 	device->set_device_funcs = zeusminer_set_device_funcs_live;
 	device->set_device_funcs = zeusminer_set_device_funcs_live;
 	
 	
 	return icarus_init(thr);
 	return icarus_init(thr);
@@ -320,7 +319,7 @@ void zeusminer_drv_init()
 	// metadata
 	// metadata
 	zeusminer_drv.dname = "zeusminer";
 	zeusminer_drv.dname = "zeusminer";
 	zeusminer_drv.name = "ZUS";
 	zeusminer_drv.name = "ZUS";
-	zeusminer_drv.supported_algos = POW_SCRYPT;
+	zeusminer_drv.drv_min_nonce_diff = common_scrypt_min_nonce_diff;
 	
 	
 	// detect device
 	// detect device
 	zeusminer_drv.lowl_probe = zeusminer_lowl_probe;
 	zeusminer_drv.lowl_probe = zeusminer_lowl_probe;

+ 12 - 3
findnonce.c

@@ -137,7 +137,7 @@ void precalc_hash(struct opencl_work_data *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[SCRYPT_MAXBUFFERS];
+	uint32_t res[OPENCL_MAX_BUFFERSIZE];
 	pthread_t pth;
 	pthread_t pth;
 	int found;
 	int found;
 };
 };
@@ -147,7 +147,11 @@ 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;
+	int found = FOUND;
+#ifdef USE_SCRYPT
+	if (work_mining_algorithm(&pcd->work)->algo == POW_SCRYPT)
+		found = SCRYPT_FOUND;
+#endif
 
 
 	pthread_detach(pthread_self());
 	pthread_detach(pthread_self());
 	RenameThread("postcalchsh");
 	RenameThread("postcalchsh");
@@ -188,7 +192,12 @@ 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);
-	buffersize = opt_scrypt ? SCRYPT_BUFFERSIZE : BUFFERSIZE;
+#ifdef USE_SCRYPT
+	if (work_mining_algorithm(work)->algo == POW_SCRYPT)
+		buffersize = SCRYPT_BUFFERSIZE;
+	else
+#endif
+		buffersize = BUFFERSIZE;
 	memcpy(&pcd->res, res, 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)) {

+ 6 - 0
findnonce.h

@@ -12,10 +12,16 @@
 #define BUFFERSIZE (sizeof(uint32_t) * MAXBUFFERS)
 #define BUFFERSIZE (sizeof(uint32_t) * MAXBUFFERS)
 #define FOUND (0x0F)
 #define FOUND (0x0F)
 
 
+#ifdef USE_SCRYPT
 #define SCRYPT_MAXBUFFERS (0x100)
 #define SCRYPT_MAXBUFFERS (0x100)
 #define SCRYPT_BUFFERSIZE (sizeof(uint32_t) * SCRYPT_MAXBUFFERS)
 #define SCRYPT_BUFFERSIZE (sizeof(uint32_t) * SCRYPT_MAXBUFFERS)
 #define SCRYPT_FOUND (0xFF)
 #define SCRYPT_FOUND (0xFF)
 
 
+#define OPENCL_MAX_BUFFERSIZE  SCRYPT_BUFFERSIZE
+#else
+#define OPENCL_MAX_BUFFERSIZE  BUFFERSIZE
+#endif
+
 #ifdef HAVE_OPENCL
 #ifdef HAVE_OPENCL
 extern void precalc_hash(struct opencl_work_data *blk, uint32_t *state, uint32_t *data);
 extern void precalc_hash(struct opencl_work_data *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);

+ 3 - 3
gc3355.c

@@ -513,7 +513,7 @@ void gc3355_init_miner(int fd, int pll_freq)
 	gc3355_set_pll_freq(fd, pll_freq);
 	gc3355_set_pll_freq(fd, pll_freq);
 }
 }
 
 
-void gc3355_init_dualminer(int fd, int pll_freq, bool scrypt_only, bool detect_only)
+void gc3355_init_dualminer(int fd, int pll_freq, bool scrypt_only, bool detect_only, bool scrypt)
 {
 {
 	gc3355_send_cmds(fd, gcp_chip_reset_cmd);
 	gc3355_send_cmds(fd, gcp_chip_reset_cmd);
 
 
@@ -525,7 +525,7 @@ void gc3355_init_dualminer(int fd, int pll_freq, bool scrypt_only, bool detect_o
 	// initialize units
 	// initialize units
 	gc3355_reset_dtr(fd);
 	gc3355_reset_dtr(fd);
 
 
-	if (opt_scrypt && scrypt_only)
+	if (scrypt && scrypt_only)
 		gc3355_scrypt_only_init(fd);
 		gc3355_scrypt_only_init(fd);
 	else
 	else
 	{
 	{
@@ -541,7 +541,7 @@ void gc3355_init_dualminer(int fd, int pll_freq, bool scrypt_only, bool detect_o
 
 
 	if (!detect_only)
 	if (!detect_only)
 	{
 	{
-		if (!opt_scrypt)
+		if (!scrypt)
 			// open sha2 units
 			// open sha2 units
 			gc3355_open_sha2_units(fd, opt_sha2_units);
 			gc3355_open_sha2_units(fd, opt_sha2_units);
 
 

+ 1 - 1
gc3355.h

@@ -44,7 +44,7 @@ extern ssize_t gc3355_read(int fd, char *buf, size_t size);
 extern ssize_t gc3355_write(int fd, const void * const buf, const size_t size);
 extern ssize_t gc3355_write(int fd, const void * const buf, const size_t size);
 
 
 extern void gc3355_init_miner(int fd, int pll_freq);
 extern void gc3355_init_miner(int fd, int pll_freq);
-extern void gc3355_init_dualminer(int fd, int pll_freq, bool scrypt_only, bool detect_only);
+extern void gc3355_init_dualminer(int fd, int pll_freq, bool scrypt_only, bool detect_only, bool scrypt);
 
 
 extern void gc3355_scrypt_reset(int fd);
 extern void gc3355_scrypt_reset(int fd);
 extern void gc3355_scrypt_only_reset(int fd);
 extern void gc3355_scrypt_only_reset(int fd);

+ 1 - 1
knc-asic

@@ -1 +1 @@
-Subproject commit 6a5c83c4a576a17d5663464e01bb8609b20b0161
+Subproject commit f15761c85e1cf35e28aeab519ef57d857d263fd4

+ 3 - 3
libbitfury.c

@@ -241,7 +241,7 @@ int libbitfury_detect_chip(struct spi_port *port, int chip_n) {
 	int i;
 	int i;
 	uint32_t newbuf[17] = {0}, oldbuf[17] = {0};
 	uint32_t newbuf[17] = {0}, oldbuf[17] = {0};
 	uint32_t ocounter;
 	uint32_t ocounter;
-	long odiff = 0;
+	long long odiff = 0;
 
 
 	memset(newbuf, 0, 17 * 4);
 	memset(newbuf, 0, 17 * 4);
 	memset(oldbuf, 0, 17 * 4);
 	memset(oldbuf, 0, 17 * 4);
@@ -274,9 +274,9 @@ int libbitfury_detect_chip(struct spi_port *port, int chip_n) {
 
 
 		counter = libbitfury_get_counter(newbuf, oldbuf);
 		counter = libbitfury_get_counter(newbuf, oldbuf);
 		if (ocounter) {
 		if (ocounter) {
-			uint32_t cdiff = libbitfury_c_diff(ocounter, counter);
+			long long cdiff = libbitfury_c_diff(ocounter, counter);
 
 
-			if (abs(odiff - cdiff) < 5000)
+			if (llabs(odiff - cdiff) < 5000)
 				return 1;
 				return 1;
 			odiff = cdiff;
 			odiff = cdiff;
 		}
 		}

File diff suppressed because it is too large
+ 566 - 113
miner.c


+ 98 - 35
miner.h

@@ -21,6 +21,7 @@
 #include <winsock2.h>
 #include <winsock2.h>
 #endif
 #endif
 
 
+#include <float.h>
 #include <stdbool.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdint.h>
 #include <sys/time.h>
 #include <sys/time.h>
@@ -277,9 +278,10 @@ struct gpu_adl {
 
 
 enum pow_algorithm {
 enum pow_algorithm {
 	POW_SHA256D = 1,
 	POW_SHA256D = 1,
+#ifdef USE_SCRYPT
 	POW_SCRYPT  = 2,
 	POW_SCRYPT  = 2,
+#endif
 };
 };
-typedef uint8_t supported_algos_t;
 
 
 struct api_data;
 struct api_data;
 struct thr_info;
 struct thr_info;
@@ -294,15 +296,19 @@ enum bfg_probe_result_flags_values {
 extern unsigned *_bfg_probe_result_flags();
 extern unsigned *_bfg_probe_result_flags();
 #define bfg_probe_result_flags (*_bfg_probe_result_flags())
 #define bfg_probe_result_flags (*_bfg_probe_result_flags())
 
 
+struct mining_algorithm;
+
 struct device_drv {
 struct device_drv {
 	const char *dname;
 	const char *dname;
 	const char *name;
 	const char *name;
 	int8_t probe_priority;
 	int8_t probe_priority;
 	bool lowl_probe_by_name_only;
 	bool lowl_probe_by_name_only;
-	supported_algos_t supported_algos;
 
 
 	// DRV-global functions
 	// DRV-global functions
 	void (*drv_init)();
 	void (*drv_init)();
+	// drv_min_nonce_diff's proc may be NULL
+	// drv_min_nonce_diff should return negative if algorithm is not supported
+	float (*drv_min_nonce_diff)(struct cgpu_info *proc, const struct mining_algorithm *);
 	void (*drv_detect)();
 	void (*drv_detect)();
 	bool (*lowl_match)(const struct lowlevel_device_info *);
 	bool (*lowl_match)(const struct lowlevel_device_info *);
 	bool (*lowl_probe)(const struct lowlevel_device_info *);
 	bool (*lowl_probe)(const struct lowlevel_device_info *);
@@ -569,9 +575,6 @@ struct cgpu_info {
 
 
 	bool disable_watchdog;
 	bool disable_watchdog;
 	bool shutdown;
 	bool shutdown;
-	
-	// Lowest difficulty supported for finding nonces
-	float min_nonce_diff;
 };
 };
 
 
 extern void renumber_cgpu(struct cgpu_info *);
 extern void renumber_cgpu(struct cgpu_info *);
@@ -947,7 +950,6 @@ extern bool opt_protocol;
 extern bool opt_dev_protocol;
 extern bool opt_dev_protocol;
 extern char *opt_coinbase_sig;
 extern char *opt_coinbase_sig;
 extern char *request_target_str;
 extern char *request_target_str;
-extern bool have_longpoll;
 extern int opt_skip_checks;
 extern int opt_skip_checks;
 extern char *opt_kernel_path;
 extern char *opt_kernel_path;
 extern char *opt_socks_proxy;
 extern char *opt_socks_proxy;
@@ -1061,6 +1063,8 @@ 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 blkhashstr(char *out, const unsigned char *hash);
+static const float minimum_pdiff = max(FLT_MIN, 1./0x100000000);
 extern void set_target_to_pdiff(void *dest_target, double pdiff);
 extern void set_target_to_pdiff(void *dest_target, double pdiff);
 #define bdiff_to_pdiff(n) (n * 1.0000152587)
 #define bdiff_to_pdiff(n) (n * 1.0000152587)
 extern void set_target_to_bdiff(void *dest_target, double bdiff);
 extern void set_target_to_bdiff(void *dest_target, double bdiff);
@@ -1093,34 +1097,83 @@ extern int enabled_pools;
 extern bool get_intrange(const char *arg, int *val1, int *val2);
 extern bool get_intrange(const char *arg, int *val1, int *val2);
 extern bool detect_stratum(struct pool *pool, char *url);
 extern bool detect_stratum(struct pool *pool, char *url);
 extern void print_summary(void);
 extern void print_summary(void);
+extern struct mining_algorithm *mining_algorithm_by_alias(const char *alias);
+extern struct mining_goal_info *get_mining_goal(const char *name);
+extern void goal_set_malgo(struct mining_goal_info *, struct mining_algorithm *);
+extern void mining_goal_reset(struct mining_goal_info * const goal);
 extern void adjust_quota_gcd(void);
 extern void adjust_quota_gcd(void);
-extern struct pool *add_pool(void);
+extern struct pool *add_pool2(struct mining_goal_info *);
+#define add_pool()  add_pool2(get_mining_goal("default"))
 extern bool add_pool_details(struct pool *pool, bool live, char *url, char *user, char *pass);
 extern bool add_pool_details(struct pool *pool, bool live, char *url, char *user, char *pass);
 
 
 #define MAX_GPUDEVICES 16
 #define MAX_GPUDEVICES 16
 #define MAX_DEVICES 4096
 #define MAX_DEVICES 4096
 
 
-#define MIN_SHA_INTENSITY -10
-#define MIN_SHA_INTENSITY_STR "-10"
-#define MAX_SHA_INTENSITY 14
-#define MAX_SHA_INTENSITY_STR "14"
-#define MIN_SCRYPT_INTENSITY 8
-#define MIN_SCRYPT_INTENSITY_STR "8"
-#define MAX_SCRYPT_INTENSITY 31
-#define MAX_SCRYPT_INTENSITY_STR "31"
-#ifdef USE_SCRYPT
-#define MIN_INTENSITY (opt_scrypt ? MIN_SCRYPT_INTENSITY : MIN_SHA_INTENSITY)
-#define MIN_INTENSITY_STR (opt_scrypt ? MIN_SCRYPT_INTENSITY_STR : MIN_SHA_INTENSITY_STR)
-#define MAX_INTENSITY (opt_scrypt ? MAX_SCRYPT_INTENSITY : MAX_SHA_INTENSITY)
-#define MAX_INTENSITY_STR (opt_scrypt ? MAX_SCRYPT_INTENSITY_STR : MAX_SHA_INTENSITY_STR)
-#define MAX_GPU_INTENSITY MAX_SCRYPT_INTENSITY
-#else
-#define MIN_INTENSITY MIN_SHA_INTENSITY
-#define MIN_INTENSITY_STR MIN_SHA_INTENSITY_STR
-#define MAX_INTENSITY MAX_SHA_INTENSITY
-#define MAX_INTENSITY_STR MAX_SHA_INTENSITY_STR
-#define MAX_GPU_INTENSITY MAX_SHA_INTENSITY
+struct block_info {
+	uint32_t block_id;
+	uint8_t prevblkhash[0x20];
+	unsigned block_seen_order;  // new_blocks when this block was first seen; was 'block_no'
+	uint32_t height;
+	time_t first_seen_time;
+	
+	UT_hash_handle hh;
+};
+
+struct blockchain_info {
+	struct block_info *blocks;
+	struct block_info *currentblk;
+	uint64_t currentblk_subsidy;  // only valid when height is known! (and assumes Bitcoin)
+	char currentblk_first_seen_time_str[0x20];  // was global blocktime
+};
+
+struct mining_algorithm {
+	const char *name;
+	const char *aliases;
+	
+	enum pow_algorithm algo;
+	uint8_t ui_skip_hash_bytes;
+	uint8_t worktime_skip_prevblk_u32;
+	float reasonable_low_nonce_diff;
+	
+	void (*hash_data_f)(void *digest, const void *data);
+	
+	int goal_refs;
+	int staged;
+	int base_queue;
+	
+	struct mining_algorithm *next;
+	
+#ifdef HAVE_OPENCL
+	bool opencl_nodefault;
+	float (*opencl_oclthreads_to_intensity)(unsigned long oclthreads);
+	unsigned long (*opencl_intensity_to_oclthreads)(float intensity);
+	unsigned long opencl_min_oclthreads;
+	unsigned long opencl_max_oclthreads;
 #endif
 #endif
+};
+
+struct mining_goal_info {
+	unsigned id;
+	char *name;
+	bool is_default;
+	
+	struct blockchain_info *blkchain;
+	
+	bytes_t *generation_script;  // was opt_coinbase_script
+	
+	struct mining_algorithm *malgo;
+	double current_diff;
+	char current_diff_str[ALLOC_H2B_SHORTV];  // was global block_diff
+	char net_hashrate[ALLOC_H2B_SHORT];
+	
+	char *current_goal_detail;
+	
+	double diff_accepted;
+	
+	bool have_longpoll;
+	
+	UT_hash_handle hh;
+};
 
 
 extern struct string_elist *scan_devices;
 extern struct string_elist *scan_devices;
 extern bool opt_force_dev_init;
 extern bool opt_force_dev_init;
@@ -1133,11 +1186,6 @@ extern bool opt_quiet;
 extern struct thr_info *control_thr;
 extern struct thr_info *control_thr;
 extern struct thr_info **mining_thr;
 extern struct thr_info **mining_thr;
 extern struct cgpu_info gpus[MAX_GPUDEVICES];
 extern struct cgpu_info gpus[MAX_GPUDEVICES];
-#ifdef USE_SCRYPT
-extern bool opt_scrypt;
-#else
-#define opt_scrypt (0)
-#endif
 extern double total_secs;
 extern double total_secs;
 extern int mining_threads;
 extern int mining_threads;
 extern struct cgpu_info *cpus;
 extern struct cgpu_info *cpus;
@@ -1170,10 +1218,9 @@ extern int opt_fail_pause;
 extern int opt_log_interval;
 extern int opt_log_interval;
 extern unsigned long long global_hashrate;
 extern unsigned long long global_hashrate;
 extern unsigned unittest_failures;
 extern unsigned unittest_failures;
-extern char *current_fullhash;
-extern double current_diff;
 extern double best_diff;
 extern double best_diff;
-extern time_t block_time;
+extern struct mining_algorithm *mining_algorithms;
+extern struct mining_goal_info *mining_goals;
 
 
 struct curl_ent {
 struct curl_ent {
 	CURL *curl;
 	CURL *curl;
@@ -1297,6 +1344,7 @@ struct pool {
 	time_t work_restart_time;
 	time_t work_restart_time;
 	char work_restart_timestamp[11];
 	char work_restart_timestamp[11];
 	uint32_t	block_id;
 	uint32_t	block_id;
+	struct mining_goal_info *goal;
 
 
 	enum pool_protocol proto;
 	enum pool_protocol proto;
 
 
@@ -1368,6 +1416,9 @@ struct pool {
 	bool stratum_init;
 	bool stratum_init;
 	bool stratum_notify;
 	bool stratum_notify;
 	struct stratum_work swork;
 	struct stratum_work swork;
+	char *goalname;
+	char *next_goalname;
+	struct mining_algorithm *next_goal_malgo;
 	uint8_t next_target[0x20];
 	uint8_t next_target[0x20];
 	char *next_nonce1;
 	char *next_nonce1;
 	int next_n2size;
 	int next_n2size;
@@ -1419,6 +1470,7 @@ struct work {
 	bool		longpoll;
 	bool		longpoll;
 	bool		stale;
 	bool		stale;
 	bool		mandatory;
 	bool		mandatory;
+	bool spare;
 	bool		block;
 	bool		block;
 
 
 	bool		stratum;
 	bool		stratum;
@@ -1522,6 +1574,7 @@ extern void kill_work(void);
 extern int prioritize_pools(char *param, int *pid);
 extern int prioritize_pools(char *param, int *pid);
 extern void validate_pool_priorities(void);
 extern void validate_pool_priorities(void);
 extern void enable_pool(struct pool *);
 extern void enable_pool(struct pool *);
+extern void manual_enable_pool(struct pool *);
 extern void disable_pool(struct pool *, enum pool_enable);
 extern void disable_pool(struct pool *, enum pool_enable);
 extern void switch_pools(struct pool *selected);
 extern void switch_pools(struct pool *selected);
 extern void remove_pool(struct pool *pool);
 extern void remove_pool(struct pool *pool);
@@ -1554,6 +1607,16 @@ extern const char *bfg_workpadding_bin;
 extern void set_simple_ntime_roll_limit(struct ntime_roll_limits *, uint32_t ntime_base, int ntime_roll, const struct timeval *tvp_ref);
 extern void set_simple_ntime_roll_limit(struct ntime_roll_limits *, uint32_t ntime_base, int ntime_roll, const struct timeval *tvp_ref);
 extern void work_set_simple_ntime_roll_limit(struct work *, int ntime_roll, const struct timeval *tvp_ref);
 extern void work_set_simple_ntime_roll_limit(struct work *, int ntime_roll, const struct timeval *tvp_ref);
 extern int work_ntime_range(struct work *, const struct timeval *tvp_earliest, const struct timeval *tvp_latest, int desired_roll);
 extern int work_ntime_range(struct work *, const struct timeval *tvp_earliest, const struct timeval *tvp_latest, int desired_roll);
+
+static inline
+struct mining_algorithm *work_mining_algorithm(const struct work * const work)
+{
+	const struct pool * const pool = work->pool;
+	const struct mining_goal_info * const goal = pool->goal;
+	struct mining_algorithm * const malgo = goal->malgo;
+	return malgo;
+}
+
 extern void work_hash(struct work *);
 extern void work_hash(struct work *);
 
 
 #define NTIME_DATA_OFFSET  0x44
 #define NTIME_DATA_OFFSET  0x44

+ 148 - 152
ocl.c

@@ -12,6 +12,7 @@
 #ifdef HAVE_OPENCL
 #ifdef HAVE_OPENCL
 
 
 #include <ctype.h>
 #include <ctype.h>
+#include <limits.h>
 #include <signal.h>
 #include <signal.h>
 #include <stdbool.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdint.h>
@@ -258,6 +259,30 @@ char *file_contents(const char *filename, int *length)
 	return (char*)buffer;
 	return (char*)buffer;
 }
 }
 
 
+char *opencl_kernel_source(const char * const filename, int * const out_sourcelen, enum cl_kernels * const out_kinterface)
+{
+	char *source = file_contents(filename, out_sourcelen);
+	if (!source)
+		return NULL;
+	char *s = strstr(source, "kernel-interface:"), *q;
+	if (s)
+	{
+		for (s = &s[17]; s[0] && isspace(s[0]); ++s)
+			if (s[0] == '\n' || s[0] == '\r')
+				break;
+		for (q = s; q[0] && !isspace(q[0]); ++q)
+		{}  // Find end of string
+		const size_t kinamelen = q - s;
+		char kiname[kinamelen + 1];
+		memcpy(kiname, s, kinamelen);
+		kiname[kinamelen] = '\0';
+		*out_kinterface = select_kernel(kiname);
+	}
+	else
+		*out_kinterface = KL_NONE;
+	return source;
+}
+
 extern int opt_g_threads;
 extern int opt_g_threads;
 
 
 int clDevicesNum(void) {
 int clDevicesNum(void) {
@@ -339,20 +364,20 @@ int clDevicesNum(void) {
 	return most_devices;
 	return most_devices;
 }
 }
 
 
-cl_int bfg_clBuildProgram(_clState * const clState, const cl_device_id devid, const char * const CompilerOptions)
+cl_int bfg_clBuildProgram(cl_program * const program, const cl_device_id devid, const char * const CompilerOptions)
 {
 {
 	cl_int status;
 	cl_int status;
 	
 	
-	status = clBuildProgram(clState->program, 1, &devid, CompilerOptions, NULL, NULL);
+	status = clBuildProgram(*program, 1, &devid, CompilerOptions, NULL, NULL);
 	
 	
 	if (status != CL_SUCCESS)
 	if (status != CL_SUCCESS)
 	{
 	{
 		applog(LOG_ERR, "Error %d: Building Program (clBuildProgram)", status);
 		applog(LOG_ERR, "Error %d: Building Program (clBuildProgram)", status);
 		size_t logSize;
 		size_t logSize;
-		status = clGetProgramBuildInfo(clState->program, devid, CL_PROGRAM_BUILD_LOG, 0, NULL, &logSize);
+		status = clGetProgramBuildInfo(*program, devid, CL_PROGRAM_BUILD_LOG, 0, NULL, &logSize);
 		
 		
 		char *log = malloc(logSize ?: 1);
 		char *log = malloc(logSize ?: 1);
-		status = clGetProgramBuildInfo(clState->program, devid, CL_PROGRAM_BUILD_LOG, logSize, log, NULL);
+		status = clGetProgramBuildInfo(*program, devid, CL_PROGRAM_BUILD_LOG, logSize, log, NULL);
 		if (logSize > 0 && log[0])
 		if (logSize > 0 && log[0])
 			applog(LOG_ERR, "%s", log);
 			applog(LOG_ERR, "%s", log);
 		free(log);
 		free(log);
@@ -418,18 +443,15 @@ void patch_opcodes(char *w, unsigned remaining)
 	applog(LOG_DEBUG, "Patched a total of %i BFI_INT instructions", patched);
 	applog(LOG_DEBUG, "Patched a total of %i BFI_INT instructions", patched);
 }
 }
 
 
-_clState *initCl(unsigned int gpu, char *name, size_t nameSize)
+_clState *opencl_create_clState(unsigned int gpu, char *name, size_t nameSize)
 {
 {
 	_clState *clState = calloc(1, sizeof(_clState));
 	_clState *clState = calloc(1, sizeof(_clState));
-	bool patchbfi = false, prog_built = false;
-	bool ismesa = false;
 	struct cgpu_info *cgpu = &gpus[gpu];
 	struct cgpu_info *cgpu = &gpus[gpu];
 	struct opencl_device_data * const data = cgpu->device_data;
 	struct opencl_device_data * const data = cgpu->device_data;
 	cl_platform_id platform = NULL;
 	cl_platform_id platform = NULL;
 	char pbuff[256], vbuff[255];
 	char pbuff[256], vbuff[255];
-	char *s, *q;
+	char *s;
 	cl_platform_id* platforms;
 	cl_platform_id* platforms;
-	cl_uint preferred_vwidth;
 	cl_device_id *devices;
 	cl_device_id *devices;
 	cl_uint numPlatforms;
 	cl_uint numPlatforms;
 	cl_uint numDevices;
 	cl_uint numDevices;
@@ -472,6 +494,7 @@ _clState *initCl(unsigned int gpu, char *name, size_t nameSize)
 	status = clGetPlatformInfo(platform, CL_PLATFORM_VERSION, sizeof(vbuff), vbuff, NULL);
 	status = clGetPlatformInfo(platform, CL_PLATFORM_VERSION, sizeof(vbuff), vbuff, NULL);
 	if (status == CL_SUCCESS)
 	if (status == CL_SUCCESS)
 		applog(LOG_INFO, "CL Platform version: %s", vbuff);
 		applog(LOG_INFO, "CL Platform version: %s", vbuff);
+	clState->platform_ver_str = strdup(vbuff);
 
 
 	status = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 0, NULL, &numDevices);
 	status = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 0, NULL, &numDevices);
 	if (status != CL_SUCCESS) {
 	if (status != CL_SUCCESS) {
@@ -569,12 +592,12 @@ _clState *initCl(unsigned int gpu, char *name, size_t nameSize)
 		clState->hasOpenCL11plus = true;
 		clState->hasOpenCL11plus = true;
 	free(devoclver);
 	free(devoclver);
 
 
-	status = clGetDeviceInfo(devices[gpu], CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, sizeof(cl_uint), (void *)&preferred_vwidth, NULL);
+	status = clGetDeviceInfo(devices[gpu], CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, sizeof(cl_uint), (void *)&clState->preferred_vwidth, NULL);
 	if (status != CL_SUCCESS) {
 	if (status != CL_SUCCESS) {
 		applog(LOG_ERR, "Error %d: Failed to clGetDeviceInfo when trying to get CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT", status);
 		applog(LOG_ERR, "Error %d: Failed to clGetDeviceInfo when trying to get CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT", status);
 		return NULL;
 		return NULL;
 	}
 	}
-	applog(LOG_DEBUG, "Preferred vector width reported %d", preferred_vwidth);
+	applog(LOG_DEBUG, "Preferred vector width reported %d", clState->preferred_vwidth);
 
 
 	status = clGetDeviceInfo(devices[gpu], CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(size_t), (void *)&clState->max_work_size, NULL);
 	status = clGetDeviceInfo(devices[gpu], CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(size_t), (void *)&clState->max_work_size, NULL);
 	if (status != CL_SUCCESS) {
 	if (status != CL_SUCCESS) {
@@ -594,7 +617,10 @@ _clState *initCl(unsigned int gpu, char *name, size_t nameSize)
 		opencl_set_intensity_from_str(cgpu, data->_init_intensity);
 		opencl_set_intensity_from_str(cgpu, data->_init_intensity);
 	}
 	}
 	else
 	else
-		data->oclthreads = intensity_to_oclthreads(MIN_INTENSITY, !opt_scrypt);
+	{
+		data->oclthreads = 1;
+		data->intensity = INT_MIN;
+	}
 	applog(LOG_DEBUG, "Max compute units reported %u", (unsigned)clState->max_compute_units);
 	applog(LOG_DEBUG, "Max compute units reported %u", (unsigned)clState->max_compute_units);
 	
 	
 	status = clGetDeviceInfo(devices[gpu], CL_DEVICE_MAX_MEM_ALLOC_SIZE , sizeof(cl_ulong), (void *)&data->max_alloc, NULL);
 	status = clGetDeviceInfo(devices[gpu], CL_DEVICE_MAX_MEM_ALLOC_SIZE , sizeof(cl_ulong), (void *)&data->max_alloc, NULL);
@@ -626,7 +652,7 @@ _clState *initCl(unsigned int gpu, char *name, size_t nameSize)
 		}
 		}
 		else
 		else
 			applog(LOG_DEBUG, "Mesa OpenCL platform detected (v%ld.%ld)", major, minor);
 			applog(LOG_DEBUG, "Mesa OpenCL platform detected (v%ld.%ld)", major, minor);
-		ismesa = true;
+		clState->is_mesa = true;
 	}
 	}
 	
 	
 	if (data->opt_opencl_binaries == OBU_DEFAULT)
 	if (data->opt_opencl_binaries == OBU_DEFAULT)
@@ -638,7 +664,44 @@ _clState *initCl(unsigned int gpu, char *name, size_t nameSize)
 		data->opt_opencl_binaries = OBU_LOADSAVE;
 		data->opt_opencl_binaries = OBU_LOADSAVE;
 #endif
 #endif
 	}
 	}
+	
+	clState->devid = devices[gpu];
+	free(devices);
+	
+	/* For some reason 2 vectors is still better even if the card says
+	 * otherwise, and many cards lie about their max so use 256 as max
+	 * unless explicitly set on the command line. Tahiti prefers 1 */
+	if (strstr(name, "Tahiti"))
+		clState->preferred_vwidth = 1;
+	else
+	if (clState->preferred_vwidth > 2)
+		clState->preferred_vwidth = 2;
 
 
+	if (data->vwidth)
+		clState->vwidth = data->vwidth;
+	else {
+		clState->vwidth = clState->preferred_vwidth;
+		data->vwidth = clState->preferred_vwidth;
+	}
+
+	clState->outputBuffer = clCreateBuffer(clState->context, CL_MEM_WRITE_ONLY, OPENCL_MAX_BUFFERSIZE, NULL, &status);
+	if (status != CL_SUCCESS) {
+		applog(LOG_ERR, "Error %d: clCreateBuffer (outputBuffer)", status);
+		return false;
+	}
+	
+	return clState;
+}
+
+bool opencl_load_kernel(struct cgpu_info * const cgpu, _clState * const clState, const char * const name, struct opencl_kernel_info * const kernelinfo, const char * const kernel_file, __maybe_unused const struct mining_algorithm * const malgo)
+{
+	const int gpu = cgpu->device_id;
+	bool patchbfi = false, prog_built = false;
+	struct opencl_device_data * const data = cgpu->device_data;
+	const char * const vbuff = clState->platform_ver_str;
+	char *s;
+	cl_int status;
+	
 	/* Create binary filename based on parameters passed to opencl
 	/* Create binary filename based on parameters passed to opencl
 	 * compiler to ensure we only load a binary that matches what would
 	 * compiler to ensure we only load a binary that matches what would
 	 * have otherwise created. The filename is:
 	 * have otherwise created. The filename is:
@@ -650,45 +713,12 @@ _clState *initCl(unsigned int gpu, char *name, size_t nameSize)
 	char filename[255];
 	char filename[255];
 	char numbuf[32];
 	char numbuf[32];
 
 
-	if (!data->kernel_file)
-	{
-		if (opt_scrypt) {
-			applog(LOG_INFO, "Selecting scrypt kernel");
-			clState->chosen_kernel = KL_SCRYPT;
-		}
-		else if (ismesa)
-		{
-			applog(LOG_INFO, "Selecting phatk kernel for Mesa");
-			clState->chosen_kernel = KL_PHATK;
-		} else if (!strstr(name, "Tahiti") &&
-			/* Detect all 2.6 SDKs not with Tahiti and use diablo kernel */
-			(strstr(vbuff, "844.4") ||  // Linux 64 bit ATI 2.6 SDK
-			 strstr(vbuff, "851.4") ||  // Windows 64 bit ""
-			 strstr(vbuff, "831.4") ||
-			 strstr(vbuff, "898.1") ||  // 12.2 driver SDK 
-			 strstr(vbuff, "923.1") ||  // 12.4
-			 strstr(vbuff, "938.2") ||  // SDK 2.7
-			 strstr(vbuff, "1113.2"))) {// SDK 2.8
-				applog(LOG_INFO, "Selecting diablo kernel");
-				clState->chosen_kernel = KL_DIABLO;
-		/* Detect all 7970s, older ATI and NVIDIA and use poclbm */
-		} else if (strstr(name, "Tahiti") || !clState->hasBitAlign) {
-			applog(LOG_INFO, "Selecting poclbm kernel");
-			clState->chosen_kernel = KL_POCLBM;
-		/* Use phatk for the rest R5xxx R6xxx */
-		} else {
-			applog(LOG_INFO, "Selecting phatk kernel");
-			clState->chosen_kernel = KL_PHATK;
-		}
-		data->kernel_file = strdup(opencl_get_kernel_interface_name(clState->chosen_kernel));
-	}
-	
-	snprintf(filename, sizeof(filename), "%s.cl", data->kernel_file);
-	snprintf(binaryfilename, sizeof(filename), "%s", data->kernel_file);
+	snprintf(filename, sizeof(filename), "%s.cl", kernel_file);
+	snprintf(binaryfilename, sizeof(filename), "%s", kernel_file);
 	int pl;
 	int pl;
-	char *source = file_contents(filename, &pl);
+	char *source = opencl_kernel_source(filename, &pl, &kernelinfo->interface);
 	if (!source)
 	if (!source)
-		return NULL;
+		return false;
 	{
 	{
 		uint8_t hash[0x20];
 		uint8_t hash[0x20];
 		char hashhex[7];
 		char hashhex[7];
@@ -696,29 +726,13 @@ _clState *initCl(unsigned int gpu, char *name, size_t nameSize)
 		bin2hex(hashhex, hash, 3);
 		bin2hex(hashhex, hash, 3);
 		tailsprintf(binaryfilename, sizeof(binaryfilename), "-%s", hashhex);
 		tailsprintf(binaryfilename, sizeof(binaryfilename), "-%s", hashhex);
 	}
 	}
-	s = strstr(source, "kernel-interface:");
-	if (s)
+	switch (kernelinfo->interface)
 	{
 	{
-		for (s = &s[17]; s[0] && isspace(s[0]); ++s)
-			if (s[0] == '\n' || s[0] == '\r')
-				break;
-		for (q = s; q[0] && !isspace(q[0]); ++q)
-		{}  // Find end of string
-		const size_t kinamelen = q - s;
-		char kiname[kinamelen + 1];
-		memcpy(kiname, s, kinamelen);
-		kiname[kinamelen] = '\0';
-		clState->chosen_kernel = select_kernel(kiname);
-	}
-	else
-	if (opt_scrypt)
-		clState->chosen_kernel = KL_SCRYPT;
-	switch (clState->chosen_kernel) {
 		case KL_NONE:
 		case KL_NONE:
 			applog(LOG_ERR, "%s: Failed to identify kernel interface for %s",
 			applog(LOG_ERR, "%s: Failed to identify kernel interface for %s",
-			       cgpu->dev_repr, data->kernel_file);
+			       cgpu->dev_repr, kernel_file);
 			free(source);
 			free(source);
-			return NULL;
+			return false;
 		case KL_PHATK:
 		case KL_PHATK:
 			if ((strstr(vbuff, "844.4") || strstr(vbuff, "851.4") ||
 			if ((strstr(vbuff, "844.4") || strstr(vbuff, "851.4") ||
 			     strstr(vbuff, "831.4") || strstr(vbuff, "898.1") ||
 			     strstr(vbuff, "831.4") || strstr(vbuff, "898.1") ||
@@ -733,47 +747,30 @@ _clState *initCl(unsigned int gpu, char *name, size_t nameSize)
 			;
 			;
 	}
 	}
 	applog(LOG_DEBUG, "%s: Using kernel %s with interface %s",
 	applog(LOG_DEBUG, "%s: Using kernel %s with interface %s",
-	       cgpu->dev_repr, data->kernel_file,
-	       opencl_get_kernel_interface_name(clState->chosen_kernel));
+	       cgpu->dev_repr, kernel_file,
+	       opencl_get_kernel_interface_name(kernelinfo->interface));
 
 
-	/* For some reason 2 vectors is still better even if the card says
-	 * otherwise, and many cards lie about their max so use 256 as max
-	 * unless explicitly set on the command line. Tahiti prefers 1 */
-	if (strstr(name, "Tahiti"))
-		preferred_vwidth = 1;
-	else if (preferred_vwidth > 2)
-		preferred_vwidth = 2;
-
-	if (data->vwidth)
-		clState->vwidth = data->vwidth;
-	else {
-		clState->vwidth = preferred_vwidth;
-		data->vwidth = preferred_vwidth;
-	}
-
-	if (((clState->chosen_kernel == KL_POCLBM || clState->chosen_kernel == KL_DIABLO || clState->chosen_kernel == KL_DIAKGCN) &&
-		clState->vwidth == 1 && clState->hasOpenCL11plus) || opt_scrypt)
-			clState->goffset = true;
+	if (((kernelinfo->interface == KL_POCLBM || kernelinfo->interface == KL_DIABLO || kernelinfo->interface == KL_DIAKGCN || kernelinfo->interface) && clState->vwidth == 1 && clState->hasOpenCL11plus) || kernelinfo->interface == KL_SCRYPT)
+		kernelinfo->goffset = true;
 
 
 	if (data->work_size && data->work_size <= clState->max_work_size)
 	if (data->work_size && data->work_size <= clState->max_work_size)
-		clState->wsize = data->work_size;
-	else if (opt_scrypt)
-		clState->wsize = 256;
-	else if (strstr(name, "Tahiti"))
-		clState->wsize = 64;
+		kernelinfo->wsize = data->work_size;
+	else
+#ifdef USE_SCRYPT
+	if (malgo->algo == POW_SCRYPT)
+		kernelinfo->wsize = 256;
+	else
+#endif
+	if (strstr(name, "Tahiti"))
+		kernelinfo->wsize = 64;
 	else
 	else
-		clState->wsize = (clState->max_work_size <= 256 ? clState->max_work_size : 256) / clState->vwidth;
-	data->work_size = clState->wsize;
+		kernelinfo->wsize = (clState->max_work_size <= 256 ? clState->max_work_size : 256) / clState->vwidth;
 
 
 #ifdef USE_SCRYPT
 #ifdef USE_SCRYPT
-	if (opt_scrypt) {
-		if (!data->opt_lg) {
-			applog(LOG_DEBUG, "GPU %d: selecting lookup gap of 2", gpu);
-			data->lookup_gap = 2;
-		} else
-			data->lookup_gap = data->opt_lg;
-
-		if (!data->opt_tc) {
+	if (kernelinfo->interface == KL_SCRYPT)
+	{
+		if (!data->thread_concurrency)
+		{
 			unsigned int sixtyfours;
 			unsigned int sixtyfours;
 
 
 			sixtyfours =  data->max_alloc / 131072 / 64 - 1;
 			sixtyfours =  data->max_alloc / 131072 / 64 - 1;
@@ -784,8 +781,7 @@ _clState *initCl(unsigned int gpu, char *name, size_t nameSize)
 					data->thread_concurrency = data->shaders * 5;
 					data->thread_concurrency = data->shaders * 5;
 			}
 			}
 			applog(LOG_DEBUG, "GPU %u: selecting thread concurrency of %lu", gpu,  (unsigned long)data->thread_concurrency);
 			applog(LOG_DEBUG, "GPU %u: selecting thread concurrency of %lu", gpu,  (unsigned long)data->thread_concurrency);
-		} else
-			data->thread_concurrency = data->opt_tc;
+		}
 	}
 	}
 #endif
 #endif
 
 
@@ -800,27 +796,30 @@ _clState *initCl(unsigned int gpu, char *name, size_t nameSize)
 	binary_sizes = calloc(sizeof(size_t) * MAX_GPUDEVICES * 4, 1);
 	binary_sizes = calloc(sizeof(size_t) * MAX_GPUDEVICES * 4, 1);
 	if (unlikely(!binary_sizes)) {
 	if (unlikely(!binary_sizes)) {
 		applog(LOG_ERR, "Unable to calloc binary_sizes");
 		applog(LOG_ERR, "Unable to calloc binary_sizes");
-		return NULL;
+		return false;
 	}
 	}
 	binaries = calloc(sizeof(char *) * MAX_GPUDEVICES * 4, 1);
 	binaries = calloc(sizeof(char *) * MAX_GPUDEVICES * 4, 1);
 	if (unlikely(!binaries)) {
 	if (unlikely(!binaries)) {
 		applog(LOG_ERR, "Unable to calloc binaries");
 		applog(LOG_ERR, "Unable to calloc binaries");
-		return NULL;
+		return false;
 	}
 	}
 
 
 	strcat(binaryfilename, name);
 	strcat(binaryfilename, name);
-	if (clState->goffset)
+	if (kernelinfo->goffset)
 		strcat(binaryfilename, "g");
 		strcat(binaryfilename, "g");
-	if (opt_scrypt) {
 #ifdef USE_SCRYPT
 #ifdef USE_SCRYPT
+	if (kernelinfo->interface == KL_SCRYPT)
+	{
 		sprintf(numbuf, "lg%utc%u", data->lookup_gap, (unsigned int)data->thread_concurrency);
 		sprintf(numbuf, "lg%utc%u", data->lookup_gap, (unsigned int)data->thread_concurrency);
 		strcat(binaryfilename, numbuf);
 		strcat(binaryfilename, numbuf);
+	}
+	else
 #endif
 #endif
-	} else {
+	{
 		sprintf(numbuf, "v%d", clState->vwidth);
 		sprintf(numbuf, "v%d", clState->vwidth);
 		strcat(binaryfilename, numbuf);
 		strcat(binaryfilename, numbuf);
 	}
 	}
-	sprintf(numbuf, "w%d", (int)clState->wsize);
+	sprintf(numbuf, "w%d", (int)kernelinfo->wsize);
 	strcat(binaryfilename, numbuf);
 	strcat(binaryfilename, numbuf);
 	sprintf(numbuf, "l%d", (int)sizeof(long));
 	sprintf(numbuf, "l%d", (int)sizeof(long));
 	strcat(binaryfilename, numbuf);
 	strcat(binaryfilename, numbuf);
@@ -852,7 +851,7 @@ _clState *initCl(unsigned int gpu, char *name, size_t nameSize)
 		if (unlikely(!binaries[slot])) {
 		if (unlikely(!binaries[slot])) {
 			applog(LOG_ERR, "Unable to calloc binaries");
 			applog(LOG_ERR, "Unable to calloc binaries");
 			fclose(binaryfile);
 			fclose(binaryfile);
-			return NULL;
+			return false;
 		}
 		}
 
 
 		if (fread(binaries[slot], 1, binary_sizes[slot], binaryfile) != binary_sizes[slot]) {
 		if (fread(binaries[slot], 1, binary_sizes[slot], binaryfile) != binary_sizes[slot]) {
@@ -862,7 +861,7 @@ _clState *initCl(unsigned int gpu, char *name, size_t nameSize)
 			goto build;
 			goto build;
 		}
 		}
 
 
-		clState->program = clCreateProgramWithBinary(clState->context, 1, &devices[gpu], &binary_sizes[slot], (const unsigned char **)binaries, &status, NULL);
+		kernelinfo->program = clCreateProgramWithBinary(clState->context, 1, &clState->devid, &binary_sizes[slot], (const unsigned char **)binaries, &status, NULL);
 		if (status != CL_SUCCESS) {
 		if (status != CL_SUCCESS) {
 			applog(LOG_ERR, "Error %d: Loading Binary into cl_program (clCreateProgramWithBinary)", status);
 			applog(LOG_ERR, "Error %d: Loading Binary into cl_program (clCreateProgramWithBinary)", status);
 			fclose(binaryfile);
 			fclose(binaryfile);
@@ -881,26 +880,26 @@ _clState *initCl(unsigned int gpu, char *name, size_t nameSize)
 	/////////////////////////////////////////////////////////////////
 	/////////////////////////////////////////////////////////////////
 
 
 build:
 build:
-	clState->program = clCreateProgramWithSource(clState->context, 1, (const char **)&source, sourceSize, &status);
+	kernelinfo->program = clCreateProgramWithSource(clState->context, 1, (const char **)&source, sourceSize, &status);
 	if (status != CL_SUCCESS) {
 	if (status != CL_SUCCESS) {
 		applog(LOG_ERR, "Error %d: Loading Binary into cl_program (clCreateProgramWithSource)", status);
 		applog(LOG_ERR, "Error %d: Loading Binary into cl_program (clCreateProgramWithSource)", status);
-		return NULL;
+		return false;
 	}
 	}
 
 
 	/* create a cl program executable for all the devices specified */
 	/* create a cl program executable for all the devices specified */
 	char *CompilerOptions = calloc(1, 256);
 	char *CompilerOptions = calloc(1, 256);
 
 
 #ifdef USE_SCRYPT
 #ifdef USE_SCRYPT
-	if (opt_scrypt)
+	if (kernelinfo->interface == KL_SCRYPT)
 		sprintf(CompilerOptions, "-D LOOKUP_GAP=%d -D CONCURRENT_THREADS=%d -D WORKSIZE=%d",
 		sprintf(CompilerOptions, "-D LOOKUP_GAP=%d -D CONCURRENT_THREADS=%d -D WORKSIZE=%d",
-			data->lookup_gap, (unsigned int)data->thread_concurrency, (int)clState->wsize);
+			data->lookup_gap, (unsigned int)data->thread_concurrency, (int)kernelinfo->wsize);
 	else
 	else
 #endif
 #endif
 	{
 	{
 		sprintf(CompilerOptions, "-D WORKSIZE=%d -D VECTORS%d -D WORKVEC=%d",
 		sprintf(CompilerOptions, "-D WORKSIZE=%d -D VECTORS%d -D WORKVEC=%d",
-			(int)clState->wsize, clState->vwidth, (int)clState->wsize * clState->vwidth);
+			(int)kernelinfo->wsize, clState->vwidth, (int)kernelinfo->wsize * clState->vwidth);
 	}
 	}
-	applog(LOG_DEBUG, "Setting worksize to %"PRId64, (int64_t)clState->wsize);
+	applog(LOG_DEBUG, "Setting worksize to %"PRId64, (int64_t)kernelinfo->wsize);
 	if (clState->vwidth > 1)
 	if (clState->vwidth > 1)
 		applog(LOG_DEBUG, "Patched source to suit %d vectors", clState->vwidth);
 		applog(LOG_DEBUG, "Patched source to suit %d vectors", clState->vwidth);
 
 
@@ -945,34 +944,34 @@ build:
 	} else
 	} else
 		applog(LOG_DEBUG, "BFI_INT patch requiring device not found, will not BFI_INT patch");
 		applog(LOG_DEBUG, "BFI_INT patch requiring device not found, will not BFI_INT patch");
 
 
-	if (clState->goffset)
+	if (kernelinfo->goffset)
 		strcat(CompilerOptions, " -D GOFFSET");
 		strcat(CompilerOptions, " -D GOFFSET");
 
 
 	if (!clState->hasOpenCL11plus)
 	if (!clState->hasOpenCL11plus)
 		strcat(CompilerOptions, " -D OCL1");
 		strcat(CompilerOptions, " -D OCL1");
 
 
 	applog(LOG_DEBUG, "CompilerOptions: %s", CompilerOptions);
 	applog(LOG_DEBUG, "CompilerOptions: %s", CompilerOptions);
-	status = bfg_clBuildProgram(clState, devices[gpu], CompilerOptions);
+	status = bfg_clBuildProgram(&kernelinfo->program, clState->devid, CompilerOptions);
 	free(CompilerOptions);
 	free(CompilerOptions);
 
 
 	if (status != CL_SUCCESS)
 	if (status != CL_SUCCESS)
-		return NULL;
+		return false;
 
 
 	prog_built = true;
 	prog_built = true;
 	
 	
 	if (!(data->opt_opencl_binaries & OBU_SAVE))
 	if (!(data->opt_opencl_binaries & OBU_SAVE))
 		goto built;
 		goto built;
 
 
-	status = clGetProgramInfo(clState->program, CL_PROGRAM_NUM_DEVICES, sizeof(cl_uint), &cpnd, NULL);
+	status = clGetProgramInfo(kernelinfo->program, CL_PROGRAM_NUM_DEVICES, sizeof(cl_uint), &cpnd, NULL);
 	if (unlikely(status != CL_SUCCESS)) {
 	if (unlikely(status != CL_SUCCESS)) {
 		applog(LOG_ERR, "Error %d: Getting program info CL_PROGRAM_NUM_DEVICES. (clGetProgramInfo)", status);
 		applog(LOG_ERR, "Error %d: Getting program info CL_PROGRAM_NUM_DEVICES. (clGetProgramInfo)", status);
-		return NULL;
+		return false;
 	}
 	}
 
 
-	status = clGetProgramInfo(clState->program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t)*cpnd, binary_sizes, NULL);
+	status = clGetProgramInfo(kernelinfo->program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t)*cpnd, binary_sizes, NULL);
 	if (unlikely(status != CL_SUCCESS)) {
 	if (unlikely(status != CL_SUCCESS)) {
 		applog(LOG_ERR, "Error %d: Getting program info CL_PROGRAM_BINARY_SIZES. (clGetProgramInfo)", status);
 		applog(LOG_ERR, "Error %d: Getting program info CL_PROGRAM_BINARY_SIZES. (clGetProgramInfo)", status);
-		return NULL;
+		return false;
 	}
 	}
 
 
 	/* The actual compiled binary ends up in a RANDOM slot! Grr, so we have
 	/* The actual compiled binary ends up in a RANDOM slot! Grr, so we have
@@ -987,13 +986,13 @@ build:
 	       gpu, (unsigned)slot, (int64_t)binary_sizes[slot]);
 	       gpu, (unsigned)slot, (int64_t)binary_sizes[slot]);
 	if (!binary_sizes[slot]) {
 	if (!binary_sizes[slot]) {
 		applog(LOG_ERR, "OpenCL compiler generated a zero sized binary, FAIL!");
 		applog(LOG_ERR, "OpenCL compiler generated a zero sized binary, FAIL!");
-		return NULL;
+		return false;
 	}
 	}
 	binaries[slot] = calloc(sizeof(char) * binary_sizes[slot], 1);
 	binaries[slot] = calloc(sizeof(char) * binary_sizes[slot], 1);
-	status = clGetProgramInfo(clState->program, CL_PROGRAM_BINARIES, sizeof(char *) * cpnd, binaries, NULL );
+	status = clGetProgramInfo(kernelinfo->program, CL_PROGRAM_BINARIES, sizeof(char *) * cpnd, binaries, NULL );
 	if (unlikely(status != CL_SUCCESS)) {
 	if (unlikely(status != CL_SUCCESS)) {
 		applog(LOG_ERR, "Error %d: Getting program info. CL_PROGRAM_BINARIES (clGetProgramInfo)", status);
 		applog(LOG_ERR, "Error %d: Getting program info. CL_PROGRAM_BINARIES (clGetProgramInfo)", status);
-		return NULL;
+		return false;
 	}
 	}
 
 
 	/* Patch the kernel if the hardware supports BFI_INT but it needs to
 	/* Patch the kernel if the hardware supports BFI_INT but it needs to
@@ -1030,16 +1029,16 @@ build:
 			w, remaining);
 			w, remaining);
 		patch_opcodes(w, length);
 		patch_opcodes(w, length);
 
 
-		status = clReleaseProgram(clState->program);
+		status = clReleaseProgram(kernelinfo->program);
 		if (status != CL_SUCCESS) {
 		if (status != CL_SUCCESS) {
 			applog(LOG_ERR, "Error %d: Releasing program. (clReleaseProgram)", status);
 			applog(LOG_ERR, "Error %d: Releasing program. (clReleaseProgram)", status);
-			return NULL;
+			return false;
 		}
 		}
 
 
-		clState->program = clCreateProgramWithBinary(clState->context, 1, &devices[gpu], &binary_sizes[slot], (const unsigned char **)&binaries[slot], &status, NULL);
+		kernelinfo->program = clCreateProgramWithBinary(clState->context, 1, &clState->devid, &binary_sizes[slot], (const unsigned char **)&binaries[slot], &status, NULL);
 		if (status != CL_SUCCESS) {
 		if (status != CL_SUCCESS) {
 			applog(LOG_ERR, "Error %d: Loading Binary into cl_program (clCreateProgramWithBinary)", status);
 			applog(LOG_ERR, "Error %d: Loading Binary into cl_program (clCreateProgramWithBinary)", status);
-			return NULL;
+			return false;
 		}
 		}
 
 
 		/* Program needs to be rebuilt */
 		/* Program needs to be rebuilt */
@@ -1056,7 +1055,7 @@ build:
 	} else {
 	} else {
 		if (unlikely(fwrite(binaries[slot], 1, binary_sizes[slot], binaryfile) != binary_sizes[slot])) {
 		if (unlikely(fwrite(binaries[slot], 1, binary_sizes[slot], binaryfile) != binary_sizes[slot])) {
 			applog(LOG_ERR, "Unable to fwrite to binaryfile");
 			applog(LOG_ERR, "Unable to fwrite to binaryfile");
-			return NULL;
+			return false;
 		}
 		}
 		fclose(binaryfile);
 		fclose(binaryfile);
 	}
 	}
@@ -1067,27 +1066,28 @@ built:
 	free(binary_sizes);
 	free(binary_sizes);
 
 
 	applog(LOG_INFO, "Initialising kernel %s with%s bitalign, %"PRId64" vectors and worksize %"PRIu64,
 	applog(LOG_INFO, "Initialising kernel %s with%s bitalign, %"PRId64" vectors and worksize %"PRIu64,
-	       filename, clState->hasBitAlign ? "" : "out", (int64_t)clState->vwidth, (uint64_t)clState->wsize);
+	       filename, clState->hasBitAlign ? "" : "out", (int64_t)clState->vwidth, (uint64_t)kernelinfo->wsize);
 
 
 	if (!prog_built) {
 	if (!prog_built) {
 		/* create a cl program executable for all the devices specified */
 		/* create a cl program executable for all the devices specified */
-		status = bfg_clBuildProgram(clState, devices[gpu], NULL);
+		status = bfg_clBuildProgram(&kernelinfo->program, clState->devid, NULL);
 		if (status != CL_SUCCESS)
 		if (status != CL_SUCCESS)
-			return NULL;
+			return false;
 	}
 	}
 
 
 	/* get a kernel object handle for a kernel with the given name */
 	/* get a kernel object handle for a kernel with the given name */
-	clState->kernel = clCreateKernel(clState->program, "search", &status);
+	kernelinfo->kernel = clCreateKernel(kernelinfo->program, "search", &status);
 	if (status != CL_SUCCESS) {
 	if (status != CL_SUCCESS) {
 		applog(LOG_ERR, "Error %d: Creating Kernel from program. (clCreateKernel)", status);
 		applog(LOG_ERR, "Error %d: Creating Kernel from program. (clCreateKernel)", status);
-		return NULL;
+		return false;
 	}
 	}
 	
 	
 	free((void*)cgpu->kname);
 	free((void*)cgpu->kname);
-	cgpu->kname = strdup(data->kernel_file);
+	cgpu->kname = strdup(kernel_file);
 
 
 #ifdef USE_SCRYPT
 #ifdef USE_SCRYPT
-	if (opt_scrypt) {
+	if (kernelinfo->interface == KL_SCRYPT && !clState->padbufsize)
+	{
 		size_t ipt = (1024 / data->lookup_gap + (1024 % data->lookup_gap > 0));
 		size_t ipt = (1024 / data->lookup_gap + (1024 % data->lookup_gap > 0));
 		size_t bufsize = 128 * ipt * data->thread_concurrency;
 		size_t bufsize = 128 * ipt * data->thread_concurrency;
 
 
@@ -1107,24 +1107,20 @@ built:
 		clState->padbuffer8 = clCreateBuffer(clState->context, CL_MEM_READ_WRITE, bufsize, NULL, &status);
 		clState->padbuffer8 = clCreateBuffer(clState->context, CL_MEM_READ_WRITE, bufsize, NULL, &status);
 		if (status != CL_SUCCESS && !clState->padbuffer8) {
 		if (status != CL_SUCCESS && !clState->padbuffer8) {
 			applog(LOG_ERR, "Error %d: clCreateBuffer (padbuffer8), decrease TC or increase LG", status);
 			applog(LOG_ERR, "Error %d: clCreateBuffer (padbuffer8), decrease TC or increase LG", status);
-			return NULL;
+			return false;
 		}
 		}
 
 
 		clState->CLbuffer0 = clCreateBuffer(clState->context, CL_MEM_READ_ONLY, 128, NULL, &status);
 		clState->CLbuffer0 = clCreateBuffer(clState->context, CL_MEM_READ_ONLY, 128, NULL, &status);
 		if (status != CL_SUCCESS) {
 		if (status != CL_SUCCESS) {
 			applog(LOG_ERR, "Error %d: clCreateBuffer (CLbuffer0)", status);
 			applog(LOG_ERR, "Error %d: clCreateBuffer (CLbuffer0)", status);
-			return NULL;
+			return false;
 		}
 		}
-		clState->outputBuffer = clCreateBuffer(clState->context, CL_MEM_WRITE_ONLY, SCRYPT_BUFFERSIZE, NULL, &status);
-	} else
-#endif
-	clState->outputBuffer = clCreateBuffer(clState->context, CL_MEM_WRITE_ONLY, BUFFERSIZE, NULL, &status);
-	if (status != CL_SUCCESS) {
-		applog(LOG_ERR, "Error %d: clCreateBuffer (outputBuffer)", status);
-		return NULL;
 	}
 	}
+#endif
 
 
-	return clState;
+	kernelinfo->loaded = true;
+	return true;
 }
 }
+
 #endif /* HAVE_OPENCL */
 #endif /* HAVE_OPENCL */
 
 

+ 29 - 8
ocl.h

@@ -11,11 +11,32 @@
 
 
 #include "miner.h"
 #include "miner.h"
 
 
-typedef struct {
-	cl_context context;
+struct opencl_kernel_info;
+typedef struct _clState _clState;
+
+typedef cl_int (*queue_kernel_parameters_func_t)(const struct opencl_kernel_info *, _clState *, struct work *, cl_uint);
+
+struct opencl_kernel_info {
+	bool loaded;
+	cl_program program;
 	cl_kernel kernel;
 	cl_kernel kernel;
+	bool goffset;
+	enum cl_kernels interface;
+	size_t wsize;
+	queue_kernel_parameters_func_t queue_kernel_parameters;
+};
+
+struct _clState {
+	cl_device_id devid;
+	char *platform_ver_str;
+	bool is_mesa;
+	
+	cl_context context;
 	cl_command_queue commandQueue;
 	cl_command_queue commandQueue;
-	cl_program program;
+	
+	struct opencl_kernel_info kernel_sha256d;
+	struct opencl_kernel_info kernel_scrypt;
+	
 	cl_mem outputBuffer;
 	cl_mem outputBuffer;
 #ifdef USE_SCRYPT
 #ifdef USE_SCRYPT
 	cl_mem CLbuffer0;
 	cl_mem CLbuffer0;
@@ -25,17 +46,17 @@ typedef struct {
 #endif
 #endif
 	bool hasBitAlign;
 	bool hasBitAlign;
 	bool hasOpenCL11plus;
 	bool hasOpenCL11plus;
-	bool goffset;
+	cl_uint preferred_vwidth;
 	cl_uint vwidth;
 	cl_uint vwidth;
 	size_t max_work_size;
 	size_t max_work_size;
-	size_t wsize;
 	cl_uint max_compute_units;
 	cl_uint max_compute_units;
-	enum cl_kernels chosen_kernel;
-} _clState;
+};
 
 
 extern FILE *opencl_open_kernel(const char *filename);
 extern FILE *opencl_open_kernel(const char *filename);
 extern char *file_contents(const char *filename, int *length);
 extern char *file_contents(const char *filename, int *length);
+extern char *opencl_kernel_source(const char *filename, int *out_sourcelen, enum cl_kernels *out_kinterface);
 extern int clDevicesNum(void);
 extern int clDevicesNum(void);
-extern _clState *initCl(unsigned int gpu, char *name, size_t nameSize);
+extern _clState *opencl_create_clState(unsigned int gpu, char *name, size_t nameSize);
+extern bool opencl_load_kernel(struct cgpu_info *, _clState *clState, const char *name, struct opencl_kernel_info *, const char *kernel_file, const struct mining_algorithm *);
 #endif /* HAVE_OPENCL */
 #endif /* HAVE_OPENCL */
 #endif /* __OCL_H__ */
 #endif /* __OCL_H__ */

+ 1 - 1
openwrt/bfgminer/Makefile

@@ -11,7 +11,7 @@ include $(TOPDIR)/rules.mk
 
 
 PKG_NAME:=bfgminer
 PKG_NAME:=bfgminer
 PKG_TITLE:=BFGMiner
 PKG_TITLE:=BFGMiner
-PKG_VERSION:=4.9.0
+PKG_VERSION:=4.10.0
 PKG_RELEASE:=1
 PKG_RELEASE:=1
 
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).txz
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).txz

+ 3 - 3
scrypt.c

@@ -489,15 +489,15 @@ void scrypt_regenhash(struct work *work)
 }
 }
 
 
 /* Used by test_nonce functions */
 /* Used by test_nonce functions */
-void scrypt_hash_data(unsigned char * const out_hash, const unsigned char * const pdata)
+void scrypt_hash_data(void * const out_hash, const void * const pdata)
 {
 {
 	uint32_t data[20], ohash[8];
 	uint32_t data[20], ohash[8];
 	char *scratchbuf;
 	char *scratchbuf;
 
 
-	be32enc_vect(data, (const uint32_t *)pdata, 20);
+	be32enc_vect(data, pdata, 20);
 	scratchbuf = alloca(SCRATCHBUF_SIZE);
 	scratchbuf = alloca(SCRATCHBUF_SIZE);
 	scrypt_1024_1_1_256_sp(data, scratchbuf, ohash);
 	scrypt_1024_1_1_256_sp(data, scratchbuf, ohash);
-	swap32tobe((void*)out_hash, ohash, 32/4);
+	swap32tobe(out_hash, ohash, 32/4);
 }
 }
 
 
 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,

+ 1 - 1
scrypt.h

@@ -7,7 +7,7 @@
 
 
 #ifdef USE_SCRYPT
 #ifdef USE_SCRYPT
 extern void test_scrypt(void);
 extern void test_scrypt(void);
-extern void scrypt_hash_data(unsigned char *out_hash, const unsigned char *data);
+extern void scrypt_hash_data(void *digest, const void *data);
 extern void scrypt_regenhash(struct work *work);
 extern void scrypt_regenhash(struct work *work);
 
 
 #else /* USE_SCRYPT */
 #else /* USE_SCRYPT */

+ 65 - 4
titan-asic.c

@@ -147,13 +147,74 @@ bool knc_titan_get_report(const char *repr, void * const ctx, int channel, int d
 	return true;
 	return true;
 }
 }
 
 
-/* Use bare function without extra checks */
-extern bool knc_titan_setup_core_(void * const ctx, int channel, int die, int core, struct titan_setup_core_params *params);
-
 /* This fails if core is hashing!
 /* This fails if core is hashing!
  * Stop it before setting up.
  * Stop it before setting up.
  */
  */
 bool knc_titan_setup_core_local(const char *repr, void * const ctx, int channel, int die, int core, struct titan_setup_core_params *params)
 bool knc_titan_setup_core_local(const char *repr, void * const ctx, int channel, int die, int core, struct titan_setup_core_params *params)
 {
 {
-	return knc_titan_setup_core_(ctx, channel, die, core, params);
+	return knc_titan_setup_core_(LOG_INFO, ctx, channel, die, core, params);
+}
+
+bool knc_titan_setup_spi(const char *repr, void * const ctx, int asic, int divider, int preclk, int declk, int sslowmin)
+{
+	uint8_t request[7];
+	int request_length;
+	int status;
+
+	request_length = knc_prepare_titan_setup(request, asic, divider, preclk, declk, sslowmin);
+
+	status = knc_syncronous_transfer_fpga(ctx, request_length, request, 0, NULL);
+	if (status) {
+		applog(LOG_INFO, "%s[%d]: setup_spi failed (%x)", repr, asic, status);
+		return false;
+	}
+
+	return true;
+}
+
+bool knc_titan_set_work_parallel(const char *repr, void * const ctx, int asic, int die, int core_start, int slot, struct work *work, bool urgent, int num, int resend)
+{
+	uint8_t request[9 + BLOCK_HEADER_BYTES_WITHOUT_NONCE];
+	int request_length;
+	int status;
+
+	request_length = knc_prepare_titan_work_request(request, asic, die, slot, core_start, core_start + num - 1, resend, work);
+
+	status = knc_syncronous_transfer_fpga(ctx, request_length, request, 0, NULL);
+	if (status) {
+		applog(LOG_INFO, "%s[%d]: set_work_parallel failed (%x)", repr, asic, status);
+		return false;
+	}
+
+	return true;
+}
+
+bool knc_titan_get_work_status(const char *repr, void * const ctx, int asic, int *num_request_busy, int *num_status_byte_error)
+{
+	uint8_t request[2];
+	int request_length;
+	int response_length = 12;
+	uint8_t response[response_length];
+	int status;
+	uint8_t num_request_busy_byte;
+	uint16_t num_status_byte_error_counters[4];
+
+	request_length = knc_prepare_titan_work_status(request, asic);
+
+	status = knc_syncronous_transfer_fpga(ctx, request_length, request, response_length, response);
+	if (status) {
+		applog(LOG_INFO, "%s[%d]: get_work_status failed (%x)", repr, asic, status);
+		return false;
+	}
+
+	status = knc_decode_work_status(response + 2, &num_request_busy_byte, num_status_byte_error_counters);
+	if (status) {
+		applog(LOG_INFO, "%s[%d]: get_work_status got undefined response", repr, asic);
+		return false;
+	}
+
+	*num_request_busy = num_request_busy_byte;
+	for (int i = 0 ; i < KNC_STATUS_BYTE_ERROR_COUNTERS ; i++)
+		num_status_byte_error[i] = num_status_byte_error_counters[i];
+	return true;
 }
 }

+ 14 - 0
titan-asic.h

@@ -16,6 +16,17 @@
 #define	KNC_TITAN_MIN_WORK_SLOT_NUM	1
 #define	KNC_TITAN_MIN_WORK_SLOT_NUM	1
 #define	KNC_TITAN_MAX_WORK_SLOT_NUM	15
 #define	KNC_TITAN_MAX_WORK_SLOT_NUM	15
 
 
+#define KNC_TITAN_FPGA_SYSCLK_FREQ      24576000
+#define KNC_TITAN_FPGA_SPI_FREQ         6144000
+#define KNC_TITAN_FPGA_SPI_DIVIDER      (KNC_TITAN_FPGA_SYSCLK_FREQ / (2*KNC_TITAN_FPGA_SPI_FREQ) - 1)
+#if KNC_TITAN_FPGA_SYSCLK_FREQ % (2*KNC_TITAN_FPGA_SPI_FREQ) != 0
+#warning Requested SPI frequency could not be accomplished exactly, adjusting as needed
+#endif
+#define KNC_TITAN_FPGA_SPI_PRECLK       7
+#define KNC_TITAN_FPGA_SPI_DECLK        7
+#define KNC_TITAN_FPGA_SPI_SSLOWMIN     15
+#define KNC_TITAN_FPGA_RETRIES          1
+
 struct nonce_report {
 struct nonce_report {
 	uint32_t nonce;
 	uint32_t nonce;
 	uint8_t slot;
 	uint8_t slot;
@@ -26,5 +37,8 @@ bool knc_titan_set_work(const char *repr, void * const ctx, int channel, int die
 bool knc_titan_set_work_multi(const char *repr, void * const ctx, int channel, int die, int core_start, int slot, struct work *work, bool urgent, bool *work_accepted, struct knc_report *reports, int num);
 bool knc_titan_set_work_multi(const char *repr, void * const ctx, int channel, int die, int core_start, int slot, struct work *work, bool urgent, bool *work_accepted, struct knc_report *reports, int num);
 bool knc_titan_get_report(const char *repr, void * const ctx, int channel, int die, int core, struct knc_report *report);
 bool knc_titan_get_report(const char *repr, void * const ctx, int channel, int die, int core, struct knc_report *report);
 bool knc_titan_setup_core_local(const char *repr, void * const ctx, int channel, int die, int core, struct titan_setup_core_params *params);
 bool knc_titan_setup_core_local(const char *repr, void * const ctx, int channel, int die, int core, struct titan_setup_core_params *params);
+bool knc_titan_setup_spi(const char *repr, void * const ctx, int asic, int divider, int preclk, int declk, int sslowmin);
+bool knc_titan_set_work_parallel(const char *repr, void * const ctx, int asic, int die, int core_start, int slot, struct work *work, bool urgent, int num, int resend);
+bool knc_titan_get_work_status(const char *repr, void * const ctx, int asic, int *num_request_busy, int *num_status_byte_error);
 
 
 #endif /* __TITAN_ASIC_H */
 #endif /* __TITAN_ASIC_H */

+ 109 - 3
util.c

@@ -790,7 +790,7 @@ char *ucs2_to_utf8_dup(uint16_t * const in, size_t sz)
 	return out;
 	return out;
 }
 }
 
 
-void hash_data(unsigned char *out_hash, const unsigned char *data)
+void hash_data(void *out_hash, const void *data)
 {
 {
 	unsigned char blkheader[80];
 	unsigned char blkheader[80];
 	
 	
@@ -1957,6 +1957,17 @@ bool isCalpha(const int c)
 	return false;
 	return false;
 }
 }
 
 
+bool match_strtok(const char * const optlist, const char * const delim, const char * const needle)
+{
+	const size_t optlist_sz = strlen(optlist) + 1;
+	char opts[optlist_sz];
+	memcpy(opts, optlist, optlist_sz);
+	for (char *el, *nextptr, *s = opts; (el = strtok_r(s, delim, &nextptr)); s = NULL)
+		if (!strcasecmp(el, needle))
+			return true;
+	return false;
+}
+
 static
 static
 bool _appdata_file_call(const char * const appname, const char * const filename, const appdata_file_callback_t cb, void * const userp, const char * const path)
 bool _appdata_file_call(const char * const appname, const char * const filename, const appdata_file_callback_t cb, void * const userp, const char * const path)
 {
 {
@@ -2553,6 +2564,19 @@ static bool parse_notify(struct pool *pool, json_t *val)
 	pool->submit_old = !clean;
 	pool->submit_old = !clean;
 	pool->swork.clean = true;
 	pool->swork.clean = true;
 	
 	
+	// stratum_set_goal ensures these are the same pointer if they match
+	if (pool->goalname != pool->next_goalname)
+	{
+		free(pool->goalname);
+		pool->goalname = pool->next_goalname;
+		mining_goal_reset(pool->goal);
+	}
+	if (pool->next_goal_malgo)
+	{
+		goal_set_malgo(pool->goal, pool->next_goal_malgo);
+		pool->next_goal_malgo = NULL;
+	}
+	
 	if (pool->next_nonce1)
 	if (pool->next_nonce1)
 	{
 	{
 		free(pool->swork.nonce1);
 		free(pool->swork.nonce1);
@@ -2629,6 +2653,8 @@ out:
 
 
 static bool parse_diff(struct pool *pool, json_t *val)
 static bool parse_diff(struct pool *pool, json_t *val)
 {
 {
+	const struct mining_goal_info * const goal = pool->goal;
+	const struct mining_algorithm * const malgo = goal->malgo;
 	double diff;
 	double diff;
 
 
 	diff = json_number_value(json_array_get(val, 0));
 	diff = json_number_value(json_array_get(val, 0));
@@ -2642,7 +2668,7 @@ static bool parse_diff(struct pool *pool, json_t *val)
 		diff = bdiff_to_pdiff(diff);
 		diff = bdiff_to_pdiff(diff);
 	}
 	}
 	
 	
-	if ((!opt_scrypt) && diff < 1 && diff > 0.999)
+	if (malgo->algo == POW_SHA256D && diff < 1 && diff > 0.999)
 		diff = 1;
 		diff = 1;
 	
 	
 #ifdef USE_SCRYPT
 #ifdef USE_SCRYPT
@@ -2660,7 +2686,7 @@ static bool parse_diff(struct pool *pool, json_t *val)
 	// Diff 16 at 1.15 Gh/s = 1 share / 60s
 	// Diff 16 at 1.15 Gh/s = 1 share / 60s
 	// Diff 16 at 7.00 Gh/s = 1 share / 10s
 	// Diff 16 at 7.00 Gh/s = 1 share / 10s
 
 
-	if (opt_scrypt && (diff >= minimum_broken_scrypt_diff))
+	if (malgo->algo == POW_SCRYPT && (diff >= minimum_broken_scrypt_diff))
 		diff /= broken_scrypt_diff_multiplier;
 		diff /= broken_scrypt_diff_multiplier;
 #endif
 #endif
 
 
@@ -2739,6 +2765,72 @@ err:
 	return true;
 	return true;
 }
 }
 
 
+static
+bool stratum_set_goal(struct pool * const pool, json_t * const val, json_t * const params)
+{
+	if (!uri_get_param_bool(pool->rpc_url, "goalreset", false))
+		return false;
+	
+	const char * const new_goalname = __json_array_string(params, 0);
+	struct mining_algorithm *new_malgo = NULL;
+	const char *emsg = NULL;
+	
+	if (json_is_array(params) && json_array_size(params) > 1)
+	{
+		json_t * const j_goaldesc = json_array_get(params, 1);
+		if (json_is_object(j_goaldesc))
+		{
+			json_t * const j_malgo = json_object_get(j_goaldesc, "malgo");
+			if (j_malgo && json_is_string(j_malgo))
+			{
+				const char * const newvalue = json_string_value(j_malgo);
+				new_malgo = mining_algorithm_by_alias(newvalue);
+				// Even if it's the current malgo, we should reset next_goal_malgo in case of a prior set_goal
+				if (new_malgo == pool->goal->malgo)
+				{}  // Do nothing, assignment takes place below
+				if (new_malgo && uri_get_param_bool(pool->rpc_url, "change_goal_malgo", false))
+				{}  // Do nothing, assignment takes place below
+				else
+				{
+					emsg = "Mining algorithm not supported";
+					// Ignore even the goal name, if we are failing
+					goto out;
+				}
+				if (new_malgo == pool->goal->malgo)
+					new_malgo = NULL;
+			}
+		}
+	}
+	
+	// Even if the goal name is not changing, we need to adopt and configuration change
+	pool->next_goal_malgo = new_malgo;
+	
+	if (pool->next_goalname && pool->next_goalname != pool->goalname)
+		free(pool->next_goalname);
+	
+	// This compares goalname to new_goalname, but matches NULL correctly :)
+	if (pool->goalname ? !strcmp(pool->goalname, new_goalname) : !new_goalname)
+		pool->next_goalname = pool->goalname;
+	else
+		pool->next_goalname = maybe_strdup(new_goalname);
+	
+out: ;
+	json_t * const j_id = json_object_get(val, "id");
+	if (j_id && !json_is_null(j_id))
+	{
+		char * const idstr = json_dumps_ANY(j_id, 0);
+		char buf[0x80];
+		if (unlikely(emsg))
+			snprintf(buf, sizeof(buf), "{\"id\":%s,\"result\":true,\"error\":null}", idstr);
+		else
+			snprintf(buf, sizeof(buf), "{\"id\":%s,\"result\":null,\"error\":[-1,\"%s\",null]}", idstr, emsg);
+		free(idstr);
+		stratum_send(pool, buf, strlen(buf));
+	}
+	
+	return true;
+}
+
 static bool parse_reconnect(struct pool *pool, json_t *val)
 static bool parse_reconnect(struct pool *pool, json_t *val)
 {
 {
 	if (opt_disable_client_reconnect)
 	if (opt_disable_client_reconnect)
@@ -2905,6 +2997,10 @@ bool parse_method(struct pool *pool, char *s)
 		goto out;
 		goto out;
 	}
 	}
 	
 	
+	// Usage: mining.set_goal("goal name", {"malgo":"SHA256d", ...})
+	if (!strncasecmp(buf, "mining.set_goal", 15) && stratum_set_goal(pool, val, params))
+		return_via(out, ret = true);
+	
 out:
 out:
 	if (val)
 	if (val)
 		json_decref(val);
 		json_decref(val);
@@ -3179,6 +3275,16 @@ resend:
 		recvd = true;
 		recvd = true;
 	}
 	}
 	
 	
+	if (uri_get_param_bool(pool->rpc_url, "goalreset", false))
+	{
+		// Default: ["notify", "set_difficulty"] (but these must be explicit if mining.capabilities is used)
+		sprintf(s, "{\"id\":null,\"method\":\"mining.capabilities\",\"params\":[[\"notify\",\"set_difficulty\",\"set_goal\"]");
+		if (request_target_str)
+			tailsprintf(s, sizeof(s), ", {\"suggested_target\":\"%s\"}", request_target_str);
+		tailsprintf(s, sizeof(s), "]}");
+		_stratum_send(pool, s, strlen(s), true);
+	}
+	
 	if (noresume) {
 	if (noresume) {
 		sprintf(s, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": []}", swork_id++);
 		sprintf(s, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": []}", swork_id++);
 	} else {
 	} else {

+ 3 - 1
util.h

@@ -125,6 +125,8 @@ bool isCspace(int c)
 	}
 	}
 }
 }
 
 
+extern bool match_strtok(const char *optlist, const char *delim, const char *needle);
+
 typedef bool (*appdata_file_callback_t)(const char *, void *);
 typedef bool (*appdata_file_callback_t)(const char *, void *);
 extern bool appdata_file_call(const char *appname, const char *filename, appdata_file_callback_t, void *userp);
 extern bool appdata_file_call(const char *appname, const char *filename, appdata_file_callback_t, void *userp);
 extern char *appdata_file_find_first(const char *appname, const char *filename);
 extern char *appdata_file_find_first(const char *appname, const char *filename);
@@ -192,7 +194,7 @@ extern char *ucs2_to_utf8_dup(uint16_t *in, size_t sz);
 }while(0)
 }while(0)
 
 
 extern void gen_hash(unsigned char *data, unsigned char *hash, int len);
 extern void gen_hash(unsigned char *data, unsigned char *hash, int len);
-extern void hash_data(unsigned char *out_hash, const unsigned char *data);
+extern void hash_data(void *digest, const void *data);
 extern void real_block_target(unsigned char *target, const unsigned char *data);
 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);

+ 5 - 1
winhacks.h

@@ -3,8 +3,12 @@
 
 
 #include <winsock2.h>
 #include <winsock2.h>
 
 
-// wincon.h contains a MOUSE_MOVED that conflicts with curses
+// wincon.h contains a KEY_EVENT that conflicts with ncurses
 #include <wincon.h>
 #include <wincon.h>
+#ifdef KEY_EVENT
+#	undef KEY_EVENT
+#endif
+// wincon.h contains a MOUSE_MOVED that conflicts with curses
 #ifdef MOUSE_MOVED
 #ifdef MOUSE_MOVED
 #	undef MOUSE_MOVED
 #	undef MOUSE_MOVED
 #endif
 #endif

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