cnic, bnx2x: Add CNIC_DRV_STATE_HANDLES_IRQ to ethdev->drv_state
authorMichael Chan <mchan@broadcom.com>
Wed, 23 Jan 2013 03:21:52 +0000 (03:21 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 23 Jan 2013 18:58:29 +0000 (13:58 -0500)
In INTA mode, cnic and bnx2x share the same IRQ.  During chip reset,
for example, cnic will stop servicing IRQs after it has shutdown the
cnic hardware resources.  However, the shared IRQ is still active as
bnx2x needs to finish the reset.  There is a window when bnx2x does
not know that cnic is no longer handling IRQ and things don't always
work properly.

Add a flag to tell bnx2x that cnic is handling IRQ.  The flag is set
before the first cnic IRQ is expected and cleared when no more cnic
IRQs are expected, so there should be no race conditions.

Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: Yuval Mintz <yuvalmin@broadcom.com>
Signed-off-by: Ariel Elior <ariele@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/cnic.c
drivers/net/ethernet/broadcom/cnic_if.h

index ac00ddcd32fa9ac54fb2a8b368c34365b5b76a3f..c4daee1b72865180c33c96e906d55f8232f060bf 100644 (file)
@@ -1875,14 +1875,12 @@ irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
                if (status & (mask | 0x1)) {
                        struct cnic_ops *c_ops = NULL;
 
-                       if (likely(bp->state == BNX2X_STATE_OPEN)) {
-                               rcu_read_lock();
-                               c_ops = rcu_dereference(bp->cnic_ops);
-                               if (c_ops)
-                                       c_ops->cnic_handler(bp->cnic_data,
-                                                           NULL);
-                               rcu_read_unlock();
-                       }
+                       rcu_read_lock();
+                       c_ops = rcu_dereference(bp->cnic_ops);
+                       if (c_ops && (bp->cnic_eth_dev.drv_state &
+                                     CNIC_DRV_STATE_HANDLES_IRQ))
+                               c_ops->cnic_handler(bp->cnic_data, NULL);
+                       rcu_read_unlock();
 
                        status &= ~mask;
                }
index df8c30d1a52cc4d1fc35e6fb8f7cf6c1b73d31c3..1c4dadc7ebbb75bdd9b76ec4264ea9c8e4280f7f 100644 (file)
@@ -4816,6 +4816,8 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
                return err;
        }
 
+       ethdev->drv_state |= CNIC_DRV_STATE_HANDLES_IRQ;
+
        return 0;
 }
 
@@ -5136,6 +5138,7 @@ static int cnic_start_bnx2x_hw(struct cnic_dev *dev)
        if (ret)
                return ret;
 
+       ethdev->drv_state |= CNIC_DRV_STATE_HANDLES_IRQ;
        return 0;
 }
 
@@ -5387,6 +5390,7 @@ static void cnic_stop_hw(struct cnic_dev *dev)
                }
                cnic_shutdown_rings(dev);
                cp->stop_cm(dev);
+               cp->ethdev->drv_state &= ~CNIC_DRV_STATE_HANDLES_IRQ;
                clear_bit(CNIC_F_CNIC_UP, &dev->flags);
                RCU_INIT_POINTER(cp->ulp_ops[CNIC_ULP_L4], NULL);
                synchronize_rcu();
index 2a35436f90956744a2efa443062001a4acde1727..0c9367a0f57d92ef56c5f0f89dea166e0e00b180 100644 (file)
@@ -179,6 +179,7 @@ struct cnic_eth_dev {
 #define CNIC_DRV_STATE_NO_ISCSI_OOO    0x00000004
 #define CNIC_DRV_STATE_NO_ISCSI                0x00000008
 #define CNIC_DRV_STATE_NO_FCOE         0x00000010
+#define CNIC_DRV_STATE_HANDLES_IRQ     0x00000020
        u32             chip_id;
        u32             max_kwqe_pending;
        struct pci_dev  *pdev;