net/qede/base: utilize FW 8.18.9.0
[dpdk.git] / drivers / net / qede / base / ecore_sriov.c
index c2fbee8..b051678 100644 (file)
@@ -146,7 +146,7 @@ static enum _ecore_status_t ecore_sp_vf_stop(struct ecore_hwfn *p_hwfn,
 }
 
 bool ecore_iov_is_valid_vfid(struct ecore_hwfn *p_hwfn, int rel_vf_id,
-                            bool b_enabled_only)
+                            bool b_enabled_only, bool b_non_malicious)
 {
        if (!p_hwfn->pf_iov_info) {
                DP_NOTICE(p_hwfn->p_dev, true, "No iov info\n");
@@ -161,6 +161,10 @@ bool ecore_iov_is_valid_vfid(struct ecore_hwfn *p_hwfn, int rel_vf_id,
            b_enabled_only)
                return false;
 
+       if ((p_hwfn->pf_iov_info->vfs_array[rel_vf_id].b_malicious) &&
+           b_non_malicious)
+               return false;
+
        return true;
 }
 
@@ -175,7 +179,8 @@ struct ecore_vf_info *ecore_iov_get_vf_info(struct ecore_hwfn *p_hwfn,
                return OSAL_NULL;
        }
 
-       if (ecore_iov_is_valid_vfid(p_hwfn, relative_vf_id, b_enabled_only))
+       if (ecore_iov_is_valid_vfid(p_hwfn, relative_vf_id,
+                                   b_enabled_only, false))
                vf = &p_hwfn->pf_iov_info->vfs_array[relative_vf_id];
        else
                DP_ERR(p_hwfn, "ecore_iov_get_vf_info: VF[%d] is not enabled\n",
@@ -549,7 +554,6 @@ void ecore_iov_free(struct ecore_hwfn *p_hwfn)
 void ecore_iov_free_hw_info(struct ecore_dev *p_dev)
 {
        OSAL_FREE(p_dev, p_dev->p_iov_info);
-       p_dev->p_iov_info = OSAL_NULL;
 }
 
 enum _ecore_status_t ecore_iov_hw_info(struct ecore_hwfn *p_hwfn)
@@ -592,18 +596,33 @@ enum _ecore_status_t ecore_iov_hw_info(struct ecore_hwfn *p_hwfn)
                DP_VERBOSE(p_hwfn, ECORE_MSG_IOV,
                           "IOV capabilities, but no VFs are published\n");
                OSAL_FREE(p_dev, p_dev->p_iov_info);
-               p_dev->p_iov_info = OSAL_NULL;
                return ECORE_SUCCESS;
        }
 
-       /* Calculate the first VF index - this is a bit tricky; Basically,
-        * VFs start at offset 16 relative to PF0, and 2nd engine VFs begin
-        * after the first engine's VFs.
+       /* First VF index based on offset is tricky:
+        *  - If ARI is supported [likely], offset - (16 - pf_id) would
+        *    provide the number for eng0. 2nd engine Vfs would begin
+        *    after the first engine's VFs.
+        *  - If !ARI, VFs would start on next device.
+        *    so offset - (256 - pf_id) would provide the number.
+        * Utilize the fact that (256 - pf_id) is achieved only be later
+        * to diffrentiate between the two.
         */
-       p_dev->p_iov_info->first_vf_in_pf = p_hwfn->p_dev->p_iov_info->offset +
-                                           p_hwfn->abs_pf_id - 16;
-       if (ECORE_PATH_ID(p_hwfn))
-               p_dev->p_iov_info->first_vf_in_pf -= MAX_NUM_VFS_BB;
+
+       if (p_hwfn->p_dev->p_iov_info->offset < (256 - p_hwfn->abs_pf_id)) {
+               u32 first = p_hwfn->p_dev->p_iov_info->offset +
+                           p_hwfn->abs_pf_id - 16;
+
+               p_dev->p_iov_info->first_vf_in_pf = first;
+
+               if (ECORE_PATH_ID(p_hwfn))
+                       p_dev->p_iov_info->first_vf_in_pf -= MAX_NUM_VFS_BB;
+       } else {
+               u32 first = p_hwfn->p_dev->p_iov_info->offset +
+                           p_hwfn->abs_pf_id - 256;
+
+               p_dev->p_iov_info->first_vf_in_pf = first;
+       }
 
        DP_VERBOSE(p_hwfn, ECORE_MSG_IOV,
                   "First VF in hwfn 0x%08x\n",
@@ -612,7 +631,8 @@ enum _ecore_status_t ecore_iov_hw_info(struct ecore_hwfn *p_hwfn)
        return ECORE_SUCCESS;
 }
 
-bool ecore_iov_pf_sanity_check(struct ecore_hwfn *p_hwfn, int vfid)
+bool _ecore_iov_pf_sanity_check(struct ecore_hwfn *p_hwfn, int vfid,
+                               bool b_fail_malicious)
 {
        /* Check PF supports sriov */
        if (IS_VF(p_hwfn->p_dev) || !IS_ECORE_SRIOV(p_hwfn->p_dev) ||
@@ -620,12 +640,17 @@ bool ecore_iov_pf_sanity_check(struct ecore_hwfn *p_hwfn, int vfid)
                return false;
 
        /* Check VF validity */
-       if (!ecore_iov_is_valid_vfid(p_hwfn, vfid, true))
+       if (!ecore_iov_is_valid_vfid(p_hwfn, vfid, true, b_fail_malicious))
                return false;
 
        return true;
 }
 
+bool ecore_iov_pf_sanity_check(struct ecore_hwfn *p_hwfn, int vfid)
+{
+       return _ecore_iov_pf_sanity_check(p_hwfn, vfid, true);
+}
+
 void ecore_iov_set_vf_to_disable(struct ecore_dev *p_dev,
                                 u16 rel_vf_id, u8 to_disable)
 {
@@ -746,6 +771,9 @@ ecore_iov_enable_vf_access(struct ecore_hwfn *p_hwfn,
 
        ecore_iov_vf_igu_reset(p_hwfn, p_ptt, vf);
 
+       /* It's possible VF was previously considered malicious */
+       vf->b_malicious = false;
+
        rc = ecore_mcp_config_vf_msix(p_hwfn, p_ptt,
                                      vf->abs_vf_id, vf->num_sbs);
        if (rc != ECORE_SUCCESS)
@@ -1661,11 +1689,9 @@ ecore_iov_reconfigure_unicast_vlan(struct ecore_hwfn *p_hwfn,
                DP_VERBOSE(p_hwfn, ECORE_MSG_IOV,
                           "Reconfiguring VLAN [0x%04x] for VF [%04x]\n",
                           filter.vlan, p_vf->relative_vf_id);
-               rc = ecore_sp_eth_filter_ucast(p_hwfn,
-                                              p_vf->opaque_fid,
-                                              &filter,
-                                              ECORE_SPQ_MODE_CB,
-                                                      OSAL_NULL);
+               rc = ecore_sp_eth_filter_ucast(p_hwfn, p_vf->opaque_fid,
+                                              &filter, ECORE_SPQ_MODE_CB,
+                                              OSAL_NULL);
                if (rc) {
                        DP_NOTICE(p_hwfn, true,
                                  "Failed to configure VLAN [%04x]"
@@ -1693,9 +1719,10 @@ ecore_iov_reconfigure_unicast_shadow(struct ecore_hwfn *p_hwfn,
        return rc;
 }
 
-static int ecore_iov_configure_vport_forced(struct ecore_hwfn *p_hwfn,
-                                           struct ecore_vf_info *p_vf,
-                                           u64 events)
+static  enum _ecore_status_t
+ecore_iov_configure_vport_forced(struct ecore_hwfn *p_hwfn,
+                                struct ecore_vf_info *p_vf,
+                                u64 events)
 {
        enum _ecore_status_t rc = ECORE_SUCCESS;
        struct ecore_filter_ucast filter;
@@ -1972,7 +1999,7 @@ static void ecore_iov_vf_mbx_start_rxq(struct ecore_hwfn *p_hwfn,
                                       struct ecore_ptt *p_ptt,
                                       struct ecore_vf_info *vf)
 {
-       struct ecore_queue_start_common_params p_params;
+       struct ecore_queue_start_common_params params;
        struct ecore_iov_vf_mbx *mbx = &vf->vf_mbx;
        u8 status = PFVF_STATUS_NO_RESOURCE;
        struct vfpf_start_rxq_tlv *req;
@@ -1985,13 +2012,13 @@ static void ecore_iov_vf_mbx_start_rxq(struct ecore_hwfn *p_hwfn,
            !ecore_iov_validate_sb(p_hwfn, vf, req->hw_sb))
                goto out;
 
-       OSAL_MEMSET(&p_params, 0, sizeof(p_params));
-       p_params.queue_id = (u8)vf->vf_queues[req->rx_qid].fw_rx_qid;
-       p_params.vf_qid = req->rx_qid;
-       p_params.vport_id = vf->vport_id;
-       p_params.stats_id = vf->abs_vf_id + 0x10,
-       p_params.sb = req->hw_sb;
-       p_params.sb_idx = req->sb_index;
+       OSAL_MEMSET(&params, 0, sizeof(params));
+       params.queue_id = (u8)vf->vf_queues[req->rx_qid].fw_rx_qid;
+       params.vf_qid = req->rx_qid;
+       params.vport_id = vf->vport_id;
+       params.stats_id = vf->abs_vf_id + 0x10;
+       params.sb = req->hw_sb;
+       params.sb_idx = req->sb_index;
 
        /* Legacy VFs have their Producers in a different location, which they
         * calculate on their own and clean the producer prior to this.
@@ -2007,7 +2034,7 @@ static void ecore_iov_vf_mbx_start_rxq(struct ecore_hwfn *p_hwfn,
 
        rc = ecore_sp_eth_rxq_start_ramrod(p_hwfn, vf->opaque_fid,
                                           vf->vf_queues[req->rx_qid].fw_cid,
-                                          &p_params,
+                                          &params,
                                           req->bd_max_bytes,
                                           req->rxq_addr,
                                           req->cqe_pbl_addr,
@@ -2072,7 +2099,7 @@ static void ecore_iov_vf_mbx_start_txq(struct ecore_hwfn *p_hwfn,
                                       struct ecore_ptt *p_ptt,
                                       struct ecore_vf_info *vf)
 {
-       struct ecore_queue_start_common_params p_params;
+       struct ecore_queue_start_common_params params;
        struct ecore_iov_vf_mbx *mbx = &vf->vf_mbx;
        u8 status = PFVF_STATUS_NO_RESOURCE;
        union ecore_qm_pq_params pq_params;
@@ -2084,26 +2111,27 @@ static void ecore_iov_vf_mbx_start_txq(struct ecore_hwfn *p_hwfn,
        pq_params.eth.is_vf = 1;
        pq_params.eth.vf_id = vf->relative_vf_id;
 
+       OSAL_MEMSET(&params, 0, sizeof(params));
        req = &mbx->req_virt->start_txq;
-       OSAL_MEMSET(&p_params, 0, sizeof(p_params));
-       p_params.queue_id = (u8)vf->vf_queues[req->tx_qid].fw_tx_qid;
-       p_params.vport_id = vf->vport_id;
-       p_params.stats_id = vf->abs_vf_id + 0x10,
-       p_params.sb = req->hw_sb;
-       p_params.sb_idx = req->sb_index;
 
        if (!ecore_iov_validate_txq(p_hwfn, vf, req->tx_qid) ||
            !ecore_iov_validate_sb(p_hwfn, vf, req->hw_sb))
                goto out;
 
-       rc = ecore_sp_eth_txq_start_ramrod(
-               p_hwfn,
-               vf->opaque_fid,
-               vf->vf_queues[req->tx_qid].fw_cid,
-               &p_params,
-               req->pbl_addr,
-               req->pbl_size,
-               &pq_params);
+       params.queue_id = (u8)vf->vf_queues[req->tx_qid].fw_tx_qid;
+       params.qzone_id = (u8)vf->vf_queues[req->tx_qid].fw_tx_qid;
+       params.vport_id = vf->vport_id;
+       params.stats_id = vf->abs_vf_id + 0x10;
+       params.sb = req->hw_sb;
+       params.sb_idx = req->sb_index;
+
+       rc = ecore_sp_eth_txq_start_ramrod(p_hwfn,
+                                          vf->opaque_fid,
+                                          vf->vf_queues[req->tx_qid].fw_cid,
+                                          &params,
+                                          req->pbl_addr,
+                                          req->pbl_size,
+                                          &pq_params);
 
        if (rc)
                status = PFVF_STATUS_FAILURE;
@@ -3061,6 +3089,13 @@ ecore_iov_execute_vf_flr_cleanup(struct ecore_hwfn *p_hwfn,
                        return rc;
                }
 
+               /* Workaround to make VF-PF channel ready, as FW
+                * doesn't do that as a part of FLR.
+                */
+               REG_WR(p_hwfn,
+                      GTT_BAR0_MAP_REG_USDM_RAM +
+                      USTORM_VF_PF_CHANNEL_READY_OFFSET(vfid), 1);
+
                /* VF_STOPPED has to be set only after final cleanup
                 * but prior to re-enabling the VF.
                 */
@@ -3127,9 +3162,10 @@ ecore_iov_single_vf_flr_cleanup(struct ecore_hwfn *p_hwfn,
        return rc;
 }
 
-int ecore_iov_mark_vf_flr(struct ecore_hwfn *p_hwfn, u32 *p_disabled_vfs)
+bool ecore_iov_mark_vf_flr(struct ecore_hwfn *p_hwfn, u32 *p_disabled_vfs)
 {
-       u16 i, found = 0;
+       bool found = false;
+       u16 i;
 
        DP_VERBOSE(p_hwfn, ECORE_MSG_IOV, "Marking FLR-ed VFs\n");
        for (i = 0; i < (VF_MAX_STATIC / 32); i++)
@@ -3139,7 +3175,7 @@ int ecore_iov_mark_vf_flr(struct ecore_hwfn *p_hwfn, u32 *p_disabled_vfs)
 
        if (!p_hwfn->p_dev->p_iov_info) {
                DP_NOTICE(p_hwfn, true, "VF flr but no IOV\n");
-               return 0;
+               return false;
        }
 
        /* Mark VFs */
@@ -3168,7 +3204,7 @@ int ecore_iov_mark_vf_flr(struct ecore_hwfn *p_hwfn, u32 *p_disabled_vfs)
                         * VF flr until ACKs, we're safe.
                         */
                        p_flr[rel_vf_id / 64] |= 1ULL << (rel_vf_id % 64);
-                       found = 1;
+                       found = true;
                }
        }
 
@@ -3227,7 +3263,8 @@ void ecore_iov_process_mbx_req(struct ecore_hwfn *p_hwfn,
                                     p_vf, mbx->first_tlv.tl.type);
 
        /* check if tlv type is known */
-       if (ecore_iov_tlv_supported(mbx->first_tlv.tl.type)) {
+       if (ecore_iov_tlv_supported(mbx->first_tlv.tl.type) &&
+           !p_vf->b_malicious) {
                /* switch on the opcode */
                switch (mbx->first_tlv.tl.type) {
                case CHANNEL_TLV_ACQUIRE:
@@ -3270,6 +3307,27 @@ void ecore_iov_process_mbx_req(struct ecore_hwfn *p_hwfn,
                        ecore_iov_vf_mbx_release(p_hwfn, p_ptt, p_vf);
                        break;
                }
+       } else if (ecore_iov_tlv_supported(mbx->first_tlv.tl.type)) {
+               /* If we've received a message from a VF we consider malicious
+                * we ignore the messasge unless it's one for RELEASE, in which
+                * case we'll let it have the benefit of doubt, allowing the
+                * next loaded driver to start again.
+                */
+               if (mbx->first_tlv.tl.type == CHANNEL_TLV_RELEASE) {
+                       /* TODO - initiate FLR, remove malicious indication */
+                       DP_VERBOSE(p_hwfn, ECORE_MSG_IOV,
+                                  "VF [%02x] - considered malicious, but wanted to RELEASE. TODO\n",
+                                  p_vf->abs_vf_id);
+               } else {
+                       DP_VERBOSE(p_hwfn, ECORE_MSG_IOV,
+                                  "VF [%02x] - considered malicious; Ignoring TLV [%04x]\n",
+                                  p_vf->abs_vf_id, mbx->first_tlv.tl.type);
+               }
+
+               ecore_iov_prepare_resp(p_hwfn, p_ptt, p_vf,
+                                      mbx->first_tlv.tl.type,
+                                      sizeof(struct pfvf_def_resp_tlv),
+                                      PFVF_STATUS_MALICIOUS);
        } else {
                /* unknown TLV - this may belong to a VF driver from the future
                 * - a version written after this PF driver was written, which
@@ -3334,21 +3392,31 @@ void ecore_iov_pf_get_and_clear_pending_events(struct ecore_hwfn *p_hwfn,
                    sizeof(u64) * ECORE_VF_ARRAY_LENGTH);
 }
 
-static enum _ecore_status_t ecore_sriov_vfpf_msg(struct ecore_hwfn *p_hwfn,
-                                                u16 abs_vfid,
-                                                struct regpair *vf_msg)
+static struct ecore_vf_info *
+ecore_sriov_get_vf_from_absid(struct ecore_hwfn *p_hwfn, u16 abs_vfid)
 {
        u8 min = (u8)p_hwfn->p_dev->p_iov_info->first_vf_in_pf;
-       struct ecore_vf_info *p_vf;
 
-       if (!ecore_iov_pf_sanity_check(p_hwfn, (int)abs_vfid - min)) {
+       if (!_ecore_iov_pf_sanity_check(p_hwfn, (int)abs_vfid - min, false)) {
                DP_VERBOSE(p_hwfn, ECORE_MSG_IOV,
-                          "Got a message from VF [abs 0x%08x] that cannot be"
+                          "Got indication for VF [abs 0x%08x] that cannot be"
                           " handled by PF\n",
                           abs_vfid);
-               return ECORE_SUCCESS;
+               return OSAL_NULL;
        }
-       p_vf = &p_hwfn->pf_iov_info->vfs_array[(u8)abs_vfid - min];
+
+       return &p_hwfn->pf_iov_info->vfs_array[(u8)abs_vfid - min];
+}
+
+static enum _ecore_status_t ecore_sriov_vfpf_msg(struct ecore_hwfn *p_hwfn,
+                                                u16 abs_vfid,
+                                                struct regpair *vf_msg)
+{
+       struct ecore_vf_info *p_vf = ecore_sriov_get_vf_from_absid(p_hwfn,
+                                                                  abs_vfid);
+
+       if (!p_vf)
+               return ECORE_SUCCESS;
 
        /* List the physical address of the request so that handler
         * could later on copy the message from it.
@@ -3358,6 +3426,25 @@ static enum _ecore_status_t ecore_sriov_vfpf_msg(struct ecore_hwfn *p_hwfn,
        return OSAL_PF_VF_MSG(p_hwfn, p_vf->relative_vf_id);
 }
 
+static void ecore_sriov_vfpf_malicious(struct ecore_hwfn *p_hwfn,
+                                      struct malicious_vf_eqe_data *p_data)
+{
+       struct ecore_vf_info *p_vf;
+
+       p_vf = ecore_sriov_get_vf_from_absid(p_hwfn, p_data->vfId);
+
+       if (!p_vf)
+               return;
+
+       DP_INFO(p_hwfn,
+               "VF [%d] - Malicious behavior [%02x]\n",
+               p_vf->abs_vf_id, p_data->errId);
+
+       p_vf->b_malicious = true;
+
+       OSAL_PF_VF_MALICIOUS(p_hwfn, p_vf->relative_vf_id);
+}
+
 enum _ecore_status_t ecore_sriov_eqe_event(struct ecore_hwfn *p_hwfn,
                                           u8 opcode,
                                           __le16 echo,
@@ -3371,6 +3458,9 @@ enum _ecore_status_t ecore_sriov_eqe_event(struct ecore_hwfn *p_hwfn,
                DP_VERBOSE(p_hwfn, ECORE_MSG_IOV,
                           "VF-FLR is still not supported\n");
                return ECORE_SUCCESS;
+       case COMMON_EVENT_MALICIOUS_VF:
+               ecore_sriov_vfpf_malicious(p_hwfn, &data->malicious_vf);
+               return ECORE_SUCCESS;
        default:
                DP_INFO(p_hwfn->p_dev, "Unknown sriov eqe event 0x%02x\n",
                        opcode);
@@ -3393,11 +3483,11 @@ u16 ecore_iov_get_next_active_vf(struct ecore_hwfn *p_hwfn, u16 rel_vf_id)
                goto out;
 
        for (i = rel_vf_id; i < p_iov->total_vfs; i++)
-               if (ecore_iov_is_valid_vfid(p_hwfn, rel_vf_id, true))
+               if (ecore_iov_is_valid_vfid(p_hwfn, rel_vf_id, true, false))
                        return i;
 
 out:
-       return MAX_NUM_VFS;
+       return E4_MAX_NUM_VFS;
 }
 
 enum _ecore_status_t ecore_iov_copy_vf_msg(struct ecore_hwfn *p_hwfn,
@@ -3439,6 +3529,12 @@ void ecore_iov_bulletin_set_forced_mac(struct ecore_hwfn *p_hwfn,
                          "Can not set forced MAC, invalid vfid [%d]\n", vfid);
                return;
        }
+       if (vf_info->b_malicious) {
+               DP_NOTICE(p_hwfn->p_dev, false,
+                         "Can't set forced MAC to malicious VF [%d]\n",
+                         vfid);
+               return;
+       }
 
        feature = 1 << MAC_ADDR_FORCED;
        OSAL_MEMCPY(vf_info->bulletin.p_virt->mac, mac, ETH_ALEN);
@@ -3463,6 +3559,12 @@ enum _ecore_status_t ecore_iov_bulletin_set_mac(struct ecore_hwfn *p_hwfn,
                          "Can not set MAC, invalid vfid [%d]\n", vfid);
                return ECORE_INVAL;
        }
+       if (vf_info->b_malicious) {
+               DP_NOTICE(p_hwfn->p_dev, false,
+                         "Can't set MAC to malicious VF [%d]\n",
+                         vfid);
+               return ECORE_INVAL;
+       }
 
        if (vf_info->bulletin.p_virt->valid_bitmap & (1 << MAC_ADDR_FORCED)) {
                DP_VERBOSE(p_hwfn, ECORE_MSG_IOV,
@@ -3488,7 +3590,14 @@ ecore_iov_bulletin_set_forced_untagged_default(struct ecore_hwfn *p_hwfn,
        vf_info = ecore_iov_get_vf_info(p_hwfn, (u16)vfid, true);
        if (!vf_info) {
                DP_NOTICE(p_hwfn->p_dev, true,
-                         "Can not set forced MAC, invalid vfid [%d]\n", vfid);
+                         "Can not set untagged default, invalid vfid [%d]\n",
+                         vfid);
+               return ECORE_INVAL;
+       }
+       if (vf_info->b_malicious) {
+               DP_NOTICE(p_hwfn->p_dev, false,
+                         "Can't set untagged default to malicious VF [%d]\n",
+                         vfid);
                return ECORE_INVAL;
        }
 
@@ -3553,6 +3662,12 @@ void ecore_iov_bulletin_set_forced_vlan(struct ecore_hwfn *p_hwfn,
                          vfid);
                return;
        }
+       if (vf_info->b_malicious) {
+               DP_NOTICE(p_hwfn->p_dev, false,
+                         "Can't set forced vlan to malicious VF [%d]\n",
+                         vfid);
+               return;
+       }
 
        feature = 1 << VLAN_ADDR_FORCED;
        vf_info->bulletin.p_virt->pvid = pvid;
@@ -3868,7 +3983,20 @@ bool ecore_iov_is_vf_initialized(struct ecore_hwfn *p_hwfn, u16 rel_vf_id)
        return (p_vf->state == VF_ENABLED);
 }
 
-int ecore_iov_get_vf_min_rate(struct ecore_hwfn *p_hwfn, int vfid)
+bool ecore_iov_is_vf_started(struct ecore_hwfn *p_hwfn,
+                            u16 rel_vf_id)
+{
+       struct ecore_vf_info *p_vf;
+
+       p_vf = ecore_iov_get_vf_info(p_hwfn, rel_vf_id, true);
+       if (!p_vf)
+               return false;
+
+       return (p_vf->state != VF_FREE && p_vf->state != VF_STOPPED);
+}
+
+enum _ecore_status_t
+ecore_iov_get_vf_min_rate(struct ecore_hwfn *p_hwfn, int vfid)
 {
        struct ecore_wfq_data *vf_vp_wfq;
        struct ecore_vf_info *vf_info;