Browse Source

Merge branch 'icarus_proc' into bfgminer

Luke Dashjr 11 years ago
parent
commit
39ba6f9b3d
3 changed files with 120 additions and 64 deletions
  1. 2 2
      deviceapi.c
  2. 1 1
      deviceapi.h
  3. 117 61
      driver-icarus.c

+ 2 - 2
deviceapi.c

@@ -1088,9 +1088,9 @@ void close_device_fd(struct thr_info * const thr)
 }
 
 
-struct cgpu_info *device_proc_by_id(struct cgpu_info * const dev, const int procid)
+struct cgpu_info *device_proc_by_id(const struct cgpu_info * const dev, const int procid)
 {
-	struct cgpu_info *proc = dev;
+	struct cgpu_info *proc = (void*)dev;
 	for (int i = 0; i < procid; ++i)
 	{
 		proc = proc->next_proc;

+ 1 - 1
deviceapi.h

@@ -114,6 +114,6 @@ extern void close_device_fd(struct thr_info *);
 	for (struct cgpu_info *procvar = dev; procvar; procvar = procvar->next_proc)
 #define for_each_logical_proc(procvar, dev)  \
 	for (struct cgpu_info *procvar = dev; procvar && procvar->device == (dev); procvar = procvar->next_proc)
-extern struct cgpu_info *device_proc_by_id(struct cgpu_info *dev, int procid);
+extern struct cgpu_info *device_proc_by_id(const struct cgpu_info *dev, int procid);
 
 #endif

+ 117 - 61
driver-icarus.c

@@ -148,6 +148,7 @@ static const char *MODE_UNKNOWN_STR = "unknown";
 
 BFG_REGISTER_DRIVER(icarus_drv)
 extern const struct bfg_set_device_definition icarus_set_device_funcs[];
+extern const struct bfg_set_device_definition icarus_set_device_funcs_live[];
 
 extern void convert_icarus_to_cairnsmore(struct cgpu_info *);
 
@@ -312,9 +313,8 @@ static const char *timing_mode_str(enum timing_mode timing_mode)
 }
 
 static
-const char *icarus_set_timing(struct cgpu_info * const proc, const char * const optname, const char * const buf, char * const replybuf, enum bfg_set_device_replytype * const out_success)
+const char *_icarus_set_timing(struct ICARUS_INFO * const info, const char * const repr, const struct device_drv * const drv, const char * const buf)
 {
-	struct ICARUS_INFO * const info = proc->device_data;
 	double Hs;
 	char *eq;
 
@@ -387,7 +387,7 @@ const char *icarus_set_timing(struct cgpu_info * const proc, const char * const
 		int def_read_count = ICARUS_READ_COUNT_TIMING;
 
 		if (info->timing_mode == MODE_DEFAULT) {
-			if (proc->drv == &icarus_drv) {
+			if (drv == &icarus_drv) {
 				info->do_default_detection = 0x10;
 			} else {
 				def_read_count = (int)(info->fullnonce * TIME_FACTOR) - 1;
@@ -404,13 +404,20 @@ const char *icarus_set_timing(struct cgpu_info * const proc, const char * const
 	info->min_data_count = MIN_DATA_COUNT;
 
 	applog(LOG_DEBUG, "%"PRIpreprv": Init: mode=%s read_count=%d limit=%dms Hs=%e",
-		proc->proc_repr,
+		repr,
 		timing_mode_str(info->timing_mode),
 		info->read_count, info->read_count_limit, info->Hs);
 	
 	return NULL;
 }
 
+static
+const char *icarus_set_timing(struct cgpu_info * const proc, const char * const optname, const char * const buf, char * const replybuf, enum bfg_set_device_replytype * const out_success)
+{
+	struct ICARUS_INFO * const info = proc->device_data;
+	return _icarus_set_timing(info, proc->proc_repr, proc->drv, buf);
+}
+
 static uint32_t mask(int work_division)
 {
 	return 0xffffffff / work_division;
@@ -437,6 +444,56 @@ int icarus_excess_nonce_size(int fd, struct ICARUS_INFO *info)
 	return bytes_read;
 }
 
+int icarus_probe_work_division(const int fd, const char * const repr, struct ICARUS_INFO * const info)
+{
+	struct timeval tv_finish;
+	
+	// For reading the nonce from Icarus
+	unsigned char res_bin[info->read_size];
+	// For storing the the 32-bit nonce
+	uint32_t res;
+	int work_division = 0;
+	
+	applog(LOG_DEBUG, "%s: Work division not specified - autodetecting", repr);
+	
+	// Special packet to probe work_division
+	unsigned char pkt[64] =
+		"\x2e\x4c\x8f\x91\xfd\x59\x5d\x2d\x7e\xa2\x0a\xaa\xcb\x64\xa2\xa0"
+		"\x43\x82\x86\x02\x77\xcf\x26\xb6\xa1\xee\x04\xc5\x6a\x5b\x50\x4a"
+		"BFGMiner Probe\0\0"
+		"BFG\0\x64\x61\x01\x1a\xc9\x06\xa9\x51\xfb\x9b\x3c\x73";
+	
+	icarus_write(fd, pkt, sizeof(pkt));
+	memset(res_bin, 0, sizeof(res_bin));
+	if (ICA_GETS_OK == icarus_gets(res_bin, fd, &tv_finish, NULL, info->read_count, info->read_size))
+	{
+		memcpy(&res, res_bin, sizeof(res));
+		res = icarus_nonce32toh(info, res);
+	}
+	else
+		res = 0;
+	
+	switch (res) {
+		case 0x04C0FDB4:
+			work_division = 1;
+			break;
+		case 0x82540E46:
+			work_division = 2;
+			break;
+		case 0x417C0F36:
+			work_division = 4;
+			break;
+		case 0x60C994D5:
+			work_division = 8;
+			break;
+		default:
+			applog(LOG_ERR, "%s: Work division autodetection failed (assuming 2): got %08x", repr, res);
+			work_division = 2;
+	}
+	applog(LOG_DEBUG, "%s: Work division autodetection got %08x (=%d)", repr, res, work_division);
+	return work_division;
+}
+
 bool icarus_detect_custom(const char *devpath, struct device_drv *api, struct ICARUS_INFO *info)
 {
 	struct timeval tv_start, tv_finish;
@@ -543,6 +600,20 @@ bool icarus_detect_custom(const char *devpath, struct device_drv *api, struct IC
 	if (serial_claim_v(devpath, api))
 		return false;
 
+	_icarus_set_timing(info, api->dname, api, "");
+	if (!info->fpga_count)
+	{
+		if (!info->work_division)
+		{
+			fd = icarus_open2(devpath, baud, true);
+			info->work_division = icarus_probe_work_division(fd, api->dname, info);
+			icarus_close(fd);
+		}
+		info->fpga_count = info->work_division;
+	}
+	// Lock fpga_count from set_work_division
+	info->user_set |= IUS_FPGA_COUNT;
+	
 	/* We have a real Icarus! */
 	struct cgpu_info *icarus;
 	icarus = calloc(1, sizeof(struct cgpu_info));
@@ -550,7 +621,8 @@ bool icarus_detect_custom(const char *devpath, struct device_drv *api, struct IC
 	icarus->device_path = strdup(devpath);
 	icarus->device_fd = -1;
 	icarus->threads = 1;
-	icarus->set_device_funcs = icarus_set_device_funcs;
+	icarus->procs = info->fpga_count;
+	icarus->set_device_funcs = icarus_set_device_funcs_live;
 	add_cgpu(icarus);
 
 	applog(LOG_INFO, "Found %"PRIpreprv" at %s",
@@ -564,7 +636,6 @@ bool icarus_detect_custom(const char *devpath, struct device_drv *api, struct IC
 	icarus->device_data = info;
 
 	timersub(&tv_finish, &tv_start, &(info->golden_tv));
-	icarus_set_timing(icarus, NULL, "", NULL, NULL);
 
 	return true;
 }
@@ -639,55 +710,7 @@ bool icarus_init(struct thr_info *thr)
 	BFGINIT(state->ob_bin, calloc(1, info->ob_size));
 	
 	if (!info->work_division)
-	{
-		struct timeval tv_finish;
-		
-		// For reading the nonce from Icarus
-		unsigned char res_bin[info->read_size];
-		// For storing the the 32-bit nonce
-		uint32_t res;
-		
-		applog(LOG_DEBUG, "%"PRIpreprv": Work division not specified - autodetecting", icarus->proc_repr);
-		
-		// Special packet to probe work_division
-		unsigned char pkt[64] =
-			"\x2e\x4c\x8f\x91\xfd\x59\x5d\x2d\x7e\xa2\x0a\xaa\xcb\x64\xa2\xa0"
-			"\x43\x82\x86\x02\x77\xcf\x26\xb6\xa1\xee\x04\xc5\x6a\x5b\x50\x4a"
-			"BFGMiner Probe\0\0"
-			"BFG\0\x64\x61\x01\x1a\xc9\x06\xa9\x51\xfb\x9b\x3c\x73";
-		
-		icarus_write(fd, pkt, sizeof(pkt));
-		memset(res_bin, 0, sizeof(res_bin));
-		if (ICA_GETS_OK == icarus_gets(res_bin, fd, &tv_finish, NULL, info->read_count, info->read_size))
-		{
-			memcpy(&res, res_bin, sizeof(res));
-			res = icarus_nonce32toh(info, res);
-		}
-		else
-			res = 0;
-		
-		switch (res) {
-			case 0x04C0FDB4:
-				info->work_division = 1;
-				break;
-			case 0x82540E46:
-				info->work_division = 2;
-				break;
-			case 0x417C0F36:
-				info->work_division = 4;
-				break;
-			case 0x60C994D5:
-				info->work_division = 8;
-				break;
-			default:
-				applog(LOG_ERR, "%"PRIpreprv": Work division autodetection failed (assuming 2): got %08x", icarus->proc_repr, res);
-				info->work_division = 2;
-		}
-		applog(LOG_DEBUG, "%"PRIpreprv": Work division autodetection got %08x (=%d)", icarus->proc_repr, res, info->work_division);
-	}
-	
-	if (!info->fpga_count)
-		info->fpga_count = info->work_division;
+		info->work_division = icarus_probe_work_division(fd, icarus->proc_repr, info);
 	
 	if (!is_power_of_two(info->work_division))
 		info->work_division = upper_power_of_two_u32(info->work_division);
@@ -696,6 +719,18 @@ bool icarus_init(struct thr_info *thr)
 	return true;
 }
 
+static
+struct thr_info *icarus_thread_for_nonce(const struct cgpu_info * const icarus, const uint32_t nonce)
+{
+	struct ICARUS_INFO * const info = icarus->device_data;
+	unsigned proc_id = 0;
+	for (int i = info->work_division, j = 0; i /= 2; ++j)
+		if (nonce & (1 << (31 - j)))
+			proc_id |= (1 << j);
+	const struct cgpu_info * const proc = device_proc_by_id(icarus, proc_id) ?: icarus;
+	return proc->thr[0];
+}
+
 static bool icarus_reopen(struct cgpu_info *icarus, struct icarus_state *state, int *fdp)
 {
 	struct ICARUS_INFO *info = icarus->device_data;
@@ -819,7 +854,7 @@ void handle_identify(struct thr_info * const thr, int ret, const bool was_first_
 			{
 				memcpy(&nonce, nonce_bin, sizeof(nonce));
 				nonce = icarus_nonce32toh(info, nonce);
-				submit_nonce(thr, state->last_work, nonce);
+				submit_nonce(icarus_thread_for_nonce(icarus, nonce), state->last_work, nonce);
 			}
 		}
 	}
@@ -964,7 +999,7 @@ keepwaiting:
 			if (nonce_work == state->last2_work)
 			{
 				// nonce was for the last job; submit and keep processing the current one
-				submit_nonce(thr, nonce_work, nonce);
+				submit_nonce(icarus_thread_for_nonce(icarus, nonce), nonce_work, nonce);
 				goto keepwaiting;
 			}
 			if (info->continue_search)
@@ -972,7 +1007,7 @@ keepwaiting:
 				read_count = info->read_count - ((timer_elapsed_us(&state->tv_workstart, NULL) / (1000000 / TIME_FACTOR)) + 1);
 				if (read_count)
 				{
-					submit_nonce(thr, nonce_work, nonce);
+					submit_nonce(icarus_thread_for_nonce(icarus, nonce), nonce_work, nonce);
 					goto keepwaiting;
 				}
 			}
@@ -1026,7 +1061,7 @@ keepwaiting:
 
 	if (ret == ICA_GETS_OK && !was_hw_error)
 	{
-		submit_nonce(thr, nonce_work, nonce);
+		submit_nonce(icarus_thread_for_nonce(icarus, nonce), nonce_work, nonce);
 		
 		icarus_transition_work(state, work);
 		
@@ -1047,7 +1082,8 @@ keepwaiting:
 		
 		if (ret == ICA_GETS_OK)
 		{
-			inc_hw_errors(thr, state->last_work, nonce);
+			// We can't be sure which processor got the error, but at least this is a decent guess
+			inc_hw_errors(icarus_thread_for_nonce(icarus, nonce), state->last_work, nonce);
 			estimate_hashes -= ICARUS_READ_TIME(info->baud, info->read_size);
 		}
 		
@@ -1217,6 +1253,18 @@ out:
 	if (unlikely(state->identify))
 		handle_identify(thr, ret, was_first_run);
 	
+	int hash_count_per_proc = hash_count / icarus->procs;
+	if (hash_count_per_proc > 0)
+	{
+		for_each_managed_proc(proc, icarus)
+		{
+			struct thr_info * const proc_thr = proc->thr[0];
+			
+			hashes_done2(proc_thr, hash_count_per_proc, NULL);
+			hash_count -= hash_count_per_proc;
+		}
+	}
+	
 	return hash_count;
 }
 
@@ -1298,7 +1346,7 @@ const char *icarus_set_fpga_count(struct cgpu_info * const proc, const char * co
 {
 	struct ICARUS_INFO * const info = proc->device_data;
 	const int fpga_count = atoi(newvalue);
-	if (fpga_count < 1 || fpga_count > info->work_division)
+	if (fpga_count < 1 || (fpga_count > info->work_division && info->work_division))
 		return "Invalid fpga_count: must be >0 and <=work_division";
 	info->fpga_count = fpga_count;
 	return NULL;
@@ -1342,6 +1390,14 @@ const struct bfg_set_device_definition icarus_set_device_funcs[] = {
 	{NULL},
 };
 
+const struct bfg_set_device_definition icarus_set_device_funcs_live[] = {
+	{"baud"         , icarus_set_baud         , "serial baud rate"},
+	{"work_division", icarus_set_work_division, "number of pieces work is split into"},
+	{"reopen"       , icarus_set_reopen       , "how often to reopen device: never, timeout, cycle, (or now for a one-shot reopen)"},
+	{"timing"       , icarus_set_timing       , "timing of device; see README.FPGA"},
+	{NULL},
+};
+
 struct device_drv icarus_drv = {
 	.dname = "icarus",
 	.name = "ICA",