diff mbox series

[17/27] net/ice/base: add functionality to check if DVM is supported

Message ID 20201215060519.302145-18-qi.z.zhang@intel.com (mailing list archive)
State Accepted, archived
Delegated to: Qi Zhang
Headers show
Series ice base code update | expand

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Zhang, Qi Z Dec. 15, 2020, 6:05 a.m. UTC
If a driver wants to configure double VLAN mode (DVM) it needs to
first check if the DDP supports DVM. To do this the driver needs to read
the package metadata section via the upload section AQ (0x04C1).

If the DDP doesn't support configuring double VLAN mode (DVM), then
there is nothing to do regarding configuring the VLAN mode of the
device.

The set_svm() or set_dvm() ops should only be called if the current
configuration supports configuring the VLAN mode of the device.

Signed-off-by: Dan Nowlin <dan.nowlin@intel.com>
Signed-off-by: Brett Creeley <brett.creeley@intel.com>
Suggested-by: Jacob Keller <jacob.e.keller@intel.com>
Signed-off-by: Qi Zhang <qi.z.zhang@intel.com>
---
 drivers/net/ice/base/ice_bitops.h    | 45 ++++++++++++++++
 drivers/net/ice/base/ice_flex_pipe.c | 63 +++++++++++++++++++++-
 drivers/net/ice/base/ice_flex_pipe.h | 11 ++++
 drivers/net/ice/base/ice_flex_type.h | 26 ++++++++++
 drivers/net/ice/base/ice_vlan_mode.c | 78 ++++++++++++++++++++++++++++
 5 files changed, 221 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/drivers/net/ice/base/ice_bitops.h b/drivers/net/ice/base/ice_bitops.h
index 39548967cc..b786bf7a18 100644
--- a/drivers/net/ice/base/ice_bitops.h
+++ b/drivers/net/ice/base/ice_bitops.h
@@ -449,4 +449,49 @@  ice_cmp_bitmap(ice_bitmap_t *bmp1, ice_bitmap_t *bmp2, u16 size)
 	return true;
 }
 
+/**
+ * ice_bitmap_from_array32 - copies u32 array source into bitmap destination
+ * @dst: the destination bitmap
+ * @src: the source u32 array
+ * @size: size of the bitmap (in bits)
+ *
+ * This function copies the src bitmap stored in an u32 array into the dst
+ * bitmap stored as an ice_bitmap_t.
+ */
+static inline void
+ice_bitmap_from_array32(ice_bitmap_t *dst, u32 *src, u16 size)
+{
+	u32 remaining_bits, i;
+
+#define BITS_PER_U32	(sizeof(u32) * BITS_PER_BYTE)
+	/* clear bitmap so we only have to set when iterating */
+	ice_zero_bitmap(dst, size);
+
+	for (i = 0; i < (u32)(size / BITS_PER_U32); i++) {
+		u32 bit_offset = i * BITS_PER_U32;
+		u32 entry = src[i];
+		u32 j;
+
+		for (j = 0; j < BITS_PER_U32; j++) {
+			if (entry & BIT(j))
+				ice_set_bit((u16)(j + bit_offset), dst);
+		}
+	}
+
+	/* still need to check the leftover bits (i.e. if size isn't evenly
+	 * divisible by BITS_PER_U32
+	 **/
+	remaining_bits = size % BITS_PER_U32;
+	if (remaining_bits) {
+		u32 bit_offset = i * BITS_PER_U32;
+		u32 entry = src[i];
+		u32 j;
+
+		for (j = 0; j < remaining_bits; j++) {
+			if (entry & BIT(j))
+				ice_set_bit((u16)(j + bit_offset), dst);
+		}
+	}
+}
+
 #endif /* _ICE_BITOPS_H_ */
diff --git a/drivers/net/ice/base/ice_flex_pipe.c b/drivers/net/ice/base/ice_flex_pipe.c
index 6c7f83899d..e511b50a00 100644
--- a/drivers/net/ice/base/ice_flex_pipe.c
+++ b/drivers/net/ice/base/ice_flex_pipe.c
@@ -807,6 +807,28 @@  ice_aq_download_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
 	return status;
 }
 
+/**
+ * ice_aq_upload_section
+ * @hw: pointer to the hardware structure
+ * @pkg_buf: the package buffer which will receive the section
+ * @buf_size: the size of the package buffer
+ * @cd: pointer to command details structure or NULL
+ *
+ * Upload Section (0x0C41)
+ */
+enum ice_status
+ice_aq_upload_section(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
+		      u16 buf_size, struct ice_sq_cd *cd)
+{
+	struct ice_aq_desc desc;
+
+	ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
+	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_upload_section);
+	desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
+
+	return ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd);
+}
+
 /**
  * ice_aq_update_pkg
  * @hw: pointer to the hardware structure
@@ -1800,7 +1822,7 @@  void ice_init_prof_result_bm(struct ice_hw *hw)
  *
  * Frees a package buffer
  */
