Commit 19d181d8 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files
Tony Nguyen says:

====================
ice: cleanups and preparation for live migration

Jake Keller says:

Various cleanups and preparation to the ice driver code for supporting
SR-IOV live migration.

The logic for unpacking Rx queue context data is added. This is the inverse
of the existing packing logic. Thanks to <linux/packing.h> this is trivial
to add.

Code to enable both reading and writing the Tx queue context for a queue
over a shared hardware register interface is added. Thanks to ice_adapter,
this is locked across all PFs that need to use it, preventing concurrency
issues with multiple PFs.

The RSS hash configuration requested by a VF is cached within the VF
structure. This will be used to track and restore the same configuration
during migration load.

ice_sriov_set_msix_vec_count() is updated to use pci_iov_vf_id() instead of
open-coding a worse equivalent, and checks to avoid rebuilding MSI-X if the
current request is for the existing amount of vectors.

A new ice_get_vf_by_dev() helper function is added to simplify accessing a
VF from its PCI device structure. This will be used more heavily within the
live migration code itself.

* '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue:
  ice: introduce ice_get_vf_by_dev() wrapper
  ice: avoid rebuilding if MSI-X vector count is unchanged
  ice: use pci_iov_vf_id() to get VF ID
  ice: expose VF functions used by live migration
  ice: move ice_vsi_update_l2tsel to ice_lib.c
  ice: save RSS hash configuration for migration
  ice: add functions to get and set Tx queue context
  ice: add support for reading and unpacking Rx queue context
====================

Link: https://patch.msgid.link/20250710214518.1824208-1-anthony.l.nguyen@intel.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents a393644d 2d925db5
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ static struct ice_adapter *ice_adapter_new(u64 dsn)

	adapter->device_serial_number = dsn;
	spin_lock_init(&adapter->ptp_gltsyn_time_lock);
	spin_lock_init(&adapter->txq_ctx_lock);
	refcount_set(&adapter->refcount, 1);

	mutex_init(&adapter->ports.lock);
+4 −1
Original line number Diff line number Diff line
@@ -27,9 +27,10 @@ struct ice_port_list {

/**
 * struct ice_adapter - PCI adapter resources shared across PFs
 * @refcount: Reference count. struct ice_pf objects hold the references.
 * @ptp_gltsyn_time_lock: Spinlock protecting access to the GLTSYN_TIME
 *                        register of the PTP clock.
 * @refcount: Reference count. struct ice_pf objects hold the references.
 * @txq_ctx_lock: Spinlock protecting access to the GLCOMM_QTX_CNTX_CTL register
 * @ctrl_pf: Control PF of the adapter
 * @ports: Ports list
 * @device_serial_number: DSN cached for collision detection on 32bit systems
@@ -38,6 +39,8 @@ struct ice_adapter {
	refcount_t refcount;
	/* For access to the GLTSYN_TIME register */
	spinlock_t ptp_gltsyn_time_lock;
	/* For access to GLCOMM_QTX_CNTX_CTL register */
	spinlock_t txq_ctx_lock;

	struct ice_pf *ctrl_pf;
	struct ice_port_list ports;
+13 −1
Original line number Diff line number Diff line
@@ -14,11 +14,23 @@

#define ICE_RXQ_CTX_SIZE_DWORDS		8
#define ICE_RXQ_CTX_SZ			(ICE_RXQ_CTX_SIZE_DWORDS * sizeof(u32))
#define ICE_TXQ_CTX_SZ			22

typedef struct __packed { u8 buf[ICE_RXQ_CTX_SZ]; } ice_rxq_ctx_buf_t;

/* The Tx queue context is 40 bytes, and includes some internal state. The
 * Admin Queue buffers don't include the internal state, so only include the
 * first 22 bytes of the context.
 */
#define ICE_TXQ_CTX_SZ			22

typedef struct __packed { u8 buf[ICE_TXQ_CTX_SZ]; } ice_txq_ctx_buf_t;

#define ICE_TXQ_CTX_FULL_SIZE_DWORDS	10
#define ICE_TXQ_CTX_FULL_SZ \
	(ICE_TXQ_CTX_FULL_SIZE_DWORDS * sizeof(u32))

typedef struct __packed { u8 buf[ICE_TXQ_CTX_FULL_SZ]; } ice_txq_ctx_buf_full_t;

struct ice_aqc_generic {
	__le32 param0;
	__le32 param1;
+230 −3
Original line number Diff line number Diff line
@@ -1342,6 +1342,26 @@ static void ice_copy_rxq_ctx_to_hw(struct ice_hw *hw,
	}
}

/**
 * ice_copy_rxq_ctx_from_hw - Copy packed Rx Queue context from HW registers
 * @hw: pointer to the hardware structure
 * @rxq_ctx: pointer to the packed Rx queue context
 * @rxq_index: the index of the Rx queue
 */
static void ice_copy_rxq_ctx_from_hw(struct ice_hw *hw,
				     ice_rxq_ctx_buf_t *rxq_ctx,
				     u32 rxq_index)
{
	u32 *ctx = (u32 *)rxq_ctx;

	/* Copy each dword separately from HW */
	for (int i = 0; i < ICE_RXQ_CTX_SIZE_DWORDS; i++, ctx++) {
		*ctx = rd32(hw, QRX_CONTEXT(i, rxq_index));

		ice_debug(hw, ICE_DBG_QCTX, "qrxdata[%d]: %08X\n", i, *ctx);
	}
}

#define ICE_CTX_STORE(struct_name, struct_field, width, lsb) \
	PACKED_FIELD((lsb) + (width) - 1, (lsb), struct struct_name, struct_field)

@@ -1385,6 +1405,21 @@ static void ice_pack_rxq_ctx(const struct ice_rlan_ctx *ctx,
		    QUIRK_LITTLE_ENDIAN | QUIRK_LSW32_IS_FIRST);
}

