/ driver-avalon-miner.c
driver-avalon-miner.c
   1  /*
   2   * Copyright 2013-2014 Con Kolivas <kernel@kolivas.org>
   3   * Copyright 2012-2014 Xiangfu <xiangfu@openmobilefree.com>
   4   * Copyright 2014-2015 Mikeqin <Fengling.Qin@gmail.com>
   5   *
   6   * This program is free software; you can redistribute it and/or modify it
   7   * under the terms of the GNU General Public License as published by the Free
   8   * Software Foundation; either version 3 of the License, or (at your option)
   9   * any later version.  See COPYING for more details.
  10   */
  11  #include <math.h>
  12  #include "config.h"
  13  #include "miner.h"
  14  #include "driver-avalon-miner.h"
  15  #include "crc.h"
  16  #include "sha2.h"
  17  #include "hexdump.c"
  18  
  19  #define UNPACK32(x, str)			\
  20  {						\
  21  	*((str) + 3) = (uint8_t) ((x)      );	\
  22  	*((str) + 2) = (uint8_t) ((x) >>  8);	\
  23  	*((str) + 1) = (uint8_t) ((x) >> 16);	\
  24  	*((str) + 0) = (uint8_t) ((x) >> 24);	\
  25  }
  26  
  27  #define PACK32(str, x)                        \
  28  {                                             \
  29      *(x) =   ((uint32_t) *((str) + 3)      )    \
  30             | ((uint32_t) *((str) + 2) <<  8)    \
  31             | ((uint32_t) *((str) + 1) << 16)    \
  32             | ((uint32_t) *((str) + 0) << 24);   \
  33  }
  34  
  35  #define V_REF	3.3
  36  #define R_REF	10000
  37  #define R0	10000
  38  #define BCOEFFICIENT	3450
  39  #define T0	25
  40  
  41  static uint32_t opt_avalonm_freq[3] = {AVAM_DEFAULT_FREQUENCY, AVAM_DEFAULT_FREQUENCY, AVAM_DEFAULT_FREQUENCY};
  42  uint8_t opt_avalonm_ntime_offset = 0;
  43  int opt_avalonm_voltage = AVAM_DEFAULT_VOLTAGE;
  44  uint32_t opt_avalonm_spispeed = AVAM_DEFAULT_SPISPEED;
  45  bool opt_avalonm_autof;
  46  static uint32_t g_freq_array[][2] = {
  47  	{100, 0x1e678447},
  48  	{113, 0x22688447},
  49  	{125, 0x1c470447},
  50  	{138, 0x2a6a8447},
  51  	{150, 0x22488447},
  52  	{163, 0x326c8447},
  53  	{175, 0x1a268447},
  54  	{188, 0x1c270447},
  55  	{200, 0x1e278447},
  56  	{213, 0x20280447},
  57  	{225, 0x22288447},
  58  	{238, 0x24290447},
  59  	{250, 0x26298447},
  60  	{263, 0x282a0447},
  61  	{275, 0x2a2a8447},
  62  	{288, 0x2c2b0447},
  63  	{300, 0x2e2b8447},
  64  	{313, 0x302c0447},
  65  	{325, 0x322c8447},
  66  	{338, 0x342d0447},
  67  	{350, 0x1a068447},
  68  	{363, 0x382e0447},
  69  	{375, 0x1c070447},
  70  	{388, 0x3c2f0447},
  71  	{400, 0x1e078447}
  72  };
  73  
  74  static uint16_t encode_voltage(uint32_t v)
  75  {
  76  	if (v == 0)
  77  		return 0xff;
  78  
  79  	return (((0x59 - (v - 5000) / 125) & 0xff) << 1 | 1);
  80  }
  81  
  82  static uint32_t decode_voltage(uint8_t v)
  83  {
  84  	if (v == 0xff)
  85  		return 0;
  86  
  87  	return (0x59 - (v >> 1)) * 125 + 5000;
  88  }
  89  
  90  static uint32_t decode_cpm(uint32_t cpm)
  91  {
  92  	int i;
  93  
  94  	for (i = 0; i < sizeof(g_freq_array) / sizeof(g_freq_array[0]); i++) {
  95  		if (g_freq_array[i][1] == cpm)
  96  			return g_freq_array[i][0];
  97  	}
  98  
  99  	return 0;
 100  }
 101  
 102  static int avalonm_init_pkg(struct avalonm_pkg *pkg, uint8_t type, uint8_t idx, uint8_t cnt)
 103  {
 104  	unsigned short crc;
 105  
 106  	pkg->head[0] = AVAM_H1;
 107  	pkg->head[1] = AVAM_H2;
 108  
 109  	pkg->type = type;
 110  	pkg->opt = 0;
 111  	pkg->idx = idx;
 112  	pkg->cnt = cnt;
 113  
 114  	crc = crc16(pkg->data, AVAM_P_DATA_LEN);
 115  
 116  	pkg->crc[0] = (crc & 0xff00) >> 8;
 117  	pkg->crc[1] = crc & 0x00ff;
 118  	return 0;
 119  }
 120  
 121  static float convert_temp(uint32_t adc)
 122  {
 123  	float ret, resistance;
 124  
 125  	if (adc >= 1023)
 126  		return -273.15;
 127  
 128  	resistance = (1023.0 / adc) - 1;
 129  	resistance = R_REF / resistance;
 130  	ret = resistance / R0;
 131  	ret = log(ret);
 132  	ret /= BCOEFFICIENT;
 133  	ret += 1.0 / (T0 + 273.15);
 134  	ret = 1.0 / ret;
 135  	ret -= 273.15;
 136  
 137  	return ret;
 138  }
 139  
 140  static float convert_voltage(uint32_t adc, float percent)
 141  {
 142  	float voltage;
 143  
 144  	voltage = adc * V_REF / 1023 / percent;
 145  	return voltage;
 146  }
 147  
 148  static void process_nonce(struct cgpu_info *avalonm, uint8_t *report)
 149  {
 150  	struct avalonm_info *info = avalonm->device_data;
 151  	struct work *work;
 152  	uint8_t ntime, chip_id;
 153  	uint32_t nonce, id;
 154  
 155  	PACK32(report, &id);
 156  	chip_id = report[6];
 157  	if (chip_id >= info->asic_cnts) {
 158  		applog(LOG_DEBUG, "%s-%d: chip_id >= info->asic_cnts(%d > %d)",
 159  				avalonm->drv->name, avalonm->device_id,
 160  				chip_id, info->asic_cnts);
 161  		return;
 162  	}
 163  
 164  	ntime = report[7];
 165  	PACK32(report + 8, &nonce);
 166  	nonce -= 0x4000;
 167  	info->usbfifo_cnt = report[13];
 168  	info->workfifo_cnt = report[14];
 169  	info->noncefifo_cnt = report[15];
 170  
 171  	applog(LOG_DEBUG, "%s-%d: Found! - ID: %08x CID: %02x N:%08x NR:%d",
 172  			avalonm->drv->name, avalonm->device_id,
 173  			id, chip_id, nonce, ntime);
 174  
 175  	work = clone_queued_work_byid(avalonm, id);
 176  	if (!work)
 177  		return;
 178  
 179  	if(!submit_noffset_nonce(info->thr, work, nonce, ntime)) {
 180  		info->hw_work[chip_id]++;
 181  		info->hw_work_i[chip_id][info->time_i]++;
 182  	}
 183  
 184  	info->matching_work[chip_id]++;
 185  	free_work(work);
 186  	info->nonce_cnts++;
 187  }
 188  
 189  static int decode_pkg(struct thr_info *thr, struct avalonm_ret *ar)
 190  {
 191  	struct cgpu_info *avalonm = thr->cgpu;
 192  	struct avalonm_info *info = avalonm->device_data;
 193  	uint32_t ret, tmp, i, freq[3];
 194  	unsigned int expected_crc;
 195  	unsigned int actual_crc;
 196  
 197  	if (ar->head[0] != AVAM_H1 && ar->head[1] != AVAM_H2) {
 198  		applog(LOG_DEBUG, "%s-%d: H1 %02x, H2 %02x",
 199  				avalonm->drv->name, avalonm->device_id,
 200  				ar->head[0], ar->head[1]);
 201  		info->crcerr_cnt++;
 202  		return 0;
 203  	}
 204  
 205  	expected_crc = crc16(ar->data, AVAM_P_DATA_LEN);
 206  	actual_crc = (ar->crc[1] & 0xff) | ((ar->crc[0] & 0xff) << 8);
 207  	if (expected_crc != actual_crc) {
 208  		applog(LOG_DEBUG, "%s-%d: %02x: expected crc(%04x), actual_crc(%04x)",
 209  		       avalonm->drv->name, avalonm->device_id,
 210  		       ar->type, expected_crc, actual_crc);
 211  		return 0;
 212  	}
 213  
 214  	switch(ar->type) {
 215  	case AVAM_P_NONCE_M:
 216  		ret = ar->type;
 217  		applog(LOG_DEBUG, "%s-%d: AVAM_P_NONCE", avalonm->drv->name, avalonm->device_id);
 218  		hexdump(ar->data, 32);
 219  		process_nonce(avalonm, ar->data);
 220  		if (ar->data[22] != 0xff) {
 221  			process_nonce(avalonm, ar->data + 16);
 222  		}
 223  		break;
 224  	case AVAM_P_STATUS_M:
 225  		ret = ar->type;
 226  		applog(LOG_DEBUG, "%s-%d: AVAM_P_STATUS_M", avalonm->drv->name, avalonm->device_id);
 227  		hexdump(ar->data, 32);
 228  		memcpy(&tmp, ar->data, 4);
 229  		if (!strncmp(info->ver, "3U", 2))
 230  			info->get_frequency[0][0] = be32toh(tmp);
 231  		else
 232  			info->spi_speed = be32toh(tmp);
 233  		memcpy(&tmp, ar->data + 4, 4);
 234  		info->led_status = be32toh(tmp);
 235  		memcpy(&tmp, ar->data + 8, 4);
 236  		info->fan_pwm = be32toh(tmp);
 237  		memcpy(&tmp, ar->data + 12, 4);
 238  		if (!strncmp(info->ver, "3U", 2))
 239  			info->get_voltage = convert_voltage(be32toh(tmp), 0.5);
 240  		else
 241  			info->get_voltage = decode_voltage((uint8_t)be32toh(tmp));
 242  		memcpy(&tmp, ar->data + 16, 4);
 243  		info->adc[0] = be32toh(tmp);
 244  		memcpy(&tmp, ar->data + 20, 4);
 245  		info->adc[1] = be32toh(tmp);
 246  		memcpy(&tmp, ar->data + 24, 4);
 247  		info->adc[2] = be32toh(tmp);
 248  		memcpy(&tmp, ar->data + 28 , 4);
 249  		info->power_good = be32toh(tmp);
 250  
 251  		/* power off notice */
 252  		if (!info->get_voltage) {
 253  			usb_buffer_clear(avalonm);
 254  			applog(LOG_NOTICE, "%s-%d: AVAM_P_STATUS_M Power off notice", avalonm->drv->name, avalonm->device_id);
 255  			info->power_on = 1;
 256  			memset(info->set_frequency, 0, sizeof(uint32_t) * info->asic_cnts * 3);
 257  			for (i = 1; i <= info->asic_cnts; i++)
 258  				FLAG_SET(info->freq_set, i);
 259  		}
 260  		break;
 261  	case AVAM_P_STATUS_FREQ:
 262  		applog(LOG_DEBUG, "%s-%d: AVAM_P_STATUS_FREQ", avalonm->drv->name, avalonm->device_id);
 263  		memcpy(&tmp, ar->data, 4);
 264  		tmp = be32toh(tmp);
 265  		freq[0] = decode_cpm(tmp);
 266  		memcpy(&tmp, ar->data + 4, 4);
 267  		tmp = be32toh(tmp);
 268  		freq[1] = decode_cpm(tmp);
 269  		memcpy(&tmp, ar->data + 8, 4);
 270  		tmp = be32toh(tmp);
 271  		freq[2] = decode_cpm(tmp);
 272  
 273  		if (!ar->opt) {
 274  			for (i = 0; i < info->asic_cnts; i++) {
 275  				info->get_frequency[i][0] = freq[0];
 276  				info->get_frequency[i][1] = freq[1];
 277  				info->get_frequency[i][2] = freq[2];
 278  			}
 279  		}
 280  
 281  		if (ar->opt) {
 282  			info->get_frequency[ar->opt - 1][0] = freq[0];
 283  			info->get_frequency[ar->opt - 1][1] = freq[1];
 284  			info->get_frequency[ar->opt - 1][2] = freq[2];
 285  		}
 286  		break;
 287  	default:
 288  		applog(LOG_DEBUG, "%s-%d: Unknown response (%x)", avalonm->drv->name, avalonm->device_id,
 289  				ar->type);
 290  		ret = 0;
 291  		break;
 292  	}
 293  
 294  	return ret;
 295  }
 296  
 297  static int avalonm_send_pkg(struct cgpu_info *avalonm, const struct avalonm_pkg *pkg)
 298  {
 299  	int err = -1;
 300  	int writecnt;
 301  
 302  	if (unlikely(avalonm->usbinfo.nodev))
 303  		return -1;
 304  
 305  	err = usb_write(avalonm, (char *)pkg, AVAM_P_COUNT, &writecnt, C_AVAM_WRITE);
 306  	if (err || writecnt != AVAM_P_COUNT) {
 307  		applog(LOG_DEBUG, "%s-%d: avalonm_send_pkg %d, w(%d-%d)!", avalonm->drv->name, avalonm->device_id, err, AVAM_P_COUNT, writecnt);
 308  		return -1;
 309  	}
 310  
 311  	return writecnt;
 312  }
 313  
 314  static int avalonm_receive_pkg(struct cgpu_info *avalonm, struct avalonm_ret *ret)
 315  {
 316  	int err = -1;
 317  	int readcnt;
 318  
 319  	if (unlikely(avalonm->usbinfo.nodev))
 320  		return -1;
 321  
 322  	err = usb_read(avalonm, (char*)ret, AVAM_P_COUNT, &readcnt, C_AVAM_READ);
 323  	if (err || readcnt != AVAM_P_COUNT) {
 324  		applog(LOG_DEBUG, "%s-%d: avalonm_receive_pkg %d, w(%d-%d)!", avalonm->drv->name, avalonm->device_id, err, AVAM_P_COUNT, readcnt);
 325  		return -1;
 326  	}
 327  
 328  	return readcnt;
 329  }
 330  
 331  static int avalonm_xfer_pkg(struct cgpu_info *avalonm, const struct avalonm_pkg *pkg, struct avalonm_ret *ret)
 332  {
 333  	if (sizeof(struct avalonm_pkg) != avalonm_send_pkg(avalonm, pkg))
 334  		return AVAM_SEND_ERROR;
 335  
 336  	if (sizeof(struct avalonm_ret) != avalonm_receive_pkg(avalonm, ret))
 337  		return AVAM_SEND_ERROR;
 338  
 339  	return AVAM_SEND_OK;
 340  }
 341  
 342  static int avalonm_get_frequency(struct cgpu_info *avalonm, uint8_t asic_index)
 343  {
 344  	struct avalonm_info *info = avalonm->device_data;
 345  	struct thr_info *thr = info->thr;
 346  	struct avalonm_pkg send_pkg;
 347  	struct avalonm_ret ar;
 348  	int ret = 0;
 349  
 350  	memset(send_pkg.data, 0, AVAM_P_DATA_LEN);
 351  	avalonm_init_pkg(&send_pkg, AVAM_P_GET_FREQ, 1, 1);
 352  	send_pkg.opt = asic_index;
 353  	ret = avalonm_xfer_pkg(avalonm, &send_pkg, &ar);
 354  	if (ret == AVAM_SEND_OK) {
 355  		ret = decode_pkg(thr, &ar);
 356  	}
 357  
 358  	return ret;
 359  }
 360  
 361  static void avalonm_set_spispeed(struct cgpu_info *avalonm, uint32_t speed)
 362  {
 363  	struct avalonm_pkg send_pkg;
 364  	int tmp;
 365  
 366  	memset(send_pkg.data, 0, AVAM_P_DATA_LEN);
 367  	tmp = speed | 0x80000000;
 368  	tmp = be32toh(tmp);
 369  	memcpy(send_pkg.data, &tmp, 4);
 370  	avalonm_init_pkg(&send_pkg, AVAM_P_SETM, 1, 1);
 371  	avalonm_send_pkg(avalonm, &send_pkg);
 372  }
 373  
 374  static struct cgpu_info *avalonm_detect_one(struct libusb_device *dev, struct usb_find_devices *found)
 375  {
 376  	struct cgpu_info *avalonm = usb_alloc_cgpu(&avalonm_drv, 1);
 377  	struct avalonm_info *info;
 378  	struct avalonm_pkg send_pkg;
 379  	struct avalonm_ret ar;
 380  	int ret, i;
 381  
 382  	if (!usb_init(avalonm, dev, found)) {
 383  		applog(LOG_ERR, "Avalonm failed usb_init");
 384  		avalonm = usb_free_cgpu(avalonm);
 385  		return NULL;
 386  	}
 387  
 388  	usb_buffer_clear(avalonm);
 389  	update_usb_stats(avalonm);
 390  
 391  	/* Cleanup the usb fifo */
 392  	while (avalonm_receive_pkg(avalonm, &ar) != -1);
 393  
 394  	/* We have an Avalonm connected */
 395  	avalonm->threads = 1;
 396  	memset(send_pkg.data, 0, AVAM_P_DATA_LEN);
 397  	avalonm_init_pkg(&send_pkg, AVAM_P_DETECT, 1, 1);
 398  	ret = avalonm_xfer_pkg(avalonm, &send_pkg, &ar);
 399  	if ((ret != AVAM_SEND_OK) || (ar.type != AVAM_P_ACKDETECT)) {
 400  		applog(LOG_DEBUG, "%s-%d: Failed to detect Avalon miner", avalonm->drv->name, avalonm->device_id);
 401  		return NULL;
 402  	}
 403  
 404  	add_cgpu(avalonm);
 405  
 406  	applog(LOG_DEBUG, "%s-%d: Found at %s", avalonm->drv->name, avalonm->device_id,
 407  	       avalonm->device_path);
 408  
 409  	avalonm->device_data = cgcalloc(sizeof(struct avalonm_info), 1);
 410  	info = avalonm->device_data;
 411  	info->thr = NULL;
 412  	memcpy(info->dna, ar.data, AVAM_MM_DNA_LEN);
 413  	memcpy(info->ver, ar.data + AVAM_MM_DNA_LEN, AVAM_MM_VER_LEN);
 414  	info->ver[AVAM_MM_VER_LEN] = '\0';
 415  	memcpy(&info->asic_cnts, ar.data + AVAM_MM_DNA_LEN + AVAM_MM_VER_LEN, 4);
 416  	info->asic_cnts = be32toh(info->asic_cnts);
 417  	if (opt_avalonm_ntime_offset >= info->asic_cnts)
 418  		quit(1, "%s-%d: invalid opt_avalonm_ntime_offset, should 0-%d", avalonm->drv->name, avalonm->device_id, info->asic_cnts - 1);
 419  
 420  	memset(info->set_frequency, 0, sizeof(uint32_t) * info->asic_cnts * 3);
 421  	memset(info->get_frequency, 0, sizeof(uint32_t) * info->asic_cnts * 3);
 422  	for (i = 0; i < info->asic_cnts; i++) {
 423  		info->opt_freq[i][0] = opt_avalonm_freq[0];
 424  		info->opt_freq[i][1] = opt_avalonm_freq[1];
 425  		info->opt_freq[i][2] = opt_avalonm_freq[2];
 426  	}
 427  	info->set_voltage = 0;
 428  	info->opt_voltage = opt_avalonm_voltage;
 429  	info->nonce_cnts = 0;
 430  	info->usbfifo_cnt = 0;
 431  	info->workfifo_cnt = 0;
 432  	info->noncefifo_cnt = 0;
 433  	info->crcerr_cnt = 0;
 434  	info->power_good = 0;
 435  	info->spi_speed = 0;
 436  	info->led_status = 0;
 437  	info->fan_pwm = 0;
 438  	info->get_voltage = 0;
 439  	info->freq_update = 0;
 440  	info->freq_set = 0;
 441  	FLAG_SET(info->freq_set, AVAM_ASIC_ALL);
 442  	memset(info->hw_work, 0, sizeof(int) * info->asic_cnts);
 443  	memset(info->matching_work, 0, sizeof(uint64_t) * info->asic_cnts);
 444  	info->adc[0] = info->adc[1] = info->adc[2] = 0;
 445  
 446  	avalonm_set_spispeed(avalonm, opt_avalonm_spispeed);
 447  	cgtime(&info->elapsed);
 448  	info->lastadj = info->lasttime = info->elapsed;
 449  	info->time_i = 0;
 450  	memset(info->hw_work_i, 0, sizeof(int) * info->asic_cnts * AVAM_DEFAULT_MOV_TIMES);
 451  	return avalonm;
 452  }
 453  
 454  static uint32_t avalonm_get_cpm(uint32_t freq)
 455  {
 456  	int i;
 457  
 458  	for (i = 0; i < (sizeof(g_freq_array) / sizeof(g_freq_array[0]) - 1); i++) {
 459  		if (freq >= g_freq_array[i][0] && freq < g_freq_array[i+1][0])
 460  			return g_freq_array[i][1];
 461  	}
 462  
 463  	/* check if the final freq match */
 464  	if (freq == g_freq_array[i][0])
 465  		return g_freq_array[i][1];
 466  
 467  	/* return the lowest freq if not found */
 468  	return g_freq_array[0][1];
 469  }
 470  
 471  static void avalonm_set_freq(struct cgpu_info *avalonm, uint8_t asic_index, uint32_t freq[])
 472  {
 473  	struct avalonm_info *info = avalonm->device_data;
 474  	struct avalonm_pkg send_pkg;
 475  	uint32_t tmp, i;
 476  	uint8_t index, change = 0;
 477  	uint32_t max_freq = 0;
 478  
 479  	if (asic_index == AVAM_ASIC_ALL) {
 480  		index = 0;
 481  		for (i = 0; i < info->asic_cnts; i++) {
 482  			if ((info->set_frequency[i][0] == freq[0]) &&
 483  				(info->set_frequency[i][1] == freq[1]) &&
 484  				(info->set_frequency[i][2] == freq[2]))
 485  				continue;
 486  
 487  			change = 1;
 488  			info->set_frequency[i][0] = freq[0];
 489  			info->set_frequency[i][1] = freq[1];
 490  			info->set_frequency[i][2] = freq[2];
 491  			FLAG_SET(info->freq_update, AVAM_ASIC_ALL);
 492  		}
 493  	}
 494  
 495  	if (asic_index != AVAM_ASIC_ALL) {
 496  		index = asic_index - 1;
 497  		if (!((info->set_frequency[index][0] == freq[0]) &&
 498  				(info->set_frequency[index][1] == freq[1]) &&
 499  				(info->set_frequency[index][2] == freq[2]))) {
 500  			change = 1;
 501  			info->set_frequency[index][0] = freq[0];
 502  			info->set_frequency[index][1] = freq[1];
 503  			info->set_frequency[index][2] = freq[2];
 504  			FLAG_SET(info->freq_update, asic_index);
 505  		}
 506  	}
 507  
 508  	if (!change)
 509  		return;
 510  
 511  	for (i = 0; i < info->asic_cnts; i++) {
 512  		if (max_freq < info->set_frequency[i][0])
 513  			max_freq = info->set_frequency[i][0];
 514  
 515  		if (max_freq < info->set_frequency[i][1])
 516  			max_freq = info->set_frequency[i][1];
 517  
 518  		if (max_freq < info->set_frequency[i][2])
 519  			max_freq = info->set_frequency[i][2];
 520  	}
 521  
 522  	info->delay_ms = CAL_DELAY(max_freq);
 523  
 524  	memset(send_pkg.data, 0, AVAM_P_DATA_LEN);
 525  	tmp = avalonm_get_cpm(freq[0]);
 526  	tmp = be32toh(tmp);
 527  	memcpy(send_pkg.data, &tmp, 4);
 528  	tmp = avalonm_get_cpm(freq[1]);
 529  	tmp = be32toh(tmp);
 530  	memcpy(send_pkg.data + 4, &tmp, 4);
 531  	tmp = avalonm_get_cpm(freq[2]);
 532  	tmp = be32toh(tmp);
 533  	memcpy(send_pkg.data + 8, &tmp, 4);
 534  
 535  	avalonm_init_pkg(&send_pkg, AVAM_P_SET_FREQ, 1, 1);
 536  	send_pkg.opt = asic_index;
 537  	avalonm_send_pkg(avalonm, &send_pkg);
 538  	applog(LOG_NOTICE, "%s-%d: Avalonm set asic_index %d freq %d,%d,%d",
 539  			avalonm->drv->name, avalonm->device_id,
 540  			asic_index,
 541  			freq[0],
 542  			freq[1],
 543  			freq[2]);
 544  }
 545  
 546  static void avalonm_set_voltage(struct cgpu_info *avalonm)
 547  {
 548  	struct avalonm_info *info = avalonm->device_data;
 549  	struct avalonm_pkg send_pkg;
 550  	uint16_t tmp;
 551  
 552  	if (!info->power_on && (info->set_voltage == info->opt_voltage))
 553  		return;
 554  
 555  	info->set_voltage = info->opt_voltage;
 556  	memset(send_pkg.data, 0, AVAM_P_DATA_LEN);
 557  	/* Use shifter to set voltage */
 558  	tmp = info->set_voltage;
 559  	tmp = encode_voltage(tmp);
 560  	tmp = htobe16(tmp);
 561  	memcpy(send_pkg.data, &tmp, 2);
 562  
 563  	/* Package the data */
 564  	avalonm_init_pkg(&send_pkg, AVAM_P_SET_VOLT, 1, 1);
 565  	avalonm_send_pkg(avalonm, &send_pkg);
 566  	applog(LOG_NOTICE, "%s-%d: Avalonm set volt %d",
 567  	       avalonm->drv->name, avalonm->device_id,
 568  	       info->set_voltage);
 569  
 570  	if (info->power_on)
 571  		cgsleep_ms(1000);
 572  
 573  	info->power_on = 0;
 574  }
 575  
 576  static inline void avalonm_detect(bool __maybe_unused hotplug)
 577  {
 578  	usb_detect(&avalonm_drv, avalonm_detect_one);
 579  }
 580  
 581  static int avalonm_get_reports(void *userdata)
 582  {
 583  	struct cgpu_info *avalonm = (struct cgpu_info *)userdata;
 584  	struct avalonm_info *info = avalonm->device_data;
 585  	struct thr_info *thr = info->thr;
 586  	struct avalonm_pkg send_pkg;
 587  	struct avalonm_ret ar;
 588  	int ret = 0;
 589  
 590  	memset(send_pkg.data, 0, AVAM_P_DATA_LEN);
 591  	avalonm_init_pkg(&send_pkg, AVAM_P_POLLING, 1, 1);
 592  	ret = avalonm_xfer_pkg(avalonm, &send_pkg, &ar);
 593  	if (ret == AVAM_SEND_OK) {
 594  		ret = decode_pkg(thr, &ar);
 595  	}
 596  
 597  	return ret;
 598  }
 599  
 600  static void rev(unsigned char *s, size_t l)
 601  {
 602  	size_t i, j;
 603  	unsigned char t;
 604  
 605  	for (i = 0, j = l - 1; i < j; i++, j--) {
 606  		t = s[i];
 607  		s[i] = s[j];
 608  		s[j] = t;
 609  	}
 610  }
 611  
 612  static int64_t avalonm_scanhash(struct thr_info *thr)
 613  {
 614  	struct cgpu_info *avalonm = thr->cgpu;
 615  	struct avalonm_info *info = avalonm->device_data;
 616  	int64_t hash_count, ms_timeout;
 617  	struct timeval current;
 618  	double device_tdiff;
 619  	uint32_t i, j, tmp;
 620  
 621  	/* Half nonce range */
 622  	ms_timeout = 0x80000000ll / 1000;
 623  
 624  	/* Wait until avalon_send_tasks signals us that it has completed
 625  	 * sending its work or a full nonce range timeout has occurred. We use
 626  	 * cgsems to never miss a wakeup. */
 627  	cgsem_mswait(&info->qsem, ms_timeout);
 628  
 629  	hash_count = info->nonce_cnts++;
 630  	info->nonce_cnts = 0;
 631  
 632  	cgtime(&current);
 633  	device_tdiff = tdiff(&current, &(info->lastadj));
 634  	if (opt_avalonm_autof && (device_tdiff > AVAM_DEFAULT_ADJ_INTERVAL || device_tdiff < 0)) {
 635  		copy_time(&info->lastadj, &current);
 636  
 637  		for (i = 0; i < AVAM_DEFAULT_ASIC_COUNT; i++) {
 638  			tmp = 0;
 639  			for (j = 0; j < AVAM_DEFAULT_MOV_TIMES; j++)
 640  				tmp += info->hw_work_i[i][j];
 641  
 642  			if (tmp > AVAM_HW_HIGH && (info->opt_freq[i][0] > opt_avalonm_freq[0] - (uint32_t)(12 * 12.5))) {
 643  				if ((info->opt_freq[i][0] == AVAM_DEFAULT_FREQUENCY_MIN) &&
 644  						(info->opt_freq[i][1] == AVAM_DEFAULT_FREQUENCY_MIN) &&
 645  						(info->opt_freq[i][2] == AVAM_DEFAULT_FREQUENCY_MIN))
 646  					continue;
 647  
 648  				if (info->opt_freq[i][0] * 10 % 125)
 649  					info->opt_freq[i][0] -= 13;
 650  				else
 651  					info->opt_freq[i][0] -= 12;
 652  
 653  				if (info->opt_freq[i][1] * 10 % 125)
 654  					info->opt_freq[i][1] -= 13;
 655  				else
 656  					info->opt_freq[i][1] -= 12;
 657  
 658  				if (info->opt_freq[i][2] * 10 % 125)
 659  					info->opt_freq[i][2] -= 13;
 660  				else
 661  					info->opt_freq[i][2] -= 12;
 662  
 663  				if (info->opt_freq[i][0] < AVAM_DEFAULT_FREQUENCY_MIN)
 664  					info->opt_freq[i][0] = AVAM_DEFAULT_FREQUENCY_MIN;
 665  
 666  				if (info->opt_freq[i][1] < AVAM_DEFAULT_FREQUENCY_MIN)
 667  					info->opt_freq[i][1] = AVAM_DEFAULT_FREQUENCY_MIN;
 668  
 669  				if (info->opt_freq[i][2] < AVAM_DEFAULT_FREQUENCY_MIN)
 670  					info->opt_freq[i][2] = AVAM_DEFAULT_FREQUENCY_MIN;
 671  
 672  				FLAG_SET(info->freq_set, i + 1);
 673  				applog(LOG_NOTICE, "%s-%d: Automatic decrease [%d] freq to %d,%d,%d",
 674  						avalonm->drv->name, avalonm->device_id, i,
 675  						info->opt_freq[i][0],
 676  						info->opt_freq[i][1],
 677  						info->opt_freq[i][2]);
 678  			}
 679  
 680  			if (tmp < AVAM_HW_LOW && (info->opt_freq[i][0] < opt_avalonm_freq[0] + (uint32_t)(8 * 12.5))) {
 681  				if ((info->opt_freq[i][0] == AVAM_DEFAULT_FREQUENCY_MAX) &&
 682  						(info->opt_freq[i][1] == AVAM_DEFAULT_FREQUENCY_MAX) &&
 683  						(info->opt_freq[i][2] == AVAM_DEFAULT_FREQUENCY_MAX))
 684  					continue;
 685  
 686  				if (info->opt_freq[i][0] * 10 % 125)
 687  					info->opt_freq[i][0] += 12;
 688  				else
 689  					info->opt_freq[i][0] += 13;
 690  
 691  				if (info->opt_freq[i][1] * 10 % 125)
 692  					info->opt_freq[i][1] += 12;
 693  				else
 694  					info->opt_freq[i][1] += 13;
 695  
 696  				if (info->opt_freq[i][2] * 10 % 125)
 697  					info->opt_freq[i][2] += 12;
 698  				else
 699  					info->opt_freq[i][2] += 13;
 700  
 701  				if (info->opt_freq[i][0] > AVAM_DEFAULT_FREQUENCY_MAX)
 702  					info->opt_freq[i][0] = AVAM_DEFAULT_FREQUENCY_MAX;
 703  
 704  				if (info->opt_freq[i][1] > AVAM_DEFAULT_FREQUENCY_MAX)
 705  					info->opt_freq[i][1] = AVAM_DEFAULT_FREQUENCY_MAX;
 706  
 707  				if (info->opt_freq[i][2] > AVAM_DEFAULT_FREQUENCY_MAX)
 708  					info->opt_freq[i][2] = AVAM_DEFAULT_FREQUENCY_MAX;
 709  
 710  				FLAG_SET(info->freq_set, i + 1);
 711  				applog(LOG_NOTICE, "%s-%d: Automatic increase [%d] freq to %d,%d,%d",
 712  						avalonm->drv->name, avalonm->device_id, i,
 713  						info->opt_freq[i][0],
 714  						info->opt_freq[i][1],
 715  						info->opt_freq[i][2]);
 716  			}
 717  		}
 718  	}
 719  
 720  	return hash_count * 0xffffffffull;
 721  }
 722  
 723  static void avalonm_rotate_array(struct cgpu_info *avalonm, struct avalonm_info *info)
 724  {
 725  	mutex_lock(&info->qlock);
 726  	avalonm->queued = 0;
 727  	if (++avalonm->work_array >= AVAM_DEFAULT_ARRAY_SIZE)
 728  		avalonm->work_array = 0;
 729  	mutex_unlock(&info->qlock);
 730  }
 731  
 732  static void *avalonm_process_tasks(void *userdata)
 733  {
 734  	char threadname[16];
 735  
 736  	struct cgpu_info *avalonm = userdata;
 737  	struct avalonm_info *info = avalonm->device_data;
 738  	struct work *work;
 739  	struct avalonm_pkg send_pkg;
 740  
 741  	int start_count, end_count, i, j, k, ret;
 742  	int avalon_get_work_count = info->asic_cnts;
 743  	struct timeval current;
 744  	double device_tdiff;
 745  
 746  	snprintf(threadname, sizeof(threadname), "%d/AvmProc", avalonm->device_id);
 747  	RenameThread(threadname);
 748  
 749  	while (likely(!avalonm->shutdown)) {
 750  		if (unlikely(avalonm->usbinfo.nodev)) {
 751  			applog(LOG_ERR, "%s-%d: Device disappeared, shutting down thread",
 752  			       avalonm->drv->name, avalonm->device_id);
 753  			goto out;
 754  		}
 755  
 756  		cgtime(&current);
 757  		device_tdiff = tdiff(&current, &(info->lasttime));
 758  		if (device_tdiff >= AVAM_DEFAULT_MOV_TIMES || device_tdiff < 0) {
 759  			copy_time(&info->lasttime, &current);
 760  			if (info->time_i++ >= AVAM_DEFAULT_MOV_TIMES)
 761  				info->time_i = 0;
 762  
 763  			for(i = 0; i < AVAM_DEFAULT_ASIC_COUNT; i++)
 764  				info->hw_work_i[i][info->time_i] = 0;
 765  		}
 766  
 767  		/* Give other threads a chance to acquire qlock. */
 768  		i = 0;
 769  		do {
 770  			cgsleep_ms(40);
 771  		} while (!avalonm->shutdown && avalonm->queued < avalon_get_work_count);
 772  
 773  		mutex_lock(&info->qlock);
 774  
 775  		start_count = avalonm->work_array * avalon_get_work_count;
 776  		end_count = start_count + avalon_get_work_count;
 777  
 778  		for (i = start_count, j = 0; i < end_count; i++, j++) {
 779  			work = avalonm->works[i];
 780  			if (likely(j < avalonm->queued && avalonm->works[i] && j < (info->asic_cnts - opt_avalonm_ntime_offset))) {
 781  				/* Configuration */
 782  				avalonm_set_voltage(avalonm);
 783  
 784  				if (FLAG_GET(info->freq_set, 0)) {
 785  					avalonm_set_freq(avalonm, AVAM_ASIC_ALL, info->opt_freq[0]);
 786  					FLAG_CLEAR(info->freq_set, 0);
 787  					cgsleep_ms(20);
 788  				}
 789  
 790  				for (k = 1; k <= info->asic_cnts; k++) {
 791  					if (FLAG_GET(info->freq_set, k)) {
 792  						avalonm_set_freq(avalonm, k, info->opt_freq[k - 1]);
 793  						FLAG_CLEAR(info->freq_set, k);
 794  						cgsleep_ms(20);
 795  					}
 796  				}
 797  
 798  				/* P_WORK part 1: midstate */
 799  				memcpy(send_pkg.data, work->midstate, AVAM_P_DATA_LEN);
 800  				rev((void *)(send_pkg.data), AVAM_P_DATA_LEN);
 801  				avalonm_init_pkg(&send_pkg, AVAM_P_WORK, 1, 2);
 802  				hexdump(send_pkg.data, 32);
 803  				avalonm_send_pkg(avalonm, &send_pkg);
 804  				if (info->freq_update)
 805  					cgsleep_ms(300);
 806  
 807  				/* P_WORK part 2:
 808  				 * id(6)+reserved(2)+ntime(1)+fan(3)+led(4)+reserved(4)+data(12) */
 809  				memset(send_pkg.data, 0, AVAM_P_DATA_LEN);
 810  
 811  				UNPACK32(work->id, send_pkg.data);
 812  
 813  				/* always roll work 0 */
 814  				if (j == 0)
 815  					send_pkg.data[8] = opt_avalonm_ntime_offset;
 816  				else
 817  					send_pkg.data[8] = 0;
 818  
 819  				/* TODO led */
 820  				UNPACK32(0, send_pkg.data + 12);
 821  
 822  				memcpy(send_pkg.data + 20, work->data + 64, 12);
 823  				rev((void *)(send_pkg.data + 20), 12);
 824  				avalonm_init_pkg(&send_pkg, AVAM_P_WORK, 2, 2);
 825  				hexdump(send_pkg.data, 32);
 826  				avalonm_send_pkg(avalonm, &send_pkg);
 827  				if (info->freq_update)
 828  					cgsleep_ms(300);
 829  			}
 830  		}
 831  
 832  		mutex_unlock(&info->qlock);
 833  		avalonm_rotate_array(avalonm, info);
 834  
 835  		cgsem_post(&info->qsem);
 836  
 837  		/* little delay, let asics process more job */
 838  		if (!strncmp(info->ver, "3U", 2))
 839  			cgsleep_ms(400);
 840  
 841  		/* Get result */
 842  		do {
 843  			ret = avalonm_get_reports(avalonm);
 844  			cgsleep_ms(5);
 845  		} while (ret != AVAM_P_STATUS_M);
 846  
 847  		if (info->freq_update) {
 848  			applog(LOG_NOTICE, "%s-%d: avalonm_process_tasks freq change flag %02x",
 849  					avalonm->drv->name, avalonm->device_id,
 850  					info->freq_update);
 851  			if (FLAG_GET(info->freq_update, 0)) {
 852  				avalonm_get_frequency(avalonm, 0);
 853  				FLAG_CLEAR(info->freq_update, 0);
 854  			}
 855  
 856  			for (i = 1; i <= info->asic_cnts; i++) {
 857  				if (FLAG_GET(info->freq_update, i)) {
 858  					avalonm_get_frequency(avalonm, i);
 859  					FLAG_CLEAR(info->freq_update, i);
 860  				}
 861  			}
 862  		}
 863  
 864  		cgsleep_ms(info->delay_ms);
 865  	}
 866  
 867  out:
 868  	return NULL;
 869  }
 870  
 871  static bool avalonm_prepare(struct thr_info *thr)
 872  {
 873  	struct cgpu_info *avalonm = thr->cgpu;
 874  	struct avalonm_info *info = avalonm->device_data;
 875  
 876  	free(avalonm->works);
 877  	avalonm->works = calloc(info->asic_cnts * sizeof(struct work *),
 878  			       AVAM_DEFAULT_ARRAY_SIZE);
 879  	if (!avalonm->works)
 880  		quit(1, "Failed to calloc avalon miner works in avalonm_prepare");
 881  
 882  	info->thr = thr;
 883  	info->delay_ms = CAL_DELAY(AVAM_DEFAULT_FREQUENCY);
 884  	info->power_on = 1;
 885  
 886  	mutex_init(&info->lock);
 887  	mutex_init(&info->qlock);
 888  	cgsem_init(&info->qsem);
 889  
 890  	if (pthread_create(&info->process_thr, NULL, avalonm_process_tasks, (void *)avalonm))
 891  		quit(1, "Failed to create avalonm process_thr");
 892  
 893  	return true;
 894  }
 895  
 896  static void avalonm_shutdown(struct thr_info *thr)
 897  {
 898  	struct cgpu_info *avalonm = thr->cgpu;
 899  	struct avalonm_info *info = avalonm->device_data;
 900  
 901  	pthread_join(info->process_thr, NULL);
 902  
 903  	cgsem_destroy(&info->qsem);
 904  	mutex_destroy(&info->qlock);
 905  	mutex_destroy(&info->lock);
 906  	free(avalonm->works);
 907  	avalonm->works = NULL;
 908  }
 909  
 910  char *set_avalonm_freq(char *arg)
 911  {
 912  	char *colon1, *colon2;
 913  	int val1 = 0, val2 = 0, val3 = 0;
 914  
 915  	if (!(*arg))
 916  		return NULL;
 917  
 918  	colon1 = strchr(arg, ':');
 919  	if (colon1)
 920  		*(colon1++) = '\0';
 921  
 922  	if (*arg) {
 923  		val1 = atoi(arg);
 924  		if (val1 < AVAM_DEFAULT_FREQUENCY_MIN || val1 > AVAM_DEFAULT_FREQUENCY_MAX)
 925  			return "Invalid value1 passed to set_avalonm_freq";
 926  	}
 927  
 928  	if (colon1 && *colon1) {
 929  		colon2 = strchr(colon1, ':');
 930  		if (colon2)
 931  			*(colon2++) = '\0';
 932  
 933  		if (*colon1) {
 934  			val2 = atoi(colon1);
 935  			if (val2 < AVAM_DEFAULT_FREQUENCY_MIN || val2 > AVAM_DEFAULT_FREQUENCY_MAX)
 936  				return "Invalid value2 passed to set_avalonm_freq";
 937  		}
 938  
 939  		if (colon2 && *colon2) {
 940  			val3 = atoi(colon2);
 941  			if (val3 < AVAM_DEFAULT_FREQUENCY_MIN || val3 > AVAM_DEFAULT_FREQUENCY_MAX)
 942  				return "Invalid value3 passed to set_avalonm_freq";
 943  		}
 944  	}
 945  
 946  	if (!val1)
 947  		val3 = val2 = val1 = AVAM_DEFAULT_FREQUENCY;
 948  
 949  	if (!val2)
 950  		val3 = val2 = val1;
 951  
 952  	if (!val3)
 953  		val3 = val2;
 954  
 955  	opt_avalonm_freq[0] = val1;
 956  	opt_avalonm_freq[1] = val2;
 957  	opt_avalonm_freq[2] = val3;
 958  	applog(LOG_NOTICE, "Update all asic frequency to %d",
 959  			(opt_avalonm_freq[0] * 4 + opt_avalonm_freq[1] * 4 + opt_avalonm_freq[2]) / 9);
 960  
 961  	return NULL;
 962  }
 963  
 964  char *set_avalonm_device_freq(struct cgpu_info *avalonm, char *arg)
 965  {
 966  	struct avalonm_info *info = avalonm->device_data;
 967  	char *colon1, *colon2;
 968  	int val1 = 0, val2 = 0, val3 = 0;
 969  	int asic_index = AVAM_ASIC_ALL;
 970  	uint8_t i;
 971  
 972  	if (!(*arg))
 973  		return NULL;
 974  
 975  	colon1 = strchr(arg, '-');
 976  	if (colon1) {
 977  		sscanf(arg, "%d-", &asic_index);
 978  		arg = colon1 + 1;
 979  		if (asic_index < 0 || asic_index > info->asic_cnts) {
 980  			applog(LOG_ERR, "invalid asic index: %d, valid range 0-%d", asic_index, info->asic_cnts);
 981  			return "Invalid asic index to set_avalonm_freq";
 982  		}
 983  	}
 984  
 985  	colon1 = strchr(arg, ':');
 986  	if (colon1)
 987  		*(colon1++) = '\0';
 988  
 989  	if (*arg) {
 990  		val1 = atoi(arg);
 991  		if (val1 < AVAM_DEFAULT_FREQUENCY_MIN || val1 > AVAM_DEFAULT_FREQUENCY_MAX)
 992  			return "Invalid value1 passed to set_avalonm_freq";
 993  	}
 994  
 995  	if (colon1 && *colon1) {
 996  		colon2 = strchr(colon1, ':');
 997  		if (colon2)
 998  			*(colon2++) = '\0';
 999  
1000  		if (*colon1) {
1001  			val2 = atoi(colon1);
1002  			if (val2 < AVAM_DEFAULT_FREQUENCY_MIN || val2 > AVAM_DEFAULT_FREQUENCY_MAX)
1003  				return "Invalid value2 passed to set_avalonm_freq";
1004  		}
1005  
1006  		if (colon2 && *colon2) {
1007  			val3 = atoi(colon2);
1008  			if (val3 < AVAM_DEFAULT_FREQUENCY_MIN || val3 > AVAM_DEFAULT_FREQUENCY_MAX)
1009  				return "Invalid value3 passed to set_avalonm_freq";
1010  		}
1011  	}
1012  
1013  	if (!val1)
1014  		val3 = val2 = val1 = AVAM_DEFAULT_FREQUENCY;
1015  
1016  	if (!val2)
1017  		val3 = val2 = val1;
1018  
1019  	if (!val3)
1020  		val3 = val2;
1021  
1022  	if (!asic_index) {
1023  		for (i = 0; i < info->asic_cnts; i++) {
1024  			info->opt_freq[i][0] = val1;
1025  			info->opt_freq[i][1] = val2;
1026  			info->opt_freq[i][2] = val3;
1027  		}
1028  		FLAG_SET(info->freq_set, AVAM_ASIC_ALL);
1029  		applog(LOG_NOTICE, "Update all asic frequency to %d",
1030  				(val1 * 4 + val2 * 4 + val3) / 9);
1031  	}
1032  
1033  	if (asic_index) {
1034  		info->opt_freq[asic_index - 1][0] = val1;
1035  		info->opt_freq[asic_index - 1][1] = val2;
1036  		info->opt_freq[asic_index - 1][2] = val3;
1037  
1038  		FLAG_SET(info->freq_set, asic_index);
1039  		applog(LOG_NOTICE, "Update asic %d frequency to %d",
1040  				asic_index - 1,
1041  				(val1 * 4 + val2 * 4 + val3) / 9);
1042  	}
1043  
1044  	return NULL;
1045  }
1046  
1047  char *set_avalonm_voltage(char *arg)
1048  {
1049  	int val, ret;
1050  
1051  	ret = sscanf(arg, "%d", &val);
1052  	if (ret < 1)
1053  		return "No values passed to avalonm-voltage";
1054  
1055  	if (val < AVAM_DEFAULT_VOLTAGE_MIN || val > AVAM_DEFAULT_VOLTAGE_MAX)
1056  		return "Invalid value passed to avalonm-voltage";
1057  
1058  	opt_avalonm_voltage = val;
1059  
1060  	return NULL;
1061  }
1062  
1063  char *set_avalonm_device_voltage(struct cgpu_info *avalonm, char *arg)
1064  {
1065  	struct avalonm_info *info = avalonm->device_data;
1066  	int val, ret;
1067  
1068  	ret = sscanf(arg, "%d", &val);
1069  	if (ret < 1)
1070  		return "No values passed to avalonm-voltage";
1071  
1072  	if (val < AVAM_DEFAULT_VOLTAGE_MIN || val > AVAM_DEFAULT_VOLTAGE_MAX)
1073  		return "Invalid value passed to avalonm-voltage";
1074  
1075  	info->opt_voltage = val;
1076  	applog(LOG_NOTICE, "%s-%d: Update voltage to %d",
1077  			avalonm->drv->name, avalonm->device_id, info->opt_voltage);
1078  
1079  	return NULL;
1080  }
1081  
1082  static char *avalonm_set_device(struct cgpu_info *avalonm, char *option, char *setting, char *replybuf)
1083  {
1084  	if (strcasecmp(option, "help") == 0) {
1085  		sprintf(replybuf, "frequency|voltage");
1086  		return replybuf;
1087  	}
1088  
1089  	if (strcasecmp(option, "frequency") == 0) {
1090  		if (!setting || !*setting) {
1091  			sprintf(replybuf, "missing frequency value");
1092  			return replybuf;
1093  		}
1094  
1095  		if (set_avalonm_device_freq(avalonm, setting)) {
1096  			sprintf(replybuf, "invalid frequency value, valid range %d-%d",
1097  				AVAM_DEFAULT_FREQUENCY_MIN, AVAM_DEFAULT_FREQUENCY_MAX);
1098  			return replybuf;
1099  		}
1100  
1101  		return NULL;
1102  	}
1103  
1104  	if (strcasecmp(option, "voltage") == 0) {
1105  		if (!setting || !*setting) {
1106  			sprintf(replybuf, "missing voltage value");
1107  			return replybuf;
1108  		}
1109  
1110  		if (set_avalonm_device_voltage(avalonm, setting)) {
1111  			sprintf(replybuf, "invalid voltage value, valid range %d-%d",
1112  					AVAM_DEFAULT_VOLTAGE_MIN, AVAM_DEFAULT_VOLTAGE_MAX);
1113  			return replybuf;
1114  		}
1115  
1116  		return NULL;
1117  	}
1118  
1119  	sprintf(replybuf, "Unknown option: %s", option);
1120  	return replybuf;
1121  }
1122  
1123  #define STATBUFLEN 512
1124  static struct api_data *avalonm_api_stats(struct cgpu_info *cgpu)
1125  {
1126  	struct api_data *root = NULL;
1127  	struct avalonm_info *info = cgpu->device_data;
1128  	char buf[256];
1129  	char statbuf[STATBUFLEN];
1130  	uint32_t i, j, tmp;
1131  	struct timeval now;
1132  
1133  	memset(statbuf, 0, STATBUFLEN);
1134  
1135  	sprintf(buf, "VER[%s]", info->ver);
1136  	strcat(statbuf, buf);
1137  
1138  	sprintf(buf, " DNA[%02x%02x%02x%02x%02x%02x%02x%02x]",
1139  				info->dna[0],
1140  				info->dna[1],
1141  				info->dna[2],
1142  				info->dna[3],
1143  				info->dna[4],
1144  				info->dna[5],
1145  				info->dna[6],
1146  				info->dna[7]);
1147  	strcat(statbuf, buf);
1148  
1149  	cgtime(&now);
1150  	sprintf(buf, " Elapsed[%.0f]", tdiff(&now, &(info->elapsed)));
1151  	strcat(statbuf, buf);
1152  
1153  	sprintf(buf, " Chips[%d]", info->asic_cnts);
1154  	strcat(statbuf, buf);
1155  
1156  	sprintf(buf, " Crc[%d]", info->crcerr_cnt);
1157  	strcat(statbuf, buf);
1158  
1159  	sprintf(buf, " Speed[%d]", info->spi_speed);
1160  	strcat(statbuf, buf);
1161  
1162  	if (!strncmp(info->ver, "3U", 2))
1163  		sprintf(buf, " Vol[%.2f]", (float)info->get_voltage);
1164  	else
1165  		sprintf(buf, " Vol[%.4f]", (float)info->get_voltage / 10000);
1166  	strcat(statbuf, buf);
1167  
1168  	if (!strncmp(info->ver, "3U", 2))
1169  		sprintf(buf, " V_CORE[%.2f]", convert_voltage(info->adc[0], 1));
1170  	else
1171  		sprintf(buf, " V12[%.2f]", convert_voltage(info->adc[0], (10 / 110)));
1172  	strcat(statbuf, buf);
1173  
1174  	if (!strncmp(info->ver, "3U", 2))
1175  		sprintf(buf, " T[%d]", info->adc[1]);
1176  	else
1177  		sprintf(buf, " TC[%.2f]", convert_temp(info->adc[1]));
1178  	strcat(statbuf, buf);
1179  
1180  	if (!strncmp(info->ver, "3U", 2)) {
1181  		sprintf(buf, " V0_9[%.2f]", convert_voltage(info->adc[2] & 0xffff, 1));
1182  		strcat(statbuf, buf);
1183  		sprintf(buf, " V1_8[%.2f]", convert_voltage((info->adc[2] >> 16) & 0xffff, 1));
1184  	} else
1185  		sprintf(buf, " TF[%.2f]", convert_temp(info->adc[2]));
1186  	strcat(statbuf, buf);
1187  
1188  	if (!strncmp(info->ver, "3U", 2)) {
1189  		sprintf(buf, " Freq[%d]", info->get_frequency[0][0]);
1190  		strcat(statbuf, buf);
1191  	} else {
1192  		strcat(statbuf, " Freq[");
1193  		for (i = 0; i < info->asic_cnts; i++) {
1194  			sprintf(buf, "%d %d %d ",
1195  					info->get_frequency[i][0],
1196  					info->get_frequency[i][1],
1197  					info->get_frequency[i][2]);
1198  			strcat(statbuf, buf);
1199  		}
1200  		statbuf[strlen(statbuf) - 1] = ']';
1201  	}
1202  
1203  	strcat(statbuf, " HW[");
1204  	for (i = 0; i < info->asic_cnts; i++) {
1205  		sprintf(buf, "%d ", info->hw_work[i]);
1206  		strcat(statbuf, buf);
1207  	}
1208  	statbuf[strlen(statbuf) - 1] = ']';
1209  
1210  	/* simple moving the sum of hardware error */
1211  	strcat(statbuf, " SHW[");
1212  	for (i = 0; i < info->asic_cnts; i++) {
1213  		tmp = 0;
1214  		for (j = 0; j < AVAM_DEFAULT_MOV_TIMES; j++)
1215  			tmp += info->hw_work_i[i][j];
1216  
1217  		sprintf(buf, "%d ", tmp);
1218  		strcat(statbuf, buf);
1219  	}
1220  	statbuf[strlen(statbuf) - 1] = ']';
1221  
1222  	strcat(statbuf, " MW[");
1223  	for (i = 0; i < info->asic_cnts; i++) {
1224  		sprintf(buf, "%ld ", info->matching_work[i]);
1225  		strcat(statbuf, buf);
1226  	}
1227  	statbuf[strlen(statbuf) - 1] = ']';
1228  
1229  	sprintf(buf, " Led[%d]", info->led_status);
1230  	strcat(statbuf, buf);
1231  
1232  	sprintf(buf, " PG[%d]", info->power_good);
1233  	strcat(statbuf, buf);
1234  
1235  	root = api_add_string(root, "AVAM Dev", statbuf, true);
1236  
1237  	sprintf(buf, "%d %d %d",
1238  			info->usbfifo_cnt,
1239  			info->workfifo_cnt,
1240  			info->noncefifo_cnt);
1241  
1242  	root = api_add_string(root, "AVAM Fifo", buf, true);
1243  	root = api_add_uint8(root, "AVAM ntime", &opt_avalonm_ntime_offset, true);
1244  	root = api_add_bool(root, "Automatic Frequency", &opt_avalonm_autof, true);
1245  	return root;
1246  }
1247  
1248  static void avalonm_statline_before(char *buf, size_t bufsiz, struct cgpu_info *avalonm)
1249  {
1250  	struct avalonm_info *info = avalonm->device_data;
1251  	int frequency;
1252  
1253  	if (!strncmp(info->ver, "3U", 2))
1254  		tailsprintf(buf, bufsiz, "%4dMhz %.2fV", info->get_frequency[0][0], (float)info->get_voltage);
1255  	else {
1256  		frequency = (info->set_frequency[0][0] * 4 + info->set_frequency[0][1] * 4 + info->set_frequency[0][2]) / 9;
1257  		tailsprintf(buf, bufsiz, "%4dMhz %.4fV", frequency, (float)info->get_voltage / 10000);
1258  	}
1259  }
1260  
1261  /* We use a replacement algorithm to only remove references to work done from
1262   * the buffer when we need the extra space for new work. */
1263  static bool avalonm_fill(struct cgpu_info *avalonm)
1264  {
1265  	struct avalonm_info *info = avalonm->device_data;
1266  	int subid, slot, ac;
1267  	struct work *work;
1268  	bool ret = true;
1269  
1270  	ac = info->asic_cnts;
1271  	mutex_lock(&info->qlock);
1272  	if (avalonm->queued >= ac)
1273  		goto out_unlock;
1274  	work = get_queued(avalonm);
1275  	if (unlikely(!work)) {
1276  		ret = false;
1277  		goto out_unlock;
1278  	}
1279  	subid = avalonm->queued++;
1280  	work->subid = subid;
1281  	slot = avalonm->work_array * ac + subid;
1282  	if (likely(avalonm->works[slot]))
1283  		work_completed(avalonm, avalonm->works[slot]);
1284  	avalonm->works[slot] = work;
1285  	if (avalonm->queued < ac)
1286  		ret = false;
1287  out_unlock:
1288  	mutex_unlock(&info->qlock);
1289  
1290  	return ret;
1291  }
1292  
1293  static void avalonm_flush_work(struct cgpu_info *avalonm)
1294  {
1295  
1296  	struct avalonm_info *info = avalonm->device_data;
1297  
1298  	/* Will overwrite any work queued. Do this unlocked since it's just
1299  	 * changing a single non-critical value and prevents deadlocks */
1300  	avalonm->queued = 0;
1301  
1302  	/* Signal main loop we need more work */
1303  	cgsem_post(&info->qsem);
1304  }
1305  
1306  struct device_drv avalonm_drv = {
1307  	.drv_id = DRIVER_avalonm,
1308  	.dname = "avalonm",
1309  	.name = "AVM",
1310  	.set_device = avalonm_set_device,
1311  	.get_api_stats = avalonm_api_stats,
1312  	.get_statline_before = avalonm_statline_before,
1313  	.drv_detect = avalonm_detect,
1314  	.thread_prepare = avalonm_prepare,
1315  
1316  	.hash_work = hash_queued_work,
1317  	.scanwork = avalonm_scanhash,
1318  	.queue_full = avalonm_fill,
1319  	.flush_work = avalonm_flush_work,
1320  
1321  	.thread_shutdown = avalonm_shutdown,
1322  };