Move most interrupt handler processing into a tasklet, and
introduce a delay after re-enabling interrupts to fix timing
issues encountered in hardware testing.

Signed-off-by: Thomas Falcon <tlfal...@linux.vnet.ibm.com>
---
 drivers/net/ethernet/ibm/ibmvnic.c | 21 +++++++++++++++++++--
 drivers/net/ethernet/ibm/ibmvnic.h |  1 +
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/ibm/ibmvnic.c 
b/drivers/net/ethernet/ibm/ibmvnic.c
index c125966..09071bf 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -3414,6 +3414,18 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
 static irqreturn_t ibmvnic_interrupt(int irq, void *instance)
 {
        struct ibmvnic_adapter *adapter = instance;
+       unsigned long flags;
+
+       spin_lock_irqsave(&adapter->crq.lock, flags);
+       vio_disable_interrupts(adapter->vdev);
+       tasklet_schedule(&adapter->tasklet);
+       spin_unlock_irqrestore(&adapter->crq.lock, flags);
+       return IRQ_HANDLED;
+}
+
+static void ibmvnic_tasklet(void *data)
+{
+       struct ibmvnic_adapter *adapter = data;
        struct ibmvnic_crq_queue *queue = &adapter->crq;
        struct vio_dev *vdev = adapter->vdev;
        union ibmvnic_crq *crq;
@@ -3421,7 +3433,6 @@ static irqreturn_t ibmvnic_interrupt(int irq, void 
*instance)
        bool done = false;
 
        spin_lock_irqsave(&queue->lock, flags);
-       vio_disable_interrupts(vdev);
        while (!done) {
                /* Pull all the valid messages off the CRQ */
                while ((crq = ibmvnic_next_crq(adapter)) != NULL) {
@@ -3429,6 +3440,8 @@ static irqreturn_t ibmvnic_interrupt(int irq, void 
*instance)
                        crq->generic.first = 0;
                }
                vio_enable_interrupts(vdev);
+               /* delay in case of firmware hiccup */
+               mdelay(10);
                crq = ibmvnic_next_crq(adapter);
                if (crq) {
                        vio_disable_interrupts(vdev);
@@ -3439,7 +3452,6 @@ static irqreturn_t ibmvnic_interrupt(int irq, void 
*instance)
                }
        }
        spin_unlock_irqrestore(&queue->lock, flags);
-       return IRQ_HANDLED;
 }
 
 static int ibmvnic_reenable_crq_queue(struct ibmvnic_adapter *adapter)
@@ -3494,6 +3506,7 @@ static void ibmvnic_release_crq_queue(struct 
ibmvnic_adapter *adapter)
 
        netdev_dbg(adapter->netdev, "Releasing CRQ\n");
        free_irq(vdev->irq, adapter);
+       tasklet_kill(&adapter->tasklet);
        do {
                rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
        } while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
@@ -3539,6 +3552,9 @@ static int ibmvnic_init_crq_queue(struct ibmvnic_adapter 
*adapter)
 
        retrc = 0;
 
+       tasklet_init(&adapter->tasklet, (void *)ibmvnic_tasklet,
+                    (unsigned long)adapter);
+
        netdev_dbg(adapter->netdev, "registering irq 0x%x\n", vdev->irq);
        rc = request_irq(vdev->irq, ibmvnic_interrupt, 0, IBMVNIC_NAME,
                         adapter);
@@ -3560,6 +3576,7 @@ static int ibmvnic_init_crq_queue(struct ibmvnic_adapter 
*adapter)
        return retrc;
 
 req_irq_failed:
+       tasklet_kill(&adapter->tasklet);
        do {
                rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
        } while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
diff --git a/drivers/net/ethernet/ibm/ibmvnic.h 
b/drivers/net/ethernet/ibm/ibmvnic.h
index dd775d9..0d0edc3 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.h
+++ b/drivers/net/ethernet/ibm/ibmvnic.h
@@ -1049,5 +1049,6 @@ struct ibmvnic_adapter {
 
        struct work_struct vnic_crq_init;
        struct work_struct ibmvnic_xport;
+       struct tasklet_struct tasklet;
        bool failover;
 };
-- 
2.7.4

Reply via email to