Browse Source

titan: Use knc-asic library for transport layer

Vitalii Demianets 11 years ago
parent
commit
bd500ebe90
5 changed files with 85 additions and 353 deletions
  1. 2 1
      Makefile.am
  2. 3 1
      configure.ac
  3. 30 74
      driver-titan.c
  4. 43 254
      titan-asic.c
  5. 7 23
      titan-asic.h

+ 2 - 1
Makefile.am

@@ -276,7 +276,8 @@ endif
 
 if USE_KNC
 if HAS_SCRYPT
-bfgminer_SOURCES += driver-titan.c titan-asic.c titan-asic.h
+bfgminer_SOURCES += driver-titan.c titan-asic.c knc-asic/knc-asic.c knc-asic/crc32.c knc-asic/knc-spimux.c knc-asic/knc-transport-spimux.c titan-asic.h knc-asic/include/knc-asic.h knc-asic/include/knc-transport.h
+bfgminer_CPPFLAGS += -I. -I./knc-asic/include
 else
 bfgminer_SOURCES += driver-knc.c
 endif

+ 3 - 1
configure.ac

@@ -609,7 +609,9 @@ if test "x$knc" = xyes; then
 		#endif
 	])
 	AC_DEFINE([USE_KNC], [1], [Defined to 1 if KnC support is wanted])
-	need_lowl_spi=yes
+	if test "x$scrypt" != xyes; then
+		need_lowl_spi=yes
+	fi
 fi
 AM_CONDITIONAL([USE_KNC], [test x$knc = xyes])
 

+ 30 - 74
driver-titan.c

@@ -10,11 +10,9 @@
 
 #include <fcntl.h>
 #include <sys/ioctl.h>
-#include <linux/spi/spidev.h>
 
 #include "deviceapi.h"
 #include "logging.h"
-#include "lowl-spi.h"
 #include "miner.h"
 #include "util.h"
 
@@ -26,11 +24,6 @@
 
 #define	KNC_POLL_INTERVAL_US		10000
 
-#define	KNC_TITAN_SPI_SPEED		3000000
-#define	KNC_TITAN_SPI_DELAY		0
-#define	KNC_TITAN_SPI_MODE		(SPI_CPHA | SPI_CPOL | SPI_CS_HIGH)
-#define	KNC_TITAN_SPI_BITS		8
-
 /* Specify here minimum number of leading zeroes in hash */
 #define	DEFAULT_DIFF_FILTERING_ZEROES	12
 #define	DEFAULT_DIFF_FILTERING_FLOAT	(1. / ((double)(0x00000000FFFFFFFF >> DEFAULT_DIFF_FILTERING_ZEROES)))
