Browse Source

avalonmm: Add clock setting and try to autodetect it if not provided

Luke Dashjr 11 years ago
parent
commit
da787448e4
1 changed files with 76 additions and 4 deletions
  1. 76 4
      driver-avalonmm.c

+ 76 - 4
driver-avalonmm.c

@@ -36,6 +36,7 @@
 #define AVALONMM_NONCE_OFFSET  0x180
 
 BFG_REGISTER_DRIVER(avalonmm_drv)
+static const struct bfg_set_device_definition avalonmm_set_device_funcs[];
 
 #define AVALONMM_PKT_DATA_SIZE  0x20
 #define AVALONMM_PKT_SIZE  (AVALONMM_PKT_DATA_SIZE + 7)
@@ -187,6 +188,7 @@ bool avalonmm_detect_one(const char * const devpath)
 			.drv = &avalonmm_drv,
 			.device_path = prev_cgpu ? prev_cgpu->device_path : strdup(devpath),
 			.device_data = (void*)(intptr_t)moduleno,
+			.set_device_funcs = avalonmm_set_device_funcs,
 			.deven = DEV_ENABLED,
 			.procs = 1,
 			.threads = prev_cgpu ? 0 : 1,
@@ -218,19 +220,27 @@ struct avalonmm_chain_state {
 	uint32_t xnonce1;
 	struct avalonmm_job *jobs[AVALONMM_CACHED_JOBS];
 	uint32_t next_jobid;
+	
+	uint32_t clock_desired;
 };
 
 struct avalonmm_module_state {
 	unsigned module_id;
 	uint16_t temp[2];
+	uint32_t clock_actual;
 };
 
+static struct cgpu_info *avalonmm_dev_for_module_id(struct cgpu_info *, uint32_t);
+static bool avalonmm_poll_once(struct cgpu_info *, int64_t *);
+
 static
 bool avalonmm_init(struct thr_info * const master_thr)
 {
 	struct cgpu_info * const master_dev = master_thr->cgpu, *dev = NULL;
 	const char * const devpath = master_dev->device_path;
 	const int fd = serial_open(devpath, 115200, 1, true);
+	uint8_t buf[AVALONMM_PKT_DATA_SIZE] = {0};
+	int64_t module_id;
 	
 	master_dev->device_fd = fd;
 	if (unlikely(fd == -1))
@@ -267,11 +277,45 @@ bool avalonmm_init(struct thr_info * const master_thr)
 		thr->cgpu_data = module;
 	}
 	
+	dev = NULL;
 	for_each_managed_proc(proc, master_dev)
 	{
+		cgpu_set_defaults(proc);
 		proc->status = LIFE_INIT2;
 	}
 	
+	
+	if (!chain->clock_desired)
+	{
+		// Get a reasonable default frequency
+		dev = master_dev;
+		struct thr_info * const thr = dev->thr[0];
+		struct avalonmm_module_state * const module = thr->cgpu_data;
+		
+resend:
+		pk_u32be(buf, AVALONMM_PKT_DATA_SIZE - 4, module->module_id);
+		avalonmm_write_cmd(fd, AMC_POLL, buf, AVALONMM_PKT_DATA_SIZE);
+		
+		while (avalonmm_poll_once(master_dev, &module_id))
+		{
+			if (module_id != module->module_id)
+				continue;
+			
+			if (module->clock_actual)
+			{
+				chain->clock_desired = module->clock_actual;
+				break;
+			}
+			else
+				goto resend;
+		}
+	}
+	
+	if (likely(chain->clock_desired))
+		applog(LOG_DEBUG, "%s: Frequency is initialised with %d MHz", master_dev->dev_repr, chain->clock_desired);
+	else
+		applogr(false, LOG_ERR, "%s: No frequency detected, please use --set %s@%s:clock=MHZ", master_dev->dev_repr, master_dev->drv->dname, devpath);
+	
 	return true;
 }
 
@@ -354,7 +398,7 @@ bool avalonmm_send_swork(const int fd, struct avalonmm_chain_state * const chain
 	pk_u32be(buf, 0, 80);  // fan speed %
 	uint16_t voltcfg = ((uint16_t)bitflip8((0x78 - /*deci-milli-volts*/6625 / 125) << 1 | 1)) << 8;
 	pk_u32be(buf, 4, voltcfg);
-	pk_u32be(buf, 8, 450/*freq*/);
+	pk_u32be(buf, 8, chain->clock_desired);
 	memcpy(&buf[0xc], mm_xnonce2_start, 4);
 	pk_u32be(buf, 0x10, xnonce2_range);
 	if (!avalonmm_write_cmd(fd, AMC_START, buf, 0x14))
@@ -420,13 +464,15 @@ struct cgpu_info *avalonmm_dev_for_module_id(struct cgpu_info * const master_dev
 }
 
 static
-bool avalonmm_poll_once(struct cgpu_info * const master_dev)
+bool avalonmm_poll_once(struct cgpu_info * const master_dev, int64_t *out_module_id)
 {
 	struct avalonmm_chain_state * const chain = master_dev->device_data;
 	const int fd = master_dev->device_fd;
 	uint8_t buf[AVALONMM_PKT_DATA_SIZE];
 	enum avalonmm_reply reply;
 	
+	*out_module_id = -1;
+	
 	if (avalonmm_read(fd, LOG_ERR, &reply, buf, sizeof(buf)) < 0)
 		return false;
 	
@@ -445,6 +491,8 @@ bool avalonmm_poll_once(struct cgpu_info * const master_dev)
 				break;
 			}
 			
+			*out_module_id = module_id;
+			
 			struct thr_info * const thr = dev->thr[0];
 			struct avalonmm_module_state * const module = thr->cgpu_data;
 			
@@ -453,7 +501,9 @@ bool avalonmm_poll_once(struct cgpu_info * const master_dev)
 #if 0
 			module->fan [0] = upk_u16be(buf,    4);
 			module->fan [1] = upk_u16be(buf,    6);
-			module->freq    = upk_u32be(buf,    8);
+#endif
+			module->clock_actual = upk_u32be(buf, 8);
+#if 0
 			module->voltage = upk_u32be(buf, 0x0c);
 #endif
 			
@@ -478,6 +528,8 @@ bool avalonmm_poll_once(struct cgpu_info * const master_dev)
 				break;
 			}
 			
+			*out_module_id = module_id;
+			
 			struct thr_info * const thr = dev->thr[0];
 			
 			bool invalid_jobid = false;
@@ -510,9 +562,10 @@ bool avalonmm_poll_once(struct cgpu_info * const master_dev)
 static
 void avalonmm_poll(struct cgpu_info * const master_dev, int n)
 {
+	int64_t dummy;
 	while (n > 0)
 	{
-		if (avalonmm_poll_once(master_dev))
+		if (avalonmm_poll_once(master_dev, &dummy))
 			--n;
 	}
 }
@@ -558,6 +611,25 @@ void avalonmm_minerloop(struct thr_info * const master_thr)
 	}
 }
 
+static
+const char *avalonmm_set_clock(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const out_success)
+{
+	struct avalonmm_chain_state * const chain = proc->device_data;
+	
+	const int nv = atoi(newvalue);
+	if (nv < 0)
+		return "Invalid clock";
+	
+	chain->clock_desired = nv;
+	
+	return NULL;
+}
+
+static const struct bfg_set_device_definition avalonmm_set_device_funcs[] = {
+	{"clock", avalonmm_set_clock, "clock frequency"},
+	{NULL},
+};
+
 struct device_drv avalonmm_drv = {
 	.dname = "avalonmm",
 	.name = "AVM",