bnxt_en: Add new NAPI poll function for 57500 chips.
authorMichael Chan <michael.chan@broadcom.com>
Sun, 14 Oct 2018 11:02:58 +0000 (07:02 -0400)
committerDavid S. Miller <davem@davemloft.net>
Tue, 16 Oct 2018 05:44:33 +0000 (22:44 -0700)
Add a new poll function that polls for NQ events.  If the NQ event is
a CQ notification, we locate the CP ring from the cq_handle and call
__bnxt_poll_work() to handle RX/TX events on the CP ring.

Add a new has_more_work field in struct bnxt_cp_ring_info to indicate
budget has been reached.  __bnxt_poll_cqs_done() is called to update or
ARM the CP rings if budget has not been reached or not.  If budget
has been reached, the next bnxt_poll_p5() call will continue to poll
from the CQ rings directly.  Otherwise, the NQ will be ARMed for the
next IRQ.

Signed-off-by: Michael Chan <michael.chan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt.h

index 10d713aa76eee40b1917938942269229a9cfc21b..f51811918b60028d2856edda3bfc3f70db98588a 100644 (file)
@@ -1900,6 +1900,7 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
        u8 event = 0;
        struct tx_cmp *txcmp;
 
+       cpr->has_more_work = 0;
        while (1) {
                int rc;
 
@@ -1920,6 +1921,8 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
                        if (unlikely(tx_pkts > bp->tx_wake_thresh)) {
                                rx_pkts = budget;
                                raw_cons = NEXT_RAW_CMP(raw_cons);
+                               if (budget)
+                                       cpr->has_more_work = 1;
                                break;
                        }
                } else if ((TX_CMP_TYPE(txcmp) & 0x30) == 0x10) {
@@ -1949,8 +1952,10 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
                }
                raw_cons = NEXT_RAW_CMP(raw_cons);
 
-               if (rx_pkts && rx_pkts == budget)
+               if (rx_pkts && rx_pkts == budget) {
+                       cpr->has_more_work = 1;
                        break;
+               }
        }
 
        if (event & BNXT_TX_EVENT) {
@@ -2106,6 +2111,104 @@ static int bnxt_poll(struct napi_struct *napi, int budget)
        return work_done;
 }
 
