gru: fix handling of mesq failures
Jack Steiner [Wed, 17 Jun 2009 23:28:23 +0000 (16:28 -0700)]
Fix endcase in handling GRU message queue failures due to NACKs of PUT
requests.  Must ensure that the "present" bits are cleared before
resending the message.

Signed-off-by: Jack Steiner <steiner@sgi.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

drivers/misc/sgi-gru/grukservices.c

index 50b4dd8..a0f9810 100644 (file)
@@ -503,6 +503,29 @@ static void send_message_queue_interrupt(struct gru_message_queue_desc *mqd)
                                mqd->interrupt_vector);
 }
 
+/*
+ * Handle a PUT failure. Note: if message was a 2-line message, one of the
+ * lines might have successfully have been written. Before sending the
+ * message, "present" must be cleared in BOTH lines to prevent the receiver
+ * from prematurely seeing the full message.
+ */
+static int send_message_put_nacked(void *cb, struct gru_message_queue_desc *mqd,
+                       void *mesg, int lines)
+{
+       unsigned long m;
+
+       m = mqd->mq_gpa + (gru_get_amo_value_head(cb) << 6);
+       if (lines == 2) {
+               gru_vset(cb, m, 0, XTYPE_CL, lines, 1, IMA);
+               if (gru_wait(cb) != CBS_IDLE)
+                       return MQE_UNEXPECTED_CB_ERR;
+       }
+       gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, lines, 1, IMA);
+       if (gru_wait(cb) != CBS_IDLE)
+               return MQE_UNEXPECTED_CB_ERR;
+       send_message_queue_interrupt(mqd);
+       return MQE_OK;
+}
 
 /*
  * Handle a gru_mesq failure. Some of these failures are software recoverable
@@ -512,7 +535,6 @@ static int send_message_failure(void *cb, struct gru_message_queue_desc *mqd,
                                void *mesg, int lines)
 {
        int substatus, ret = 0;
-       unsigned long m;
 
        substatus = gru_get_cb_message_queue_substatus(cb);
        switch (substatus) {
@@ -534,14 +556,7 @@ static int send_message_failure(void *cb, struct gru_message_queue_desc *mqd,
                break;
        case CBSS_PUT_NACKED:
                STAT(mesq_send_put_nacked);
-               m = mqd->mq_gpa + (gru_get_amo_value_head(cb) << 6);
-               gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, lines, 1, IMA);
-               if (gru_wait(cb) == CBS_IDLE) {
-                       ret = MQE_OK;
-                       send_message_queue_interrupt(mqd);
-               } else {
-                       ret = MQE_UNEXPECTED_CB_ERR;
-               }
+               ret = send_message_put_nacked(cb, mqd, mesg, lines);
                break;
        default:
                BUG();