net/qede: change copyright info to Cavium
[dpdk.git] / drivers / net / qede / base / ecore_int.c
index acf8759..7272f05 100644 (file)
@@ -1,15 +1,16 @@
 /*
- * Copyright (c) 2016 QLogic Corporation.
+ * Copyright (c) 2016 - 2018 Cavium Inc.
  * All rights reserved.
- * www.qlogic.com
+ * www.cavium.com
  *
  * See LICENSE.qede_pmd for copyright and licensing details.
  */
 
+#include <rte_string_fns.h>
+
 #include "bcm_osal.h"
 #include "ecore.h"
 #include "ecore_spq.h"
-#include "reg_addr.h"
 #include "ecore_gtt_reg_addr.h"
 #include "ecore_init_ops.h"
 #include "ecore_rt_defs.h"
@@ -30,7 +31,7 @@ struct ecore_pi_info {
 struct ecore_sb_sp_info {
        struct ecore_sb_info sb_info;
        /* per protocol index data */
-       struct ecore_pi_info pi_info_arr[PIS_PER_SB];
+       struct ecore_pi_info pi_info_arr[PIS_PER_SB_E4];
 };
 
 enum ecore_attention_type {
@@ -286,9 +287,11 @@ out:
 #define ECORE_PGLUE_ATTENTION_ILT_VALID (1 << 23)
 
 enum _ecore_status_t ecore_pglueb_rbc_attn_handler(struct ecore_hwfn *p_hwfn,
-                                                  struct ecore_ptt *p_ptt)
+                                                  struct ecore_ptt *p_ptt,
+                                                  bool is_hw_init)
 {
        u32 tmp;
+       char str[512] = {0};
 
        tmp = ecore_rd(p_hwfn, p_ptt, PGLUE_B_REG_TX_ERR_WR_DETAILS2);
        if (tmp & ECORE_PGLUE_ATTENTION_VALID) {
@@ -300,9 +303,8 @@ enum _ecore_status_t ecore_pglueb_rbc_attn_handler(struct ecore_hwfn *p_hwfn,
                                   PGLUE_B_REG_TX_ERR_WR_ADD_63_32);
                details = ecore_rd(p_hwfn, p_ptt,
                                   PGLUE_B_REG_TX_ERR_WR_DETAILS);
-
-               DP_NOTICE(p_hwfn, false,
-                         "Illegal write by chip to [%08x:%08x] blocked. Details: %08x [PFID %02x, VFID %02x, VF_VALID %02x] Details2 %08x [Was_error %02x BME deassert %02x FID_enable deassert %02x]\n",
+               OSAL_SNPRINTF(str, 512,
+                        "Illegal write by chip to [%08x:%08x] blocked. Details: %08x [PFID %02x, VFID %02x, VF_VALID %02x] Details2 %08x [Was_error %02x BME deassert %02x FID_enable deassert %02x]\n",
                          addr_hi, addr_lo, details,
                          (u8)((details &
                                ECORE_PGLUE_ATTENTION_DETAILS_PFID_MASK) >>
@@ -319,6 +321,10 @@ enum _ecore_status_t ecore_pglueb_rbc_attn_handler(struct ecore_hwfn *p_hwfn,
                                1 : 0),
                          (u8)((tmp & ECORE_PGLUE_ATTENTION_DETAILS2_FID_EN) ?
                                1 : 0));
+               if (is_hw_init)
+                       DP_VERBOSE(p_hwfn, ECORE_MSG_INTR, "%s", str);
+               else
+                       DP_NOTICE(p_hwfn, false, "%s", str);
        }
 
        tmp = ecore_rd(p_hwfn, p_ptt, PGLUE_B_REG_TX_ERR_RD_DETAILS2);
@@ -394,7 +400,7 @@ enum _ecore_status_t ecore_pglueb_rbc_attn_handler(struct ecore_hwfn *p_hwfn,
 
 static enum _ecore_status_t ecore_pglueb_rbc_attn_cb(struct ecore_hwfn *p_hwfn)
 {
-       return ecore_pglueb_rbc_attn_handler(p_hwfn, p_hwfn->p_dpc_ptt);
+       return ecore_pglueb_rbc_attn_handler(p_hwfn, p_hwfn->p_dpc_ptt, false);
 }
 
 static enum _ecore_status_t ecore_fw_assertion(struct ecore_hwfn *p_hwfn)
@@ -414,31 +420,136 @@ ecore_general_attention_35(struct ecore_hwfn *p_hwfn)
        return ECORE_SUCCESS;
 }
 
-#define ECORE_DORQ_ATTENTION_REASON_MASK (0xfffff)
-#define ECORE_DORQ_ATTENTION_OPAQUE_MASK (0xffff)
-#define ECORE_DORQ_ATTENTION_SIZE_MASK  (0x7f0000)
-#define ECORE_DORQ_ATTENTION_SIZE_SHIFT         (16)
+#define ECORE_DORQ_ATTENTION_REASON_MASK       (0xfffff)
+#define ECORE_DORQ_ATTENTION_OPAQUE_MASK       (0xffff)
+#define ECORE_DORQ_ATTENTION_OPAQUE_SHIFT      (0x0)
+#define ECORE_DORQ_ATTENTION_SIZE_MASK         (0x7f)
+#define ECORE_DORQ_ATTENTION_SIZE_SHIFT                (16)
+
+#define ECORE_DB_REC_COUNT                     10
+#define ECORE_DB_REC_INTERVAL                  100
+
+/* assumes sticky overflow indication was set for this PF */
+static enum _ecore_status_t ecore_db_rec_attn(struct ecore_hwfn *p_hwfn,
+                                             struct ecore_ptt *p_ptt)
+{
+       u8 count = ECORE_DB_REC_COUNT;
+       u32 usage = 1;
+
+       /* wait for usage to zero or count to run out. This is necessary since
+        * EDPM doorbell transactions can take multiple 64b cycles, and as such
+        * can "split" over the pci. Possibly, the doorbell drop can happen with
+        * half an EDPM in the queue and other half dropped. Another EDPM
+        * doorbell to the same address (from doorbell recovery mechanism or
+        * from the doorbelling entity) could have first half dropped and second
+        * half interperted as continuation of the first. To prevent such
+        * malformed doorbells from reaching the device, flush the queue before
+        * releaseing the overflow sticky indication.
+        */
+       while (count-- && usage) {
+               usage = ecore_rd(p_hwfn, p_ptt, DORQ_REG_PF_USAGE_CNT);
+               OSAL_UDELAY(ECORE_DB_REC_INTERVAL);
+       }
+
+       /* should have been depleted by now */
+       if (usage) {
+               DP_NOTICE(p_hwfn->p_dev, false,
+                         "DB recovery: doorbell usage failed to zero after %d usec. usage was %x\n",
+                         ECORE_DB_REC_INTERVAL * ECORE_DB_REC_COUNT, usage);
+               return ECORE_TIMEOUT;
+       }
+
+       /* flush any pedning (e)dpm as they may never arrive */
+       ecore_wr(p_hwfn, p_ptt, DORQ_REG_DPM_FORCE_ABORT, 0x1);
+
+       /* release overflow sticky indication (stop silently dropping
+        * everything)
+        */
+       ecore_wr(p_hwfn, p_ptt, DORQ_REG_PF_OVFL_STICKY, 0x0);
+
+       /* repeat all last doorbells (doorbell drop recovery) */
+       ecore_db_recovery_execute(p_hwfn, DB_REC_REAL_DEAL);
+
+       return ECORE_SUCCESS;
+}
 
 static enum _ecore_status_t ecore_dorq_attn_cb(struct ecore_hwfn *p_hwfn)
 {
-       u32 reason;
+       u32 int_sts, first_drop_reason, details, address, overflow,
+               all_drops_reason;
+       struct ecore_ptt *p_ptt = p_hwfn->p_dpc_ptt;
+       enum _ecore_status_t rc;
 
-       reason = ecore_rd(p_hwfn, p_hwfn->p_dpc_ptt, DORQ_REG_DB_DROP_REASON) &
-           ECORE_DORQ_ATTENTION_REASON_MASK;
-       if (reason) {
-               u32 details = ecore_rd(p_hwfn, p_hwfn->p_dpc_ptt,
-                                      DORQ_REG_DB_DROP_DETAILS);
+       int_sts = ecore_rd(p_hwfn, p_ptt, DORQ_REG_INT_STS);
+       DP_NOTICE(p_hwfn->p_dev, false, "DORQ attention. int_sts was %x\n",
+                 int_sts);
 
-               DP_INFO(p_hwfn->p_dev,
-                       "DORQ db_drop: address 0x%08x Opaque FID 0x%04x"
-                       " Size [bytes] 0x%08x Reason: 0x%08x\n",
-                       ecore_rd(p_hwfn, p_hwfn->p_dpc_ptt,
-                                DORQ_REG_DB_DROP_DETAILS_ADDRESS),
-                       (u16)(details & ECORE_DORQ_ATTENTION_OPAQUE_MASK),
-                       ((details & ECORE_DORQ_ATTENTION_SIZE_MASK) >>
-                        ECORE_DORQ_ATTENTION_SIZE_SHIFT) * 4, reason);
+       /* int_sts may be zero since all PFs were interrupted for doorbell
+        * overflow but another one already handled it. Can abort here. If
+        * This PF also requires overflow recovery we will be interrupted again
+        */
+       if (!int_sts)
+               return ECORE_SUCCESS;
+
+       /* check if db_drop or overflow happened */
+       if (int_sts & (DORQ_REG_INT_STS_DB_DROP |
+                      DORQ_REG_INT_STS_DORQ_FIFO_OVFL_ERR)) {
+               /* obtain data about db drop/overflow */
+               first_drop_reason = ecore_rd(p_hwfn, p_ptt,
+                                 DORQ_REG_DB_DROP_REASON) &
+                                 ECORE_DORQ_ATTENTION_REASON_MASK;
+               details = ecore_rd(p_hwfn, p_ptt,
+                                  DORQ_REG_DB_DROP_DETAILS);
+               address = ecore_rd(p_hwfn, p_ptt,
+                                  DORQ_REG_DB_DROP_DETAILS_ADDRESS);
+               overflow = ecore_rd(p_hwfn, p_ptt,
+                                   DORQ_REG_PF_OVFL_STICKY);
+               all_drops_reason = ecore_rd(p_hwfn, p_ptt,
+                                           DORQ_REG_DB_DROP_DETAILS_REASON);
+
+               /* log info */
+               DP_NOTICE(p_hwfn->p_dev, false,
+                         "Doorbell drop occurred\n"
+                         "Address\t\t0x%08x\t(second BAR address)\n"
+                         "FID\t\t0x%04x\t\t(Opaque FID)\n"
+                         "Size\t\t0x%04x\t\t(in bytes)\n"
+                         "1st drop reason\t0x%08x\t(details on first drop since last handling)\n"
+                         "Sticky reasons\t0x%08x\t(all drop reasons since last handling)\n"
+                         "Overflow\t0x%x\t\t(a per PF indication)\n",
+                         address,
+                         GET_FIELD(details, ECORE_DORQ_ATTENTION_OPAQUE),
+                         GET_FIELD(details, ECORE_DORQ_ATTENTION_SIZE) * 4,
+                         first_drop_reason, all_drops_reason, overflow);
+
+               /* if this PF caused overflow, initiate recovery */
+               if (overflow) {
+                       rc = ecore_db_rec_attn(p_hwfn, p_ptt);
+                       if (rc != ECORE_SUCCESS)
+                               return rc;
+               }
+
+               /* clear the doorbell drop details and prepare for next drop */
+               ecore_wr(p_hwfn, p_ptt, DORQ_REG_DB_DROP_DETAILS_REL, 0);
+
+               /* mark interrupt as handeld (note: even if drop was due to a
+                * different reason than overflow we mark as handled)
+                */
+               ecore_wr(p_hwfn, p_ptt, DORQ_REG_INT_STS_WR,
+                        DORQ_REG_INT_STS_DB_DROP |
+                        DORQ_REG_INT_STS_DORQ_FIFO_OVFL_ERR);
+
+               /* if there are no indications otherthan drop indications,
+                * success
+                */
+               if ((int_sts & ~(DORQ_REG_INT_STS_DB_DROP |
+                                DORQ_REG_INT_STS_DORQ_FIFO_OVFL_ERR |
+                                DORQ_REG_INT_STS_DORQ_FIFO_AFULL)) == 0)
+                       return ECORE_SUCCESS;
        }
 
+       /* some other indication was present - non recoverable */
+       DP_INFO(p_hwfn, "DORQ fatal attention\n");
+
        return ECORE_INVAL;
 }
 
@@ -1000,9 +1111,9 @@ static enum _ecore_status_t ecore_int_deassertion(struct ecore_hwfn *p_hwfn,
                                                              p_aeu->bit_name,
                                                              num);
                                        else
-                                               OSAL_STRNCPY(bit_name,
-                                                            p_aeu->bit_name,
-                                                            30);
+                                               strlcpy(bit_name,
+                                                       p_aeu->bit_name,
+                                                       sizeof(bit_name));
 
                                        /* We now need to pass bitmask in its
                                         * correct position.
@@ -1302,8 +1413,7 @@ static enum _ecore_status_t ecore_int_sb_attn_alloc(struct ecore_hwfn *p_hwfn,
        /* SB struct */
        p_sb = OSAL_ALLOC(p_dev, GFP_KERNEL, sizeof(*p_sb));
        if (!p_sb) {
-               DP_NOTICE(p_dev, true,
-                         "Failed to allocate `struct ecore_sb_attn_info'\n");
+               DP_NOTICE(p_dev, false, "Failed to allocate `struct ecore_sb_attn_info'\n");
                return ECORE_NOMEM;
        }
 
@@ -1311,8 +1421,7 @@ static enum _ecore_status_t ecore_int_sb_attn_alloc(struct ecore_hwfn *p_hwfn,
        p_virt = OSAL_DMA_ALLOC_COHERENT(p_dev, &p_phys,
                                         SB_ATTN_ALIGNED_SIZE(p_hwfn));
        if (!p_virt) {
-               DP_NOTICE(p_dev, true,
-                         "Failed to allocate status block (attentions)\n");
+               DP_NOTICE(p_dev, false, "Failed to allocate status block (attentions)\n");
                OSAL_FREE(p_dev, p_sb);
                return ECORE_NOMEM;
        }
@@ -1387,7 +1496,7 @@ static void _ecore_int_cau_conf_pi(struct ecore_hwfn *p_hwfn,
        if (IS_VF(p_hwfn->p_dev))
                return;/* @@@TBD MichalK- VF CAU... */
 
-       sb_offset = igu_sb_id * PIS_PER_SB;
+       sb_offset = igu_sb_id * PIS_PER_SB_E4;
        OSAL_MEMSET(&pi_entry, 0, sizeof(struct cau_pi_entry));
 
        SET_FIELD(pi_entry.prod, CAU_PI_ENTRY_PI_TIMESET, timeset);
@@ -1691,8 +1800,7 @@ static enum _ecore_status_t ecore_int_sp_sb_alloc(struct ecore_hwfn *p_hwfn,
            OSAL_ALLOC(p_hwfn->p_dev, GFP_KERNEL,
                       sizeof(*p_sb));
        if (!p_sb) {
-               DP_NOTICE(p_hwfn, true,
-                         "Failed to allocate `struct ecore_sb_info'\n");
+               DP_NOTICE(p_hwfn, false, "Failed to allocate `struct ecore_sb_info'\n");
                return ECORE_NOMEM;
        }
 
@@ -1700,7 +1808,7 @@ static enum _ecore_status_t ecore_int_sp_sb_alloc(struct ecore_hwfn *p_hwfn,
        p_virt = OSAL_DMA_ALLOC_COHERENT(p_hwfn->p_dev,
                                         &p_phys, SB_ALIGNED_SIZE(p_hwfn));
        if (!p_virt) {
-               DP_NOTICE(p_hwfn, true, "Failed to allocate status block\n");
+               DP_NOTICE(p_hwfn, false, "Failed to allocate status block\n");
                OSAL_FREE(p_hwfn->p_dev, p_sb);
                return ECORE_NOMEM;
        }
@@ -1821,15 +1929,6 @@ ecore_int_igu_enable(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
                          enum ecore_int_mode int_mode)
 {
        enum _ecore_status_t rc = ECORE_SUCCESS;
-       u32 tmp;
-
-       /* @@@tmp - Starting with MFW 8.2.1.0 we've started hitting AVS stop
-        * attentions. Since we're waiting for BRCM answer regarding this
-        * attention, in the meanwhile we simply mask it.
-        */
-       tmp = ecore_rd(p_hwfn, p_ptt, MISC_REG_AEU_ENABLE4_IGU_OUT_0);
-       tmp &= ~0x800;
-       ecore_wr(p_hwfn, p_ptt, MISC_REG_AEU_ENABLE4_IGU_OUT_0, tmp);
 
        ecore_int_igu_enable_attn(p_hwfn, p_ptt);
 
@@ -2572,10 +2671,11 @@ enum _ecore_status_t ecore_int_get_sb_dbg(struct ecore_hwfn *p_hwfn,
        p_info->igu_cons = ecore_rd(p_hwfn, p_ptt,
                                    IGU_REG_CONSUMER_MEM + sbid * 4);
 
-       for (i = 0; i < PIS_PER_SB; i++)
+       for (i = 0; i < PIS_PER_SB_E4; i++)
                p_info->pi[i] = (u16)ecore_rd(p_hwfn, p_ptt,
                                              CAU_REG_PI_MEMORY +
-                                             sbid * 4 * PIS_PER_SB +  i * 4);
+                                             sbid * 4 * PIS_PER_SB_E4 +
+                                             i * 4);
 
        return ECORE_SUCCESS;
 }