diff --git a/ASIC-README b/ASIC-README index ff758ab9..821c21bc 100644 --- a/ASIC-README +++ b/ASIC-README @@ -84,15 +84,17 @@ degrees. Avalon commands: +--avalon-auto Adjust avalon overclock frequency dynamically for best hashrate --avalon-cutoff Set avalon overheat cut off temperature (default: 60) --avalon-options Set avalon options baud:miners:asic:timeout:freq --avalon-temp Set avalon target temperature (default: 50) -eg: ---avalon-cutoff 65 -This will cut off the avalon should it get up to 65 degrees and will then -re-enable it when it gets to the target temperature as specified by avalon-temp. +Avalon auto will enable dynamic overclocking gradually increasing and +decreasing the frequency till the highest hashrate that keeps hardware errors +around 1% is achieved. This WILL run your avalon beyond its normal specification +so the usual warnings apply. When avalon-auto is enabled, the avalon-options +for frequency and timeout are used as the starting point only. eg: --avalon-temp 55 @@ -103,6 +105,12 @@ very low such as 0 will achieve this. This option can be added to the "More options" entry in the web interface if you do not have a direct way of setting it. +eg: +--avalon-cutoff 65 + +This will cut off the avalon should it get up to 65 degrees and will then +re-enable it when it gets to the target temperature as specified by avalon-temp. + eg: --avalon-options 115200:24:10:45:282 diff --git a/README b/README index 5b94fe55..4612372d 100644 --- a/README +++ b/README @@ -233,6 +233,7 @@ See SCRYPT-README for more information regarding litecoin mining. ASIC and FPGA mining boards (BFL ASIC, BitForce, Icarus, ModMiner, Ztex) only options: +--avalon-auto Adjust avalon overclock frequency dynamically for best hashrate --avalon-cutoff Set avalon overheat cut off temperature (default: 60) --avalon-options Set avalon options baud:miners:asic:timeout:freq --avalon-temp Set avalon target temperature (default: 50) diff --git a/cgminer.c b/cgminer.c index ae12bbb4..a514caba 100644 --- a/cgminer.c +++ b/cgminer.c @@ -1057,6 +1057,9 @@ static struct opt_table opt_config_table[] = { opt_hidden), #endif #ifdef USE_AVALON + OPT_WITHOUT_ARG("--avalon-auto", + opt_set_bool, &opt_avalon_auto, + "Adjust avalon overclock frequency dynamically for best hashrate"), OPT_WITH_ARG("--avalon-cutoff", set_int_0_to_100, opt_show_intval, &opt_avalon_overheat, "Set avalon overheat cut off temperature"), diff --git a/driver-avalon.c b/driver-avalon.c index b6c79e84..4efc7832 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -42,6 +42,8 @@ int opt_avalon_temp = AVALON_TEMP_TARGET; int opt_avalon_overheat = AVALON_TEMP_OVERHEAT; +bool opt_avalon_auto; + static int option_offset = -1; struct device_drv avalon_drv; @@ -51,6 +53,7 @@ static int avalon_init_task(struct avalon_task *at, uint8_t miner_num, uint8_t nonce_elf, uint8_t gate_miner, int frequency) { + uint16_t *lefreq16; uint8_t *buf; static bool first = true; @@ -98,37 +101,8 @@ static int avalon_init_task(struct avalon_task *at, buf[9] = 0x01; buf[10] = 0x00; buf[11] = 0x00; - switch (frequency) { - case 256: - buf[6] = 0x03; - buf[7] = 0x08; - break; - default: - case 270: - buf[6] = 0x73; - buf[7] = 0x08; - break; - case 282: - buf[6] = 0xd3; - buf[7] = 0x08; - break; - case 300: - buf[6] = 0x63; - buf[7] = 0x09; - break; - case 325: - buf[6] = 0x28; - buf[7] = 0x0a; - break; - case 350: - buf[6] = 0xf0; - buf[7] = 0x0a; - break; - case 375: - buf[6] = 0xb8; - buf[7] = 0x0b; - break; - } + lefreq16 = (uint16_t *)&buf[6]; + *lefreq16 = htole16(frequency * 8); return 0; } @@ -731,6 +705,11 @@ static void avalon_parse_results(struct cgpu_info *avalon, struct avalon_info *i mutex_lock(&info->lock); if (!info->nonces++) gettemp = true; + info->auto_nonces++; + mutex_unlock(&info->lock); + } else if (opt_avalon_auto) { + mutex_lock(&info->lock); + info->auto_hw++; mutex_unlock(&info->lock); } @@ -842,6 +821,31 @@ static void avalon_rotate_array(struct cgpu_info *avalon) avalon->work_array = 0; } +static void avalon_set_timeout(struct avalon_info *info) +{ + info->timeout = AVALON_TIMEOUT_FACTOR / info->frequency; +} + +static void avalon_inc_freq(struct avalon_info *info) +{ + info->frequency += 2; + if (info->frequency > AVALON_MAX_FREQUENCY) + info->frequency = AVALON_MAX_FREQUENCY; + avalon_set_timeout(info); + applog(LOG_NOTICE, "Avalon increasing frequency to %d, timeout %d", + info->frequency, info->timeout); +} + +static void avalon_dec_freq(struct avalon_info *info) +{ + info->frequency -= 1; + if (info->frequency < AVALON_MIN_FREQUENCY) + info->frequency = AVALON_MIN_FREQUENCY; + avalon_set_timeout(info); + applog(LOG_NOTICE, "Avalon decreasing frequency to %d, timeout %d", + info->frequency, info->timeout); +} + static void *avalon_send_tasks(void *userdata) { struct cgpu_info *avalon = (struct cgpu_info *)userdata; @@ -860,6 +864,24 @@ static void *avalon_send_tasks(void *userdata) while (avalon_buffer_full(avalon)) cgsem_wait(&info->write_sem); + if (opt_avalon_auto && info->auto_queued >= AVALON_AUTO_CYCLE) { + mutex_lock(&info->lock); + if (info->auto_nonces >= (AVALON_AUTO_CYCLE * 19 / 20) && + info->auto_nonces <= (AVALON_AUTO_CYCLE * 21 / 20)) { + int total = info->auto_nonces + info->auto_hw; + + /* Try to keep hw errors ~1-1.5% */ + if (info->auto_hw * 100 < total) + avalon_inc_freq(info); + else if (info->auto_hw * 66 > total) + avalon_dec_freq(info); + } + info->auto_queued = + info->auto_nonces = + info->auto_hw = 0; + mutex_unlock(&info->lock); + } + mutex_lock(&info->qlock); start_count = avalon->work_array * avalon_get_work_count; end_count = start_count + avalon_get_work_count; @@ -877,11 +899,15 @@ static void *avalon_send_tasks(void *userdata) info->timeout, info->asic_count, info->miner_count, 1, 0, info->frequency); avalon_create_task(&at, avalon->works[i]); + info->auto_queued++; } else { idled++; avalon_init_task(&at, 0, 0, info->fan_pwm, info->timeout, info->asic_count, info->miner_count, 1, 1, info->frequency); + /* Reset the auto_queued count if we end up + * idling any miners. */ + info->auto_queued = 0; } ret = avalon_send_task(&at, avalon); diff --git a/driver-avalon.h b/driver-avalon.h index 7a0df4d2..0de31c87 100644 --- a/driver-avalon.h +++ b/driver-avalon.h @@ -25,15 +25,21 @@ #define AVALON_FAN_FACTOR 120 #define AVALON_DEFAULT_FAN_MAX_PWM 0xA0 /* 100% */ #define AVALON_DEFAULT_FAN_MIN_PWM 0x20 /* 20% */ + #define AVALON_TEMP_TARGET 50 #define AVALON_TEMP_HYSTERESIS 3 #define AVALON_TEMP_OVERHEAT 60 #define AVALON_DEFAULT_TIMEOUT 0x2D +#define AVALON_MIN_FREQUENCY 256 +#define AVALON_MAX_FREQUENCY 450 +#define AVALON_TIMEOUT_FACTOR 12000 #define AVALON_DEFAULT_FREQUENCY 282 #define AVALON_DEFAULT_MINER_NUM 0x20 #define AVALON_DEFAULT_ASIC_NUM 0xA +#define AVALON_AUTO_CYCLE 1024 + #define AVALON_FTDI_READSIZE 510 #define AVALON_USB_PACKETSIZE 512 #define AVALON_READBUF_SIZE 8192 @@ -118,6 +124,10 @@ struct avalon_info { cgsem_t write_sem; int nonces; + int auto_queued; + int auto_nonces; + int auto_hw; + bool idle; bool reset; bool overheat; @@ -142,6 +152,7 @@ ASSERT1(sizeof(uint32_t) == 4); extern struct avalon_info **avalon_info; extern int opt_avalon_temp; extern int opt_avalon_overheat; +extern bool opt_avalon_auto; #endif /* USE_AVALON */ #endif /* AVALON_H */