| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456 |
- /*
- * Copyright 2014 Luke Dashjr
- * Copyright 2014 Nate Woolls
- * Copyright 2014 GridSeed Team
- *
- * 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
- * Software Foundation; either version 3 of the License, or (at your option)
- * any later version. See COPYING for more details.
- */
- #include "config.h"
- #include <stdbool.h>
- #include "deviceapi.h"
- #include "lowlevel.h"
- #include "lowl-vcom.h"
- #include "gc3355.h"
- #define GRIDSEED_DEFAULT_FREQUENCY 600
- #define GRIDSEED_MAX_QUEUED 10
- BFG_REGISTER_DRIVER(gridseed_drv)
- /*
- * helper functions
- */
- static
- struct cgpu_info *gridseed_alloc_device(const char *path, struct device_drv *driver, struct gc3355_orb_info *info)
- {
- struct cgpu_info *device = calloc(1, sizeof(struct cgpu_info));
- if (unlikely(!device))
- quit(1, "Failed to malloc cgpu_info");
-
- device->drv = driver;
- device->device_path = strdup(path);
- device->device_fd = -1;
- device->threads = 1;
- device->procs = GC3355_ORB_DEFAULT_CHIPS;
- device->device_data = info;
-
- return device;
- }
- static
- struct gc3355_orb_info *gridseed_alloc_info()
- {
- struct gc3355_orb_info *info = calloc(1, sizeof(struct gc3355_orb_info));
- if (unlikely(!info))
- quit(1, "Failed to malloc gc3355_orb_info");
-
- info->freq = GRIDSEED_DEFAULT_FREQUENCY;
-
- return info;
- }
- static
- void gridseed_empty_work(int fd)
- {
- unsigned char buf[GC3355_READ_SIZE];
- gc3355_read(fd, (char *)buf, GC3355_READ_SIZE);
- }
- /*
- * device detection
- */
- static
- bool gridseed_detect_custom(const char *path, struct device_drv *driver, struct gc3355_orb_info *info)
- {
- int fd = gc3355_open(path);
- if(fd < 0)
- return false;
-
- gridseed_empty_work(fd);
-
- uint32_t fw_version = gc3355_get_firmware_version(fd);
-
- if (fw_version == -1)
- {
- applog(LOG_ERR, "%s: Invalid detect response from %s", gridseed_drv.dname, path);
- gc3355_close(fd);
- return false;
- }
-
- if (serial_claim_v(path, driver))
- return false;
-
- struct cgpu_info *device = gridseed_alloc_device(path, driver, info);
-
- if (!add_cgpu(device))
- return false;
-
- device->device_fd = fd;
-
- gc3355_init_usborb(device->device_fd, info->freq, false, false);
-
- applog(LOG_INFO, "Found %"PRIpreprv" at %s", device->proc_repr, path);
- applog(LOG_DEBUG, "%"PRIpreprv": Init: firmware=%d", device->proc_repr, fw_version);
-
- return true;
- }
- static
- bool gridseed_detect_one(const char *path)
- {
- struct gc3355_orb_info *info = gridseed_alloc_info();
-
- if (!gridseed_detect_custom(path, &gridseed_drv, info))
- {
- free(info);
- return false;
- }
- return true;
- }
- static
- bool gridseed_lowl_probe(const struct lowlevel_device_info * const info)
- {
- return vcom_lowl_probe_wrapper(info, gridseed_detect_one);
- }
- /*
- * setup & shutdown
- */
- static
- bool gridseed_thread_prepare(struct thr_info *thr)
- {
- thr->cgpu_data = calloc(1, sizeof(*thr->cgpu_data));
-
- if (opt_scrypt)
- {
- struct cgpu_info *device = thr->cgpu;
- device->min_nonce_diff = 1./0x10000;
- }
-
- return true;
- }
- static
- bool gridseed_set_queue_full(const struct cgpu_info * const device, int needwork);
- static
- bool gridseed_thread_init(struct thr_info *master_thr)
- {
- struct cgpu_info * const device = master_thr->cgpu, *proc;
- gridseed_set_queue_full(device, 0);
- timer_set_now(&master_thr->tv_poll);
-
- // kick off queue minerloop
- gridseed_set_queue_full(device, device->procs * 2);
-
- return true;
- }
- static
- void gridseed_thread_shutdown(struct thr_info *thr)
- {
- struct cgpu_info *device = thr->cgpu;
- gc3355_close(device->device_fd);
-
- free(thr->cgpu_data);
- }
- static
- void gridseed_reinit_device(struct cgpu_info * const proc)
- {
- timer_set_now(&proc->thr[0]->tv_poll);
- }
- /*
- * queued mining loop
- */
- static
- bool gridseed_set_queue_full(const struct cgpu_info * const device, int needwork)
- {
- struct gc3355_orb_info * const info = device->device_data;
- struct thr_info * const master_thr = device->thr[0];
-
- if (needwork != -1)
- info->needwork = needwork;
-
- const bool full = (device->device_fd == -1 || !info->needwork);
-
- if (full == master_thr->queue_full)
- return full;
-
- for (const struct cgpu_info *proc = device; proc; proc = proc->next_proc)
- {
- struct thr_info * const thr = proc->thr[0];
- thr->queue_full = full;
- }
-
- return full;
- }
- static
- bool gridseed_send_work(const struct cgpu_info * const device, struct work *work)
- {
- struct gc3355_orb_info * const info = device->device_data;
- int work_size = opt_scrypt ? 156 : 52;
- unsigned char cmd[work_size];
-
- if (opt_scrypt)
- {
- gc3355_scrypt_reset(device->device_fd);
- gc3355_scrypt_prepare_work(cmd, work);
- }
- else
- gc3355_sha2_prepare_work(cmd, work, true);
-
- // send work
- if (sizeof(cmd) != gc3355_write(device->device_fd, cmd, sizeof(cmd)))
- {
- applog(LOG_ERR, "%s: Failed to send work", device->dev_repr);
- return false;
- }
-
- return true;
- }
- static
- void gridseed_prune_queue(const struct cgpu_info * const device, struct work *work)
- {
- struct thr_info * const master_thr = device->thr[0];
-
- // prune queue
- int prunequeue = HASH_COUNT(master_thr->work_list) - GRIDSEED_MAX_QUEUED;
- if (prunequeue > 0)
- {
- struct work *tmp;
- applog(LOG_DEBUG, "%s: Pruning %d old work item%s",
- device->dev_repr, prunequeue, prunequeue == 1 ? "" : "s");
- HASH_ITER(hh, master_thr->work_list, work, tmp)
- {
- HASH_DEL(master_thr->work_list, work);
- free_work(work);
- if (--prunequeue < 1)
- break;
- }
- }
- }
- // send work to the device & queue work
- static
- bool gridseed_queue_append(struct thr_info * const thr, struct work *work)
- {
- const struct cgpu_info * const device = thr->cgpu->device;
- struct gc3355_orb_info * const info = device->device_data;
- struct thr_info * const master_thr = device->thr[0];
-
- // if queue is full (-1 is a check flag) do not append new work
- if (gridseed_set_queue_full(device, -1))
- return false;
-
- // send work
- if (!gridseed_send_work(device, work))
- return false;
-
- // store work in queue
- HASH_ADD(hh, master_thr->work_list, id, sizeof(work->id), work);
-
- // prune queue
- gridseed_prune_queue(device, work);
-
- // sets info->needwork equal to 2nd arg and updates "full" flags
- gridseed_set_queue_full(device, info->needwork - 1);
-
- return true;
- }
- static
- void gridseed_queue_flush(struct thr_info * const thr)
- {
- const struct cgpu_info *device = thr->cgpu;
- if (device != device->device)
- return;
-
- gridseed_set_queue_full(device, device->procs);
- }
- static
- const struct cgpu_info *gridseed_proc_by_id(const struct cgpu_info * const dev, int procid)
- {
- const struct cgpu_info *proc = dev;
- for (int i = 0; i < procid; ++i)
- {
- proc = proc->next_proc;
- if (unlikely(!proc))
- return NULL;
- }
- return proc;
- }
- static
- void gridseed_submit_nonce(struct thr_info * const master_thr, const unsigned char buf[GC3355_READ_SIZE])
- {
- struct work *work;
- uint32_t nonce;
- int workid;
- struct cgpu_info * const device = master_thr->cgpu;
- struct gc3355_orb_info * const info = device->device_data;
-
- // extract workid from buffer
- memcpy(&workid, buf + 8, 4);
- // extract nonce from buffer
- memcpy(&nonce, buf + 4, 4);
- // extract chip # from nonce
- const int chip = nonce / ((uint32_t)0xffffffff / GC3355_ORB_DEFAULT_CHIPS);
- // find processor by device & chip
- const struct cgpu_info *proc = gridseed_proc_by_id(device, chip);
- // default process to device
- if (unlikely(!proc))
- proc = device;
- // the thread specific to the ASIC chip:
- struct thr_info * thr = proc->thr[0];
-
- nonce = htole32(nonce);
-
- // find the queued work for this nonce, by workid
- HASH_FIND(hh, master_thr->work_list, &workid, sizeof(workid), work);
- if (work)
- {
- submit_nonce(thr, work, nonce);
-
- HASH_DEL(master_thr->work_list, work);
-
- gridseed_set_queue_full(device, info->needwork + 2);
- }
- }
- static
- void gridseed_estimate_hashes(const struct cgpu_info * const device)
- {
- const struct cgpu_info *proc = device;
- const struct gc3355_orb_info *info = device->device_data;
-
- while (true)
- {
- hashes_done2(proc->thr[0], info->freq * 0xA4, NULL);
- proc = proc->next_proc;
- if (unlikely(!proc))
- return;
- }
- }
- #define GRIDSEED_SHORT_WORK_DELAY_MS 20
- #define GRIDSEED_LONG_WORK_DELAY_MS 30
- // read from device for nonce or command
- static
- void gridseed_poll(struct thr_info * const master_thr)
- {
- struct cgpu_info * const device = master_thr->cgpu;
- int fd = device->device_fd;
- unsigned char buf[GC3355_READ_SIZE];
- int read = 0;
- struct timeval tv_timeout;
- timer_set_delay_from_now(&tv_timeout, GRIDSEED_LONG_WORK_DELAY_MS * 1000); // X MS
- bool timeout = false;
-
- while (!master_thr->work_restart && (read = gc3355_read(device->device_fd, (char *)buf, GC3355_READ_SIZE)) > 0)
- {
- if (buf[0] == 0x55)
- {
- switch(buf[1]) {
- case 0xaa:
- // Queue length result
- // could watch for watchdog reset here
- break;
- case 0x10: // BTC result
- case 0x20: // LTC result
- {
- gridseed_submit_nonce(master_thr, buf);
- break;
- }
- }
- } else
- {
- applog(LOG_ERR, "%"PRIpreprv": Unrecognized response", device->proc_repr);
- break;
- }
-
- if (timer_passed(&tv_timeout, NULL))
- {
- // allow work to be sent to the device
- applog(LOG_DEBUG, "%s poll: timeout met", device->dev_repr);
- timeout = true;
- break;
- }
- }
-
- gridseed_estimate_hashes(device);
-
- // allow work to be sent to the device
- timer_set_delay_from_now(&master_thr->tv_poll, GRIDSEED_SHORT_WORK_DELAY_MS * 1000); // X MS
- }
- /*
- * specify settings / options
- */
- // support for --set-device dualminer:clock=freq
- static
- char *gridseed_set_device(struct cgpu_info *device, char *option, char *setting, char *replybuf)
- {
- if (strcasecmp(option, "clock") == 0)
- {
- int val = atoi(setting);
-
- struct gc3355_orb_info *info = (struct gc3355_orb_info *)(device->device_data);
- info->freq = val;
- int fd = device->device_fd;
-
- gc3355_set_pll_freq(fd, val);
-
- return NULL;
- }
-
- sprintf(replybuf, "Unknown option: %s", option);
- return replybuf;
- }
- struct device_drv gridseed_drv =
- {
- // metadata
- .dname = "gridseed",
- .name = "GSD",
- .supported_algos = POW_SCRYPT,
-
- // detect device
- .lowl_probe = gridseed_lowl_probe,
-
- // initialize device
- .thread_prepare = gridseed_thread_prepare,
- .thread_init = gridseed_thread_init,
- .reinit_device = gridseed_reinit_device,
-
- // specify mining type - scanhash
- .minerloop = minerloop_queue,
-
- // queued mining hooks
- .queue_append = gridseed_queue_append,
- .queue_flush = gridseed_queue_flush,
- .poll = gridseed_poll,
-
- // teardown device
- .thread_shutdown = gridseed_thread_shutdown,
-
- // specify settings / options
- .set_device = gridseed_set_device,
- };
|