/**
 * ice_unpack_rxq_ctx - Unpack Rx queue context from a HW buffer
 * @buf: the HW buffer to unpack from
 * @ctx: the Rx queue context to unpack
 *
 * Unpack the Rx queue context from the HW buffer into the CPU-friendly
 * structure.
 */
static void ice_unpack_rxq_ctx(const ice_rxq_ctx_buf_t *buf,
			       struct ice_rlan_ctx *ctx)
{
	unpack_fields(buf, sizeof(*buf), ctx, ice_rlan_ctx_fields,
		      QUIRK_LITTLE_ENDIAN | QUIRK_LSW32_IS_FIRST);
}

/**
 * ice_write_rxq_ctx - Write Rx Queue context to hardware
 * @hw: pointer to the hardware structure
@@ -1410,6 +1445,31 @@ int ice_write_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx,
	return 0;
}

/**
 * ice_read_rxq_ctx - Read Rx queue context from HW
 * @hw: pointer to the hardware structure
 * @rlan_ctx: pointer to the Rx queue context
 * @rxq_index: the index of the Rx queue
 *
 * Read the Rx queue context from the hardware registers, and unpack it into
 * the sparse Rx queue context structure.
 *
 * Returns: 0 on success, or -EINVAL if the Rx queue index is invalid.
 */
int ice_read_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx,
		     u32 rxq_index)
{
	ice_rxq_ctx_buf_t buf = {};

	if (rxq_index > QRX_CTRL_MAX_INDEX)
		return -EINVAL;

	ice_copy_rxq_ctx_from_hw(hw, &buf, rxq_index);
	ice_unpack_rxq_ctx(&buf, rlan_ctx);

	return 0;
}

/* LAN Tx Queue Context */
static const struct packed_field_u8 ice_tlan_ctx_fields[] = {
				    /* Field			Width	LSB */
@@ -1443,12 +1503,12 @@ static const struct packed_field_u8 ice_tlan_ctx_fields[] = {
};

/**
 * ice_pack_txq_ctx - Pack Tx queue context into a HW buffer
 * ice_pack_txq_ctx - Pack Tx queue context into Admin Queue buffer
 * @ctx: the Tx queue context to pack
 * @buf: the HW buffer to pack into
 * @buf: the Admin Queue HW buffer to pack into
 *
 * Pack the Tx queue context from the CPU-friendly unpacked buffer into its
 * bit-packed HW layout.
 * bit-packed Admin Queue layout.
 */
void ice_pack_txq_ctx(const struct ice_tlan_ctx *ctx, ice_txq_ctx_buf_t *buf)
{
@@ -1456,6 +1516,173 @@ void ice_pack_txq_ctx(const struct ice_tlan_ctx *ctx, ice_txq_ctx_buf_t *buf)
		    QUIRK_LITTLE_ENDIAN | QUIRK_LSW32_IS_FIRST);
}

