Browse Source

Icarus driver working with Linux and Windows

nfactor-troky
Kano 13 years ago
parent
commit
80f4fbbdeb
  1. 199
      driver-icarus.c

199
driver-icarus.c

@ -1,6 +1,7 @@
/* /*
* Copyright 2012 Luke Dashjr * Copyright 2012 Luke Dashjr
* Copyright 2012 Xiangfu <xiangfu@openmobilefree.com> * Copyright 2012 Xiangfu <xiangfu@openmobilefree.com>
* Copyright 2012 Andrew Smith
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free * under the terms of the GNU General Public License as published by the Free
@ -45,18 +46,38 @@
#else #else
#include <windows.h> #include <windows.h>
#include <io.h> #include <io.h>
#endif
#ifdef HAVE_SYS_EPOLL_H #ifndef timersub
#include <sys/epoll.h> #define timersub(a, b, result) \
#define HAVE_EPOLL do { \
(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
(result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
if ((result)->tv_usec < 0) { \
--(result)->tv_sec; \
(result)->tv_usec += 1000000; \
} \
} while (0)
#endif
#endif #endif
#include "elist.h" #include "elist.h"
#include "miner.h" #include "miner.h"
// 8 second timeout // This is valid for a standard Icarus Rev 3
#define ICARUS_READ_FAULT_DECISECONDS (1) // Assuming each hash pair takes 5.26ns then a whole nonce range would take 11.3s
#define ICARUS_READ_FAULT_COUNT (80) // Giving a little leaway 11.1s would be best
//#define ICARUS_READ_COUNT_DEFAULT 111
#define ICARUS_READ_COUNT_DEFAULT 80
// 2 x 11.1 / (5.26 x 10^-9)
//#define ESTIMATE_HASHES 0xFB90365E
// This is the 8s value but causes hash rate loss
//#define ESTIMATE_HASHES 0xB54E9147
// TODO: determine why returning any other value when no nonce is found
// causes hash rate loss
#define ESTIMATE_HASHES 0xffffffff
struct device_api icarus_api; struct device_api icarus_api;
@ -93,7 +114,7 @@ static int icarus_open(const char *devpath)
ISTRIP | INLCR | IGNCR | ICRNL | IXON); ISTRIP | INLCR | IGNCR | ICRNL | IXON);
my_termios.c_oflag &= ~OPOST; my_termios.c_oflag &= ~OPOST;
my_termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); my_termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
my_termios.c_cc[VTIME] = ICARUS_READ_FAULT_DECISECONDS; my_termios.c_cc[VTIME] = 1; /* block 0.1 second */
my_termios.c_cc[VMIN] = 0; my_termios.c_cc[VMIN] = 0;
tcsetattr(serialfd, TCSANOW, &my_termios); tcsetattr(serialfd, TCSANOW, &my_termios);
@ -102,43 +123,40 @@ static int icarus_open(const char *devpath)
return serialfd; return serialfd;
#else #else
COMMCONFIG comCfg;
HANDLE hSerial = CreateFile(devpath, GENERIC_READ | GENERIC_WRITE, 0, HANDLE hSerial = CreateFile(devpath, GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_EXISTING, 0, NULL); NULL, OPEN_EXISTING, 0, NULL);
if (unlikely(hSerial == INVALID_HANDLE_VALUE)) if (unlikely(hSerial == INVALID_HANDLE_VALUE))
return -1; return -1;
COMMTIMEOUTS cto = {1000, 0, 1000, 0, 1000}; // thanks to af_newbie for pointers about this
memset(&comCfg, 0 , sizeof(comCfg));
comCfg.dwSize = sizeof(COMMCONFIG);
comCfg.wVersion = 1;
comCfg.dcb.DCBlength = sizeof(DCB);
comCfg.dcb.BaudRate = 115200;
comCfg.dcb.fBinary = 1;
comCfg.dcb.fDtrControl = DTR_CONTROL_ENABLE;
comCfg.dcb.fRtsControl = RTS_CONTROL_ENABLE;
comCfg.dcb.ByteSize = 8;
SetCommConfig(hSerial, &comCfg, sizeof(comCfg));
// block 0.1 second
COMMTIMEOUTS cto = {100, 0, 100, 0, 100};
SetCommTimeouts(hSerial, &cto); SetCommTimeouts(hSerial, &cto);
return _open_osfhandle((LONG)hSerial, 0); return _open_osfhandle((LONG)hSerial, 0);
#endif #endif
} }
static int icarus_gets(unsigned char *buf, size_t bufLen, int fd, volatile unsigned long *wr) static int icarus_gets(unsigned char *buf, size_t bufLen, int fd, int thr_id, int read_count)
{ {
ssize_t ret = 0; ssize_t ret = 0;
int rc = 0; int rc = 0;
int epollfd = -1;
#ifdef HAVE_EPOLL
struct epoll_event ev, evr;
epollfd = epoll_create(1);
if (epollfd != -1) {
ev.events = EPOLLIN;
ev.data.fd = fd;
if (-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev)) {
close(epollfd);
epollfd = -1;
}
}
#endif
while (bufLen) { while (bufLen) {
#ifdef HAVE_EPOLL
if (epollfd != -1 && epoll_wait(epollfd, &evr, 1, ICARUS_READ_FAULT_DECISECONDS * 100) != 1)
ret = 0;
else
#endif
ret = read(fd, buf, 1); ret = read(fd, buf, 1);
if (ret == 1) { if (ret == 1) {
bufLen--; bufLen--;
@ -147,20 +165,19 @@ static int icarus_gets(unsigned char *buf, size_t bufLen, int fd, volatile unsig
} }
rc++; rc++;
if (*wr) if (rc >= read_count) {
applog(LOG_DEBUG,
"Icarus Read: No data in %.2f seconds", (float)(rc/10.0f));
return 1; return 1;
if (rc == ICARUS_READ_FAULT_COUNT) { }
if (epollfd != -1)
close(epollfd); if (thr_id >= 0 && work_restart[thr_id].restart) {
applog(LOG_DEBUG, applog(LOG_DEBUG,
"Icarus Read: No data in %d seconds", rc * ICARUS_READ_FAULT_DECISECONDS / 10); "Icarus Read: Work restart at %.2f seconds", (float)(rc/10.0f));
return 1; return 1;
} }
} }
if (epollfd != -1)
close(epollfd);
return 0; return 0;
} }
@ -179,14 +196,20 @@ static int icarus_write(int fd, const void *buf, size_t bufLen)
static bool icarus_detect_one(const char *devpath) static bool icarus_detect_one(const char *devpath)
{ {
struct timeval tv1, tv2;
int fd; int fd;
// Block 171874 nonce = (0xa2870100) = 0x000187a2
// N.B. golden_ob MUST take less time to calculate
// than the timeout set in icarus_open()
// This one takes ~0.53ms on Rev3 Icarus
const char golden_ob[] = const char golden_ob[] =
"2db907f9cb4eb938ded904f4832c4331" "4679ba4ec99876bf4bfe086082b40025"
"0380e3aeb54364057e7fec5157bfc533" "4df6c356451471139a3afa71e48f544a"
"00000000000000000000000080000000" "00000000000000000000000000000000"
"00000000a58e091ac342724e7c3dc346"; "0000000087320b1a1426674f2fa722ce";
const char golden_nonce[] = "063c5e01";
const char golden_nonce[] = "000187a2";
unsigned char ob_bin[64], nonce_bin[4]; unsigned char ob_bin[64], nonce_bin[4];
char *nonce_hex; char *nonce_hex;
@ -202,10 +225,11 @@ static bool icarus_detect_one(const char *devpath)
hex2bin(ob_bin, golden_ob, sizeof(ob_bin)); hex2bin(ob_bin, golden_ob, sizeof(ob_bin));
icarus_write(fd, ob_bin, sizeof(ob_bin)); icarus_write(fd, ob_bin, sizeof(ob_bin));
gettimeofday(&tv1, NULL);
memset(nonce_bin, 0, sizeof(nonce_bin)); memset(nonce_bin, 0, sizeof(nonce_bin));
volatile unsigned long wr = 0; icarus_gets(nonce_bin, sizeof(nonce_bin), fd, -1, 1);
icarus_gets(nonce_bin, sizeof(nonce_bin), fd, &wr); gettimeofday(&tv2, NULL);
icarus_close(fd); icarus_close(fd);
@ -219,6 +243,10 @@ static bool icarus_detect_one(const char *devpath)
free(nonce_hex); free(nonce_hex);
return false; return false;
} }
applog(LOG_DEBUG,
"Icarus Detect: "
"Test succeeded at %s: got %s",
devpath, nonce_hex);
free(nonce_hex); free(nonce_hex);
} else } else
return false; return false;
@ -227,9 +255,10 @@ static bool icarus_detect_one(const char *devpath)
struct cgpu_info *icarus; struct cgpu_info *icarus;
icarus = calloc(1, sizeof(struct cgpu_info)); icarus = calloc(1, sizeof(struct cgpu_info));
icarus->api = &icarus_api; icarus->api = &icarus_api;
icarus->device_id = total_devices;
icarus->device_path = strdup(devpath); icarus->device_path = strdup(devpath);
icarus->threads = 1; icarus->threads = 1;
add_cgpu(icarus); devices[total_devices++] = icarus;
applog(LOG_INFO, "Found Icarus at %s, mark as %d", applog(LOG_INFO, "Found Icarus at %s, mark as %d",
devpath, icarus->device_id); devpath, icarus->device_id);
@ -246,8 +275,6 @@ static void icarus_detect()
s = iter->string; s = iter->string;
if (!strncmp("icarus:", iter->string, 7)) if (!strncmp("icarus:", iter->string, 7))
s += 7; s += 7;
if (!strcmp(s, "auto") || !strcmp(s, "noauto"))
continue;
if (icarus_detect_one(s)) if (icarus_detect_one(s))
string_elist_del(iter); string_elist_del(iter);
} }
@ -259,6 +286,15 @@ static bool icarus_prepare(struct thr_info *thr)
struct timeval now; struct timeval now;
int fd = icarus_open(icarus->device_path);
if (unlikely(-1 == fd)) {
applog(LOG_ERR, "Failed to open Icarus on %s",
icarus->device_path);
return false;
}
icarus->device_fd = fd;
applog(LOG_INFO, "Opened Icarus on %s", icarus->device_path); applog(LOG_INFO, "Opened Icarus on %s", icarus->device_path);
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
get_datestamp(icarus->init, &now); get_datestamp(icarus->init, &now);
@ -269,8 +305,7 @@ static bool icarus_prepare(struct thr_info *thr)
static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work, static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
__maybe_unused uint64_t max_nonce) __maybe_unused uint64_t max_nonce)
{ {
volatile unsigned long *wr = &work_restart[thr->id].restart; const int thr_id = thr->id;
struct cgpu_info *icarus; struct cgpu_info *icarus;
int fd; int fd;
int ret; int ret;
@ -279,16 +314,10 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
char *ob_hex, *nonce_hex; char *ob_hex, *nonce_hex;
uint32_t nonce; uint32_t nonce;
uint32_t hash_count; uint32_t hash_count;
struct timeval tv_start, tv_end, diff; struct timeval tv1, tv2, elapsed;
icarus = thr->cgpu; icarus = thr->cgpu;
fd = icarus->device_fd;
fd = icarus_open(icarus->device_path);
if (unlikely(-1 == fd)) {
applog(LOG_ERR, "Failed to open Icarus on %s",
icarus->device_path);
return 0;
}
memset(ob_bin, 0, sizeof(ob_bin)); memset(ob_bin, 0, sizeof(ob_bin));
memcpy(ob_bin, work->midstate, 32); memcpy(ob_bin, work->midstate, 32);
@ -298,55 +327,50 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
#ifndef WIN32 #ifndef WIN32
tcflush(fd, TCOFLUSH); tcflush(fd, TCOFLUSH);
#endif #endif
gettimeofday(&tv_start, NULL);
ret = icarus_write(fd, ob_bin, sizeof(ob_bin)); ret = icarus_write(fd, ob_bin, sizeof(ob_bin));
if (ret) { gettimeofday(&tv1, NULL);
icarus_close(fd); if (ret)
return 0; /* This should never happen */ return 0; /* This should never happen */
}
ob_hex = bin2hex(ob_bin, sizeof(ob_bin)); ob_hex = bin2hex(ob_bin, sizeof(ob_bin));
if (ob_hex) { if (ob_hex) {
applog(LOG_DEBUG, "Icarus %s send: %s", applog(LOG_DEBUG, "Icarus %d sent: %s",
icarus->device_id, ob_hex); icarus->device_id, ob_hex);
free(ob_hex); free(ob_hex);
} }
/* Icarus will return 8 bytes nonces or nothing */ /* Icarus will return 8 bytes nonces or nothing */
memset(nonce_bin, 0, sizeof(nonce_bin)); memset(nonce_bin, 0, sizeof(nonce_bin));
ret = icarus_gets(nonce_bin, sizeof(nonce_bin), fd, wr); ret = icarus_gets(nonce_bin, sizeof(nonce_bin), fd, thr_id,
ICARUS_READ_COUNT_DEFAULT);
gettimeofday(&tv_end, NULL); gettimeofday(&tv2, NULL);
timeval_subtract(&diff, &tv_end, &tv_start);
nonce_hex = bin2hex(nonce_bin, sizeof(nonce_bin));
if (nonce_hex) {
applog(LOG_DEBUG, "Icarus %d returned (in %d.%06d seconds): %s",
icarus->device_id, diff.tv_sec, diff.tv_usec, nonce_hex);
free(nonce_hex);
}
memcpy((char *)&nonce, nonce_bin, sizeof(nonce_bin)); memcpy((char *)&nonce, nonce_bin, sizeof(nonce_bin));
work->blk.nonce = 0xffffffff; // aborted before becoming idle, get new work
icarus_close(fd); if (nonce == 0 && ret) {
timersub(&tv2, &tv1, &elapsed);
if (nonce == 0 && ret) { applog(LOG_DEBUG, "Icarus %d no nonce = 0x%08x hashes (%ld.%06lds)",
if (unlikely(diff.tv_sec > 12 || (diff.tv_sec == 11 && diff.tv_usec > 300067))) icarus->device_id, ESTIMATE_HASHES, elapsed.tv_sec, elapsed.tv_usec);
return 0xffffffff; return ESTIMATE_HASHES;
// Approximately how much of the nonce Icarus scans in 1 second...
// 0x16a7a561 would be if it was exactly 380 MH/s
// 0x168b7b4b was the average over a 201-sample period based on time to find actual shares
return (0x168b7b4b * diff.tv_sec) + (0x17a * diff.tv_usec);
} }
#ifndef __BIG_ENDIAN__ #ifndef __BIG_ENDIAN__
nonce = swab32(nonce); nonce = swab32(nonce);
#endif #endif
work->blk.nonce = 0xffffffff;
submit_nonce(thr, work, nonce); submit_nonce(thr, work, nonce);
timersub(&tv2, &tv1, &elapsed);
nonce_hex = bin2hex(nonce_bin, sizeof(nonce_bin));
if (nonce_hex) {
applog(LOG_DEBUG, "Icarus %d returned (elapsed %ld.%06ld seconds): %s",
icarus->device_id, elapsed.tv_sec, elapsed.tv_usec, nonce_hex);
free(nonce_hex);
}
hash_count = (nonce & 0x7fffffff); hash_count = (nonce & 0x7fffffff);
if (hash_count == 0) if (hash_count == 0)
hash_count = 2; hash_count = 2;
@ -357,7 +381,8 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
hash_count <<= 1; hash_count <<= 1;
} }
applog(LOG_DEBUG, "0x%x hashes in %d.%06d seconds", hash_count, diff.tv_sec, diff.tv_usec); applog(LOG_DEBUG, "Icarus %d nonce = 0x%08x = 0x%08x hashes (%ld.%06lds)",
icarus->device_id, nonce, hash_count, elapsed.tv_sec, elapsed.tv_usec);
return hash_count; return hash_count;
} }
@ -372,6 +397,8 @@ static void icarus_shutdown(struct thr_info *thr)
if (icarus->device_path) if (icarus->device_path)
free(icarus->device_path); free(icarus->device_path);
close(icarus->device_fd);
devices[icarus->device_id] = NULL; devices[icarus->device_id] = NULL;
free(icarus); free(icarus);

Loading…
Cancel
Save