Browse Source

Merge commit '5c7e0308' into mm_lastwork

Luke Dashjr 13 years ago
parent
commit
61ceb7e2ce
30 changed files with 2802 additions and 822 deletions
  1. 52 5
      API-README
  2. 54 42
      FPGA-README
  3. 1 1
      Makefile.am
  4. 208 0
      NEWS
  5. 28 10
      README
  6. 33 9
      adl.c
  7. 3 3
      adl.h
  8. 611 164
      api.c
  9. 345 126
      cgminer.c
  10. 3 3
      configure.ac
  11. 370 80
      driver-bitforce.c
  12. 13 17
      driver-cpu.c
  13. 1 1
      driver-cpu.h
  14. 40 29
      driver-icarus.c
  15. 11 10
      driver-modminer.c
  16. 29 35
      driver-opencl.c
  17. 13 14
      driver-ztex.c
  18. 63 38
      fpgautils.c
  19. 4 4
      fpgautils.h
  20. 112 24
      miner.h
  21. 739 133
      miner.php
  22. 2 2
      sha256_4way.c
  23. 2 2
      sha256_altivec_4way.c
  24. 4 6
      sha256_cryptopp.c
  25. 2 2
      sha256_generic.c
  26. 2 2
      sha256_sse2_amd64.c
  27. 2 2
      sha256_sse2_i386.c
  28. 2 2
      sha256_sse4_amd64.c
  29. 2 2
      sha256_via.c
  30. 51 54
      util.c

+ 52 - 5
API-README

@@ -19,8 +19,9 @@ IP addresses are automatically padded with extra '.0's as needed
 Without a /prefix is the same as specifying /32
 Without a /prefix is the same as specifying /32
 0/0 means all IP addresses.
 0/0 means all IP addresses.
 The 'W:' on the front gives that address/subnet privileged access to commands
 The 'W:' on the front gives that address/subnet privileged access to commands
-that modify cgminer.
+that modify cgminer (thus all API commands)
 Without it those commands return an access denied status.
 Without it those commands return an access denied status.
+See --api-groups below to define other groups like W:
 Privileged access is checked in the order the IP addresses were supplied to
 Privileged access is checked in the order the IP addresses were supplied to
 "--api-allow"
 "--api-allow"
 The first match determines the privilege level.
 The first match determines the privilege level.
@@ -28,6 +29,26 @@ Using the "--api-allow" option overides the "--api-network" option if they
 are both specified
 are both specified
 With "--api-allow", 127.0.0.1 is not by default given access unless specified
 With "--api-allow", 127.0.0.1 is not by default given access unless specified
 
 
+More groups (like the privileged group W:) can be defined using the
+--api-groups command
+Valid groups are only the letters A-Z (except R & W are predefined) and are
+not case sensitive
+The R: group is the same as not privileged access
+The W: group is (as stated) privileged access (thus all API commands)
+To give an IP address/subnet access to a group you use the group letter
+in front of the IP address instead of W: e.g. P:192.168.0/32
+An IP address/subnet can only be a member of one group
+A sample API group would be:
+ --api-groups P:switchpool:enablepool:addpool:disablepool:removepool:*
+This would create a group 'P' that can do all current pool commands and all
+non-priviliged commands - the '*' means all non-priviledged commands
+Without the '*' the group would only have access to the pool commands
+Defining multiple groups example:
+ --api-groups Q:quit:restart:*,S:save
+This would define 2 groups:
+ Q: that can 'quit' and 'restart' as well as all non-priviledged commands
+ S: that can only 'save' and no other commands
+
 The RPC API request can be either simple text or JSON.
 The RPC API request can be either simple text or JSON.
 
 
 If the request is JSON (starts with '{'), it will reply with a JSON formatted
 If the request is JSON (starts with '{'), it will reply with a JSON formatted
@@ -80,14 +101,14 @@ The STATUS section is:
    This defaults to the cgminer version but is the value of --api-description
    This defaults to the cgminer version but is the value of --api-description
    if it was specified at runtime.
    if it was specified at runtime.
 
 
-For API version 1.9:
+For API version 1.10 and later:
 
 
 The list of requests - a (*) means it requires privileged access - and replies are:
 The list of requests - a (*) means it requires privileged access - and replies are:
 
 
  Request       Reply Section  Details
  Request       Reply Section  Details
  -------       -------------  -------
  -------       -------------  -------
- version       VERSION        CGMiner=cgminer version
-                              API=API version
+ version       VERSION        CGMiner=cgminer, version
+                              API=API| version
 
 
  config        CONFIG         Some miner configuration information:
  config        CONFIG         Some miner configuration information:
                               GPU Count=N, <- the number of GPUs
                               GPU Count=N, <- the number of GPUs
@@ -243,6 +264,9 @@ The list of requests - a (*) means it requires privileged access - and replies a
                               Device drivers are also able to add stats to the
                               Device drivers are also able to add stats to the
                               end of the details returned
                               end of the details returned
 
 
+ check|cmd     COMMAND        Exists=Y/N, <- 'cmd' exists in this version
+                              Access=Y/N| <- you have access to use 'cmd'
+
 When you enable, disable or restart a GPU or PGA, you will also get Thread messages
 When you enable, disable or restart a GPU or PGA, you will also get Thread messages
 in the cgminer status window
 in the cgminer status window
 
 
@@ -285,11 +309,34 @@ miner.php - an example web page to access the API
 Feature Changelog for external applications using the API:
 Feature Changelog for external applications using the API:
 
 
 
 
-API V1.12
+API V1.14
+
+Modified API commands:
+ 'stats' - more icarus timing stats added
+ 'notify' - include new device comms error counter
+
+The internal code for handling data was rewritten (~25% of the code)
+Completely backward compatible
+
+----------
+
+API V1.13 (cgminer v2.4.4)
+
+Added API commands:
+ 'check'
+
+Support was added to cgminer for API access groups with the --api-groups option
+It's 100% backward compatible with previous --api-access commands
+
+----------
+
+API V1.12 (cgminer v2.4.3)
 
 
 Modified API commands:
 Modified API commands:
  'stats' - more pool stats added
  'stats' - more pool stats added
 
 
+Support for the ModMinerQuad FPGA was added
+
 ----------
 ----------
 
 
 API V1.11 (cgminer v2.4.2)
 API V1.11 (cgminer v2.4.2)

+ 54 - 42
FPGA-README

@@ -1,6 +1,18 @@
 
 
 This README contains extended details about FPGA mining with cgminer
 This README contains extended details about FPGA mining with cgminer
 
 
+Bitforce
+
+--bfl-range         Use nonce range on bitforce devices if supported
+
+This option is only for bitforce devices. Earlier devices such as the single
+did not have any way of doing small amounts of work which meant that a lot of
+work could be lost across block changes. Some of the "minirigs" have support
+for doing this, so less work is lost across a longpoll. However, it comes at
+a cost of 1% in overall hashrate so this feature is disabled by default. It
+is only recommended you enable this if you are mining with a minirig on
+p2pool.
+
 
 
 Icarus
 Icarus
 
 
@@ -12,45 +24,45 @@ There is a hidden option in cgminer when Icarus support is compiled in:
            long          Re-calculate the hash time continuously
            long          Re-calculate the hash time continuously
            value[=N]     Specify the hash time in nanoseconds (e.g. 2.6316) and abort time (e.g. 2.6316=80)
            value[=N]     Specify the hash time in nanoseconds (e.g. 2.6316) and abort time (e.g. 2.6316=80)
 
 
-     Icarus timing is required for devices that do not exactly match a default Icarus Rev3 in
-     processing speed
-     If you have an Icarus Rev3 you should not normally need to use --icarus-timing since the
-     default values will maximise the MH/s and display it correctly
-
-     Icarus timing is used to determine the number of hashes that have been checked when it aborts
-     a nonce range (including on a LongPoll)
-     It is also used to determine the elapsed time when it should abort a nonce range to avoid
-     letting the Icarus go idle, but also to safely maximise that time
-
-     'short' or 'long' mode should only be used on a computer that has enough CPU available to run
-     cgminer without any CPU delays (an active desktop or swapping computer would not be stable enough)
-     Any CPU delays while calculating the hash time will affect the result
-     'short' mode only requires the computer to be stable until it has completed ~315 difficulty 1 shares
-     'long' mode requires it to always be stable to ensure accuracy, however, over time it continually
-     corrects itself
-
-     When in 'short' or 'long' mode, it will report the hash time value each time it is re-calculated
-     In 'short' or 'long' mode, the scan abort time starts at 5 seconds and uses the default 2.6316ns
-     scan hash time, for the first 5 nonce's or one minute (whichever is longer)
-
-     In 'default' or 'value' mode the 'constants' are calculated once at the start, based on the default
-     value or the value specified
-     The optional additional =N specifies to set the default abort at N 1/10ths of a second, not the
-     calculated value, which is 112 for 2.6316ns
-
-     To determine the hash time value for a non Icarus Rev3 device or an Icarus Rev3 with a different
-     bitstream to the default one, use 'long' mode and give it at least a few hundred shares, or use
-     'short' mode and take note of the final hash time value (Hs) calculated
-     You can also use the RPC API 'stats' command to see the current hash time (Hs) at any time
-
-     The Icarus code currently only works with a dual FPGA device that supports the same commands as
-     Icarus Rev3 requires and also is less than ~840MH/s and greater than 2MH/s
-     If a dual FPGA device does hash faster than ~840MH/s it should work correctly if you supply the
-     correct hash time nanoseconds value
-
-     The timing code itself will affect the Icarus performance since it increases the delay after
-     work is completed or aborted until it starts again
-     The increase is, however, extremely small and the actual increase is reported with the
-     RPC API 'stats' command (a very slow CPU will make it more noticeable)
-     Using the 'short' mode will remove this delay after 'short' mode completes
-     The delay doesn't affect the calculation of the correct hash time
+Icarus timing is required for devices that do not exactly match a default Icarus Rev3 in
+processing speed
+If you have an Icarus Rev3 you should not normally need to use --icarus-timing since the
+default values will maximise the MH/s and display it correctly
+
+Icarus timing is used to determine the number of hashes that have been checked when it aborts
+a nonce range (including on a LongPoll)
+It is also used to determine the elapsed time when it should abort a nonce range to avoid
+letting the Icarus go idle, but also to safely maximise that time
+
+'short' or 'long' mode should only be used on a computer that has enough CPU available to run
+cgminer without any CPU delays (an active desktop or swapping computer would not be stable enough)
+Any CPU delays while calculating the hash time will affect the result
+'short' mode only requires the computer to be stable until it has completed ~315 difficulty 1 shares
+'long' mode requires it to always be stable to ensure accuracy, however, over time it continually
+corrects itself
+
+When in 'short' or 'long' mode, it will report the hash time value each time it is re-calculated
+In 'short' or 'long' mode, the scan abort time starts at 5 seconds and uses the default 2.6316ns
+scan hash time, for the first 5 nonce's or one minute (whichever is longer)
+
+In 'default' or 'value' mode the 'constants' are calculated once at the start, based on the default
+value or the value specified
+The optional additional =N specifies to set the default abort at N 1/10ths of a second, not the
+calculated value, which is 112 for 2.6316ns
+
+To determine the hash time value for a non Icarus Rev3 device or an Icarus Rev3 with a different
+bitstream to the default one, use 'long' mode and give it at least a few hundred shares, or use
+'short' mode and take note of the final hash time value (Hs) calculated
+You can also use the RPC API 'stats' command to see the current hash time (Hs) at any time
+
+The Icarus code currently only works with a dual FPGA device that supports the same commands as
+Icarus Rev3 requires and also is less than ~840MH/s and greater than 2MH/s
+If a dual FPGA device does hash faster than ~840MH/s it should work correctly if you supply the
+correct hash time nanoseconds value
+
+The timing code itself will affect the Icarus performance since it increases the delay after
+work is completed or aborted until it starts again
+The increase is, however, extremely small and the actual increase is reported with the
+RPC API 'stats' command (a very slow CPU will make it more noticeable)
+Using the 'short' mode will remove this delay after 'short' mode completes
+The delay doesn't affect the calculation of the correct hash time

+ 1 - 1
Makefile.am

@@ -69,7 +69,7 @@ endif # HAS_YASM
 endif # HAS_CPUMINE
 endif # HAS_CPUMINE
 
 
 if NEED_FPGAUTILS
 if NEED_FPGAUTILS
-cgminer_SOURCES += fpgautils.c
+cgminer_SOURCES += fpgautils.c fpgautils.h
 endif
 endif
 
 
 if HAS_BITFORCE
 if HAS_BITFORCE

+ 208 - 0
NEWS

@@ -1,3 +1,211 @@
+Version 2.5.0 - July 6, 2012
+
+- Fix --benchmark not working since the dynamic addition of pools and pool
+stats.
+- Make disabling BFL nonce range support a warning since it has to be explicitly
+enabled on the command line now.
+- miner.php allow renaming table headers
+- Make bitforce nonce range support a command line option --bfl-range since
+enabling it decrease hashrate by 1%.
+- Add sanity checking to make sure we don't make sleep_ms less than 0 in
+bitforce.
+- The fastest minirig devices need a significantly smaller starting sleep time.
+- Use a much shorter initial sleep time to account for faster devices and nonce
+range working, and increase it if nonce range fails to work.
+- Use nmsleep instead of usleep in bitforce.
+- Provide a ms based sleep function that uses nanosleep to avoid the inaccuracy
+of usleep on SMP systems.
+- delay_time_ms is always set so need not be initialised in bitforce.
+- Increase bitforce timeout to 10 seconds.
+- Add more hysteresis and poll ~5 times to allow for timer delays in bitforce
+devices.
+- miner.php allow alternating line colours (off by default)
+- Display the actual duration of wait when it is greater than the cutoff.
+- Set nonce to maximum once we determine nonce range support is broken.
+- Initial wait time is always known so no need to zero it beforehand in
+bitforce.
+- No point counting wait time until the work is actually sent to bitforce
+devices.
+- Use string comparison functions instead of explicit comparisons.
+- Account for wait_ms time when nonce_range is in use on BFL.
+- Split nonces up into 1/5 chunks when nonce range is supported.
+- limit clear buffer iterations.
+- Ad fd check to clear buffer.
+- miner.php remove incorrect 'DATE' error message
+- miner.php allow summary header in custom pages
+- Disable nonce range support in BFL when broken support is detected.
+- Restart_wait is only called with a ms value so incorporate that into the
+function.
+- Only try to adjust dev width when curses is built in.
+- miner.php define custom sum fields as a simple array
+- Fix off-by-one error in nonce increment in bfl.
+- Use BE when setting nonce in bitforce nonce range work.
+- Enable nonce range in the normal init sequence for bfl.
+- Queue extra work at 2/3 differently depending on whether we're using nonce
+range or not.
+- Initially enable support for nonce range support on bfl, splitting nonces up
+into 3/4 size and only disable it if it fails on work submit.
+- Attempt to detect nonce range support in BFL by sending work requring its
+support.
+- Limit retrying on busy for up to BITFORCE_TIMEOUT_MS
+- Attempt to initialise while bitforce device returns BUSY.
+- Extend length of string that can be passed to BFL devices.
+- Fix signedness warning.
+- Adjust device width column to be consistent.
+- Use cgpu-> not gpus[] in watchdog thread.
+- Add api stats (sleep time)
+- Timing tweaks Added long and short timeouts, short for detecting throttling,
+long to give up totally. Reset sleep time when device re-initialised Still check
+results after timeout Back up a larger time if result on first poll.
+- Add API Notify counter 'Comms Error'
+- Style police on api.c
+- Do all logging outside of the bitforce mutex locking to avoid deadlocks.
+- Remove applog call from bfwrite to prevent grabbing nested mutexes.
+- Bitforce style changes.
+- Minor style changes.
+- Remove needless roundl define.
+- Made JSON error message verbose.
+- Fine-tune timing adjustment. Also remove old work_restart timing.
+- Check for gpu return times of >= 0, not just 0, to fix intensity dropping to
+-10.
+- Restart is zeroed in the mining thread so no need to do it inside the bitforce
+code.
+- More improvements to comms. BFL return nothing when throttling, so should not
+be considered an error. Instead repeat with a longer delay.
+- Polling every 10ms there's not much point checking the pthread_cond_timedwait
+as it just adds overhead. Simply check the value of work_restart in the bfl main
+polling loop.
+- Use a pthread conditional that is broadcast whenever work restarts are
+required. Create a generic wait function waiting a specified time on that
+conditional that returns if the condition is met or a specified time passed to
+it has elapsed. Use this to do smarter polling in bitforce to abort work, queue
+more work, and check for results to minimise time spent working needlessly.
+- Add busy time to wait time.
+- api.c put version up to 1.14
+- Add tiny delay after writing to BFL Change BFL errors to something more human
+readable Send work busy re-tries after 10ms delay
+
+
+Version 2.4.4 - July 1, 2012
+
+- Fix builds on non gnu platforms.
+- api.c ensure old mode is always available when not using --api-groups + quit()
+on param errors
+- Implement rudimentary X-Mining-Hashrate support.
+- Detect large swings in temperature when below the target temperature range and
+change fan by amounts dependant on the value of tdiff.
+- Adjust the fanspeed by the magnitude of the temperature difference when in the
+optimal range.
+- Revert "Restarting cgminer from within after ADL has been corrupted only leads
+to a crash. Display a warning only and disable fanspeed monitoring."
+- api.c fix json already closed
+- implement and document API option --api-groups
+- Put upper bounds to under 2 hours that work can be rolled into the future for
+bitcoind will deem it invalid beyond that.
+- define API option --api-groups
+- api.c allow unwell devices to be enabled so they can be cured
+- miner.php - fix/enable autorefresh for custom pages
+- miner.php allow custom summary pages - new 'Mobile' summary
+- Work around pools that advertise very low expire= time inappropriately as this
+leads to many false positives for stale shares detected.
+- Only show ztex board count if any exist.
+- There is no need for work to be a union in struct workio_cmd
+- fpgautils.c include a debug message for all unknown open errors
+- Don't keep rolling work right up to the expire= cut off. Use 2/3 of the time
+between the scantime and the expiry as cutoff for reusing work.
+- Log a specific error when serial opens fail due to lack of user permissions
+- Increase GPU timing resolution to microsecond and add sanity check to ensure
+times are positive.
+- Opencl code may start executing before the clfinish order is given to it so
+get the start timing used for dynamic intensity from before the kernel is
+queued.
+- fpgautils.c - set BAUD rate according to termio spec
+- fpgautils.c - linux ordering back to the correct way
+- miner.php remove unneeded '.'s
+- miner.php add auto refresh options
+- miner.php add 'restart' next to 'quit'
+- miner.php make fontname/size configurable with myminer.php
+- Make the pools array a dynamically allocated array to allow unlimited pools to
+be added.
+- Make the devices array a dynamically allocated array of pointers to allow
+unlimited devices.
+- Dynamic intensity for GPUs should be calculated on a per device basis. Clean
+up the code to only calculate it if required as well.
+- Use a queueing bool set under control_lock to prevent multiple calls to
+queue_request racing.
+- Use the work clone flag to determine if we should subtract it from the total
+queued variable and provide a subtract queued function to prevent looping over
+locked code.
+- Don't decrement staged extras count from longpoll work.
+- Count longpoll's contribution to the queue.
+- Increase queued count before pushing message.
+- Test we have enough work queued for pools with and without rolltime
+capability.
+- As work is sorted by age, we can discard the oldest work at regular intervals
+to keep only 1 of the newest work items per mining thread.
+- Roll work again after duplicating it to prevent duplicates on return to the
+clone function.
+- Abstract out work cloning and clone $mining_threads copies whenever a rollable
+work item is found and return a clone instead.
+- api.c display Pool Av in json
+- Take into account average getwork delay as a marker of pool communications
+when considering work stale.
+- Work out a rolling average getwork delay stored in pool_stats.
+- Getwork delay in stats should include retries for each getwork call.
+- Walk through the thread list instead of searching for them when disabling
+threads for dynamic mode.
+- Extend nrolltime to support the expiry= parameter. Do this by turning the
+rolltime bool into an integer set to the expiry time. If the pool supports
+rolltime but not expiry= then set the expiry time to the standard scantime.
+- When disabling fanspeed monitoring on adl failure, remove any twin GPU
+association. This could have been leading to hangs on machines with dual GPU
+cards when ADL failed.
+- modminer: Don't delay 2nd+ FPGAs during work restart
+- Disable OpenCL code when not available.
+- Fix openwrt crashing on regeneratehash() by making check_solve a noop.
+- FPGA - allow device detect override without an open failure
+- Fix sign warning.
+
+
+Version 2.4.3 - June 14, 2012
+
+- can_roll and should_roll should have no bearing on the cycle period within the
+miner_thread so remove it.
+- Check for strategy being changed to load balance when enabling LPs.
+- Check that all threads on the device that called get_work are waiting on
+getwork before considering the pool lagging.
+- Iterate over each thread belonging to each device in the hashmeter instead of
+searching for them now that they're a list.
+- When using rotate pool strategy, ensure we only select from alive enabled
+pools.
+- Start longpoll from every pool when load balance strategy is in use.
+- Add mandatory and block fields to the work struct. Flag any shares that are
+detected as blocks as mandatory to submit, along with longpoll work from a
+previously rejecting pool.
+- Consider the fan optimal if fanspeed is dropping but within the optimal speed
+window.
+- Fix typo in some API messages (succeess/success)
+- api.c MMQ stat bugs
+- Bugfix: Fix warnings when built without libudev support
+- Bugfix: slay a variety of warnings
+- Bugfix: modminer: Fix unsigned/signed comparison and similar warnings
+- API add ModMinerQuad support
+- Bugfix: Honour forceauto parameter in serial_detect functions
+- modminer: Temperature sensor improvements
+- modminer: Make log messages more consistent in format
+- Only adjust GPU speed up if the fanspeed is within the normal fanrange and
+hasn't been turned to maximum speed under overheat conditions.
+- ModMiner use valid .name
+- New driver: BTCFPGA ModMiner
+- Abstract generally useful FPGA code into fpgautils.c
+- API add stats for pool getworks
+- miner.php option to hide specific fields from the display
+- miner.php add version numbers to the summary page
+- Update debian configs to v2.4.2
+- Add API and FPGA READMEs into Makefile to be included in source distribution.
+- Icarus - fix unit64_t printf warnings
+
+
 Version 2.4.2 - June 2, 2012
 Version 2.4.2 - June 2, 2012
 
 
 - API.class compiled with Java SE 6.0_03 - works with Win7x64
 - API.class compiled with Java SE 6.0_03 - works with Win7x64