/**
 * ice_pack_txq_ctx_full - Pack Tx queue context into a HW buffer
 * @ctx: the Tx queue context to pack
 * @buf: the HW buffer to pack into
 *
 * Pack the Tx queue context from the CPU-friendly unpacked buffer into its
 * bit-packed HW layout, including the internal data portion.
 */
static void ice_pack_txq_ctx_full(const struct ice_tlan_ctx *ctx,
				  ice_txq_ctx_buf_full_t *buf)
{
	pack_fields(buf, sizeof(*buf), ctx, ice_tlan_ctx_fields,
		    QUIRK_LITTLE_ENDIAN | QUIRK_LSW32_IS_FIRST);
}

/**
 * ice_unpack_txq_ctx_full - Unpack Tx queue context from a HW buffer
 * @buf: the HW buffer to unpack from
 * @ctx: the Tx queue context to unpack
 *
 * Unpack the Tx queue context from the HW buffer (including the full internal
 * state) into the CPU-friendly structure.
 */
static void ice_unpack_txq_ctx_full(const ice_txq_ctx_buf_full_t *buf,
				    struct ice_tlan_ctx *ctx)
{
	unpack_fields(buf, sizeof(*buf), ctx, ice_tlan_ctx_fields,
		      QUIRK_LITTLE_ENDIAN | QUIRK_LSW32_IS_FIRST);
}

/**
 * ice_copy_txq_ctx_from_hw - Copy Tx Queue context from HW registers
 * @hw: pointer to the hardware structure
 * @txq_ctx: pointer to the packed Tx queue context, including internal state
 * @txq_index: the index of the Tx queue
 *
 * Copy Tx Queue context from HW register space to dense structure
 */
static void ice_copy_txq_ctx_from_hw(struct ice_hw *hw,
				     ice_txq_ctx_buf_full_t *txq_ctx,
				     u32 txq_index)
{
	struct ice_pf *pf = container_of(hw, struct ice_pf, hw);
	u32 *ctx = (u32 *)txq_ctx;
	u32 txq_base, reg;

	/* Get Tx queue base within card space */
	txq_base = rd32(hw, PFLAN_TX_QALLOC(hw->pf_id));
	txq_base = FIELD_GET(PFLAN_TX_QALLOC_FIRSTQ_M, txq_base);

	reg = FIELD_PREP(GLCOMM_QTX_CNTX_CTL_CMD_M,
			 GLCOMM_QTX_CNTX_CTL_CMD_READ) |
	      FIELD_PREP(GLCOMM_QTX_CNTX_CTL_QUEUE_ID_M,
			 txq_base + txq_index) |
	      GLCOMM_QTX_CNTX_CTL_CMD_EXEC_M;

	/* Prevent other PFs on the same adapter from accessing the Tx queue
	 * context interface concurrently.
	 */
	spin_lock(&pf->adapter->txq_ctx_lock);

	wr32(hw, GLCOMM_QTX_CNTX_CTL, reg);
	ice_flush(hw);

	/* Copy each dword separately from HW */
	for (int i = 0; i < ICE_TXQ_CTX_FULL_SIZE_DWORDS; i++, ctx++) {
		*ctx = rd32(hw, GLCOMM_QTX_CNTX_DATA(i));

		ice_debug(hw, ICE_DBG_QCTX, "qtxdata[%d]: %08X\n", i, *ctx);
	}

	spin_unlock(&pf->adapter->txq_ctx_lock);
}

/**
 * ice_copy_txq_ctx_to_hw - Copy Tx Queue context into HW registers
 * @hw: pointer to the hardware structure
 * @txq_ctx: pointer to the packed Tx queue context, including internal state
 * @txq_index: the index of the Tx queue
 */
