net/qede/base: fix numbering L2 VF queues
authorRasesh Mody <rasesh.mody@cavium.com>
Sat, 18 Mar 2017 06:50:21 +0000 (23:50 -0700)
committerFerruh Yigit <ferruh.yigit@intel.com>
Tue, 4 Apr 2017 16:59:44 +0000 (18:59 +0200)
There are some constellations where Due to lack of resource allocation
in MFW, There would be an insufficient number of L2 queues for all the
VFs.

This introduces a new feature ECORE_VF_L2_QUE which correctly numbers
the number of VF queues. Notice it might be larger than the actual
number of VFs in configuration space, in which case its the ecore
client responsibility not to try activating that many.

As part of the fix, also correct the nubmering of the VF queues. As
their numbering is dependent on the SBs of the PF, which might only be
partially used by L2 [as half would be assigned for RDMA which doesn't
require L2 queues], we make the numbering consecutive with that of the
L2 queues only.

Fixes: ec94dbc57362 ("qede: add base driver")

Signed-off-by: Rasesh Mody <rasesh.mody@cavium.com>
drivers/net/qede/base/ecore.h
drivers/net/qede/base/ecore_dev.c
drivers/net/qede/base/ecore_int.c

index b41ff4a..b2f4910 100644 (file)
@@ -288,6 +288,7 @@ enum ecore_feature {
        ECORE_RDMA_CNQ,
        ECORE_ISCSI_CQ,
        ECORE_FCOE_CQ,
+       ECORE_VF_L2_QUE,
        ECORE_MAX_FEATURES,
 };
 
index 5555174..b5873bd 100644 (file)
@@ -2057,6 +2057,7 @@ static void get_function_id(struct ecore_hwfn *p_hwfn)
 static void ecore_hw_set_feat(struct ecore_hwfn *p_hwfn)
 {
        u32 *feat_num = p_hwfn->hw_info.feat_num;
+       struct ecore_sb_cnt_info sb_cnt_info;
        int num_features = 1;
 
        /* L2 Queues require each: 1 status block. 1 L2 queue */
@@ -2065,11 +2066,21 @@ static void ecore_hw_set_feat(struct ecore_hwfn *p_hwfn)
                       RESC_NUM(p_hwfn, ECORE_SB) / num_features,
                       RESC_NUM(p_hwfn, ECORE_L2_QUEUE));
 
+       OSAL_MEM_ZERO(&sb_cnt_info, sizeof(sb_cnt_info));
+       ecore_int_get_num_sbs(p_hwfn, &sb_cnt_info);
+       feat_num[ECORE_VF_L2_QUE] =
+               OSAL_MIN_T(u32,
+                          RESC_NUM(p_hwfn, ECORE_L2_QUEUE) -
+                          FEAT_NUM(p_hwfn, ECORE_PF_L2_QUE),
+                          sb_cnt_info.sb_iov_cnt);
+
        DP_VERBOSE(p_hwfn, ECORE_MSG_PROBE,
-                  "#PF_L2_QUEUES=%d #ROCE_CNQ=%d #SBS=%d num_features=%d\n",
-                  feat_num[ECORE_PF_L2_QUE],
-                  feat_num[ECORE_RDMA_CNQ],
-                  RESC_NUM(p_hwfn, ECORE_SB), num_features);
+                  "#PF_L2_QUEUES=%d VF_L2_QUEUES=%d #ROCE_CNQ=%d #SBS=%d num_features=%d\n",
+                  (int)FEAT_NUM(p_hwfn, ECORE_PF_L2_QUE),
+                  (int)FEAT_NUM(p_hwfn, ECORE_VF_L2_QUE),
+                  (int)FEAT_NUM(p_hwfn, ECORE_RDMA_CNQ),
+                  RESC_NUM(p_hwfn, ECORE_SB),
+                  num_features);
 }
 
 static enum resource_id_enum
index 96f283b..1a157a5 100644 (file)
@@ -1964,6 +1964,31 @@ enum _ecore_status_t ecore_int_igu_read_cam(struct ecore_hwfn *p_hwfn,
                        }
                }
        }
+
+       /* There's a possibility the igu_sb_cnt_iov doesn't properly reflect
+        * the number of VF SBs [especially for first VF on engine, as we can't
+        * diffrentiate between empty entries and its entries].
+        * Since we don't really support more SBs than VFs today, prevent any
+        * such configuration by sanitizing the number of SBs to equal the
+        * number of VFs.
+        */
+       if (IS_PF_SRIOV(p_hwfn)) {
+               u16 total_vfs = p_hwfn->p_dev->p_iov_info->total_vfs;
+
+               if (total_vfs < p_igu_info->free_blks) {
+                       DP_VERBOSE(p_hwfn, (ECORE_MSG_INTR | ECORE_MSG_IOV),
+                                  "Limiting number of SBs for IOV - %04x --> %04x\n",
+                                  p_igu_info->free_blks,
+                                  p_hwfn->p_dev->p_iov_info->total_vfs);
+                       p_igu_info->free_blks = total_vfs;
+               } else if (total_vfs > p_igu_info->free_blks) {
+                       DP_NOTICE(p_hwfn, true,
+                                 "IGU has only %04x SBs for VFs while the device has %04x VFs\n",
+                                 p_igu_info->free_blks, total_vfs);
+                       return ECORE_INVAL;
+               }
+       }
+
        p_igu_info->igu_sb_cnt_iov = p_igu_info->free_blks;
 
        DP_VERBOSE(p_hwfn, ECORE_MSG_INTR,
@@ -2101,8 +2126,14 @@ u16 ecore_int_queue_id_from_sb_id(struct ecore_hwfn *p_hwfn, u16 sb_id)
            (sb_id < p_info->igu_base_sb + p_info->igu_sb_cnt)) {
                return sb_id - p_info->igu_base_sb;
        } else if ((sb_id >= p_info->igu_base_sb_iov) &&
-                  (sb_id < p_info->igu_base_sb_iov + p_info->igu_sb_cnt_iov)) {
-               return sb_id - p_info->igu_base_sb_iov + p_info->igu_sb_cnt;
+                  (sb_id < p_info->igu_base_sb_iov +
+                           p_info->igu_sb_cnt_iov)) {
+               /* We want the first VF queue to be adjacent to the
+                * last PF queue. Since L2 queues can be partial to
+                * SBs, we'll use the feature instead.
+                */
+               return sb_id - p_info->igu_base_sb_iov +
+                      FEAT_NUM(p_hwfn, ECORE_PF_L2_QUE);
        } else {
                DP_NOTICE(p_hwfn, true, "SB %d not in range for function\n",
                          sb_id);