net/sfc: check actual all multicast unknown unicast filters
[dpdk.git] / drivers / net / ice / base / ice_flex_pipe.c
index 2d29e98..de14d9d 100644 (file)
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2001-2019
+ * Copyright(c) 2001-2020
  */
 
 #include "ice_common.h"
@@ -876,8 +876,9 @@ ice_find_seg_in_pkg(struct ice_hw *hw, u32 seg_type,
 
        ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
        ice_debug(hw, ICE_DBG_PKG, "Package format version: %d.%d.%d.%d\n",
-                 pkg_hdr->format_ver.major, pkg_hdr->format_ver.minor,
-                 pkg_hdr->format_ver.update, pkg_hdr->format_ver.draft);
+                 pkg_hdr->pkg_format_ver.major, pkg_hdr->pkg_format_ver.minor,
+                 pkg_hdr->pkg_format_ver.update,
+                 pkg_hdr->pkg_format_ver.draft);
 
        /* Search all package segments for the requested segment type */
        for (i = 0; i < LE32_TO_CPU(pkg_hdr->seg_count); i++) {
@@ -1048,13 +1049,15 @@ ice_download_pkg(struct ice_hw *hw, struct ice_seg *ice_seg)
        struct ice_buf_table *ice_buf_tbl;
 
        ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
-       ice_debug(hw, ICE_DBG_PKG, "Segment version: %d.%d.%d.%d\n",
-                 ice_seg->hdr.seg_ver.major, ice_seg->hdr.seg_ver.minor,
-                 ice_seg->hdr.seg_ver.update, ice_seg->hdr.seg_ver.draft);
+       ice_debug(hw, ICE_DBG_PKG, "Segment format version: %d.%d.%d.%d\n",
+                 ice_seg->hdr.seg_format_ver.major,
+                 ice_seg->hdr.seg_format_ver.minor,
+                 ice_seg->hdr.seg_format_ver.update,
+                 ice_seg->hdr.seg_format_ver.draft);
 
        ice_debug(hw, ICE_DBG_PKG, "Seg: type 0x%X, size %d, name %s\n",
                  LE32_TO_CPU(ice_seg->hdr.seg_type),
-                 LE32_TO_CPU(ice_seg->hdr.seg_size), ice_seg->hdr.seg_name);
+                 LE32_TO_CPU(ice_seg->hdr.seg_size), ice_seg->hdr.seg_id);
 
        ice_buf_tbl = ice_find_buf_table(ice_seg);
 
