be2net: fix INTx ISR for interrupt behaviour on BE2
authorSathya Perla <sathya.perla@emulex.com>
Tue, 27 Nov 2012 19:50:02 +0000 (19:50 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 28 Nov 2012 16:35:08 +0000 (11:35 -0500)
On BE2 chip, an interrupt may be raised even when EQ is in un-armed state.
As a result be_intx()::events_get() and be_poll:events_get() can race and
notify an EQ wrongly.

Fix this by counting events only in be_poll(). Commit 0b545a629 fixes
the same issue in the MSI-x path.

But, on Lancer, INTx can be de-asserted only by notifying num evts. This
is not an issue as the above BE2 behavior doesn't exist/has never been
seen on Lancer.

Signed-off-by: Sathya Perla <sathya.perla@emulex.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/emulex/benet/be_main.c

index adef536c1586f7552f09bccb92e35b57e09b8bc5..0661e9379583ec215b644e6f4fed4d2076498b7c 100644 (file)
@@ -1675,24 +1675,6 @@ static inline int events_get(struct be_eq_obj *eqo)
        return num;
 }
 
-static int event_handle(struct be_eq_obj *eqo)
-{
-       bool rearm = false;
-       int num = events_get(eqo);
-
-       /* Deal with any spurious interrupts that come without events */
-       if (!num)
-               rearm = true;
-
-       if (num || msix_enabled(eqo->adapter))
-               be_eq_notify(eqo->adapter, eqo->q.id, rearm, true, num);
-
-       if (num)
-               napi_schedule(&eqo->napi);
-
-       return num;
-}
-
 /* Leaves the EQ is disarmed state */
 static void be_eq_clean(struct be_eq_obj *eqo)
 {
@@ -2014,15 +1996,23 @@ static int be_rx_cqs_create(struct be_adapter *adapter)
 
 static irqreturn_t be_intx(int irq, void *dev)
 {
-       struct be_adapter *adapter = dev;
-       int num_evts;
+       struct be_eq_obj *eqo = dev;
+       struct be_adapter *adapter = eqo->adapter;
+       int num_evts = 0;
 
-       /* With INTx only one EQ is used */
-       num_evts = event_handle(&adapter->eq_obj[0]);
-       if (num_evts)
-               return IRQ_HANDLED;
-       else
-               return IRQ_NONE;
+       /* On Lancer, clear-intr bit of the EQ DB does not work.
+        * INTx is de-asserted only on notifying num evts.
+        */
+       if (lancer_chip(adapter))
+               num_evts = events_get(eqo);
+
+       /* The EQ-notify may not de-assert INTx rightaway, causing
+        * the ISR to be invoked again. So, return HANDLED even when
+        * num_evts is zero.
+        */
+       be_eq_notify(adapter, eqo->q.id, false, true, num_evts);
+       napi_schedule(&eqo->napi);
+       return IRQ_HANDLED;
 }
 
 static irqreturn_t be_msix(int irq, void *dev)
@@ -2342,10 +2332,10 @@ static int be_irq_register(struct be_adapter *adapter)
                        return status;
        }
 
-       /* INTx */
+       /* INTx: only the first EQ is used */
        netdev->irq = adapter->pdev->irq;
        status = request_irq(netdev->irq, be_intx, IRQF_SHARED, netdev->name,
-                       adapter);
+                            &adapter->eq_obj[0]);
        if (status) {
                dev_err(&adapter->pdev->dev,
                        "INTx request IRQ failed - err %d\n", status);
@@ -2367,7 +2357,7 @@ static void be_irq_unregister(struct be_adapter *adapter)
 
        /* INTx */
        if (!msix_enabled(adapter)) {
-               free_irq(netdev->irq, adapter);
+               free_irq(netdev->irq, &adapter->eq_obj[0]);
                goto done;
        }
 
@@ -3023,8 +3013,10 @@ static void be_netpoll(struct net_device *netdev)
        struct be_eq_obj *eqo;
        int i;
 
-       for_all_evt_queues(adapter, eqo, i)
-               event_handle(eqo);
+       for_all_evt_queues(adapter, eqo, i) {
+               be_eq_notify(eqo->adapter, eqo->q.id, false, true, 0);
+               napi_schedule(&eqo->napi);
+       }
 
        return;
 }