qlcnic: Fix mailbox completion handling during spurious interrupt
authorRajesh Borundia <rajesh.borundia@qlogic.com>
Tue, 8 Mar 2016 07:39:58 +0000 (02:39 -0500)
committerDavid S. Miller <davem@davemloft.net>
Thu, 10 Mar 2016 21:15:54 +0000 (16:15 -0500)
o While the driver is in the middle of a MB completion processing
and it receives a spurious MB interrupt, it is mistaken as a good MB
completion interrupt leading to premature completion of the next MB
request. Fix the driver to guard against this by checking the current
state of MB processing and ignore the spurious interrupt.
Also added a stats counter to record this condition.

Signed-off-by: Rajesh Borundia <rajesh.borundia@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c

index d18667b1b5b7a70f1dd74f595938556e6e67436c..55007f1e6bbcc77981414e9db1e73d8db8502988 100644 (file)
@@ -566,6 +566,7 @@ struct qlcnic_adapter_stats {
        u64  tx_dma_map_error;
        u64  spurious_intr;
        u64  mac_filter_limit_overrun;
+       u64  mbx_spurious_intr;
 };
 
 /*
index e3d1bb722903e1c2b8c679c2e11e8314d0de8ed2..f9640d5ce6baa774d1f980a2c6eb652fc301eab8 100644 (file)
@@ -2338,9 +2338,9 @@ static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter,
 
 static irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data)
 {
+       u32 mask, resp, event, rsp_status = QLC_83XX_MBX_RESPONSE_ARRIVED;
        struct qlcnic_adapter *adapter = data;
        struct qlcnic_mailbox *mbx;
-       u32 mask, resp, event;
        unsigned long flags;
 
        mbx = adapter->ahw->mailbox;
@@ -2350,10 +2350,14 @@ static irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data)
                goto out;
 
        event = readl(QLCNIC_MBX_FW(adapter->ahw, 0));
-       if (event &  QLCNIC_MBX_ASYNC_EVENT)
+       if (event &  QLCNIC_MBX_ASYNC_EVENT) {
                __qlcnic_83xx_process_aen(adapter);
-       else
-               qlcnic_83xx_notify_mbx_response(mbx);
+       } else {
+               if (mbx->rsp_status != rsp_status)
+                       qlcnic_83xx_notify_mbx_response(mbx);
+               else
+                       adapter->stats.mbx_spurious_intr++;
+       }
 
 out:
        mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
@@ -4053,6 +4057,7 @@ static void qlcnic_83xx_mailbox_worker(struct work_struct *work)
        struct list_head *head = &mbx->cmd_q;
        struct qlcnic_hardware_context *ahw;
        struct qlcnic_cmd_args *cmd = NULL;
+       unsigned long flags;
 
        ahw = adapter->ahw;
 
@@ -4062,7 +4067,9 @@ static void qlcnic_83xx_mailbox_worker(struct work_struct *work)
                        return;
                }
 
+               spin_lock_irqsave(&mbx->aen_lock, flags);
                mbx->rsp_status = QLC_83XX_MBX_RESPONSE_WAIT;
+               spin_unlock_irqrestore(&mbx->aen_lock, flags);
 
                spin_lock(&mbx->queue_lock);
 
index 494e8105adee7834341353ddc81cf65a70a33b9c..0a2318cad34d74a6000f710a375848b1c3f54f45 100644 (file)
@@ -59,7 +59,8 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
         QLC_OFF(stats.mac_filter_limit_overrun)},
        {"spurious intr", QLC_SIZEOF(stats.spurious_intr),
         QLC_OFF(stats.spurious_intr)},
-
+       {"mbx spurious intr", QLC_SIZEOF(stats.mbx_spurious_intr),
+        QLC_OFF(stats.mbx_spurious_intr)},
 };
 
 static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {