@@ -1540,6 +1540,34 @@ ice_copy_rxq_ctx_to_hw(struct ice_hw *hw, u8 *ice_rxq_ctx, u32 rxq_index)
return 0;
}
+/**
+ * ice_copy_rxq_ctx_from_hw - Copy rxq context register from HW
+ * @hw: pointer to the hardware structure
+ * @ice_rxq_ctx: pointer to the rxq context
+ * @rxq_index: the index of the Rx queue
+ *
+ * Copy rxq context from HW register space to dense structure
+ */
+static int
+ice_copy_rxq_ctx_from_hw(struct ice_hw *hw, u8 *ice_rxq_ctx, u32 rxq_index)
+{
+ u8 i;
+
+ if (!ice_rxq_ctx || rxq_index > QRX_CTRL_MAX_INDEX)
+ return -EINVAL;
+
+ /* Copy each dword separately from HW */
+ for (i = 0; i < ICE_RXQ_CTX_SIZE_DWORDS; i++) {
+ u32 *ctx = (u32 *)(ice_rxq_ctx + (i * sizeof(u32)));
+
+ *ctx = rd32(hw, QRX_CONTEXT(i, rxq_index));
+
+ ice_debug(hw, ICE_DBG_QCTX, "qrxdata[%d]: %08X\n", i, *ctx);
+ }
+
+ return 0;
+}
+
/* LAN Rx Queue Context */
static const struct ice_ctx_ele ice_rlan_ctx_info[] = {
/* Field Width LSB */
@@ -1591,6 +1619,32 @@ ice_write_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx,
return ice_copy_rxq_ctx_to_hw(hw, ctx_buf, rxq_index);
}
+/**
+ * ice_read_rxq_ctx - Read rxq context from HW
+ * @hw: pointer to the hardware structure
+ * @rlan_ctx: pointer to the rxq context
+ * @rxq_index: the index of the Rx queue
+ *
+ * Read rxq context from HW register space and then converts it from dense
+ * structure to sparse
+ */
+int
+ice_read_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx,
+ u32 rxq_index)
+{
+ u8 ctx_buf[ICE_RXQ_CTX_SZ] = { 0 };
+ int status;
+
+ if (!rlan_ctx)
+ return -EINVAL;
+
+ status = ice_copy_rxq_ctx_from_hw(hw, ctx_buf, rxq_index);
+ if (status)
+ return status;
+
+ return ice_get_ctx(ctx_buf, (u8 *)rlan_ctx, ice_rlan_ctx_info);
+}
+
/* LAN Tx Queue Context */
const struct ice_ctx_ele ice_tlan_ctx_info[] = {
/* Field Width LSB */
@@ -4743,6 +4797,220 @@ ice_set_ctx(struct ice_hw *hw, u8 *src_ctx, u8 *dest_ctx,
return 0;
}
+/**
+ * ice_read_byte - read context byte into struct
+ * @src_ctx: the context structure to read from
+ * @dest_ctx: the context to be written to
+ * @ce_info: a description of the struct to be filled
+ */
+static void
+ice_read_byte(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info)
+{
+ u8 dest_byte, mask;
+ u8 *src, *target;
+ u16 shift_width;
+
+ /* prepare the bits and mask */
+ shift_width = ce_info->lsb % 8;
+ mask = (u8)(BIT(ce_info->width) - 1);
+
+ /* shift to correct alignment */
+ mask <<= shift_width;
+
+ /* get the current bits from the src bit string */
+ src = src_ctx + (ce_info->lsb / 8);
+
+ memcpy(&dest_byte, src, sizeof(dest_byte));
+
+ dest_byte &= mask;
+
+ dest_byte >>= shift_width;
+
+ /* get the address from the struct field */
+ target = dest_ctx + ce_info->offset;
+
+ /* put it back in the struct */
+ memcpy(target, &dest_byte, sizeof(dest_byte));
+}
+
+/**
+ * ice_read_word - read context word into struct
+ * @src_ctx: the context structure to read from
+ * @dest_ctx: the context to be written to
+ * @ce_info: a description of the struct to be filled
+ */
+static void
+ice_read_word(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info)
+{
+ u16 dest_word, mask;
+ u8 *src, *target;
+ __le16 src_word;
+ u16 shift_width;
+
+ /* prepare the bits and mask */
+ shift_width = ce_info->lsb % 8;
+ mask = BIT(ce_info->width) - 1;
+
+ /* shift to correct alignment */
+ mask <<= shift_width;
+
+ /* get the current bits from the src bit string */
+ src = src_ctx + (ce_info->lsb / 8);
+
+ memcpy(&src_word, src, sizeof(src_word));
+
+ /* the data in the memory is stored as little endian so mask it
+ * correctly
+ */
+ src_word &= cpu_to_le16(mask);
+
+ /* get the data back into host order before shifting */
+ dest_word = le16_to_cpu(src_word);
+
+ dest_word >>= shift_width;
+
+ /* get the address from the struct field */
+ target = dest_ctx + ce_info->offset;
+
+ /* put it back in the struct */
+ memcpy(target, &dest_word, sizeof(dest_word));
+}
+
+/**
+ * ice_read_dword - read context dword into struct
+ * @src_ctx: the context structure to read from
+ * @dest_ctx: the context to be written to
+ * @ce_info: a description of the struct to be filled
+ */
+static void
+ice_read_dword(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info)
+{
+ u32 dest_dword, mask;
+ __le32 src_dword;
+ u8 *src, *target;
+ u16 shift_width;
+
+ /* prepare the bits and mask */
+ shift_width = ce_info->lsb % 8;
+
+ /* if the field width is exactly 32 on an x86 machine, then the shift
+ * operation will not work because the SHL instructions count is masked
+ * to 5 bits so the shift will do nothing
+ */
+ if (ce_info->width < 32)
+ mask = BIT(ce_info->width) - 1;
+ else
+ mask = (u32)~0;
+
+ /* shift to correct alignment */
+ mask <<= shift_width;
+
+ /* get the current bits from the src bit string */
+ src = src_ctx + (ce_info->lsb / 8);
+
+ memcpy(&src_dword, src, sizeof(src_dword));
+
+ /* the data in the memory is stored as little endian so mask it
+ * correctly
+ */
+ src_dword &= cpu_to_le32(mask);
+
+ /* get the data back into host order before shifting */
+ dest_dword = le32_to_cpu(src_dword);
+
+ dest_dword >>= shift_width;
+
+ /* get the address from the struct field */
+ target = dest_ctx + ce_info->offset;
+
+ /* put it back in the struct */
+ memcpy(target, &dest_dword, sizeof(dest_dword));
+}
+
+/**
+ * ice_read_qword - read context qword into struct
+ * @src_ctx: the context structure to read from
+ * @dest_ctx: the context to be written to
+ * @ce_info: a description of the struct to be filled
+ */
+static void
+ice_read_qword(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info)
+{
+ u64 dest_qword, mask;
+ __le64 src_qword;
+ u8 *src, *target;
+ u16 shift_width;
+
+ /* prepare the bits and mask */
+ shift_width = ce_info->lsb % 8;
+
+ /* if the field width is exactly 64 on an x86 machine, then the shift
+ * operation will not work because the SHL instructions count is masked
+ * to 6 bits so the shift will do nothing
+ */
+ if (ce_info->width < 64)
+ mask = BIT_ULL(ce_info->width) - 1;
+ else
+ mask = (u64)~0;
+
+ /* shift to correct alignment */
+ mask <<= shift_width;
+
+ /* get the current bits from the src bit string */
+ src = src_ctx + (ce_info->lsb / 8);
+
+ memcpy(&src_qword, src, sizeof(src_qword));
+
+ /* the data in the memory is stored as little endian so mask it
+ * correctly
+ */
+ src_qword &= cpu_to_le64(mask);
+
+ /* get the data back into host order before shifting */
+ dest_qword = le64_to_cpu(src_qword);
+
+ dest_qword >>= shift_width;
+
+ /* get the address from the struct field */
+ target = dest_ctx + ce_info->offset;
+
+ /* put it back in the struct */
+ memcpy(target, &dest_qword, sizeof(dest_qword));
+}
+
+/**
+ * ice_get_ctx - extract context bits from a packed structure
+ * @src_ctx: pointer to a generic packed context structure
+ * @dest_ctx: pointer to a generic non-packed context structure
+ * @ce_info: a description of the structure to be read from
+ */
+int
+ice_get_ctx(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info)
+{
+ int i;
+
+ for (i = 0; ce_info[i].width; i++) {
+ switch (ce_info[i].size_of) {
+ case 1:
+ ice_read_byte(src_ctx, dest_ctx, &ce_info[i]);
+ break;
+ case 2:
+ ice_read_word(src_ctx, dest_ctx, &ce_info[i]);
+ break;
+ case 4:
+ ice_read_dword(src_ctx, dest_ctx, &ce_info[i]);
+ break;
+ case 8:
+ ice_read_qword(src_ctx, dest_ctx, &ce_info[i]);
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
/**
* ice_get_lan_q_ctx - get the LAN queue context for the given VSI and TC
* @hw: pointer to the HW struct
@@ -55,6 +55,9 @@ void ice_set_safe_mode_caps(struct ice_hw *hw);
int
ice_write_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx,
u32 rxq_index);
+int
+ice_read_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx,
+ u32 rxq_index);
int
ice_aq_get_rss_lut(struct ice_hw *hw, struct ice_aq_get_set_rss_lut_params *get_params);
@@ -74,6 +77,8 @@ extern const struct ice_ctx_ele ice_tlan_ctx_info[];
int
ice_set_ctx(struct ice_hw *hw, u8 *src_ctx, u8 *dest_ctx,
const struct ice_ctx_ele *ce_info);
+int
+ice_get_ctx(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info);
extern struct mutex ice_global_cfg_lock_sw;