|
|
@@ -64,6 +64,7 @@ enum hashfast_opcode {
|
|
|
HFOP_USB_SHUTDOWN = 0x85,
|
|
|
HFOP_DIE_STATUS = 0x86,
|
|
|
HFOP_GWQ_STATUS = 0x87,
|
|
|
+ HFOP_UMS_CLOCK_CHANGE = 0x88,
|
|
|
HFOP_WORK_RESTART = 0x88,
|
|
|
HFOP_USB_STATS1 = 0x89,
|
|
|
HFOP_USB_GWQSTATS = 0x8a,
|
|
|
@@ -84,6 +85,10 @@ enum hashfast_config_flags {
|
|
|
HFCF_PWM_ACTIVE_LV = 1 << 0xe,
|
|
|
};
|
|
|
|
|
|
+enum hashfast_clock_change_cmd {
|
|
|
+ HFWR_SET_CLOCK = 1 << 0xc,
|
|
|
+};
|
|
|
+
|
|
|
typedef unsigned long hashfast_isn_t;
|
|
|
|
|
|
static inline
|
|
|
@@ -232,10 +237,12 @@ const char *hashfast_set_clock(struct cgpu_info * const proc, const char * const
|
|
|
}
|
|
|
|
|
|
static const struct bfg_set_device_definition hashfast_set_device_funcs_probe[] = {
|
|
|
- {"clock", hashfast_set_clock, "clock frequency (can only be set at startup, with --set-device)"},
|
|
|
+ {"clock", hashfast_set_clock, "clock frequency"},
|
|
|
{NULL},
|
|
|
};
|
|
|
|
|
|
+static const struct bfg_set_device_definition hashfast_set_device_funcs[];
|
|
|
+
|
|
|
static
|
|
|
bool hashfast_detect_one(const char * const devpath)
|
|
|
{
|
|
|
@@ -284,6 +291,9 @@ bool hashfast_detect_one(const char * const devpath)
|
|
|
if (serial_claim_v(devpath, &hashfast_ums_drv))
|
|
|
return false;
|
|
|
|
|
|
+ // Hijack hdata for a quick way to transfer clock to init
|
|
|
+ pmsg->hdata = clock;
|
|
|
+
|
|
|
struct cgpu_info * const cgpu = malloc(sizeof(*cgpu));
|
|
|
*cgpu = (struct cgpu_info){
|
|
|
.drv = &hashfast_ums_drv,
|
|
|
@@ -295,6 +305,9 @@ bool hashfast_detect_one(const char * const devpath)
|
|
|
.cutofftemp = 100,
|
|
|
};
|
|
|
|
|
|
+ if (fwrev >= 0x0005)
|
|
|
+ cgpu->set_device_funcs = hashfast_set_device_funcs;
|
|
|
+
|
|
|
return add_cgpu(cgpu);
|
|
|
|
|
|
err:
|
|
|
@@ -319,6 +332,8 @@ struct hashfast_chip_state {
|
|
|
struct cgpu_info **coreprocs;
|
|
|
hashfast_isn_t last_isn;
|
|
|
float voltages[HASHFAST_MAX_VOLTAGES];
|
|
|
+ uint16_t clock;
|
|
|
+ uint16_t clock_desired;
|
|
|
uint8_t cfgdata[HASHFAST_CONFIG_DATA_SIZE];
|
|
|
};
|
|
|
|
|
|
@@ -333,6 +348,28 @@ struct hashfast_core_state {
|
|
|
unsigned queued;
|
|
|
};
|
|
|
|
|
|
+static
|
|
|
+const char *hashfast_set_clock_runtime(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 thr_info * const thr = proc->thr[0];
|
|
|
+ struct hashfast_dev_state * const devstate = proc->device_data;
|
|
|
+ struct hashfast_core_state * const cs = thr->cgpu_data;
|
|
|
+ struct hashfast_chip_state * const chipstate = &devstate->chipstates[cs->chipaddr];
|
|
|
+
|
|
|
+ const int nv = atoi(newvalue);
|
|
|
+ if (nv >= 0xfff)
|
|
|
+ return "Clock frequency too high";
|
|
|
+
|
|
|
+ chipstate->clock_desired = nv;
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct bfg_set_device_definition hashfast_set_device_funcs[] = {
|
|
|
+ {"clock", hashfast_set_clock_runtime, "clock frequency"},
|
|
|
+ {NULL},
|
|
|
+};
|
|
|
+
|
|
|
static
|
|
|
void hashfast_init_cfgdata(struct hashfast_chip_state * const chipstate)
|
|
|
{
|
|
|
@@ -378,6 +415,13 @@ void hashfast_init_cfgdata(struct hashfast_chip_state * const chipstate)
|
|
|
pk_u16le(cfgdata, 0xe, pwm_pulse_period);
|
|
|
}
|
|
|
|
|
|
+static
|
|
|
+uint16_t hashfast_chip_thermal_cutoff_hdata(const float temp)
|
|
|
+{
|
|
|
+ const uint16_t v = (temp + 61.5) * 0x1000 / 240;
|
|
|
+ return HFCH_THERMAL_LIMIT | (v & 0x3ff);
|
|
|
+}
|
|
|
+
|
|
|
static
|
|
|
bool hashfast_init(struct thr_info * const master_thr)
|
|
|
{
|
|
|
@@ -395,11 +439,15 @@ bool hashfast_init(struct thr_info * const master_thr)
|
|
|
.fwrev = upk_u16le(pmsg->data, 0),
|
|
|
};
|
|
|
|
|
|
+ const uint16_t clock = pmsg->hdata;
|
|
|
+
|
|
|
for (i = 0; i < pmsg->chipaddr; ++i)
|
|
|
{
|
|
|
chipstate = &chipstates[i];
|
|
|
*chipstate = (struct hashfast_chip_state){
|
|
|
.coreprocs = malloc(sizeof(struct cgpu_info *) * pmsg->coreaddr),
|
|
|
+ .clock = clock,
|
|
|
+ .clock_desired = clock,
|
|
|
};
|
|
|
hashfast_init_cfgdata(chipstate);
|
|
|
}
|
|
|
@@ -446,7 +494,7 @@ bool hashfast_queue_append(struct thr_info * const thr, struct work * const work
|
|
|
hashfast_isn_t isn;
|
|
|
uint8_t seq;
|
|
|
|
|
|
- if (cs->has_pending)
|
|
|
+ if (cs->has_pending || chipstate->clock_desired != chipstate->clock)
|
|
|
{
|
|
|
thr->queue_full = true;
|
|
|
return false;
|
|
|
@@ -620,6 +668,7 @@ bool hashfast_poll_msg(struct thr_info * const master_thr)
|
|
|
{
|
|
|
const uint8_t *data = &msg.data[8];
|
|
|
struct cgpu_info *proc = hashfast_find_proc(master_thr, msg.chipaddr, 0);
|
|
|
+ struct cgpu_info *first_proc = proc;
|
|
|
if (unlikely(!proc))
|
|
|
{
|
|
|
applog(LOG_ERR, "%s: Unknown chip address %u",
|
|
|
@@ -660,13 +709,50 @@ bool hashfast_poll_msg(struct thr_info * const master_thr)
|
|
|
{
|
|
|
++cores_transitioned;
|
|
|
cs->has_pending = false;
|
|
|
- thr->queue_full = false;
|
|
|
+ // Avoid refilling pending slot if we are preparing to change the clock frequency
|
|
|
+ if (chipstate->clock_desired == chipstate->clock)
|
|
|
+ thr->queue_full = false;
|
|
|
}
|
|
|
}
|
|
|
applog(LOG_DEBUG, "%s: STATUS from chipaddr=0x%02x with hdata=0x%04x (isn=0x%lx): total=%d uptodate=%d active=%d pending=%d transitioned=%d",
|
|
|
dev->dev_repr, (unsigned)msg.chipaddr, (unsigned)msg.hdata, isn,
|
|
|
devstate->cores_per_chip, cores_uptodate,
|
|
|
cores_active, cores_pending, cores_transitioned);
|
|
|
+ if ((!cores_active) && chipstate->clock_desired != chipstate->clock)
|
|
|
+ {
|
|
|
+ // All cores finished their work, change clock frequency and then refill
|
|
|
+ uint8_t buf[HASHFAST_HEADER_SIZE + HASHFAST_CONFIG_DATA_SIZE];
|
|
|
+ uint16_t clock = chipstate->clock_desired, hdata;
|
|
|
+ if (!hashfast_send_msg(fd, buf, HFOP_UMS_CLOCK_CHANGE, msg.chipaddr, 0, HFWR_SET_CLOCK | clock, 0))
|
|
|
+ {
|
|
|
+ applog(LOG_ERR, "%"PRIpreprv": Clock change failure (%s)", proc->proc_repr, "OP_UMS_CLOCK_CHANGE");
|
|
|
+ goto clockchangefailed;
|
|
|
+ }
|
|
|
+ // Until we send HFOP_CONFIG, the state is undefined
|
|
|
+ chipstate->clock = 0;
|
|
|
+
|
|
|
+ hdata = HFCH_WRITE;
|
|
|
+ hdata |= hashfast_chip_thermal_cutoff_hdata(110);
|
|
|
+ pk_uNle(chipstate->cfgdata, 8, 0, 0xc, clock);
|
|
|
+ memcpy(&buf[HASHFAST_HEADER_SIZE], chipstate->cfgdata, HASHFAST_CONFIG_DATA_SIZE);
|
|
|
+ if (!hashfast_send_msg(fd, buf, HFOP_CONFIG, msg.chipaddr, 0, hdata, HASHFAST_CONFIG_DATA_SIZE))
|
|
|
+ {
|
|
|
+ applog(LOG_ERR, "%"PRIpreprv": Clock change failure (%s)", proc->proc_repr, "OP_CONFIG");
|
|
|
+ goto clockchangefailed;
|
|
|
+ }
|
|
|
+
|
|
|
+ chipstate->clock = clock;
|
|
|
+
|
|
|
+ // Time to refill queues
|
|
|
+ proc = first_proc;
|
|
|
+ for (int i = 0; i < devstate->cores_per_chip; ++i, (proc = proc->next_proc))
|
|
|
+ {
|
|
|
+ struct thr_info * const thr = proc->thr[0];
|
|
|
+ thr->queue_full = false;
|
|
|
+ }
|
|
|
+
|
|
|
+clockchangefailed: ;
|
|
|
+ }
|
|
|
break;
|
|
|
}
|
|
|
}
|