-static void ice_pkg_buf_free(struct ice_hw *hw, struct ice_buf_build *bld)
+void ice_pkg_buf_free(struct ice_hw *hw, struct ice_buf_build *bld)
 {
 	ice_free(hw, bld);
 }
@@ -1899,6 +1921,43 @@  ice_pkg_buf_alloc_section(struct ice_buf_build *bld, u32 type, u16 size)
 	return NULL;
 }
 
+/**
+ * ice_pkg_buf_alloc_single_section
+ * @hw: pointer to the HW structure
+ * @type: the section type value
+ * @size: the size of the section to reserve (in bytes)
+ * @section: returns pointer to the section
+ *
+ * Allocates a package buffer with a single section.
+ * Note: all package contents must be in Little Endian form.
+ */
+struct ice_buf_build *
+ice_pkg_buf_alloc_single_section(struct ice_hw *hw, u32 type, u16 size,
+				 void **section)
+{
+	struct ice_buf_build *buf;
+
+	if (!section)
+		return NULL;
+
+	buf = ice_pkg_buf_alloc(hw);
+	if (!buf)
+		return NULL;
+
+	if (ice_pkg_buf_reserve_section(buf, 1))
+		goto ice_pkg_buf_alloc_single_section_err;
+
+	*section = ice_pkg_buf_alloc_section(buf, type, size);
+	if (!*section)
+		goto ice_pkg_buf_alloc_single_section_err;
+
+	return buf;
+
+ice_pkg_buf_alloc_single_section_err:
+	ice_pkg_buf_free(hw, buf);
+	return NULL;
+}
+
 /**
  * ice_pkg_buf_get_active_sections
  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
@@ -1926,7 +1985,7 @@  static u16 ice_pkg_buf_get_active_sections(struct ice_buf_build *bld)
  *
  * Return a pointer to the buffer's header
  */
-static struct ice_buf *ice_pkg_buf(struct ice_buf_build *bld)
+struct ice_buf *ice_pkg_buf(struct ice_buf_build *bld)
 {
 	if (!bld)
 		return NULL;
diff --git a/drivers/net/ice/base/ice_flex_pipe.h b/drivers/net/ice/base/ice_flex_pipe.h
index 214c7a2837..d4679cc940 100644
--- a/drivers/net/ice/base/ice_flex_pipe.h
+++ b/drivers/net/ice/base/ice_flex_pipe.h
@@ -38,6 +38,12 @@  ice_init_prof_result_bm(struct ice_hw *hw);
 enum ice_status
 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);
+enum ice_status
+ice_pkg_buf_unreserve_section(struct ice_buf_build *bld, u16 count);
+u16 ice_pkg_buf_get_free_space(struct ice_buf_build *bld);
+enum ice_status
+ice_aq_upload_section(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
+		      u16 buf_size, struct ice_sq_cd *cd);
 bool
 ice_get_open_tunnel_port(struct ice_hw *hw, enum ice_tunnel_type type,
 			 u16 *port);
@@ -75,6 +81,11 @@  void ice_clear_hw_tbls(struct ice_hw *hw);
 void ice_free_hw_tbls(struct ice_hw *hw);
 enum ice_status
 ice_rem_prof(struct ice_hw *hw, enum ice_block blk, u64 id);
+struct ice_buf_build *
+ice_pkg_buf_alloc_single_section(struct ice_hw *hw, u32 type, u16 size,
+				 void **section);
+struct ice_buf *ice_pkg_buf(struct ice_buf_build *bld);
+void ice_pkg_buf_free(struct ice_hw *hw, struct ice_buf_build *bld);
 
 enum ice_status
 ice_set_key(u8 *key, u16 size, u8 *val, u8 *upd, u8 *dc, u8 *nm, u16 off,
diff --git a/drivers/net/ice/base/ice_flex_type.h b/drivers/net/ice/base/ice_flex_type.h
index 7d0204fa50..08db7f2c9a 100644
--- a/drivers/net/ice/base/ice_flex_type.h
+++ b/drivers/net/ice/base/ice_flex_type.h
@@ -787,4 +787,30 @@  enum ice_prof_type {
 	ICE_PROF_TUN_ALL = 0xE,
 	ICE_PROF_ALL = 0xFF,
 };
+
+/* Number of bits/bytes contained in meta init entry. Note, this should be a
+ * multiple of 32 bits.
+ */
+#define ICE_META_INIT_BITS	192
+#define ICE_META_INIT_DW_CNT	(ICE_META_INIT_BITS / (sizeof(__le32) * \
+				 BITS_PER_BYTE))
+
+/* The meta init Flag field starts at this bit */
+#define ICE_META_FLAGS_ST		123
+
+/* The entry and bit to check for Double VLAN Mode (DVM) support */
+#define ICE_META_VLAN_MODE_ENTRY	0
+#define ICE_META_FLAG_VLAN_MODE		60
+#define ICE_META_VLAN_MODE_BIT		(ICE_META_FLAGS_ST + \
+					 ICE_META_FLAG_VLAN_MODE)
+
+struct ice_meta_init_entry {
+	__le32 bm[ICE_META_INIT_DW_CNT];
+};
+
+struct ice_meta_init_section {
+	__le16 count;
+	__le16 offset;
+	struct ice_meta_init_entry entry[1];
+};
 #endif /* _ICE_FLEX_TYPE_H_ */
