Commit 4e11ec16a3fbd5e2af7407773df82d295fcc2f0f

kanoi 2014-07-11T00:25:14

minion - led+more api setting

diff --git a/API-README b/API-README
index 62d3c47..0bbab5c 100644
--- a/API-README
+++ b/API-README
@@ -443,6 +443,9 @@ The list of requests - a (*) means it requires privileged access - and replies:
                                AVA+BTB opt=freq val=256 to 1024 - chip frequency
                                BTB opt=millivolts val=1000 to 1400 - corevoltage
                                MBA opt=reset val=0 to chipcount - reset a chip
+                               MBA opt=freq val=0-chip:100-1400 - set chip freq
+                               MBA opt=ledcount val=0-100 - chip count for led
+                               MBA opt=ledlimit val=0-200 - led off below GHs
 
  lcd           LCD            An all-in-one short status summary of the miner
                               e.g. Elapsed,GHS av,GHS 5m,GHS 5s,Temp,
diff --git a/ASIC-README b/ASIC-README
index 3756238..553f345 100644
--- a/ASIC-README
+++ b/ASIC-README
@@ -241,7 +241,10 @@ ASIC SPECIFIC COMMANDS
 --hfa-temp-target <arg> Set the hashfast target temperature (0 to disable) (default: 88)
 --klondike-options <arg> Set klondike options clock:temptarget
 --minion-chipreport <arg> Seconds to report chip 5min hashrate, range 0-100 (default: 0=disabled)
---minion-freq <arg> Set minion chip frequencies in MHz, single value or comma list, range 100-1400 (default: 1000)
+--minion-freq <arg> Set minion chip frequencies in MHz, single value or comma list, range 100-1400 (default: 1200)
+--minion-idlecount  Report when IdleCount is >0 or changes
+--minion-ledcount   Turn off led when more than this many chips below the ledlimit (default: 0)
+--minion-ledlimit   Turn off led when chips GHs are below this (default: 90)
 --minion-idlecount  Report when IdleCount is >0 or changes
 --minion-noautofreq Disable automatic frequency adjustment
 --minion-overheat   Enable directly halting any chip when the status exceeds 100C
diff --git a/README b/README
index eb60b17..9b14346 100644
--- a/README
+++ b/README
@@ -219,8 +219,10 @@ Options for both config file and command line:
 --log|-l <arg>      Interval in seconds between log output (default: 5)
 --lowmem            Minimise caching of shares for low memory applications
 --minion-chipreport <arg> Seconds to report chip 5min hashrate, range 0-100 (default: 0=disabled)
---minion-freq <arg> Set minion chip frequencies in MHz, single value or comma list, range 100-1400 (default: 1000)
+--minion-freq <arg> Set minion chip frequencies in MHz, single value or comma list, range 100-1400 (default: 1200)
 --minion-idlecount  Report when IdleCount is >0 or changes
+--minion-ledcount   Turn off led when more than this many chips below the ledlimit (default: 0)
+--minion-ledlimit   Turn off led when chips GHs are below this (default: 90)
 --minion-noautofreq Disable automatic frequency adjustment
 --minion-overheat   Enable directly halting any chip when the status exceeds 100C
 --minion-temp <arg> Set minion chip temperature threshold, single value or comma list, range 120-160 (default: 135C)
diff --git a/cgminer.c b/cgminer.c
index b0330b3..ddf0605 100644
--- a/cgminer.c
+++ b/cgminer.c
@@ -250,6 +250,8 @@ int opt_minion_chipreport;
 char *opt_minion_cores;
 char *opt_minion_freq;
 bool opt_minion_idlecount;
+int opt_minion_ledcount;
+int opt_minion_ledlimit = 90;
 bool opt_minion_noautofreq;
 bool opt_minion_overheat;
 char *opt_minion_temp;
@@ -1351,13 +1353,19 @@ static struct opt_table opt_config_table[] = {
 		     "Seconds to report chip 5min hashrate, range 0-100 (default: 0=disabled)"),
 	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)"),
+		     "Set minion chip frequencies in MHz, single value or comma list, range 100-1400 (default: 1200)"),
 	OPT_WITH_ARG("--minion-cores",
 		     opt_set_charp, NULL, &opt_minion_cores,
 		     opt_hidden),
 	OPT_WITHOUT_ARG("--minion-idlecount",
 		     opt_set_bool, &opt_minion_idlecount,
 		     "Report when IdleCount is >0 or changes"),
