123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377 |
- /*
- * Copyright 2013-2014 Con Kolivas <kernel@kolivas.org>
- *
- * 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 "miner.h"
- #include "driver-cointerra.h"
- static const char *cointerra_hdr = "ZZ";
- int opt_ps_load;
- static void cta_gen_message(char *msg, char type)
- {
- memset(msg, 0, CTA_MSG_SIZE);
- memcpy(msg, cointerra_hdr, 2);
- msg[CTA_MSG_TYPE] = type;
- }
- /* Find the number of leading zero bits in diff */
- static uint8_t diff_to_bits(double diff)
- {
- uint64_t diff64;
- uint8_t i;
- diff /= 0.9999847412109375;
- diff *= (double)2147483648.0;
- if (diff > 0x8000000000000000ULL)
- diff = 0x8000000000000000ULL;
- /* Convert it to an integer */
- diff64 = diff;
- for (i = 0; diff64; i++, diff64 >>= 1);
- return i;
- }
- static double bits_to_diff(uint8_t bits)
- {
- double ret = 1.0;
- if (likely(bits > 32))
- ret *= 1ull << (bits - 32);
- else if (unlikely(bits < 32))
- ret /= 1ull << (32 - bits);
- return ret;
- }
- static bool cta_reset_init(char *buf)
- {
- return ((buf[CTA_MSG_TYPE] == CTA_RECV_RDONE) && ((buf[CTA_RESET_TYPE]&0x3) == CTA_RESET_INIT));
- }
- static char *mystrstr(char *haystack, int size, const char *needle)
- {
- int loop = 0;
- while (loop < (size-1)) {
- if ((haystack[loop] == needle[0])&&
- (haystack[loop+1] == needle[1]))
- return &haystack[loop];
- loop++;
- }
- return NULL;
- }
- static bool cta_open(struct cgpu_info *cointerra)
- {
- int err, amount, offset = 0;
- char buf[CTA_MSG_SIZE];
- cgtimer_t ts_start;
- bool ret = false;
- if (cointerra->usbinfo.nodev)
- return false;
- applog(LOG_INFO, "CTA_OPEN");
- cta_gen_message(buf, CTA_SEND_RESET);
- // set the initial difficulty
- buf[CTA_RESET_TYPE] = CTA_RESET_INIT | CTA_RESET_DIFF;
- buf[CTA_RESET_DIFF] = diff_to_bits(CTA_INIT_DIFF);
- buf[CTA_RESET_LOAD] = opt_cta_load ? opt_cta_load : 255;
- buf[CTA_RESET_PSLOAD] = opt_ps_load;
- if (cointerra->usbinfo.nodev)
- return ret;
- err = usb_write(cointerra, buf, CTA_MSG_SIZE, &amount, C_CTA_WRITE);
- if (err) {
- applog(LOG_INFO, "Write error %d, wrote %d of %d", err, amount, CTA_MSG_SIZE);
- return ret;
- }
- cgtimer_time(&ts_start);
- /* Read from the device for up to 2 seconds discarding any data that
- * doesn't match a reset complete acknowledgement. */
- while (42) {
- cgtimer_t ts_now, ts_diff;
- char *msg;
- cgtimer_time(&ts_now);
- cgtimer_sub(&ts_now, &ts_start, &ts_diff);
- if (cgtimer_to_ms(&ts_diff) > 2000) {
- applog(LOG_DEBUG, "%s %d: Timed out waiting for response to reset init",
- cointerra->drv->name, cointerra->device_id);
- break;
- }
- if (cointerra->usbinfo.nodev)
- break;
- err = usb_read(cointerra, buf + offset, CTA_MSG_SIZE - offset, &amount, C_CTA_READ);
- if (err && err != LIBUSB_ERROR_TIMEOUT) {
- applog(LOG_INFO, "%s %d: Read error %d, read %d", cointerra->drv->name,
- cointerra->device_id, err, amount);
- break;
- }
- if (!amount)
- continue;
- msg = mystrstr(buf, amount, cointerra_hdr);
- if (!msg) {
- /* Keep the last byte in case it's the first byte of
- * the 2 byte header. */
- offset = 1;
- memmove(buf, buf + amount - 1, offset);
- continue;
- }
- if (msg > buf) {
- /* length of message = offset for next usb_read after moving */
- offset = CTA_MSG_SIZE - (msg - buf);
- memmove(buf, msg, offset);
- continue;
- }
- /* We have a full sized message starting with the header now */
- if (cta_reset_init(buf)) {
- /* We can't store any other data returned with this
- * reset since we have not allocated any memory for
- * a cointerra_info structure yet. */
- applog(LOG_INFO, "%s %d: Successful reset init received",
- cointerra->drv->name, cointerra->device_id);
- ret = true;
- break;
- }
- }
- return ret;
- }
- static void cta_clear_work(struct cgpu_info *cgpu)
- {
- struct work *work, *tmp;
- wr_lock(&cgpu->qlock);
- HASH_ITER(hh, cgpu->queued_work, work, tmp) {
- __work_completed(cgpu, work);
- free_work(work);
- }
- wr_unlock(&cgpu->qlock);
- }
- static void cta_close(struct cgpu_info *cointerra)
- {
- struct cointerra_info *info = cointerra->device_data;
- /* Wait for read thread to die */
- pthread_join(info->read_thr, NULL);
- /* Open does the same reset init followed by response as is required to
- * close the device. */
- if (!cta_open(cointerra)) {
- applog(LOG_INFO, "%s %d: Reset on close failed", cointerra->drv->name,
- cointerra->device_id);
- }
- mutex_destroy(&info->lock);
- mutex_destroy(&info->sendlock);
- /* Don't free info here to avoid trying to access dereferenced members
- * once a device is unplugged. */
- cta_clear_work(cointerra);
- }
- static struct cgpu_info *cta_detect_one(struct libusb_device *dev, struct usb_find_devices *found)
- {
- struct cgpu_info *cointerra = usb_alloc_cgpu(&cointerra_drv, 1);
- int tries = 0;
- if (!usb_init(cointerra, dev, found))
- goto fail;
- applog(LOG_INFO, "%s %d: Found at %s", cointerra->drv->name,
- cointerra->device_id, cointerra->device_path);
- while (!cta_open(cointerra) && !cointerra->usbinfo.nodev) {
- if (tries++ > 3)
- goto failed_open;
- applog(LOG_INFO, "%s %d: Failed to open %d times, retrying", cointerra->drv->name,
- cointerra->device_id, tries);
- }
- if (!add_cgpu(cointerra))
- goto fail_close;
- update_usb_stats(cointerra);
- applog(LOG_INFO, "%s %d: Successfully set up %s", cointerra->drv->name,
- cointerra->device_id, cointerra->device_path);
- return cointerra;
- fail_close:
- cta_close(cointerra);
- failed_open:
- applog(LOG_INFO, "%s %d: Failed to initialise %s", cointerra->drv->name,
- cointerra->device_id, cointerra->device_path);
- fail:
- usb_free_cgpu(cointerra);
- return NULL;
- }
- static void cta_detect(bool __maybe_unused hotplug)
- {
- usb_detect(&cointerra_drv, cta_detect_one);
- }
- /* This function will remove a work item from the hashtable if it matches the
- * id in work->subid and return a pointer to the work but it will not free the
- * work. It may return NULL if it cannot find matching work. */
- static struct work *take_work_by_id(struct cgpu_info *cgpu, uint16_t id)
- {
- struct work *work, *tmp, *ret = NULL;
- wr_lock(&cgpu->qlock);
- HASH_ITER(hh, cgpu->queued_work, work, tmp) {
- if (work->subid == id) {
- ret = work;
- break;
- }
- }
- if (ret)
- __work_completed(cgpu, ret);
- wr_unlock(&cgpu->qlock);
- return ret;
- }
- /* This function will look up a work item in the hashtable if it matches the
- * id in work->subid and return a cloned work item if it matches. It may return
- * NULL if it cannot find matching work. */
- static struct work *clone_work_by_id(struct cgpu_info *cgpu, uint16_t id)
- {
- struct work *work, *tmp, *ret = NULL;
- rd_lock(&cgpu->qlock);
- HASH_ITER(hh, cgpu->queued_work, work, tmp) {
- if (work->subid == id) {
- ret = work;
- break;
- }
- }
- if (ret)
- ret = copy_work(ret);
- rd_unlock(&cgpu->qlock);
- return ret;
- }
- static bool cta_send_msg(struct cgpu_info *cointerra, char *buf);
- static uint16_t hu16_from_msg(char *buf, int msg)
- {
- return le16toh(*(uint16_t *)&buf[msg]);
- }
- static uint32_t hu32_from_msg(char *buf, int msg)
- {
- return le32toh(*(uint32_t *)&buf[msg]);
- }
- static uint64_t hu64_from_msg(char *buf, int msg)
- {
- return le64toh(*(uint64_t *)&buf[msg]);
- }
- static uint8_t u8_from_msg(char *buf, int msg)
- {
- return *(uint8_t *)&buf[msg];
- }
- static void msg_from_hu16(char *buf, int msg, uint16_t val)
- {
- *(uint16_t *)&buf[msg] = htole16(val);
- }
- static void cta_parse_reqwork(struct cgpu_info *cointerra, struct cointerra_info *info,
- char *buf)
- {
- uint16_t retwork;
- retwork = hu16_from_msg(buf, CTA_REQWORK_REQUESTS);
- applog(LOG_DEBUG, "%s %d: Request work message for %u items received",
- cointerra->drv->name, cointerra->device_id, retwork);
- mutex_lock(&info->lock);
- info->requested = retwork;
- /* Wake up the main scanwork loop since we need more
- * work. */
- pthread_cond_signal(&info->wake_cond);
- mutex_unlock(&info->lock);
- }
- static void cta_parse_recvmatch(struct thr_info *thr, struct cgpu_info *cointerra,
- struct cointerra_info *info, char *buf)
- {
- uint32_t timestamp_offset, mcu_tag;
- uint16_t retwork;
- struct work *work;
- /* No endian switch needs doing here since it's sent and returned as
- * the same 4 bytes */
- retwork = *(uint16_t *)(&buf[CTA_DRIVER_TAG]);
- mcu_tag = hu32_from_msg(buf, CTA_MCU_TAG);
- applog(LOG_DEBUG, "%s %d: Match message for id 0x%04x MCU id 0x%08x received",
- cointerra->drv->name, cointerra->device_id, retwork, mcu_tag);
- work = clone_work_by_id(cointerra, retwork);
- if (likely(work)) {
- uint8_t wdiffbits = u8_from_msg(buf, CTA_WORK_DIFFBITS);
- uint32_t nonce = hu32_from_msg(buf, CTA_MATCH_NONCE);
- unsigned char rhash[32];
- char outhash[16];
- double wdiff;
- bool ret;
- timestamp_offset = hu32_from_msg(buf, CTA_MATCH_NOFFSET);
- if (timestamp_offset) {
- struct work *base_work = work;
- work = copy_work_noffset(base_work, timestamp_offset);
- free_work(base_work);
- }
- /* Test against the difficulty we asked for along with the work */
- wdiff = bits_to_diff(wdiffbits);
- ret = test_nonce_diff(work, nonce, wdiff);
- if (opt_debug) {
- /* Debugging, remove me */
- swab256(rhash, work->hash);
- __bin2hex(outhash, rhash, 8);
- applog(LOG_WARNING, "submit work %s 0x%04x 0x%08x %d 0x%08x",
- outhash, retwork, mcu_tag, timestamp_offset, nonce);
- }
- if (likely(ret)) {
- uint8_t asic, core, pipe, coreno;
- int pipeno, bitchar, bitbit;
- uint64_t hashes;
- asic = u8_from_msg(buf, CTA_MCU_ASIC);
- core = u8_from_msg(buf, CTA_MCU_CORE);
- pipe = u8_from_msg(buf, CTA_MCU_PIPE);
- pipeno = asic * 512 + core * 128 + pipe;
- coreno = asic * 4 + core;
- if (unlikely(asic > 1 || core > 3 || pipe > 127 || pipeno > 1023)) {
- applog(LOG_WARNING, "%s %d: MCU invalid pipe asic %d core %d pipe %d",
- cointerra->drv->name, cointerra->device_id, asic, core, pipe);
- coreno = 0;
- } else {
- info->last_pipe_nonce[pipeno] = time(NULL);
- bitchar = pipeno / 8;
- bitbit = pipeno % 8;
- info->pipe_bitmap[bitchar] |= 0x80 >> bitbit;
- }
- applog(LOG_DEBUG, "%s %d: Submitting tested work job_id %s work_id %u",
- cointerra->drv->name, cointerra->device_id, work->job_id, work->subid);
- ret = submit_tested_work(thr, work);
- hashes = (uint64_t)wdiff * 0x100000000ull;
- mutex_lock(&info->lock);
- info->share_hashes += hashes;
- info->tot_core_hashes[coreno] += hashes;
- info->hashes += nonce;
- mutex_unlock(&info->lock);
- } else {
- char sendbuf[CTA_MSG_SIZE];
- uint8_t asic, core, coreno;
- asic = u8_from_msg(buf, CTA_MCU_ASIC);
- core = u8_from_msg(buf, CTA_MCU_CORE);
- coreno = asic * 4 + core;
- inc_hw_errors(thr);
- applog(LOG_WARNING, "%s %d: Notify bad match work",
- cointerra->drv->name, cointerra->device_id);
- if (coreno < CTA_CORES)
- info->fmatch_errors[coreno]++;
- if (opt_debug) {
- uint64_t sdiff = share_diff(work);
- unsigned char midstate[32], wdata[12];
- char hexmidstate[68], hexwdata[28];
- uint16_t wid;
- memcpy(&wid, &info->work_id, 2);
- flip32(midstate, work->midstate);
- __bin2hex(hexmidstate, midstate, 32);
- flip12(wdata, &work->data[64]);
- __bin2hex(hexwdata, wdata, 12);
- applog(LOG_DEBUG, "False match sent: work id %u midstate %s blkhdr %s",
- wid, hexmidstate, hexwdata);
- applog(LOG_DEBUG, "False match reports: work id 0x%04x MCU id 0x%08x work diff %.1f",
- retwork, mcu_tag, wdiff);
- applog(LOG_DEBUG, "False match tested: nonce 0x%08x noffset %d %s",
- nonce, timestamp_offset, outhash);
- applog(LOG_DEBUG, "False match devdiff set to %.1f share diff calc %"PRIu64,
- work->device_diff, sdiff);
- }
- /* Tell the device we got a false match */
- cta_gen_message(sendbuf, CTA_SEND_FMATCH);
- memcpy(sendbuf + 3, buf + 3, CTA_MSG_SIZE - 3);
- cta_send_msg(cointerra, sendbuf);
- }
- free_work(work);
- } else {
- applog(LOG_WARNING, "%s %d: Matching work id 0x%X %d not found", cointerra->drv->name,
- cointerra->device_id, retwork, __LINE__);
- inc_hw_errors(thr);
- mutex_lock(&info->lock);
- info->no_matching_work++;
- mutex_unlock(&info->lock);
- }
- }
- static void cta_parse_wdone(struct thr_info *thr, struct cgpu_info *cointerra,
- struct cointerra_info *info, char *buf)
- {
- uint16_t retwork = *(uint16_t *)(&buf[CTA_DRIVER_TAG]);
- struct work *work = take_work_by_id(cointerra, retwork);
- uint64_t hashes;
- if (likely(work)) {
- free_work(work);
- applog(LOG_DEBUG, "%s %d: Done work found id 0x%X %d",
- cointerra->drv->name, cointerra->device_id, retwork, __LINE__);
- } else {
- applog(LOG_WARNING, "%s %d: Done work not found id 0x%X %d",
- cointerra->drv->name, cointerra->device_id, retwork, __LINE__);
- inc_hw_errors(thr);
- }
- /* Removing hashes from work done message */
- hashes = hu64_from_msg(buf, CTA_WDONE_NONCES);
- if (unlikely(hashes > (61 * 0x100000000ull))) {
- applog(LOG_INFO, "%s Invalid hash returned %"PRIu64"x %"PRIu64"x %"PRIu64"X",
- __func__, info->hashes, hashes, hashes);
- hashes = 0;
- }
- mutex_lock(&info->lock);
- info->hashes += hashes;
- mutex_unlock(&info->lock);
- }
- static void u16array_from_msg(uint16_t *u16, int entries, int var, char *buf)
- {
- int i, j;
- for (i = 0, j = 0; i < entries; i++, j += sizeof(uint16_t))
- u16[i] = hu16_from_msg(buf, var + j);
- }
- static void cta_parse_statread(struct cgpu_info *cointerra, struct cointerra_info *info,
- char *buf)
- {
- float max_temp = 0;
- int i;
- mutex_lock(&info->lock);
- u16array_from_msg(info->coretemp, CTA_CORES, CTA_STAT_CORETEMPS, buf);
- info->ambtemp_low = hu16_from_msg(buf, CTA_STAT_AMBTEMP_LOW);
- info->ambtemp_avg = hu16_from_msg(buf, CTA_STAT_AMBTEMP_AVG);
- info->ambtemp_high = hu16_from_msg(buf, CTA_STAT_AMBTEMP_HIGH);
- u16array_from_msg(info->pump_tachs, CTA_PUMPS, CTA_STAT_PUMP_TACHS, buf);
- u16array_from_msg(info->fan_tachs, CTA_FANS, CTA_STAT_FAN_TACHS, buf);
- u16array_from_msg(info->corevolts, CTA_CORES, CTA_STAT_CORE_VOLTS, buf);
- info->volts33 = hu16_from_msg(buf, CTA_STAT_VOLTS33);
- info->volts12 = hu16_from_msg(buf, CTA_STAT_VOLTS12);
- info->inactive = hu16_from_msg(buf, CTA_STAT_INACTIVE);
- info->active = hu16_from_msg(buf, CTA_STAT_ACTIVE);
- mutex_unlock(&info->lock);
- for (i = 0; i < CTA_CORES; i++) {
- if (info->coretemp[i] > max_temp)
- max_temp = info->coretemp[i];
- }
- max_temp /= 100.0;
- /* Store the max temperature in the cgpu struct as an exponentially
- * changing value. */
- cointerra->temp = cointerra->temp * 0.63 + max_temp * 0.37;
- }
- static void u8array_from_msg(uint8_t *u8, int entries, int var, char *buf)
- {
- int i;
- for (i = 0; i < entries; i++)
- u8[i] = u8_from_msg(buf, var + i);
- }
- static void cta_parse_statset(struct cointerra_info *info, char *buf)
- {
- mutex_lock(&info->lock);
- u8array_from_msg(info->coreperf, CTA_CORES, CTA_STAT_PERFMODE, buf);
- u8array_from_msg(info->fanspeed, CTA_FANS, CTA_STAT_FANSPEEDS, buf);
- info->dies_active = u8_from_msg(buf, CTA_STAT_DIES_ACTIVE);
- u8array_from_msg(info->pipes_enabled, CTA_CORES, CTA_STAT_PIPES_ENABLED, buf);
- u16array_from_msg(info->corefreqs, CTA_CORES, CTA_STAT_CORE_FREQS, buf);
- info->uptime = hu32_from_msg(buf,CTA_STAT_UPTIME);
- mutex_unlock(&info->lock);
- }
- static void cta_parse_irstat(struct cointerra_info *info, char *buf)
- {
- uint8_t channel = u8_from_msg(buf,CTA_IRSTAT_CHANNEL);
- if (channel >= CTA_CORES)
- return;
- mutex_lock(&info->lock);
- info->irstat_vin[channel] = hu16_from_msg(buf,CTA_IRSTAT_VIN);
- info->irstat_iin[channel] = hu16_from_msg(buf,CTA_IRSTAT_IIN);
- info->irstat_vout[channel] = hu16_from_msg(buf,CTA_IRSTAT_VOUT);
- info->irstat_iout[channel] = hu16_from_msg(buf,CTA_IRSTAT_IOUT);
- info->irstat_temp1[channel] = hu16_from_msg(buf,CTA_IRSTAT_TEMP1);
- info->irstat_temp2[channel] = hu16_from_msg(buf,CTA_IRSTAT_TEMP2);
- info->irstat_pout[channel] = hu16_from_msg(buf,CTA_IRSTAT_POUT);
- info->irstat_pin[channel] = hu16_from_msg(buf,CTA_IRSTAT_PIN);
- info->irstat_efficiency[channel] = hu16_from_msg(buf,CTA_IRSTAT_EFF);
- info->irstat_status[channel] = hu16_from_msg(buf,CTA_IRSTAT_STATUS);
- mutex_unlock(&info->lock);
- }
- static void cta_parse_info(struct cgpu_info *cointerra, struct cointerra_info *info,
- char *buf)
- {
- mutex_lock(&info->lock);
- info->hwrev = hu64_from_msg(buf, CTA_INFO_HWREV);
- info->serial = hu32_from_msg(buf, CTA_INFO_SERNO);
- info->asics = u8_from_msg(buf, CTA_INFO_NUMASICS);
- info->dies = u8_from_msg(buf, CTA_INFO_NUMDIES);
- info->cores = hu16_from_msg(buf, CTA_INFO_NUMCORES);
- info->board_number = u8_from_msg(buf, CTA_INFO_BOARDNUMBER);
- info->fwrev[0] = u8_from_msg(buf, CTA_INFO_FWREV_MAJ);
- info->fwrev[1] = u8_from_msg(buf, CTA_INFO_FWREV_MIN);
- info->fwrev[2] = u8_from_msg(buf, CTA_INFO_FWREV_MIC);
- info->fw_year = hu16_from_msg(buf, CTA_INFO_FWDATE_YEAR);
- info->fw_month = u8_from_msg(buf, CTA_INFO_FWDATE_MONTH);
- info->fw_day = u8_from_msg(buf, CTA_INFO_FWDATE_DAY);
- info->init_diffbits = u8_from_msg(buf, CTA_INFO_INITDIFFBITS);
- info->min_diffbits = u8_from_msg(buf, CTA_INFO_MINDIFFBITS);
- info->max_diffbits = u8_from_msg(buf, CTA_INFO_MAXDIFFBITS);
- mutex_unlock(&info->lock);
- if (!cointerra->unique_id) {
- uint32_t b32 = htobe32(info->serial);
- cointerra->unique_id = bin2hex((unsigned char *)&b32, 4);
- }
- }
- static void cta_parse_rdone(struct cgpu_info *cointerra, struct cointerra_info *info,
- char *buf)
- {
- uint8_t reset_type, diffbits;
- uint64_t wdone;
- reset_type = buf[CTA_RESET_TYPE];
- diffbits = buf[CTA_RESET_DIFF];
- wdone = hu64_from_msg(buf, CTA_WDONE_NONCES);
- if (wdone) {
- applog(LOG_INFO, "%s %d: Reset done type %u message %u diffbits %"PRIu64" done received",
- cointerra->drv->name, cointerra->device_id, reset_type, diffbits, wdone);
- mutex_lock(&info->lock);
- info->hashes += wdone;
- mutex_unlock(&info->lock);
- }
- /* Note that the cgsem that is posted here must not be waited on while
- * holding the info->lock to not get into a livelock since this
- * function also grabs the lock first and it's always best to not sleep
- * while holding a lock. */
- if (reset_type == CTA_RESET_NEW) {
- cta_clear_work(cointerra);
- /* Tell reset sender that the reset is complete
- * and it may resume. */
- cgsem_post(&info->reset_sem);
- }
- }
- static void cta_zero_stats(struct cgpu_info *cointerra);
- static void cta_parse_debug(struct cointerra_info *info, char *buf)
- {
- mutex_lock(&info->lock);
- info->tot_underruns = hu16_from_msg(buf, CTA_STAT_UNDERRUNS);
- u16array_from_msg(info->tot_hw_errors, CTA_CORES, CTA_STAT_HW_ERRORS, buf);
- info->tot_hashes = hu64_from_msg(buf, CTA_STAT_HASHES);
- info->tot_flushed_hashes = hu64_from_msg(buf, CTA_STAT_FLUSHED_HASHES);
- info->autovoltage = u8_from_msg(buf, CTA_STAT_AUTOVOLTAGE);
- info->current_ps_percent = u8_from_msg(buf, CTA_STAT_POWER_PERCENT);
- info->power_used = hu16_from_msg(buf,CTA_STAT_POWER_USED);
- info->power_voltage = hu16_from_msg(buf,CTA_STAT_VOLTAGE);
- info->ipower_used = hu16_from_msg(buf,CTA_STAT_IPOWER_USED);
- info->ipower_voltage = hu16_from_msg(buf,CTA_STAT_IVOLTAGE);
- info->power_temps[0] = hu16_from_msg(buf,CTA_STAT_PS_TEMP1);
- info->power_temps[1] = hu16_from_msg(buf,CTA_STAT_PS_TEMP2);
- mutex_unlock(&info->lock);
- /* Autovoltage is positive only once at startup and eventually drops
- * to zero. After that time we reset the stats since they're unreliable
- * till then. */
- if (unlikely(!info->autovoltage_complete && !info->autovoltage)) {
- struct cgpu_info *cointerra = info->thr->cgpu;
- info->autovoltage_complete = true;
- cgtime(&cointerra->dev_start_tv);
- cta_zero_stats(cointerra);
- cointerra->total_mhashes = 0;
- cointerra->accepted = 0;
- cointerra->rejected = 0;
- cointerra->hw_errors = 0;
- cointerra->utility = 0.0;
- cointerra->last_share_pool_time = 0;
- cointerra->diff1 = 0;
- cointerra->diff_accepted = 0;
- cointerra->diff_rejected = 0;
- cointerra->last_share_diff = 0;
- }
- }
- static int verify_checksum(char *buf)
- {
- unsigned char checksum = 0;
- unsigned char i;
- for (i = 0; i < 63; i++)
- checksum += buf[i];
- return (checksum == buf[63]);
- }
- static void cta_parse_msg(struct thr_info *thr, struct cgpu_info *cointerra,
- struct cointerra_info *info, char *buf)
- {
- if ((buf[CTA_MSG_TYPE] != CTA_RECV_MATCH)&&
- (buf[CTA_MSG_TYPE] != CTA_RECV_WDONE)) {
- if (unlikely(verify_checksum(buf) == 0)) {
- inc_hw_errors(thr);
- applog(LOG_WARNING, "%s %d: checksum bad",cointerra->drv->name,cointerra->device_id);
- return;
- }
- }
- switch (buf[CTA_MSG_TYPE]) {
- default:
- case CTA_RECV_UNUSED:
- applog(LOG_INFO, "%s %d: Unidentified message type %u",
- cointerra->drv->name, cointerra->device_id, buf[CTA_MSG_TYPE]);
- break;
- case CTA_RECV_REQWORK:
- cta_parse_reqwork(cointerra, info, buf);
- break;
- case CTA_RECV_MATCH:
- cta_parse_recvmatch(thr, cointerra, info, buf);
- break;
- case CTA_RECV_WDONE:
- applog(LOG_DEBUG, "%s %d: Work done message received",
- cointerra->drv->name, cointerra->device_id);
- cta_parse_wdone(thr, cointerra, info, buf);
- break;
- case CTA_RECV_STATREAD:
- applog(LOG_DEBUG, "%s %d: Status readings message received",
- cointerra->drv->name, cointerra->device_id);
- cta_parse_statread(cointerra, info, buf);
- break;
- case CTA_RECV_STATSET:
- applog(LOG_DEBUG, "%s %d: Status settings message received",
- cointerra->drv->name, cointerra->device_id);
- cta_parse_statset(info, buf);
- break;
- case CTA_RECV_INFO:
- applog(LOG_DEBUG, "%s %d: Info message received",
- cointerra->drv->name, cointerra->device_id);
- cta_parse_info(cointerra, info, buf);
- break;
- case CTA_RECV_MSG:
- applog(LOG_NOTICE, "%s %d: MSG: %s",
- cointerra->drv->name, cointerra->device_id, &buf[CTA_MSG_RECVD]);
- break;
- case CTA_RECV_RDONE:
- cta_parse_rdone(cointerra, info, buf);
- break;
- case CTA_RECV_STATDEBUG:
- cta_parse_debug(info, buf);
- break;
- case CTA_RECV_IRSTAT:
- cta_parse_irstat(info, buf);
- break;
- }
- }
- static void *cta_recv_thread(void *arg)
- {
- struct thr_info *thr = (struct thr_info *)arg;
- struct cgpu_info *cointerra = thr->cgpu;
- struct cointerra_info *info = cointerra->device_data;
- char threadname[24];
- int offset = 0;
- snprintf(threadname, 24, "cta_recv/%d", cointerra->device_id);
- RenameThread(threadname);
- while (likely(!cointerra->shutdown)) {
- char buf[CTA_READBUF_SIZE];
- int amount, err;
- if (unlikely(cointerra->usbinfo.nodev)) {
- applog(LOG_DEBUG, "%s %d: Device disappeared, disabling recv thread",
- cointerra->drv->name, cointerra->device_id);
- break;
- }
- err = usb_read(cointerra, buf + offset, CTA_MSG_SIZE, &amount, C_CTA_READ);
- if (err && err != LIBUSB_ERROR_TIMEOUT) {
- applog(LOG_ERR, "%s %d: Read error %d, read %d", cointerra->drv->name,
- cointerra->device_id, err, amount);
- break;
- }
- offset += amount;
- while (offset >= CTA_MSG_SIZE) {
- char *msg = mystrstr(buf, offset, cointerra_hdr);
- int begin;
- if (unlikely(!msg)) {
- applog(LOG_WARNING, "%s %d: No message header found, discarding buffer",
- cointerra->drv->name, cointerra->device_id);
- inc_hw_errors(thr);
- /* Save the last byte in case it's the fist
- * byte of a header. */
- begin = CTA_MSG_SIZE - 1;
- offset -= begin;
- memmove(buf, buf + begin, offset);
- continue;
- }
- if (unlikely(msg != buf)) {
- begin = msg - buf;
- applog(LOG_WARNING, "%s %d: Reads out of sync, discarding %d bytes",
- cointerra->drv->name, cointerra->device_id, begin);
- inc_hw_errors(thr);
- offset -= begin;
- memmove(buf, msg, offset);
- if (offset < CTA_MSG_SIZE)
- break;
- }
- /* We have enough buffer for a full message, parse now */
- cta_parse_msg(thr, cointerra, info, msg);
- offset -= CTA_MSG_SIZE;
- if (offset > 0)
- memmove(buf, buf + CTA_MSG_SIZE, offset);
- }
- }
- return NULL;
- }
- static bool cta_send_msg(struct cgpu_info *cointerra, char *buf)
- {
- struct cointerra_info *info = cointerra->device_data;
- int amount, err;
- if (unlikely(cointerra->usbinfo.nodev))
- return false;
- /* Serialise usb writes to prevent overlap in case multiple threads
- * send messages */
- mutex_lock(&info->sendlock);
- err = usb_write(cointerra, buf, CTA_MSG_SIZE, &amount, C_CTA_WRITE);
- mutex_unlock(&info->sendlock);
- if (unlikely(err || amount != CTA_MSG_SIZE)) {
- applog(LOG_ERR, "%s %d: Write error %d, wrote %d of %d", cointerra->drv->name,
- cointerra->device_id, err, amount, CTA_MSG_SIZE);
- return false;
- }
- return true;
- }
- static bool cta_prepare(struct thr_info *thr)
- {
- struct cgpu_info *cointerra = thr->cgpu;
- struct cointerra_info *info = calloc(sizeof(struct cointerra_info), 1);
- char buf[CTA_MSG_SIZE];
- if (unlikely(cointerra->usbinfo.nodev))
- return false;
- if (unlikely(!info))
- quit(1, "Failed to calloc info in cta_detect_one");
- cointerra->device_data = info;
- /* Nominally set a requested value when starting, preempting the need
- * for a req-work message. */
- info->requested = CTA_MAX_QUEUE;
- info->thr = thr;
- mutex_init(&info->lock);
- mutex_init(&info->sendlock);
- if (unlikely(pthread_cond_init(&info->wake_cond, NULL)))
- quit(1, "Failed to create cta pthread cond");
- cgsem_init(&info->reset_sem);
- if (pthread_create(&info->read_thr, NULL, cta_recv_thread, (void *)thr))
- quit(1, "Failed to create cta_recv_thread");
- /* Request a single status setting message */
- cta_gen_message(buf, CTA_SEND_REQUEST);
- msg_from_hu16(buf, CTA_REQ_MSGTYPE, CTA_RECV_STATSET);
- msg_from_hu16(buf, CTA_REQ_INTERVAL, 0);
- if (!cta_send_msg(cointerra, buf))
- return false;
- /* Request status debug messages every 60 seconds */
- cta_gen_message(buf, CTA_SEND_REQUEST);
- msg_from_hu16(buf, CTA_REQ_MSGTYPE, CTA_RECV_STATDEBUG);
- msg_from_hu16(buf, CTA_REQ_INTERVAL, 6000);
- if (!cta_send_msg(cointerra, buf))
- return false;
- cgtime(&info->core_hash_start);
- return true;
- }
- static void cta_send_reset(struct cgpu_info *cointerra, struct cointerra_info *info,
- uint8_t reset_type, uint8_t diffbits);
- static void cta_flush_work(struct cgpu_info *cointerra);
- /* *_fill and *_scanwork are serialised wrt to each other */
- static bool cta_fill(struct cgpu_info *cointerra)
- {
- struct cointerra_info *info = cointerra->device_data;
- bool ret = true;
- char buf[CTA_MSG_SIZE];
- struct work *work = NULL;
- unsigned short nroll_limit;
- uint32_t swab[8];
- uint8_t diffbits;
- //applog(LOG_WARNING, "%s %d: cta_fill %d", cointerra->drv->name, cointerra->device_id,__LINE__);
- if (unlikely(info->thr->work_restart))
- cta_flush_work(cointerra);
- mutex_lock(&info->lock);
- if (!info->requested)
- goto out_unlock;
- work = get_queued(cointerra);
- if (unlikely(!work)) {
- ret = false;
- goto out_unlock;
- }
- if (--info->requested > 0)
- ret = false;
- /* It does not matter what endian this uint16_t is since it will be
- * the same value on sending to the MC as returning in match/done. This
- * will automatically wrap as a uint16_t. It cannot be zero for the MCU
- * though. */
- if (unlikely(++info->work_id == 0))
- info->work_id = 1;
- work->subid = info->work_id;
- diffbits = diff_to_bits(work->device_diff);
- cta_gen_message(buf, CTA_SEND_WORK);
- memcpy(buf + CTA_DRIVER_TAG, &info->work_id, 2);
- flip32(swab, work->midstate);
- memcpy(buf + CTA_WORK_MIDSTATE, swab, 32);
- flip12(swab, &work->data[64]);
- memcpy(buf + CTA_WORK_DATA, swab, 12);
- nroll_limit = htole16(work->drv_rolllimit);
- memcpy(buf + CTA_WORK_NROLL, &nroll_limit, 2);
- memcpy(buf + CTA_WORK_DIFFBITS, &diffbits, 1);
- out_unlock:
- mutex_unlock(&info->lock);
- if (work) {
- cgtime(&work->tv_work_start);
- applog(LOG_DEBUG, "%s %d: Sending work job_id %s work_id %u", cointerra->drv->name,
- cointerra->device_id, work->job_id, work->subid);
- if (unlikely(!cta_send_msg(cointerra, buf))) {
- work_completed(cointerra, work);
- applog(LOG_INFO, "%s %d: Failed to send work",
- cointerra->drv->name, cointerra->device_id);
- /* The device will fail after this */
- }
- }
- return ret;
- }
- static void cta_send_reset(struct cgpu_info *cointerra, struct cointerra_info *info,
- uint8_t reset_type, uint8_t diffbits)
- {
- char buf[CTA_MSG_SIZE];
- int ret, retries = 0;
- /* Clear any accumulated messages in case we've gotten out of sync. */
- cgsem_reset(&info->reset_sem);
- resend:
- cta_gen_message(buf, CTA_SEND_RESET);
- buf[CTA_RESET_TYPE] = reset_type;
- buf[CTA_RESET_LOAD] = opt_cta_load ? opt_cta_load : 255;
- buf[CTA_RESET_PSLOAD] = opt_ps_load;
- applog(LOG_INFO, "%s %d: Sending Reset type %u with diffbits %u", cointerra->drv->name,
- cointerra->device_id, reset_type, diffbits);
- cta_send_msg(cointerra, buf);
- /* Wait for read thread to parse a reset message and signal us we may
- * return to submitting other messages. Use a timeout in case we have
- * a problem and the reset done message never returns. */
- if (reset_type == CTA_RESET_NEW) {
- ret = cgsem_mswait(&info->reset_sem, CTA_RESET_TIMEOUT);
- if (ret) {
- if (++retries < 5) {
- applog(LOG_INFO, "%s %d: Timed out waiting for reset done msg, retrying",
- cointerra->drv->name, cointerra->device_id);
- goto resend;
- }
- applog(LOG_WARNING, "%s %d: Timed out waiting for reset done msg",
- cointerra->drv->name, cointerra->device_id);
- }
- /* Good place to flush any work we have */
- flush_queue(cointerra);
- }
- }
- static void cta_flush_work(struct cgpu_info *cointerra)
- {
- struct cointerra_info *info = cointerra->device_data;
- applog(LOG_INFO, "%s %d: cta_flush_work %d", cointerra->drv->name, cointerra->device_id,
- __LINE__);
- cta_send_reset(cointerra, info, CTA_RESET_NEW, 0);
- info->thr->work_restart = false;
- }
- static void cta_update_work(struct cgpu_info *cointerra)
- {
- struct cointerra_info *info = cointerra->device_data;
- applog(LOG_INFO, "%s %d: Update work", cointerra->drv->name, cointerra->device_id);
- cta_send_reset(cointerra, info, CTA_RESET_UPDATE, 0);
- }
- static void cta_zero_corehashes(struct cointerra_info *info)
- {
- int i;
- for (i = 0; i < CTA_CORES; i++)
- info->tot_core_hashes[i] = 0;
- cgtime(&info->core_hash_start);
- }
- /* Send per core hashrate calculations at regular intervals ~every 5 minutes */
- static void cta_send_corehashes(struct cgpu_info *cointerra, struct cointerra_info *info,
- double corehash_time)
- {
- uint16_t core_ghs[CTA_CORES];
- double k[CTA_CORES];
- char buf[CTA_MSG_SIZE];
- int i, offset;
- for (i = 0; i < CTA_CORES; i++) {
- k[i] = (double)info->tot_core_hashes[i];
- #if 0
- k[i] /= ((double)32 * (double)0x100000000ull);
- k[i] = sqrt(k[i]) + 1;
- k[i] *= k[i];
- k[i] = k[i] * 32 * ((double)0x100000000ull );
- #endif
- k[i] /= ((double)1000000000 * corehash_time);
- core_ghs[i] = k[i];
- }
- cta_gen_message(buf, CTA_SEND_COREHASHRATE);
- offset = CTA_CORE_HASHRATES;
- for (i = 0; i < CTA_CORES; i++) {
- msg_from_hu16(buf, offset, core_ghs[i]);
- offset += 2; // uint16_t
- }
- cta_send_msg(cointerra, buf);
- }
- static int64_t cta_scanwork(struct thr_info *thr)
- {
- struct cgpu_info *cointerra = thr->cgpu;
- struct cointerra_info *info = cointerra->device_data;
- double corehash_time;
- struct timeval now;
- uint32_t runtime;
- int64_t hashes;
- applog(LOG_DEBUG, "%s %d: cta_scanwork %d", cointerra->drv->name, cointerra->device_id,__LINE__);
- if (unlikely(cointerra->usbinfo.nodev)) {
- hashes = -1;
- goto out;
- }
- cgtime(&now);
- if (unlikely(thr->work_restart)) {
- applog(LOG_INFO, "%s %d: Flush work line %d",
- cointerra->drv->name, cointerra->device_id,__LINE__);
- cta_flush_work(cointerra);
- } else {
- struct timespec abstime, tsdiff = {0, 500000000};
- time_t now_t;
- int i;
- timeval_to_spec(&abstime, &now);
- timeraddspec(&abstime, &tsdiff);
- /* Discard work that was started more than 5 minutes ago as
- * a safety precaution backup in case the hardware failed to
- * return a work done message for some work items. */
- age_queued_work(cointerra, 300.0);
- /* Each core should be 1.7MH so at max diff of 32 should
- * average a share every ~80 seconds.Use this opportunity to
- * unset the bits in any pipes that have not returned a valid
- * nonce for over 30 full nonce ranges or 2400s. */
- now_t = time(NULL);
- for (i = 0; i < 1024; i++) {
- if (unlikely(now_t > info->last_pipe_nonce[i] + 2400)) {
- int bitchar = i / 8, bitbit = i % 8;
- info->pipe_bitmap[bitchar] &= ~(0x80 >> bitbit);
- }
- }
- /* Sleep for up to 0.5 seconds, waking if we need work or
- * have received a restart message. */
- mutex_lock(&info->lock);
- pthread_cond_timedwait(&info->wake_cond, &info->lock, &abstime);
- mutex_unlock(&info->lock);
- if (thr->work_restart) {
- applog(LOG_INFO, "%s %d: Flush work line %d",
- cointerra->drv->name, cointerra->device_id,__LINE__);
- cta_flush_work(cointerra);
- }
- }
- corehash_time = tdiff(&now, &info->core_hash_start);
- if (corehash_time > 300) {
- cta_send_corehashes(cointerra, info, corehash_time);
- cta_zero_corehashes(info);
- }
- mutex_lock(&info->lock);
- hashes = info->share_hashes;
- info->tot_share_hashes += info->share_hashes;
- info->tot_calc_hashes += info->hashes;
- runtime = cgpu_runtime(thr->cgpu);
- runtime /= 30;
- info->old_hashes[runtime % 32] = info->tot_calc_hashes;
- info->hashes = info->share_hashes = 0;
- mutex_unlock(&info->lock);
- if (unlikely(cointerra->usbinfo.nodev))
- hashes = -1;
- out:
- return hashes;
- }
- /* This is used for a work restart. We don't actually perform the work restart
- * here but wake up the scanwork loop if it's waiting on the conditional so
- * that it can test for the restart message. */
- static void cta_wake(struct cgpu_info *cointerra)
- {
- struct cointerra_info *info = cointerra->device_data;
- mutex_lock(&info->lock);
- pthread_cond_signal(&info->wake_cond);
- mutex_unlock(&info->lock);
- }
- static void cta_shutdown(struct thr_info *thr)
- {
- struct cgpu_info *cointerra = thr->cgpu;
- cta_close(cointerra);
- }
- static void cta_zero_stats(struct cgpu_info *cointerra)
- {
- struct cointerra_info *info = cointerra->device_data;
- int i;
- info->tot_calc_hashes = 0;
- info->tot_reset_hashes = info->tot_hashes;
- info->tot_share_hashes = 0;
- cta_zero_corehashes(info);
- for (i = 0; i < 16 * 2; i++)
- info->old_hashes[i] = 0;
- }
- static int bits_set(char v)
- {
- int c;
- for (c = 0; v; c++)
- v &= v - 1;
- return c;
- }
- static struct api_data *cta_api_stats(struct cgpu_info *cgpu)
- {
- struct api_data *root = NULL;
- struct cointerra_info *info = cgpu->device_data;
- double dev_runtime = cgpu_runtime(cgpu);
- int i, asic, core, coreno = 0;
- struct timeval now;
- char bitmaphex[36];
- uint64_t ghs, val;
- char buf[64];
- uint32_t runtime = cgpu_runtime(cgpu);
- /* Info data */
- root = api_add_uint16(root, "HW Revision", &info->hwrev, false);
- root = api_add_uint32(root, "Serial", &info->serial, false);
- root = api_add_uint8(root, "Asics", &info->asics, false);
- root = api_add_uint8(root, "Dies", &info->dies, false);
- root = api_add_uint16(root, "Cores", &info->cores, false);
- root = api_add_uint8(root, "Board number", &info->board_number, false);
- sprintf(buf, "%u.%u.%u", info->fwrev[0], info->fwrev[1], info->fwrev[2]);
- root = api_add_string(root, "FW Revision", buf, true);
- sprintf(buf, "%04u-%02u-%02u", info->fw_year, info->fw_month, info->fw_day);
- root = api_add_string(root, "FW Date", buf, true);
- root = api_add_uint8(root, "Init diffbits", &info->init_diffbits, false);
- root = api_add_uint8(root, "Min diffbits", &info->min_diffbits, false);
- root = api_add_uint8(root, "Max diffbits", &info->max_diffbits, false);
- /* Status readings */
- for (i = 0; i < CTA_CORES; i++) {
- sprintf(buf, "CoreTemp%d", i);
- root = api_add_int16(root, buf, &info->coretemp[i], false);
- }
- root = api_add_int16(root, "Ambient Low", &info->ambtemp_low, false);
- root = api_add_int16(root, "Ambient Avg", &info->ambtemp_avg, false);
- root = api_add_int16(root, "Ambient High", &info->ambtemp_high, false);
- for (i = 0; i < CTA_PUMPS; i++) {
- sprintf(buf, "PumpRPM%d", i);
- root = api_add_uint16(root, buf, &info->pump_tachs[i], false);
- }
- for (i = 0; i < CTA_FANS; i++) {
- sprintf(buf, "FanRPM%d", i);
- root = api_add_uint16(root, buf, &info->fan_tachs[i], false);
- }
- for (i = 0; i < CTA_CORES; i++) {
- sprintf(buf, "CoreFreqs%d", i);
- root = api_add_uint16(root, buf, &info->corefreqs[i], false);
- }
- for (i = 0; i < CTA_CORES; i++) {
- sprintf(buf, "CoreVolts%d", i);
- root = api_add_uint16(root, buf, &info->corevolts[i], false);
- }
- root = api_add_uint16(root, "Volts3.3", &info->volts33, false);
- root = api_add_uint16(root, "Volts12", &info->volts12, false);
- root = api_add_uint16(root, "Inactive", &info->inactive, false);
- root = api_add_uint16(root, "Active", &info->active, false);
- /* Status settings */
- for (i = 0; i < CTA_CORES; i++) {
- sprintf(buf, "CorePerfMode%d", i);
- root = api_add_uint8(root, buf, &info->coreperf[i], false);
- }
- for (i = 0; i < CTA_FANS; i++) {
- sprintf(buf, "FanSpeed%d", i);
- root = api_add_uint8(root, buf, &info->fanspeed[i], false);
- }
- root = api_add_uint8(root, "DiesActive", &info->dies_active, false);
- for (i = 0; i < CTA_CORES; i++) {
- sprintf(buf, "PipesEnabled%d", i);
- root = api_add_uint8(root, buf, &info->pipes_enabled[i], false);
- }
- /* Status debug */
- root = api_add_int(root, "Underruns", &info->tot_underruns, false);
- for (i = 0; i < CTA_CORES; i++) {
- sprintf(buf, "HWErrors%d", i);
- root = api_add_uint16(root, buf, &info->tot_hw_errors[i], false);
- }
- ghs = info->tot_calc_hashes / dev_runtime;
- root = api_add_uint64(root, "Calc hashrate", &ghs, true);
- ghs = (info->tot_hashes - info->tot_reset_hashes) / dev_runtime;
- root = api_add_uint64(root, "Hashrate", &ghs, true);
- //root = api_add_uint64(root, "cgminer 15m Hashrate", &cgpu->rolling15, true);
- // get runtime in 30 second steps
- runtime = runtime / 30;
- // store the current hashes
- info->old_hashes[runtime%32] = info->tot_calc_hashes;
- // calc the 15 minute average hashrate
- ghs = (info->old_hashes[(runtime+31)%32] - info->old_hashes[(runtime+1)%32])/(15*60);
- root = api_add_uint64(root, "15m Hashrate", &ghs, true);
- ghs = info->tot_share_hashes / dev_runtime;
- root = api_add_uint64(root, "Share hashrate", &ghs, true);
- root = api_add_uint64(root, "Total calc hashes", &info->tot_calc_hashes, false);
- ghs = info->tot_hashes - info->tot_reset_hashes;
- root = api_add_uint64(root, "Total hashes", &ghs, true);
- root = api_add_uint64(root, "Total raw hashes", &info->tot_hashes, false);
- root = api_add_uint64(root, "Total share hashes", &info->tot_share_hashes, false);
- root = api_add_uint64(root, "Total flushed hashes", &info->tot_flushed_hashes, false);
- val = cgpu->diff_accepted * 0x100000000ull;
- root = api_add_uint64(root, "Accepted hashes", &val, true);
- ghs = val / dev_runtime;
- root = api_add_uint64(root, "Accepted hashrate", &ghs, true);
- val = cgpu->diff_rejected * 0x100000000ull;
- root = api_add_uint64(root, "Rejected hashes", &val, true);
- ghs = val / dev_runtime;
- root = api_add_uint64(root, "Rejected hashrate", &ghs, true);
- cgtime(&now);
- dev_runtime = tdiff(&now, &info->core_hash_start);
- if (dev_runtime < 1)
- dev_runtime = 1;
- for (i = 0; i < CTA_CORES; i++) {
- sprintf(buf, "Core%d hashrate", i);
- ghs = info->tot_core_hashes[i] / dev_runtime;
- root = api_add_uint64(root, buf, &ghs, true);
- }
- root = api_add_uint32(root, "Uptime",&info->uptime,false);
- for (asic = 0; asic < 2; asic++) {
- for (core = 0; core < 4; core++) {
- char bitmapcount[40], asiccore[12];
- int count = 0;
- sprintf(asiccore, "Asic%dCore%d", asic, core);
- __bin2hex(bitmaphex, &info->pipe_bitmap[coreno], 16);
- for (i = coreno; i < coreno + 16; i++)
- count += bits_set(info->pipe_bitmap[i]);
- snprintf(bitmapcount, 40, "%d:%s", count, bitmaphex);
- root = api_add_string(root, asiccore, bitmapcount, true);
- coreno += 16;
- }
- }
- root = api_add_uint8(root, "AV", &info->autovoltage, false);
- root = api_add_uint8(root, "Power Supply Percent", &info->current_ps_percent, false);
- //if (info->power_used != 0) {
- {
- double value = info->power_used/100.0;
- value *= (info->power_voltage/100.0);
- root = api_add_double(root, "Power Used", &value, true);
- }
- root = api_add_uint16(root, "IOUT", &info->power_used, false);
- root = api_add_uint16(root, "VOUT", &info->power_voltage, false);
- root = api_add_uint16(root, "IIN", &info->ipower_used, false);
- root = api_add_uint16(root, "VIN", &info->ipower_voltage, false);
- root = api_add_uint16(root, "PSTemp1", &info->power_temps[0], false);
- root = api_add_uint16(root, "PSTemp2", &info->power_temps[1], false);
- //}
- for (core = 0; core < CTA_CORES; core++) {
- char name[20];
- char str[20];
- double value;
- sprintf(name,"IRVIN%d",core+1);
- value = info->irstat_vin[core]/100.0;
- root = api_add_double(root,name,&value,true);
- sprintf(name,"IRIIN%d",core+1);
- value = info->irstat_iin[core]/100.0;
- root = api_add_double(root,name,&value,true);
- sprintf(name,"IRVOUT%d",core+1);
- value = info->irstat_vout[core]/100.0;
- root = api_add_double(root,name,&value,true);
- sprintf(name,"IRIOUT%d",core+1);
- value = info->irstat_iout[core]/100.0;
- root = api_add_double(root,name,&value,true);
- sprintf(name,"IRTEMP1_%d",core+1);
- value = info->irstat_temp1[core]/100.0;
- root = api_add_double(root,name,&value,true);
- sprintf(name,"IRTEMP2_%d",core+1);
- value = info->irstat_temp2[core]/100.0;
- root = api_add_double(root,name,&value,true);
- sprintf(name,"IRPOUT%d",core+1);
- value = info->irstat_pout[core]/100.0;
- root = api_add_double(root,name,&value,true);
- sprintf(name,"IRPIN%d",core+1);
- value = info->irstat_pin[core]/100.0;
- root = api_add_double(root,name,&value,true);
- sprintf(name,"IREFFICIENCY%d",core+1);
- value = info->irstat_efficiency[core]/100.0;
- root = api_add_double(root,name,&value,true);
- sprintf(name,"IRSTATUS%d",core+1);
- //root = api_add_uint16(root,name,&info->irstat_status[core],false);
- sprintf(str,"0x%04X",info->irstat_status[core]);
- root = api_add_string(root, name, str, true);
- }
- for (i = 0; i < CTA_CORES; i++) {
- sprintf(buf, "CoreFmatch%d", i);
- root = api_add_int16(root, buf, &info->fmatch_errors[i], false);
- }
- return root;
- }
- static void cta_statline_before(char *buf, size_t bufsiz, struct cgpu_info *cointerra)
- {
- struct cointerra_info *info = cointerra->device_data;
- double max_volt = 0;
- int freq = 0, i;
- for (i = 0; i < CTA_CORES; i++) {
- if (info->corevolts[i] > max_volt)
- max_volt = info->corevolts[i];
- if (info->corefreqs[i] > freq)
- freq = info->corefreqs[i];
- }
- max_volt /= 1000;
- tailsprintf(buf, bufsiz, "%3dMHz %3.1fC %3.2fV", freq, cointerra->temp, max_volt);
- }
- struct device_drv cointerra_drv = {
- .drv_id = DRIVER_cointerra,
- .dname = "cointerra",
- .name = "CTA",
- .drv_detect = cta_detect,
- .thread_prepare = cta_prepare,
- .hash_work = hash_queued_work,
- .queue_full = cta_fill,
- .update_work = cta_update_work,
- .scanwork = cta_scanwork,
- .flush_work = cta_wake,
- .get_api_stats = cta_api_stats,
- .get_statline_before = cta_statline_before,
- .thread_shutdown = cta_shutdown,
- .zero_stats = cta_zero_stats,
- .max_diff = 64, // Set it below the actual limit to check nonces
- };
|