| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- /*
- * Copyright 2014 Luke Dashjr
- *
- * 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 <stdint.h>
- #include <string.h>
- #include <unistd.h>
- #include "deviceapi.h"
- #include "lowl-vcom.h"
- #include "miner.h"
- #define ROCKMINER_MIN_FREQ_MHZ 200
- #define ROCKMINER_MAX_CHIPS 64
- #define ROCKMINER_WORK_REQ_SIZE 0x40
- #define ROCKMINER_REPLY_SIZE 8
- enum rockminer_replies {
- ROCKMINER_REPLY_NONCE_FOUND = 0,
- };
- BFG_REGISTER_DRIVER(rockminer_drv)
- struct rockminer_chip_data {
- uint8_t next_work_req[ROCKMINER_WORK_REQ_SIZE];
- };
- static
- void rockminer_job_buf_init(uint8_t * const buf, const uint8_t chipid)
- {
- memset(&buf[0x20], 0, 0x10);
- buf[0x30] = 0xaa;
- // 0x31 is frequency, filled in elsewhere
- buf[0x32] = chipid;
- buf[0x33] = 0x55;
- }
- static
- void rockminer_job_buf_set_freq(uint8_t * const buf, const unsigned short freq)
- {
- buf[0x31] = (freq / 10) - 1;
- }
- static const uint8_t golden_midstate[] = {
- 0x4a, 0x54, 0x8f, 0xe4, 0x71, 0xfa, 0x3a, 0x9a,
- 0x13, 0x71, 0x14, 0x45, 0x56, 0xc3, 0xf6, 0x4d,
- 0x25, 0x00, 0xb4, 0x82, 0x60, 0x08, 0xfe, 0x4b,
- 0xbf, 0x76, 0x98, 0xc9, 0x4e, 0xba, 0x79, 0x46,
- };
- static const uint8_t golden_datatail[] = {
- 0xce, 0x22, 0xa7, 0x2f,
- 0x4f, 0x67, 0x26, 0x14, 0x1a, 0x0b, 0x32, 0x87,
- };
- static const uint8_t golden_result[] = {
- 0x00, 0x01, 0x87, 0xa2,
- };
- int8_t rockminer_bisect_chips(const int fd, uint8_t * const buf)
- {
- static const int max_concurrent_tests = 4;
- int concurrent_tests = max_concurrent_tests;
- uint8_t tests[max_concurrent_tests];
- uint8_t reply[ROCKMINER_REPLY_SIZE];
- uint8_t minvalid = 0, maxvalid = ROCKMINER_MAX_CHIPS - 1;
- uint8_t pertest;
- char msg[0x10];
- ssize_t rsz;
-
- do {
- pertest = (maxvalid + 1 - minvalid) / concurrent_tests;
- if (!pertest)
- pertest = 1;
- msg[0] = '\0';
- for (int i = 0; i < concurrent_tests; ++i)
- {
- uint8_t chipid = (minvalid + pertest * (i + 1)) - 1;
- if (chipid > maxvalid)
- {
- concurrent_tests = i;
- break;
- }
- tests[i] = chipid;
-
- buf[0x32] = chipid;
- if (write(fd, buf, ROCKMINER_WORK_REQ_SIZE) != ROCKMINER_WORK_REQ_SIZE)
- applogr(-1, LOG_DEBUG, "%s(%d): Error sending request for chip %d", __func__, fd, chipid);
-
- tailsprintf(msg, sizeof(msg), "%d ", chipid);
- }
-
- msg[strlen(msg)-1] = '\0';
- applog(LOG_DEBUG, "%s(%d): Testing chips %s (within range %d-%d)", __func__, fd, msg, minvalid, maxvalid);
-
- while ( (rsz = read(fd, reply, sizeof(reply))) == sizeof(reply))
- {
- const uint8_t chipid = reply[5] & 0x3f;
- if (chipid > minvalid)
- {
- applog(LOG_DEBUG, "%s(%d): Saw chip %d", __func__, fd, chipid);
- minvalid = chipid;
- if (minvalid >= tests[concurrent_tests-1])
- break;
- }
- }
-
- for (int i = concurrent_tests; i--; )
- {
- if (tests[i] > minvalid)
- {
- applog(LOG_DEBUG, "%s(%d): Didn't see chip %d", __func__, fd, tests[i]);
- maxvalid = tests[i] - 1;
- }
- else
- break;
- }
- } while (minvalid != maxvalid);
-
- return maxvalid + 1;
- }
- static
- bool rockminer_detect_one(const char * const devpath)
- {
- int fd, chips;
- uint8_t buf[ROCKMINER_WORK_REQ_SIZE], reply[ROCKMINER_REPLY_SIZE];
- ssize_t rsz;
-
- fd = serial_open(devpath, 0, 1, true);
- if (fd < 0)
- return_via_applog(err, , LOG_DEBUG, "%s: %s %s", rockminer_drv.dname, "Failed to open", devpath);
-
- applog(LOG_DEBUG, "%s: %s %s", rockminer_drv.dname, "Successfully opened", devpath);
-
- rockminer_job_buf_init(buf, 0);
- rockminer_job_buf_set_freq(buf, ROCKMINER_MIN_FREQ_MHZ);
- memcpy(&buf[ 0], golden_midstate, 0x20);
- memcpy(&buf[0x34], golden_datatail, 0xc);
-
- if (write(fd, buf, sizeof(buf)) != sizeof(buf))
- return_via_applog(err, , LOG_DEBUG, "%s: %s %s", rockminer_drv.dname, "Error sending request to ", devpath);
-
- while (true)
- {
- rsz = read(fd, reply, sizeof(reply));
- if (rsz != sizeof(reply))
- return_via_applog(err, , LOG_DEBUG, "%s: Short read from %s (%d)", rockminer_drv.dname, devpath, rsz);
- if ((!memcmp(reply, golden_result, sizeof(golden_result))) && (reply[4] & 0xf) == ROCKMINER_REPLY_NONCE_FOUND)
- break;
- }
-
- applog(LOG_DEBUG, "%s: Found chip 0 on %s, probing for total chip count", rockminer_drv.dname, devpath);
- chips = rockminer_bisect_chips(fd, buf);
- applog(LOG_DEBUG, "%s: Identified %d chips on %s", rockminer_drv.dname, chips, devpath);
-
- if (serial_claim_v(devpath, &rockminer_drv))
- goto err;
-
- serial_close(fd);
-
- struct cgpu_info * const cgpu = malloc(sizeof(*cgpu));
- *cgpu = (struct cgpu_info){
- .drv = &rockminer_drv,
- .device_path = strdup(devpath),
- .deven = DEV_ENABLED,
- .procs = chips,
- .threads = 1,
- };
- // NOTE: Xcode's clang has a bug where it cannot find fields inside anonymous unions (more details in fpgautils)
- cgpu->device_fd = -1;
-
- return add_cgpu(cgpu);
- err:
- if (fd >= 0)
- serial_close(fd);
- return false;
- }
- static
- bool rockminer_lowl_probe(const struct lowlevel_device_info * const info)
- {
- return vcom_lowl_probe_wrapper(info, rockminer_detect_one);
- }
- struct device_drv rockminer_drv = {
- .dname = "rockminer",
- .name = "RKM",
- .lowl_probe = rockminer_lowl_probe,
- };
|