+static int __bnxt_poll_cqs(struct bnxt *bp, struct bnxt_napi *bnapi, int budget)
+{
+       struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
+       int i, work_done = 0;
+
+       for (i = 0; i < 2; i++) {
+               struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[i];
+
+               if (cpr2) {
+                       work_done += __bnxt_poll_work(bp, cpr2,
+                                                     budget - work_done);
+                       cpr->has_more_work |= cpr2->has_more_work;
+               }
+       }
+       return work_done;
+}
+
+static void __bnxt_poll_cqs_done(struct bnxt *bp, struct bnxt_napi *bnapi,
+                                u64 dbr_type, bool all)
+{
+       struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[i];
+               struct bnxt_db_info *db;
+
+               if (cpr2 && (all || cpr2->had_work_done)) {
+                       db = &cpr2->cp_db;
+                       writeq(db->db_key64 | dbr_type |
+                              RING_CMP(cpr2->cp_raw_cons), db->doorbell);
+                       cpr2->had_work_done = 0;
+               }
+       }
+       __bnxt_poll_work_done(bp, bnapi);
+}
+
+static int bnxt_poll_p5(struct napi_struct *napi, int budget)
+{
+       struct bnxt_napi *bnapi = container_of(napi, struct bnxt_napi, napi);
+       struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
+       u32 raw_cons = cpr->cp_raw_cons;
+       struct bnxt *bp = bnapi->bp;
+       struct nqe_cn *nqcmp;
+       int work_done = 0;
+       u32 cons;
+
+       if (cpr->has_more_work) {
+               cpr->has_more_work = 0;
+               work_done = __bnxt_poll_cqs(bp, bnapi, budget);
+               if (cpr->has_more_work) {
+                       __bnxt_poll_cqs_done(bp, bnapi, DBR_TYPE_CQ, false);
+                       return work_done;
+               }
+               __bnxt_poll_cqs_done(bp, bnapi, DBR_TYPE_CQ_ARMALL, true);
+               if (napi_complete_done(napi, work_done))
+                       BNXT_DB_NQ_ARM_P5(&cpr->cp_db, cpr->cp_raw_cons);
+               return work_done;
+       }
+       while (1) {
+               cons = RING_CMP(raw_cons);
+               nqcmp = &cpr->nq_desc_ring[CP_RING(cons)][CP_IDX(cons)];
+
+               if (!NQ_CMP_VALID(nqcmp, raw_cons)) {
+                       __bnxt_poll_cqs_done(bp, bnapi, DBR_TYPE_CQ_ARMALL,
+                                            false);
+                       cpr->cp_raw_cons = raw_cons;
+                       if (napi_complete_done(napi, work_done))
+                               BNXT_DB_NQ_ARM_P5(&cpr->cp_db,
+                                                 cpr->cp_raw_cons);
+                       return work_done;
+               }
+
+               /* The valid test of the entry must be done first before
+                * reading any further.
+                */
+               dma_rmb();
+
+               if (nqcmp->type == cpu_to_le16(NQ_CN_TYPE_CQ_NOTIFICATION)) {
+                       u32 idx = le32_to_cpu(nqcmp->cq_handle_low);
+                       struct bnxt_cp_ring_info *cpr2;
+
+                       cpr2 = cpr->cp_ring_arr[idx];
+                       work_done += __bnxt_poll_work(bp, cpr2,
+                                                     budget - work_done);
+                       cpr->has_more_work = cpr2->has_more_work;
+               } else {
+                       bnxt_hwrm_handler(bp, (struct tx_cmp *)nqcmp);
+               }
+               raw_cons = NEXT_RAW_CMP(raw_cons);
+               if (cpr->has_more_work)
+                       break;
+       }
+       __bnxt_poll_cqs_done(bp, bnapi, DBR_TYPE_CQ, true);
+       cpr->cp_raw_cons = raw_cons;
+       return work_done;
+}
+
 static void bnxt_free_tx_skbs(struct bnxt *bp)
 {
        int i, max_idx;
@@ -7211,12 +7314,15 @@ static void bnxt_init_napi(struct bnxt *bp)
        struct bnxt_napi *bnapi;
 
        if (bp->flags & BNXT_FLAG_USING_MSIX) {
-               if (BNXT_CHIP_TYPE_NITRO_A0(bp))
+               int (*poll_fn)(struct napi_struct *, int) = bnxt_poll;
+
+               if (bp->flags & BNXT_FLAG_CHIP_P5)
+                       poll_fn = bnxt_poll_p5;
+               else if (BNXT_CHIP_TYPE_NITRO_A0(bp))
                        cp_nr_rings--;
                for (i = 0; i < cp_nr_rings; i++) {
                        bnapi = bp->bnapi[i];
-                       netif_napi_add(bp->dev, &bnapi->napi,
-                                      bnxt_poll, 64);
+                       netif_napi_add(bp->dev, &bnapi->napi, poll_fn, 64);
                }
                if (BNXT_CHIP_TYPE_NITRO_A0(bp)) {
                        bnapi = bp->bnapi[cp_nr_rings];
index 48cb2d54c3bc60bf4724bf1d45e791e3de00d262..0fe57e36912b84777d6f49f7d8bc0dc25f4fdb38 100644 (file)
@@ -537,6 +537,9 @@ struct nqe_cn {
        (!!((agg)->rx_agg_cmp_v & cpu_to_le32(RX_AGG_CMP_V)) == \
         !((raw_cons) & bp->cp_bit))
 
+#define NQ_CMP_VALID(nqcmp, raw_cons)                          \
+       (!!((nqcmp)->v & cpu_to_le32(NQ_CN_V)) == !((raw_cons) & bp->cp_bit))
+
 #define TX_CMP_TYPE(txcmp)                                     \
        (le32_to_cpu((txcmp)->tx_cmp_flags_type) & CMP_TYPE)
 
@@ -793,6 +796,7 @@ struct bnxt_cp_ring_info {
        struct bnxt_db_info     cp_db;
 
        u8                      had_work_done:1;
+       u8                      has_more_work:1;
 
        struct bnxt_coal        rx_ring_coal;
        u64                     rx_packets;