Commit 99a68da9f33760f9f58ac839e8cb6182b347cabc

kanoi 2014-05-08T12:11:10

Merge pull request #588 from kanoi/min Minion Updates

diff --git a/ASIC-README b/ASIC-README
index 6e82783..e68837c 100644
--- a/ASIC-README
+++ b/ASIC-README
@@ -7,6 +7,7 @@ Currently supported devices include:
 - BF1 (bitfury) USB (red and blue)
 - KnCminer Mercury, Saturn and Jupiter
 - BlackArrow Bitfury
+- BlackArrow Minion
 - Bi*fury USB
 - Onestring miner USB
 - Hexfury USB
@@ -55,6 +56,14 @@ The current BlackArrow Bitfury devices are similar to the Bitfury GPIO mining
 boards, with both V1 and V2 controllers, and come up as BaB.
 
 
+BlackArrow Minion devices
+
+BlackArrow Minion devices need the --enable-minion option when compiling
+cgminer.
+
+BlackArrow Minion devices are SPI/GPIO mining devices and come up as MBA
+
+
 BITFURY devices
 
 Bitfury devices need the --enable-bitfury option when compiling cgminer.
@@ -225,6 +234,7 @@ ASIC SPECIFIC COMMANDS
 --hfa-temp-overheat <arg> Set the hashfast overheat throttling temperature (default: 95)
 --hfa-temp-target <arg> Set the hashfast target temperature (0 to disable) (default: 88)
 --klondike-options <arg> Set klondike options clock:temptarget
+--minion-freq <arg> Set minion chip frequencies in MHz, single value or comma list, range 100-1400 (default: 1000)
 --nfu-bits <arg>    Set nanofury bits for overclocking, range 32-63 (default: 50)
 
 
diff --git a/README b/README
index 7e59bd7..c3eb8d6 100644
--- a/README
+++ b/README
@@ -218,6 +218,7 @@ Options for both config file and command line:
 --load-balance      Change multipool strategy from failover to quota based balance
 --log|-l <arg>      Interval in seconds between log output (default: 5)
 --lowmem            Minimise caching of shares for low memory applications
+--minion-freq <arg> Set minion chip frequencies in MHz, single value or comma list, range 100-1400 (default: 1000)
 --monitor|-m <arg>  Use custom pipe cmd for output messages
 --nfu-bits <arg>    Set nanofury bits for overclocking, range 32-63 (default: 50)
 --net-delay         Impose small delays in networking to not overload slow routers
diff --git a/api.c b/api.c
index ed28b42..eebd2a0 100644
--- a/api.c
+++ b/api.c
@@ -2190,14 +2190,16 @@ static void devstatus(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __ma
 		io_close(io_data);
 }
 
