OSDN Git Service

qed: Use VF-queue feature
authorMintz, Yuval <Yuval.Mintz@cavium.com>
Mon, 31 Oct 2016 05:14:26 +0000 (07:14 +0200)
committerDavid S. Miller <davem@davemloft.net>
Mon, 31 Oct 2016 19:52:36 +0000 (15:52 -0400)
Driver sets several restrictions about the number of supported VFs
according to available HW/FW resources.
This creates a problem as there are constellations which can't be
supported [as limitation don't accurately describe the resources],
as well as holes where enabling IOV would fail due to supposed
lack of resources.

This introduces a new interal feature - vf-queues, which would
be used to lift some of the restriction and accurately enumerate
the queues that can be used by a given PF's VFs.

Signed-off-by: Yuval Mintz <Yuval.Mintz@cavium.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/qlogic/qed/qed.h
drivers/net/ethernet/qlogic/qed/qed_dev.c
drivers/net/ethernet/qlogic/qed/qed_int.c
drivers/net/ethernet/qlogic/qed/qed_sriov.c

index 8828ffa..6d3013f 100644 (file)
@@ -174,6 +174,7 @@ enum QED_FEATURE {
        QED_PF_L2_QUE,
        QED_VF,
        QED_RDMA_CNQ,
+       QED_VF_L2_QUE,
        QED_MAX_FEATURES,
 };
 
index 127ed5f..d996afe 100644 (file)
@@ -1476,6 +1476,7 @@ static void get_function_id(struct qed_hwfn *p_hwfn)
 static void qed_hw_set_feat(struct qed_hwfn *p_hwfn)
 {
        u32 *feat_num = p_hwfn->hw_info.feat_num;
+       struct qed_sb_cnt_info sb_cnt_info;
        int num_features = 1;
 
        if (IS_ENABLED(CONFIG_QED_RDMA) &&
@@ -1494,10 +1495,21 @@ static void qed_hw_set_feat(struct qed_hwfn *p_hwfn)
        feat_num[QED_PF_L2_QUE] = min_t(u32, RESC_NUM(p_hwfn, QED_SB) /
                                                num_features,
                                        RESC_NUM(p_hwfn, QED_L2_QUEUE));
-       DP_VERBOSE(p_hwfn, NETIF_MSG_PROBE,
-                  "#PF_L2_QUEUES=%d #SBS=%d num_features=%d\n",
-                  feat_num[QED_PF_L2_QUE], RESC_NUM(p_hwfn, QED_SB),
-                  num_features);
+
+       memset(&sb_cnt_info, 0, sizeof(sb_cnt_info));
+       qed_int_get_num_sbs(p_hwfn, &sb_cnt_info);
+       feat_num[QED_VF_L2_QUE] =
+           min_t(u32,
+                 RESC_NUM(p_hwfn, QED_L2_QUEUE) -
+                 FEAT_NUM(p_hwfn, QED_PF_L2_QUE), sb_cnt_info.sb_iov_cnt);
+
+       DP_VERBOSE(p_hwfn,
+                  NETIF_MSG_PROBE,
+                  "#PF_L2_QUEUES=%d VF_L2_QUEUES=%d #ROCE_CNQ=%d #SBS=%d num_features=%d\n",
+                  (int)FEAT_NUM(p_hwfn, QED_PF_L2_QUE),
+                  (int)FEAT_NUM(p_hwfn, QED_VF_L2_QUE),
+                  (int)FEAT_NUM(p_hwfn, QED_RDMA_CNQ),
+                  RESC_NUM(p_hwfn, QED_SB), num_features);
 }
 
 static int qed_hw_get_resc(struct qed_hwfn *p_hwfn)
index 2adedc6..bb74e1c 100644 (file)
@@ -3030,6 +3030,31 @@ int qed_int_igu_read_cam(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
                        }
                }
        }
+
+       /* 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->cdev->p_iov_info->total_vfs;
+
+               if (total_vfs < p_igu_info->free_blks) {
+                       DP_VERBOSE(p_hwfn,
+                                  (NETIF_MSG_INTR | QED_MSG_IOV),
+                                  "Limiting number of SBs for IOV - %04x --> %04x\n",
+                                  p_igu_info->free_blks,
+                                  p_hwfn->cdev->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,
+                                 "IGU has only %04x SBs for VFs while the device has %04x VFs\n",
+                                 p_igu_info->free_blks, total_vfs);
+                       return -EINVAL;
+               }
+       }
        p_igu_info->igu_sb_cnt_iov = p_igu_info->free_blks;
 
        DP_VERBOSE(
@@ -3163,7 +3188,12 @@ u16 qed_int_queue_id_from_sb_id(struct qed_hwfn *p_hwfn, u16 sb_id)
                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;
+               /* 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, QED_PF_L2_QUE);
        } else {
                DP_NOTICE(p_hwfn, "SB %d not in range for function\n", sb_id);
                return 0;
index 6f029f9..f3f742a 100644 (file)
@@ -3470,7 +3470,6 @@ int qed_sriov_disable(struct qed_dev *cdev, bool pci_enabled)
 
 static int qed_sriov_enable(struct qed_dev *cdev, int num)
 {
-       struct qed_sb_cnt_info sb_cnt_info;
        int i, j, rc;
 
        if (num >= RESC_NUM(&cdev->hwfns[0], QED_VPORT)) {
@@ -3483,7 +3482,11 @@ static int qed_sriov_enable(struct qed_dev *cdev, int num)
        for_each_hwfn(cdev, j) {
                struct qed_hwfn *hwfn = &cdev->hwfns[j];
                struct qed_ptt *ptt = qed_ptt_acquire(hwfn);
-               int num_sbs = 0, limit = 16;
+               int num_queues;
+
+               /* Make sure not to use more than 16 queues per VF */
+               num_queues = min_t(int,
+                                  FEAT_NUM(hwfn, QED_VF_L2_QUE) / num, 16);
 
                if (!ptt) {
                        DP_ERR(hwfn, "Failed to acquire ptt\n");
@@ -3491,19 +3494,11 @@ static int qed_sriov_enable(struct qed_dev *cdev, int num)
                        goto err;
                }
 
-               if (IS_MF_DEFAULT(hwfn))
-                       limit = MAX_NUM_VFS_BB / hwfn->num_funcs_on_engine;
-
-               memset(&sb_cnt_info, 0, sizeof(sb_cnt_info));
-               qed_int_get_num_sbs(hwfn, &sb_cnt_info);
-               num_sbs = min_t(int, sb_cnt_info.sb_free_blk, limit);
-
                for (i = 0; i < num; i++) {
                        if (!qed_iov_is_valid_vfid(hwfn, i, false, true))
                                continue;
 
-                       rc = qed_iov_init_hw_for_vf(hwfn,
-                                                   ptt, i, num_sbs / num);
+                       rc = qed_iov_init_hw_for_vf(hwfn, ptt, i, num_queues);
                        if (rc) {
                                DP_ERR(cdev, "Failed to enable VF[%d]\n", i);
                                qed_ptt_release(hwfn, ptt);