@@ -67,7 +60,7 @@ struct knc_titan_die {
 };
 
 struct knc_titan_info {
-	struct spi_port *spi;
+	void *ctx;
 	struct cgpu_info *cgpu;
 	int cores;
 	struct knc_titan_die dies[KNC_TITAN_MAX_ASICS][KNC_TITAN_DIES_PER_ASIC];
@@ -81,37 +74,14 @@ struct knc_titan_info {
 	struct work *devicework;
 };
 
-static bool knc_titan_spi_open(const char *repr, struct spi_port * const spi)
-{
-	const char * const spipath = "/dev/spidev1.0";
-	const int fd = open(spipath, O_RDWR);
-	const uint8_t lsbfirst = 0;
-	if (0 > fd)
-		return false;
-	if (ioctl(fd, SPI_IOC_WR_MODE         , &spi->mode )) goto fail;
-	if (ioctl(fd, SPI_IOC_WR_LSB_FIRST    , &lsbfirst  )) goto fail;
-	if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &spi->bits )) goto fail;
-	if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ , &spi->speed)) goto fail;
-	spi->fd = fd;
-	return true;
-
-fail:
-	close(fd);
-	spi->fd = -1;
-	applog(LOG_WARNING, "%s: Failed to open %s", repr, spipath);
-	return false;
-}
-
-#define	knc_titan_spi_txrx	linux_spi_txrx
-
 static bool knc_titan_detect_one(const char *devpath)
 {
 	static struct cgpu_info *prev_cgpu = NULL;
 	struct cgpu_info *cgpu;
-	struct spi_port *spi;
+	void *ctx;
 	struct knc_titan_info *knc;
 	int cores = 0, asic, die;
-	struct titan_info_response resp;
+	struct knc_die_info die_info;
 	char repr[6];
 
 	cgpu = malloc(sizeof(*cgpu));
@@ -119,22 +89,7 @@ static bool knc_titan_detect_one(const char *devpath)
 		quit(1, "Failed to alloc cgpu_info");
 
 	if (!prev_cgpu) {
-		spi = calloc(1, sizeof(*spi));
-		if (unlikely(!spi))
-			quit(1, "Failed to alloc spi_port");
-
-		/* Be careful, read lowl-spi.h comments for warnings */
-		memset(spi, 0, sizeof(*spi));
-		spi->txrx = knc_titan_spi_txrx;
-		spi->cgpu = cgpu;
-		spi->repr = knc_titan_drv.dname;
-		spi->logprio = LOG_ERR;
-		spi->speed = KNC_TITAN_SPI_SPEED;
-		spi->delay = KNC_TITAN_SPI_DELAY;
-		spi->mode = KNC_TITAN_SPI_MODE;
-		spi->bits = KNC_TITAN_SPI_BITS;
-
-		if (!knc_titan_spi_open(knc_titan_drv.name, spi)) {
+		if (NULL == (ctx = knc_trnsp_new(NULL))) {
 			free(cgpu);
 			return false;
 		}
@@ -143,28 +98,29 @@ static bool knc_titan_detect_one(const char *devpath)
 		if (unlikely(!knc))
 			quit(1, "Failed to alloc knc_titan_info");
 
-		knc->spi = spi;
+		knc->ctx = ctx;
 		knc->cgpu = cgpu;
 		knc->workqueue_max = KNC_TITAN_WORKSLOTS_PER_CORE + 1;
 	} else {
 		knc = prev_cgpu->device_data;
-		spi = knc->spi;
+		ctx = knc->ctx;
 	}
 
 	snprintf(repr, sizeof(repr), "%s %s", knc_titan_drv.name, devpath);
 	asic = atoi(devpath);
 	for (die = 0; die < KNC_TITAN_DIES_PER_ASIC; ++die) {
-		if (!knc_titan_spi_get_info(repr, spi, &resp, die, KNC_TITAN_CORES_PER_DIE))
+		die_info.cores = KNC_TITAN_CORES_PER_DIE; /* core hint */
+		if (!knc_titan_get_info(repr, ctx, asic, die, &die_info))
 			continue;
-		if (0 < resp.cores) {
+		if (0 < die_info.cores) {
 			knc->dies[asic][die] = (struct knc_titan_die) {
 				.asicno = asic,
 				.dieno = die,
-				.cores = resp.cores,
+				.cores = die_info.cores,
 				.first_proc = cgpu,
 				.freq = KNC_TITAN_DEFAULT_FREQUENCY,
 			};
-			cores += resp.cores;
+			cores += die_info.cores;
 		} else {
 			knc->dies[asic][die] = (struct knc_titan_die) {
 				.asicno = -INT_MAX,
@@ -178,8 +134,7 @@ static bool knc_titan_detect_one(const char *devpath)
 		free(cgpu);
 		if (!prev_cgpu) {
 			free(knc);
-			close(spi->fd);
-			free(spi);
+			knc_trnsp_free(ctx);
 		}
 		return false;
 	}
@@ -220,11 +175,11 @@ static void knc_titan_detect(void)
 	generic_detect(&knc_titan_drv, knc_titan_detect_one, knc_titan_detect_auto, GDF_REQUIRE_DNAME | GDF_DEFAULT_NOAUTO);
 }
 
-static void knc_titan_clean_flush(const char *repr, struct spi_port * const spi, int die)
+static void knc_titan_clean_flush(const char *repr, void * const ctx, int asic, int die)
 {
-	struct titan_report report;
+	struct knc_report report;
 	bool unused;
-	knc_titan_set_work(repr, spi, &report, die, 0xFFFF, 0, NULL, true, &unused);
+	knc_titan_set_work(repr, ctx, asic, die, 0xFFFF, 0, NULL, true, &unused, &report);
 }
 
 static bool knc_titan_init(struct thr_info * const thr)
@@ -279,7 +234,7 @@ static bool knc_titan_init(struct thr_info * const thr)
 			applog(LOG_DEBUG, "%s Allocated core %d:%d:%d", proc->device->dev_repr, asic, die, (i - core_base));
 
 			if (0 == knccore->coreno)
-				knc_titan_clean_flush(proc->device->dev_repr, knc->spi, knccore->dieno);
+				knc_titan_clean_flush(proc->device->dev_repr, knc->ctx, knccore->asicno, knccore->dieno);
 
 			proc = proc->next_proc;
 			if ((!proc) || proc->device == proc)
@@ -320,7 +275,7 @@ static bool knc_titan_init(struct thr_info * const thr)
 		mythr = proc->thr[0];
 		knccore = mythr->cgpu_data;
 		applog(LOG_DEBUG, "%s Setup core %d:%d:%d, nonces 0x%08X - 0x%08X", proc->device->dev_repr, knccore->asicno, knccore->dieno, knccore->coreno, setup_params.nonce_bottom, setup_params.nonce_top);
-		knc_titan_setup_core(proc->device->dev_repr, knc->spi, &setup_params, knccore->dieno, knccore->coreno);
+		knc_titan_setup_core(proc->device->dev_repr, knc->ctx, knccore->asicno, knccore->dieno, knccore->coreno, &setup_params);
 	}
 
 	timer_set_now(&thr->tv_poll);
@@ -435,8 +390,8 @@ static void knc_titan_poll(struct thr_info * const thr)
 	struct work *work, *tmp;
 	int workaccept = 0;
 	unsigned long delay_usecs = KNC_POLL_INTERVAL_US;
-	struct titan_report report;
-	struct titan_info_response info_resp;
+	struct knc_report report;
+	struct knc_die_info die_info;
 	int asic = 0; /* TODO: the asic number must iterate from 0 to 5 */
 	int die = 0; /* TODO: the die number must iterate from 0 to 3 */
 	int i, tmp_int;
@@ -449,7 +404,7 @@ static void knc_titan_poll(struct thr_info * const thr)
 	knccore = cgpu->thr[0]->cgpu_data;
 	DL_FOREACH_SAFE(knc->workqueue, work, tmp) {
 		bool work_accepted;
-		if (!knc_titan_set_work(cgpu->dev_repr, knc->spi, &report, die, 0xFFFF, knccore->next_slot, work, knc->need_flush, &work_accepted))
+		if (!knc_titan_set_work(cgpu->dev_repr, knc->ctx, asic, die, 0xFFFF, knccore->next_slot, work, knc->need_flush, &work_accepted, &report))
 			work_accepted = false;
 		if (!work_accepted)
 			break;
@@ -477,37 +432,38 @@ static void knc_titan_poll(struct thr_info * const thr)
 	while (true) {
 		if (0 >= knc->dies[asic][die].cores)
 			break;
-		if (!knc_titan_spi_get_info(cgpu->dev_repr, knc->spi, &info_resp, die, knc->dies[asic][die].cores))
+		die_info.cores = knc->dies[asic][die].cores; /* core hint */
+		if (!knc_titan_get_info(cgpu->dev_repr, knc->ctx, asic, die, &die_info))
 			break;
 		for (proc = knc->dies[asic][die].first_proc; proc; proc = proc->next_proc) {
 			mythr = proc->thr[0];
 			knccore = mythr->cgpu_data;
 			if ((knccore->dieno != die) || (knccore->asicno != asic))
 				break;
-			if (!info_resp.have_report[knccore->coreno])
+			if (!die_info.has_report[knccore->coreno])
 				continue;
-			if (!knc_titan_get_report(proc->proc_repr, knc->spi, &report, die, knccore->coreno))
+			if (!knc_titan_get_report(proc->proc_repr, knc->ctx, asic, die, knccore->coreno, &report))
 				continue;
 			/* if last_nonce.slot == 0, then there was a flush and all reports are stale */
 			if (0 != knccore->last_nonce.slot) {
 				for (i = 0; i < KNC_TITAN_NONCES_PER_REPORT; ++i) {
-					if ((report.nonces[i].slot == knccore->last_nonce.slot) &&
-					    (report.nonces[i].nonce == knccore->last_nonce.nonce))
+					if ((report.nonce[i].slot == knccore->last_nonce.slot) &&
+					    (report.nonce[i].nonce == knccore->last_nonce.nonce))
 						break;
-					tmp_int = report.nonces[i].slot;
+					tmp_int = report.nonce[i].slot;
 					HASH_FIND_INT(knc->devicework, &tmp_int, work);
 					if (!work) {
 						applog(LOG_WARNING, "%"PRIpreprv": Got nonce for unknown work in slot %u", proc->proc_repr, tmp_int);
 						continue;
 					}
-					if (submit_nonce(mythr, work, report.nonces[i].nonce)) {
+					if (submit_nonce(mythr, work, report.nonce[i].nonce)) {
 						hashes_done2(mythr, DEFAULT_DIFF_HASHES_PER_NONCE, NULL);
 						knccore->hwerr_in_row = 0;
 					}
 				}
 			}
-			knccore->last_nonce.slot = report.nonces[0].slot;
-			knccore->last_nonce.nonce = report.nonces[0].nonce;
+			knccore->last_nonce.slot = report.nonce[0].slot;
+			knccore->last_nonce.nonce = report.nonce[0].nonce;
 		}
 		/* TODO: switch to next asic/die */
 		break;

+ 43 - 254
titan-asic.c

@@ -8,277 +8,70 @@
  * any later version.  See COPYING for more details.
  */
 
-#include <zlib.h>
-
 #include "miner.h"
 #include "logging.h"
-#include "lowl-spi.h"
 
 #include "titan-asic.h"
 
-/* ASIC Command codes */
-#define	KNC_ASIC_CMD_GETINFO		0x80
-#define	KNC_ASIC_CMD_REPORT		0x82
-#define	KNC_ASIC_CMD_SETWORK		0x81
-#define	KNC_ASIC_CMD_SETWORK_URGENT	0x83
-#define	KNC_ASIC_CMD_SETUP_CORE		0x87
-
-/* Error bits */
-#define	ERR_SEND_CRC_FAIL	(1 << 0)
-#define	ERR_RCV_CRC_FAIL	(1 << 1)
-#define	ERR_BAD_RESPONSE	(1 << 2)
-#define	ERR_OTHER_ERR		(1 << 31)
-
-#define	CRC32_SIZE			4
-/* In SPI responses after crc goes trailer: status(1 byte) + address(3 bytes) */
-#define	SPI_RESPONSE_TRAILER_SIZE	4
-
-#define	RCV_STATUS_NOFLAGS	0x81
-#define	RCV_STATUS_ACCEPTED_WORK (1 << 2)
-#define	RCV_STATUS_SEND_CRC_BAD	(1 << 5)
-
-/* send_size - size of send_buf, without crc
- * transfer_size - total size of transfer
- */
-static uint8_t * spi_transfer(struct spi_port * const spi, uint8_t *send_buf, int send_size, int transfer_size, int rcv_crc_data_len, uint32_t *errors, bool *work_accepted)
+bool knc_titan_get_info(const char *repr, void * const ctx, int channel, int die, struct knc_die_info *die_info)
 {
-	uint8_t *rxbuf, crcbuf[CRC32_SIZE];
-	uint32_t crc;
-	uint8_t rcv_status;
-	int min_transfer_size = send_size + CRC32_SIZE + SPI_RESPONSE_TRAILER_SIZE;
-	if (0 < rcv_crc_data_len) {
-		if (min_transfer_size < (4 + rcv_crc_data_len + CRC32_SIZE + SPI_RESPONSE_TRAILER_SIZE))
-			min_transfer_size = 4 + rcv_crc_data_len + CRC32_SIZE + SPI_RESPONSE_TRAILER_SIZE;
-	}
-
-	*errors = 0;
-	*work_accepted = false;
-	if (transfer_size < min_transfer_size) {
-exit_other_error:
-		*errors |= ERR_OTHER_ERR;
-		return NULL;
-	}
-	spi_clear_buf(spi);
-	spi_emit_buf(spi, send_buf, send_size);
-	crc = crc32(0, Z_NULL, 0);
-	crc = crc32(crc, send_buf, send_size);
-	*((uint32_t *)crcbuf) = htobe32(crc);
-	spi_emit_buf(spi, crcbuf, CRC32_SIZE);
-	spi_emit_nop(spi, transfer_size - spi_getbufsz(spi));
-	if (!spi_txrx(spi))
-		goto exit_other_error;
-	rxbuf = spi_getrxbuf(spi);
-
-	rcv_status = rxbuf[transfer_size - SPI_RESPONSE_TRAILER_SIZE];
-	if (RCV_STATUS_NOFLAGS != (rcv_status & (~(RCV_STATUS_SEND_CRC_BAD | RCV_STATUS_ACCEPTED_WORK))))
-		*errors |= ERR_BAD_RESPONSE;
-	if (rcv_status & RCV_STATUS_SEND_CRC_BAD)
-		*errors |= ERR_SEND_CRC_FAIL;
-	if (0 < rcv_crc_data_len) {
-		crc = crc32(0, Z_NULL, 0);
-		crc = crc32(crc, rxbuf + 4, rcv_crc_data_len);
-		memcpy(crcbuf, &rxbuf[4 + rcv_crc_data_len], CRC32_SIZE);
-		if (crc != be32toh(*((uint32_t *)crcbuf)))
-			*errors |= ERR_RCV_CRC_FAIL;
-	}
-	*work_accepted = ((0 == *errors) && (rcv_status & RCV_STATUS_ACCEPTED_WORK));
-#if 0
-	{
-		uint8_t *txbuf = spi_gettxbuf(spi);
-		char str[8192];
-		int i, n;
-		n = 0;
-		for (i = 0; i < transfer_size; ++i)
-			n += sprintf(&str[n], i ? ",0x%02hhX" : "0x%02hhX", txbuf[i]);
-		applog(LOG_NOTICE, "TX: %s", str);
-		n = 0;
-		for (i = 0; i < transfer_size; ++i)
-			n += sprintf(&str[n], i ? ",0x%02hhX" : "0x%02hhX", rxbuf[i]);
-		applog(LOG_NOTICE, "RX: %s", str);
-		if (0 < rcv_crc_data_len)
-			applog(LOG_NOTICE, "RX-CRC: 0x%08X", crc);
-	}
-#endif
-	return rxbuf;
+	int rc;
+	rc = knc_detect_die(ctx, channel, die, die_info);
+	return (0 == rc);
 }
 
-/*
- * core_hint - which number of cores is expected. The function needs to know it to
- *   calculate the SPI transfer size. It uses this hint for the first transfer.
- *   If the first transfer fails, it assumes that it is because of wrong hint and
- *   then tries to detect right number of cores from the first response.
- */
-bool knc_titan_spi_get_info(const char *repr, struct spi_port * const spi, struct titan_info_response *resp, int die, int core_hint)
+bool knc_titan_set_work(const char *repr, void * const ctx, int channel, int die, int core, int slot, struct work *work, bool urgent, bool *work_accepted, struct knc_report *report)
 {
-	uint8_t get_info_cmd[] = {KNC_ASIC_CMD_GETINFO, die, 0x00, 0x00};
-	uint8_t *rxbuf;
-	uint32_t errors;
-	uint16_t revision;
-	int transfer_size = 24 + ((core_hint + 3) / 4);
-	int i, core;
-	bool unused;
+	int request_length = 4 + 1 + 6*4 + 3*4 + 8*4;
+	uint8_t request[request_length];
+	int response_length = 1 + 1 + (1 + 4) * 5;
+	uint8_t response[response_length];
+	int status;
 
-	for (i = 0; i < 3; ++i) {
-		rxbuf = spi_transfer(spi, get_info_cmd, sizeof(get_info_cmd), transfer_size, transfer_size - 4 - CRC32_SIZE - SPI_RESPONSE_TRAILER_SIZE, &errors, &unused);
-		if (NULL == rxbuf) {
-exit_unrec_error:	applog(LOG_ERR, "%s[%d] knc_titan_spi_get_info: Unrecognized error", repr, die);
+	request_length = knc_prepare_titan_setwork(request, die, core, slot, work, urgent);
+	status = knc_syncronous_transfer(ctx, channel, request_length, request, response_length, response);
+	if (status != KNC_ACCEPTED) {
+		*work_accepted = false;
+		if (response[0] == 0x7f) {
+			applog(LOG_DEBUG, "%s[%d:%d]: Core disabled", repr, channel, die);
 			return false;
 		}
-		if (errors != ERR_SEND_CRC_FAIL)
-			break;
-		/* If the only error is SEND_CRC, assume there was a communication error
-		 * and retry three times
-		 */
-	}
-	if (ERR_SEND_CRC_FAIL == errors) {
-		applog(LOG_ERR, "%s[%d] knc_titan_spi_get_info: CRC error in Tx", repr, die);
-		return false;
-	}
-
-	if (0 != errors) {
-		/* It might be that we have different number of cores. Try to guess it
-		 * from partial response.
-		 */
-		revision = (rxbuf[6] << 8) | rxbuf[7];
-		if (KNC_TITAN_ASIC_REVISION != revision) {
-exit_bad_revision:	applog(LOG_ERR, "%s[%d] knc_titan_spi_get_info: Bad revision 0x%04hX", repr, die, revision);
+		if (status & KNC_ERR_MASK) {
+			applog(LOG_ERR, "%s[%d:%d]: Failed to set work state (%x)", repr, channel, die, status);
 			return false;
 		}
-		resp->cores = (rxbuf[4] << 8) | rxbuf[5];
-		if (resp->cores != core_hint) {
-			applog(LOG_NOTICE, "%s[%d] core hint %d might be wrong, new guess is %d", repr, die, core_hint, resp->cores);
-			transfer_size = 24 + ((resp->cores + 3) / 4);
-			for (i = 0; i < 3; ++i) {
-				rxbuf = spi_transfer(spi, get_info_cmd, sizeof(get_info_cmd), transfer_size, transfer_size - 4 - CRC32_SIZE - SPI_RESPONSE_TRAILER_SIZE, &errors, &unused);
-				if (NULL == rxbuf)
-					goto exit_unrec_error;
-				if (errors != ERR_SEND_CRC_FAIL)
-					break;
-				/* If the only error is SEND_CRC, assume there was a communication error
-				 * and retry three times
-				 */
-			}
+		if (!(status & KNC_ERR_MASK)) {
+			/* !KNC_ERRMASK */
+			applog(LOG_DEBUG, "%s[%d:%d]: Core busy", repr, channel, die, status);
 		}
 	}
 
-	if (0 != errors) {
-		applog(LOG_ERR, "%s[%d] knc_titan_spi_get_info: Communication failed, errors = 0x%X", repr, die, errors);
-		return false;
-	}
-
-	revision = (rxbuf[6] << 8) | rxbuf[7];
-	if (KNC_TITAN_ASIC_REVISION != revision)
-		goto exit_bad_revision;
-	resp->cores = (rxbuf[4] << 8) | rxbuf[5];
-	resp->pll_state = *((uint64_t *)(&rxbuf[8]));
-	for (core = 0; core < resp->cores; ) {
-		uint8_t data = rxbuf[16 + (core / 4)];
-		resp->want_work[core] = !!(data & (1 << 7));
-		resp->have_report[core] = !!(data & (1 << 6));
-		if (++core >= resp->cores)
-			break;
-		resp->want_work[core] = !!(data & (1 << 5));
-		resp->have_report[core] = !!(data & (1 << 4));
-		if (++core >= resp->cores)
-			break;
-		resp->want_work[core] = !!(data & (1 << 3));
-		resp->have_report[core] = !!(data & (1 << 2));
-		if (++core >= resp->cores)
-			break;
-		resp->want_work[core] = !!(data & (1 << 1));
-		resp->have_report[core] = !!(data & (1 << 0));
-		if (++core >= resp->cores)
-			break;
-	}
-
+	knc_decode_report(response, report, KNC_VERSION_TITAN);
 	return true;
 }
 
-static void knc_titan_parse_get_report(uint8_t *data, struct titan_report *report)
-{
-	int i;
-
-	report->flags = data[0];
-	report->core_counter = data[1];
-	report->slot_core = (data[2] >> 4) & 0x0F;
-	for (i = 0; i < KNC_TITAN_NONCES_PER_REPORT; ++i) {
-		report->nonces[i].slot = data[2 + i * 5] & 0x0F;
-		report->nonces[i].nonce = ((uint32_t)data[2 + i * 5 + 1] << 24) |
-					  ((uint32_t)data[2 + i * 5 + 2] << 16) |
-					  ((uint32_t)data[2 + i * 5 + 3] << 8) |
-					  ((uint32_t)data[2 + i * 5 + 4]);
-	}
-}
-
-bool knc_titan_set_work(const char *repr, struct spi_port * const spi, struct titan_report *report, int die, int core, int slot, struct work *work, bool urgent, bool *work_accepted)
+bool knc_titan_get_report(const char *repr, void * const ctx, int channel, int die, int core, struct knc_report *report)
 {
-#define	SETWORK_CMD_SIZE	(5 + BLOCK_HEADER_BYTES_WITHOUT_NONCE)
-	uint8_t set_work_cmd_aligned[3 + SETWORK_CMD_SIZE] = {
-		0, 0, 0, /* three extra bytes for alignment */
-		urgent ? KNC_ASIC_CMD_SETWORK_URGENT : KNC_ASIC_CMD_SETWORK,
-		die,
-		(core >> 8) & 0xFF,
-		core & 0xFF,
-		0xF0 | (slot & 0x0F),
-		/* next follows data. Thanks to the first three extra bytes it is 64bit-aligned */
-	};
-	const int send_size = sizeof(set_work_cmd_aligned) - 3;
-	const int transfer_size = send_size + CRC32_SIZE + SPI_RESPONSE_TRAILER_SIZE;
-	uint8_t *rxbuf;
-	int i;
-	uint32_t *src, *dst;
-	uint32_t errors;
+	uint8_t request[4];
+	int request_length;
+	int response_length = 1 + 1 + (1 + 4) * 5;
+	uint8_t response[response_length];
+	int status;
 
-	if (NULL != work) {
-		src = (uint32_t *)work->data;
-		dst = (uint32_t *)(&set_work_cmd_aligned[3 + 5]);
-		for (i = 0; i < (BLOCK_HEADER_BYTES_WITHOUT_NONCE / 4); ++i)
-			dst[i] = htobe32(src[i]);
-	} else {
-		/* Empty work is allowed only for the "purge" (slot = 0) operation */
-		if (0 != slot) {
-			applog(LOG_ERR, "%s[%d:%d] knc_titan_set_work: Invalid work", repr, die, core);
-			return false;
-		}
-	}
-
-	rxbuf = spi_transfer(spi, &set_work_cmd_aligned[3], send_size, transfer_size, 2 + KNC_TITAN_NONCES_PER_REPORT * 5, &errors, work_accepted);
-	if (NULL == rxbuf) {
-		applog(LOG_ERR, "%s[%d:%d] knc_titan_set_work: Unrecognized error", repr, die, core);
-		return false;
-	}
-	if (0 != errors) {
-		applog(LOG_ERR, "%s[%d:%d] knc_titan_set_work: Communication failed, errors = 0x%X", repr, die, core, errors);
+	request_length = knc_prepare_report(request, die, core);
+	status = knc_syncronous_transfer(ctx, channel, request_length, request, response_length, response);
+	if (status) {
+		applog(LOG_ERR, "%s[%d:%d]: get_report failed (%x)", repr, channel, die, status);
 		return false;
 	}
-	knc_titan_parse_get_report(&rxbuf[4], report);
-	return true;
-}
 
-bool knc_titan_get_report(const char *repr, struct spi_port * const spi, struct titan_report *report, int die, int core)
-{
-	uint8_t get_report_cmd[] = {KNC_ASIC_CMD_REPORT, die, (core >> 8) & 0xFF, core & 0xFF};
-	const int send_size = sizeof(get_report_cmd);
-	const int transfer_size = send_size + 2 + KNC_TITAN_NONCES_PER_REPORT * 5 + CRC32_SIZE + SPI_RESPONSE_TRAILER_SIZE;
-	uint8_t *rxbuf;
-	uint32_t errors;
-	bool unused;
-
-	rxbuf = spi_transfer(spi, get_report_cmd, send_size, transfer_size, 2 + KNC_TITAN_NONCES_PER_REPORT * 5, &errors, &unused);
-	if (NULL == rxbuf) {
-		applog(LOG_ERR, "%s[%d:%d] knc_titan_get_report: Unrecognized error", repr, die, core);
-		return false;
-	}
-	if (0 != errors) {
-		applog(LOG_ERR, "%s[%d:%d] knc_titan_get_report: Communication failed, errors = 0x%X", repr, die, core, errors);
-		return false;
-	}
-	knc_titan_parse_get_report(&rxbuf[4], report);
+	knc_decode_report(response, report, KNC_VERSION_TITAN);
 	return true;
 }
 
-bool knc_titan_setup_core(const char *repr, struct spi_port * const spi, struct titan_setup_core_params *params, int die, int core)
+bool knc_titan_setup_core(const char *repr, void * const ctx, int channel, int die, int core, struct titan_setup_core_params *params)
 {
+#define	SETWORK_CMD_SIZE	(5 + BLOCK_HEADER_BYTES_WITHOUT_NONCE)
 	/* The size of command is the same as for set_work */
 	uint8_t setup_core_cmd[SETWORK_CMD_SIZE] = {
 		KNC_ASIC_CMD_SETUP_CORE,
@@ -288,10 +81,9 @@ bool knc_titan_setup_core(const char *repr, struct spi_port * const spi, struct
 		/* next follows padding and data */
 	};
 	const int send_size = sizeof(setup_core_cmd);
-	const int transfer_size = send_size + CRC32_SIZE + SPI_RESPONSE_TRAILER_SIZE;
-	uint8_t *rxbuf;
-	uint32_t errors;
-	bool unused;
+	int response_length = send_size;
+	uint8_t response[response_length];
+	int status;
 	uint32_t *src, *dst;
 	int i;
 	struct titan_packed_core_params {
@@ -494,14 +286,11 @@ bool knc_titan_setup_core(const char *repr, struct spi_port * const spi, struct
 	for (i = 0; i < (sizeof(packed_params) / 4); ++i)
 		dst[i] = htobe32(src[i]);
 
-	rxbuf = spi_transfer(spi, setup_core_cmd, send_size, transfer_size, 0, &errors, &unused);
-	if (NULL == rxbuf) {
-		applog(LOG_ERR, "%s[%d:%d] knc_titan_setup_core: Unrecognized error", repr, die, core);
-		return false;
-	}
-	if (0 != errors) {
-		applog(LOG_ERR, "%s[%d:%d] knc_titan_setup_core: Communication failed, errors = 0x%X", repr, die, core, errors);
+	status = knc_syncronous_transfer(ctx, channel, send_size, setup_core_cmd, response_length, response);
+	if (status) {
+		applog(LOG_ERR, "%s[%d:%d]: setup_core failed (%x)", repr, channel, die, status);
 		return false;
 	}
+
 	return true;
-}
+}

+ 7 - 23
titan-asic.h

@@ -1,8 +1,8 @@
 #ifndef __TITAN_ASIC_H
 #define __TITAN_ASIC_H
 
-#define	BLOCK_HEADER_BYTES			80
-#define	BLOCK_HEADER_BYTES_WITHOUT_NONCE	(BLOCK_HEADER_BYTES - 4)
+#include "knc-asic.h"
+#include "knc-transport.h"
 
 #define	KNC_TITAN_MAX_ASICS		6
 #define	KNC_TITAN_DIES_PER_ASIC		4
@@ -12,27 +12,11 @@
 #define	KNC_TITAN_THREADS_PER_CORE	8
 #define	KNC_TITAN_NONCES_PER_REPORT	5
 
-#define	KNC_TITAN_ASIC_REVISION		0xA102
-
 struct nonce_report {
 	uint32_t nonce;
 	uint8_t slot;
 };
 
-struct titan_info_response {
-	uint64_t pll_state;
-	uint16_t cores;
-	bool want_work[KNC_TITAN_CORES_PER_DIE];
-	bool have_report[KNC_TITAN_CORES_PER_DIE];
-};
-
-struct titan_report {
-	uint8_t flags;
-	uint8_t core_counter;
-	uint8_t slot_core;
-	struct nonce_report nonces[KNC_TITAN_NONCES_PER_REPORT];
-};
-
 struct titan_setup_core_params {
 	uint16_t bad_address_mask[2];
 	uint16_t bad_address_match[2];
@@ -46,9 +30,9 @@ struct titan_setup_core_params {
 	uint32_t nonce_bottom;
 };
 
-bool knc_titan_spi_get_info(const char *repr, struct spi_port * const spi, struct titan_info_response *resp, int die, int core_hint);
-bool knc_titan_get_report(const char *repr, struct spi_port * const spi, struct titan_report *report, int die, int core);
-bool knc_titan_set_work(const char *repr, struct spi_port * const spi, struct titan_report *report, int die, int core, int slot, struct work *work, bool urgent, bool *work_accepted);
-bool knc_titan_setup_core(const char *repr, struct spi_port * const spi, struct titan_setup_core_params *params, int die, int core);
+bool knc_titan_get_info(const char *repr, void * const ctx, int channel, int die, struct knc_die_info *die_info);
+bool knc_titan_set_work(const char *repr, void * const ctx, int channel, int die, int core, int slot, struct work *work, bool urgent, bool *work_accepted, struct knc_report *report);
+bool knc_titan_get_report(const char *repr, void * const ctx, int channel, int die, int core, struct knc_report *report);
+bool knc_titan_setup_core(const char *repr, void * const ctx, int channel, int die, int core, struct titan_setup_core_params *params);
 
-#endif /* __TITAN_ASIC_H */
+#endif /* __TITAN_ASIC_H */