+	OPT_WITH_ARG("--minion-ledcount",
+		     set_int_0_to_100, opt_show_intval, &opt_minion_ledcount,
+		     "Turn off led when more than this many chips below the ledlimit (default: 0)"),
+	OPT_WITH_ARG("--minion-ledlimit",
+		     set_int_0_to_200, opt_show_intval, &opt_minion_ledlimit,
+		     "Turn off led when chips GHs are below this (default: 90)"),
 	OPT_WITHOUT_ARG("--minion-noautofreq",
 		     opt_set_bool, &opt_minion_noautofreq,
 		     "Disable automatic frequency adjustment"),
diff --git a/driver-minion.c b/driver-minion.c
index 2bb3831..2ec6a49 100644
--- a/driver-minion.c
+++ b/driver-minion.c
@@ -152,6 +152,7 @@ static struct minion_select_pins {
 // All SYS data sizes are DATA_SIZ
 #define MINION_SYS_CHIP_SIG 0x00
 #define MINION_SYS_CHIP_STA 0x01
+#define MINION_SYS_SPI_LED 0x02
 #define MINION_SYS_TEMP_CTL 0x03
 #define MINION_SYS_FREQ_CTL 0x04
 #define MINION_SYS_NONCE_LED 0x05
@@ -344,6 +345,9 @@ 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_SPI_LED_ON 0xa5a5
+#define MINION_SPI_LED_OFF 0x0
+
 #define MINION_FREQ_MIN 100
 #define MINION_FREQ_DEF 1200
 #define MINION_FREQ_MAX 1400
@@ -852,6 +856,9 @@ struct minion_info {
 	double wt_max;
 	uint64_t wt_bands[TIME_BANDS+1];
 
+	bool lednow;
+	bool setled;
+
 	bool initialised;
 };
 
@@ -916,6 +923,8 @@ static const char *addr2txt(uint8_t addr)
 			return "RChipSig";
 		case READ_ADDR(MINION_SYS_CHIP_STA):
 			return "RChipSta";
+		case WRITE_ADDR(MINION_SYS_SPI_LED):
+			return "WLed";
 		case WRITE_ADDR(MINION_SYS_MISC_CTL):
 			return "WMiscCtrl";
 		case WRITE_ADDR(MINION_SYS_RSTN_CTL):
@@ -1026,6 +1035,7 @@ static void display_ioctl(int reply, uint32_t osiz, uint8_t *obuf, uint32_t rsiz
 		case READ_ADDR(MINION_SYS_CHIP_SIG):
 		case READ_ADDR(MINION_SYS_CHIP_STA):
 			break;
+		case WRITE_ADDR(MINION_SYS_SPI_LED):
 		case WRITE_ADDR(MINION_SYS_MISC_CTL):
 		case WRITE_ADDR(MINION_SYS_RSTN_CTL):
 			if (osiz > HSIZE()) {
@@ -2288,11 +2298,15 @@ unalloc:
 static char *minion_set(struct cgpu_info *minioncgpu, char *option, char *setting, char *replybuf)
 {
 	struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
-	int chip;
+	int chip, val;
+	char *colon;
 
 	if (strcasecmp(option, "help") == 0) {
-		sprintf(replybuf, "reset: chip 0-%d",
-				  minioninfo->chips - 1);
+		sprintf(replybuf, "reset: chip 0-%d freq: 0-%d:%d-%d "
+				  "ledcount: 0-100 ledlimit: 0-200",
+				  minioninfo->chips - 1,
+				  minioninfo->chips - 1,
+				  MINION_FREQ_MIN, MINION_FREQ_MAX);
 		return replybuf;
 	}
 
@@ -2319,6 +2333,88 @@ static char *minion_set(struct cgpu_info *minioncgpu, char *option, char *settin
 		return NULL;
 	}
 
+	// This must do a reset also - but changes the freq
+	if (strcasecmp(option, "freq") == 0) {
+		if (!setting || !*setting) {
+			sprintf(replybuf, "missing chip:freq");
+			return replybuf;
+		}
+
+		colon = strchr(setting, ':');
+		if (!colon) {
+			sprintf(replybuf, "missing ':' for chip:freq");
+			return replybuf;
+		}
+
+		*(colon++) = '\0';
+		if (!*colon) {
+			sprintf(replybuf, "missing freq in chip:freq");
+			return replybuf;
+		}
+
+		chip = atoi(setting);
+		if (chip < 0 || chip >= minioninfo->chips) {
+			sprintf(replybuf, "invalid freq: chip '%s' valid range 0-%d",
+					  setting,
+					  minioninfo->chips);
+			return replybuf;
+		}
+
+		if (!minioninfo->has_chip[chip]) {
+			sprintf(replybuf, "unable to modify chip %d - chip disabled",
+					  chip);
+			return replybuf;
+		}
+
+		val = atoi(colon);
+		if (val < MINION_FREQ_MIN || val > MINION_FREQ_MAX) {
+			sprintf(replybuf, "invalid freq: '%s' valid range %d-%d",
+					  setting,
+					  MINION_FREQ_MIN, MINION_FREQ_MAX);
+			return replybuf;
+		}
+
+		minioninfo->init_freq[chip] = val - (val % MINION_FREQ_FACTOR);
+		minioninfo->flag_reset[chip] = true;
+		minioninfo->do_reset[chip] = 0.0;
+
+		return NULL;
+	}
+
+	if (strcasecmp(option, "ledcount") == 0) {
+		if (!setting || !*setting) {
+			sprintf(replybuf, "missing ledcount value");
+			return replybuf;
+		}
+
+		val = atoi(setting);
+		if (val < 0 || val > 100) {
+			sprintf(replybuf, "invalid ledcount: '%s' valid range 0-100",
+					  setting);
+			return replybuf;
+		}
+
+		opt_minion_ledcount = val;
+		return NULL;
+	}
+
+	if (strcasecmp(option, "ledlimit") == 0) {
+		if (!setting || !*setting) {
+			sprintf(replybuf, "missing ledlimit value");
+			return replybuf;
+		}
+
+		val = atoi(setting);
+		if (val < 0 || val > 200) {
+			sprintf(replybuf, "invalid ledlimit: GHs '%s' valid range 0-200",
+					  setting);
+			return replybuf;
+		}
+
+		opt_minion_ledlimit = val;
+		return NULL;
+	}
+
 	sprintf(replybuf, "Unknown option: %s", option);
 	return replybuf;
 }
@@ -2385,6 +2481,7 @@ static void *minion_spi_write(void *userdata)
 				// TODO: case MINION_SYS_TEMP_CTL:
 				// TODO: case MINION_SYS_FREQ_CTL:
 				case READ_ADDR(MINION_SYS_CHIP_STA):
+				case WRITE_ADDR(MINION_SYS_SPI_LED):
 				case WRITE_ADDR(MINION_SYS_RSTN_CTL):
 				case WRITE_ADDR(MINION_SYS_INT_CLR):
 				case READ_ADDR(MINION_SYS_IDLE_CNT):
@@ -2564,6 +2661,7 @@ static void *minion_spi_write(void *userdata)
 						}
 						break;
 					case WRITE_ADDR(MINION_SYS_INT_CLR):
+					case WRITE_ADDR(MINION_SYS_SPI_LED):
 						break;
 					default:
 						break;
@@ -3508,6 +3606,37 @@ static void sys_chip_sta(struct cgpu_info *minioncgpu, int chip)
 				k_add_head(minioninfo->task_list, item);
 				K_WUNLOCK(minioninfo->task_list);
 			}
+
+			if (minioninfo->lednow != minioninfo->setled) {
+				uint32_t led;
+
+				minioninfo->lednow = minioninfo->setled;
+				if (minioninfo->lednow)
+					led = MINION_SPI_LED_ON;
+				else
+					led = MINION_SPI_LED_OFF;
+
+				K_WLOCK(minioninfo->tfree_list);
+				item = k_unlink_head(minioninfo->tfree_list);
+				DATA_TASK(item)->tid = ++(minioninfo->next_tid);
+				K_WUNLOCK(minioninfo->tfree_list);
+
+				DATA_TASK(item)->chip = 0;
+				DATA_TASK(item)->write = true;
+				DATA_TASK(item)->address = MINION_SYS_SPI_LED;
+				DATA_TASK(item)->task_id = 0;
+				DATA_TASK(item)->wsiz = MINION_SYS_SIZ;
+				DATA_TASK(item)->rsiz = 0;
+				DATA_TASK(item)->wbuf[0] = led & 0xff;
+				DATA_TASK(item)->wbuf[1] = (led >> 8) & 0xff;
+				DATA_TASK(item)->wbuf[2] = (led >> 16) & 0xff;
+				DATA_TASK(item)->wbuf[3] = (led >> 24) & 0xff;
+				DATA_TASK(item)->urgent = false;
+
+				K_WLOCK(minioninfo->task_list);
+				k_add_head(minioninfo->task_list, item);
+				K_WUNLOCK(minioninfo->task_list);
+			}
 		}
 	}
 }
