sparc64: ensure LDC channel is ready before communication
authorJag Raman <jag.raman@oracle.com>
Fri, 9 Jun 2017 16:29:30 +0000 (12:29 -0400)
committerDavid S. Miller <davem@davemloft.net>
Sat, 10 Jun 2017 21:10:55 +0000 (14:10 -0700)
Ensure that LDC channel is up before writing to it, in RAW mode. Generate
event to bring the LDC channel up, if it's not up already.

Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
Reviewed-by: Aaron Young <aaron.young@oracle.com>
Reviewed-by: Alexandre Chartre <alexandre.chartre@oracle.com>
Reviewed-by: Bijan Mottahedeh <bijan.mottahedeh@oracle.com>
Reviewed-by: Liam Merwick <liam.merwick@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
arch/sparc/kernel/ldc.c

index 902cbf4fa007408e2a43553de55f2a04c37b7524..639da7b53e836a07aff0e818ad5722d4cd919052 100644 (file)
@@ -813,9 +813,14 @@ static irqreturn_t ldc_rx(int irq, void *dev_id)
                lp->hs_state = LDC_HS_COMPLETE;
                ldc_set_state(lp, LDC_STATE_CONNECTED);
 
-               event_mask |= LDC_EVENT_UP;
-
-               orig_state = lp->chan_state;
+               /*
+                * Generate an LDC_EVENT_UP event if the channel
+                * was not already up.
+                */
+               if (orig_state != LDC_CHANNEL_UP) {
+                       event_mask |= LDC_EVENT_UP;
+                       orig_state = lp->chan_state;
+               }
        }
 
        /* If we are in reset state, flush the RX queue and ignore
@@ -929,7 +934,14 @@ static irqreturn_t ldc_tx(int irq, void *dev_id)
                lp->hs_state = LDC_HS_COMPLETE;
                ldc_set_state(lp, LDC_STATE_CONNECTED);
 
-               event_mask |= LDC_EVENT_UP;
+               /*
+                * Generate an LDC_EVENT_UP event if the channel
+                * was not already up.
+                */
+               if (orig_state != LDC_CHANNEL_UP) {
+                       event_mask |= LDC_EVENT_UP;
+                       orig_state = lp->chan_state;
+               }
        }
 
        spin_unlock_irqrestore(&lp->lock, flags);
@@ -1475,9 +1487,17 @@ void __ldc_print(struct ldc_channel *lp, const char *caller)
 static int write_raw(struct ldc_channel *lp, const void *buf, unsigned int size)
 {
        struct ldc_packet *p;
-       unsigned long new_tail;
+       unsigned long new_tail, hv_err;
        int err;
 
+       hv_err = sun4v_ldc_tx_get_state(lp->id, &lp->tx_head, &lp->tx_tail,
+                                       &lp->chan_state);
+       if (unlikely(hv_err))
+               return -EBUSY;
+
+       if (unlikely(lp->chan_state != LDC_CHANNEL_UP))
+               return LDC_ABORT(lp);
+
        if (size > LDC_PACKET_SIZE)
                return -EMSGSIZE;