Commit bcae3a91f9418e1ed7c03d4b9277028e38b58c3f

Con Kolivas 2014-02-07T09:35:27

Issue a shutdown prior to a reset command for hfa devices and lock access to reads awaiting the response if the device is already running.

diff --git a/driver-hashfast.c b/driver-hashfast.c
index 90667c2..f4d0fa0 100644
--- a/driver-hashfast.c
+++ b/driver-hashfast.c
@@ -457,13 +457,18 @@ tryagain:
 	return true;
 }
 
-static void hfa_send_shutdown(struct cgpu_info *hashfast)
+static bool hfa_send_shutdown(struct cgpu_info *hashfast)
 {
+	bool ret = false;
+
 	if (hashfast->usbinfo.nodev)
-		return;
-	hfa_send_frame(hashfast, HF_USB_CMD(OP_USB_SHUTDOWN), 0, NULL, 0);
-	/* Wait to allow device to properly shut down. */
-	cgsleep_ms(1000);
+		return ret;
+	if (hfa_send_frame(hashfast, HF_USB_CMD(OP_USB_SHUTDOWN), 0, NULL, 0)) {
+		/* Wait to allow device to properly shut down. */
+		cgsleep_ms(1000);
+		ret = true;
+	}
+	return ret;
 }
 
 static void hfa_clear_readbuf(struct cgpu_info *hashfast)
@@ -638,6 +643,8 @@ out:
 	return ret;
 }
 
+static bool hfa_running_reset(struct cgpu_info *hashfast, struct hashfast_info *info);
+
 static void hfa_parse_gwq_status(struct cgpu_info *hashfast, struct hashfast_info *info,
 				 struct hf_header *h)
 {
@@ -652,8 +659,7 @@ static void hfa_parse_gwq_status(struct cgpu_info *hashfast, struct hashfast_inf
 	if (unlikely(h->core_address & 0x80)) {
 		applog(LOG_ERR, "%s %d Thermal overload tripped! Resetting device",
 		       hashfast->drv->name, hashfast->device_id);
-		hfa_send_shutdown(hashfast);
-		if (hfa_reset(hashfast, info)) {
+		if (hfa_running_reset(hashfast, info)) {
 			applog(LOG_NOTICE, "%s %d: Succesfully reset, continuing operation",
 			       hashfast->drv->name, hashfast->device_id);
 			return;
@@ -913,7 +919,11 @@ static void *hfa_read(void *arg)
 	while (likely(!hashfast->shutdown)) {
 		char buf[512];
 		struct hf_header *h = (struct hf_header *)buf;
-		bool ret = hfa_get_packet(hashfast, h);
+		bool ret;
+
+		mutex_lock(&info->rlock);
+		ret = hfa_get_packet(hashfast, h);
+		mutex_unlock(&info->rlock);
 
 		if (unlikely(hashfast->usbinfo.nodev))
 			break;
@@ -976,6 +986,7 @@ static bool hfa_prepare(struct thr_info *thr)
 	struct timeval now;
 
 	mutex_init(&info->lock);
+	mutex_init(&info->rlock);
 	if (pthread_create(&info->read_thr, NULL, hfa_read, (void *)thr))
 		quit(1, "Failed to pthread_create read thr in hfa_prepare");
 
@@ -1227,6 +1238,26 @@ dies_only:
 	}
 }
 
+static bool hfa_running_reset(struct cgpu_info *hashfast, struct hashfast_info *info)
+{
+	bool ret;
+
+	ret = hfa_send_shutdown(hashfast);
+	if (!ret)
+		goto out;
+
+	/* hfa_reset is the only other place we read from the device so we must
+	 * inhibit the read thread from reading our response to the
+	 * OP_USB_INIT */
+	mutex_lock(&info->rlock);
+	hfa_clear_readbuf(hashfast);
+	ret = hfa_reset(hashfast, info);
+	mutex_unlock(&info->rlock);
+
+out:
+	return ret;
+}
+
 static int64_t hfa_scanwork(struct thr_info *thr)
 {
 	struct cgpu_info *hashfast = thr->cgpu;
@@ -1250,7 +1281,7 @@ static int64_t hfa_scanwork(struct thr_info *thr)
 			applog(LOG_WARNING, "%s %d: Decreasing clock speed to %d with reset",
 			       hashfast->drv->name, hashfast->device_id, info->hash_clock_rate);
 		}
-		ret = hfa_reset(hashfast, info);
+		ret = hfa_running_reset(hashfast, info);
 		if (!ret) {
 			applog(LOG_ERR, "%s %d: Failed to reset after hash failure, disabling",
 			       hashfast->drv->name, hashfast->device_id);
@@ -1266,7 +1297,7 @@ restart:
 		thr->work_restart = false;
 		ret = hfa_send_frame(hashfast, HF_USB_CMD(OP_WORK_RESTART), 0, (uint8_t *)NULL, 0);
 		if (unlikely(!ret)) {
-			ret = hfa_reset(hashfast, info);
+			ret = hfa_running_reset(hashfast, info);
 			if (unlikely(!ret)) {
 				applog(LOG_ERR, "%s %d: Failed to reset after write failure, disabling",
 				       hashfast->drv->name, hashfast->device_id);
@@ -1327,7 +1358,7 @@ restart:
 			sequence = 0;
 		ret = hfa_send_frame(hashfast, OP_HASH, sequence, (uint8_t *)&op_hash_data, sizeof(op_hash_data));
 		if (unlikely(!ret)) {
-			ret = hfa_reset(hashfast, info);
+			ret = hfa_running_reset(hashfast, info);
 			if (unlikely(!ret)) {
 				applog(LOG_ERR, "%s %d: Failed to reset after write failure, disabling",
 				       hashfast->drv->name, hashfast->device_id);
diff --git a/driver-hashfast.h b/driver-hashfast.h
index e19a990..7e160b6 100644
--- a/driver-hashfast.h
+++ b/driver-hashfast.h
@@ -112,6 +112,7 @@ struct hashfast_info {
 	int core_ntime_roll;                        // Total core ntime roll amount
 
 	pthread_mutex_t lock;
+	pthread_mutex_t rlock;
 	struct work **works;
 	uint16_t hash_sequence_head;                // HOST:   The next hash sequence # to be sent
 	uint16_t hash_sequence_tail;                // HOST:   Follows device_sequence_tail around to free work