@@ -1101,14 +1104,16 @@ ice_init_pkg_info(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr)
 
        seg_hdr = ice_find_seg_in_pkg(hw, SEGMENT_TYPE_ICE, pkg_hdr);
        if (seg_hdr) {
-               hw->ice_pkg_ver = seg_hdr->seg_ver;
-               ice_memcpy(hw->ice_pkg_name, seg_hdr->seg_name,
+               hw->ice_pkg_ver = seg_hdr->seg_format_ver;
+               ice_memcpy(hw->ice_pkg_name, seg_hdr->seg_id,
                           sizeof(hw->ice_pkg_name), ICE_NONDMA_TO_NONDMA);
 
-               ice_debug(hw, ICE_DBG_PKG, "Ice Pkg: %d.%d.%d.%d, %s\n",
-                         seg_hdr->seg_ver.major, seg_hdr->seg_ver.minor,
-                         seg_hdr->seg_ver.update, seg_hdr->seg_ver.draft,
-                         seg_hdr->seg_name);
+               ice_debug(hw, ICE_DBG_PKG, "Ice Seg: %d.%d.%d.%d, %s\n",
+                         seg_hdr->seg_format_ver.major,
+                         seg_hdr->seg_format_ver.minor,
+                         seg_hdr->seg_format_ver.update,
+                         seg_hdr->seg_format_ver.draft,
+                         seg_hdr->seg_id);
        } else {
                ice_debug(hw, ICE_DBG_INIT,
                          "Did not find ice segment in driver package\n");
@@ -1150,9 +1155,11 @@ static enum ice_status ice_get_pkg_info(struct ice_hw *hw)
                if (pkg_info->pkg_info[i].is_active) {
                        flags[place++] = 'A';
                        hw->active_pkg_ver = pkg_info->pkg_info[i].ver;
+                       hw->active_track_id =
+                               LE32_TO_CPU(pkg_info->pkg_info[i].track_id);
                        ice_memcpy(hw->active_pkg_name,
                                   pkg_info->pkg_info[i].name,
-                                  sizeof(hw->active_pkg_name),
+                                  sizeof(pkg_info->pkg_info[i].name),
                                   ICE_NONDMA_TO_NONDMA);
                        hw->active_pkg_in_nvm = pkg_info->pkg_info[i].is_in_nvm;
                }
@@ -1193,10 +1200,10 @@ static enum ice_status ice_verify_pkg(struct ice_pkg_hdr *pkg, u32 len)
        if (len < sizeof(*pkg))
                return ICE_ERR_BUF_TOO_SHORT;
 
-       if (pkg->format_ver.major != ICE_PKG_FMT_VER_MAJ ||
-           pkg->format_ver.minor != ICE_PKG_FMT_VER_MNR ||
-           pkg->format_ver.update != ICE_PKG_FMT_VER_UPD ||
-           pkg->format_ver.draft != ICE_PKG_FMT_VER_DFT)
+       if (pkg->pkg_format_ver.major != ICE_PKG_FMT_VER_MAJ ||
+           pkg->pkg_format_ver.minor != ICE_PKG_FMT_VER_MNR ||
+           pkg->pkg_format_ver.update != ICE_PKG_FMT_VER_UPD ||
+           pkg->pkg_format_ver.draft != ICE_PKG_FMT_VER_DFT)
                return ICE_ERR_CFG;
 
        /* pkg must have at least one segment */
@@ -1253,6 +1260,8 @@ static void ice_init_pkg_regs(struct ice_hw *hw)
 #define ICE_SW_BLK_INP_MASK_L 0xFFFFFFFF
 #define ICE_SW_BLK_INP_MASK_H 0x0000FFFF
 #define ICE_SW_BLK_IDX 0
+       if (hw->dcf_enabled)
+               return;
 
        /* setup Switch block input mask, which is 48-bits in two parts */
        wr32(hw, GL_PREEXT_L2_PMASK0(ICE_SW_BLK_IDX), ICE_SW_BLK_INP_MASK_L);
@@ -1277,6 +1286,70 @@ static enum ice_status ice_chk_pkg_version(struct ice_pkg_ver *pkg_ver)
        return ICE_SUCCESS;
 }
 
+/**
+ * ice_chk_pkg_compat
+ * @hw: pointer to the hardware structure
+ * @ospkg: pointer to the package hdr
+ * @seg: pointer to the package segment hdr
+ *
+ * This function checks the package version compatibility with driver and NVM
+ */
+static enum ice_status
+ice_chk_pkg_compat(struct ice_hw *hw, struct ice_pkg_hdr *ospkg,
+                  struct ice_seg **seg)
+{
+       struct ice_aqc_get_pkg_info_resp *pkg;
+       enum ice_status status;
+       u16 size;
+       u32 i;
+
+       ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
+
+       /* Check package version compatibility */
+       status = ice_chk_pkg_version(&hw->pkg_ver);
+       if (status) {
+               ice_debug(hw, ICE_DBG_INIT, "Package version check failed.\n");
+               return status;
+       }
+
+       /* find ICE segment in given package */
+       *seg = (struct ice_seg *)ice_find_seg_in_pkg(hw, SEGMENT_TYPE_ICE,
+                                                    ospkg);
+       if (!*seg) {
+               ice_debug(hw, ICE_DBG_INIT, "no ice segment in package.\n");
+               return ICE_ERR_CFG;
+       }
+
+       /* Check if FW is compatible with the OS package */
+       size = ice_struct_size(pkg, pkg_info, ICE_PKG_CNT - 1);
+       pkg = (struct ice_aqc_get_pkg_info_resp *)ice_malloc(hw, size);
+       if (!pkg)
+               return ICE_ERR_NO_MEMORY;
+
+       status = ice_aq_get_pkg_info_list(hw, pkg, size, NULL);
+       if (status)
+               goto fw_ddp_compat_free_alloc;
+
+       for (i = 0; i < LE32_TO_CPU(pkg->count); i++) {
+               /* loop till we find the NVM package */
+               if (!pkg->pkg_info[i].is_in_nvm)
+                       continue;
+               if ((*seg)->hdr.seg_format_ver.major !=
+                       pkg->pkg_info[i].ver.major ||
+                   (*seg)->hdr.seg_format_ver.minor >
+                       pkg->pkg_info[i].ver.minor) {
+                       status = ICE_ERR_FW_DDP_MISMATCH;
+                       ice_debug(hw, ICE_DBG_INIT,
+                                 "OS package is not compatible with NVM.\n");
+               }
+               /* done processing NVM package so break */
+               break;
+       }
+fw_ddp_compat_free_alloc:
+       ice_free(hw, pkg);
+       return status;
+}
+
 /**
  * ice_init_pkg - initialize/download package
  * @hw: pointer to the hardware structure
@@ -1327,17 +1400,10 @@ enum ice_status ice_init_pkg(struct ice_hw *hw, u8 *buf, u32 len)
        /* before downloading the package, check package version for
         * compatibility with driver
         */
-       status = ice_chk_pkg_version(&hw->pkg_ver);
+       status = ice_chk_pkg_compat(hw, pkg, &seg);
        if (status)
                return status;
 
-       /* find segment in given package */
-       seg = (struct ice_seg *)ice_find_seg_in_pkg(hw, SEGMENT_TYPE_ICE, pkg);
-       if (!seg) {
-               ice_debug(hw, ICE_DBG_INIT, "no ice segment in package.\n");
-               return ICE_ERR_CFG;
-       }
-
        /* initialize package hints and then download package */
        ice_init_pkg_hints(hw, seg);
        status = ice_download_pkg(hw, seg);
@@ -1562,7 +1628,7 @@ ice_get_sw_fv_bitmap(struct ice_hw *hw, enum ice_prof_type req_profs,
  * allocated for every list entry.
  */
 enum ice_status
-ice_get_sw_fv_list(struct ice_hw *hw, u16 *prot_ids, u16 ids_cnt,
+ice_get_sw_fv_list(struct ice_hw *hw, u8 *prot_ids, u16 ids_cnt,
                   ice_bitmap_t *bm, struct LIST_HEAD_TYPE *fv_list)
 {
        struct ice_sw_fv_list_entry *fvl;
@@ -1817,7 +1883,7 @@ static struct ice_buf *ice_pkg_buf(struct ice_buf_build *bld)
 }
 
 /**
- * ice_tunnel_port_in_use
+ * ice_tunnel_port_in_use_hlpr - helper function to determine tunnel usage
  * @hw: pointer to the HW structure
  * @port: port to search for
  * @index: optionally returns index
@@ -1825,7 +1891,7 @@ static struct ice_buf *ice_pkg_buf(struct ice_buf_build *bld)
  * Returns whether a port is already in use as a tunnel, and optionally its
  * index
  */
-bool ice_tunnel_port_in_use(struct ice_hw *hw, u16 port, u16 *index)
+static bool ice_tunnel_port_in_use_hlpr(struct ice_hw *hw, u16 port, u16 *index)
 {
        u16 i;
 
@@ -1839,6 +1905,26 @@ bool ice_tunnel_port_in_use(struct ice_hw *hw, u16 port, u16 *index)
        return false;
 }
 
+/**
+ * ice_tunnel_port_in_use
+ * @hw: pointer to the HW structure
+ * @port: port to search for
+ * @index: optionally returns index
+ *
+ * Returns whether a port is already in use as a tunnel, and optionally its
+ * index
+ */
+bool ice_tunnel_port_in_use(struct ice_hw *hw, u16 port, u16 *index)
+{
+       bool res;
+
+       ice_acquire_lock(&hw->tnl_lock);
+       res = ice_tunnel_port_in_use_hlpr(hw, port, index);
+       ice_release_lock(&hw->tnl_lock);
+
+       return res;
+}
+
 /**
  * ice_tunnel_get_type
  * @hw: pointer to the HW structure
@@ -1850,15 +1936,21 @@ bool ice_tunnel_port_in_use(struct ice_hw *hw, u16 port, u16 *index)
 bool
 ice_tunnel_get_type(struct ice_hw *hw, u16 port, enum ice_tunnel_type *type)
 {
+       bool res = false;
        u16 i;
 
+       ice_acquire_lock(&hw->tnl_lock);
+
        for (i = 0; i < hw->tnl.count && i < ICE_TUNNEL_MAX_ENTRIES; i++)
                if (hw->tnl.tbl[i].in_use && hw->tnl.tbl[i].port == port) {
                        *type = hw->tnl.tbl[i].type;
-                       return true;
+                       res = true;
+                       break;
                }
 
-       return false;
+       ice_release_lock(&hw->tnl_lock);
+
+       return res;
 }
 
 /**
@@ -1887,7 +1979,7 @@ ice_find_free_tunnel_entry(struct ice_hw *hw, enum ice_tunnel_type type,
 }
 
 /**
- * ice_get_tunnel_port - retrieve an open tunnel port
+ * ice_get_open_tunnel_port - retrieve an open tunnel port
  * @hw: pointer to the HW structure
  * @type: tunnel type (TNL_ALL will return any open port)
  * @port: returns open port
@@ -1896,16 +1988,22 @@ bool
 ice_get_open_tunnel_port(struct ice_hw *hw, enum ice_tunnel_type type,
                         u16 *port)
 {
+       bool res = false;
        u16 i;
 
+       ice_acquire_lock(&hw->tnl_lock);
+
        for (i = 0; i < hw->tnl.count && i < ICE_TUNNEL_MAX_ENTRIES; i++)
                if (hw->tnl.tbl[i].valid && hw->tnl.tbl[i].in_use &&
                    (type == TNL_ALL || hw->tnl.tbl[i].type == type)) {
                        *port = hw->tnl.tbl[i].port;
-                       return true;
+                       res = true;
+                       break;
                }
 
-       return false;
+       ice_release_lock(&hw->tnl_lock);
+
+       return res;
 }
 
 /**
@@ -1926,15 +2024,24 @@ ice_create_tunnel(struct ice_hw *hw, enum ice_tunnel_type type, u16 port)
        struct ice_buf_build *bld;
        u16 index;
 
-       if (ice_tunnel_port_in_use(hw, port, NULL))
-               return ICE_ERR_ALREADY_EXISTS;
+       ice_acquire_lock(&hw->tnl_lock);
 
-       if (!ice_find_free_tunnel_entry(hw, type, &index))
-               return ICE_ERR_OUT_OF_RANGE;
+       if (ice_tunnel_port_in_use_hlpr(hw, port, &index)) {
+               hw->tnl.tbl[index].ref++;
+               status = ICE_SUCCESS;
+               goto ice_create_tunnel_end;
+       }
+
+       if (!ice_find_free_tunnel_entry(hw, type, &index)) {
+               status = ICE_ERR_OUT_OF_RANGE;
+               goto ice_create_tunnel_end;
+       }
 
        bld = ice_pkg_buf_alloc(hw);
-       if (!bld)
-               return ICE_ERR_NO_MEMORY;
+       if (!bld) {
+               status = ICE_ERR_NO_MEMORY;
+               goto ice_create_tunnel_end;
+       }
 
        /* allocate 2 sections, one for Rx parser, one for Tx parser */
        if (ice_pkg_buf_reserve_section(bld, 2))
@@ -1963,7 +2070,7 @@ ice_create_tunnel(struct ice_hw *hw, enum ice_tunnel_type type, u16 port)
         */
        ice_set_key((u8 *)&sect_rx->tcam[0].key, sizeof(sect_rx->tcam[0].key),
                    (u8 *)&port, NULL, NULL, NULL,
-                   offsetof(struct ice_boost_key_value, hv_dst_port_key),
+                   (u16)offsetof(struct ice_boost_key_value, hv_dst_port_key),
                    sizeof(sect_rx->tcam[0].key.key.hv_dst_port_key));
 
        /* exact copy of entry to Tx section entry */
@@ -1974,11 +2081,15 @@ ice_create_tunnel(struct ice_hw *hw, enum ice_tunnel_type type, u16 port)
        if (!status) {
                hw->tnl.tbl[index].port = port;
                hw->tnl.tbl[index].in_use = true;
+               hw->tnl.tbl[index].ref = 1;
        }
 
 ice_create_tunnel_err:
        ice_pkg_buf_free(hw, bld);
 
+ice_create_tunnel_end:
+       ice_release_lock(&hw->tnl_lock);
+
        return status;
 }
 
@@ -1998,24 +2109,38 @@ enum ice_status ice_destroy_tunnel(struct ice_hw *hw, u16 port, bool all)
        enum ice_status status = ICE_ERR_MAX_LIMIT;
        struct ice_buf_build *bld;
        u16 count = 0;
+       u16 index;
        u16 size;
        u16 i;
 
+       ice_acquire_lock(&hw->tnl_lock);
+
+       if (!all && ice_tunnel_port_in_use_hlpr(hw, port, &index))
+               if (hw->tnl.tbl[index].ref > 1) {
+                       hw->tnl.tbl[index].ref--;
+                       status = ICE_SUCCESS;
+                       goto ice_destroy_tunnel_end;
+               }
+
        /* determine count */
        for (i = 0; i < hw->tnl.count && i < ICE_TUNNEL_MAX_ENTRIES; i++)
                if (hw->tnl.tbl[i].valid && hw->tnl.tbl[i].in_use &&
                    (all || hw->tnl.tbl[i].port == port))
                        count++;
 
-       if (!count)
-               return ICE_ERR_PARAM;
+       if (!count) {
+               status = ICE_ERR_PARAM;
+               goto ice_destroy_tunnel_end;
+       }
 
        /* size of section - there is at least one entry */
-       size = (count - 1) * sizeof(*sect_rx->tcam) + sizeof(*sect_rx);
+       size = ice_struct_size(sect_rx, tcam, count - 1);
 
        bld = ice_pkg_buf_alloc(hw);
-       if (!bld)
-               return ICE_ERR_NO_MEMORY;
+       if (!bld) {
+               status = ICE_ERR_NO_MEMORY;
+               goto ice_destroy_tunnel_end;
+       }
 
        /* allocate 2 sections, one for Rx parser, one for Tx parser */
        if (ice_pkg_buf_reserve_section(bld, 2))
@@ -2057,6 +2182,7 @@ enum ice_status ice_destroy_tunnel(struct ice_hw *hw, u16 port, bool all)
                for (i = 0; i < hw->tnl.count &&
                     i < ICE_TUNNEL_MAX_ENTRIES; i++)
                        if (hw->tnl.tbl[i].marked) {
+                               hw->tnl.tbl[i].ref = 0;
                                hw->tnl.tbl[i].port = 0;
                                hw->tnl.tbl[i].in_use = false;
                                hw->tnl.tbl[i].marked = false;
@@ -2065,6 +2191,9 @@ enum ice_status ice_destroy_tunnel(struct ice_hw *hw, u16 port, bool all)
 ice_destroy_tunnel_err:
        ice_pkg_buf_free(hw, bld);
 
+ice_destroy_tunnel_end:
+       ice_release_lock(&hw->tnl_lock);
+
        return status;
 }
 
@@ -2078,7 +2207,7 @@ ice_destroy_tunnel_err:
  * @off: variable to receive the protocol offset
  */
 enum ice_status
-ice_find_prot_off(struct ice_hw *hw, enum ice_block blk, u8 prof, u8 fv_idx,
+ice_find_prot_off(struct ice_hw *hw, enum ice_block blk, u8 prof, u16 fv_idx,
                  u8 *prot, u16 *off)
 {
        struct ice_fv_word *fv_ext;
@@ -2680,9 +2809,9 @@ ice_find_prof_id_with_mask(struct ice_hw *hw, enum ice_block blk,
                           struct ice_fv_word *fv, u16 *masks, u8 *prof_id)
 {
        struct ice_es *es = &hw->blk[blk].es;
-       u16 i;
+       u8 i;
 
-       for (i = 0; i < es->count; i++) {
+       for (i = 0; i < (u8)es->count; i++) {
                u16 off = i * es->fvw;
 
                if (memcmp(&es->t[off], fv, es->fvw * sizeof(*fv)))
@@ -3528,7 +3657,8 @@ static void ice_free_flow_profs(struct ice_hw *hw, u8 blk_idx)
 
                LIST_FOR_EACH_ENTRY_SAFE(e, t, &p->entries,
                                         ice_flow_entry, l_entry)
-                       ice_flow_rem_entry(hw, ICE_FLOW_ENTRY_HNDL(e));
+                       ice_flow_rem_entry(hw, (enum ice_block)blk_idx,
+                                          ICE_FLOW_ENTRY_HNDL(e));
 
                LIST_DEL(&p->l_entry);
                if (p->acts)
@@ -3601,7 +3731,8 @@ void ice_free_hw_tbls(struct ice_hw *hw)
                ice_free(hw, r);
        }
        ice_destroy_lock(&hw->rss_locks);
-       ice_shutdown_all_prof_masks(hw);
+       if (!hw->dcf_enabled)
+               ice_shutdown_all_prof_masks(hw);
        ice_memset(hw->blk, 0, sizeof(hw->blk), ICE_NONDMA_MEM);
 }
 
@@ -3681,7 +3812,8 @@ enum ice_status ice_init_hw_tbls(struct ice_hw *hw)
 
        ice_init_lock(&hw->rss_locks);
        INIT_LIST_HEAD(&hw->rss_list_head);
-       ice_init_all_prof_masks(hw);
+       if (!hw->dcf_enabled)
+               ice_init_all_prof_masks(hw);
        for (i = 0; i < ICE_BLK_COUNT; i++) {
                struct ice_prof_redir *prof_redir = &hw->blk[i].prof_redir;
                struct ice_prof_tcam *prof = &hw->blk[i].prof;
@@ -4464,7 +4596,7 @@ ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],
        ice_declare_bitmap(ptgs_used, ICE_XLT1_CNT);
        struct ice_prof_map *prof;
        enum ice_status status;
-       u32 byte = 0;
+       u8 byte = 0;
        u8 prof_id;
 
        ice_zero_bitmap(ptgs_used, ICE_XLT1_CNT);
@@ -4513,7 +4645,7 @@ ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],
 
        /* build list of ptgs */
        while (bytes && prof->ptg_cnt < ICE_MAX_PTG_PER_PROFILE) {
-               u32 bit;
+               u8 bit;
 
                if (!ptypes[byte]) {
                        bytes--;
@@ -4562,7 +4694,7 @@ ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],
                                }
 
                                /* nothing left in byte, then exit */
-                               m = ~((1 << (bit + 1)) - 1);
+                               m = ~(u8)((1 << (bit + 1)) - 1);
                                if (!(ptypes[byte] & m))
                                        break;
                        }
@@ -5335,8 +5467,10 @@ ice_add_prof_id_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, u64 hdl,
                                              t->tcam[i].ptg, vsig, 0,
                                              t->tcam[i].attr.flags, vl_msk,
                                              dc_msk, nm_msk);
-               if (status)
+               if (status) {
+                       ice_free(hw, p);
                        goto err_ice_add_prof_id_vsig;
+               }
 
                /* log change */
                LIST_ADD(&p->list_entry, chg);