Browse Source

add fan/temp control

Xiangfu 13 years ago
parent
commit
61c6eb06b9
2 changed files with 87 additions and 60 deletions
  1. 82 59
      driver-avalon.c
  2. 5 1
      driver-avalon.h

+ 82 - 59
driver-avalon.c

@@ -38,38 +38,19 @@ static int option_offset = -1;
 
 
 struct avalon_info **avalon_info;
 struct avalon_info **avalon_info;
 struct device_api avalon_api;
 struct device_api avalon_api;
-static int avalon_init_task(struct thr_info *thr, struct avalon_task *at,
+static int avalon_init_task(struct avalon_task *at,
 			    uint8_t reset, uint8_t ff, uint8_t fan,
 			    uint8_t reset, uint8_t ff, uint8_t fan,
-			    uint8_t timeout_p, uint8_t asic_num_p,
-			    uint8_t miner_num_p, uint8_t nonce_elf_p)
+			    uint8_t timeout, uint8_t asic_num,
+			    uint8_t miner_num, uint8_t nonce_elf)
 {
 {
 	static bool first = true;
 	static bool first = true;
 
 
-	uint8_t timeout;
-	uint8_t asic_num;
-	uint8_t miner_num;
-
-	struct cgpu_info *avalon;
-	struct avalon_info *info;
-
 	if (unlikely(!at))
 	if (unlikely(!at))
 		return -1;
 		return -1;
 
 
-	if (unlikely(!thr && (timeout_p <= 0 || asic_num_p <= 0 || miner_num_p <= 0)))
+	if (unlikely(timeout <= 0 || asic_num <= 0 || miner_num <= 0))
 		return -1;
 		return -1;
 
 
-	timeout = timeout_p;
-	miner_num = miner_num_p;
-	asic_num = asic_num_p;
-
-	if (likely(thr)) {
-		avalon = thr->cgpu;
-		info = avalon_info[avalon->device_id];
-		timeout = info->timeout;
-		miner_num = info->miner_count;
-		asic_num = info->asic_count;
-	}
-
 	memset(at, 0, sizeof(struct avalon_task));
 	memset(at, 0, sizeof(struct avalon_task));
 
 
 	if (unlikely(reset)) {
 	if (unlikely(reset)) {
@@ -93,7 +74,7 @@ static int avalon_init_task(struct thr_info *thr, struct avalon_task *at,
 	at->asic_num = asic_num;
 	at->asic_num = asic_num;
 	at->miner_num = miner_num;
 	at->miner_num = miner_num;
 
 
-	at->nonce_elf = nonce_elf_p;
+	at->nonce_elf = nonce_elf;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -291,18 +272,19 @@ static int avalon_decode_nonce(struct thr_info *thr, struct work **work,
 	return i;
 	return i;
 }
 }
 
 
-static int avalon_reset(int fd, uint8_t timeout_p, uint8_t asic_num_p,
-			uint8_t miner_num_p, struct avalon_result *ar)
+static int avalon_reset(int fd, struct avalon_result *ar)
 {
 {
 	struct avalon_task at;
 	struct avalon_task at;
 	uint8_t *buf;
 	uint8_t *buf;
 	int ret, i = 0;
 	int ret, i = 0;
 	struct timespec p;
 	struct timespec p;
 
 
-	avalon_init_task(NULL,
-			 &at, 1, 0,
+	avalon_init_task(&at, 1, 0,
 			 AVALON_DEFAULT_FAN_PWM,
 			 AVALON_DEFAULT_FAN_PWM,
-			 timeout_p, asic_num_p, miner_num_p, 1);
+			 AVALON_DEFAULT_TIMEOUT,
+			 AVALON_DEFAULT_ASIC_NUM,
+			 AVALON_DEFAULT_MINER_NUM,
+			 0);
 	ret = avalon_send_task(fd, &at, NULL);
 	ret = avalon_send_task(fd, &at, NULL);
 	if (ret == AVA_SEND_ERROR)
 	if (ret == AVA_SEND_ERROR)
 		return 1;
 		return 1;
@@ -469,7 +451,7 @@ static bool avalon_detect_one(const char *devpath)
 		return false;
 		return false;
 	}
 	}
 
 
-	ret = avalon_reset(fd, timeout, asic_count, miner_count, &ar);
+	ret = avalon_reset(fd, &ar);
 	avalon_close(fd);
 	avalon_close(fd);
 
 
 	if (ret) {
 	if (ret) {
@@ -504,10 +486,19 @@ static bool avalon_detect_one(const char *devpath)
 	info->miner_count = miner_count;
 	info->miner_count = miner_count;
 	info->asic_count = asic_count;
 	info->asic_count = asic_count;
 	info->timeout = timeout;
 	info->timeout = timeout;
-
 	info->read_count = ((float)info->timeout * AVALON_HASH_TIME_FACTOR *
 	info->read_count = ((float)info->timeout * AVALON_HASH_TIME_FACTOR *
 			    AVALON_TIME_FACTOR) / (float)info->miner_count;
 			    AVALON_TIME_FACTOR) / (float)info->miner_count;
 
 
+	info->fan_pwm = AVALON_DEFAULT_FAN_PWM;
+	info->temp_max = 0;
+	info->temp_history_count = 4 / (int)(info->timeout * AVALON_HASH_TIME_FACTOR) + 1;
+	if (info->temp_history_count <= 0)
+		info->temp_history_count = 1;
+
+	info->temp_history_index = 0;
+	info->temp_sum = 0;
+	info->temp_old = 0;
+
 	return true;
 	return true;
 }
 }
 
 
@@ -523,8 +514,6 @@ static bool avalon_prepare(struct thr_info *thr)
 	struct timeval now;
 	struct timeval now;
 	int fd, ret;
 	int fd, ret;
 
 
-	struct avalon_info *info = avalon_info[avalon->device_id];
-
 	avalon->device_fd = -1;
 	avalon->device_fd = -1;
 	fd = avalon_open(avalon->device_path,
 	fd = avalon_open(avalon->device_path,
 			     avalon_info[avalon->device_id]->baud);
 			     avalon_info[avalon->device_id]->baud);
@@ -533,8 +522,7 @@ static bool avalon_prepare(struct thr_info *thr)
 		       avalon->device_path);
 		       avalon->device_path);
 		return false;
 		return false;
 	}
 	}
