liquidio: fix for iq and droq cnts going negative
authorSatanand Burla <satananda.burla@cavium.com>
Tue, 31 Jan 2017 21:04:42 +0000 (13:04 -0800)
committerDavid S. Miller <davem@davemloft.net>
Wed, 1 Feb 2017 17:25:40 +0000 (12:25 -0500)
Flush the mmio writes before releasing spin locks.
if the maintained counts get too high > 2M force
writeback of the counts to clear them

Signed-off-by: Satanand Burla <satananda.burla@cavium.com>
Signed-off-by: Felix Manlunas <felix.manlunas@cavium.com>
Signed-off-by: Raghu Vatsavayi <raghu.vatsavayi@cavium.com>
Signed-off-by: Derek Chickles <derek.chickles@cavium.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/cavium/liquidio/lio_main.c
drivers/net/ethernet/cavium/liquidio/lio_vf_main.c
drivers/net/ethernet/cavium/liquidio/liquidio_common.h
drivers/net/ethernet/cavium/liquidio/octeon_device.c

index fbe1986b87f6b6cdf7c30e635715a5ae49a911a5..c12cfa4113ccef6e3e3f4a8dfa73de05d132d30a 100644 (file)
@@ -2445,7 +2445,11 @@ static int liquidio_napi_poll(struct napi_struct *napi, int budget)
                        __func__, iq_no);
        }
 
-       if ((work_done < budget) && (tx_done)) {
+       /* force enable interrupt if reg cnts are high to avoid wraparound */
+       if ((work_done < budget && tx_done) ||
+           (iq->pkt_in_done >= MAX_REG_CNT) ||
+           (droq->pkt_count >= MAX_REG_CNT)) {
+               tx_done = 1;
                napi_complete_done(napi, work_done);
                octeon_process_droq_poll_cmd(droq->oct_dev, droq->q_no,
                                             POLL_EVENT_ENABLE_INTR, 0);
index 78cfa8ba1b57e3b9b97abaf66b7a61696bda9ab4..631f1c0f9e4d09cfbca813cda9201754b0619735 100644 (file)
@@ -1630,7 +1630,11 @@ static int liquidio_napi_poll(struct napi_struct *napi, int budget)
                        __func__, iq_no);
        }
 
-       if ((work_done < budget) && (tx_done)) {
+       /* force enable interrupt if reg cnts are high to avoid wraparound */
+       if ((work_done < budget && tx_done) ||
+           (iq->pkt_in_done >= MAX_REG_CNT) ||
+           (droq->pkt_count >= MAX_REG_CNT)) {
+               tx_done = 1;
                napi_complete_done(napi, work_done);
                octeon_process_droq_poll_cmd(droq->oct_dev, droq->q_no,
                                             POLL_EVENT_ENABLE_INTR, 0);
index bc0af8af1a0ca975e3ceb23a9f976afcddb51c1b..294c6f3c6b48254044c610c78625c9c3c86e9b1f 100644 (file)
@@ -99,6 +99,7 @@ enum octeon_tag_type {
 #define CVM_DRV_APP_END             (CVM_DRV_INVALID_APP - 1)
 
 #define BYTES_PER_DHLEN_UNIT        8
+#define MAX_REG_CNT                 2000000U
 
 static inline u32 incr_index(u32 index, u32 count, u32 max)
 {
index a8df493a50127d6a23e899bd95b582f0157f13ae..9675ffbf25e6bd9bf34d346204f1b0fbcbcfa185 100644 (file)
@@ -1361,6 +1361,8 @@ void lio_enable_irq(struct octeon_droq *droq, struct octeon_instr_queue *iq)
                spin_lock_bh(&droq->lock);
                writel(droq->pkt_count, droq->pkts_sent_reg);
                droq->pkt_count = 0;
+               /* this write needs to be flushed before we release the lock */
+               mmiowb();
                spin_unlock_bh(&droq->lock);
                oct = droq->oct_dev;
        }
@@ -1368,6 +1370,8 @@ void lio_enable_irq(struct octeon_droq *droq, struct octeon_instr_queue *iq)
                spin_lock_bh(&iq->lock);
                writel(iq->pkt_in_done, iq->inst_cnt_reg);
                iq->pkt_in_done = 0;
+               /* this write needs to be flushed before we release the lock */
+               mmiowb();
                spin_unlock_bh(&iq->lock);
                oct = iq->oct_dev;
        }