Use semaphores to signal a reset to pause the read thread while the write thread does the actual reset, making all writes come from the same place.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
diff --git a/driver-avalon.c b/driver-avalon.c
index 5bafe17..7373c1d 100644
--- a/driver-avalon.c
+++ b/driver-avalon.c
@@ -716,25 +716,15 @@ static void avalon_parse_results(struct cgpu_info *avalon, struct avalon_info *i
memmove(buf, buf + spare, *offset);
}
-static void __avalon_running_reset(struct cgpu_info *avalon,
+static void avalon_running_reset(struct cgpu_info *avalon,
struct avalon_info *info)
{
- info->reset = true;
avalon_reset(avalon, false);
avalon_idle(avalon, info);
avalon->results = 0;
info->reset = false;
}
-static void avalon_running_reset(struct cgpu_info *avalon,
- struct avalon_info *info)
-{
- /* Lock to prevent more work being sent during reset */
- mutex_lock(&info->qlock);
- __avalon_running_reset(avalon, info);
- mutex_unlock(&info->qlock);
-}
-
static void *avalon_get_results(void *userdata)
{
struct cgpu_info *avalon = (struct cgpu_info *)userdata;
@@ -762,6 +752,15 @@ static void *avalon_get_results(void *userdata)
offset = 0;
}
+ if (unlikely(info->reset)) {
+ /* Tell the write thread it can start the reset */
+ sem_post(&info->write_sem);
+ sem_wait(&info->read_sem);
+
+ /* Discard anything in the buffer */
+ offset = 0;
+ }
+
cgtime(&tv_start);
ret = avalon_read(avalon, buf, rsize, AVALON_READ_TIMEOUT,
C_AVALON_READ);
@@ -782,12 +781,6 @@ static void *avalon_get_results(void *userdata)
hexdump((uint8_t *)buf, ret);
}
- /* During a reset, goes on reading but discards anything */
- if (unlikely(info->reset)) {
- offset = 0;
- continue;
- }
-
memcpy(&readbuf[offset], &buf, ret);
offset += ret;
}
@@ -818,7 +811,14 @@ static void *avalon_send_tasks(void *userdata)
wait_avalon_ready(avalon);
- pthread_setcanceltype(PTHREAD_CANCEL_DISABLE, NULL);
+ if (unlikely(info->reset)) {
+ /* Wait till read thread tells us it's received the
+ * reset message */
+ sem_wait(&info->write_sem);
+ avalon_running_reset(avalon, info);
+ sem_post(&info->read_sem);
+ }
+
mutex_lock(&info->qlock);
start_count = avalon->work_array * avalon_get_work_count;
end_count = start_count + avalon_get_work_count;
@@ -849,7 +849,7 @@ static void *avalon_send_tasks(void *userdata)
applog(LOG_ERR, "AVA%i: Comms error(buffer)",
avalon->device_id);
dev_error(avalon, REASON_DEV_COMMS_ERROR);
- __avalon_running_reset(avalon, info);
+ info->reset = true;
break;
}
}
@@ -857,7 +857,6 @@ static void *avalon_send_tasks(void *userdata)
avalon_rotate_array(avalon);
pthread_cond_signal(&info->qcond);
mutex_unlock(&info->qlock);
- pthread_setcanceltype(PTHREAD_CANCEL_ENABLE, NULL);
if (unlikely(idled && !info->idle)) {
info->idle = true;
@@ -885,8 +884,10 @@ static bool avalon_prepare(struct thr_info *thr)
mutex_init(&info->qlock);
if (unlikely(pthread_cond_init(&info->qcond, NULL)))
quit(1, "Failed to pthread_cond_init avalon qcond");
-
- info->reset = true;
+ if (unlikely(sem_init(&info->read_sem, 0, 0)))
+ quit(1, "Failed to sem_init avalon read_sem");
+ if (unlikely(sem_init(&info->write_sem, 0, 0)))
+ quit(1, "Failed to sem_init avalon write_sem");
if (pthread_create(&info->read_thr, NULL, avalon_get_results, (void *)avalon))
quit(1, "Failed to create avalon read_thr");
@@ -894,11 +895,6 @@ static bool avalon_prepare(struct thr_info *thr)
if (pthread_create(&info->write_thr, NULL, avalon_send_tasks, (void *)avalon))
quit(1, "Failed to create avalon write_thr");
- mutex_lock(&info->qlock);
- info->reset = false;
- pthread_cond_wait(&info->qcond, &info->qlock);
- mutex_unlock(&info->qlock);
-
avalon_init(avalon);
cgtime(&now);
@@ -911,11 +907,12 @@ static void do_avalon_close(struct thr_info *thr)
struct cgpu_info *avalon = thr->cgpu;
struct avalon_info *info = avalon->device_data;
+ info->reset = true;
pthread_cancel(info->read_thr);
pthread_join(info->read_thr, NULL);
pthread_cancel(info->write_thr);
pthread_join(info->write_thr, NULL);
- __avalon_running_reset(avalon, info);
+ avalon_running_reset(avalon, info);
info->no_matching_work = 0;
}
@@ -1051,7 +1048,7 @@ static int64_t avalon_scanhash(struct thr_info *thr)
avalon->results += info->nonces;
if (avalon->results > miner_count)
avalon->results = miner_count;
- if (!info->idle)
+ if (!info->idle && !info->reset)
avalon->results -= miner_count / 3;
else
avalon->results = miner_count;
@@ -1060,10 +1057,10 @@ static int64_t avalon_scanhash(struct thr_info *thr)
/* Check for nothing but consecutive bad results or consistently less
* results than we should be getting and reset the FPGA if necessary */
- if (avalon->results < -miner_count) {
+ if (avalon->results < -miner_count && !info->reset) {
applog(LOG_ERR, "AVA%d: Result return rate low, resetting!",
avalon->device_id);
- avalon_running_reset(avalon, info);
+ info->reset = true;
}
/* This hashmeter is just a utility counter based on returned shares */
diff --git a/driver-avalon.h b/driver-avalon.h
index a2b3265..d4a6286 100644
--- a/driver-avalon.h
+++ b/driver-avalon.h
@@ -12,6 +12,8 @@
#ifdef USE_AVALON
+#include <semaphore.h>
+
#define AVALON_RESET_FAULT_DECISECONDS 1
#define AVALON_MINER_THREADS 1
@@ -107,6 +109,8 @@ struct avalon_info {
pthread_mutex_t lock;
pthread_mutex_t qlock;
pthread_cond_t qcond;
+ sem_t read_sem;
+ sem_t write_sem;
int nonces;
bool idle;