-	ret = avalon_reset(fd, info->timeout, info->asic_count,
-			   info->miner_count, &ar);
+	ret = avalon_reset(fd, &ar);
 	if (ret)
 	if (ret)
 		return false;
 		return false;
 	avalon->device_fd = fd;
 	avalon->device_fd = fd;
@@ -579,6 +567,55 @@ static void do_avalon_close(struct thr_info *thr)
 	avalon_free_work(thr, info->bulk3);
 	avalon_free_work(thr, info->bulk3);
 }
 }
 
 
+static inline void record_temp_fan(struct avalon_info *info, struct avalon_result *ar, float *temp_avg)
+{
+	info->fan0 = ar->fan0 * AVALON_FAN_FACTOR;
+	info->fan1 = ar->fan1 * AVALON_FAN_FACTOR;
+	info->fan2 = ar->fan2 * AVALON_FAN_FACTOR;
+
+	info->temp0 = ar->temp0;
+	info->temp1 = ar->temp1;
+	info->temp2 = ar->temp2;
+	if (ar->temp0 & 0x80) {
+		ar->temp0 &= 0x7f;
+		info->temp0 = ~ar->temp0 + 1;
+	}
+	if (ar->temp1 & 0x80) {
+		ar->temp1 &= 0x7f;
+		info->temp1 = ~ar->temp1 + 1;
+	}
+	if (ar->temp2 & 0x80) {
+		ar->temp2 &= 0x7f;
+		info->temp2 = ~ar->temp2 + 1;
+	}
+
+	*temp_avg = (info->temp0 + info->temp1 + info->temp2) / 3;
+
+	if (info->temp0 > info->temp_max)
+		info->temp_max = info->temp0;
+	if (info->temp1 > info->temp_max)
+		info->temp_max = info->temp1;
+	if (info->temp2 > info->temp_max)
+		info->temp_max = info->temp2;
+}
+
+static void adjust_temp(struct avalon_info *info)
+{
+	int temp_new;
+
+	temp_new = info->temp_sum / info->temp_history_count;
+
+	if (temp_new < 40)
+		info->fan_pwm = 0xA;
+	else if (temp_new > 60)
+		info->fan_pwm = AVALON_DEFAULT_FAN_PWM;
+	else if (temp_new - info->temp_old > 2)
+		info->fan_pwm = (temp_new - 40) * 9 + 10;
+
+	info->temp_old = temp_new;
+	info->temp_sum = 0;
+}
+
 static int64_t avalon_scanhash(struct thr_info *thr, struct work **work,
 static int64_t avalon_scanhash(struct thr_info *thr, struct work **work,
 			       __maybe_unused int64_t max_nonce)
 			       __maybe_unused int64_t max_nonce)
 {
 {
@@ -624,7 +661,9 @@ static int64_t avalon_scanhash(struct thr_info *thr, struct work **work,
 
 
 	i = 0;
 	i = 0;
 	while (true) {
 	while (true) {
-		avalon_init_task(thr, &at, 0, 0, 0, 0, 0, 0, 1);
+		avalon_init_task(&at, 0, 0, info->fan_pwm,
+				 info->timeout, info->asic_count,
+				 info->miner_count, 1);
 		avalon_create_task(&at, work[i]);
 		avalon_create_task(&at, work[i]);
 		ret = avalon_send_task(fd, &at, thr);
 		ret = avalon_send_task(fd, &at, thr);
 		if (unlikely(ret == AVA_SEND_ERROR ||
 		if (unlikely(ret == AVA_SEND_ERROR ||
@@ -696,21 +735,7 @@ static int64_t avalon_scanhash(struct thr_info *thr, struct work **work,
 			avalon_free_work(thr, info->bulk3);
 			avalon_free_work(thr, info->bulk3);
 			continue;
 			continue;
 		}
 		}
-		avalon->temp = (ar.temp0 + ar.temp1 + ar.temp2) / 3;
-		info->fan0 = ar.fan0 * AVALON_FAN_FACTOR;
-		info->fan1 = ar.fan1 * AVALON_FAN_FACTOR;
-		info->fan2 = ar.fan2 * AVALON_FAN_FACTOR;
-
-		info->temp0 = ar.temp0;
-		info->temp1 = ar.temp1;
-		info->temp2 = ar.temp2;
-
-		if (info->temp0 > info->temp_max)
-			info->temp_max = info->temp0;
-		if (info->temp1 > info->temp_max)
-			info->temp_max = info->temp1;
-		if (info->temp2 > info->temp_max)
-			info->temp_max = info->temp2;
+		record_temp_fan(info, &ar, &(avalon->temp));
 
 
 		work_i0 = avalon_decode_nonce(thr, info->bulk0, &ar, &nonce);
 		work_i0 = avalon_decode_nonce(thr, info->bulk0, &ar, &nonce);
 		work_i1 = avalon_decode_nonce(thr, info->bulk1, &ar, &nonce);
 		work_i1 = avalon_decode_nonce(thr, info->bulk1, &ar, &nonce);
@@ -752,14 +777,12 @@ static int64_t avalon_scanhash(struct thr_info *thr, struct work **work,
 	       "Temp1: %dC, Temp2: %dC, Temp3: %dC, TempMAX: %dC",
 	       "Temp1: %dC, Temp2: %dC, Temp3: %dC, TempMAX: %dC",
 	       info->fan0, info->fan1, info->fan2,
 	       info->fan0, info->fan1, info->fan2,
 	       info->temp0, info->temp1, info->temp2, info->temp_max);
 	       info->temp0, info->temp1, info->temp2, info->temp_max);
-	/*
-	 * TODO: add fan/temp control
-	 * 1. add task_num to init_task
-	 * 2. record the gate_status at info-> [code here].
-	 *   when TEMP reach a HIGH gate miner
-	 *   when TEMP reach a LOW trigger miner
-	 * 3. enable/disable gate on init_task
-	 */
+	info->temp_history_index++;
+	info->temp_sum += info->temp2;
+	if (info->temp_history_index == info->temp_history_count) {
+		adjust_temp(info);
+		info->temp_history_index = 0;
+	}
 
 
 	/*
 	/*
 	 * FIXME: Each work split to 10 pieces, each piece send to a
 	 * FIXME: Each work split to 10 pieces, each piece send to a

+ 5 - 1
driver-avalon.h

@@ -81,8 +81,12 @@ struct avalon_info {
 	int temp0;
 	int temp0;
 	int temp1;
 	int temp1;
 	int temp2;
 	int temp2;
-
 	int temp_max;
 	int temp_max;
+	int temp_history_count;
+	int temp_history_index;
+	int temp_sum;
+	int temp_old;
+	int fan_pwm;
 
 
 	int no_matching_work;
 	int no_matching_work;
 	int matching_work[AVALON_DEFAULT_MINER_NUM];
 	int matching_work[AVALON_DEFAULT_MINER_NUM];