static struct api_data*
get_ztex_drv_extra_device_status(struct cgpu_info *ztex)
{
	struct api_data*root = NULL;
	struct libztex_device *ztexr = ztex->device_ztex;

	if (ztexr) {
		double frequency = ztexr->freqM1 * (ztexr->dclk.freqM + 1);
		root = api_add_freq(root, "Frequency", &frequency, true);
	}

	return root;
}
Exemplo n.º 2
0
bool cairnsmore_supports_dynclock(int fd)
{
	if (!cairnsmore_send_cmd(fd, 0, 1, true))
		return false;
	if (!cairnsmore_send_cmd(fd, 0, 1, true))
		return false;

	uint32_t nonce = 0;
	{
		struct timeval tv_finish;
		struct thr_info dummy = {
			.work_restart = false,
			.work_restart_fd = -1,
		};
		icarus_gets((unsigned char*)&nonce, fd, &tv_finish, &dummy, 1);
	}
	applog(LOG_DEBUG, "Cairnsmore dynclock detection... Got %08x", nonce);
	switch (nonce) {
		case 0x00949a6f:  // big    endian
		case 0x6f9a9400:  // little endian
			// Hashed the command, so it's not supported
			return false;
		default:
			applog(LOG_WARNING, "Unexpected nonce from dynclock probe: %08x", be32toh(nonce));
			return false;
		case 0:
			return true;
	}
}

#define cairnsmore_send_cmd(fd, cmd, data) cairnsmore_send_cmd(fd, cmd, data, false)

static bool cairnsmore_change_clock_func(struct thr_info *thr, int bestM)
{
	struct cgpu_info *cm1 = thr->cgpu;
	struct ICARUS_INFO *info = cm1->cgpu_data;

	if (unlikely(!cairnsmore_send_cmd(cm1->device_fd, 0, bestM)))
		return false;

	// Adjust Hs expectations for frequency change
	info->Hs = info->Hs * (double)bestM / (double)info->dclk.freqM;

	char repr[0x10];
	sprintf(repr, "%s %u", cm1->api->name, cm1->device_id);
	dclk_msg_freqchange(repr, 2.5 * (double)info->dclk.freqM, 2.5 * (double)bestM, NULL);
	info->dclk.freqM = bestM;

	return true;
}

static bool cairnsmore_init(struct thr_info *thr)
{
	struct cgpu_info *cm1 = thr->cgpu;
	struct ICARUS_INFO *info = cm1->cgpu_data;
	struct icarus_state *state = thr->cgpu_data;

	if (cairnsmore_supports_dynclock(cm1->device_fd)) {
		info->dclk_change_clock_func = cairnsmore_change_clock_func;

		dclk_prepare(&info->dclk);
		info->dclk.freqMinM = CAIRNSMORE1_MINIMUM_CLOCK / 2.5;
		info->dclk.freqMaxM = CAIRNSMORE1_MAXIMUM_CLOCK / 2.5;
		info->dclk.freqM =
		info->dclk.freqMDefault = CAIRNSMORE1_DEFAULT_CLOCK / 2.5;
		cairnsmore_send_cmd(cm1->device_fd, 0, info->dclk.freqM);
		applog(LOG_WARNING, "%s %u: Frequency set to %u MHz (range: %u-%u)",
		       cm1->api->name, cm1->device_id,
		       CAIRNSMORE1_DEFAULT_CLOCK, CAIRNSMORE1_MINIMUM_CLOCK, CAIRNSMORE1_MAXIMUM_CLOCK
		);
		// The dynamic-clocking firmware connects each FPGA as its own device
		if (!(info->user_set & 1)) {
			info->work_division = 1;
			if (!(info->user_set & 2))
				info->fpga_count = 1;
		}
	} else {
		applog(LOG_WARNING, "%s %u: Frequency scaling not supported",
			cm1->api->name, cm1->device_id
		);
	}
	// Commands corrupt the hash state, so next scanhash is a firstrun
	state->firstrun = true;

	return true;
}

void convert_icarus_to_cairnsmore(struct cgpu_info *cm1)
{
	struct ICARUS_INFO *info = cm1->cgpu_data;
	info->Hs = CAIRNSMORE1_HASH_TIME;
	info->fullnonce = info->Hs * (((double)0xffffffff) + 1);
	info->timing_mode = MODE_LONG;
	info->do_icarus_timing = true;
	cm1->api = &cairnsmore_api;
	renumber_cgpu(cm1);
	cairnsmore_init(cm1->thr[0]);
}

static struct api_data *cairnsmore_api_extra_device_status(struct cgpu_info *cm1)
{
	struct ICARUS_INFO *info = cm1->cgpu_data;
	struct api_data*root = NULL;

	if (info->dclk.freqM) {
		double frequency = 2.5 * info->dclk.freqM;
		root = api_add_freq(root, "Frequency", &frequency, true);
	}

	return root;
}

static bool cairnsmore_identify(struct cgpu_info *cm1)
{
	struct ICARUS_INFO *info = cm1->cgpu_data;
	if (!info->dclk.freqM)
		return false;
	
	cairnsmore_send_cmd(cm1->device_fd, 1, 1);
	sleep(5);
	cairnsmore_send_cmd(cm1->device_fd, 1, 0);
	cm1->flash_led = true;
	return true;
}

extern struct device_api icarus_api;

static void cairnsmore_api_init()
{
	cairnsmore_api = icarus_api;
	cairnsmore_api.dname = "cairnsmore";
	cairnsmore_api.name = "ECM";
	cairnsmore_api.api_detect = cairnsmore_detect;
	cairnsmore_api.thread_init = cairnsmore_init;
	cairnsmore_api.identify_device = cairnsmore_identify;
	cairnsmore_api.get_api_extra_device_status = cairnsmore_api_extra_device_status;
}