@@ -3974,8 +4103,7 @@ static void chip_report(struct cgpu_info *minioncgpu)
 	size_t len;
 	double elapsed, ghs, expect, howlong;
 	K_ITEM *pitem;
-	int msdiff;
-	int chip;
+	int msdiff, chip, low_chips;
 	int res_err_count;
 
 	cgtime(&now);
@@ -3985,39 +4113,47 @@ static void chip_report(struct cgpu_info *minioncgpu)
 		return;
 	}
 
+	// Always run the calculations to check chip GHs for the LED
+	low_chips = 0;
+	buf[0] = '\0';
+	res_err_msg[0] = '\0';
+	res_err_msg[1] = '\0';
+	K_RLOCK(minioninfo->hfree_list);
+	for (chip = 0; chip < (int)MINION_CHIPS; chip++) {
+		if (minioninfo->has_chip[chip]) {
+			len = strlen(buf);
+			if (minioninfo->hchip_list[chip]->count < 2)
+				ghs = 0.0;
+			else {
+				ghs = 0xffffffffull * (minioninfo->hchip_list[chip]->count - 1);
+				ghs /= 1000000000.0;
+				ghs /= tdiff(&now, &(DATA_HIST(minioninfo->hchip_list[chip]->tail)->when));
+			}
+			if (ghs < opt_minion_ledlimit)
+				low_chips++;
+			res_err_count = minioninfo->res_err_count[chip];
+			minioninfo->res_err_count[chip] = 0;
+			if (res_err_count > 100)
+				res_err_msg[0] = '!';
+			else if (res_err_count > 50)
+				res_err_msg[0] = '*';
+			else if (res_err_count > 0)
+				res_err_msg[0] = '\'';
+			else
+				res_err_msg[0] = '\0';
+			snprintf(buf + len, sizeof(buf) - len,
+				 " %d=%s%.2f", chip, res_err_msg, ghs);
+			minioninfo->history_ghs[chip] = ghs;
+		}
+	}
+	K_RUNLOCK(minioninfo->hfree_list);
+
+	minioninfo->setled = !(low_chips > opt_minion_ledcount);
+
+	// But only display it if required
 	if (opt_minion_chipreport > 0) {
 		msdiff = ms_tdiff(&now, &(minioninfo->chip_rpt));
 		if (msdiff >= (opt_minion_chipreport * 1000)) {
-			buf[0] = '\0';
-			res_err_msg[0] = '\0';
-			res_err_msg[1] = '\0';
-			K_RLOCK(minioninfo->hfree_list);
-			for (chip = 0; chip < (int)MINION_CHIPS; chip++) {
-				if (minioninfo->has_chip[chip]) {
-					len = strlen(buf);
-					if (minioninfo->hchip_list[chip]->count < 2)
-						ghs = 0.0;
-					else {
-						ghs = 0xffffffffull * (minioninfo->hchip_list[chip]->count - 1);
-						ghs /= 1000000000.0;
-						ghs /= tdiff(&now, &(DATA_HIST(minioninfo->hchip_list[chip]->tail)->when));
-					}
-					res_err_count = minioninfo->res_err_count[chip];
-					minioninfo->res_err_count[chip] = 0;
-					if (res_err_count > 100)
-						res_err_msg[0] = '!';
-					else if (res_err_count > 50)
-						res_err_msg[0] = '*';
-					else if (res_err_count > 0)
-						res_err_msg[0] = '\'';
-					else
-						res_err_msg[0] = '\0';
-					snprintf(buf + len, sizeof(buf) - len,
-						 " %d=%s%.2f", chip, res_err_msg, ghs);
-					minioninfo->history_ghs[chip] = ghs;
-				}
-			}
-			K_RUNLOCK(minioninfo->hfree_list);
 			memcpy(&(minioninfo->chip_chk), &now, sizeof(now));
 			applogsiz(LOG_WARNING, 512,
 				  "%s%d: Chip GHs%s",
diff --git a/miner.h b/miner.h
index 74c8345..a26f35a 100644
--- a/miner.h
+++ b/miner.h
@@ -1024,6 +1024,8 @@ extern int opt_minion_chipreport;
 extern char *opt_minion_cores;
 extern char *opt_minion_freq;
 extern bool opt_minion_idlecount;
+extern int opt_minion_ledcount;
+extern int opt_minion_ledlimit;
 extern bool opt_minion_noautofreq;
 extern bool opt_minion_overheat;
 extern char *opt_minion_temp;