static void ice_copy_txq_ctx_to_hw(struct ice_hw *hw,
				   const ice_txq_ctx_buf_full_t *txq_ctx,
				   u32 txq_index)
{
	struct ice_pf *pf = container_of(hw, struct ice_pf, hw);
	u32 txq_base, reg;

	/* Get Tx queue base within card space */
	txq_base = rd32(hw, PFLAN_TX_QALLOC(hw->pf_id));
	txq_base = FIELD_GET(PFLAN_TX_QALLOC_FIRSTQ_M, txq_base);

	reg = FIELD_PREP(GLCOMM_QTX_CNTX_CTL_CMD_M,
			 GLCOMM_QTX_CNTX_CTL_CMD_WRITE_NO_DYN) |
	      FIELD_PREP(GLCOMM_QTX_CNTX_CTL_QUEUE_ID_M,
			 txq_base + txq_index) |
	      GLCOMM_QTX_CNTX_CTL_CMD_EXEC_M;

	/* Prevent other PFs on the same adapter from accessing the Tx queue
	 * context interface concurrently.
	 */
	spin_lock(&pf->adapter->txq_ctx_lock);

	/* Copy each dword separately to HW */
	for (int i = 0; i < ICE_TXQ_CTX_FULL_SIZE_DWORDS; i++) {
		u32 ctx = ((const u32 *)txq_ctx)[i];

		wr32(hw, GLCOMM_QTX_CNTX_DATA(i), ctx);

		ice_debug(hw, ICE_DBG_QCTX, "qtxdata[%d]: %08X\n", i, ctx);
	}

	wr32(hw, GLCOMM_QTX_CNTX_CTL, reg);
	ice_flush(hw);

	spin_unlock(&pf->adapter->txq_ctx_lock);
}

/**
 * ice_read_txq_ctx - Read Tx queue context from HW
 * @hw: pointer to the hardware structure
 * @tlan_ctx: pointer to the Tx queue context
 * @txq_index: the index of the Tx queue
 *
 * Read the Tx queue context from the HW registers, then unpack it into the
 * ice_tlan_ctx structure for use.
 *
 * Returns: 0 on success, or -EINVAL on an invalid Tx queue index.
 */
int ice_read_txq_ctx(struct ice_hw *hw, struct ice_tlan_ctx *tlan_ctx,
		     u32 txq_index)
{
	ice_txq_ctx_buf_full_t buf = {};

	if (txq_index > QTX_COMM_HEAD_MAX_INDEX)
		return -EINVAL;

	ice_copy_txq_ctx_from_hw(hw, &buf, txq_index);
	ice_unpack_txq_ctx_full(&buf, tlan_ctx);

	return 0;
}

/**
 * ice_write_txq_ctx - Write Tx queue context to HW
 * @hw: pointer to the hardware structure
 * @tlan_ctx: pointer to the Tx queue context
 * @txq_index: the index of the Tx queue
 *
 * Pack the Tx queue context into the dense HW layout, then write it into the
 * HW registers.
 *
 * Returns: 0 on success, or -EINVAL on an invalid Tx queue index.
 */
int ice_write_txq_ctx(struct ice_hw *hw, struct ice_tlan_ctx *tlan_ctx,
		      u32 txq_index)
{
	ice_txq_ctx_buf_full_t buf = {};

	if (txq_index > QTX_COMM_HEAD_MAX_INDEX)
		return -EINVAL;

	ice_pack_txq_ctx_full(tlan_ctx, &buf);
	ice_copy_txq_ctx_to_hw(hw, &buf, txq_index);

	return 0;
}

/* Sideband Queue command wrappers */

/**
+6 −0
Original line number Diff line number Diff line
@@ -118,6 +118,12 @@ 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_read_txq_ctx(struct ice_hw *hw, struct ice_tlan_ctx *tlan_ctx,
		     u32 txq_index);
int ice_write_txq_ctx(struct ice_hw *hw, struct ice_tlan_ctx *tlan_ctx,
		      u32 txq_index);

int
ice_aq_get_rss_lut(struct ice_hw *hw, struct ice_aq_get_set_rss_lut_params *get_params);
Loading