+ 28 - 10
README

@@ -119,6 +119,8 @@ Options for both config file and command line:
                     This overrides --api-network and you must specify 127.0.0.1 if it is required
                     This overrides --api-network and you must specify 127.0.0.1 if it is required
                     W: in front of the IP address gives that address privileged access to all api commands
                     W: in front of the IP address gives that address privileged access to all api commands
 --api-description   Description placed in the API status header (default: cgminer version)
 --api-description   Description placed in the API status header (default: cgminer version)
+--api-groups        API one letter groups G:cmd:cmd[,P:cmd:*...]
+                    See API-README for usage
 --api-listen        Listen for API requests (default: disabled)
 --api-listen        Listen for API requests (default: disabled)
                     By default any command that does not just display data returns access denied
                     By default any command that does not just display data returns access denied
                     See --api-allow to overcome this
                     See --api-allow to overcome this
@@ -199,16 +201,23 @@ FPGA mining boards(BitForce, Icarus, ModMiner, Ztex) only options:
 
 
 --scan-serial|-S <arg> Serial port to probe for FPGA mining device
 --scan-serial|-S <arg> Serial port to probe for FPGA mining device
 
 
-     By default, cgminer will scan for autodetected FPGAs unless at least one
-     -S is specified for that driver. If you specify -S and still want cgminer
-     to scan, you must also use "-S auto". If you want to prevent cgminer from
-     scanning without specifying a device, you can use "-S noauto". Note that
-     presently, autodetection only works on Linux, and might only detect one
-     device depending on the version of udev being used.
+This option is only for BitForce, Icarus, and/or ModMiner FPGAs
 
 
-     On linux <arg> is usually of the format /dev/ttyUSBn
-     On windows <arg> is usually of the format \\.\COMn
-       (where n = the correct device number for the FPGA device)
+By default, cgminer will scan for autodetected FPGAs unless at least one
+-S is specified for that driver. If you specify -S and still want cgminer
+to scan, you must also use "-S auto". If you want to prevent cgminer from
+scanning without specifying a device, you can use "-S noauto". Note that
+presently, autodetection only works on Linux, and might only detect one
+device depending on the version of udev being used.
+
+On linux <arg> is usually of the format /dev/ttyUSBn
+On windows <arg> is usually of the format \\.\COMn
+(where n = the correct device number for the FPGA device)
+
+The official supplied binaries are compiled with support for all FPGAs.
+To force the code to only attempt detection with a specific driver,
+prepend the argument with the driver name followed by a colon.
+For example, "icarus:/dev/ttyUSB0" or "bitforce:\\.\COM5"
 
 
 For other FPGA details see the FPGA-README
 For other FPGA details see the FPGA-README
 
 
@@ -786,7 +795,9 @@ A; Try the --net-delay option.
 Q: How do I tune for p2pool?
 Q: How do I tune for p2pool?
 A: p2pool has very rapid expiration of work and new blocks, it is suggested you
 A: p2pool has very rapid expiration of work and new blocks, it is suggested you
 decrease intensity by 1 from your optimal value, and decrease GPU threads to 1
 decrease intensity by 1 from your optimal value, and decrease GPU threads to 1
-with -g 1.
+with -g 1. It is also recommended to use --failover-only since the work is
+effectively like a different block chain. If mining with a minirig, it is worth
+adding the --bfl-range option.
 
 
 Q: Are kernels from other mining software useable in cgminer?
 Q: Are kernels from other mining software useable in cgminer?
 A: No, the APIs are slightly different between the different software and they
 A: No, the APIs are slightly different between the different software and they
@@ -803,6 +814,13 @@ They are Field-Programmable Gate Arrays that have been programmed to do Bitcoin
 mining. Since the acronym needs to be only 3 characters, the "Field-" part has
 mining. Since the acronym needs to be only 3 characters, the "Field-" part has
 been skipped.
 been skipped.
 
 
+Q: How do I get my BFL device to auto-recognise?
+A: They are only automatically recognised on linux, and no option needs to be
+passed to them. The only thing that needs to be done is to load the driver for
+them, which on linux would require:
+sudo modprobe ftdi_sio vendor=0x0403 product=0x6014
+
+
 ---
 ---
 
 
 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

+ 33 - 9
adl.c

@@ -13,6 +13,7 @@
 
 
 #include <stdio.h>
 #include <stdio.h>
 #include <string.h>
 #include <string.h>
+#include <math.h>
 
 
 #ifdef HAVE_CURSES
 #ifdef HAVE_CURSES
 #include <curses.h>
 #include <curses.h>
@@ -692,9 +693,18 @@ int gpu_fanpercent(int gpu)
 	unlock_adl();
 	unlock_adl();
 	if (unlikely(ga->has_fanspeed && ret == -1)) {
 	if (unlikely(ga->has_fanspeed && ret == -1)) {
 		applog(LOG_WARNING, "GPU %d stopped reporting fanspeed due to driver corruption", gpu);
 		applog(LOG_WARNING, "GPU %d stopped reporting fanspeed due to driver corruption", gpu);
-		applog(LOG_WARNING, "You will need to start cgminer from scratch to correct this");
+		if (opt_restart) {
+			applog(LOG_WARNING, "Restart enabled, will attempt to restart cgminer");
+			applog(LOG_WARNING, "You can disable this with the --no-restart option");
+			app_restart();
+		}
 		applog(LOG_WARNING, "Disabling fanspeed monitoring on this device");
 		applog(LOG_WARNING, "Disabling fanspeed monitoring on this device");
 		ga->has_fanspeed = false;
 		ga->has_fanspeed = false;
+		if (ga->twin) {
+			applog(LOG_WARNING, "Disabling fanspeed linking on GPU twins");
+			ga->twin->twin = NULL;;
+			ga->twin = NULL;
+		}
 	}
 	}
 	return ret;
 	return ret;
 }
 }