diff --git a/drivers/net/ice/base/ice_vlan_mode.c b/drivers/net/ice/base/ice_vlan_mode.c
index 603de74e25..363354ff3f 100644
--- a/drivers/net/ice/base/ice_vlan_mode.c
+++ b/drivers/net/ice/base/ice_vlan_mode.c
@@ -5,6 +5,81 @@ 
 #include "ice_vlan_mode.h"
 #include "ice_common.h"
 
+/**
+ * ice_pkg_supports_dvm - determine if DDP supports Double VLAN mode (DVM)
+ * @hw: pointer to the HW struct
+ * @dvm: output variable to determine if DDP supports DVM(true) or SVM(false)
+ */
+static enum ice_status
+ice_pkg_get_supported_vlan_mode(struct ice_hw *hw, bool *dvm)
+{
+	u16 meta_init_size = sizeof(struct ice_meta_init_section);
+	struct ice_meta_init_section *sect;
+	struct ice_buf_build *bld;
+	enum ice_status status;
+
+	/* if anything fails, we assume there is no DVM support */
+	*dvm = false;
+
+	bld = ice_pkg_buf_alloc_single_section(hw,
+					       ICE_SID_RXPARSER_METADATA_INIT,
+					       meta_init_size, (void **)&sect);
+	if (!bld)
+		return ICE_ERR_NO_MEMORY;
+
+	/* only need to read a single section */
+	sect->count = CPU_TO_LE16(1);
+	sect->offset = CPU_TO_LE16(ICE_META_VLAN_MODE_ENTRY);
+
+	status = ice_aq_upload_section(hw,
+				       (struct ice_buf_hdr *)ice_pkg_buf(bld),
+				       ICE_PKG_BUF_SIZE, NULL);
+	if (!status) {
+		ice_declare_bitmap(entry, ICE_META_INIT_BITS);
+		u32 arr[ICE_META_INIT_DW_CNT];
+		u16 i;
+
+		/* convert to host bitmap format */
+		for (i = 0; i < ICE_META_INIT_DW_CNT; i++)
+			arr[i] = LE32_TO_CPU(sect->entry[0].bm[i]);
+
+		ice_bitmap_from_array32(entry, arr, (u16)ICE_META_INIT_BITS);
+
+		/* check if DVM is supported */
+		*dvm = ice_is_bit_set(entry, ICE_META_VLAN_MODE_BIT);
+	}
+
+	ice_pkg_buf_free(hw, bld);
+
+	return status;
+}
+
+/**
+ * ice_is_dvm_supported - check if double VLAN mode is supported based on DDP
+ * @hw: pointer to the hardware structure
+ *
+ * Returns true if DVM is supported and false if only SVM is supported. This
+ * function should only be called while the global config lock is held and after
+ * the package has been successfully downloaded.
+ */
+static bool ice_is_dvm_supported(struct ice_hw *hw)
+{
+	enum ice_status status;
+	bool pkg_supports_dvm;
+
+	status = ice_pkg_get_supported_vlan_mode(hw, &pkg_supports_dvm);
+	if (status) {
+		ice_debug(hw, ICE_DBG_PKG, "Failed to get supported VLAN mode, err %d\n",
+			  status);
+		return false;
+	}
+
+	if (!pkg_supports_dvm)
+		return false;
+
+	return true;
+}
+
 /**
  * ice_set_svm - set single VLAN mode
  * @hw: pointer to the HW structure
@@ -34,6 +109,9 @@  enum ice_status ice_set_vlan_mode(struct ice_hw *hw)
 {
 	enum ice_status status = ICE_ERR_NOT_IMPL;
 
+	if (!ice_is_dvm_supported(hw))
+		return ICE_SUCCESS;
+
 	if (hw->vlan_mode_ops.set_dvm)
 		status = hw->vlan_mode_ops.set_dvm(hw);