-static void edevstatus(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
+static void edevstatus(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
 {
 	bool io_open = false;
 	int devcount = 0;
 	int numasc = 0;
 	int numpga = 0;
 	int i;
+#ifdef USE_USBUTILS
 	time_t howoldsec = 0;
+#endif
 
 #ifdef HAVE_AN_ASIC
 	numasc = numascs();
@@ -2212,8 +2214,10 @@ static void edevstatus(struct io_data *io_data, __maybe_unused SOCKETTYPE c, cha
 		return;
 	}
 
+#ifdef USE_USBUTILS
 	if (param && *param)
 		howoldsec = (time_t)atoi(param);
+#endif
 
 	message(io_data, MSG_DEVS, 0, NULL, isjson);
 	if (isjson)
@@ -3315,17 +3319,19 @@ static void minerstats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __m
 		io_close(io_data);
 }
 
-static void minerestats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
+static void minerestats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
 {
 	struct cgpu_info *cgpu;
 	bool io_open = false;
 	struct api_data *extra;
 	char id[20];
 	int i, j;
+#ifdef USE_USBUTILS
 	time_t howoldsec = 0;
 
 	if (param && *param)
 		howoldsec = (time_t)atoi(param);
+#endif
 
 	message(io_data, MSG_MINESTATS, 0, NULL, isjson);
 	if (isjson)
diff --git a/cgminer.c b/cgminer.c
index 265dd99..10053ab 100644
--- a/cgminer.c
+++ b/cgminer.c
@@ -238,6 +238,9 @@ static char *opt_set_bitmain_freq;
 static char *opt_set_hfa_fan;
 #endif
 static char *opt_set_null;
+#ifdef USE_MINION
+char *opt_minion_freq;
+#endif
 
 #ifdef USE_USBUTILS
 char *opt_usb_select = NULL;
@@ -1309,6 +1312,11 @@ static struct opt_table opt_config_table[] = {
 	OPT_WITHOUT_ARG("--lowmem",
 			opt_set_bool, &opt_lowmem,
 			"Minimise caching of shares for low memory applications"),
+#ifdef USE_MINION
+	OPT_WITH_ARG("--minion-freq",
+		     opt_set_charp, NULL, &opt_minion_freq,
+		     "Set minion chip frequencies in MHz, single value or comma list, range 100-1400 (default: 1000)"),
+#endif
 #if defined(unix) || defined(__APPLE__)
 	OPT_WITH_ARG("--monitor|-m",
 		     opt_set_charp, NULL, &opt_stderr_cmd,
diff --git a/driver-minion.c b/driver-minion.c
index 4c12f8c..ffa1f4e 100644
--- a/driver-minion.c
+++ b/driver-minion.c
@@ -10,6 +10,8 @@
 #include "config.h"
 #include "compat.h"
 #include "miner.h"
+#include <ctype.h>
+#include <math.h>
 
 #ifndef LINUX
 static void minion_detect(__maybe_unused bool hotplug)
@@ -210,6 +212,29 @@ struct minion_header {
 #define MINION_CHIP_SIG_SHIFT3 (((MINION_CHIP_SIG & 0xffffff00) >>  8) & 0x00ffffff)
 #define MINION_CHIP_SIG_SHIFT4 (((MINION_CHIP_SIG & 0xffff0000) >> 16) & 0x0000ffff)
 
+#define MINION_FREQ_MIN 1
+#define MINION_FREQ_DEF 10
+#define MINION_FREQ_MAX 14
+#define MINION_FREQ_FACTOR 100
+
+static uint32_t minion_freq[] = {
+	0x0,
+	0x205032,	//  1 =  100Mhz
+	0x203042,	//  2 =  200Mhz
+	0x20204B,	//  3 =  300Mhz
+	0x201042,	//  4 =  400Mhz
+	0x201053,	//  5 =  500Mhz
+	0x200032,	//  6 =  600Mhz
+	0x20003A,	//  7 =  700Mhz
+	0x200042,	//  8 =  800Mhz
+	0x20004B,	//  9 =  900Mhz
+	0x200053,	// 10 = 1000Mhz
+	0x21005B,	// 11 = 1100Mhz
+	0x210064,	// 12 = 1200Mhz
+	0x21006C,	// 13 = 1300Mhz
+	0x210074	// 14 = 1400Mhz
+};
+
 #define STA_TEMP(_sta) ((uint16_t)((_sta)[3] & 0x1f))
 #define STA_CORES(_sta) ((uint16_t)((_sta)[2]))
 #define STA_FREQ(_sta) ((uint32_t)((_sta)[1]) * 0x100 + (uint32_t)((_sta)[0]))
@@ -385,8 +410,9 @@ typedef struct k_list {
 #define K_RLOCK(_list) cg_rlock(_list->lock)
 #define K_RUNLOCK(_list) cg_runlock(_list->lock)
 
-// Set this to 0 to remove iostats processing
-#define DO_IO_STATS 1
+// Set this to 1 to enable iostats processing
+// N.B. it slows down mining
+#define DO_IO_STATS 0
 
 #if DO_IO_STATS
 #define IO_STAT_NOW(_tv) cgtime(_tv)
@@ -511,6 +537,7 @@ struct minion_info {
 	// TODO: need to track disabled chips - done?
 	int chips;
 	bool chip[MINION_CHIPS];
+	int init_freq[MINION_CHIPS];
 
 	uint32_t next_task_id;
 
@@ -1067,12 +1094,13 @@ static int build_cmd(struct cgpu_info *minioncgpu, struct minion_info *minioninf
 	return reply;
 }
 
-// TODO: hard coded for now
 static void init_chip(struct cgpu_info *minioncgpu, struct minion_info *minioninfo, int chip)
 {
 	uint8_t rbuf[MINION_BUFSIZ];
 	uint8_t data[4];
 	__maybe_unused int reply;
+	int choice;
+	uint32_t freq;
 
 	// Complete chip reset
 	data[0] = 0x00;
@@ -1103,6 +1131,20 @@ static void init_chip(struct cgpu_info *minioncgpu, struct minion_info *minionin
 	reply = build_cmd(minioncgpu, minioninfo,
 			  chip, WRITE_ADDR(MINION_SYS_MISC_CTL),
 			  rbuf, 0, data);
+
+	// Set chip frequency
+	choice = minioninfo->init_freq[chip];
+	if (choice < MINION_FREQ_MIN || choice > MINION_FREQ_MAX)
+		choice = MINION_FREQ_DEF;
+	freq = minion_freq[choice];
+	data[0] = (uint8_t)(freq & 0xff);
+	data[1] = (uint8_t)(((freq & 0xff00) >> 8) & 0xff);
+	data[2] = (uint8_t)(((freq & 0xff0000) >> 16) & 0xff);
+	data[3] = (uint8_t)(((freq & 0xff000000) >> 24) & 0xff);
+
+	reply = build_cmd(minioncgpu, minioninfo,
+			  chip, WRITE_ADDR(MINION_SYS_FREQ_CTL),
+			  rbuf, 0, data);
 }
 
 // TODO: hard coded for now
@@ -1576,6 +1618,40 @@ static bool minion_init_gpio_interrupt(struct cgpu_info *minioncgpu, struct mini
 	return true;
 }
 
+static void minion_process_options(struct minion_info *minioninfo)
+{
+	int last_freq = MINION_FREQ_DEF;
+	char *freq, *comma, *buf;
+	int i;
+
+	if (opt_minion_freq && *opt_minion_freq) {
+		buf = freq = strdup(opt_minion_freq);
+		comma = strchr(freq, ',');
+		if (comma)
+			*(comma++) = '\0';
+
+		for (i = 0; i < MINION_CHIPS; i++) {
+			if (freq && isdigit(*freq)) {
+				last_freq = (int)round((double)atoi(freq) / (double)MINION_FREQ_FACTOR);
+				if (last_freq < MINION_FREQ_MIN)
+					last_freq = MINION_FREQ_MIN;
+				if (last_freq > MINION_FREQ_MAX)
+					last_freq = MINION_FREQ_MAX;
+
+				freq = comma;
+				if (comma) {
+					comma = strchr(freq, ',');
+					if (comma)
+						*(comma++) = '\0';
+				}
+			}
+			minioninfo->init_freq[i] = last_freq;
+		}
+
+		free(buf);
+	}
+}
+
 static void minion_detect(bool hotplug)
 {
 	struct cgpu_info *minioncgpu = NULL;
@@ -1607,6 +1683,11 @@ static void minion_detect(bool hotplug)
 	mutex_init(&(minioninfo->spi_lock));
 	mutex_init(&(minioninfo->sta_lock));
 
+	for (i = 0; i < MINION_CHIPS; i++)
+		minioninfo->init_freq[i] = MINION_FREQ_DEF;
+
+	minion_process_options(minioninfo);
+
 	applog(LOG_WARNING, "%s: checking for chips ...", minioncgpu->drv->dname);
 
 	minion_detect_chips(minioncgpu, minioninfo);
@@ -1903,12 +1984,8 @@ static void *minion_spi_reply(void *userdata)
 									K_WUNLOCK(minioninfo->rnonce_list);
 									cgsem_post(&(minioninfo->nonce_ready));
 								} else {
-									applog(LOG_ERR, "%s%i: Invalid task_id - chip %d core %d task 0x%04x nonce 0x%08x",
-											minioncgpu->drv->name, minioncgpu->device_id,
-											DATAR(item)->chip,
-											DATAR(item)->core,
-											DATAR(item)->task_id,
-											DATAR(item)->nonce);
+									applog(LOG_ERR, "%s%i: Invalid task_id - chip %d",
+											minioncgpu->drv->name, minioncgpu->device_id, chip);
 								}
 							}
 						}
@@ -2565,6 +2642,30 @@ static int64_t minion_scanwork(__maybe_unused struct thr_info *thr)
 	return hashcount;
 }
 
+static const char *min_temp_0 = "<40";
+static const char *min_temp_1 = "40-60";
+static const char *min_temp_3 = "60-80";
+static const char *min_temp_7 = "80-100";
+static const char *min_temp_15 = ">100";
+static const char *min_temp_invalid = "?";
+
+static const char *temp_str(uint16_t temp)
+{
+	switch (temp) {
+		case 0:
+			return min_temp_0;
+		case 1:
+			return min_temp_1;
+		case 3:
+			return min_temp_3;
+		case 7:
+			return min_temp_7;
+		case 15:
+			return min_temp_15;
+	}
+	return min_temp_invalid;
+}
+
 static void minion_get_statline_before(char *buf, size_t bufsiz, struct cgpu_info *minioncgpu)
 {
 	struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
@@ -2583,8 +2684,8 @@ static void minion_get_statline_before(char *buf, size_t bufsiz, struct cgpu_inf
 	}
 	mutex_unlock(&(minioninfo->sta_lock));
 
-	tailsprintf(buf, bufsiz, "max%3dC Ch:%2d Co:%d",
-				 (int)max_temp, minioninfo->chips, (int)cores);
+	tailsprintf(buf, bufsiz, "max%sC Ch:%2d Co:%d",
+				 temp_str(max_temp), minioninfo->chips, (int)cores);
 }
 
 #define CHIPS_PER_STAT 8
@@ -2610,9 +2711,19 @@ static struct api_data *minion_api_stats(struct cgpu_info *minioncgpu)
 
 	max_chip = 0;
 	for (chip = 0; chip < MINION_CHIPS; chip++)
-		if (minioninfo->chip[chip])
+		if (minioninfo->chip[chip]) {
 			max_chip = chip;
 
+			snprintf(buf, sizeof(buf), "Chip %d Temperature", chip);
+			root = api_add_const(root, buf, temp_str(minioninfo->chip_status[chip].temp), false);
+			snprintf(buf, sizeof(buf), "Chip %d Cores", chip);
+			root = api_add_uint16(root, buf, &(minioninfo->chip_status[chip].cores), true);
+			snprintf(buf, sizeof(buf), "Chip %d Frequency", chip);
+			root = api_add_uint32(root, buf, &(minioninfo->chip_status[chip].freq), true);
+			snprintf(buf, sizeof(buf), "Chip %d InitFreq", chip);
+			root = api_add_int(root, buf, &(minioninfo->init_freq[chip]), true);
+		}
+
 	for (i = 0; i <= max_chip; i += CHIPS_PER_STAT) {
 		to = i + CHIPS_PER_STAT - 1;
 		if (to > max_chip)
@@ -2682,6 +2793,7 @@ static struct api_data *minion_api_stats(struct cgpu_info *minioncgpu)
 	root = api_add_int(root, "RFree Count", &(minioninfo->rfree_list->count), true);
 	root = api_add_int(root, "RNonce Count", &(minioninfo->rnonce_list->count), true);
 
+#if DO_IO_STATS
 #define sta_api(_name, _iostat) \
 	do { \
 		if ((_iostat).count) { \
@@ -2725,6 +2837,7 @@ static struct api_data *minion_api_stats(struct cgpu_info *minioncgpu)
 				    minioncgpu->drv->name, minioncgpu->device_id,
 				    total_secs, buf, data);
 	}
+#endif
 
 	root = api_add_elapsed(root, "Elapsed", &(total_secs), true);
 
diff --git a/miner.h b/miner.h
index 388c433..3189842 100644
--- a/miner.h
+++ b/miner.h
@@ -1008,6 +1008,9 @@ extern char *opt_bitmine_a1_options;
 extern char *opt_bitmain_options;
 extern bool opt_bitmain_hwerror;
 #endif
+#ifdef USE_MINION
+extern char *opt_minion_freq;
+#endif
 #ifdef USE_USBUTILS
 extern char *opt_usb_select;
 extern int opt_usbdump;