@@ -1015,6 +1025,7 @@ static int set_powertune(int gpu, int iPercentage)
 static bool fan_autotune(int gpu, int temp, int fanpercent, int lasttemp, bool *fan_window)
 static bool fan_autotune(int gpu, int temp, int fanpercent, int lasttemp, bool *fan_window)
 {
 {
 	struct cgpu_info *cgpu = &gpus[gpu];
 	struct cgpu_info *cgpu = &gpus[gpu];
+	int tdiff = round(temp - lasttemp);
 	struct gpu_adl *ga = &cgpu->adl;
 	struct gpu_adl *ga = &cgpu->adl;
 	int top = gpus[gpu].gpu_fan;
 	int top = gpus[gpu].gpu_fan;
 	int bot = gpus[gpu].min_fan;
 	int bot = gpus[gpu].min_fan;
@@ -1029,7 +1040,7 @@ static bool fan_autotune(int gpu, int temp, int fanpercent, int lasttemp, bool *
 		cgpu->device_last_not_well = time(NULL);
 		cgpu->device_last_not_well = time(NULL);
 		cgpu->device_not_well_reason = REASON_DEV_OVER_HEAT;
 		cgpu->device_not_well_reason = REASON_DEV_OVER_HEAT;
 		cgpu->dev_over_heat_count++;
 		cgpu->dev_over_heat_count++;
-	} else if (temp > ga->targettemp && fanpercent < top && temp >= lasttemp) {
+	} else if (temp > ga->targettemp && fanpercent < top && tdiff >= 0) {
 		applog(LOG_DEBUG, "Temperature over target, increasing fanspeed");
 		applog(LOG_DEBUG, "Temperature over target, increasing fanspeed");
 		if (temp > ga->targettemp + opt_hysteresis)
 		if (temp > ga->targettemp + opt_hysteresis)
 			newpercent = ga->targetfan + 10;
 			newpercent = ga->targetfan + 10;
@@ -1037,18 +1048,26 @@ static bool fan_autotune(int gpu, int temp, int fanpercent, int lasttemp, bool *
 			newpercent = ga->targetfan + 5;
 			newpercent = ga->targetfan + 5;
 		if (newpercent > top)
 		if (newpercent > top)
 			newpercent = top;
 			newpercent = top;
-	} else if (fanpercent > bot && temp < ga->targettemp - opt_hysteresis && temp <= lasttemp) {
-		applog(LOG_DEBUG, "Temperature %d degrees below target, decreasing fanspeed", opt_hysteresis);
-		newpercent = ga->targetfan - 1;
+	} else if (fanpercent > bot && temp < ga->targettemp - opt_hysteresis) {
+		/* Detect large swings of 5 degrees or more and change fan by
+		 * a proportion more */
+		if (tdiff <= 0) {
+			applog(LOG_DEBUG, "Temperature %d degrees below target, decreasing fanspeed", opt_hysteresis);
+			newpercent = ga->targetfan - 1 + tdiff / 5;
+		} else if (tdiff >= 5) {
+			applog(LOG_DEBUG, "Temperature climbed %d while below target, increasing fanspeed", tdiff);
+			newpercent = ga->targetfan + tdiff / 5;
+		}
 	} else {
 	} else {
+
 		/* We're in the optimal range, make minor adjustments if the
 		/* We're in the optimal range, make minor adjustments if the
 		 * temp is still drifting */
 		 * temp is still drifting */
-		if (fanpercent > bot && temp < lasttemp && lasttemp < ga->targettemp) {
+		if (fanpercent > bot && tdiff < 0 && lasttemp < ga->targettemp) {
 			applog(LOG_DEBUG, "Temperature dropping while in target range, decreasing fanspeed");
 			applog(LOG_DEBUG, "Temperature dropping while in target range, decreasing fanspeed");
-			newpercent = ga->targetfan - 1;
-		} else if (fanpercent < top && temp > lasttemp && temp > ga->targettemp - opt_hysteresis) {
+			newpercent = ga->targetfan + tdiff;
+		} else if (fanpercent < top && tdiff > 0 && temp > ga->targettemp - opt_hysteresis) {
 			applog(LOG_DEBUG, "Temperature rising while in target range, increasing fanspeed");
 			applog(LOG_DEBUG, "Temperature rising while in target range, increasing fanspeed");
-			newpercent = ga->targetfan + 1;
+			newpercent = ga->targetfan + tdiff;
 		}
 		}
 	}
 	}
 
 
@@ -1065,6 +1084,11 @@ static bool fan_autotune(int gpu, int temp, int fanpercent, int lasttemp, bool *
 	if (newpercent != fanpercent) {
 	if (newpercent != fanpercent) {
 		applog(LOG_INFO, "Setting GPU %d fan percentage to %d", gpu, newpercent);
 		applog(LOG_INFO, "Setting GPU %d fan percentage to %d", gpu, newpercent);
 		set_fanspeed(gpu, newpercent);
 		set_fanspeed(gpu, newpercent);
+		/* If the fanspeed is going down and we're below the top speed,
+		 * consider the fan optimal to prevent minute changes in
+		 * fanspeed delaying GPU engine speed changes */
+		if (newpercent < fanpercent && *fan_window)
+			return true;
 		return false;
 		return false;
 	}
 	}
 	return true;
 	return true;

+ 3 - 3
adl.h

@@ -21,8 +21,8 @@ void gpu_autotune(int gpu, enum dev_enable *denable);
 void clear_adl(int nDevs);
 void clear_adl(int nDevs);
 #else /* HAVE_ADL */
 #else /* HAVE_ADL */
 #define adl_active (0)
 #define adl_active (0)
-static inline void init_adl(int nDevs) {}
-static inline void change_gpusettings(int gpu) { }
-static inline void clear_adl(int nDevs) {}
+static inline void init_adl(__maybe_unused int nDevs) {}
+static inline void change_gpusettings(__maybe_unused int gpu) { }
+static inline void clear_adl(__maybe_unused int nDevs) {}
 #endif
 #endif
 #endif
 #endif

File diff suppressed because it is too large
+ 611 - 164
api.c


File diff suppressed because it is too large
+ 345 - 126
cgminer.c


+ 3 - 3
configure.ac

@@ -1,8 +1,8 @@
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 m4_define([v_maj], [2])
 m4_define([v_maj], [2])
-m4_define([v_min], [4])
-m4_define([v_mic], [2])
+m4_define([v_min], [5])
+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])
 m4_define([lt_rev], m4_eval(v_maj + v_min))
 m4_define([lt_rev], m4_eval(v_maj + v_min))
@@ -21,7 +21,7 @@ AC_CONFIG_HEADERS([config.h])
 
 
 AM_INIT_AUTOMAKE([foreign])
 AM_INIT_AUTOMAKE([foreign])
 m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
 m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
-AC_GNU_SOURCE
+AC_USE_SYSTEM_EXTENSIONS
 
 
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##

+ 370 - 80
driver-bitforce.c

@@ -20,6 +20,12 @@
 #include "fpgautils.h"
 #include "fpgautils.h"
 #include "miner.h"
 #include "miner.h"
 
 
+#define BITFORCE_SLEEP_MS 500
+#define BITFORCE_TIMEOUT_MS 10000
+#define BITFORCE_LONG_TIMEOUT_MS 15000
+#define BITFORCE_CHECK_INTERVAL_MS 10
+#define WORK_CHECK_INTERVAL_MS 50
+#define MAX_START_DELAY_US 100000
 
 
 struct device_api bitforce_api;
 struct device_api bitforce_api;
 
 
@@ -29,79 +35,88 @@ static void BFgets(char *buf, size_t bufLen, int fd)
 {
 {
 	do
 	do
 		--bufLen;
 		--bufLen;
-	while (likely(bufLen && read(fd, buf, 1) && (buf++)[0] != '\n'))
-		;
+	while (likely(bufLen && read(fd, buf, 1) && (buf++)[0] != '\n'));
+
 	buf[0] = '\0';
 	buf[0] = '\0';
 }
 }
 
 
-static ssize_t BFwrite2(int fd, const void *buf, ssize_t bufLen)
+static ssize_t BFwrite(int fd, const void *buf, ssize_t bufLen)
 {
 {
-	return write(fd, buf, bufLen);
+	if ((bufLen) != write(fd, buf, bufLen))
+		return 0;
+	else
+		return bufLen;
 }
 }
 
 
-#define BFwrite(fd, buf, bufLen)  do {  \
-	if ((bufLen) != BFwrite2(fd, buf, bufLen)) {  \
-		applog(LOG_ERR, "Error writing to BitForce (" #buf ")");  \
-		return 0;  \
-	}  \
-} while(0)
-
 #define BFclose(fd) close(fd)
 #define BFclose(fd) close(fd)
 
 
 static bool bitforce_detect_one(const char *devpath)
 static bool bitforce_detect_one(const char *devpath)
 {
 {
-	char *s;
+	int fdDev = BFopen(devpath);
+	struct cgpu_info *bitforce;
 	char pdevbuf[0x100];
 	char pdevbuf[0x100];
+	char *s;
+
+	applog(LOG_DEBUG, "BFL: Attempting to open %s", devpath);
 
 
-	int fdDev = BFopen(devpath);
 	if (unlikely(fdDev == -1)) {
 	if (unlikely(fdDev == -1)) {
-		applog(LOG_DEBUG, "BitForce Detect: Failed to open %s", devpath);
+		applog(LOG_ERR, "BFL: Failed to open %s", devpath);
 		return false;
 		return false;
 	}
 	}
+
 	BFwrite(fdDev, "ZGX", 3);
 	BFwrite(fdDev, "ZGX", 3);
 	BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
 	BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
 	if (unlikely(!pdevbuf[0])) {
 	if (unlikely(!pdevbuf[0])) {
-		applog(LOG_ERR, "Error reading from BitForce (ZGX)");
+		applog(LOG_ERR, "BFL: Error reading (ZGX)");
 		return 0;
 		return 0;
 	}
 	}
+
 	BFclose(fdDev);
 	BFclose(fdDev);
 	if (unlikely(!strstr(pdevbuf, "SHA256"))) {
 	if (unlikely(!strstr(pdevbuf, "SHA256"))) {
-		applog(LOG_DEBUG, "BitForce Detect: Didn't recognise BitForce on %s", devpath);
+		applog(LOG_ERR, "BFL: Didn't recognise BitForce on %s", devpath);
 		return false;
 		return false;
 	}
 	}
 
 
 	// We have a real BitForce!
 	// We have a real BitForce!
-	struct cgpu_info *bitforce;
 	bitforce = calloc(1, sizeof(*bitforce));
 	bitforce = calloc(1, sizeof(*bitforce));
 	bitforce->api = &bitforce_api;
 	bitforce->api = &bitforce_api;
 	bitforce->device_path = strdup(devpath);
 	bitforce->device_path = strdup(devpath);
 	bitforce->deven = DEV_ENABLED;
 	bitforce->deven = DEV_ENABLED;
 	bitforce->threads = 1;
 	bitforce->threads = 1;
-	if (likely((!memcmp(pdevbuf, ">>>ID: ", 7)) && (s = strstr(pdevbuf + 3, ">>>"))))
-	{
+	/* Initially enable support for nonce range and disable it later if it
+	 * fails */
+	if (opt_bfl_noncerange) {
+		bitforce->nonce_range = true;
+		bitforce->sleep_ms = BITFORCE_SLEEP_MS;
+	} else
+		bitforce->sleep_ms = BITFORCE_SLEEP_MS * 5;
+
+	if (likely((!memcmp(pdevbuf, ">>>ID: ", 7)) && (s = strstr(pdevbuf + 3, ">>>")))) {
 		s[0] = '\0';
 		s[0] = '\0';
 		bitforce->name = strdup(pdevbuf + 7);
 		bitforce->name = strdup(pdevbuf + 7);
 	}
 	}
+	
+	mutex_init(&bitforce->device_mutex);
 
 
 	return add_cgpu(bitforce);
 	return add_cgpu(bitforce);
 }
 }
 
 
 static char bitforce_detect_auto()
 static char bitforce_detect_auto()
 {
 {
-	return
-	serial_autodetect_udev     (bitforce_detect_one, "BitFORCE*SHA256") ?:
-	serial_autodetect_devserial(bitforce_detect_one, "BitFORCE_SHA256") ?:
-	0;
+	return (serial_autodetect_udev     (bitforce_detect_one, "BitFORCE*SHA256") ?:
+		serial_autodetect_devserial(bitforce_detect_one, "BitFORCE_SHA256") ?:
+		0);
 }
 }
 
 
 static void bitforce_detect()
 static void bitforce_detect()
 {
 {
-	serial_detect_auto("bitforce", bitforce_detect_one, bitforce_detect_auto);
+	serial_detect_auto(bitforce_api.dname, bitforce_detect_one, bitforce_detect_auto);
 }
 }
 
 
 static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce)
 static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce)
 {
 {
 	float gt = bitforce->temp;
 	float gt = bitforce->temp;
+
 	if (gt > 0)
 	if (gt > 0)
 		tailsprintf(buf, "%5.1fC ", gt);
 		tailsprintf(buf, "%5.1fC ", gt);
 	else
 	else
@@ -112,78 +127,123 @@ static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce)
 static bool bitforce_thread_prepare(struct thr_info *thr)
 static bool bitforce_thread_prepare(struct thr_info *thr)
 {
 {
 	struct cgpu_info *bitforce = thr->cgpu;
 	struct cgpu_info *bitforce = thr->cgpu;
-
+	int fdDev = BFopen(bitforce->device_path);
 	struct timeval now;
 	struct timeval now;
 
 
-	int fdDev = BFopen(bitforce->device_path);
-	if (unlikely(-1 == fdDev)) {
-		applog(LOG_ERR, "Failed to open BitForce on %s", bitforce->device_path);
+	if (unlikely(fdDev == -1)) {
+		applog(LOG_ERR, "BFL%i: Failed to open %s", bitforce->device_id, bitforce->device_path);
 		return false;
 		return false;
 	}
 	}
 
 
 	bitforce->device_fd = fdDev;
 	bitforce->device_fd = fdDev;
 
 
-	applog(LOG_INFO, "Opened BitForce on %s", bitforce->device_path);
+	applog(LOG_INFO, "BFL%i: Opened %s", bitforce->device_id, bitforce->device_path);
 	gettimeofday(&now, NULL);
 	gettimeofday(&now, NULL);
 	get_datestamp(bitforce->init, &now);
 	get_datestamp(bitforce->init, &now);
 
 
 	return true;
 	return true;
 }
 }
 
 
-static uint64_t bitforce_scanhash(struct thr_info *thr, struct work *work, uint64_t __maybe_unused max_nonce)
+static void biforce_clear_buffer(struct cgpu_info *bitforce)
 {
 {
-	struct cgpu_info *bitforce = thr->cgpu;
 	int fdDev = bitforce->device_fd;
 	int fdDev = bitforce->device_fd;
+	char pdevbuf[0x100];
+	int count = 0;
+
+	if (!fdDev)
+		return;
+
+	applog(LOG_DEBUG, "BFL%i: Clearing read buffer", bitforce->device_id);
 
 
+	mutex_lock(&bitforce->device_mutex);
+	do {
+		pdevbuf[0] = '\0';
+		BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
+	} while (pdevbuf[0] && (++count < 10));
+	mutex_unlock(&bitforce->device_mutex);
+}
+
+void bitforce_init(struct cgpu_info *bitforce)
+{
+	char *devpath = bitforce->device_path;
+	int fdDev = bitforce->device_fd, retries = 0;
 	char pdevbuf[0x100];
 	char pdevbuf[0x100];
-	unsigned char ob[61] = ">>>>>>>>12345678901234567890123456789012123456789012>>>>>>>>";
-	int i;
-	char *pnoncebuf;
 	char *s;
 	char *s;
-	uint32_t nonce;
 
 
-	BFwrite(fdDev, "ZDX", 3);
-	BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
-	if (unlikely(!pdevbuf[0])) {
-		applog(LOG_ERR, "Error reading from BitForce (ZDX)");
-		return 0;
-	}
-	if (unlikely(pdevbuf[0] != 'O' || pdevbuf[1] != 'K')) {
-		applog(LOG_ERR, "BitForce ZDX reports: %s", pdevbuf);
-		return 0;
-	}
+	applog(LOG_WARNING, "BFL%i: Re-initalizing", bitforce->device_id);
 
 
-	memcpy(ob + 8, work->midstate, 32);
-	memcpy(ob + 8 + 32, work->data + 64, 12);
-	BFwrite(fdDev, ob, 60);
-	if (opt_debug) {
-		s = bin2hex(ob + 8, 44);
-		applog(LOG_DEBUG, "BitForce block data: %s", s);
-		free(s);
+	biforce_clear_buffer(bitforce);
+
+	mutex_lock(&bitforce->device_mutex);
+	if (fdDev)
+		BFclose(fdDev);
+	bitforce->device_fd = 0;
+
+	fdDev = BFopen(devpath);
+	if (unlikely(fdDev == -1)) {
+		mutex_unlock(&bitforce->device_mutex);
+		applog(LOG_ERR, "BFL%i: Failed to open %s", bitforce->device_id, devpath);
+		return;
 	}
 	}
 
 
-	BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
-	if (unlikely(!pdevbuf[0])) {
-		applog(LOG_ERR, "Error reading from BitForce (block data)");
-		return 0;
+	do {
+		BFwrite(fdDev, "ZGX", 3);
+		BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
+
+		if (unlikely(!pdevbuf[0])) {
+			mutex_unlock(&bitforce->device_mutex);
+			applog(LOG_ERR, "BFL%i: Error reading (ZGX)", bitforce->device_id);
+			return;
+		}
+
+		if (retries++)
+			nmsleep(10);
+	} while (!strstr(pdevbuf, "BUSY") && (retries * 10 < BITFORCE_TIMEOUT_MS));
+
+	if (unlikely(!strstr(pdevbuf, "SHA256"))) {
+		mutex_unlock(&bitforce->device_mutex);
+		applog(LOG_ERR, "BFL%i: Didn't recognise BitForce on %s returned: %s", bitforce->device_id, devpath, pdevbuf);
+		return;
 	}
 	}
-	if (unlikely(pdevbuf[0] != 'O' || pdevbuf[1] != 'K')) {
-		applog(LOG_ERR, "BitForce block data reports: %s", pdevbuf);
-		return 0;
+	
+	if (likely((!memcmp(pdevbuf, ">>>ID: ", 7)) && (s = strstr(pdevbuf + 3, ">>>")))) {
+		s[0] = '\0';
+		bitforce->name = strdup(pdevbuf + 7);
 	}
 	}
 
 
+	bitforce->device_fd = fdDev;
+	bitforce->sleep_ms = BITFORCE_SLEEP_MS;
+
+	mutex_unlock(&bitforce->device_mutex);
+}
+
+static bool bitforce_get_temp(struct cgpu_info *bitforce)
+{
+	int fdDev = bitforce->device_fd;
+	char pdevbuf[0x100];
+	char *s;
+
+	if (!fdDev)
+		return false;
+
+	mutex_lock(&bitforce->device_mutex);
 	BFwrite(fdDev, "ZLX", 3);
 	BFwrite(fdDev, "ZLX", 3);
 	BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
 	BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
+	mutex_unlock(&bitforce->device_mutex);
+	
 	if (unlikely(!pdevbuf[0])) {
 	if (unlikely(!pdevbuf[0])) {
-		applog(LOG_ERR, "Error reading from BitForce (ZKX)");
-		return 0;
+		applog(LOG_ERR, "BFL%i: Error: Get temp returned empty string", bitforce->device_id);
+		bitforce->temp = 0;
+		return false;
 	}
 	}
+
 	if ((!strncasecmp(pdevbuf, "TEMP", 4)) && (s = strchr(pdevbuf + 4, ':'))) {
 	if ((!strncasecmp(pdevbuf, "TEMP", 4)) && (s = strchr(pdevbuf + 4, ':'))) {
 		float temp = strtof(s + 1, NULL);
 		float temp = strtof(s + 1, NULL);
+
 		if (temp > 0) {
 		if (temp > 0) {
 			bitforce->temp = temp;
 			bitforce->temp = temp;
 			if (temp > bitforce->cutofftemp) {
 			if (temp > bitforce->cutofftemp) {
-				applog(LOG_WARNING, "Hit thermal cutoff limit on %s %d, disabling!", bitforce->api->name, bitforce->device_id);
+				applog(LOG_WARNING, "BFL%i: Hit thermal cutoff limit, disabling!", bitforce->device_id);
 				bitforce->deven = DEV_RECOVER;
 				bitforce->deven = DEV_RECOVER;
 
 
 				bitforce->device_last_not_well = time(NULL);
 				bitforce->device_last_not_well = time(NULL);
@@ -192,27 +252,150 @@ static uint64_t bitforce_scanhash(struct thr_info *thr, struct work *work, uint6
 			}
 			}
 		}
 		}
 	}
 	}
+	return true;
+}
 
 
-	usleep(4500000);
-	i = 4500;
-	while (1) {
+static bool bitforce_send_work(struct thr_info *thr, struct work *work)
+{
+	struct cgpu_info *bitforce = thr->cgpu;
+	int fdDev = bitforce->device_fd;
+	unsigned char ob[70];
+	char pdevbuf[0x100];
+	char *s;
+
+	if (!fdDev)
+		return false;
+re_send:
+	mutex_lock(&bitforce->device_mutex);
+	if (bitforce->nonce_range)
+		BFwrite(fdDev, "ZPX", 3);
+	else
+		BFwrite(fdDev, "ZDX", 3);
+	BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
+	if (!pdevbuf[0] || !strncasecmp(pdevbuf, "B", 1)) {
+		mutex_unlock(&bitforce->device_mutex);
+		nmsleep(WORK_CHECK_INTERVAL_MS);
+		goto re_send;
+	} else if (unlikely(strncasecmp(pdevbuf, "OK", 2))) {
+		mutex_unlock(&bitforce->device_mutex);
+		if (bitforce->nonce_range) {
+			applog(LOG_WARNING, "BFL%i: Does not support nonce range, disabling", bitforce->device_id);
+			bitforce->nonce_range = false;
+			bitforce->sleep_ms *= 5;
+			goto re_send;
+		}
+		applog(LOG_ERR, "BFL%i: Error: Send work reports: %s", bitforce->device_id, pdevbuf);
+		return false;
+	}
+
+	sprintf((char *)ob, ">>>>>>>>");
+	memcpy(ob + 8, work->midstate, 32);
+	memcpy(ob + 8 + 32, work->data + 64, 12);
+	if (!bitforce->nonce_range) {
+		sprintf((char *)ob + 8 + 32 + 12, ">>>>>>>>");
+		work->blk.nonce = bitforce->nonces = 0xffffffff;
+		BFwrite(fdDev, ob, 60);
+	} else {
+		uint32_t *nonce;
+
+		nonce = (uint32_t *)(ob + 8 + 32 + 12);
+		*nonce = htobe32(work->blk.nonce);
+		nonce = (uint32_t *)(ob + 8 + 32 + 12 + 4);
+		/* Split work up into 1/5th nonce ranges */
+		bitforce->nonces = 0x33333332;
+		*nonce = htobe32(work->blk.nonce + bitforce->nonces);
+		work->blk.nonce += bitforce->nonces + 1;
+		sprintf((char *)ob + 8 + 32 + 12 + 8, ">>>>>>>>");
+		BFwrite(fdDev, ob, 68);
+	}
+
+	BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
+	mutex_unlock(&bitforce->device_mutex);
+
+	if (opt_debug) {
+		s = bin2hex(ob + 8, 44);
+		applog(LOG_DEBUG, "BFL%i: block data: %s", bitforce->device_id, s);
+		free(s);
+	}
+
+	if (unlikely(!pdevbuf[0])) {
+		applog(LOG_ERR, "BFL%i: Error: Send block data returned empty string", bitforce->device_id);
+		return false;
+	}
+
+	if (unlikely(strncasecmp(pdevbuf, "OK", 2))) {
+		applog(LOG_ERR, "BFL%i: Error: Send block data reports: %s", bitforce->device_id, pdevbuf);
+		return false;
+	}
+
+	return true;
+}
+
+static int64_t bitforce_get_result(struct thr_info *thr, struct work *work)
+{
+	struct cgpu_info *bitforce = thr->cgpu;
+	int fdDev = bitforce->device_fd;
+	unsigned int delay_time_ms;
+	char pdevbuf[0x100];
+	char *pnoncebuf;
+	uint32_t nonce;
+
+	if (!fdDev)
+		return -1;
+
+	while (bitforce->wait_ms < BITFORCE_LONG_TIMEOUT_MS) {
+		if (unlikely(thr->work_restart))
+			return 0;
+
+		mutex_lock(&bitforce->device_mutex);
 		BFwrite(fdDev, "ZFX", 3);
 		BFwrite(fdDev, "ZFX", 3);
 		BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
 		BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
-		if (unlikely(!pdevbuf[0])) {
-			applog(LOG_ERR, "Error reading from BitForce (ZFX)");
+		mutex_unlock(&bitforce->device_mutex);
+
+		if (pdevbuf[0] && strncasecmp(pdevbuf, "B", 1)) /* BFL does not respond during throttling */
+			break;
+
+		/* if BFL is throttling, no point checking so quickly */
+		delay_time_ms = (pdevbuf[0] ? BITFORCE_CHECK_INTERVAL_MS : 2 * WORK_CHECK_INTERVAL_MS);
+		nmsleep(delay_time_ms);
+		bitforce->wait_ms += delay_time_ms;
+	}
+
+	if (bitforce->wait_ms >= BITFORCE_TIMEOUT_MS) {
+		applog(LOG_ERR, "BFL%i: took %dms - longer than %dms", bitforce->device_id,
+		       bitforce->wait_ms, BITFORCE_TIMEOUT_MS);
+		bitforce->device_last_not_well = time(NULL);
+		bitforce->device_not_well_reason = REASON_DEV_OVER_HEAT;
+		bitforce->dev_over_heat_count++;
+
+		if (!pdevbuf[0])           /* Only return if we got nothing after timeout - there still may be results */
 			return 0;
 			return 0;
+	} else if (!strncasecmp(pdevbuf, "N", 1)) {/* Hashing complete (NONCE-FOUND or NO-NONCE) */
+		    /* Simple timing adjustment. Allow a few polls to cope with
+		     * OS timer delays being variably reliable. wait_ms will
+		     * always equal sleep_ms when we've waited greater than or
+		     * equal to the result return time.*/
+	        delay_time_ms = bitforce->sleep_ms;
+		if (bitforce->wait_ms > bitforce->sleep_ms + (WORK_CHECK_INTERVAL_MS * 2))
+			bitforce->sleep_ms += (bitforce->wait_ms - bitforce->sleep_ms) / 2;
+		else if (bitforce->wait_ms == bitforce->sleep_ms) {
+			if (bitforce->sleep_ms > WORK_CHECK_INTERVAL_MS)
+				bitforce->sleep_ms -= WORK_CHECK_INTERVAL_MS;
+			else if (bitforce->sleep_ms > BITFORCE_CHECK_INTERVAL_MS)
+				bitforce->sleep_ms -= BITFORCE_CHECK_INTERVAL_MS;
 		}
 		}
-		if (pdevbuf[0] != 'B')
-		    break;
-		usleep(10000);
-		i += 10;
-	}
-	applog(LOG_DEBUG, "BitForce waited %dms until %s\n", i, pdevbuf);
-	work->blk.nonce = 0xffffffff;
-	if (pdevbuf[2] == '-')
-		return 0xffffffff;
+
+		if (delay_time_ms != bitforce->sleep_ms)
+			  applog(LOG_DEBUG, "BFL%i: Wait time changed to: %d", bitforce->device_id, bitforce->sleep_ms, bitforce->wait_ms);
+	}
+
+	applog(LOG_DEBUG, "BFL%i: waited %dms until %s", bitforce->device_id, bitforce->wait_ms, pdevbuf);
+	if (!strncasecmp(&pdevbuf[2], "-", 1))
+		return bitforce->nonces;   /* No valid nonce found */
+	else if (!strncasecmp(pdevbuf, "I", 1))
+		return 0;          /* Device idle */
 	else if (strncasecmp(pdevbuf, "NONCE-FOUND", 11)) {
 	else if (strncasecmp(pdevbuf, "NONCE-FOUND", 11)) {
-		applog(LOG_ERR, "BitForce result reports: %s", pdevbuf);
+		applog(LOG_WARNING, "BFL%i: Error: Get result reports: %s", bitforce->device_id, pdevbuf);
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -223,21 +406,128 @@ static uint64_t bitforce_scanhash(struct thr_info *thr, struct work *work, uint6
 #ifndef __BIG_ENDIAN__
 #ifndef __BIG_ENDIAN__
 		nonce = swab32(nonce);
 		nonce = swab32(nonce);
 #endif
 #endif
-
+		if (unlikely(bitforce->nonce_range && (nonce >= work->blk.nonce ||
+			(work->blk.nonce > 0 && nonce < work->blk.nonce - bitforce->nonces - 1)))) {
+				applog(LOG_WARNING, "BFL%i: Disabling broken nonce range support", bitforce->device_id);
+				bitforce->nonce_range = false;
+				work->blk.nonce = 0xffffffff;
+				bitforce->sleep_ms *= 5;
+		}
+			
 		submit_nonce(thr, work, nonce);
 		submit_nonce(thr, work, nonce);
-		if (pnoncebuf[8] != ',')
+		if (strncmp(&pnoncebuf[8], ",", 1))
 			break;
 			break;
 		pnoncebuf += 9;
 		pnoncebuf += 9;
 	}
 	}
 
 
-	return 0xffffffff;
+	return bitforce->nonces;
+}
+
+static void bitforce_shutdown(struct thr_info *thr)
+{
+	struct cgpu_info *bitforce = thr->cgpu;
+
+	BFclose(bitforce->device_fd);
+	bitforce->device_fd = 0;
+}
+
+static void biforce_thread_enable(struct thr_info *thr)
+{
+	struct cgpu_info *bitforce = thr->cgpu;
+
+	bitforce_init(bitforce);
+}
+
+static int64_t bitforce_scanhash(struct thr_info *thr, struct work *work, int64_t __maybe_unused max_nonce)
+{
+	struct cgpu_info *bitforce = thr->cgpu;
+	unsigned int sleep_time;
+	int64_t ret;
+
+	ret = bitforce_send_work(thr, work);
+
+	if (!bitforce->nonce_range) {
+		/* Initially wait 2/3 of the average cycle time so we can request more
+		work before full scan is up */
+		sleep_time = (2 * bitforce->sleep_ms) / 3;
+		if (!restart_wait(sleep_time))
+			return 0;
+
+		bitforce->wait_ms = sleep_time;
+		queue_request(thr, false);
+
+		/* Now wait athe final 1/3rd; no bitforce should be finished by now */
+		sleep_time = bitforce->sleep_ms - sleep_time;
+		if (!restart_wait(sleep_time))
+			return 0;
+
+		bitforce->wait_ms += sleep_time;
+	} else {
+		sleep_time = bitforce->sleep_ms;
+		if (!restart_wait(sleep_time))
+			return 0;
+
+		bitforce->wait_ms = sleep_time;
+	}
+
+	if (ret)
+		ret = bitforce_get_result(thr, work);
+
+	if (!ret) {
+		ret = 0;
+		applog(LOG_ERR, "BFL%i: Comms error", bitforce->device_id);
+		bitforce->device_last_not_well = time(NULL);
+		bitforce->device_not_well_reason = REASON_DEV_COMMS_ERROR;
+		bitforce->dev_comms_error_count++;
+		/* empty read buffer */
+		biforce_clear_buffer(bitforce);
+	}
+	return ret;
+}
+
+static bool bitforce_get_stats(struct cgpu_info *bitforce)
+{
+	return bitforce_get_temp(bitforce);
+}
+
+static bool bitforce_thread_init(struct thr_info *thr)
+{
+	struct cgpu_info *bitforce = thr->cgpu;
+	unsigned int wait;
+
+	/* Pause each new thread a random time between 0-100ms 
+	so the devices aren't making calls all at the same time. */
+	wait = (rand() * MAX_START_DELAY_US)/RAND_MAX;
+	applog(LOG_DEBUG, "BFL%i: Delaying start by %dms", bitforce->device_id, wait / 1000);
+	usleep(wait);
+
+	return true;
+}
+
+static struct api_data *bitforce_api_stats(struct cgpu_info *cgpu)
+{
+	struct api_data *root = NULL;
+
+	// Warning, access to these is not locked - but we don't really
+	// care since hashing performance is way more important than
+	// locking access to displaying API debug 'stats'
+	// If locking becomes an issue for any of them, use copy_data=true also
+	root = api_add_uint(root, "Sleep Time", &(cgpu->sleep_ms), false);
+
+	return root;
 }
 }
 
 
 struct device_api bitforce_api = {
 struct device_api bitforce_api = {
 	.dname = "bitforce",
 	.dname = "bitforce",
 	.name = "BFL",
 	.name = "BFL",
 	.api_detect = bitforce_detect,
 	.api_detect = bitforce_detect,
+	.get_api_stats = bitforce_api_stats,
+	.reinit_device = bitforce_init,
 	.get_statline_before = get_bitforce_statline_before,
 	.get_statline_before = get_bitforce_statline_before,
+	.get_stats = bitforce_get_stats,
 	.thread_prepare = bitforce_thread_prepare,
 	.thread_prepare = bitforce_thread_prepare,
+	.thread_init = bitforce_thread_init,
 	.scanhash = bitforce_scanhash,
 	.scanhash = bitforce_scanhash,
+	.thread_shutdown = bitforce_shutdown,
+	.thread_enable = biforce_thread_enable
 };
 };

+ 13 - 17
driver-cpu.c

@@ -81,51 +81,51 @@ extern int dev_from_id(int thr_id);
 
 
 
 
 /* chipset-optimized hash functions */
 /* chipset-optimized hash functions */
-extern bool ScanHash_4WaySSE2(int, const unsigned char *pmidstate,
+extern bool ScanHash_4WaySSE2(struct thr_info*, const unsigned char *pmidstate,
 	unsigned char *pdata, unsigned char *phash1, unsigned char *phash,
 	unsigned char *pdata, unsigned char *phash1, unsigned char *phash,
 	const unsigned char *ptarget,
 	const unsigned char *ptarget,
 	uint32_t max_nonce, uint32_t *last_nonce, uint32_t nonce);
 	uint32_t max_nonce, uint32_t *last_nonce, uint32_t nonce);
 
 
-extern bool ScanHash_altivec_4way(int thr_id, const unsigned char *pmidstate,
+extern bool ScanHash_altivec_4way(struct thr_info*, const unsigned char *pmidstate,
 	unsigned char *pdata,
 	unsigned char *pdata,
 	unsigned char *phash1, unsigned char *phash,
 	unsigned char *phash1, unsigned char *phash,
 	const unsigned char *ptarget,
 	const unsigned char *ptarget,
 	uint32_t max_nonce, uint32_t *last_nonce, uint32_t nonce);
 	uint32_t max_nonce, uint32_t *last_nonce, uint32_t nonce);
 
 
-extern bool scanhash_via(int, const unsigned char *pmidstate,
+extern bool scanhash_via(struct thr_info*, const unsigned char *pmidstate,
 	unsigned char *pdata,
 	unsigned char *pdata,
 	unsigned char *phash1, unsigned char *phash,
 	unsigned char *phash1, unsigned char *phash,
 	const unsigned char *target,
 	const unsigned char *target,
 	uint32_t max_nonce, uint32_t *last_nonce, uint32_t n);
 	uint32_t max_nonce, uint32_t *last_nonce, uint32_t n);
 
 
-extern bool scanhash_c(int, const unsigned char *midstate, unsigned char *data,
+extern bool scanhash_c(struct thr_info*, const unsigned char *midstate, unsigned char *data,
 	      unsigned char *hash1, unsigned char *hash,
 	      unsigned char *hash1, unsigned char *hash,
 	      const unsigned char *target,
 	      const unsigned char *target,
 	      uint32_t max_nonce, uint32_t *last_nonce, uint32_t n);
 	      uint32_t max_nonce, uint32_t *last_nonce, uint32_t n);
 
 
-extern bool scanhash_cryptopp(int, const unsigned char *midstate,unsigned char *data,
+extern bool scanhash_cryptopp(struct thr_info*, const unsigned char *midstate,unsigned char *data,
 	      unsigned char *hash1, unsigned char *hash,
 	      unsigned char *hash1, unsigned char *hash,
 	      const unsigned char *target,
 	      const unsigned char *target,
 	      uint32_t max_nonce, uint32_t *last_nonce, uint32_t n);
 	      uint32_t max_nonce, uint32_t *last_nonce, uint32_t n);
 
 
-extern bool scanhash_asm32(int, const unsigned char *midstate,unsigned char *data,
+extern bool scanhash_asm32(struct thr_info*, const unsigned char *midstate,unsigned char *data,
 	      unsigned char *hash1, unsigned char *hash,
 	      unsigned char *hash1, unsigned char *hash,
 	      const unsigned char *target,
 	      const unsigned char *target,
 	      uint32_t max_nonce, uint32_t *last_nonce, uint32_t nonce);
 	      uint32_t max_nonce, uint32_t *last_nonce, uint32_t nonce);
 
 
-extern bool scanhash_sse2_64(int, const unsigned char *pmidstate, unsigned char *pdata,
+extern bool scanhash_sse2_64(struct thr_info*, const unsigned char *pmidstate, unsigned char *pdata,
 	unsigned char *phash1, unsigned char *phash,
 	unsigned char *phash1, unsigned char *phash,
 	const unsigned char *ptarget,
 	const unsigned char *ptarget,
 	uint32_t max_nonce, uint32_t *last_nonce,
 	uint32_t max_nonce, uint32_t *last_nonce,
 	uint32_t nonce);
 	uint32_t nonce);
 
 
-extern bool scanhash_sse4_64(int, const unsigned char *pmidstate, unsigned char *pdata,
+extern bool scanhash_sse4_64(struct thr_info*, const unsigned char *pmidstate, unsigned char *pdata,
 	unsigned char *phash1, unsigned char *phash,
 	unsigned char *phash1, unsigned char *phash,
 	const unsigned char *ptarget,
 	const unsigned char *ptarget,
 	uint32_t max_nonce, uint32_t *last_nonce,
 	uint32_t max_nonce, uint32_t *last_nonce,
 	uint32_t nonce);
 	uint32_t nonce);
 
 
-extern bool scanhash_sse2_32(int, const unsigned char *pmidstate, unsigned char *pdata,
+extern bool scanhash_sse2_32(struct thr_info*, const unsigned char *pmidstate, unsigned char *pdata,
 	unsigned char *phash1, unsigned char *phash,
 	unsigned char *phash1, unsigned char *phash,
 	const unsigned char *ptarget,
 	const unsigned char *ptarget,
 	uint32_t max_nonce, uint32_t *last_nonce,
 	uint32_t max_nonce, uint32_t *last_nonce,
@@ -224,8 +224,7 @@ double bench_algo_stage3(
 	memset(&work, 0, sizeof(work));
 	memset(&work, 0, sizeof(work));
 	memcpy(&work, &bench_block, min_size);
 	memcpy(&work, &bench_block, min_size);
 
 
-	struct work_restart dummy;
-	work_restart = &dummy;
+	struct thr_info dummy = {0};
 
 
 	struct timeval end;
 	struct timeval end;
 	struct timeval start;
 	struct timeval start;
@@ -236,7 +235,7 @@ double bench_algo_stage3(
 			{
 			{
 				sha256_func func = sha256_funcs[algo];
 				sha256_func func = sha256_funcs[algo];
 				(*func)(
 				(*func)(
-					0,
+					&dummy,
 					work.midstate,
 					work.midstate,
 					work.data,
 					work.data,
 					work.hash1,
 					work.hash1,
@@ -248,7 +247,6 @@ double bench_algo_stage3(
 				);
 				);
 			}
 			}
 	gettimeofday(&end, 0);
 	gettimeofday(&end, 0);
-	work_restart = NULL;
 
 
 	uint64_t usec_end = ((uint64_t)end.tv_sec)*1000*1000 + end.tv_usec;
 	uint64_t usec_end = ((uint64_t)end.tv_sec)*1000*1000 + end.tv_usec;
 	uint64_t usec_start = ((uint64_t)start.tv_sec)*1000*1000 + start.tv_usec;
 	uint64_t usec_start = ((uint64_t)start.tv_sec)*1000*1000 + start.tv_usec;
@@ -731,8 +729,6 @@ static void cpu_detect()
 	if (num_processors < 1)
 	if (num_processors < 1)
 		return;
 		return;
 
 
-	if (total_devices + opt_n_threads > MAX_DEVICES)
-		opt_n_threads = MAX_DEVICES - total_devices;
 	cpus = calloc(opt_n_threads, sizeof(struct cgpu_info));
 	cpus = calloc(opt_n_threads, sizeof(struct cgpu_info));
 	if (unlikely(!cpus))
 	if (unlikely(!cpus))
 		quit(1, "Failed to calloc cpus");
 		quit(1, "Failed to calloc cpus");
@@ -781,7 +777,7 @@ static bool cpu_thread_init(struct thr_info *thr)
 	return true;
 	return true;
 }
 }
 
 
-static uint64_t cpu_scanhash(struct thr_info *thr, struct work *work, uint64_t max_nonce)
+static int64_t cpu_scanhash(struct thr_info *thr, struct work *work, int64_t max_nonce)
 {
 {
 	const int thr_id = thr->id;
 	const int thr_id = thr->id;
 
 
@@ -797,7 +793,7 @@ CPUSearch:
 	{
 	{
 		sha256_func func = sha256_funcs[opt_algo];
 		sha256_func func = sha256_funcs[opt_algo];
 		rc = (*func)(
 		rc = (*func)(
-			thr_id,
+			thr,
 			work->midstate,
 			work->midstate,
 			work->data,
 			work->data,
 			work->hash1,
 			work->hash1,

+ 1 - 1
driver-cpu.h

@@ -1,7 +1,7 @@
 #ifndef __DEVICE_CPU_H__
 #ifndef __DEVICE_CPU_H__
 #define __DEVICE_CPU_H__
 #define __DEVICE_CPU_H__
 
 
-#include "miner.h" /* for work_restart, TODO: re-factor dependency */
+#include "miner.h"
 
 
 #include "config.h"
 #include "config.h"
 #include <stdbool.h>
 #include <stdbool.h>

+ 40 - 29
driver-icarus.c

@@ -179,7 +179,7 @@ struct ICARUS_INFO {
 };
 };
 
 
 // One for each possible device
 // One for each possible device
-static struct ICARUS_INFO *icarus_info[MAX_DEVICES];
+static struct ICARUS_INFO **icarus_info;
 
 
 struct device_api icarus_api;
 struct device_api icarus_api;
 
 
@@ -198,7 +198,7 @@ static void rev(unsigned char *s, size_t l)
 #define icarus_open2(devpath, purge)  serial_open(devpath, 115200, ICARUS_READ_FAULT_DECISECONDS, purge)
 #define icarus_open2(devpath, purge)  serial_open(devpath, 115200, ICARUS_READ_FAULT_DECISECONDS, purge)
 #define icarus_open(devpath)  icarus_open2(devpath, false)
 #define icarus_open(devpath)  icarus_open2(devpath, false)
 
 
-static int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, int thr_id, int read_count)
+static int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, struct thr_info *thr, int read_count)
 {
 {
 	ssize_t ret = 0;
 	ssize_t ret = 0;
 	int rc = 0;
 	int rc = 0;
@@ -232,7 +232,7 @@ static int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, in
 			return 1;
 			return 1;
 		}
 		}
 
 
-		if (thr_id >= 0 && work_restart[thr_id].restart) {
+		if (thr->work_restart) {
 			if (opt_debug) {
 			if (opt_debug) {
 				applog(LOG_DEBUG,
 				applog(LOG_DEBUG,
 					"Icarus Read: Work restart at %.2f seconds",
 					"Icarus Read: Work restart at %.2f seconds",
@@ -379,6 +379,8 @@ static bool icarus_detect_one(const char *devpath)
 	unsigned char ob_bin[64], nonce_bin[ICARUS_READ_SIZE];
 	unsigned char ob_bin[64], nonce_bin[ICARUS_READ_SIZE];
 	char *nonce_hex;
 	char *nonce_hex;
 
 
+	applog(LOG_DEBUG, "Icarus Detect: Attempting to open %s", devpath);
+
 	fd = icarus_open2(devpath, true);
 	fd = icarus_open2(devpath, true);
 	if (unlikely(fd == -1)) {
 	if (unlikely(fd == -1)) {
 		applog(LOG_ERR, "Icarus Detect: Failed to open %s", devpath);
 		applog(LOG_ERR, "Icarus Detect: Failed to open %s", devpath);
@@ -390,7 +392,10 @@ static bool icarus_detect_one(const char *devpath)
 	gettimeofday(&tv_start, NULL);
 	gettimeofday(&tv_start, NULL);
 
 
 	memset(nonce_bin, 0, sizeof(nonce_bin));
 	memset(nonce_bin, 0, sizeof(nonce_bin));
-	icarus_gets(nonce_bin, fd, &tv_finish, -1, 1);
+	struct thr_info dummy = {
+		.work_restart = false,
+	};
+	icarus_gets(nonce_bin, fd, &tv_finish, &dummy, 1);
 
 
 	icarus_close(fd);
 	icarus_close(fd);
 
 
@@ -419,15 +424,15 @@ static bool icarus_detect_one(const char *devpath)
 	icarus->device_path = strdup(devpath);
 	icarus->device_path = strdup(devpath);
 	icarus->threads = 1;
 	icarus->threads = 1;
 	add_cgpu(icarus);
 	add_cgpu(icarus);
+	icarus_info = realloc(icarus_info, sizeof(struct ICARUS_INFO *) * (total_devices + 1));
 
 
 	applog(LOG_INFO, "Found Icarus at %s, mark as %d",
 	applog(LOG_INFO, "Found Icarus at %s, mark as %d",
 		devpath, icarus->device_id);
 		devpath, icarus->device_id);
 
 
-	if (icarus_info[icarus->device_id] == NULL) {
-		icarus_info[icarus->device_id] = (struct ICARUS_INFO *)malloc(sizeof(struct ICARUS_INFO));
-		if (unlikely(!(icarus_info[icarus->device_id])))
-			quit(1, "Failed to malloc ICARUS_INFO");
-	}
+	// Since we are adding a new device on the end it needs to always be allocated
+	icarus_info[icarus->device_id] = (struct ICARUS_INFO *)malloc(sizeof(struct ICARUS_INFO));
+	if (unlikely(!(icarus_info[icarus->device_id])))
+		quit(1, "Failed to malloc ICARUS_INFO");
 
 
 	info = icarus_info[icarus->device_id];
 	info = icarus_info[icarus->device_id];
 
 
@@ -444,7 +449,7 @@ static bool icarus_detect_one(const char *devpath)
 
 
 static void icarus_detect()
 static void icarus_detect()
 {
 {
-	serial_detect("icarus", icarus_detect_one);
+	serial_detect(icarus_api.dname, icarus_detect_one);
 }
 }
 
 
 static bool icarus_prepare(struct thr_info *thr)
 static bool icarus_prepare(struct thr_info *thr)
@@ -469,10 +474,9 @@ static bool icarus_prepare(struct thr_info *thr)
 	return true;
 	return true;
 }
 }
 
 
-static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
-				__maybe_unused uint64_t max_nonce)
+static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
+				__maybe_unused int64_t max_nonce)
 {
 {
-	const int thr_id = thr->id;
 	struct cgpu_info *icarus;
 	struct cgpu_info *icarus;
 	int fd;
 	int fd;
 	int ret;
 	int ret;
@@ -482,7 +486,7 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	unsigned char ob_bin[64], nonce_bin[ICARUS_READ_SIZE];
 	unsigned char ob_bin[64], nonce_bin[ICARUS_READ_SIZE];
 	char *ob_hex;
 	char *ob_hex;
 	uint32_t nonce;
 	uint32_t nonce;
-	uint64_t hash_count;
+	int64_t hash_count;
 	struct timeval tv_start, tv_finish, elapsed;
 	struct timeval tv_start, tv_finish, elapsed;
 	struct timeval tv_history_start, tv_history_finish;
 	struct timeval tv_history_start, tv_history_finish;
 	double Ti, Xi;
 	double Ti, Xi;
@@ -492,9 +496,9 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	int count;
 	int count;
 	double Hs, W, fullnonce;
 	double Hs, W, fullnonce;
 	int read_count;
 	int read_count;
-	uint64_t estimate_hashes;
+	int64_t estimate_hashes;
 	uint32_t values;
 	uint32_t values;
-	uint64_t hash_count_range;
+	int64_t hash_count_range;
 
 
 	elapsed.tv_sec = elapsed.tv_usec = 0;
 	elapsed.tv_sec = elapsed.tv_usec = 0;
 
 
@@ -511,7 +515,7 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 #endif
 #endif
 	ret = icarus_write(fd, ob_bin, sizeof(ob_bin));
 	ret = icarus_write(fd, ob_bin, sizeof(ob_bin));
 	if (ret)
 	if (ret)
-		return 0;	/* This should never happen */
+		return -1;	/* This should never happen */
 
 
 	gettimeofday(&tv_start, NULL);
 	gettimeofday(&tv_start, NULL);
 
 
@@ -527,7 +531,7 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	/* Icarus will return 4 bytes (ICARUS_READ_SIZE) nonces or nothing */
 	/* Icarus will return 4 bytes (ICARUS_READ_SIZE) nonces or nothing */
 	memset(nonce_bin, 0, sizeof(nonce_bin));
 	memset(nonce_bin, 0, sizeof(nonce_bin));
 	info = icarus_info[icarus->device_id];
 	info = icarus_info[icarus->device_id];
-	ret = icarus_gets(nonce_bin, fd, &tv_finish, thr_id, info->read_count);
+	ret = icarus_gets(nonce_bin, fd, &tv_finish, thr, info->read_count);
 
 
 	work->blk.nonce = 0xffffffff;
 	work->blk.nonce = 0xffffffff;
 	memcpy((char *)&nonce, nonce_bin, sizeof(nonce_bin));
 	memcpy((char *)&nonce, nonce_bin, sizeof(nonce_bin));
@@ -674,23 +678,30 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	return hash_count;
 	return hash_count;
 }
 }
 
 
-static void icarus_api_stats(char *buf, struct cgpu_info *cgpu, bool isjson)
+static struct api_data *icarus_api_stats(struct cgpu_info *cgpu)
 {
 {
+	struct api_data *root = NULL;
 	struct ICARUS_INFO *info = icarus_info[cgpu->device_id];
 	struct ICARUS_INFO *info = icarus_info[cgpu->device_id];
 
 
 	// Warning, access to these is not locked - but we don't really
 	// Warning, access to these is not locked - but we don't really
 	// care since hashing performance is way more important than
 	// care since hashing performance is way more important than
 	// locking access to displaying API debug 'stats'
 	// locking access to displaying API debug 'stats'
-	sprintf(buf, isjson
-		? "\"read_count\":%d,\"fullnonce\":%f,\"count\":%d,\"Hs\":%.15f,\"W\":%f,\"total_values\":%u,\"range\":%"PRIu64",\"history_count\":%"PRIu64",\"history_time\":%f,\"min_data_count\":%u,\"timing_values\":%u"
-		: "read_count=%d,fullnonce=%f,count=%d,Hs=%.15f,W=%f,total_values=%u,range=%"PRIu64",history_count=%"PRIu64",history_time=%f,min_data_count=%u,timing_values=%u",
-		info->read_count, info->fullnonce,
-		info->count, info->Hs, info->W,
-		info->values, info->hash_count_range,
-		info->history_count,
-		(double)(info->history_time.tv_sec)
-			+ ((double)(info->history_time.tv_usec))/((double)1000000),
-		info->min_data_count, info->history[0].values);
+	// If locking becomes an issue for any of them, use copy_data=true also
+	root = api_add_int(root, "read_count", &(info->read_count), false);
+	root = api_add_double(root, "fullnonce", &(info->fullnonce), false);
+	root = api_add_int(root, "count", &(info->count), false);
+	root = api_add_hs(root, "Hs", &(info->Hs), false);
+	root = api_add_double(root, "W", &(info->W), false);
+	root = api_add_uint(root, "total_values", &(info->values), false);
+	root = api_add_uint64(root, "range", &(info->hash_count_range), false);
+	root = api_add_uint64(root, "history_count", &(info->history_count), false);
+	root = api_add_timeval(root, "history_time", &(info->history_time), false);
+	root = api_add_uint(root, "min_data_count", &(info->min_data_count), false);
+	root = api_add_uint(root, "timing_values", &(info->history[0].values), false);
+	root = api_add_const(root, "timing_mode", timing_mode_str(info->timing_mode), false);
+	root = api_add_bool(root, "is_timing", &(info->do_icarus_timing), false);
+
+	return root;
 }
 }
 
 
 static void icarus_shutdown(struct thr_info *thr)
 static void icarus_shutdown(struct thr_info *thr)

+ 11 - 10
driver-modminer.c

@@ -121,7 +121,7 @@ modminer_detect_auto()
 static void
 static void
 modminer_detect()
 modminer_detect()
 {
 {
-	serial_detect_auto("modminer", modminer_detect_one, modminer_detect_auto);
+	serial_detect_auto(modminer_api.dname, modminer_detect_one, modminer_detect_auto);
 }
 }
 
 
 #define bailout(...)  return _bailout(-1, modminer, __VA_ARGS__);
 #define bailout(...)  return _bailout(-1, modminer, __VA_ARGS__);
@@ -346,6 +346,8 @@ modminer_fpga_init(struct thr_info *thr)
 
 
 	mutex_unlock(&modminer->device_mutex);
 	mutex_unlock(&modminer->device_mutex);
 
 
+	thr->primary_thread = true;
+
 	return true;
 	return true;
 }
 }
 
 
@@ -424,7 +426,7 @@ fd_set fds;
 	return true;
 	return true;
 }
 }
 
 
-#define work_restart(thr)  work_restart[thr->id].restart
+#define work_restart(thr)  thr->work_restart
 
 
 static uint64_t
 static uint64_t
 modminer_process_results(struct thr_info*thr)
 modminer_process_results(struct thr_info*thr)
@@ -500,7 +502,7 @@ modminer_process_results(struct thr_info*thr)
 
 
 	struct timeval tv_workend, elapsed;
 	struct timeval tv_workend, elapsed;
 	gettimeofday(&tv_workend, NULL);
 	gettimeofday(&tv_workend, NULL);
-	timeval_subtract(&elapsed, &tv_workend, &state->tv_workstart);
+	timersub(&tv_workend, &state->tv_workstart, &elapsed);
 
 
 	uint64_t hashes = (uint64_t)state->clock * (((uint64_t)elapsed.tv_sec * 1000000) + elapsed.tv_usec);
 	uint64_t hashes = (uint64_t)state->clock * (((uint64_t)elapsed.tv_sec * 1000000) + elapsed.tv_usec);
 	if (hashes > 0xffffffff)
 	if (hashes > 0xffffffff)
@@ -514,11 +516,11 @@ modminer_process_results(struct thr_info*thr)
 	return hashes;
 	return hashes;
 }
 }
 
 
-static uint64_t
-modminer_scanhash(struct thr_info*thr, struct work*work, uint64_t __maybe_unused max_nonce)
+static int64_t
+modminer_scanhash(struct thr_info*thr, struct work*work, int64_t __maybe_unused max_nonce)
 {
 {
 	struct modminer_fpga_state *state = thr->cgpu_data;
 	struct modminer_fpga_state *state = thr->cgpu_data;
-	uint64_t hashes = 1;
+	int64_t hashes = 0;
 	bool startwork;
 	bool startwork;
 
 
 	startwork = modminer_prepare_next_work(state, work);
 	startwork = modminer_prepare_next_work(state, work);
@@ -526,15 +528,14 @@ modminer_scanhash(struct thr_info*thr, struct work*work, uint64_t __maybe_unused
 		hashes = modminer_process_results(thr);
 		hashes = modminer_process_results(thr);
 		if (work_restart(thr)) {
 		if (work_restart(thr)) {
 			state->work_running = false;
 			state->work_running = false;
-			return 1;
+			return 0;
 		}
 		}
-	}
-	else
+	} else
 		state->work_running = true;
 		state->work_running = true;
 
 
 	if (startwork) {
 	if (startwork) {
 		if (!modminer_start_work(thr))
 		if (!modminer_start_work(thr))
-			return 0;
+			return -1;
 		memcpy(&state->running_work, work, sizeof(state->running_work));
 		memcpy(&state->running_work, work, sizeof(state->running_work));
 	}
 	}
 
 

+ 29 - 35
driver-opencl.c

@@ -538,15 +538,11 @@ struct cgpu_info *cpus;
 void pause_dynamic_threads(int gpu)
 void pause_dynamic_threads(int gpu)
 {
 {
 	struct cgpu_info *cgpu = &gpus[gpu];
 	struct cgpu_info *cgpu = &gpus[gpu];
-	int i, thread_no = 0;
+	int i;
 
 
-	for (i = 0; i < mining_threads; i++) {
+	for (i = 1; i < cgpu->threads; i++) {
 		struct thr_info *thr = &thr_info[i];
 		struct thr_info *thr = &thr_info[i];
 
 
-		if (thr->cgpu != cgpu)
-			continue;
-		if (!thread_no++)
-			continue;
 		if (!thr->pause && cgpu->dynamic) {
 		if (!thr->pause && cgpu->dynamic) {
 			applog(LOG_WARNING, "Disabling extra threads due to dynamic mode.");
 			applog(LOG_WARNING, "Disabling extra threads due to dynamic mode.");
 			applog(LOG_WARNING, "Tune dynamic intensity with --gpu-dyninterval");
 			applog(LOG_WARNING, "Tune dynamic intensity with --gpu-dyninterval");
@@ -990,7 +986,7 @@ static cl_int queue_diablo_kernel(_clState *clState, dev_blk_ctx *blk, cl_uint t
 }
 }
 
 
 static void set_threads_hashes(unsigned int vectors, unsigned int *threads,
 static void set_threads_hashes(unsigned int vectors, unsigned int *threads,
-			       unsigned int *hashes, size_t *globalThreads,
+			       int64_t *hashes, size_t *globalThreads,
 			       unsigned int minthreads, int intensity)
 			       unsigned int minthreads, int intensity)
 {
 {
 	*threads = 1 << (15 + intensity);
 	*threads = 1 << (15 + intensity);
@@ -1110,7 +1106,7 @@ out:
 	return NULL;
 	return NULL;
 }
 }
 #else
 #else
-void *reinit_gpu(void *userdata)
+void *reinit_gpu(__maybe_unused void *userdata)
 {
 {
 	return NULL;
 	return NULL;
 }
 }
@@ -1130,9 +1126,6 @@ static void opencl_detect()
 		nDevs = 0;
 		nDevs = 0;
 	}
 	}
 
 
-	if (MAX_DEVICES - total_devices < nDevs)
-		nDevs = MAX_DEVICES - total_devices;
-
 	if (!nDevs)
 	if (!nDevs)
 		return;
 		return;
 
 
@@ -1345,45 +1338,46 @@ static bool opencl_prepare_work(struct thr_info __maybe_unused *thr, struct work
 
 
 extern int opt_dynamic_interval;
 extern int opt_dynamic_interval;
 
 
-static uint64_t opencl_scanhash(struct thr_info *thr, struct work *work,
-				uint64_t __maybe_unused max_nonce)
+static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
+				int64_t __maybe_unused max_nonce)
 {
 {
 	const int thr_id = thr->id;
 	const int thr_id = thr->id;
 	struct opencl_thread_data *thrdata = thr->cgpu_data;
 	struct opencl_thread_data *thrdata = thr->cgpu_data;
 	struct cgpu_info *gpu = thr->cgpu;
 	struct cgpu_info *gpu = thr->cgpu;
 	_clState *clState = clStates[thr_id];
 	_clState *clState = clStates[thr_id];
 	const cl_kernel *kernel = &clState->kernel;
 	const cl_kernel *kernel = &clState->kernel;
+	const int dynamic_us = opt_dynamic_interval * 1000;
 
 
-	double gpu_ms_average = 7;
 	cl_int status;
 	cl_int status;
-
 	size_t globalThreads[1];
 	size_t globalThreads[1];
 	size_t localThreads[1] = { clState->wsize };
 	size_t localThreads[1] = { clState->wsize };
 	unsigned int threads;
 	unsigned int threads;
-	unsigned int hashes;
-
-
-	struct timeval tv_gpustart, tv_gpuend, diff;
-	suseconds_t gpu_us;
+	int64_t hashes;
 
 
-	gettimeofday(&tv_gpustart, NULL);
-	timeval_subtract(&diff, &tv_gpustart, &tv_gpuend);
 	/* This finish flushes the readbuffer set with CL_FALSE later */
 	/* This finish flushes the readbuffer set with CL_FALSE later */
+	gettimeofday(&gpu->tv_gpustart, NULL);
 	clFinish(clState->commandQueue);
 	clFinish(clState->commandQueue);
-	gettimeofday(&tv_gpuend, NULL);
-	timeval_subtract(&diff, &tv_gpuend, &tv_gpustart);
-	gpu_us = diff.tv_sec * 1000000 + diff.tv_usec;
-	decay_time(&gpu_ms_average, gpu_us / 1000);
+	gettimeofday(&gpu->tv_gpuend, NULL);
+
 	if (gpu->dynamic) {
 	if (gpu->dynamic) {
-		/* Try to not let the GPU be out for longer than 6ms, but
-		 * increase intensity when the system is idle, unless
-		 * dynamic is disabled. */
-		if (gpu_ms_average > opt_dynamic_interval) {
-			if (gpu->intensity > MIN_INTENSITY)
-				--gpu->intensity;
-		} else if (gpu_ms_average < ((opt_dynamic_interval / 2) ? : 1)) {
-			if (gpu->intensity < MAX_INTENSITY)
-				++gpu->intensity;
+		struct timeval diff;
+		suseconds_t gpu_us;
+
+		timersub(&gpu->tv_gpuend, &gpu->tv_gpustart, &diff);
+		gpu_us = diff.tv_sec * 1000000 + diff.tv_usec;
+		if (likely(gpu_us >= 0)) {
+			gpu->gpu_us_average = (gpu->gpu_us_average + gpu_us * 0.63) / 1.63;
+
+			/* Try to not let the GPU be out for longer than 
+			 * opt_dynamic_interval in ms, but increase
+			 * intensity when the system is idle in dynamic mode */
+			if (gpu->gpu_us_average > dynamic_us) {
+				if (gpu->intensity > MIN_INTENSITY)
+					--gpu->intensity;
+			} else if (gpu->gpu_us_average < dynamic_us / 2) {
+				if (gpu->intensity < MAX_INTENSITY)
+					++gpu->intensity;
+			}
 		}
 		}
 	}
 	}
 	set_threads_hashes(clState->vwidth, &threads, &hashes, globalThreads,
 	set_threads_hashes(clState->vwidth, &threads, &hashes, globalThreads,

+ 13 - 14
driver-ztex.c

@@ -63,11 +63,10 @@ static void ztex_detect(void)
 	struct cgpu_info *ztex;
 	struct cgpu_info *ztex;
 
 
 	cnt = libztex_scanDevices(&ztex_devices);
 	cnt = libztex_scanDevices(&ztex_devices);
-	applog(LOG_WARNING, "Found %d ztex board(s)", cnt);
+	if (cnt > 0)
+		applog(LOG_WARNING, "Found %d ztex board%s", cnt, cnt > 1 ? "s" : "");
 
 
 	for (i = 0; i < cnt; i++) {
 	for (i = 0; i < cnt; i++) {
-		if (total_devices == MAX_DEVICES)
-			break;
 		ztex = calloc(1, sizeof(struct cgpu_info));
 		ztex = calloc(1, sizeof(struct cgpu_info));
 		ztex->api = &ztex_api;
 		ztex->api = &ztex_api;
 		ztex->device_ztex = ztex_devices[i]->dev;
 		ztex->device_ztex = ztex_devices[i]->dev;
@@ -186,8 +185,8 @@ static bool ztex_checkNonce(struct libztex_device *ztex,
 	return true;
 	return true;
 }
 }
 
 
-static uint64_t ztex_scanhash(struct thr_info *thr, struct work *work,
-                              __maybe_unused uint64_t max_nonce)
+static int64_t ztex_scanhash(struct thr_info *thr, struct work *work,
+                              __maybe_unused int64_t max_nonce)
 {
 {
 	struct libztex_device *ztex;
 	struct libztex_device *ztex;
 	unsigned char sendbuf[44];
 	unsigned char sendbuf[44];
@@ -216,7 +215,7 @@ static uint64_t ztex_scanhash(struct thr_info *thr, struct work *work,
 			ztex_disable(thr);
 			ztex_disable(thr);
 			applog(LOG_ERR, "%s: Failed to send hash data with err %d, giving up", ztex->repr, i);
 			applog(LOG_ERR, "%s: Failed to send hash data with err %d, giving up", ztex->repr, i);
 			ztex_releaseFpga(ztex);
 			ztex_releaseFpga(ztex);
-			return 0;
+			return -1;
 		}
 		}
 	}
 	}
 	ztex_releaseFpga(ztex);
 	ztex_releaseFpga(ztex);
@@ -226,7 +225,7 @@ static uint64_t ztex_scanhash(struct thr_info *thr, struct work *work,
 	lastnonce = malloc(sizeof(uint32_t)*ztex->numNonces);
 	lastnonce = malloc(sizeof(uint32_t)*ztex->numNonces);
 	if (lastnonce == NULL) {
 	if (lastnonce == NULL) {
 		applog(LOG_ERR, "%s: failed to allocate lastnonce[%d]", ztex->repr, ztex->numNonces);
 		applog(LOG_ERR, "%s: failed to allocate lastnonce[%d]", ztex->repr, ztex->numNonces);
-		return 0;
+		return -1;
 	}
 	}
 	memset(lastnonce, 0, sizeof(uint32_t)*ztex->numNonces);
 	memset(lastnonce, 0, sizeof(uint32_t)*ztex->numNonces);
 	
 	
@@ -234,16 +233,16 @@ static uint64_t ztex_scanhash(struct thr_info *thr, struct work *work,
 	backlog = malloc(sizeof(uint32_t) * backlog_max);
 	backlog = malloc(sizeof(uint32_t) * backlog_max);
 	if (backlog == NULL) {
 	if (backlog == NULL) {
 		applog(LOG_ERR, "%s: failed to allocate backlog[%d]", ztex->repr, backlog_max);
 		applog(LOG_ERR, "%s: failed to allocate backlog[%d]", ztex->repr, backlog_max);
-		return 0;
+		return -1;
 	}
 	}
 	memset(backlog, 0, sizeof(uint32_t) * backlog_max);
 	memset(backlog, 0, sizeof(uint32_t) * backlog_max);
 	
 	
 	overflow = false;
 	overflow = false;
 
 
 	applog(LOG_DEBUG, "%s: entering poll loop", ztex->repr);
 	applog(LOG_DEBUG, "%s: entering poll loop", ztex->repr);
-	while (!(overflow || work_restart[thr->id].restart)) {
+	while (!(overflow || thr->work_restart)) {
 		usleep(250000);
 		usleep(250000);
-		if (work_restart[thr->id].restart) {
+		if (thr->work_restart) {
 			applog(LOG_DEBUG, "%s: New work detected", ztex->repr);
 			applog(LOG_DEBUG, "%s: New work detected", ztex->repr);
 			break;
 			break;
 		}
 		}
@@ -261,12 +260,12 @@ static uint64_t ztex_scanhash(struct thr_info *thr, struct work *work,
 				free(lastnonce);
 				free(lastnonce);
 				free(backlog);
 				free(backlog);
 				ztex_releaseFpga(ztex);
 				ztex_releaseFpga(ztex);
-				return 0;
+				return -1;
 			}
 			}
 		}
 		}
 		ztex_releaseFpga(ztex);
 		ztex_releaseFpga(ztex);
 
 
-		if (work_restart[thr->id].restart) {
+		if (thr->work_restart) {
 			applog(LOG_DEBUG, "%s: New work detected", ztex->repr);
 			applog(LOG_DEBUG, "%s: New work detected", ztex->repr);
 			break;
 			break;
 		}
 		}
@@ -331,7 +330,7 @@ static uint64_t ztex_scanhash(struct thr_info *thr, struct work *work,
 		free(lastnonce);
 		free(lastnonce);
 		free(backlog);
 		free(backlog);
 		
 		
-		return 0;
+		return -1;
 	}
 	}
 
 
 	applog(LOG_DEBUG, "%s: exit %1.8X", ztex->repr, noncecnt);
 	applog(LOG_DEBUG, "%s: exit %1.8X", ztex->repr, noncecnt);
@@ -341,7 +340,7 @@ static uint64_t ztex_scanhash(struct thr_info *thr, struct work *work,
 	free(lastnonce);
 	free(lastnonce);
 	free(backlog);
 	free(backlog);
 	
 	
-	return noncecnt > 0? noncecnt: 1;
+	return noncecnt;
 }
 }
 
 
 static void ztex_statline_before(char *buf, struct cgpu_info *cgpu)
 static void ztex_statline_before(char *buf, struct cgpu_info *cgpu)

+ 63 - 38
fpgautils.c

@@ -15,6 +15,7 @@
 #include <string.h>
 #include <string.h>
 
 
 #ifndef WIN32
 #ifndef WIN32
+#include <errno.h>
 #include <termios.h>
 #include <termios.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <unistd.h>
@@ -36,13 +37,10 @@
 #include "logging.h"
 #include "logging.h"
 #include "miner.h"
 #include "miner.h"
 
 
+#ifdef HAVE_LIBUDEV
 char
 char
 serial_autodetect_udev(detectone_func_t detectone, const char*prodname)
 serial_autodetect_udev(detectone_func_t detectone, const char*prodname)
 {
 {
-#ifdef HAVE_LIBUDEV
-	if (total_devices == MAX_DEVICES)
-		return 0;
-
 	struct udev *udev = udev_new();
 	struct udev *udev = udev_new();
 	struct udev_enumerate *enumerate = udev_enumerate_new(udev);
 	struct udev_enumerate *enumerate = udev_enumerate_new(udev);
 	struct udev_list_entry *list_entry;
 	struct udev_list_entry *list_entry;
@@ -64,26 +62,24 @@ serial_autodetect_udev(detectone_func_t detectone, const char*prodname)
 			++found;
 			++found;
 
 
 		udev_device_unref(device);
 		udev_device_unref(device);
-
-		if (total_devices == MAX_DEVICES)
-			break;
 	}
 	}
 	udev_enumerate_unref(enumerate);
 	udev_enumerate_unref(enumerate);
 	udev_unref(udev);
 	udev_unref(udev);
 
 
 	return found;
 	return found;
+}
 #else
 #else
+char
+serial_autodetect_udev(__maybe_unused detectone_func_t detectone, __maybe_unused const char*prodname)
+{
 	return 0;
 	return 0;
-#endif
 }
 }
+#endif
 
 
 char
 char
 serial_autodetect_devserial(detectone_func_t detectone, const char*prodname)
 serial_autodetect_devserial(detectone_func_t detectone, const char*prodname)
 {
 {
 #ifndef WIN32
 #ifndef WIN32
-	if (total_devices == MAX_DEVICES)
-		return 0;
-
 	DIR *D;
 	DIR *D;
 	struct dirent *de;
 	struct dirent *de;
 	const char udevdir[] = "/dev/serial/by-id";
 	const char udevdir[] = "/dev/serial/by-id";
@@ -100,11 +96,8 @@ serial_autodetect_devserial(detectone_func_t detectone, const char*prodname)
 		if (!strstr(de->d_name, prodname))
 		if (!strstr(de->d_name, prodname))
 			continue;
 			continue;
 		strcpy(devfile, de->d_name);
 		strcpy(devfile, de->d_name);
-		if (detectone(devpath)) {
+		if (detectone(devpath))
 			++found;
 			++found;
-			if (total_devices == MAX_DEVICES)
-				break;
-		}
 	}
 	}
 	closedir(D);
 	closedir(D);
 
 
@@ -115,20 +108,22 @@ serial_autodetect_devserial(detectone_func_t detectone, const char*prodname)
 }
 }
 
 
 char
 char
-_serial_detect(const char*dnamec, size_t dnamel, detectone_func_t detectone, autoscan_func_t autoscan, bool forceauto)
+_serial_detect(const char*dname, detectone_func_t detectone, autoscan_func_t autoscan, bool forceauto)
 {
 {
-	if (total_devices == MAX_DEVICES)
-		return 0;
-
 	struct string_elist *iter, *tmp;
 	struct string_elist *iter, *tmp;
-	const char*s;
+	const char*s, *p;
 	bool inhibitauto = false;
 	bool inhibitauto = false;
 	char found = 0;
 	char found = 0;
+	size_t dnamel = strlen(dname);
 
 
 	list_for_each_entry_safe(iter, tmp, &scan_devices, list) {
 	list_for_each_entry_safe(iter, tmp, &scan_devices, list) {
 		s = iter->string;
 		s = iter->string;
-		if (!strncmp(dnamec, iter->string, dnamel))
-			s += dnamel;
+		if ((p = strchr(s, ':')) && p[1] != '\0') {
+			size_t plen = p - s;
+			if (plen != dnamel || strncasecmp(s, dname, plen))
+				continue;
+			s = p + 1;
+		}
 		if (!strcmp(s, "auto"))
 		if (!strcmp(s, "auto"))
 			forceauto = true;
 			forceauto = true;
 		else
 		else
@@ -139,12 +134,10 @@ _serial_detect(const char*dnamec, size_t dnamel, detectone_func_t detectone, aut
 			string_elist_del(iter);
 			string_elist_del(iter);
 			inhibitauto = true;
 			inhibitauto = true;
 			++found;
 			++found;
-			if (total_devices == MAX_DEVICES)
-				break;
 		}
 		}
 	}
 	}
 
 
-	if ((forceauto || !inhibitauto) && autoscan && total_devices < MAX_DEVICES)
+	if ((forceauto || !inhibitauto) && autoscan)
 		found += autoscan();
 		found += autoscan();
 
 
 	return found;
 	return found;
@@ -156,7 +149,21 @@ serial_open(const char*devpath, unsigned long baud, signed short timeout, bool p
 #ifdef WIN32
 #ifdef WIN32
 	HANDLE hSerial = CreateFile(devpath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
 	HANDLE hSerial = CreateFile(devpath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
 	if (unlikely(hSerial == INVALID_HANDLE_VALUE))
 	if (unlikely(hSerial == INVALID_HANDLE_VALUE))
+	{
+		DWORD e = GetLastError();
+		switch (e) {
+		case ERROR_ACCESS_DENIED:
+			applog(LOG_ERR, "Do not have user privileges required to open %s", devpath);
+			break;
+		case ERROR_SHARING_VIOLATION:
+			applog(LOG_ERR, "%s is already in use by another process", devpath);
+			break;
+		default:
+			applog(LOG_DEBUG, "Open %s failed, GetLastError:%u", devpath, e);
+			break;
+		}
 		return -1;
 		return -1;
+	}
 
 
 	// thanks to af_newbie for pointers about this
 	// thanks to af_newbie for pointers about this
 	COMMCONFIG comCfg = {0};
 	COMMCONFIG comCfg = {0};
@@ -187,30 +194,48 @@ serial_open(const char*devpath, unsigned long baud, signed short timeout, bool p
 	int fdDev = open(devpath, O_RDWR | O_CLOEXEC | O_NOCTTY);
 	int fdDev = open(devpath, O_RDWR | O_CLOEXEC | O_NOCTTY);
 
 
 	if (unlikely(fdDev == -1))
 	if (unlikely(fdDev == -1))
+	{
+		if (errno == EACCES)
+			applog(LOG_ERR, "Do not have user privileges required to open %s", devpath);
+		else
+			applog(LOG_DEBUG, "Open %s failed, errno:%d", devpath, errno);
+
 		return -1;
 		return -1;
+	}
 
 
-	struct termios pattr;
-	tcgetattr(fdDev, &pattr);
-	pattr.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
-	pattr.c_oflag &= ~OPOST;
-	pattr.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
-	pattr.c_cflag &= ~(CSIZE | PARENB);
-	pattr.c_cflag |= CS8;
+	struct termios my_termios;
+
+	tcgetattr(fdDev, &my_termios);
 
 
 	switch (baud) {
 	switch (baud) {
-	case 0: break;
-	case 115200: pattr.c_cflag = B115200; break;
+	case 0:
+		break;
+	case 115200:
+		cfsetispeed( &my_termios, B115200 );
+		cfsetospeed( &my_termios, B115200 );
+		break;
+	// TODO: try some higher speeds with the Icarus and BFL to see
+	// if they support them and if setting them makes any difference
 	default:
 	default:
 		applog(LOG_WARNING, "Unrecognized baud rate: %lu", baud);
 		applog(LOG_WARNING, "Unrecognized baud rate: %lu", baud);
 	}
 	}
-	pattr.c_cflag |= CREAD | CLOCAL;
+
+	my_termios.c_cflag |= CS8;
+	my_termios.c_cflag |= CREAD;
+	my_termios.c_cflag |= CLOCAL;
+	my_termios.c_cflag &= ~(CSIZE | PARENB);
+
+	my_termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK |
+				ISTRIP | INLCR | IGNCR | ICRNL | IXON);
+	my_termios.c_oflag &= ~OPOST;
+	my_termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
 
 
 	if (timeout >= 0) {
 	if (timeout >= 0) {
-		pattr.c_cc[VTIME] = (cc_t)timeout;
-		pattr.c_cc[VMIN] = 0;
+		my_termios.c_cc[VTIME] = (cc_t)timeout;
+		my_termios.c_cc[VMIN] = 0;
 	}
 	}
 
 
-	tcsetattr(fdDev, TCSANOW, &pattr);
+	tcsetattr(fdDev, TCSANOW, &my_termios);
 	if (purge)
 	if (purge)
 		tcflush(fdDev, TCIOFLUSH);
 		tcflush(fdDev, TCIOFLUSH);
 	return fdDev;
 	return fdDev;

+ 4 - 4
fpgautils.h

@@ -16,13 +16,13 @@
 typedef bool(*detectone_func_t)(const char*);
 typedef bool(*detectone_func_t)(const char*);
 typedef char(*autoscan_func_t)();
 typedef char(*autoscan_func_t)();
 
 
-extern char _serial_detect(const char*dnamec, size_t dnamel, detectone_func_t, autoscan_func_t, bool force_autoscan);
+extern char _serial_detect(const char*dname, detectone_func_t, autoscan_func_t, bool force_autoscan);
 #define serial_detect_fauto(dname, detectone, autoscan)  \
 #define serial_detect_fauto(dname, detectone, autoscan)  \
-	_serial_detect(dname ":", sizeof(dname)+1, detectone, autoscan, true)
+	_serial_detect(dname, detectone, autoscan, true)
 #define serial_detect_auto(dname, detectone, autoscan)  \
 #define serial_detect_auto(dname, detectone, autoscan)  \
-	_serial_detect(dname ":", sizeof(dname)+1, detectone, autoscan, false)
+	_serial_detect(dname, detectone, autoscan, false)
 #define serial_detect(dname, detectone)  \
 #define serial_detect(dname, detectone)  \
-	_serial_detect(dname ":", sizeof(dname)+1, detectone,     NULL, false)
+	_serial_detect(dname, detectone,     NULL, false)
 extern char serial_autodetect_devserial(detectone_func_t, const char*prodname);
 extern char serial_autodetect_devserial(detectone_func_t, const char*prodname);
 extern char serial_autodetect_udev     (detectone_func_t, const char*prodname);
 extern char serial_autodetect_udev     (detectone_func_t, const char*prodname);
 
 

+ 112 - 24
miner.h

@@ -220,6 +220,7 @@ struct gpu_adl {
 };
 };
 #endif
 #endif
 
 
+struct api_data;
 struct thr_info;
 struct thr_info;
 struct work;
 struct work;
 
 
@@ -234,7 +235,8 @@ struct device_api {
 	void (*reinit_device)(struct cgpu_info*);
 	void (*reinit_device)(struct cgpu_info*);
 	void (*get_statline_before)(char*, struct cgpu_info*);
 	void (*get_statline_before)(char*, struct cgpu_info*);
 	void (*get_statline)(char*, struct cgpu_info*);
 	void (*get_statline)(char*, struct cgpu_info*);
-	void (*get_api_stats)(char*, struct cgpu_info*, bool);
+	struct api_data *(*get_api_stats)(struct cgpu_info*);
+	bool (*get_stats)(struct cgpu_info*);
 
 
 	// Thread-specific functions
 	// Thread-specific functions
 	bool (*thread_prepare)(struct thr_info*);
 	bool (*thread_prepare)(struct thr_info*);
@@ -242,8 +244,9 @@ struct device_api {
 	bool (*thread_init)(struct thr_info*);
 	bool (*thread_init)(struct thr_info*);
 	void (*free_work)(struct thr_info*, struct work*);
 	void (*free_work)(struct thr_info*, struct work*);
 	bool (*prepare_work)(struct thr_info*, struct work*);
 	bool (*prepare_work)(struct thr_info*, struct work*);
-	uint64_t (*scanhash)(struct thr_info*, struct work*, uint64_t);
+	int64_t (*scanhash)(struct thr_info*, struct work*, int64_t);
 	void (*thread_shutdown)(struct thr_info*);
 	void (*thread_shutdown)(struct thr_info*);
+	void (*thread_enable)(struct thr_info*);
 };
 };
 
 
 enum dev_enable {
 enum dev_enable {
@@ -269,6 +272,7 @@ enum dev_reason {
 	REASON_DEV_NOSTART,
 	REASON_DEV_NOSTART,
 	REASON_DEV_OVER_HEAT,
 	REASON_DEV_OVER_HEAT,
 	REASON_DEV_THERMAL_CUTOFF,
 	REASON_DEV_THERMAL_CUTOFF,
+	REASON_DEV_COMMS_ERROR,
 };
 };
 
 
 #define REASON_NONE			"None"
 #define REASON_NONE			"None"
@@ -280,6 +284,7 @@ enum dev_reason {
 #define REASON_DEV_NOSTART_STR		"Device failed to start"
 #define REASON_DEV_NOSTART_STR		"Device failed to start"
 #define REASON_DEV_OVER_HEAT_STR	"Device over heated"
 #define REASON_DEV_OVER_HEAT_STR	"Device over heated"
 #define REASON_DEV_THERMAL_CUTOFF_STR	"Device reached thermal cutoff"
 #define REASON_DEV_THERMAL_CUTOFF_STR	"Device reached thermal cutoff"
+#define REASON_DEV_COMMS_ERROR_STR	"Device comms error"
 #define REASON_UNKNOWN_STR		"Unknown reason - code bug"
 #define REASON_UNKNOWN_STR		"Unknown reason - code bug"
 
 
 #define MIN_SEC_UNSET 99999999
 #define MIN_SEC_UNSET 99999999
@@ -298,6 +303,7 @@ struct cgminer_pool_stats {
 	struct timeval getwork_wait;
 	struct timeval getwork_wait;
 	struct timeval getwork_wait_max;
 	struct timeval getwork_wait_max;
 	struct timeval getwork_wait_min;
 	struct timeval getwork_wait_min;
+	double getwork_wait_rolling;
 };
 };
 
 
 struct cgpu_info {
 struct cgpu_info {
@@ -313,12 +319,19 @@ struct cgpu_info {
 #endif
 #endif
 		int device_fd;
 		int device_fd;
 	};
 	};
+#ifdef USE_BITFORCE
+	unsigned int wait_ms;
+	unsigned int sleep_ms;
+	uint32_t nonces;
+	bool nonce_range;
+#endif
 	pthread_mutex_t		device_mutex;
 	pthread_mutex_t		device_mutex;
 
 
 	enum dev_enable deven;
 	enum dev_enable deven;
 	int accepted;
 	int accepted;
 	int rejected;
 	int rejected;
 	int hw_errors;
 	int hw_errors;
+	unsigned int low_count;
 	double rolling;
 	double rolling;
 	double total_mhashes;
 	double total_mhashes;
 	double utility;
 	double utility;
@@ -331,16 +344,20 @@ struct cgpu_info {
 
 
 	unsigned int max_hashes;
 	unsigned int max_hashes;
 
 
+	const char *kname;
+#ifdef HAVE_OPENCL
 	bool mapped;
 	bool mapped;
 	int virtual_gpu;
 	int virtual_gpu;
 	int virtual_adl;
 	int virtual_adl;
 	int intensity;
 	int intensity;
 	bool dynamic;
 	bool dynamic;
-	char *kname;
-#ifdef HAVE_OPENCL
 	cl_uint vwidth;
 	cl_uint vwidth;
 	size_t work_size;
 	size_t work_size;
 	enum cl_kernels kernel;
 	enum cl_kernels kernel;
+
+	struct timeval tv_gpustart;;
+	struct timeval tv_gpuend;
+	double gpu_us_average;
 #endif
 #endif
 
 
 	float temp;
 	float temp;
@@ -373,6 +390,7 @@ struct cgpu_info {
 	int dev_nostart_count;
 	int dev_nostart_count;
 	int dev_over_heat_count;	// It's a warning but worth knowing
 	int dev_over_heat_count;	// It's a warning but worth knowing
 	int dev_thermal_cutoff_count;
 	int dev_thermal_cutoff_count;
+	int dev_comms_error_count;
 
 
 	struct cgminer_stats cgminer_stats;
 	struct cgminer_stats cgminer_stats;
 };
 };
@@ -391,6 +409,7 @@ struct thread_q {
 struct thr_info {
 struct thr_info {
 	int		id;
 	int		id;
 	int		device_thread;
 	int		device_thread;
+	bool		primary_thread;
 
 
 	pthread_t	pth;
 	pthread_t	pth;
 	struct thread_q	*q;
 	struct thread_q	*q;
@@ -402,12 +421,14 @@ struct thr_info {
 	bool	pause;
 	bool	pause;
 	bool	getwork;
 	bool	getwork;
 	double	rolling;
 	double	rolling;
+
+	bool	work_restart;
 };
 };
 
 
 extern int thr_info_create(struct thr_info *thr, pthread_attr_t *attr, void *(*start) (void *), void *arg);
 extern int thr_info_create(struct thr_info *thr, pthread_attr_t *attr, void *(*start) (void *), void *arg);
 extern void thr_info_cancel(struct thr_info *thr);
 extern void thr_info_cancel(struct thr_info *thr);
 extern void thr_info_freeze(struct thr_info *thr);
 extern void thr_info_freeze(struct thr_info *thr);
-
+extern void nmsleep(unsigned int msecs);
 
 
 struct string_elist {
 struct string_elist {
 	char *string;
 	char *string;
@@ -518,6 +539,7 @@ extern bool opt_autofan;
 extern bool opt_autoengine;
 extern bool opt_autoengine;
 extern bool use_curses;
 extern bool use_curses;
 extern char *opt_api_allow;
 extern char *opt_api_allow;
+extern char *opt_api_groups;
 extern char *opt_api_description;
 extern char *opt_api_description;
 extern int opt_api_port;
 extern int opt_api_port;
 extern bool opt_api_listen;
 extern bool opt_api_listen;
@@ -525,17 +547,20 @@ extern bool opt_api_network;
 extern bool opt_delaynet;
 extern bool opt_delaynet;
 extern bool opt_restart;
 extern bool opt_restart;
 extern char *opt_icarus_timing;
 extern char *opt_icarus_timing;
+#ifdef USE_BITFORCE
+extern bool opt_bfl_noncerange;
+#endif
 
 
 extern pthread_rwlock_t netacc_lock;
 extern pthread_rwlock_t netacc_lock;
 
 
 extern const uint32_t sha256_init_state[];
 extern const uint32_t sha256_init_state[];
 extern json_t *json_rpc_call(CURL *curl, const char *url, const char *userpass,
 extern json_t *json_rpc_call(CURL *curl, const char *url, const char *userpass,
-			     const char *rpc_req, bool, bool, bool *,
+			     const char *rpc_req, bool, bool, int *,
 			     struct pool *pool, bool);
 			     struct pool *pool, bool);
 extern char *bin2hex(const unsigned char *p, size_t len);
 extern char *bin2hex(const unsigned char *p, size_t len);
 extern bool hex2bin(unsigned char *p, const char *hexstr, size_t len);
 extern bool hex2bin(unsigned char *p, const char *hexstr, size_t len);
 
 
-typedef bool (*sha256_func)(int thr_id, const unsigned char *pmidstate,
+typedef bool (*sha256_func)(struct thr_info*, const unsigned char *pmidstate,
 	unsigned char *pdata,
 	unsigned char *pdata,
 	unsigned char *phash1, unsigned char *phash,
 	unsigned char *phash1, unsigned char *phash,
 	const unsigned char *ptarget,
 	const unsigned char *ptarget,
@@ -543,19 +568,16 @@ typedef bool (*sha256_func)(int thr_id, const unsigned char *pmidstate,
 	uint32_t *last_nonce,
 	uint32_t *last_nonce,
 	uint32_t nonce);
 	uint32_t nonce);
 
 
-extern int
-timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y);
-
 extern bool fulltest(const unsigned char *hash, const unsigned char *target);
 extern bool fulltest(const unsigned char *hash, const unsigned char *target);
 
 
 extern int opt_scantime;
 extern int opt_scantime;
 
 
-struct work_restart {
-	volatile unsigned long	restart;
-	char			padding[128 - sizeof(unsigned long)];
-};
+extern pthread_mutex_t restart_lock;
+extern pthread_cond_t restart_cond;
 
 
 extern void thread_reportin(struct thr_info *thr);
 extern void thread_reportin(struct thr_info *thr);
+extern bool queue_request(struct thr_info *thr, bool needed);
+extern int restart_wait(unsigned int mstime);
 
 
 extern void kill_work(void);
 extern void kill_work(void);
 
 
@@ -573,14 +595,9 @@ extern void api(int thr_id);
 
 
 extern struct pool *current_pool(void);
 extern struct pool *current_pool(void);
 extern int active_pools(void);
 extern int active_pools(void);
-extern int add_pool_details(bool live, char *url, char *user, char *pass);
-
-#define ADD_POOL_MAXIMUM 1
-#define ADD_POOL_OK 0
+extern void add_pool_details(bool live, char *url, char *user, char *pass);
 
 
 #define MAX_GPUDEVICES 16
 #define MAX_GPUDEVICES 16
-#define MAX_DEVICES 64
-#define MAX_POOLS (32)
 
 
 #define MIN_INTENSITY -10
 #define MIN_INTENSITY -10
 #define _MIN_INTENSITY_STR "-10"
 #define _MIN_INTENSITY_STR "-10"
@@ -594,16 +611,15 @@ extern int num_processors;
 extern int hw_errors;
 extern int hw_errors;
 extern bool use_syslog;
 extern bool use_syslog;
 extern struct thr_info *thr_info;
 extern struct thr_info *thr_info;
-extern struct work_restart *work_restart;
 extern struct cgpu_info gpus[MAX_GPUDEVICES];
 extern struct cgpu_info gpus[MAX_GPUDEVICES];
 extern int gpu_threads;
 extern int gpu_threads;
 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;
 extern int total_devices;
 extern int total_devices;
-extern struct cgpu_info *devices[];
+extern struct cgpu_info **devices;
 extern int total_pools;
 extern int total_pools;
-extern struct pool *pools[MAX_POOLS];
+extern struct pool **pools;
 extern const char *algo_names[];
 extern const char *algo_names[];
 extern enum sha256_algos opt_algo;
 extern enum sha256_algos opt_algo;
 extern struct strategies strategies[];
 extern struct strategies strategies[];
@@ -618,6 +634,7 @@ extern unsigned int local_work;
 extern unsigned int total_go, total_ro;
 extern unsigned int total_go, total_ro;
 extern const int opt_cutofftemp;
 extern const int opt_cutofftemp;
 extern int opt_log_interval;
 extern int opt_log_interval;
+extern unsigned long long global_hashrate;
 
 
 #ifdef HAVE_OPENCL
 #ifdef HAVE_OPENCL
 typedef struct {
 typedef struct {
@@ -732,9 +749,11 @@ struct work {
 	bool		mined;
 	bool		mined;
 	bool		clone;
 	bool		clone;
 	bool		cloned;
 	bool		cloned;
-	bool		rolltime;
+	int		rolltime;
 	bool		longpoll;
 	bool		longpoll;
 	bool		stale;
 	bool		stale;
+	bool		mandatory;
+	bool		block;
 
 
 	unsigned int	work_block;
 	unsigned int	work_block;
 	int		id;
 	int		id;
@@ -743,6 +762,24 @@ struct work {
 	time_t share_found_time;
 	time_t share_found_time;
 };
 };
 
 
+#ifdef USE_MODMINER 
+struct modminer_fpga_state {
+	bool work_running;
+	struct work running_work;
+	struct timeval tv_workstart;
+	uint32_t hashes;
+
+	char next_work_cmd[46];
+
+	unsigned char clock;
+	int no_nonce_counter;
+	int good_share_counter;
+	time_t last_cutoff_reduced;
+
+	unsigned char temp;
+};
+#endif
+
 extern void get_datestamp(char *, struct timeval *);
 extern void get_datestamp(char *, struct timeval *);
 extern bool test_nonce(struct work *work, uint32_t nonce, bool checktarget);
 extern bool test_nonce(struct work *work, uint32_t nonce, bool checktarget);
 bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce);
 bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce);
@@ -768,4 +805,55 @@ extern bool successful_connect;
 extern void adl(void);
 extern void adl(void);
 extern void app_restart(void);
 extern void app_restart(void);
 
 
+enum api_data_type {
+	API_ESCAPE,
+	API_STRING,
+	API_CONST,
+	API_INT,
+	API_UINT,
+	API_UINT32,
+	API_UINT64,
+	API_DOUBLE,
+	API_ELAPSED,
+	API_BOOL,
+	API_TIMEVAL,
+	API_TIME,
+	API_MHS,
+	API_MHTOTAL,
+	API_TEMP,
+	API_UTILITY,
+	API_FREQ,
+	API_VOLTS,
+	API_HS
+};
+
+struct api_data {
+	enum api_data_type type;
+	char *name;
+	void *data;
+	bool data_was_malloc;
+	struct api_data *prev;
+	struct api_data *next;
+};
+
+extern struct api_data *api_add_escape(struct api_data *root, char *name, char *data, bool copy_data);
+extern struct api_data *api_add_string(struct api_data *root, char *name, char *data, bool copy_data);
+extern struct api_data *api_add_const(struct api_data *root, char *name, const char *data, bool copy_data);
+extern struct api_data *api_add_int(struct api_data *root, char *name, int *data, bool copy_data);
+extern struct api_data *api_add_uint(struct api_data *root, char *name, unsigned int *data, bool copy_data);
+extern struct api_data *api_add_uint32(struct api_data *root, char *name, uint32_t *data, bool copy_data);
+extern struct api_data *api_add_uint64(struct api_data *root, char *name, uint64_t *data, bool copy_data);
+extern struct api_data *api_add_double(struct api_data *root, char *name, double *data, bool copy_data);
+extern struct api_data *api_add_elapsed(struct api_data *root, char *name, double *data, bool copy_data);
+extern struct api_data *api_add_bool(struct api_data *root, char *name, bool *data, bool copy_data);
+extern struct api_data *api_add_timeval(struct api_data *root, char *name, struct timeval *data, bool copy_data);
+extern struct api_data *api_add_time(struct api_data *root, char *name, time_t *data, bool copy_data);
+extern struct api_data *api_add_mhs(struct api_data *root, char *name, double *data, bool copy_data);
+extern struct api_data *api_add_mhstotal(struct api_data *root, char *name, double *data, bool copy_data);
+extern struct api_data *api_add_temp(struct api_data *root, char *name, float *data, bool copy_data);
+extern struct api_data *api_add_utility(struct api_data *root, char *name, double *data, bool copy_data);
+extern struct api_data *api_add_freq(struct api_data *root, char *name, double *data, bool copy_data);
+extern struct api_data *api_add_volts(struct api_data *root, char *name, float *data, bool copy_data);
+extern struct api_data *api_add_hs(struct api_data *root, char *name, double *data, bool copy_data);
+
 #endif /* __MINER_H__ */
 #endif /* __MINER_H__ */

File diff suppressed because it is too large
+ 739 - 133
miner.php


+ 2 - 2
sha256_4way.c

@@ -100,7 +100,7 @@ static const unsigned int pSHA256InitState[8] =
 {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
 {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
 
 
 
 
-bool ScanHash_4WaySSE2(int thr_id, const unsigned char *pmidstate,
+bool ScanHash_4WaySSE2(struct thr_info*thr, const unsigned char *pmidstate,
 	unsigned char *pdata,
 	unsigned char *pdata,
 	unsigned char *phash1, unsigned char *phash,
 	unsigned char *phash1, unsigned char *phash,
 	const unsigned char *ptarget,
 	const unsigned char *ptarget,
@@ -139,7 +139,7 @@ bool ScanHash_4WaySSE2(int thr_id, const unsigned char *pmidstate,
             }
             }
         }
         }
 
 
-        if ((nonce >= max_nonce) || work_restart[thr_id].restart)
+        if ((nonce >= max_nonce) || thr->work_restart)
         {
         {
             *last_nonce = nonce;
             *last_nonce = nonce;
             return false;
             return false;

+ 2 - 2
sha256_altivec_4way.c

@@ -73,7 +73,7 @@ static const unsigned int pSHA256InitState[8] =
 {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
 {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
 
 
 
 
-bool ScanHash_altivec_4way(int thr_id, const unsigned char *pmidstate,
+bool ScanHash_altivec_4way(struct thr_info*thr, const unsigned char *pmidstate,
 	unsigned char *pdata,
 	unsigned char *pdata,
 	unsigned char *phash1, unsigned char *phash,
 	unsigned char *phash1, unsigned char *phash,
 	const unsigned char *ptarget,
 	const unsigned char *ptarget,
@@ -111,7 +111,7 @@ bool ScanHash_altivec_4way(int thr_id, const unsigned char *pmidstate,
             }
             }
         }
         }
 
 
-        if ((nonce >= max_nonce) || work_restart[thr_id].restart)
+        if ((nonce >= max_nonce) || thr->work_restart)
         {
         {
             *last_nonce = nonce;
             *last_nonce = nonce;
             return false;
             return false;

+ 4 - 6
sha256_cryptopp.c

@@ -93,7 +93,7 @@ static void runhash(void *state, const void *input, const void *init)
 }
 }
 
 
 /* suspiciously similar to ScanHash* from bitcoin */
 /* suspiciously similar to ScanHash* from bitcoin */
-bool scanhash_cryptopp(int thr_id, const unsigned char *midstate,
+bool scanhash_cryptopp(struct thr_info*thr, const unsigned char *midstate,
 		unsigned char *data,
 		unsigned char *data,
 	        unsigned char *hash1, unsigned char *hash,
 	        unsigned char *hash1, unsigned char *hash,
 		const unsigned char *target,
 		const unsigned char *target,
@@ -105,8 +105,6 @@ bool scanhash_cryptopp(int thr_id, const unsigned char *midstate,
 
 
 	data += 64;
 	data += 64;
 
 
-	work_restart[thr_id].restart = 0;
-
 	while (1) {
 	while (1) {
 		n++;
 		n++;
 		*nonce = n;
 		*nonce = n;
@@ -119,7 +117,7 @@ bool scanhash_cryptopp(int thr_id, const unsigned char *midstate,
 			return true;
 			return true;
 		}
 		}
 
 
-		if ((n >= max_nonce) || work_restart[thr_id].restart) {
+		if ((n >= max_nonce) || thr->work_restart) {
 			*last_nonce = n;
 			*last_nonce = n;
 			return false;
 			return false;
 		}
 		}
@@ -577,7 +575,7 @@ static void runhash32(void *state, const void *input, const void *init)
 }
 }
 
 
 /* suspiciously similar to ScanHash* from bitcoin */
 /* suspiciously similar to ScanHash* from bitcoin */
-bool scanhash_asm32(int thr_id, const unsigned char *midstate,
+bool scanhash_asm32(struct thr_info*thr, const unsigned char *midstate,
 		unsigned char *data,
 		unsigned char *data,
 	        unsigned char *hash1, unsigned char *hash,
 	        unsigned char *hash1, unsigned char *hash,
 		const unsigned char *target,
 		const unsigned char *target,
@@ -601,7 +599,7 @@ bool scanhash_asm32(int thr_id, const unsigned char *midstate,
 			return true;
 			return true;
 		}
 		}
 
 
-		if ((n >= max_nonce) || work_restart[thr_id].restart) {
+		if ((n >= max_nonce) || thr->work_restart) {
 			*last_nonce = n;
 			*last_nonce = n;
 			return false;
 			return false;
 		}
 		}

+ 2 - 2
sha256_generic.c

@@ -239,7 +239,7 @@ const uint32_t sha256_init_state[8] = {
 };
 };
 
 
 /* suspiciously similar to ScanHash* from bitcoin */
 /* suspiciously similar to ScanHash* from bitcoin */
-bool scanhash_c(int thr_id, const unsigned char *midstate, unsigned char *data,
+bool scanhash_c(struct thr_info*thr, const unsigned char *midstate, unsigned char *data,
 	        unsigned char *hash1, unsigned char *hash,
 	        unsigned char *hash1, unsigned char *hash,
 		const unsigned char *target,
 		const unsigned char *target,
 	        uint32_t max_nonce, uint32_t *last_nonce,
 	        uint32_t max_nonce, uint32_t *last_nonce,
@@ -265,7 +265,7 @@ bool scanhash_c(int thr_id, const unsigned char *midstate, unsigned char *data,
 			return true;
 			return true;
 		}
 		}
 
 
-		if ((n >= max_nonce) || work_restart[thr_id].restart) {
+		if ((n >= max_nonce) || thr->work_restart) {
 			*last_nonce = n;
 			*last_nonce = n;
 			return false;
 			return false;
 		}
 		}

+ 2 - 2
sha256_sse2_amd64.c

@@ -48,7 +48,7 @@ const uint32_t sha256_init[8]__attribute__((aligned(0x100))) =
 __m128i g_4sha256_k[64];
 __m128i g_4sha256_k[64];
 __m128i sha256_consts_m128i[64]__attribute__((aligned(0x1000)));
 __m128i sha256_consts_m128i[64]__attribute__((aligned(0x1000)));
 
 
-bool scanhash_sse2_64(int thr_id, const unsigned char *pmidstate,
+bool scanhash_sse2_64(struct thr_info*thr, const unsigned char *pmidstate,
 	unsigned char *pdata,
 	unsigned char *pdata,
 	unsigned char *phash1, unsigned char *phash,
 	unsigned char *phash1, unsigned char *phash,
 	const unsigned char *ptarget,
 	const unsigned char *ptarget,
@@ -119,7 +119,7 @@ bool scanhash_sse2_64(int thr_id, const unsigned char *pmidstate,
 		}
 		}
 	}
 	}
 
 
-        if (unlikely((nonce >= max_nonce) || work_restart[thr_id].restart))
+        if (unlikely((nonce >= max_nonce) || thr->work_restart))
         {
         {
 			*last_nonce = nonce;
 			*last_nonce = nonce;
 			return false;
 			return false;

+ 2 - 2
sha256_sse2_i386.c

@@ -48,7 +48,7 @@ const uint32_t sha256_32init[8]__attribute__((aligned(0x100))) =
 __m128i g_4sha256_k[64];
 __m128i g_4sha256_k[64];
 __m128i sha256_consts_m128i[64]__attribute__((aligned(0x1000)));
 __m128i sha256_consts_m128i[64]__attribute__((aligned(0x1000)));
 
 
-bool scanhash_sse2_32(int thr_id, const unsigned char *pmidstate,
+bool scanhash_sse2_32(struct thr_info*thr, const unsigned char *pmidstate,
 	unsigned char *pdata,
 	unsigned char *pdata,
 	unsigned char *phash1, unsigned char *phash,
 	unsigned char *phash1, unsigned char *phash,
 	const unsigned char *ptarget,
 	const unsigned char *ptarget,
@@ -111,7 +111,7 @@ bool scanhash_sse2_32(int thr_id, const unsigned char *pmidstate,
 	    }
 	    }
 	}
 	}
 
 
-	if (unlikely((nonce >= max_nonce) || work_restart[thr_id].restart)) {
+	if (unlikely((nonce >= max_nonce) || thr->work_restart)) {
 		*last_nonce = nonce;
 		*last_nonce = nonce;
 		return false;
 		return false;
 	}
 	}

+ 2 - 2
sha256_sse4_amd64.c

@@ -47,7 +47,7 @@ static uint32_t g_sha256_hinit[8] =
 
 
 __m128i g_4sha256_k[64];
 __m128i g_4sha256_k[64];
 
 
-bool scanhash_sse4_64(int thr_id, const unsigned char *pmidstate,
+bool scanhash_sse4_64(struct thr_info*thr, const unsigned char *pmidstate,
 	unsigned char *pdata,
 	unsigned char *pdata,
 	unsigned char *phash1, unsigned char *phash,
 	unsigned char *phash1, unsigned char *phash,
 	const unsigned char *ptarget,
 	const unsigned char *ptarget,
@@ -118,7 +118,7 @@ bool scanhash_sse4_64(int thr_id, const unsigned char *pmidstate,
 		}
 		}
 	}
 	}
 
 
-        if (unlikely((nonce >= max_nonce) || work_restart[thr_id].restart))
+        if (unlikely((nonce >= max_nonce) || thr->work_restart))
         {
         {
 			*last_nonce = nonce;
 			*last_nonce = nonce;
 			return false;
 			return false;

+ 2 - 2
sha256_via.c

@@ -19,7 +19,7 @@ static void via_sha256(void *hash, void *buf, unsigned len)
 		     :"memory");
 		     :"memory");
 }
 }
 
 
-bool scanhash_via(int thr_id, const unsigned char *pmidstate,
+bool scanhash_via(struct thr_info*thr, const unsigned char *pmidstate,
 	unsigned char *data_inout,
 	unsigned char *data_inout,
 	unsigned char *phash1, unsigned char *phash,
 	unsigned char *phash1, unsigned char *phash,
 	const unsigned char *target,
 	const unsigned char *target,
@@ -74,7 +74,7 @@ bool scanhash_via(int thr_id, const unsigned char *pmidstate,
 			return true;
 			return true;
 		}
 		}
 
 
-		if ((n >= max_nonce) || work_restart[thr_id].restart) {
+		if ((n >= max_nonce) || thr->work_restart) {
 			*last_nonce = n;
 			*last_nonce = n;
 			return false;
 			return false;
 		}
 		}

+ 51 - 54
util.c

@@ -56,7 +56,7 @@ struct upload_buffer {
 
 
 struct header_info {
 struct header_info {
 	char		*lp_path;
 	char		*lp_path;
-	bool		has_rolltime;
+	int		rolltime;
 	char		*reason;
 	char		*reason;
 };
 };
 
 
@@ -147,9 +147,9 @@ static size_t resp_hdr_cb(void *ptr, size_t size, size_t nmemb, void *user_data)
 
 
 	memcpy(val, rem, remlen);	/* store value, trim trailing ws */
 	memcpy(val, rem, remlen);	/* store value, trim trailing ws */
 	val[remlen] = 0;
 	val[remlen] = 0;
-	while ((*val) && (isspace(val[strlen(val) - 1]))) {
+	while ((*val) && (isspace(val[strlen(val) - 1])))
 		val[strlen(val) - 1] = 0;
 		val[strlen(val) - 1] = 0;
-	}
+
 	if (!*val)			/* skip blank value */
 	if (!*val)			/* skip blank value */
 		goto out;
 		goto out;
 
 
@@ -157,11 +157,16 @@ static size_t resp_hdr_cb(void *ptr, size_t size, size_t nmemb, void *user_data)
 		applog(LOG_DEBUG, "HTTP hdr(%s): %s", key, val);
 		applog(LOG_DEBUG, "HTTP hdr(%s): %s", key, val);
 
 
 	if (!strcasecmp("X-Roll-Ntime", key)) {
 	if (!strcasecmp("X-Roll-Ntime", key)) {
-		if (!strncasecmp("N", val, 1)) {
+		if (!strncasecmp("N", val, 1))
 			applog(LOG_DEBUG, "X-Roll-Ntime: N found");
 			applog(LOG_DEBUG, "X-Roll-Ntime: N found");
-		} else {
-			applog(LOG_DEBUG, "X-Roll-Ntime found");
-			hi->has_rolltime = true;
+		else {
+			/* Check to see if expire= is supported and if not, set
+			 * the rolltime to the default scantime */
+			if (strlen(val) > 7 && !strncasecmp("expire=", val, 7))
+				sscanf(val + 7, "%d", &hi->rolltime);
+			else
+				hi->rolltime = opt_scantime;
+			applog(LOG_DEBUG, "X-Roll-Ntime expiry set to %d", hi->rolltime);
 		}
 		}
 	}
 	}
 
 
@@ -248,20 +253,20 @@ static void set_nettime(void)
 
 
 json_t *json_rpc_call(CURL *curl, const char *url,
 json_t *json_rpc_call(CURL *curl, const char *url,
 		      const char *userpass, const char *rpc_req,
 		      const char *userpass, const char *rpc_req,
-		      bool probe, bool longpoll, bool *rolltime,
+		      bool probe, bool longpoll, int *rolltime,
 		      struct pool *pool, bool share)
 		      struct pool *pool, bool share)
 {
 {
-	json_t *val, *err_val, *res_val;
-	int rc;
+	long timeout = longpoll ? (60 * 60) : 60;
 	struct data_buffer all_data = {NULL, 0};
 	struct data_buffer all_data = {NULL, 0};
-	struct upload_buffer upload_data;
-	json_error_t err;
-	struct curl_slist *headers = NULL;
+	struct header_info hi = {NULL, 0, NULL};
 	char len_hdr[64], user_agent_hdr[128];
 	char len_hdr[64], user_agent_hdr[128];
 	char curl_err_str[CURL_ERROR_SIZE];
 	char curl_err_str[CURL_ERROR_SIZE];
-	long timeout = longpoll ? (60 * 60) : 60;
-	struct header_info hi = {NULL, false, NULL};
+	struct curl_slist *headers = NULL;
+	struct upload_buffer upload_data;
+	json_t *val, *err_val, *res_val;
 	bool probing = false;
 	bool probing = false;
+	json_error_t err;
+	int rc;
 
 
 	memset(&err, 0, sizeof(err));
 	memset(&err, 0, sizeof(err));
 
 
@@ -320,6 +325,14 @@ json_t *json_rpc_call(CURL *curl, const char *url,
 		"Content-type: application/json");
 		"Content-type: application/json");
 	headers = curl_slist_append(headers,
 	headers = curl_slist_append(headers,
 		"X-Mining-Extensions: longpoll midstate rollntime submitold");
 		"X-Mining-Extensions: longpoll midstate rollntime submitold");
+
+	if (likely(global_hashrate)) {
+		char ghashrate[255];
+
+		sprintf(ghashrate, "X-Mining-Hashrate: %llu", global_hashrate);
+		headers = curl_slist_append(headers, ghashrate);
+	}
+
 	headers = curl_slist_append(headers, len_hdr);
 	headers = curl_slist_append(headers, len_hdr);
 	headers = curl_slist_append(headers, user_agent_hdr);
 	headers = curl_slist_append(headers, user_agent_hdr);
 	headers = curl_slist_append(headers, "Expect:"); /* disable Expect hdr*/
 	headers = curl_slist_append(headers, "Expect:"); /* disable Expect hdr*/
@@ -367,15 +380,14 @@ json_t *json_rpc_call(CURL *curl, const char *url,
 			if (pool->hdr_path != NULL)
 			if (pool->hdr_path != NULL)
 				free(pool->hdr_path);
 				free(pool->hdr_path);
 			pool->hdr_path = hi.lp_path;
 			pool->hdr_path = hi.lp_path;
-		} else {
+		} else
 			pool->hdr_path = NULL;
 			pool->hdr_path = NULL;
-		}
 	} else if (hi.lp_path) {
 	} else if (hi.lp_path) {
 		free(hi.lp_path);
 		free(hi.lp_path);
 		hi.lp_path = NULL;
 		hi.lp_path = NULL;
 	}
 	}
 
 
-	*rolltime = hi.has_rolltime;
+	*rolltime = hi.rolltime;
 
 
 	val = JSON_LOADS(all_data.buf, &err);
 	val = JSON_LOADS(all_data.buf, &err);
 	if (!val) {
 	if (!val) {
@@ -389,6 +401,7 @@ json_t *json_rpc_call(CURL *curl, const char *url,
 
 
 	if (opt_protocol) {
 	if (opt_protocol) {
 		char *s = json_dumps(val, JSON_INDENT(3));
 		char *s = json_dumps(val, JSON_INDENT(3));
+
 		applog(LOG_DEBUG, "JSON protocol response:\n%s", s);
 		applog(LOG_DEBUG, "JSON protocol response:\n%s", s);
 		free(s);
 		free(s);
 	}
 	}
@@ -438,8 +451,8 @@ err_out:
 
 
 char *bin2hex(const unsigned char *p, size_t len)
 char *bin2hex(const unsigned char *p, size_t len)
 {
 {
-	unsigned int i;
 	char *s = malloc((len * 2) + 1);
 	char *s = malloc((len * 2) + 1);
+	unsigned int i;
 
 
 	if (!s)
 	if (!s)
 		return NULL;
 		return NULL;
@@ -480,43 +493,14 @@ bool hex2bin(unsigned char *p, const char *hexstr, size_t len)
 	return (len == 0 && *hexstr == 0) ? true : false;
 	return (len == 0 && *hexstr == 0) ? true : false;
 }
 }
 
 
-/* Subtract the `struct timeval' values X and Y,
-   storing the result in RESULT.
-   Return 1 if the difference is negative, otherwise 0.  */
-
-int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y)
-{
-	/* Perform the carry for the later subtraction by updating Y. */
-	if (x->tv_usec < y->tv_usec) {
-		int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
-
-		y->tv_usec -= 1000000 * nsec;
-		y->tv_sec += nsec;
-	}
-	if (x->tv_usec - y->tv_usec > 1000000) {
-		int nsec = (x->tv_usec - y->tv_usec) / 1000000;
-
-		y->tv_usec += 1000000 * nsec;
-		y->tv_sec -= nsec;
-	}
-
-	/* Compute the time remaining to wait.
-	 * `tv_usec' is certainly positive. */
-	result->tv_sec = x->tv_sec - y->tv_sec;
-	result->tv_usec = x->tv_usec - y->tv_usec;
-
-	/* Return 1 if result is negative. */
-	return x->tv_sec < y->tv_sec;
-}
-
 bool fulltest(const unsigned char *hash, const unsigned char *target)
 bool fulltest(const unsigned char *hash, const unsigned char *target)
 {
 {
 	unsigned char hash_swap[32], target_swap[32];
 	unsigned char hash_swap[32], target_swap[32];
 	uint32_t *hash32 = (uint32_t *) hash_swap;
 	uint32_t *hash32 = (uint32_t *) hash_swap;
 	uint32_t *target32 = (uint32_t *) target_swap;
 	uint32_t *target32 = (uint32_t *) target_swap;
-	int i;
-	bool rc = true;
 	char *hash_str, *target_str;
 	char *hash_str, *target_str;
+	bool rc = true;
+	int i;
 
 
 	swap256(hash_swap, hash);
 	swap256(hash_swap, hash);
 	swap256(target_swap, target);
 	swap256(target_swap, target);
@@ -669,10 +653,7 @@ out:
 
 
 int thr_info_create(struct thr_info *thr, pthread_attr_t *attr, void *(*start) (void *), void *arg)
 int thr_info_create(struct thr_info *thr, pthread_attr_t *attr, void *(*start) (void *), void *arg)
 {
 {
-	int ret;
-
-	ret = pthread_create(&thr->pth, attr, start, arg);
-	return ret;
+	return pthread_create(&thr->pth, attr, start, arg);
 }
 }
 
 
 void thr_info_freeze(struct thr_info *thr)
 void thr_info_freeze(struct thr_info *thr)
@@ -706,3 +687,19 @@ void thr_info_cancel(struct thr_info *thr)
 		PTH(thr) = 0L;
 		PTH(thr) = 0L;
 	}
 	}
 }
 }
+
+/* Provide a ms based sleep that uses nanosleep to avoid poor usleep accuracy
+ * on SMP machines */
+void nmsleep(unsigned int msecs)
+{
+	struct timespec twait, tleft;
+	int ret;
+
+	tleft.tv_sec = msecs / 1000;
+	tleft.tv_nsec = (uint64_t)(msecs * 1000000) - (uint64_t)(twait.tv_sec / 1000000000);
+	do {
+		twait.tv_sec = tleft.tv_sec;
+		twait.tv_nsec = tleft.tv_nsec;
+		ret = nanosleep(&twait, &tleft);
+	} while (ret == -1 && errno == EINTR);
+}

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